d99cf8c015
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3644 42af7a65-404d-4744-a932-0658087f49c3
268 lines
8.3 KiB
C
Executable File
268 lines
8.3 KiB
C
Executable File
/****************************************************************************
|
|
* arch/arm/src/lpc31xx/lpc31_pllconfig.c
|
|
*
|
|
* Copyright (C) 2009-2010 Gregory Nutt. All rights reserved.
|
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
|
*
|
|
* References:
|
|
* - NXP UM10314 LPC3130/31 User manual Rev. 1.01 — 9 September 2009
|
|
* - NXP lpc313x.cdl.drivers.zip example driver code
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <arch/board/board.h>
|
|
|
|
#include "lpc31_cgudrvr.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: lpc31_switchdomains
|
|
*
|
|
* Description:
|
|
* Temporarily switch the referemce clock of all domains whose selected
|
|
* input is the PLL-to-be configured .
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline uint16_t
|
|
lpc31_switchdomains(const struct lpc31_pllconfig_s * const cfg)
|
|
{
|
|
uint32_t hppll = (cfg->hppll ? CGU_SSR_HPPLL1 : CGU_SSR_HPPLL0);
|
|
uint32_t address;
|
|
uint32_t regval;
|
|
uint16_t dmnset = 0;
|
|
int i;
|
|
|
|
/* Check each domain */
|
|
|
|
for (i = 0; i < CGU_NDOMAINS; i++)
|
|
{
|
|
/* Get the switch status registers (SSR) for this frequency input domain */
|
|
|
|
address = LPC31_CGU_SSR(i);
|
|
regval = getreg32(address);
|
|
|
|
/* Check if the current frequency selection is the PLL-to-be-configured */
|
|
|
|
if ((regval & CGU_SSR_FS_MASK) == hppll)
|
|
{
|
|
/* Yes.. switch reference clock in to FFAST */
|
|
|
|
lpc31_selectfreqin((enum lpc31_domainid_e)i, CGU_FS_FFAST);
|
|
|
|
/* Add the domain to the set to be restored after the PLL is configured */
|
|
|
|
dmnset |= (1 << i);
|
|
}
|
|
}
|
|
|
|
return dmnset;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: lpc31_restoredomains
|
|
*
|
|
* Description:
|
|
* Restore the PLL reference clock to the domains that were temporarily
|
|
switched to FFAST by lpc31_switchdomains.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void
|
|
lpc31_restoredomains(const struct lpc31_pllconfig_s * const cfg,
|
|
uint16_t dmnset)
|
|
{
|
|
uint32_t finsel = (cfg->hppll ? CGU_FS_HPPLL1 : CGU_FS_HPPLL0);
|
|
int i;
|
|
|
|
/* Check each domain */
|
|
|
|
for (i = 0; i < CGU_NDOMAINS; i++)
|
|
{
|
|
/* Was this one switched? */
|
|
|
|
if ((dmnset & (1 << i)) != 0)
|
|
{
|
|
/* Switch input reference clock to newly configured HPLL */
|
|
|
|
lpc31_selectfreqin((enum lpc31_domainid_e)i, finsel);
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: lpc31_pllconfig
|
|
*
|
|
* Description:
|
|
* Configure the PLL according to the provided selections.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void lpc31_pllconfig(const struct lpc31_pllconfig_s * const cfg)
|
|
{
|
|
uint32_t pllbase;
|
|
uint16_t dmnset = 0;
|
|
|
|
/* Switch domains connected to HPLL to FFAST */
|
|
|
|
dmnset = lpc31_switchdomains(cfg);
|
|
|
|
/* Get the PLL register base address */
|
|
|
|
pllbase = LPC313x_CGU_HPPLL(cfg->hppll);
|
|
|
|
/* Disable clock, disable skew enable, power down pll, (dis/en)able post
|
|
* divider, (dis/en)able pre-divider, disable free running mode, disable bandsel,
|
|
* enable up limmiter, disable bypass
|
|
*/
|
|
|
|
putreg32(CGU_HPMODE_PD, pllbase + LPC31_CGU_HPMODE_OFFSET);
|
|
|
|
/* Select PLL input frequency source */
|
|
|
|
putreg32(cfg->finsel, pllbase + LPC31_CGU_HPFINSEL_OFFSET);
|
|
|
|
/* Set M divider */
|
|
|
|
putreg32(cfg->mdec & CGU_HPMDEC_MASK, pllbase + LPC31_CGU_HPMDEC_OFFSET);
|
|
|
|
/* Set N divider */
|
|
|
|
putreg32(cfg->ndec & CGU_HPNDEC_MASK, pllbase + LPC31_CGU_HPNDEC_OFFSET);
|
|
|
|
/* Set P divider */
|
|
|
|
putreg32(cfg->pdec & CGU_HPPDEC_MASK, pllbase + LPC31_CGU_HPPDEC_OFFSET);
|
|
|
|
/* Set bandwidth */
|
|
|
|
putreg32(cfg->selr, pllbase + LPC31_CGU_HPSELR_OFFSET);
|
|
putreg32(cfg->seli, pllbase + LPC31_CGU_HPSELI_OFFSET);
|
|
putreg32(cfg->selp, pllbase + LPC31_CGU_HPSELP_OFFSET);
|
|
|
|
/* Power up pll */
|
|
|
|
putreg32((cfg->mode & ~CGU_HPMODE_PD) | CGU_HPMODE_CLKEN, pllbase + LPC31_CGU_HPMODE_OFFSET);
|
|
|
|
/* Save the estimated freq in driver data for future clk calcs */
|
|
|
|
g_boardfreqin[CGU_FREQIN_HPPLL0 + cfg->hppll] = cfg->freq;
|
|
|
|
/* Wait for PLL to lock */
|
|
|
|
while ((getreg32(pllbase + LPC31_CGU_HPSTATUS_OFFSET) & CGU_HPSTATUS_LOCK) == 0);
|
|
|
|
/* Switch the domains that were temporarily switched to FFAST back to the HPPLL */
|
|
|
|
lpc31_restoredomains(cfg, dmnset);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Name: lpc31_hp0pllconfig
|
|
*
|
|
* Description:
|
|
* Configure the HP0 PLL according to the board.h selections.
|
|
*
|
|
************************************************************************/
|
|
|
|
void lpc31_hp0pllconfig(void)
|
|
{
|
|
struct lpc31_pllconfig_s cfg =
|
|
{
|
|
.hppll = CGU_HP0PLL,
|
|
.finsel = BOARD_HPLL0_FINSEL,
|
|
.ndec = BOARD_HPLL0_NDEC,
|
|
.mdec = BOARD_HPLL0_MDEC,
|
|
.pdec = BOARD_HPLL0_PDEC,
|
|
.selr = BOARD_HPLL0_SELR,
|
|
.seli = BOARD_HPLL0_SELI,
|
|
.selp = BOARD_HPLL0_SELP,
|
|
.mode = BOARD_HPLL0_MODE,
|
|
.freq = BOARD_HPLL0_FREQ
|
|
};
|
|
|
|
lpc31_pllconfig(&cfg);
|
|
}
|
|
|
|
/************************************************************************
|
|
* Name: lpc31_hp1pllconfig
|
|
*
|
|
* Description:
|
|
* Configure the HP1 PLL according to the board.h selections.
|
|
*
|
|
************************************************************************/
|
|
|
|
void lpc31_hp1pllconfig(void)
|
|
{
|
|
struct lpc31_pllconfig_s cfg =
|
|
{
|
|
.hppll = CGU_HP1PLL,
|
|
.finsel = BOARD_HPLL1_FINSEL,
|
|
.ndec = BOARD_HPLL1_NDEC,
|
|
.mdec = BOARD_HPLL1_MDEC,
|
|
.pdec = BOARD_HPLL1_PDEC,
|
|
.selr = BOARD_HPLL1_SELR,
|
|
.seli = BOARD_HPLL1_SELI,
|
|
.selp = BOARD_HPLL1_SELP,
|
|
.mode = BOARD_HPLL1_MODE,
|
|
.freq = BOARD_HPLL1_FREQ
|
|
};
|
|
|
|
lpc31_pllconfig(&cfg);
|
|
}
|
|
|