Initial support for MPC8641 HPCN board.
[pandora-u-boot.git] / drivers / tsec.c
1 /*
2  * tsec.c
3  * Freescale Three Speed Ethernet Controller driver
4  *
5  * This software may be used and distributed according to the
6  * terms of the GNU Public License, Version 2, incorporated
7  * herein by reference.
8  *
9  * Copyright 2004 Freescale Semiconductor.
10  * (C) Copyright 2003, Motorola, Inc.
11  * author Andy Fleming
12  *
13  */
14
15 #include <config.h>
16 #include <mpc85xx.h>
17 #include <mpc86xx.h>
18 #include <common.h>
19 #include <malloc.h>
20 #include <net.h>
21 #include <command.h>
22
23 #if defined(CONFIG_TSEC_ENET)
24 #include "tsec.h"
25 #include "miiphy.h"
26
27 DECLARE_GLOBAL_DATA_PTR;
28
29 #define TX_BUF_CNT              2
30
31 static uint rxIdx;      /* index of the current RX buffer */
32 static uint txIdx;      /* index of the current TX buffer */
33
34 typedef volatile struct rtxbd {
35         txbd8_t txbd[TX_BUF_CNT];
36         rxbd8_t rxbd[PKTBUFSRX];
37 }  RTXBD;
38
39 struct tsec_info_struct {
40         unsigned int phyaddr;
41         u32 flags;
42         unsigned int phyregidx;
43 };
44
45
46 /* The tsec_info structure contains 3 values which the
47  * driver uses to determine how to operate a given ethernet
48  * device.  For now, the structure is initialized with the
49  * knowledge that all current implementations have 2 TSEC
50  * devices, and one FEC.  The information needed is:
51  *  phyaddr - The address of the PHY which is attached to
52  *      the given device.
53  *
54  *  flags - This variable indicates whether the device
55  *      supports gigabit speed ethernet, and whether it should be
56  *      in reduced mode.
57  *
58  *  phyregidx - This variable specifies which ethernet device
59  *      controls the MII Management registers which are connected
60  *      to the PHY.  For 8540/8560, only TSEC1 (index 0) has
61  *      access to the PHYs, so all of the entries have "0".
62  *
63  * The values specified in the table are taken from the board's
64  * config file in include/configs/.  When implementing a new
65  * board with ethernet capability, it is necessary to define:
66  *   TSEC1_PHY_ADDR
67  *   TSEC1_PHYIDX
68  *   TSEC2_PHY_ADDR
69  *   TSEC2_PHYIDX
70  *
71  * and for 8560:
72  *   FEC_PHY_ADDR
73  *   FEC_PHYIDX
74  */
75 static struct tsec_info_struct tsec_info[] = {
76 #if defined(CONFIG_MPC85XX_TSEC1) || defined(CONFIG_MPC83XX_TSEC1)
77         {TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX},
78 #elif defined(CONFIG_MPC86XX_TSEC1)
79         {TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX},
80 #else
81         { 0, 0, 0},
82 #endif
83 #if defined(CONFIG_MPC85XX_TSEC2) || defined(CONFIG_MPC83XX_TSEC2)
84         {TSEC2_PHY_ADDR, TSEC_GIGABIT, TSEC2_PHYIDX},
85 #elif defined(CONFIG_MPC86XX_TSEC2)
86         {TSEC2_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC2_PHYIDX},
87 #else
88         { 0, 0, 0},
89 #endif
90 #ifdef CONFIG_MPC85XX_FEC
91         {FEC_PHY_ADDR, 0, FEC_PHYIDX},
92 #else
93 #if defined(CONFIG_MPC85XX_TSEC3) || defined(CONFIG_MPC83XX_TSEC3) || defined(CONFIG_MPC86XX_TSEC3)
94         {TSEC3_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC3_PHYIDX},
95 #else
96         { 0, 0, 0},
97 #endif
98 #if defined(CONFIG_MPC85XX_TSEC4) || defined(CONFIG_MPC83XX_TSEC4)
99         {TSEC4_PHY_ADDR, TSEC_REDUCED, TSEC4_PHYIDX},
100 #elif defined(CONFIG_MPC86XX_TSEC4)
101        {TSEC4_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC4_PHYIDX},
102 #else
103         { 0, 0, 0},
104 #endif
105 #endif
106 };
107
108 #define MAXCONTROLLERS  (4)
109
110 static int relocated = 0;
111
112 static struct tsec_private *privlist[MAXCONTROLLERS];
113
114 #ifdef __GNUC__
115 static RTXBD rtx __attribute__ ((aligned(8)));
116 #else
117 #error "rtx must be 64-bit aligned"
118 #endif
119
120 static int tsec_send(struct eth_device* dev, volatile void *packet, int length);
121 static int tsec_recv(struct eth_device* dev);
122 static int tsec_init(struct eth_device* dev, bd_t * bd);
123 static void tsec_halt(struct eth_device* dev);
124 static void init_registers(volatile tsec_t *regs);
125 static void startup_tsec(struct eth_device *dev);
126 static int init_phy(struct eth_device *dev);
127 void write_phy_reg(struct tsec_private *priv, uint regnum, uint value);
128 uint read_phy_reg(struct tsec_private *priv, uint regnum);
129 struct phy_info * get_phy_info(struct eth_device *dev);
130 void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd);
131 static void adjust_link(struct eth_device *dev);
132 static void relocate_cmds(void);
133 static int tsec_miiphy_write(char *devname, unsigned char addr,
134                 unsigned char reg, unsigned short value);
135 static int tsec_miiphy_read(char *devname, unsigned char addr,
136                 unsigned char reg, unsigned short *value);
137
138 /* Initialize device structure. Returns success if PHY
139  * initialization succeeded (i.e. if it recognizes the PHY)
140  */
141 int tsec_initialize(bd_t *bis, int index, char *devname)
142 {
143         struct eth_device* dev;
144         int i;
145         struct tsec_private *priv;
146
147         dev = (struct eth_device*) malloc(sizeof *dev);
148
149         if(NULL == dev)
150                 return 0;
151
152         memset(dev, 0, sizeof *dev);
153
154         priv = (struct tsec_private *) malloc(sizeof(*priv));
155
156         if(NULL == priv)
157                 return 0;
158
159         privlist[index] = priv;
160         priv->regs = (volatile tsec_t *)(TSEC_BASE_ADDR + index*TSEC_SIZE);
161         priv->phyregs = (volatile tsec_t *)(TSEC_BASE_ADDR +
162                         tsec_info[index].phyregidx*TSEC_SIZE);
163
164         priv->phyaddr = tsec_info[index].phyaddr;
165         priv->flags = tsec_info[index].flags;
166
167         sprintf(dev->name, devname);
168         dev->iobase = 0;
169         dev->priv   = priv;
170         dev->init   = tsec_init;
171         dev->halt   = tsec_halt;
172         dev->send   = tsec_send;
173         dev->recv   = tsec_recv;
174
175         /* Tell u-boot to get the addr from the env */
176         for(i=0;i<6;i++)
177                 dev->enetaddr[i] = 0;
178
179         eth_register(dev);
180
181
182         /* Reset the MAC */
183         priv->regs->maccfg1 |= MACCFG1_SOFT_RESET;
184         priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
185
186 #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) \
187         && !defined(BITBANGMII)
188         miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
189 #endif
190
191         /* Try to initialize PHY here, and return */
192         return init_phy(dev);
193 }
194
195
196 /* Initializes data structures and registers for the controller,
197  * and brings the interface up.  Returns the link status, meaning
198  * that it returns success if the link is up, failure otherwise.
199  * This allows u-boot to find the first active controller. */
200 int tsec_init(struct eth_device* dev, bd_t * bd)
201 {
202         uint tempval;
203         char tmpbuf[MAC_ADDR_LEN];
204         int i;
205         struct tsec_private *priv = (struct tsec_private *)dev->priv;
206         volatile tsec_t *regs = priv->regs;
207
208         /* Make sure the controller is stopped */
209         tsec_halt(dev);
210
211         /* Init MACCFG2.  Defaults to GMII */
212         regs->maccfg2 = MACCFG2_INIT_SETTINGS;
213
214         /* Init ECNTRL */
215         regs->ecntrl = ECNTRL_INIT_SETTINGS;
216
217         /* Copy the station address into the address registers.
218          * Backwards, because little endian MACS are dumb */
219         for(i=0;i<MAC_ADDR_LEN;i++) {
220                 tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
221         }
222         regs->macstnaddr1 = *((uint *)(tmpbuf));
223
224         tempval = *((uint *)(tmpbuf +4));
225
226         regs->macstnaddr2 = tempval;
227
228         /* reset the indices to zero */
229         rxIdx = 0;
230         txIdx = 0;
231
232         /* Clear out (for the most part) the other registers */
233         init_registers(regs);
234
235         /* Ready the device for tx/rx */
236         startup_tsec(dev);
237
238         /* If there's no link, fail */
239         return priv->link;
240
241 }
242
243
244 /* Write value to the device's PHY through the registers
245  * specified in priv, modifying the register specified in regnum.
246  * It will wait for the write to be done (or for a timeout to
247  * expire) before exiting
248  */
249 void write_phy_reg(struct tsec_private *priv, uint regnum, uint value)
250 {
251         volatile tsec_t *regbase = priv->phyregs;
252         uint phyid = priv->phyaddr;
253         int timeout=1000000;
254
255         regbase->miimadd = (phyid << 8) | regnum;
256         regbase->miimcon = value;
257         asm("sync");
258
259         timeout=1000000;
260         while((regbase->miimind & MIIMIND_BUSY) && timeout--);
261 }
262
263
264 /* Reads register regnum on the device's PHY through the
265  * registers specified in priv.  It lowers and raises the read
266  * command, and waits for the data to become valid (miimind
267  * notvalid bit cleared), and the bus to cease activity (miimind
268  * busy bit cleared), and then returns the value
269  */
270 uint read_phy_reg(struct tsec_private *priv, uint regnum)
271 {
272         uint value;
273         volatile tsec_t *regbase = priv->phyregs;
274         uint phyid = priv->phyaddr;
275
276         /* Put the address of the phy, and the register
277          * number into MIIMADD */
278         regbase->miimadd = (phyid << 8) | regnum;
279
280         /* Clear the command register, and wait */
281         regbase->miimcom = 0;
282         asm("sync");
283
284         /* Initiate a read command, and wait */
285         regbase->miimcom = MIIM_READ_COMMAND;
286         asm("sync");
287
288         /* Wait for the the indication that the read is done */
289         while((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY)));
290
291         /* Grab the value read from the PHY */
292         value = regbase->miimstat;
293
294         return value;
295 }
296
297
298 /* Discover which PHY is attached to the device, and configure it
299  * properly.  If the PHY is not recognized, then return 0
300  * (failure).  Otherwise, return 1
301  */
302 static int init_phy(struct eth_device *dev)
303 {
304         struct tsec_private *priv = (struct tsec_private *)dev->priv;
305         struct phy_info *curphy;
306
307         /* Assign a Physical address to the TBI */
308
309         {
310                 volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR);
311                 regs->tbipa = TBIPA_VALUE;
312                 regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE);
313                 regs->tbipa = TBIPA_VALUE;
314                 asm("sync");
315         }
316
317         /* Reset MII (due to new addresses) */
318         priv->phyregs->miimcfg = MIIMCFG_RESET;
319         asm("sync");
320         priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE;
321         asm("sync");
322         while(priv->phyregs->miimind & MIIMIND_BUSY);
323
324         if(0 == relocated)
325                 relocate_cmds();
326
327         /* Get the cmd structure corresponding to the attached
328          * PHY */
329         curphy = get_phy_info(dev);
330
331         if(NULL == curphy) {
332                 printf("%s: No PHY found\n", dev->name);
333
334                 return 0;
335         }
336
337         priv->phyinfo = curphy;
338
339         phy_run_commands(priv, priv->phyinfo->config);
340
341         return 1;
342 }
343
344
345 /* Returns which value to write to the control register. */
346 /* For 10/100, the value is slightly different */
347 uint mii_cr_init(uint mii_reg, struct tsec_private *priv)
348 {
349         if(priv->flags & TSEC_GIGABIT)
350                 return MIIM_CONTROL_INIT;
351         else
352                 return MIIM_CR_INIT;
353 }
354
355
356 /* Parse the status register for link, and then do
357  * auto-negotiation */
358 uint mii_parse_sr(uint mii_reg, struct tsec_private *priv)
359 {
360         /*
361          * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
362          */
363         mii_reg = read_phy_reg(priv, MIIM_STATUS);
364         if ((mii_reg & PHY_BMSR_AUTN_ABLE) && !(mii_reg & PHY_BMSR_AUTN_COMP)) {
365                 int i = 0;
366
367                 puts ("Waiting for PHY auto negotiation to complete");
368                 while (!((mii_reg & PHY_BMSR_AUTN_COMP) && (mii_reg & MIIM_STATUS_LINK))) {
369                         /*
370                          * Timeout reached ?
371                          */
372                         if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
373                                 puts (" TIMEOUT !\n");
374                                 priv->link = 0;
375                                 break;
376                         }
377
378                         if ((i++ % 1000) == 0) {
379                                 putc ('.');
380                         }
381                         udelay (1000);  /* 1 ms */
382                         mii_reg = read_phy_reg(priv, MIIM_STATUS);
383                 }
384                 puts (" done\n");
385                 priv->link = 1;
386                 udelay (500000);        /* another 500 ms (results in faster booting) */
387         } else {
388                 priv->link = 1;
389         }
390
391         return 0;
392 }
393
394
395 /* Parse the 88E1011's status register for speed and duplex
396  * information */
397 uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private *priv)
398 {
399         uint speed;
400
401         mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
402
403         if (!((mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE) &&
404               (mii_reg & MIIM_88E1011_PHYSTAT_LINK))) {
405                 int i = 0;
406
407                 puts ("Waiting for PHY realtime link");
408                 while (!((mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE) &&
409                          (mii_reg & MIIM_88E1011_PHYSTAT_LINK))) {
410                         /*
411                          * Timeout reached ?
412                          */
413                         if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
414                                 puts (" TIMEOUT !\n");
415                                 priv->link = 0;
416                                 break;
417                         }
418
419                         if ((i++ % 1000) == 0) {
420                                 putc ('.');
421                         }
422                         udelay (1000);  /* 1 ms */
423                         mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
424                 }
425                 puts (" done\n");
426                 udelay (500000);        /* another 500 ms (results in faster booting) */
427         }
428
429         if(mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
430                 priv->duplexity = 1;
431         else
432                 priv->duplexity = 0;
433
434         speed = (mii_reg &MIIM_88E1011_PHYSTAT_SPEED);
435
436         switch(speed) {
437                 case MIIM_88E1011_PHYSTAT_GBIT:
438                         priv->speed = 1000;
439                         break;
440                 case MIIM_88E1011_PHYSTAT_100:
441                         priv->speed = 100;
442                         break;
443                 default:
444                         priv->speed = 10;
445         }
446
447         return 0;
448 }
449
450
451 /* Parse the cis8201's status register for speed and duplex
452  * information */
453 uint mii_parse_cis8201(uint mii_reg, struct tsec_private *priv)
454 {
455         uint speed;
456
457         if(mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
458                 priv->duplexity = 1;
459         else
460                 priv->duplexity = 0;
461
462         speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
463         switch(speed) {
464                 case MIIM_CIS8201_AUXCONSTAT_GBIT:
465                         priv->speed = 1000;
466                         break;
467                 case MIIM_CIS8201_AUXCONSTAT_100:
468                         priv->speed = 100;
469                         break;
470                 default:
471                         priv->speed = 10;
472                         break;
473         }
474
475         return 0;
476 }
477 /* Parse the vsc8244's status register for speed and duplex
478  * information */
479 uint mii_parse_vsc8244(uint mii_reg, struct tsec_private *priv)
480 {
481         uint speed;
482                                                                                 
483         if(mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX)
484                 priv->duplexity = 1;
485         else
486                 priv->duplexity = 0;
487                                                                                 
488         speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED;
489         switch(speed) {
490                 case MIIM_VSC8244_AUXCONSTAT_GBIT:
491                         priv->speed = 1000;
492                         break;
493                 case MIIM_VSC8244_AUXCONSTAT_100:
494                         priv->speed = 100;
495                         break;
496                 default:
497                         priv->speed = 10;
498                         break;
499         }
500                                                                                 
501         return 0;
502 }
503
504
505 /* Parse the DM9161's status register for speed and duplex
506  * information */
507 uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private *priv)
508 {
509         if(mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H))
510                 priv->speed = 100;
511         else
512                 priv->speed = 10;
513
514         if(mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F))
515                 priv->duplexity = 1;
516         else
517                 priv->duplexity = 0;
518
519         return 0;
520 }
521
522
523 /* Hack to write all 4 PHYs with the LED values */
524 uint mii_cis8204_fixled(uint mii_reg, struct tsec_private *priv)
525 {
526         uint phyid;
527         volatile tsec_t *regbase = priv->phyregs;
528         int timeout=1000000;
529
530         for(phyid=0;phyid<4;phyid++) {
531                 regbase->miimadd = (phyid << 8) | mii_reg;
532                 regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT;
533                 asm("sync");
534
535                 timeout=1000000;
536                 while((regbase->miimind & MIIMIND_BUSY) && timeout--);
537         }
538
539         return MIIM_CIS8204_SLEDCON_INIT;
540 }
541
542 uint mii_cis8204_setmode(uint mii_reg, struct tsec_private *priv)
543 {
544         if (priv->flags & TSEC_REDUCED)
545                 return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII;
546         else
547                 return MIIM_CIS8204_EPHYCON_INIT;
548 }
549
550 /* Initialized required registers to appropriate values, zeroing
551  * those we don't care about (unless zero is bad, in which case,
552  * choose a more appropriate value) */
553 static void init_registers(volatile tsec_t *regs)
554 {
555         /* Clear IEVENT */
556         regs->ievent = IEVENT_INIT_CLEAR;
557
558         regs->imask = IMASK_INIT_CLEAR;
559
560         regs->hash.iaddr0 = 0;
561         regs->hash.iaddr1 = 0;
562         regs->hash.iaddr2 = 0;
563         regs->hash.iaddr3 = 0;
564         regs->hash.iaddr4 = 0;
565         regs->hash.iaddr5 = 0;
566         regs->hash.iaddr6 = 0;
567         regs->hash.iaddr7 = 0;
568
569         regs->hash.gaddr0 = 0;
570         regs->hash.gaddr1 = 0;
571         regs->hash.gaddr2 = 0;
572         regs->hash.gaddr3 = 0;
573         regs->hash.gaddr4 = 0;
574         regs->hash.gaddr5 = 0;
575         regs->hash.gaddr6 = 0;
576         regs->hash.gaddr7 = 0;
577
578         regs->rctrl = 0x00000000;
579
580         /* Init RMON mib registers */
581         memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
582
583         regs->rmon.cam1 = 0xffffffff;
584         regs->rmon.cam2 = 0xffffffff;
585
586         regs->mrblr = MRBLR_INIT_SETTINGS;
587
588         regs->minflr = MINFLR_INIT_SETTINGS;
589
590         regs->attr = ATTR_INIT_SETTINGS;
591         regs->attreli = ATTRELI_INIT_SETTINGS;
592
593 }
594
595
596 /* Configure maccfg2 based on negotiated speed and duplex
597  * reported by PHY handling code */
598 static void adjust_link(struct eth_device *dev)
599 {
600         struct tsec_private *priv = (struct tsec_private *)dev->priv;
601         volatile tsec_t *regs = priv->regs;
602
603         if(priv->link) {
604                 if(priv->duplexity != 0)
605                         regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
606                 else
607                         regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX);
608
609                 switch(priv->speed) {
610                         case 1000:
611                                 regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF))
612                                         | MACCFG2_GMII);
613                                 break;
614                         case 100:
615                         case 10:
616                                 regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF))
617                                         | MACCFG2_MII);
618
619                                 /* If We're in reduced mode, we need
620                                  * to say whether we're 10 or 100 MB.
621                                  */
622                                 if ((priv->speed == 100)
623                                     && (priv->flags & TSEC_REDUCED))
624                                         regs->ecntrl |= ECNTRL_R100;
625                                 else
626                                         regs->ecntrl &= ~(ECNTRL_R100);
627                                 break;
628                         default:
629                                 printf("%s: Speed was bad\n", dev->name);
630                                 break;
631                 }
632
633                 printf("Speed: %d, %s duplex\n", priv->speed,
634                                 (priv->duplexity) ? "full" : "half");
635
636         } else {
637                 printf("%s: No link.\n", dev->name);
638         }
639 }
640
641
642 /* Set up the buffers and their descriptors, and bring up the
643  * interface */
644 static void startup_tsec(struct eth_device *dev)
645 {
646         int i;
647         struct tsec_private *priv = (struct tsec_private *)dev->priv;
648         volatile tsec_t *regs = priv->regs;
649
650         /* Point to the buffer descriptors */
651         regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);
652         regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
653
654         /* Initialize the Rx Buffer descriptors */
655         for (i = 0; i < PKTBUFSRX; i++) {
656                 rtx.rxbd[i].status = RXBD_EMPTY;
657                 rtx.rxbd[i].length = 0;
658                 rtx.rxbd[i].bufPtr = (uint)NetRxPackets[i];
659         }
660         rtx.rxbd[PKTBUFSRX -1].status |= RXBD_WRAP;
661
662         /* Initialize the TX Buffer Descriptors */
663         for(i=0; i<TX_BUF_CNT; i++) {
664                 rtx.txbd[i].status = 0;
665                 rtx.txbd[i].length = 0;
666                 rtx.txbd[i].bufPtr = 0;
667         }
668         rtx.txbd[TX_BUF_CNT -1].status |= TXBD_WRAP;
669
670         /* Start up the PHY */
671         phy_run_commands(priv, priv->phyinfo->startup);
672         adjust_link(dev);
673
674         /* Enable Transmit and Receive */
675         regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
676
677         /* Tell the DMA it is clear to go */
678         regs->dmactrl |= DMACTRL_INIT_SETTINGS;
679         regs->tstat = TSTAT_CLEAR_THALT;
680         regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
681 }
682
683 /* This returns the status bits of the device.  The return value
684  * is never checked, and this is what the 8260 driver did, so we
685  * do the same.  Presumably, this would be zero if there were no
686  * errors */
687 static int tsec_send(struct eth_device* dev, volatile void *packet, int length)
688 {
689         int i;
690         int result = 0;
691         struct tsec_private *priv = (struct tsec_private *)dev->priv;
692         volatile tsec_t *regs = priv->regs;
693
694         /* Find an empty buffer descriptor */
695         for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
696                 if (i >= TOUT_LOOP) {
697                         debug ("%s: tsec: tx buffers full\n", dev->name);
698                         return result;
699                 }
700         }
701
702         rtx.txbd[txIdx].bufPtr = (uint)packet;
703         rtx.txbd[txIdx].length = length;
704         rtx.txbd[txIdx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
705
706         /* Tell the DMA to go */
707         regs->tstat = TSTAT_CLEAR_THALT;
708
709         /* Wait for buffer to be transmitted */
710         for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
711                 if (i >= TOUT_LOOP) {
712                         debug ("%s: tsec: tx error\n", dev->name);
713                         return result;
714                 }
715         }
716
717         txIdx = (txIdx + 1) % TX_BUF_CNT;
718         result = rtx.txbd[txIdx].status & TXBD_STATS;
719
720         return result;
721 }
722
723 static int tsec_recv(struct eth_device* dev)
724 {
725         int length;
726         struct tsec_private *priv = (struct tsec_private *)dev->priv;
727         volatile tsec_t *regs = priv->regs;
728
729         while(!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
730
731                 length = rtx.rxbd[rxIdx].length;
732
733                 /* Send the packet up if there were no errors */
734                 if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
735                         NetReceive(NetRxPackets[rxIdx], length - 4);
736                 } else {
737                         printf("Got error %x\n",
738                                         (rtx.rxbd[rxIdx].status & RXBD_STATS));
739                 }
740
741                 rtx.rxbd[rxIdx].length = 0;
742
743                 /* Set the wrap bit if this is the last element in the list */
744                 rtx.rxbd[rxIdx].status = RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
745
746                 rxIdx = (rxIdx + 1) % PKTBUFSRX;
747         }
748
749         if(regs->ievent&IEVENT_BSY) {
750                 regs->ievent = IEVENT_BSY;
751                 regs->rstat = RSTAT_CLEAR_RHALT;
752         }
753
754         return -1;
755
756 }
757
758
759 /* Stop the interface */
760 static void tsec_halt(struct eth_device* dev)
761 {
762         struct tsec_private *priv = (struct tsec_private *)dev->priv;
763         volatile tsec_t *regs = priv->regs;
764
765         regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
766         regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS);
767
768         while(!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC)));
769
770         regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);
771
772         /* Shut down the PHY, as needed */
773         phy_run_commands(priv, priv->phyinfo->shutdown);
774 }
775
776
777 struct phy_info phy_info_M88E1011S = {
778         0x01410c6,
779         "Marvell 88E1011S",
780         4,
781         (struct phy_cmd[]) { /* config */
782                 /* Reset and configure the PHY */
783                 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
784                 {0x1d, 0x1f, NULL},
785                 {0x1e, 0x200c, NULL},
786                 {0x1d, 0x5, NULL},
787                 {0x1e, 0x0, NULL},
788                 {0x1e, 0x100, NULL},
789                 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
790                 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
791                 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
792                 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
793                 {miim_end,}
794         },
795         (struct phy_cmd[]) { /* startup */
796                 /* Status is read once to clear old link state */
797                 {MIIM_STATUS, miim_read, NULL},
798                 /* Auto-negotiate */
799                 {MIIM_STATUS, miim_read, &mii_parse_sr},
800                 /* Read the status */
801                 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
802                 {miim_end,}
803         },
804         (struct phy_cmd[]) { /* shutdown */
805                 {miim_end,}
806         },
807 };
808
809 struct phy_info phy_info_M88E1111S = {
810         0x01410cc,
811         "Marvell 88E1111S",
812         4,
813         (struct phy_cmd[]) { /* config */
814           /* Reset and configure the PHY */
815                 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
816                 {0x1d, 0x1f, NULL},
817                 {0x1e, 0x200c, NULL},
818                 {0x1d, 0x5, NULL},
819                 {0x1e, 0x0, NULL},
820                 {0x1e, 0x100, NULL},
821                 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
822                 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
823                 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
824                 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
825                 {miim_end,}
826         },
827         (struct phy_cmd[]) { /* startup */
828           /* Status is read once to clear old link state */
829                 {MIIM_STATUS, miim_read, NULL},
830                 /* Auto-negotiate */
831                 {MIIM_STATUS, miim_read, &mii_parse_sr},
832                 /* Read the status */
833                 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
834                 {miim_end,}
835         },
836         (struct phy_cmd[]) { /* shutdown */
837                 {miim_end,}
838         },
839 };
840
841 struct phy_info phy_info_cis8204 = {
842         0x3f11,
843         "Cicada Cis8204",
844         6,
845         (struct phy_cmd[]) { /* config */
846                 /* Override PHY config settings */
847                 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
848                 /* Configure some basic stuff */
849                 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
850                 {MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT, &mii_cis8204_fixled},
851                 {MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT, &mii_cis8204_setmode},
852                 {miim_end,}
853         },
854         (struct phy_cmd[]) { /* startup */
855                 /* Read the Status (2x to make sure link is right) */
856                 {MIIM_STATUS, miim_read, NULL},
857                 /* Auto-negotiate */
858                 {MIIM_STATUS, miim_read, &mii_parse_sr},
859                 /* Read the status */
860                 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
861                 {miim_end,}
862         },
863         (struct phy_cmd[]) { /* shutdown */
864                 {miim_end,}
865         },
866 };
867
868 /* Cicada 8201 */
869 struct phy_info phy_info_cis8201 = {
870         0xfc41,
871         "CIS8201",
872         4,
873         (struct phy_cmd[]) { /* config */
874                 /* Override PHY config settings */
875                 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
876                 /* Set up the interface mode */
877                 {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL},
878                 /* Configure some basic stuff */
879                 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
880                 {miim_end,}
881         },
882         (struct phy_cmd[]) { /* startup */
883                 /* Read the Status (2x to make sure link is right) */
884                 {MIIM_STATUS, miim_read, NULL},
885                 /* Auto-negotiate */
886                 {MIIM_STATUS, miim_read, &mii_parse_sr},
887                 /* Read the status */
888                 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
889                 {miim_end,}
890         },
891         (struct phy_cmd[]) { /* shutdown */
892                 {miim_end,}
893         },
894 };
895 struct phy_info phy_info_VSC8244 = {
896         0x3f1b,
897         "Vitesse VSC8244",
898         6,
899         (struct phy_cmd[]) { /* config */
900         /* Override PHY config settings */
901                 /* Configure some basic stuff */
902                 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
903                 {miim_end,}
904         },
905         (struct phy_cmd[]) { /* startup */
906                 /* Read the Status (2x to make sure link is right) */
907                 {MIIM_STATUS, miim_read, NULL},
908                 /* Auto-negotiate */
909                 {MIIM_STATUS, miim_read, &mii_parse_sr},
910                 /* Read the status */
911                 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
912                 {miim_end,}
913         },
914         (struct phy_cmd[]) { /* shutdown */
915                 {miim_end,}
916         },
917 };
918
919
920 struct phy_info phy_info_dm9161 = {
921         0x0181b88,
922         "Davicom DM9161E",
923         4,
924         (struct phy_cmd[]) { /* config */
925                 {MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL},
926                 /* Do not bypass the scrambler/descrambler */
927                 {MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL},
928                 /* Clear 10BTCSR to default */
929                 {MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL},
930                 /* Configure some basic stuff */
931                 {MIIM_CONTROL, MIIM_CR_INIT, NULL},
932                 /* Restart Auto Negotiation */
933                 {MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL},
934                 {miim_end,}
935         },
936         (struct phy_cmd[]) { /* startup */
937                 /* Status is read once to clear old link state */
938                 {MIIM_STATUS, miim_read, NULL},
939                 /* Auto-negotiate */
940                 {MIIM_STATUS, miim_read, &mii_parse_sr},
941                 /* Read the status */
942                 {MIIM_DM9161_SCSR, miim_read, &mii_parse_dm9161_scsr},
943                 {miim_end,}
944         },
945         (struct phy_cmd[]) { /* shutdown */
946                 {miim_end,}
947         },
948 };
949
950 uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv)
951 {
952         unsigned int speed;
953         if (priv->link) {
954                 speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK;
955
956                 switch (speed) {
957                 case MIIM_LXT971_SR2_10HDX:
958                         priv->speed = 10;
959                         priv->duplexity = 0;
960                         break;
961                 case MIIM_LXT971_SR2_10FDX:
962                         priv->speed = 10;
963                         priv->duplexity = 1;
964                         break;
965                 case MIIM_LXT971_SR2_100HDX:
966                         priv->speed = 100;
967                         priv->duplexity = 0;
968                 default:
969                         priv->speed = 100;
970                         priv->duplexity = 1;
971                         break;
972                 }
973         } else {
974                 priv->speed = 0;
975                 priv->duplexity = 0;
976         }
977
978         return 0;
979 }
980
981 static struct phy_info phy_info_lxt971 = {
982         0x0001378e,
983         "LXT971",
984         4,
985         (struct phy_cmd []) {  /* config */
986                 { MIIM_CR, MIIM_CR_INIT, mii_cr_init }, /* autonegotiate */
987                 { miim_end, }
988         },
989         (struct phy_cmd []) {  /* startup - enable interrupts */
990                 /* { 0x12, 0x00f2, NULL }, */
991                 { MIIM_STATUS, miim_read, NULL },
992                 { MIIM_STATUS, miim_read, &mii_parse_sr },
993                 { MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2 },
994                 { miim_end, }
995         },
996         (struct phy_cmd []) {  /* shutdown - disable interrupts */
997                 { miim_end, }
998         },
999 };
1000
1001 /* Parse the DP83865's link and auto-neg status register for speed and duplex
1002  * information */
1003 uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv)
1004 {
1005         switch (mii_reg & MIIM_DP83865_SPD_MASK) {
1006
1007         case MIIM_DP83865_SPD_1000:
1008                 priv->speed = 1000;
1009                 break;
1010
1011         case MIIM_DP83865_SPD_100:
1012                 priv->speed = 100;
1013                 break;
1014
1015         default:
1016                 priv->speed = 10;
1017                 break;
1018
1019         }
1020
1021         if (mii_reg & MIIM_DP83865_DPX_FULL)
1022                 priv->duplexity = 1;
1023         else
1024                 priv->duplexity = 0;
1025
1026         return 0;
1027 }
1028
1029 struct phy_info phy_info_dp83865 = {
1030         0x20005c7,
1031         "NatSemi DP83865",
1032         4,
1033         (struct phy_cmd[]) { /* config */
1034                 {MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL},
1035                 {miim_end,}
1036         },
1037         (struct phy_cmd[]) { /* startup */
1038                 /* Status is read once to clear old link state */
1039                 {MIIM_STATUS, miim_read, NULL},
1040                 /* Auto-negotiate */
1041                 {MIIM_STATUS, miim_read, &mii_parse_sr},
1042                 /* Read the link and auto-neg status */
1043                 {MIIM_DP83865_LANR, miim_read, &mii_parse_dp83865_lanr},
1044                 {miim_end,}
1045         },
1046         (struct phy_cmd[]) { /* shutdown */
1047                 {miim_end,}
1048         },
1049 };
1050
1051 struct phy_info *phy_info[] = {
1052 #if 0
1053         &phy_info_cis8201,
1054 #endif
1055         &phy_info_cis8204,
1056         &phy_info_M88E1011S,
1057         &phy_info_M88E1111S,
1058         &phy_info_dm9161,
1059         &phy_info_lxt971,
1060         &phy_info_VSC8244,
1061         &phy_info_dp83865,
1062         NULL
1063 };
1064
1065
1066 /* Grab the identifier of the device's PHY, and search through
1067  * all of the known PHYs to see if one matches.  If so, return
1068  * it, if not, return NULL */
1069 struct phy_info * get_phy_info(struct eth_device *dev)
1070 {
1071         struct tsec_private *priv = (struct tsec_private *)dev->priv;
1072         uint phy_reg, phy_ID;
1073         int i;
1074         struct phy_info *theInfo = NULL;
1075
1076         /* Grab the bits from PHYIR1, and put them in the upper half */
1077         phy_reg = read_phy_reg(priv, MIIM_PHYIR1);
1078         phy_ID = (phy_reg & 0xffff) << 16;
1079
1080         /* Grab the bits from PHYIR2, and put them in the lower half */
1081         phy_reg = read_phy_reg(priv, MIIM_PHYIR2);
1082         phy_ID |= (phy_reg & 0xffff);
1083
1084         /* loop through all the known PHY types, and find one that */
1085         /* matches the ID we read from the PHY. */
1086         for(i=0; phy_info[i]; i++) {
1087                 if(phy_info[i]->id == (phy_ID >> phy_info[i]->shift))
1088                         theInfo = phy_info[i];
1089         }
1090
1091         if(theInfo == NULL)
1092         {
1093                 printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
1094                 return NULL;
1095         } else {
1096                 debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
1097         }
1098
1099         return theInfo;
1100 }
1101
1102
1103 /* Execute the given series of commands on the given device's
1104  * PHY, running functions as necessary*/
1105 void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
1106 {
1107         int i;
1108         uint result;
1109         volatile tsec_t *phyregs = priv->phyregs;
1110
1111         phyregs->miimcfg = MIIMCFG_RESET;
1112
1113         phyregs->miimcfg = MIIMCFG_INIT_VALUE;
1114
1115         while(phyregs->miimind & MIIMIND_BUSY);
1116
1117         for(i=0;cmd->mii_reg != miim_end;i++) {
1118                 if(cmd->mii_data == miim_read) {
1119                         result = read_phy_reg(priv, cmd->mii_reg);
1120
1121                         if(cmd->funct != NULL)
1122                                 (*(cmd->funct))(result, priv);
1123
1124                 } else {
1125                         if(cmd->funct != NULL)
1126                                 result = (*(cmd->funct))(cmd->mii_reg, priv);
1127                         else
1128                                 result = cmd->mii_data;
1129
1130                         write_phy_reg(priv, cmd->mii_reg, result);
1131
1132                 }
1133                 cmd++;
1134         }
1135 }
1136
1137
1138 /* Relocate the function pointers in the phy cmd lists */
1139 static void relocate_cmds(void)
1140 {
1141         struct phy_cmd **cmdlistptr;
1142         struct phy_cmd *cmd;
1143         int i,j,k;
1144
1145         for(i=0; phy_info[i]; i++) {
1146                 /* First thing's first: relocate the pointers to the
1147                  * PHY command structures (the structs were done) */
1148                 phy_info[i] = (struct phy_info *) ((uint)phy_info[i]
1149                                 + gd->reloc_off);
1150                 phy_info[i]->name += gd->reloc_off;
1151                 phy_info[i]->config =
1152                         (struct phy_cmd *)((uint)phy_info[i]->config
1153                                            + gd->reloc_off);
1154                 phy_info[i]->startup =
1155                         (struct phy_cmd *)((uint)phy_info[i]->startup
1156                                            + gd->reloc_off);
1157                 phy_info[i]->shutdown =
1158                         (struct phy_cmd *)((uint)phy_info[i]->shutdown
1159                                            + gd->reloc_off);
1160
1161                 cmdlistptr = &phy_info[i]->config;
1162                 j=0;
1163                 for(;cmdlistptr <= &phy_info[i]->shutdown;cmdlistptr++) {
1164                         k=0;
1165                         for(cmd=*cmdlistptr;cmd->mii_reg != miim_end;cmd++) {
1166                                 /* Only relocate non-NULL pointers */
1167                                 if(cmd->funct)
1168                                         cmd->funct += gd->reloc_off;
1169
1170                                 k++;
1171                         }
1172                         j++;
1173                 }
1174         }
1175
1176         relocated = 1;
1177 }
1178
1179
1180 #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) \
1181         && !defined(BITBANGMII)
1182
1183 struct tsec_private * get_priv_for_phy(unsigned char phyaddr)
1184 {
1185         int i;
1186
1187         for(i=0;i<MAXCONTROLLERS;i++) {
1188                 if(privlist[i]->phyaddr == phyaddr)
1189                         return privlist[i];
1190         }
1191
1192         return NULL;
1193 }
1194
1195 /*
1196  * Read a MII PHY register.
1197  *
1198  * Returns:
1199  *  0 on success
1200  */
1201 static int tsec_miiphy_read(char *devname, unsigned char addr,
1202                 unsigned char reg, unsigned short *value)
1203 {
1204         unsigned short ret;
1205         struct tsec_private *priv = get_priv_for_phy(addr);
1206
1207         if(NULL == priv) {
1208                 printf("Can't read PHY at address %d\n", addr);
1209                 return -1;
1210         }
1211
1212         ret = (unsigned short)read_phy_reg(priv, reg);
1213         *value = ret;
1214
1215         return 0;
1216 }
1217
1218 /*
1219  * Write a MII PHY register.
1220  *
1221  * Returns:
1222  *  0 on success
1223  */
1224 static int tsec_miiphy_write(char *devname, unsigned char addr,
1225                 unsigned char reg, unsigned short value)
1226 {
1227         struct tsec_private *priv = get_priv_for_phy(addr);
1228
1229         if(NULL == priv) {
1230                 printf("Can't write PHY at address %d\n", addr);
1231                 return -1;
1232         }
1233
1234         write_phy_reg(priv, reg, value);
1235
1236         return 0;
1237 }
1238
1239 #endif /* defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
1240                 && !defined(BITBANGMII) */
1241
1242 #endif /* CONFIG_TSEC_ENET */