static inline void __ramfunc__ sam_pllasetup(void) { uint32_t regval; /* Configure PLLA */ #ifdef SAMA5_HAVE_PLLAR_DIV regval = (BOARD_CKGR_PLLAR_DIV | BOARD_CKGR_PLLAR_COUNT | BOARD_CKGR_PLLAR_OUT | BOARD_CKGR_PLLAR_MUL | PMC_CKGR_PLLAR_ONE); #else regval = (PMC_CKGR_PLLAR_DIV_BYPASS | BOARD_CKGR_PLLAR_COUNT | BOARD_CKGR_PLLAR_OUT | BOARD_CKGR_PLLAR_MUL | PMC_CKGR_PLLAR_ONE); #endif putreg32(regval, SAM_PMC_CKGR_PLLAR); /* Set the PLL Charge Pump Current Register to zero */ putreg32(0, SAM_PMC_PLLICPR); /* And wait for the PLL to lock on */ sam_pmcwait(PMC_INT_LOCKA); }
static inline void __ramfunc__ sam_enablemosc(void) { uint32_t regval; /* Switch from the internal 12MHz RC to the main external oscillator */ if ((getreg32(SAM_PMC_CKGR_MOR) & PMC_CKGR_MOR_MOSCSEL) == 0) { /* Enable main external oscillator */ regval = getreg32(SAM_PMC_CKGR_MOR); regval |= PMC_CKGR_MOR_MOSCXTEN | PMC_CKGR_MOR_KEY; putreg32(regval, SAM_PMC_CKGR_MOR); /* Wait for the main clock to become ready */ while ((getreg32(SAM_PMC_CKGR_MCFR) & PMC_CKGR_MCFR_MAINFRDY) == 0); /* Disable external OSC 12 MHz bypass */ regval = getreg32(SAM_PMC_CKGR_MOR); regval &= ~PMC_CKGR_MOR_MOSCXTBY; regval |= PMC_CKGR_MOR_KEY; putreg32(regval, SAM_PMC_CKGR_MOR); /* Switch main clock source to the external oscillator */ regval = getreg32(SAM_PMC_CKGR_MOR); regval |= (PMC_CKGR_MOR_MOSCSEL | PMC_CKGR_MOR_KEY); putreg32(regval, SAM_PMC_CKGR_MOR); /* Wait for the main clock status change for the external oscillator * selection. */ sam_pmcwait(PMC_INT_MOSCSELS); /* And handle the case where MCK is running on main CLK */ sam_pmcwait(PMC_INT_MCKRDY); } }
static inline void __ramfunc__ sam_selectplla(void) { uint32_t regval; /* Select the PLLA output as the main clock input */ regval = getreg32(SAM_PMC_MCKR); regval &= ~PMC_MCKR_CSS_MASK; regval |= BOARD_PMC_MCKR_CSS; putreg32(regval, SAM_PMC_MCKR); /* Wait for the main clock to be ready again */ sam_pmcwait(PMC_INT_MCKRDY); }
static inline void __ramfunc__ sam_mckdivider(void) { uint32_t regval; /* Set the main clock divider */ regval = getreg32(SAM_PMC_MCKR); regval &= ~PMC_MCKR_MDIV_MASK; regval |= BOARD_PMC_MCKR_MDIV; putreg32(regval, SAM_PMC_MCKR); /* Wait for the main clock to be ready again */ sam_pmcwait(PMC_INT_MCKRDY); }
static inline void __ramfunc__ sam_selectmosc(void) { uint32_t regval; /* Select the main oscillator as the input clock for PCK and MCK */ regval = getreg32(SAM_PMC_MCKR); regval &= ~PMC_MCKR_CSS_MASK; regval |= PMC_MCKR_CSS_MAIN; putreg32(regval, SAM_PMC_MCKR); /* Wait for main clock to be ready */ sam_pmcwait(PMC_INT_MCKRDY); }
static inline void __ramfunc__ sam_plladivider(void) { uint32_t regval; /* Is the PLLA divider currently set? */ regval = getreg32(SAM_PMC_MCKR); if ((regval & PMC_MCKR_PLLADIV2) != 0) { #if BOARD_PMC_MCKR_PLLADIV == 0 /* The divider is set and we are configured to clear it */ regval &= ~PMC_MCKR_PLLADIV2; #else /* The divider is already set */ return; #endif } else { #if BOARD_PMC_MCKR_PLLADIV == 0 /* The divider is already cleared */ return; #else /* The divider is clear and we are configured to set it */ regval |= PMC_MCKR_PLLADIV2; #endif } /* Set/clear the divider */ putreg32(regval, SAM_PMC_MCKR); /* We changed the PLLA divider. Wait for the main clock to be ready again */ sam_pmcwait(PMC_INT_MCKRDY); }
void sam_usbclock(void) { uint32_t regval; /* Enable UTMI Clocking. The USBHS can work in two modes: * * - Normal mode where High speed, Full speed and Low speed are available. * - Low-power mode where only Full speed and Low speed are available. * * Only the normal mode is supported by this logic of this function. Low- * power mode was handled in the sam_clockconfig(). */ /* UTMI normal mode, High/Full/Low Speed * * Disable the 48MHz USB FS Clock. It is not used in this configuration */ putreg32(PMC_USBCLK, SAM_PMC_SCDR); /* Select the UTMI PLL as the USB PLL clock input (480MHz) with a divider * of 1. UPLL output frequency is determined only by the 12/16MHz crystal * selection set in sam_clockconfig(). */ putreg32(PMC_USB_USBS_UPLL, SAM_PMC_USB); /* Enable the UTMI PLL with the maximum start-up time */ regval = PMC_CKGR_UCKR_UPLLEN | PMC_CKGR_UCKR_UPLLCOUNT_MAX; putreg32(regval, SAM_PMC_CKGR_UCKR); /* Wait for LOCKU */ sam_pmcwait(PMC_INT_LOCKU); }
static inline void sam_pmcsetup(void) { uint32_t regval; /* Enable main oscillator (if it has not already been selected) */ if ((getreg32(SAM_PMC_CKGR_MOR) & PMC_CKGR_MOR_MOSCSEL) == 0) { /* "When the MOSCXTEN bit and the MOSCXTCNT are written in CKGR_MOR to * enable the main oscillator, the MOSCXTS bit in the Power Management * Controller Status Register (PMC_SR) is cleared and the counter starts * counting down on the slow clock divided by 8 from the MOSCXTCNT * value. ... When the counter reaches 0, the MOSCXTS bit is set, * indicating that the main clock is valid." */ putreg32(BOARD_CKGR_MOR, SAM_PMC_CKGR_MOR); sam_pmcwait(PMC_INT_MOSCXTS); } /* "Switch to the main oscillator. The selection is made by writing the * MOSCSEL bit in the Main Oscillator Register (CKGR_MOR). The switch of * the Main Clock source is glitch free, so there is no need to run out * of SLCK, PLLACK or UPLLCK in order to change the selection. The MOSCSELS * bit of the power Management Controller Status Register (PMC_SR) allows * knowing when the switch sequence is done." * * MOSCSELS: Main Oscillator Selection Status * 0 = Selection is done * 1 = Selection is in progress */ putreg32((BOARD_CKGR_MOR | PMC_CKGR_MOR_MOSCSEL), SAM_PMC_CKGR_MOR); sam_pmcwait(PMC_INT_MOSCSELS); /* "Select the master clock. "The Master Clock selection is made by writing * the CSS field (Clock Source Selection) in PMC_MCKR (Master Clock Register). * The prescaler supports the division by a power of 2 of the selected clock * between 1 and 64, and the division by 3. The PRES field in PMC_MCKR programs * the prescaler. Each time PMC_MCKR is written to define a new Master Clock, * the MCKRDY bit is cleared in PMC_SR. It reads 0 until the Master Clock is * established. */ regval = getreg32(SAM_PMC_MCKR); regval &= ~PMC_MCKR_CSS_MASK; regval |= PMC_MCKR_CSS_MAIN; putreg32(regval, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); /* Setup PLLA and wait for LOCKA */ putreg32(BOARD_CKGR_PLLAR, SAM_PMC_CKGR_PLLAR); sam_pmcwait(PMC_INT_LOCKA); #ifdef CONFIG_SAMV7_USBDEVHS /* UTMI configuration: Enable port0, select 12/16 MHz MAINOSC crystal source */ #if BOARD_MAINOSC_FREQUENCY == 12000000 putreg32(UTMI_CKTRIM_FREQ_XTAL12, SAM_UTMI_CKTRIM); #elif BOARD_MAINOSC_FREQUENCY == 16000000 putreg32(UTMI_CKTRIM_FREQ_XTAL16, SAM_UTMI_CKTRIM); #else # error ERROR: Unrecognized MAINSOSC frequency #endif #ifdef CONFIG_SAMV7_USBDEVHS_LOWPOWER /* Enable UTMI Clocking. The USBHS can work in two modes: * * - Normal mode where High speed, Full speed and Low speed are available. * - Low-power mode where only Full speed and Low speed are available. * * Only the Low-power mode is mode is supported by the logic here. Normal * mode logic is handled in the function sam_usbclock(). */ /* UTMI Low-power mode, Full/Low Speed mode * * Enable the 48MHz FS Clock. */ putreg32(PMC_USBCLK, SAM_PMC_SCER); /* Select the UTMI PLL as the USB PLL clock input (480MHz) with divider * to get to 48MHz. UPLL output frequency is determined only by the * 12/16MHz crystal selection above. */ regval = PMC_USB_USBS_UPLL; if ((getreg32(SAM_PMC_MCKR) & PMC_MCKR_PLLADIV2) != 0) { /* Divider = 480 Mhz / 2 / 48 Mhz = 5 */ regval |= PMC_USB_USBDIV(4); } else { /* Divider = 480 Mhz / 1 / 48 Mhz = 10 */ regval |= PMC_USB_USBDIV(9); } putreg32(regval, SAM_PMC_USB); /* Enable the UTMI PLL with the maximum start-up time */ regval = PMC_CKGR_UCKR_UPLLEN | PMC_CKGR_UCKR_UPLLCOUNT_MAX; putreg32(regval, SAM_PMC_CKGR_UCKR); /* Wait for LOCKU */ sam_pmcwait(PMC_INT_LOCKU); #endif /* CONFIG_SAMV7_USBDEVHS_LOWPOWER */ #endif /* CONFIG_SAMV7_USBDEVHS */ /* Switch to the fast clock and wait for MCKRDY */ putreg32(BOARD_PMC_MCKR_FAST, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); putreg32(BOARD_PMC_MCKR, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); }
static inline void sam_pmcsetup(void) { uint32_t regval; /* Enable main oscillator (if it has not already been selected) */ if ((getreg32(SAM_PMC_CKGR_MOR) & PMC_CKGR_MOR_MOSCSEL) == 0) { /* "When the MOSCXTEN bit and the MOSCXTCNT are written in CKGR_MOR to * enable the main oscillator, the MOSCXTS bit in the Power Management * Controller Status Register (PMC_SR) is cleared and the counter starts * counting down on the slow clock divided by 8 from the MOSCXTCNT * value. ... When the counter reaches 0, the MOSCXTS bit is set, * indicating that the main clock is valid." */ putreg32(BOARD_CKGR_MOR, SAM_PMC_CKGR_MOR); sam_pmcwait(PMC_INT_MOSCXTS); } /* "Switch to the main oscillator. The selection is made by writing the * MOSCSEL bit in the Main Oscillator Register (CKGR_MOR). The switch of * the Main Clock source is glitch free, so there is no need to run out * of SLCK, PLLACK or UPLLCK in order to change the selection. The MOSCSELS * bit of the power Management Controller Status Register (PMC_SR) allows * knowing when the switch sequence is done." * * MOSCSELS: Main Oscillator Selection Status * 0 = Selection is done * 1 = Selection is in progress */ putreg32((BOARD_CKGR_MOR | PMC_CKGR_MOR_MOSCSEL), SAM_PMC_CKGR_MOR); sam_pmcwait(PMC_INT_MOSCSELS); /* "Select the master clock. "The Master Clock selection is made by writing * the CSS field (Clock Source Selection) in PMC_MCKR (Master Clock Register). * The prescaler supports the division by a power of 2 of the selected clock * between 1 and 64, and the division by 3. The PRES field in PMC_MCKR programs * the prescaler. Each time PMC_MCKR is written to define a new Master Clock, * the MCKRDY bit is cleared in PMC_SR. It reads 0 until the Master Clock is * established. */ regval = getreg32(SAM_PMC_MCKR); regval &= ~PMC_MCKR_CSS_MASK; regval |= PMC_MCKR_CSS_MAIN; putreg32(regval, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); #if defined(CONFIG_ARCH_CHIP_SAM4E) /* Setup the maximum value for the PLLAR multiplier. The PMMR register * "defines the maximum value of multiplication factor that can be sent to * PLLA. Any value of the MULA bitfield ... above PLLA_MMAX is saturated * to PLLA_MMAX. */ //putreg32(PMC_PMMR_MASK, SAM_PMC_PMMR); #endif /* Setup PLLA and wait for LOCKA */ putreg32(BOARD_CKGR_PLLAR, SAM_PMC_CKGR_PLLAR); sam_pmcwait(PMC_INT_LOCKA); #ifdef CONFIG_ARCH_CHIP_SAM4CM /* Setup PLLB and wait for LOCKB */ putreg32(BOARD_CKGR_PLLBR, SAM_PMC_CKGR_PLLBR); sam_pmcwait(PMC_INT_LOCKB); #endif #ifdef CONFIG_USBDEV /* Setup UTMI for USB and wait for LOCKU */ #ifdef SAM_PMC_CKGR_UCKR /* This MCU has a USB PLL. Configure the UPLL and wait for it to lock. */ regval = getreg32(SAM_PMC_CKGR_UCKR); regval |= BOARD_CKGR_UCKR; putreg32(regval, SAM_PMC_CKGR_UCKR); sam_pmcwait(PMC_INT_LOCKU); #else /* This board does not have a UPLL. Use the output of PLLA or PLLA * (depending on USBS) and setup the PLL divisor to generate the 48MHz * USB clock. */ regval = (BOARD_PMC_USBS | BOARD_PMC_USBDIV); putreg32(regval, SAM_PMC_USB); #if 0 /* Done in the UDP driver */ /* Set the UDP bit in the SCER register to enable the USB clock output */ regval = getreg32(SAM_PMC_SCER); regval |= PMC_UDP; putreg32(regval, SAM_PMC_SCER); #endif /* 0 */ #endif /* SAM_PMC_CKGR_UCKR */ #endif /* CONFIG_USBDEV */ /* Switch to the fast clock and wait for MCKRDY */ putreg32(BOARD_PMC_MCKR_FAST, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); putreg32(BOARD_PMC_MCKR, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); }
static inline void sam_pmcsetup(void) { uint32_t regval; /* Enable main oscillator (if it has not already been selected) */ if ((getreg32(SAM_PMC_CKGR_MOR) & PMC_CKGR_MOR_MOSCSEL) == 0) { /* "When the MOSCXTEN bit and the MOSCXTCNT are written in CKGR_MOR to * enable the main oscillator, the MOSCXTS bit in the Power Management * Controller Status Register (PMC_SR) is cleared and the counter starts * counting down on the slow clock divided by 8 from the MOSCXTCNT * value. ... When the counter reaches 0, the MOSCXTS bit is set, * indicating that the main clock is valid." */ putreg32(BOARD_CKGR_MOR, SAM_PMC_CKGR_MOR); sam_pmcwait(PMC_INT_MOSCXTS); } /* "Switch to the main oscillator. The selection is made by writing the * MOSCSEL bit in the Main Oscillator Register (CKGR_MOR). The switch of * the Main Clock source is glitch free, so there is no need to run out * of SLCK, PLLACK or UPLLCK in order to change the selection. The MOSCSELS * bit of the power Management Controller Status Register (PMC_SR) allows * knowing when the switch sequence is done." * * MOSCSELS: Main Oscillator Selection Status * 0 = Selection is done * 1 = Selection is in progress */ putreg32((BOARD_CKGR_MOR | PMC_CKGR_MOR_MOSCSEL), SAM_PMC_CKGR_MOR); sam_pmcwait(PMC_INT_MOSCSELS); /* "Select the master clock. "The Master Clock selection is made by writing * the CSS field (Clock Source Selection) in PMC_MCKR (Master Clock Register). * The prescaler supports the division by a power of 2 of the selected clock * between 1 and 64, and the division by 3. The PRES field in PMC_MCKR programs * the prescaler. Each time PMC_MCKR is written to define a new Master Clock, * the MCKRDY bit is cleared in PMC_SR. It reads 0 until the Master Clock is * established. */ regval = getreg32(SAM_PMC_MCKR); regval &= ~PMC_MCKR_CSS_MASK; regval |= PMC_MCKR_CSS_MAIN; putreg32(regval, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); /* Setup PLLA and wait for LOCKA */ putreg32(BOARD_CKGR_PLLAR, SAM_PMC_CKGR_PLLAR); sam_pmcwait(PMC_INT_LOCKA); /* Setup UTMI for USB and wait for LOCKU */ #ifdef CONFIG_USBDEV regval = getreg32(SAM_PMC_CKGR_UCKR); regval |= BOARD_CKGR_UCKR; putreg32(regval, SAM_PMC_CKGR_UCKR); sam_pmcwait(PMC_INT_LOCKU); #endif /* Switch to the fast clock and wait for MCKRDY */ putreg32(BOARD_PMC_MCKR_FAST, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); putreg32(BOARD_PMC_MCKR, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); }
static inline void sam_usbclockconfig(void) { #if defined(CONFIG_SAMA5_EHCI) || defined(CONFIG_SAMA5_OHCI) || \ defined(CONFIG_SAMA5_UDPHS) /* We can either get the clock from the UPLL or from PLLA. In this latter * case, however, the PLLACK frequency must be a multiple of 48MHz. */ #if defined(BOARD_USE_UPLL) uint32_t regval; /* The USB Host High Speed requires a 480 MHz clock (UPLLCK) for the * embedded High-speed transceivers. UPLLCK is the output of the 480 MHz * UTMI PLL (UPLL). The source clock of the UTMI PLL is the Main OSC output: * Either the 12MHz internal oscillator on a 12MHz crystal. The Main OSC * must be 12MHz because the UPLL has a built-in 40x multiplier. * * For High-speed operations, the user has to perform the following: * * 1) Enable UHP peripheral clock, bit (1 << AT91C_ID_UHPHS) in * PMC_PCER register. * 2) Write CKGR_PLLCOUNT field in PMC_UCKR register. * 3) Enable UPLL, bit AT91C_CKGR_UPLLEN in PMC_UCKR register. * 4) Wait until UTMI_PLL is locked. LOCKU bit in PMC_SR register * 5) Enable BIAS, bit AT91C_CKGR_BIASEN in PMC_UCKR register. * 6) Select UPLLCK as Input clock of OHCI part, USBS bit in PMC_USB * register. * 7) Program the OHCI clocks (UHP48M and UHP12M) with USBDIV field in * PMC_USB register. USBDIV must be 9 (division by 10) if UPLLCK is * selected. * 8) Enable OHCI clocks, UHP bit in PMC_SCER register. * * Steps 2 through 7 performed here. 1 and 8 are performed in the EHCI * driver is initialized. */ /* 2) Write CKGR_PLLCOUNT field in PMC_UCKR register. */ regval = PMC_CKGR_UCKR_UPLLCOUNT(BOARD_CKGR_UCKR_UPLLCOUNT); putreg32(regval, SAM_PMC_CKGR_UCKR); /* 3) Enable UPLL, bit AT91C_CKGR_UPLLEN in PMC_UCKR register. */ regval |= PMC_CKGR_UCKR_UPLLEN; putreg32(regval, SAM_PMC_CKGR_UCKR); /* 4) Wait until UTMI_PLL is locked. LOCKU bit in PMC_SR register */ sam_pmcwait(PMC_INT_LOCKU); /* 5) Enable BIAS, bit AT91C_CKGR_BIASEN in PMC_UCKR register. */ regval |= PMC_CKGR_UCKR_BIASCOUNT(BOARD_CKGR_UCKR_BIASCOUNT); putreg32(regval, SAM_PMC_CKGR_UCKR); regval |= PMC_CKGR_UCKR_BIASEN; putreg32(regval, SAM_PMC_CKGR_UCKR); /* 6) Select UPLLCK as Input clock of OHCI part, USBS bit in PMC_USB * register. */ regval = PMC_USB_USBS_UPLL; putreg32(regval, SAM_PMC_USB); /* 7) Program the OHCI clocks (UHP48M and UHP12M) with USBDIV field in * PMC_USB register. USBDIV must be 9 (division by 10) if UPLLCK is * selected. * * REVISIT: The divisor of 10 produces a rate that is too high with * SAMA5D3. A divisor of 5, however, seems to work just fine for the * SAMA5D3. The SAMA5D4, on the other hand, needs the divisor of 10. * No idea why? Let the board.h file decide which to use. */ regval |= PMC_USB_USBDIV(BOARD_UPLL_OHCI_DIV-1); putreg32(regval, SAM_PMC_USB); #else /* BOARD_USE_UPLL */ /* For OHCI Full-speed operations only, the user has to perform the * following: * * 1) Enable UHP peripheral clock, bit (1 << AT91C_ID_UHPHS) in PMC_PCER * register. * 2) Select PLLACK as Input clock of OHCI part, USBS bit in PMC_USB * register. * 3) Program the OHCI clocks (UHP48M and UHP12M) with USBDIV field in * PMC_USB register. USBDIV value is calculated regarding the PLLACK * value and USB Full-speed accuracy. * 4) Enable the OHCI clocks, UHP bit in PMC_SCER register. * * Steps 2 and 3 are done here. 1 and 2 are performed with the OHCI * driver is initialized. */ putreg32(BOARD_OHCI_INPUT | BOARD_OHCI_DIVIDER << PMC_USB_USBDIV_SHIFT, SAM_PMC_USB); #endif /* BOARD_USE_UPLL */ #endif /* CONFIG_SAMA5_EHCI ||CONFIG_SAMA5_OHCI) || CONFIG_SAMA5_UDPHS */ }