diff options
author | pdeuskar <pdeuskar@FreeBSD.org> | 2003-03-21 21:47:31 +0000 |
---|---|---|
committer | pdeuskar <pdeuskar@FreeBSD.org> | 2003-03-21 21:47:31 +0000 |
commit | a56305572587eb0a4e0d7793a845b70c41bafa8c (patch) | |
tree | d20e66c9988dbf11f5c7af5d38ff1994edbc7898 /sys/dev/em/if_em_hw.c | |
parent | 38bdc5fff0d6cc0edd89dcfd2a0e6c5388c6a00a (diff) | |
download | FreeBSD-src-a56305572587eb0a4e0d7793a845b70c41bafa8c.zip FreeBSD-src-a56305572587eb0a4e0d7793a845b70c41bafa8c.tar.gz |
Added support for 82541 and 82547 based adapters.
- These have Intel gigabit PHY
- 82547 uses CSA interface
MFC after: 1 week
Diffstat (limited to 'sys/dev/em/if_em_hw.c')
-rw-r--r-- | sys/dev/em/if_em_hw.c | 1517 |
1 files changed, 1198 insertions, 319 deletions
diff --git a/sys/dev/em/if_em_hw.c b/sys/dev/em/if_em_hw.c index 88bf617..6803fd8 100644 --- a/sys/dev/em/if_em_hw.c +++ b/sys/dev/em/if_em_hw.c @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright (c) 2001-2002, Intel Corporation + Copyright (c) 2001-2003, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -35,9 +35,11 @@ /* if_em_hw.c * Shared functions for accessing and configuring the MAC */ - + #include <dev/em/if_em_hw.h> +static int32_t em_set_phy_type(struct em_hw *hw); +static void em_phy_init_script(struct em_hw *hw); static int32_t em_setup_fiber_link(struct em_hw *hw); static int32_t em_setup_copper_link(struct em_hw *hw); static int32_t em_phy_force_speed_duplex(struct em_hw *hw); @@ -48,22 +50,103 @@ static void em_lower_mdi_clk(struct em_hw *hw, uint32_t *ctrl); static void em_shift_out_mdi_bits(struct em_hw *hw, uint32_t data, uint16_t count); static uint16_t em_shift_in_mdi_bits(struct em_hw *hw); static int32_t em_phy_reset_dsp(struct em_hw *hw); +static int32_t em_write_eeprom_spi(struct em_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +static int32_t em_write_eeprom_microwire(struct em_hw *hw, + uint16_t offset, uint16_t words, + uint16_t *data); +static int32_t em_spi_eeprom_ready(struct em_hw *hw); static void em_raise_ee_clk(struct em_hw *hw, uint32_t *eecd); static void em_lower_ee_clk(struct em_hw *hw, uint32_t *eecd); static void em_shift_out_ee_bits(struct em_hw *hw, uint16_t data, uint16_t count); -static uint16_t em_shift_in_ee_bits(struct em_hw *hw); -static void em_setup_eeprom(struct em_hw *hw); -static void em_clock_eeprom(struct em_hw *hw); -static void em_cleanup_eeprom(struct em_hw *hw); +static uint16_t em_shift_in_ee_bits(struct em_hw *hw, uint16_t count); +static int32_t em_acquire_eeprom(struct em_hw *hw); +static void em_release_eeprom(struct em_hw *hw); static void em_standby_eeprom(struct em_hw *hw); static int32_t em_id_led_init(struct em_hw * hw); +/****************************************************************************** + * Set the phy type member in the hw struct. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +em_set_phy_type(struct em_hw *hw) +{ + DEBUGFUNC("em_set_phy_type"); + + switch(hw->phy_id) { + case M88E1000_E_PHY_ID: + case M88E1000_I_PHY_ID: + case M88E1011_I_PHY_ID: + hw->phy_type = em_phy_m88; + break; + case IGP01E1000_I_PHY_ID: + hw->phy_type = em_phy_igp; + break; + default: + /* Should never have loaded on this device */ + hw->phy_type = em_phy_undefined; + return -E1000_ERR_PHY_TYPE; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** + * IGP phy init script - initializes the GbE PHY + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +em_phy_init_script(struct em_hw *hw) +{ + DEBUGFUNC("em_phy_init_script"); + + if(hw->phy_init_script) { + msec_delay(10); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000); + em_write_phy_reg(hw,0x0000,0x0140); + + msec_delay(5); + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F95); + em_write_phy_reg(hw,0x0015,0x0001); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F71); + em_write_phy_reg(hw,0x0011,0xBD21); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F79); + em_write_phy_reg(hw,0x0019,0x0018); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F30); + em_write_phy_reg(hw,0x0010,0x1600); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F31); + em_write_phy_reg(hw,0x0011,0x0014); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F32); + em_write_phy_reg(hw,0x0012,0x161C); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F94); + em_write_phy_reg(hw,0x0014,0x0003); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F96); + em_write_phy_reg(hw,0x0016,0x003F); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x2010); + em_write_phy_reg(hw,0x0010,0x0008); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000); + em_write_phy_reg(hw,0x0000,0x3300); + } +} /****************************************************************************** * Set the mac type member in the hw struct. - * + * * hw - Struct containing variables accessed by shared code *****************************************************************************/ int32_t @@ -110,6 +193,13 @@ em_set_mac_type(struct em_hw *hw) case E1000_DEV_ID_82546EB_FIBER: hw->mac_type = em_82546; break; + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + hw->mac_type = em_82541; + break; + case E1000_DEV_ID_82547EI: + hw->mac_type = em_82547; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; @@ -130,9 +220,10 @@ em_reset_hw(struct em_hw *hw) uint32_t ctrl_ext; uint32_t icr; uint32_t manc; + uint32_t led_ctrl; DEBUGFUNC("em_reset_hw"); - + /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ if(hw->mac_type == em_82542_rev2_0) { DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); @@ -156,7 +247,7 @@ em_reset_hw(struct em_hw *hw) /* Delay to allow any outstanding PCI transactions to complete before * resetting the device - */ + */ msec_delay(10); /* Issue a global reset to the MAC. This will reset the chip's @@ -167,7 +258,13 @@ em_reset_hw(struct em_hw *hw) DEBUGOUT("Issuing a global reset to MAC\n"); ctrl = E1000_READ_REG(hw, CTRL); - if(hw->mac_type > em_82543) + /* Must reset the PHY before resetting the MAC */ + if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { + E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST)); + msec_delay(5); + } + + if((hw->mac_type > em_82543) && (hw->mac_type != em_82547)) E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST)); else E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); @@ -184,13 +281,25 @@ em_reset_hw(struct em_hw *hw) msec_delay(2); } else { /* Wait for EEPROM reload (it happens automatically) */ - msec_delay(4); + msec_delay(5); /* Dissable HW ARPs on ASF enabled adapters */ manc = E1000_READ_REG(hw, MANC); manc &= ~(E1000_MANC_ARP_EN); E1000_WRITE_REG(hw, MANC, manc); } - + + if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { + em_phy_init_script(hw); + + /* Configure activity LED after PHY reset */ + led_ctrl = E1000_READ_REG(hw, LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= IGP_ACTIVITY_LED_ENABLE; + if(hw->mac_type == em_82547) + led_ctrl |= IGP_LED3_MODE; + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + } + /* Clear interrupt mask to stop board from generating interrupts */ DEBUGOUT("Masking off all interrupts\n"); E1000_WRITE_REG(hw, IMC, 0xffffffff); @@ -209,8 +318,8 @@ em_reset_hw(struct em_hw *hw) * Performs basic configuration of the adapter. * * hw - Struct containing variables accessed by shared code - * - * Assumes that the controller has previously been reset and is in a + * + * Assumes that the controller has previously been reset and is in a * post-reset uninitialized state. Initializes the receive address registers, * multicast table, and VLAN filter table. Calls routines to setup link * configuration and flow control settings. Clears all on-chip counters. Leaves @@ -235,7 +344,7 @@ em_init_hw(struct em_hw *hw) DEBUGOUT("Error Initializing Identification LED\n"); return ret_val; } - + /* Set the Media Type and exit with error if it is not valid. */ if(hw->mac_type != em_82543) { /* tbi_compatibility is only valid on 82543 */ @@ -338,13 +447,13 @@ em_init_hw(struct em_hw *hw) /****************************************************************************** * Configures flow control and link settings. - * + * * hw - Struct containing variables accessed by shared code - * + * * Determines which flow control settings to use. Calls the apropriate media- * specific link configuration function. Configures the flow control settings. * Assuming the adapter has a valid link partner, a valid link should be - * established. Assumes the hardware has previously been reset and the + * established. Assumes the hardware has previously been reset and the * transmitter and receiver are not enabled. *****************************************************************************/ int32_t @@ -364,7 +473,7 @@ em_setup_link(struct em_hw *hw) * control setting, then the variable hw->fc will * be initialized based on a value in the EEPROM. */ - if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) { + if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -372,7 +481,7 @@ em_setup_link(struct em_hw *hw) if(hw->fc == em_fc_default) { if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0) hw->fc = em_fc_none; - else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == + else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR) hw->fc = em_fc_tx_pause; else @@ -401,7 +510,7 @@ em_setup_link(struct em_hw *hw) * or em_phy_setup() is called. */ if(hw->mac_type == em_82543) { - ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << + ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << SWDPIO__EXT_SHIFT); E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); } @@ -427,7 +536,7 @@ em_setup_link(struct em_hw *hw) * these registers will be set to a default threshold that may be * adjusted later by the driver's runtime code. However, if the * ability to transmit pause frames in not enabled, then these - * registers will be set to 0. + * registers will be set to 0. */ if(!(hw->fc & em_fc_tx_pause)) { E1000_WRITE_REG(hw, FCRTL, 0); @@ -456,7 +565,7 @@ em_setup_link(struct em_hw *hw) * link. Assumes the hardware has been previously reset and the transmitter * and receiver are not enabled. *****************************************************************************/ -static int32_t +static int32_t em_setup_fiber_link(struct em_hw *hw) { uint32_t ctrl; @@ -468,29 +577,29 @@ em_setup_fiber_link(struct em_hw *hw) DEBUGFUNC("em_setup_fiber_link"); - /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be - * set when the optics detect a signal. On older adapters, it will be + /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be + * set when the optics detect a signal. On older adapters, it will be * cleared when there is a signal */ ctrl = E1000_READ_REG(hw, CTRL); if(hw->mac_type > em_82544) signal = E1000_CTRL_SWDPIN1; else signal = 0; - + /* Take the link out of reset */ ctrl &= ~(E1000_CTRL_LRST); - + em_config_collision_dist(hw); /* Check for a software override of the flow control settings, and setup * the device accordingly. If auto-negotiation is enabled, then software * will have to set the "PAUSE" bits to the correct value in the Tranmsit * Config Word Register (TXCW) and re-start auto-negotiation. However, if - * auto-negotiation is disabled, then software will have to manually + * auto-negotiation is disabled, then software will have to manually * configure the two flow control enable bits in the CTRL register. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, but + * 1: Rx flow control is enabled (we can receive pause frames, but * not send pause frames). * 2: Tx flow control is enabled (we can send pause frames but we do * not support receiving pause frames). @@ -502,8 +611,8 @@ em_setup_fiber_link(struct em_hw *hw) txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); break; case em_fc_rx_pause: - /* RX Flow control is enabled and TX Flow control is disabled by a - * software over-ride. Since there really isn't a way to advertise + /* RX Flow control is enabled and TX Flow control is disabled by a + * software over-ride. Since there really isn't a way to advertise * that we are capable of RX Pause ONLY, we will advertise that we * support both symmetric and asymmetric RX PAUSE. Later, we will * disable the adapter's ability to send PAUSE frames. @@ -511,7 +620,7 @@ em_setup_fiber_link(struct em_hw *hw) txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); break; case em_fc_tx_pause: - /* TX Flow control is enabled, and RX Flow control is disabled, by a + /* TX Flow control is enabled, and RX Flow control is disabled, by a * software over-ride. */ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); @@ -542,8 +651,8 @@ em_setup_fiber_link(struct em_hw *hw) msec_delay(1); /* If we have a signal (the cable is plugged in) then poll for a "Link-Up" - * indication in the Device Status Register. Time-out if a link isn't - * seen in 500 milliseconds seconds (Auto-negotiation should complete in + * indication in the Device Status Register. Time-out if a link isn't + * seen in 500 milliseconds seconds (Auto-negotiation should complete in * less than 500 milliseconds even if the other end is doing it in SW). */ if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) { @@ -554,7 +663,7 @@ em_setup_fiber_link(struct em_hw *hw) if(status & E1000_STATUS_LU) break; } if(i == (LINK_UP_TIMEOUT / 10)) { - /* AutoNeg failed to achieve a link, so we'll call + /* AutoNeg failed to achieve a link, so we'll call * em_check_for_link. This routine will force the link up if we * detect a signal. This will allow us to communicate with * non-autonegotiating link partners. @@ -582,10 +691,10 @@ em_setup_fiber_link(struct em_hw *hw) * * hw - Struct containing variables accessed by shared code ******************************************************************************/ -static int32_t +static int32_t em_setup_copper_link(struct em_hw *hw) { - uint32_t ctrl; + uint32_t ctrl, led_ctrl; int32_t ret_val; uint16_t i; uint16_t phy_data; @@ -615,6 +724,69 @@ em_setup_copper_link(struct em_hw *hw) } DEBUGOUT1("Phy ID = %x \n", hw->phy_id); +if (hw->phy_type == em_phy_igp) { + + ret_val = em_phy_reset(hw); + if(ret_val < 0) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } + + /* Wait 10ms for MAC to configure PHY from eeprom settings */ + msec_delay(15); + + if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + + /* Configure activity LED after PHY reset */ + led_ctrl = E1000_READ_REG(hw, LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= IGP_ACTIVITY_LED_ENABLE; + if(hw->mac_type == em_82547) + led_ctrl |= IGP_LED3_MODE; + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + + if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { + /* Disable SmartSpeed */ + if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + /* Set auto Master/Slave resolution process */ + if(em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + phy_data &= ~CR_1000T_MS_ENABLE; + if(em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + } + + if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + + /* Force MDI for IGP PHY */ + phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | IGP01E1000_PSCR_FORCE_MDI_MDIX); + + hw->mdix = 1; + + if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + +} else { /* Enable CRS on TX. This must be set for half-duplex operation. */ if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); @@ -688,7 +860,8 @@ em_setup_copper_link(struct em_hw *hw) DEBUGOUT("Error Resetting the PHY\n"); return ret_val; } - +} + /* Options: * autoneg = 1 (default) * PHY will advertise value(s) parsed from @@ -747,6 +920,7 @@ em_setup_copper_link(struct em_hw *hw) return ret_val; } } + hw->get_link_status = TRUE; } else { DEBUGOUT("Forcing speed and duplex\n"); ret_val = em_phy_force_speed_duplex(hw); @@ -1025,6 +1199,7 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); +if (hw->phy_type == em_phy_m88) { if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; @@ -1042,6 +1217,23 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Need to reset the PHY or these changes will be ignored */ mii_ctrl_reg |= MII_CR_RESET; +} else { + /* Clear Auto-Crossover to force MDI manually. IGP requires MDI + * forced whenever speed or duplex are forced. + */ + if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + + phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; + phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + + if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } +} /* Write back the modified PHY MII control register. */ if(em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) { @@ -1080,7 +1272,7 @@ em_phy_force_speed_duplex(struct em_hw *hw) } if(i == 0) { /* We didn't get link */ /* Reset the DSP and wait again for link. */ - + ret_val = em_phy_reset_dsp(hw); if(ret_val < 0) { DEBUGOUT("Error Resetting PHY DSP\n"); @@ -1104,7 +1296,8 @@ em_phy_force_speed_duplex(struct em_hw *hw) } } } - + +if (hw->phy_type == em_phy_m88) { /* Because we reset the PHY above, we need to re-force TX_CLK in the * Extended PHY Specific Control Register to 25MHz clock. This value * defaults back to a 2.5MHz clock when the PHY is reset. @@ -1131,6 +1324,7 @@ em_phy_force_speed_duplex(struct em_hw *hw) DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } +} return 0; } @@ -1147,6 +1341,8 @@ em_config_collision_dist(struct em_hw *hw) { uint32_t tctl; + DEBUGFUNC("em_config_collision_dist"); + tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_COLD; @@ -1183,6 +1379,26 @@ em_config_mac_to_phy(struct em_hw *hw) /* Set up duplex in the Device Control and Transmit Control * registers depending on negotiated values. */ +if (hw->phy_type == em_phy_igp) { + if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD; + else ctrl &= ~E1000_CTRL_FD; + + em_config_collision_dist(hw); + + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) + ctrl |= E1000_CTRL_SPD_1000; + else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_100MBPS) + ctrl |= E1000_CTRL_SPD_100; +} else { if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; @@ -1199,6 +1415,7 @@ em_config_mac_to_phy(struct em_hw *hw) ctrl |= E1000_CTRL_SPD_1000; else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) ctrl |= E1000_CTRL_SPD_100; +} /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); return 0; @@ -1206,7 +1423,7 @@ em_config_mac_to_phy(struct em_hw *hw) /****************************************************************************** * Forces the MAC's flow control settings. - * + * * hw - Struct containing variables accessed by shared code * * Sets the TFCE and RFCE bits in the device control register to reflect @@ -1273,7 +1490,7 @@ em_force_mac_fc(struct em_hw *hw) /****************************************************************************** * Configures flow control settings after link is established - * + * * hw - Struct containing variables accessed by shared code * * Should be called immediately after a valid link has been established. @@ -1495,9 +1712,9 @@ em_check_for_link(struct em_hw *hw) uint16_t lp_capability; DEBUGFUNC("em_check_for_link"); - - /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be - * set when the optics detect a signal. On older adapters, it will be + + /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be + * set when the optics detect a signal. On older adapters, it will be * cleared when there is a signal */ if(hw->mac_type > em_82544) signal = E1000_CTRL_SWDPIN1; @@ -1530,6 +1747,10 @@ em_check_for_link(struct em_hw *hw) if(phy_data & MII_SR_LINK_STATUS) { hw->get_link_status = FALSE; + /* Check if there was DownShift, must be checked immediately after + * link-up */ + em_check_downshift(hw); + } else { /* No link detected */ return 0; @@ -1558,7 +1779,7 @@ em_check_for_link(struct em_hw *hw) } } - /* Configure Flow Control now that Auto-Neg has completed. First, we + /* Configure Flow Control now that Auto-Neg has completed. First, we * need to restore the desired flow control settings because we may * have had to re-autoneg with a different link partner. */ @@ -1587,7 +1808,7 @@ em_check_for_link(struct em_hw *hw) NWAY_LPAR_100TX_HD_CAPS | NWAY_LPAR_100TX_FD_CAPS | NWAY_LPAR_100T4_CAPS)) { - /* If our link partner advertises anything in addition to + /* If our link partner advertises anything in addition to * gigabit, we do not need to enable TBI compatibility. */ if(hw->tbi_compatibility_on) { @@ -1791,7 +2012,7 @@ em_shift_out_mdi_bits(struct em_hw *hw, uint32_t mask; /* We need to shift "count" number of bits out to the PHY. So, the value - * in the "data" parameter will be shifted out to the PHY one bit at a + * in the "data" parameter will be shifted out to the PHY one bit at a * time. In order to do this, "data" must be broken down into bits. */ mask = 0x01; @@ -1828,7 +2049,7 @@ em_shift_out_mdi_bits(struct em_hw *hw, * * hw - Struct containing variables accessed by shared code * -* Bits are shifted in in MSB to LSB order. +* Bits are shifted in in MSB to LSB order. ******************************************************************************/ static uint16_t em_shift_in_mdi_bits(struct em_hw *hw) @@ -1843,7 +2064,7 @@ em_shift_in_mdi_bits(struct em_hw *hw) * These two bits are ignored by us and thrown away. Bits are "shifted in" * by raising the input to the Management Data Clock (setting the MDC bit), * and then reading the value of the MDIO bit. - */ + */ ctrl = E1000_READ_REG(hw, CTRL); /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */ @@ -1903,7 +2124,7 @@ em_read_phy_reg(struct em_hw *hw, * PHY to retrieve the desired data. */ mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) | - (phy_addr << E1000_MDIC_PHY_SHIFT) | + (phy_addr << E1000_MDIC_PHY_SHIFT) | (E1000_MDIC_OP_READ)); E1000_WRITE_REG(hw, MDIC, mdic); @@ -1941,7 +2162,7 @@ em_read_phy_reg(struct em_hw *hw, * READ operation is performed. These two bits are thrown away * followed by a shift in of 16 bits which contains the desired data. */ - mdic = ((reg_addr) | (phy_addr << 5) | + mdic = ((reg_addr) | (phy_addr << 5) | (PHY_OP_READ << 10) | (PHY_SOF << 12)); em_shift_out_mdi_bits(hw, mdic, 14); @@ -1985,7 +2206,7 @@ em_write_phy_reg(struct em_hw *hw, */ mdic = (((uint32_t) phy_data) | (reg_addr << E1000_MDIC_REG_SHIFT) | - (phy_addr << E1000_MDIC_PHY_SHIFT) | + (phy_addr << E1000_MDIC_PHY_SHIFT) | (E1000_MDIC_OP_WRITE)); E1000_WRITE_REG(hw, MDIC, mdic); @@ -2003,12 +2224,12 @@ em_write_phy_reg(struct em_hw *hw, } else { /* We'll need to use the SW defined pins to shift the write command * out to the PHY. We first send a preamble to the PHY to signal the - * beginning of the MII instruction. This is done by sending 32 + * beginning of the MII instruction. This is done by sending 32 * consecutive "1" bits. */ em_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); - /* Now combine the remaining required fields that will indicate a + /* Now combine the remaining required fields that will indicate a * write operation. We use this method instead of calling the * em_shift_out_mdi_bits routine for each field in the command. The * format of a MII write instruction is as follows: @@ -2021,6 +2242,7 @@ em_write_phy_reg(struct em_hw *hw, em_shift_out_mdi_bits(hw, mdic, 32); } + return 0; } @@ -2032,8 +2254,7 @@ em_write_phy_reg(struct em_hw *hw, void em_phy_hw_reset(struct em_hw *hw) { - uint32_t ctrl; - uint32_t ctrl_ext; + uint32_t ctrl, ctrl_ext, led_ctrl; DEBUGFUNC("em_phy_hw_reset"); @@ -2064,6 +2285,21 @@ em_phy_hw_reset(struct em_hw *hw) E1000_WRITE_FLUSH(hw); } usec_delay(150); + + if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { + if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) { + DEBUGOUT("PHY Write Error\n"); + return; + } + + /* Configure activity LED after PHY reset */ + led_ctrl = E1000_READ_REG(hw, LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= IGP_ACTIVITY_LED_ENABLE; + if(hw->mac_type == em_82547) + led_ctrl |= IGP_LED3_MODE; + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + } } /****************************************************************************** @@ -2090,6 +2326,9 @@ em_phy_reset(struct em_hw *hw) return -E1000_ERR_PHY; } usec_delay(1); + if (hw->phy_type == em_phy_igp) { + em_phy_init_script(hw); + } return 0; } @@ -2103,6 +2342,7 @@ em_detect_gig_phy(struct em_hw *hw) { uint16_t phy_id_high, phy_id_low; boolean_t match = FALSE; + int32_t phy_init_status; DEBUGFUNC("em_detect_gig_phy"); @@ -2112,7 +2352,11 @@ em_detect_gig_phy(struct em_hw *hw) return -E1000_ERR_PHY; } hw->phy_id = (uint32_t) (phy_id_high << 16); - usec_delay(2); +#ifdef MPW3 + /* Tabor/Mpw - changed from 2 to 20 since it did not read the low word in + * the mpw, might be fixed in A0 */ +#endif + usec_delay(20); if(em_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; @@ -2120,23 +2364,39 @@ em_detect_gig_phy(struct em_hw *hw) hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK); hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK; +#ifdef MPW3 /* Tabor MPW3 workaround, expect to be removed in Tabor A0 */ + /* workaround for MPW - IGP PHYID is incorrect! */ + if(hw->phy_id == 0x02A80400) + hw->phy_id = 0x02A80380; + +#endif switch(hw->mac_type) { case em_82543: if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE; break; case em_82544: if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE; +#ifdef MPW3 /* MPW3 only, expected to be removed in Tabor A0 */ + /* MPW driver only - IGP should work with Cordova */ + if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; +#endif break; case em_82540: case em_82545: case em_82546: if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE; break; + case em_82541: + case em_82547: + if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; + break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; } - if(match) { + phy_init_status = em_set_phy_type(hw); + + if ((match) && (phy_init_status == E1000_SUCCESS)) { DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id); return 0; } @@ -2154,7 +2414,7 @@ em_phy_reset_dsp(struct em_hw *hw) { int32_t ret_val = -E1000_ERR_PHY; DEBUGFUNC("em_phy_reset_dsp"); - + do { if(em_write_phy_reg(hw, 29, 0x001d) < 0) break; if(em_write_phy_reg(hw, 30, 0x00c1) < 0) break; @@ -2167,6 +2427,133 @@ em_phy_reset_dsp(struct em_hw *hw) } /****************************************************************************** +* Get PHY information from various PHY registers for igp PHY only. +* +* hw - Struct containing variables accessed by shared code +* phy_info - PHY information structure +******************************************************************************/ +int32_t +em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info) +{ + uint16_t phy_data, polarity, min_length, max_length, average; + + DEBUGFUNC("em_phy_igp_get_info"); + + /* The downshift status is checked only once, after link is established, + * and it stored in the hw->speed_downgraded parameter. */ + phy_info->downshift = hw->speed_downgraded; + + /* IGP01E1000 does not need to support it. */ + phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_normal; + + /* IGP01E1000 always correct polarity reversal */ + phy_info->polarity_correction = em_polarity_reversal_enabled; + + /* Check polarity status */ + if(em_check_polarity(hw, &polarity) < 0) + return -E1000_ERR_PHY; + + phy_info->cable_polarity = polarity; + + if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >> + IGP01E1000_PSSR_MDIX_SHIFT; + + if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + /* Local/Remote Receiver Information are only valid at 1000 Mbps */ + if(em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + + /* Get cable length */ + if(em_get_cable_length(hw, &min_length, &max_length) < 0) + return -E1000_ERR_PHY; + + /* transalte to old method */ + average = (max_length + min_length) / 2; + + if(average <= em_igp_cable_length_50) + phy_info->cable_length = em_cable_length_50; + else if(average <= em_igp_cable_length_80) + phy_info->cable_length = em_cable_length_50_80; + else if(average <= em_igp_cable_length_110) + phy_info->cable_length = em_cable_length_80_110; + else if(average <= em_igp_cable_length_140) + phy_info->cable_length = em_cable_length_110_140; + else + phy_info->cable_length = em_cable_length_140; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** +* Get PHY information from various PHY registers fot m88 PHY only. +* +* hw - Struct containing variables accessed by shared code +* phy_info - PHY information structure +******************************************************************************/ +int32_t +em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info) +{ + uint16_t phy_data, polarity; + + DEBUGFUNC("em_phy_m88_get_info"); + + /* The downshift status is checked only once, after link is established, + * and it stored in the hw->speed_downgraded parameter. */ + phy_info->downshift = hw->speed_downgraded; + + if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->extended_10bt_distance = + (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> + M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; + phy_info->polarity_correction = + (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >> + M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; + + /* Check polarity status */ + if(em_check_polarity(hw, &polarity) < 0) + return -E1000_ERR_PHY; + + phy_info->cable_polarity = polarity; + + if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >> + M88E1000_PSSR_MDIX_SHIFT; + + if(phy_data & M88E1000_PSSR_1000MBS) { + /* Cable Length Estimation and Local/Remote Receiver Informatoion + * are only valid at 1000 Mbps + */ + phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT); + + if(em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + + phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** * Get PHY information from various PHY registers * * hw - Struct containing variables accessed by shared code @@ -2176,7 +2563,6 @@ int32_t em_phy_get_info(struct em_hw *hw, struct em_phy_info *phy_info) { - int32_t ret_val = -E1000_ERR_PHY; uint16_t phy_data; DEBUGFUNC("em_phy_get_info"); @@ -2184,6 +2570,7 @@ em_phy_get_info(struct em_hw *hw, phy_info->cable_length = em_cable_length_undefined; phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_undefined; phy_info->cable_polarity = em_rev_polarity_undefined; + phy_info->downshift = em_downshift_undefined; phy_info->polarity_correction = em_polarity_reversal_undefined; phy_info->mdix_mode = em_auto_x_mode_undefined; phy_info->local_rx = em_1000t_rx_status_undefined; @@ -2194,47 +2581,23 @@ em_phy_get_info(struct em_hw *hw, return -E1000_ERR_CONFIG; } - do { - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break; - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break; - if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) { - DEBUGOUT("PHY info is only valid if link is up\n"); - return -E1000_ERR_CONFIG; - } - - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) - break; - phy_info->extended_10bt_distance = - (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> - M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; - phy_info->polarity_correction = - (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >> - M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; - - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) - break; - phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> - M88E1000_PSSR_REV_POLARITY_SHIFT; - phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >> - M88E1000_PSSR_MDIX_SHIFT; - if(phy_data & M88E1000_PSSR_1000MBS) { - /* Cable Length Estimation and Local/Remote Receiver Informatoion - * are only valid at 1000 Mbps - */ - phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> - M88E1000_PSSR_CABLE_LENGTH_SHIFT); - if(em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) - break; - phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> - SR_1000T_LOCAL_RX_STATUS_SHIFT; - phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >> - SR_1000T_REMOTE_RX_STATUS_SHIFT; - } - ret_val = 0; - } while(0); + if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) { + DEBUGOUT("PHY info is only valid if link is up\n"); + return -E1000_ERR_CONFIG; + } - if(ret_val < 0) DEBUGOUT("PHY Read Error\n"); - return ret_val; + if (hw->phy_type == em_phy_igp) + return em_phy_igp_get_info(hw, phy_info); + else + return em_phy_m88_get_info(hw, phy_info); } int32_t @@ -2251,6 +2614,107 @@ em_validate_mdi_setting(struct em_hw *hw) } +/****************************************************************************** + * Sets up eeprom variables in the hw struct. Must be called after mac_type + * is configured. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +void +em_init_eeprom_params(struct em_hw *hw) +{ + struct em_eeprom_info *eeprom = &hw->eeprom; + uint32_t eecd = E1000_READ_REG(hw, EECD); + uint16_t eeprom_size; + + DEBUGFUNC("em_init_eeprom_params"); + + switch (hw->mac_type) { + case em_82542_rev2_0: + case em_82542_rev2_1: + case em_82543: + case em_82544: + eeprom->type = em_eeprom_microwire; + eeprom->word_size = 64; + eeprom->opcode_bits = 3; + eeprom->address_bits = 6; + eeprom->delay_usec = 50; + break; + case em_82540: + case em_82545: + case em_82546: + eeprom->type = em_eeprom_microwire; + eeprom->opcode_bits = 3; + eeprom->delay_usec = 50; + if(eecd & E1000_EECD_SIZE) { + eeprom->word_size = 256; + eeprom->address_bits = 8; + } else { + eeprom->word_size = 64; + eeprom->address_bits = 6; + } + break; + case em_82541: + case em_82547: + default: + if (eecd & E1000_EECD_TYPE) { + eeprom->type = em_eeprom_spi; + eeprom->opcode_bits = 8; + eeprom->delay_usec = 1; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->page_size = 32; + eeprom->address_bits = 16; + } else { + eeprom->page_size = 8; + eeprom->address_bits = 8; + } + } else { + eeprom->type = em_eeprom_microwire; + eeprom->opcode_bits = 3; + eeprom->delay_usec = 50; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->word_size = 256; + eeprom->address_bits = 8; + } else { + eeprom->word_size = 64; + eeprom->address_bits = 6; + } + } + break; + } + + if (eeprom->type == em_eeprom_spi) { + eeprom->word_size = 64; + if (em_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) { + eeprom_size &= EEPROM_SIZE_MASK; + + switch (eeprom_size) { + case EEPROM_SIZE_16KB: + eeprom->word_size = 8192; + break; + case EEPROM_SIZE_8KB: + eeprom->word_size = 4096; + break; + case EEPROM_SIZE_4KB: + eeprom->word_size = 2048; + break; + case EEPROM_SIZE_2KB: + eeprom->word_size = 1024; + break; + case EEPROM_SIZE_1KB: + eeprom->word_size = 512; + break; + case EEPROM_SIZE_512B: + eeprom->word_size = 256; + break; + case EEPROM_SIZE_128B: + default: + eeprom->word_size = 64; + break; + } + } + } +} /****************************************************************************** * Raises the EEPROM's clock input. @@ -2268,26 +2732,26 @@ em_raise_ee_clk(struct em_hw *hw, *eecd = *eecd | E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + usec_delay(hw->eeprom.delay_usec); } /****************************************************************************** * Lowers the EEPROM's clock input. * - * hw - Struct containing variables accessed by shared code + * hw - Struct containing variables accessed by shared code * eecd - EECD's current value *****************************************************************************/ static void em_lower_ee_clk(struct em_hw *hw, uint32_t *eecd) { - /* Lower the clock input to the EEPROM (by clearing the SK bit), and then - * wait 50 microseconds. + /* Lower the clock input to the EEPROM (by clearing the SK bit), and then + * wait 50 microseconds. */ *eecd = *eecd & ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + usec_delay(hw->eeprom.delay_usec); } /****************************************************************************** @@ -2302,16 +2766,21 @@ em_shift_out_ee_bits(struct em_hw *hw, uint16_t data, uint16_t count) { + struct em_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd; uint32_t mask; /* We need to shift "count" bits out to the EEPROM. So, value in the * "data" parameter will be shifted out to the EEPROM one bit at a time. - * In order to do this, "data" must be broken down into bits. + * In order to do this, "data" must be broken down into bits. */ mask = 0x01 << (count - 1); eecd = E1000_READ_REG(hw, EECD); - eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); + if (eeprom->type == em_eeprom_microwire) { + eecd &= ~E1000_EECD_DO; + } else if (eeprom->type == em_eeprom_spi) { + eecd |= E1000_EECD_DO; + } do { /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1", * and then raising and then lowering the clock (the SK bit controls @@ -2326,7 +2795,7 @@ em_shift_out_ee_bits(struct em_hw *hw, E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + usec_delay(eeprom->delay_usec); em_raise_ee_clk(hw, &eecd); em_lower_ee_clk(hw, &eecd); @@ -2346,7 +2815,7 @@ em_shift_out_ee_bits(struct em_hw *hw, * hw - Struct containing variables accessed by shared code *****************************************************************************/ static uint16_t -em_shift_in_ee_bits(struct em_hw *hw) +em_shift_in_ee_bits(struct em_hw *hw, uint16_t count) { uint32_t eecd; uint32_t i; @@ -2364,7 +2833,7 @@ em_shift_in_ee_bits(struct em_hw *hw) eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); data = 0; - for(i = 0; i < 16; i++) { + for(i = 0; i < count; i++) { data = data << 1; em_raise_ee_clk(hw, &eecd); @@ -2385,104 +2854,196 @@ em_shift_in_ee_bits(struct em_hw *hw) * * hw - Struct containing variables accessed by shared code * - * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This + * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This * function should be called before issuing a command to the EEPROM. *****************************************************************************/ -static void -em_setup_eeprom(struct em_hw *hw) +static int32_t +em_acquire_eeprom(struct em_hw *hw) { - uint32_t eecd; + struct em_eeprom_info *eeprom = &hw->eeprom; + uint32_t eecd, i=0; + + DEBUGFUNC("em_acquire_eeprom"); eecd = E1000_READ_REG(hw, EECD); - /* Clear SK and DI */ - eecd &= ~(E1000_EECD_SK | E1000_EECD_DI); - E1000_WRITE_REG(hw, EECD, eecd); + /* Request EEPROM Access */ + if(hw->mac_type > em_82544) { + eecd |= E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + eecd = E1000_READ_REG(hw, EECD); + while((!(eecd & E1000_EECD_GNT)) && + (i < E1000_EEPROM_GRANT_ATTEMPTS)) { + i++; + usec_delay(5); + eecd = E1000_READ_REG(hw, EECD); + } + if(!(eecd & E1000_EECD_GNT)) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + DEBUGOUT("Could not acquire EEPROM grant\n"); + return -E1000_ERR_EEPROM; + } + } - /* Set CS */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, EECD, eecd); + /* Setup EEPROM for Read/Write */ + + if (eeprom->type == em_eeprom_microwire) { + /* Clear SK and DI */ + eecd &= ~(E1000_EECD_DI | E1000_EECD_SK); + E1000_WRITE_REG(hw, EECD, eecd); + + /* Set CS */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + } else if (eeprom->type == em_eeprom_spi) { + /* Clear SK and CS */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(hw, EECD, eecd); + usec_delay(1); + } + + return E1000_SUCCESS; } /****************************************************************************** * Returns EEPROM to a "standby" state - * + * * hw - Struct containing variables accessed by shared code *****************************************************************************/ static void em_standby_eeprom(struct em_hw *hw) { + struct em_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd; eecd = E1000_READ_REG(hw, EECD); - /* Deselct EEPROM */ - eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + if(eeprom->type == em_eeprom_microwire) { + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); - /* Clock high */ - eecd |= E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + /* Clock high */ + eecd |= E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); - /* Select EEPROM */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + /* Select EEPROM */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); - /* Clock low */ - eecd &= ~E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + /* Clock low */ + eecd &= ~E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); + } else if(eeprom->type == em_eeprom_spi) { + /* Toggle CS to flush commands */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); + eecd &= ~E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); + } } /****************************************************************************** - * Raises then lowers the EEPROM's clock pin + * Terminates a command by inverting the EEPROM's chip select pin * * hw - Struct containing variables accessed by shared code *****************************************************************************/ static void -em_clock_eeprom(struct em_hw *hw) +em_release_eeprom(struct em_hw *hw) { uint32_t eecd; + DEBUGFUNC("em_release_eeprom"); + eecd = E1000_READ_REG(hw, EECD); - /* Rising edge of clock */ - eecd |= E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + if (hw->eeprom.type == em_eeprom_spi) { + eecd |= E1000_EECD_CS; /* Pull CS high */ + eecd &= ~E1000_EECD_SK; /* Lower SCK */ - /* Falling edge of clock */ - eecd &= ~E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + E1000_WRITE_REG(hw, EECD, eecd); + + usec_delay(hw->eeprom.delay_usec); + } else if(hw->eeprom.type == em_eeprom_microwire) { + /* cleanup eeprom */ + + /* CS on Microwire is active-high */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); + + E1000_WRITE_REG(hw, EECD, eecd); + + /* Rising edge of clock */ + eecd |= E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(hw->eeprom.delay_usec); + + /* Falling edge of clock */ + eecd &= ~E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(hw->eeprom.delay_usec); + } + + /* Stop requesting EEPROM access */ + if(hw->mac_type > em_82544) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + } } /****************************************************************************** - * Terminates a command by lowering the EEPROM's chip select pin + * Reads a 16 bit word from the EEPROM. * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -static void -em_cleanup_eeprom(struct em_hw *hw) +int32_t +em_spi_eeprom_ready(struct em_hw *hw) { - uint32_t eecd; + uint16_t retry_count = 0; + uint8_t spi_stat_reg; - eecd = E1000_READ_REG(hw, EECD); + DEBUGFUNC("em_spi_eeprom_ready"); - eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); + /* Read "Status Register" repeatedly until the LSB is cleared. The + * EEPROM will signal that the command has been completed by clearing + * bit 0 of the internal status register. If it's not cleared within + * 5 milliseconds, then error out. + */ + retry_count = 0; + do { + em_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI, + hw->eeprom.opcode_bits); + spi_stat_reg = (uint8_t)em_shift_in_ee_bits(hw, 8); + if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI)) + break; - E1000_WRITE_REG(hw, EECD, eecd); + usec_delay(5); + retry_count += 5; + + } while(retry_count < EEPROM_MAX_RETRY_SPI); + + /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and + * only 0-5mSec on 5V devices) + */ + if(retry_count >= EEPROM_MAX_RETRY_SPI) { + DEBUGOUT("SPI EEPROM Status error\n"); + return -E1000_ERR_EEPROM; + } - em_clock_eeprom(hw); + return E1000_SUCCESS; } /****************************************************************************** @@ -2490,71 +3051,76 @@ em_cleanup_eeprom(struct em_hw *hw) * * hw - Struct containing variables accessed by shared code * offset - offset of word in the EEPROM to read - * data - word read from the EEPROM + * data - word read from the EEPROM + * words - number of words to read *****************************************************************************/ int32_t em_read_eeprom(struct em_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data) { - uint32_t eecd; + struct em_eeprom_info *eeprom = &hw->eeprom; uint32_t i = 0; - boolean_t large_eeprom = FALSE; DEBUGFUNC("em_read_eeprom"); - /* Request EEPROM Access */ - if(hw->mac_type > em_82544) { - eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE; - eecd |= E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - eecd = E1000_READ_REG(hw, EECD); - while((!(eecd & E1000_EECD_GNT)) && (i < 100)) { - i++; - usec_delay(5); - eecd = E1000_READ_REG(hw, EECD); - } - if(!(eecd & E1000_EECD_GNT)) { - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; - } + /* A check for invalid values: offset too large, too many words, and not + * enough words. + */ + if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) || + (words == 0)) { + DEBUGOUT("\"words\" parameter out of bounds\n"); + return -E1000_ERR_EEPROM; } - /* Prepare the EEPROM for reading */ - em_setup_eeprom(hw); + /* Prepare the EEPROM for reading */ + if (em_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; - /* Send the READ command (opcode + addr) */ - em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3); - if(large_eeprom) { - /* If we have a 256 word EEPROM, there are 8 address bits */ - em_shift_out_ee_bits(hw, offset, 8); - } else { - /* If we have a 64 word EEPROM, there are 6 address bits */ - em_shift_out_ee_bits(hw, offset, 6); - } + if(eeprom->type == em_eeprom_spi) { + uint8_t read_opcode = EEPROM_READ_OPCODE_SPI; - /* Read the data */ - *data = em_shift_in_ee_bits(hw); + if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM; - /* End this read operation */ - em_standby_eeprom(hw); + em_standby_eeprom(hw); - /* Stop requesting EEPROM access */ - if(hw->mac_type > em_82544) { - eecd = E1000_READ_REG(hw, EECD); - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); + /* Some SPI eeproms use the 8th address bit embedded in the opcode */ + if((eeprom->address_bits == 8) && (offset >= 128)) + read_opcode |= EEPROM_A8_OPCODE_SPI; + + /* Send the READ command (opcode + addr) */ + em_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits); + em_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits); + } + else if(eeprom->type == em_eeprom_microwire) { + /* Send the READ command (opcode + addr) */ + em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE, + eeprom->opcode_bits); + em_shift_out_ee_bits(hw, offset, eeprom->address_bits); } + /* Read the data. The address of the eeprom internally increments with + * each word (microwire) or byte (spi) being read, saving on the overhead + * of eeprom setup and tear-down. The address counter will roll over if + * reading beyond the size of the eeprom, thus allowing the entire memory + * to be read starting from any offset. */ + for (i = 0; i < words; i++) { + uint16_t word_in = em_shift_in_ee_bits(hw, 16); + if (eeprom->type == em_eeprom_spi) + word_in = (word_in >> 8) | (word_in << 8); + data[i] = word_in; + } + + /* End this read operation */ + em_release_eeprom(hw); + return 0; } /****************************************************************************** * Verifies that the EEPROM has a valid checksum - * + * * hw - Struct containing variables accessed by shared code * * Reads the first 64 16 bit words of the EEPROM and sums the values read. @@ -2570,7 +3136,7 @@ em_validate_eeprom_checksum(struct em_hw *hw) DEBUGFUNC("em_validate_eeprom_checksum"); for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { - if(em_read_eeprom(hw, i, &eeprom_data) < 0) { + if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2580,7 +3146,7 @@ em_validate_eeprom_checksum(struct em_hw *hw) if(checksum == (uint16_t) EEPROM_SUM) { return 0; } else { - DEBUGOUT("EEPROM Checksum Invalid\n"); + DEBUGOUT("EEPROM Checksum Invalid\n"); return -E1000_ERR_EEPROM; } } @@ -2602,14 +3168,14 @@ em_update_eeprom_checksum(struct em_hw *hw) DEBUGFUNC("em_update_eeprom_checksum"); for(i = 0; i < EEPROM_CHECKSUM_REG; i++) { - if(em_read_eeprom(hw, i, &eeprom_data) < 0) { + if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } checksum += eeprom_data; } checksum = (uint16_t) EEPROM_SUM - checksum; - if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum) < 0) { + if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) { DEBUGOUT("EEPROM Write Error\n"); return -E1000_ERR_EEPROM; } @@ -2617,118 +3183,201 @@ em_update_eeprom_checksum(struct em_hw *hw) } /****************************************************************************** - * Writes a 16 bit word to a given offset in the EEPROM. + * Parent function for writing words to the different EEPROM types. * * hw - Struct containing variables accessed by shared code * offset - offset within the EEPROM to be written to - * data - 16 bit word to be writen to the EEPROM + * words - number of words to write + * data - 16 bit word to be written to the EEPROM * - * If em_update_eeprom_checksum is not called after this function, the + * If em_update_eeprom_checksum is not called after this function, the * EEPROM will most likely contain an invalid checksum. *****************************************************************************/ int32_t em_write_eeprom(struct em_hw *hw, uint16_t offset, - uint16_t data) + uint16_t words, + uint16_t *data) { - uint32_t eecd; - uint32_t i = 0; + struct em_eeprom_info *eeprom = &hw->eeprom; int32_t status = 0; - boolean_t large_eeprom = FALSE; DEBUGFUNC("em_write_eeprom"); - /* Request EEPROM Access */ - if(hw->mac_type > em_82544) { - eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE; - eecd |= E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - eecd = E1000_READ_REG(hw, EECD); - while((!(eecd & E1000_EECD_GNT)) && (i < 100)) { - i++; - usec_delay(5); - eecd = E1000_READ_REG(hw, EECD); - } - if(!(eecd & E1000_EECD_GNT)) { - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; - } + /* A check for invalid values: offset too large, too many words, and not + * enough words. + */ + if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) || + (words == 0)) { + DEBUGOUT("\"words\" parameter out of bounds\n"); + return -E1000_ERR_EEPROM; } /* Prepare the EEPROM for writing */ - em_setup_eeprom(hw); + if (em_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; - /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) command - * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This puts the EEPROM - * into write/erase mode. - */ - em_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5); - if(large_eeprom) - em_shift_out_ee_bits(hw, 0, 6); + if(eeprom->type == em_eeprom_microwire) + status = em_write_eeprom_microwire(hw, offset, words, data); else - em_shift_out_ee_bits(hw, 0, 4); + status = em_write_eeprom_spi(hw, offset, words, data); - /* Prepare the EEPROM */ - em_standby_eeprom(hw); + /* Done with writing */ + em_release_eeprom(hw); - /* Send the Write command (3-bit opcode + addr) */ - em_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3); - if(large_eeprom) - /* If we have a 256 word EEPROM, there are 8 address bits */ - em_shift_out_ee_bits(hw, offset, 8); - else - /* If we have a 64 word EEPROM, there are 6 address bits */ - em_shift_out_ee_bits(hw, offset, 6); + return status; +} + +/****************************************************************************** + * Writes a 16 bit word to a given offset in an SPI EEPROM. + * + * hw - Struct containing variables accessed by shared code + * offset - offset within the EEPROM to be written to + * words - number of words to write + * data - pointer to array of 8 bit words to be written to the EEPROM + * + *****************************************************************************/ +int32_t +em_write_eeprom_spi(struct em_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) +{ + struct em_eeprom_info *eeprom = &hw->eeprom; + uint16_t widx = 0; - /* Send the data */ - em_shift_out_ee_bits(hw, data, 16); + DEBUGFUNC("em_write_eeprom_spi"); - /* Toggle the CS line. This in effect tells to EEPROM to actually execute - * the command in question. - */ - em_standby_eeprom(hw); + while (widx < words) { + uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI; - /* Now read DO repeatedly until is high (equal to '1'). The EEEPROM will - * signal that the command has been completed by raising the DO signal. - * If DO does not go high in 10 milliseconds, then error out. - */ - for(i = 0; i < 200; i++) { - eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_DO) break; - usec_delay(50); - } - if(i == 200) { - DEBUGOUT("EEPROM Write did not complete\n"); - status = -E1000_ERR_EEPROM; + if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM; + + em_standby_eeprom(hw); + + /* Send the WRITE ENABLE command (8 bit opcode ) */ + em_shift_out_ee_bits(hw, EEPROM_WREN_OPCODE_SPI, + eeprom->opcode_bits); + + em_standby_eeprom(hw); + + /* Some SPI eeproms use the 8th address bit embedded in the opcode */ + if((eeprom->address_bits == 8) && (offset >= 128)) + write_opcode |= EEPROM_A8_OPCODE_SPI; + + /* Send the Write command (8-bit opcode + addr) */ + em_shift_out_ee_bits(hw, write_opcode, eeprom->opcode_bits); + + em_shift_out_ee_bits(hw, (uint16_t)((offset + widx)*2), + eeprom->address_bits); + + /* Send the data */ + + /* Loop to allow for up to whole page write (32 bytes) of eeprom */ + while (widx < words) { + uint16_t word_out = data[widx]; + word_out = (word_out >> 8) | (word_out << 8); + em_shift_out_ee_bits(hw, word_out, 16); + widx++; + + /* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE + * operation, while the smaller eeproms are capable of an 8-byte + * PAGE WRITE operation. Break the inner loop to pass new address + */ + if((((offset + widx)*2) % eeprom->page_size) == 0) { + em_standby_eeprom(hw); + break; + } + } } - /* Recover from write */ - em_standby_eeprom(hw); + return E1000_SUCCESS; +} - /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) command - * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This takes the EEPROM - * out of write/erase mode. +/****************************************************************************** + * Writes a 16 bit word to a given offset in a Microwire EEPROM. + * + * hw - Struct containing variables accessed by shared code + * offset - offset within the EEPROM to be written to + * words - number of words to write + * data - pointer to array of 16 bit words to be written to the EEPROM + * + *****************************************************************************/ +int32_t +em_write_eeprom_microwire(struct em_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) +{ + struct em_eeprom_info *eeprom = &hw->eeprom; + uint32_t eecd; + uint16_t words_written = 0; + uint16_t i = 0; + + DEBUGFUNC("em_write_eeprom_microwire"); + + /* Send the write enable command to the EEPROM (3-bit opcode plus + * 6/8-bit dummy address beginning with 11). It's less work to include + * the 11 of the dummy address as part of the opcode than it is to shift + * it over the correct number of bits for the address. This puts the + * EEPROM into write/erase mode. */ - em_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5); - if(large_eeprom) - em_shift_out_ee_bits(hw, 0, 6); - else - em_shift_out_ee_bits(hw, 0, 4); + em_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE_MICROWIRE, + (uint16_t)(eeprom->opcode_bits + 2)); - /* Done with writing */ - em_cleanup_eeprom(hw); + em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2)); - /* Stop requesting EEPROM access */ - if(hw->mac_type > em_82544) { - eecd = E1000_READ_REG(hw, EECD); - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); + /* Prepare the EEPROM */ + em_standby_eeprom(hw); + + while (words_written < words) { + /* Send the Write command (3-bit opcode + addr) */ + em_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE_MICROWIRE, + eeprom->opcode_bits); + + em_shift_out_ee_bits(hw, (uint16_t)(offset + words_written), + eeprom->address_bits); + + /* Send the data */ + em_shift_out_ee_bits(hw, data[words_written], 16); + + /* Toggle the CS line. This in effect tells the EEPROM to execute + * the previous command. + */ + em_standby_eeprom(hw); + + /* Read DO repeatedly until it is high (equal to '1'). The EEPROM will + * signal that the command has been completed by raising the DO signal. + * If DO does not go high in 10 milliseconds, then error out. + */ + for(i = 0; i < 200; i++) { + eecd = E1000_READ_REG(hw, EECD); + if(eecd & E1000_EECD_DO) break; + usec_delay(50); + } + if(i == 200) { + DEBUGOUT("EEPROM Write did not complete\n"); + return -E1000_ERR_EEPROM; + } + + /* Recover from write */ + em_standby_eeprom(hw); + + words_written++; } - return status; + /* Send the write disable command to the EEPROM (3-bit opcode plus + * 6/8-bit dummy address beginning with 10). It's less work to include + * the 10 of the dummy address as part of the opcode than it is to shift + * it over the correct number of bits for the address. This takes the + * EEPROM out of write/erase mode. + */ + em_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE_MICROWIRE, + (uint16_t)(eeprom->opcode_bits + 2)); + + em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2)); + + return 0; } /****************************************************************************** @@ -2747,7 +3396,7 @@ em_read_part_num(struct em_hw *hw, DEBUGFUNC("em_read_part_num"); /* Get word 0 from EEPROM */ - if(em_read_eeprom(hw, offset, &eeprom_data) < 0) { + if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2755,7 +3404,7 @@ em_read_part_num(struct em_hw *hw, *part_num = (uint32_t) (eeprom_data << 16); /* Get word 1 from EEPROM */ - if(em_read_eeprom(hw, ++offset, &eeprom_data) < 0) { + if(em_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2781,7 +3430,7 @@ em_read_mac_addr(struct em_hw * hw) for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) { offset = i >> 1; - if(em_read_eeprom(hw, offset, &eeprom_data) < 0) { + if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2803,7 +3452,7 @@ em_read_mac_addr(struct em_hw * hw) /****************************************************************************** * Initializes receive address filters. * - * hw - Struct containing variables accessed by shared code + * hw - Struct containing variables accessed by shared code * * Places the MAC address in receive address register 0 and clears the rest * of the receive addresss registers. Clears the multicast table. Assumes @@ -2848,7 +3497,7 @@ em_init_rx_addrs(struct em_hw *hw) * * The given list replaces any existing list. Clears the last 15 receive * address registers and the multicast table. Uses receive address registers - * for the first 15 multicast addresses, and hashes the rest into the + * for the first 15 multicast addresses, and hashes the rest into the * multicast table. *****************************************************************************/ void @@ -2897,7 +3546,7 @@ em_mc_addr_list_update(struct em_hw *hw, DEBUGOUT1(" Hash value = 0x%03X\n", hash_value); /* Place this multicast address in the RAR if there is room, * - * else put it in the MTA + * else put it in the MTA */ if(rar_used_count < E1000_RAR_ENTRIES) { em_rar_set(hw, @@ -2915,7 +3564,7 @@ em_mc_addr_list_update(struct em_hw *hw, * Hashes an address to determine its location in the multicast table * * hw - Struct containing variables accessed by shared code - * mc_addr - the multicast address to hash + * mc_addr - the multicast address to hash *****************************************************************************/ uint32_t em_hash_mc_addr(struct em_hw *hw, @@ -2924,7 +3573,7 @@ em_hash_mc_addr(struct em_hw *hw, uint32_t hash_value = 0; /* The portion of the address that is used for the hash table is - * determined by the mc_filter_type setting. + * determined by the mc_filter_type setting. */ switch (hw->mc_filter_type) { /* [0] [1] [2] [3] [4] [5] @@ -2967,12 +3616,12 @@ em_mta_set(struct em_hw *hw, uint32_t mta; uint32_t temp; - /* The MTA is a register array of 128 32-bit registers. - * It is treated like an array of 4096 bits. We want to set + /* The MTA is a register array of 128 32-bit registers. + * It is treated like an array of 4096 bits. We want to set * bit BitArray[hash_value]. So we figure out what register * the bit is in, read it, OR in the new bit, then write - * back the new value. The register is determined by the - * upper 7 bits of the hash value and the bit within that + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that * register are determined by the lower 5 bits of the value. */ hash_reg = (hash_value >> 5) & 0x7F; @@ -3010,7 +3659,7 @@ em_rar_set(struct em_hw *hw, uint32_t rar_low, rar_high; /* HW expects these in little endian so we reverse the byte order - * from network order (big endian) to little endian + * from network order (big endian) to little endian */ rar_low = ((uint32_t) addr[0] | ((uint32_t) addr[1] << 8) | @@ -3068,24 +3717,24 @@ em_id_led_init(struct em_hw * hw) const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF; uint16_t eeprom_data, i, temp; const uint16_t led_mask = 0x0F; - + DEBUGFUNC("em_id_led_init"); - + if(hw->mac_type < em_82540) { /* Nothing to do */ return 0; } - + ledctl = E1000_READ_REG(hw, LEDCTL); hw->ledctl_default = ledctl; hw->ledctl_mode1 = hw->ledctl_default; hw->ledctl_mode2 = hw->ledctl_default; - - if(em_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, &eeprom_data) < 0) { + + if(em_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } - if((eeprom_data== ID_LED_RESERVED_0000) || + if((eeprom_data== ID_LED_RESERVED_0000) || (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT; for(i = 0; i < 4; i++) { temp = (eeprom_data >> (i << 2)) & led_mask; @@ -3136,9 +3785,9 @@ int32_t em_setup_led(struct em_hw *hw) { uint32_t ledctl; - + DEBUGFUNC("em_setup_led"); - + switch(hw->device_id) { case E1000_DEV_ID_82542: case E1000_DEV_ID_82543GC_FIBER: @@ -3156,7 +3805,7 @@ em_setup_led(struct em_hw *hw) hw->ledctl_default = ledctl; /* Turn off LED0 */ ledctl &= ~(E1000_LEDCTL_LED0_IVRT | - E1000_LEDCTL_LED0_BLINK | + E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED0_MODE_MASK); ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT); E1000_WRITE_REG(hw, LEDCTL, ledctl); @@ -3168,6 +3817,9 @@ em_setup_led(struct em_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); break; default: @@ -3206,6 +3858,9 @@ em_cleanup_led(struct em_hw *hw) case E1000_DEV_ID_82545EM_FIBER: case E1000_DEV_ID_82546EB_COPPER: case E1000_DEV_ID_82546EB_FIBER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: /* Restore LEDCTL settings */ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default); break; @@ -3215,7 +3870,7 @@ em_cleanup_led(struct em_hw *hw) } return 0; } - + /****************************************************************************** * Turns on the software controllable LED * @@ -3257,6 +3912,9 @@ em_led_on(struct em_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2); break; default: @@ -3307,6 +3965,9 @@ em_led_off(struct em_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); break; default: @@ -3317,7 +3978,7 @@ em_led_off(struct em_hw *hw) } /****************************************************************************** - * Clears all hardware statistics counters. + * Clears all hardware statistics counters. * * hw - Struct containing variables accessed by shared code *****************************************************************************/ @@ -3436,7 +4097,7 @@ em_update_adaptive(struct em_hw *hw) DEBUGFUNC("em_update_adaptive"); if(hw->adaptive_ifs) { - if((hw->collision_delta * hw->ifs_ratio) > + if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) { if(hw->tx_packet_delta > MIN_NUM_XMITS) { hw->in_ifs_mode = TRUE; @@ -3449,7 +4110,7 @@ em_update_adaptive(struct em_hw *hw) } } } else { - if((hw->in_ifs_mode == TRUE) && + if((hw->in_ifs_mode == TRUE) && (hw->tx_packet_delta <= MIN_NUM_XMITS)) { hw->current_ifs_val = 0; hw->in_ifs_mode = FALSE; @@ -3463,7 +4124,7 @@ em_update_adaptive(struct em_hw *hw) /****************************************************************************** * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT - * + * * hw - Struct containing variables accessed by shared code * frame_len - The length of the frame in question * mac_addr - The Ethernet destination address of the frame in question @@ -3491,16 +4152,16 @@ em_tbi_adjust_stats(struct em_hw *hw, carry_bit = 0x80000000 & stats->gorcl; stats->gorcl += frame_len; /* If the high bit of Gorcl (the low 32 bits of the Good Octets - * Received Count) was one before the addition, - * AND it is zero after, then we lost the carry out, + * Received Count) was one before the addition, + * AND it is zero after, then we lost the carry out, * need to add one to Gorch (Good Octets Received Count High). - * This could be simplified if all environments supported + * This could be simplified if all environments supported * 64-bit integers. */ if(carry_bit && ((stats->gorcl & 0x80000000) == 0)) stats->gorch++; /* Is this a broadcast or multicast? Check broadcast first, - * since the test for a multicast frame will test positive on + * since the test for a multicast frame will test positive on * a broadcast frame. */ if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) @@ -3621,3 +4282,221 @@ em_write_reg_io(struct em_hw *hw, em_io_write(hw, io_data, value); } + +/****************************************************************************** + * Estimates the cable length. + * + * hw - Struct containing variables accessed by shared code + * min_length - The estimated minimum length + * max_length - The estimated maximum length + * + * returns: E1000_SUCCESS / -E1000_ERR_XXX + * + * This function always returns a ranged length (minimum & maximum). + * So for M88 phy's, this function interprets the one value returned from the + * register to the minimum and maximum range. + * For IGP phy's, the function calculates the range by the AGC registers. + *****************************************************************************/ +int32_t +em_get_cable_length(struct em_hw *hw, uint16_t *min_length, + uint16_t *max_length) +{ + uint16_t agc_value = 0; + uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE; + uint16_t i, phy_data; + + DEBUGFUNC("em_get_cable_length"); + + *min_length = *max_length = 0; + + /* Use old method for Phy older than IGP */ + if(hw->phy_type == em_phy_m88) { + if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + /* Convert the enum value to ranged values */ + switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT) { + case em_cable_length_50: + *min_length = 0; + *max_length = em_igp_cable_length_50; + break; + case em_cable_length_50_80: + *min_length = em_igp_cable_length_50; + *max_length = em_igp_cable_length_80; + break; + case em_cable_length_80_110: + *min_length = em_igp_cable_length_80; + *max_length = em_igp_cable_length_110; + break; + case em_cable_length_110_140: + *min_length = em_igp_cable_length_110; + *max_length = em_igp_cable_length_140; + break; + case em_cable_length_140: + *min_length = em_igp_cable_length_140; + *max_length = em_igp_cable_length_170; + break; + default: + return -E1000_ERR_PHY; + break; + } + } else if(hw->phy_type == em_phy_igp) { /* For IGP PHY */ + uint16_t agc_reg_array[IGP01E1000_PHY_AGC_NUM] = {IGP01E1000_PHY_AGC_A, + IGP01E1000_PHY_AGC_B, + IGP01E1000_PHY_AGC_C, + IGP01E1000_PHY_AGC_D}; + /* Read the AGC registers for all channels */ + for(i = 0; i < IGP01E1000_PHY_AGC_NUM; i++) { + if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + agc_reg_array[i]) != E1000_SUCCESS) + return -E1000_ERR_PHY; + if(em_read_phy_reg(hw, agc_reg_array[i] & + IGP01E1000_PHY_PAGE_SELECT, &phy_data) != + E1000_SUCCESS) + return -E1000_ERR_PHY; + + cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT; + + /* Array bound check. */ + if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) || + (cur_agc == 0)) + return -E1000_ERR_PHY; + + agc_value += cur_agc; + + /* Update minimal AGC value. */ + if(min_agc > cur_agc) + min_agc = cur_agc; + } + + /* Return to page 0 */ + if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) != + E1000_SUCCESS) + return -E1000_ERR_PHY; + + /* Remove the minimal AGC result for length < 50m */ + if(agc_value < IGP01E1000_PHY_AGC_NUM * em_igp_cable_length_50) { + agc_value -= min_agc; + + /* Get the average length of the remaining 3 channels */ + agc_value /= (IGP01E1000_PHY_AGC_NUM - 1); + } else { + /* Get the average length of all the 4 channels. */ + agc_value /= IGP01E1000_PHY_AGC_NUM; + } + + /* Set the range of the calculated length. */ + *min_length = ((em_igp_cable_length_table[agc_value] - + IGP01E1000_AGC_RANGE) > 0) ? + (em_igp_cable_length_table[agc_value] - + IGP01E1000_AGC_RANGE) : 0; + *max_length = em_igp_cable_length_table[agc_value] + + IGP01E1000_AGC_RANGE; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** + * Check the cable polarity + * + * hw - Struct containing variables accessed by shared code + * polarity - output parameter : 0 - Polarity is not reversed + * 1 - Polarity is reversed. + * + * returns: E1000_SUCCESS / -E1000_ERR_XXX + * + * For phy's older then IGP, this function simply reads the polarity bit in the + * Phy Status register. For IGP phy's, this bit is valid only if link speed is + * 10 Mbps. If the link speed is 100 Mbps there is no polarity so this bit will + * return 0. If the link speed is 1000 Mbps the polarity status is in the + * IGP01E1000_PHY_PCS_INIT_REG. + *****************************************************************************/ +int32_t +em_check_polarity(struct em_hw *hw, uint16_t *polarity) +{ + uint16_t phy_data; + + DEBUGFUNC("em_check_polarity"); + + if(hw->phy_type == em_phy_m88) { + /* return the Polarity bit in the Status register. */ + if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> + M88E1000_PSSR_REV_POLARITY_SHIFT; + } else if(hw->phy_type == em_phy_igp) { + /* Read the Status register to check the speed */ + if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to + * find the polarity status */ + if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + + /* Read the GIG initialization PCS register (0x00B4) */ + if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_PCS_INIT_REG) < 0) + return -E1000_ERR_PHY; + + if(em_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG & + IGP01E1000_PHY_PAGE_SELECT, &phy_data) < 0) + return -E1000_ERR_PHY; + + /* Return to page 0 */ + if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) != + E1000_SUCCESS) + return -E1000_ERR_PHY; + + /* Check the polarity bits */ + *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0; + } else { + /* For 10 Mbps, read the polarity bit in the status register. (for + * 100 Mbps this bit is always 0) */ + *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED; + } + } + return E1000_SUCCESS; +} + +/****************************************************************************** + * Check if Downshift occured + * + * hw - Struct containing variables accessed by shared code + * downshift - output parameter : 0 - No Downshift ocured. + * 1 - Downshift ocured. + * + * returns: E1000_SUCCESS / -E1000_ERR_XXX + * + * For phy's older then IGP, this function reads the Downshift bit in the Phy + * Specific Status register. For IGP phy's, it reads the Downgrade bit in the + * Link Health register. In IGP this bit is latched high, so the driver must + * read it immediately after link is established. + *****************************************************************************/ +int32_t +em_check_downshift(struct em_hw *hw) +{ + uint16_t phy_data; + + DEBUGFUNC("em_check_downshift"); + + if(hw->phy_type == em_phy_igp) { + if(em_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0; + } + else if(hw->phy_type == em_phy_m88) { + if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >> + M88E1000_PSSR_DOWNSHIFT_SHIFT; + } + return E1000_SUCCESS; +} + |