1 //==========================================================================
5 // Device driver for FEC
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.
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.
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
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.
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.
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.
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####
42 // -------------------------------------------
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.
47 // -------------------------------------------
49 //####BSDCOPYRIGHTEND####
50 //==========================================================================
51 //#####DESCRIPTIONBEGIN####
53 // Author(s): Fred Fan
57 // Description: Driver for FEC ethernet controller
61 //####DESCRIPTIONEND####
63 //==========================================================================
65 #include <pkgconf/system.h>
67 #include <cyg/kernel/kapi.h>
69 #include <pkgconf/io_eth_drivers.h>
70 #include <pkgconf/devs_eth_fec.h>
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>
82 #include <cyg/io/eth/eth_drv.h>
83 #include <cyg/io/eth/netdev.h>
85 static bool mxc_fec_init(struct cyg_netdevtab_entry *tab);
87 #include <cyg/io/fec.h>
89 #include CYGDAT_DEVS_ETH_FEC_INL
94 #include <cyg/hal/plf_mmap.h>
95 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
96 #include <flash_config.h>
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 */
105 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show);
107 #ifndef CYGPKG_DEVS_ETH_PHY
109 * Global variable which contains the name of FEC driver and device.
111 static char mxc_fec_name[] = "mxc_fec";
114 * Global variable which defines the private structure of FEC device.
116 static mxc_fec_priv_t mxc_fec_private;
120 * Global variable which defines the buffer descriptors for receive frames
121 * comment:: it must aligned by 128-bits.
123 static mxc_fec_bd_t mxc_fec_rx_bd[FEC_BD_RX_NUM] __attribute__ ((aligned(32)));
126 * Global variable which defines the buffer descriptors for transmit frames
127 * comment:: it must aligned by 128-bits.
129 static mxc_fec_bd_t mxc_fec_tx_bd[FEC_BD_TX_NUM] __attribute__ ((aligned(32)));
132 * Global variable which contains the frame buffers
134 static unsigned char mxc_fec_rx_buf[FEC_BD_RX_NUM][2048] __attribute__ ((aligned(32)));
137 * Global variable which contains the frame buffers
139 static unsigned char mxc_fec_tx_buf[FEC_BD_TX_NUM][2048] __attribute__ ((aligned(32)));
142 static void dump_packet(const unsigned char *pkt, size_t len)
146 diag_printf("Packet dump: %u byte", len);
147 for (i = 0; i < len; i++) {
149 diag_printf("\n%04x:", i);
158 diag_printf(" %02x", pkt[i]);
165 static inline volatile void *fec_reg_addr(volatile void *base, unsigned int reg)
167 return (volatile void *)((unsigned long)base + reg);
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,
174 unsigned long val = readl(fec_reg_addr(base, reg));
176 if (net_debug) diag_printf("Read %08lx from FEC reg %s[%03x]\n",
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)
185 if (net_debug) diag_printf("Writing %08lx to FEC reg %s[%03x]\n",
187 writel(val, fec_reg_addr(base, reg));
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,
194 unsigned short val = readw(fec_reg_addr(base, reg));
196 if (net_debug) diag_printf("Read %04x from FEC reg %s[%03x]\n",
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)
205 if (net_debug) diag_printf("Writing %04x to FEC reg %s[%03x]\n",
207 writew(val, fec_reg_addr(base, reg));
211 * This function gets the value of PHY registers via MII interface
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)
217 unsigned long waiting = FEC_MII_TIMEOUT;
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);
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 */
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);
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));
240 hal_delay_us(FEC_MII_TICK);
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);
249 * This function set the value of PHY registers by MII interface
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)
255 unsigned long waiting = FEC_MII_TIMEOUT;
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);
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));
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);
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));
280 hal_delay_us(FEC_MII_TICK);
282 if (net_debug) diag_printf("%s: Write to phy register succeeded\n", __FUNCTION__);
287 mxc_fec_set_mac_address(volatile mxc_fec_reg_t *hw_reg, unsigned char *enaddr)
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);
298 value = (value << 8) + enaddr[5];
299 mxc_fec_reg_write(hw_reg, paur, value << 16);
302 #ifdef CYGOPT_HAL_ARM_MXC_FEC_MIIGSK
303 static int mxc_fec_mii_setup(mxc_fec_priv_t *priv)
305 volatile mxc_fec_reg_t *hw_reg = priv->hw_reg;
307 * setup the MII gasket for RMII mode
310 /* disable the gasket */
311 mxc_fec_reg_write16(hw_reg, miigsk_enr, 0);
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);
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));
322 /* re-enable the gasket */
323 mxc_fec_reg_write16(hw_reg, miigsk_enr, MIIGSK_ENR_EN);
325 /* wait until MII gasket is ready */
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");
336 static inline int mxc_fec_mii_setup(mxc_fec_priv_t *priv)
343 * This function enables the FEC for reception of packets
346 mxc_fec_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
348 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
349 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
351 if (!(priv && hw_reg)) {
352 diag_printf("BUG[start]: FEC driver not initialized\n");
355 if (enaddr == NULL) {
356 diag_printf("BUG[start]: no MAC address supplied\n");
359 mxc_fec_set_mac_address(hw_reg, enaddr);
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);
367 * This function pauses the FEC controller.
370 mxc_fec_stop(struct eth_drv_sc *sc)
372 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
373 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
375 if (!(priv && hw_reg)) {
376 diag_printf("BUG[stop]: FEC driver not initialized\n");
379 mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) & ~FEC_ETHER_EN);
383 mxc_fec_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length)
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);
392 * This function checks the status of FEC control.
395 mxc_fec_can_send(struct eth_drv_sc *sc)
397 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
398 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
400 if (!(priv && hw_reg)) {
401 diag_printf("BUG[can_send]: FEC driver not initialized\n");
405 diag_printf("WARNING[can_send]: MXC_FEC is busy for transmission\n");
409 if (!(mxc_fec_reg_read(hw_reg, ecr) & FEC_ETHER_EN)) {
410 diag_printf("WARNING[can_send]: MXC_FEC is not enabled\n");
414 if (mxc_fec_reg_read(hw_reg, tcr) & FEC_TCR_RFC_PAUSE) {
415 diag_printf("WARNING[can_send]: MXC_FEC is paused\n");
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
425 #ifdef CYGPKG_DEVS_ETH_PHY
426 unsigned short value;
427 value = _eth_phy_state(priv->phy);
429 unsigned short value;
430 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
432 if (value & PHY_STATUS_LINK_ST) {
433 if (!(priv->status & FEC_STATUS_LINK_ON)) {
434 mxc_fec_phy_status(priv, value, true);
437 if (priv->status & FEC_STATUS_LINK_ON) {
438 mxc_fec_phy_status(priv, value, true);
443 return priv->status & FEC_STATUS_LINK_ON;
447 * This function transmits a frame.
450 mxc_fec_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total,
453 mxc_fec_priv_t *dev = sc ? sc->driver_private : NULL;
454 volatile mxc_fec_reg_t *hw_reg = dev ? dev->hw_reg : NULL;
458 if (dev == NULL || hw_reg == NULL) {
459 diag_printf("BUG[TX]: FEC driver not initialized\n");
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);
470 for (i = 0, off = 0, p = dev->tx_cur; i < sg_len; i++) {
473 if (p->status & BD_TX_ST_RDY) {
474 diag_printf("BUG[TX]: trying to resend already finished buffer\n");
477 if (sg_list[i].buf == 0) {
478 diag_printf("WARNING[TX]: sg_list->buf is NULL\n");
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;
486 diag_printf("WARNING[TX]: packet size %d too small\n", 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) {
500 mxc_fec_reg_write(hw_reg, tdar, FEC_RX_TX_ACTIVE);
504 * This function receives ready Frame in DB.
507 mxc_fec_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
509 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
513 if (sg_list == NULL || priv == NULL || sg_len <= 0) {
514 diag_printf("BUG[RX]: FEC driver not initialized\n");
518 /*TODO: I think if buf pointer is NULL, this function
519 * should not be called
521 if (sg_list->buf == 0) {
522 diag_printf("WARING[RX]: the sg_list is empty\n");
527 if (p->status & BD_RX_ST_EMPTY) {
528 diag_printf("BUG[RX]: empty buffer received; status=%04x\n", p->status);
532 if (!(p->status & BD_RX_ST_LAST)) {
533 diag_printf("BUG[RX]: status=%0xx\n", p->status);
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);
543 mxc_fec_deliver(struct eth_drv_sc *sc)
545 /*TODO::When redboot support thread ,
546 * the polling function will be called at here
551 /* This funtion just called by polling funtion */
553 mxc_fec_check_rx_bd(struct eth_drv_sc *sc)
555 mxc_fec_priv_t *priv = sc->driver_private;
557 volatile mxc_fec_reg_t *hw_reg = priv->hw_reg;
560 for (i = 0, p = priv->rx_cur; i < FEC_RX_FRAMES; i++) {
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.
566 if (p->status & BD_RX_ST_EMPTY) {
569 if (!(p->status & BD_RX_ST_LAST)) {
570 diag_printf("BUG[RX]: status=%04x, length=%x\n", p->status, p->length);
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);
581 sc->funs->eth_drv->recv(sc, p->length - 4);
584 p->status = (p->status & BD_RX_ST_WRAP) | BD_RX_ST_EMPTY;
586 if (p->status & BD_RX_ST_WRAP) {
592 mxc_fec_reg_write(hw_reg, rdar, mxc_fec_reg_read(hw_reg, rdar) | FEC_RX_TX_ACTIVE);
597 * This function checks the event of FEC controller
600 mxc_fec_poll(struct eth_drv_sc *sc)
602 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
603 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
606 static unsigned long last_poll;
607 int poll_intvl = (priv->status & FEC_STATUS_LINK_ON) ? 100 : 10;
609 if (priv == NULL || hw_reg == NULL) {
610 diag_printf("BUG[POLL]: FEC driver not initialized\n");
616 value = mxc_fec_reg_read(hw_reg, eir);
617 mxc_fec_reg_write(hw_reg, eir, value & ~FEC_EVENT_MII);
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);
626 if (value & FEC_EVENT_TX) {
628 sc->funs->eth_drv->tx_done(sc, priv->tx_key, 0);
632 if (value & FEC_EVENT_RX) {
634 mxc_fec_check_rx_bd(sc);
637 if (value & FEC_EVENT_HBERR) {
638 diag_printf("WARNGING[POLL]: Heartbeat error!\n");
641 if (value & FEC_EVENT_EBERR) {
642 diag_printf("WARNING[POLL]: Ethernet Bus Error!\n");
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);
651 unsigned short value;
652 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
655 if (value & PHY_STATUS_LINK_ST) {
656 if (!(priv->status & FEC_STATUS_LINK_ON)) {
657 mxc_fec_phy_status(priv, value, true);
660 if (priv->status & FEC_STATUS_LINK_ON) {
661 mxc_fec_phy_status(priv, value, true);
668 mxc_fec_int_vector(struct eth_drv_sc *sc)
671 * get FEC interrupt number
677 * The function initializes the description buffer for receiving or transmitting
680 mxc_fec_bd_init(mxc_fec_priv_t *dev)
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;
689 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_rx_buf[i]);
692 dev->rx_bd[i - 1].status |= BD_RX_ST_WRAP;
693 dev->rx_cur = dev->rx_bd;
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++) {
699 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_tx_buf[i]);
702 dev->tx_bd[i - 1].status |= BD_TX_ST_WRAP;
703 dev->tx_cur = dev->tx_bd;
705 /*TODO:: add the sync function for items*/
709 *This function initializes FEC controller.
712 mxc_fec_chip_init(mxc_fec_priv_t *dev)
714 volatile mxc_fec_reg_t *hw_reg = dev->hw_reg;
715 unsigned long ipg_clk;
716 unsigned long clkdiv;
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);
723 mxc_fec_reg_write(hw_reg, eimr, 0);
724 mxc_fec_reg_write(hw_reg, eir, ~0);
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);
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);
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);
738 ipg_clk = get_main_clock(IPG_CLK);
739 clkdiv = ((ipg_clk + 499999) / 2500000 / 2) << 1;
741 mxc_fec_reg_write(hw_reg, mscr, (mxc_fec_reg_read(hw_reg, mscr) & ~0x7e) |
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);
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));
751 /* must be done before enabling the MII gasket
752 * (otherwise MIIGSK_ENR_READY will never assert)
754 mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) | FEC_ETHER_EN);
757 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show)
759 #ifdef CYGPKG_DEVS_ETH_PHY
760 if (value & ETH_PHY_STAT_LINK) {
761 int changed = !(dev->status & FEC_STATUS_LINK_ON);
763 dev->status |= FEC_STATUS_LINK_ON;
764 if (value & ETH_PHY_STAT_FDX) {
765 dev->status |= FEC_STATUS_FULL_DPLX;
767 dev->status &= ~FEC_STATUS_FULL_DPLX;
769 if (value & ETH_PHY_STAT_100MB) {
770 changed |= !(dev->status & ETH_PHY_STAT_100MB);
771 dev->status |= FEC_STATUS_100M;
773 changed |= !!(dev->status & ETH_PHY_STAT_100MB);
774 dev->status &= ~FEC_STATUS_100M;
777 mxc_fec_mii_setup(dev);
780 dev->status &= ~FEC_STATUS_LINK_ON;
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;
789 changed |= dev->status & FEC_STATUS_LINK_ON;
790 dev->status &= ~FEC_STATUS_LINK_ON;
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;
797 dev->status &= ~FEC_STATUS_FULL_DPLX;
799 if (value & PHY_DIAG_RATE) {
800 changed |= !(dev->status & FEC_STATUS_100M);
801 dev->status |= FEC_STATUS_100M;
803 changed |= dev->status & FEC_STATUS_100M;
804 dev->status &= ~FEC_STATUS_100M;
807 mxc_fec_mii_setup(dev);
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");
818 diag_printf("FEC: no cable\n");
822 #ifndef CYGPKG_DEVS_ETH_PHY
824 * This function initializes the PHY
827 mxc_fec_phy_init(mxc_fec_priv_t *dev)
830 unsigned short value = 0;
831 unsigned long timeout = FEC_COMMON_TIMEOUT;
834 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET);
836 if (mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
840 if (!(value & PHY_CTRL_RESET)) {
841 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
844 hal_delay_us(FEC_MII_TICK);
847 if (value & PHY_CTRL_RESET) {
848 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
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);
862 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
863 PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
865 timeout = FEC_COMMON_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);
872 hal_delay_us(FEC_MII_TICK);
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);
878 unsigned long value = 0;
879 unsigned long id = 0, timeout = 50;
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;
892 diag_printf("[Warning] FEC not connect right PHY: ID=%lx\n", id);
895 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
896 PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
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);
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)) {
910 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_EXP_REG, &value);
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);
917 /* Wait for auto-negotiation to complete */
918 while (((value & PHY_INT_AUTO_NEG) == 0) && (timeout != 0)) {
920 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_INT_SRC_REG, &value);
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;
929 dev->status &= ~FEC_STATUS_LINK_ON;
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;
937 dev->status &= ~FEC_STATUS_FULL_DPLX;
939 if (value & PHY_DIAG_DPLX) {
940 dev->status |= FEC_STATUS_100M;
942 dev->status &= ~FEC_STATUS_100M;
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;
954 dev->status &= ~FEC_STATUS_FULL_DPLX;
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;
963 dev->status &= ~FEC_STATUS_FULL_DPLX;
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");
975 static int mxc_fec_discover_phy(mxc_fec_priv_t *fep, unsigned char def_addr)
978 unsigned char phy_addr = def_addr;
979 unsigned long id = 0;
982 for (i = 0; i < 32; i++) {
983 unsigned short mii_reg;
985 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
990 if (mii_reg != 0xffff && mii_reg != 0) {
991 /* Got first part of ID, now get remainder.
994 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR2, &mii_reg);
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);
1004 phy_addr = (phy_addr + 1) % 32;
1005 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
1013 fep->mxc_fec_reg_write(hw_reg, mscr, 0);
1022 * generic PHY support functions
1024 void mxc_fec_phy_reset(void)
1026 unsigned short value = 0;
1027 unsigned long timeout=FEC_COMMON_TIMEOUT;
1028 mxc_fec_priv_t *dev = &mxc_fec_private;
1031 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1033 _eth_phy_write(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, PHY_CTRL_RESET);
1035 if (!_eth_phy_read(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, &value)) {
1039 if (!(value & PHY_CTRL_RESET)) {
1040 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
1043 hal_delay_us(FEC_MII_TICK);
1046 if (value & PHY_CTRL_RESET) {
1047 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
1052 void mxc_fec_phy_init(void)
1054 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1057 bool mxc_fec_phy_read(int reg, int unit, unsigned short *data)
1060 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1061 ret = mxc_fec_mii_read(mxc_fec_private.hw_reg, unit, reg, data);
1065 void mxc_fec_phy_write(int reg, int unit, unsigned short data)
1067 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1068 mxc_fec_mii_write(mxc_fec_private.hw_reg, unit, reg, data);
1071 /*! This function initializes the FEC driver.
1072 * It is called by net_init in net module of RedBoot during RedBoot init
1075 mxc_fec_init(struct cyg_netdevtab_entry *tab)
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};
1081 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1085 if (net_debug) diag_printf("%s:\n", __FUNCTION__);
1087 diag_printf("%s: no driver attached\n", __FUNCTION__);
1091 private = MXC_FEC_PRIVATE(sc);
1092 if (private == NULL) {
1093 private = &mxc_fec_private;
1095 if (private->provide_esa) {
1096 ok = private->provide_esa(eth_add_local);
1098 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
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);
1110 diag_printf("No ESA provided via fuses or RedBoot config\n");
1114 private->hw_reg = (volatile void *)SOC_FEC_BASE;
1115 private->tx_busy = 0;
1116 private->status = 0;
1118 mxc_fec_bd_init(private);
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__);
1126 _eth_phy_state(private->phy);
1128 ok = mxc_fec_discover_phy(private, PHY_PORT_ADDR);
1130 diag_printf("%s: no PHY found\n", __FUNCTION__);
1133 private->phy_addr = ok;
1134 mxc_fec_phy_init(private);
1136 /* TODO:: initialize System Resource : irq, timer */
1138 sc->funs->eth_drv->init(sc, eth_add_local);
1139 mxc_fec_phy_status(private, _eth_phy_state(private->phy), true);
1144 #ifndef CYGPKG_DEVS_ETH_PHY
1146 * Global variable which defines the FEC driver,
1148 ETH_DRV_SC(mxc_fec_sc,
1149 &mxc_fec_private, // Driver specific data
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);
1162 * Global variable which defines the FEC device
1164 NETDEVTAB_ENTRY(mxc_fec_netdev,
1169 #endif // CYGPKG_DEVS_ETH_PHY