1c4775476SKuo-Jung Su /* 2c4775476SKuo-Jung Su * Faraday 10/100Mbps Ethernet Controller 3c4775476SKuo-Jung Su * 4*102a8cd3SKuo-Jung Su * (C) Copyright 2013 Faraday Technology 5c4775476SKuo-Jung Su * Dante Su <dantesu@faraday-tech.com> 6c4775476SKuo-Jung Su * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8c4775476SKuo-Jung Su */ 9c4775476SKuo-Jung Su 10c4775476SKuo-Jung Su #include <common.h> 11c4775476SKuo-Jung Su #include <command.h> 12c4775476SKuo-Jung Su #include <malloc.h> 13c4775476SKuo-Jung Su #include <net.h> 14c4775476SKuo-Jung Su #include <asm/errno.h> 15c4775476SKuo-Jung Su #include <asm/io.h> 16c4775476SKuo-Jung Su #include <asm/dma-mapping.h> 17c4775476SKuo-Jung Su 18c4775476SKuo-Jung Su #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) 19c4775476SKuo-Jung Su #include <miiphy.h> 20c4775476SKuo-Jung Su #endif 21c4775476SKuo-Jung Su 22c4775476SKuo-Jung Su #include "ftmac110.h" 23c4775476SKuo-Jung Su 24c4775476SKuo-Jung Su #define CFG_RXDES_NUM 8 25c4775476SKuo-Jung Su #define CFG_TXDES_NUM 2 26c4775476SKuo-Jung Su #define CFG_XBUF_SIZE 1536 27c4775476SKuo-Jung Su 28c4775476SKuo-Jung Su #define CFG_MDIORD_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */ 29c4775476SKuo-Jung Su #define CFG_MDIOWR_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */ 30c4775476SKuo-Jung Su #define CFG_LINKUP_TIMEOUT (CONFIG_SYS_HZ << 2) /* 4 sec */ 31c4775476SKuo-Jung Su 32c4775476SKuo-Jung Su /* 33c4775476SKuo-Jung Su * FTMAC110 DMA design issue 34c4775476SKuo-Jung Su * 35c4775476SKuo-Jung Su * Its DMA engine has a weird restriction that its Rx DMA engine 36c4775476SKuo-Jung Su * accepts only 16-bits aligned address, 32-bits aligned is not 37c4775476SKuo-Jung Su * acceptable. However this restriction does not apply to Tx DMA. 38c4775476SKuo-Jung Su * 39c4775476SKuo-Jung Su * Conclusion: 40c4775476SKuo-Jung Su * (1) Tx DMA Buffer Address: 41c4775476SKuo-Jung Su * 1 bytes aligned: Invalid 42c4775476SKuo-Jung Su * 2 bytes aligned: O.K 43c4775476SKuo-Jung Su * 4 bytes aligned: O.K (-> u-boot ZeroCopy is possible) 44c4775476SKuo-Jung Su * (2) Rx DMA Buffer Address: 45c4775476SKuo-Jung Su * 1 bytes aligned: Invalid 46c4775476SKuo-Jung Su * 2 bytes aligned: O.K 47c4775476SKuo-Jung Su * 4 bytes aligned: Invalid 48c4775476SKuo-Jung Su */ 49c4775476SKuo-Jung Su 50c4775476SKuo-Jung Su struct ftmac110_chip { 51c4775476SKuo-Jung Su void __iomem *regs; 52c4775476SKuo-Jung Su uint32_t imr; 53c4775476SKuo-Jung Su uint32_t maccr; 54c4775476SKuo-Jung Su uint32_t lnkup; 55c4775476SKuo-Jung Su uint32_t phy_addr; 56c4775476SKuo-Jung Su 57c4775476SKuo-Jung Su struct ftmac110_rxd *rxd; 58c4775476SKuo-Jung Su ulong rxd_dma; 59c4775476SKuo-Jung Su uint32_t rxd_idx; 60c4775476SKuo-Jung Su 61c4775476SKuo-Jung Su struct ftmac110_txd *txd; 62c4775476SKuo-Jung Su ulong txd_dma; 63c4775476SKuo-Jung Su uint32_t txd_idx; 64c4775476SKuo-Jung Su }; 65c4775476SKuo-Jung Su 66c4775476SKuo-Jung Su static int ftmac110_reset(struct eth_device *dev); 67c4775476SKuo-Jung Su 68c4775476SKuo-Jung Su static uint16_t mdio_read(struct eth_device *dev, 69c4775476SKuo-Jung Su uint8_t phyaddr, uint8_t phyreg) 70c4775476SKuo-Jung Su { 71c4775476SKuo-Jung Su struct ftmac110_chip *chip = dev->priv; 72c4775476SKuo-Jung Su struct ftmac110_regs __iomem *regs = chip->regs; 73c4775476SKuo-Jung Su uint32_t tmp, ts; 74c4775476SKuo-Jung Su uint16_t ret = 0xffff; 75c4775476SKuo-Jung Su 76c4775476SKuo-Jung Su tmp = PHYCR_READ 77c4775476SKuo-Jung Su | (phyaddr << PHYCR_ADDR_SHIFT) 78c4775476SKuo-Jung Su | (phyreg << PHYCR_REG_SHIFT); 79c4775476SKuo-Jung Su 80c4775476SKuo-Jung Su writel(tmp, ®s->phycr); 81c4775476SKuo-Jung Su 82c4775476SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) { 83c4775476SKuo-Jung Su tmp = readl(®s->phycr); 84c4775476SKuo-Jung Su if (tmp & PHYCR_READ) 85c4775476SKuo-Jung Su continue; 86c4775476SKuo-Jung Su break; 87c4775476SKuo-Jung Su } 88c4775476SKuo-Jung Su 89c4775476SKuo-Jung Su if (tmp & PHYCR_READ) 90c4775476SKuo-Jung Su printf("ftmac110: mdio read timeout\n"); 91c4775476SKuo-Jung Su else 92c4775476SKuo-Jung Su ret = (uint16_t)(tmp & 0xffff); 93c4775476SKuo-Jung Su 94c4775476SKuo-Jung Su return ret; 95c4775476SKuo-Jung Su } 96c4775476SKuo-Jung Su 97c4775476SKuo-Jung Su static void mdio_write(struct eth_device *dev, 98c4775476SKuo-Jung Su uint8_t phyaddr, uint8_t phyreg, uint16_t phydata) 99c4775476SKuo-Jung Su { 100c4775476SKuo-Jung Su struct ftmac110_chip *chip = dev->priv; 101c4775476SKuo-Jung Su struct ftmac110_regs __iomem *regs = chip->regs; 102c4775476SKuo-Jung Su uint32_t tmp, ts; 103c4775476SKuo-Jung Su 104c4775476SKuo-Jung Su tmp = PHYCR_WRITE 105c4775476SKuo-Jung Su | (phyaddr << PHYCR_ADDR_SHIFT) 106c4775476SKuo-Jung Su | (phyreg << PHYCR_REG_SHIFT); 107c4775476SKuo-Jung Su 108c4775476SKuo-Jung Su writel(phydata, ®s->phydr); 109c4775476SKuo-Jung Su writel(tmp, ®s->phycr); 110c4775476SKuo-Jung Su 111c4775476SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) { 112c4775476SKuo-Jung Su if (readl(®s->phycr) & PHYCR_WRITE) 113c4775476SKuo-Jung Su continue; 114c4775476SKuo-Jung Su break; 115c4775476SKuo-Jung Su } 116c4775476SKuo-Jung Su 117c4775476SKuo-Jung Su if (readl(®s->phycr) & PHYCR_WRITE) 118c4775476SKuo-Jung Su printf("ftmac110: mdio write timeout\n"); 119c4775476SKuo-Jung Su } 120c4775476SKuo-Jung Su 121c4775476SKuo-Jung Su static uint32_t ftmac110_phyqry(struct eth_device *dev) 122c4775476SKuo-Jung Su { 123c4775476SKuo-Jung Su ulong ts; 124c4775476SKuo-Jung Su uint32_t maccr; 125c4775476SKuo-Jung Su uint16_t pa, tmp, bmsr, bmcr; 126c4775476SKuo-Jung Su struct ftmac110_chip *chip = dev->priv; 127c4775476SKuo-Jung Su 128c4775476SKuo-Jung Su /* Default = 100Mbps Full */ 129c4775476SKuo-Jung Su maccr = MACCR_100M | MACCR_FD; 130c4775476SKuo-Jung Su 131c4775476SKuo-Jung Su /* 1. find the phy device */ 132c4775476SKuo-Jung Su for (pa = 0; pa < 32; ++pa) { 133c4775476SKuo-Jung Su tmp = mdio_read(dev, pa, MII_PHYSID1); 134c4775476SKuo-Jung Su if (tmp == 0xFFFF || tmp == 0x0000) 135c4775476SKuo-Jung Su continue; 136c4775476SKuo-Jung Su chip->phy_addr = pa; 137c4775476SKuo-Jung Su break; 138c4775476SKuo-Jung Su } 139c4775476SKuo-Jung Su if (pa >= 32) { 140c4775476SKuo-Jung Su puts("ftmac110: phy device not found!\n"); 141c4775476SKuo-Jung Su goto exit; 142c4775476SKuo-Jung Su } 143c4775476SKuo-Jung Su 144c4775476SKuo-Jung Su /* 2. wait until link-up & auto-negotiation complete */ 145c4775476SKuo-Jung Su chip->lnkup = 0; 146c4775476SKuo-Jung Su bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR); 147c4775476SKuo-Jung Su ts = get_timer(0); 148c4775476SKuo-Jung Su do { 149c4775476SKuo-Jung Su bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR); 150c4775476SKuo-Jung Su chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0; 151c4775476SKuo-Jung Su if (!chip->lnkup) 152c4775476SKuo-Jung Su continue; 153c4775476SKuo-Jung Su if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE)) 154c4775476SKuo-Jung Su break; 155c4775476SKuo-Jung Su } while (get_timer(ts) < CFG_LINKUP_TIMEOUT); 156c4775476SKuo-Jung Su if (!chip->lnkup) { 157c4775476SKuo-Jung Su puts("ftmac110: link down\n"); 158c4775476SKuo-Jung Su goto exit; 159c4775476SKuo-Jung Su } 160c4775476SKuo-Jung Su if (!(bmcr & BMCR_ANENABLE)) 161c4775476SKuo-Jung Su puts("ftmac110: auto negotiation disabled\n"); 162c4775476SKuo-Jung Su else if (!(bmsr & BMSR_ANEGCOMPLETE)) 163c4775476SKuo-Jung Su puts("ftmac110: auto negotiation timeout\n"); 164c4775476SKuo-Jung Su 165c4775476SKuo-Jung Su /* 3. derive MACCR */ 166c4775476SKuo-Jung Su if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) { 167c4775476SKuo-Jung Su tmp = mdio_read(dev, chip->phy_addr, MII_ADVERTISE); 168c4775476SKuo-Jung Su tmp &= mdio_read(dev, chip->phy_addr, MII_LPA); 169c4775476SKuo-Jung Su if (tmp & LPA_100FULL) /* 100Mbps full-duplex */ 170c4775476SKuo-Jung Su maccr = MACCR_100M | MACCR_FD; 171c4775476SKuo-Jung Su else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */ 172c4775476SKuo-Jung Su maccr = MACCR_100M; 173c4775476SKuo-Jung Su else if (tmp & LPA_10FULL) /* 10Mbps full-duplex */ 174c4775476SKuo-Jung Su maccr = MACCR_FD; 175c4775476SKuo-Jung Su else if (tmp & LPA_10HALF) /* 10Mbps half-duplex */ 176c4775476SKuo-Jung Su maccr = 0; 177c4775476SKuo-Jung Su } else { 178c4775476SKuo-Jung Su if (bmcr & BMCR_SPEED100) 179c4775476SKuo-Jung Su maccr = MACCR_100M; 180c4775476SKuo-Jung Su else 181c4775476SKuo-Jung Su maccr = 0; 182c4775476SKuo-Jung Su if (bmcr & BMCR_FULLDPLX) 183c4775476SKuo-Jung Su maccr |= MACCR_FD; 184c4775476SKuo-Jung Su } 185c4775476SKuo-Jung Su 186c4775476SKuo-Jung Su exit: 187c4775476SKuo-Jung Su printf("ftmac110: %d Mbps, %s\n", 188c4775476SKuo-Jung Su (maccr & MACCR_100M) ? 100 : 10, 189c4775476SKuo-Jung Su (maccr & MACCR_FD) ? "Full" : "half"); 190c4775476SKuo-Jung Su return maccr; 191c4775476SKuo-Jung Su } 192c4775476SKuo-Jung Su 193c4775476SKuo-Jung Su static int ftmac110_reset(struct eth_device *dev) 194c4775476SKuo-Jung Su { 195c4775476SKuo-Jung Su uint8_t *a; 196c4775476SKuo-Jung Su uint32_t i, maccr; 197c4775476SKuo-Jung Su struct ftmac110_chip *chip = dev->priv; 198c4775476SKuo-Jung Su struct ftmac110_regs __iomem *regs = chip->regs; 199c4775476SKuo-Jung Su 200c4775476SKuo-Jung Su /* 1. MAC reset */ 201c4775476SKuo-Jung Su writel(MACCR_RESET, ®s->maccr); 202c4775476SKuo-Jung Su for (i = get_timer(0); get_timer(i) < 1000; ) { 203c4775476SKuo-Jung Su if (readl(®s->maccr) & MACCR_RESET) 204c4775476SKuo-Jung Su continue; 205c4775476SKuo-Jung Su break; 206c4775476SKuo-Jung Su } 207c4775476SKuo-Jung Su if (readl(®s->maccr) & MACCR_RESET) { 208c4775476SKuo-Jung Su printf("ftmac110: reset failed\n"); 209c4775476SKuo-Jung Su return -ENXIO; 210c4775476SKuo-Jung Su } 211c4775476SKuo-Jung Su 212c4775476SKuo-Jung Su /* 1-1. Init tx ring */ 213c4775476SKuo-Jung Su for (i = 0; i < CFG_TXDES_NUM; ++i) { 214c4775476SKuo-Jung Su /* owned by SW */ 215c4775476SKuo-Jung Su chip->txd[i].ct[0] = 0; 216c4775476SKuo-Jung Su } 217c4775476SKuo-Jung Su chip->txd_idx = 0; 218c4775476SKuo-Jung Su 219c4775476SKuo-Jung Su /* 1-2. Init rx ring */ 220c4775476SKuo-Jung Su for (i = 0; i < CFG_RXDES_NUM; ++i) { 221c4775476SKuo-Jung Su /* owned by HW */ 222c4775476SKuo-Jung Su chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER); 223c4775476SKuo-Jung Su } 224c4775476SKuo-Jung Su chip->rxd_idx = 0; 225c4775476SKuo-Jung Su 226c4775476SKuo-Jung Su /* 2. PHY status query */ 227c4775476SKuo-Jung Su maccr = ftmac110_phyqry(dev); 228c4775476SKuo-Jung Su 229c4775476SKuo-Jung Su /* 3. Fix up the MACCR value */ 230c4775476SKuo-Jung Su chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT 231c4775476SKuo-Jung Su | MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN; 232c4775476SKuo-Jung Su 233c4775476SKuo-Jung Su /* 4. MAC address setup */ 234c4775476SKuo-Jung Su a = dev->enetaddr; 235c4775476SKuo-Jung Su writel(a[1] | (a[0] << 8), ®s->mac[0]); 236c4775476SKuo-Jung Su writel(a[5] | (a[4] << 8) | (a[3] << 16) 237c4775476SKuo-Jung Su | (a[2] << 24), ®s->mac[1]); 238c4775476SKuo-Jung Su 239c4775476SKuo-Jung Su /* 5. MAC registers setup */ 240c4775476SKuo-Jung Su writel(chip->rxd_dma, ®s->rxba); 241c4775476SKuo-Jung Su writel(chip->txd_dma, ®s->txba); 242c4775476SKuo-Jung Su /* interrupt at each tx/rx */ 243c4775476SKuo-Jung Su writel(ITC_DEFAULT, ®s->itc); 244c4775476SKuo-Jung Su /* no tx pool, rx poll = 1 normal cycle */ 245c4775476SKuo-Jung Su writel(APTC_DEFAULT, ®s->aptc); 246c4775476SKuo-Jung Su /* rx threshold = [6/8 fifo, 2/8 fifo] */ 247c4775476SKuo-Jung Su writel(DBLAC_DEFAULT, ®s->dblac); 248c4775476SKuo-Jung Su /* disable & clear all interrupt status */ 249c4775476SKuo-Jung Su chip->imr = 0; 250c4775476SKuo-Jung Su writel(ISR_ALL, ®s->isr); 251c4775476SKuo-Jung Su writel(chip->imr, ®s->imr); 252c4775476SKuo-Jung Su /* enable mac */ 253c4775476SKuo-Jung Su writel(chip->maccr, ®s->maccr); 254c4775476SKuo-Jung Su 255c4775476SKuo-Jung Su return 0; 256c4775476SKuo-Jung Su } 257c4775476SKuo-Jung Su 258c4775476SKuo-Jung Su static int ftmac110_probe(struct eth_device *dev, bd_t *bis) 259c4775476SKuo-Jung Su { 260c4775476SKuo-Jung Su debug("ftmac110: probe\n"); 261c4775476SKuo-Jung Su 262c4775476SKuo-Jung Su if (ftmac110_reset(dev)) 263c4775476SKuo-Jung Su return -1; 264c4775476SKuo-Jung Su 265c4775476SKuo-Jung Su return 0; 266c4775476SKuo-Jung Su } 267c4775476SKuo-Jung Su 268c4775476SKuo-Jung Su static void ftmac110_halt(struct eth_device *dev) 269c4775476SKuo-Jung Su { 270c4775476SKuo-Jung Su struct ftmac110_chip *chip = dev->priv; 271c4775476SKuo-Jung Su struct ftmac110_regs __iomem *regs = chip->regs; 272c4775476SKuo-Jung Su 273c4775476SKuo-Jung Su writel(0, ®s->imr); 274c4775476SKuo-Jung Su writel(0, ®s->maccr); 275c4775476SKuo-Jung Su 276c4775476SKuo-Jung Su debug("ftmac110: halt\n"); 277c4775476SKuo-Jung Su } 278c4775476SKuo-Jung Su 279c4775476SKuo-Jung Su static int ftmac110_send(struct eth_device *dev, void *pkt, int len) 280c4775476SKuo-Jung Su { 281c4775476SKuo-Jung Su struct ftmac110_chip *chip = dev->priv; 282c4775476SKuo-Jung Su struct ftmac110_regs __iomem *regs = chip->regs; 283c4775476SKuo-Jung Su struct ftmac110_txd *des; 284c4775476SKuo-Jung Su 285c4775476SKuo-Jung Su if (!chip->lnkup) 286c4775476SKuo-Jung Su return 0; 287c4775476SKuo-Jung Su 288c4775476SKuo-Jung Su if (len <= 0 || len > CFG_XBUF_SIZE) { 289c4775476SKuo-Jung Su printf("ftmac110: bad tx pkt len(%d)\n", len); 290c4775476SKuo-Jung Su return 0; 291c4775476SKuo-Jung Su } 292c4775476SKuo-Jung Su 293c4775476SKuo-Jung Su len = max(60, len); 294c4775476SKuo-Jung Su 295c4775476SKuo-Jung Su des = &chip->txd[chip->txd_idx]; 296c4775476SKuo-Jung Su if (le32_to_cpu(des->ct[0]) & FTMAC110_TXCT0_OWNER) { 297c4775476SKuo-Jung Su /* kick-off Tx DMA */ 298c4775476SKuo-Jung Su writel(0xffffffff, ®s->txpd); 299c4775476SKuo-Jung Su printf("ftmac110: out of txd\n"); 300c4775476SKuo-Jung Su return 0; 301c4775476SKuo-Jung Su } 302c4775476SKuo-Jung Su 303c4775476SKuo-Jung Su memcpy(des->vbuf, (void *)pkt, len); 304c4775476SKuo-Jung Su dma_map_single(des->vbuf, len, DMA_TO_DEVICE); 305c4775476SKuo-Jung Su 306c4775476SKuo-Jung Su /* update len, fts and lts */ 307c4775476SKuo-Jung Su des->ct[1] &= cpu_to_le32(FTMAC110_TXCT1_END); 308c4775476SKuo-Jung Su des->ct[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len) 309c4775476SKuo-Jung Su | FTMAC110_TXCT1_FTS | FTMAC110_TXCT1_LTS); 310c4775476SKuo-Jung Su 311c4775476SKuo-Jung Su /* set owner bit and clear others */ 312c4775476SKuo-Jung Su des->ct[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER); 313c4775476SKuo-Jung Su 314c4775476SKuo-Jung Su /* kick-off Tx DMA */ 315c4775476SKuo-Jung Su writel(0xffffffff, ®s->txpd); 316c4775476SKuo-Jung Su 317c4775476SKuo-Jung Su chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM; 318c4775476SKuo-Jung Su 319c4775476SKuo-Jung Su return len; 320c4775476SKuo-Jung Su } 321c4775476SKuo-Jung Su 322c4775476SKuo-Jung Su static int ftmac110_recv(struct eth_device *dev) 323c4775476SKuo-Jung Su { 324c4775476SKuo-Jung Su struct ftmac110_chip *chip = dev->priv; 325c4775476SKuo-Jung Su struct ftmac110_rxd *des; 326c4775476SKuo-Jung Su uint32_t ct0, len, rlen = 0; 327c4775476SKuo-Jung Su uint8_t *buf; 328c4775476SKuo-Jung Su 329c4775476SKuo-Jung Su if (!chip->lnkup) 330c4775476SKuo-Jung Su return 0; 331c4775476SKuo-Jung Su 332c4775476SKuo-Jung Su do { 333c4775476SKuo-Jung Su des = &chip->rxd[chip->rxd_idx]; 334c4775476SKuo-Jung Su ct0 = le32_to_cpu(des->ct[0]); 335c4775476SKuo-Jung Su if (ct0 & FTMAC110_RXCT0_OWNER) 336c4775476SKuo-Jung Su break; 337c4775476SKuo-Jung Su 338c4775476SKuo-Jung Su len = FTMAC110_RXCT0_LEN(ct0); 339c4775476SKuo-Jung Su buf = des->vbuf; 340c4775476SKuo-Jung Su 341c4775476SKuo-Jung Su if (ct0 & FTMAC110_RXCT0_ERRMASK) { 342c4775476SKuo-Jung Su printf("ftmac110: rx error\n"); 343c4775476SKuo-Jung Su } else { 344c4775476SKuo-Jung Su dma_map_single(buf, len, DMA_FROM_DEVICE); 345c4775476SKuo-Jung Su NetReceive(buf, len); 346c4775476SKuo-Jung Su rlen += len; 347c4775476SKuo-Jung Su } 348c4775476SKuo-Jung Su 349c4775476SKuo-Jung Su /* owned by hardware */ 350c4775476SKuo-Jung Su des->ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER); 351c4775476SKuo-Jung Su 352c4775476SKuo-Jung Su chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM; 353c4775476SKuo-Jung Su } while (0); 354c4775476SKuo-Jung Su 355c4775476SKuo-Jung Su return rlen; 356c4775476SKuo-Jung Su } 357c4775476SKuo-Jung Su 358c4775476SKuo-Jung Su #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) 359c4775476SKuo-Jung Su 360c4775476SKuo-Jung Su static int ftmac110_mdio_read( 361c4775476SKuo-Jung Su const char *devname, uint8_t addr, uint8_t reg, uint16_t *value) 362c4775476SKuo-Jung Su { 363c4775476SKuo-Jung Su int ret = 0; 364c4775476SKuo-Jung Su struct eth_device *dev; 365c4775476SKuo-Jung Su 366c4775476SKuo-Jung Su dev = eth_get_dev_by_name(devname); 367c4775476SKuo-Jung Su if (dev == NULL) { 368c4775476SKuo-Jung Su printf("%s: no such device\n", devname); 369c4775476SKuo-Jung Su ret = -1; 370c4775476SKuo-Jung Su } else { 371c4775476SKuo-Jung Su *value = mdio_read(dev, addr, reg); 372c4775476SKuo-Jung Su } 373c4775476SKuo-Jung Su 374c4775476SKuo-Jung Su return ret; 375c4775476SKuo-Jung Su } 376c4775476SKuo-Jung Su 377c4775476SKuo-Jung Su static int ftmac110_mdio_write( 378c4775476SKuo-Jung Su const char *devname, uint8_t addr, uint8_t reg, uint16_t value) 379c4775476SKuo-Jung Su { 380c4775476SKuo-Jung Su int ret = 0; 381c4775476SKuo-Jung Su struct eth_device *dev; 382c4775476SKuo-Jung Su 383c4775476SKuo-Jung Su dev = eth_get_dev_by_name(devname); 384c4775476SKuo-Jung Su if (dev == NULL) { 385c4775476SKuo-Jung Su printf("%s: no such device\n", devname); 386c4775476SKuo-Jung Su ret = -1; 387c4775476SKuo-Jung Su } else { 388c4775476SKuo-Jung Su mdio_write(dev, addr, reg, value); 389c4775476SKuo-Jung Su } 390c4775476SKuo-Jung Su 391c4775476SKuo-Jung Su return ret; 392c4775476SKuo-Jung Su } 393c4775476SKuo-Jung Su 394c4775476SKuo-Jung Su #endif /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */ 395c4775476SKuo-Jung Su 396c4775476SKuo-Jung Su int ftmac110_initialize(bd_t *bis) 397c4775476SKuo-Jung Su { 398c4775476SKuo-Jung Su int i, card_nr = 0; 399c4775476SKuo-Jung Su struct eth_device *dev; 400c4775476SKuo-Jung Su struct ftmac110_chip *chip; 401c4775476SKuo-Jung Su 402c4775476SKuo-Jung Su dev = malloc(sizeof(*dev) + sizeof(*chip)); 403c4775476SKuo-Jung Su if (dev == NULL) { 404c4775476SKuo-Jung Su panic("ftmac110: out of memory 1\n"); 405c4775476SKuo-Jung Su return -1; 406c4775476SKuo-Jung Su } 407c4775476SKuo-Jung Su chip = (struct ftmac110_chip *)(dev + 1); 408c4775476SKuo-Jung Su memset(dev, 0, sizeof(*dev) + sizeof(*chip)); 409c4775476SKuo-Jung Su 410c4775476SKuo-Jung Su sprintf(dev->name, "FTMAC110#%d", card_nr); 411c4775476SKuo-Jung Su 412c4775476SKuo-Jung Su dev->iobase = CONFIG_FTMAC110_BASE; 413c4775476SKuo-Jung Su chip->regs = (void __iomem *)dev->iobase; 414c4775476SKuo-Jung Su dev->priv = chip; 415c4775476SKuo-Jung Su dev->init = ftmac110_probe; 416c4775476SKuo-Jung Su dev->halt = ftmac110_halt; 417c4775476SKuo-Jung Su dev->send = ftmac110_send; 418c4775476SKuo-Jung Su dev->recv = ftmac110_recv; 419c4775476SKuo-Jung Su 420c4775476SKuo-Jung Su if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr)) 421c4775476SKuo-Jung Su eth_random_enetaddr(dev->enetaddr); 422c4775476SKuo-Jung Su 423c4775476SKuo-Jung Su /* allocate tx descriptors (it must be 16 bytes aligned) */ 424c4775476SKuo-Jung Su chip->txd = dma_alloc_coherent( 425c4775476SKuo-Jung Su sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma); 426c4775476SKuo-Jung Su if (!chip->txd) 427c4775476SKuo-Jung Su panic("ftmac110: out of memory 3\n"); 428c4775476SKuo-Jung Su memset(chip->txd, 0, 429c4775476SKuo-Jung Su sizeof(struct ftmac110_txd) * CFG_TXDES_NUM); 430c4775476SKuo-Jung Su for (i = 0; i < CFG_TXDES_NUM; ++i) { 431c4775476SKuo-Jung Su void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE); 432c4775476SKuo-Jung Su if (!va) 433c4775476SKuo-Jung Su panic("ftmac110: out of memory 4\n"); 434c4775476SKuo-Jung Su chip->txd[i].vbuf = va; 435c4775476SKuo-Jung Su chip->txd[i].buf = cpu_to_le32(virt_to_phys(va)); 436c4775476SKuo-Jung Su chip->txd[i].ct[1] = 0; 437c4775476SKuo-Jung Su chip->txd[i].ct[0] = 0; /* owned by SW */ 438c4775476SKuo-Jung Su } 439c4775476SKuo-Jung Su chip->txd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_TXCT1_END); 440c4775476SKuo-Jung Su chip->txd_idx = 0; 441c4775476SKuo-Jung Su 442c4775476SKuo-Jung Su /* allocate rx descriptors (it must be 16 bytes aligned) */ 443c4775476SKuo-Jung Su chip->rxd = dma_alloc_coherent( 444c4775476SKuo-Jung Su sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma); 445c4775476SKuo-Jung Su if (!chip->rxd) 446c4775476SKuo-Jung Su panic("ftmac110: out of memory 4\n"); 447c4775476SKuo-Jung Su memset((void *)chip->rxd, 0, 448c4775476SKuo-Jung Su sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM); 449c4775476SKuo-Jung Su for (i = 0; i < CFG_RXDES_NUM; ++i) { 450c4775476SKuo-Jung Su void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2); 451c4775476SKuo-Jung Su if (!va) 452c4775476SKuo-Jung Su panic("ftmac110: out of memory 5\n"); 453c4775476SKuo-Jung Su /* it needs to be exactly 2 bytes aligned */ 454c4775476SKuo-Jung Su va = ((uint8_t *)va + 2); 455c4775476SKuo-Jung Su chip->rxd[i].vbuf = va; 456c4775476SKuo-Jung Su chip->rxd[i].buf = cpu_to_le32(virt_to_phys(va)); 457c4775476SKuo-Jung Su chip->rxd[i].ct[1] = cpu_to_le32(CFG_XBUF_SIZE); 458c4775476SKuo-Jung Su chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER); 459c4775476SKuo-Jung Su } 460c4775476SKuo-Jung Su chip->rxd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_RXCT1_END); 461c4775476SKuo-Jung Su chip->rxd_idx = 0; 462c4775476SKuo-Jung Su 463c4775476SKuo-Jung Su eth_register(dev); 464c4775476SKuo-Jung Su 465c4775476SKuo-Jung Su #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) 466c4775476SKuo-Jung Su miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write); 467c4775476SKuo-Jung Su #endif 468c4775476SKuo-Jung Su 469c4775476SKuo-Jung Su card_nr++; 470c4775476SKuo-Jung Su 471c4775476SKuo-Jung Su return card_nr; 472c4775476SKuo-Jung Su } 473