summaryrefslogtreecommitdiff
path: root/cpu/ppc4xx/speed.c
diff options
context:
space:
mode:
authorStefan Roese <sr@denx.de>2007-10-05 17:10:59 +0200
committerStefan Roese <sr@denx.de>2007-10-31 21:20:49 +0100
commitdbbd125721aea6645fdb962f36bd41f59e272f9d (patch)
tree726c0998b77e26179294b8686cd005e70eb218ce /cpu/ppc4xx/speed.c
parent1d7b874e9c9a7c66f5d8da9ec78a3733765d3e31 (diff)
ppc4xx: Add PPC405EX support
Signed-off-by: Stefan Roese <sr@denx.de>
Diffstat (limited to 'cpu/ppc4xx/speed.c')
-rw-r--r--cpu/ppc4xx/speed.c180
1 files changed, 174 insertions, 6 deletions
diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c
index da5330a360..750b095876 100644
--- a/cpu/ppc4xx/speed.c
+++ b/cpu/ppc4xx/speed.c
@@ -1,5 +1,5 @@
/*
- * (C) Copyright 2000
+ * (C) Copyright 2000-2007
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
@@ -263,7 +263,7 @@ void get_sys_info (sys_info_t *sysInfo)
sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
- sysInfo->freqEPB = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
+ sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
/* Figure which timer source to use */
@@ -317,7 +317,7 @@ void get_sys_info (sys_info_t * sysInfo)
if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
sysInfo->freqPLB >>= 1;
sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
- sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
+ sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
}
#else
@@ -393,7 +393,7 @@ void get_sys_info (sys_info_t * sysInfo)
sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
- sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
+ sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
#if defined(CONFIG_YUCCA)
/* Determine PCI Clock Period */
@@ -733,6 +733,8 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo)
* Determine PLB clock frequency
*/
sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
+
+ sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
}
@@ -856,6 +858,9 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo)
*/
sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
+
+ sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
+ sysInfo->pllExtBusDiv;
}
/********************************************
@@ -874,13 +879,175 @@ ulong get_OPB_freq (void)
return val;
}
+#elif defined(CONFIG_405EX)
+
+/*
+ * TODO: We need to get the CPR registers and calculate these values correctly!!!!
+ * We need the specs!!!!
+ */
+static unsigned char get_fbdv(unsigned char index)
+{
+ unsigned char ret = 0;
+ /* This is table should be 256 bytes.
+ * Only take first 52 values.
+ */
+ unsigned char fbdv_tb[] = {
+ 0x00, 0xff, 0x7f, 0xfd,
+ 0x7a, 0xf5, 0x6a, 0xd5,
+ 0x2a, 0xd4, 0x29, 0xd3,
+ 0x26, 0xcc, 0x19, 0xb3,
+ 0x67, 0xce, 0x1d, 0xbb,
+ 0x77, 0xee, 0x5d, 0xba,
+ 0x74, 0xe9, 0x52, 0xa5,
+ 0x4b, 0x96, 0x2c, 0xd8,
+ 0x31, 0xe3, 0x46, 0x8d,
+ 0x1b, 0xb7, 0x6f, 0xde,
+ 0x3d, 0xfb, 0x76, 0xed,
+ 0x5a, 0xb5, 0x6b, 0xd6,
+ 0x2d, 0xdb, 0x36, 0xec,
+
+ };
+
+ if ((index & 0x7f) == 0)
+ return 1;
+ while (ret < sizeof (fbdv_tb)) {
+ if (fbdv_tb[ret] == index)
+ break;
+ ret++;
+ }
+ ret++;
+
+ return ret;
+}
+
+#define PLL_FBK_PLL_LOCAL 0
+#define PLL_FBK_CPU 1
+#define PLL_FBK_PERCLK 5
+
+void get_sys_info (sys_info_t * sysInfo)
+{
+ unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
+ unsigned long m = 1;
+ unsigned int tmp;
+ unsigned char fwdva[16] = {
+ 1, 2, 14, 9, 4, 11, 16, 13,
+ 12, 5, 6, 15, 10, 7, 8, 3,
+ };
+ unsigned char sel, cpudv0, plb2xDiv;
+
+ mfcpr(cpr0_plld, tmp);
+
+ /*
+ * Determine forward divider A
+ */
+ sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
+
+ /*
+ * Determine FBK_DIV.
+ */
+ sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
+
+ /*
+ * Determine PLBDV0
+ */
+ sysInfo->pllPlbDiv = 2;
+
+ /*
+ * Determine PERDV0
+ */
+ mfcpr(cpr0_perd, tmp);
+ tmp = (tmp >> 24) & 0x03;
+ sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
+
+ /*
+ * Determine OPBDV0
+ */
+ mfcpr(cpr0_opbd, tmp);
+ tmp = (tmp >> 24) & 0x03;
+ sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
+
+ /* Determine PLB2XDV0 */
+ mfcpr(cpr0_plbd, tmp);
+ tmp = (tmp >> 16) & 0x07;
+ plb2xDiv = (tmp == 0) ? 8 : tmp;
+
+ /* Determine CPUDV0 */
+ mfcpr(cpr0_cpud, tmp);
+ tmp = (tmp >> 24) & 0x07;
+ cpudv0 = (tmp == 0) ? 8 : tmp;
+
+ /* Determine SEL(5:7) in CPR0_PLLC */
+ mfcpr(cpr0_pllc, tmp);
+ sel = (tmp >> 24) & 0x07;
+
+ /*
+ * Determine the M factor
+ * PLL local: M = FBDV
+ * CPU clock: M = FBDV * FWDVA * CPUDV0
+ * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
+ *
+ */
+ switch (sel) {
+ case PLL_FBK_CPU:
+ m = sysInfo->pllFwdDiv * cpudv0;
+ break;
+ case PLL_FBK_PERCLK:
+ m = sysInfo->pllFwdDiv * plb2xDiv * 2
+ * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
+ break;
+ case PLL_FBK_PLL_LOCAL:
+ break;
+ default:
+ printf("%s unknown m\n", __FUNCTION__);
+ return;
+
+ }
+ m *= sysInfo->pllFbkDiv;
+
+ /*
+ * Determine VCO clock frequency
+ */
+ sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+ (unsigned long long)sysClkPeriodPs;
+
+ /*
+ * Determine CPU clock frequency
+ */
+ sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
+
+ /*
+ * Determine PLB clock frequency, ddr1x should be the same
+ */
+ sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
+ sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+ sysInfo->freqDDR = sysInfo->freqPLB;
+ sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
+}
+
+/********************************************
+ * get_OPB_freq
+ * return OPB bus freq in Hz
+ *********************************************/
+ulong get_OPB_freq (void)
+{
+ ulong val = 0;
+
+ PPC405_SYS_INFO sys_info;
+
+ get_sys_info (&sys_info);
+ val = sys_info.freqPLB / sys_info.pllOpbDiv;
+
+ return val;
+}
+
#endif
int get_clocks (void)
{
#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
- defined(CONFIG_440) || defined(CONFIG_405)
+ defined(CONFIG_405EX) || defined(CONFIG_405) || \
+ defined(CONFIG_440)
sys_info_t sys_info;
get_sys_info (&sys_info);
@@ -907,7 +1074,8 @@ ulong get_bus_freq (ulong dummy)
#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
- defined(CONFIG_440) || defined(CONFIG_405)
+ defined(CONFIG_405EX) || defined(CONFIG_405) || \
+ defined(CONFIG_440)
sys_info_t sys_info;
get_sys_info (&sys_info);