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