]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/devs/eth/fec/v2_0/src/if_fec.c
TX53 Release 2011-12-20
[karo-tx-redboot.git] / packages / devs / eth / fec / v2_0 / src / if_fec.c
1 //==========================================================================
2 //
3 //      dev/if_fec.c
4 //
5 //      Device driver for FEC
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //####BSDCOPYRIGHTBEGIN####
41 //
42 // -------------------------------------------
43 //
44 // Portions of this software may have been derived from OpenBSD or other sources,
45 // and are covered by the appropriate copyright disclaimers included herein.
46 //
47 // -------------------------------------------
48 //
49 //####BSDCOPYRIGHTEND####
50 //==========================================================================
51 //#####DESCRIPTIONBEGIN####
52 //
53 // Author(s):    Fred Fan
54 // Contributors:
55 // Date:         2006-08-23
56 // Purpose:
57 // Description:  Driver for FEC ethernet controller
58 //
59 // Note:
60 //
61 //####DESCRIPTIONEND####
62 //
63 //==========================================================================
64
65 #include <pkgconf/system.h>
66 #ifdef CYGPKG_KERNEL
67 #include <cyg/kernel/kapi.h>
68 #endif
69 #include <pkgconf/io_eth_drivers.h>
70 #include <pkgconf/devs_eth_fec.h>
71
72 #include <cyg/infra/cyg_type.h>
73 #include <cyg/infra/cyg_ass.h>
74 #include <cyg/hal/hal_arch.h>
75 #include <cyg/hal/hal_intr.h>
76 #include <cyg/hal/hal_endian.h>
77 #include <cyg/infra/diag.h>
78 #include <cyg/hal/drv_api.h>
79 #include <cyg/hal/hal_soc.h>
80 #undef __ECOS
81 #define __ECOS
82 #include <cyg/io/eth/eth_drv.h>
83 #include <cyg/io/eth/netdev.h>
84
85 static bool mxc_fec_init(struct cyg_netdevtab_entry *tab);
86
87 #include <cyg/io/fec.h>
88 #define __WANT_DEVS
89 #include CYGDAT_DEVS_ETH_FEC_INL
90 #undef __WANT_DEVS
91
92 #include <redboot.h>
93
94 #include <cyg/hal/plf_mmap.h>
95 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
96 #include <flash_config.h>
97 #endif
98
99
100 #define MII_REG_CR                      0  /* Control Register                                             */
101 #define MII_REG_SR                      1  /* Status Register                                              */
102 #define MII_REG_PHYIR1          2  /* PHY Identification Register 1                        */
103 #define MII_REG_PHYIR2          3  /* PHY Identification Register 2                        */
104
105 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show);
106
107 #ifndef CYGPKG_DEVS_ETH_PHY
108 /*!
109  * Global variable which contains the name of FEC driver and device.
110  */
111 static char  mxc_fec_name[] = "mxc_fec";
112
113 /*!
114  * Global variable which defines the private structure of FEC device.
115  */
116 static mxc_fec_priv_t  mxc_fec_private;
117 #endif
118
119 /*!
120  * Global variable which defines the buffer descriptors for receive frames
121  *      comment:: it must aligned by 128-bits.
122  */
123 static mxc_fec_bd_t mxc_fec_rx_bd[FEC_BD_RX_NUM] __attribute__ ((aligned(32)));
124
125 /*!
126  * Global variable which defines the buffer descriptors for transmit frames
127  *      comment:: it must aligned by 128-bits.
128  */
129 static mxc_fec_bd_t mxc_fec_tx_bd[FEC_BD_TX_NUM] __attribute__ ((aligned(32)));
130
131 /*!
132  * Global variable which contains the frame buffers
133  */
134 static unsigned char mxc_fec_rx_buf[FEC_BD_RX_NUM][2048] __attribute__ ((aligned(32)));
135
136 /*!
137  * Global variable which contains the frame buffers
138  */
139 static unsigned char mxc_fec_tx_buf[FEC_BD_TX_NUM][2048] __attribute__ ((aligned(32)));
140
141 #if 1
142 static void dump_packet(const unsigned char *pkt, size_t len)
143 {
144         int i;
145
146         diag_printf("Packet dump: %u byte", len);
147         for (i = 0; i < len; i++) {
148                 if (i % 16 == 0) {
149                         diag_printf("\n%04x:", i);
150                 } else {
151                         if (i % 4 == 0) {
152                                 diag_printf(" ");
153                         }
154                         if (i % 8 == 0) {
155                                 diag_printf(" ");
156                         }
157                 }
158                 diag_printf(" %02x", pkt[i]);
159         }
160         if (i % 16)
161                 diag_printf("\n");
162 }
163 #endif
164
165 static inline volatile void *fec_reg_addr(volatile void *base, unsigned int reg)
166 {
167         return (volatile void *)((unsigned long)base + reg);
168 }
169
170 #define mxc_fec_reg_read(hw_reg,reg) _mxc_fec_reg_read(hw_reg, reg, #reg)
171 static inline unsigned long _mxc_fec_reg_read(volatile void *base, unsigned int reg,
172                                                                                         const char *name)
173 {
174         unsigned long val = readl(fec_reg_addr(base, reg));
175
176         if (net_debug) diag_printf("Read %08lx from FEC reg %s[%03x]\n",
177                                    val, name, reg);
178         return val;
179 }
180
181 #define mxc_fec_reg_write(hw_reg,reg,val) _mxc_fec_reg_write(hw_reg, reg, val, #reg)
182 static inline void _mxc_fec_reg_write(volatile void *base, unsigned int reg,
183                                                                           unsigned long val, const char *name)
184 {
185         if (net_debug) diag_printf("Writing %08lx to FEC reg %s[%03x]\n",
186                                                         val, name, reg);
187         writel(val, fec_reg_addr(base, reg));
188 }
189
190 #define mxc_fec_reg_read16(hw_reg,reg) _mxc_fec_reg_read16(hw_reg, reg, #reg)
191 static inline unsigned short _mxc_fec_reg_read16(volatile void *base, unsigned int reg,
192                                                                                                 const char *name)
193 {
194         unsigned short val = readw(fec_reg_addr(base, reg));
195
196         if (net_debug) diag_printf("Read %04x from FEC reg %s[%03x]\n",
197                                                         val, name, reg);
198         return val;
199 }
200
201 #define mxc_fec_reg_write16(hw_reg,reg,val) _mxc_fec_reg_write16(hw_reg, reg, val, #reg)
202 static inline void _mxc_fec_reg_write16(volatile void *base, unsigned int reg,
203                                                                                 unsigned short val, const char *name)
204 {
205         if (net_debug) diag_printf("Writing %04x to FEC reg %s[%03x]\n",
206                                                         val, name, reg);
207         writew(val, fec_reg_addr(base, reg));
208 }
209
210 /*!
211  * This function gets the value of PHY registers via MII interface
212  */
213 static int
214 mxc_fec_mii_read(volatile mxc_fec_reg_t *hw_reg, unsigned char phy_addr, unsigned char reg_addr,
215                                  unsigned short int *value)
216 {
217         unsigned long waiting = FEC_MII_TIMEOUT;
218
219         if (net_debug) diag_printf("%s: Trying to read phy[%02x] reg %04x\n",
220                                                         __FUNCTION__, phy_addr, reg_addr);
221         if (mxc_fec_reg_read(hw_reg, eir) & FEC_EVENT_MII) {
222                 if (net_debug) diag_printf("%s: Clearing EIR_EVENT_MII\n", __FUNCTION__);
223                 mxc_fec_reg_write(hw_reg, eir, FEC_EVENT_MII);
224         }
225         if (net_debug) diag_printf("%s: EIR=%08lx\n", __FUNCTION__, mxc_fec_reg_read(hw_reg, eir));
226         mxc_fec_reg_write(hw_reg, mmfr, FEC_MII_READ(phy_addr, reg_addr));/* Write CMD */
227         while (1) {
228                 if (mxc_fec_reg_read(hw_reg, eir) & FEC_EVENT_MII) {
229                         if (net_debug) diag_printf("%s: Got EIR_EVENT_MII: EIR=%08lx\n",
230                                                    __FUNCTION__, mxc_fec_reg_read(hw_reg, eir));
231                         mxc_fec_reg_write(hw_reg, eir, FEC_EVENT_MII);
232                         break;
233                 }
234                 if (--waiting == 0) {
235                         diag_printf("%s: Read from PHY at addr %d reg 0x%02x timed out: EIR=%08lx\n",
236                                                 __FUNCTION__, phy_addr, reg_addr,
237                                                 mxc_fec_reg_read(hw_reg, eir));
238                         return -1;
239                 }
240                 hal_delay_us(FEC_MII_TICK);
241         }
242         *value = FEC_MII_GET_DATA(mxc_fec_reg_read(hw_reg, mmfr));
243         if (net_debug) diag_printf("%s: Read %04x from phy[%02x] reg %04x\n", __FUNCTION__,
244                                                         *value, phy_addr, reg_addr);
245         return 0;
246 }
247
248 /*!
249  * This function set the value of  PHY registers by MII interface
250  */
251 static int
252 mxc_fec_mii_write(volatile mxc_fec_reg_t *hw_reg, unsigned char phy_addr, unsigned char reg_addr,
253                   unsigned short int value)
254 {
255         unsigned long waiting = FEC_MII_TIMEOUT;
256
257         if (net_debug) diag_printf("%s: Trying to write %04x to phy[%02x] reg %04x\n", __FUNCTION__,
258                                    value, phy_addr, reg_addr);
259         if (mxc_fec_reg_read(hw_reg, eir) & FEC_EVENT_MII) {
260                 if (net_debug) diag_printf("%s: Clearing EIR_EVENT_MII\n", __FUNCTION__);
261                 mxc_fec_reg_write(hw_reg, eir, FEC_EVENT_MII);
262         }
263         if (net_debug) diag_printf("%s: EIR=%08lx\n", __FUNCTION__, mxc_fec_reg_read(hw_reg, eir));
264         mxc_fec_reg_write(hw_reg, mmfr,  FEC_MII_WRITE(phy_addr, reg_addr, value));/* Write CMD */
265         if (net_debug) diag_printf("%s: Wrote cmd %08x to MMFR\n", __FUNCTION__,
266                                    FEC_MII_WRITE(phy_addr, reg_addr, value));
267         while (1) {
268                 if (mxc_fec_reg_read(hw_reg, eir) & FEC_EVENT_MII) {
269                         if (net_debug) diag_printf("%s: Got EIR_EVENT_MII: EIR=%08lx\n",
270                                                    __FUNCTION__, mxc_fec_reg_read(hw_reg, eir));
271                         mxc_fec_reg_write(hw_reg, eir, FEC_EVENT_MII);
272                         break;
273                 }
274                 if (--waiting == 0) {
275                         diag_printf("%s: Write to PHY at addr %d reg 0x%02x timed out: EIR=%08lx\n",
276                                                 __FUNCTION__, phy_addr, reg_addr,
277                                                 mxc_fec_reg_read(hw_reg, eir));
278                         return -1;
279                 }
280                 hal_delay_us(FEC_MII_TICK);
281         }
282         if (net_debug) diag_printf("%s: Write to phy register succeeded\n", __FUNCTION__);
283         return 0;
284 }
285
286 static void
287 mxc_fec_set_mac_address(volatile mxc_fec_reg_t *hw_reg, unsigned char *enaddr)
288 {
289         unsigned long value;
290
291         value = enaddr[0];
292         value = (value << 8) + enaddr[1];
293         value = (value << 8) + enaddr[2];
294         value = (value << 8) + enaddr[3];
295         mxc_fec_reg_write(hw_reg, palr, value);
296
297         value = enaddr[4];
298         value = (value << 8) + enaddr[5];
299         mxc_fec_reg_write(hw_reg, paur, value << 16);
300 }
301
302 #ifdef CYGOPT_HAL_ARM_MXC_FEC_MIIGSK
303 static int mxc_fec_mii_setup(mxc_fec_priv_t *priv)
304 {
305         volatile mxc_fec_reg_t *hw_reg = priv->hw_reg;
306         /*
307          * setup the MII gasket for RMII mode
308          */
309
310         /* disable the gasket */
311         mxc_fec_reg_write16(hw_reg, miigsk_enr, 0);
312
313         /* wait for the gasket to be disabled */
314         while (mxc_fec_reg_read16(hw_reg, miigsk_enr) & MIIGSK_ENR_READY)
315                 hal_delay_us(FEC_COMMON_TICK);
316
317         /* configure gasket for RMII, 50 MHz, no loopback, and no echo */
318         mxc_fec_reg_write16(hw_reg, miigsk_cfgr, MIIGSK_CFGR_IF_MODE_RMII |
319                                                 ((!priv || (priv->status & FEC_STATUS_100M)) ?
320                                                         0 : MIIGSK_CFGR_FRCONT));
321
322         /* re-enable the gasket */
323         mxc_fec_reg_write16(hw_reg, miigsk_enr, MIIGSK_ENR_EN);
324
325         /* wait until MII gasket is ready */
326         int max_loops = 10;
327         while ((mxc_fec_reg_read16(hw_reg, miigsk_enr) & MIIGSK_ENR_READY) == 0) {
328                 if (--max_loops <= 0) {
329                         diag_printf("WAIT for MII Gasket ready timed out\n");
330                         return -1;
331                 }
332         }
333         return 0;
334 }
335 #else
336 static inline int mxc_fec_mii_setup(mxc_fec_priv_t *priv)
337 {
338         return 0;
339 }
340 #endif
341
342 /*!
343  * This function enables the FEC for reception of packets
344  */
345 static void
346 mxc_fec_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
347 {
348         mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
349         volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
350
351         if (!(priv && hw_reg)) {
352                 diag_printf("BUG[start]: FEC driver not initialized\n");
353                 return;
354         }
355         if (enaddr == NULL) {
356                 diag_printf("BUG[start]: no MAC address supplied\n");
357                 return;
358         }
359         mxc_fec_set_mac_address(hw_reg, enaddr);
360
361         priv->tx_busy = 0;
362         mxc_fec_reg_write(hw_reg, rdar, FEC_RX_TX_ACTIVE);
363         mxc_fec_reg_write(hw_reg, ecr, FEC_ETHER_EN);
364 }
365
366 /*!
367  * This function pauses the FEC controller.
368  */
369 static void
370 mxc_fec_stop(struct eth_drv_sc *sc)
371 {
372         mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
373         volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
374
375         if (!(priv && hw_reg)) {
376                 diag_printf("BUG[stop]: FEC driver not initialized\n");
377                 return;
378         }
379         mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) & ~FEC_ETHER_EN);
380 }
381
382 static int
383 mxc_fec_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length)
384 {
385         /*TODO:: Add support */
386         diag_printf("mxc_fec_control: key=0x%08lx, data=%p, data_len=0x%08x\n",
387                                 key, data, data_length);
388         return 0;
389 }
390
391 /*!
392  * This function checks the status of FEC control.
393  */
394 static int
395 mxc_fec_can_send(struct eth_drv_sc *sc)
396 {
397         mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
398         volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
399
400         if (!(priv && hw_reg)) {
401                 diag_printf("BUG[can_send]: FEC driver not initialized\n");
402                 return 0;
403         }
404         if (priv->tx_busy) {
405                 diag_printf("WARNING[can_send]: MXC_FEC is busy for transmission\n");
406                 return 0;
407         }
408
409         if (!(mxc_fec_reg_read(hw_reg, ecr) & FEC_ETHER_EN)) {
410                 diag_printf("WARNING[can_send]: MXC_FEC is not enabled\n");
411                 return 0;
412         }
413
414         if (mxc_fec_reg_read(hw_reg, tcr) & FEC_TCR_RFC_PAUSE) {
415                 diag_printf("WARNING[can_send]: MXC_FEC is paused\n");
416                 return 0;
417         }
418
419         if (!(priv->status & FEC_STATUS_LINK_ON)) {
420                 /* Reading the PHY status for every packet to be sent is
421                  * a real performance killer.
422                  * Thus, only read the PHY status when the link is down to
423                  * detect a possible new connection
424                  */
425 #ifdef CYGPKG_DEVS_ETH_PHY
426                 unsigned short value;
427                 value = _eth_phy_state(priv->phy);
428                 if (value & ETH_PHY_STAT_LINK) {
429                         mxc_fec_phy_status(priv, value, true);
430                 }
431 #else
432                 unsigned short value;
433                 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
434                 if (value & PHY_STATUS_LINK_ST) {
435                         mxc_fec_phy_status(priv, 0, true);
436                 }
437 #endif
438         }
439
440         return priv->status & FEC_STATUS_LINK_ON;
441 }
442
443 /*!
444  * This function transmits a frame.
445  */
446 static void
447 mxc_fec_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total,
448                         unsigned long key)
449 {
450         mxc_fec_priv_t *dev = sc ? sc->driver_private : NULL;
451         volatile mxc_fec_reg_t *hw_reg = dev ? dev->hw_reg : NULL;
452         mxc_fec_bd_t *p;
453         int i, off;
454
455         if (dev == NULL || hw_reg == NULL) {
456                 diag_printf("BUG[TX]: FEC driver not initialized\n");
457                 return;
458         }
459         if (total > (FEC_FRAME_LEN - 4)) total = FEC_FRAME_LEN - 4;
460         if (sg_list == NULL || total <= 14) {
461                 if (sc->funs->eth_drv && sc->funs->eth_drv->tx_done) {
462                         sc->funs->eth_drv->tx_done(sc, key, -1);
463                 }
464                 return;
465         }
466
467         for (i = 0, off = 0, p = dev->tx_cur; i < sg_len; i++) {
468                 unsigned long vaddr;
469
470                 if (p->status & BD_TX_ST_RDY) {
471                         diag_printf("BUG[TX]: trying to resend already finished buffer\n");
472                         break;
473                 }
474                 if (sg_list[i].buf == 0) {
475                         diag_printf("WARNING[TX]: sg_list->buf is NULL\n");
476                         break;
477                 }
478                 vaddr = hal_ioremap_nocache((unsigned long)p->data) + off;
479                 memcpy((void *)vaddr, (void *)sg_list[i].buf, sg_list[i].len);
480                 off += sg_list[i].len;
481         }
482         if (off < 14) {
483                 diag_printf("WARNING[TX]: packet size %d too small\n", off);
484                 return;
485         }
486         p->length = off;
487         p->status &= ~BD_TX_ST_ABC;
488         p->status |= BD_TX_ST_LAST | BD_TX_ST_RDY | BD_TX_ST_TC;
489         if (p->status & BD_TX_ST_WRAP) {
490                 p = dev->tx_bd;
491         } else {
492                 p++;
493         }
494         dev->tx_cur = p;
495         dev->tx_busy = 1;
496         dev->tx_key = key;
497         mxc_fec_reg_write(hw_reg, tdar, FEC_RX_TX_ACTIVE);
498 }
499
500 /*!
501  * This function receives ready Frame in DB.
502  */
503 static void
504 mxc_fec_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
505 {
506         mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
507         mxc_fec_bd_t *p;
508         unsigned long vaddr;
509
510         if (sg_list == NULL || priv == NULL || sg_len <= 0) {
511                 diag_printf("BUG[RX]: FEC driver not initialized\n");
512                 return;
513         }
514
515         /*TODO: I think if buf pointer is NULL, this function
516          * should not be called
517          */
518         if (sg_list->buf == 0) {
519                 diag_printf("WARING[RX]: the sg_list is empty\n");
520                 return;
521         }
522         p = priv->rx_cur;
523
524         if (p->status & BD_RX_ST_EMPTY) {
525                 diag_printf("BUG[RX]: empty buffer received; status=%04x\n", p->status);
526                 return;
527         }
528
529         if (!(p->status & BD_RX_ST_LAST)) {
530                 diag_printf("BUG[RX]: status=%0xx\n", p->status);
531                 return;
532         }
533         vaddr = hal_ioremap_nocache((unsigned long)p->data);
534         /*TODO::D_CACHE invalidate this data buffer*/
535         memcpy((void *)sg_list->buf, (void *)vaddr, p->length - 4);
536         if (net_debug) dump_packet((void *)sg_list->buf, p->length - 4);
537 }
538
539 static void
540 mxc_fec_deliver(struct eth_drv_sc *sc)
541 {
542         /*TODO::When redboot support thread ,
543          *      the polling function will be called at here
544          */
545         return;
546 }
547
548 /* This funtion just called by polling funtion */
549 static void
550 mxc_fec_check_rx_bd(struct eth_drv_sc *sc)
551 {
552         mxc_fec_priv_t *priv = sc->driver_private;
553         mxc_fec_bd_t *p;
554         volatile mxc_fec_reg_t *hw_reg = priv->hw_reg;
555         int i;
556
557         for (i = 0, p = priv->rx_cur; i < FEC_RX_FRAMES; i++) {
558                 /*
559                  * TODO::D-CACHE invalidate this BD.
560                  * In WRITE_BACK mode: this may destroy the next BD
561                  * when the CACHE_LINE is written back.
562                  */
563                 if (p->status & BD_RX_ST_EMPTY) {
564                         break;
565                 }
566                 if (!(p->status & BD_RX_ST_LAST)) {
567                         diag_printf("BUG[RX]: status=%04x, length=%x\n", p->status, p->length);
568                         goto skip_next;
569                 }
570
571                 if (p->status & BD_RX_ST_ERRS) {
572                         diag_printf("RX error: status=%08x errors=%08x\n", p->status,
573                                                 p->status & BD_RX_ST_ERRS);
574                 } else if (p->length > FEC_FRAME_LEN) {
575                         diag_printf("RX error: packet size 0x%08x larger than max frame length: 0x%08x\n",
576                                                 p->length, FEC_FRAME_LEN);
577                 } else {
578                         sc->funs->eth_drv->recv(sc, p->length - 4);
579                 }
580         skip_next:
581                 p->status = (p->status & BD_RX_ST_WRAP) | BD_RX_ST_EMPTY;
582
583                 if (p->status & BD_RX_ST_WRAP) {
584                         p = priv->rx_bd;
585                 } else {
586                         p++;
587                 }
588                 priv->rx_cur = p;
589                 mxc_fec_reg_write(hw_reg, rdar, FEC_RX_TX_ACTIVE);
590         }
591 }
592
593 /*!
594  * This function checks the event of FEC controller
595  */
596 static void
597 mxc_fec_poll(struct eth_drv_sc *sc)
598 {
599         mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
600         volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
601         unsigned long value;
602         int dbg = net_debug;
603         static unsigned long last_poll;
604         int poll_intvl = (priv->status & FEC_STATUS_LINK_ON) ? 100 : 10;
605
606         if (priv == NULL || hw_reg == NULL) {
607                 diag_printf("BUG[POLL]: FEC driver not initialized\n");
608                 return;
609         }
610 #if 1
611         net_debug = 0;
612 #endif
613         value = mxc_fec_reg_read(hw_reg, eir);
614         mxc_fec_reg_write(hw_reg, eir, value & ~FEC_EVENT_MII);
615 #if 1
616         net_debug = dbg;
617 #endif
618         if (value & FEC_EVENT_TX_ERR) {
619                 diag_printf("WARNING[POLL]: Transmit error\n");
620                 sc->funs->eth_drv->tx_done(sc, priv->tx_key, -1);
621                 priv->tx_busy = 0;
622         } else {
623                 if (value & FEC_EVENT_TX) {
624                         last_poll = 0;
625                         sc->funs->eth_drv->tx_done(sc, priv->tx_key, 0);
626                         priv->tx_busy = 0;
627                 }
628         }
629         if (value & FEC_EVENT_RX) {
630                 last_poll = 0;
631                 mxc_fec_check_rx_bd(sc);
632         }
633
634         if (value & FEC_EVENT_HBERR) {
635                 diag_printf("WARNGING[POLL]: Heartbeat error!\n");
636         }
637
638         if (value & FEC_EVENT_EBERR) {
639                 diag_printf("WARNING[POLL]: Ethernet Bus Error!\n");
640         }
641
642         if (value & (FEC_EVENT_TX_ERR | FEC_EVENT_HBERR | FEC_EVENT_EBERR) ||
643                 last_poll++ > poll_intvl) {
644 #ifdef CYGPKG_DEVS_ETH_PHY
645                 unsigned short value;
646                 value = _eth_phy_state(priv->phy);
647                 if (!(value & ETH_PHY_STAT_LINK) ^
648                         !(priv->status & FEC_STATUS_LINK_ON)) {
649                         mxc_fec_phy_status(priv, value, true);
650                 }
651 #else
652                 unsigned short value;
653                 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
654                 if (!(value & PHY_STATUS_LINK_ST) ^
655                         !(priv->status & FEC_STATUS_LINK_ON)) {
656                         mxc_fec_phy_status(priv, 0, true);
657                 }
658 #endif
659                 last_poll = 0;
660         }
661 }
662
663 static int
664 mxc_fec_int_vector(struct eth_drv_sc *sc)
665 {
666         /*TODO::
667          *      get FEC interrupt number
668          */
669         return -1;
670 }
671
672 /*!
673  * The function initializes the description buffer for receiving or transmitting
674  */
675 static void
676 mxc_fec_bd_init(mxc_fec_priv_t *dev)
677 {
678         int i;
679         mxc_fec_bd_t *p;
680
681         p = dev->rx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_rx_bd));
682         for (i = 0; i < FEC_BD_RX_NUM; i++, p++) {
683                 p->status = BD_RX_ST_EMPTY;
684                 p->length = 0;
685                 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_rx_buf[i]);
686         }
687
688         dev->rx_bd[i - 1].status |= BD_RX_ST_WRAP;
689         dev->rx_cur = dev->rx_bd;
690
691         p = dev->tx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_tx_bd));
692         for (i = 0; i < FEC_BD_TX_NUM; i++, p++) {
693                 p->status = 0;
694                 p->length = 0;
695                 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_tx_buf[i]);
696         }
697
698         dev->tx_bd[i - 1].status |= BD_TX_ST_WRAP;
699         dev->tx_cur = dev->tx_bd;
700
701         /*TODO:: add the sync function for items*/
702 }
703
704 /*!
705  *This function initializes FEC controller.
706  */
707 static void
708 mxc_fec_chip_init(mxc_fec_priv_t *dev)
709 {
710         volatile mxc_fec_reg_t *hw_reg = dev->hw_reg;
711         unsigned long ipg_clk;
712         unsigned long clkdiv;
713
714         mxc_fec_reg_write(hw_reg, ecr, FEC_RESET);
715         while (mxc_fec_reg_read(hw_reg, ecr) & FEC_RESET) {
716                 hal_delay_us(FEC_COMMON_TICK);
717         }
718
719         mxc_fec_reg_write(hw_reg, eimr, 0);
720         mxc_fec_reg_write(hw_reg, eir, ~0);
721
722         mxc_fec_reg_write(hw_reg, rcr,
723                                         (mxc_fec_reg_read(hw_reg, rcr) & ~0x3F) |
724                                         FEC_RCR_FCE | FEC_RCR_MII_MODE);
725
726         mxc_fec_reg_write(hw_reg, tcr, mxc_fec_reg_read(hw_reg, tcr) | FEC_TCR_FDEN);
727         mxc_fec_reg_write(hw_reg, mibc, mxc_fec_reg_read(hw_reg, mibc) | FEC_MIB_DISABLE);
728
729         mxc_fec_reg_write(hw_reg, iaur, 0);
730         mxc_fec_reg_write(hw_reg, ialr, 0);
731         mxc_fec_reg_write(hw_reg, gaur, 0);
732         mxc_fec_reg_write(hw_reg, galr, 0);
733
734         ipg_clk = get_main_clock(IPG_CLK);
735         clkdiv = ((ipg_clk + 499999) / 2500000 / 2) << 1;
736 #if 1
737         mxc_fec_reg_write(hw_reg, mscr, (mxc_fec_reg_read(hw_reg, mscr) & ~0x7e) |
738                                         clkdiv);
739 #endif
740         if (net_debug) diag_printf("mscr set to %08lx(%08lx) for ipg_clk %ld\n",
741                                                         clkdiv, mxc_fec_reg_read(hw_reg, mscr), ipg_clk);
742
743         mxc_fec_reg_write(hw_reg, emrbr, 2048 - 16);
744         mxc_fec_reg_write(hw_reg, erdsr, hal_virt_to_phy((unsigned long)dev->rx_bd));
745         mxc_fec_reg_write(hw_reg, etdsr, hal_virt_to_phy((unsigned long)dev->tx_bd));
746
747         /* must be done before enabling the MII gasket
748          * (otherwise MIIGSK_ENR_READY will never assert)
749          */
750         mxc_fec_reg_write(hw_reg, ecr, FEC_ETHER_EN);
751 }
752
753 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show)
754 {
755         int changed = 0;
756 #ifdef CYGPKG_DEVS_ETH_PHY
757         if (value & ETH_PHY_STAT_LINK) {
758                 changed = !(dev->status & FEC_STATUS_LINK_ON);
759                 dev->status |= FEC_STATUS_LINK_ON;
760                 if (value & ETH_PHY_STAT_FDX) {
761                         dev->status |= FEC_STATUS_FULL_DPLX;
762                 } else {
763                         dev->status &= ~FEC_STATUS_FULL_DPLX;
764                 }
765                 if (value & ETH_PHY_STAT_100MB) {
766                         changed |= !(dev->status & ETH_PHY_STAT_100MB);
767                         dev->status |= FEC_STATUS_100M;
768                 } else {
769                         changed |= !!(dev->status & ETH_PHY_STAT_100MB);
770                         dev->status &= ~FEC_STATUS_100M;
771                 }
772         } else {
773                 changed = !!(dev->status & FEC_STATUS_LINK_ON);
774                 dev->status &= ~FEC_STATUS_LINK_ON;
775         }
776 #else
777         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value);
778         if (value & PHY_STATUS_LINK_ST) {
779                 changed |= !(dev->status & FEC_STATUS_LINK_ON);
780                 dev->status |= FEC_STATUS_LINK_ON;
781         } else {
782                 changed |= dev->status & FEC_STATUS_LINK_ON;
783                 dev->status &= ~FEC_STATUS_LINK_ON;
784         }
785
786         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_DIAG_REG, &value);
787         if (value & PHY_DIAG_DPLX) {
788                 dev->status |= FEC_STATUS_FULL_DPLX;
789         } else {
790                 dev->status &= ~FEC_STATUS_FULL_DPLX;
791         }
792         if (value & PHY_DIAG_RATE) {
793                 changed |= !(dev->status & FEC_STATUS_100M);
794                 dev->status |= FEC_STATUS_100M;
795         } else {
796                 changed |= dev->status & FEC_STATUS_100M;
797                 dev->status &= ~FEC_STATUS_100M;
798         }
799 #endif
800         if (changed) {
801                 if (dev->status & FEC_STATUS_FULL_DPLX) {
802                         mxc_fec_reg_write(dev->hw_reg, tcr,
803                                                         (mxc_fec_reg_read(dev->hw_reg, tcr) & ~FEC_TCR_HBC) |
804                                                         FEC_TCR_FDEN);
805                         mxc_fec_reg_write(dev->hw_reg, rcr,
806                                                         (mxc_fec_reg_read(dev->hw_reg, rcr) & ~FEC_RCR_DRT) |
807                                                         FEC_RCR_FCE);
808                 } else {
809                         mxc_fec_reg_write(dev->hw_reg, tcr,
810                                                         (mxc_fec_reg_read(dev->hw_reg, tcr) & ~FEC_TCR_FDEN) |
811                                                         FEC_TCR_HBC);
812                         mxc_fec_reg_write(dev->hw_reg, rcr,
813                                                         (mxc_fec_reg_read(dev->hw_reg, rcr) & ~FEC_RCR_FCE) |
814                                                         FEC_RCR_DRT);
815                 }
816                 mxc_fec_mii_setup(dev);
817         }
818         if (!show || !changed) {
819                 return;
820         }
821         if (dev->status & FEC_STATUS_LINK_ON) {
822                 diag_printf("FEC: [ %s ] [ %s ]:\n",
823                                         (dev->status & FEC_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
824                                         (dev->status & FEC_STATUS_100M) ? "100 Mbps" : "10 Mbps");
825         } else {
826                 diag_printf("FEC: no cable\n");
827         }
828 }
829
830 #ifndef CYGPKG_DEVS_ETH_PHY
831 /*!
832  * This function initializes the PHY
833  */
834 static bool
835 mxc_fec_phy_init(mxc_fec_priv_t *dev)
836 {
837 #if 1
838         unsigned short value = 0;
839         unsigned long timeout = FEC_COMMON_TIMEOUT;
840
841         /* Reset PHY */
842         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET);
843         while (timeout--) {
844                 if (mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
845                         return false;
846                 }
847
848                 if (!(value & PHY_CTRL_RESET)) {
849                         if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
850                         break;
851                 }
852                 hal_delay_us(FEC_MII_TICK);
853         }
854
855         if (value & PHY_CTRL_RESET) {
856                 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
857                 return false;
858         }
859
860         unsigned long id;
861         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
862         id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
863         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
864         id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
865         if (id == 0 || id == 0xffffffff) {
866                 diag_printf("FEC could not identify PHY: ID=%08lx\n", id);
867                 return false;
868         }
869
870         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
871                           PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
872
873         timeout = FEC_COMMON_TIMEOUT;
874         while (timeout-- &&
875                 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value) == 0) {
876                 if (value & PHY_STATUS_LINK_ST) {
877                         if (net_debug) diag_printf("PHY Status: %04x\n", value);
878                         break;
879                 }
880                 hal_delay_us(FEC_MII_TICK);
881         }
882         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, &value);
883         value &= ~PHY_LED_SEL;
884         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, value);
885 #else
886         unsigned long value = 0;
887         unsigned long id = 0, timeout = 50;
888
889         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
890         id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
891         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
892         id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
893
894         switch (id) {
895         case 0x00540088:
896                 break;
897         case 0x00007C0C:
898                 break;
899         default:
900                 diag_printf("[Warning] FEC not connect right PHY: ID=%lx\n", id);
901         }
902
903         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
904                                         PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
905
906 #ifdef CYGPKG_HAL_ARM_MX27ADS
907         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, &value);
908         value &= ~PHY_LED_SEL;
909         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, value);
910 #endif
911
912 #if defined(CYGPKG_HAL_ARM_MX51) || defined(CYGPKG_HAL_ARM_MX25_3STACK) || \
913         defined(CYGPKG_HAL_ARM_MX35_3STACK) || defined(CYGPKG_HAL_ARM_MX27_3STACK)
914         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_EXP_REG, &value);
915         /* Wait for packet to arrive */
916         while (((value & PHY_AUTO_NEG_NEW_PAGE) == 0) && (timeout != 0)) {
917                 hal_delay_us(100);
918                 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_EXP_REG, &value);
919                 timeout--;
920         }
921         /* Check if link is capable of auto-negotiation */
922         if ((value & PHY_AUTO_NEG_CAP) == 1) {
923                 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_INT_SRC_REG, &value);
924                 timeout = 50;
925                 /* Wait for auto-negotiation to complete */
926                 while (((value & PHY_INT_AUTO_NEG) == 0) && (timeout != 0)) {
927                         hal_delay_us(100);
928                         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_INT_SRC_REG, &value);
929                         timeout--;
930                 }
931         }
932 #endif
933         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value);
934         if (value & PHY_STATUS_LINK_ST) {
935                 dev->status |= FEC_STATUS_LINK_ON;
936         } else {
937                 dev->status &= ~FEC_STATUS_LINK_ON;
938         }
939
940 #ifdef CYGPKG_HAL_ARM_MX27ADS
941         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_DIAG_REG, &value);
942         if (value & PHY_DIAG_DPLX) {
943                 dev->status |= FEC_STATUS_FULL_DPLX;
944         } else {
945                 dev->status &= ~FEC_STATUS_FULL_DPLX;
946         }
947         if (value & PHY_DIAG_DPLX) {
948                 dev->status |= FEC_STATUS_100M;
949         } else {
950                 dev->status &= ~FEC_STATUS_100M;
951         }
952 #endif
953
954 #if defined(CYGPKG_HAL_ARM_MX51) || defined(CYGPKG_HAL_ARM_MX25_3STACK) || \
955         defined(CYGPKG_HAL_ARM_MX35_3STACK)
956         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_REG, &value);
957         if (value & PHY_AUTO_10BASET) {
958                 dev->status &= ~FEC_STATUS_100M;
959                 if (value & PHY_AUTO_10BASET_DPLX) {
960                         dev->status |= FEC_STATUS_FULL_DPLX;
961                 } else {
962                         dev->status &= ~FEC_STATUS_FULL_DPLX;
963                 }
964         }
965
966         if (value & PHY_AUTO_100BASET) {
967                 dev->status |= FEC_STATUS_100M;
968                 if (value & PHY_AUTO_100BASET_DPLX) {
969                         dev->status |= FEC_STATUS_FULL_DPLX;
970                 } else {
971                         dev->status &= ~FEC_STATUS_FULL_DPLX;
972                 }
973         }
974 #endif
975         diag_printf("FEC: [ %s ] [ %s ] [ %s ]:\n",
976                 (dev->status & FEC_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
977                 (dev->status & FEC_STATUS_LINK_ON) ? "connected" : "disconnected",
978                 (dev->status & FEC_STATUS_100M) ? "100M bps" : "10M bps");
979 #endif
980         return true;
981 }
982
983 static int mxc_fec_discover_phy(mxc_fec_priv_t *fep, unsigned char def_addr)
984 {
985         int ret = 0;
986         unsigned char phy_addr = def_addr;
987         unsigned long id = 0;
988         int i;
989
990         for (i = 0; i < 32; i++) {
991                 unsigned short mii_reg;
992
993                 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
994
995                 if (ret != 0) {
996                         break;
997                 }
998                 if (mii_reg != 0xffff && mii_reg != 0) {
999                         /* Got first part of ID, now get remainder.
1000                         */
1001                         id = mii_reg;
1002                         ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR2, &mii_reg);
1003                         if (ret != 0) {
1004                                 break;
1005                         }
1006                         id = (id << 16) | mii_reg;
1007                         if (net_debug) diag_printf("%s: discovered PHY %08lx at addr %x\n",
1008                                                    __FUNCTION__, id, phy_addr);
1009                         ret = phy_addr;
1010                         break;
1011                 } else {
1012                         phy_addr = (phy_addr + 1) % 32;
1013                         ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
1014                         if (ret != 0) {
1015                                 break;
1016                         }
1017                 }
1018         }
1019         if (id == 0) {
1020                 /* Disable MII */
1021                 fep->mxc_fec_reg_write(hw_reg, mscr, 0);
1022                 ret = -1;
1023         }
1024
1025         return ret;
1026 }
1027 #endif
1028
1029 /*
1030  * generic PHY support functions
1031  */
1032 void mxc_fec_phy_reset(void)
1033 {
1034         unsigned short value = 0;
1035         unsigned long timeout=FEC_COMMON_TIMEOUT;
1036         mxc_fec_priv_t *dev = &mxc_fec_private;
1037
1038         /* Reset PHY */
1039         if (net_debug) diag_printf("%s\n", __FUNCTION__);
1040
1041         _eth_phy_write(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, PHY_CTRL_RESET);
1042         while (timeout--) {
1043                 if (!_eth_phy_read(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, &value)) {
1044                         return;
1045                 }
1046
1047                 if (!(value & PHY_CTRL_RESET)) {
1048                         if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
1049                         break;
1050                 }
1051                 hal_delay_us(FEC_MII_TICK);
1052         }
1053
1054         if (value & PHY_CTRL_RESET) {
1055                 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
1056                 return;
1057         }
1058 }
1059
1060 void mxc_fec_phy_init(void)
1061 {
1062         if (net_debug) diag_printf("%s\n", __FUNCTION__);
1063 }
1064
1065 bool mxc_fec_phy_read(int reg, int unit, unsigned short *data)
1066 {
1067         int ret;
1068         if (net_debug) diag_printf("%s\n", __FUNCTION__);
1069         ret = mxc_fec_mii_read(mxc_fec_private.hw_reg, unit, reg, data);
1070         return ret == 0;
1071 }
1072
1073 void mxc_fec_phy_write(int reg, int unit, unsigned short data)
1074 {
1075         if (net_debug) diag_printf("%s\n", __FUNCTION__);
1076         mxc_fec_mii_write(mxc_fec_private.hw_reg, unit, reg, data);
1077 }
1078
1079 /*! This function initializes the FEC driver.
1080  * It is called by net_init in net module of RedBoot during RedBoot init
1081  */
1082 static bool
1083 mxc_fec_init(struct cyg_netdevtab_entry *tab)
1084 {
1085         struct eth_drv_sc *sc = tab ? tab->device_instance : NULL;
1086         mxc_fec_priv_t *private;
1087         unsigned char eth_add_local[ETHER_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1088         int ok = 0;
1089 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1090         cyg_bool set_esa;
1091 #endif
1092
1093         if (net_debug)  diag_printf("%s:\n", __FUNCTION__);
1094         if (sc == NULL) {
1095                 diag_printf("%s: no driver attached\n", __FUNCTION__);
1096                 return false;
1097         }
1098
1099         private = MXC_FEC_PRIVATE(sc);
1100         if (private == NULL) {
1101                 private = &mxc_fec_private;
1102         }
1103         if (private->provide_esa) {
1104                 ok = private->provide_esa(eth_add_local);
1105         }
1106 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1107         if (!ok) {
1108                 /* Get MAC address from fconfig */
1109                 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
1110                                                                                  "fec_esa", &set_esa, CONFIG_BOOL);
1111                 if (ok && set_esa) {
1112                         CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
1113                                                                                 "fec_esa_data", eth_add_local, CONFIG_ESA);
1114                 }
1115         }
1116 #endif
1117         if (!ok) {
1118                 diag_printf("No ESA provided via fuses or RedBoot config\n");
1119                 return false;
1120         }
1121
1122         private->hw_reg = (volatile void *)SOC_FEC_BASE;
1123         private->tx_busy = 0;
1124         private->status = 0;
1125
1126         mxc_fec_bd_init(private);
1127
1128         mxc_fec_chip_init(private);
1129 #ifdef CYGPKG_DEVS_ETH_PHY
1130         if (!_eth_phy_init(private->phy)) {
1131                 diag_printf("%s: Failed to initialize PHY\n", __FUNCTION__);
1132                 return false;
1133         }
1134         _eth_phy_state(private->phy);
1135 #else
1136         ok = mxc_fec_discover_phy(private, PHY_PORT_ADDR);
1137         if (ok < 0) {
1138                 diag_printf("%s: no PHY found\n", __FUNCTION__);
1139                 return false;
1140         }
1141         private->phy_addr = ok;
1142         mxc_fec_phy_init(private);
1143 #endif
1144         /* TODO:: initialize System Resource : irq, timer */
1145
1146         sc->funs->eth_drv->init(sc, eth_add_local);
1147         mxc_fec_phy_status(private, _eth_phy_state(private->phy), true);
1148
1149         return true;
1150 }
1151
1152 #ifndef CYGPKG_DEVS_ETH_PHY
1153 /*!
1154  * Global variable which defines the FEC driver,
1155  */
1156 ETH_DRV_SC(mxc_fec_sc,
1157                 &mxc_fec_private,       // Driver specific data
1158                 mxc_fec_name,
1159                 mxc_fec_start,
1160                 mxc_fec_stop,
1161                 mxc_fec_control,
1162                 mxc_fec_can_send,
1163                 mxc_fec_send,
1164                 mxc_fec_recv,
1165                 mxc_fec_deliver,         // "pseudoDSR" called from fast net thread
1166                 mxc_fec_poll,            // poll function, encapsulates ISR and DSR
1167                 mxc_fec_int_vector);
1168
1169 /*!
1170  * Global variable which defines the FEC device
1171  */
1172 NETDEVTAB_ENTRY(mxc_fec_netdev,
1173                                 mxc_fec_name,
1174                                 mxc_fec_init,
1175                                 &mxc_fec_sc);
1176
1177 #endif // CYGPKG_DEVS_ETH_PHY