blob: cfc4e582bfc244f50f736c212845976d3bd44af4 [file] [log] [blame]
/***********************************************************************
* $Id: system_LPC43xx.c 8389 2011-10-19 13:53:14Z nxp28536 $
*
* Project: LPC43xx Common
*
* Description:
* CMSIS Cortex-M4 Device Peripheral Access Layer Source File
* for the NXP LPC43xx Device Series
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#include <stdint.h>
#if defined CORE_M4
#include "LPC43xx.h"
#endif
#ifdef CORE_M0
#include "LPC43xx_M0.h"
#endif
#include "scu.h"
#include "type.h"
#include "config.h"
/*--------------------- Clock Configuration ----------------------------------*/
//#define OTP
#define FLASH_SETUP 0
#define FLASHCFG_Val 0x0000303A
/*----------------------------------------------------------------------------
Check the register settings
*----------------------------------------------------------------------------*/
#define CHECK_RANGE(val, min, max) ((val < min) || (val > max))
#define CHECK_RSVD(val, mask) (val & mask)
/* Clock Configuration -------------------------------------------------------*/
#if (CHECK_RSVD((SCS_Val), ~0x00000030))
#error "SCS: Invalid values of reserved bits!"
#endif
#if (CHECK_RANGE((CLKSRCSEL_Val), 0, 2))
#error "CLKSRCSEL: Value out of range!"
#endif
#if (CHECK_RSVD((PLL0CFG_Val), ~0x00FF7FFF))
#error "PLL0CFG: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PLL1CFG_Val), ~0x0000007F))
#error "PLL1CFG: Invalid values of reserved bits!"
#endif
#if ((CCLKCFG_Val != 0) && (((CCLKCFG_Val - 1) % 2)))
#error "CCLKCFG: CCLKSEL field does not contain only odd values or 0!"
#endif
#if (CHECK_RSVD((USBCLKCFG_Val), ~0x0000000F))
#error "USBCLKCFG: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PCLKSEL0_Val), 0x000C0C00))
#error "PCLKSEL0: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PCLKSEL1_Val), 0x03000300))
#error "PCLKSEL1: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PCONP_Val), 0x10100821))
#error "PCONP: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((CLKOUTCFG_Val), ~0x000001FF))
#error "CLKOUTCFG: Invalid values of reserved bits!"
#endif
/* Flash Accelerator Configuration -------------------------------------------*/
#if (CHECK_RSVD((FLASHCFG_Val), ~0x0000F07F))
#error "FLASHCFG: Invalid values of reserved bits!"
#endif
/*----------------------------------------------------------------------------
DEFINES
*----------------------------------------------------------------------------*/
uint32_t XtalFrequency = 0;
uint32_t PL160M_0Frequency = 0;
uint32_t PL160M_1Frequency = 0;
uint32_t PL160M_2Frequency = 0;
uint32_t PL550Frequency = 0;
uint32_t PL550FracFrequency = 0; //New in Falcon
uint32_t IDIVAFrequency = 0;
uint32_t IDIVBFrequency = 0;
uint32_t IDIVCFrequency = 0;
uint32_t IDIVDFrequency = 0;
uint32_t IDIVEFrequency = 0;
uint32_t USB1Frequency = 0;
uint32_t M4Frequency = 0;
uint32_t SPIFIFrequency = 0;
uint32_t SPIFrequency = 0;
uint32_t EnetRxFrequency = 0;
uint32_t EnetTxFrequency = 0;
uint32_t EXTFrequency = 0;
uint32_t VPB1Frequency = 0;
uint32_t VPB3Frequency = 0;
uint32_t LCDFrequency = 0;
uint32_t SCIFrequency = 0;
uint32_t VADCFrequency = 0;
uint32_t SDIOFrequency = 0;
uint32_t SSP0Frequency = 0;
uint32_t SSP1Frequency = 0;
uint32_t UART0Frequency = 0;
uint32_t UART1Frequency = 0;
uint32_t UART2Frequency = 0;
uint32_t UART3Frequency = 0;
uint32_t OUTFrequency = 0;
uint32_t AOTESTFrequency = 0;
uint32_t ISOFrequency = 0;
uint32_t BSRFrequency = 0;
uint32_t CLK_TESTFrequency = 0;
uint32_t APLLFrequency = 0;
uint32_t SPARE0Frequency = 0;
uint32_t SPARE1Frequency = 0;
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
*
*/
void SystemInit(void)
{
// M4 runs on IRC by default
M4Frequency = IRC_OSC;
XtalFrequency = XTAL_FREQ;
EXTFrequency = EXT_FREQ;
}
/**
* Set Clock
*
* @param target PLL, source clock, division
* @return none
*
* @brief Setup a clock
*/
void SetClock(CLKBASE_Type target_clk, CLKSRC_Type src_clk, CLKDIV_Type div)
{
volatile uint32_t target_clk_adr;
volatile uint8_t auto_block=TRUE;
uint32_t src_freq;
EnableSourceClk(src_clk);
switch(div)
{
case(DIV1): // Divide by 1 == no division
break;
case(DIV2):
LPC_CGU->IDIVA_CTRL = (src_clk<<24) | (1<<2) | AUTO_BLOCK;
IDIVAFrequency = GetClockFrequency(src_clk)/2;
src_clk = SRC_IDIV_0; // Set new src_clk for target_clk
break;
case(DIV4):
LPC_CGU->IDIVB_CTRL = (src_clk<<24) | (3<<2) |AUTO_BLOCK;
IDIVBFrequency = GetClockFrequency(src_clk)/4;
src_clk = SRC_IDIV_1; // Set new src_clk for target_clk
break;
case(DIV8):
LPC_CGU->IDIVC_CTRL = (src_clk<<24) | (7<<2) |AUTO_BLOCK;
IDIVCFrequency = GetClockFrequency(src_clk)/8;
src_clk = SRC_IDIV_2; // Set new src_clk for target_clk
break;
case(DIV16):
LPC_CGU->IDIVD_CTRL = (src_clk<<24) | (15<<2) |AUTO_BLOCK;
IDIVDFrequency = GetClockFrequency(src_clk)/16;
src_clk = SRC_IDIV_3; // Set new src_clk for target_clk
break;
case(DIV256):
LPC_CGU->IDIVE_CTRL = (src_clk<<24) | (255<<2) |AUTO_BLOCK; // MAX 128? IDIV bit 2:9 = 7 bits = 127 max
IDIVEFrequency = GetClockFrequency(src_clk)/256;
src_clk = SRC_IDIV_4; // Set new src_clk for target_clk
break;
default:
break;
}
src_freq = GetClockFrequency(src_clk);
switch(target_clk)
{
case(BASE_OUT_CLK):
{
LPC_SCU->SFSCLK_0 = 1; // function 1; CGU clk out, diable pull down, disable pull-up
auto_block = FALSE;
break;
}
case(XTAL):
{
XtalFrequency = (uint32_t) src_clk; // convert target clock directly to frequency
break;
}
case(ENET_RX):
{
EnetRxFrequency = (uint32_t) src_clk; // convert target clock directly to frequency
break;
}
case(ENET_TX):
{
EnetTxFrequency = (uint32_t) src_clk; // convert target clock directly to frequency
break;
}
case(BASE_USB1_CLK):
{
USB1Frequency = src_freq;
break;
}
case(BASE_M4_CLK):
{
M4Frequency = src_freq;
break;
}
case(BASE_SPIFI_CLK):
{
SPIFIFrequency = src_freq;
break;
}
case(BASE_SPI_CLK):
{
SPIFrequency = src_freq;
break;
}
case(BASE_PHY_RX_CLK):
{
EnetRxFrequency = src_freq;
break;
}
case(BASE_PHY_TX_CLK):
{
EnetTxFrequency = src_freq;
break;
}
case(BASE_VPB1_CLK):
{
VPB1Frequency = src_freq;
break;
}
case(BASE_VPB3_CLK):
{
VPB3Frequency = src_freq;
break;
}
case(BASE_LCD_CLK):
{
LCDFrequency = src_freq;
break;
}
case (BASE_VADC_CLK) :
{
VADCFrequency = src_freq;
break;
}
case(BASE_SDIO_CLK):
{
SDIOFrequency = src_freq;
break;
}
case(BASE_SSP0_CLK):
{
SSP0Frequency = src_freq;
break;
}
case(BASE_SSP1_CLK):
{
SSP1Frequency = src_freq;
break;
}
case(BASE_UART0_CLK):
{
UART0Frequency = src_freq;
break;
}
case(BASE_UART1_CLK):
{
UART1Frequency = src_freq;
break;
}
case(BASE_UART2_CLK):
{
UART2Frequency = src_freq;
break;
}
case(BASE_UART3_CLK):
{
UART3Frequency = src_freq;
break;
}
case(BASE_AOTEST_CLK):
{
AOTESTFrequency = src_freq;
break;
}
case(BASE_ISO_TCK):
{
ISOFrequency = src_freq;
break;
}
case(BASE_BSR_TCK):
{
BSRFrequency = src_freq;
break;
}
case(BASE_CLK_TEST):
{
CLK_TESTFrequency = src_freq;
break;
}
case(BASE_APLL_CLK): //New in Falcon
{
APLLFrequency = src_freq;
break;
}
case(BASE_SPARE0_CLK): //New in Falcon
{
SPARE0Frequency = src_freq;
break;
}
case(BASE_SPARE1_CLK): //New in Falcon
{
SPARE1Frequency = src_freq;
break;
}
default:
break;
}
if(target_clk<200)
{
target_clk_adr = (uint32_t) &LPC_CGU->IDIVA_CTRL + (target_clk-2)*4;
*(uint32_t *)target_clk_adr = (src_clk<<24) | (auto_block<<11);
}
}
/**
* Get Clock Frequency
*
* @param source clock
* @return frequency
*
* @brief returns the current frequency of a base clock
*/
uint32_t GetClockFrequency(CLKSRC_Type src_clk)
{
switch(src_clk)
{
case(SRC_OSC32K):
return RTC_CLK;
case(SRC_IRC):
return IRC_OSC;
case(SRC_ENET_RX_CLK):
return EnetRxFrequency;
case(SRC_ENET_TX_CLK):
return EnetTxFrequency;
case(SRC_EXT_TCK):
return EXTFrequency;
case(SRC_XTAL):
return XtalFrequency;
case(SRC_PL550M_0):
return PL550Frequency;
case(SRC_PL550M_FRAC): //New in Falcon
return PL550FracFrequency;
case(SRC_PL160M_0):
return PL160M_0Frequency;
case(SRC_PL160M_1):
return PL160M_1Frequency;
case(SRC_PL160M_2):
return PL160M_2Frequency;
case(SRC_IDIV_0):
return IDIVAFrequency;
case(SRC_IDIV_1):
return IDIVBFrequency;
case(SRC_IDIV_2):
return IDIVCFrequency;
case(SRC_IDIV_3):
return IDIVDFrequency;
case(SRC_IDIV_4):
return IDIVEFrequency;
default:
return 0;
}
}
/**
* Set PL160M
*
* @param source clock, desired frequency
* @return none
*
* @brief Setup the PL160M PLL
* If frequency equals 0 then disable PLL
* Integer mode only (fbsel=1, direct=0)
* Fclkout = M * Fclkin/N
* Fcc0 = 2 * P * Fclkout = 2 * P * M * Fclkin/N
* msel+1 = feedback-divider value M (1 to 2^15)
* nsel+1 = pre-divider value N (1 to 2^8)
* psel+1 = post-divider value P(x2) (1 to 2^5)
*/
void SetPL160M(CLKSRC_Type src_clk, uint32_t mult)
{
uint32_t msel=0, nsel=0, psel=0, pval=1;
// EnableSourceClk(src_clk);
if(mult==0)
{
LPC_CGU->PLL1_CTRL |= PD_ENABLE; // Power down PLL
DisableSourceClk(src_clk);
}
else
{
EnableSourceClk(src_clk);
switch(src_clk)
{
case(SRC_OSC32K):
PL160M_0Frequency = mult * RTC_CLK;
break;
case(SRC_IRC):
PL160M_0Frequency = mult * IRC_OSC;
break;
case(SRC_ENET_RX_CLK):
PL160M_0Frequency = mult * EnetRxFrequency;
break;
case(SRC_ENET_TX_CLK):
PL160M_0Frequency = mult * EnetTxFrequency;
break;
case(SRC_EXT_TCK):
PL160M_0Frequency = mult * EXTFrequency;
break;
case(SRC_XTAL):
PL160M_0Frequency = mult * XtalFrequency;
break;
default:
PL160M_0Frequency = mult * IRC_OSC;
break;
}
// CCO must be in range of 156 - 320 MHz
// Increase P if FCCO is too low.
msel = mult-1;
//psel is encoded such that 0=1, 1=2, 2=4, 3=8
while(2*(pval)*PL160M_0Frequency < 156000000) {
psel++;
pval*=2;
}
// if(2*(pval)*PL160M_0Frequency > 320000000) {
// THIS IS OUT OF RANGE!!!
// HOW DO WE ASSERT IN SAMPLE CODE?
// __breakpoint(0);
// }
LPC_CGU->PLL1_CTRL = (src_clk<<24) | (msel<<16) | (nsel<<12) | (psel<<8) | FBSEL;
while((LPC_CGU->PLL1_STAT&1) == 0x0); // Wait for PLL lock
}
}
/**
* Set PLL USB (PL550M)
*
* @param enable
* @return none
*
* @brief Setup the USB PLL to 480 MHz
* If enable equals 0 then disable PLL
* Only clock sources IRC and XTAL are valid
* Mode1a only: Normal operating mode without post- and pre-divider
* Fclkout = 2 * M * Fclkin
* msel+1 = feedback-divider value M (1 to 2^15)
*/
void SetPLLUSB(CLKSRC_Type src_clk, uint8_t enable)
{
if(!enable)
{
LPC_CGU->PLL0USB_CTRL |= PD_ENABLE; // Power down PLL
}
else
{
// Setup PLL550 to generate 480MHz from 12 MHz crystal
LPC_CGU->PLL0USB_CTRL |= PD_ENABLE; // Power down PLL
// P N
LPC_CGU->PLL0USB_NP_DIV = (98<<0) | (514<<12);
// SELP SELI SELR MDEC
LPC_CGU->PLL0USB_MDIV = (0xB<<17)|(0x10<<22)|(0<<28)|(0x7FFA<<0);
LPC_CGU->PLL0USB_CTRL =(SRC_XTAL<<24) | (0x3<<2) | CLKEN;
// Set the USB0 clock source to PLL550 (480MHz)
LPC_CGU->BASE_USB0_CLK = (0<<0) | (1<<11) | (SRC_PL550M_0<<24);
while((LPC_CGU->PLL0USB_STAT&1) == 0x0); // Wait for PLL lock
}
PL550Frequency = 480000000UL;
}
/**
* Enable source clock pheripheral
*
* @param clock source
* @return none
*
* @brief Enable clock specific peripherals
*/
void EnableSourceClk(CLKSRC_Type src_clk)
{
uint32_t i=0;
const uint32_t PlainEnable = (0x2 << 3); /* no pull up, no pull down (plain) */
if(src_clk == SRC_OSC32K)
{
LPC_CREG->CREG0 &= ~((1<<3)|(1<<2)); // Active mode of 32 KHz osc and release reset
LPC_CREG->CREG0 |= (1<<1)|(1<<0); // Enable 32 kHz & 1 kHz on osc32k
}
if(src_clk == SRC_ENET_RX_CLK)scu_pinmux(0xC ,0 , PlainEnable, FUNC3); // enet_rx_clk on PC_0 func 3
if(src_clk == SRC_ENET_TX_CLK)scu_pinmux(0x1 ,19, PlainEnable, FUNC0); // enet_tx_clk on P1_19 func 0
if(src_clk == SRC_XTAL && (LPC_CGU->XTAL_OSC_CTRL&0x1))
{
LPC_CGU->XTAL_OSC_CTRL &= ~(1<<0); // Enable Xo50M
for(i=0;i<0xFFFF;i++);
}
}
/**
* Disable source clock pheripheral
*
* @param clock source
* @return none
*
* @brief Disable clock specific peripherals
*/
void DisableSourceClk(CLKSRC_Type src_clk)
{
uint32_t i=0;
const uint32_t PlainEnable = (0x2 << 3); /* no pull up, no pull down (plain) */
if(src_clk == SRC_OSC32K)
{
LPC_CREG->CREG0 &= ~((1<<1)|(1<<0)); // Disable 32 kHz & 1 kHz on osc32k
LPC_CREG->CREG0 |= ((1<<3)|(1<<2)); // osc32k in power down and in reset mode
}
if(src_clk == SRC_ENET_RX_CLK)scu_pinmux(0xC ,0 , PlainEnable, FUNC0); // nc on PC_0 func 0
if(src_clk == SRC_ENET_TX_CLK)scu_pinmux(0x1 ,19, PlainEnable, FUNC2); // nc on P1_19 func 2
if(src_clk == SRC_XTAL)
{
LPC_CGU->XTAL_OSC_CTRL = (1<<0); // Disable Xo50M
for(i=0;i<0xFFFF;i++);
}
}