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