Merge with git://www.denx.de/git/u-boot.git
[platform/kernel/u-boot.git] / board / bf537-stamp / ether_bf537.c
1 /*
2  * ADI Blackfin 537 MAC Ethernet
3  *
4  * Copyright (c) 2005 Analog Device, Inc.
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 #include <common.h>
26 #include <config.h>
27 #include <asm/blackfin.h>
28 #include <net.h>
29 #include <command.h>
30 #include <malloc.h>
31 #include "ether_bf537.h"
32
33 #ifdef CONFIG_POST
34 #include <post.h>
35 #endif
36
37 #undef DEBUG_ETHERNET
38
39 #ifdef DEBUG_ETHERNET
40 #define DEBUGF(fmt,args...) printf(fmt,##args)
41 #else
42 #define DEBUGF(fmt,args...)
43 #endif
44
45 #if defined(CONFIG_CMD_NET)
46
47 #define RXBUF_BASE_ADDR         0xFF900000
48 #define TXBUF_BASE_ADDR         0xFF800000
49 #define TX_BUF_CNT              1
50
51 #define TOUT_LOOP               1000000
52
53 ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT];
54 ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX];
55 static u16 txIdx;               /* index of the current RX buffer */
56 static u16 rxIdx;               /* index of the current TX buffer */
57
58 u8 SrcAddr[6];
59 u16 PHYregs[NO_PHY_REGS];       /* u16 PHYADDR; */
60
61 /* DMAx_CONFIG values at DMA Restart */
62 const ADI_DMA_CONFIG_REG rxdmacfg = { 1, 1, 2, 0, 0, 0, 0, 5, 7 };
63
64 #if 0
65         rxdmacfg.b_DMA_EN = 1;  /* enabled */
66         rxdmacfg.b_WNR    = 1;  /* write to memory */
67         rxdmacfg.b_WDSIZE = 2;  /* wordsize is 32 bits */
68         rxdmacfg.b_DMA2D  = 0;  /* N/A */
69         rxdmacfg.b_RESTART= 0;  /* N/A */
70         rxdmacfg.b_DI_SEL = 0;  /* N/A */
71         rxdmacfg.b_DI_EN  = 0;  /* no interrupt */
72         rxdmacfg.b_NDSIZE = 5;  /* 5 half words is desc size. */
73         rxdmacfg.b_FLOW   = 7;  /* large desc flow  */
74 #endif
75
76 const ADI_DMA_CONFIG_REG txdmacfg = { 1, 0, 2, 0, 0, 0, 0, 5, 7 };
77
78 #if 0
79         txdmacfg.b_DMA_EN = 1;  /* enabled */
80         txdmacfg.b_WNR    = 0;  /* read from memory */
81         txdmacfg.b_WDSIZE = 2;  /* wordsize is 32 bits */
82         txdmacfg.b_DMA2D  = 0;  /* N/A */
83         txdmacfg.b_RESTART= 0;  /* N/A */
84         txdmacfg.b_DI_SEL = 0;  /* N/A */
85         txdmacfg.b_DI_EN  = 0;  /* no interrupt */
86         txdmacfg.b_NDSIZE = 5;  /* 5 half words is desc size. */
87         txdmacfg.b_FLOW   = 7;  /* large desc flow */
88 #endif
89
90 ADI_ETHER_BUFFER *SetupRxBuffer(int no);
91 ADI_ETHER_BUFFER *SetupTxBuffer(int no);
92
93 static int bfin_EMAC_init(struct eth_device *dev, bd_t * bd);
94 static void bfin_EMAC_halt(struct eth_device *dev);
95 static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet,
96                           int length);
97 static int bfin_EMAC_recv(struct eth_device *dev);
98
99 int bfin_EMAC_initialize(bd_t * bis)
100 {
101         struct eth_device *dev;
102         dev = (struct eth_device *)malloc(sizeof(*dev));
103         if (dev == NULL)
104                 hang();
105
106         memset(dev, 0, sizeof(*dev));
107         sprintf(dev->name, "BF537 ETHERNET");
108
109         dev->iobase = 0;
110         dev->priv = 0;
111         dev->init = bfin_EMAC_init;
112         dev->halt = bfin_EMAC_halt;
113         dev->send = bfin_EMAC_send;
114         dev->recv = bfin_EMAC_recv;
115
116         eth_register(dev);
117
118         return 1;
119 }
120
121 static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet,
122                           int length)
123 {
124         int i;
125         int result = 0;
126         unsigned int *buf;
127         buf = (unsigned int *)packet;
128
129         if (length <= 0) {
130                 printf("Ethernet: bad packet size: %d\n", length);
131                 goto out;
132         }
133
134         if ((*pDMA2_IRQ_STATUS & DMA_ERR) != 0) {
135                 printf("Ethernet: tx DMA error\n");
136                 goto out;
137         }
138
139         for (i = 0; (*pDMA2_IRQ_STATUS & DMA_RUN) != 0; i++) {
140                 if (i > TOUT_LOOP) {
141                         puts("Ethernet: tx time out\n");
142                         goto out;
143                 }
144         }
145         txbuf[txIdx]->FrmData->NoBytes = length;
146         memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length);
147         txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData;
148         *pDMA2_NEXT_DESC_PTR = &txbuf[txIdx]->Dma[0];
149         *pDMA2_CONFIG = *(u16 *) (void *)(&txdmacfg);
150         *pEMAC_OPMODE |= TE;
151
152         for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) {
153                 if (i > TOUT_LOOP) {
154                         puts("Ethernet: tx error\n");
155                         goto out;
156                 }
157         }
158         result = txbuf[txIdx]->StatusWord;
159         txbuf[txIdx]->StatusWord = 0;
160         if ((txIdx + 1) >= TX_BUF_CNT)
161                 txIdx = 0;
162         else
163                 txIdx++;
164       out:
165         DEBUGF("BFIN EMAC send: length = %d\n", length);
166         return result;
167 }
168
169 static int bfin_EMAC_recv(struct eth_device *dev)
170 {
171         int length = 0;
172
173         for (;;) {
174                 if ((rxbuf[rxIdx]->StatusWord & RX_COMP) == 0) {
175                         length = -1;
176                         break;
177                 }
178                 if ((rxbuf[rxIdx]->StatusWord & RX_DMAO) != 0) {
179                         printf("Ethernet: rx dma overrun\n");
180                         break;
181                 }
182                 if ((rxbuf[rxIdx]->StatusWord & RX_OK) == 0) {
183                         printf("Ethernet: rx error\n");
184                         break;
185                 }
186                 length = rxbuf[rxIdx]->StatusWord & 0x000007FF;
187                 if (length <= 4) {
188                         printf("Ethernet: bad frame\n");
189                         break;
190                 }
191                 NetRxPackets[rxIdx] =
192                     (volatile uchar *)(rxbuf[rxIdx]->FrmData->Dest);
193                 NetReceive(NetRxPackets[rxIdx], length - 4);
194                 *pDMA1_IRQ_STATUS |= DMA_DONE | DMA_ERR;
195                 rxbuf[rxIdx]->StatusWord = 0x00000000;
196                 if ((rxIdx + 1) >= PKTBUFSRX)
197                         rxIdx = 0;
198                 else
199                         rxIdx++;
200         }
201
202         return length;
203 }
204
205 /**************************************************************
206  *
207  * Ethernet Initialization Routine
208  *
209  *************************************************************/
210
211 static int bfin_EMAC_init(struct eth_device *dev, bd_t * bd)
212 {
213         u32 opmode;
214         int dat;
215         int i;
216         DEBUGF("Eth_init: ......\n");
217
218         txIdx = 0;
219         rxIdx = 0;
220
221 /* Initialize System Register */
222         if (SetupSystemRegs(&dat) < 0)
223                 return -1;
224
225 /* Initialize EMAC address */
226         SetupMacAddr(SrcAddr);
227
228 /* Initialize TX and RX buffer */
229         for (i = 0; i < PKTBUFSRX; i++) {
230                 rxbuf[i] = SetupRxBuffer(i);
231                 if (i > 0) {
232                         rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR =
233                             &(rxbuf[i]->Dma[0]);
234                         if (i == (PKTBUFSRX - 1))
235                                 rxbuf[i]->Dma[1].NEXT_DESC_PTR =
236                                     &(rxbuf[0]->Dma[0]);
237                 }
238         }
239         for (i = 0; i < TX_BUF_CNT; i++) {
240                 txbuf[i] = SetupTxBuffer(i);
241                 if (i > 0) {
242                         txbuf[i - 1]->Dma[1].NEXT_DESC_PTR =
243                             &(txbuf[i]->Dma[0]);
244                         if (i == (TX_BUF_CNT - 1))
245                                 txbuf[i]->Dma[1].NEXT_DESC_PTR =
246                                     &(txbuf[0]->Dma[0]);
247                 }
248         }
249
250         /* Set RX DMA */
251         *pDMA1_NEXT_DESC_PTR = &rxbuf[0]->Dma[0];
252         *pDMA1_CONFIG = *((u16 *) (void *)&rxbuf[0]->Dma[0].CONFIG);
253
254         /* Wait MII done */
255         PollMdcDone();
256
257         /* We enable only RX here */
258         /* ASTP   : Enable Automatic Pad Stripping
259            PR     : Promiscuous Mode for test
260            PSF    : Receive frames with total length less than 64 bytes.
261            FDMODE : Full Duplex Mode
262            LB     : Internal Loopback for test
263            RE     : Receiver Enable */
264         if (dat == FDMODE)
265                 opmode = ASTP | FDMODE | PSF;
266         else
267                 opmode = ASTP | PSF;
268         opmode |= RE;
269 #ifdef CONFIG_BFIN_MAC_RMII
270         opmode |= TE | RMII;
271 #endif
272         /* Turn on the EMAC */
273         *pEMAC_OPMODE = opmode;
274         return 0;
275 }
276
277 static void bfin_EMAC_halt(struct eth_device *dev)
278 {
279         DEBUGF("Eth_halt: ......\n");
280         /* Turn off the EMAC */
281         *pEMAC_OPMODE = 0x00000000;
282         /* Turn off the EMAC RX DMA */
283         *pDMA1_CONFIG = 0x0000;
284         *pDMA2_CONFIG = 0x0000;
285
286 }
287
288 void SetupMacAddr(u8 * MACaddr)
289 {
290         char *tmp, *end;
291         int i;
292         /* this depends on a little-endian machine */
293         tmp = getenv("ethaddr");
294         if (tmp) {
295                 for (i = 0; i < 6; i++) {
296                         MACaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
297                         if (tmp)
298                                 tmp = (*end) ? end + 1 : end;
299                 }
300
301 #ifndef CONFIG_NETCONSOLE
302                 printf("Using MAC Address %02X:%02X:%02X:%02X:%02X:%02X\n",
303                        MACaddr[0], MACaddr[1],
304                        MACaddr[2], MACaddr[3], MACaddr[4], MACaddr[5]);
305 #endif
306                 *pEMAC_ADDRLO = MACaddr[0] | MACaddr[1] << 8 |
307                     MACaddr[2] << 16 | MACaddr[3] << 24;
308                 *pEMAC_ADDRHI = MACaddr[4] | MACaddr[5] << 8;
309         }
310 }
311
312 void PollMdcDone(void)
313 {
314         /* poll the STABUSY bit */
315         while (*pEMAC_STAADD & STABUSY) ;
316 }
317
318 void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data)
319 {
320         PollMdcDone();
321
322         *pEMAC_STADAT = Data;
323
324         *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) |
325             STAOP | STAIE | STABUSY;
326 }
327
328 /*********************************************************************************
329  *              Read an off-chip register in a PHY through the MDC/MDIO port     *
330  *********************************************************************************/
331 u16 RdPHYReg(u16 PHYAddr, u16 RegAddr)
332 {
333         u16 Data;
334
335         PollMdcDone();
336
337         *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) |
338             STAIE | STABUSY;
339
340         PollMdcDone();
341
342         Data = (u16) * pEMAC_STADAT;
343
344         PHYregs[RegAddr] = Data;        /* save shadow copy */
345
346         return Data;
347 }
348
349 void SoftResetPHY(void)
350 {
351         u16 phydat;
352         /* set the reset bit */
353         WrPHYReg(PHYADDR, PHY_MODECTL, PHY_RESET);
354         /* and clear it again */
355         WrPHYReg(PHYADDR, PHY_MODECTL, 0x0000);
356         do {
357                 /* poll until reset is complete */
358                 phydat = RdPHYReg(PHYADDR, PHY_MODECTL);
359         } while ((phydat & PHY_RESET) != 0);
360 }
361
362 int SetupSystemRegs(int *opmode)
363 {
364         u16 sysctl, phydat;
365         int count = 0;
366         /* Enable PHY output */
367         *pVR_CTL |= PHYCLKOE;
368         /* MDC  = 2.5 MHz */
369         sysctl = SET_MDCDIV(24);
370         /* Odd word alignment for Receive Frame DMA word */
371         /* Configure checksum support and rcve frame word alignment */
372         sysctl |= RXDWA | RXCKS;
373         *pEMAC_SYSCTL = sysctl;
374         /* auto negotiation on  */
375         /* full duplex */
376         /* 100 Mbps */
377         phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET;
378         WrPHYReg(PHYADDR, PHY_MODECTL, phydat);
379         do {
380                 udelay(1000);
381                 phydat = RdPHYReg(PHYADDR, PHY_MODESTAT);
382                 if (count > 3000) {
383                         printf
384                             ("Link is down, please check your network connection\n");
385                         return -1;
386                 }
387                 count++;
388         } while (!(phydat & 0x0004));
389
390         phydat = RdPHYReg(PHYADDR, PHY_ANLPAR);
391
392         if ((phydat & 0x0100) || (phydat & 0x0040))
393                 *opmode = FDMODE;
394         else
395                 *opmode = 0;
396
397         *pEMAC_MMC_CTL = RSTC | CROLL;
398
399         /* Initialize the TX DMA channel registers */
400         *pDMA2_X_COUNT = 0;
401         *pDMA2_X_MODIFY = 4;
402         *pDMA2_Y_COUNT = 0;
403         *pDMA2_Y_MODIFY = 0;
404
405         /* Initialize the RX DMA channel registers */
406         *pDMA1_X_COUNT = 0;
407         *pDMA1_X_MODIFY = 4;
408         *pDMA1_Y_COUNT = 0;
409         *pDMA1_Y_MODIFY = 0;
410         return 0;
411 }
412
413 ADI_ETHER_BUFFER *SetupRxBuffer(int no)
414 {
415         ADI_ETHER_FRAME_BUFFER *frmbuf;
416         ADI_ETHER_BUFFER *buf;
417         int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2;   /* ensure a multi. of 4 */
418         int total_size = nobytes_buffer + RECV_BUFSIZE;
419
420         buf = (ADI_ETHER_BUFFER *) (RXBUF_BASE_ADDR + no * total_size);
421         frmbuf =
422             (ADI_ETHER_FRAME_BUFFER *) (RXBUF_BASE_ADDR + no * total_size +
423                                         nobytes_buffer);
424
425         memset(buf, 0x00, nobytes_buffer);
426         buf->FrmData = frmbuf;
427         memset(frmbuf, 0xfe, RECV_BUFSIZE);
428
429         /* set up first desc to point to receive frame buffer */
430         buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
431         buf->Dma[0].START_ADDR = (u32) buf->FrmData;
432         buf->Dma[0].CONFIG.b_DMA_EN = 1;        /* enabled */
433         buf->Dma[0].CONFIG.b_WNR = 1;   /* Write to memory */
434         buf->Dma[0].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
435         buf->Dma[0].CONFIG.b_NDSIZE = 5;        /* 5 half words is desc size. */
436         buf->Dma[0].CONFIG.b_FLOW = 7;  /* large desc flow */
437
438         /* set up second desc to point to status word */
439         buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]);
440         buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum;
441         buf->Dma[1].CONFIG.b_DMA_EN = 1;        /* enabled */
442         buf->Dma[1].CONFIG.b_WNR = 1;   /* Write to memory */
443         buf->Dma[1].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
444         buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
445         buf->Dma[1].CONFIG.b_NDSIZE = 5;        /* must be 0 when FLOW is 0 */
446         buf->Dma[1].CONFIG.b_FLOW = 7;  /* stop */
447
448         return buf;
449 }
450
451 ADI_ETHER_BUFFER *SetupTxBuffer(int no)
452 {
453         ADI_ETHER_FRAME_BUFFER *frmbuf;
454         ADI_ETHER_BUFFER *buf;
455         int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2;   /* ensure a multi. of 4 */
456         int total_size = nobytes_buffer + RECV_BUFSIZE;
457
458         buf = (ADI_ETHER_BUFFER *) (TXBUF_BASE_ADDR + no * total_size);
459         frmbuf =
460             (ADI_ETHER_FRAME_BUFFER *) (TXBUF_BASE_ADDR + no * total_size +
461                                         nobytes_buffer);
462
463         memset(buf, 0x00, nobytes_buffer);
464         buf->FrmData = frmbuf;
465         memset(frmbuf, 0x00, RECV_BUFSIZE);
466
467         /* set up first desc to point to receive frame buffer */
468         buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
469         buf->Dma[0].START_ADDR = (u32) buf->FrmData;
470         buf->Dma[0].CONFIG.b_DMA_EN = 1;        /* enabled */
471         buf->Dma[0].CONFIG.b_WNR = 0;   /* Read to memory */
472         buf->Dma[0].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
473         buf->Dma[0].CONFIG.b_NDSIZE = 5;        /* 5 half words is desc size. */
474         buf->Dma[0].CONFIG.b_FLOW = 7;  /* large desc flow */
475
476         /* set up second desc to point to status word */
477         buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]);
478         buf->Dma[1].START_ADDR = (u32) & buf->StatusWord;
479         buf->Dma[1].CONFIG.b_DMA_EN = 1;        /* enabled */
480         buf->Dma[1].CONFIG.b_WNR = 1;   /* Write to memory */
481         buf->Dma[1].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
482         buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
483         buf->Dma[1].CONFIG.b_NDSIZE = 0;        /* must be 0 when FLOW is 0 */
484         buf->Dma[1].CONFIG.b_FLOW = 0;  /* stop */
485
486         return buf;
487 }
488
489 #if defined(CONFIG_POST) && defined(CFG_POST_ETHER)
490 int ether_post_test(int flags)
491 {
492         uchar buf[64];
493         int i, value = 0;
494         int length;
495
496         printf("\n--------");
497         bfin_EMAC_init(NULL, NULL);
498         /* construct the package */
499         buf[0] = buf[6] = (unsigned char)(*pEMAC_ADDRLO & 0xFF);
500         buf[1] = buf[7] = (unsigned char)((*pEMAC_ADDRLO & 0xFF00) >> 8);
501         buf[2] = buf[8] = (unsigned char)((*pEMAC_ADDRLO & 0xFF0000) >> 16);
502         buf[3] = buf[9] = (unsigned char)((*pEMAC_ADDRLO & 0xFF000000) >> 24);
503         buf[4] = buf[10] = (unsigned char)(*pEMAC_ADDRHI & 0xFF);
504         buf[5] = buf[11] = (unsigned char)((*pEMAC_ADDRHI & 0xFF00) >> 8);
505         buf[12] = 0x08;         /* Type: ARP */
506         buf[13] = 0x06;
507         buf[14] = 0x00;         /* Hardware type: Ethernet */
508         buf[15] = 0x01;
509         buf[16] = 0x08;         /* Protocal type: IP */
510         buf[17] = 0x00;
511         buf[18] = 0x06;         /* Hardware size    */
512         buf[19] = 0x04;         /* Protocol size    */
513         buf[20] = 0x00;         /* Opcode: request  */
514         buf[21] = 0x01;
515
516         for (i = 0; i < 42; i++)
517                 buf[i + 22] = i;
518         printf("--------Send 64 bytes......\n");
519         bfin_EMAC_send(NULL, (volatile void *)buf, 64);
520         for (i = 0; i < 100; i++) {
521                 udelay(10000);
522                 if ((rxbuf[rxIdx]->StatusWord & RX_COMP) != 0) {
523                         value = 1;
524                         break;
525                 }
526         }
527         if (value == 0) {
528                 printf("--------EMAC can't receive any data\n");
529                 eth_halt();
530                 return -1;
531         }
532         length = rxbuf[rxIdx]->StatusWord & 0x000007FF - 4;
533         for (i = 0; i < length; i++) {
534                 if (rxbuf[rxIdx]->FrmData->Dest[i] != buf[i]) {
535                         printf("--------EMAC receive error data!\n");
536                         eth_halt();
537                         return -1;
538                 }
539         }
540         printf("--------receive %d bytes, matched\n", length);
541         bfin_EMAC_halt(NULL);
542         return 0;
543 }
544 #endif
545 #endif