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> 23*d780e74fSAnatolij 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 13362cbc408SIlya Yanok static int dnet_send(struct eth_device *netdev, volatile void *packet, 13462cbc408SIlya Yanok int length) 13562cbc408SIlya Yanok { 13662cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 137*d780e74fSAnatolij Gustschin int i, wrsz; 13862cbc408SIlya Yanok unsigned int *bufp; 13962cbc408SIlya Yanok unsigned int tx_cmd; 14062cbc408SIlya Yanok 14162cbc408SIlya Yanok debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length); 14262cbc408SIlya Yanok 14362cbc408SIlya Yanok bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC); 14462cbc408SIlya Yanok wrsz = (u32)length + 3; 14562cbc408SIlya Yanok wrsz += ((u32)packet) & 0x3; 14662cbc408SIlya Yanok wrsz >>= 2; 14762cbc408SIlya Yanok tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length; 14862cbc408SIlya Yanok 14962cbc408SIlya Yanok /* check if there is enough room for the current frame */ 15062cbc408SIlya Yanok if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) { 15162cbc408SIlya Yanok for (i = 0; i < wrsz; i++) 15262cbc408SIlya Yanok writel(*bufp++, &dnet->regs->TX_DATA_FIFO); 15362cbc408SIlya Yanok /* 15462cbc408SIlya Yanok * inform MAC that a packet's written and ready 15562cbc408SIlya Yanok * to be shipped out 15662cbc408SIlya Yanok */ 15762cbc408SIlya Yanok writel(tx_cmd, &dnet->regs->TX_LEN_FIFO); 15862cbc408SIlya Yanok } else { 15962cbc408SIlya Yanok printf(DRIVERNAME "No free space (actual %d, required %d " 16062cbc408SIlya Yanok "(words))\n", DNET_FIFO_SIZE - 16162cbc408SIlya Yanok readl(&dnet->regs->TX_FIFO_WCNT), wrsz); 16262cbc408SIlya Yanok } 16362cbc408SIlya Yanok 16462cbc408SIlya Yanok /* No one cares anyway */ 16562cbc408SIlya Yanok return 0; 16662cbc408SIlya Yanok } 16762cbc408SIlya Yanok 16862cbc408SIlya Yanok 16962cbc408SIlya Yanok static int dnet_recv(struct eth_device *netdev) 17062cbc408SIlya Yanok { 17162cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 17262cbc408SIlya Yanok unsigned int *data_ptr; 17362cbc408SIlya Yanok int pkt_len, poll, i; 17462cbc408SIlya Yanok u32 cmd_word; 17562cbc408SIlya Yanok 17662cbc408SIlya Yanok debug("Waiting for pkt (polling)\n"); 17762cbc408SIlya Yanok poll = 50; 17862cbc408SIlya Yanok while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) { 17962cbc408SIlya Yanok udelay(10); /* wait 10 usec */ 18062cbc408SIlya Yanok if (--poll == 0) 18162cbc408SIlya Yanok return 0; /* no pkt available */ 18262cbc408SIlya Yanok } 18362cbc408SIlya Yanok 18462cbc408SIlya Yanok cmd_word = readl(&dnet->regs->RX_LEN_FIFO); 18562cbc408SIlya Yanok pkt_len = cmd_word & 0xFFFF; 18662cbc408SIlya Yanok 18762cbc408SIlya Yanok debug("Got pkt with size %d bytes\n", pkt_len); 18862cbc408SIlya Yanok 18962cbc408SIlya Yanok if (cmd_word & 0xDF180000) 19062cbc408SIlya Yanok printf("%s packet receive error %x\n", __func__, cmd_word); 19162cbc408SIlya Yanok 19262cbc408SIlya Yanok data_ptr = (unsigned int *) NetRxPackets[0]; 19362cbc408SIlya Yanok 19462cbc408SIlya Yanok for (i = 0; i < (pkt_len + 3) >> 2; i++) 19562cbc408SIlya Yanok *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO); 19662cbc408SIlya Yanok 19762cbc408SIlya Yanok NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */ 19862cbc408SIlya Yanok 19962cbc408SIlya Yanok return 0; 20062cbc408SIlya Yanok } 20162cbc408SIlya Yanok 20262cbc408SIlya Yanok static void dnet_set_hwaddr(struct eth_device *netdev) 20362cbc408SIlya Yanok { 20462cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 20562cbc408SIlya Yanok u16 tmp; 20662cbc408SIlya Yanok 207*d780e74fSAnatolij Gustschin tmp = get_unaligned_be16(netdev->enetaddr); 20862cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); 209*d780e74fSAnatolij Gustschin tmp = get_unaligned_be16(&netdev->enetaddr[2]); 21062cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); 211*d780e74fSAnatolij Gustschin tmp = get_unaligned_be16(&netdev->enetaddr[4]); 21262cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); 21362cbc408SIlya Yanok } 21462cbc408SIlya Yanok 21562cbc408SIlya Yanok static void dnet_phy_reset(struct dnet_device *dnet) 21662cbc408SIlya Yanok { 21762cbc408SIlya Yanok struct eth_device *netdev = &dnet->netdev; 21862cbc408SIlya Yanok int i; 21962cbc408SIlya Yanok u16 status, adv; 22062cbc408SIlya Yanok 22162cbc408SIlya Yanok adv = ADVERTISE_CSMA | ADVERTISE_ALL; 22262cbc408SIlya Yanok dnet_mdio_write(dnet, MII_ADVERTISE, adv); 22362cbc408SIlya Yanok printf("%s: Starting autonegotiation...\n", netdev->name); 22462cbc408SIlya Yanok dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE 22562cbc408SIlya Yanok | BMCR_ANRESTART)); 22662cbc408SIlya Yanok 22762cbc408SIlya Yanok for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 22862cbc408SIlya Yanok status = dnet_mdio_read(dnet, MII_BMSR); 22962cbc408SIlya Yanok if (status & BMSR_ANEGCOMPLETE) 23062cbc408SIlya Yanok break; 23162cbc408SIlya Yanok udelay(100); 23262cbc408SIlya Yanok } 23362cbc408SIlya Yanok 23462cbc408SIlya Yanok if (status & BMSR_ANEGCOMPLETE) 23562cbc408SIlya Yanok printf("%s: Autonegotiation complete\n", netdev->name); 23662cbc408SIlya Yanok else 23762cbc408SIlya Yanok printf("%s: Autonegotiation timed out (status=0x%04x)\n", 23862cbc408SIlya Yanok netdev->name, status); 23962cbc408SIlya Yanok } 24062cbc408SIlya Yanok 24162cbc408SIlya Yanok static int dnet_phy_init(struct dnet_device *dnet) 24262cbc408SIlya Yanok { 24362cbc408SIlya Yanok struct eth_device *netdev = &dnet->netdev; 24462cbc408SIlya Yanok u16 phy_id, status, adv, lpa; 24562cbc408SIlya Yanok int media, speed, duplex; 24662cbc408SIlya Yanok int i; 24762cbc408SIlya Yanok u32 ctl_reg; 24862cbc408SIlya Yanok 24962cbc408SIlya Yanok /* Find a PHY */ 25062cbc408SIlya Yanok for (i = 0; i < 32; i++) { 25162cbc408SIlya Yanok dnet->phy_addr = i; 25262cbc408SIlya Yanok phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 25362cbc408SIlya Yanok if (phy_id != 0xffff) { 25462cbc408SIlya Yanok /* ok we found it */ 25562cbc408SIlya Yanok printf("Found PHY at address %d PHYID (%04x:%04x)\n", 25662cbc408SIlya Yanok i, phy_id, 25762cbc408SIlya Yanok dnet_mdio_read(dnet, MII_PHYSID2)); 25862cbc408SIlya Yanok break; 25962cbc408SIlya Yanok } 26062cbc408SIlya Yanok } 26162cbc408SIlya Yanok 26262cbc408SIlya Yanok /* Check if the PHY is up to snuff... */ 26362cbc408SIlya Yanok phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 26462cbc408SIlya Yanok if (phy_id == 0xffff) { 26562cbc408SIlya Yanok printf("%s: No PHY present\n", netdev->name); 26662cbc408SIlya Yanok return -1; 26762cbc408SIlya Yanok } 26862cbc408SIlya Yanok 26962cbc408SIlya Yanok status = dnet_mdio_read(dnet, MII_BMSR); 27062cbc408SIlya Yanok if (!(status & BMSR_LSTATUS)) { 27162cbc408SIlya Yanok /* Try to re-negotiate if we don't have link already. */ 27262cbc408SIlya Yanok dnet_phy_reset(dnet); 27362cbc408SIlya Yanok 27462cbc408SIlya Yanok for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 27562cbc408SIlya Yanok status = dnet_mdio_read(dnet, MII_BMSR); 27662cbc408SIlya Yanok if (status & BMSR_LSTATUS) 27762cbc408SIlya Yanok break; 27862cbc408SIlya Yanok udelay(100); 27962cbc408SIlya Yanok } 28062cbc408SIlya Yanok } 28162cbc408SIlya Yanok 28262cbc408SIlya Yanok if (!(status & BMSR_LSTATUS)) { 28362cbc408SIlya Yanok printf("%s: link down (status: 0x%04x)\n", 28462cbc408SIlya Yanok netdev->name, status); 28562cbc408SIlya Yanok return -1; 28662cbc408SIlya Yanok } else { 28762cbc408SIlya Yanok adv = dnet_mdio_read(dnet, MII_ADVERTISE); 28862cbc408SIlya Yanok lpa = dnet_mdio_read(dnet, MII_LPA); 28962cbc408SIlya Yanok media = mii_nway_result(lpa & adv); 29062cbc408SIlya Yanok speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) 29162cbc408SIlya Yanok ? 1 : 0); 29262cbc408SIlya Yanok duplex = (media & ADVERTISE_FULL) ? 1 : 0; 29362cbc408SIlya Yanok /* 1000BaseT ethernet is not supported */ 29462cbc408SIlya Yanok printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", 29562cbc408SIlya Yanok netdev->name, 29662cbc408SIlya Yanok speed ? "100" : "10", 29762cbc408SIlya Yanok duplex ? "full" : "half", 29862cbc408SIlya Yanok lpa); 29962cbc408SIlya Yanok 30062cbc408SIlya Yanok ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 30162cbc408SIlya Yanok 30262cbc408SIlya Yanok if (duplex) 30362cbc408SIlya Yanok ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); 30462cbc408SIlya Yanok else 30562cbc408SIlya Yanok ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; 30662cbc408SIlya Yanok 30762cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); 30862cbc408SIlya Yanok 30962cbc408SIlya Yanok return 0; 31062cbc408SIlya Yanok } 31162cbc408SIlya Yanok } 31262cbc408SIlya Yanok 31362cbc408SIlya Yanok static int dnet_init(struct eth_device *netdev, bd_t *bd) 31462cbc408SIlya Yanok { 31562cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 31662cbc408SIlya Yanok u32 config; 31762cbc408SIlya Yanok 31862cbc408SIlya Yanok /* 31962cbc408SIlya Yanok * dnet_halt should have been called at some point before now, 32062cbc408SIlya Yanok * so we'll assume the controller is idle. 32162cbc408SIlya Yanok */ 32262cbc408SIlya Yanok 32362cbc408SIlya Yanok /* set hardware address */ 32462cbc408SIlya Yanok dnet_set_hwaddr(netdev); 32562cbc408SIlya Yanok 32662cbc408SIlya Yanok if (dnet_phy_init(dnet) < 0) 32762cbc408SIlya Yanok return -1; 32862cbc408SIlya Yanok 32962cbc408SIlya Yanok /* flush rx/tx fifos */ 33062cbc408SIlya Yanok writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, 33162cbc408SIlya Yanok &dnet->regs->SYS_CTL); 33262cbc408SIlya Yanok udelay(1000); 33362cbc408SIlya Yanok writel(0, &dnet->regs->SYS_CTL); 33462cbc408SIlya Yanok 33562cbc408SIlya Yanok config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 33662cbc408SIlya Yanok 33762cbc408SIlya Yanok config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | 33862cbc408SIlya Yanok DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | 33962cbc408SIlya Yanok DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | 34062cbc408SIlya Yanok DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; 34162cbc408SIlya Yanok 34262cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config); 34362cbc408SIlya Yanok 34462cbc408SIlya Yanok /* Enable TX and RX */ 34562cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 34662cbc408SIlya Yanok DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); 34762cbc408SIlya Yanok 34862cbc408SIlya Yanok return 0; 34962cbc408SIlya Yanok } 35062cbc408SIlya Yanok 35162cbc408SIlya Yanok static void dnet_halt(struct eth_device *netdev) 35262cbc408SIlya Yanok { 35362cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 35462cbc408SIlya Yanok 35562cbc408SIlya Yanok /* Disable TX and RX */ 35662cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0); 35762cbc408SIlya Yanok } 35862cbc408SIlya Yanok 35962cbc408SIlya Yanok int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr) 36062cbc408SIlya Yanok { 36162cbc408SIlya Yanok struct dnet_device *dnet; 36262cbc408SIlya Yanok struct eth_device *netdev; 36362cbc408SIlya Yanok unsigned int dev_capa; 36462cbc408SIlya Yanok 36562cbc408SIlya Yanok dnet = malloc(sizeof(struct dnet_device)); 36662cbc408SIlya Yanok if (!dnet) { 36762cbc408SIlya Yanok printf("Error: Failed to allocate memory for DNET%d\n", id); 36862cbc408SIlya Yanok return -1; 36962cbc408SIlya Yanok } 37062cbc408SIlya Yanok memset(dnet, 0, sizeof(struct dnet_device)); 37162cbc408SIlya Yanok 37262cbc408SIlya Yanok netdev = &dnet->netdev; 37362cbc408SIlya Yanok 37462cbc408SIlya Yanok dnet->regs = (struct dnet_registers *)regs; 37562cbc408SIlya Yanok dnet->phy_addr = phy_addr; 37662cbc408SIlya Yanok 37762cbc408SIlya Yanok sprintf(netdev->name, "dnet%d", id); 37862cbc408SIlya Yanok netdev->init = dnet_init; 37962cbc408SIlya Yanok netdev->halt = dnet_halt; 38062cbc408SIlya Yanok netdev->send = dnet_send; 38162cbc408SIlya Yanok netdev->recv = dnet_recv; 38262cbc408SIlya Yanok 38362cbc408SIlya Yanok dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF; 38462cbc408SIlya Yanok debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name, 38562cbc408SIlya Yanok (dev_capa & DNET_HAS_MDIO) ? "" : "no ", 38662cbc408SIlya Yanok (dev_capa & DNET_HAS_IRQ) ? "" : "no ", 38762cbc408SIlya Yanok (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ", 38862cbc408SIlya Yanok (dev_capa & DNET_HAS_DMA) ? "" : "no "); 38962cbc408SIlya Yanok 39062cbc408SIlya Yanok eth_register(netdev); 39162cbc408SIlya Yanok 39262cbc408SIlya Yanok return 0; 39362cbc408SIlya Yanok } 394