diff options
Diffstat (limited to 'drivers/inca-ip_sw.c')
-rw-r--r-- | drivers/inca-ip_sw.c | 164 |
1 files changed, 131 insertions, 33 deletions
diff --git a/drivers/inca-ip_sw.c b/drivers/inca-ip_sw.c index 88bc813..3b6397d 100644 --- a/drivers/inca-ip_sw.c +++ b/drivers/inca-ip_sw.c @@ -1,7 +1,7 @@ /* * INCA-IP internal switch ethernet driver. * - * (C) Copyright 2003 + * (C) Copyright 2003-2004 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * See file CREDITS for list of people who contributed to this @@ -67,6 +67,11 @@ #define INCA_DMA_RX_SOP 0x40000000 #define INCA_DMA_RX_EOP 0x20000000 +#define INCA_SWITCH_PHY_SPEED_10H 0x1 +#define INCA_SWITCH_PHY_SPEED_10F 0x5 +#define INCA_SWITCH_PHY_SPEED_100H 0x2 +#define INCA_SWITCH_PHY_SPEED_100F 0x6 + /************************ Auto MDIX settings ************************/ #define INCA_IP_AUTO_MDIX_LAN_PORTS_DIR INCA_IP_Ports_P1_DIR #define INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL INCA_IP_Ports_P1_ALTSEL @@ -221,8 +226,7 @@ static int inca_switch_init(struct eth_device *dev, bd_t * bis) /* Initialize the descriptor rings. */ - for (i = 0; i < NUM_RX_DESC; i++) - { + for (i = 0; i < NUM_RX_DESC; i++) { inca_rx_descriptor_t * rx_desc = KSEG1ADDR(&rx_ring[i]); memset(rx_desc, 0, sizeof(rx_ring[i])); @@ -330,8 +334,7 @@ static int inca_switch_init(struct eth_device *dev, bd_t * bis) } -static int inca_switch_send(struct eth_device *dev, volatile void *packet, - int length) +static int inca_switch_send(struct eth_device *dev, volatile void *packet, int length) { int i; int res = -1; @@ -628,7 +631,12 @@ static void inca_dma_init(void) #if defined(CONFIG_INCA_IP_SWITCH_AMDIX) static int inca_amdix(void) { - u32 regValue = 0; + u32 phyReg1 = 0; + u32 phyReg4 = 0; + u32 phyReg5 = 0; + u32 phyReg6 = 0; + u32 phyReg31 = 0; + u32 regEphy = 0; int mdi_flag; int retries; @@ -637,31 +645,29 @@ static int inca_amdix(void) *INCA_IP_AUTO_MDIX_LAN_PORTS_DIR |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); *INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); +#if 0 /* Wait for signal. */ retries = WAIT_SIGNAL_RETRIES; - while (--retries) - { + while (--retries) { SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, (0x1 << 31) | /* RA */ (0x0 << 30) | /* Read */ (0x6 << 21) | /* LAN */ (17 << 16)); /* PHY_MCSR */ - do - { - SW_READ_REG(INCA_IP_Switch_MDIO_ACC, regValue); - } - while (regValue & (1 << 31)); + do { + SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1); + } while (phyReg1 & (1 << 31)); - if (regValue & (1 << 1)) - { + if (phyReg1 & (1 << 1)) { /* Signal detected */ break; } } if (!retries) - return -1; + goto Fail; +#endif /* Set MDI mode. */ @@ -671,43 +677,135 @@ static int inca_amdix(void) /* Wait for link. */ retries = WAIT_LINK_RETRIES; - while (--retries) - { + while (--retries) { udelay(LINK_RETRY_DELAY * 1000); SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, (0x1 << 31) | /* RA */ (0x0 << 30) | /* Read */ (0x6 << 21) | /* LAN */ (1 << 16)); /* PHY_BSR */ - do - { - SW_READ_REG(INCA_IP_Switch_MDIO_ACC, regValue); - } - while (regValue & (1 << 31)); + do { + SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1); + } while (phyReg1 & (1 << 31)); - if (regValue & (1 << 2)) - { + if (phyReg1 & (1 << 2)) { /* Link is up */ break; - } - else if (mdi_flag) - { + } else if (mdi_flag) { /* Set MDIX mode */ *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); mdi_flag = 0; - } - else - { + } else { /* Set MDI mode */ *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); mdi_flag = 1; } } - if (!retries) - return -1; + if (!retries) { + goto Fail; + } else { + SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, + (0x1 << 31) | /* RA */ + (0x0 << 30) | /* Read */ + (0x6 << 21) | /* LAN */ + (1 << 16)); /* PHY_BSR */ + do { + SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1); + } while (phyReg1 & (1 << 31)); + + /* Auto-negotiation / Parallel detection complete + */ + if (phyReg1 & (1 << 5)) { + SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, + (0x1 << 31) | /* RA */ + (0x0 << 30) | /* Read */ + (0x6 << 21) | /* LAN */ + (31 << 16)); /* PHY_SCSR */ + do { + SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg31); + } while (phyReg31 & (1 << 31)); + + switch ((phyReg31 >> 2) & 0x7) { + case INCA_SWITCH_PHY_SPEED_10H: + /* 10Base-T Half-duplex */ + regEphy = 0; + break; + case INCA_SWITCH_PHY_SPEED_10F: + /* 10Base-T Full-duplex */ + regEphy = INCA_IP_Switch_EPHY_DL; + break; + case INCA_SWITCH_PHY_SPEED_100H: + /* 100Base-TX Half-duplex */ + regEphy = INCA_IP_Switch_EPHY_SL; + break; + case INCA_SWITCH_PHY_SPEED_100F: + /* 100Base-TX Full-duplex */ + regEphy = INCA_IP_Switch_EPHY_SL | INCA_IP_Switch_EPHY_DL; + break; + } + + /* In case of Auto-negotiation, + * update the negotiated PAUSE support status + */ + if (phyReg1 & (1 << 3)) { + SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, + (0x1 << 31) | /* RA */ + (0x0 << 30) | /* Read */ + (0x6 << 21) | /* LAN */ + (6 << 16)); /* PHY_ANER */ + do { + SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg6); + } while (phyReg6 & (1 << 31)); + + /* We are Autoneg-able. + * Is Link partner also able to autoneg? + */ + if (phyReg6 & (1 << 0)) { + SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, + (0x1 << 31) | /* RA */ + (0x0 << 30) | /* Read */ + (0x6 << 21) | /* LAN */ + (4 << 16)); /* PHY_ANAR */ + do { + SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg4); + } while (phyReg4 & (1 << 31)); + + /* We advertise PAUSE capab. + * Does link partner also advertise it? + */ + if (phyReg4 & (1 << 10)) { + SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, + (0x1 << 31) | /* RA */ + (0x0 << 30) | /* Read */ + (0x6 << 21) | /* LAN */ + (5 << 16)); /* PHY_ANLPAR */ + do { + SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg5); + } while (phyReg5 & (1 << 31)); + + /* Link partner is PAUSE capab. + */ + if (phyReg5 & (1 << 10)) { + regEphy |= INCA_IP_Switch_EPHY_PL; + } + } + } + + } + + /* Link is up */ + regEphy |= INCA_IP_Switch_EPHY_LL; + + SW_WRITE_REG(INCA_IP_Switch_EPHY, regEphy); + } + } return 0; + +Fail: + printf("No Link on LAN port\n"); + return -1; } #endif /* CONFIG_INCA_IP_SWITCH_AMDIX */ |