xref: /rk3399_rockchip-uboot/drivers/net/macb.c (revision 2439e4bfa111babf4bc07ba20efbf3e36036813e)
1*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
2*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2005-2006 Atmel Corporation
3*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
4*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * This program is free software; you can redistribute it and/or modify
5*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * it under the terms of the GNU General Public License as published by
6*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * the Free Software Foundation; either version 2 of the License, or
7*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * (at your option) any later version.
8*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
9*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * This program is distributed in the hope that it will be useful,
10*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * GNU General Public License for more details.
13*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
14*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * You should have received a copy of the GNU General Public License
15*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * along with this program; if not, write to the Free Software
16*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
18*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
19*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
20*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_MACB) \
21*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	&& (defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_MII))
22*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
23*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
24*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * The u-boot networking stack is a little weird.  It seems like the
25*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * networking core allocates receive buffers up front without any
26*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * regard to the hardware that's supposed to actually receive those
27*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * packets.
28*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
29*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * The MACB receives packets into 128-byte receive buffers, so the
30*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * buffers allocated by the core isn't very practical to use.  We'll
31*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * allocate our own, but we need one such buffer in case a packet
32*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * wraps around the DMA ring so that we have to copy it.
33*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
34*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * Therefore, define CFG_RX_ETH_BUFFER to 1 in the board-specific
35*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * configuration header.  This way, the core allocates one RX buffer
36*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * and one TX buffer, each of which can hold a ethernet packet of
37*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * maximum size.
38*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
39*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * For some reason, the networking core unconditionally specifies a
40*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * 32-byte packet "alignment" (which really should be called
41*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * "padding").  MACB shouldn't need that, but we'll refrain from any
42*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * core modifications here...
43*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
44*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
45*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h>
46*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h>
47*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
48*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <linux/mii.h>
49*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
50*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/dma-mapping.h>
51*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/clk.h>
52*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
53*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include "macb.h"
54*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
55*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define barrier() asm volatile("" ::: "memory")
56*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
57*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_RX_BUFFER_SIZE		4096
58*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_RX_RING_SIZE		(CFG_MACB_RX_BUFFER_SIZE / 128)
59*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_TX_RING_SIZE		16
60*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_TX_TIMEOUT		1000
61*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_AUTONEG_TIMEOUT	5000000
62*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
63*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc {
64*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32	addr;
65*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32	ctrl;
66*2439e4bfSJean-Christophe PLAGNIOL-VILLARD };
67*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
68*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_USED		0x00000001
69*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_WRAP		0x00000002
70*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
71*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRMLEN_MASK	0x00000fff
72*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_START	0x00004000
73*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_END		0x00008000
74*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_TYPEID_MATCH	0x00400000
75*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR4_MATCH	0x00800000
76*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR3_MATCH	0x01000000
77*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR2_MATCH	0x02000000
78*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR1_MATCH	0x04000000
79*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_BROADCAST		0x80000000
80*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
81*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRMLEN_MASK	0x000007ff
82*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRAME_END		0x00008000
83*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_NOCRC		0x00010000
84*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_EXHAUSTED		0x08000000
85*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_UNDERRUN		0x10000000
86*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_MAXRETRY		0x20000000
87*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_WRAP		0x40000000
88*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_USED		0x80000000
89*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
90*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device {
91*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	void			*regs;
92*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
93*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned int		rx_tail;
94*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned int		tx_head;
95*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned int		tx_tail;
96*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
97*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	void			*rx_buffer;
98*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	void			*tx_buffer;
99*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct macb_dma_desc	*rx_ring;
100*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct macb_dma_desc	*tx_ring;
101*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
102*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long		rx_buffer_dma;
103*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long		rx_ring_dma;
104*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long		tx_ring_dma;
105*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
106*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	const struct device	*dev;
107*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct eth_device	netdev;
108*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned short		phy_addr;
109*2439e4bfSJean-Christophe PLAGNIOL-VILLARD };
110*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
111*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
112*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
113*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
114*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long netctl;
115*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long netstat;
116*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long frame;
117*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
118*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl = macb_readl(macb, NCR);
119*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl |= MACB_BIT(MPE);
120*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, NCR, netctl);
121*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
122*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	frame = (MACB_BF(SOF, 1)
123*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(RW, 1)
124*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(PHYA, macb->phy_addr)
125*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(REGA, reg)
126*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(CODE, 2)
127*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(DATA, value));
128*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, MAN, frame);
129*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
130*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	do {
131*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		netstat = macb_readl(macb, NSR);
132*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} while (!(netstat & MACB_BIT(IDLE)));
133*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
134*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl = macb_readl(macb, NCR);
135*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl &= ~MACB_BIT(MPE);
136*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, NCR, netctl);
137*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
138*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
139*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
140*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
141*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long netctl;
142*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long netstat;
143*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long frame;
144*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
145*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl = macb_readl(macb, NCR);
146*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl |= MACB_BIT(MPE);
147*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, NCR, netctl);
148*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
149*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	frame = (MACB_BF(SOF, 1)
150*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(RW, 2)
151*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(PHYA, macb->phy_addr)
152*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(REGA, reg)
153*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(CODE, 2));
154*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, MAN, frame);
155*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
156*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	do {
157*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		netstat = macb_readl(macb, NSR);
158*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} while (!(netstat & MACB_BIT(IDLE)));
159*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
160*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	frame = macb_readl(macb, MAN);
161*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
162*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl = macb_readl(macb, NCR);
163*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl &= ~MACB_BIT(MPE);
164*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, NCR, netctl);
165*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
166*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return MACB_BFEXT(DATA, frame);
167*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
168*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
169*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_NET)
170*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
171*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_send(struct eth_device *netdev, volatile void *packet,
172*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		     int length)
173*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
174*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct macb_device *macb = to_macb(netdev);
175*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long paddr, ctrl;
176*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned int tx_head = macb->tx_head;
177*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
178*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
179*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	paddr = dma_map_single(packet, length, DMA_TO_DEVICE);
180*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
181*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	ctrl = length & TXBUF_FRMLEN_MASK;
182*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	ctrl |= TXBUF_FRAME_END;
183*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (tx_head == (CFG_MACB_TX_RING_SIZE - 1)) {
184*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		ctrl |= TXBUF_WRAP;
185*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		macb->tx_head = 0;
186*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else
187*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		macb->tx_head++;
188*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
189*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb->tx_ring[tx_head].ctrl = ctrl;
190*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb->tx_ring[tx_head].addr = paddr;
191*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	barrier();
192*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
193*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
194*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/*
195*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 * I guess this is necessary because the networking core may
196*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 * re-use the transmit buffer as soon as we return...
197*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 */
198*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i <= CFG_MACB_TX_TIMEOUT; i++) {
199*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		barrier();
200*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		ctrl = macb->tx_ring[tx_head].ctrl;
201*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (ctrl & TXBUF_USED)
202*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
203*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(1);
204*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
205*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
206*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dma_unmap_single(packet, length, paddr);
207*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
208*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (i <= CFG_MACB_TX_TIMEOUT) {
209*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (ctrl & TXBUF_UNDERRUN)
210*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("%s: TX underrun\n", netdev->name);
211*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (ctrl & TXBUF_EXHAUSTED)
212*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("%s: TX buffers exhausted in mid frame\n",
213*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			       netdev->name);
214*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else {
215*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s: TX timeout\n", netdev->name);
216*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
217*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
218*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* No one cares anyway */
219*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
220*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
221*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
222*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void reclaim_rx_buffers(struct macb_device *macb,
223*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			       unsigned int new_tail)
224*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
225*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned int i;
226*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
227*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	i = macb->rx_tail;
228*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (i > new_tail) {
229*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		macb->rx_ring[i].addr &= ~RXADDR_USED;
230*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		i++;
231*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (i > CFG_MACB_RX_RING_SIZE)
232*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			i = 0;
233*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
234*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
235*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (i < new_tail) {
236*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		macb->rx_ring[i].addr &= ~RXADDR_USED;
237*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		i++;
238*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
239*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
240*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	barrier();
241*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb->rx_tail = new_tail;
242*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
243*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
244*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_recv(struct eth_device *netdev)
245*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
246*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct macb_device *macb = to_macb(netdev);
247*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned int rx_tail = macb->rx_tail;
248*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	void *buffer;
249*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int length;
250*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int wrapped = 0;
251*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 status;
252*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
253*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (;;) {
254*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED))
255*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			return -1;
256*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
257*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		status = macb->rx_ring[rx_tail].ctrl;
258*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (status & RXBUF_FRAME_START) {
259*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (rx_tail != macb->rx_tail)
260*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				reclaim_rx_buffers(macb, rx_tail);
261*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			wrapped = 0;
262*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
263*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
264*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (status & RXBUF_FRAME_END) {
265*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			buffer = macb->rx_buffer + 128 * macb->rx_tail;
266*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			length = status & RXBUF_FRMLEN_MASK;
267*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (wrapped) {
268*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				unsigned int headlen, taillen;
269*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
270*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				headlen = 128 * (CFG_MACB_RX_RING_SIZE
271*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 						 - macb->rx_tail);
272*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				taillen = length - headlen;
273*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				memcpy((void *)NetRxPackets[0],
274*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				       buffer, headlen);
275*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				memcpy((void *)NetRxPackets[0] + headlen,
276*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				       macb->rx_buffer, taillen);
277*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				buffer = (void *)NetRxPackets[0];
278*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
279*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
280*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			NetReceive(buffer, length);
281*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (++rx_tail >= CFG_MACB_RX_RING_SIZE)
282*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				rx_tail = 0;
283*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			reclaim_rx_buffers(macb, rx_tail);
284*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		} else {
285*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (++rx_tail >= CFG_MACB_RX_RING_SIZE) {
286*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				wrapped = 1;
287*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				rx_tail = 0;
288*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
289*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
290*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		barrier();
291*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
292*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
293*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
294*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
295*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
296*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_phy_reset(struct macb_device *macb)
297*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
298*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct eth_device *netdev = &macb->netdev;
299*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
300*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 status, adv;
301*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
302*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	adv = ADVERTISE_CSMA | ADVERTISE_ALL;
303*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_mdio_write(macb, MII_ADVERTISE, adv);
304*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s: Starting autonegotiation...\n", netdev->name);
305*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
306*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					 | BMCR_ANRESTART));
307*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
308*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
309*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		status = macb_mdio_read(macb, MII_BMSR);
310*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (status & BMSR_ANEGCOMPLETE)
311*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
312*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(100);
313*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
314*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
315*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (status & BMSR_ANEGCOMPLETE)
316*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s: Autonegotiation complete\n", netdev->name);
317*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	else
318*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s: Autonegotiation timed out (status=0x%04x)\n",
319*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       netdev->name, status);
320*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
321*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
322*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_phy_init(struct macb_device *macb)
323*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
324*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct eth_device *netdev = &macb->netdev;
325*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 ncfgr;
326*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 phy_id, status, adv, lpa;
327*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int media, speed, duplex;
328*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
329*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
330*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Check if the PHY is up to snuff... */
331*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_id = macb_mdio_read(macb, MII_PHYSID1);
332*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (phy_id == 0xffff) {
333*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s: No PHY present\n", netdev->name);
334*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
335*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
336*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
337*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	status = macb_mdio_read(macb, MII_BMSR);
338*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!(status & BMSR_LSTATUS)) {
339*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Try to re-negotiate if we don't have link already. */
340*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		macb_phy_reset(macb);
341*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
342*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
343*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			status = macb_mdio_read(macb, MII_BMSR);
344*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (status & BMSR_LSTATUS)
345*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				break;
346*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			udelay(100);
347*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
348*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
349*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
350*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!(status & BMSR_LSTATUS)) {
351*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s: link down (status: 0x%04x)\n",
352*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       netdev->name, status);
353*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
354*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else {
355*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		adv = macb_mdio_read(macb, MII_ADVERTISE);
356*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		lpa = macb_mdio_read(macb, MII_LPA);
357*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		media = mii_nway_result(lpa & adv);
358*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
359*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			 ? 1 : 0);
360*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		duplex = (media & ADVERTISE_FULL) ? 1 : 0;
361*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
362*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       netdev->name,
363*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       speed ? "100" : "10",
364*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       duplex ? "full" : "half",
365*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       lpa);
366*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
367*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		ncfgr = macb_readl(macb, NCFGR);
368*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
369*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (speed)
370*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			ncfgr |= MACB_BIT(SPD);
371*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (duplex)
372*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			ncfgr |= MACB_BIT(FD);
373*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		macb_writel(macb, NCFGR, ncfgr);
374*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 1;
375*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
376*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
377*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
378*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_init(struct eth_device *netdev, bd_t *bd)
379*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
380*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct macb_device *macb = to_macb(netdev);
381*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long paddr;
382*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 hwaddr_bottom;
383*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 hwaddr_top;
384*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
385*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
386*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/*
387*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 * macb_halt should have been called at some point before now,
388*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 * so we'll assume the controller is idle.
389*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 */
390*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
391*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* initialize DMA descriptors */
392*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	paddr = macb->rx_buffer_dma;
393*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CFG_MACB_RX_RING_SIZE; i++) {
394*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (i == (CFG_MACB_RX_RING_SIZE - 1))
395*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			paddr |= RXADDR_WRAP;
396*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		macb->rx_ring[i].addr = paddr;
397*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		macb->rx_ring[i].ctrl = 0;
398*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		paddr += 128;
399*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
400*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < CFG_MACB_TX_RING_SIZE; i++) {
401*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		macb->tx_ring[i].addr = 0;
402*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (i == (CFG_MACB_TX_RING_SIZE - 1))
403*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
404*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		else
405*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			macb->tx_ring[i].ctrl = TXBUF_USED;
406*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
407*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb->rx_tail = macb->tx_head = macb->tx_tail = 0;
408*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
409*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, RBQP, macb->rx_ring_dma);
410*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, TBQP, macb->tx_ring_dma);
411*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
412*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* set hardware address */
413*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	hwaddr_bottom = cpu_to_le32(*((u32 *)netdev->enetaddr));
414*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, SA1B, hwaddr_bottom);
415*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	hwaddr_top = cpu_to_le16(*((u16 *)(netdev->enetaddr + 4)));
416*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, SA1T, hwaddr_top);
417*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
418*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* choose RMII or MII mode. This depends on the board */
419*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_RMII
420*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, USRIO, 0);
421*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #else
422*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, USRIO, MACB_BIT(MII));
423*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
424*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
425*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!macb_phy_init(macb))
426*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
427*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
428*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Enable TX and RX */
429*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE));
430*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
431*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 1;
432*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
433*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
434*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_halt(struct eth_device *netdev)
435*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
436*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct macb_device *macb = to_macb(netdev);
437*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 ncr, tsr;
438*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
439*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Halt the controller and wait for any ongoing transmission to end. */
440*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	ncr = macb_readl(macb, NCR);
441*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	ncr |= MACB_BIT(THALT);
442*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, NCR, ncr);
443*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
444*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	do {
445*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tsr = macb_readl(macb, TSR);
446*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} while (tsr & MACB_BIT(TGO));
447*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
448*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Disable TX and RX, and clear statistics */
449*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, NCR, MACB_BIT(CLRSTAT));
450*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
451*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
452*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
453*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
454*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct macb_device *macb;
455*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct eth_device *netdev;
456*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long macb_hz;
457*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 ncfgr;
458*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
459*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb = malloc(sizeof(struct macb_device));
460*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!macb) {
461*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("Error: Failed to allocate memory for MACB%d\n", id);
462*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return -1;
463*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
464*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	memset(macb, 0, sizeof(struct macb_device));
465*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
466*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netdev = &macb->netdev;
467*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
468*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb->rx_buffer = dma_alloc_coherent(CFG_MACB_RX_BUFFER_SIZE,
469*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					     &macb->rx_buffer_dma);
470*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb->rx_ring = dma_alloc_coherent(CFG_MACB_RX_RING_SIZE
471*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					   * sizeof(struct macb_dma_desc),
472*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					   &macb->rx_ring_dma);
473*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb->tx_ring = dma_alloc_coherent(CFG_MACB_TX_RING_SIZE
474*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					   * sizeof(struct macb_dma_desc),
475*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					   &macb->tx_ring_dma);
476*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
477*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb->regs = regs;
478*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb->phy_addr = phy_addr;
479*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
480*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	sprintf(netdev->name, "macb%d", id);
481*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netdev->init = macb_init;
482*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netdev->halt = macb_halt;
483*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netdev->send = macb_send;
484*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netdev->recv = macb_recv;
485*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
486*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/*
487*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 * Do some basic initialization so that we at least can talk
488*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 * to the PHY
489*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 */
490*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_hz = get_macb_pclk_rate(id);
491*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (macb_hz < 20000000)
492*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		ncfgr = MACB_BF(CLK, MACB_CLK_DIV8);
493*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	else if (macb_hz < 40000000)
494*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		ncfgr = MACB_BF(CLK, MACB_CLK_DIV16);
495*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	else if (macb_hz < 80000000)
496*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		ncfgr = MACB_BF(CLK, MACB_CLK_DIV32);
497*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	else
498*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		ncfgr = MACB_BF(CLK, MACB_CLK_DIV64);
499*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
500*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(macb, NCFGR, ncfgr);
501*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
502*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	eth_register(netdev);
503*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
504*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
505*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
506*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
507*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
508*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
509*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_MII)
510*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
511*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value)
512*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
513*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long netctl;
514*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long netstat;
515*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long frame;
516*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int iflag;
517*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
518*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	iflag = disable_interrupts();
519*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl = macb_readl(&macb, EMACB_NCR);
520*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl |= MACB_BIT(MPE);
521*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(&macb, EMACB_NCR, netctl);
522*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (iflag)
523*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		enable_interrupts();
524*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
525*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	frame = (MACB_BF(SOF, 1)
526*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(RW, 2)
527*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(PHYA, addr)
528*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(REGA, reg)
529*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(CODE, 2));
530*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(&macb, EMACB_MAN, frame);
531*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
532*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	do {
533*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		netstat = macb_readl(&macb, EMACB_NSR);
534*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} while (!(netstat & MACB_BIT(IDLE)));
535*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
536*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	frame = macb_readl(&macb, EMACB_MAN);
537*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	*value = MACB_BFEXT(DATA, frame);
538*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
539*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	iflag = disable_interrupts();
540*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl = macb_readl(&macb, EMACB_NCR);
541*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl &= ~MACB_BIT(MPE);
542*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(&macb, EMACB_NCR, netctl);
543*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (iflag)
544*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		enable_interrupts();
545*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
546*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
547*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
548*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
549*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value)
550*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
551*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long netctl;
552*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long netstat;
553*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long frame;
554*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int iflag;
555*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
556*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	iflag = disable_interrupts();
557*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl = macb_readl(&macb, EMACB_NCR);
558*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl |= MACB_BIT(MPE);
559*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(&macb, EMACB_NCR, netctl);
560*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (iflag)
561*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		enable_interrupts();
562*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
563*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	frame = (MACB_BF(SOF, 1)
564*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(RW, 1)
565*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(PHYA, addr)
566*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(REGA, reg)
567*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(CODE, 2)
568*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 | MACB_BF(DATA, value));
569*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(&macb, EMACB_MAN, frame);
570*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
571*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	do {
572*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		netstat = macb_readl(&macb, EMACB_NSR);
573*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} while (!(netstat & MACB_BIT(IDLE)));
574*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
575*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	iflag = disable_interrupts();
576*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl = macb_readl(&macb, EMACB_NCR);
577*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	netctl &= ~MACB_BIT(MPE);
578*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	macb_writel(&macb, EMACB_NCR, netctl);
579*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (iflag)
580*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		enable_interrupts();
581*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
582*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
583*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
584*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
585*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
586*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
587*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_MACB */
588