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, FEC_RX_TX_ACTIVE);
363 mxc_fec_reg_write(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);
428 if (value & ETH_PHY_STAT_LINK) {
429 mxc_fec_phy_status(priv, value, true);
432 unsigned short value;
433 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
434 if (value & PHY_STATUS_LINK_ST) {
435 mxc_fec_phy_status(priv, 0, true);
440 return priv->status & FEC_STATUS_LINK_ON;
444 * This function transmits a frame.
447 mxc_fec_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total,
450 mxc_fec_priv_t *dev = sc ? sc->driver_private : NULL;
451 volatile mxc_fec_reg_t *hw_reg = dev ? dev->hw_reg : NULL;
455 if (dev == NULL || hw_reg == NULL) {
456 diag_printf("BUG[TX]: FEC driver not initialized\n");
459 if (total > (FEC_FRAME_LEN - 4)) total = FEC_FRAME_LEN - 4;
460 if (sg_list == NULL || total <= 14) {
461 if (sc->funs->eth_drv && sc->funs->eth_drv->tx_done) {
462 sc->funs->eth_drv->tx_done(sc, key, -1);
467 for (i = 0, off = 0, p = dev->tx_cur; i < sg_len; i++) {
470 if (p->status & BD_TX_ST_RDY) {
471 diag_printf("BUG[TX]: trying to resend already finished buffer\n");
474 if (sg_list[i].buf == 0) {
475 diag_printf("WARNING[TX]: sg_list->buf is NULL\n");
478 vaddr = hal_ioremap_nocache((unsigned long)p->data) + off;
479 memcpy((void *)vaddr, (void *)sg_list[i].buf, sg_list[i].len);
480 off += sg_list[i].len;
483 diag_printf("WARNING[TX]: packet size %d too small\n", off);
487 p->status &= ~BD_TX_ST_ABC;
488 p->status |= BD_TX_ST_LAST | BD_TX_ST_RDY | BD_TX_ST_TC;
489 if (p->status & BD_TX_ST_WRAP) {
497 mxc_fec_reg_write(hw_reg, tdar, FEC_RX_TX_ACTIVE);
501 * This function receives ready Frame in DB.
504 mxc_fec_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
506 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
510 if (sg_list == NULL || priv == NULL || sg_len <= 0) {
511 diag_printf("BUG[RX]: FEC driver not initialized\n");
515 /*TODO: I think if buf pointer is NULL, this function
516 * should not be called
518 if (sg_list->buf == 0) {
519 diag_printf("WARING[RX]: the sg_list is empty\n");
524 if (p->status & BD_RX_ST_EMPTY) {
525 diag_printf("BUG[RX]: empty buffer received; status=%04x\n", p->status);
529 if (!(p->status & BD_RX_ST_LAST)) {
530 diag_printf("BUG[RX]: status=%0xx\n", p->status);
533 vaddr = hal_ioremap_nocache((unsigned long)p->data);
534 /*TODO::D_CACHE invalidate this data buffer*/
535 memcpy((void *)sg_list->buf, (void *)vaddr, p->length - 4);
536 if (net_debug) dump_packet((void *)sg_list->buf, p->length - 4);
540 mxc_fec_deliver(struct eth_drv_sc *sc)
542 /*TODO::When redboot support thread ,
543 * the polling function will be called at here
548 /* This funtion just called by polling funtion */
550 mxc_fec_check_rx_bd(struct eth_drv_sc *sc)
552 mxc_fec_priv_t *priv = sc->driver_private;
554 volatile mxc_fec_reg_t *hw_reg = priv->hw_reg;
557 for (i = 0, p = priv->rx_cur; i < FEC_RX_FRAMES; i++) {
559 * TODO::D-CACHE invalidate this BD.
560 * In WRITE_BACK mode: this may destroy the next BD
561 * when the CACHE_LINE is written back.
563 if (p->status & BD_RX_ST_EMPTY) {
566 if (!(p->status & BD_RX_ST_LAST)) {
567 diag_printf("BUG[RX]: status=%04x, length=%x\n", p->status, p->length);
571 if (p->status & BD_RX_ST_ERRS) {
572 diag_printf("RX error: status=%08x errors=%08x\n", p->status,
573 p->status & BD_RX_ST_ERRS);
574 } else if (p->length > FEC_FRAME_LEN) {
575 diag_printf("RX error: packet size 0x%08x larger than max frame length: 0x%08x\n",
576 p->length, FEC_FRAME_LEN);
578 sc->funs->eth_drv->recv(sc, p->length - 4);
581 p->status = (p->status & BD_RX_ST_WRAP) | BD_RX_ST_EMPTY;
583 if (p->status & BD_RX_ST_WRAP) {
589 mxc_fec_reg_write(hw_reg, rdar, FEC_RX_TX_ACTIVE);
594 * This function checks the event of FEC controller
597 mxc_fec_poll(struct eth_drv_sc *sc)
599 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
600 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
603 static unsigned long last_poll;
604 int poll_intvl = (priv->status & FEC_STATUS_LINK_ON) ? 100 : 10;
606 if (priv == NULL || hw_reg == NULL) {
607 diag_printf("BUG[POLL]: FEC driver not initialized\n");
613 value = mxc_fec_reg_read(hw_reg, eir);
614 mxc_fec_reg_write(hw_reg, eir, value & ~FEC_EVENT_MII);
618 if (value & FEC_EVENT_TX_ERR) {
619 diag_printf("WARNING[POLL]: Transmit error\n");
620 sc->funs->eth_drv->tx_done(sc, priv->tx_key, -1);
623 if (value & FEC_EVENT_TX) {
625 sc->funs->eth_drv->tx_done(sc, priv->tx_key, 0);
629 if (value & FEC_EVENT_RX) {
631 mxc_fec_check_rx_bd(sc);
634 if (value & FEC_EVENT_HBERR) {
635 diag_printf("WARNGING[POLL]: Heartbeat error!\n");
638 if (value & FEC_EVENT_EBERR) {
639 diag_printf("WARNING[POLL]: Ethernet Bus Error!\n");
642 if (value & (FEC_EVENT_TX_ERR | FEC_EVENT_HBERR | FEC_EVENT_EBERR) ||
643 last_poll++ > poll_intvl) {
644 #ifdef CYGPKG_DEVS_ETH_PHY
645 unsigned short value;
646 value = _eth_phy_state(priv->phy);
647 if (!(value & ETH_PHY_STAT_LINK) ^
648 !(priv->status & FEC_STATUS_LINK_ON)) {
649 mxc_fec_phy_status(priv, value, true);
652 unsigned short value;
653 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
654 if (!(value & PHY_STATUS_LINK_ST) ^
655 !(priv->status & FEC_STATUS_LINK_ON)) {
656 mxc_fec_phy_status(priv, 0, true);
664 mxc_fec_int_vector(struct eth_drv_sc *sc)
667 * get FEC interrupt number
673 * The function initializes the description buffer for receiving or transmitting
676 mxc_fec_bd_init(mxc_fec_priv_t *dev)
681 p = dev->rx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_rx_bd));
682 for (i = 0; i < FEC_BD_RX_NUM; i++, p++) {
683 p->status = BD_RX_ST_EMPTY;
685 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_rx_buf[i]);
688 dev->rx_bd[i - 1].status |= BD_RX_ST_WRAP;
689 dev->rx_cur = dev->rx_bd;
691 p = dev->tx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_tx_bd));
692 for (i = 0; i < FEC_BD_TX_NUM; i++, p++) {
695 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_tx_buf[i]);
698 dev->tx_bd[i - 1].status |= BD_TX_ST_WRAP;
699 dev->tx_cur = dev->tx_bd;
701 /*TODO:: add the sync function for items*/
705 *This function initializes FEC controller.
708 mxc_fec_chip_init(mxc_fec_priv_t *dev)
710 volatile mxc_fec_reg_t *hw_reg = dev->hw_reg;
711 unsigned long ipg_clk;
712 unsigned long clkdiv;
714 mxc_fec_reg_write(hw_reg, ecr, FEC_RESET);
715 while (mxc_fec_reg_read(hw_reg, ecr) & FEC_RESET) {
716 hal_delay_us(FEC_COMMON_TICK);
719 mxc_fec_reg_write(hw_reg, eimr, 0);
720 mxc_fec_reg_write(hw_reg, eir, ~0);
722 mxc_fec_reg_write(hw_reg, rcr,
723 (mxc_fec_reg_read(hw_reg, rcr) & ~0x3F) |
724 FEC_RCR_FCE | FEC_RCR_MII_MODE);
726 mxc_fec_reg_write(hw_reg, tcr, mxc_fec_reg_read(hw_reg, tcr) | FEC_TCR_FDEN);
727 mxc_fec_reg_write(hw_reg, mibc, mxc_fec_reg_read(hw_reg, mibc) | FEC_MIB_DISABLE);
729 mxc_fec_reg_write(hw_reg, iaur, 0);
730 mxc_fec_reg_write(hw_reg, ialr, 0);
731 mxc_fec_reg_write(hw_reg, gaur, 0);
732 mxc_fec_reg_write(hw_reg, galr, 0);
734 ipg_clk = get_main_clock(IPG_CLK);
735 clkdiv = ((ipg_clk + 499999) / 2500000 / 2) << 1;
737 mxc_fec_reg_write(hw_reg, mscr, (mxc_fec_reg_read(hw_reg, mscr) & ~0x7e) |
740 if (net_debug) diag_printf("mscr set to %08lx(%08lx) for ipg_clk %ld\n",
741 clkdiv, mxc_fec_reg_read(hw_reg, mscr), ipg_clk);
743 mxc_fec_reg_write(hw_reg, emrbr, 2048 - 16);
744 mxc_fec_reg_write(hw_reg, erdsr, hal_virt_to_phy((unsigned long)dev->rx_bd));
745 mxc_fec_reg_write(hw_reg, etdsr, hal_virt_to_phy((unsigned long)dev->tx_bd));
747 /* must be done before enabling the MII gasket
748 * (otherwise MIIGSK_ENR_READY will never assert)
750 mxc_fec_reg_write(hw_reg, ecr, FEC_ETHER_EN);
753 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show)
756 #ifdef CYGPKG_DEVS_ETH_PHY
757 if (value & ETH_PHY_STAT_LINK) {
758 changed = !(dev->status & FEC_STATUS_LINK_ON);
759 dev->status |= FEC_STATUS_LINK_ON;
760 if (value & ETH_PHY_STAT_FDX) {
761 dev->status |= FEC_STATUS_FULL_DPLX;
763 dev->status &= ~FEC_STATUS_FULL_DPLX;
765 if (value & ETH_PHY_STAT_100MB) {
766 changed |= !(dev->status & ETH_PHY_STAT_100MB);
767 dev->status |= FEC_STATUS_100M;
769 changed |= !!(dev->status & ETH_PHY_STAT_100MB);
770 dev->status &= ~FEC_STATUS_100M;
773 changed = !!(dev->status & FEC_STATUS_LINK_ON);
774 dev->status &= ~FEC_STATUS_LINK_ON;
777 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value);
778 if (value & PHY_STATUS_LINK_ST) {
779 changed |= !(dev->status & FEC_STATUS_LINK_ON);
780 dev->status |= FEC_STATUS_LINK_ON;
782 changed |= dev->status & FEC_STATUS_LINK_ON;
783 dev->status &= ~FEC_STATUS_LINK_ON;
786 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_DIAG_REG, &value);
787 if (value & PHY_DIAG_DPLX) {
788 dev->status |= FEC_STATUS_FULL_DPLX;
790 dev->status &= ~FEC_STATUS_FULL_DPLX;
792 if (value & PHY_DIAG_RATE) {
793 changed |= !(dev->status & FEC_STATUS_100M);
794 dev->status |= FEC_STATUS_100M;
796 changed |= dev->status & FEC_STATUS_100M;
797 dev->status &= ~FEC_STATUS_100M;
801 if (dev->status & FEC_STATUS_FULL_DPLX) {
802 mxc_fec_reg_write(dev->hw_reg, tcr,
803 (mxc_fec_reg_read(dev->hw_reg, tcr) & ~FEC_TCR_HBC) |
805 mxc_fec_reg_write(dev->hw_reg, rcr,
806 (mxc_fec_reg_read(dev->hw_reg, rcr) & ~FEC_RCR_DRT) |
809 mxc_fec_reg_write(dev->hw_reg, tcr,
810 (mxc_fec_reg_read(dev->hw_reg, tcr) & ~FEC_TCR_FDEN) |
812 mxc_fec_reg_write(dev->hw_reg, rcr,
813 (mxc_fec_reg_read(dev->hw_reg, rcr) & ~FEC_RCR_FCE) |
816 mxc_fec_mii_setup(dev);
818 if (!show || !changed) {
821 if (dev->status & FEC_STATUS_LINK_ON) {
822 diag_printf("FEC: [ %s ] [ %s ]:\n",
823 (dev->status & FEC_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
824 (dev->status & FEC_STATUS_100M) ? "100 Mbps" : "10 Mbps");
826 diag_printf("FEC: no cable\n");
830 #ifndef CYGPKG_DEVS_ETH_PHY
832 * This function initializes the PHY
835 mxc_fec_phy_init(mxc_fec_priv_t *dev)
838 unsigned short value = 0;
839 unsigned long timeout = FEC_COMMON_TIMEOUT;
842 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET);
844 if (mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
848 if (!(value & PHY_CTRL_RESET)) {
849 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
852 hal_delay_us(FEC_MII_TICK);
855 if (value & PHY_CTRL_RESET) {
856 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
861 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
862 id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
863 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
864 id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
865 if (id == 0 || id == 0xffffffff) {
866 diag_printf("FEC could not identify PHY: ID=%08lx\n", id);
870 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
871 PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
873 timeout = FEC_COMMON_TIMEOUT;
875 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value) == 0) {
876 if (value & PHY_STATUS_LINK_ST) {
877 if (net_debug) diag_printf("PHY Status: %04x\n", value);
880 hal_delay_us(FEC_MII_TICK);
882 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, &value);
883 value &= ~PHY_LED_SEL;
884 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, value);
886 unsigned long value = 0;
887 unsigned long id = 0, timeout = 50;
889 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
890 id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
891 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
892 id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
900 diag_printf("[Warning] FEC not connect right PHY: ID=%lx\n", id);
903 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
904 PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
906 #ifdef CYGPKG_HAL_ARM_MX27ADS
907 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, &value);
908 value &= ~PHY_LED_SEL;
909 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, value);
912 #if defined(CYGPKG_HAL_ARM_MX51) || defined(CYGPKG_HAL_ARM_MX25_3STACK) || \
913 defined(CYGPKG_HAL_ARM_MX35_3STACK) || defined(CYGPKG_HAL_ARM_MX27_3STACK)
914 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_EXP_REG, &value);
915 /* Wait for packet to arrive */
916 while (((value & PHY_AUTO_NEG_NEW_PAGE) == 0) && (timeout != 0)) {
918 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_EXP_REG, &value);
921 /* Check if link is capable of auto-negotiation */
922 if ((value & PHY_AUTO_NEG_CAP) == 1) {
923 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_INT_SRC_REG, &value);
925 /* Wait for auto-negotiation to complete */
926 while (((value & PHY_INT_AUTO_NEG) == 0) && (timeout != 0)) {
928 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_INT_SRC_REG, &value);
933 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value);
934 if (value & PHY_STATUS_LINK_ST) {
935 dev->status |= FEC_STATUS_LINK_ON;
937 dev->status &= ~FEC_STATUS_LINK_ON;
940 #ifdef CYGPKG_HAL_ARM_MX27ADS
941 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_DIAG_REG, &value);
942 if (value & PHY_DIAG_DPLX) {
943 dev->status |= FEC_STATUS_FULL_DPLX;
945 dev->status &= ~FEC_STATUS_FULL_DPLX;
947 if (value & PHY_DIAG_DPLX) {
948 dev->status |= FEC_STATUS_100M;
950 dev->status &= ~FEC_STATUS_100M;
954 #if defined(CYGPKG_HAL_ARM_MX51) || defined(CYGPKG_HAL_ARM_MX25_3STACK) || \
955 defined(CYGPKG_HAL_ARM_MX35_3STACK)
956 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_REG, &value);
957 if (value & PHY_AUTO_10BASET) {
958 dev->status &= ~FEC_STATUS_100M;
959 if (value & PHY_AUTO_10BASET_DPLX) {
960 dev->status |= FEC_STATUS_FULL_DPLX;
962 dev->status &= ~FEC_STATUS_FULL_DPLX;
966 if (value & PHY_AUTO_100BASET) {
967 dev->status |= FEC_STATUS_100M;
968 if (value & PHY_AUTO_100BASET_DPLX) {
969 dev->status |= FEC_STATUS_FULL_DPLX;
971 dev->status &= ~FEC_STATUS_FULL_DPLX;
975 diag_printf("FEC: [ %s ] [ %s ] [ %s ]:\n",
976 (dev->status & FEC_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
977 (dev->status & FEC_STATUS_LINK_ON) ? "connected" : "disconnected",
978 (dev->status & FEC_STATUS_100M) ? "100M bps" : "10M bps");
983 static int mxc_fec_discover_phy(mxc_fec_priv_t *fep, unsigned char def_addr)
986 unsigned char phy_addr = def_addr;
987 unsigned long id = 0;
990 for (i = 0; i < 32; i++) {
991 unsigned short mii_reg;
993 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
998 if (mii_reg != 0xffff && mii_reg != 0) {
999 /* Got first part of ID, now get remainder.
1002 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR2, &mii_reg);
1006 id = (id << 16) | mii_reg;
1007 if (net_debug) diag_printf("%s: discovered PHY %08lx at addr %x\n",
1008 __FUNCTION__, id, phy_addr);
1012 phy_addr = (phy_addr + 1) % 32;
1013 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
1021 fep->mxc_fec_reg_write(hw_reg, mscr, 0);
1030 * generic PHY support functions
1032 void mxc_fec_phy_reset(void)
1034 unsigned short value = 0;
1035 unsigned long timeout=FEC_COMMON_TIMEOUT;
1036 mxc_fec_priv_t *dev = &mxc_fec_private;
1039 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1041 _eth_phy_write(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, PHY_CTRL_RESET);
1043 if (!_eth_phy_read(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, &value)) {
1047 if (!(value & PHY_CTRL_RESET)) {
1048 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
1051 hal_delay_us(FEC_MII_TICK);
1054 if (value & PHY_CTRL_RESET) {
1055 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
1060 void mxc_fec_phy_init(void)
1062 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1065 bool mxc_fec_phy_read(int reg, int unit, unsigned short *data)
1068 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1069 ret = mxc_fec_mii_read(mxc_fec_private.hw_reg, unit, reg, data);
1073 void mxc_fec_phy_write(int reg, int unit, unsigned short data)
1075 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1076 mxc_fec_mii_write(mxc_fec_private.hw_reg, unit, reg, data);
1079 /*! This function initializes the FEC driver.
1080 * It is called by net_init in net module of RedBoot during RedBoot init
1083 mxc_fec_init(struct cyg_netdevtab_entry *tab)
1085 struct eth_drv_sc *sc = tab ? tab->device_instance : NULL;
1086 mxc_fec_priv_t *private;
1087 unsigned char eth_add_local[ETHER_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1089 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1093 if (net_debug) diag_printf("%s:\n", __FUNCTION__);
1095 diag_printf("%s: no driver attached\n", __FUNCTION__);
1099 private = MXC_FEC_PRIVATE(sc);
1100 if (private == NULL) {
1101 private = &mxc_fec_private;
1103 if (private->provide_esa) {
1104 ok = private->provide_esa(eth_add_local);
1106 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1108 /* Get MAC address from fconfig */
1109 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
1110 "fec_esa", &set_esa, CONFIG_BOOL);
1111 if (ok && set_esa) {
1112 CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
1113 "fec_esa_data", eth_add_local, CONFIG_ESA);
1118 diag_printf("No ESA provided via fuses or RedBoot config\n");
1122 private->hw_reg = (volatile void *)SOC_FEC_BASE;
1123 private->tx_busy = 0;
1124 private->status = 0;
1126 mxc_fec_bd_init(private);
1128 mxc_fec_chip_init(private);
1129 #ifdef CYGPKG_DEVS_ETH_PHY
1130 if (!_eth_phy_init(private->phy)) {
1131 diag_printf("%s: Failed to initialize PHY\n", __FUNCTION__);
1134 _eth_phy_state(private->phy);
1136 ok = mxc_fec_discover_phy(private, PHY_PORT_ADDR);
1138 diag_printf("%s: no PHY found\n", __FUNCTION__);
1141 private->phy_addr = ok;
1142 mxc_fec_phy_init(private);
1144 /* TODO:: initialize System Resource : irq, timer */
1146 sc->funs->eth_drv->init(sc, eth_add_local);
1147 mxc_fec_phy_status(private, _eth_phy_state(private->phy), true);
1152 #ifndef CYGPKG_DEVS_ETH_PHY
1154 * Global variable which defines the FEC driver,
1156 ETH_DRV_SC(mxc_fec_sc,
1157 &mxc_fec_private, // Driver specific data
1165 mxc_fec_deliver, // "pseudoDSR" called from fast net thread
1166 mxc_fec_poll, // poll function, encapsulates ISR and DSR
1167 mxc_fec_int_vector);
1170 * Global variable which defines the FEC device
1172 NETDEVTAB_ENTRY(mxc_fec_netdev,
1177 #endif // CYGPKG_DEVS_ETH_PHY