From 7a07c009521a64b62bd3e7ba8fd7559d8de187d3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 Oct 2006 18:12:36 +0200 Subject: [PATCH] sky2: fix fiber support Fix support for fiber based devices. Needed to keep track of PMD type to add workaround in setup. Add support for gigabit half duplex fiber. Signed-off-by: Stephen Hemminger Signed-off-by: Adrian Bunk --- drivers/net/sky2.c | 81 ++++++++++++++++++++++++++++------------------ drivers/net/sky2.h | 15 ++++++++- 2 files changed, 63 insertions(+), 33 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index e939d165c78f..d77358649af7 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -316,7 +316,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) } ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); - if (hw->copper) { + if (sky2_is_copper(hw)) { if (hw->chip_id == CHIP_ID_YUKON_FE) { /* enable automatic crossover */ ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1; @@ -333,25 +333,37 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA; } } - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); } else { /* workaround for deviation #4.88 (CRC errors) */ /* disable Automatic Crossover */ ctrl &= ~PHY_M_PC_MDIX_MSK; - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); + } - if (hw->chip_id == CHIP_ID_YUKON_XL) { - /* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */ - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2); - ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); - ctrl &= ~PHY_M_MAC_MD_MSK; - ctrl |= PHY_M_MAC_MODE_SEL(PHY_M_MAC_MD_1000BX); - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); + + /* special setup for PHY 88E1112 Fiber */ + if (hw->chip_id == CHIP_ID_YUKON_XL && !sky2_is_copper(hw)) { + pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); + /* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */ + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2); + ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); + ctrl &= ~PHY_M_MAC_MD_MSK; + ctrl |= PHY_M_MAC_MODE_SEL(PHY_M_MAC_MD_1000BX); + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); + + if (hw->pmd_type == 'P') { /* select page 1 to access Fiber registers */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 1); + + /* for SFP-module set SIGDET polarity to low */ + ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); + ctrl |= PHY_M_FIB_SIGD_POL; + gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); } + + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); } ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL); @@ -368,7 +380,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) adv = PHY_AN_CSMA; if (sky2->autoneg == AUTONEG_ENABLE) { - if (hw->copper) { + if (sky2_is_copper(hw)) { if (sky2->advertising & ADVERTISED_1000baseT_Full) ct1000 |= PHY_M_1000C_AFD; if (sky2->advertising & ADVERTISED_1000baseT_Half) @@ -381,8 +393,12 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) adv |= PHY_M_AN_10_FD; if (sky2->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - } else /* special defines for FIBER (88E1011S only) */ - adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; + } else { /* special defines for FIBER (88E1040S only) */ + if (sky2->advertising & ADVERTISED_1000baseT_Full) + adv |= PHY_M_AN_1000X_AFD; + if (sky2->advertising & ADVERTISED_1000baseT_Half) + adv |= PHY_M_AN_1000X_AHD; + } /* Set Flow-control capabilities */ if (sky2->tx_pause && sky2->rx_pause) @@ -1465,7 +1481,7 @@ static int sky2_down(struct net_device *dev) static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux) { - if (!hw->copper) + if (!sky2_is_copper(hw)) return SPEED_1000; if (hw->chip_id == CHIP_ID_YUKON_FE) @@ -2226,7 +2242,7 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk) static int sky2_reset(struct sky2_hw *hw) { u16 status; - u8 t8, pmd_type; + u8 t8; int i; sky2_write8(hw, B0_CTST, CS_RST_CLR); @@ -2262,9 +2278,7 @@ static int sky2_reset(struct sky2_hw *hw) sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); - pmd_type = sky2_read8(hw, B2_PMD_TYP); - hw->copper = !(pmd_type == 'L' || pmd_type == 'S'); - + hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); hw->ports = 1; t8 = sky2_read8(hw, B2_Y2_HW_RES); if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) { @@ -2374,21 +2388,22 @@ static int sky2_reset(struct sky2_hw *hw) static u32 sky2_supported_modes(const struct sky2_hw *hw) { - u32 modes; - if (hw->copper) { - modes = SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | SUPPORTED_Autoneg | SUPPORTED_TP; + if (sky2_is_copper(hw)) { + u32 modes = SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | SUPPORTED_Autoneg | SUPPORTED_TP; if (hw->chip_id != CHIP_ID_YUKON_FE) modes |= SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full; + | SUPPORTED_1000baseT_Full; + return modes; } else - modes = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE - | SUPPORTED_Autoneg; - return modes; + return SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full + | SUPPORTED_Autoneg + | SUPPORTED_FIBRE; } static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) @@ -2399,7 +2414,7 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->transceiver = XCVR_INTERNAL; ecmd->supported = sky2_supported_modes(hw); ecmd->phy_address = PHY_ADDR_MARV; - if (hw->copper) { + if (sky2_is_copper(hw)) { ecmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half @@ -2408,12 +2423,14 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP; ecmd->port = PORT_TP; - } else + ecmd->speed = sky2->speed; + } else { + ecmd->speed = SPEED_1000; ecmd->port = PORT_FIBRE; + } ecmd->advertising = sky2->advertising; ecmd->autoneg = sky2->autoneg; - ecmd->speed = sky2->speed; ecmd->duplex = sky2->duplex; return 0; } diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index c91e0a4a4be7..83ccadc2c9b2 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1314,6 +1314,14 @@ enum { PHY_M_FESC_SEL_CL_A = 1<<0, /* Select Class A driver (100B-TX) */ }; +/* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */ +/***** PHY_MARV_PHY_CTRL (page 1) 16 bit r/w Fiber Specific Ctrl *****/ +enum { + PHY_M_FIB_FORCE_LNK = 1<<10,/* Force Link Good */ + PHY_M_FIB_SIGD_POL = 1<<9, /* SIGDET Polarity */ + PHY_M_FIB_TX_DIS = 1<<3, /* Transmitter Disable */ +}; + /* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */ /***** PHY_MARV_PHY_CTRL (page 2) 16 bit r/w MAC Specific Ctrl *****/ enum { @@ -1884,7 +1892,7 @@ struct sky2_hw { int pm_cap; u8 chip_id; u8 chip_rev; - u8 copper; + u8 pmd_type; u8 ports; struct sky2_status_le *st_le; @@ -1892,6 +1900,11 @@ struct sky2_hw { dma_addr_t st_dma; }; +static inline int sky2_is_copper(const struct sky2_hw *hw) +{ + return !(hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P'); +} + /* Register accessor for memory mapped device */ static inline u32 sky2_read32(const struct sky2_hw *hw, unsigned reg) { -- 2.39.5