4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
33 * \brief LM3S1968 Clocking driver.
35 * \author Andrea Righi <arighi@develer.com>
38 #include <cfg/compiler.h>
39 #include <cfg/debug.h>
41 #include "clock_lm3s.h"
43 /* The PLL VCO frequency is 400 MHz */
44 #define PLL_VCO 400000000UL
46 /* Extract the system clock divisor from the RCC register */
47 #define RCC_TO_DIV(rcc) \
48 (((rcc & SYSCTL_RCC_SYSDIV_MASK) >> \
49 SYSCTL_RCC_SYSDIV_SHIFT) + 1)
52 * Very small delay: each loop takes 3 cycles.
54 void NAKED lm3s_busyWait(unsigned long iterations)
56 register uint32_t __n asm("r0") = iterations;
62 : : "r"(__n) : "memory", "cc");
65 INLINE unsigned long clock_get_rate(void)
67 reg32_t rcc = HWREG(SYSCTL_RCC);
69 return rcc & SYSCTL_RCC_USESYSDIV ?
70 PLL_VCO / 2 / RCC_TO_DIV(rcc) : PLL_VCO;
74 * Try to evaluate the correct SYSDIV value depending on the desired CPU
77 INLINE int evaluate_sysdiv(unsigned long freq)
82 * NOTE: with BYPASS=0, SYSDIV < 3 are reserved values (see LM3S1968
83 * Microcontroller DATASHEET, p.78).
85 for (i = 3; i < 16; i++)
86 if (freq >= (PLL_VCO / 2 / (i + 1)))
97 rcc = HWREG(SYSCTL_RCC);
98 rcc2 = HWREG(SYSCTL_RCC2);
101 * Step #1: bypass the PLL and system clock divider by setting the
102 * BYPASS bit and clearing the USESYS bit in the RCC register. This
103 * configures the system to run off a “raw” clock source (using the
104 * main oscillator or internal oscillator) and allows for the new PLL
105 * configuration to be validated before switching the system clock to
108 rcc |= SYSCTL_RCC_BYPASS;
109 rcc &= ~SYSCTL_RCC_USESYSDIV;
110 rcc2 |= SYSCTL_RCC2_BYPASS2;
112 /* Write back RCC/RCC2 registers */
113 HWREG(SYSCTL_RCC) = rcc;
114 HWREG(SYSCTL_RCC) = rcc2;
119 * Step #2: select the crystal value (XTAL) and oscillator source
120 * (OSCSRC), and clear the PWRDN bit in RCC/RCC2. Setting the XTAL
121 * field automatically pulls valid PLL configuration data for the
122 * appropriate crystal, and clearing the PWRDN bit powers and enables
123 * the PLL and its output.
126 /* Enable the main oscillator first. */
127 rcc &= ~(SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS);
128 rcc |= SYSCTL_RCC_IOSCDIS;
130 /* Do not override RCC register fields */
131 rcc2 &= ~SYSCTL_RCC2_USERCC2;
133 rcc &= ~(SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M | SYSCTL_RCC_PWRDN);
134 rcc |= XTAL_FREQ | SYSCTL_RCC_OSCSRC_MAIN;
136 /* Clear the PLL lock interrupt. */
137 HWREG(SYSCTL_MISC) = SYSCTL_INT_PLL_LOCK;
139 HWREG(SYSCTL_RCC) = rcc;
140 HWREG(SYSCTL_RCC) = rcc2;
145 * Step #3: select the desired system divider (SYSDIV) in RCC/RCC2 and
146 * set the USESYS bit in RCC. The SYSDIV field determines the system
147 * frequency for the microcontroller.
149 rcc &= ~(SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_USESYSDIV);
152 for (i = 3; i < 16; i++)
153 if (CPU_FREQ >= (clk / (i + 1)))
155 rcc |= SYSCTL_RCC_USESYSDIV |
156 (evaluate_sysdiv(CPU_FREQ) << SYSCTL_RCC_SYSDIV_SHIFT);
159 * Step #4: wait for the PLL to lock by polling the PLLLRIS bit in the
160 * Raw Interrupt Status (RIS) register.
162 for (i = 0; i < 32768; i++)
163 if (HWREG(SYSCTL_RIS) & SYSCTL_INT_PLL_LOCK)
167 * Step #5: enable use of the PLL by clearing the BYPASS bit in
170 rcc &= ~SYSCTL_RCC_BYPASS;
172 HWREG(SYSCTL_RCC) = rcc;