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