X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fnet%2Ffec_mxc.c;h=ab90afa41eb8f30c4a0611b155032473e9268c35;hb=3ce04d9bba017012751cbecf25b923bcb02ccb54;hp=faf008cea16ec958ecc3bb32c8947f9a26d628c8;hpb=0b23fb368d08c9669fac647971ff249c3f9fee8f;p=oweals%2Fu-boot.git diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index faf008cea1..ab90afa41e 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -55,12 +55,14 @@ struct fec_priv gfec = { .tbd_base = NULL, .tbd_index = 0, .bd = NULL, + .rdb_ptr = NULL, + .base_ptr = NULL, }; /* * MII-interface related functions */ -static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr, +static int fec_miiphy_read(const char *dev, uint8_t phyAddr, uint8_t regAddr, uint16_t *retVal) { struct eth_device *edev = eth_get_dev_by_name(dev); @@ -84,7 +86,7 @@ static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr, /* * wait for the related interrupt */ - start = get_timer_masked(); + start = get_timer(0); while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) { if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) { printf("Read MDIO failed...\n"); @@ -106,7 +108,18 @@ static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr, return 0; } -static int fec_miiphy_write(char *dev, uint8_t phyAddr, uint8_t regAddr, +static void fec_mii_setspeed(struct fec_priv *fec) +{ + /* + * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock + * and do not drop the Preamble. + */ + writel((((imx_get_fecclk() / 1000000) + 2) / 5) << 1, + &fec->eth->mii_speed); + debug("fec_init: mii_speed %#lx\n", + fec->eth->mii_speed); +} +static int fec_miiphy_write(const char *dev, uint8_t phyAddr, uint8_t regAddr, uint16_t data) { struct eth_device *edev = eth_get_dev_by_name(dev); @@ -125,7 +138,7 @@ static int fec_miiphy_write(char *dev, uint8_t phyAddr, uint8_t regAddr, /* * wait for the MII interrupt */ - start = get_timer_masked(); + start = get_timer(0); while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) { if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) { printf("Write MDIO failed...\n"); @@ -149,17 +162,21 @@ static int miiphy_restart_aneg(struct eth_device *dev) * Wake up from sleep if necessary * Reset PHY, then delay 300ns */ - miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_MIPGSR, 0x00FF); - miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_BMCR, - PHY_BMCR_RESET); +#ifdef CONFIG_MX27 + miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, MII_DCOUNTER, 0x00FF); +#endif + miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, MII_BMCR, + BMCR_RESET); udelay(1000); /* * Set the auto-negotiation advertisement register bits */ - miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_ANAR, 0x1e0); - miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_BMCR, - PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); + miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, MII_ADVERTISE, + LPA_100FULL | LPA_100HALF | LPA_10FULL | + LPA_10HALF | PHY_ANLPAR_PSB_802_3); + miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, MII_BMCR, + BMCR_ANENABLE | BMCR_ANRESTART); return 0; } @@ -172,7 +189,7 @@ static int miiphy_wait_aneg(struct eth_device *dev) /* * Wait for AN completion */ - start = get_timer_masked(); + start = get_timer(0); do { if (get_timer(start) > (CONFIG_SYS_HZ * 5)) { printf("%s: Autonegotiation timeout\n", dev->name); @@ -180,12 +197,12 @@ static int miiphy_wait_aneg(struct eth_device *dev) } if (miiphy_read(dev->name, CONFIG_FEC_MXC_PHYADDR, - PHY_BMSR, &status)) { + MII_BMSR, &status)) { printf("%s: Autonegotiation failed. status: 0x%04x\n", dev->name, status); return -1; } - } while (!(status & PHY_BMSR_LS)); + } while (!(status & BMSR_LSTATUS)); return 0; } @@ -228,10 +245,11 @@ static int fec_rbd_init(struct fec_priv *fec, int count, int size) uint32_t p = 0; /* reserve data memory and consider alignment */ - fec->rdb_ptr = malloc(size * count + DB_DATA_ALIGNMENT); + if (fec->rdb_ptr == NULL) + fec->rdb_ptr = malloc(size * count + DB_DATA_ALIGNMENT); p = (uint32_t)fec->rdb_ptr; if (!p) { - puts("fec_imx27: not enough malloc memory!\n"); + puts("fec_mxc: not enough malloc memory\n"); return -ENOMEM; } memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT); @@ -294,17 +312,13 @@ static void fec_rbd_clean(int last, struct fec_bd *pRbd) static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac) { - struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; - int i; - - for (i = 0; i < 6; i++) - mac[6-1-i] = readl(&iim->iim_bank_area0[IIM0_MAC + i]); - - return is_valid_ether_addr(mac); + imx_get_mac_from_fuse(mac); + return !is_valid_ether_addr(mac); } -static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac) +static int fec_set_hwaddr(struct eth_device *dev) { + uchar *mac = dev->enetaddr; struct fec_priv *fec = (struct fec_priv *)dev->priv; writel(0, &fec->eth->iaddr1); @@ -338,11 +352,40 @@ static int fec_open(struct eth_device *edev) /* * Enable FEC-Lite controller */ - writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl); + writel(readl(&fec->eth->ecntrl) | FEC_ECNTRL_ETHER_EN, + &fec->eth->ecntrl); +#if defined(CONFIG_MX25) || defined(CONFIG_MX53) + udelay(100); + /* + * setup the MII gasket for RMII mode + */ + + /* disable the gasket */ + writew(0, &fec->eth->miigsk_enr); + + /* wait for the gasket to be disabled */ + while (readw(&fec->eth->miigsk_enr) & MIIGSK_ENR_READY) + udelay(2); + + /* configure gasket for RMII, 50 MHz, no loopback, and no echo */ + writew(MIIGSK_CFGR_IF_MODE_RMII, &fec->eth->miigsk_cfgr); + + /* re-enable the gasket */ + writew(MIIGSK_ENR_EN, &fec->eth->miigsk_enr); + + /* wait until MII gasket is ready */ + int max_loops = 10; + while ((readw(&fec->eth->miigsk_enr) & MIIGSK_ENR_READY) == 0) { + if (--max_loops <= 0) { + printf("WAIT for MII Gasket ready timed out\n"); + break; + } + } +#endif miiphy_wait_aneg(edev); - miiphy_speed(edev->name, 0); - miiphy_duplex(edev->name, 0); + miiphy_speed(edev->name, CONFIG_FEC_MXC_PHYADDR); + miiphy_duplex(edev->name, CONFIG_FEC_MXC_PHYADDR); /* * Enable SmartDMA receive task @@ -358,16 +401,20 @@ static int fec_init(struct eth_device *dev, bd_t* bd) uint32_t base; struct fec_priv *fec = (struct fec_priv *)dev->priv; + /* Initialize MAC address */ + fec_set_hwaddr(dev); + /* * reserve memory for both buffer descriptor chains at once * Datasheet forces the startaddress of each chain is 16 byte * aligned */ - fec->base_ptr = malloc((2 + FEC_RBD_NUM) * - sizeof(struct fec_bd) + DB_ALIGNMENT); + if (fec->base_ptr == NULL) + fec->base_ptr = malloc((2 + FEC_RBD_NUM) * + sizeof(struct fec_bd) + DB_ALIGNMENT); base = (uint32_t)fec->base_ptr; if (!base) { - puts("fec_imx27: not enough malloc memory!\n"); + puts("fec_mxc: not enough malloc memory\n"); return -ENOMEM; } memset((void *)base, 0, (2 + FEC_RBD_NUM) * @@ -405,14 +452,8 @@ static int fec_init(struct eth_device *dev, bd_t* bd) * Frame length=1518; MII mode; */ writel(0x05ee0024, &fec->eth->r_cntrl); /* FIXME 0x05ee0004 */ - /* - * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock - * and do not drop the Preamble. - */ - writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1, - &fec->eth->mii_speed); - debug("fec_init: mii_speed %#lx\n", - (((imx_get_ahbclk() / 1000000) + 2) / 5) << 1); + + fec_mii_setspeed(fec); } /* * Set Opcode/Pause Duration Register @@ -444,6 +485,7 @@ static int fec_init(struct eth_device *dev, bd_t* bd) */ if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) { free(fec->base_ptr); + fec->base_ptr = NULL; return -ENOMEM; } fec_tbd_init(fec); @@ -468,7 +510,7 @@ static void fec_halt(struct eth_device *dev) /* * issue graceful stop command to the FEC transmitter if necessary */ - writel(FEC_ECNTRL_RESET | readl(&fec->eth->x_cntrl), + writel(FEC_TCNTRL_GTS | readl(&fec->eth->x_cntrl), &fec->eth->x_cntrl); debug("eth_halt: wait for stop regs\n"); @@ -476,7 +518,7 @@ static void fec_halt(struct eth_device *dev) * wait for graceful stop to register */ while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA))) - ; /* FIXME ensure time */ + udelay(1); /* * Disable SmartDMA tasks @@ -488,11 +530,10 @@ static void fec_halt(struct eth_device *dev) * Disable the Ethernet Controller * Note: this will also reset the BD index counter! */ - writel(0, &fec->eth->ecntrl); + writel(readl(&fec->eth->ecntrl) & ~FEC_ECNTRL_ETHER_EN, + &fec->eth->ecntrl); fec->rbd_index = 0; fec->tbd_index = 0; - free(fec->rdb_ptr); - free(fec->base_ptr); debug("eth_halt: done\n"); } @@ -517,7 +558,7 @@ static int fec_send(struct eth_device *dev, volatile void* packet, int length) * Check for valid length of data. */ if ((length > 1500) || (length <= 0)) { - printf("Payload (%d) to large!\n", length); + printf("Payload (%d) too large\n", length); return -1; } @@ -549,7 +590,7 @@ static int fec_send(struct eth_device *dev, volatile void* packet, int length) * wait until frame is sent . */ while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) { - /* FIXME: Timeout */ + udelay(1); } debug("fec_send: status 0x%x index %d\n", readw(&fec->tbd_base[fec->tbd_index].status), @@ -646,29 +687,23 @@ static int fec_recv(struct eth_device *dev) static int fec_probe(bd_t *bd) { - struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; struct eth_device *edev; struct fec_priv *fec = &gfec; - unsigned char ethaddr_str[20]; unsigned char ethaddr[6]; - char *tmp = getenv("ethaddr"); - char *end; - - /* enable FEC clock */ - writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1); - writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0); /* create and fill edev struct */ edev = (struct eth_device *)malloc(sizeof(struct eth_device)); if (!edev) { - puts("fec_imx27: not enough malloc memory!\n"); + puts("fec_mxc: not enough malloc memory\n"); return -ENOMEM; } + memset(edev, 0, sizeof(*edev)); edev->priv = fec; edev->init = fec_init; edev->send = fec_send; edev->recv = fec_recv; edev->halt = fec_halt; + edev->write_hwaddr = fec_set_hwaddr; fec->eth = (struct ethernet_regs *)IMX_FEC_BASE; fec->bd = bd; @@ -676,7 +711,7 @@ static int fec_probe(bd_t *bd) fec->xcv_type = MII100; /* Reset chip. */ - writel(FEC_ECNTRL_RESET, &fec->eth->ecntrl); + writel(readl(&fec->eth->ecntrl) | FEC_ECNTRL_RESET, &fec->eth->ecntrl); while (readl(&fec->eth->ecntrl) & 1) udelay(10); @@ -697,35 +732,18 @@ static int fec_probe(bd_t *bd) * Frame length=1518; MII mode; */ writel(0x05ee0024, &fec->eth->r_cntrl); /* FIXME 0x05ee0004 */ - /* - * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock - * and do not drop the Preamble. - */ - writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1, - &fec->eth->mii_speed); - debug("fec_init: mii_speed %#lx\n", - (((imx_get_ahbclk() / 1000000) + 2) / 5) << 1); + fec_mii_setspeed(fec); - sprintf(edev->name, "FEC_MXC"); + sprintf(edev->name, "FEC"); miiphy_register(edev->name, fec_miiphy_read, fec_miiphy_write); eth_register(edev); - if ((NULL != tmp) && (12 <= strlen(tmp))) { - int i; - /* convert MAC from string to int */ - for (i = 0; i < 6; i++) { - ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0; - if (tmp) - tmp = (*end) ? end + 1 : end; - } - } else if (fec_get_hwaddr(edev, ethaddr) == 0) { - printf("got MAC address from EEPROM: %pM\n", ethaddr); - setenv("ethaddr", (char *)ethaddr_str); + if (fec_get_hwaddr(edev, ethaddr) == 0) { + printf("got MAC address from fuse: %pM\n", ethaddr); + memcpy(edev->enetaddr, ethaddr, 6); } - memcpy(edev->enetaddr, ethaddr, 6); - fec_set_hwaddr(edev, ethaddr); return 0; } @@ -739,4 +757,3 @@ int fecmxc_initialize(bd_t *bd) return lout; } -