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>
95 #include <cyg/io/fec.h>
97 #include CYGDAT_DEVS_ETH_FEC_INL
102 #include <cyg/hal/hal_mm.h>
103 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
104 #include <flash_config.h>
108 #define MII_REG_CR 0 /* Control Register */
109 #define MII_REG_SR 1 /* Status Register */
110 #define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */
111 #define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */
113 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show);
115 #ifndef CYGPKG_DEVS_ETH_PHY
117 * Global variable which contains the name of FEC driver and device.
119 static char mxc_fec_name[] = "mxc_fec";
122 * Global variable which defines the private structure of FEC device.
124 static mxc_fec_priv_t mxc_fec_private ;
128 *Global variable which defines the buffer descriptions for receiving frame
129 * comment:: it must aligned by 128-bits.
131 static mxc_fec_bd_t mxc_fec_rx_bd[FEC_BD_RX_NUM] __attribute__ ( ( aligned(32) ) ) ;
134 *Global variable which defines the buffer descriptions for receiving frame
135 * comment:: it must aligned by 128-bits.
137 static mxc_fec_bd_t mxc_fec_tx_bd[FEC_BD_TX_NUM] __attribute__ ( ( aligned(32) ) ) ;
140 * Global variable which contains the frame buffers ,
142 static unsigned char mxc_fec_rx_buf[FEC_BD_RX_NUM][2048] __attribute__ ( ( aligned(32) ) ) ;
145 * Global variable which contains the frame buffers ,
147 static unsigned char mxc_fec_tx_buf[FEC_BD_TX_NUM][2048] __attribute__ ( ( aligned(32) ) ) ;
151 * This function get the value of PHY registers by MII interface
154 mxc_fec_mii_read(volatile mxc_fec_reg_t *hw_reg, unsigned char phy_addr, unsigned char reg_addr,
155 unsigned short int *value)
157 unsigned long waiting = FEC_MII_TIMEOUT;
159 if (net_debug) diag_printf("%s: Trying to read phy[%02x] reg %04x\n",
160 __FUNCTION__, phy_addr, reg_addr);
161 if (hw_reg->eir & FEC_EVENT_MII) {
162 if (net_debug) diag_printf("%s: Clearing EIR_EVENT_MII\n", __FUNCTION__);
163 hw_reg->eir = FEC_EVENT_MII ;
165 if (net_debug) diag_printf("%s: EIR=%08lx\n", __FUNCTION__, hw_reg->eir);
166 hw_reg->mmfr = FEC_MII_READ(phy_addr, reg_addr);/*Write CMD*/
168 if (hw_reg->eir & FEC_EVENT_MII) {
169 if (net_debug) diag_printf("%s: Got EIR_EVENT_MII: EIR=%08lx\n",
170 __FUNCTION__, hw_reg->eir);
171 hw_reg->eir = FEC_EVENT_MII ;
174 if (--waiting == 0) {
175 diag_printf("%s: Read from PHY at addr %d reg 0x%02x timed out: EIR=%08lx\n",
176 __FUNCTION__, phy_addr, reg_addr, hw_reg->eir);
179 hal_delay_us(FEC_MII_TICK);
181 *value = FEC_MII_GET_DATA(hw_reg->mmfr);
182 if (net_debug) diag_printf("%s: Read %04x from phy[%02x] reg %04x\n", __FUNCTION__,
183 *value, phy_addr, reg_addr);
188 * This function set the value of PHY registers by MII interface
191 mxc_fec_mii_write(volatile mxc_fec_reg_t * hw_reg, unsigned char phy_addr, unsigned char reg_addr,
192 unsigned short int value)
194 unsigned long waiting = FEC_MII_TIMEOUT;
196 if (net_debug) diag_printf("%s: Trying to write %04x to phy[%02x] reg %04x\n", __FUNCTION__,
197 value, phy_addr, reg_addr);
198 if(hw_reg->eir & FEC_EVENT_MII ) {
199 if (net_debug) diag_printf("%s: Clearing EIR_EVENT_MII\n", __FUNCTION__);
200 hw_reg->eir = FEC_EVENT_MII;
202 if (net_debug) diag_printf("%s: EIR=%08lx\n", __FUNCTION__, hw_reg->eir);
203 hw_reg->mmfr = FEC_MII_WRITE(phy_addr, reg_addr, value);/*Write CMD*/
204 if (net_debug) diag_printf("%s: Wrote cmd %08x to MMFR\n", __FUNCTION__,
205 FEC_MII_WRITE(phy_addr, reg_addr, value));
207 if (hw_reg->eir & FEC_EVENT_MII) {
208 if (net_debug) diag_printf("%s: Got EIR_EVENT_MII: EIR=%08lx\n",
209 __FUNCTION__, hw_reg->eir);
210 hw_reg->eir = FEC_EVENT_MII ;
213 if (--waiting == 0) {
214 diag_printf("%s: Write to PHY at addr %d reg 0x%02x timed out: EIR=%08lx\n",
215 __FUNCTION__, phy_addr, reg_addr, hw_reg->eir);
218 hal_delay_us(FEC_MII_TICK);
220 if (net_debug) diag_printf("%s: Write to phy register succeeded\n", __FUNCTION__);
225 mxc_fec_set_mac_address(volatile mxc_fec_reg_t *dev, unsigned char *enaddr)
230 value = (value << 8) + enaddr[1];
231 value = (value << 8) + enaddr[2];
232 value = (value << 8) + enaddr[3];
236 value = (value << 8) + enaddr[5];
237 dev->paur = (value << 16);
241 * This function set the value of PHY registers by MII interface
244 mxc_fec_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
246 mxc_fec_priv_t *priv = sc?sc->driver_private:NULL;
247 volatile mxc_fec_reg_t *chip = priv?priv->hw_reg:NULL;
249 if (!(priv && chip) || enaddr == NULL ) {
250 diag_printf("BUG[start]: MAC address or some fields in driver is NULL\n");
253 mxc_fec_set_mac_address(chip, enaddr);
256 chip->ecr |= FEC_ETHER_EN;
257 chip->rdar |= FEC_RX_TX_ACTIVE;
261 * This function pauses the FEC controller.
264 mxc_fec_stop(struct eth_drv_sc *sc)
266 mxc_fec_priv_t *priv = sc?sc->driver_private:NULL;
267 volatile mxc_fec_reg_t *chip = priv?priv->hw_reg:NULL;
268 if (!(priv && chip)) {
269 diag_printf("BUG[stop]: some fields in driver is NULL\n");
272 chip->ecr &= ~FEC_ETHER_EN;
276 mxc_fec_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length)
278 /*TODO:: Add support */
279 diag_printf("mxc_fec_control: key=0x%08lx, data=%p, data_len=0x%08x\n",
280 key, data, data_length);
285 * This function checks the status of FEC control.
288 mxc_fec_can_send(struct eth_drv_sc *sc)
290 mxc_fec_priv_t *priv = sc?sc->driver_private:NULL;
291 volatile mxc_fec_reg_t *hw_reg = priv?priv->hw_reg:NULL;
293 if (!(priv && hw_reg)) {
294 diag_printf("BUG[can_send]:the private pointer and register pointer in MXC_FEC is NULL\n");
298 diag_printf("WARNING[can_send]: MXC_FEC is busy for transmittinig\n");
302 if (!(hw_reg->ecr & FEC_ETHER_EN)) {
303 diag_printf("WARNING[can_send]: MXC_FEC is not enabled\n");
307 if (hw_reg->tcr & FEC_TCR_RFC_PAUSE) {
308 diag_printf("WARNING[can_send]: MXC_FEC is paused\n");
312 if (!(priv->status & FEC_STATUS_LINK_ON)) {
313 /* Reading the PHY status for every packet to be sent is
314 * a real performance killer.
315 * Thus, only read the PHY status when the link is down to
316 * detect a possible new connection
318 #ifdef CYGPKG_DEVS_ETH_PHY
319 unsigned short value;
320 value = _eth_phy_state(priv->phy);
322 unsigned short value;
323 mxc_fec_mii_read(hw_reg, priv->phy_addr, 1, &value);
325 if (value & PHY_STATUS_LINK_ST) {
326 if (!(priv->status & FEC_STATUS_LINK_ON)) {
327 mxc_fec_phy_status(priv, value, true);
330 if (priv->status & FEC_STATUS_LINK_ON) {
331 mxc_fec_phy_status(priv, value, true);
336 return priv->status & FEC_STATUS_LINK_ON;
340 * This function transmits a frame.
343 mxc_fec_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total,
346 mxc_fec_priv_t *dev = sc?sc->driver_private:NULL;
347 volatile mxc_fec_reg_t *hw_reg = dev?dev->hw_reg:NULL;
351 if ( dev == NULL || hw_reg == NULL) {
352 diag_printf("BUG[TX]: some fields in driver are NULL\n");
355 if ( total > (FEC_FRAME_LEN-4)) total = FEC_FRAME_LEN-4;
356 if ( sg_list == NULL || total <= 14 ) {
357 if(sc->funs->eth_drv && sc->funs->eth_drv->tx_done) {
358 sc->funs->eth_drv->tx_done(sc, key, -1);
363 for(i=0, off=0, p = dev->tx_cur; i<sg_len; i++) {
365 if(p->status & BD_TX_ST_RDY) {
366 diag_printf("BUG[TX]:MXC_FEC's status=%x\n", p->status);
369 if (sg_list[i].buf == 0) {
370 diag_printf("WARNING[TX]: sg_list->buf is NULL\n");
373 vaddr = hal_ioremap_nocache((unsigned long)p->data) + off;
374 memcpy((void *)vaddr, (void *)sg_list[i].buf, sg_list[i].len);
375 off += sg_list[i].len;
378 diag_printf("WARNING[TX]: data len is %d\n", off);
382 p->status &= ~(BD_TX_ST_LAST|BD_TX_ST_RDY|BD_TX_ST_TC|BD_TX_ST_ABC);
383 p->status |= BD_TX_ST_LAST| BD_TX_ST_RDY | BD_TX_ST_TC;
384 if(p->status & BD_TX_ST_WRAP ) {
390 hw_reg->tdar = FEC_RX_TX_ACTIVE;
394 * This function receives ready Frame in DB.
397 mxc_fec_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
399 mxc_fec_priv_t * priv = sc?sc->driver_private:NULL;
402 if(sg_list == NULL || priv == NULL || sg_len <= 0) {
403 diag_printf("BUG[RX]: driver's private field or argument of this calling is NULL \n");
407 /*TODO: I think if buf pointer is NULL, this function
408 * should not be called
410 if(sg_list->buf == 0) {
411 diag_printf("WARING[RX]: the sg_list is empty\n");
416 if(p->status & BD_RX_ST_EMPTY) {
417 diag_printf("BUG[RX]: status =%x\n", p->status);
421 if(!(p->status & BD_RX_ST_LAST)) {
422 diag_printf("BUG[RX]: status =%x\n", p->status);
425 vaddr = hal_ioremap_nocache((unsigned long)p->data);
426 /*TODO::D_CACHE invalid this data buffer*/
427 memcpy((void *)sg_list->buf, (void *)vaddr, p->length -4);
431 mxc_fec_deliver(struct eth_drv_sc *sc)
433 /*TODO::When redboot support thread ,
434 * the polling function will be called at here
440 mxc_fec_check_rx_bd(struct eth_drv_sc * sc)
442 /* This funtion just called by polling funtion*/
443 mxc_fec_priv_t * priv = sc->driver_private;
445 volatile mxc_fec_reg_t * hw_reg = priv->hw_reg;
448 for(i = 0, p = priv->rx_cur; i< FEC_RX_FRAMES; i++){
449 /*TODO::D-CACHE invalid this BD.
450 *In WRITE_BACK mode: this maybe destroy the next BD
451 * when the CACHE_LINE write back.
453 if(p->status & BD_RX_ST_EMPTY) {
456 if(!(p->status & BD_RX_ST_LAST)) {
457 diag_printf("BUG[RX]: status=%x, length=%x\n", p->status, p->length);
461 if((p->status & BD_RX_ST_ERRS)|| (p->length > FEC_FRAME_LEN)) {
462 diag_printf("BUG[RX]: status=%x, length=%x\n", p->status, p->length);
464 sc->funs->eth_drv->recv(sc, p->length -4);
467 p->status = (p->status & BD_RX_ST_WRAP) | BD_RX_ST_EMPTY;
469 if ( p->status & BD_RX_ST_WRAP) {
475 hw_reg->ecr |= FEC_ETHER_EN;
476 hw_reg->rdar |= FEC_RX_TX_ACTIVE;
481 * This function checks the event of FEC controller
484 mxc_fec_poll(struct eth_drv_sc * sc)
486 mxc_fec_priv_t * priv = sc?sc->driver_private:NULL;
487 volatile mxc_fec_reg_t * hw_reg = priv?priv->hw_reg:NULL;
490 if ( priv == NULL || hw_reg == NULL) {
491 diag_printf("BUG[POLL]: some fields in driver are NULL\n");
495 hw_reg->eir = value & (~FEC_EVENT_MII);
497 if(value&FEC_EVENT_TX_ERR) {
498 diag_printf("WARNING[POLL]: There are errors(%lu) for transmit\n",
499 value&FEC_EVENT_TX_ERR);
500 sc->funs->eth_drv->tx_done(sc, priv->tx_key, -1);
503 if(value&FEC_EVENT_TX) {
504 sc->funs->eth_drv->tx_done(sc, priv->tx_key, 0);
509 if(value&FEC_EVENT_RX) {
510 mxc_fec_check_rx_bd(sc);
513 if(value & FEC_EVENT_HBERR) {
514 diag_printf("WARNGING[POLL]: Hearbeat error!\n");
517 if(value & FEC_EVENT_EBERR) {
518 diag_printf("WARNING[POLL]: Ethernet Bus Error!\n");
524 mxc_fec_int_vector(struct eth_drv_sc *sc)
527 * get FEC interrupt number
533 * The function initializes the description buffer for receiving or transmitting
536 mxc_fec_bd_init(mxc_fec_priv_t * dev)
541 p = dev->rx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_rx_bd));
542 for(i=0; i<FEC_BD_RX_NUM; i++, p++){
543 p->status = BD_RX_ST_EMPTY;
545 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_rx_buf[i]);
548 dev->rx_bd[i-1].status |= BD_RX_ST_WRAP;
549 dev->rx_cur = dev->rx_bd;
551 p = dev->tx_bd = (void *)hal_ioremap_nocache(hal_virt_to_phy((unsigned long)mxc_fec_tx_bd));
552 for(i=0; i<FEC_BD_TX_NUM; i++, p++){
555 p->data = (void *)hal_virt_to_phy((unsigned long)mxc_fec_tx_buf[i]);
558 dev->tx_bd[i-1].status |= BD_TX_ST_WRAP;
559 dev->tx_cur = dev->tx_bd;
561 /*TODO:: add the sync function for items*/
565 *This function initializes FEC controller.
568 mxc_fec_chip_init(mxc_fec_priv_t * dev)
570 volatile mxc_fec_reg_t * chip = dev->hw_reg;
571 unsigned long ipg_clk;
573 chip->ecr = FEC_RESET;
574 while(chip->ecr & FEC_RESET) {
575 hal_delay_us(FEC_COMMON_TICK);
578 chip->eimr = 0x00000000;
579 chip->eir = 0xFFFFFFFF;
581 chip->rcr = (chip->rcr&~(0x0000003F))|FEC_RCR_FCE|FEC_RCR_MII_MODE;
582 chip->tcr |= FEC_TCR_FDEN;
583 chip->mibc |= FEC_MIB_DISABLE;
590 /*TODO:: Use MII_SPEED(IPG_CLK) to get the value*/
591 ipg_clk = get_main_clock(IPG_CLK);
593 chip->mscr = (chip->mscr & 0x7e) | (((ipg_clk + 499999) / 2500000 / 2) << 1);
594 if (net_debug) diag_printf("mscr set to %08lx for ipg_clk %ld\n", chip->mscr,
597 chip->emrbr = 2048-16;
598 chip->erdsr = hal_virt_to_phy((unsigned long)dev->rx_bd);
599 chip->etdsr = hal_virt_to_phy((unsigned long)dev->tx_bd);
602 static void mxc_fec_phy_status(mxc_fec_priv_t *dev, unsigned short value, bool show)
604 #ifdef CYGPKG_DEVS_ETH_PHY
605 if (value & ETH_PHY_STAT_LINK) {
606 dev->status |= FEC_STATUS_LINK_ON;
607 if (value & ETH_PHY_STAT_FDX) {
608 dev->status |= FEC_STATUS_FULL_DPLX;
610 dev->status &= ~FEC_STATUS_FULL_DPLX;
612 if (value & ETH_PHY_STAT_100MB) {
613 dev->status |= FEC_STATUS_100M;
615 dev->status &= ~FEC_STATUS_100M;
618 dev->status &= ~FEC_STATUS_LINK_ON;
621 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value);
622 if (value & PHY_STATUS_LINK_ST) {
623 dev->status |= FEC_STATUS_LINK_ON;
625 dev->status &= ~FEC_STATUS_LINK_ON;
628 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_DIAG_REG, &value);
629 if (value & PHY_DIAG_DPLX) {
630 dev->status |= FEC_STATUS_FULL_DPLX;
632 dev->status &= ~FEC_STATUS_FULL_DPLX;
634 if (value & PHY_DIAG_RATE) {
635 dev->status |= FEC_STATUS_100M;
637 dev->status &= ~FEC_STATUS_100M;
643 if (dev->status & FEC_STATUS_LINK_ON) {
644 diag_printf("FEC: [ %s ] [ %s ]:\n",
645 (dev->status & FEC_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
646 (dev->status & FEC_STATUS_100M) ? "100 Mbps" : "10 Mbps");
648 diag_printf("FEC: no cable\n");
652 #ifndef CYGPKG_DEVS_ETH_PHY
654 * This function initialize PHY
657 mxc_fec_phy_init(mxc_fec_priv_t *dev)
659 unsigned short value = 0;
660 unsigned long timeout=FEC_COMMON_TIMEOUT;
662 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET);
664 if (mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
668 if(!(value & PHY_CTRL_RESET)) {
669 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
672 hal_delay_us(FEC_MII_TICK);
675 if (value & PHY_CTRL_RESET) {
676 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
681 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
682 id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
683 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
684 id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
685 if( id == 0 || id == 0xffffffff) {
686 diag_printf("FEC could not identify PHY: ID=%08lx\n", id);
690 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_CTRL_REG,
691 PHY_CTRL_AUTO_NEG | PHY_CTRL_FULL_DPLX);
693 timeout = FEC_COMMON_TIMEOUT;
695 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_STATUS_REG, &value) == 0) {
696 if (value & PHY_STATUS_LINK_ST) {
697 if (net_debug) diag_printf("PHY Status: %04x\n", value);
700 hal_delay_us(FEC_MII_TICK);
702 mxc_fec_mii_read(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, &value);
703 value &= ~(PHY_LED_SEL);
704 mxc_fec_mii_write(dev->hw_reg, dev->phy_addr, PHY_MODE_REG, value);
709 static int mxc_fec_discover_phy(mxc_fec_priv_t *fep, unsigned char def_addr)
712 unsigned char phy_addr = def_addr;
713 unsigned long id = 0;
715 for (i = 0; i < 32; i++) {
716 unsigned short mii_reg;
718 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
723 if (mii_reg != 0xffff && mii_reg != 0) {
724 /* Got first part of ID, now get remainder.
727 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR2, &mii_reg);
731 id = (id << 16) | mii_reg;
732 if (net_debug) diag_printf("%s: discovered PHY %08lx at addr %x\n",
733 __FUNCTION__, id, phy_addr);
737 phy_addr = (phy_addr + 1) % 32;
738 ret = mxc_fec_mii_read(fep->hw_reg, phy_addr, MII_REG_PHYIR1, &mii_reg);
746 fep->hw_reg->mscr = 0;
755 * generic PHY support functions
757 void mxc_fec_phy_reset(void)
759 unsigned short value = 0;
760 unsigned long timeout=FEC_COMMON_TIMEOUT;
761 mxc_fec_priv_t *dev = &mxc_fec_private;
764 if (net_debug) diag_printf("%s\n", __FUNCTION__);
766 _eth_phy_write(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, PHY_CTRL_RESET);
768 if (!_eth_phy_read(dev->phy, PHY_CTRL_REG, dev->phy->phy_addr, &value)) {
772 if(!(value & PHY_CTRL_RESET)) {
773 if (net_debug) diag_printf("%s: FEC reset completed\n", __FUNCTION__);
776 hal_delay_us(FEC_MII_TICK);
779 if (value & PHY_CTRL_RESET) {
780 diag_printf("%s: FEC PHY reset timed out\n", __FUNCTION__);
785 void mxc_fec_phy_init(void)
787 if (net_debug) diag_printf("%s\n", __FUNCTION__);
790 bool mxc_fec_phy_read(int reg, int unit, unsigned short *data)
793 if (net_debug) diag_printf("%s\n", __FUNCTION__);
794 ret = mxc_fec_mii_read(mxc_fec_private.hw_reg, unit, reg, data);
798 void mxc_fec_phy_write(int reg, int unit, unsigned short data)
800 if (net_debug) diag_printf("%s\n", __FUNCTION__);
801 mxc_fec_mii_write(mxc_fec_private.hw_reg, unit, reg, data);
804 /*! This function initializes the FEC driver.
805 * It is called by net_init in net module of RedBoot during RedBoot init
808 mxc_fec_init(struct cyg_netdevtab_entry *tab)
810 struct eth_drv_sc * sc = tab ? tab->device_instance : NULL;
811 mxc_fec_priv_t * private;
812 char eth_add_local[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
813 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
817 /* Get MAC address */
818 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
819 "fec_esa", &set_esa, CONFIG_BOOL);
821 CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
822 "fec_esa_data", eth_add_local, CONFIG_ESA);
825 if (net_debug) diag_printf("%s:\n", __FUNCTION__);
827 diag_printf("%s: no driver attached\n", __FUNCTION__);
831 private = MXC_FEC_PRIVATE(sc);
832 if (private == NULL) {
833 private = MXC_FEC_PRIVATE(sc) = &mxc_fec_private;
836 private->hw_reg = (void *)SOC_FEC_BASE;
837 private->tx_busy = 0;
840 mxc_fec_bd_init(private);
842 mxc_fec_chip_init(private);
843 #ifdef CYGPKG_DEVS_ETH_PHY
844 if (!_eth_phy_init(private->phy)) {
845 diag_printf("%s: Failed to initialize PHY\n", __FUNCTION__);
848 _eth_phy_state(private->phy);
850 ok = mxc_fec_discover_phy(private, PHY_PORT_ADDR);
852 diag_printf("%s: no PHY found\n", __FUNCTION__);
855 private->phy_addr = ok;
856 mxc_fec_phy_init(private);
858 /*TODO:: initialize System Resource : irq, timer */
860 sc->funs->eth_drv->init(sc, eth_add_local);
861 mxc_fec_phy_status(private, _eth_phy_state(private->phy), true);
866 #ifndef CYGPKG_DEVS_ETH_PHY
868 * Global variable which defines the FEC driver,
870 ETH_DRV_SC(mxc_fec_sc,
871 &mxc_fec_private, // Driver specific data
879 mxc_fec_deliver, // "pseudoDSR" called from fast net thread
880 mxc_fec_poll, // poll function, encapsulates ISR and DSR
884 * Global variable which defines the FEC device
886 NETDEVTAB_ENTRY(mxc_fec_netdev,