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