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);
303 * This function enables the FEC for reception of packets
306 mxc_fec_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
308 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
309 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
311 if (!(priv && hw_reg)) {
312 diag_printf("BUG[start]: FEC driver not initialized\n");
315 if (enaddr == NULL) {
316 diag_printf("BUG[start]: no MAC address supplied\n");
319 mxc_fec_set_mac_address(hw_reg, enaddr);
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
326 * setup the MII gasket for RMII mode
329 /* disable the gasket */
330 mxc_fec_reg_write16(hw_reg, miigsk_enr, 0);
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);
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);
339 /* re-enable the gasket */
340 mxc_fec_reg_write16(hw_reg, miigsk_enr, MIIGSK_ENR_EN);
342 /* wait until MII gasket is ready */
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");
354 * This function pauses the FEC controller.
357 mxc_fec_stop(struct eth_drv_sc *sc)
359 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
360 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
362 if (!(priv && hw_reg)) {
363 diag_printf("BUG[stop]: FEC driver not initialized\n");
366 mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) & ~FEC_ETHER_EN);
370 mxc_fec_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length)
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);
379 * This function checks the status of FEC control.
382 mxc_fec_can_send(struct eth_drv_sc *sc)
384 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
385 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
387 if (!(priv && hw_reg)) {
388 diag_printf("BUG[can_send]: FEC driver not initialized\n");
392 diag_printf("WARNING[can_send]: MXC_FEC is busy for transmission\n");
396 if (!(mxc_fec_reg_read(hw_reg, ecr) & FEC_ETHER_EN)) {
397 diag_printf("WARNING[can_send]: MXC_FEC is not enabled\n");
401 if (mxc_fec_reg_read(hw_reg, tcr) & FEC_TCR_RFC_PAUSE) {
402 diag_printf("WARNING[can_send]: MXC_FEC is paused\n");
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
412 #ifdef CYGPKG_DEVS_ETH_PHY
413 unsigned short value;
414 value = _eth_phy_state(priv->phy);
416 unsigned short value;
417 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
419 if (value & PHY_STATUS_LINK_ST) {
420 if (!(priv->status & FEC_STATUS_LINK_ON)) {
421 mxc_fec_phy_status(priv, value, true);
424 if (priv->status & FEC_STATUS_LINK_ON) {
425 mxc_fec_phy_status(priv, value, true);
430 return priv->status & FEC_STATUS_LINK_ON;
434 * This function transmits a frame.
437 mxc_fec_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total,
440 mxc_fec_priv_t *dev = sc ? sc->driver_private : NULL;
441 volatile mxc_fec_reg_t *hw_reg = dev ? dev->hw_reg : NULL;
445 if (dev == NULL || hw_reg == NULL) {
446 diag_printf("BUG[TX]: FEC driver not initialized\n");
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);
457 for (i = 0, off = 0, p = dev->tx_cur; i < sg_len; i++) {
460 if (p->status & BD_TX_ST_RDY) {
461 diag_printf("BUG[TX]: trying to resend already finished buffer\n");
464 if (sg_list[i].buf == 0) {
465 diag_printf("WARNING[TX]: sg_list->buf is NULL\n");
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;
473 diag_printf("WARNING[TX]: packet size %d too small\n", 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) {
487 mxc_fec_reg_write(hw_reg, tdar, FEC_RX_TX_ACTIVE);
491 * This function receives ready Frame in DB.
494 mxc_fec_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
496 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
500 if (sg_list == NULL || priv == NULL || sg_len <= 0) {
501 diag_printf("BUG[RX]: FEC driver not initialized\n");
505 /*TODO: I think if buf pointer is NULL, this function
506 * should not be called
508 if (sg_list->buf == 0) {
509 diag_printf("WARING[RX]: the sg_list is empty\n");
514 if (p->status & BD_RX_ST_EMPTY) {
515 diag_printf("BUG[RX]: empty buffer received; status=%04x\n", p->status);
519 if (!(p->status & BD_RX_ST_LAST)) {
520 diag_printf("BUG[RX]: status=%0xx\n", p->status);
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);
530 mxc_fec_deliver(struct eth_drv_sc *sc)
532 /*TODO::When redboot support thread ,
533 * the polling function will be called at here
538 /* This funtion just called by polling funtion */
540 mxc_fec_check_rx_bd(struct eth_drv_sc *sc)
542 mxc_fec_priv_t *priv = sc->driver_private;
544 volatile mxc_fec_reg_t *hw_reg = priv->hw_reg;
547 for (i = 0, p = priv->rx_cur; i < FEC_RX_FRAMES; i++) {
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.
553 if (p->status & BD_RX_ST_EMPTY) {
556 if (!(p->status & BD_RX_ST_LAST)) {
557 diag_printf("BUG[RX]: status=%04x, length=%x\n", p->status, p->length);
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);
568 sc->funs->eth_drv->recv(sc, p->length - 4);
571 p->status = (p->status & BD_RX_ST_WRAP) | BD_RX_ST_EMPTY;
573 if (p->status & BD_RX_ST_WRAP) {
579 mxc_fec_reg_write(hw_reg, rdar, mxc_fec_reg_read(hw_reg, rdar) | FEC_RX_TX_ACTIVE);
584 * This function checks the event of FEC controller
587 mxc_fec_poll(struct eth_drv_sc *sc)
589 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
590 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
594 if (priv == NULL || hw_reg == NULL) {
595 diag_printf("BUG[POLL]: FEC driver not initialized\n");
601 value = mxc_fec_reg_read(hw_reg, eir);
602 mxc_fec_reg_write(hw_reg, eir, value & ~FEC_EVENT_MII);
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);
611 if (value & FEC_EVENT_TX) {
612 sc->funs->eth_drv->tx_done(sc, priv->tx_key, 0);
617 if (value & FEC_EVENT_RX) {
618 mxc_fec_check_rx_bd(sc);
621 if (value & FEC_EVENT_HBERR) {
622 diag_printf("WARNGING[POLL]: Hearbeat error!\n");
625 if (value & FEC_EVENT_EBERR) {
626 diag_printf("WARNING[POLL]: Ethernet Bus Error!\n");
631 mxc_fec_int_vector(struct eth_drv_sc *sc)
634 * get FEC interrupt number
640 * The function initializes the description buffer for receiving or transmitting
643 mxc_fec_bd_init(mxc_fec_priv_t *dev)
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;
652 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_rx_buf[i]);
655 dev->rx_bd[i - 1].status |= BD_RX_ST_WRAP;
656 dev->rx_cur = dev->rx_bd;
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++) {
662 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_tx_buf[i]);
665 dev->tx_bd[i - 1].status |= BD_TX_ST_WRAP;
666 dev->tx_cur = dev->tx_bd;
668 /*TODO:: add the sync function for items*/
672 *This function initializes FEC controller.
675 mxc_fec_chip_init(mxc_fec_priv_t *dev)
677 volatile mxc_fec_reg_t *hw_reg = dev->hw_reg;
678 unsigned long ipg_clk;
679 unsigned long clkdiv;
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);
686 mxc_fec_reg_write(hw_reg, eimr, 0);
687 mxc_fec_reg_write(hw_reg, eir, ~0);
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);
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);
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);
701 ipg_clk = get_main_clock(IPG_CLK);
702 clkdiv = ((ipg_clk + 499999) / 2500000 / 2) << 1;
704 mxc_fec_reg_write(hw_reg, mscr, (mxc_fec_reg_read(hw_reg, mscr) & ~0x7e) |
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);
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));
714 /* must be done before enabling the MII gasket
715 * (otherwise MIIGSK_ENR_READY will never assert)
717 mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) | FEC_ETHER_EN);
720 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show)
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;
728 dev->status &= ~FEC_STATUS_FULL_DPLX;
730 if (value & ETH_PHY_STAT_100MB) {
731 dev->status |= FEC_STATUS_100M;
733 dev->status &= ~FEC_STATUS_100M;
736 dev->status &= ~FEC_STATUS_LINK_ON;
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;
743 dev->status &= ~FEC_STATUS_LINK_ON;
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;
750 dev->status &= ~FEC_STATUS_FULL_DPLX;
752 if (value & PHY_DIAG_RATE) {
753 dev->status |= FEC_STATUS_100M;
755 dev->status &= ~FEC_STATUS_100M;
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");
766 diag_printf("FEC: no cable\n");
770 #ifndef CYGPKG_DEVS_ETH_PHY
772 * This function initializes the PHY
775 mxc_fec_phy_init(mxc_fec_priv_t *dev)
778 unsigned short value = 0;
779 unsigned long timeout = FEC_COMMON_TIMEOUT;
782 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET);
784 if (mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
788 if (!(value & PHY_CTRL_RESET)) {
789 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
792 hal_delay_us(FEC_MII_TICK);
795 if (value & PHY_CTRL_RESET) {
796 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
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);
810 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
811 PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
813 timeout = FEC_COMMON_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);
820 hal_delay_us(FEC_MII_TICK);
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);
826 unsigned long value = 0;
827 unsigned long id = 0, timeout = 50;
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;
840 diag_printf("[Warning] FEC not connect right PHY: ID=%lx\n", id);
843 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
844 PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
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);
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)) {
858 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_EXP_REG, &value);
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);
865 /* Wait for auto-negotiation to complete */
866 while (((value & PHY_INT_AUTO_NEG) == 0) && (timeout != 0)) {
868 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_INT_SRC_REG, &value);
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;
877 dev->status &= ~FEC_STATUS_LINK_ON;
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;
885 dev->status &= ~FEC_STATUS_FULL_DPLX;
887 if (value & PHY_DIAG_DPLX) {
888 dev->status |= FEC_STATUS_100M;
890 dev->status &= ~FEC_STATUS_100M;
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;
902 dev->status &= ~FEC_STATUS_FULL_DPLX;
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;
911 dev->status &= ~FEC_STATUS_FULL_DPLX;
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");
923 static int mxc_fec_discover_phy(mxc_fec_priv_t *fep, unsigned char def_addr)
926 unsigned char phy_addr = def_addr;
927 unsigned long id = 0;
930 for (i = 0; i < 32; i++) {
931 unsigned short mii_reg;
933 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
938 if (mii_reg != 0xffff && mii_reg != 0) {
939 /* Got first part of ID, now get remainder.
942 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR2, &mii_reg);
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);
952 phy_addr = (phy_addr + 1) % 32;
953 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
961 fep->mxc_fec_reg_write(hw_reg, mscr, 0);
970 * generic PHY support functions
972 void mxc_fec_phy_reset(void)
974 unsigned short value = 0;
975 unsigned long timeout=FEC_COMMON_TIMEOUT;
976 mxc_fec_priv_t *dev = &mxc_fec_private;
979 if (net_debug) diag_printf("%s\n", __FUNCTION__);
981 _eth_phy_write(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, PHY_CTRL_RESET);
983 if (!_eth_phy_read(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, &value)) {
987 if (!(value & PHY_CTRL_RESET)) {
988 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
991 hal_delay_us(FEC_MII_TICK);
994 if (value & PHY_CTRL_RESET) {
995 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
1000 void mxc_fec_phy_init(void)
1002 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1005 bool mxc_fec_phy_read(int reg, int unit, unsigned short *data)
1008 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1009 ret = mxc_fec_mii_read(mxc_fec_private.hw_reg, unit, reg, data);
1013 void mxc_fec_phy_write(int reg, int unit, unsigned short data)
1015 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1016 mxc_fec_mii_write(mxc_fec_private.hw_reg, unit, reg, data);
1019 /*! This function initializes the FEC driver.
1020 * It is called by net_init in net module of RedBoot during RedBoot init
1023 mxc_fec_init(struct cyg_netdevtab_entry *tab)
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};
1029 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1033 if (net_debug) diag_printf("%s:\n", __FUNCTION__);
1035 diag_printf("%s: no driver attached\n", __FUNCTION__);
1039 private = MXC_FEC_PRIVATE(sc);
1040 if (private == NULL) {
1041 private = &mxc_fec_private;
1043 if (private->provide_esa) {
1044 ok = private->provide_esa(eth_add_local);
1046 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
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);
1058 diag_printf("No ESA provided via fuses or RedBoot config\n");
1062 private->hw_reg = (volatile void *)SOC_FEC_BASE;
1063 private->tx_busy = 0;
1064 private->status = 0;
1066 mxc_fec_bd_init(private);
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__);
1074 _eth_phy_state(private->phy);
1076 ok = mxc_fec_discover_phy(private, PHY_PORT_ADDR);
1078 diag_printf("%s: no PHY found\n", __FUNCTION__);
1081 private->phy_addr = ok;
1082 mxc_fec_phy_init(private);
1084 /* TODO:: initialize System Resource : irq, timer */
1086 sc->funs->eth_drv->init(sc, eth_add_local);
1087 mxc_fec_phy_status(private, _eth_phy_state(private->phy), true);
1092 #ifndef CYGPKG_DEVS_ETH_PHY
1094 * Global variable which defines the FEC driver,
1096 ETH_DRV_SC(mxc_fec_sc,
1097 &mxc_fec_private, // Driver specific data
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);
1110 * Global variable which defines the FEC device
1112 NETDEVTAB_ENTRY(mxc_fec_netdev,
1117 #endif // CYGPKG_DEVS_ETH_PHY