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