xref: /rk3399_rockchip-uboot/drivers/net/ep93xx_eth.c (revision 90aa625c9a9e1fb7a2f001fd8e50099bacaf92b8)
1594d57d0SMatthias Kaehlcke /*
2594d57d0SMatthias Kaehlcke  * Cirrus Logic EP93xx ethernet MAC / MII driver.
3594d57d0SMatthias Kaehlcke  *
4594d57d0SMatthias Kaehlcke  * Copyright (C) 2010, 2009
5594d57d0SMatthias Kaehlcke  * Matthias Kaehlcke <matthias@kaehlcke.net>
6594d57d0SMatthias Kaehlcke  *
7594d57d0SMatthias Kaehlcke  * Copyright (C) 2004, 2005
8594d57d0SMatthias Kaehlcke  * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
9594d57d0SMatthias Kaehlcke  *
10594d57d0SMatthias Kaehlcke  * Based on the original eth.[ch] Cirrus Logic EP93xx Rev D. Ethernet Driver,
11594d57d0SMatthias Kaehlcke  * which is
12594d57d0SMatthias Kaehlcke  *
13594d57d0SMatthias Kaehlcke  * (C) Copyright 2002 2003
14594d57d0SMatthias Kaehlcke  * Adam Bezanson, Network Audio Technologies, Inc.
15594d57d0SMatthias Kaehlcke  * <bezanson@netaudiotech.com>
16594d57d0SMatthias Kaehlcke  *
171a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
18594d57d0SMatthias Kaehlcke  */
19594d57d0SMatthias Kaehlcke 
20594d57d0SMatthias Kaehlcke #include <command.h>
21594d57d0SMatthias Kaehlcke #include <common.h>
22594d57d0SMatthias Kaehlcke #include <asm/arch/ep93xx.h>
23594d57d0SMatthias Kaehlcke #include <asm/io.h>
24594d57d0SMatthias Kaehlcke #include <malloc.h>
25594d57d0SMatthias Kaehlcke #include <miiphy.h>
26594d57d0SMatthias Kaehlcke #include <linux/types.h>
27594d57d0SMatthias Kaehlcke #include "ep93xx_eth.h"
28594d57d0SMatthias Kaehlcke 
29594d57d0SMatthias Kaehlcke #define GET_PRIV(eth_dev)	((struct ep93xx_priv *)(eth_dev)->priv)
30594d57d0SMatthias Kaehlcke #define GET_REGS(eth_dev)	(GET_PRIV(eth_dev)->regs)
31594d57d0SMatthias Kaehlcke 
32594d57d0SMatthias Kaehlcke /* ep93xx_miiphy ops forward declarations */
335a49f174SJoe Hershberger static int ep93xx_miiphy_read(struct mii_dev *bus, int addr, int devad,
345a49f174SJoe Hershberger 			      int reg);
355a49f174SJoe Hershberger static int ep93xx_miiphy_write(struct mii_dev *bus, int addr, int devad,
365a49f174SJoe Hershberger 			       int reg, u16 value);
37594d57d0SMatthias Kaehlcke 
38594d57d0SMatthias Kaehlcke #if defined(EP93XX_MAC_DEBUG)
39594d57d0SMatthias Kaehlcke /**
40594d57d0SMatthias Kaehlcke  * Dump ep93xx_mac values to the terminal.
41594d57d0SMatthias Kaehlcke  */
dump_dev(struct eth_device * dev)42594d57d0SMatthias Kaehlcke static void dump_dev(struct eth_device *dev)
43594d57d0SMatthias Kaehlcke {
44594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
45594d57d0SMatthias Kaehlcke 	int i;
46594d57d0SMatthias Kaehlcke 
47594d57d0SMatthias Kaehlcke 	printf("\ndump_dev()\n");
48594d57d0SMatthias Kaehlcke 	printf("  rx_dq.base	     %p\n", priv->rx_dq.base);
49594d57d0SMatthias Kaehlcke 	printf("  rx_dq.current	     %p\n", priv->rx_dq.current);
50594d57d0SMatthias Kaehlcke 	printf("  rx_dq.end	     %p\n", priv->rx_dq.end);
51594d57d0SMatthias Kaehlcke 	printf("  rx_sq.base	     %p\n", priv->rx_sq.base);
52594d57d0SMatthias Kaehlcke 	printf("  rx_sq.current	     %p\n", priv->rx_sq.current);
53594d57d0SMatthias Kaehlcke 	printf("  rx_sq.end	     %p\n", priv->rx_sq.end);
54594d57d0SMatthias Kaehlcke 
55594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMRXDESC; i++)
561fd92db8SJoe Hershberger 		printf("  rx_buffer[%2.d]      %p\n", i, net_rx_packets[i]);
57594d57d0SMatthias Kaehlcke 
58594d57d0SMatthias Kaehlcke 	printf("  tx_dq.base	     %p\n", priv->tx_dq.base);
59594d57d0SMatthias Kaehlcke 	printf("  tx_dq.current	     %p\n", priv->tx_dq.current);
60594d57d0SMatthias Kaehlcke 	printf("  tx_dq.end	     %p\n", priv->tx_dq.end);
61594d57d0SMatthias Kaehlcke 	printf("  tx_sq.base	     %p\n", priv->tx_sq.base);
62594d57d0SMatthias Kaehlcke 	printf("  tx_sq.current	     %p\n", priv->tx_sq.current);
63594d57d0SMatthias Kaehlcke 	printf("  tx_sq.end	     %p\n", priv->tx_sq.end);
64594d57d0SMatthias Kaehlcke }
65594d57d0SMatthias Kaehlcke 
66594d57d0SMatthias Kaehlcke /**
67594d57d0SMatthias Kaehlcke  * Dump all RX status queue entries to the terminal.
68594d57d0SMatthias Kaehlcke  */
dump_rx_status_queue(struct eth_device * dev)69594d57d0SMatthias Kaehlcke static void dump_rx_status_queue(struct eth_device *dev)
70594d57d0SMatthias Kaehlcke {
71594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
72594d57d0SMatthias Kaehlcke 	int i;
73594d57d0SMatthias Kaehlcke 
74594d57d0SMatthias Kaehlcke 	printf("\ndump_rx_status_queue()\n");
75594d57d0SMatthias Kaehlcke 	printf("  descriptor address	 word1		 word2\n");
76594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMRXDESC; i++) {
77594d57d0SMatthias Kaehlcke 		printf("  [ %p ]	     %08X	 %08X\n",
78594d57d0SMatthias Kaehlcke 			priv->rx_sq.base + i,
79594d57d0SMatthias Kaehlcke 			(priv->rx_sq.base + i)->word1,
80594d57d0SMatthias Kaehlcke 			(priv->rx_sq.base + i)->word2);
81594d57d0SMatthias Kaehlcke 	}
82594d57d0SMatthias Kaehlcke }
83594d57d0SMatthias Kaehlcke 
84594d57d0SMatthias Kaehlcke /**
85594d57d0SMatthias Kaehlcke  * Dump all RX descriptor queue entries to the terminal.
86594d57d0SMatthias Kaehlcke  */
dump_rx_descriptor_queue(struct eth_device * dev)87594d57d0SMatthias Kaehlcke static void dump_rx_descriptor_queue(struct eth_device *dev)
88594d57d0SMatthias Kaehlcke {
89594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
90594d57d0SMatthias Kaehlcke 	int i;
91594d57d0SMatthias Kaehlcke 
92594d57d0SMatthias Kaehlcke 	printf("\ndump_rx_descriptor_queue()\n");
93594d57d0SMatthias Kaehlcke 	printf("  descriptor address	 word1		 word2\n");
94594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMRXDESC; i++) {
95594d57d0SMatthias Kaehlcke 		printf("  [ %p ]	     %08X	 %08X\n",
96594d57d0SMatthias Kaehlcke 			priv->rx_dq.base + i,
97594d57d0SMatthias Kaehlcke 			(priv->rx_dq.base + i)->word1,
98594d57d0SMatthias Kaehlcke 			(priv->rx_dq.base + i)->word2);
99594d57d0SMatthias Kaehlcke 	}
100594d57d0SMatthias Kaehlcke }
101594d57d0SMatthias Kaehlcke 
102594d57d0SMatthias Kaehlcke /**
103594d57d0SMatthias Kaehlcke  * Dump all TX descriptor queue entries to the terminal.
104594d57d0SMatthias Kaehlcke  */
dump_tx_descriptor_queue(struct eth_device * dev)105594d57d0SMatthias Kaehlcke static void dump_tx_descriptor_queue(struct eth_device *dev)
106594d57d0SMatthias Kaehlcke {
107594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
108594d57d0SMatthias Kaehlcke 	int i;
109594d57d0SMatthias Kaehlcke 
110594d57d0SMatthias Kaehlcke 	printf("\ndump_tx_descriptor_queue()\n");
111594d57d0SMatthias Kaehlcke 	printf("  descriptor address	 word1		 word2\n");
112594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMTXDESC; i++) {
113594d57d0SMatthias Kaehlcke 		printf("  [ %p ]	     %08X	 %08X\n",
114594d57d0SMatthias Kaehlcke 			priv->tx_dq.base + i,
115594d57d0SMatthias Kaehlcke 			(priv->tx_dq.base + i)->word1,
116594d57d0SMatthias Kaehlcke 			(priv->tx_dq.base + i)->word2);
117594d57d0SMatthias Kaehlcke 	}
118594d57d0SMatthias Kaehlcke }
119594d57d0SMatthias Kaehlcke 
120594d57d0SMatthias Kaehlcke /**
121594d57d0SMatthias Kaehlcke  * Dump all TX status queue entries to the terminal.
122594d57d0SMatthias Kaehlcke  */
dump_tx_status_queue(struct eth_device * dev)123594d57d0SMatthias Kaehlcke static void dump_tx_status_queue(struct eth_device *dev)
124594d57d0SMatthias Kaehlcke {
125594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
126594d57d0SMatthias Kaehlcke 	int i;
127594d57d0SMatthias Kaehlcke 
128594d57d0SMatthias Kaehlcke 	printf("\ndump_tx_status_queue()\n");
129594d57d0SMatthias Kaehlcke 	printf("  descriptor address	 word1\n");
130594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMTXDESC; i++) {
131594d57d0SMatthias Kaehlcke 		printf("  [ %p ]	     %08X\n",
132594d57d0SMatthias Kaehlcke 			priv->rx_sq.base + i,
133594d57d0SMatthias Kaehlcke 			(priv->rx_sq.base + i)->word1);
134594d57d0SMatthias Kaehlcke 	}
135594d57d0SMatthias Kaehlcke }
136594d57d0SMatthias Kaehlcke #else
137594d57d0SMatthias Kaehlcke #define dump_dev(x)
138594d57d0SMatthias Kaehlcke #define dump_rx_descriptor_queue(x)
139594d57d0SMatthias Kaehlcke #define dump_rx_status_queue(x)
140594d57d0SMatthias Kaehlcke #define dump_tx_descriptor_queue(x)
141594d57d0SMatthias Kaehlcke #define dump_tx_status_queue(x)
142594d57d0SMatthias Kaehlcke #endif	/* defined(EP93XX_MAC_DEBUG) */
143594d57d0SMatthias Kaehlcke 
144594d57d0SMatthias Kaehlcke /**
145594d57d0SMatthias Kaehlcke  * Reset the EP93xx MAC by twiddling the soft reset bit and spinning until
146594d57d0SMatthias Kaehlcke  * it's cleared.
147594d57d0SMatthias Kaehlcke  */
ep93xx_mac_reset(struct eth_device * dev)148594d57d0SMatthias Kaehlcke static void ep93xx_mac_reset(struct eth_device *dev)
149594d57d0SMatthias Kaehlcke {
150594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
151594d57d0SMatthias Kaehlcke 	uint32_t value;
152594d57d0SMatthias Kaehlcke 
153594d57d0SMatthias Kaehlcke 	debug("+ep93xx_mac_reset");
154594d57d0SMatthias Kaehlcke 
155594d57d0SMatthias Kaehlcke 	value = readl(&mac->selfctl);
156594d57d0SMatthias Kaehlcke 	value |= SELFCTL_RESET;
157594d57d0SMatthias Kaehlcke 	writel(value, &mac->selfctl);
158594d57d0SMatthias Kaehlcke 
159594d57d0SMatthias Kaehlcke 	while (readl(&mac->selfctl) & SELFCTL_RESET)
160594d57d0SMatthias Kaehlcke 		; /* noop */
161594d57d0SMatthias Kaehlcke 
162594d57d0SMatthias Kaehlcke 	debug("-ep93xx_mac_reset");
163594d57d0SMatthias Kaehlcke }
164594d57d0SMatthias Kaehlcke 
165594d57d0SMatthias Kaehlcke /* Eth device open */
ep93xx_eth_open(struct eth_device * dev,bd_t * bd)166594d57d0SMatthias Kaehlcke static int ep93xx_eth_open(struct eth_device *dev, bd_t *bd)
167594d57d0SMatthias Kaehlcke {
168594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
169594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
170594d57d0SMatthias Kaehlcke 	uchar *mac_addr = dev->enetaddr;
171594d57d0SMatthias Kaehlcke 	int i;
172594d57d0SMatthias Kaehlcke 
173594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_open");
174594d57d0SMatthias Kaehlcke 
175594d57d0SMatthias Kaehlcke 	/* Reset the MAC */
176594d57d0SMatthias Kaehlcke 	ep93xx_mac_reset(dev);
177594d57d0SMatthias Kaehlcke 
178594d57d0SMatthias Kaehlcke 	/* Reset the descriptor queues' current and end address values */
179594d57d0SMatthias Kaehlcke 	priv->tx_dq.current = priv->tx_dq.base;
180594d57d0SMatthias Kaehlcke 	priv->tx_dq.end = (priv->tx_dq.base + NUMTXDESC);
181594d57d0SMatthias Kaehlcke 
182594d57d0SMatthias Kaehlcke 	priv->tx_sq.current = priv->tx_sq.base;
183594d57d0SMatthias Kaehlcke 	priv->tx_sq.end = (priv->tx_sq.base + NUMTXDESC);
184594d57d0SMatthias Kaehlcke 
185594d57d0SMatthias Kaehlcke 	priv->rx_dq.current = priv->rx_dq.base;
186594d57d0SMatthias Kaehlcke 	priv->rx_dq.end = (priv->rx_dq.base + NUMRXDESC);
187594d57d0SMatthias Kaehlcke 
188594d57d0SMatthias Kaehlcke 	priv->rx_sq.current = priv->rx_sq.base;
189594d57d0SMatthias Kaehlcke 	priv->rx_sq.end = (priv->rx_sq.base + NUMRXDESC);
190594d57d0SMatthias Kaehlcke 
191594d57d0SMatthias Kaehlcke 	/*
192594d57d0SMatthias Kaehlcke 	 * Set the transmit descriptor and status queues' base address,
193594d57d0SMatthias Kaehlcke 	 * current address, and length registers.  Set the maximum frame
194594d57d0SMatthias Kaehlcke 	 * length and threshold. Enable the transmit descriptor processor.
195594d57d0SMatthias Kaehlcke 	 */
196594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->tx_dq.base, &mac->txdq.badd);
197594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->tx_dq.base, &mac->txdq.curadd);
198594d57d0SMatthias Kaehlcke 	writel(sizeof(struct tx_descriptor) * NUMTXDESC, &mac->txdq.blen);
199594d57d0SMatthias Kaehlcke 
200594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->tx_sq.base, &mac->txstsq.badd);
201594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->tx_sq.base, &mac->txstsq.curadd);
202594d57d0SMatthias Kaehlcke 	writel(sizeof(struct tx_status) * NUMTXDESC, &mac->txstsq.blen);
203594d57d0SMatthias Kaehlcke 
204594d57d0SMatthias Kaehlcke 	writel(0x00040000, &mac->txdthrshld);
205594d57d0SMatthias Kaehlcke 	writel(0x00040000, &mac->txststhrshld);
206594d57d0SMatthias Kaehlcke 
207594d57d0SMatthias Kaehlcke 	writel((TXSTARTMAX << 0) | (PKTSIZE_ALIGN << 16), &mac->maxfrmlen);
208594d57d0SMatthias Kaehlcke 	writel(BMCTL_TXEN, &mac->bmctl);
209594d57d0SMatthias Kaehlcke 
210594d57d0SMatthias Kaehlcke 	/*
211594d57d0SMatthias Kaehlcke 	 * Set the receive descriptor and status queues' base address,
212594d57d0SMatthias Kaehlcke 	 * current address, and length registers.  Enable the receive
213594d57d0SMatthias Kaehlcke 	 * descriptor processor.
214594d57d0SMatthias Kaehlcke 	 */
215594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->rx_dq.base, &mac->rxdq.badd);
216594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->rx_dq.base, &mac->rxdq.curadd);
217594d57d0SMatthias Kaehlcke 	writel(sizeof(struct rx_descriptor) * NUMRXDESC, &mac->rxdq.blen);
218594d57d0SMatthias Kaehlcke 
219594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.badd);
220594d57d0SMatthias Kaehlcke 	writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.curadd);
221594d57d0SMatthias Kaehlcke 	writel(sizeof(struct rx_status) * NUMRXDESC, &mac->rxstsq.blen);
222594d57d0SMatthias Kaehlcke 
223594d57d0SMatthias Kaehlcke 	writel(0x00040000, &mac->rxdthrshld);
224594d57d0SMatthias Kaehlcke 
225594d57d0SMatthias Kaehlcke 	writel(BMCTL_RXEN, &mac->bmctl);
226594d57d0SMatthias Kaehlcke 
227594d57d0SMatthias Kaehlcke 	writel(0x00040000, &mac->rxststhrshld);
228594d57d0SMatthias Kaehlcke 
229594d57d0SMatthias Kaehlcke 	/* Wait until the receive descriptor processor is active */
230594d57d0SMatthias Kaehlcke 	while (!(readl(&mac->bmsts) & BMSTS_RXACT))
231594d57d0SMatthias Kaehlcke 		; /* noop */
232594d57d0SMatthias Kaehlcke 
233594d57d0SMatthias Kaehlcke 	/*
234594d57d0SMatthias Kaehlcke 	 * Initialize the RX descriptor queue. Clear the TX descriptor queue.
235594d57d0SMatthias Kaehlcke 	 * Clear the RX and TX status queues. Enqueue the RX descriptor and
236594d57d0SMatthias Kaehlcke 	 * status entries to the MAC.
237594d57d0SMatthias Kaehlcke 	 */
238594d57d0SMatthias Kaehlcke 	for (i = 0; i < NUMRXDESC; i++) {
239594d57d0SMatthias Kaehlcke 		/* set buffer address */
2401fd92db8SJoe Hershberger 		(priv->rx_dq.base + i)->word1 = (uint32_t)net_rx_packets[i];
241594d57d0SMatthias Kaehlcke 
242594d57d0SMatthias Kaehlcke 		/* set buffer length, clear buffer index and NSOF */
243594d57d0SMatthias Kaehlcke 		(priv->rx_dq.base + i)->word2 = PKTSIZE_ALIGN;
244594d57d0SMatthias Kaehlcke 	}
245594d57d0SMatthias Kaehlcke 
246594d57d0SMatthias Kaehlcke 	memset(priv->tx_dq.base, 0,
247594d57d0SMatthias Kaehlcke 		(sizeof(struct tx_descriptor) * NUMTXDESC));
248594d57d0SMatthias Kaehlcke 	memset(priv->rx_sq.base, 0,
249594d57d0SMatthias Kaehlcke 		(sizeof(struct rx_status) * NUMRXDESC));
250594d57d0SMatthias Kaehlcke 	memset(priv->tx_sq.base, 0,
251594d57d0SMatthias Kaehlcke 		(sizeof(struct tx_status) * NUMTXDESC));
252594d57d0SMatthias Kaehlcke 
253594d57d0SMatthias Kaehlcke 	writel(NUMRXDESC, &mac->rxdqenq);
254594d57d0SMatthias Kaehlcke 	writel(NUMRXDESC, &mac->rxstsqenq);
255594d57d0SMatthias Kaehlcke 
256594d57d0SMatthias Kaehlcke 	/* Set the primary MAC address */
257594d57d0SMatthias Kaehlcke 	writel(AFP_IAPRIMARY, &mac->afp);
258594d57d0SMatthias Kaehlcke 	writel(mac_addr[0] | (mac_addr[1] << 8) |
259594d57d0SMatthias Kaehlcke 		(mac_addr[2] << 16) | (mac_addr[3] << 24),
260594d57d0SMatthias Kaehlcke 		&mac->indad);
261594d57d0SMatthias Kaehlcke 	writel(mac_addr[4] | (mac_addr[5] << 8), &mac->indad_upper);
262594d57d0SMatthias Kaehlcke 
263594d57d0SMatthias Kaehlcke 	/* Turn on RX and TX */
264594d57d0SMatthias Kaehlcke 	writel(RXCTL_IA0 | RXCTL_BA | RXCTL_SRXON |
265594d57d0SMatthias Kaehlcke 		RXCTL_RCRCA | RXCTL_MA, &mac->rxctl);
266594d57d0SMatthias Kaehlcke 	writel(TXCTL_STXON, &mac->txctl);
267594d57d0SMatthias Kaehlcke 
268594d57d0SMatthias Kaehlcke 	/* Dump data structures if we're debugging */
269594d57d0SMatthias Kaehlcke 	dump_dev(dev);
270594d57d0SMatthias Kaehlcke 	dump_rx_descriptor_queue(dev);
271594d57d0SMatthias Kaehlcke 	dump_rx_status_queue(dev);
272594d57d0SMatthias Kaehlcke 	dump_tx_descriptor_queue(dev);
273594d57d0SMatthias Kaehlcke 	dump_tx_status_queue(dev);
274594d57d0SMatthias Kaehlcke 
275594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_open");
276594d57d0SMatthias Kaehlcke 
277594d57d0SMatthias Kaehlcke 	return 1;
278594d57d0SMatthias Kaehlcke }
279594d57d0SMatthias Kaehlcke 
280594d57d0SMatthias Kaehlcke /**
281594d57d0SMatthias Kaehlcke  * Halt EP93xx MAC transmit and receive by clearing the TxCTL and RxCTL
282594d57d0SMatthias Kaehlcke  * registers.
283594d57d0SMatthias Kaehlcke  */
ep93xx_eth_close(struct eth_device * dev)284594d57d0SMatthias Kaehlcke static void ep93xx_eth_close(struct eth_device *dev)
285594d57d0SMatthias Kaehlcke {
286594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
287594d57d0SMatthias Kaehlcke 
288594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_close");
289594d57d0SMatthias Kaehlcke 
290594d57d0SMatthias Kaehlcke 	writel(0x00000000, &mac->rxctl);
291594d57d0SMatthias Kaehlcke 	writel(0x00000000, &mac->txctl);
292594d57d0SMatthias Kaehlcke 
293594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_close");
294594d57d0SMatthias Kaehlcke }
295594d57d0SMatthias Kaehlcke 
296594d57d0SMatthias Kaehlcke /**
297594d57d0SMatthias Kaehlcke  * Copy a frame of data from the MAC into the protocol layer for further
298594d57d0SMatthias Kaehlcke  * processing.
299594d57d0SMatthias Kaehlcke  */
ep93xx_eth_rcv_packet(struct eth_device * dev)300594d57d0SMatthias Kaehlcke static int ep93xx_eth_rcv_packet(struct eth_device *dev)
301594d57d0SMatthias Kaehlcke {
302594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
303594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
304594d57d0SMatthias Kaehlcke 	int len = -1;
305594d57d0SMatthias Kaehlcke 
306594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_rcv_packet");
307594d57d0SMatthias Kaehlcke 
308594d57d0SMatthias Kaehlcke 	if (RX_STATUS_RFP(priv->rx_sq.current)) {
309594d57d0SMatthias Kaehlcke 		if (RX_STATUS_RWE(priv->rx_sq.current)) {
310594d57d0SMatthias Kaehlcke 			/*
311594d57d0SMatthias Kaehlcke 			 * We have a good frame. Extract the frame's length
312594d57d0SMatthias Kaehlcke 			 * from the current rx_status_queue entry, and copy
3131fd92db8SJoe Hershberger 			 * the frame's data into net_rx_packets[] of the
314594d57d0SMatthias Kaehlcke 			 * protocol stack. We track the total number of
315594d57d0SMatthias Kaehlcke 			 * bytes in the frame (nbytes_frame) which will be
316594d57d0SMatthias Kaehlcke 			 * used when we pass the data off to the protocol
3171fd92db8SJoe Hershberger 			 * layer via net_process_received_packet().
318594d57d0SMatthias Kaehlcke 			 */
319594d57d0SMatthias Kaehlcke 			len = RX_STATUS_FRAME_LEN(priv->rx_sq.current);
320594d57d0SMatthias Kaehlcke 
3211fd92db8SJoe Hershberger 			net_process_received_packet(
3221fd92db8SJoe Hershberger 				(uchar *)priv->rx_dq.current->word1, len);
323594d57d0SMatthias Kaehlcke 
324594d57d0SMatthias Kaehlcke 			debug("reporting %d bytes...\n", len);
325594d57d0SMatthias Kaehlcke 		} else {
326594d57d0SMatthias Kaehlcke 			/* Do we have an erroneous packet? */
327*90aa625cSMasahiro Yamada 			pr_err("packet rx error, status %08X %08X",
328594d57d0SMatthias Kaehlcke 				priv->rx_sq.current->word1,
329594d57d0SMatthias Kaehlcke 				priv->rx_sq.current->word2);
330594d57d0SMatthias Kaehlcke 			dump_rx_descriptor_queue(dev);
331594d57d0SMatthias Kaehlcke 			dump_rx_status_queue(dev);
332594d57d0SMatthias Kaehlcke 		}
333594d57d0SMatthias Kaehlcke 
334594d57d0SMatthias Kaehlcke 		/*
335594d57d0SMatthias Kaehlcke 		 * Clear the associated status queue entry, and
336594d57d0SMatthias Kaehlcke 		 * increment our current pointers to the next RX
337594d57d0SMatthias Kaehlcke 		 * descriptor and status queue entries (making sure
338594d57d0SMatthias Kaehlcke 		 * we wrap properly).
339594d57d0SMatthias Kaehlcke 		 */
340594d57d0SMatthias Kaehlcke 		memset((void *)priv->rx_sq.current, 0,
341594d57d0SMatthias Kaehlcke 			sizeof(struct rx_status));
342594d57d0SMatthias Kaehlcke 
343594d57d0SMatthias Kaehlcke 		priv->rx_sq.current++;
344594d57d0SMatthias Kaehlcke 		if (priv->rx_sq.current >= priv->rx_sq.end)
345594d57d0SMatthias Kaehlcke 			priv->rx_sq.current = priv->rx_sq.base;
346594d57d0SMatthias Kaehlcke 
347594d57d0SMatthias Kaehlcke 		priv->rx_dq.current++;
348594d57d0SMatthias Kaehlcke 		if (priv->rx_dq.current >= priv->rx_dq.end)
349594d57d0SMatthias Kaehlcke 			priv->rx_dq.current = priv->rx_dq.base;
350594d57d0SMatthias Kaehlcke 
351594d57d0SMatthias Kaehlcke 		/*
352594d57d0SMatthias Kaehlcke 		 * Finally, return the RX descriptor and status entries
353594d57d0SMatthias Kaehlcke 		 * back to the MAC engine, and loop again, checking for
354594d57d0SMatthias Kaehlcke 		 * more descriptors to process.
355594d57d0SMatthias Kaehlcke 		 */
356594d57d0SMatthias Kaehlcke 		writel(1, &mac->rxdqenq);
357594d57d0SMatthias Kaehlcke 		writel(1, &mac->rxstsqenq);
358594d57d0SMatthias Kaehlcke 	} else {
359594d57d0SMatthias Kaehlcke 		len = 0;
360594d57d0SMatthias Kaehlcke 	}
361594d57d0SMatthias Kaehlcke 
362594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_rcv_packet %d", len);
363594d57d0SMatthias Kaehlcke 	return len;
364594d57d0SMatthias Kaehlcke }
365594d57d0SMatthias Kaehlcke 
366594d57d0SMatthias Kaehlcke /**
367594d57d0SMatthias Kaehlcke  * Send a block of data via ethernet.
368594d57d0SMatthias Kaehlcke  */
ep93xx_eth_send_packet(struct eth_device * dev,void * const packet,int const length)369594d57d0SMatthias Kaehlcke static int ep93xx_eth_send_packet(struct eth_device *dev,
37010cbe3b6SJoe Hershberger 				void * const packet, int const length)
371594d57d0SMatthias Kaehlcke {
372594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = GET_REGS(dev);
373594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv = GET_PRIV(dev);
374594d57d0SMatthias Kaehlcke 	int ret = -1;
375594d57d0SMatthias Kaehlcke 
376594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_send_packet");
377594d57d0SMatthias Kaehlcke 
378594d57d0SMatthias Kaehlcke 	/* Parameter check */
379594d57d0SMatthias Kaehlcke 	BUG_ON(packet == NULL);
380594d57d0SMatthias Kaehlcke 
381594d57d0SMatthias Kaehlcke 	/*
382594d57d0SMatthias Kaehlcke 	 * Initialize the TX descriptor queue with the new packet's info.
383594d57d0SMatthias Kaehlcke 	 * Clear the associated status queue entry. Enqueue the packet
384594d57d0SMatthias Kaehlcke 	 * to the MAC for transmission.
385594d57d0SMatthias Kaehlcke 	 */
386594d57d0SMatthias Kaehlcke 
387594d57d0SMatthias Kaehlcke 	/* set buffer address */
388594d57d0SMatthias Kaehlcke 	priv->tx_dq.current->word1 = (uint32_t)packet;
389594d57d0SMatthias Kaehlcke 
390594d57d0SMatthias Kaehlcke 	/* set buffer length and EOF bit */
391594d57d0SMatthias Kaehlcke 	priv->tx_dq.current->word2 = length | TX_DESC_EOF;
392594d57d0SMatthias Kaehlcke 
393594d57d0SMatthias Kaehlcke 	/* clear tx status */
394594d57d0SMatthias Kaehlcke 	priv->tx_sq.current->word1 = 0;
395594d57d0SMatthias Kaehlcke 
396594d57d0SMatthias Kaehlcke 	/* enqueue the TX descriptor */
397594d57d0SMatthias Kaehlcke 	writel(1, &mac->txdqenq);
398594d57d0SMatthias Kaehlcke 
399594d57d0SMatthias Kaehlcke 	/* wait for the frame to become processed */
400594d57d0SMatthias Kaehlcke 	while (!TX_STATUS_TXFP(priv->tx_sq.current))
401594d57d0SMatthias Kaehlcke 		; /* noop */
402594d57d0SMatthias Kaehlcke 
403594d57d0SMatthias Kaehlcke 	if (!TX_STATUS_TXWE(priv->tx_sq.current)) {
404*90aa625cSMasahiro Yamada 		pr_err("packet tx error, status %08X",
405594d57d0SMatthias Kaehlcke 			priv->tx_sq.current->word1);
406594d57d0SMatthias Kaehlcke 		dump_tx_descriptor_queue(dev);
407594d57d0SMatthias Kaehlcke 		dump_tx_status_queue(dev);
408594d57d0SMatthias Kaehlcke 
409594d57d0SMatthias Kaehlcke 		/* TODO: Add better error handling? */
410594d57d0SMatthias Kaehlcke 		goto eth_send_out;
411594d57d0SMatthias Kaehlcke 	}
412594d57d0SMatthias Kaehlcke 
413594d57d0SMatthias Kaehlcke 	ret = 0;
414594d57d0SMatthias Kaehlcke 	/* Fall through */
415594d57d0SMatthias Kaehlcke 
416594d57d0SMatthias Kaehlcke eth_send_out:
417594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_send_packet %d", ret);
418594d57d0SMatthias Kaehlcke 	return ret;
419594d57d0SMatthias Kaehlcke }
420594d57d0SMatthias Kaehlcke 
421594d57d0SMatthias Kaehlcke #if defined(CONFIG_MII)
ep93xx_miiphy_initialize(bd_t * const bd)422594d57d0SMatthias Kaehlcke int ep93xx_miiphy_initialize(bd_t * const bd)
423594d57d0SMatthias Kaehlcke {
4245a49f174SJoe Hershberger 	int retval;
4255a49f174SJoe Hershberger 	struct mii_dev *mdiodev = mdio_alloc();
4265a49f174SJoe Hershberger 	if (!mdiodev)
4275a49f174SJoe Hershberger 		return -ENOMEM;
4285a49f174SJoe Hershberger 	strncpy(mdiodev->name, "ep93xx_eth0", MDIO_NAME_LEN);
4295a49f174SJoe Hershberger 	mdiodev->read = ep93xx_miiphy_read;
4305a49f174SJoe Hershberger 	mdiodev->write = ep93xx_miiphy_write;
4315a49f174SJoe Hershberger 
4325a49f174SJoe Hershberger 	retval = mdio_register(mdiodev);
4335a49f174SJoe Hershberger 	if (retval < 0)
4345a49f174SJoe Hershberger 		return retval;
435594d57d0SMatthias Kaehlcke 	return 0;
436594d57d0SMatthias Kaehlcke }
437594d57d0SMatthias Kaehlcke #endif
438594d57d0SMatthias Kaehlcke 
439594d57d0SMatthias Kaehlcke /**
440594d57d0SMatthias Kaehlcke  * Initialize the EP93xx MAC.  The MAC hardware is reset.  Buffers are
441594d57d0SMatthias Kaehlcke  * allocated, if necessary, for the TX and RX descriptor and status queues,
442594d57d0SMatthias Kaehlcke  * as well as for received packets.  The EP93XX MAC hardware is initialized.
443594d57d0SMatthias Kaehlcke  * Transmit and receive operations are enabled.
444594d57d0SMatthias Kaehlcke  */
ep93xx_eth_initialize(u8 dev_num,int base_addr)445594d57d0SMatthias Kaehlcke int ep93xx_eth_initialize(u8 dev_num, int base_addr)
446594d57d0SMatthias Kaehlcke {
447594d57d0SMatthias Kaehlcke 	int ret = -1;
448594d57d0SMatthias Kaehlcke 	struct eth_device *dev;
449594d57d0SMatthias Kaehlcke 	struct ep93xx_priv *priv;
450594d57d0SMatthias Kaehlcke 
451594d57d0SMatthias Kaehlcke 	debug("+ep93xx_eth_initialize");
452594d57d0SMatthias Kaehlcke 
453594d57d0SMatthias Kaehlcke 	priv = malloc(sizeof(*priv));
454594d57d0SMatthias Kaehlcke 	if (!priv) {
455*90aa625cSMasahiro Yamada 		pr_err("malloc() failed");
456594d57d0SMatthias Kaehlcke 		goto eth_init_failed_0;
457594d57d0SMatthias Kaehlcke 	}
458594d57d0SMatthias Kaehlcke 	memset(priv, 0, sizeof(*priv));
459594d57d0SMatthias Kaehlcke 
460594d57d0SMatthias Kaehlcke 	priv->regs = (struct mac_regs *)base_addr;
461594d57d0SMatthias Kaehlcke 
462594d57d0SMatthias Kaehlcke 	priv->tx_dq.base = calloc(NUMTXDESC,
463594d57d0SMatthias Kaehlcke 				sizeof(struct tx_descriptor));
464594d57d0SMatthias Kaehlcke 	if (priv->tx_dq.base == NULL) {
465*90aa625cSMasahiro Yamada 		pr_err("calloc() failed");
466594d57d0SMatthias Kaehlcke 		goto eth_init_failed_1;
467594d57d0SMatthias Kaehlcke 	}
468594d57d0SMatthias Kaehlcke 
469594d57d0SMatthias Kaehlcke 	priv->tx_sq.base = calloc(NUMTXDESC,
470594d57d0SMatthias Kaehlcke 				sizeof(struct tx_status));
471594d57d0SMatthias Kaehlcke 	if (priv->tx_sq.base == NULL) {
472*90aa625cSMasahiro Yamada 		pr_err("calloc() failed");
473594d57d0SMatthias Kaehlcke 		goto eth_init_failed_2;
474594d57d0SMatthias Kaehlcke 	}
475594d57d0SMatthias Kaehlcke 
476594d57d0SMatthias Kaehlcke 	priv->rx_dq.base = calloc(NUMRXDESC,
477594d57d0SMatthias Kaehlcke 				sizeof(struct rx_descriptor));
478594d57d0SMatthias Kaehlcke 	if (priv->rx_dq.base == NULL) {
479*90aa625cSMasahiro Yamada 		pr_err("calloc() failed");
480594d57d0SMatthias Kaehlcke 		goto eth_init_failed_3;
481594d57d0SMatthias Kaehlcke 	}
482594d57d0SMatthias Kaehlcke 
483594d57d0SMatthias Kaehlcke 	priv->rx_sq.base = calloc(NUMRXDESC,
484594d57d0SMatthias Kaehlcke 				sizeof(struct rx_status));
485594d57d0SMatthias Kaehlcke 	if (priv->rx_sq.base == NULL) {
486*90aa625cSMasahiro Yamada 		pr_err("calloc() failed");
487594d57d0SMatthias Kaehlcke 		goto eth_init_failed_4;
488594d57d0SMatthias Kaehlcke 	}
489594d57d0SMatthias Kaehlcke 
490594d57d0SMatthias Kaehlcke 	dev = malloc(sizeof *dev);
491594d57d0SMatthias Kaehlcke 	if (dev == NULL) {
492*90aa625cSMasahiro Yamada 		pr_err("malloc() failed");
493594d57d0SMatthias Kaehlcke 		goto eth_init_failed_5;
494594d57d0SMatthias Kaehlcke 	}
495594d57d0SMatthias Kaehlcke 	memset(dev, 0, sizeof *dev);
496594d57d0SMatthias Kaehlcke 
497594d57d0SMatthias Kaehlcke 	dev->iobase = base_addr;
498594d57d0SMatthias Kaehlcke 	dev->priv = priv;
499594d57d0SMatthias Kaehlcke 	dev->init = ep93xx_eth_open;
500594d57d0SMatthias Kaehlcke 	dev->halt = ep93xx_eth_close;
501594d57d0SMatthias Kaehlcke 	dev->send = ep93xx_eth_send_packet;
502594d57d0SMatthias Kaehlcke 	dev->recv = ep93xx_eth_rcv_packet;
503594d57d0SMatthias Kaehlcke 
504594d57d0SMatthias Kaehlcke 	sprintf(dev->name, "ep93xx_eth-%hu", dev_num);
505594d57d0SMatthias Kaehlcke 
506594d57d0SMatthias Kaehlcke 	eth_register(dev);
507594d57d0SMatthias Kaehlcke 
508594d57d0SMatthias Kaehlcke 	/* Done! */
509594d57d0SMatthias Kaehlcke 	ret = 1;
510594d57d0SMatthias Kaehlcke 	goto eth_init_done;
511594d57d0SMatthias Kaehlcke 
512594d57d0SMatthias Kaehlcke eth_init_failed_5:
513594d57d0SMatthias Kaehlcke 	free(priv->rx_sq.base);
514594d57d0SMatthias Kaehlcke 	/* Fall through */
515594d57d0SMatthias Kaehlcke 
516594d57d0SMatthias Kaehlcke eth_init_failed_4:
517594d57d0SMatthias Kaehlcke 	free(priv->rx_dq.base);
518594d57d0SMatthias Kaehlcke 	/* Fall through */
519594d57d0SMatthias Kaehlcke 
520594d57d0SMatthias Kaehlcke eth_init_failed_3:
521594d57d0SMatthias Kaehlcke 	free(priv->tx_sq.base);
522594d57d0SMatthias Kaehlcke 	/* Fall through */
523594d57d0SMatthias Kaehlcke 
524594d57d0SMatthias Kaehlcke eth_init_failed_2:
525594d57d0SMatthias Kaehlcke 	free(priv->tx_dq.base);
526594d57d0SMatthias Kaehlcke 	/* Fall through */
527594d57d0SMatthias Kaehlcke 
528594d57d0SMatthias Kaehlcke eth_init_failed_1:
529594d57d0SMatthias Kaehlcke 	free(priv);
530594d57d0SMatthias Kaehlcke 	/* Fall through */
531594d57d0SMatthias Kaehlcke 
532594d57d0SMatthias Kaehlcke eth_init_failed_0:
533594d57d0SMatthias Kaehlcke 	/* Fall through */
534594d57d0SMatthias Kaehlcke 
535594d57d0SMatthias Kaehlcke eth_init_done:
536594d57d0SMatthias Kaehlcke 	debug("-ep93xx_eth_initialize %d", ret);
537594d57d0SMatthias Kaehlcke 	return ret;
538594d57d0SMatthias Kaehlcke }
539594d57d0SMatthias Kaehlcke 
540594d57d0SMatthias Kaehlcke #if defined(CONFIG_MII)
541594d57d0SMatthias Kaehlcke 
542594d57d0SMatthias Kaehlcke /**
543594d57d0SMatthias Kaehlcke  * Maximum MII address we support
544594d57d0SMatthias Kaehlcke  */
545594d57d0SMatthias Kaehlcke #define MII_ADDRESS_MAX			31
546594d57d0SMatthias Kaehlcke 
547594d57d0SMatthias Kaehlcke /**
548594d57d0SMatthias Kaehlcke  * Maximum MII register address we support
549594d57d0SMatthias Kaehlcke  */
550594d57d0SMatthias Kaehlcke #define MII_REGISTER_MAX		31
551594d57d0SMatthias Kaehlcke 
552594d57d0SMatthias Kaehlcke /**
553594d57d0SMatthias Kaehlcke  * Read a 16-bit value from an MII register.
554594d57d0SMatthias Kaehlcke  */
ep93xx_miiphy_read(struct mii_dev * bus,int addr,int devad,int reg)5555a49f174SJoe Hershberger static int ep93xx_miiphy_read(struct mii_dev *bus, int addr, int devad,
5565a49f174SJoe Hershberger 			      int reg)
557594d57d0SMatthias Kaehlcke {
5585a49f174SJoe Hershberger 	unsigned short value = 0;
559594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
560594d57d0SMatthias Kaehlcke 	int ret = -1;
561594d57d0SMatthias Kaehlcke 	uint32_t self_ctl;
562594d57d0SMatthias Kaehlcke 
563594d57d0SMatthias Kaehlcke 	debug("+ep93xx_miiphy_read");
564594d57d0SMatthias Kaehlcke 
565594d57d0SMatthias Kaehlcke 	/* Parameter checks */
5665a49f174SJoe Hershberger 	BUG_ON(bus->name == NULL);
567594d57d0SMatthias Kaehlcke 	BUG_ON(addr > MII_ADDRESS_MAX);
568594d57d0SMatthias Kaehlcke 	BUG_ON(reg > MII_REGISTER_MAX);
569594d57d0SMatthias Kaehlcke 
570594d57d0SMatthias Kaehlcke 	/*
571594d57d0SMatthias Kaehlcke 	 * Save the current SelfCTL register value.  Set MAC to suppress
572594d57d0SMatthias Kaehlcke 	 * preamble bits.  Wait for any previous MII command to complete
573594d57d0SMatthias Kaehlcke 	 * before issuing the new command.
574594d57d0SMatthias Kaehlcke 	 */
575594d57d0SMatthias Kaehlcke 	self_ctl = readl(&mac->selfctl);
576594d57d0SMatthias Kaehlcke #if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
577594d57d0SMatthias Kaehlcke 	writel(self_ctl & ~(1 << 8), &mac->selfctl);
578594d57d0SMatthias Kaehlcke #endif	/* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
579594d57d0SMatthias Kaehlcke 
580594d57d0SMatthias Kaehlcke 	while (readl(&mac->miists) & MIISTS_BUSY)
581594d57d0SMatthias Kaehlcke 		; /* noop */
582594d57d0SMatthias Kaehlcke 
583594d57d0SMatthias Kaehlcke 	/*
584594d57d0SMatthias Kaehlcke 	 * Issue the MII 'read' command.  Wait for the command to complete.
585594d57d0SMatthias Kaehlcke 	 * Read the MII data value.
586594d57d0SMatthias Kaehlcke 	 */
587594d57d0SMatthias Kaehlcke 	writel(MIICMD_OPCODE_READ | ((uint32_t)addr << 5) | (uint32_t)reg,
588594d57d0SMatthias Kaehlcke 		&mac->miicmd);
589594d57d0SMatthias Kaehlcke 	while (readl(&mac->miists) & MIISTS_BUSY)
590594d57d0SMatthias Kaehlcke 		; /* noop */
591594d57d0SMatthias Kaehlcke 
5925a49f174SJoe Hershberger 	value = (unsigned short)readl(&mac->miidata);
593594d57d0SMatthias Kaehlcke 
594594d57d0SMatthias Kaehlcke 	/* Restore the saved SelfCTL value and return. */
595594d57d0SMatthias Kaehlcke 	writel(self_ctl, &mac->selfctl);
596594d57d0SMatthias Kaehlcke 
597594d57d0SMatthias Kaehlcke 	ret = 0;
598594d57d0SMatthias Kaehlcke 	/* Fall through */
599594d57d0SMatthias Kaehlcke 
600594d57d0SMatthias Kaehlcke 	debug("-ep93xx_miiphy_read");
6015a49f174SJoe Hershberger 	if (ret < 0)
602594d57d0SMatthias Kaehlcke 		return ret;
6035a49f174SJoe Hershberger 	return value;
604594d57d0SMatthias Kaehlcke }
605594d57d0SMatthias Kaehlcke 
606594d57d0SMatthias Kaehlcke /**
607594d57d0SMatthias Kaehlcke  * Write a 16-bit value to an MII register.
608594d57d0SMatthias Kaehlcke  */
ep93xx_miiphy_write(struct mii_dev * bus,int addr,int devad,int reg,u16 value)6095a49f174SJoe Hershberger static int ep93xx_miiphy_write(struct mii_dev *bus, int addr, int devad,
6105a49f174SJoe Hershberger 			       int reg, u16 value)
611594d57d0SMatthias Kaehlcke {
612594d57d0SMatthias Kaehlcke 	struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
613594d57d0SMatthias Kaehlcke 	int ret = -1;
614594d57d0SMatthias Kaehlcke 	uint32_t self_ctl;
615594d57d0SMatthias Kaehlcke 
616594d57d0SMatthias Kaehlcke 	debug("+ep93xx_miiphy_write");
617594d57d0SMatthias Kaehlcke 
618594d57d0SMatthias Kaehlcke 	/* Parameter checks */
6195a49f174SJoe Hershberger 	BUG_ON(bus->name == NULL);
620594d57d0SMatthias Kaehlcke 	BUG_ON(addr > MII_ADDRESS_MAX);
621594d57d0SMatthias Kaehlcke 	BUG_ON(reg > MII_REGISTER_MAX);
622594d57d0SMatthias Kaehlcke 
623594d57d0SMatthias Kaehlcke 	/*
624594d57d0SMatthias Kaehlcke 	 * Save the current SelfCTL register value.  Set MAC to suppress
625594d57d0SMatthias Kaehlcke 	 * preamble bits.  Wait for any previous MII command to complete
626594d57d0SMatthias Kaehlcke 	 * before issuing the new command.
627594d57d0SMatthias Kaehlcke 	 */
628594d57d0SMatthias Kaehlcke 	self_ctl = readl(&mac->selfctl);
629594d57d0SMatthias Kaehlcke #if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
630594d57d0SMatthias Kaehlcke 	writel(self_ctl & ~(1 << 8), &mac->selfctl);
631594d57d0SMatthias Kaehlcke #endif	/* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
632594d57d0SMatthias Kaehlcke 
633594d57d0SMatthias Kaehlcke 	while (readl(&mac->miists) & MIISTS_BUSY)
634594d57d0SMatthias Kaehlcke 		; /* noop */
635594d57d0SMatthias Kaehlcke 
636594d57d0SMatthias Kaehlcke 	/* Issue the MII 'write' command.  Wait for the command to complete. */
637594d57d0SMatthias Kaehlcke 	writel((uint32_t)value, &mac->miidata);
638594d57d0SMatthias Kaehlcke 	writel(MIICMD_OPCODE_WRITE | ((uint32_t)addr << 5) | (uint32_t)reg,
639594d57d0SMatthias Kaehlcke 		&mac->miicmd);
640594d57d0SMatthias Kaehlcke 	while (readl(&mac->miists) & MIISTS_BUSY)
641594d57d0SMatthias Kaehlcke 		; /* noop */
642594d57d0SMatthias Kaehlcke 
643594d57d0SMatthias Kaehlcke 	/* Restore the saved SelfCTL value and return. */
644594d57d0SMatthias Kaehlcke 	writel(self_ctl, &mac->selfctl);
645594d57d0SMatthias Kaehlcke 
646594d57d0SMatthias Kaehlcke 	ret = 0;
647594d57d0SMatthias Kaehlcke 	/* Fall through */
648594d57d0SMatthias Kaehlcke 
649594d57d0SMatthias Kaehlcke 	debug("-ep93xx_miiphy_write");
650594d57d0SMatthias Kaehlcke 	return ret;
651594d57d0SMatthias Kaehlcke }
652594d57d0SMatthias Kaehlcke #endif	/* defined(CONFIG_MII) */
653