xref: /OK3568_Linux_fs/u-boot/drivers/net/dnet.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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