From: Luigi 'Comio' Mantellini <luigi.mantell...@idf-hit.com>

Signed-off-by: Luigi 'Comio' Mantellini <luigi.mantell...@idf-hit.com>
---
 cpu/mpc85xx/ether_fcc.c |  400 ++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 379 insertions(+), 21 deletions(-)

diff --git a/cpu/mpc85xx/ether_fcc.c b/cpu/mpc85xx/ether_fcc.c
index 5f1414d..7d8234e 100644
--- a/cpu/mpc85xx/ether_fcc.c
+++ b/cpu/mpc85xx/ether_fcc.c
@@ -1,5 +1,9 @@
 /*
  * MPC8560 FCC Fast Ethernet
+ *
+ * Copyright (c) 2009 Industrie Dial Face S.p.A.
+ * Luigi 'Comio' Mantellini <luigi.mantell...@idf-hit.com>
+ *
  * Copyright (c) 2003 Motorola,Inc.
  * Xianghua Xiao, (x.x...@motorola.com)
  *
@@ -55,7 +59,11 @@
 #if defined(CONFIG_ETHER_ON_FCC) && defined(CONFIG_CMD_NET) && \
        defined(CONFIG_NET_MULTI)
 
-static struct ether_fcc_info_s
+extern int mpc85xx_init_phy(struct eth_device *dev);
+
+struct ether_fcc_info_s;
+
+struct ether_fcc_info_s
 {
        int ether_index;
        int proff_enet;
@@ -63,39 +71,60 @@ static struct ether_fcc_info_s
        ulong cpm_cr_enet_page;
        ulong cmxfcr_mask;
        ulong cmxfcr_value;
-}
-       ether_fcc_info[] =
+#ifdef CONFIG_MPC85XX_BITBANGMII
+       int mdiopin;
+       int mdcpin;
+       uint phyaddr;
+#endif
+};
+
+static struct ether_fcc_info_s ether_fcc_info[] =
 {
 #ifdef CONFIG_ETHER_ON_FCC1
 {
-       0,
-       PROFF_FCC1,
-       CPM_CR_FCC1_SBLOCK,
-       CPM_CR_FCC1_PAGE,
-       CONFIG_SYS_CMXFCR_MASK1,
-       CONFIG_SYS_CMXFCR_VALUE1
+       .ether_index = 0,
+       .proff_enet = PROFF_FCC1,
+       .cpm_cr_enet_sblock = CPM_CR_FCC1_SBLOCK,
+       .cpm_cr_enet_page = CPM_CR_FCC1_PAGE,
+       .cmxfcr_mask = CONFIG_SYS_CMXFCR_MASK1,
+       .cmxfcr_value = CONFIG_SYS_CMXFCR_VALUE1,
+#ifdef CONFIG_MPC85XX_BITBANGMII
+       .mdiopin = CONFIG_SYS_FCC1_MDIO,
+       .mdcpin = CONFIG_SYS_FCC1_MDC,
+       .phyaddr = CONFIG_SYS_FCC1_PHYADDR
+#endif
 },
 #endif
 
 #ifdef CONFIG_ETHER_ON_FCC2
 {
-       1,
-       PROFF_FCC2,
-       CPM_CR_FCC2_SBLOCK,
-       CPM_CR_FCC2_PAGE,
-       CONFIG_SYS_CMXFCR_MASK2,
-       CONFIG_SYS_CMXFCR_VALUE2
+       .ether_index = 1,
+       .proff_enet = PROFF_FCC2,
+       .cpm_cr_enet_sblock = CPM_CR_FCC2_SBLOCK,
+       .cpm_cr_enet_page = CPM_CR_FCC2_PAGE,
+       .cmxfcr_mask = CONFIG_SYS_CMXFCR_MASK2,
+       .cmxfcr_value = CONFIG_SYS_CMXFCR_VALUE2,
+#ifdef CONFIG_MPC85XX_BITBANGMII
+       .mdiopin =CONFIG_SYS_FCC2_MDIO,
+       .mdcpin = CONFIG_SYS_FCC2_MDC,
+       .phyaddr = CONFIG_SYS_FCC2_PHYADDR
+#endif
 },
 #endif
 
 #ifdef CONFIG_ETHER_ON_FCC3
 {
-       2,
-       PROFF_FCC3,
-       CPM_CR_FCC3_SBLOCK,
-       CPM_CR_FCC3_PAGE,
-       CONFIG_SYS_CMXFCR_MASK3,
-       CONFIG_SYS_CMXFCR_VALUE3
+       .ether_index = 2,
+       .proff_enet = PROFF_FCC3,
+       .cpm_cr_enet_sblock = CPM_CR_FCC3_SBLOCK,
+       .cpm_cr_enet_page = CPM_CR_FCC3_PAGE,
+       .cmxfcr_mask = CONFIG_SYS_CMXFCR_MASK3,
+       .cmxfcr_value = CONFIG_SYS_CMXFCR_VALUE3,
+#ifdef CONFIG_MPC85XX_BITBANGMII
+       .mdiopin =CONFIG_SYS_FCC3_MDIO,
+       .mdcpin = CONFIG_SYS_FCC3_MDC,
+       .phyaddr = CONFIG_SYS_FCC3_PHYADDR
+#endif
 },
 #endif
 };
@@ -139,6 +168,329 @@ static RTXBD rtx __attribute__ ((aligned(8)));
 
 #undef ET_DEBUG
 
+#ifdef CONFIG_MPC85XX_BITBANGMII
+
+#include <asm/iopin_85xx.h>
+
+#define DECLARE_IOPIN(iopin, pin) \
+       iopin_t iopin; \
+       iopin.port = pin / 32; \
+       iopin.pin = pin % 32; \
+       iopin.flag = 0;
+
+static inline void mpc85xx_udelay(unsigned long delay)
+{
+       udelay(delay);
+}
+
+static void mpc85xx_mdio_active(int pin)
+{
+       DECLARE_IOPIN(iopin, pin);
+
+       iopin_set_act(&iopin);
+       iopin_set_gen(&iopin);
+       iopin_set_out(&iopin);
+       iopin_set_high(&iopin);
+}
+
+static inline void mpc85xx_mdc_active(int pin)
+{
+       DECLARE_IOPIN(iopin, pin);
+
+       iopin_set_act(&iopin);
+       iopin_set_gen(&iopin);
+       iopin_set_out(&iopin);
+       iopin_set_high(&iopin);
+}
+
+static void mpc85xx_mdio_tristate(int pin)
+{
+       DECLARE_IOPIN(iopin, pin);
+
+       iopin_set_odr(&iopin);
+       iopin_set_gen(&iopin);
+       iopin_set_in(&iopin);
+       iopin_set_high(&iopin);
+}
+
+static void mpc85xx_mdio_set(int pin, int value)
+{
+       DECLARE_IOPIN(iopin, pin);
+
+       if (value)
+               iopin_set_high(&iopin);
+       else
+               iopin_set_low(&iopin);
+}
+
+static inline void mpc85xx_mdc_set(int pin, int value)
+{
+       mpc85xx_mdio_set(pin, value);
+}
+
+static int mpc85xx_mdio_get(int pin)
+{
+       DECLARE_IOPIN(iopin, pin);
+
+       if (iopin_is_high(&iopin))
+               return 1;
+       else
+               return 0;
+}
+
+/*****************************************************************************
+ *
+ * Utility to send the preamble, address, and register (common to read
+ * and write).
+ */
+static void mpc85xx_miiphy_pre (struct ether_fcc_info_s *info, char read, 
unsigned char addr, unsigned char reg)
+{
+       int j;                  /* counter */
+
+       int mdio = info->mdiopin;
+       int mdc  = info->mdcpin;
+
+       /*
+        * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
+        * The IEEE spec says this is a PHY optional requirement.  The AMD
+        * 79C874 requires one after power up and one after a MII communications
+        * error.  This means that we are doing more preambles than we need,
+        * but it is safer and will be much more robust.
+        */
+
+       mpc85xx_mdio_active(mdio);
+       mpc85xx_mdc_active(mdc);
+       mpc85xx_mdio_set(mdio, 1);
+
+       for (j = 0; j < 32; j++) {
+               mpc85xx_mdc_set(mdc, 0);
+               mpc85xx_udelay(1);
+               mpc85xx_mdc_set(mdc, 1);
+               mpc85xx_udelay(1);
+       }
+
+       /* send the start bit (01) and the read opcode (10) or write (10) */
+       mpc85xx_mdc_set(mdc, 0);
+       mpc85xx_mdio_set(mdio, 0);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc, 1);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc, 0);
+       mpc85xx_mdio_set(mdio, 1);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc, 1);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc, 0);
+       mpc85xx_mdio_set(mdio, read);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc, 1);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc, 0);
+       mpc85xx_mdio_set(mdio, !read);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc, 1);
+       mpc85xx_udelay(1);
+
+       /* send the PHY address */
+       for (j = 0; j < 5; j++) {
+               mpc85xx_mdc_set(mdc, 0);
+               if ((addr & 0x10) == 0) {
+                       mpc85xx_mdio_set(mdio, 0);
+               } else {
+                       mpc85xx_mdio_set(mdio, 1);
+               }
+               mpc85xx_udelay(1);
+               mpc85xx_mdc_set(mdc, 1);
+               mpc85xx_udelay(1);
+               addr <<= 1;
+       }
+
+       /* send the register address */
+       for (j = 0; j < 5; j++) {
+               mpc85xx_mdc_set(mdc, 0);
+               if ((reg & 0x10) == 0) {
+                       mpc85xx_mdio_set(mdio, 0);
+               } else {
+                       mpc85xx_mdio_set(mdio, 1);
+               }
+               mpc85xx_udelay(1);
+               mpc85xx_mdc_set(mdc, 1);
+               mpc85xx_udelay(1);
+               reg <<= 1;
+       }
+}
+
+/*****************************************************************************
+ *
+ * Read a MII PHY register.
+ *
+ * Returns:
+ *   0 on success
+ */
+int mpc85xx_bb_miiphy_read (char *devname, unsigned char addr,
+               unsigned char reg, unsigned short *value)
+{
+       short rdreg;            /* register working value */
+       int j;                  /* counter */
+
+       struct eth_device *dev;
+       struct ether_fcc_info_s *info;
+
+       int mdio;
+       int mdc;
+
+       if ((value == NULL) || (devname == NULL)) {
+               puts("NULL value pointer\n");
+               return (-1);
+       }
+
+       dev = eth_get_dev_by_name(devname);
+
+       if (dev == NULL) {
+               puts("Unknown net device: ");
+               puts(devname);
+               puts("\n");
+               return (-1);
+       }
+
+       info = (struct ether_fcc_info_s *)(dev->priv);
+
+       mdio = info->mdiopin;
+       mdc = info->mdcpin;
+
+       mpc85xx_miiphy_pre (info, 1, addr, reg);
+
+       /* tri-state our MDIO I/O pin so we can read */
+       mpc85xx_mdc_set(mdc, 0);
+       mpc85xx_mdio_tristate(mdio);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc, 1);
+       mpc85xx_udelay(1);
+
+       /* check the turnaround bit: the PHY should be driving it to zero */
+       if (mpc85xx_mdio_get(mdio) != 0) {
+               /* puts ("PHY didn't drive TA low\n"); */
+               for (j = 0; j < 32; j++) {
+                       mpc85xx_mdc_set(mdc, 0);
+                       mpc85xx_udelay(1);
+                       mpc85xx_mdc_set(mdc, 1);
+                       mpc85xx_udelay(1);
+               }
+               /* There is no PHY, set value to 0xFFFF and return */
+               *value = 0xFFFF;
+               return (-1);
+       }
+
+       mpc85xx_mdc_set(mdc, 0);
+       mpc85xx_udelay(1);
+
+       /* read 16 bits of register data, MSB first */
+       rdreg = 0;
+       for (j = 0; j < 16; j++) {
+               mpc85xx_mdc_set(mdc, 1);
+               mpc85xx_udelay(1);
+               rdreg <<= 1;
+               rdreg |= mpc85xx_mdio_get(mdio);
+               mpc85xx_mdc_set(mdc, 0);
+               mpc85xx_udelay(1);
+       }
+
+       mpc85xx_mdc_set(mdc,  1);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc,  0);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc,  1);
+       mpc85xx_udelay(1);
+
+       *value = rdreg;
+
+#ifdef ET_DEBUG
+       printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value);
+#endif
+
+       return 0;
+}
+
+
+/*****************************************************************************
+ *
+ * Write a MII PHY register.
+ *
+ * Returns:
+ *   0 on success
+ */
+int mpc85xx_bb_miiphy_write (char *devname, unsigned char addr,
+               unsigned char reg, unsigned short value)
+{
+       int j;                  /* counter */
+
+       struct eth_device *dev;
+       struct ether_fcc_info_s *info;
+
+       int mdio;
+       int mdc;
+
+       if (devname == NULL) {
+               puts("NULL value pointer\n");
+               return (-1);
+       }
+
+       dev = eth_get_dev_by_name(devname);
+
+       if (dev == NULL) {
+               puts("Unknown net device: ");
+               puts(devname);
+               puts("\n");
+               return (-1);
+       }
+
+       info = (struct ether_fcc_info_s *)(dev->priv);
+
+       mdio = info->mdiopin;
+       mdc = info->mdcpin;
+
+       mpc85xx_miiphy_pre (info, 0, addr, reg);
+
+       /* send the turnaround (10) */
+       mpc85xx_mdc_set(mdc,  0);
+       mpc85xx_mdio_set(mdio, 1);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc,  1);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc,  0);
+       mpc85xx_mdio_set(mdio, 0);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc,  1);
+       mpc85xx_udelay(1);
+
+       /* write 16 bits of register data, MSB first */
+       for (j = 0; j < 16; j++) {
+               mpc85xx_mdc_set(mdc,  0);
+               if ((value & 0x00008000) == 0) {
+                       mpc85xx_mdio_set(mdio, 0);
+               } else {
+                       mpc85xx_mdio_set(mdio, 1);
+               }
+               mpc85xx_udelay(1);
+               mpc85xx_mdc_set(mdc,  1);
+               mpc85xx_udelay(1);
+               value <<= 1;
+       }
+
+       /*
+        * Tri-state the MDIO line.
+        */
+       mpc85xx_mdio_tristate(mdio);
+       mpc85xx_mdc_set(mdc,  0);
+       mpc85xx_udelay(1);
+       mpc85xx_mdc_set(mdc,  1);
+       mpc85xx_udelay(1);
+
+       return 0;
+}
+
+#endif
+
 static int fec_send(struct eth_device* dev, volatile void *packet, int length)
 {
     int i = 0;
@@ -461,6 +813,12 @@ int fec_initialize(bd_t *bis)
                miiphy_register(dev->name,
                                bb_miiphy_read, bb_miiphy_write);
 #endif
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) \
+               && defined(CONFIG_MPC85XX_BITBANGMII)
+               miiphy_register(dev->name,
+                               mpc85xx_bb_miiphy_read, 
mpc85xx_bb_miiphy_write);
+               mpc85xx_init_phy(dev);
+#endif
        }
 
        return 1;
-- 
1.6.3.3

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to