xref: /rk3399_rockchip-uboot/drivers/net/ep93xx_eth.c (revision 594d57d0ccce649d6ccd881b8d9c5ea8d0c307ef)
1*594d57d0SMatthias Kaehlcke /*
2*594d57d0SMatthias Kaehlcke  * Cirrus Logic EP93xx ethernet MAC / MII driver.
3*594d57d0SMatthias Kaehlcke  *
4*594d57d0SMatthias Kaehlcke  * Copyright (C) 2010, 2009
5*594d57d0SMatthias Kaehlcke  * Matthias Kaehlcke <matthias@kaehlcke.net>
6*594d57d0SMatthias Kaehlcke  *
7*594d57d0SMatthias Kaehlcke  * Copyright (C) 2004, 2005
8*594d57d0SMatthias Kaehlcke  * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
9*594d57d0SMatthias Kaehlcke  *
10*594d57d0SMatthias Kaehlcke  * Based on the original eth.[ch] Cirrus Logic EP93xx Rev D. Ethernet Driver,
11*594d57d0SMatthias Kaehlcke  * which is
12*594d57d0SMatthias Kaehlcke  *
13*594d57d0SMatthias Kaehlcke  * (C) Copyright 2002 2003
14*594d57d0SMatthias Kaehlcke  * Adam Bezanson, Network Audio Technologies, Inc.
15*594d57d0SMatthias Kaehlcke  * <bezanson@netaudiotech.com>
16*594d57d0SMatthias Kaehlcke  *
17*594d57d0SMatthias Kaehlcke  * See file CREDITS for list of people who contributed to this project.
18*594d57d0SMatthias Kaehlcke  *
19*594d57d0SMatthias Kaehlcke  * This program is free software; you can redistribute it and/or modify
20*594d57d0SMatthias Kaehlcke  * it under the terms of the GNU General Public License as published by
21*594d57d0SMatthias Kaehlcke  * the Free Software Foundation; either version 2 of the License, or
22*594d57d0SMatthias Kaehlcke  * (at your option) any later version.
23*594d57d0SMatthias Kaehlcke  *
24*594d57d0SMatthias Kaehlcke  * This program is distributed in the hope that it will be useful, but
25*594d57d0SMatthias Kaehlcke  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26*594d57d0SMatthias Kaehlcke  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27*594d57d0SMatthias Kaehlcke  * for more details.
28*594d57d0SMatthias Kaehlcke  *
29*594d57d0SMatthias Kaehlcke  * You should have received a copy of the GNU General Public License along
30*594d57d0SMatthias Kaehlcke  * with this program; if not, write to the Free Software Foundation, Inc.,
31*594d57d0SMatthias Kaehlcke  * 675 Mass Ave, Cambridge, MA 02139, USA.
32*594d57d0SMatthias Kaehlcke  */
33*594d57d0SMatthias Kaehlcke 
34*594d57d0SMatthias Kaehlcke #include <command.h>
35*594d57d0SMatthias Kaehlcke #include <common.h>
36*594d57d0SMatthias Kaehlcke #include <asm/arch/ep93xx.h>
37*594d57d0SMatthias Kaehlcke #include <asm/io.h>
38*594d57d0SMatthias Kaehlcke #include <malloc.h>
39*594d57d0SMatthias Kaehlcke #include <miiphy.h>
40*594d57d0SMatthias Kaehlcke #include <linux/types.h>
41*594d57d0SMatthias Kaehlcke #include "ep93xx_eth.h"
42*594d57d0SMatthias Kaehlcke 
43*594d57d0SMatthias Kaehlcke #define GET_PRIV(eth_dev)	((struct ep93xx_priv *)(eth_dev)->priv)
44*594d57d0SMatthias Kaehlcke #define GET_REGS(eth_dev)	(GET_PRIV(eth_dev)->regs)
45*594d57d0SMatthias Kaehlcke 
46*594d57d0SMatthias Kaehlcke /* ep93xx_miiphy ops forward declarations */
47*594d57d0SMatthias Kaehlcke static int ep93xx_miiphy_read(char * const dev, unsigned char const addr,
48*594d57d0SMatthias Kaehlcke 			unsigned char const reg, unsigned short * const value);
49*594d57d0SMatthias Kaehlcke static int ep93xx_miiphy_write(char * const dev, unsigned char const addr,
50*594d57d0SMatthias Kaehlcke 			unsigned char const reg, unsigned short const value);
51*594d57d0SMatthias Kaehlcke 
52*594d57d0SMatthias Kaehlcke #if defined(EP93XX_MAC_DEBUG)
53*594d57d0SMatthias Kaehlcke /**
54*594d57d0SMatthias Kaehlcke  * Dump ep93xx_mac values to the terminal.
55*594d57d0SMatthias Kaehlcke  */
56*594d57d0SMatthias Kaehlcke static void dump_dev(struct eth_device *dev)
57*594d57d0SMatthias Kaehlcke {
58*594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
59*594d57d0SMatthias Kaehlcke 	int i;
60*594d57d0SMatthias Kaehlcke 
61*594d57d0SMatthias Kaehlcke 	printf("\ndump_dev()\n");
62*594d57d0SMatthias Kaehlcke 	printf("  rx_dq.base	     %p\n", priv->rx_dq.base);
63*594d57d0SMatthias Kaehlcke 	printf("  rx_dq.current	     %p\n", priv->rx_dq.current);
64*594d57d0SMatthias Kaehlcke 	printf("  rx_dq.end	     %p\n", priv->rx_dq.end);
65*594d57d0SMatthias Kaehlcke 	printf("  rx_sq.base	     %p\n", priv->rx_sq.base);
66*594d57d0SMatthias Kaehlcke 	printf("  rx_sq.current	     %p\n", priv->rx_sq.current);
67*594d57d0SMatthias Kaehlcke 	printf("  rx_sq.end	     %p\n", priv->rx_sq.end);
68*594d57d0SMatthias Kaehlcke 
69*594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMRXDESC; i++)
70*594d57d0SMatthias Kaehlcke 		printf("  rx_buffer[%2.d]      %p\n", i, NetRxPackets[i]);
71*594d57d0SMatthias Kaehlcke 
72*594d57d0SMatthias Kaehlcke 	printf("  tx_dq.base	     %p\n", priv->tx_dq.base);
73*594d57d0SMatthias Kaehlcke 	printf("  tx_dq.current	     %p\n", priv->tx_dq.current);
74*594d57d0SMatthias Kaehlcke 	printf("  tx_dq.end	     %p\n", priv->tx_dq.end);
75*594d57d0SMatthias Kaehlcke 	printf("  tx_sq.base	     %p\n", priv->tx_sq.base);
76*594d57d0SMatthias Kaehlcke 	printf("  tx_sq.current	     %p\n", priv->tx_sq.current);
77*594d57d0SMatthias Kaehlcke 	printf("  tx_sq.end	     %p\n", priv->tx_sq.end);
78*594d57d0SMatthias Kaehlcke }
79*594d57d0SMatthias Kaehlcke 
80*594d57d0SMatthias Kaehlcke /**
81*594d57d0SMatthias Kaehlcke  * Dump all RX status queue entries to the terminal.
82*594d57d0SMatthias Kaehlcke  */
83*594d57d0SMatthias Kaehlcke static void dump_rx_status_queue(struct eth_device *dev)
84*594d57d0SMatthias Kaehlcke {
85*594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
86*594d57d0SMatthias Kaehlcke 	int i;
87*594d57d0SMatthias Kaehlcke 
88*594d57d0SMatthias Kaehlcke 	printf("\ndump_rx_status_queue()\n");
89*594d57d0SMatthias Kaehlcke 	printf("  descriptor address	 word1		 word2\n");
90*594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMRXDESC; i++) {
91*594d57d0SMatthias Kaehlcke 		printf("  [ %p ]	     %08X	 %08X\n",
92*594d57d0SMatthias Kaehlcke 			priv->rx_sq.base + i,
93*594d57d0SMatthias Kaehlcke 			(priv->rx_sq.base + i)->word1,
94*594d57d0SMatthias Kaehlcke 			(priv->rx_sq.base + i)->word2);
95*594d57d0SMatthias Kaehlcke 	}
96*594d57d0SMatthias Kaehlcke }
97*594d57d0SMatthias Kaehlcke 
98*594d57d0SMatthias Kaehlcke /**
99*594d57d0SMatthias Kaehlcke  * Dump all RX descriptor queue entries to the terminal.
100*594d57d0SMatthias Kaehlcke  */
101*594d57d0SMatthias Kaehlcke static void dump_rx_descriptor_queue(struct eth_device *dev)
102*594d57d0SMatthias Kaehlcke {
103*594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
104*594d57d0SMatthias Kaehlcke 	int i;
105*594d57d0SMatthias Kaehlcke 
106*594d57d0SMatthias Kaehlcke 	printf("\ndump_rx_descriptor_queue()\n");
107*594d57d0SMatthias Kaehlcke 	printf("  descriptor address	 word1		 word2\n");
108*594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMRXDESC; i++) {
109*594d57d0SMatthias Kaehlcke 		printf("  [ %p ]	     %08X	 %08X\n",
110*594d57d0SMatthias Kaehlcke 			priv->rx_dq.base + i,
111*594d57d0SMatthias Kaehlcke 			(priv->rx_dq.base + i)->word1,
112*594d57d0SMatthias Kaehlcke 			(priv->rx_dq.base + i)->word2);
113*594d57d0SMatthias Kaehlcke 	}
114*594d57d0SMatthias Kaehlcke }
115*594d57d0SMatthias Kaehlcke 
116*594d57d0SMatthias Kaehlcke /**
117*594d57d0SMatthias Kaehlcke  * Dump all TX descriptor queue entries to the terminal.
118*594d57d0SMatthias Kaehlcke  */
119*594d57d0SMatthias Kaehlcke static void dump_tx_descriptor_queue(struct eth_device *dev)
120*594d57d0SMatthias Kaehlcke {
121*594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
122*594d57d0SMatthias Kaehlcke 	int i;
123*594d57d0SMatthias Kaehlcke 
124*594d57d0SMatthias Kaehlcke 	printf("\ndump_tx_descriptor_queue()\n");
125*594d57d0SMatthias Kaehlcke 	printf("  descriptor address	 word1		 word2\n");
126*594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMTXDESC; i++) {
127*594d57d0SMatthias Kaehlcke 		printf("  [ %p ]	     %08X	 %08X\n",
128*594d57d0SMatthias Kaehlcke 			priv->tx_dq.base + i,
129*594d57d0SMatthias Kaehlcke 			(priv->tx_dq.base + i)->word1,
130*594d57d0SMatthias Kaehlcke 			(priv->tx_dq.base + i)->word2);
131*594d57d0SMatthias Kaehlcke 	}
132*594d57d0SMatthias Kaehlcke }
133*594d57d0SMatthias Kaehlcke 
134*594d57d0SMatthias Kaehlcke /**
135*594d57d0SMatthias Kaehlcke  * Dump all TX status queue entries to the terminal.
136*594d57d0SMatthias Kaehlcke  */
137*594d57d0SMatthias Kaehlcke static void dump_tx_status_queue(struct eth_device *dev)
138*594d57d0SMatthias Kaehlcke {
139*594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
140*594d57d0SMatthias Kaehlcke 	int i;
141*594d57d0SMatthias Kaehlcke 
142*594d57d0SMatthias Kaehlcke 	printf("\ndump_tx_status_queue()\n");
143*594d57d0SMatthias Kaehlcke 	printf("  descriptor address	 word1\n");
144*594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMTXDESC; i++) {
145*594d57d0SMatthias Kaehlcke 		printf("  [ %p ]	     %08X\n",
146*594d57d0SMatthias Kaehlcke 			priv->rx_sq.base + i,
147*594d57d0SMatthias Kaehlcke 			(priv->rx_sq.base + i)->word1);
148*594d57d0SMatthias Kaehlcke 	}
149*594d57d0SMatthias Kaehlcke }
150*594d57d0SMatthias Kaehlcke #else
151*594d57d0SMatthias Kaehlcke #define dump_dev(x)
152*594d57d0SMatthias Kaehlcke #define dump_rx_descriptor_queue(x)
153*594d57d0SMatthias Kaehlcke #define dump_rx_status_queue(x)
154*594d57d0SMatthias Kaehlcke #define dump_tx_descriptor_queue(x)
155*594d57d0SMatthias Kaehlcke #define dump_tx_status_queue(x)
156*594d57d0SMatthias Kaehlcke #endif	/* defined(EP93XX_MAC_DEBUG) */
157*594d57d0SMatthias Kaehlcke 
158*594d57d0SMatthias Kaehlcke /**
159*594d57d0SMatthias Kaehlcke  * Reset the EP93xx MAC by twiddling the soft reset bit and spinning until
160*594d57d0SMatthias Kaehlcke  * it's cleared.
161*594d57d0SMatthias Kaehlcke  */
162*594d57d0SMatthias Kaehlcke static void ep93xx_mac_reset(struct eth_device *dev)
163*594d57d0SMatthias Kaehlcke {
164*594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
165*594d57d0SMatthias Kaehlcke 	uint32_t value;
166*594d57d0SMatthias Kaehlcke 
167*594d57d0SMatthias Kaehlcke 	debug("+ep93xx_mac_reset");
168*594d57d0SMatthias Kaehlcke 
169*594d57d0SMatthias Kaehlcke 	value = readl(&mac->selfctl);
170*594d57d0SMatthias Kaehlcke 	value |= SELFCTL_RESET;
171*594d57d0SMatthias Kaehlcke 	writel(value, &mac->selfctl);
172*594d57d0SMatthias Kaehlcke 
173*594d57d0SMatthias Kaehlcke 	while (readl(&mac->selfctl) & SELFCTL_RESET)
174*594d57d0SMatthias Kaehlcke 		; /* noop */
175*594d57d0SMatthias Kaehlcke 
176*594d57d0SMatthias Kaehlcke 	debug("-ep93xx_mac_reset");
177*594d57d0SMatthias Kaehlcke }
178*594d57d0SMatthias Kaehlcke 
179*594d57d0SMatthias Kaehlcke /* Eth device open */
180*594d57d0SMatthias Kaehlcke static int ep93xx_eth_open(struct eth_device *dev, bd_t *bd)
181*594d57d0SMatthias Kaehlcke {
182*594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
183*594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
184*594d57d0SMatthias Kaehlcke 	uchar *mac_addr = dev->enetaddr;
185*594d57d0SMatthias Kaehlcke 	int i;
186*594d57d0SMatthias Kaehlcke 
187*594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_open");
188*594d57d0SMatthias Kaehlcke 
189*594d57d0SMatthias Kaehlcke 	/* Reset the MAC */
190*594d57d0SMatthias Kaehlcke 	ep93xx_mac_reset(dev);
191*594d57d0SMatthias Kaehlcke 
192*594d57d0SMatthias Kaehlcke 	/* Reset the descriptor queues' current and end address values */
193*594d57d0SMatthias Kaehlcke 	priv->tx_dq.current = priv->tx_dq.base;
194*594d57d0SMatthias Kaehlcke 	priv->tx_dq.end = (priv->tx_dq.base + NUMTXDESC);
195*594d57d0SMatthias Kaehlcke 
196*594d57d0SMatthias Kaehlcke 	priv->tx_sq.current = priv->tx_sq.base;
197*594d57d0SMatthias Kaehlcke 	priv->tx_sq.end = (priv->tx_sq.base + NUMTXDESC);
198*594d57d0SMatthias Kaehlcke 
199*594d57d0SMatthias Kaehlcke 	priv->rx_dq.current = priv->rx_dq.base;
200*594d57d0SMatthias Kaehlcke 	priv->rx_dq.end = (priv->rx_dq.base + NUMRXDESC);
201*594d57d0SMatthias Kaehlcke 
202*594d57d0SMatthias Kaehlcke 	priv->rx_sq.current = priv->rx_sq.base;
203*594d57d0SMatthias Kaehlcke 	priv->rx_sq.end = (priv->rx_sq.base + NUMRXDESC);
204*594d57d0SMatthias Kaehlcke 
205*594d57d0SMatthias Kaehlcke 	/*
206*594d57d0SMatthias Kaehlcke 	 * Set the transmit descriptor and status queues' base address,
207*594d57d0SMatthias Kaehlcke 	 * current address, and length registers.  Set the maximum frame
208*594d57d0SMatthias Kaehlcke 	 * length and threshold. Enable the transmit descriptor processor.
209*594d57d0SMatthias Kaehlcke 	 */
210*594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->tx_dq.base, &mac->txdq.badd);
211*594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->tx_dq.base, &mac->txdq.curadd);
212*594d57d0SMatthias Kaehlcke 	writel(sizeof(struct tx_descriptor) * NUMTXDESC, &mac->txdq.blen);
213*594d57d0SMatthias Kaehlcke 
214*594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->tx_sq.base, &mac->txstsq.badd);
215*594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->tx_sq.base, &mac->txstsq.curadd);
216*594d57d0SMatthias Kaehlcke 	writel(sizeof(struct tx_status) * NUMTXDESC, &mac->txstsq.blen);
217*594d57d0SMatthias Kaehlcke 
218*594d57d0SMatthias Kaehlcke 	writel(0x00040000, &mac->txdthrshld);
219*594d57d0SMatthias Kaehlcke 	writel(0x00040000, &mac->txststhrshld);
220*594d57d0SMatthias Kaehlcke 
221*594d57d0SMatthias Kaehlcke 	writel((TXSTARTMAX << 0) | (PKTSIZE_ALIGN << 16), &mac->maxfrmlen);
222*594d57d0SMatthias Kaehlcke 	writel(BMCTL_TXEN, &mac->bmctl);
223*594d57d0SMatthias Kaehlcke 
224*594d57d0SMatthias Kaehlcke 	/*
225*594d57d0SMatthias Kaehlcke 	 * Set the receive descriptor and status queues' base address,
226*594d57d0SMatthias Kaehlcke 	 * current address, and length registers.  Enable the receive
227*594d57d0SMatthias Kaehlcke 	 * descriptor processor.
228*594d57d0SMatthias Kaehlcke 	 */
229*594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->rx_dq.base, &mac->rxdq.badd);
230*594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->rx_dq.base, &mac->rxdq.curadd);
231*594d57d0SMatthias Kaehlcke 	writel(sizeof(struct rx_descriptor) * NUMRXDESC, &mac->rxdq.blen);
232*594d57d0SMatthias Kaehlcke 
233*594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.badd);
234*594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.curadd);
235*594d57d0SMatthias Kaehlcke 	writel(sizeof(struct rx_status) * NUMRXDESC, &mac->rxstsq.blen);
236*594d57d0SMatthias Kaehlcke 
237*594d57d0SMatthias Kaehlcke 	writel(0x00040000, &mac->rxdthrshld);
238*594d57d0SMatthias Kaehlcke 
239*594d57d0SMatthias Kaehlcke 	writel(BMCTL_RXEN, &mac->bmctl);
240*594d57d0SMatthias Kaehlcke 
241*594d57d0SMatthias Kaehlcke 	writel(0x00040000, &mac->rxststhrshld);
242*594d57d0SMatthias Kaehlcke 
243*594d57d0SMatthias Kaehlcke 	/* Wait until the receive descriptor processor is active */
244*594d57d0SMatthias Kaehlcke 	while (!(readl(&mac->bmsts) & BMSTS_RXACT))
245*594d57d0SMatthias Kaehlcke 		; /* noop */
246*594d57d0SMatthias Kaehlcke 
247*594d57d0SMatthias Kaehlcke 	/*
248*594d57d0SMatthias Kaehlcke 	 * Initialize the RX descriptor queue. Clear the TX descriptor queue.
249*594d57d0SMatthias Kaehlcke 	 * Clear the RX and TX status queues. Enqueue the RX descriptor and
250*594d57d0SMatthias Kaehlcke 	 * status entries to the MAC.
251*594d57d0SMatthias Kaehlcke 	 */
252*594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMRXDESC; i++) {
253*594d57d0SMatthias Kaehlcke 		/* set buffer address */
254*594d57d0SMatthias Kaehlcke 		(priv->rx_dq.base + i)->word1 = (uint32_t)NetRxPackets[i];
255*594d57d0SMatthias Kaehlcke 
256*594d57d0SMatthias Kaehlcke 		/* set buffer length, clear buffer index and NSOF */
257*594d57d0SMatthias Kaehlcke 		(priv->rx_dq.base + i)->word2 = PKTSIZE_ALIGN;
258*594d57d0SMatthias Kaehlcke 	}
259*594d57d0SMatthias Kaehlcke 
260*594d57d0SMatthias Kaehlcke 	memset(priv->tx_dq.base, 0,
261*594d57d0SMatthias Kaehlcke 		(sizeof(struct tx_descriptor) * NUMTXDESC));
262*594d57d0SMatthias Kaehlcke 	memset(priv->rx_sq.base, 0,
263*594d57d0SMatthias Kaehlcke 		(sizeof(struct rx_status) * NUMRXDESC));
264*594d57d0SMatthias Kaehlcke 	memset(priv->tx_sq.base, 0,
265*594d57d0SMatthias Kaehlcke 		(sizeof(struct tx_status) * NUMTXDESC));
266*594d57d0SMatthias Kaehlcke 
267*594d57d0SMatthias Kaehlcke 	writel(NUMRXDESC, &mac->rxdqenq);
268*594d57d0SMatthias Kaehlcke 	writel(NUMRXDESC, &mac->rxstsqenq);
269*594d57d0SMatthias Kaehlcke 
270*594d57d0SMatthias Kaehlcke 	/* Set the primary MAC address */
271*594d57d0SMatthias Kaehlcke 	writel(AFP_IAPRIMARY, &mac->afp);
272*594d57d0SMatthias Kaehlcke 	writel(mac_addr[0] | (mac_addr[1] << 8) |
273*594d57d0SMatthias Kaehlcke 		(mac_addr[2] << 16) | (mac_addr[3] << 24),
274*594d57d0SMatthias Kaehlcke 		&mac->indad);
275*594d57d0SMatthias Kaehlcke 	writel(mac_addr[4] | (mac_addr[5] << 8), &mac->indad_upper);
276*594d57d0SMatthias Kaehlcke 
277*594d57d0SMatthias Kaehlcke 	/* Turn on RX and TX */
278*594d57d0SMatthias Kaehlcke 	writel(RXCTL_IA0 | RXCTL_BA | RXCTL_SRXON |
279*594d57d0SMatthias Kaehlcke 		RXCTL_RCRCA | RXCTL_MA, &mac->rxctl);
280*594d57d0SMatthias Kaehlcke 	writel(TXCTL_STXON, &mac->txctl);
281*594d57d0SMatthias Kaehlcke 
282*594d57d0SMatthias Kaehlcke 	/* Dump data structures if we're debugging */
283*594d57d0SMatthias Kaehlcke 	dump_dev(dev);
284*594d57d0SMatthias Kaehlcke 	dump_rx_descriptor_queue(dev);
285*594d57d0SMatthias Kaehlcke 	dump_rx_status_queue(dev);
286*594d57d0SMatthias Kaehlcke 	dump_tx_descriptor_queue(dev);
287*594d57d0SMatthias Kaehlcke 	dump_tx_status_queue(dev);
288*594d57d0SMatthias Kaehlcke 
289*594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_open");
290*594d57d0SMatthias Kaehlcke 
291*594d57d0SMatthias Kaehlcke 	return 1;
292*594d57d0SMatthias Kaehlcke }
293*594d57d0SMatthias Kaehlcke 
294*594d57d0SMatthias Kaehlcke /**
295*594d57d0SMatthias Kaehlcke  * Halt EP93xx MAC transmit and receive by clearing the TxCTL and RxCTL
296*594d57d0SMatthias Kaehlcke  * registers.
297*594d57d0SMatthias Kaehlcke  */
298*594d57d0SMatthias Kaehlcke static void ep93xx_eth_close(struct eth_device *dev)
299*594d57d0SMatthias Kaehlcke {
300*594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
301*594d57d0SMatthias Kaehlcke 
302*594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_close");
303*594d57d0SMatthias Kaehlcke 
304*594d57d0SMatthias Kaehlcke 	writel(0x00000000, &mac->rxctl);
305*594d57d0SMatthias Kaehlcke 	writel(0x00000000, &mac->txctl);
306*594d57d0SMatthias Kaehlcke 
307*594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_close");
308*594d57d0SMatthias Kaehlcke }
309*594d57d0SMatthias Kaehlcke 
310*594d57d0SMatthias Kaehlcke /**
311*594d57d0SMatthias Kaehlcke  * Copy a frame of data from the MAC into the protocol layer for further
312*594d57d0SMatthias Kaehlcke  * processing.
313*594d57d0SMatthias Kaehlcke  */
314*594d57d0SMatthias Kaehlcke static int ep93xx_eth_rcv_packet(struct eth_device *dev)
315*594d57d0SMatthias Kaehlcke {
316*594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
317*594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
318*594d57d0SMatthias Kaehlcke 	int len = -1;
319*594d57d0SMatthias Kaehlcke 
320*594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_rcv_packet");
321*594d57d0SMatthias Kaehlcke 
322*594d57d0SMatthias Kaehlcke 	if (RX_STATUS_RFP(priv->rx_sq.current)) {
323*594d57d0SMatthias Kaehlcke 		if (RX_STATUS_RWE(priv->rx_sq.current)) {
324*594d57d0SMatthias Kaehlcke 			/*
325*594d57d0SMatthias Kaehlcke 			 * We have a good frame. Extract the frame's length
326*594d57d0SMatthias Kaehlcke 			 * from the current rx_status_queue entry, and copy
327*594d57d0SMatthias Kaehlcke 			 * the frame's data into NetRxPackets[] of the
328*594d57d0SMatthias Kaehlcke 			 * protocol stack. We track the total number of
329*594d57d0SMatthias Kaehlcke 			 * bytes in the frame (nbytes_frame) which will be
330*594d57d0SMatthias Kaehlcke 			 * used when we pass the data off to the protocol
331*594d57d0SMatthias Kaehlcke 			 * layer via NetReceive().
332*594d57d0SMatthias Kaehlcke 			 */
333*594d57d0SMatthias Kaehlcke 			len = RX_STATUS_FRAME_LEN(priv->rx_sq.current);
334*594d57d0SMatthias Kaehlcke 
335*594d57d0SMatthias Kaehlcke 			NetReceive((uchar *)priv->rx_dq.current->word1,	len);
336*594d57d0SMatthias Kaehlcke 
337*594d57d0SMatthias Kaehlcke 			debug("reporting %d bytes...\n", len);
338*594d57d0SMatthias Kaehlcke 		} else {
339*594d57d0SMatthias Kaehlcke 			/* Do we have an erroneous packet? */
340*594d57d0SMatthias Kaehlcke 			error("packet rx error, status %08X %08X",
341*594d57d0SMatthias Kaehlcke 				priv->rx_sq.current->word1,
342*594d57d0SMatthias Kaehlcke 				priv->rx_sq.current->word2);
343*594d57d0SMatthias Kaehlcke 			dump_rx_descriptor_queue(dev);
344*594d57d0SMatthias Kaehlcke 			dump_rx_status_queue(dev);
345*594d57d0SMatthias Kaehlcke 		}
346*594d57d0SMatthias Kaehlcke 
347*594d57d0SMatthias Kaehlcke 		/*
348*594d57d0SMatthias Kaehlcke 		 * Clear the associated status queue entry, and
349*594d57d0SMatthias Kaehlcke 		 * increment our current pointers to the next RX
350*594d57d0SMatthias Kaehlcke 		 * descriptor and status queue entries (making sure
351*594d57d0SMatthias Kaehlcke 		 * we wrap properly).
352*594d57d0SMatthias Kaehlcke 		 */
353*594d57d0SMatthias Kaehlcke 		memset((void *)priv->rx_sq.current, 0,
354*594d57d0SMatthias Kaehlcke 			sizeof(struct rx_status));
355*594d57d0SMatthias Kaehlcke 
356*594d57d0SMatthias Kaehlcke 		priv->rx_sq.current++;
357*594d57d0SMatthias Kaehlcke 		if (priv->rx_sq.current >= priv->rx_sq.end)
358*594d57d0SMatthias Kaehlcke 			priv->rx_sq.current = priv->rx_sq.base;
359*594d57d0SMatthias Kaehlcke 
360*594d57d0SMatthias Kaehlcke 		priv->rx_dq.current++;
361*594d57d0SMatthias Kaehlcke 		if (priv->rx_dq.current >= priv->rx_dq.end)
362*594d57d0SMatthias Kaehlcke 			priv->rx_dq.current = priv->rx_dq.base;
363*594d57d0SMatthias Kaehlcke 
364*594d57d0SMatthias Kaehlcke 		/*
365*594d57d0SMatthias Kaehlcke 		 * Finally, return the RX descriptor and status entries
366*594d57d0SMatthias Kaehlcke 		 * back to the MAC engine, and loop again, checking for
367*594d57d0SMatthias Kaehlcke 		 * more descriptors to process.
368*594d57d0SMatthias Kaehlcke 		 */
369*594d57d0SMatthias Kaehlcke 		writel(1, &mac->rxdqenq);
370*594d57d0SMatthias Kaehlcke 		writel(1, &mac->rxstsqenq);
371*594d57d0SMatthias Kaehlcke 	} else {
372*594d57d0SMatthias Kaehlcke 		len = 0;
373*594d57d0SMatthias Kaehlcke 	}
374*594d57d0SMatthias Kaehlcke 
375*594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_rcv_packet %d", len);
376*594d57d0SMatthias Kaehlcke 	return len;
377*594d57d0SMatthias Kaehlcke }
378*594d57d0SMatthias Kaehlcke 
379*594d57d0SMatthias Kaehlcke /**
380*594d57d0SMatthias Kaehlcke  * Send a block of data via ethernet.
381*594d57d0SMatthias Kaehlcke  */
382*594d57d0SMatthias Kaehlcke static int ep93xx_eth_send_packet(struct eth_device *dev,
383*594d57d0SMatthias Kaehlcke 				volatile void * const packet, int const length)
384*594d57d0SMatthias Kaehlcke {
385*594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
386*594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
387*594d57d0SMatthias Kaehlcke 	int ret = -1;
388*594d57d0SMatthias Kaehlcke 
389*594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_send_packet");
390*594d57d0SMatthias Kaehlcke 
391*594d57d0SMatthias Kaehlcke 	/* Parameter check */
392*594d57d0SMatthias Kaehlcke 	BUG_ON(packet == NULL);
393*594d57d0SMatthias Kaehlcke 
394*594d57d0SMatthias Kaehlcke 	/*
395*594d57d0SMatthias Kaehlcke 	 * Initialize the TX descriptor queue with the new packet's info.
396*594d57d0SMatthias Kaehlcke 	 * Clear the associated status queue entry. Enqueue the packet
397*594d57d0SMatthias Kaehlcke 	 * to the MAC for transmission.
398*594d57d0SMatthias Kaehlcke 	 */
399*594d57d0SMatthias Kaehlcke 
400*594d57d0SMatthias Kaehlcke 	/* set buffer address */
401*594d57d0SMatthias Kaehlcke 	priv->tx_dq.current->word1 = (uint32_t)packet;
402*594d57d0SMatthias Kaehlcke 
403*594d57d0SMatthias Kaehlcke 	/* set buffer length and EOF bit */
404*594d57d0SMatthias Kaehlcke 	priv->tx_dq.current->word2 = length | TX_DESC_EOF;
405*594d57d0SMatthias Kaehlcke 
406*594d57d0SMatthias Kaehlcke 	/* clear tx status */
407*594d57d0SMatthias Kaehlcke 	priv->tx_sq.current->word1 = 0;
408*594d57d0SMatthias Kaehlcke 
409*594d57d0SMatthias Kaehlcke 	/* enqueue the TX descriptor */
410*594d57d0SMatthias Kaehlcke 	writel(1, &mac->txdqenq);
411*594d57d0SMatthias Kaehlcke 
412*594d57d0SMatthias Kaehlcke 	/* wait for the frame to become processed */
413*594d57d0SMatthias Kaehlcke 	while (!TX_STATUS_TXFP(priv->tx_sq.current))
414*594d57d0SMatthias Kaehlcke 		; /* noop */
415*594d57d0SMatthias Kaehlcke 
416*594d57d0SMatthias Kaehlcke 	if (!TX_STATUS_TXWE(priv->tx_sq.current)) {
417*594d57d0SMatthias Kaehlcke 		error("packet tx error, status %08X",
418*594d57d0SMatthias Kaehlcke 			priv->tx_sq.current->word1);
419*594d57d0SMatthias Kaehlcke 		dump_tx_descriptor_queue(dev);
420*594d57d0SMatthias Kaehlcke 		dump_tx_status_queue(dev);
421*594d57d0SMatthias Kaehlcke 
422*594d57d0SMatthias Kaehlcke 		/* TODO: Add better error handling? */
423*594d57d0SMatthias Kaehlcke 		goto eth_send_out;
424*594d57d0SMatthias Kaehlcke 	}
425*594d57d0SMatthias Kaehlcke 
426*594d57d0SMatthias Kaehlcke 	ret = 0;
427*594d57d0SMatthias Kaehlcke 	/* Fall through */
428*594d57d0SMatthias Kaehlcke 
429*594d57d0SMatthias Kaehlcke eth_send_out:
430*594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_send_packet %d", ret);
431*594d57d0SMatthias Kaehlcke 	return ret;
432*594d57d0SMatthias Kaehlcke }
433*594d57d0SMatthias Kaehlcke 
434*594d57d0SMatthias Kaehlcke #if defined(CONFIG_MII)
435*594d57d0SMatthias Kaehlcke int ep93xx_miiphy_initialize(bd_t * const bd)
436*594d57d0SMatthias Kaehlcke {
437*594d57d0SMatthias Kaehlcke 	miiphy_register("ep93xx_eth0", ep93xx_miiphy_read, ep93xx_miiphy_write);
438*594d57d0SMatthias Kaehlcke 	return 0;
439*594d57d0SMatthias Kaehlcke }
440*594d57d0SMatthias Kaehlcke #endif
441*594d57d0SMatthias Kaehlcke 
442*594d57d0SMatthias Kaehlcke /**
443*594d57d0SMatthias Kaehlcke  * Initialize the EP93xx MAC.  The MAC hardware is reset.  Buffers are
444*594d57d0SMatthias Kaehlcke  * allocated, if necessary, for the TX and RX descriptor and status queues,
445*594d57d0SMatthias Kaehlcke  * as well as for received packets.  The EP93XX MAC hardware is initialized.
446*594d57d0SMatthias Kaehlcke  * Transmit and receive operations are enabled.
447*594d57d0SMatthias Kaehlcke  */
448*594d57d0SMatthias Kaehlcke int ep93xx_eth_initialize(u8 dev_num, int base_addr)
449*594d57d0SMatthias Kaehlcke {
450*594d57d0SMatthias Kaehlcke 	int ret = -1;
451*594d57d0SMatthias Kaehlcke 	struct eth_device *dev;
452*594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv;
453*594d57d0SMatthias Kaehlcke 
454*594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_initialize");
455*594d57d0SMatthias Kaehlcke 
456*594d57d0SMatthias Kaehlcke 	priv = malloc(sizeof(*priv));
457*594d57d0SMatthias Kaehlcke 	if (!priv) {
458*594d57d0SMatthias Kaehlcke 		error("malloc() failed");
459*594d57d0SMatthias Kaehlcke 		goto eth_init_failed_0;
460*594d57d0SMatthias Kaehlcke 	}
461*594d57d0SMatthias Kaehlcke 	memset(priv, 0, sizeof(*priv));
462*594d57d0SMatthias Kaehlcke 
463*594d57d0SMatthias Kaehlcke 	priv->regs = (struct mac_regs *)base_addr;
464*594d57d0SMatthias Kaehlcke 
465*594d57d0SMatthias Kaehlcke 	priv->tx_dq.base = calloc(NUMTXDESC,
466*594d57d0SMatthias Kaehlcke 				sizeof(struct tx_descriptor));
467*594d57d0SMatthias Kaehlcke 	if (priv->tx_dq.base == NULL) {
468*594d57d0SMatthias Kaehlcke 		error("calloc() failed");
469*594d57d0SMatthias Kaehlcke 		goto eth_init_failed_1;
470*594d57d0SMatthias Kaehlcke 	}
471*594d57d0SMatthias Kaehlcke 
472*594d57d0SMatthias Kaehlcke 	priv->tx_sq.base = calloc(NUMTXDESC,
473*594d57d0SMatthias Kaehlcke 				sizeof(struct tx_status));
474*594d57d0SMatthias Kaehlcke 	if (priv->tx_sq.base == NULL) {
475*594d57d0SMatthias Kaehlcke 		error("calloc() failed");
476*594d57d0SMatthias Kaehlcke 		goto eth_init_failed_2;
477*594d57d0SMatthias Kaehlcke 	}
478*594d57d0SMatthias Kaehlcke 
479*594d57d0SMatthias Kaehlcke 	priv->rx_dq.base = calloc(NUMRXDESC,
480*594d57d0SMatthias Kaehlcke 				sizeof(struct rx_descriptor));
481*594d57d0SMatthias Kaehlcke 	if (priv->rx_dq.base == NULL) {
482*594d57d0SMatthias Kaehlcke 		error("calloc() failed");
483*594d57d0SMatthias Kaehlcke 		goto eth_init_failed_3;
484*594d57d0SMatthias Kaehlcke 	}
485*594d57d0SMatthias Kaehlcke 
486*594d57d0SMatthias Kaehlcke 	priv->rx_sq.base = calloc(NUMRXDESC,
487*594d57d0SMatthias Kaehlcke 				sizeof(struct rx_status));
488*594d57d0SMatthias Kaehlcke 	if (priv->rx_sq.base == NULL) {
489*594d57d0SMatthias Kaehlcke 		error("calloc() failed");
490*594d57d0SMatthias Kaehlcke 		goto eth_init_failed_4;
491*594d57d0SMatthias Kaehlcke 	}
492*594d57d0SMatthias Kaehlcke 
493*594d57d0SMatthias Kaehlcke 	dev = malloc(sizeof *dev);
494*594d57d0SMatthias Kaehlcke 	if (dev == NULL) {
495*594d57d0SMatthias Kaehlcke 		error("malloc() failed");
496*594d57d0SMatthias Kaehlcke 		goto eth_init_failed_5;
497*594d57d0SMatthias Kaehlcke 	}
498*594d57d0SMatthias Kaehlcke 	memset(dev, 0, sizeof *dev);
499*594d57d0SMatthias Kaehlcke 
500*594d57d0SMatthias Kaehlcke 	dev->iobase = base_addr;
501*594d57d0SMatthias Kaehlcke 	dev->priv = priv;
502*594d57d0SMatthias Kaehlcke 	dev->init = ep93xx_eth_open;
503*594d57d0SMatthias Kaehlcke 	dev->halt = ep93xx_eth_close;
504*594d57d0SMatthias Kaehlcke 	dev->send = ep93xx_eth_send_packet;
505*594d57d0SMatthias Kaehlcke 	dev->recv = ep93xx_eth_rcv_packet;
506*594d57d0SMatthias Kaehlcke 
507*594d57d0SMatthias Kaehlcke 	sprintf(dev->name, "ep93xx_eth-%hu", dev_num);
508*594d57d0SMatthias Kaehlcke 
509*594d57d0SMatthias Kaehlcke 	eth_register(dev);
510*594d57d0SMatthias Kaehlcke 
511*594d57d0SMatthias Kaehlcke 	/* Done! */
512*594d57d0SMatthias Kaehlcke 	ret = 1;
513*594d57d0SMatthias Kaehlcke 	goto eth_init_done;
514*594d57d0SMatthias Kaehlcke 
515*594d57d0SMatthias Kaehlcke eth_init_failed_5:
516*594d57d0SMatthias Kaehlcke 	free(priv->rx_sq.base);
517*594d57d0SMatthias Kaehlcke 	/* Fall through */
518*594d57d0SMatthias Kaehlcke 
519*594d57d0SMatthias Kaehlcke eth_init_failed_4:
520*594d57d0SMatthias Kaehlcke 	free(priv->rx_dq.base);
521*594d57d0SMatthias Kaehlcke 	/* Fall through */
522*594d57d0SMatthias Kaehlcke 
523*594d57d0SMatthias Kaehlcke eth_init_failed_3:
524*594d57d0SMatthias Kaehlcke 	free(priv->tx_sq.base);
525*594d57d0SMatthias Kaehlcke 	/* Fall through */
526*594d57d0SMatthias Kaehlcke 
527*594d57d0SMatthias Kaehlcke eth_init_failed_2:
528*594d57d0SMatthias Kaehlcke 	free(priv->tx_dq.base);
529*594d57d0SMatthias Kaehlcke 	/* Fall through */
530*594d57d0SMatthias Kaehlcke 
531*594d57d0SMatthias Kaehlcke eth_init_failed_1:
532*594d57d0SMatthias Kaehlcke 	free(priv);
533*594d57d0SMatthias Kaehlcke 	/* Fall through */
534*594d57d0SMatthias Kaehlcke 
535*594d57d0SMatthias Kaehlcke eth_init_failed_0:
536*594d57d0SMatthias Kaehlcke 	/* Fall through */
537*594d57d0SMatthias Kaehlcke 
538*594d57d0SMatthias Kaehlcke eth_init_done:
539*594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_initialize %d", ret);
540*594d57d0SMatthias Kaehlcke 	return ret;
541*594d57d0SMatthias Kaehlcke }
542*594d57d0SMatthias Kaehlcke 
543*594d57d0SMatthias Kaehlcke #if defined(CONFIG_MII)
544*594d57d0SMatthias Kaehlcke 
545*594d57d0SMatthias Kaehlcke /**
546*594d57d0SMatthias Kaehlcke  * Maximum MII address we support
547*594d57d0SMatthias Kaehlcke  */
548*594d57d0SMatthias Kaehlcke #define MII_ADDRESS_MAX			31
549*594d57d0SMatthias Kaehlcke 
550*594d57d0SMatthias Kaehlcke /**
551*594d57d0SMatthias Kaehlcke  * Maximum MII register address we support
552*594d57d0SMatthias Kaehlcke  */
553*594d57d0SMatthias Kaehlcke #define MII_REGISTER_MAX		31
554*594d57d0SMatthias Kaehlcke 
555*594d57d0SMatthias Kaehlcke /**
556*594d57d0SMatthias Kaehlcke  * Read a 16-bit value from an MII register.
557*594d57d0SMatthias Kaehlcke  */
558*594d57d0SMatthias Kaehlcke static int ep93xx_miiphy_read(char * const dev, unsigned char const addr,
559*594d57d0SMatthias Kaehlcke 			unsigned char const reg, unsigned short * const value)
560*594d57d0SMatthias Kaehlcke {
561*594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
562*594d57d0SMatthias Kaehlcke 	int ret = -1;
563*594d57d0SMatthias Kaehlcke 	uint32_t self_ctl;
564*594d57d0SMatthias Kaehlcke 
565*594d57d0SMatthias Kaehlcke 	debug("+ep93xx_miiphy_read");
566*594d57d0SMatthias Kaehlcke 
567*594d57d0SMatthias Kaehlcke 	/* Parameter checks */
568*594d57d0SMatthias Kaehlcke 	BUG_ON(dev == NULL);
569*594d57d0SMatthias Kaehlcke 	BUG_ON(addr > MII_ADDRESS_MAX);
570*594d57d0SMatthias Kaehlcke 	BUG_ON(reg > MII_REGISTER_MAX);
571*594d57d0SMatthias Kaehlcke 	BUG_ON(value == NULL);
572*594d57d0SMatthias Kaehlcke 
573*594d57d0SMatthias Kaehlcke 	/*
574*594d57d0SMatthias Kaehlcke 	 * Save the current SelfCTL register value.  Set MAC to suppress
575*594d57d0SMatthias Kaehlcke 	 * preamble bits.  Wait for any previous MII command to complete
576*594d57d0SMatthias Kaehlcke 	 * before issuing the new command.
577*594d57d0SMatthias Kaehlcke 	 */
578*594d57d0SMatthias Kaehlcke 	self_ctl = readl(&mac->selfctl);
579*594d57d0SMatthias Kaehlcke #if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
580*594d57d0SMatthias Kaehlcke 	writel(self_ctl & ~(1 << 8), &mac->selfctl);
581*594d57d0SMatthias Kaehlcke #endif	/* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
582*594d57d0SMatthias Kaehlcke 
583*594d57d0SMatthias Kaehlcke 	while (readl(&mac->miists) & MIISTS_BUSY)
584*594d57d0SMatthias Kaehlcke 		; /* noop */
585*594d57d0SMatthias Kaehlcke 
586*594d57d0SMatthias Kaehlcke 	/*
587*594d57d0SMatthias Kaehlcke 	 * Issue the MII 'read' command.  Wait for the command to complete.
588*594d57d0SMatthias Kaehlcke 	 * Read the MII data value.
589*594d57d0SMatthias Kaehlcke 	 */
590*594d57d0SMatthias Kaehlcke 	writel(MIICMD_OPCODE_READ | ((uint32_t)addr << 5) | (uint32_t)reg,
591*594d57d0SMatthias Kaehlcke 		&mac->miicmd);
592*594d57d0SMatthias Kaehlcke 	while (readl(&mac->miists) & MIISTS_BUSY)
593*594d57d0SMatthias Kaehlcke 		; /* noop */
594*594d57d0SMatthias Kaehlcke 
595*594d57d0SMatthias Kaehlcke 	*value = (unsigned short)readl(&mac->miidata);
596*594d57d0SMatthias Kaehlcke 
597*594d57d0SMatthias Kaehlcke 	/* Restore the saved SelfCTL value and return. */
598*594d57d0SMatthias Kaehlcke 	writel(self_ctl, &mac->selfctl);
599*594d57d0SMatthias Kaehlcke 
600*594d57d0SMatthias Kaehlcke 	ret = 0;
601*594d57d0SMatthias Kaehlcke 	/* Fall through */
602*594d57d0SMatthias Kaehlcke 
603*594d57d0SMatthias Kaehlcke 	debug("-ep93xx_miiphy_read");
604*594d57d0SMatthias Kaehlcke 	return ret;
605*594d57d0SMatthias Kaehlcke }
606*594d57d0SMatthias Kaehlcke 
607*594d57d0SMatthias Kaehlcke /**
608*594d57d0SMatthias Kaehlcke  * Write a 16-bit value to an MII register.
609*594d57d0SMatthias Kaehlcke  */
610*594d57d0SMatthias Kaehlcke static int ep93xx_miiphy_write(char * const dev, unsigned char const addr,
611*594d57d0SMatthias Kaehlcke 			unsigned char const reg, unsigned short const value)
612*594d57d0SMatthias Kaehlcke {
613*594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
614*594d57d0SMatthias Kaehlcke 	int ret = -1;
615*594d57d0SMatthias Kaehlcke 	uint32_t self_ctl;
616*594d57d0SMatthias Kaehlcke 
617*594d57d0SMatthias Kaehlcke 	debug("+ep93xx_miiphy_write");
618*594d57d0SMatthias Kaehlcke 
619*594d57d0SMatthias Kaehlcke 	/* Parameter checks */
620*594d57d0SMatthias Kaehlcke 	BUG_ON(dev == NULL);
621*594d57d0SMatthias Kaehlcke 	BUG_ON(addr > MII_ADDRESS_MAX);
622*594d57d0SMatthias Kaehlcke 	BUG_ON(reg > MII_REGISTER_MAX);
623*594d57d0SMatthias Kaehlcke 
624*594d57d0SMatthias Kaehlcke 	/*
625*594d57d0SMatthias Kaehlcke 	 * Save the current SelfCTL register value.  Set MAC to suppress
626*594d57d0SMatthias Kaehlcke 	 * preamble bits.  Wait for any previous MII command to complete
627*594d57d0SMatthias Kaehlcke 	 * before issuing the new command.
628*594d57d0SMatthias Kaehlcke 	 */
629*594d57d0SMatthias Kaehlcke 	self_ctl = readl(&mac->selfctl);
630*594d57d0SMatthias Kaehlcke #if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
631*594d57d0SMatthias Kaehlcke 	writel(self_ctl & ~(1 << 8), &mac->selfctl);
632*594d57d0SMatthias Kaehlcke #endif	/* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
633*594d57d0SMatthias Kaehlcke 
634*594d57d0SMatthias Kaehlcke 	while (readl(&mac->miists) & MIISTS_BUSY)
635*594d57d0SMatthias Kaehlcke 		; /* noop */
636*594d57d0SMatthias Kaehlcke 
637*594d57d0SMatthias Kaehlcke 	/* Issue the MII 'write' command.  Wait for the command to complete. */
638*594d57d0SMatthias Kaehlcke 	writel((uint32_t)value, &mac->miidata);
639*594d57d0SMatthias Kaehlcke 	writel(MIICMD_OPCODE_WRITE | ((uint32_t)addr << 5) | (uint32_t)reg,
640*594d57d0SMatthias Kaehlcke 		&mac->miicmd);
641*594d57d0SMatthias Kaehlcke 	while (readl(&mac->miists) & MIISTS_BUSY)
642*594d57d0SMatthias Kaehlcke 		; /* noop */
643*594d57d0SMatthias Kaehlcke 
644*594d57d0SMatthias Kaehlcke 	/* Restore the saved SelfCTL value and return. */
645*594d57d0SMatthias Kaehlcke 	writel(self_ctl, &mac->selfctl);
646*594d57d0SMatthias Kaehlcke 
647*594d57d0SMatthias Kaehlcke 	ret = 0;
648*594d57d0SMatthias Kaehlcke 	/* Fall through */
649*594d57d0SMatthias Kaehlcke 
650*594d57d0SMatthias Kaehlcke 	debug("-ep93xx_miiphy_write");
651*594d57d0SMatthias Kaehlcke 	return ret;
652*594d57d0SMatthias Kaehlcke }
653*594d57d0SMatthias Kaehlcke #endif	/* defined(CONFIG_MII) */
654