ppc4xx: Fix problem in PLL clock calculation

This patch was originall provided by David Mitchell <dmitchell@amcc.com>
and fixes a bug in the PLL clock calculation.

Signed-off-by: Stefan Roese <sr@denx.de>
master
Stefan Roese 17 years ago
parent 35d22f957a
commit 273db7e1bd
  1. 9
      cpu/ppc4xx/serial.c
  2. 33
      cpu/ppc4xx/speed.c
  3. 2
      include/ppc405.h

@ -448,12 +448,17 @@ static void serial_divs (int baudrate, unsigned long *pudiv,
unsigned long i; unsigned long i;
unsigned long est; /* current estimate */ unsigned long est; /* current estimate */
unsigned long plloutb; unsigned long plloutb;
unsigned long cpr_pllc;
u32 reg; u32 reg;
/* check the pll feedback source */
mfcpr(cprpllc, cpr_pllc);
get_sys_info(&sysinfo); get_sys_info(&sysinfo);
plloutb = ((CONFIG_SYS_CLK_FREQ * sysinfo.pllFwdDiv * sysinfo.pllFbkDiv) plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
/ sysinfo.pllFwdDivB); sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) * sysinfo.pllFbkDiv) /
sysinfo.pllFwdDivB);
udiv = 256; /* Assume lowest possible serial clk */ udiv = 256; /* Assume lowest possible serial clk */
div = plloutb / (16 * baudrate); /* total divisor */ div = plloutb / (16 * baudrate); /* total divisor */
umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */ umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */

@ -771,6 +771,7 @@ ulong get_PCI_freq (void)
void get_sys_info (PPC405_SYS_INFO * sysInfo) void get_sys_info (PPC405_SYS_INFO * sysInfo)
{ {
unsigned long cpr_plld; unsigned long cpr_plld;
unsigned long cpr_pllc;
unsigned long cpr_primad; unsigned long cpr_primad;
unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000); unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
unsigned long primad_cpudv; unsigned long primad_cpudv;
@ -780,6 +781,7 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo)
* Read PLL Mode registers * Read PLL Mode registers
*/ */
mfcpr(cprplld, cpr_plld); mfcpr(cprplld, cpr_plld);
mfcpr(cprpllc, cpr_pllc);
/* /*
* Determine forward divider A * Determine forward divider A
@ -787,20 +789,18 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo)
sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16); sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
/* /*
* Determine forward divider B (should be equal to A) * Determine forward divider B
*/ */
sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8); sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
if (sysInfo->pllFwdDivB == 0) { if (sysInfo->pllFwdDivB == 0)
sysInfo->pllFwdDivB = 8; sysInfo->pllFwdDivB = 8;
}
/* /*
* Determine FBK_DIV. * Determine FBK_DIV.
*/ */
sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24); sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
if (sysInfo->pllFbkDiv == 0) { if (sysInfo->pllFbkDiv == 0)
sysInfo->pllFbkDiv = 256; sysInfo->pllFbkDiv = 256;
}
/* /*
* Read CPR_PRIMAD register * Read CPR_PRIMAD register
@ -810,30 +810,30 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo)
* Determine PLB_DIV. * Determine PLB_DIV.
*/ */
sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16); sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
if (sysInfo->pllPlbDiv == 0) { if (sysInfo->pllPlbDiv == 0)
sysInfo->pllPlbDiv = 16; sysInfo->pllPlbDiv = 16;
}
/* /*
* Determine EXTBUS_DIV. * Determine EXTBUS_DIV.
*/ */
sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK); sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
if (sysInfo->pllExtBusDiv == 0) { if (sysInfo->pllExtBusDiv == 0)
sysInfo->pllExtBusDiv = 16; sysInfo->pllExtBusDiv = 16;
}
/* /*
* Determine OPB_DIV. * Determine OPB_DIV.
*/ */
sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8); sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
if (sysInfo->pllOpbDiv == 0) { if (sysInfo->pllOpbDiv == 0)
sysInfo->pllOpbDiv = 16; sysInfo->pllOpbDiv = 16;
}
/* /*
* Determine the M factor * Determine the M factor
*/ */
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB; if (cpr_pllc & PLLC_SRC_MASK)
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
else
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
/* /*
* Determine VCO clock frequency * Determine VCO clock frequency
@ -845,16 +845,17 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo)
* Determine CPU clock frequency * Determine CPU clock frequency
*/ */
primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24); primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
if (primad_cpudv == 0) { if (primad_cpudv == 0)
primad_cpudv = 16; primad_cpudv = 16;
}
sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) / primad_cpudv; sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
sysInfo->pllFwdDiv / primad_cpudv;
/* /*
* Determine PLB clock frequency * Determine PLB clock frequency
*/ */
sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) / sysInfo->pllPlbDiv; sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
} }
/******************************************** /********************************************

@ -617,6 +617,8 @@
#define CPR_CLKUPD_ENDVCH_EN 0x20000000 /* Enable CPR Sys. Div. Changes */ #define CPR_CLKUPD_ENDVCH_EN 0x20000000 /* Enable CPR Sys. Div. Changes */
#define CPR_PERD0_SPIDV_MASK 0x000F0000 /* SPI Clock Divider */ #define CPR_PERD0_SPIDV_MASK 0x000F0000 /* SPI Clock Divider */
#define PLLC_SRC_MASK 0x20000000 /* PLL feedback source */
#define PLLD_FBDV_MASK 0x1F000000 /* PLL feedback divider value */ #define PLLD_FBDV_MASK 0x1F000000 /* PLL feedback divider value */
#define PLLD_FWDVA_MASK 0x000F0000 /* PLL forward divider A value */ #define PLLD_FWDVA_MASK 0x000F0000 /* PLL forward divider A value */
#define PLLD_FWDVB_MASK 0x00000700 /* PLL forward divider B value */ #define PLLD_FWDVB_MASK 0x00000700 /* PLL forward divider B value */

Loading…
Cancel
Save