* Patch by Travis Sawyer, 01 Mar 2004:
  Ocotea:
  - Add IBM PPC440GX Ref Platform support (Ocotea)
    Original code by Paul Reynolds <PaulReynolds@lhsolutions.com>
    Adapted to U-Boot and 440GX port
  440gx_enet.c:
  - Add gracious handling of all Ethernet Pin Selections for 440GX
  - Add RGMII selection for Cicada CIS8201 Gigabit PHY
  ppc440.h:
  - Add needed bit definitions
  - Fix formatting

* Patch by Carl Riechers, 1 Mar 2004:
  Add PPC440GX prbdv0 divider to fix memory clock calculation.

* Patch by Stephan Linz, 27 Feb 2004
  - avoid problems for targets without NFS download support
diff --git a/cpu/ppc4xx/440gx_enet.c b/cpu/ppc4xx/440gx_enet.c
index c8259b1..ba7418a 100644
--- a/cpu/ppc4xx/440gx_enet.c
+++ b/cpu/ppc4xx/440gx_enet.c
@@ -187,6 +187,11 @@
 	unsigned short devnum;
 	unsigned short reg_short;
 	sys_info_t sysinfo;
+#if defined (CONFIG_440_GX)
+	unsigned long pfc1;
+	unsigned long zmiifer;
+	unsigned long rmiifer;
+#endif
 
 	EMAC_440GX_HW_PST hw_p = dev->priv;
 
@@ -262,17 +267,84 @@
 	reg = 0;
 	out32 (ZMII_FER, 0);
 	udelay (100);
-	out32 (ZMII_FER, ZMII_FER_MDI << ZMII_FER_V (devnum));
-	out32 (ZMII_SSR, 0x11110000);
-	/* reset emac so we have access to the phy */
-	__asm__ volatile ("eieio");
 
-	out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
-	__asm__ volatile ("eieio");
+#if defined(CONFIG_440_GX)
+	mfsdr(sdr_pfc1, pfc1);
+	pfc1 = SDR0_PFC1_EPS_DECODE(pfc1);
 
-	if ((devnum == 2) || (devnum == 3))
+	switch (pfc1) {
+	case 1:
+		zmiifer = (ZMII_FER_MDI | ZMII_FER_RMII) << ZMII_FER_V(devnum);
+		rmiifer = 0x0;
+		break;
+	case 2:
+		zmiifer = (ZMII_FER_MDI | ZMII_FER_SMII) << ZMII_FER_V(devnum);
+		rmiifer = 0x0;
+		break;
+	case 3:
+		if (devnum == 0) {
+			zmiifer = (ZMII_FER_MDI | ZMII_FER_RMII) << ZMII_FER_V(devnum);
+			rmiifer = 0x0;
+		} else if (devnum == 2) {
+			zmiifer = (ZMII_FER_MDI | ZMII_FER_RMII) << ZMII_FER_V(devnum);
+			rmiifer = RGMII_FER_RGMII << RGMII_FER_V(devnum);
+		} else { /* invalid case */
+			zmiifer = 0x0;
+			rmiifer = 0x0;
+		}
+		break;
+	case 4:
+		if ((devnum == 0) || (devnum == 1)) {
+			zmiifer = (ZMII_FER_MDI | ZMII_FER_SMII) << ZMII_FER_V (devnum);
+			rmiifer = 0x0;
+		} else { /* ((devnum == 2) || (devnum == 3)) */
+			zmiifer = (ZMII_FER_MDI/* | ZMII_FER_RMII */) << ZMII_FER_V (devnum);
+			rmiifer = RGMII_FER_RGMII << RGMII_FER_V (devnum);
+		}
+		break;
+	case 5:
+		if ((devnum == 0) || (devnum == 1) || (devnum == 2)) {
+			zmiifer = (ZMII_FER_MDI | ZMII_FER_SMII) << ZMII_FER_V (devnum);
+			rmiifer = 0x0;
+		} else {
+			zmiifer = (ZMII_FER_MDI | ZMII_FER_RMII) << ZMII_FER_V(devnum);
+			rmiifer = RGMII_FER_RGMII << RGMII_FER_V(devnum);
+		}
+		break;
+	case 6:
+		if ((devnum == 0) || (devnum == 1)) {
+			zmiifer = (ZMII_FER_MDI | ZMII_FER_SMII) << ZMII_FER_V (devnum);
+			rmiifer = 0x0;
+		} else {
+			zmiifer = (ZMII_FER_MDI | ZMII_FER_RMII) << ZMII_FER_V(devnum);
+			rmiifer = RGMII_FER_RGMII << RGMII_FER_V(devnum);
+		}
+		break;
+	case 0:
+	default:
+		zmiifer = (ZMII_FER_MDI | ZMII_FER_MII) << ZMII_FER_V(devnum);
+		rmiifer = 0x0;
+		break;
+	}
+
+	out32 (ZMII_FER, zmiifer);
+	out32 (RGMII_FER, rmiifer);
+#else
+	if ((devnum == 0) || (devnum == 1)) {
+		out32 (ZMII_FER, (ZMII_FER_SMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
+	}
+	else { /* ((devnum == 2) || (devnum == 3)) */
+		out32 (ZMII_FER, ZMII_FER_MDI << ZMII_FER_V (devnum));
 		out32 (RGMII_FER, ((RGMII_FER_RGMII << RGMII_FER_V (2)) |
 				   (RGMII_FER_RGMII << RGMII_FER_V (3))));
+	}
+#endif
+	out32 (ZMII_SSR, ZMII_SSR_SP << ZMII_SSR_V(devnum));
+	__asm__ volatile ("eieio");
+
+	/* reset emac so we have access to the phy */
+
+	out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
 	__asm__ volatile ("eieio");
 
 	failsafe = 1000;
@@ -325,6 +397,16 @@
 	/* Reset the phy */
 	miiphy_reset (reg);
 
+#if defined(CONFIG_CIS8201_PHY)
+	/*
+	 * Cicada 8201 PHY needs to have an extended register whacked
+	 * for RGMII mode.
+	 */
+	if ( ((devnum == 2) || (devnum ==3)) && (4 == pfc1) ) {
+		miiphy_write (reg, 23, 0x1200);
+	}
+#endif
+
 	/* Start/Restart autonegotiation */
 	phy_setup_aneg (reg);
 	udelay (1000);
@@ -332,7 +414,7 @@
 	miiphy_read (reg, PHY_BMSR, &reg_short);
 
 	/*
-	 * Wait if PHY is able of autonegotiation and autonegotiation is not complete
+	 * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
 	 */
 	if ((reg_short & PHY_BMSR_AUTN_ABLE)
 	    && !(reg_short & PHY_BMSR_AUTN_COMP)) {
diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c
index e776050..7172fe3 100644
--- a/cpu/ppc4xx/speed.c
+++ b/cpu/ppc4xx/speed.c
@@ -247,7 +247,7 @@
 	unsigned long temp1;
 	unsigned long lfdiv;
 	unsigned long m;
-
+	unsigned long prbdv0;    
 
 	/* Extract configured divisors */
 	mfsdr( sdr_sdstp0,strp0 );
@@ -263,6 +263,7 @@
 	sysInfo->pllOpbDiv = temp ? temp : 4;
 	temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
 	sysInfo->pllExtBusDiv = temp ? temp : 4;
+	prbdv0 = (strp0 >> 2) & 0x7;
 
 	/* Calculate 'M' based on feedback source */
 	temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
@@ -284,7 +285,7 @@
 	/* Now calculate the individual clocks */
 	sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
 	sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
-	sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
+	sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
 	sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
 	sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv;