]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/eth/fec/v2_0/src/if_fec.c
TX51 Release 2011-07-27
[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 CYGPKG_HAL_ARM_MX25
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, mxc_fec_reg_read(hw_reg, rdar) | FEC_RX_TX_ACTIVE);
363         mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(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 #else
429                 unsigned short value;
430                 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
431 #endif
432                 if (value & PHY_STATUS_LINK_ST) {
433                         if (!(priv->status & FEC_STATUS_LINK_ON)) {
434                                 mxc_fec_phy_status(priv, value, true);
435                         }
436                 } else {
437                         if (priv->status & FEC_STATUS_LINK_ON) {
438                                 mxc_fec_phy_status(priv, value, true);
439                         }
440                 }
441         }
442
443         return priv->status & FEC_STATUS_LINK_ON;
444 }
445
446 /*!
447  * This function transmits a frame.
448  */
449 static void
450 mxc_fec_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total,
451                         unsigned long key)
452 {
453         mxc_fec_priv_t *dev = sc ? sc->driver_private : NULL;
454         volatile mxc_fec_reg_t *hw_reg = dev ? dev->hw_reg : NULL;
455         mxc_fec_bd_t *p;
456         int i, off;
457
458         if (dev == NULL || hw_reg == NULL) {
459                 diag_printf("BUG[TX]: FEC driver not initialized\n");
460                 return;
461         }
462         if (total > (FEC_FRAME_LEN - 4)) total = FEC_FRAME_LEN - 4;
463         if (sg_list == NULL || total <= 14) {
464                 if (sc->funs->eth_drv && sc->funs->eth_drv->tx_done) {
465                         sc->funs->eth_drv->tx_done(sc, key, -1);
466                 }
467                 return;
468         }
469
470         for (i = 0, off = 0, p = dev->tx_cur; i < sg_len; i++) {
471                 unsigned long vaddr;
472
473                 if (p->status & BD_TX_ST_RDY) {
474                         diag_printf("BUG[TX]: trying to resend already finished buffer\n");
475                         break;
476                 }
477                 if (sg_list[i].buf == 0) {
478                         diag_printf("WARNING[TX]: sg_list->buf is NULL\n");
479                         break;
480                 }
481                 vaddr = hal_ioremap_nocache((unsigned long)p->data) + off;
482                 memcpy((void *)vaddr, (void *)sg_list[i].buf, sg_list[i].len);
483                 off += sg_list[i].len;
484         }
485         if (off < 14) {
486                 diag_printf("WARNING[TX]: packet size %d too small\n", off);
487                 return;
488         }
489         p->length = off;
490         p->status &= ~BD_TX_ST_ABC;
491         p->status |= BD_TX_ST_LAST | BD_TX_ST_RDY | BD_TX_ST_TC;
492         if (p->status & BD_TX_ST_WRAP) {
493                 p = dev->tx_bd;
494         } else {
495                 p++;
496         }
497         dev->tx_cur = p;
498         dev->tx_busy = 1;
499         dev->tx_key = key;
500         mxc_fec_reg_write(hw_reg, tdar, FEC_RX_TX_ACTIVE);
501 }
502
503 /*!
504  * This function receives ready Frame in DB.
505  */
506 static void
507 mxc_fec_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
508 {
509         mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
510         mxc_fec_bd_t *p;
511         unsigned long vaddr;
512
513         if (sg_list == NULL || priv == NULL || sg_len <= 0) {
514                 diag_printf("BUG[RX]: FEC driver not initialized\n");
515                 return;
516         }
517
518         /*TODO: I think if buf pointer is NULL, this function
519          * should not be called
520          */
521         if (sg_list->buf == 0) {
522                 diag_printf("WARING[RX]: the sg_list is empty\n");
523                 return;
524         }
525         p = priv->rx_cur;
526
527         if (p->status & BD_RX_ST_EMPTY) {
528                 diag_printf("BUG[RX]: empty buffer received; status=%04x\n", p->status);
529                 return;
530         }
531
532         if (!(p->status & BD_RX_ST_LAST)) {
533                 diag_printf("BUG[RX]: status=%0xx\n", p->status);
534                 return;
535         }
536         vaddr = hal_ioremap_nocache((unsigned long)p->data);
537         /*TODO::D_CACHE invalidate this data buffer*/
538         memcpy((void *)sg_list->buf, (void *)vaddr, p->length - 4);
539         if (net_debug) dump_packet((void *)sg_list->buf, p->length - 4);
540 }
541
542 static void
543 mxc_fec_deliver(struct eth_drv_sc *sc)
544 {
545         /*TODO::When redboot support thread ,
546          *      the polling function will be called at here
547          */
548         return;
549 }
550
551 /* This funtion just called by polling funtion */
552 static void
553 mxc_fec_check_rx_bd(struct eth_drv_sc *sc)
554 {
555         mxc_fec_priv_t *priv = sc->driver_private;
556         mxc_fec_bd_t *p;
557         volatile mxc_fec_reg_t *hw_reg = priv->hw_reg;
558         int i;
559
560         for (i = 0, p = priv->rx_cur; i < FEC_RX_FRAMES; i++) {
561                 /*
562                  * TODO::D-CACHE invalidate this BD.
563                  * In WRITE_BACK mode: this may destroy the next BD
564                  * when the CACHE_LINE is written back.
565                  */
566                 if (p->status & BD_RX_ST_EMPTY) {
567                         break;
568                 }
569                 if (!(p->status & BD_RX_ST_LAST)) {
570                         diag_printf("BUG[RX]: status=%04x, length=%x\n", p->status, p->length);
571                         goto skip_next;
572                 }
573
574                 if (p->status & BD_RX_ST_ERRS) {
575                         diag_printf("RX error: status=%08x errors=%08x\n", p->status,
576                                                 p->status & BD_RX_ST_ERRS);
577                 } else if (p->length > FEC_FRAME_LEN) {
578                         diag_printf("RX error: packet size 0x%08x larger than max frame length: 0x%08x\n",
579                                                 p->length, FEC_FRAME_LEN);
580                 } else {
581                         sc->funs->eth_drv->recv(sc, p->length - 4);
582                 }
583         skip_next:
584                 p->status = (p->status & BD_RX_ST_WRAP) | BD_RX_ST_EMPTY;
585
586                 if (p->status & BD_RX_ST_WRAP) {
587                         p = priv->rx_bd;
588                 } else {
589                         p++;
590                 }
591                 priv->rx_cur = p;
592                 mxc_fec_reg_write(hw_reg, rdar, mxc_fec_reg_read(hw_reg, rdar) | FEC_RX_TX_ACTIVE);
593         }
594 }
595
596 /*!
597  * This function checks the event of FEC controller
598  */
599 static void
600 mxc_fec_poll(struct eth_drv_sc *sc)
601 {
602         mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
603         volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
604         unsigned long value;
605         int dbg = net_debug;
606         static unsigned long last_poll;
607         int poll_intvl = (priv->status & FEC_STATUS_LINK_ON) ? 100 : 10;
608
609         if (priv == NULL || hw_reg == NULL) {
610                 diag_printf("BUG[POLL]: FEC driver not initialized\n");
611                 return;
612         }
613 #if 1
614         net_debug = 0;
615 #endif
616         value = mxc_fec_reg_read(hw_reg, eir);
617         mxc_fec_reg_write(hw_reg, eir, value & ~FEC_EVENT_MII);
618 #if 1
619         net_debug = dbg;
620 #endif
621         if (value & FEC_EVENT_TX_ERR) {
622                 diag_printf("WARNING[POLL]: Transmit error\n");
623                 sc->funs->eth_drv->tx_done(sc, priv->tx_key, -1);
624                 priv->tx_busy = 0;
625         } else {
626                 if (value & FEC_EVENT_TX) {
627                         last_poll = 0;
628                         sc->funs->eth_drv->tx_done(sc, priv->tx_key, 0);
629                         priv->tx_busy = 0;
630                 }
631         }
632         if (value & FEC_EVENT_RX) {
633                 last_poll = 0;
634                 mxc_fec_check_rx_bd(sc);
635         }
636
637         if (value & FEC_EVENT_HBERR) {
638                 diag_printf("WARNGING[POLL]: Heartbeat error!\n");
639         }
640
641         if (value & FEC_EVENT_EBERR) {
642                 diag_printf("WARNING[POLL]: Ethernet Bus Error!\n");
643         }
644
645         if (value & (FEC_EVENT_TX_ERR | FEC_EVENT_HBERR | FEC_EVENT_EBERR) ||
646                 last_poll++ > poll_intvl) {
647 #ifdef CYGPKG_DEVS_ETH_PHY
648                 unsigned short value;
649                 value = _eth_phy_state(priv->phy);
650 #else
651                 unsigned short value;
652                 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
653 #endif
654                 last_poll = 0;
655                 if (value & PHY_STATUS_LINK_ST) {
656                         if (!(priv->status & FEC_STATUS_LINK_ON)) {
657                                 mxc_fec_phy_status(priv, value, true);
658                         }
659                 } else {
660                         if (priv->status & FEC_STATUS_LINK_ON) {
661                                 mxc_fec_phy_status(priv, value, true);
662                         }
663                 }
664         }
665 }
666
667 static int
668 mxc_fec_int_vector(struct eth_drv_sc *sc)
669 {
670         /*TODO::
671          *      get FEC interrupt number
672          */
673         return -1;
674 }
675
676 /*!
677  * The function initializes the description buffer for receiving or transmitting
678  */
679 static void
680 mxc_fec_bd_init(mxc_fec_priv_t *dev)
681 {
682         int i;
683         mxc_fec_bd_t *p;
684
685         p = dev->rx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_rx_bd));
686         for (i = 0; i < FEC_BD_RX_NUM; i++, p++) {
687                 p->status = BD_RX_ST_EMPTY;
688                 p->length = 0;
689                 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_rx_buf[i]);
690         }
691
692         dev->rx_bd[i - 1].status |= BD_RX_ST_WRAP;
693         dev->rx_cur = dev->rx_bd;
694
695         p = dev->tx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_tx_bd));
696         for (i = 0; i < FEC_BD_TX_NUM; i++, p++) {
697                 p->status = 0;
698                 p->length = 0;
699                 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_tx_buf[i]);
700         }
701
702         dev->tx_bd[i - 1].status |= BD_TX_ST_WRAP;
703         dev->tx_cur = dev->tx_bd;
704
705         /*TODO:: add the sync function for items*/
706 }
707
708 /*!
709  *This function initializes FEC controller.
710  */
711 static void
712 mxc_fec_chip_init(mxc_fec_priv_t *dev)
713 {
714         volatile mxc_fec_reg_t *hw_reg = dev->hw_reg;
715         unsigned long ipg_clk;
716         unsigned long clkdiv;
717
718         mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) | FEC_RESET);
719         while (mxc_fec_reg_read(hw_reg, ecr) & FEC_RESET) {
720                 hal_delay_us(FEC_COMMON_TICK);
721         }
722
723         mxc_fec_reg_write(hw_reg, eimr, 0);
724         mxc_fec_reg_write(hw_reg, eir, ~0);
725
726         mxc_fec_reg_write(hw_reg, rcr,
727                                         (mxc_fec_reg_read(hw_reg, rcr) & ~0x3F) |
728                                         FEC_RCR_FCE | FEC_RCR_MII_MODE);
729
730         mxc_fec_reg_write(hw_reg, tcr, mxc_fec_reg_read(hw_reg, tcr) | FEC_TCR_FDEN);
731         mxc_fec_reg_write(hw_reg, mibc, mxc_fec_reg_read(hw_reg, mibc) | FEC_MIB_DISABLE);
732
733         mxc_fec_reg_write(hw_reg, iaur, 0);
734         mxc_fec_reg_write(hw_reg, ialr, 0);
735         mxc_fec_reg_write(hw_reg, gaur, 0);
736         mxc_fec_reg_write(hw_reg, galr, 0);
737
738         ipg_clk = get_main_clock(IPG_CLK);
739         clkdiv = ((ipg_clk + 499999) / 2500000 / 2) << 1;
740 #if 1
741         mxc_fec_reg_write(hw_reg, mscr, (mxc_fec_reg_read(hw_reg, mscr) & ~0x7e) |
742                                         clkdiv);
743 #endif
744         if (net_debug) diag_printf("mscr set to %08lx(%08lx) for ipg_clk %ld\n",
745                                                         clkdiv, mxc_fec_reg_read(hw_reg, mscr), ipg_clk);
746
747         mxc_fec_reg_write(hw_reg, emrbr, 2048 - 16);
748         mxc_fec_reg_write(hw_reg, erdsr, hal_virt_to_phy((unsigned long)dev->rx_bd));
749         mxc_fec_reg_write(hw_reg, etdsr, hal_virt_to_phy((unsigned long)dev->tx_bd));
750
751         /* must be done before enabling the MII gasket
752          * (otherwise MIIGSK_ENR_READY will never assert)
753          */
754         mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) | FEC_ETHER_EN);
755 }
756
757 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show)
758 {
759 #ifdef CYGPKG_DEVS_ETH_PHY
760         if (value & ETH_PHY_STAT_LINK) {
761                 int changed = !(dev->status & FEC_STATUS_LINK_ON);
762
763                 dev->status |= FEC_STATUS_LINK_ON;
764                 if (value & ETH_PHY_STAT_FDX) {
765                         dev->status |= FEC_STATUS_FULL_DPLX;
766                 } else {
767                         dev->status &= ~FEC_STATUS_FULL_DPLX;
768                 }
769                 if (value & ETH_PHY_STAT_100MB) {
770                         changed |= !(dev->status & ETH_PHY_STAT_100MB);
771                         dev->status |= FEC_STATUS_100M;
772                 } else {
773                         changed |= !!(dev->status & ETH_PHY_STAT_100MB);
774                         dev->status &= ~FEC_STATUS_100M;
775                 }
776                 if (changed) {
777                         mxc_fec_mii_setup(dev);
778                 }
779         } else {
780                 dev->status &= ~FEC_STATUS_LINK_ON;
781         }
782 #else
783         int changed = 0;
784         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value);
785         if (value & PHY_STATUS_LINK_ST) {
786                 changed |= !(dev->status & FEC_STATUS_LINK_ON);
787                 dev->status |= FEC_STATUS_LINK_ON;
788         } else {
789                 changed |= dev->status & FEC_STATUS_LINK_ON;
790                 dev->status &= ~FEC_STATUS_LINK_ON;
791         }
792
793         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_DIAG_REG, &value);
794         if (value & PHY_DIAG_DPLX) {
795                 dev->status |= FEC_STATUS_FULL_DPLX;
796         } else {
797                 dev->status &= ~FEC_STATUS_FULL_DPLX;
798         }
799         if (value & PHY_DIAG_RATE) {
800                 changed |= !(dev->status & FEC_STATUS_100M);
801                 dev->status |= FEC_STATUS_100M;
802         } else {
803                 changed |= dev->status & FEC_STATUS_100M;
804                 dev->status &= ~FEC_STATUS_100M;
805         }
806         if (changed) {
807                 mxc_fec_mii_setup(dev);
808         }
809 #endif
810         if (!show) {
811                 return;
812         }
813         if (dev->status & FEC_STATUS_LINK_ON) {
814                 diag_printf("FEC: [ %s ] [ %s ]:\n",
815                                         (dev->status & FEC_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
816                                         (dev->status & FEC_STATUS_100M) ? "100 Mbps" : "10 Mbps");
817         } else {
818                 diag_printf("FEC: no cable\n");
819         }
820 }
821
822 #ifndef CYGPKG_DEVS_ETH_PHY
823 /*!
824  * This function initializes the PHY
825  */
826 static bool
827 mxc_fec_phy_init(mxc_fec_priv_t *dev)
828 {
829 #if 1
830         unsigned short value = 0;
831         unsigned long timeout = FEC_COMMON_TIMEOUT;
832
833         /*Reset PHY*/
834         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET);
835         while (timeout--) {
836                 if (mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
837                         return false;
838                 }
839
840                 if (!(value & PHY_CTRL_RESET)) {
841                         if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
842                         break;
843                 }
844                 hal_delay_us(FEC_MII_TICK);
845         }
846
847         if (value & PHY_CTRL_RESET) {
848                 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
849                 return false;
850         }
851
852         unsigned long id;
853         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
854         id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
855         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
856         id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
857         if (id == 0 || id == 0xffffffff) {
858                 diag_printf("FEC could not identify PHY: ID=%08lx\n", id);
859                 return false;
860         }
861
862         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
863                           PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
864
865         timeout = FEC_COMMON_TIMEOUT;
866         while (timeout-- &&
867                 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value) == 0) {
868                 if (value & PHY_STATUS_LINK_ST) {
869                         if (net_debug) diag_printf("PHY Status: %04x\n", value);
870                         break;
871                 }
872                 hal_delay_us(FEC_MII_TICK);
873         }
874         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, &value);
875         value &= ~PHY_LED_SEL;
876         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, value);
877 #else
878         unsigned long value = 0;
879         unsigned long id = 0, timeout = 50;
880
881         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
882         id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
883         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
884         id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
885
886         switch (id) {
887         case 0x00540088:
888                 break;
889         case 0x00007C0C:
890                 break;
891         default:
892                 diag_printf("[Warning] FEC not connect right PHY: ID=%lx\n", id);
893         }
894
895         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
896                                         PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
897
898 #ifdef CYGPKG_HAL_ARM_MX27ADS
899         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, &value);
900         value &= ~PHY_LED_SEL;
901         mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, value);
902 #endif
903
904 #if defined(CYGPKG_HAL_ARM_MX51) || defined(CYGPKG_HAL_ARM_MX25_3STACK) || \
905         defined(CYGPKG_HAL_ARM_MX35_3STACK) || defined(CYGPKG_HAL_ARM_MX27_3STACK)
906         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_EXP_REG, &value);
907         /* Wait for packet to arrive */
908         while (((value & PHY_AUTO_NEG_NEW_PAGE) == 0) && (timeout != 0)) {
909                 hal_delay_us(100);
910                 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_EXP_REG, &value);
911                 timeout--;
912         }
913         /* Check if link is capable of auto-negotiation */
914         if ((value & PHY_AUTO_NEG_CAP) == 1) {
915                 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_INT_SRC_REG, &value);
916                 timeout = 50;
917                 /* Wait for auto-negotiation to complete */
918                 while (((value & PHY_INT_AUTO_NEG) == 0) && (timeout != 0)) {
919                         hal_delay_us(100);
920                         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_INT_SRC_REG, &value);
921                         timeout--;
922                 }
923         }
924 #endif
925         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value);
926         if (value & PHY_STATUS_LINK_ST) {
927                 dev->status |= FEC_STATUS_LINK_ON;
928         } else {
929                 dev->status &= ~FEC_STATUS_LINK_ON;
930         }
931
932 #ifdef CYGPKG_HAL_ARM_MX27ADS
933         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_DIAG_REG, &value);
934         if (value & PHY_DIAG_DPLX) {
935                 dev->status |= FEC_STATUS_FULL_DPLX;
936         } else {
937                 dev->status &= ~FEC_STATUS_FULL_DPLX;
938         }
939         if (value & PHY_DIAG_DPLX) {
940                 dev->status |= FEC_STATUS_100M;
941         } else {
942                 dev->status &= ~FEC_STATUS_100M;
943         }
944 #endif
945
946 #if defined(CYGPKG_HAL_ARM_MX51) || defined(CYGPKG_HAL_ARM_MX25_3STACK) || \
947         defined(CYGPKG_HAL_ARM_MX35_3STACK)
948         mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_REG, &value);
949         if (value & PHY_AUTO_10BASET) {
950                 dev->status &= ~FEC_STATUS_100M;
951                 if (value & PHY_AUTO_10BASET_DPLX) {
952                         dev->status |= FEC_STATUS_FULL_DPLX;
953                 } else {
954                         dev->status &= ~FEC_STATUS_FULL_DPLX;
955                 }
956         }
957
958         if (value & PHY_AUTO_100BASET) {
959                 dev->status |= FEC_STATUS_100M;
960                 if (value & PHY_AUTO_100BASET_DPLX) {
961                         dev->status |= FEC_STATUS_FULL_DPLX;
962                 } else {
963                         dev->status &= ~FEC_STATUS_FULL_DPLX;
964                 }
965         }
966 #endif
967         diag_printf("FEC: [ %s ] [ %s ] [ %s ]:\n",
968                 (dev->status&FEC_STATUS_FULL_DPLX)?"FULL_DUPLEX":"HALF_DUPLEX",
969                 (dev->status&FEC_STATUS_LINK_ON)?"connected":"disconnected",
970                 (dev->status&FEC_STATUS_100M)?"100M bps":"10M bps");
971 #endif
972         return true;
973 }
974
975 static int mxc_fec_discover_phy(mxc_fec_priv_t *fep, unsigned char def_addr)
976 {
977         int ret = 0;
978         unsigned char phy_addr = def_addr;
979         unsigned long id = 0;
980         int i;
981
982         for (i = 0; i < 32; i++) {
983                 unsigned short mii_reg;
984
985                 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
986
987                 if (ret != 0) {
988                         break;
989                 }
990                 if (mii_reg != 0xffff && mii_reg != 0) {
991                         /* Got first part of ID, now get remainder.
992                         */
993                         id = mii_reg;
994                         ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR2, &mii_reg);
995                         if (ret != 0) {
996                                 break;
997                         }
998                         id = (id << 16) | mii_reg;
999                         if (net_debug) diag_printf("%s: discovered PHY %08lx at addr %x\n",
1000                                                    __FUNCTION__, id, phy_addr);
1001                         ret = phy_addr;
1002                         break;
1003                 } else {
1004                         phy_addr = (phy_addr + 1) % 32;
1005                         ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
1006                         if (ret != 0) {
1007                                 break;
1008                         }
1009                 }
1010         }
1011         if (id == 0) {
1012                 /* Disable MII */
1013                 fep->mxc_fec_reg_write(hw_reg, mscr, 0);
1014                 ret = -1;
1015         }
1016
1017         return ret;
1018 }
1019 #endif
1020
1021 /*
1022  * generic PHY support functions
1023  */
1024 void mxc_fec_phy_reset(void)
1025 {
1026         unsigned short value = 0;
1027         unsigned long timeout=FEC_COMMON_TIMEOUT;
1028         mxc_fec_priv_t *dev = &mxc_fec_private;
1029
1030         /* Reset PHY */
1031         if (net_debug) diag_printf("%s\n", __FUNCTION__);
1032
1033         _eth_phy_write(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, PHY_CTRL_RESET);
1034         while (timeout--) {
1035                 if (!_eth_phy_read(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, &value)) {
1036                         return;
1037                 }
1038
1039                 if (!(value & PHY_CTRL_RESET)) {
1040                         if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
1041                         break;
1042                 }
1043                 hal_delay_us(FEC_MII_TICK);
1044         }
1045
1046         if (value & PHY_CTRL_RESET) {
1047                 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
1048                 return;
1049         }
1050 }
1051
1052 void mxc_fec_phy_init(void)
1053 {
1054         if (net_debug) diag_printf("%s\n", __FUNCTION__);
1055 }
1056
1057 bool mxc_fec_phy_read(int reg, int unit, unsigned short *data)
1058 {
1059         int ret;
1060         if (net_debug) diag_printf("%s\n", __FUNCTION__);
1061         ret = mxc_fec_mii_read(mxc_fec_private.hw_reg, unit, reg, data);
1062         return ret == 0;
1063 }
1064
1065 void mxc_fec_phy_write(int reg, int unit, unsigned short data)
1066 {
1067         if (net_debug) diag_printf("%s\n", __FUNCTION__);
1068         mxc_fec_mii_write(mxc_fec_private.hw_reg, unit, reg, data);
1069 }
1070
1071 /*! This function initializes the FEC driver.
1072  * It is called by net_init in net module of RedBoot during RedBoot init
1073  */
1074 static bool
1075 mxc_fec_init(struct cyg_netdevtab_entry *tab)
1076 {
1077         struct eth_drv_sc *sc = tab ? tab->device_instance : NULL;
1078         mxc_fec_priv_t *private;
1079         unsigned char eth_add_local[ETHER_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1080         int ok = 0;
1081 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1082         cyg_bool set_esa;
1083 #endif
1084
1085         if (net_debug)  diag_printf("%s:\n", __FUNCTION__);
1086         if (sc == NULL) {
1087                 diag_printf("%s: no driver attached\n", __FUNCTION__);
1088                 return false;
1089         }
1090
1091         private = MXC_FEC_PRIVATE(sc);
1092         if (private == NULL) {
1093                 private = &mxc_fec_private;
1094         }
1095         if (private->provide_esa) {
1096                 ok = private->provide_esa(eth_add_local);
1097         }
1098 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1099         if (!ok) {
1100                 /* Get MAC address from fconfig */
1101                 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
1102                                                                                  "fec_esa", &set_esa, CONFIG_BOOL);
1103                 if (ok && set_esa) {
1104                         CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
1105                                                                                 "fec_esa_data", eth_add_local, CONFIG_ESA);
1106                 }
1107         }
1108 #endif
1109         if (!ok) {
1110                 diag_printf("No ESA provided via fuses or RedBoot config\n");
1111                 return false;
1112         }
1113
1114         private->hw_reg = (volatile void *)SOC_FEC_BASE;
1115         private->tx_busy = 0;
1116         private->status = 0;
1117
1118         mxc_fec_bd_init(private);
1119
1120         mxc_fec_chip_init(private);
1121 #ifdef CYGPKG_DEVS_ETH_PHY
1122         if (!_eth_phy_init(private->phy)) {
1123                 diag_printf("%s: Failed to initialize PHY\n", __FUNCTION__);
1124                 return false;
1125         }
1126         _eth_phy_state(private->phy);
1127 #else
1128         ok = mxc_fec_discover_phy(private, PHY_PORT_ADDR);
1129         if (ok < 0) {
1130                 diag_printf("%s: no PHY found\n", __FUNCTION__);
1131                 return false;
1132         }
1133         private->phy_addr = ok;
1134         mxc_fec_phy_init(private);
1135 #endif
1136         /* TODO:: initialize System Resource : irq, timer */
1137
1138         sc->funs->eth_drv->init(sc, eth_add_local);
1139         mxc_fec_phy_status(private, _eth_phy_state(private->phy), true);
1140
1141         return true;
1142 }
1143
1144 #ifndef CYGPKG_DEVS_ETH_PHY
1145 /*!
1146  * Global variable which defines the FEC driver,
1147  */
1148 ETH_DRV_SC(mxc_fec_sc,
1149                 &mxc_fec_private,       // Driver specific data
1150                 mxc_fec_name,
1151                 mxc_fec_start,
1152                 mxc_fec_stop,
1153                 mxc_fec_control,
1154                 mxc_fec_can_send,
1155                 mxc_fec_send,
1156                 mxc_fec_recv,
1157                 mxc_fec_deliver,         // "pseudoDSR" called from fast net thread
1158                 mxc_fec_poll,            // poll function, encapsulates ISR and DSR
1159                 mxc_fec_int_vector);
1160
1161 /*!
1162  * Global variable which defines the FEC device
1163  */
1164 NETDEVTAB_ENTRY(mxc_fec_netdev,
1165                                 mxc_fec_name,
1166                                 mxc_fec_init,
1167                                 &mxc_fec_sc);
1168
1169 #endif // CYGPKG_DEVS_ETH_PHY