162cbc408SIlya Yanok /* 262cbc408SIlya Yanok * Dave Ethernet Controller driver 362cbc408SIlya Yanok * 462cbc408SIlya Yanok * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> 562cbc408SIlya Yanok * 662cbc408SIlya Yanok * This program is free software; you can redistribute it and/or modify 762cbc408SIlya Yanok * it under the terms of the GNU General Public License version 2 as 862cbc408SIlya Yanok * published by the Free Software Foundation. 962cbc408SIlya Yanok */ 1062cbc408SIlya Yanok 1162cbc408SIlya Yanok #include <common.h> 1262cbc408SIlya Yanok 1362cbc408SIlya Yanok #ifndef CONFIG_DNET_AUTONEG_TIMEOUT 1462cbc408SIlya Yanok #define CONFIG_DNET_AUTONEG_TIMEOUT 5000000 /* default value */ 1562cbc408SIlya Yanok #endif 1662cbc408SIlya Yanok 1762cbc408SIlya Yanok #include <net.h> 1862cbc408SIlya Yanok #include <malloc.h> 1962cbc408SIlya Yanok #include <linux/mii.h> 2062cbc408SIlya Yanok 2162cbc408SIlya Yanok #include <miiphy.h> 2262cbc408SIlya Yanok #include <asm/io.h> 23d780e74fSAnatolij Gustschin #include <asm/unaligned.h> 2462cbc408SIlya Yanok 2562cbc408SIlya Yanok #include "dnet.h" 2662cbc408SIlya Yanok 2762cbc408SIlya Yanok struct dnet_device { 2862cbc408SIlya Yanok struct dnet_registers *regs; 2962cbc408SIlya Yanok const struct device *dev; 3062cbc408SIlya Yanok struct eth_device netdev; 3162cbc408SIlya Yanok unsigned short phy_addr; 3262cbc408SIlya Yanok }; 3362cbc408SIlya Yanok 3462cbc408SIlya Yanok /* get struct dnet_device from given struct netdev */ 3562cbc408SIlya Yanok #define to_dnet(_nd) container_of(_nd, struct dnet_device, netdev) 3662cbc408SIlya Yanok 3762cbc408SIlya Yanok /* function for reading internal MAC register */ 3862cbc408SIlya Yanok u16 dnet_readw_mac(struct dnet_device *dnet, u16 reg) 3962cbc408SIlya Yanok { 4062cbc408SIlya Yanok u16 data_read; 4162cbc408SIlya Yanok 4262cbc408SIlya Yanok /* issue a read */ 4362cbc408SIlya Yanok writel(reg, &dnet->regs->MACREG_ADDR); 4462cbc408SIlya Yanok 4562cbc408SIlya Yanok /* since a read/write op to the MAC is very slow, 4662cbc408SIlya Yanok * we must wait before reading the data */ 4762cbc408SIlya Yanok udelay(1); 4862cbc408SIlya Yanok 4962cbc408SIlya Yanok /* read data read from the MAC register */ 5062cbc408SIlya Yanok data_read = readl(&dnet->regs->MACREG_DATA); 5162cbc408SIlya Yanok 5262cbc408SIlya Yanok /* all done */ 5362cbc408SIlya Yanok return data_read; 5462cbc408SIlya Yanok } 5562cbc408SIlya Yanok 5662cbc408SIlya Yanok /* function for writing internal MAC register */ 5762cbc408SIlya Yanok void dnet_writew_mac(struct dnet_device *dnet, u16 reg, u16 val) 5862cbc408SIlya Yanok { 5962cbc408SIlya Yanok /* load data to write */ 6062cbc408SIlya Yanok writel(val, &dnet->regs->MACREG_DATA); 6162cbc408SIlya Yanok 6262cbc408SIlya Yanok /* issue a write */ 6362cbc408SIlya Yanok writel(reg | DNET_INTERNAL_WRITE, &dnet->regs->MACREG_ADDR); 6462cbc408SIlya Yanok 6562cbc408SIlya Yanok /* since a read/write op to the MAC is very slow, 6662cbc408SIlya Yanok * we must wait before exiting */ 6762cbc408SIlya Yanok udelay(1); 6862cbc408SIlya Yanok } 6962cbc408SIlya Yanok 7062cbc408SIlya Yanok static void dnet_mdio_write(struct dnet_device *dnet, u8 reg, u16 value) 7162cbc408SIlya Yanok { 7262cbc408SIlya Yanok u16 tmp; 7362cbc408SIlya Yanok 7462cbc408SIlya Yanok debug(DRIVERNAME "dnet_mdio_write %02x:%02x <- %04x\n", 7562cbc408SIlya Yanok dnet->phy_addr, reg, value); 7662cbc408SIlya Yanok 7762cbc408SIlya Yanok while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 7862cbc408SIlya Yanok DNET_INTERNAL_GMII_MNG_CMD_FIN)) 7962cbc408SIlya Yanok ; 8062cbc408SIlya Yanok 8162cbc408SIlya Yanok /* prepare for a write operation */ 8262cbc408SIlya Yanok tmp = (1 << 13); 8362cbc408SIlya Yanok 8462cbc408SIlya Yanok /* only 5 bits allowed for register offset */ 8562cbc408SIlya Yanok reg &= 0x1f; 8662cbc408SIlya Yanok 8762cbc408SIlya Yanok /* prepare reg_value for a write */ 8862cbc408SIlya Yanok tmp |= (dnet->phy_addr << 8); 8962cbc408SIlya Yanok tmp |= reg; 9062cbc408SIlya Yanok 9162cbc408SIlya Yanok /* write data to write first */ 9262cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG, value); 9362cbc408SIlya Yanok 9462cbc408SIlya Yanok /* write control word */ 9562cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp); 9662cbc408SIlya Yanok 9762cbc408SIlya Yanok while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 9862cbc408SIlya Yanok DNET_INTERNAL_GMII_MNG_CMD_FIN)) 9962cbc408SIlya Yanok ; 10062cbc408SIlya Yanok } 10162cbc408SIlya Yanok 10262cbc408SIlya Yanok static u16 dnet_mdio_read(struct dnet_device *dnet, u8 reg) 10362cbc408SIlya Yanok { 10462cbc408SIlya Yanok u16 value; 10562cbc408SIlya Yanok 10662cbc408SIlya Yanok while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 10762cbc408SIlya Yanok DNET_INTERNAL_GMII_MNG_CMD_FIN)) 10862cbc408SIlya Yanok ; 10962cbc408SIlya Yanok 11062cbc408SIlya Yanok /* only 5 bits allowed for register offset*/ 11162cbc408SIlya Yanok reg &= 0x1f; 11262cbc408SIlya Yanok 11362cbc408SIlya Yanok /* prepare reg_value for a read */ 11462cbc408SIlya Yanok value = (dnet->phy_addr << 8); 11562cbc408SIlya Yanok value |= reg; 11662cbc408SIlya Yanok 11762cbc408SIlya Yanok /* write control word */ 11862cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, value); 11962cbc408SIlya Yanok 12062cbc408SIlya Yanok /* wait for end of transfer */ 12162cbc408SIlya Yanok while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 12262cbc408SIlya Yanok DNET_INTERNAL_GMII_MNG_CMD_FIN)) 12362cbc408SIlya Yanok ; 12462cbc408SIlya Yanok 12562cbc408SIlya Yanok value = dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG); 12662cbc408SIlya Yanok 12762cbc408SIlya Yanok debug(DRIVERNAME "dnet_mdio_read %02x:%02x <- %04x\n", 12862cbc408SIlya Yanok dnet->phy_addr, reg, value); 12962cbc408SIlya Yanok 13062cbc408SIlya Yanok return value; 13162cbc408SIlya Yanok } 13262cbc408SIlya Yanok 133*6e758ef5SJoe Hershberger static int dnet_send(struct eth_device *netdev, void *packet, int length) 13462cbc408SIlya Yanok { 13562cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 136d780e74fSAnatolij Gustschin int i, wrsz; 13762cbc408SIlya Yanok unsigned int *bufp; 13862cbc408SIlya Yanok unsigned int tx_cmd; 13962cbc408SIlya Yanok 14062cbc408SIlya Yanok debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length); 14162cbc408SIlya Yanok 14262cbc408SIlya Yanok bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC); 14362cbc408SIlya Yanok wrsz = (u32)length + 3; 14462cbc408SIlya Yanok wrsz += ((u32)packet) & 0x3; 14562cbc408SIlya Yanok wrsz >>= 2; 14662cbc408SIlya Yanok tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length; 14762cbc408SIlya Yanok 14862cbc408SIlya Yanok /* check if there is enough room for the current frame */ 14962cbc408SIlya Yanok if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) { 15062cbc408SIlya Yanok for (i = 0; i < wrsz; i++) 15162cbc408SIlya Yanok writel(*bufp++, &dnet->regs->TX_DATA_FIFO); 15262cbc408SIlya Yanok /* 15362cbc408SIlya Yanok * inform MAC that a packet's written and ready 15462cbc408SIlya Yanok * to be shipped out 15562cbc408SIlya Yanok */ 15662cbc408SIlya Yanok writel(tx_cmd, &dnet->regs->TX_LEN_FIFO); 15762cbc408SIlya Yanok } else { 15862cbc408SIlya Yanok printf(DRIVERNAME "No free space (actual %d, required %d " 15962cbc408SIlya Yanok "(words))\n", DNET_FIFO_SIZE - 16062cbc408SIlya Yanok readl(&dnet->regs->TX_FIFO_WCNT), wrsz); 16162cbc408SIlya Yanok } 16262cbc408SIlya Yanok 16362cbc408SIlya Yanok /* No one cares anyway */ 16462cbc408SIlya Yanok return 0; 16562cbc408SIlya Yanok } 16662cbc408SIlya Yanok 16762cbc408SIlya Yanok 16862cbc408SIlya Yanok static int dnet_recv(struct eth_device *netdev) 16962cbc408SIlya Yanok { 17062cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 17162cbc408SIlya Yanok unsigned int *data_ptr; 17262cbc408SIlya Yanok int pkt_len, poll, i; 17362cbc408SIlya Yanok u32 cmd_word; 17462cbc408SIlya Yanok 17562cbc408SIlya Yanok debug("Waiting for pkt (polling)\n"); 17662cbc408SIlya Yanok poll = 50; 17762cbc408SIlya Yanok while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) { 17862cbc408SIlya Yanok udelay(10); /* wait 10 usec */ 17962cbc408SIlya Yanok if (--poll == 0) 18062cbc408SIlya Yanok return 0; /* no pkt available */ 18162cbc408SIlya Yanok } 18262cbc408SIlya Yanok 18362cbc408SIlya Yanok cmd_word = readl(&dnet->regs->RX_LEN_FIFO); 18462cbc408SIlya Yanok pkt_len = cmd_word & 0xFFFF; 18562cbc408SIlya Yanok 18662cbc408SIlya Yanok debug("Got pkt with size %d bytes\n", pkt_len); 18762cbc408SIlya Yanok 18862cbc408SIlya Yanok if (cmd_word & 0xDF180000) 18962cbc408SIlya Yanok printf("%s packet receive error %x\n", __func__, cmd_word); 19062cbc408SIlya Yanok 19162cbc408SIlya Yanok data_ptr = (unsigned int *) NetRxPackets[0]; 19262cbc408SIlya Yanok 19362cbc408SIlya Yanok for (i = 0; i < (pkt_len + 3) >> 2; i++) 19462cbc408SIlya Yanok *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO); 19562cbc408SIlya Yanok 19662cbc408SIlya Yanok NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */ 19762cbc408SIlya Yanok 19862cbc408SIlya Yanok return 0; 19962cbc408SIlya Yanok } 20062cbc408SIlya Yanok 20162cbc408SIlya Yanok static void dnet_set_hwaddr(struct eth_device *netdev) 20262cbc408SIlya Yanok { 20362cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 20462cbc408SIlya Yanok u16 tmp; 20562cbc408SIlya Yanok 206d780e74fSAnatolij Gustschin tmp = get_unaligned_be16(netdev->enetaddr); 20762cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); 208d780e74fSAnatolij Gustschin tmp = get_unaligned_be16(&netdev->enetaddr[2]); 20962cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); 210d780e74fSAnatolij Gustschin tmp = get_unaligned_be16(&netdev->enetaddr[4]); 21162cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); 21262cbc408SIlya Yanok } 21362cbc408SIlya Yanok 21462cbc408SIlya Yanok static void dnet_phy_reset(struct dnet_device *dnet) 21562cbc408SIlya Yanok { 21662cbc408SIlya Yanok struct eth_device *netdev = &dnet->netdev; 21762cbc408SIlya Yanok int i; 21862cbc408SIlya Yanok u16 status, adv; 21962cbc408SIlya Yanok 22062cbc408SIlya Yanok adv = ADVERTISE_CSMA | ADVERTISE_ALL; 22162cbc408SIlya Yanok dnet_mdio_write(dnet, MII_ADVERTISE, adv); 22262cbc408SIlya Yanok printf("%s: Starting autonegotiation...\n", netdev->name); 22362cbc408SIlya Yanok dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE 22462cbc408SIlya Yanok | BMCR_ANRESTART)); 22562cbc408SIlya Yanok 22662cbc408SIlya Yanok for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 22762cbc408SIlya Yanok status = dnet_mdio_read(dnet, MII_BMSR); 22862cbc408SIlya Yanok if (status & BMSR_ANEGCOMPLETE) 22962cbc408SIlya Yanok break; 23062cbc408SIlya Yanok udelay(100); 23162cbc408SIlya Yanok } 23262cbc408SIlya Yanok 23362cbc408SIlya Yanok if (status & BMSR_ANEGCOMPLETE) 23462cbc408SIlya Yanok printf("%s: Autonegotiation complete\n", netdev->name); 23562cbc408SIlya Yanok else 23662cbc408SIlya Yanok printf("%s: Autonegotiation timed out (status=0x%04x)\n", 23762cbc408SIlya Yanok netdev->name, status); 23862cbc408SIlya Yanok } 23962cbc408SIlya Yanok 24062cbc408SIlya Yanok static int dnet_phy_init(struct dnet_device *dnet) 24162cbc408SIlya Yanok { 24262cbc408SIlya Yanok struct eth_device *netdev = &dnet->netdev; 24362cbc408SIlya Yanok u16 phy_id, status, adv, lpa; 24462cbc408SIlya Yanok int media, speed, duplex; 24562cbc408SIlya Yanok int i; 24662cbc408SIlya Yanok u32 ctl_reg; 24762cbc408SIlya Yanok 24862cbc408SIlya Yanok /* Find a PHY */ 24962cbc408SIlya Yanok for (i = 0; i < 32; i++) { 25062cbc408SIlya Yanok dnet->phy_addr = i; 25162cbc408SIlya Yanok phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 25262cbc408SIlya Yanok if (phy_id != 0xffff) { 25362cbc408SIlya Yanok /* ok we found it */ 25462cbc408SIlya Yanok printf("Found PHY at address %d PHYID (%04x:%04x)\n", 25562cbc408SIlya Yanok i, phy_id, 25662cbc408SIlya Yanok dnet_mdio_read(dnet, MII_PHYSID2)); 25762cbc408SIlya Yanok break; 25862cbc408SIlya Yanok } 25962cbc408SIlya Yanok } 26062cbc408SIlya Yanok 26162cbc408SIlya Yanok /* Check if the PHY is up to snuff... */ 26262cbc408SIlya Yanok phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 26362cbc408SIlya Yanok if (phy_id == 0xffff) { 26462cbc408SIlya Yanok printf("%s: No PHY present\n", netdev->name); 26562cbc408SIlya Yanok return -1; 26662cbc408SIlya Yanok } 26762cbc408SIlya Yanok 26862cbc408SIlya Yanok status = dnet_mdio_read(dnet, MII_BMSR); 26962cbc408SIlya Yanok if (!(status & BMSR_LSTATUS)) { 27062cbc408SIlya Yanok /* Try to re-negotiate if we don't have link already. */ 27162cbc408SIlya Yanok dnet_phy_reset(dnet); 27262cbc408SIlya Yanok 27362cbc408SIlya Yanok for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 27462cbc408SIlya Yanok status = dnet_mdio_read(dnet, MII_BMSR); 27562cbc408SIlya Yanok if (status & BMSR_LSTATUS) 27662cbc408SIlya Yanok break; 27762cbc408SIlya Yanok udelay(100); 27862cbc408SIlya Yanok } 27962cbc408SIlya Yanok } 28062cbc408SIlya Yanok 28162cbc408SIlya Yanok if (!(status & BMSR_LSTATUS)) { 28262cbc408SIlya Yanok printf("%s: link down (status: 0x%04x)\n", 28362cbc408SIlya Yanok netdev->name, status); 28462cbc408SIlya Yanok return -1; 28562cbc408SIlya Yanok } else { 28662cbc408SIlya Yanok adv = dnet_mdio_read(dnet, MII_ADVERTISE); 28762cbc408SIlya Yanok lpa = dnet_mdio_read(dnet, MII_LPA); 28862cbc408SIlya Yanok media = mii_nway_result(lpa & adv); 28962cbc408SIlya Yanok speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) 29062cbc408SIlya Yanok ? 1 : 0); 29162cbc408SIlya Yanok duplex = (media & ADVERTISE_FULL) ? 1 : 0; 29262cbc408SIlya Yanok /* 1000BaseT ethernet is not supported */ 29362cbc408SIlya Yanok printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", 29462cbc408SIlya Yanok netdev->name, 29562cbc408SIlya Yanok speed ? "100" : "10", 29662cbc408SIlya Yanok duplex ? "full" : "half", 29762cbc408SIlya Yanok lpa); 29862cbc408SIlya Yanok 29962cbc408SIlya Yanok ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 30062cbc408SIlya Yanok 30162cbc408SIlya Yanok if (duplex) 30262cbc408SIlya Yanok ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); 30362cbc408SIlya Yanok else 30462cbc408SIlya Yanok ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; 30562cbc408SIlya Yanok 30662cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); 30762cbc408SIlya Yanok 30862cbc408SIlya Yanok return 0; 30962cbc408SIlya Yanok } 31062cbc408SIlya Yanok } 31162cbc408SIlya Yanok 31262cbc408SIlya Yanok static int dnet_init(struct eth_device *netdev, bd_t *bd) 31362cbc408SIlya Yanok { 31462cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 31562cbc408SIlya Yanok u32 config; 31662cbc408SIlya Yanok 31762cbc408SIlya Yanok /* 31862cbc408SIlya Yanok * dnet_halt should have been called at some point before now, 31962cbc408SIlya Yanok * so we'll assume the controller is idle. 32062cbc408SIlya Yanok */ 32162cbc408SIlya Yanok 32262cbc408SIlya Yanok /* set hardware address */ 32362cbc408SIlya Yanok dnet_set_hwaddr(netdev); 32462cbc408SIlya Yanok 32562cbc408SIlya Yanok if (dnet_phy_init(dnet) < 0) 32662cbc408SIlya Yanok return -1; 32762cbc408SIlya Yanok 32862cbc408SIlya Yanok /* flush rx/tx fifos */ 32962cbc408SIlya Yanok writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, 33062cbc408SIlya Yanok &dnet->regs->SYS_CTL); 33162cbc408SIlya Yanok udelay(1000); 33262cbc408SIlya Yanok writel(0, &dnet->regs->SYS_CTL); 33362cbc408SIlya Yanok 33462cbc408SIlya Yanok config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 33562cbc408SIlya Yanok 33662cbc408SIlya Yanok config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | 33762cbc408SIlya Yanok DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | 33862cbc408SIlya Yanok DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | 33962cbc408SIlya Yanok DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; 34062cbc408SIlya Yanok 34162cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config); 34262cbc408SIlya Yanok 34362cbc408SIlya Yanok /* Enable TX and RX */ 34462cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 34562cbc408SIlya Yanok DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); 34662cbc408SIlya Yanok 34762cbc408SIlya Yanok return 0; 34862cbc408SIlya Yanok } 34962cbc408SIlya Yanok 35062cbc408SIlya Yanok static void dnet_halt(struct eth_device *netdev) 35162cbc408SIlya Yanok { 35262cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 35362cbc408SIlya Yanok 35462cbc408SIlya Yanok /* Disable TX and RX */ 35562cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0); 35662cbc408SIlya Yanok } 35762cbc408SIlya Yanok 35862cbc408SIlya Yanok int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr) 35962cbc408SIlya Yanok { 36062cbc408SIlya Yanok struct dnet_device *dnet; 36162cbc408SIlya Yanok struct eth_device *netdev; 36262cbc408SIlya Yanok unsigned int dev_capa; 36362cbc408SIlya Yanok 36462cbc408SIlya Yanok dnet = malloc(sizeof(struct dnet_device)); 36562cbc408SIlya Yanok if (!dnet) { 36662cbc408SIlya Yanok printf("Error: Failed to allocate memory for DNET%d\n", id); 36762cbc408SIlya Yanok return -1; 36862cbc408SIlya Yanok } 36962cbc408SIlya Yanok memset(dnet, 0, sizeof(struct dnet_device)); 37062cbc408SIlya Yanok 37162cbc408SIlya Yanok netdev = &dnet->netdev; 37262cbc408SIlya Yanok 37362cbc408SIlya Yanok dnet->regs = (struct dnet_registers *)regs; 37462cbc408SIlya Yanok dnet->phy_addr = phy_addr; 37562cbc408SIlya Yanok 37662cbc408SIlya Yanok sprintf(netdev->name, "dnet%d", id); 37762cbc408SIlya Yanok netdev->init = dnet_init; 37862cbc408SIlya Yanok netdev->halt = dnet_halt; 37962cbc408SIlya Yanok netdev->send = dnet_send; 38062cbc408SIlya Yanok netdev->recv = dnet_recv; 38162cbc408SIlya Yanok 38262cbc408SIlya Yanok dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF; 38362cbc408SIlya Yanok debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name, 38462cbc408SIlya Yanok (dev_capa & DNET_HAS_MDIO) ? "" : "no ", 38562cbc408SIlya Yanok (dev_capa & DNET_HAS_IRQ) ? "" : "no ", 38662cbc408SIlya Yanok (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ", 38762cbc408SIlya Yanok (dev_capa & DNET_HAS_DMA) ? "" : "no "); 38862cbc408SIlya Yanok 38962cbc408SIlya Yanok eth_register(netdev); 39062cbc408SIlya Yanok 39162cbc408SIlya Yanok return 0; 39262cbc408SIlya Yanok } 393