net: mii: Use spatch to update miiphy_register
[platform/kernel/u-boot.git] / drivers / net / bfin_mac.c
1 /*
2  * Driver for Blackfin On-Chip MAC device
3  *
4  * Copyright (c) 2005-2008 Analog Device, Inc.
5  *
6  * Licensed under the GPL-2 or later.
7  */
8
9 #include <common.h>
10 #include <config.h>
11 #include <net.h>
12 #include <netdev.h>
13 #include <command.h>
14 #include <malloc.h>
15 #include <miiphy.h>
16 #include <linux/mii.h>
17
18 #include <asm/blackfin.h>
19 #include <asm/clock.h>
20 #include <asm/portmux.h>
21 #include <asm/mach-common/bits/dma.h>
22 #include <asm/mach-common/bits/emac.h>
23 #include <asm/mach-common/bits/pll.h>
24
25 #include "bfin_mac.h"
26
27 #ifndef CONFIG_PHY_ADDR
28 # define CONFIG_PHY_ADDR 1
29 #endif
30 #ifndef CONFIG_PHY_CLOCK_FREQ
31 # define CONFIG_PHY_CLOCK_FREQ 2500000
32 #endif
33
34 #ifdef CONFIG_POST
35 #include <post.h>
36 #endif
37
38 #define RXBUF_BASE_ADDR         0xFF900000
39 #define TXBUF_BASE_ADDR         0xFF800000
40 #define TX_BUF_CNT              1
41
42 #define TOUT_LOOP               1000000
43
44 static ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT];
45 static ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX];
46 static u16 txIdx;               /* index of the current RX buffer */
47 static u16 rxIdx;               /* index of the current TX buffer */
48
49 /* DMAx_CONFIG values at DMA Restart */
50 static const union {
51         u16 data;
52         ADI_DMA_CONFIG_REG reg;
53 } txdmacfg = {
54         .reg = {
55                 .b_DMA_EN  = 1, /* enabled */
56                 .b_WNR     = 0, /* read from memory */
57                 .b_WDSIZE  = 2, /* wordsize is 32 bits */
58                 .b_DMA2D   = 0,
59                 .b_RESTART = 0,
60                 .b_DI_SEL  = 0,
61                 .b_DI_EN   = 0, /* no interrupt */
62                 .b_NDSIZE  = 5, /* 5 half words is desc size */
63                 .b_FLOW    = 7  /* large desc flow */
64         },
65 };
66
67 static int bfin_miiphy_wait(void)
68 {
69         /* poll the STABUSY bit */
70         while (bfin_read_EMAC_STAADD() & STABUSY)
71                 continue;
72         return 0;
73 }
74
75 static int bfin_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
76 {
77         ushort val = 0;
78         if (bfin_miiphy_wait())
79                 return 1;
80         bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STABUSY);
81         if (bfin_miiphy_wait())
82                 return 1;
83         val = bfin_read_EMAC_STADAT();
84         return val;
85 }
86
87 static int bfin_miiphy_write(struct mii_dev *bus, int addr, int devad,
88                              int reg, u16 val)
89 {
90         if (bfin_miiphy_wait())
91                 return 1;
92         bfin_write_EMAC_STADAT(val);
93         bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STAOP | STABUSY);
94         return 0;
95 }
96
97 int bfin_EMAC_initialize(bd_t *bis)
98 {
99         struct eth_device *dev;
100         dev = malloc(sizeof(*dev));
101         if (dev == NULL)
102                 hang();
103
104         memset(dev, 0, sizeof(*dev));
105         strcpy(dev->name, "bfin_mac");
106
107         dev->iobase = 0;
108         dev->priv = 0;
109         dev->init = bfin_EMAC_init;
110         dev->halt = bfin_EMAC_halt;
111         dev->send = bfin_EMAC_send;
112         dev->recv = bfin_EMAC_recv;
113         dev->write_hwaddr = bfin_EMAC_setup_addr;
114
115         eth_register(dev);
116
117 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
118         int retval;
119         struct mii_dev *mdiodev = mdio_alloc();
120         if (!mdiodev)
121                 return -ENOMEM;
122         strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
123         mdiodev->read = bfin_miiphy_read;
124         mdiodev->write = bfin_miiphy_write;
125
126         retval = mdio_register(mdiodev);
127         if (retval < 0)
128                 return retval;
129 #endif
130
131         return 0;
132 }
133
134 static int bfin_EMAC_send(struct eth_device *dev, void *packet, int length)
135 {
136         int i;
137         int result = 0;
138
139         if (length <= 0) {
140                 printf("Ethernet: bad packet size: %d\n", length);
141                 goto out;
142         }
143
144         if (bfin_read_DMA2_IRQ_STATUS() & DMA_ERR) {
145                 printf("Ethernet: tx DMA error\n");
146                 goto out;
147         }
148
149         for (i = 0; (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN); ++i) {
150                 if (i > TOUT_LOOP) {
151                         puts("Ethernet: tx time out\n");
152                         goto out;
153                 }
154         }
155         txbuf[txIdx]->FrmData->NoBytes = length;
156         memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length);
157         txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData;
158         bfin_write_DMA2_NEXT_DESC_PTR(txbuf[txIdx]->Dma);
159         bfin_write_DMA2_CONFIG(txdmacfg.data);
160         bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
161
162         for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) {
163                 if (i > TOUT_LOOP) {
164                         puts("Ethernet: tx error\n");
165                         goto out;
166                 }
167         }
168         result = txbuf[txIdx]->StatusWord;
169         txbuf[txIdx]->StatusWord = 0;
170         if ((txIdx + 1) >= TX_BUF_CNT)
171                 txIdx = 0;
172         else
173                 txIdx++;
174  out:
175         debug("BFIN EMAC send: length = %d\n", length);
176         return result;
177 }
178
179 static int bfin_EMAC_recv(struct eth_device *dev)
180 {
181         int length = 0;
182
183         for (;;) {
184                 if ((rxbuf[rxIdx]->StatusWord & RX_COMP) == 0) {
185                         length = -1;
186                         break;
187                 }
188                 if ((rxbuf[rxIdx]->StatusWord & RX_DMAO) != 0) {
189                         printf("Ethernet: rx dma overrun\n");
190                         break;
191                 }
192                 if ((rxbuf[rxIdx]->StatusWord & RX_OK) == 0) {
193                         printf("Ethernet: rx error\n");
194                         break;
195                 }
196                 length = rxbuf[rxIdx]->StatusWord & 0x000007FF;
197                 if (length <= 4) {
198                         printf("Ethernet: bad frame\n");
199                         break;
200                 }
201
202                 debug("%s: len = %d\n", __func__, length - 4);
203
204                 net_rx_packets[rxIdx] = rxbuf[rxIdx]->FrmData->Dest;
205                 net_process_received_packet(net_rx_packets[rxIdx], length - 4);
206                 bfin_write_DMA1_IRQ_STATUS(DMA_DONE | DMA_ERR);
207                 rxbuf[rxIdx]->StatusWord = 0x00000000;
208                 if ((rxIdx + 1) >= PKTBUFSRX)
209                         rxIdx = 0;
210                 else
211                         rxIdx++;
212         }
213
214         return length;
215 }
216
217 /**************************************************************
218  *
219  * Ethernet Initialization Routine
220  *
221  *************************************************************/
222
223 /* MDC = SCLK / MDC_freq / 2 - 1 */
224 #define MDC_FREQ_TO_DIV(mdc_freq) (get_sclk() / (mdc_freq) / 2 - 1)
225
226 #ifndef CONFIG_BFIN_MAC_PINS
227 # ifdef CONFIG_RMII
228 #  define CONFIG_BFIN_MAC_PINS P_RMII0
229 # else
230 #  define CONFIG_BFIN_MAC_PINS P_MII0
231 # endif
232 #endif
233
234 static int bfin_miiphy_init(struct eth_device *dev, int *opmode)
235 {
236         const unsigned short pins[] = CONFIG_BFIN_MAC_PINS;
237         u16 phydat;
238         size_t count;
239
240         /* Enable PHY output */
241         bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE);
242
243         /* Set all the pins to peripheral mode */
244         peripheral_request_list(pins, "bfin_mac");
245
246         /* Odd word alignment for Receive Frame DMA word */
247         /* Configure checksum support and rcve frame word alignment */
248         bfin_write_EMAC_SYSCTL(RXDWA | RXCKS | SET_MDCDIV(MDC_FREQ_TO_DIV(CONFIG_PHY_CLOCK_FREQ)));
249
250         /* turn on auto-negotiation and wait for link to come up */
251         bfin_miiphy_write(dev->name, CONFIG_PHY_ADDR, MII_BMCR, BMCR_ANENABLE);
252         count = 0;
253         while (1) {
254                 ++count;
255                 if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_BMSR, &phydat))
256                         return -1;
257                 if (phydat & BMSR_LSTATUS)
258                         break;
259                 if (count > 30000) {
260                         printf("%s: link down, check cable\n", dev->name);
261                         return -1;
262                 }
263                 udelay(100);
264         }
265
266         /* see what kind of link we have */
267         if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_LPA, &phydat))
268                 return -1;
269         if (phydat & LPA_DUPLEX)
270                 *opmode = FDMODE;
271         else
272                 *opmode = 0;
273
274         bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
275         bfin_write_EMAC_VLAN1(EMAC_VLANX_DEF_VAL);
276         bfin_write_EMAC_VLAN2(EMAC_VLANX_DEF_VAL);
277
278         /* Initialize the TX DMA channel registers */
279         bfin_write_DMA2_X_COUNT(0);
280         bfin_write_DMA2_X_MODIFY(4);
281         bfin_write_DMA2_Y_COUNT(0);
282         bfin_write_DMA2_Y_MODIFY(0);
283
284         /* Initialize the RX DMA channel registers */
285         bfin_write_DMA1_X_COUNT(0);
286         bfin_write_DMA1_X_MODIFY(4);
287         bfin_write_DMA1_Y_COUNT(0);
288         bfin_write_DMA1_Y_MODIFY(0);
289
290         return 0;
291 }
292
293 static int bfin_EMAC_setup_addr(struct eth_device *dev)
294 {
295         bfin_write_EMAC_ADDRLO(
296                 dev->enetaddr[0] |
297                 dev->enetaddr[1] << 8 |
298                 dev->enetaddr[2] << 16 |
299                 dev->enetaddr[3] << 24
300         );
301         bfin_write_EMAC_ADDRHI(
302                 dev->enetaddr[4] |
303                 dev->enetaddr[5] << 8
304         );
305         return 0;
306 }
307
308 static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd)
309 {
310         u32 opmode;
311         int dat;
312         int i;
313         debug("Eth_init: ......\n");
314
315         txIdx = 0;
316         rxIdx = 0;
317
318         /* Initialize System Register */
319         if (bfin_miiphy_init(dev, &dat) < 0)
320                 return -1;
321
322         /* Initialize EMAC address */
323         bfin_EMAC_setup_addr(dev);
324
325         /* Initialize TX and RX buffer */
326         for (i = 0; i < PKTBUFSRX; i++) {
327                 rxbuf[i] = SetupRxBuffer(i);
328                 if (i > 0) {
329                         rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR = rxbuf[i]->Dma;
330                         if (i == (PKTBUFSRX - 1))
331                                 rxbuf[i]->Dma[1].NEXT_DESC_PTR = rxbuf[0]->Dma;
332                 }
333         }
334         for (i = 0; i < TX_BUF_CNT; i++) {
335                 txbuf[i] = SetupTxBuffer(i);
336                 if (i > 0) {
337                         txbuf[i - 1]->Dma[1].NEXT_DESC_PTR = txbuf[i]->Dma;
338                         if (i == (TX_BUF_CNT - 1))
339                                 txbuf[i]->Dma[1].NEXT_DESC_PTR = txbuf[0]->Dma;
340                 }
341         }
342
343         /* Set RX DMA */
344         bfin_write_DMA1_NEXT_DESC_PTR(rxbuf[0]->Dma);
345         bfin_write_DMA1_CONFIG(rxbuf[0]->Dma[0].CONFIG_DATA);
346
347         /* Wait MII done */
348         bfin_miiphy_wait();
349
350         /* We enable only RX here */
351         /* ASTP   : Enable Automatic Pad Stripping
352            PR     : Promiscuous Mode for test
353            PSF    : Receive frames with total length less than 64 bytes.
354            FDMODE : Full Duplex Mode
355            LB     : Internal Loopback for test
356            RE     : Receiver Enable */
357         if (dat == FDMODE)
358                 opmode = ASTP | FDMODE | PSF;
359         else
360                 opmode = ASTP | PSF;
361         opmode |= RE;
362 #ifdef CONFIG_RMII
363         opmode |= TE | RMII;
364 #endif
365         /* Turn on the EMAC */
366         bfin_write_EMAC_OPMODE(opmode);
367         return 0;
368 }
369
370 static void bfin_EMAC_halt(struct eth_device *dev)
371 {
372         debug("Eth_halt: ......\n");
373         /* Turn off the EMAC */
374         bfin_write_EMAC_OPMODE(0);
375         /* Turn off the EMAC RX DMA */
376         bfin_write_DMA1_CONFIG(0);
377         bfin_write_DMA2_CONFIG(0);
378 }
379
380 ADI_ETHER_BUFFER *SetupRxBuffer(int no)
381 {
382         ADI_ETHER_FRAME_BUFFER *frmbuf;
383         ADI_ETHER_BUFFER *buf;
384         int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2;   /* ensure a multi. of 4 */
385         int total_size = nobytes_buffer + RECV_BUFSIZE;
386
387         buf = (void *) (RXBUF_BASE_ADDR + no * total_size);
388         frmbuf = (void *) (RXBUF_BASE_ADDR + no * total_size + nobytes_buffer);
389
390         memset(buf, 0x00, nobytes_buffer);
391         buf->FrmData = frmbuf;
392         memset(frmbuf, 0xfe, RECV_BUFSIZE);
393
394         /* set up first desc to point to receive frame buffer */
395         buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
396         buf->Dma[0].START_ADDR = (u32) buf->FrmData;
397         buf->Dma[0].CONFIG.b_DMA_EN = 1;        /* enabled */
398         buf->Dma[0].CONFIG.b_WNR = 1;   /* Write to memory */
399         buf->Dma[0].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
400         buf->Dma[0].CONFIG.b_NDSIZE = 5;        /* 5 half words is desc size. */
401         buf->Dma[0].CONFIG.b_FLOW = 7;  /* large desc flow */
402
403         /* set up second desc to point to status word */
404         buf->Dma[1].NEXT_DESC_PTR = buf->Dma;
405         buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum;
406         buf->Dma[1].CONFIG.b_DMA_EN = 1;        /* enabled */
407         buf->Dma[1].CONFIG.b_WNR = 1;   /* Write to memory */
408         buf->Dma[1].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
409         buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
410         buf->Dma[1].CONFIG.b_NDSIZE = 5;        /* must be 0 when FLOW is 0 */
411         buf->Dma[1].CONFIG.b_FLOW = 7;  /* stop */
412
413         return buf;
414 }
415
416 ADI_ETHER_BUFFER *SetupTxBuffer(int no)
417 {
418         ADI_ETHER_FRAME_BUFFER *frmbuf;
419         ADI_ETHER_BUFFER *buf;
420         int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2;   /* ensure a multi. of 4 */
421         int total_size = nobytes_buffer + RECV_BUFSIZE;
422
423         buf = (void *) (TXBUF_BASE_ADDR + no * total_size);
424         frmbuf = (void *) (TXBUF_BASE_ADDR + no * total_size + nobytes_buffer);
425
426         memset(buf, 0x00, nobytes_buffer);
427         buf->FrmData = frmbuf;
428         memset(frmbuf, 0x00, RECV_BUFSIZE);
429
430         /* set up first desc to point to receive frame buffer */
431         buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
432         buf->Dma[0].START_ADDR = (u32) buf->FrmData;
433         buf->Dma[0].CONFIG.b_DMA_EN = 1;        /* enabled */
434         buf->Dma[0].CONFIG.b_WNR = 0;   /* Read to memory */
435         buf->Dma[0].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
436         buf->Dma[0].CONFIG.b_NDSIZE = 5;        /* 5 half words is desc size. */
437         buf->Dma[0].CONFIG.b_FLOW = 7;  /* large desc flow */
438
439         /* set up second desc to point to status word */
440         buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]);
441         buf->Dma[1].START_ADDR = (u32) & buf->StatusWord;
442         buf->Dma[1].CONFIG.b_DMA_EN = 1;        /* enabled */
443         buf->Dma[1].CONFIG.b_WNR = 1;   /* Write to memory */
444         buf->Dma[1].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
445         buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
446         buf->Dma[1].CONFIG.b_NDSIZE = 0;        /* must be 0 when FLOW is 0 */
447         buf->Dma[1].CONFIG.b_FLOW = 0;  /* stop */
448
449         return buf;
450 }
451
452 #if defined(CONFIG_POST) && defined(CONFIG_SYS_POST_ETHER)
453 int ether_post_test(int flags)
454 {
455         uchar buf[64];
456         int i, value = 0;
457         int length;
458         uint addr;
459
460         printf("\n--------");
461         bfin_EMAC_init(NULL, NULL);
462         /* construct the package */
463         addr = bfin_read_EMAC_ADDRLO();
464         buf[0] = buf[6] = addr;
465         buf[1] = buf[7] = addr >> 8;
466         buf[2] = buf[8] = addr >> 16;
467         buf[3] = buf[9] = addr >> 24;
468         addr = bfin_read_EMAC_ADDRHI();
469         buf[4] = buf[10] = addr;
470         buf[5] = buf[11] = addr >> 8;
471         buf[12] = 0x08;         /* Type: ARP */
472         buf[13] = 0x06;
473         buf[14] = 0x00;         /* Hardware type: Ethernet */
474         buf[15] = 0x01;
475         buf[16] = 0x08;         /* Protocal type: IP */
476         buf[17] = 0x00;
477         buf[18] = 0x06;         /* Hardware size    */
478         buf[19] = 0x04;         /* Protocol size    */
479         buf[20] = 0x00;         /* Opcode: request  */
480         buf[21] = 0x01;
481
482         for (i = 0; i < 42; i++)
483                 buf[i + 22] = i;
484         printf("--------Send 64 bytes......\n");
485         bfin_EMAC_send(NULL, buf, 64);
486         for (i = 0; i < 100; i++) {
487                 udelay(10000);
488                 if ((rxbuf[rxIdx]->StatusWord & RX_COMP) != 0) {
489                         value = 1;
490                         break;
491                 }
492         }
493         if (value == 0) {
494                 printf("--------EMAC can't receive any data\n");
495                 eth_halt();
496                 return -1;
497         }
498         length = rxbuf[rxIdx]->StatusWord & 0x000007FF - 4;
499         for (i = 0; i < length; i++) {
500                 if (rxbuf[rxIdx]->FrmData->Dest[i] != buf[i]) {
501                         printf("--------EMAC receive error data!\n");
502                         eth_halt();
503                         return -1;
504                 }
505         }
506         printf("--------receive %d bytes, matched\n", length);
507         bfin_EMAC_halt(NULL);
508         return 0;
509 }
510 #endif