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>
diff --git a/cpu/ppc4xx/serial.c b/cpu/ppc4xx/serial.c
index e62dd9d..a75e5ee 100644
--- a/cpu/ppc4xx/serial.c
+++ b/cpu/ppc4xx/serial.c
@@ -448,12 +448,17 @@
 	unsigned long i;
 	unsigned long est;		/* current estimate */
 	unsigned long plloutb;
+	unsigned long cpr_pllc;
 	u32 reg;
 
+	/* check the pll feedback source */
+	mfcpr(cprpllc, cpr_pllc);
+
 	get_sys_info(&sysinfo);
 
-	plloutb = ((CONFIG_SYS_CLK_FREQ * sysinfo.pllFwdDiv * sysinfo.pllFbkDiv)
-		   / sysinfo.pllFwdDivB);
+	plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ? 
+		sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) * sysinfo.pllFbkDiv) / 
+		sysinfo.pllFwdDivB);
 	udiv = 256;			/* Assume lowest possible serial clk */
 	div = plloutb / (16 * baudrate); /* total divisor */
 	umin = (plloutb / get_OPB_freq()) << 1;	/* 2 x OPB divisor */
diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c
index 028b11a..da5330a 100644
--- a/cpu/ppc4xx/speed.c
+++ b/cpu/ppc4xx/speed.c
@@ -771,6 +771,7 @@
 void get_sys_info (PPC405_SYS_INFO * sysInfo)
 {
 	unsigned long cpr_plld;
+	unsigned long cpr_pllc;
 	unsigned long cpr_primad;
 	unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
 	unsigned long primad_cpudv;
@@ -780,6 +781,7 @@
 	 * Read PLL Mode registers
 	 */
 	mfcpr(cprplld, cpr_plld);
+	mfcpr(cprpllc, cpr_pllc);
 
 	/*
 	 * Determine forward divider A
@@ -787,20 +789,18 @@
 	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);
-	if (sysInfo->pllFwdDivB == 0) {
+	if (sysInfo->pllFwdDivB == 0)
 		sysInfo->pllFwdDivB = 8;
-	}
 
 	/*
 	 * Determine FBK_DIV.
 	 */
 	sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
-	if (sysInfo->pllFbkDiv == 0) {
+	if (sysInfo->pllFbkDiv == 0)
 		sysInfo->pllFbkDiv = 256;
-	}
 
 	/*
 	 * Read CPR_PRIMAD register
@@ -810,30 +810,30 @@
 	 * Determine PLB_DIV.
 	 */
 	sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
-	if (sysInfo->pllPlbDiv == 0) {
+	if (sysInfo->pllPlbDiv == 0)
 		sysInfo->pllPlbDiv = 16;
-	}
 
 	/*
 	 * Determine EXTBUS_DIV.
 	 */
 	sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
-	if (sysInfo->pllExtBusDiv == 0) {
+	if (sysInfo->pllExtBusDiv == 0)
 		sysInfo->pllExtBusDiv = 16;
-	}
 
 	/*
 	 * Determine OPB_DIV.
 	 */
 	sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
-	if (sysInfo->pllOpbDiv == 0) {
+	if (sysInfo->pllOpbDiv == 0)
 		sysInfo->pllOpbDiv = 16;
-	}
 
 	/*
 	 * 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
@@ -845,16 +845,17 @@
 	 * Determine CPU clock frequency
 	 */
 	primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
-	if (primad_cpudv == 0) {
+	if (primad_cpudv == 0)
 		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
 	 */
-	sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) / sysInfo->pllPlbDiv;
+	sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
+		sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
 }
 
 /********************************************
diff --git a/include/ppc405.h b/include/ppc405.h
index 8e64731..e4522e7 100644
--- a/include/ppc405.h
+++ b/include/ppc405.h
@@ -617,6 +617,8 @@
 #define CPR_CLKUPD_ENDVCH_EN   0x20000000     /* Enable CPR Sys. Div. Changes */
 #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_FWDVA_MASK        0x000F0000     /* PLL forward divider A value */
 #define PLLD_FWDVB_MASK        0x00000700     /* PLL forward divider B value */