123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- /*
- * @brief LPC8xx clock driver
- *
- * @note
- * Copyright(C) NXP Semiconductors, 2012
- * All rights reserved.
- *
- * @par
- * Software that is described herein is for illustrative purposes only
- * which provides customers with programming information regarding the
- * LPC products. This software is supplied "AS IS" without any warranties of
- * any kind, and NXP Semiconductors and its licenser disclaim any and
- * all warranties, express or implied, including all implied warranties of
- * merchantability, fitness for a particular purpose and non-infringement of
- * intellectual property rights. NXP Semiconductors assumes no responsibility
- * or liability for the use of the software, conveys no license or rights under any
- * patent, copyright, mask work right, or any other intellectual property rights in
- * or to any products. NXP Semiconductors reserves the right to make changes
- * in the software without notification. NXP Semiconductors also makes no
- * representation or warranty that such application will be suitable for the
- * specified use without further testing or modification.
- *
- * @par
- * Permission to use, copy, modify, and distribute this software and its
- * documentation is hereby granted, under NXP Semiconductors' and its
- * licensor's relevant copyrights in the software, without fee, provided that it
- * is used in conjunction with NXP Semiconductors microcontrollers. This
- * copyright, permission, and disclaimer notice must appear in all copies of
- * this code.
- */
- #define _CHIP_COMMON_
- #include "chip.h"
- /*****************************************************************************
- * Private types/enumerations/variables
- ****************************************************************************/
- /* Inprecise clock rates for the watchdog oscillator */
- static const uint32_t wdtOSCRate[WDTLFO_OSC_4_60 + 1] = {
- 0, /* WDT_OSC_ILLEGAL */
- 600000, /* WDT_OSC_0_60 */
- 1050000, /* WDT_OSC_1_05 */
- 1400000, /* WDT_OSC_1_40 */
- 1750000, /* WDT_OSC_1_75 */
- 2100000, /* WDT_OSC_2_10 */
- 2400000, /* WDT_OSC_2_40 */
- 2700000, /* WDT_OSC_2_70 */
- 3000000, /* WDT_OSC_3_00 */
- 3250000, /* WDT_OSC_3_25 */
- 3500000, /* WDT_OSC_3_50 */
- 3750000, /* WDT_OSC_3_75 */
- 4000000, /* WDT_OSC_4_00 */
- 4200000, /* WDT_OSC_4_20 */
- 4400000, /* WDT_OSC_4_40 */
- 4600000 /* WDT_OSC_4_60 */
- };
- typedef struct {
- uint16_t freq_main; // main clock frequency in MHz
- uint16_t freq_sys; // system (CPU) clock frequency in MHz
- uint16_t freq_fcco; // FCCO clock frequency in MHz
- uint16_t msel; // MSEL (pre-decremented)
- uint16_t psel; // PSEL (pre-decremented)
- uint16_t divider; // SYSAHBCLKDIV
- } LPC_8XX_PLL_T;
-
- /*
- * This table contains all useful PLL configurations
- * for "integer" MHZ (e.g. 1MHz, 2MHz, etc.) frequencies.
- *
- * This table has two inputs:
- * - freq_main: This is the main frequency.
- * - freq_sys: This is the system (CPU) frequency.
- * These are used to select which table entry to use.
- *
- * There are many ways to get some frequencies. For example,
- * there are eight ways to make the CPU run at 12MHZ. If the peripheral bus
- * needs to run very fast, it's possible to set the main clock
- * up to 96MHz. If low power is a requirement, it's possible to set the main
- * clock to 12MHz.
- *
- * All the rest of the table entries are outputs.
- * - freq_fcco is simply an FYI value. It is not used for programming.
- * - MSEL / PSEL / divider are used to program the PLL.
- */
- static const LPC_8XX_PLL_T config_tab[] = {
- { 12, 12, 192, 0, 3, 1 }, // 12.0000MHz
- { 12, 6, 192, 0, 3, 2 }, // 6.0000MHz
- { 12, 4, 192, 0, 3, 3 }, // 4.0000MHz
- { 12, 3, 192, 0, 3, 4 }, // 3.0000MHz
- { 12, 2, 192, 0, 3, 6 }, // 2.0000MHz
- { 12, 1, 192, 0, 3, 12 }, // 1.0000MHz
- { 24, 24, 192, 1, 2, 1 }, // 24.0000MHz
- { 24, 12, 192, 1, 2, 2 }, // 12.0000MHz
- { 24, 8, 192, 1, 2, 3 }, // 8.0000MHz
- { 24, 6, 192, 1, 2, 4 }, // 6.0000MHz
- { 24, 4, 192, 1, 2, 6 }, // 4.0000MHz
- { 24, 3, 192, 1, 2, 8 }, // 3.0000MHz
- { 24, 2, 192, 1, 2, 12 }, // 2.0000MHz
- { 24, 1, 192, 1, 2, 24 }, // 1.0000MHz
- { 36, 18, 288, 2, 2, 2 }, // 18.0000MHz
- { 36, 12, 288, 2, 2, 3 }, // 12.0000MHz
- { 36, 9, 288, 2, 2, 4 }, // 9.0000MHz
- { 36, 6, 288, 2, 2, 6 }, // 6.0000MHz
- { 36, 4, 288, 2, 2, 9 }, // 4.0000MHz
- { 36, 3, 288, 2, 2, 12 }, // 3.0000MHz
- { 36, 2, 288, 2, 2, 18 }, // 2.0000MHz
- { 36, 1, 288, 2, 2, 36 }, // 1.0000MHz
- { 48, 24, 192, 3, 1, 2 }, // 24.0000MHz
- { 48, 16, 192, 3, 1, 3 }, // 16.0000MHz
- { 48, 12, 192, 3, 1, 4 }, // 12.0000MHz
- { 48, 8, 192, 3, 1, 6 }, // 8.0000MHz
- { 48, 6, 192, 3, 1, 8 }, // 6.0000MHz
- { 48, 4, 192, 3, 1, 12 }, // 4.0000MHz
- { 48, 3, 192, 3, 1, 16 }, // 3.0000MHz
- { 48, 2, 192, 3, 1, 24 }, // 2.0000MHz
- { 48, 1, 192, 3, 1, 48 }, // 1.0000MHz
- { 60, 30, 240, 4, 1, 2 }, // 30.0000MHz
- { 60, 20, 240, 4, 1, 3 }, // 20.0000MHz
- { 60, 15, 240, 4, 1, 4 }, // 15.0000MHz
- { 60, 12, 240, 4, 1, 5 }, // 12.0000MHz
- { 60, 10, 240, 4, 1, 6 }, // 10.0000MHz
- { 60, 6, 240, 4, 1, 10 }, // 6.0000MHz
- { 60, 5, 240, 4, 1, 12 }, // 5.0000MHz
- { 60, 4, 240, 4, 1, 15 }, // 4.0000MHz
- { 60, 3, 240, 4, 1, 20 }, // 3.0000MHz
- { 60, 2, 240, 4, 1, 30 }, // 2.0000MHz
- { 60, 1, 240, 4, 1, 60 }, // 1.0000MHz
- { 72, 24, 288, 5, 1, 3 }, // 24.0000MHz
- { 72, 18, 288, 5, 1, 4 }, // 18.0000MHz
- { 72, 12, 288, 5, 1, 6 }, // 12.0000MHz
- { 72, 9, 288, 5, 1, 8 }, // 9.0000MHz
- { 72, 8, 288, 5, 1, 9 }, // 8.0000MHz
- { 72, 6, 288, 5, 1, 12 }, // 6.0000MHz
- { 72, 4, 288, 5, 1, 18 }, // 4.0000MHz
- { 72, 3, 288, 5, 1, 24 }, // 3.0000MHz
- { 72, 2, 288, 5, 1, 36 }, // 2.0000MHz
- { 72, 1, 288, 5, 1, 72 }, // 1.0000MHz
- { 84, 28, 168, 6, 0, 3 }, // 28.0000MHz
- { 84, 21, 168, 6, 0, 4 }, // 21.0000MHz
- { 84, 14, 168, 6, 0, 6 }, // 14.0000MHz
- { 84, 12, 168, 6, 0, 7 }, // 12.0000MHz
- { 84, 7, 168, 6, 0, 12 }, // 7.0000MHz
- { 84, 6, 168, 6, 0, 14 }, // 6.0000MHz
- { 84, 4, 168, 6, 0, 21 }, // 4.0000MHz
- { 84, 3, 168, 6, 0, 28 }, // 3.0000MHz
- { 84, 2, 168, 6, 0, 42 }, // 2.0000MHz
- { 84, 1, 168, 6, 0, 84 }, // 1.0000MHz
- { 96, 24, 192, 7, 0, 4 }, // 24.0000MHz
- { 96, 16, 192, 7, 0, 6 }, // 16.0000MHz
- { 96, 12, 192, 7, 0, 8 }, // 12.0000MHz
- { 96, 8, 192, 7, 0, 12 }, // 8.0000MHz
- { 96, 6, 192, 7, 0, 16 }, // 6.0000MHz
- { 96, 4, 192, 7, 0, 24 }, // 4.0000MHz
- { 96, 3, 192, 7, 0, 32 }, // 3.0000MHz
- { 96, 2, 192, 7, 0, 48 }, // 2.0000MHz
- { 96, 1, 192, 7, 0, 96 }, // 1.0000MHz
- };
- static const uint16_t config_tab_ct = sizeof(config_tab) / sizeof(LPC_8XX_PLL_T);
- static uint16_t config_tab_idx = 0;
- /*****************************************************************************
- * Public types/enumerations/variables
- ****************************************************************************/
- /* System Clock Frequency (Core Clock) */
- uint32_t SystemCoreClock;
- /*****************************************************************************
- * Private functions
- ****************************************************************************/
- static void pll_config(const LPC_8XX_PLL_T* pll_cfg)
- {
- Chip_SYSCTL_PowerUp(SYSCTL_SLPWAKE_IRC_PD); /* turn on the IRC by clearing the power down bit */
- Chip_Clock_SetSystemPLLSource(SYSCTL_PLLCLKSRC_IRC); /* select PLL input to be IRC */
- Chip_Clock_SetMainClockSource(SYSCTL_MAINCLKSRC_IRC);
- Chip_FMC_SetFLASHAccess(FLASHTIM_30MHZ_CPU); /* setup FLASH access to 2 clocks (up to 30MHz) */
- Chip_SYSCTL_PowerDown(SYSCTL_SLPWAKE_SYSPLL_PD); /* power down PLL to change the PLL divider ratio */
- Chip_Clock_SetupSystemPLL(pll_cfg->msel, pll_cfg->psel); /* configure the PLL */
- Chip_SYSCTL_PowerUp(SYSCTL_SLPWAKE_SYSPLL_PD); /* turn on the PLL by clearing the power down bit */
- while (!Chip_Clock_IsSystemPLLLocked()) {} /* wait for PLL to lock */
- Chip_Clock_SetSysClockDiv(pll_cfg->divider); /* load the divider */
- Chip_Clock_SetMainClockSource(SYSCTL_MAINCLKSRC_PLLOUT); /* enable the new Frequency */
- }
- /* Compute a WDT or LFO rate */
- static uint32_t Chip_Clock_GetWDTLFORate(uint32_t reg)
- {
- uint32_t div;
- CHIP_WDTLFO_OSC_T clk;
- /* Get WDT oscillator settings */
- clk = (CHIP_WDTLFO_OSC_T) ((reg >> 5) & 0xF);
- div = reg & 0x1F;
- /* Compute clock rate and divided by divde value */
- return wdtOSCRate[clk] / ((div + 1) << 1);
- }
- /* Compute PLL frequency */
- static uint32_t Chip_Clock_GetPLLFreq(uint32_t PLLReg, uint32_t inputRate)
- {
- uint32_t m_val = ((PLLReg & 0x1F) + 1);
- return (inputRate * m_val);
- }
- /*****************************************************************************
- * Public functions
- ****************************************************************************/
- bool Chip_IRC_SetFreq(uint32_t main, uint32_t sys)
- {
- uint16_t freq_m = main/1000000; /* main frequency in MHz */
- uint16_t freq_s = sys/1000000; /* system frequency in MHz */
- bool found = false; /* frequencies found */
- uint32_t i = 0;
- if (freq_s > 30) /* if system frequency is higher than 30MHz... */
- return false; /* ...don't attempt to set it */
- if (freq_m > 96) /* if main frequency is higher than 96MHz... */
- return false; /* ...don't attempt to set it */
-
- for (i=0; i<config_tab_ct; i++) { /* loop through table */
- if ((freq_m == config_tab[i].freq_main) && (freq_s == config_tab[i].freq_sys)) { /* attempt to find a match */
- config_tab_idx = i; /* save the data for later */
- found = true; /* set state to found */
- break; /* go config the PLL */
- }
- }
- if (found == true) { /* if a match has been found */
- pll_config(&config_tab[config_tab_idx]); /* configure the PLL */
- }
- return found; /* return operation status */
- }
- // Open this API only if ROM headers are included
- #ifdef LPC_PWRD_API
- void Chip_IRC_SetFreq_ROM(uint32_t sys)
- {
- uint32_t cmd[4], resp[2];
- Chip_SYSCTL_PowerUp(SYSCTL_SLPWAKE_IRC_PD); /* Turn on the IRC by clearing the power down bit */
- Chip_Clock_SetSystemPLLSource(SYSCTL_PLLCLKSRC_IRC); /* Select PLL input to be IRC */
- Chip_FMC_SetFLASHAccess(FLASHTIM_30MHZ_CPU); /* Setup FLASH access to 2 clocks (up to 30MHz) */
-
- cmd[0] = Chip_Clock_GetIntOscRate() / 1000; /* in KHz */
- cmd[1] = sys / 1000; /* system clock rate in kHz */
- cmd[2] = CPU_FREQ_EQU;
- cmd[3] = sys / 10000; /* Timeout. See UM10601, section 23.4.1.3 for details */
- LPC_PWRD_API->set_pll(cmd, resp); /* Attempt to set the PLL */
- while (resp[0] != PLL_CMD_SUCCESS) {} /* Dead loop on fail */
- }
- #else
- #endif
- /* Update system core clock rate, should be called if the system has
- a clock rate change */
- void SystemCoreClockUpdate(void)
- {
- /* CPU core speed */
- SystemCoreClock = Chip_Clock_GetSystemClockRate();
- }
- /* Set System PLL clock source */
- void Chip_Clock_SetSystemPLLSource(CHIP_SYSCTL_PLLCLKSRC_T src)
- {
- LPC_SYSCTL->SYSPLLCLKSEL = (uint32_t) src;
-
- /* sequnce a 0 followed by 1 to update PLL source selection */
- LPC_SYSCTL->SYSPLLCLKUEN = 0;
- LPC_SYSCTL->SYSPLLCLKUEN = 1;
- }
- /* Bypass System Oscillator and set oscillator frequency range */
- void Chip_Clock_SetPLLBypass(bool bypass, bool highfr)
- {
- uint32_t ctrl = 0;
- if (bypass) {
- ctrl |= (1 << 0);
- }
- if (highfr) {
- ctrl |= (1 << 1);
- }
- LPC_SYSCTL->SYSOSCCTRL = ctrl;
- }
- /* Set main system clock source */
- void Chip_Clock_SetMainClockSource(CHIP_SYSCTL_MAINCLKSRC_T src)
- {
- LPC_SYSCTL->MAINCLKSEL = (uint32_t) src;
-
- /* sequnce a 0 followed by 1 to update MAINCLK source selection */
- LPC_SYSCTL->MAINCLKUEN = 0;
- LPC_SYSCTL->MAINCLKUEN = 1;
- }
- /* Set CLKOUT clock source and divider */
- void Chip_Clock_SetCLKOUTSource(CHIP_SYSCTL_CLKOUTSRC_T src, uint32_t div)
- {
- LPC_SYSCTL->CLKOUTSEL = (uint32_t) src;
-
- /* sequnce a 0 followed by 1 to update CLKOUT source selection */
- LPC_SYSCTL->CLKOUTUEN = 0;
- LPC_SYSCTL->CLKOUTUEN = 1;
- LPC_SYSCTL->CLKOUTDIV = div;
- }
- /* Return estimated watchdog oscillator rate */
- uint32_t Chip_Clock_GetWDTOSCRate(void)
- {
- return Chip_Clock_GetWDTLFORate(LPC_SYSCTL->WDTOSCCTRL & ~SYSCTL_WDTOSCCTRL_RESERVED);
- }
- /* Return System PLL input clock rate */
- uint32_t Chip_Clock_GetSystemPLLInClockRate(void)
- {
- uint32_t clkRate;
- switch ((CHIP_SYSCTL_PLLCLKSRC_T) (LPC_SYSCTL->SYSPLLCLKSEL & 0x3)) {
- case SYSCTL_PLLCLKSRC_IRC:
- clkRate = Chip_Clock_GetIntOscRate();
- break;
- case SYSCTL_PLLCLKSRC_SYSOSC:
- clkRate = Chip_Clock_GetMainOscRate();
- break;
- case SYSCTL_PLLCLKSRC_EXT_CLKIN:
- clkRate = Chip_Clock_GetExtClockInRate();
- break;
- default:
- clkRate = 0;
- }
- return clkRate;
- }
- /* Return System PLL output clock rate */
- uint32_t Chip_Clock_GetSystemPLLOutClockRate(void)
- {
- return Chip_Clock_GetPLLFreq((LPC_SYSCTL->SYSPLLCTRL & ~SYSCTL_SYSPLLCTRL_RESERVED),
- Chip_Clock_GetSystemPLLInClockRate());
- }
- /* Return main clock rate */
- uint32_t Chip_Clock_GetMainClockRate(void)
- {
- uint32_t clkRate = 0;
- switch ((CHIP_SYSCTL_MAINCLKSRC_T) (LPC_SYSCTL->MAINCLKSEL & 0x3)) {
- case SYSCTL_MAINCLKSRC_IRC:
- clkRate = Chip_Clock_GetIntOscRate();
- break;
- case SYSCTL_MAINCLKSRC_PLLIN:
- clkRate = Chip_Clock_GetSystemPLLInClockRate();
- break;
- case SYSCTL_MAINCLKSRC_WDTOSC:
- clkRate = Chip_Clock_GetWDTOSCRate();
- break;
- case SYSCTL_MAINCLKSRC_PLLOUT:
- clkRate = Chip_Clock_GetSystemPLLOutClockRate();
- break;
- }
- return clkRate;
- }
- /* Return system clock rate */
- uint32_t Chip_Clock_GetSystemClockRate(void)
- {
- /* No point in checking for divide by 0 */
- return Chip_Clock_GetMainClockRate() / (LPC_SYSCTL->SYSAHBCLKDIV & ~SYSCTL_SYSAHBCLKDIV_RESERVED);
- }
- /* Get USART 0/1/2 UART base rate */
- uint32_t Chip_Clock_GetUSARTNBaseClockRate(void)
- {
- uint64_t inclk;
- uint32_t div;
- div = (uint32_t) Chip_Clock_GetUARTClockDiv();
- if (div == 0) {
- /* Divider is 0 so UART clock is disabled */
- inclk = 0;
- }
- else {
- uint32_t mult, divf;
- /* Input clock into FRG block is the divided main system clock */
- inclk = (uint64_t) (Chip_Clock_GetMainClockRate() / div);
- divf = Chip_SYSCTL_GetUSARTFRGDivider();
- if (divf == 0xFF) {
- /* Fractional part is enabled, get multiplier */
- mult = (uint32_t) Chip_SYSCTL_GetUSARTFRGMultiplier();
- /* Get fractional error */
- inclk = (inclk * 256) / (uint64_t) (256 + mult);
- }
- }
- return (uint32_t) inclk;
- }
- /* Set USART 0/1/2 UART base rate */
- uint32_t Chip_Clock_SetUSARTNBaseClockRate(uint32_t rate, bool fEnable)
- {
- uint32_t div, inclk;
- /* Input clock into FRG block is the main system clock */
- inclk = Chip_Clock_GetMainClockRate();
- /* Get integer divider for coarse rate */
- div = inclk / rate;
- if (div == 0) {
- div = 1;
- }
- /* Approximated rate with only integer divider */
- Chip_Clock_SetUARTClockDiv((uint8_t) div);
- if (fEnable) {
- uint32_t uart_fra_multiplier;
- /* Reset FRG */
- Chip_SYSCTL_PeriphReset(RESET_UARTFBRG);
- /* Enable fractional divider */
- Chip_SYSCTL_SetUSARTFRGDivider(0xFF);
- /* Compute the fractional divisor (the lower byte is the
- fractional portion) */
- uart_fra_multiplier = ((inclk / div) * 256) / rate;
- /* ...just the fractional portion (the lower byte) */
- Chip_SYSCTL_SetUSARTFRGMultiplier((uint8_t) uart_fra_multiplier);
- }
- else {
- /* Disable fractional generator and use integer divider only */
- Chip_SYSCTL_SetUSARTFRGDivider(0);
- }
- return Chip_Clock_GetUSARTNBaseClockRate();
- }
- /* Get the IOCONCLKDIV clock rate */
- uint32_t Chip_Clock_GetIOCONCLKDIVClockRate(CHIP_PIN_CLKDIV_T reg)
- {
- uint32_t div = LPC_SYSCTL->IOCONCLKDIV[reg] & ~SYSCTL_IOCONCLKDIV_RESERVED;
- uint32_t main_clk = Chip_Clock_GetMainClockRate();
-
- return (div == 0) ? 0 : (main_clk / div);
- }
- void Chip_Clock_SetIOCONCLKDIV(CHIP_PIN_CLKDIV_T reg, uint8_t div)
- {
- int t_reg = IOCONCLK_MAX-reg;
- LPC_SYSCTL->IOCONCLKDIV[t_reg] = div;
- }
|