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