summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-12-22 11:45:10 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-12-22 11:45:10 -0600
commitf401d4504753f5c7e43aae2fbba86efbc6930adf (patch)
treedbb0b91d3e6128f75820b136439da24f3cc45d58
parent9f41f2c5ac982852a91945a7d2c448f5767e66c3 (diff)
downloadnuttx-f401d4504753f5c7e43aae2fbba86efbc6930adf.tar.gz
nuttx-f401d4504753f5c7e43aae2fbba86efbc6930adf.tar.bz2
nuttx-f401d4504753f5c7e43aae2fbba86efbc6930adf.zip
TM4C129X: First cut at new Tiva clock configuration logic
-rw-r--r--nuttx/arch/arm/src/tiva/tiva_syscontrol.h24
-rw-r--r--nuttx/arch/arm/src/tiva/tm4c129_syscontrol.c315
2 files changed, 273 insertions, 66 deletions
diff --git a/nuttx/arch/arm/src/tiva/tiva_syscontrol.h b/nuttx/arch/arm/src/tiva/tiva_syscontrol.h
index b012a2746..fc1bef595 100644
--- a/nuttx/arch/arm/src/tiva/tiva_syscontrol.h
+++ b/nuttx/arch/arm/src/tiva/tiva_syscontrol.h
@@ -93,24 +93,30 @@ extern "C"
* The pllfreq0 and pllfreq1 settings derive from the PLL M, N, and Q
* values to generate Fvco like:
*
- * Fin = Fxtal / (Q + 1 )(N + 1) -OR- Fpiosc / (Q + 1)(N + 1)
+ * Fin = Fxtal / Q / N -OR- Fpiosc / Q / N
* Mdiv = Mint + (MFrac / 1024)
* Fvco = Fin * Mdiv
*
- * When the PLL is active, the system clock frequency (SysClk) is calculated
- * using the following equation:
+ * When the PLL is active, the system clock frequency (SysClk) is
+ * calculated using the following equation:
*
- * SysClk = Fvco/ (sysdiv + 1)
+ * SysClk = Fvco/ sysdiv
*
- * See the helper macros M2PLLFREQ0(mint,mfrac) and QN2PLLFREQ1(q,n).
+ * NOTE: The input clock to the PLL may be either the external crystal
+ * (Fxtal) or PIOSC (Fpiosc). This logic supports only the external
+ * crystal as the PLL source clock.
*
- * NOTE: The input clock to the PLL may be either the external crystal
- * (Fxtal) or PIOSC (Fpiosc). This logic supports only the external
- * crystal as the PLL source clock.
+ * Input Parameters:
+ * pllfreq0 - PLLFREQ0 register value (see helper macro M2PLLFREQ0()
+ * pllfreq1 - PLLFREQ1 register value (see helper macro QN2PLLFREQ1()
+ * sysdiv - Fvco divider value
+ *
+ * Returned Value:
+ * The resulting SysClk frequency
*
****************************************************************************/
-void tiva_clockconfig(uint32_t pllfreq0, uint32_t pllfreq1, uint32_t sysdiv);
+uint32_t tiva_clockconfig(uint32_t pllfreq0, uint32_t pllfreq1, uint32_t sysdiv);
#else
/****************************************************************************
diff --git a/nuttx/arch/arm/src/tiva/tm4c129_syscontrol.c b/nuttx/arch/arm/src/tiva/tm4c129_syscontrol.c
index 3be5b68cc..425909a4d 100644
--- a/nuttx/arch/arm/src/tiva/tm4c129_syscontrol.c
+++ b/nuttx/arch/arm/src/tiva/tm4c129_syscontrol.c
@@ -55,14 +55,70 @@
* Pre-processor Definitions
****************************************************************************/
-#define FAST_OSCDELAY (512*1024)
-#define SLOW_OSCDELAY (4*1024)
-#define PLLLOCK_DELAY (32*1024)
+#if XTAL_FREQUENCY < 5000000 || XTAL_FREQUENCY > 25000000
+# error Crystal frequency is not supported
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure supports mapping of a frequency to optimal memory timing */
+
+struct f2memtim0_s
+{
+ uint32_t frequency;
+ uint32_t memtim0;
+};
/****************************************************************************
* Private Data
****************************************************************************/
+/* This structure supports mapping of a frequency to optimal memory timing */
+
+static const struct f2memtim0_s g_f2memtim0[] =
+{
+ {
+ 16000000,
+ (SYSCON_MEMTIM0_FWS(0) | SYSCON_MEMTIM0_FBCE | SYSCON_MEMTIM0_FBCHT_0p5 |
+ SYSCON_MEMTIM0_EWS(0) | SYSCON_MEMTIM0_EBCE | SYSCON_MEMTIM0_EBCHT_0p5 |
+ SYSCON_MEMTIM0_MB1)
+ },
+ {
+ 40000000,
+ (SYSCON_MEMTIM0_FWS(1) | SYSCON_MEMTIM0_FBCHT_1p5 |
+ SYSCON_MEMTIM0_EWS(1) | SYSCON_MEMTIM0_EBCHT_1p5 |
+ SYSCON_MEMTIM0_MB1)
+ },
+ {
+ 60000000,
+ (SYSCON_MEMTIM0_FWS(2) | SYSCON_MEMTIM0_FBCHT_2 |
+ SYSCON_MEMTIM0_EWS(2) | SYSCON_MEMTIM0_EBCHT_2 |
+ SYSCON_MEMTIM0_MB1)
+ },
+ {
+ 80000000,
+ (SYSCON_MEMTIM0_FWS(3) | SYSCON_MEMTIM0_FBCHT_2p5 |
+ SYSCON_MEMTIM0_EWS(3) | SYSCON_MEMTIM0_EBCHT_2p5 |
+ SYSCON_MEMTIM0_MB1)
+ },
+ {
+ 100000000,
+ (SYSCON_MEMTIM0_FWS(4) | SYSCON_MEMTIM0_FBCHT_3 |
+ SYSCON_MEMTIM0_EWS(4) | SYSCON_MEMTIM0_EBCHT_3 |
+ SYSCON_MEMTIM0_MB1)
+ },
+ {
+ 120000000,
+ (SYSCON_MEMTIM0_FWS(5) | SYSCON_MEMTIM0_FBCHT_3p5 |
+ SYSCON_MEMTIM0_EWS(5) | SYSCON_MEMTIM0_EBCHT_3p5 |
+ SYSCON_MEMTIM0_MB1)
+ },
+};
+
+#define NMEMTIM0_SETTINGS (sizeof(g_f2memtim0) / sizeof(struct f2memtim0_s))
+
/****************************************************************************
* Public Data
****************************************************************************/
@@ -72,74 +128,79 @@
****************************************************************************/
/****************************************************************************
- * Name: tiva_delay
+ * Name: tiva_memtim0
*
* Description:
- * Wait for the newly selected oscillator(s) to settle. This is tricky
- * because the time that we wait can be significant and is determined by
- * the previous clock setting, not the one that we are configuring.
+ * Given a SysClk frequency, perform a table lookup to select the optimal
+ * FLASH and EEPROM configuration for the MEMTIM0 register.
*
****************************************************************************/
-static inline void tiva_delay(uint32_t delay)
+static uint32_t tiva_memtim0(uint32_t sysclk)
{
- __asm__ __volatile__("1:\n"
- "\tsubs %0, #1\n"
- "\tbne 1b\n"
- : "=r"(delay) : "r"(delay));
-}
+ int i;
-/****************************************************************************
- * Name: tiva_oscdelay
- *
- * Description:
- * Wait for the newly selected oscillator(s) to settle. This is tricky because
- * the time that we wait can be significant and is determined by the previous
- * clock setting, not the one that we are configuring.
- *
- ****************************************************************************/
+ /* Search for the optimal memory timing */
-static inline void tiva_oscdelay(uint32_t rcc, uint32_t rcc2)
-{
- /* Wait for the oscillator to stabilize. A smaller delay is used if the
- * current clock rate is very slow.
- */
+ for (i = 0; i < NMEMTIM0_SETTINGS; i++)
+ {
+ /* Check if if the SysClk is less than the maximum frequency for this
+ * flash memory timing.
+ */
- uint32_t delay = FAST_OSCDELAY;
-#warning Missing logic
+ if (sysclk <= g_f2memtim0[i].frequency)
+ {
+ /* Yes.. then this FLASH memory timing is the best choice for the
+ * given system clock frequency.
+ */
- /* Then delay that number of loops */
+ return(g_f2memtim0[i].memtim0);
+ }
+ }
- tiva_delay(delay);
+ /* No appropriate flash memory timing could be found. The device is
+ * being clocked too fast.
+ */
+
+ DEBUGPANIC();
+ return 0;
}
/****************************************************************************
- * Name: tiva_pll_lock
+ * Name: tiva_vco_frequency
*
* Description:
- * The new RCC values have been selected... wait for the PLL to lock on
+ * Given the crystal frequency and the PLLFREQ0 and PLLFREQ1 register
+ * settings, return the SysClk frequency.
*
****************************************************************************/
-static inline void tiva_pll_lock(void)
+static uint32_t tiva_vco_frequency(uint32_t pllfreq0, uint32_t pllfreq1)
{
- volatile uint32_t delay;
-
- /* Loop until the lock is achieved or until a timeout occurs */
+ uint64_t fvcob10;
+ uint32_t mint;
+ uint32_t mfrac;
+ uint32_t q;
+ uint32_t n;
+ uint32_t mdivb10;
- for (delay = PLLLOCK_DELAY; delay > 0; delay--)
- {
- /* Check if the PLL is locked on */
+ /* Extract all of the values from the hardware register values. */
- if ((getreg32(TIVA_SYSCON_RIS) & SYSCON_RIS_PLLLRIS) != 0)
- {
- /* Yes.. return now */
+ mfrac = (pllfreq0 & SYSCON_PLLFREQ0_MFRAC_MASK) >> SYSCON_PLLFREQ0_MFRAC_SHIFT;
+ mint = (pllfreq0 & SYSCON_PLLFREQ0_MINT_MASK) >> SYSCON_PLLFREQ0_MINT_SHIFT;
+ q = ((pllfreq1 & SYSCON_PLLFREQ1_Q_MASK) >> SYSCON_PLLFREQ1_Q_SHIFT) + 1;
+ n = ((pllfreq1 & SYSCON_PLLFREQ1_N_MASK) >> SYSCON_PLLFREQ1_N_SHIFT) + 1;
- return;
- }
- }
+ /* Algorithm:
+ *
+ * Fin = Fxtal / Q / N (-OR- Fpiosc / Q / N)
+ * Mdiv = Mint + (MFrac / 1024)
+ * Fvco = Fin * Mdiv
+ */
- /* If we get here, then PLL lock was not achieved */
+ mdivb10 = (mint << 10) + mfrac;
+ fvcob10 = (mdivb10 * (uint64_t)XTAL_FREQUENCY) / (q * n);
+ return (uint32_t)(fvcob10 >> 10);
}
/****************************************************************************
@@ -157,26 +218,166 @@ static inline void tiva_pll_lock(void)
* The pllfreq0 and pllfreq1 settings derive from the PLL M, N, and Q
* values to generate Fvco like:
*
- * Fin = Fxtal / (Q + 1 )(N + 1) -OR- Fpiosc / (Q + 1)(N + 1)
+ * Fin = Fxtal / Q / N -OR- Fpiosc / Q / N
* Mdiv = Mint + (MFrac / 1024)
* Fvco = Fin * Mdiv
*
- * When the PLL is active, the system clock frequency (SysClk) is calculated
- * using the following equation:
+ * When the PLL is active, the system clock frequency (SysClk) is
+ * calculated using the following equation:
+ *
+ * SysClk = Fvco/ sysdiv
*
- * SysClk = Fvco/ (sysdiv + 1)
+ * NOTE: The input clock to the PLL may be either the external crystal
+ * (Fxtal) or PIOSC (Fpiosc). This logic supports only the external
+ * crystal as the PLL source clock.
*
- * See the helper macros M2PLLFREQ0(mint,mfrac) and QN2PLLFREQ1(q,n).
+ * Input Parameters:
+ * pllfreq0 - PLLFREQ0 register value (see helper macro M2PLLFREQ0()
+ * pllfreq1 - PLLFREQ1 register value (see helper macro QN2PLLFREQ1()
+ * sysdiv - Fvco divider value
*
- * NOTE: The input clock to the PLL may be either the external crystal
- * (Fxtal) or PIOSC (Fpiosc). This logic supports only the external
- * crystal as the PLL source clock.
+ * Returned Value:
+ * The resulting SysClk frequency
*
****************************************************************************/
-void tiva_clockconfig(uint32_t pllfreq0, uint32_t pllfreq1, uint32_t sysdiv)
+uint32_t tiva_clockconfig(uint32_t pllfreq0, uint32_t pllfreq1, uint32_t sysdiv)
{
-#warning Missing logic
+ uint32_t oscselect;
+ uint32_t sysclk;
+ uint32_t regval;
+ int32_t timeout;
+ bool newpll;
+
+ /* Set the PLL source select to MOSC. */
+
+ oscselect = SYSCON_RSCLKCFG_OSCSRC_MOSC | SYSCON_RSCLKCFG_PLLSRC_MOSC;
+
+ /* Clear MOSC power down, high oscillator range setting, and no crystal
+ * present settings.
+ */
+
+ regval = getreg32(TIVA_SYSCON_MOSCCTL);
+ regval &= ~(SYSCON_MOSCCTL_OSCRNG | SYSCON_MOSCCTL_PWRDN |
+ SYSCON_MOSCCTL_NOXTAL);
+
+#if XTAL_FREQUENCY >= 10000000
+ /* Increase the drive strength for MOSC of 10 MHz and above. */
+
+ regval |= SYSCON_MOSCCTL_OSCRNG;
+#endif
+
+ putreg32(regval, TIVA_SYSCON_MOSCCTL);
+
+ /* Set the memory timings for the maximum external frequency since this
+ * could be a switch to PIOSC or possibly to MOSC which can be up to
+ * 25MHz.
+ */
+
+ regval = tiva_memtim0(25000000);
+ putreg32(regval, TIVA_SYSCON_MEMTIM0);
+
+ /* Clear any previous PLL divider and source setup. Update the clock
+ * configuration to switch back to PIOSC.
+ */
+
+ regval = getreg32(TIVA_SYSCON_RSCLKCFG);
+ regval &= ~(SYSCON_RSCLKCFG_PSYSDIV_MASK | SYSCON_RSCLKCFG_OSCSRC_MASK |
+ SYSCON_RSCLKCFG_PLLSRC_MASK | SYSCON_RSCLKCFG_USEPLL);
+ regval |= SYSCON_RSCLKCFG_MEMTIMU;
+ putreg32(regval, TIVA_SYSCON_RSCLKCFG);
+
+ /* If there were no changes to the PLL do not force the PLL to lock by
+ * writing the PLL settings.
+ */
+
+ newpll = (getreg32(TIVA_SYSCON_PLLFREQ1) != pllfreq1 ||
+ getreg32(TIVA_SYSCON_PLLFREQ0) != pllfreq0);
+
+ /* If there are new PLL settings write them. */
+
+ if (newpll)
+ {
+ /* Set the oscillator source. */
+
+ regval = getreg32(TIVA_SYSCON_RSCLKCFG);
+ regval |= oscselect;
+ putreg32(regval, TIVA_SYSCON_RSCLKCFG);
+
+ /* Set the M, N and Q values provided by the pllfreq0 and pllfreq1
+ * parameters.
+ */
+
+ putreg32(pllfreq1, TIVA_SYSCON_PLLFREQ1);
+
+ regval = getreg32(TIVA_SYSCON_PLLFREQ0);
+ regval &= SYSCON_PLLFREQ0_PLLPWR;
+ pllfreq0 |= regval;
+ putreg32(pllfreq0, TIVA_SYSCON_PLLFREQ0);
+ }
+
+ /* Calculate the actual system clock. */
+
+ sysclk = tiva_vco_frequency(pllfreq0, pllfreq1) / sysdiv;
+
+ /* Set the Flash and EEPROM timing values. */
+
+ regval = tiva_memtim0(sysclk);
+ putreg32(regval, TIVA_SYSCON_MEMTIM0);
+
+ /* Was the PLL already powered up? */
+
+ if ((getreg32(TIVA_SYSCON_PLLFREQ0) & SYSCON_PLLFREQ0_PLLPWR) != 0)
+ {
+ /* Yes.. Is this a new PLL setting? */
+
+ if (newpll == true)
+ {
+ /* Yes.. Trigger the PLL to lock to the new frequency. */
+
+ regval = getreg32(TIVA_SYSCON_RSCLKCFG);
+ regval |= SYSCON_RSCLKCFG_NEWFREQ;
+ putreg32(regval, TIVA_SYSCON_RSCLKCFG);
+ }
+ }
+ else
+ {
+ /* No... No already powered. Power up the PLL now. */
+
+ regval = getreg32(TIVA_SYSCON_PLLFREQ0);
+ regval |= SYSCON_PLLFREQ0_PLLPWR;
+ putreg32(regval, TIVA_SYSCON_PLLFREQ0);
+ }
+
+ /* Wait until the PLL has locked. */
+
+ for (timeout = 32768; timeout > 0; timeout--)
+ {
+ if ((getreg32(TIVA_SYSCON_PLLSTAT) & SYSCON_PLLSTAT_LOCK) != 0)
+ {
+ /* Break out of the loop before the timeout expires if the PLL
+ * reports that it is locked.
+ */
+
+ break;
+ }
+ }
+
+ /* If the loop above did not timeout then switch over to the PLL */
+
+ if (timeout > 0)
+ {
+ regval = getreg32(TIVA_SYSCON_RSCLKCFG);
+ regval |= SYSCON_RSCLKCFG_PSYSDIV(sysdiv - 1) | SYSCON_RSCLKCFG_USEPLL |
+ SYSCON_RSCLKCFG_MEMTIMU | oscselect;
+ putreg32(regval, TIVA_SYSCON_RSCLKCFG);
+ }
+ else
+ {
+ sysclk = 0;
+ }
+
+ return sysclk;
}
/****************************************************************************