xref: /rk3399_rockchip-uboot/drivers/net/davinci_emac.c (revision 09cdd1b9b01450e91786d26ff3c866dc9c8d8d6b)
1*09cdd1b9SBen Warren /*
2*09cdd1b9SBen Warren  * Ethernet driver for TI TMS320DM644x (DaVinci) chips.
3*09cdd1b9SBen Warren  *
4*09cdd1b9SBen Warren  * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
5*09cdd1b9SBen Warren  *
6*09cdd1b9SBen Warren  * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright
7*09cdd1b9SBen Warren  * follows:
8*09cdd1b9SBen Warren  *
9*09cdd1b9SBen Warren  * ----------------------------------------------------------------------------
10*09cdd1b9SBen Warren  *
11*09cdd1b9SBen Warren  * dm644x_emac.c
12*09cdd1b9SBen Warren  *
13*09cdd1b9SBen Warren  * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM
14*09cdd1b9SBen Warren  *
15*09cdd1b9SBen Warren  * Copyright (C) 2005 Texas Instruments.
16*09cdd1b9SBen Warren  *
17*09cdd1b9SBen Warren  * ----------------------------------------------------------------------------
18*09cdd1b9SBen Warren  *
19*09cdd1b9SBen Warren  * This program is free software; you can redistribute it and/or modify
20*09cdd1b9SBen Warren  * it under the terms of the GNU General Public License as published by
21*09cdd1b9SBen Warren  * the Free Software Foundation; either version 2 of the License, or
22*09cdd1b9SBen Warren  * (at your option) any later version.
23*09cdd1b9SBen Warren  *
24*09cdd1b9SBen Warren  * This program is distributed in the hope that it will be useful,
25*09cdd1b9SBen Warren  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26*09cdd1b9SBen Warren  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27*09cdd1b9SBen Warren  * GNU General Public License for more details.
28*09cdd1b9SBen Warren  *
29*09cdd1b9SBen Warren  *  You should have received a copy of the GNU General Public License
30*09cdd1b9SBen Warren  *  along with this program; if not, write to the Free Software
31*09cdd1b9SBen Warren  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32*09cdd1b9SBen Warren  * ----------------------------------------------------------------------------
33*09cdd1b9SBen Warren 
34*09cdd1b9SBen Warren  * Modifications:
35*09cdd1b9SBen Warren  * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot.
36*09cdd1b9SBen Warren  * ver  1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors
37*09cdd1b9SBen Warren  *
38*09cdd1b9SBen Warren  */
39*09cdd1b9SBen Warren #include <common.h>
40*09cdd1b9SBen Warren #include <command.h>
41*09cdd1b9SBen Warren #include <net.h>
42*09cdd1b9SBen Warren #include <miiphy.h>
43*09cdd1b9SBen Warren #include <asm/arch/emac_defs.h>
44*09cdd1b9SBen Warren 
45*09cdd1b9SBen Warren #ifdef CONFIG_DRIVER_TI_EMAC
46*09cdd1b9SBen Warren 
47*09cdd1b9SBen Warren #ifdef CONFIG_CMD_NET
48*09cdd1b9SBen Warren 
49*09cdd1b9SBen Warren unsigned int	emac_dbg = 0;
50*09cdd1b9SBen Warren #define debug_emac(fmt,args...)	if (emac_dbg) printf(fmt,##args)
51*09cdd1b9SBen Warren 
52*09cdd1b9SBen Warren /* Internal static functions */
53*09cdd1b9SBen Warren static int davinci_eth_hw_init (void);
54*09cdd1b9SBen Warren static int davinci_eth_open (void);
55*09cdd1b9SBen Warren static int davinci_eth_close (void);
56*09cdd1b9SBen Warren static int davinci_eth_send_packet (volatile void *packet, int length);
57*09cdd1b9SBen Warren static int davinci_eth_rcv_packet (void);
58*09cdd1b9SBen Warren static void davinci_eth_mdio_enable(void);
59*09cdd1b9SBen Warren 
60*09cdd1b9SBen Warren static int gen_init_phy(int phy_addr);
61*09cdd1b9SBen Warren static int gen_is_phy_connected(int phy_addr);
62*09cdd1b9SBen Warren static int gen_get_link_speed(int phy_addr);
63*09cdd1b9SBen Warren static int gen_auto_negotiate(int phy_addr);
64*09cdd1b9SBen Warren 
65*09cdd1b9SBen Warren /* Wrappers exported to the U-Boot proper */
66*09cdd1b9SBen Warren int eth_hw_init(void)
67*09cdd1b9SBen Warren {
68*09cdd1b9SBen Warren 	return(davinci_eth_hw_init());
69*09cdd1b9SBen Warren }
70*09cdd1b9SBen Warren 
71*09cdd1b9SBen Warren int eth_init(bd_t * bd)
72*09cdd1b9SBen Warren {
73*09cdd1b9SBen Warren 	return(davinci_eth_open());
74*09cdd1b9SBen Warren }
75*09cdd1b9SBen Warren 
76*09cdd1b9SBen Warren void eth_halt(void)
77*09cdd1b9SBen Warren {
78*09cdd1b9SBen Warren 	davinci_eth_close();
79*09cdd1b9SBen Warren }
80*09cdd1b9SBen Warren 
81*09cdd1b9SBen Warren int eth_send(volatile void *packet, int length)
82*09cdd1b9SBen Warren {
83*09cdd1b9SBen Warren 	return(davinci_eth_send_packet(packet, length));
84*09cdd1b9SBen Warren }
85*09cdd1b9SBen Warren 
86*09cdd1b9SBen Warren int eth_rx(void)
87*09cdd1b9SBen Warren {
88*09cdd1b9SBen Warren 	return(davinci_eth_rcv_packet());
89*09cdd1b9SBen Warren }
90*09cdd1b9SBen Warren 
91*09cdd1b9SBen Warren void eth_mdio_enable(void)
92*09cdd1b9SBen Warren {
93*09cdd1b9SBen Warren 	davinci_eth_mdio_enable();
94*09cdd1b9SBen Warren }
95*09cdd1b9SBen Warren /* End of wrappers */
96*09cdd1b9SBen Warren 
97*09cdd1b9SBen Warren 
98*09cdd1b9SBen Warren static u_int8_t davinci_eth_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
99*09cdd1b9SBen Warren 
100*09cdd1b9SBen Warren /*
101*09cdd1b9SBen Warren  * This function must be called before emac_open() if you want to override
102*09cdd1b9SBen Warren  * the default mac address.
103*09cdd1b9SBen Warren  */
104*09cdd1b9SBen Warren void davinci_eth_set_mac_addr(const u_int8_t *addr)
105*09cdd1b9SBen Warren {
106*09cdd1b9SBen Warren 	int i;
107*09cdd1b9SBen Warren 
108*09cdd1b9SBen Warren 	for (i = 0; i < sizeof (davinci_eth_mac_addr); i++) {
109*09cdd1b9SBen Warren 		davinci_eth_mac_addr[i] = addr[i];
110*09cdd1b9SBen Warren 	}
111*09cdd1b9SBen Warren }
112*09cdd1b9SBen Warren 
113*09cdd1b9SBen Warren /* EMAC Addresses */
114*09cdd1b9SBen Warren static volatile emac_regs	*adap_emac = (emac_regs *)EMAC_BASE_ADDR;
115*09cdd1b9SBen Warren static volatile ewrap_regs	*adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR;
116*09cdd1b9SBen Warren static volatile mdio_regs	*adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR;
117*09cdd1b9SBen Warren 
118*09cdd1b9SBen Warren /* EMAC descriptors */
119*09cdd1b9SBen Warren static volatile emac_desc	*emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
120*09cdd1b9SBen Warren static volatile emac_desc	*emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
121*09cdd1b9SBen Warren static volatile emac_desc	*emac_rx_active_head = 0;
122*09cdd1b9SBen Warren static volatile emac_desc	*emac_rx_active_tail = 0;
123*09cdd1b9SBen Warren static int			emac_rx_queue_active = 0;
124*09cdd1b9SBen Warren 
125*09cdd1b9SBen Warren /* Receive packet buffers */
126*09cdd1b9SBen Warren static unsigned char		emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
127*09cdd1b9SBen Warren 
128*09cdd1b9SBen Warren /* PHY address for a discovered PHY (0xff - not found) */
129*09cdd1b9SBen Warren static volatile u_int8_t	active_phy_addr = 0xff;
130*09cdd1b9SBen Warren 
131*09cdd1b9SBen Warren phy_t				phy;
132*09cdd1b9SBen Warren 
133*09cdd1b9SBen Warren static void davinci_eth_mdio_enable(void)
134*09cdd1b9SBen Warren {
135*09cdd1b9SBen Warren 	u_int32_t	clkdiv;
136*09cdd1b9SBen Warren 
137*09cdd1b9SBen Warren 	clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
138*09cdd1b9SBen Warren 
139*09cdd1b9SBen Warren 	adap_mdio->CONTROL = (clkdiv & 0xff) |
140*09cdd1b9SBen Warren 		MDIO_CONTROL_ENABLE |
141*09cdd1b9SBen Warren 		MDIO_CONTROL_FAULT |
142*09cdd1b9SBen Warren 		MDIO_CONTROL_FAULT_ENABLE;
143*09cdd1b9SBen Warren 
144*09cdd1b9SBen Warren 	while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;}
145*09cdd1b9SBen Warren }
146*09cdd1b9SBen Warren 
147*09cdd1b9SBen Warren /*
148*09cdd1b9SBen Warren  * Tries to find an active connected PHY. Returns 1 if address if found.
149*09cdd1b9SBen Warren  * If no active PHY (or more than one PHY) found returns 0.
150*09cdd1b9SBen Warren  * Sets active_phy_addr variable.
151*09cdd1b9SBen Warren  */
152*09cdd1b9SBen Warren static int davinci_eth_phy_detect(void)
153*09cdd1b9SBen Warren {
154*09cdd1b9SBen Warren 	u_int32_t	phy_act_state;
155*09cdd1b9SBen Warren 	int		i;
156*09cdd1b9SBen Warren 
157*09cdd1b9SBen Warren 	active_phy_addr = 0xff;
158*09cdd1b9SBen Warren 
159*09cdd1b9SBen Warren 	if ((phy_act_state = adap_mdio->ALIVE) == 0)
160*09cdd1b9SBen Warren 		return(0);				/* No active PHYs */
161*09cdd1b9SBen Warren 
162*09cdd1b9SBen Warren 	debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state);
163*09cdd1b9SBen Warren 
164*09cdd1b9SBen Warren 	for (i = 0; i < 32; i++) {
165*09cdd1b9SBen Warren 		if (phy_act_state & (1 << i)) {
166*09cdd1b9SBen Warren 			if (phy_act_state & ~(1 << i))
167*09cdd1b9SBen Warren 				return(0);		/* More than one PHY */
168*09cdd1b9SBen Warren 			else {
169*09cdd1b9SBen Warren 				active_phy_addr = i;
170*09cdd1b9SBen Warren 				return(1);
171*09cdd1b9SBen Warren 			}
172*09cdd1b9SBen Warren 		}
173*09cdd1b9SBen Warren 	}
174*09cdd1b9SBen Warren 
175*09cdd1b9SBen Warren 	return(0);	/* Just to make GCC happy */
176*09cdd1b9SBen Warren }
177*09cdd1b9SBen Warren 
178*09cdd1b9SBen Warren 
179*09cdd1b9SBen Warren /* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
180*09cdd1b9SBen Warren int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
181*09cdd1b9SBen Warren {
182*09cdd1b9SBen Warren 	int	tmp;
183*09cdd1b9SBen Warren 
184*09cdd1b9SBen Warren 	while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
185*09cdd1b9SBen Warren 
186*09cdd1b9SBen Warren 	adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO |
187*09cdd1b9SBen Warren 				MDIO_USERACCESS0_WRITE_READ |
188*09cdd1b9SBen Warren 				((reg_num & 0x1f) << 21) |
189*09cdd1b9SBen Warren 				((phy_addr & 0x1f) << 16);
190*09cdd1b9SBen Warren 
191*09cdd1b9SBen Warren 	/* Wait for command to complete */
192*09cdd1b9SBen Warren 	while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;}
193*09cdd1b9SBen Warren 
194*09cdd1b9SBen Warren 	if (tmp & MDIO_USERACCESS0_ACK) {
195*09cdd1b9SBen Warren 		*data = tmp & 0xffff;
196*09cdd1b9SBen Warren 		return(1);
197*09cdd1b9SBen Warren 	}
198*09cdd1b9SBen Warren 
199*09cdd1b9SBen Warren 	*data = -1;
200*09cdd1b9SBen Warren 	return(0);
201*09cdd1b9SBen Warren }
202*09cdd1b9SBen Warren 
203*09cdd1b9SBen Warren /* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */
204*09cdd1b9SBen Warren int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
205*09cdd1b9SBen Warren {
206*09cdd1b9SBen Warren 
207*09cdd1b9SBen Warren 	while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
208*09cdd1b9SBen Warren 
209*09cdd1b9SBen Warren 	adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO |
210*09cdd1b9SBen Warren 				MDIO_USERACCESS0_WRITE_WRITE |
211*09cdd1b9SBen Warren 				((reg_num & 0x1f) << 21) |
212*09cdd1b9SBen Warren 				((phy_addr & 0x1f) << 16) |
213*09cdd1b9SBen Warren 				(data & 0xffff);
214*09cdd1b9SBen Warren 
215*09cdd1b9SBen Warren 	/* Wait for command to complete */
216*09cdd1b9SBen Warren 	while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
217*09cdd1b9SBen Warren 
218*09cdd1b9SBen Warren 	return(1);
219*09cdd1b9SBen Warren }
220*09cdd1b9SBen Warren 
221*09cdd1b9SBen Warren /* PHY functions for a generic PHY */
222*09cdd1b9SBen Warren static int gen_init_phy(int phy_addr)
223*09cdd1b9SBen Warren {
224*09cdd1b9SBen Warren 	int	ret = 1;
225*09cdd1b9SBen Warren 
226*09cdd1b9SBen Warren 	if (gen_get_link_speed(phy_addr)) {
227*09cdd1b9SBen Warren 		/* Try another time */
228*09cdd1b9SBen Warren 		ret = gen_get_link_speed(phy_addr);
229*09cdd1b9SBen Warren 	}
230*09cdd1b9SBen Warren 
231*09cdd1b9SBen Warren 	return(ret);
232*09cdd1b9SBen Warren }
233*09cdd1b9SBen Warren 
234*09cdd1b9SBen Warren static int gen_is_phy_connected(int phy_addr)
235*09cdd1b9SBen Warren {
236*09cdd1b9SBen Warren 	u_int16_t	dummy;
237*09cdd1b9SBen Warren 
238*09cdd1b9SBen Warren 	return(davinci_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy));
239*09cdd1b9SBen Warren }
240*09cdd1b9SBen Warren 
241*09cdd1b9SBen Warren static int gen_get_link_speed(int phy_addr)
242*09cdd1b9SBen Warren {
243*09cdd1b9SBen Warren 	u_int16_t	tmp;
244*09cdd1b9SBen Warren 
245*09cdd1b9SBen Warren 	if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04))
246*09cdd1b9SBen Warren 		return(1);
247*09cdd1b9SBen Warren 
248*09cdd1b9SBen Warren 	return(0);
249*09cdd1b9SBen Warren }
250*09cdd1b9SBen Warren 
251*09cdd1b9SBen Warren static int gen_auto_negotiate(int phy_addr)
252*09cdd1b9SBen Warren {
253*09cdd1b9SBen Warren 	u_int16_t	tmp;
254*09cdd1b9SBen Warren 
255*09cdd1b9SBen Warren 	if (!davinci_eth_phy_read(phy_addr, PHY_BMCR, &tmp))
256*09cdd1b9SBen Warren 		return(0);
257*09cdd1b9SBen Warren 
258*09cdd1b9SBen Warren 	/* Restart Auto_negotiation  */
259*09cdd1b9SBen Warren 	tmp |= PHY_BMCR_AUTON;
260*09cdd1b9SBen Warren 	davinci_eth_phy_write(phy_addr, PHY_BMCR, tmp);
261*09cdd1b9SBen Warren 
262*09cdd1b9SBen Warren 	/*check AutoNegotiate complete */
263*09cdd1b9SBen Warren 	udelay (10000);
264*09cdd1b9SBen Warren 	if (!davinci_eth_phy_read(phy_addr, PHY_BMSR, &tmp))
265*09cdd1b9SBen Warren 		return(0);
266*09cdd1b9SBen Warren 
267*09cdd1b9SBen Warren 	if (!(tmp & PHY_BMSR_AUTN_COMP))
268*09cdd1b9SBen Warren 		return(0);
269*09cdd1b9SBen Warren 
270*09cdd1b9SBen Warren 	return(gen_get_link_speed(phy_addr));
271*09cdd1b9SBen Warren }
272*09cdd1b9SBen Warren /* End of generic PHY functions */
273*09cdd1b9SBen Warren 
274*09cdd1b9SBen Warren 
275*09cdd1b9SBen Warren #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
276*09cdd1b9SBen Warren static int davinci_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value)
277*09cdd1b9SBen Warren {
278*09cdd1b9SBen Warren 	return(davinci_eth_phy_read(addr, reg, value) ? 0 : 1);
279*09cdd1b9SBen Warren }
280*09cdd1b9SBen Warren 
281*09cdd1b9SBen Warren static int davinci_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value)
282*09cdd1b9SBen Warren {
283*09cdd1b9SBen Warren 	return(davinci_eth_phy_write(addr, reg, value) ? 0 : 1);
284*09cdd1b9SBen Warren }
285*09cdd1b9SBen Warren 
286*09cdd1b9SBen Warren int davinci_eth_miiphy_initialize(bd_t *bis)
287*09cdd1b9SBen Warren {
288*09cdd1b9SBen Warren 	miiphy_register(phy.name, davinci_mii_phy_read, davinci_mii_phy_write);
289*09cdd1b9SBen Warren 
290*09cdd1b9SBen Warren 	return(1);
291*09cdd1b9SBen Warren }
292*09cdd1b9SBen Warren #endif
293*09cdd1b9SBen Warren 
294*09cdd1b9SBen Warren /*
295*09cdd1b9SBen Warren  * This function initializes the emac hardware. It does NOT initialize
296*09cdd1b9SBen Warren  * EMAC modules power or pin multiplexors, that is done by board_init()
297*09cdd1b9SBen Warren  * much earlier in bootup process. Returns 1 on success, 0 otherwise.
298*09cdd1b9SBen Warren  */
299*09cdd1b9SBen Warren static int davinci_eth_hw_init(void)
300*09cdd1b9SBen Warren {
301*09cdd1b9SBen Warren 	u_int32_t	phy_id;
302*09cdd1b9SBen Warren 	u_int16_t	tmp;
303*09cdd1b9SBen Warren 	int		i;
304*09cdd1b9SBen Warren 
305*09cdd1b9SBen Warren 	davinci_eth_mdio_enable();
306*09cdd1b9SBen Warren 
307*09cdd1b9SBen Warren 	for (i = 0; i < 256; i++) {
308*09cdd1b9SBen Warren 		if (adap_mdio->ALIVE)
309*09cdd1b9SBen Warren 			break;
310*09cdd1b9SBen Warren 		udelay(10);
311*09cdd1b9SBen Warren 	}
312*09cdd1b9SBen Warren 
313*09cdd1b9SBen Warren 	if (i >= 256) {
314*09cdd1b9SBen Warren 		printf("No ETH PHY detected!!!\n");
315*09cdd1b9SBen Warren 		return(0);
316*09cdd1b9SBen Warren 	}
317*09cdd1b9SBen Warren 
318*09cdd1b9SBen Warren 	/* Find if a PHY is connected and get it's address */
319*09cdd1b9SBen Warren 	if (!davinci_eth_phy_detect())
320*09cdd1b9SBen Warren 		return(0);
321*09cdd1b9SBen Warren 
322*09cdd1b9SBen Warren 	/* Get PHY ID and initialize phy_ops for a detected PHY */
323*09cdd1b9SBen Warren 	if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) {
324*09cdd1b9SBen Warren 		active_phy_addr = 0xff;
325*09cdd1b9SBen Warren 		return(0);
326*09cdd1b9SBen Warren 	}
327*09cdd1b9SBen Warren 
328*09cdd1b9SBen Warren 	phy_id = (tmp << 16) & 0xffff0000;
329*09cdd1b9SBen Warren 
330*09cdd1b9SBen Warren 	if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) {
331*09cdd1b9SBen Warren 		active_phy_addr = 0xff;
332*09cdd1b9SBen Warren 		return(0);
333*09cdd1b9SBen Warren 	}
334*09cdd1b9SBen Warren 
335*09cdd1b9SBen Warren 	phy_id |= tmp & 0x0000ffff;
336*09cdd1b9SBen Warren 
337*09cdd1b9SBen Warren 	switch (phy_id) {
338*09cdd1b9SBen Warren 		case PHY_LXT972:
339*09cdd1b9SBen Warren 			sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr);
340*09cdd1b9SBen Warren 			phy.init = lxt972_init_phy;
341*09cdd1b9SBen Warren 			phy.is_phy_connected = lxt972_is_phy_connected;
342*09cdd1b9SBen Warren 			phy.get_link_speed = lxt972_get_link_speed;
343*09cdd1b9SBen Warren 			phy.auto_negotiate = lxt972_auto_negotiate;
344*09cdd1b9SBen Warren 			break;
345*09cdd1b9SBen Warren 		case PHY_DP83848:
346*09cdd1b9SBen Warren 			sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr);
347*09cdd1b9SBen Warren 			phy.init = dp83848_init_phy;
348*09cdd1b9SBen Warren 			phy.is_phy_connected = dp83848_is_phy_connected;
349*09cdd1b9SBen Warren 			phy.get_link_speed = dp83848_get_link_speed;
350*09cdd1b9SBen Warren 			phy.auto_negotiate = dp83848_auto_negotiate;
351*09cdd1b9SBen Warren 			break;
352*09cdd1b9SBen Warren 		default:
353*09cdd1b9SBen Warren 			sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr);
354*09cdd1b9SBen Warren 			phy.init = gen_init_phy;
355*09cdd1b9SBen Warren 			phy.is_phy_connected = gen_is_phy_connected;
356*09cdd1b9SBen Warren 			phy.get_link_speed = gen_get_link_speed;
357*09cdd1b9SBen Warren 			phy.auto_negotiate = gen_auto_negotiate;
358*09cdd1b9SBen Warren 	}
359*09cdd1b9SBen Warren 
360*09cdd1b9SBen Warren 	printf("Ethernet PHY: %s\n", phy.name);
361*09cdd1b9SBen Warren 
362*09cdd1b9SBen Warren 	return(1);
363*09cdd1b9SBen Warren }
364*09cdd1b9SBen Warren 
365*09cdd1b9SBen Warren 
366*09cdd1b9SBen Warren /* Eth device open */
367*09cdd1b9SBen Warren static int davinci_eth_open(void)
368*09cdd1b9SBen Warren {
369*09cdd1b9SBen Warren 	dv_reg_p		addr;
370*09cdd1b9SBen Warren 	u_int32_t		clkdiv, cnt;
371*09cdd1b9SBen Warren 	volatile emac_desc	*rx_desc;
372*09cdd1b9SBen Warren 
373*09cdd1b9SBen Warren 	debug_emac("+ emac_open\n");
374*09cdd1b9SBen Warren 
375*09cdd1b9SBen Warren 	/* Reset EMAC module and disable interrupts in wrapper */
376*09cdd1b9SBen Warren 	adap_emac->SOFTRESET = 1;
377*09cdd1b9SBen Warren 	while (adap_emac->SOFTRESET != 0) {;}
378*09cdd1b9SBen Warren 	adap_ewrap->EWCTL = 0;
379*09cdd1b9SBen Warren 	for (cnt = 0; cnt < 5; cnt++) {
380*09cdd1b9SBen Warren 		clkdiv = adap_ewrap->EWCTL;
381*09cdd1b9SBen Warren 	}
382*09cdd1b9SBen Warren 
383*09cdd1b9SBen Warren 	rx_desc = emac_rx_desc;
384*09cdd1b9SBen Warren 
385*09cdd1b9SBen Warren 	adap_emac->TXCONTROL = 0x01;
386*09cdd1b9SBen Warren 	adap_emac->RXCONTROL = 0x01;
387*09cdd1b9SBen Warren 
388*09cdd1b9SBen Warren 	/* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */
389*09cdd1b9SBen Warren 	/* Using channel 0 only - other channels are disabled */
390*09cdd1b9SBen Warren 	adap_emac->MACINDEX = 0;
391*09cdd1b9SBen Warren 	adap_emac->MACADDRHI =
392*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[3] << 24) |
393*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[2] << 16) |
394*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[1] << 8)  |
395*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[0]);
396*09cdd1b9SBen Warren 	adap_emac->MACADDRLO =
397*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[5] << 8) |
398*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[4]);
399*09cdd1b9SBen Warren 
400*09cdd1b9SBen Warren 	adap_emac->MACHASH1 = 0;
401*09cdd1b9SBen Warren 	adap_emac->MACHASH2 = 0;
402*09cdd1b9SBen Warren 
403*09cdd1b9SBen Warren 	/* Set source MAC address - REQUIRED */
404*09cdd1b9SBen Warren 	adap_emac->MACSRCADDRHI =
405*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[3] << 24) |
406*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[2] << 16) |
407*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[1] << 8)  |
408*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[0]);
409*09cdd1b9SBen Warren 	adap_emac->MACSRCADDRLO =
410*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[4] << 8) |
411*09cdd1b9SBen Warren 		(davinci_eth_mac_addr[5]);
412*09cdd1b9SBen Warren 
413*09cdd1b9SBen Warren 	/* Set DMA 8 TX / 8 RX Head pointers to 0 */
414*09cdd1b9SBen Warren 	addr = &adap_emac->TX0HDP;
415*09cdd1b9SBen Warren 	for(cnt = 0; cnt < 16; cnt++)
416*09cdd1b9SBen Warren 		*addr++ = 0;
417*09cdd1b9SBen Warren 
418*09cdd1b9SBen Warren 	addr = &adap_emac->RX0HDP;
419*09cdd1b9SBen Warren 	for(cnt = 0; cnt < 16; cnt++)
420*09cdd1b9SBen Warren 		*addr++ = 0;
421*09cdd1b9SBen Warren 
422*09cdd1b9SBen Warren 	/* Clear Statistics (do this before setting MacControl register) */
423*09cdd1b9SBen Warren 	addr = &adap_emac->RXGOODFRAMES;
424*09cdd1b9SBen Warren 	for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
425*09cdd1b9SBen Warren 		*addr++ = 0;
426*09cdd1b9SBen Warren 
427*09cdd1b9SBen Warren 	/* No multicast addressing */
428*09cdd1b9SBen Warren 	adap_emac->MACHASH1 = 0;
429*09cdd1b9SBen Warren 	adap_emac->MACHASH2 = 0;
430*09cdd1b9SBen Warren 
431*09cdd1b9SBen Warren 	/* Create RX queue and set receive process in place */
432*09cdd1b9SBen Warren 	emac_rx_active_head = emac_rx_desc;
433*09cdd1b9SBen Warren 	for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
434*09cdd1b9SBen Warren 		rx_desc->next = (u_int32_t)(rx_desc + 1);
435*09cdd1b9SBen Warren 		rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
436*09cdd1b9SBen Warren 		rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
437*09cdd1b9SBen Warren 		rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
438*09cdd1b9SBen Warren 		rx_desc++;
439*09cdd1b9SBen Warren 	}
440*09cdd1b9SBen Warren 
441*09cdd1b9SBen Warren 	/* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
442*09cdd1b9SBen Warren 	rx_desc--;
443*09cdd1b9SBen Warren 	rx_desc->next = 0;
444*09cdd1b9SBen Warren 	emac_rx_active_tail = rx_desc;
445*09cdd1b9SBen Warren 	emac_rx_queue_active = 1;
446*09cdd1b9SBen Warren 
447*09cdd1b9SBen Warren 	/* Enable TX/RX */
448*09cdd1b9SBen Warren 	adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE;
449*09cdd1b9SBen Warren 	adap_emac->RXBUFFEROFFSET = 0;
450*09cdd1b9SBen Warren 
451*09cdd1b9SBen Warren 	/* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
452*09cdd1b9SBen Warren 	adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN;
453*09cdd1b9SBen Warren 
454*09cdd1b9SBen Warren 	/* Enable ch 0 only */
455*09cdd1b9SBen Warren 	adap_emac->RXUNICASTSET = 0x01;
456*09cdd1b9SBen Warren 
457*09cdd1b9SBen Warren 	/* Enable MII interface and Full duplex mode */
458*09cdd1b9SBen Warren 	adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE);
459*09cdd1b9SBen Warren 
460*09cdd1b9SBen Warren 	/* Init MDIO & get link state */
461*09cdd1b9SBen Warren 	clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
462*09cdd1b9SBen Warren 	adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT);
463*09cdd1b9SBen Warren 
464*09cdd1b9SBen Warren 	if (!phy.get_link_speed(active_phy_addr))
465*09cdd1b9SBen Warren 		return(0);
466*09cdd1b9SBen Warren 
467*09cdd1b9SBen Warren 	/* Start receive process */
468*09cdd1b9SBen Warren 	adap_emac->RX0HDP = (u_int32_t)emac_rx_desc;
469*09cdd1b9SBen Warren 
470*09cdd1b9SBen Warren 	debug_emac("- emac_open\n");
471*09cdd1b9SBen Warren 
472*09cdd1b9SBen Warren 	return(1);
473*09cdd1b9SBen Warren }
474*09cdd1b9SBen Warren 
475*09cdd1b9SBen Warren /* EMAC Channel Teardown */
476*09cdd1b9SBen Warren static void davinci_eth_ch_teardown(int ch)
477*09cdd1b9SBen Warren {
478*09cdd1b9SBen Warren 	dv_reg		dly = 0xff;
479*09cdd1b9SBen Warren 	dv_reg		cnt;
480*09cdd1b9SBen Warren 
481*09cdd1b9SBen Warren 	debug_emac("+ emac_ch_teardown\n");
482*09cdd1b9SBen Warren 
483*09cdd1b9SBen Warren 	if (ch == EMAC_CH_TX) {
484*09cdd1b9SBen Warren 		/* Init TX channel teardown */
485*09cdd1b9SBen Warren 		adap_emac->TXTEARDOWN = 1;
486*09cdd1b9SBen Warren 		for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) {
487*09cdd1b9SBen Warren 			/* Wait here for Tx teardown completion interrupt to occur
488*09cdd1b9SBen Warren 			 * Note: A task delay can be called here to pend rather than
489*09cdd1b9SBen Warren 			 * occupying CPU cycles - anyway it has been found that teardown
490*09cdd1b9SBen Warren 			 * takes very few cpu cycles and does not affect functionality */
491*09cdd1b9SBen Warren 			 dly--;
492*09cdd1b9SBen Warren 			 udelay(1);
493*09cdd1b9SBen Warren 			 if (dly == 0)
494*09cdd1b9SBen Warren 				break;
495*09cdd1b9SBen Warren 		}
496*09cdd1b9SBen Warren 		adap_emac->TX0CP = cnt;
497*09cdd1b9SBen Warren 		adap_emac->TX0HDP = 0;
498*09cdd1b9SBen Warren 	} else {
499*09cdd1b9SBen Warren 		/* Init RX channel teardown */
500*09cdd1b9SBen Warren 		adap_emac->RXTEARDOWN = 1;
501*09cdd1b9SBen Warren 		for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) {
502*09cdd1b9SBen Warren 			/* Wait here for Rx teardown completion interrupt to occur
503*09cdd1b9SBen Warren 			 * Note: A task delay can be called here to pend rather than
504*09cdd1b9SBen Warren 			 * occupying CPU cycles - anyway it has been found that teardown
505*09cdd1b9SBen Warren 			 * takes very few cpu cycles and does not affect functionality */
506*09cdd1b9SBen Warren 			 dly--;
507*09cdd1b9SBen Warren 			 udelay(1);
508*09cdd1b9SBen Warren 			 if (dly == 0)
509*09cdd1b9SBen Warren 				break;
510*09cdd1b9SBen Warren 		}
511*09cdd1b9SBen Warren 		adap_emac->RX0CP = cnt;
512*09cdd1b9SBen Warren 		adap_emac->RX0HDP = 0;
513*09cdd1b9SBen Warren 	}
514*09cdd1b9SBen Warren 
515*09cdd1b9SBen Warren 	debug_emac("- emac_ch_teardown\n");
516*09cdd1b9SBen Warren }
517*09cdd1b9SBen Warren 
518*09cdd1b9SBen Warren /* Eth device close */
519*09cdd1b9SBen Warren static int davinci_eth_close(void)
520*09cdd1b9SBen Warren {
521*09cdd1b9SBen Warren 	debug_emac("+ emac_close\n");
522*09cdd1b9SBen Warren 
523*09cdd1b9SBen Warren 	davinci_eth_ch_teardown(EMAC_CH_TX);	/* TX Channel teardown */
524*09cdd1b9SBen Warren 	davinci_eth_ch_teardown(EMAC_CH_RX);	/* RX Channel teardown */
525*09cdd1b9SBen Warren 
526*09cdd1b9SBen Warren 	/* Reset EMAC module and disable interrupts in wrapper */
527*09cdd1b9SBen Warren 	adap_emac->SOFTRESET = 1;
528*09cdd1b9SBen Warren 	adap_ewrap->EWCTL = 0;
529*09cdd1b9SBen Warren 
530*09cdd1b9SBen Warren 	debug_emac("- emac_close\n");
531*09cdd1b9SBen Warren 	return(1);
532*09cdd1b9SBen Warren }
533*09cdd1b9SBen Warren 
534*09cdd1b9SBen Warren static int tx_send_loop = 0;
535*09cdd1b9SBen Warren 
536*09cdd1b9SBen Warren /*
537*09cdd1b9SBen Warren  * This function sends a single packet on the network and returns
538*09cdd1b9SBen Warren  * positive number (number of bytes transmitted) or negative for error
539*09cdd1b9SBen Warren  */
540*09cdd1b9SBen Warren static int davinci_eth_send_packet (volatile void *packet, int length)
541*09cdd1b9SBen Warren {
542*09cdd1b9SBen Warren 	int ret_status = -1;
543*09cdd1b9SBen Warren 
544*09cdd1b9SBen Warren 	tx_send_loop = 0;
545*09cdd1b9SBen Warren 
546*09cdd1b9SBen Warren 	/* Return error if no link */
547*09cdd1b9SBen Warren 	if (!phy.get_link_speed (active_phy_addr)) {
548*09cdd1b9SBen Warren 		printf ("WARN: emac_send_packet: No link\n");
549*09cdd1b9SBen Warren 		return (ret_status);
550*09cdd1b9SBen Warren 	}
551*09cdd1b9SBen Warren 
552*09cdd1b9SBen Warren 	/* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
553*09cdd1b9SBen Warren 	if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
554*09cdd1b9SBen Warren 		length = EMAC_MIN_ETHERNET_PKT_SIZE;
555*09cdd1b9SBen Warren 	}
556*09cdd1b9SBen Warren 
557*09cdd1b9SBen Warren 	/* Populate the TX descriptor */
558*09cdd1b9SBen Warren 	emac_tx_desc->next = 0;
559*09cdd1b9SBen Warren 	emac_tx_desc->buffer = (u_int8_t *) packet;
560*09cdd1b9SBen Warren 	emac_tx_desc->buff_off_len = (length & 0xffff);
561*09cdd1b9SBen Warren 	emac_tx_desc->pkt_flag_len = ((length & 0xffff) |
562*09cdd1b9SBen Warren 				      EMAC_CPPI_SOP_BIT |
563*09cdd1b9SBen Warren 				      EMAC_CPPI_OWNERSHIP_BIT |
564*09cdd1b9SBen Warren 				      EMAC_CPPI_EOP_BIT);
565*09cdd1b9SBen Warren 	/* Send the packet */
566*09cdd1b9SBen Warren 	adap_emac->TX0HDP = (unsigned int) emac_tx_desc;
567*09cdd1b9SBen Warren 
568*09cdd1b9SBen Warren 	/* Wait for packet to complete or link down */
569*09cdd1b9SBen Warren 	while (1) {
570*09cdd1b9SBen Warren 		if (!phy.get_link_speed (active_phy_addr)) {
571*09cdd1b9SBen Warren 			davinci_eth_ch_teardown (EMAC_CH_TX);
572*09cdd1b9SBen Warren 			return (ret_status);
573*09cdd1b9SBen Warren 		}
574*09cdd1b9SBen Warren 		if (adap_emac->TXINTSTATRAW & 0x01) {
575*09cdd1b9SBen Warren 			ret_status = length;
576*09cdd1b9SBen Warren 			break;
577*09cdd1b9SBen Warren 		}
578*09cdd1b9SBen Warren 		tx_send_loop++;
579*09cdd1b9SBen Warren 	}
580*09cdd1b9SBen Warren 
581*09cdd1b9SBen Warren 	return (ret_status);
582*09cdd1b9SBen Warren }
583*09cdd1b9SBen Warren 
584*09cdd1b9SBen Warren /*
585*09cdd1b9SBen Warren  * This function handles receipt of a packet from the network
586*09cdd1b9SBen Warren  */
587*09cdd1b9SBen Warren static int davinci_eth_rcv_packet (void)
588*09cdd1b9SBen Warren {
589*09cdd1b9SBen Warren 	volatile emac_desc *rx_curr_desc;
590*09cdd1b9SBen Warren 	volatile emac_desc *curr_desc;
591*09cdd1b9SBen Warren 	volatile emac_desc *tail_desc;
592*09cdd1b9SBen Warren 	int status, ret = -1;
593*09cdd1b9SBen Warren 
594*09cdd1b9SBen Warren 	rx_curr_desc = emac_rx_active_head;
595*09cdd1b9SBen Warren 	status = rx_curr_desc->pkt_flag_len;
596*09cdd1b9SBen Warren 	if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
597*09cdd1b9SBen Warren 		if (status & EMAC_CPPI_RX_ERROR_FRAME) {
598*09cdd1b9SBen Warren 			/* Error in packet - discard it and requeue desc */
599*09cdd1b9SBen Warren 			printf ("WARN: emac_rcv_pkt: Error in packet\n");
600*09cdd1b9SBen Warren 		} else {
601*09cdd1b9SBen Warren 			NetReceive (rx_curr_desc->buffer,
602*09cdd1b9SBen Warren 				    (rx_curr_desc->buff_off_len & 0xffff));
603*09cdd1b9SBen Warren 			ret = rx_curr_desc->buff_off_len & 0xffff;
604*09cdd1b9SBen Warren 		}
605*09cdd1b9SBen Warren 
606*09cdd1b9SBen Warren 		/* Ack received packet descriptor */
607*09cdd1b9SBen Warren 		adap_emac->RX0CP = (unsigned int) rx_curr_desc;
608*09cdd1b9SBen Warren 		curr_desc = rx_curr_desc;
609*09cdd1b9SBen Warren 		emac_rx_active_head =
610*09cdd1b9SBen Warren 			(volatile emac_desc *) rx_curr_desc->next;
611*09cdd1b9SBen Warren 
612*09cdd1b9SBen Warren 		if (status & EMAC_CPPI_EOQ_BIT) {
613*09cdd1b9SBen Warren 			if (emac_rx_active_head) {
614*09cdd1b9SBen Warren 				adap_emac->RX0HDP =
615*09cdd1b9SBen Warren 					(unsigned int) emac_rx_active_head;
616*09cdd1b9SBen Warren 			} else {
617*09cdd1b9SBen Warren 				emac_rx_queue_active = 0;
618*09cdd1b9SBen Warren 				printf ("INFO:emac_rcv_packet: RX Queue not active\n");
619*09cdd1b9SBen Warren 			}
620*09cdd1b9SBen Warren 		}
621*09cdd1b9SBen Warren 
622*09cdd1b9SBen Warren 		/* Recycle RX descriptor */
623*09cdd1b9SBen Warren 		rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
624*09cdd1b9SBen Warren 		rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
625*09cdd1b9SBen Warren 		rx_curr_desc->next = 0;
626*09cdd1b9SBen Warren 
627*09cdd1b9SBen Warren 		if (emac_rx_active_head == 0) {
628*09cdd1b9SBen Warren 			printf ("INFO: emac_rcv_pkt: active queue head = 0\n");
629*09cdd1b9SBen Warren 			emac_rx_active_head = curr_desc;
630*09cdd1b9SBen Warren 			emac_rx_active_tail = curr_desc;
631*09cdd1b9SBen Warren 			if (emac_rx_queue_active != 0) {
632*09cdd1b9SBen Warren 				adap_emac->RX0HDP =
633*09cdd1b9SBen Warren 					(unsigned int) emac_rx_active_head;
634*09cdd1b9SBen Warren 				printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
635*09cdd1b9SBen Warren 				emac_rx_queue_active = 1;
636*09cdd1b9SBen Warren 			}
637*09cdd1b9SBen Warren 		} else {
638*09cdd1b9SBen Warren 			tail_desc = emac_rx_active_tail;
639*09cdd1b9SBen Warren 			emac_rx_active_tail = curr_desc;
640*09cdd1b9SBen Warren 			tail_desc->next = (unsigned int) curr_desc;
641*09cdd1b9SBen Warren 			status = tail_desc->pkt_flag_len;
642*09cdd1b9SBen Warren 			if (status & EMAC_CPPI_EOQ_BIT) {
643*09cdd1b9SBen Warren 				adap_emac->RX0HDP = (unsigned int) curr_desc;
644*09cdd1b9SBen Warren 				status &= ~EMAC_CPPI_EOQ_BIT;
645*09cdd1b9SBen Warren 				tail_desc->pkt_flag_len = status;
646*09cdd1b9SBen Warren 			}
647*09cdd1b9SBen Warren 		}
648*09cdd1b9SBen Warren 		return (ret);
649*09cdd1b9SBen Warren 	}
650*09cdd1b9SBen Warren 	return (0);
651*09cdd1b9SBen Warren }
652*09cdd1b9SBen Warren 
653*09cdd1b9SBen Warren #endif /* CONFIG_CMD_NET */
654*09cdd1b9SBen Warren 
655*09cdd1b9SBen Warren #endif /* CONFIG_DRIVER_TI_EMAC */
656