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 #ifdef CYGPKG_DEVS_ETH_PHY
86 /* generic PHY device access functions */
87 void mxc_fec_phy_init(void);
88 void mxc_fec_phy_reset(void);
89 bool mxc_fec_phy_read(int reg, int unit, unsigned short *data);
90 void mxc_fec_phy_write(int reg, int unit, unsigned short data);
92 #include <cyg/io/eth_phy.h>
94 static bool mxc_fec_init(struct cyg_netdevtab_entry *tab);
96 #include <cyg/io/fec.h>
98 #include CYGDAT_DEVS_ETH_FEC_INL
103 #include <cyg/hal/hal_mm.h>
104 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
105 #include <flash_config.h>
109 #define MII_REG_CR 0 /* Control Register */
110 #define MII_REG_SR 1 /* Status Register */
111 #define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */
112 #define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */
114 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show);
116 #ifndef CYGPKG_DEVS_ETH_PHY
118 * Global variable which contains the name of FEC driver and device.
120 static char mxc_fec_name[] = "mxc_fec";
123 * Global variable which defines the private structure of FEC device.
125 static mxc_fec_priv_t mxc_fec_private;
129 * Global variable which defines the buffer descriptors for receive frames
130 * comment:: it must aligned by 128-bits.
132 static mxc_fec_bd_t mxc_fec_rx_bd[FEC_BD_RX_NUM] __attribute__ ((aligned(32)));
135 * Global variable which defines the buffer descriptors for transmit frames
136 * comment:: it must aligned by 128-bits.
138 static mxc_fec_bd_t mxc_fec_tx_bd[FEC_BD_TX_NUM] __attribute__ ((aligned(32)));
141 * Global variable which contains the frame buffers
143 static unsigned char mxc_fec_rx_buf[FEC_BD_RX_NUM][2048] __attribute__ ((aligned(32)));
146 * Global variable which contains the frame buffers
148 static unsigned char mxc_fec_tx_buf[FEC_BD_TX_NUM][2048] __attribute__ ((aligned(32)));
151 static void dump_packet (unsigned char *pkt, size_t len)
155 diag_printf("Packet dump: %u byte", len);
156 for (i = 0; i < len; i++) {
158 diag_printf("\n%04x:", i);
167 diag_printf(" %02x", pkt[i]);
174 #define mxc_fec_reg_read(hw_reg,reg) _mxc_fec_reg_read(&(hw_reg)->reg, #reg)
175 static inline unsigned long _mxc_fec_reg_read(volatile unsigned long *addr,
178 unsigned long val = readl(addr);
180 if (net_debug) diag_printf("Read %08lx from FEC reg %s[%p]\n",
185 #define mxc_fec_reg_write(hw_reg,reg,val) _mxc_fec_reg_write(&(hw_reg)->reg, val, #reg)
186 static inline void _mxc_fec_reg_write(volatile unsigned long *addr,
187 unsigned long val, const char *reg)
189 if (net_debug) diag_printf("Writing %08lx to FEC reg %s[%p]\n",
194 #define mxc_fec_reg_read16(hw_reg,reg) _mxc_fec_reg_read16(&(hw_reg)->reg, #reg)
195 static inline unsigned short _mxc_fec_reg_read16(volatile unsigned short *addr,
198 unsigned short val = readw(addr);
200 if (net_debug) diag_printf("Read %04x from FEC reg %s[%p]\n",
205 #define mxc_fec_reg_write16(hw_reg,reg,val) _mxc_fec_reg_write16(&(hw_reg)->reg, val, #reg)
206 static inline void _mxc_fec_reg_write16(volatile unsigned short *addr,
207 unsigned short val, const char *reg)
209 if (net_debug) diag_printf("Writing %04x to FEC reg %s[%p]\n",
215 * This function gets the value of PHY registers via MII interface
218 mxc_fec_mii_read(volatile mxc_fec_reg_t *hw_reg, unsigned char phy_addr, unsigned char reg_addr,
219 unsigned short int *value)
221 unsigned long waiting = FEC_MII_TIMEOUT;
223 if (net_debug) diag_printf("%s: Trying to read phy[%02x] reg %04x\n",
224 __FUNCTION__, phy_addr, reg_addr);
225 if (mxc_fec_reg_read(hw_reg, eir) & FEC_EVENT_MII) {
226 if (net_debug) diag_printf("%s: Clearing EIR_EVENT_MII\n", __FUNCTION__);
227 mxc_fec_reg_write(hw_reg, eir, FEC_EVENT_MII);
229 if (net_debug) diag_printf("%s: EIR=%08lx\n", __FUNCTION__, mxc_fec_reg_read(hw_reg, eir));
230 mxc_fec_reg_write(hw_reg, mmfr, FEC_MII_READ(phy_addr, reg_addr));/* Write CMD */
232 if (mxc_fec_reg_read(hw_reg, eir) & FEC_EVENT_MII) {
233 if (net_debug) diag_printf("%s: Got EIR_EVENT_MII: EIR=%08lx\n",
234 __FUNCTION__, mxc_fec_reg_read(hw_reg, eir));
235 mxc_fec_reg_write(hw_reg, eir, FEC_EVENT_MII);
238 if (--waiting == 0) {
239 diag_printf("%s: Read from PHY at addr %d reg 0x%02x timed out: EIR=%08lx\n",
240 __FUNCTION__, phy_addr, reg_addr,
241 mxc_fec_reg_read(hw_reg, eir));
244 hal_delay_us(FEC_MII_TICK);
246 *value = FEC_MII_GET_DATA(mxc_fec_reg_read(hw_reg, mmfr));
247 if (net_debug) diag_printf("%s: Read %04x from phy[%02x] reg %04x\n", __FUNCTION__,
248 *value, phy_addr, reg_addr);
253 * This function set the value of PHY registers by MII interface
256 mxc_fec_mii_write(volatile mxc_fec_reg_t *hw_reg, unsigned char phy_addr, unsigned char reg_addr,
257 unsigned short int value)
259 unsigned long waiting = FEC_MII_TIMEOUT;
261 if (net_debug) diag_printf("%s: Trying to write %04x to phy[%02x] reg %04x\n", __FUNCTION__,
262 value, phy_addr, reg_addr);
263 if (mxc_fec_reg_read(hw_reg, eir) & FEC_EVENT_MII) {
264 if (net_debug) diag_printf("%s: Clearing EIR_EVENT_MII\n", __FUNCTION__);
265 mxc_fec_reg_write(hw_reg, eir, FEC_EVENT_MII);
267 if (net_debug) diag_printf("%s: EIR=%08lx\n", __FUNCTION__, mxc_fec_reg_read(hw_reg, eir));
268 mxc_fec_reg_write(hw_reg, mmfr, FEC_MII_WRITE(phy_addr, reg_addr, value));/* Write CMD */
269 if (net_debug) diag_printf("%s: Wrote cmd %08x to MMFR\n", __FUNCTION__,
270 FEC_MII_WRITE(phy_addr, reg_addr, value));
272 if (mxc_fec_reg_read(hw_reg, eir) & FEC_EVENT_MII) {
273 if (net_debug) diag_printf("%s: Got EIR_EVENT_MII: EIR=%08lx\n",
274 __FUNCTION__, mxc_fec_reg_read(hw_reg, eir));
275 mxc_fec_reg_write(hw_reg, eir, FEC_EVENT_MII);
278 if (--waiting == 0) {
279 diag_printf("%s: Write to PHY at addr %d reg 0x%02x timed out: EIR=%08lx\n",
280 __FUNCTION__, phy_addr, reg_addr,
281 mxc_fec_reg_read(hw_reg, eir));
284 hal_delay_us(FEC_MII_TICK);
286 if (net_debug) diag_printf("%s: Write to phy register succeeded\n", __FUNCTION__);
291 mxc_fec_set_mac_address(volatile mxc_fec_reg_t *hw_reg, unsigned char *enaddr)
296 value = (value << 8) + enaddr[1];
297 value = (value << 8) + enaddr[2];
298 value = (value << 8) + enaddr[3];
299 mxc_fec_reg_write(hw_reg, palr, value);
302 value = (value << 8) + enaddr[5];
303 mxc_fec_reg_write(hw_reg, paur, value << 16);
307 * This function enables the FEC for reception of packets
310 mxc_fec_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
312 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
313 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
315 if (!(priv && hw_reg)) {
316 diag_printf("BUG[start]: FEC driver not initialized\n");
319 if (enaddr == NULL) {
320 diag_printf("BUG[start]: no MAC address supplied\n");
323 mxc_fec_set_mac_address(hw_reg, enaddr);
326 mxc_fec_reg_write(hw_reg, rdar, mxc_fec_reg_read(hw_reg, rdar) | FEC_RX_TX_ACTIVE);
327 mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) | FEC_ETHER_EN);
328 #ifdef CYGPKG_HAL_ARM_MX25
330 * setup the MII gasket for RMII mode
333 /* disable the gasket */
334 mxc_fec_reg_write16(hw_reg, miigsk_enr, 0);
336 /* wait for the gasket to be disabled */
337 while (mxc_fec_reg_read16(hw_reg, miigsk_enr) & MIIGSK_ENR_READY)
338 hal_delay_us(FEC_COMMON_TICK);
340 /* configure gasket for RMII, 50 MHz, no loopback, and no echo */
341 mxc_fec_reg_write16(hw_reg, miigsk_cfgr, MIIGSK_CFGR_IF_MODE_RMII);
343 /* re-enable the gasket */
344 mxc_fec_reg_write16(hw_reg, miigsk_enr, MIIGSK_ENR_EN);
346 /* wait until MII gasket is ready */
348 while ((mxc_fec_reg_read16(hw_reg, miigsk_enr) & MIIGSK_ENR_READY) == 0) {
349 if (--max_loops <= 0) {
350 diag_printf("WAIT for MII Gasket ready timed out\n");
358 * This function pauses the FEC controller.
361 mxc_fec_stop(struct eth_drv_sc *sc)
363 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
364 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
366 if (!(priv && hw_reg)) {
367 diag_printf("BUG[stop]: FEC driver not initialized\n");
370 mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) & ~FEC_ETHER_EN);
374 mxc_fec_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length)
376 /*TODO:: Add support */
377 diag_printf("mxc_fec_control: key=0x%08lx, data=%p, data_len=0x%08x\n",
378 key, data, data_length);
383 * This function checks the status of FEC control.
386 mxc_fec_can_send(struct eth_drv_sc *sc)
388 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
389 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
391 if (!(priv && hw_reg)) {
392 diag_printf("BUG[can_send]: FEC driver not initialized\n");
396 diag_printf("WARNING[can_send]: MXC_FEC is busy for transmission\n");
400 if (!(mxc_fec_reg_read(hw_reg, ecr) & FEC_ETHER_EN)) {
401 diag_printf("WARNING[can_send]: MXC_FEC is not enabled\n");
405 if (mxc_fec_reg_read(hw_reg, tcr) & FEC_TCR_RFC_PAUSE) {
406 diag_printf("WARNING[can_send]: MXC_FEC is paused\n");
410 if (!(priv->status & FEC_STATUS_LINK_ON)) {
411 /* Reading the PHY status for every packet to be sent is
412 * a real performance killer.
413 * Thus, only read the PHY status when the link is down to
414 * detect a possible new connection
416 #ifdef CYGPKG_DEVS_ETH_PHY
417 unsigned short value;
418 value = _eth_phy_state(priv->phy);
420 unsigned short value;
421 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
423 if (value & PHY_STATUS_LINK_ST) {
424 if (!(priv->status & FEC_STATUS_LINK_ON)) {
425 mxc_fec_phy_status(priv, value, true);
428 if (priv->status & FEC_STATUS_LINK_ON) {
429 mxc_fec_phy_status(priv, value, true);
434 return priv->status & FEC_STATUS_LINK_ON;
438 * This function transmits a frame.
441 mxc_fec_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total,
444 mxc_fec_priv_t *dev = sc ? sc->driver_private : NULL;
445 volatile mxc_fec_reg_t *hw_reg = dev ? dev->hw_reg : NULL;
449 if (dev == NULL || hw_reg == NULL) {
450 diag_printf("BUG[TX]: FEC driver not initialized\n");
453 if (total > (FEC_FRAME_LEN - 4)) total = FEC_FRAME_LEN - 4;
454 if (sg_list == NULL || total <= 14) {
455 if (sc->funs->eth_drv && sc->funs->eth_drv->tx_done) {
456 sc->funs->eth_drv->tx_done(sc, key, -1);
461 for (i = 0, off = 0, p = dev->tx_cur; i < sg_len; i++) {
464 if (p->status & BD_TX_ST_RDY) {
465 diag_printf("BUG[TX]: trying to resend already finished buffer\n");
468 if (sg_list[i].buf == 0) {
469 diag_printf("WARNING[TX]: sg_list->buf is NULL\n");
472 vaddr = hal_ioremap_nocache((unsigned long)p->data) + off;
473 memcpy((void *)vaddr, (void *)sg_list[i].buf, sg_list[i].len);
474 off += sg_list[i].len;
477 diag_printf("WARNING[TX]: packet size %d too small\n", off);
481 //p->status &= ~(BD_TX_ST_LAST | BD_TX_ST_RDY | BD_TX_ST_TC | BD_TX_ST_ABC);
482 p->status &= ~BD_TX_ST_ABC;
483 p->status |= BD_TX_ST_LAST | BD_TX_ST_RDY | BD_TX_ST_TC;
484 if (p->status & BD_TX_ST_WRAP) {
492 mxc_fec_reg_write(hw_reg, tdar, FEC_RX_TX_ACTIVE);
496 * This function receives ready Frame in DB.
499 mxc_fec_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
501 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
505 if (sg_list == NULL || priv == NULL || sg_len <= 0) {
506 diag_printf("BUG[RX]: FEC driver not initialized\n");
510 /*TODO: I think if buf pointer is NULL, this function
511 * should not be called
513 if (sg_list->buf == 0) {
514 diag_printf("WARING[RX]: the sg_list is empty\n");
519 if (p->status & BD_RX_ST_EMPTY) {
520 diag_printf("BUG[RX]: empty buffer received; status=%04x\n", p->status);
524 if (!(p->status & BD_RX_ST_LAST)) {
525 diag_printf("BUG[RX]: status=%0xx\n", p->status);
528 vaddr = hal_ioremap_nocache((unsigned long)p->data);
529 /*TODO::D_CACHE invalid this data buffer*/
530 memcpy((void *)sg_list->buf, (void *)vaddr, p->length - 4);
534 mxc_fec_deliver(struct eth_drv_sc *sc)
536 /*TODO::When redboot support thread ,
537 * the polling function will be called at here
542 /* This funtion just called by polling funtion */
544 mxc_fec_check_rx_bd(struct eth_drv_sc *sc)
546 mxc_fec_priv_t *priv = sc->driver_private;
548 volatile mxc_fec_reg_t *hw_reg = priv->hw_reg;
551 for (i = 0, p = priv->rx_cur; i < FEC_RX_FRAMES; i++) {
553 * TODO::D-CACHE invalidate this BD.
554 * In WRITE_BACK mode: this may destroy the next BD
555 * when the CACHE_LINE is written back.
557 if (p->status & BD_RX_ST_EMPTY) {
560 if (!(p->status & BD_RX_ST_LAST)) {
561 diag_printf("BUG[RX]: status=%04x, length=%x\n", p->status, p->length);
565 if (p->status & BD_RX_ST_ERRS) {
566 diag_printf("RX error: status=%08x errors=%08x\n", p->status,
567 p->status & BD_RX_ST_ERRS);
568 } else if (p->length > FEC_FRAME_LEN) {
569 diag_printf("RX error: packet size 0x%08x larger than max frame length: 0x%08x\n",
570 p->length, FEC_FRAME_LEN);
572 sc->funs->eth_drv->recv(sc, p->length - 4);
575 p->status = (p->status & BD_RX_ST_WRAP) | BD_RX_ST_EMPTY;
577 if (p->status & BD_RX_ST_WRAP) {
583 mxc_fec_reg_write(hw_reg, rdar, mxc_fec_reg_read(hw_reg, rdar) | FEC_RX_TX_ACTIVE);
588 * This function checks the event of FEC controller
591 mxc_fec_poll(struct eth_drv_sc *sc)
593 mxc_fec_priv_t *priv = sc ? sc->driver_private : NULL;
594 volatile mxc_fec_reg_t *hw_reg = priv ? priv->hw_reg : NULL;
598 if (priv == NULL || hw_reg == NULL) {
599 diag_printf("BUG[POLL]: FEC driver not initialized\n");
605 value = mxc_fec_reg_read(hw_reg, eir);
606 mxc_fec_reg_write(hw_reg, eir, value & ~FEC_EVENT_MII);
610 if (value & FEC_EVENT_TX_ERR) {
611 diag_printf("WARNING[POLL]: Transmit error\n");
612 sc->funs->eth_drv->tx_done(sc, priv->tx_key, -1);
615 if (value & FEC_EVENT_TX) {
616 sc->funs->eth_drv->tx_done(sc, priv->tx_key, 0);
621 if (value & FEC_EVENT_RX) {
622 mxc_fec_check_rx_bd(sc);
625 if (value & FEC_EVENT_HBERR) {
626 diag_printf("WARNGING[POLL]: Hearbeat error!\n");
629 if (value & FEC_EVENT_EBERR) {
630 diag_printf("WARNING[POLL]: Ethernet Bus Error!\n");
635 mxc_fec_int_vector(struct eth_drv_sc *sc)
638 * get FEC interrupt number
644 * The function initializes the description buffer for receiving or transmitting
647 mxc_fec_bd_init(mxc_fec_priv_t *dev)
652 p = dev->rx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_rx_bd));
653 for (i = 0; i < FEC_BD_RX_NUM; i++, p++) {
654 p->status = BD_RX_ST_EMPTY;
656 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_rx_buf[i]);
659 dev->rx_bd[i - 1].status |= BD_RX_ST_WRAP;
660 dev->rx_cur = dev->rx_bd;
662 p = dev->tx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_tx_bd));
663 for (i = 0; i < FEC_BD_TX_NUM; i++, p++) {
666 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_tx_buf[i]);
669 dev->tx_bd[i - 1].status |= BD_TX_ST_WRAP;
670 dev->tx_cur = dev->tx_bd;
672 /*TODO:: add the sync function for items*/
676 *This function initializes FEC controller.
679 mxc_fec_chip_init(mxc_fec_priv_t *dev)
681 volatile mxc_fec_reg_t *hw_reg = dev->hw_reg;
682 unsigned long ipg_clk;
684 mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) | FEC_RESET);
685 while (mxc_fec_reg_read(hw_reg, ecr) & FEC_RESET) {
686 hal_delay_us(FEC_COMMON_TICK);
689 mxc_fec_reg_write(hw_reg, eimr, 0);
690 mxc_fec_reg_write(hw_reg, eir, ~0);
692 mxc_fec_reg_write(hw_reg, rcr,
693 (mxc_fec_reg_read(hw_reg, rcr) & ~0x3F) |
694 FEC_RCR_FCE | FEC_RCR_MII_MODE);
696 mxc_fec_reg_write(hw_reg, tcr, mxc_fec_reg_read(hw_reg, tcr) | FEC_TCR_FDEN);
697 mxc_fec_reg_write(hw_reg, mibc, mxc_fec_reg_read(hw_reg, mibc) | FEC_MIB_DISABLE);
699 mxc_fec_reg_write(hw_reg, iaur, 0);
700 mxc_fec_reg_write(hw_reg, ialr, 0);
701 mxc_fec_reg_write(hw_reg, gaur, 0);
702 mxc_fec_reg_write(hw_reg, galr, 0);
704 ipg_clk = get_main_clock(IPG_CLK);
706 mxc_fec_reg_write(hw_reg, mscr,
707 (mxc_fec_reg_read(hw_reg, mscr) & ~0x7e) |
708 (((ipg_clk + 499999) / 2500000 / 2) << 1));
709 if (net_debug) diag_printf("mscr set to %08lx for ipg_clk %ld\n",
710 mxc_fec_reg_read(hw_reg, mscr), ipg_clk);
712 mxc_fec_reg_write(hw_reg, emrbr, 2048 - 16);
713 mxc_fec_reg_write(hw_reg, erdsr, hal_virt_to_phy((unsigned long)dev->rx_bd));
714 mxc_fec_reg_write(hw_reg, etdsr, hal_virt_to_phy((unsigned long)dev->tx_bd));
716 /* must be done before enabling the MII gasket
717 * (otherwise MIIGSK_ENR_READY will never assert)
719 mxc_fec_reg_write(hw_reg, ecr, mxc_fec_reg_read(hw_reg, ecr) | FEC_ETHER_EN);
722 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show)
724 #ifdef CYGPKG_DEVS_ETH_PHY
725 if (value & ETH_PHY_STAT_LINK) {
726 dev->status |= FEC_STATUS_LINK_ON;
727 if (value & ETH_PHY_STAT_FDX) {
728 dev->status |= FEC_STATUS_FULL_DPLX;
730 dev->status &= ~FEC_STATUS_FULL_DPLX;
732 if (value & ETH_PHY_STAT_100MB) {
733 dev->status |= FEC_STATUS_100M;
735 dev->status &= ~FEC_STATUS_100M;
738 dev->status &= ~FEC_STATUS_LINK_ON;
741 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value);
742 if (value & PHY_STATUS_LINK_ST) {
743 dev->status |= FEC_STATUS_LINK_ON;
745 dev->status &= ~FEC_STATUS_LINK_ON;
748 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_DIAG_REG, &value);
749 if (value & PHY_DIAG_DPLX) {
750 dev->status |= FEC_STATUS_FULL_DPLX;
752 dev->status &= ~FEC_STATUS_FULL_DPLX;
754 if (value & PHY_DIAG_RATE) {
755 dev->status |= FEC_STATUS_100M;
757 dev->status &= ~FEC_STATUS_100M;
763 if (dev->status & FEC_STATUS_LINK_ON) {
764 diag_printf("FEC: [ %s ] [ %s ]:\n",
765 (dev->status & FEC_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
766 (dev->status & FEC_STATUS_100M) ? "100 Mbps" : "10 Mbps");
768 diag_printf("FEC: no cable\n");
772 #ifndef CYGPKG_DEVS_ETH_PHY
774 * This function initializes the PHY
777 mxc_fec_phy_init(mxc_fec_priv_t *dev)
780 unsigned short value = 0;
781 unsigned long timeout = FEC_COMMON_TIMEOUT;
784 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET);
786 if (mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
790 if (!(value & PHY_CTRL_RESET)) {
791 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
794 hal_delay_us(FEC_MII_TICK);
797 if (value & PHY_CTRL_RESET) {
798 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
803 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
804 id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
805 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
806 id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
807 if (id == 0 || id == 0xffffffff) {
808 diag_printf("FEC could not identify PHY: ID=%08lx\n", id);
812 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
813 PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
815 timeout = FEC_COMMON_TIMEOUT;
817 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value) == 0) {
818 if (value & PHY_STATUS_LINK_ST) {
819 if (net_debug) diag_printf("PHY Status: %04x\n", value);
822 hal_delay_us(FEC_MII_TICK);
824 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, &value);
825 value &= ~PHY_LED_SEL;
826 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, value);
828 unsigned long value = 0;
829 unsigned long id = 0, timeout = 50;
831 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
832 id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
833 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
834 id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
842 diag_printf("[Warning] FEC not connect right PHY: ID=%lx\n", id);
845 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, PHY_CTRL_AUTO_NEG|PHY_CTRL_FULL_DPLX);
847 #ifdef CYGPKG_HAL_ARM_MX27ADS
848 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, &value);
849 value &= ~PHY_LED_SEL;
850 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, value);
853 #if defined(CYGPKG_HAL_ARM_MX51) || defined (CYGPKG_HAL_ARM_MX25_3STACK) || 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) || defined (CYGPKG_HAL_ARM_MX35_3STACK)
895 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_AUTO_NEG_REG, &value);
896 if (value & PHY_AUTO_10BASET) {
897 dev->status &= ~FEC_STATUS_100M;
898 if (value & PHY_AUTO_10BASET_DPLX) {
899 dev->status |= FEC_STATUS_FULL_DPLX;
901 dev->status &= ~FEC_STATUS_FULL_DPLX;
905 if (value & PHY_AUTO_100BASET) {
906 dev->status |= FEC_STATUS_100M;
907 if (value & PHY_AUTO_100BASET_DPLX) {
908 dev->status |= FEC_STATUS_FULL_DPLX;
910 dev->status &= ~FEC_STATUS_FULL_DPLX;
914 diag_printf("FEC: [ %s ] [ %s ] [ %s ]:\n",
915 (dev->status&FEC_STATUS_FULL_DPLX)?"FULL_DUPLEX":"HALF_DUPLEX",
916 (dev->status&FEC_STATUS_LINK_ON)?"connected":"disconnected",
917 (dev->status&FEC_STATUS_100M)?"100M bps":"10M bps");
922 static int mxc_fec_discover_phy(mxc_fec_priv_t *fep, unsigned char def_addr)
925 unsigned char phy_addr = def_addr;
926 unsigned long id = 0;
928 for (i = 0; i < 32; i++) {
929 unsigned short mii_reg;
931 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
936 if (mii_reg != 0xffff && mii_reg != 0) {
937 /* Got first part of ID, now get remainder.
940 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR2, &mii_reg);
944 id = (id << 16) | mii_reg;
945 if (net_debug) diag_printf("%s: discovered PHY %08lx at addr %x\n",
946 __FUNCTION__, id, phy_addr);
950 phy_addr = (phy_addr + 1) % 32;
951 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
959 fep->mxc_fec_reg_write(hw_reg, mscr, 0);
968 * generic PHY support functions
970 void mxc_fec_phy_reset(void)
972 unsigned short value = 0;
973 unsigned long timeout=FEC_COMMON_TIMEOUT;
974 mxc_fec_priv_t *dev = &mxc_fec_private;
977 if (net_debug) diag_printf("%s\n", __FUNCTION__);
979 _eth_phy_write(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, PHY_CTRL_RESET);
981 if (!_eth_phy_read(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, &value)) {
985 if (!(value & PHY_CTRL_RESET)) {
986 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
989 hal_delay_us(FEC_MII_TICK);
992 if (value & PHY_CTRL_RESET) {
993 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
998 void mxc_fec_phy_init(void)
1000 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1003 bool mxc_fec_phy_read(int reg, int unit, unsigned short *data)
1006 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1007 ret = mxc_fec_mii_read(mxc_fec_private.hw_reg, unit, reg, data);
1011 void mxc_fec_phy_write(int reg, int unit, unsigned short data)
1013 if (net_debug) diag_printf("%s\n", __FUNCTION__);
1014 mxc_fec_mii_write(mxc_fec_private.hw_reg, unit, reg, data);
1017 /*! This function initializes the FEC driver.
1018 * It is called by net_init in net module of RedBoot during RedBoot init
1021 mxc_fec_init(struct cyg_netdevtab_entry *tab)
1023 struct eth_drv_sc *sc = tab ? tab->device_instance : NULL;
1024 mxc_fec_priv_t *private;
1025 unsigned char eth_add_local[ETHER_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1027 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1031 if (net_debug) diag_printf("%s:\n", __FUNCTION__);
1033 diag_printf("%s: no driver attached\n", __FUNCTION__);
1037 private = MXC_FEC_PRIVATE(sc);
1038 if (private == NULL) {
1039 private = &mxc_fec_private;
1041 if (private->provide_esa) {
1042 ok = private->provide_esa(eth_add_local);
1044 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1046 /* Get MAC address from fconfig */
1047 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
1048 "fec_esa", &set_esa, CONFIG_BOOL);
1049 if (ok && set_esa) {
1050 CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
1051 "fec_esa_data", eth_add_local, CONFIG_ESA);
1056 diag_printf("No ESA provided via fuses or RedBoot config\n");
1060 private->hw_reg = (void *)SOC_FEC_BASE;
1061 private->tx_busy = 0;
1062 private->status = 0;
1064 mxc_fec_bd_init(private);
1066 mxc_fec_chip_init(private);
1067 #ifdef CYGPKG_DEVS_ETH_PHY
1068 if (!_eth_phy_init(private->phy)) {
1069 diag_printf("%s: Failed to initialize PHY\n", __FUNCTION__);
1072 _eth_phy_state(private->phy);
1074 ok = mxc_fec_discover_phy(private, PHY_PORT_ADDR);
1076 diag_printf("%s: no PHY found\n", __FUNCTION__);
1079 private->phy_addr = ok;
1080 mxc_fec_phy_init(private);
1082 /* TODO:: initialize System Resource : irq, timer */
1084 sc->funs->eth_drv->init(sc, eth_add_local);
1085 mxc_fec_phy_status(private, _eth_phy_state(private->phy), true);
1090 #ifndef CYGPKG_DEVS_ETH_PHY
1092 * Global variable which defines the FEC driver,
1094 ETH_DRV_SC(mxc_fec_sc,
1095 &mxc_fec_private, // Driver specific data
1103 mxc_fec_deliver, // "pseudoDSR" called from fast net thread
1104 mxc_fec_poll, // poll function, encapsulates ISR and DSR
1105 mxc_fec_int_vector);
1108 * Global variable which defines the FEC device
1110 NETDEVTAB_ENTRY(mxc_fec_netdev,
1115 #endif // CYGPKG_DEVS_ETH_PHY