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