1*62cbc408SIlya Yanok /* 2*62cbc408SIlya Yanok * Dave Ethernet Controller driver 3*62cbc408SIlya Yanok * 4*62cbc408SIlya Yanok * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> 5*62cbc408SIlya Yanok * 6*62cbc408SIlya Yanok * This program is free software; you can redistribute it and/or modify 7*62cbc408SIlya Yanok * it under the terms of the GNU General Public License version 2 as 8*62cbc408SIlya Yanok * published by the Free Software Foundation. 9*62cbc408SIlya Yanok */ 10*62cbc408SIlya Yanok 11*62cbc408SIlya Yanok #include <common.h> 12*62cbc408SIlya Yanok 13*62cbc408SIlya Yanok #ifndef CONFIG_DNET_AUTONEG_TIMEOUT 14*62cbc408SIlya Yanok #define CONFIG_DNET_AUTONEG_TIMEOUT 5000000 /* default value */ 15*62cbc408SIlya Yanok #endif 16*62cbc408SIlya Yanok 17*62cbc408SIlya Yanok #include <net.h> 18*62cbc408SIlya Yanok #include <malloc.h> 19*62cbc408SIlya Yanok #include <linux/mii.h> 20*62cbc408SIlya Yanok 21*62cbc408SIlya Yanok #include <miiphy.h> 22*62cbc408SIlya Yanok #include <asm/io.h> 23*62cbc408SIlya Yanok 24*62cbc408SIlya Yanok #include "dnet.h" 25*62cbc408SIlya Yanok 26*62cbc408SIlya Yanok struct dnet_device { 27*62cbc408SIlya Yanok struct dnet_registers *regs; 28*62cbc408SIlya Yanok const struct device *dev; 29*62cbc408SIlya Yanok struct eth_device netdev; 30*62cbc408SIlya Yanok unsigned short phy_addr; 31*62cbc408SIlya Yanok }; 32*62cbc408SIlya Yanok 33*62cbc408SIlya Yanok /* get struct dnet_device from given struct netdev */ 34*62cbc408SIlya Yanok #define to_dnet(_nd) container_of(_nd, struct dnet_device, netdev) 35*62cbc408SIlya Yanok 36*62cbc408SIlya Yanok /* function for reading internal MAC register */ 37*62cbc408SIlya Yanok u16 dnet_readw_mac(struct dnet_device *dnet, u16 reg) 38*62cbc408SIlya Yanok { 39*62cbc408SIlya Yanok u16 data_read; 40*62cbc408SIlya Yanok 41*62cbc408SIlya Yanok /* issue a read */ 42*62cbc408SIlya Yanok writel(reg, &dnet->regs->MACREG_ADDR); 43*62cbc408SIlya Yanok 44*62cbc408SIlya Yanok /* since a read/write op to the MAC is very slow, 45*62cbc408SIlya Yanok * we must wait before reading the data */ 46*62cbc408SIlya Yanok udelay(1); 47*62cbc408SIlya Yanok 48*62cbc408SIlya Yanok /* read data read from the MAC register */ 49*62cbc408SIlya Yanok data_read = readl(&dnet->regs->MACREG_DATA); 50*62cbc408SIlya Yanok 51*62cbc408SIlya Yanok /* all done */ 52*62cbc408SIlya Yanok return data_read; 53*62cbc408SIlya Yanok } 54*62cbc408SIlya Yanok 55*62cbc408SIlya Yanok /* function for writing internal MAC register */ 56*62cbc408SIlya Yanok void dnet_writew_mac(struct dnet_device *dnet, u16 reg, u16 val) 57*62cbc408SIlya Yanok { 58*62cbc408SIlya Yanok /* load data to write */ 59*62cbc408SIlya Yanok writel(val, &dnet->regs->MACREG_DATA); 60*62cbc408SIlya Yanok 61*62cbc408SIlya Yanok /* issue a write */ 62*62cbc408SIlya Yanok writel(reg | DNET_INTERNAL_WRITE, &dnet->regs->MACREG_ADDR); 63*62cbc408SIlya Yanok 64*62cbc408SIlya Yanok /* since a read/write op to the MAC is very slow, 65*62cbc408SIlya Yanok * we must wait before exiting */ 66*62cbc408SIlya Yanok udelay(1); 67*62cbc408SIlya Yanok } 68*62cbc408SIlya Yanok 69*62cbc408SIlya Yanok static void dnet_mdio_write(struct dnet_device *dnet, u8 reg, u16 value) 70*62cbc408SIlya Yanok { 71*62cbc408SIlya Yanok u16 tmp; 72*62cbc408SIlya Yanok 73*62cbc408SIlya Yanok debug(DRIVERNAME "dnet_mdio_write %02x:%02x <- %04x\n", 74*62cbc408SIlya Yanok dnet->phy_addr, reg, value); 75*62cbc408SIlya Yanok 76*62cbc408SIlya Yanok while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 77*62cbc408SIlya Yanok DNET_INTERNAL_GMII_MNG_CMD_FIN)) 78*62cbc408SIlya Yanok ; 79*62cbc408SIlya Yanok 80*62cbc408SIlya Yanok /* prepare for a write operation */ 81*62cbc408SIlya Yanok tmp = (1 << 13); 82*62cbc408SIlya Yanok 83*62cbc408SIlya Yanok /* only 5 bits allowed for register offset */ 84*62cbc408SIlya Yanok reg &= 0x1f; 85*62cbc408SIlya Yanok 86*62cbc408SIlya Yanok /* prepare reg_value for a write */ 87*62cbc408SIlya Yanok tmp |= (dnet->phy_addr << 8); 88*62cbc408SIlya Yanok tmp |= reg; 89*62cbc408SIlya Yanok 90*62cbc408SIlya Yanok /* write data to write first */ 91*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG, value); 92*62cbc408SIlya Yanok 93*62cbc408SIlya Yanok /* write control word */ 94*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp); 95*62cbc408SIlya Yanok 96*62cbc408SIlya Yanok while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 97*62cbc408SIlya Yanok DNET_INTERNAL_GMII_MNG_CMD_FIN)) 98*62cbc408SIlya Yanok ; 99*62cbc408SIlya Yanok } 100*62cbc408SIlya Yanok 101*62cbc408SIlya Yanok static u16 dnet_mdio_read(struct dnet_device *dnet, u8 reg) 102*62cbc408SIlya Yanok { 103*62cbc408SIlya Yanok u16 value; 104*62cbc408SIlya Yanok 105*62cbc408SIlya Yanok while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 106*62cbc408SIlya Yanok DNET_INTERNAL_GMII_MNG_CMD_FIN)) 107*62cbc408SIlya Yanok ; 108*62cbc408SIlya Yanok 109*62cbc408SIlya Yanok /* only 5 bits allowed for register offset*/ 110*62cbc408SIlya Yanok reg &= 0x1f; 111*62cbc408SIlya Yanok 112*62cbc408SIlya Yanok /* prepare reg_value for a read */ 113*62cbc408SIlya Yanok value = (dnet->phy_addr << 8); 114*62cbc408SIlya Yanok value |= reg; 115*62cbc408SIlya Yanok 116*62cbc408SIlya Yanok /* write control word */ 117*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, value); 118*62cbc408SIlya Yanok 119*62cbc408SIlya Yanok /* wait for end of transfer */ 120*62cbc408SIlya Yanok while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 121*62cbc408SIlya Yanok DNET_INTERNAL_GMII_MNG_CMD_FIN)) 122*62cbc408SIlya Yanok ; 123*62cbc408SIlya Yanok 124*62cbc408SIlya Yanok value = dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG); 125*62cbc408SIlya Yanok 126*62cbc408SIlya Yanok debug(DRIVERNAME "dnet_mdio_read %02x:%02x <- %04x\n", 127*62cbc408SIlya Yanok dnet->phy_addr, reg, value); 128*62cbc408SIlya Yanok 129*62cbc408SIlya Yanok return value; 130*62cbc408SIlya Yanok } 131*62cbc408SIlya Yanok 132*62cbc408SIlya Yanok static int dnet_send(struct eth_device *netdev, volatile void *packet, 133*62cbc408SIlya Yanok int length) 134*62cbc408SIlya Yanok { 135*62cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 136*62cbc408SIlya Yanok int i, len, wrsz; 137*62cbc408SIlya Yanok unsigned int *bufp; 138*62cbc408SIlya Yanok unsigned int tx_cmd; 139*62cbc408SIlya Yanok 140*62cbc408SIlya Yanok debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length); 141*62cbc408SIlya Yanok 142*62cbc408SIlya Yanok /* frame size (words) */ 143*62cbc408SIlya Yanok len = (length + 3) >> 2; 144*62cbc408SIlya Yanok 145*62cbc408SIlya Yanok bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC); 146*62cbc408SIlya Yanok wrsz = (u32)length + 3; 147*62cbc408SIlya Yanok wrsz += ((u32)packet) & 0x3; 148*62cbc408SIlya Yanok wrsz >>= 2; 149*62cbc408SIlya Yanok tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length; 150*62cbc408SIlya Yanok 151*62cbc408SIlya Yanok /* check if there is enough room for the current frame */ 152*62cbc408SIlya Yanok if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) { 153*62cbc408SIlya Yanok for (i = 0; i < wrsz; i++) 154*62cbc408SIlya Yanok writel(*bufp++, &dnet->regs->TX_DATA_FIFO); 155*62cbc408SIlya Yanok /* 156*62cbc408SIlya Yanok * inform MAC that a packet's written and ready 157*62cbc408SIlya Yanok * to be shipped out 158*62cbc408SIlya Yanok */ 159*62cbc408SIlya Yanok writel(tx_cmd, &dnet->regs->TX_LEN_FIFO); 160*62cbc408SIlya Yanok } else { 161*62cbc408SIlya Yanok printf(DRIVERNAME "No free space (actual %d, required %d " 162*62cbc408SIlya Yanok "(words))\n", DNET_FIFO_SIZE - 163*62cbc408SIlya Yanok readl(&dnet->regs->TX_FIFO_WCNT), wrsz); 164*62cbc408SIlya Yanok } 165*62cbc408SIlya Yanok 166*62cbc408SIlya Yanok /* No one cares anyway */ 167*62cbc408SIlya Yanok return 0; 168*62cbc408SIlya Yanok } 169*62cbc408SIlya Yanok 170*62cbc408SIlya Yanok 171*62cbc408SIlya Yanok static int dnet_recv(struct eth_device *netdev) 172*62cbc408SIlya Yanok { 173*62cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 174*62cbc408SIlya Yanok unsigned int *data_ptr; 175*62cbc408SIlya Yanok int pkt_len, poll, i; 176*62cbc408SIlya Yanok u32 cmd_word; 177*62cbc408SIlya Yanok 178*62cbc408SIlya Yanok debug("Waiting for pkt (polling)\n"); 179*62cbc408SIlya Yanok poll = 50; 180*62cbc408SIlya Yanok while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) { 181*62cbc408SIlya Yanok udelay(10); /* wait 10 usec */ 182*62cbc408SIlya Yanok if (--poll == 0) 183*62cbc408SIlya Yanok return 0; /* no pkt available */ 184*62cbc408SIlya Yanok } 185*62cbc408SIlya Yanok 186*62cbc408SIlya Yanok cmd_word = readl(&dnet->regs->RX_LEN_FIFO); 187*62cbc408SIlya Yanok pkt_len = cmd_word & 0xFFFF; 188*62cbc408SIlya Yanok 189*62cbc408SIlya Yanok debug("Got pkt with size %d bytes\n", pkt_len); 190*62cbc408SIlya Yanok 191*62cbc408SIlya Yanok if (cmd_word & 0xDF180000) 192*62cbc408SIlya Yanok printf("%s packet receive error %x\n", __func__, cmd_word); 193*62cbc408SIlya Yanok 194*62cbc408SIlya Yanok data_ptr = (unsigned int *) NetRxPackets[0]; 195*62cbc408SIlya Yanok 196*62cbc408SIlya Yanok for (i = 0; i < (pkt_len + 3) >> 2; i++) 197*62cbc408SIlya Yanok *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO); 198*62cbc408SIlya Yanok 199*62cbc408SIlya Yanok NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */ 200*62cbc408SIlya Yanok 201*62cbc408SIlya Yanok return 0; 202*62cbc408SIlya Yanok } 203*62cbc408SIlya Yanok 204*62cbc408SIlya Yanok static void dnet_set_hwaddr(struct eth_device *netdev) 205*62cbc408SIlya Yanok { 206*62cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 207*62cbc408SIlya Yanok u16 tmp; 208*62cbc408SIlya Yanok 209*62cbc408SIlya Yanok tmp = cpu_to_be16(*((u16 *)netdev->enetaddr)); 210*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); 211*62cbc408SIlya Yanok tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 2))); 212*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); 213*62cbc408SIlya Yanok tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 4))); 214*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); 215*62cbc408SIlya Yanok } 216*62cbc408SIlya Yanok 217*62cbc408SIlya Yanok static void dnet_phy_reset(struct dnet_device *dnet) 218*62cbc408SIlya Yanok { 219*62cbc408SIlya Yanok struct eth_device *netdev = &dnet->netdev; 220*62cbc408SIlya Yanok int i; 221*62cbc408SIlya Yanok u16 status, adv; 222*62cbc408SIlya Yanok 223*62cbc408SIlya Yanok adv = ADVERTISE_CSMA | ADVERTISE_ALL; 224*62cbc408SIlya Yanok dnet_mdio_write(dnet, MII_ADVERTISE, adv); 225*62cbc408SIlya Yanok printf("%s: Starting autonegotiation...\n", netdev->name); 226*62cbc408SIlya Yanok dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE 227*62cbc408SIlya Yanok | BMCR_ANRESTART)); 228*62cbc408SIlya Yanok 229*62cbc408SIlya Yanok for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 230*62cbc408SIlya Yanok status = dnet_mdio_read(dnet, MII_BMSR); 231*62cbc408SIlya Yanok if (status & BMSR_ANEGCOMPLETE) 232*62cbc408SIlya Yanok break; 233*62cbc408SIlya Yanok udelay(100); 234*62cbc408SIlya Yanok } 235*62cbc408SIlya Yanok 236*62cbc408SIlya Yanok if (status & BMSR_ANEGCOMPLETE) 237*62cbc408SIlya Yanok printf("%s: Autonegotiation complete\n", netdev->name); 238*62cbc408SIlya Yanok else 239*62cbc408SIlya Yanok printf("%s: Autonegotiation timed out (status=0x%04x)\n", 240*62cbc408SIlya Yanok netdev->name, status); 241*62cbc408SIlya Yanok } 242*62cbc408SIlya Yanok 243*62cbc408SIlya Yanok static int dnet_phy_init(struct dnet_device *dnet) 244*62cbc408SIlya Yanok { 245*62cbc408SIlya Yanok struct eth_device *netdev = &dnet->netdev; 246*62cbc408SIlya Yanok u16 phy_id, status, adv, lpa; 247*62cbc408SIlya Yanok int media, speed, duplex; 248*62cbc408SIlya Yanok int i; 249*62cbc408SIlya Yanok u32 ctl_reg; 250*62cbc408SIlya Yanok 251*62cbc408SIlya Yanok /* Find a PHY */ 252*62cbc408SIlya Yanok for (i = 0; i < 32; i++) { 253*62cbc408SIlya Yanok dnet->phy_addr = i; 254*62cbc408SIlya Yanok phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 255*62cbc408SIlya Yanok if (phy_id != 0xffff) { 256*62cbc408SIlya Yanok /* ok we found it */ 257*62cbc408SIlya Yanok printf("Found PHY at address %d PHYID (%04x:%04x)\n", 258*62cbc408SIlya Yanok i, phy_id, 259*62cbc408SIlya Yanok dnet_mdio_read(dnet, MII_PHYSID2)); 260*62cbc408SIlya Yanok break; 261*62cbc408SIlya Yanok } 262*62cbc408SIlya Yanok } 263*62cbc408SIlya Yanok 264*62cbc408SIlya Yanok /* Check if the PHY is up to snuff... */ 265*62cbc408SIlya Yanok phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 266*62cbc408SIlya Yanok if (phy_id == 0xffff) { 267*62cbc408SIlya Yanok printf("%s: No PHY present\n", netdev->name); 268*62cbc408SIlya Yanok return -1; 269*62cbc408SIlya Yanok } 270*62cbc408SIlya Yanok 271*62cbc408SIlya Yanok status = dnet_mdio_read(dnet, MII_BMSR); 272*62cbc408SIlya Yanok if (!(status & BMSR_LSTATUS)) { 273*62cbc408SIlya Yanok /* Try to re-negotiate if we don't have link already. */ 274*62cbc408SIlya Yanok dnet_phy_reset(dnet); 275*62cbc408SIlya Yanok 276*62cbc408SIlya Yanok for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 277*62cbc408SIlya Yanok status = dnet_mdio_read(dnet, MII_BMSR); 278*62cbc408SIlya Yanok if (status & BMSR_LSTATUS) 279*62cbc408SIlya Yanok break; 280*62cbc408SIlya Yanok udelay(100); 281*62cbc408SIlya Yanok } 282*62cbc408SIlya Yanok } 283*62cbc408SIlya Yanok 284*62cbc408SIlya Yanok if (!(status & BMSR_LSTATUS)) { 285*62cbc408SIlya Yanok printf("%s: link down (status: 0x%04x)\n", 286*62cbc408SIlya Yanok netdev->name, status); 287*62cbc408SIlya Yanok return -1; 288*62cbc408SIlya Yanok } else { 289*62cbc408SIlya Yanok adv = dnet_mdio_read(dnet, MII_ADVERTISE); 290*62cbc408SIlya Yanok lpa = dnet_mdio_read(dnet, MII_LPA); 291*62cbc408SIlya Yanok media = mii_nway_result(lpa & adv); 292*62cbc408SIlya Yanok speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) 293*62cbc408SIlya Yanok ? 1 : 0); 294*62cbc408SIlya Yanok duplex = (media & ADVERTISE_FULL) ? 1 : 0; 295*62cbc408SIlya Yanok /* 1000BaseT ethernet is not supported */ 296*62cbc408SIlya Yanok printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", 297*62cbc408SIlya Yanok netdev->name, 298*62cbc408SIlya Yanok speed ? "100" : "10", 299*62cbc408SIlya Yanok duplex ? "full" : "half", 300*62cbc408SIlya Yanok lpa); 301*62cbc408SIlya Yanok 302*62cbc408SIlya Yanok ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 303*62cbc408SIlya Yanok 304*62cbc408SIlya Yanok if (duplex) 305*62cbc408SIlya Yanok ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); 306*62cbc408SIlya Yanok else 307*62cbc408SIlya Yanok ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; 308*62cbc408SIlya Yanok 309*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); 310*62cbc408SIlya Yanok 311*62cbc408SIlya Yanok return 0; 312*62cbc408SIlya Yanok } 313*62cbc408SIlya Yanok } 314*62cbc408SIlya Yanok 315*62cbc408SIlya Yanok static int dnet_init(struct eth_device *netdev, bd_t *bd) 316*62cbc408SIlya Yanok { 317*62cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 318*62cbc408SIlya Yanok u32 config; 319*62cbc408SIlya Yanok 320*62cbc408SIlya Yanok /* 321*62cbc408SIlya Yanok * dnet_halt should have been called at some point before now, 322*62cbc408SIlya Yanok * so we'll assume the controller is idle. 323*62cbc408SIlya Yanok */ 324*62cbc408SIlya Yanok 325*62cbc408SIlya Yanok /* set hardware address */ 326*62cbc408SIlya Yanok dnet_set_hwaddr(netdev); 327*62cbc408SIlya Yanok 328*62cbc408SIlya Yanok if (dnet_phy_init(dnet) < 0) 329*62cbc408SIlya Yanok return -1; 330*62cbc408SIlya Yanok 331*62cbc408SIlya Yanok /* flush rx/tx fifos */ 332*62cbc408SIlya Yanok writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, 333*62cbc408SIlya Yanok &dnet->regs->SYS_CTL); 334*62cbc408SIlya Yanok udelay(1000); 335*62cbc408SIlya Yanok writel(0, &dnet->regs->SYS_CTL); 336*62cbc408SIlya Yanok 337*62cbc408SIlya Yanok config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 338*62cbc408SIlya Yanok 339*62cbc408SIlya Yanok config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | 340*62cbc408SIlya Yanok DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | 341*62cbc408SIlya Yanok DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | 342*62cbc408SIlya Yanok DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; 343*62cbc408SIlya Yanok 344*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config); 345*62cbc408SIlya Yanok 346*62cbc408SIlya Yanok /* Enable TX and RX */ 347*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 348*62cbc408SIlya Yanok DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); 349*62cbc408SIlya Yanok 350*62cbc408SIlya Yanok return 0; 351*62cbc408SIlya Yanok } 352*62cbc408SIlya Yanok 353*62cbc408SIlya Yanok static void dnet_halt(struct eth_device *netdev) 354*62cbc408SIlya Yanok { 355*62cbc408SIlya Yanok struct dnet_device *dnet = to_dnet(netdev); 356*62cbc408SIlya Yanok 357*62cbc408SIlya Yanok /* Disable TX and RX */ 358*62cbc408SIlya Yanok dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0); 359*62cbc408SIlya Yanok } 360*62cbc408SIlya Yanok 361*62cbc408SIlya Yanok int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr) 362*62cbc408SIlya Yanok { 363*62cbc408SIlya Yanok struct dnet_device *dnet; 364*62cbc408SIlya Yanok struct eth_device *netdev; 365*62cbc408SIlya Yanok unsigned int dev_capa; 366*62cbc408SIlya Yanok 367*62cbc408SIlya Yanok dnet = malloc(sizeof(struct dnet_device)); 368*62cbc408SIlya Yanok if (!dnet) { 369*62cbc408SIlya Yanok printf("Error: Failed to allocate memory for DNET%d\n", id); 370*62cbc408SIlya Yanok return -1; 371*62cbc408SIlya Yanok } 372*62cbc408SIlya Yanok memset(dnet, 0, sizeof(struct dnet_device)); 373*62cbc408SIlya Yanok 374*62cbc408SIlya Yanok netdev = &dnet->netdev; 375*62cbc408SIlya Yanok 376*62cbc408SIlya Yanok dnet->regs = (struct dnet_registers *)regs; 377*62cbc408SIlya Yanok dnet->phy_addr = phy_addr; 378*62cbc408SIlya Yanok 379*62cbc408SIlya Yanok sprintf(netdev->name, "dnet%d", id); 380*62cbc408SIlya Yanok netdev->init = dnet_init; 381*62cbc408SIlya Yanok netdev->halt = dnet_halt; 382*62cbc408SIlya Yanok netdev->send = dnet_send; 383*62cbc408SIlya Yanok netdev->recv = dnet_recv; 384*62cbc408SIlya Yanok 385*62cbc408SIlya Yanok dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF; 386*62cbc408SIlya Yanok debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name, 387*62cbc408SIlya Yanok (dev_capa & DNET_HAS_MDIO) ? "" : "no ", 388*62cbc408SIlya Yanok (dev_capa & DNET_HAS_IRQ) ? "" : "no ", 389*62cbc408SIlya Yanok (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ", 390*62cbc408SIlya Yanok (dev_capa & DNET_HAS_DMA) ? "" : "no "); 391*62cbc408SIlya Yanok 392*62cbc408SIlya Yanok eth_register(netdev); 393*62cbc408SIlya Yanok 394*62cbc408SIlya Yanok return 0; 395*62cbc408SIlya Yanok } 396*62cbc408SIlya Yanok 397