16621Sbt150084 /*
26621Sbt150084 * CDDL HEADER START
36621Sbt150084 *
46621Sbt150084 * The contents of this file are subject to the terms of the
56621Sbt150084 * Common Development and Distribution License (the "License").
66621Sbt150084 * You may not use this file except in compliance with the License.
76621Sbt150084 *
86621Sbt150084 * You can obtain a copy of the license at:
96621Sbt150084 * http://www.opensolaris.org/os/licensing.
106621Sbt150084 * See the License for the specific language governing permissions
116621Sbt150084 * and limitations under the License.
126621Sbt150084 *
136621Sbt150084 * When using or redistributing this file, you may do so under the
146621Sbt150084 * License only. No other modification of this header is permitted.
156621Sbt150084 *
166621Sbt150084 * If applicable, add the following below this CDDL HEADER, with the
176621Sbt150084 * fields enclosed by brackets "[]" replaced with your own identifying
186621Sbt150084 * information: Portions Copyright [yyyy] [name of copyright owner]
196621Sbt150084 *
206621Sbt150084 * CDDL HEADER END
216621Sbt150084 */
226621Sbt150084
236621Sbt150084 /*
24*13006SChenlu.Chen@Sun.COM * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
256621Sbt150084 */
266621Sbt150084
27*13006SChenlu.Chen@Sun.COM /*
28*13006SChenlu.Chen@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
29*13006SChenlu.Chen@Sun.COM */
30*13006SChenlu.Chen@Sun.COM
31*13006SChenlu.Chen@Sun.COM /* IntelVersion: 1.109 scm_061610_003709 */
326621Sbt150084
336621Sbt150084 #include "ixgbe_api.h"
346621Sbt150084 #include "ixgbe_common.h"
356621Sbt150084 #include "ixgbe_phy.h"
369353SSamuel.Tu@Sun.COM
379353SSamuel.Tu@Sun.COM static void ixgbe_i2c_start(struct ixgbe_hw *hw);
389353SSamuel.Tu@Sun.COM static void ixgbe_i2c_stop(struct ixgbe_hw *hw);
399353SSamuel.Tu@Sun.COM static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data);
409353SSamuel.Tu@Sun.COM static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data);
419353SSamuel.Tu@Sun.COM static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw);
429353SSamuel.Tu@Sun.COM static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data);
439353SSamuel.Tu@Sun.COM static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data);
449353SSamuel.Tu@Sun.COM static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
459353SSamuel.Tu@Sun.COM static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
469353SSamuel.Tu@Sun.COM static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data);
479353SSamuel.Tu@Sun.COM static bool ixgbe_get_i2c_data(u32 *i2cctl);
489353SSamuel.Tu@Sun.COM void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw);
496621Sbt150084
506621Sbt150084 /*
516621Sbt150084 * ixgbe_init_phy_ops_generic - Inits PHY function ptrs
526621Sbt150084 * @hw: pointer to the hardware structure
536621Sbt150084 *
546621Sbt150084 * Initialize the function pointers.
556621Sbt150084 */
566621Sbt150084 s32
ixgbe_init_phy_ops_generic(struct ixgbe_hw * hw)576621Sbt150084 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw)
586621Sbt150084 {
596621Sbt150084 struct ixgbe_phy_info *phy = &hw->phy;
606621Sbt150084
6110998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_init_phy_ops_generic");
6210998SChenlu.Chen@Sun.COM
636621Sbt150084 /* PHY */
646621Sbt150084 phy->ops.identify = &ixgbe_identify_phy_generic;
656621Sbt150084 phy->ops.reset = &ixgbe_reset_phy_generic;
666621Sbt150084 phy->ops.read_reg = &ixgbe_read_phy_reg_generic;
676621Sbt150084 phy->ops.write_reg = &ixgbe_write_phy_reg_generic;
686621Sbt150084 phy->ops.setup_link = &ixgbe_setup_phy_link_generic;
696621Sbt150084 phy->ops.setup_link_speed = &ixgbe_setup_phy_link_speed_generic;
708490SPaul.Guo@Sun.COM phy->ops.check_link = NULL;
7110998SChenlu.Chen@Sun.COM phy->ops.get_firmware_version = ixgbe_get_phy_firmware_version_generic;
729353SSamuel.Tu@Sun.COM phy->ops.read_i2c_byte = &ixgbe_read_i2c_byte_generic;
739353SSamuel.Tu@Sun.COM phy->ops.write_i2c_byte = &ixgbe_write_i2c_byte_generic;
749353SSamuel.Tu@Sun.COM phy->ops.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic;
759353SSamuel.Tu@Sun.COM phy->ops.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic;
769353SSamuel.Tu@Sun.COM phy->ops.i2c_bus_clear = &ixgbe_i2c_bus_clear;
778490SPaul.Guo@Sun.COM phy->ops.identify_sfp = &ixgbe_identify_sfp_module_generic;
788490SPaul.Guo@Sun.COM phy->sfp_type = ixgbe_sfp_type_unknown;
79*13006SChenlu.Chen@Sun.COM phy->ops.check_overtemp = &ixgbe_tn_check_overtemp;
806621Sbt150084
816621Sbt150084 return (IXGBE_SUCCESS);
826621Sbt150084 }
836621Sbt150084
846621Sbt150084 /*
856621Sbt150084 * ixgbe_identify_phy_generic - Get physical layer module
866621Sbt150084 * @hw: pointer to hardware structure
876621Sbt150084 *
886621Sbt150084 * Determines the physical layer module found on the current adapter.
896621Sbt150084 */
906621Sbt150084 s32
ixgbe_identify_phy_generic(struct ixgbe_hw * hw)916621Sbt150084 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
926621Sbt150084 {
936621Sbt150084 s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
946621Sbt150084 u32 phy_addr;
959353SSamuel.Tu@Sun.COM u16 ext_ability = 0;
966621Sbt150084
9710998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_identify_phy_generic");
9810998SChenlu.Chen@Sun.COM
996621Sbt150084 if (hw->phy.type == ixgbe_phy_unknown) {
1006621Sbt150084 for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
1016621Sbt150084 if (ixgbe_validate_phy_addr(hw, phy_addr)) {
1026621Sbt150084 hw->phy.addr = phy_addr;
1036621Sbt150084 (void) ixgbe_get_phy_id(hw);
1046621Sbt150084 hw->phy.type =
1056621Sbt150084 ixgbe_get_phy_type_from_id(hw->phy.id);
1069353SSamuel.Tu@Sun.COM
1079353SSamuel.Tu@Sun.COM if (hw->phy.type == ixgbe_phy_unknown) {
1089353SSamuel.Tu@Sun.COM hw->phy.ops.read_reg(hw,
1099353SSamuel.Tu@Sun.COM IXGBE_MDIO_PHY_EXT_ABILITY,
1109353SSamuel.Tu@Sun.COM IXGBE_MDIO_PMA_PMD_DEV_TYPE,
1119353SSamuel.Tu@Sun.COM &ext_ability);
1129353SSamuel.Tu@Sun.COM if (ext_ability &
1139353SSamuel.Tu@Sun.COM IXGBE_MDIO_PHY_10GBASET_ABILITY ||
1149353SSamuel.Tu@Sun.COM ext_ability &
1159353SSamuel.Tu@Sun.COM IXGBE_MDIO_PHY_1000BASET_ABILITY)
1169353SSamuel.Tu@Sun.COM hw->phy.type =
1179353SSamuel.Tu@Sun.COM ixgbe_phy_cu_unknown;
1189353SSamuel.Tu@Sun.COM else
1199353SSamuel.Tu@Sun.COM hw->phy.type =
1209353SSamuel.Tu@Sun.COM ixgbe_phy_generic;
1219353SSamuel.Tu@Sun.COM }
1229353SSamuel.Tu@Sun.COM
1236621Sbt150084 status = IXGBE_SUCCESS;
1246621Sbt150084 break;
1256621Sbt150084 }
1266621Sbt150084 }
1279353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
1289353SSamuel.Tu@Sun.COM hw->phy.addr = 0;
1296621Sbt150084 } else {
1306621Sbt150084 status = IXGBE_SUCCESS;
1316621Sbt150084 }
1326621Sbt150084
1336621Sbt150084 return (status);
1346621Sbt150084 }
1356621Sbt150084
1366621Sbt150084 /*
1376621Sbt150084 * ixgbe_validate_phy_addr - Determines phy address is valid
1386621Sbt150084 * @hw: pointer to hardware structure
1396621Sbt150084 *
1406621Sbt150084 */
1416621Sbt150084 bool
ixgbe_validate_phy_addr(struct ixgbe_hw * hw,u32 phy_addr)1426621Sbt150084 ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
1436621Sbt150084 {
1446621Sbt150084 u16 phy_id = 0;
1458490SPaul.Guo@Sun.COM bool valid = false;
1466621Sbt150084
14710998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_validate_phy_addr");
14810998SChenlu.Chen@Sun.COM
1496621Sbt150084 hw->phy.addr = phy_addr;
1506621Sbt150084 hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
1516621Sbt150084 IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id);
1526621Sbt150084
1536621Sbt150084 if (phy_id != 0xFFFF && phy_id != 0x0)
1548490SPaul.Guo@Sun.COM valid = true;
1556621Sbt150084
1566621Sbt150084 return (valid);
1576621Sbt150084 }
1586621Sbt150084
1596621Sbt150084 /*
1606621Sbt150084 * ixgbe_get_phy_id - Get the phy type
1616621Sbt150084 * @hw: pointer to hardware structure
1626621Sbt150084 *
1636621Sbt150084 */
1646621Sbt150084 s32
ixgbe_get_phy_id(struct ixgbe_hw * hw)1656621Sbt150084 ixgbe_get_phy_id(struct ixgbe_hw *hw)
1666621Sbt150084 {
1676621Sbt150084 u32 status;
1686621Sbt150084 u16 phy_id_high = 0;
1696621Sbt150084 u16 phy_id_low = 0;
1706621Sbt150084
17110998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_get_phy_id");
17210998SChenlu.Chen@Sun.COM
1736621Sbt150084 status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
1746621Sbt150084 IXGBE_MDIO_PMA_PMD_DEV_TYPE,
1756621Sbt150084 &phy_id_high);
1766621Sbt150084
1776621Sbt150084 if (status == IXGBE_SUCCESS) {
1786621Sbt150084 hw->phy.id = (u32)(phy_id_high << 16);
1796621Sbt150084 status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW,
1806621Sbt150084 IXGBE_MDIO_PMA_PMD_DEV_TYPE,
1816621Sbt150084 &phy_id_low);
1826621Sbt150084 hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
1836621Sbt150084 hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
1846621Sbt150084 }
1856621Sbt150084
1866621Sbt150084 return (status);
1876621Sbt150084 }
1886621Sbt150084
1896621Sbt150084 /*
1906621Sbt150084 * ixgbe_get_phy_type_from_id - Get the phy type
1916621Sbt150084 * @hw: pointer to hardware structure
1926621Sbt150084 *
1936621Sbt150084 */
1946621Sbt150084 enum ixgbe_phy_type
ixgbe_get_phy_type_from_id(u32 phy_id)1956621Sbt150084 ixgbe_get_phy_type_from_id(u32 phy_id)
1966621Sbt150084 {
1976621Sbt150084 enum ixgbe_phy_type phy_type;
1986621Sbt150084
19910998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_get_phy_type_from_id");
20010998SChenlu.Chen@Sun.COM
2016621Sbt150084 switch (phy_id) {
2028490SPaul.Guo@Sun.COM case TN1010_PHY_ID:
2038490SPaul.Guo@Sun.COM phy_type = ixgbe_phy_tn;
2048490SPaul.Guo@Sun.COM break;
20510305SPaul.Guo@Sun.COM case AQ1002_PHY_ID:
20610305SPaul.Guo@Sun.COM phy_type = ixgbe_phy_aq;
20710305SPaul.Guo@Sun.COM break;
2086621Sbt150084 case QT2022_PHY_ID:
2096621Sbt150084 phy_type = ixgbe_phy_qt;
2106621Sbt150084 break;
2118490SPaul.Guo@Sun.COM case ATH_PHY_ID:
2128490SPaul.Guo@Sun.COM phy_type = ixgbe_phy_nl;
2138490SPaul.Guo@Sun.COM break;
2146621Sbt150084 default:
2156621Sbt150084 phy_type = ixgbe_phy_unknown;
2166621Sbt150084 break;
2176621Sbt150084 }
2186621Sbt150084
2198490SPaul.Guo@Sun.COM DEBUGOUT1("phy type found is %d\n", phy_type);
2208490SPaul.Guo@Sun.COM
2216621Sbt150084 return (phy_type);
2226621Sbt150084 }
2236621Sbt150084
2246621Sbt150084 /*
2256621Sbt150084 * ixgbe_reset_phy_generic - Performs a PHY reset
2266621Sbt150084 * @hw: pointer to hardware structure
2276621Sbt150084 */
2286621Sbt150084 s32
ixgbe_reset_phy_generic(struct ixgbe_hw * hw)2296621Sbt150084 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
2306621Sbt150084 {
2319353SSamuel.Tu@Sun.COM u32 i;
2329353SSamuel.Tu@Sun.COM u16 ctrl = 0;
2339353SSamuel.Tu@Sun.COM s32 status = IXGBE_SUCCESS;
2349353SSamuel.Tu@Sun.COM
23510998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_reset_phy_generic");
23610998SChenlu.Chen@Sun.COM
2379353SSamuel.Tu@Sun.COM if (hw->phy.type == ixgbe_phy_unknown)
2389353SSamuel.Tu@Sun.COM status = ixgbe_identify_phy_generic(hw);
2399353SSamuel.Tu@Sun.COM
2409353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS || hw->phy.type == ixgbe_phy_none)
2419353SSamuel.Tu@Sun.COM goto out;
2429353SSamuel.Tu@Sun.COM
243*13006SChenlu.Chen@Sun.COM if (!hw->phy.reset_if_overtemp &&
244*13006SChenlu.Chen@Sun.COM (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw))) {
245*13006SChenlu.Chen@Sun.COM /* Don't reset PHY if it's shut down due to overtemp. */
246*13006SChenlu.Chen@Sun.COM goto out;
247*13006SChenlu.Chen@Sun.COM }
248*13006SChenlu.Chen@Sun.COM
2496621Sbt150084 /*
2506621Sbt150084 * Perform soft PHY reset to the PHY_XS.
2516621Sbt150084 * This will cause a soft reset to the PHY
2526621Sbt150084 */
2539353SSamuel.Tu@Sun.COM hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
2546621Sbt150084 IXGBE_MDIO_PHY_XS_DEV_TYPE,
2556621Sbt150084 IXGBE_MDIO_PHY_XS_RESET);
2569353SSamuel.Tu@Sun.COM
257*13006SChenlu.Chen@Sun.COM /*
258*13006SChenlu.Chen@Sun.COM * Poll for reset bit to self-clear indicating reset is complete.
259*13006SChenlu.Chen@Sun.COM * Some PHYs could take up to 3 seconds to complete and need about
260*13006SChenlu.Chen@Sun.COM * 1.7 usec delay after the reset is complete.
261*13006SChenlu.Chen@Sun.COM */
262*13006SChenlu.Chen@Sun.COM for (i = 0; i < 30; i++) {
263*13006SChenlu.Chen@Sun.COM msec_delay(100);
2649353SSamuel.Tu@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
2659353SSamuel.Tu@Sun.COM IXGBE_MDIO_PHY_XS_DEV_TYPE, &ctrl);
266*13006SChenlu.Chen@Sun.COM if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) {
267*13006SChenlu.Chen@Sun.COM usec_delay(2);
2689353SSamuel.Tu@Sun.COM break;
269*13006SChenlu.Chen@Sun.COM }
2709353SSamuel.Tu@Sun.COM }
2719353SSamuel.Tu@Sun.COM
2729353SSamuel.Tu@Sun.COM if (ctrl & IXGBE_MDIO_PHY_XS_RESET) {
2739353SSamuel.Tu@Sun.COM status = IXGBE_ERR_RESET_FAILED;
2749353SSamuel.Tu@Sun.COM DEBUGOUT("PHY reset polling failed to complete.\n");
2759353SSamuel.Tu@Sun.COM }
2769353SSamuel.Tu@Sun.COM
2779353SSamuel.Tu@Sun.COM out:
2789353SSamuel.Tu@Sun.COM return (status);
2796621Sbt150084 }
2806621Sbt150084
2816621Sbt150084 /*
2826621Sbt150084 * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register
2836621Sbt150084 * @hw: pointer to hardware structure
2846621Sbt150084 * @reg_addr: 32 bit address of PHY register to read
2856621Sbt150084 * @phy_data: Pointer to read data from PHY register
2866621Sbt150084 */
2876621Sbt150084 s32
ixgbe_read_phy_reg_generic(struct ixgbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)2886621Sbt150084 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
2896621Sbt150084 u32 device_type, u16 *phy_data)
2906621Sbt150084 {
2916621Sbt150084 u32 command;
2926621Sbt150084 u32 i;
2936621Sbt150084 u32 data;
2946621Sbt150084 s32 status = IXGBE_SUCCESS;
2956621Sbt150084 u16 gssr;
2966621Sbt150084
29710998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_read_phy_reg_generic");
29810998SChenlu.Chen@Sun.COM
2996621Sbt150084 if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
3006621Sbt150084 gssr = IXGBE_GSSR_PHY1_SM;
3016621Sbt150084 else
3026621Sbt150084 gssr = IXGBE_GSSR_PHY0_SM;
3036621Sbt150084
3046621Sbt150084 if (ixgbe_acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS)
3056621Sbt150084 status = IXGBE_ERR_SWFW_SYNC;
3066621Sbt150084
3076621Sbt150084 if (status == IXGBE_SUCCESS) {
3086621Sbt150084 /* Setup and write the address cycle command */
3096621Sbt150084 command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
3106621Sbt150084 (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
3116621Sbt150084 (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
3126621Sbt150084 (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
3136621Sbt150084
3146621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
3156621Sbt150084
3166621Sbt150084 /*
3176621Sbt150084 * Check every 10 usec to see if the address cycle completed.
3186621Sbt150084 * The MDI Command bit will clear when the operation is
3196621Sbt150084 * complete
3206621Sbt150084 */
3216621Sbt150084 for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
3226621Sbt150084 usec_delay(10);
3236621Sbt150084
3246621Sbt150084 command = IXGBE_READ_REG(hw, IXGBE_MSCA);
3256621Sbt150084
3266621Sbt150084 if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
3276621Sbt150084 break;
3286621Sbt150084 }
3296621Sbt150084 }
3306621Sbt150084
3316621Sbt150084 if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
3326621Sbt150084 DEBUGOUT("PHY address command did not complete.\n");
3336621Sbt150084 status = IXGBE_ERR_PHY;
3346621Sbt150084 }
3356621Sbt150084
3366621Sbt150084 if (status == IXGBE_SUCCESS) {
3376621Sbt150084 /*
3386621Sbt150084 * Address cycle complete, setup and write the read
3396621Sbt150084 * command
3406621Sbt150084 */
3416621Sbt150084 command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
3426621Sbt150084 (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
3436621Sbt150084 (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
3446621Sbt150084 (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
3456621Sbt150084
3466621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
3476621Sbt150084
3486621Sbt150084 /*
3496621Sbt150084 * Check every 10 usec to see if the address cycle
3506621Sbt150084 * completed. The MDI Command bit will clear when the
3516621Sbt150084 * operation is complete
3526621Sbt150084 */
3536621Sbt150084 for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
3546621Sbt150084 usec_delay(10);
3556621Sbt150084
3566621Sbt150084 command = IXGBE_READ_REG(hw, IXGBE_MSCA);
3576621Sbt150084
3586621Sbt150084 if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
3596621Sbt150084 break;
3606621Sbt150084 }
3616621Sbt150084
3626621Sbt150084 if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
3636621Sbt150084 DEBUGOUT("PHY read command didn't complete\n");
3646621Sbt150084 status = IXGBE_ERR_PHY;
3656621Sbt150084 } else {
3666621Sbt150084 /*
3676621Sbt150084 * Read operation is complete. Get the data
3686621Sbt150084 * from MSRWD
3696621Sbt150084 */
3706621Sbt150084 data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
3716621Sbt150084 data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
3726621Sbt150084 *phy_data = (u16)(data);
3736621Sbt150084 }
3746621Sbt150084 }
3756621Sbt150084
3766621Sbt150084 ixgbe_release_swfw_sync(hw, gssr);
3776621Sbt150084 }
3786621Sbt150084
3796621Sbt150084 return (status);
3806621Sbt150084 }
3816621Sbt150084
3826621Sbt150084 /*
3836621Sbt150084 * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register
3846621Sbt150084 * @hw: pointer to hardware structure
3856621Sbt150084 * @reg_addr: 32 bit PHY register to write
3866621Sbt150084 * @device_type: 5 bit device type
3876621Sbt150084 * @phy_data: Data to write to the PHY register
3886621Sbt150084 */
ixgbe_write_phy_reg_generic(struct ixgbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)3896621Sbt150084 s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
3906621Sbt150084 u32 device_type, u16 phy_data)
3916621Sbt150084 {
3926621Sbt150084 u32 command;
3936621Sbt150084 u32 i;
3946621Sbt150084 s32 status = IXGBE_SUCCESS;
3956621Sbt150084 u16 gssr;
3966621Sbt150084
39710998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_write_phy_reg_generic");
39810998SChenlu.Chen@Sun.COM
3996621Sbt150084 if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
4006621Sbt150084 gssr = IXGBE_GSSR_PHY1_SM;
4016621Sbt150084 else
4026621Sbt150084 gssr = IXGBE_GSSR_PHY0_SM;
4036621Sbt150084
4046621Sbt150084 if (ixgbe_acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS)
4056621Sbt150084 status = IXGBE_ERR_SWFW_SYNC;
4066621Sbt150084
4076621Sbt150084 if (status == IXGBE_SUCCESS) {
4086621Sbt150084 /*
4096621Sbt150084 * Put the data in the MDI single read and write data register
4106621Sbt150084 */
4116621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
4126621Sbt150084
4136621Sbt150084 /* Setup and write the address cycle command */
4146621Sbt150084 command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
4156621Sbt150084 (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
4166621Sbt150084 (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
4176621Sbt150084 (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
4186621Sbt150084
4196621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
4206621Sbt150084
4216621Sbt150084 /*
4226621Sbt150084 * Check every 10 usec to see if the address cycle completed.
4236621Sbt150084 * The MDI Command bit will clear when the operation is
4246621Sbt150084 * complete
4256621Sbt150084 */
4266621Sbt150084 for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
4276621Sbt150084 usec_delay(10);
4286621Sbt150084
4296621Sbt150084 command = IXGBE_READ_REG(hw, IXGBE_MSCA);
4306621Sbt150084
4316621Sbt150084 if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
4326621Sbt150084 break;
4336621Sbt150084 }
4346621Sbt150084
4356621Sbt150084 if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
4366621Sbt150084 DEBUGOUT("PHY address cmd didn't complete\n");
4376621Sbt150084 status = IXGBE_ERR_PHY;
4386621Sbt150084 }
4396621Sbt150084
4406621Sbt150084 if (status == IXGBE_SUCCESS) {
4416621Sbt150084 /*
4426621Sbt150084 * Address cycle complete, setup and write the write
4436621Sbt150084 * command
4446621Sbt150084 */
4456621Sbt150084 command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
4466621Sbt150084 (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
4476621Sbt150084 (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
4486621Sbt150084 (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
4496621Sbt150084
4506621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
4516621Sbt150084
4526621Sbt150084 /*
4536621Sbt150084 * Check every 10 usec to see if the address cycle
4546621Sbt150084 * completed. The MDI Command bit will clear when the
4556621Sbt150084 * operation is complete
4566621Sbt150084 */
4576621Sbt150084 for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
4586621Sbt150084 usec_delay(10);
4596621Sbt150084
4606621Sbt150084 command = IXGBE_READ_REG(hw, IXGBE_MSCA);
4616621Sbt150084
4626621Sbt150084 if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
4636621Sbt150084 break;
4646621Sbt150084 }
4656621Sbt150084
4666621Sbt150084 if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
4676621Sbt150084 DEBUGOUT("PHY address cmd didn't complete\n");
4686621Sbt150084 status = IXGBE_ERR_PHY;
4696621Sbt150084 }
4706621Sbt150084 }
4716621Sbt150084
4726621Sbt150084 ixgbe_release_swfw_sync(hw, gssr);
4736621Sbt150084 }
4746621Sbt150084
4756621Sbt150084 return (status);
4766621Sbt150084 }
4776621Sbt150084
4786621Sbt150084 /*
4796621Sbt150084 * ixgbe_setup_phy_link_generic - Set and restart autoneg
4806621Sbt150084 * @hw: pointer to hardware structure
4816621Sbt150084 *
4826621Sbt150084 * Restart autonegotiation and PHY and waits for completion.
4836621Sbt150084 */
4846621Sbt150084 s32
ixgbe_setup_phy_link_generic(struct ixgbe_hw * hw)4856621Sbt150084 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
4866621Sbt150084 {
48710305SPaul.Guo@Sun.COM s32 status = IXGBE_SUCCESS;
4886621Sbt150084 u32 time_out;
4896621Sbt150084 u32 max_time_out = 10;
4906621Sbt150084 u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
49110998SChenlu.Chen@Sun.COM bool autoneg = false;
49210998SChenlu.Chen@Sun.COM ixgbe_link_speed speed;
4936621Sbt150084
49410998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_setup_phy_link_generic");
49510998SChenlu.Chen@Sun.COM
49610998SChenlu.Chen@Sun.COM (void) ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg);
49710998SChenlu.Chen@Sun.COM
49810998SChenlu.Chen@Sun.COM if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
49910998SChenlu.Chen@Sun.COM /* Set or unset auto-negotiation 10G advertisement */
50010998SChenlu.Chen@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
50110998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
50210998SChenlu.Chen@Sun.COM &autoneg_reg);
50310998SChenlu.Chen@Sun.COM
50410998SChenlu.Chen@Sun.COM autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE;
50510998SChenlu.Chen@Sun.COM if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
50610998SChenlu.Chen@Sun.COM autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE;
50710998SChenlu.Chen@Sun.COM
50810998SChenlu.Chen@Sun.COM hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
50910998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
51010998SChenlu.Chen@Sun.COM autoneg_reg);
51110998SChenlu.Chen@Sun.COM }
5126621Sbt150084
51310998SChenlu.Chen@Sun.COM if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
51410998SChenlu.Chen@Sun.COM /* Set or unset auto-negotiation 1G advertisement */
51510998SChenlu.Chen@Sun.COM hw->phy.ops.read_reg(hw,
51610998SChenlu.Chen@Sun.COM IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
51710998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
51810998SChenlu.Chen@Sun.COM &autoneg_reg);
51910998SChenlu.Chen@Sun.COM
52010998SChenlu.Chen@Sun.COM autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE;
52110998SChenlu.Chen@Sun.COM if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
52210998SChenlu.Chen@Sun.COM autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE;
5236621Sbt150084
52410998SChenlu.Chen@Sun.COM hw->phy.ops.write_reg(hw,
52510998SChenlu.Chen@Sun.COM IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
52610998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
52710998SChenlu.Chen@Sun.COM autoneg_reg);
52810998SChenlu.Chen@Sun.COM }
52910998SChenlu.Chen@Sun.COM
53010998SChenlu.Chen@Sun.COM if (speed & IXGBE_LINK_SPEED_100_FULL) {
53110998SChenlu.Chen@Sun.COM /* Set or unset auto-negotiation 100M advertisement */
53210998SChenlu.Chen@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
53310998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
53410998SChenlu.Chen@Sun.COM &autoneg_reg);
53510998SChenlu.Chen@Sun.COM
53610998SChenlu.Chen@Sun.COM autoneg_reg &= ~IXGBE_MII_100BASE_T_ADVERTISE;
53710998SChenlu.Chen@Sun.COM if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
53810998SChenlu.Chen@Sun.COM autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE;
53910998SChenlu.Chen@Sun.COM
54010998SChenlu.Chen@Sun.COM hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
54110998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
54210998SChenlu.Chen@Sun.COM autoneg_reg);
54310998SChenlu.Chen@Sun.COM }
5446621Sbt150084
5456621Sbt150084 /* Restart PHY autonegotiation and wait for completion */
5466621Sbt150084 hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
5476621Sbt150084 IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
5486621Sbt150084
5496621Sbt150084 autoneg_reg |= IXGBE_MII_RESTART;
5506621Sbt150084
5516621Sbt150084 hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
5526621Sbt150084 IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
5536621Sbt150084
5546621Sbt150084 /* Wait for autonegotiation to finish */
5556621Sbt150084 for (time_out = 0; time_out < max_time_out; time_out++) {
5566621Sbt150084 usec_delay(10);
5576621Sbt150084 /* Restart PHY autonegotiation and wait for completion */
5586621Sbt150084 status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
5596621Sbt150084 IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
5606621Sbt150084 &autoneg_reg);
5616621Sbt150084
5626621Sbt150084 autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE;
5636621Sbt150084 if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) {
5646621Sbt150084 break;
5656621Sbt150084 }
5666621Sbt150084 }
5676621Sbt150084
56810998SChenlu.Chen@Sun.COM if (time_out == max_time_out) {
5696621Sbt150084 status = IXGBE_ERR_LINK_SETUP;
57010998SChenlu.Chen@Sun.COM DEBUGOUT("ixgbe_setup_phy_link_generic: time out");
57110998SChenlu.Chen@Sun.COM }
5726621Sbt150084
5736621Sbt150084 return (status);
5746621Sbt150084 }
5756621Sbt150084
5766621Sbt150084 /*
5776621Sbt150084 * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities
5786621Sbt150084 * @hw: pointer to hardware structure
5796621Sbt150084 * @speed: new link speed
5808490SPaul.Guo@Sun.COM * @autoneg: true if autonegotiation enabled
5816621Sbt150084 */
58210998SChenlu.Chen@Sun.COM s32
ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw * hw,ixgbe_link_speed speed,bool autoneg,bool autoneg_wait_to_complete)58310998SChenlu.Chen@Sun.COM ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
5846621Sbt150084 ixgbe_link_speed speed,
5856621Sbt150084 bool autoneg,
5866621Sbt150084 bool autoneg_wait_to_complete)
5876621Sbt150084 {
5886621Sbt150084 UNREFERENCED_PARAMETER(autoneg);
5896621Sbt150084 UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
5906621Sbt150084
59110998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_setup_phy_link_speed_generic");
59210998SChenlu.Chen@Sun.COM
5936621Sbt150084 /*
5946621Sbt150084 * Clear autoneg_advertised and set new values based on input link
5956621Sbt150084 * speed.
5966621Sbt150084 */
5976621Sbt150084 hw->phy.autoneg_advertised = 0;
5986621Sbt150084
5996621Sbt150084 if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
6006621Sbt150084 hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
6016621Sbt150084 }
60210305SPaul.Guo@Sun.COM
6036621Sbt150084 if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
6046621Sbt150084 hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
6056621Sbt150084 }
6066621Sbt150084
60710305SPaul.Guo@Sun.COM if (speed & IXGBE_LINK_SPEED_100_FULL)
60810305SPaul.Guo@Sun.COM hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;
60910305SPaul.Guo@Sun.COM
6106621Sbt150084 /* Setup link based on the new speed settings */
6116621Sbt150084 hw->phy.ops.setup_link(hw);
6126621Sbt150084
6136621Sbt150084 return (IXGBE_SUCCESS);
6146621Sbt150084 }
6158490SPaul.Guo@Sun.COM
6168490SPaul.Guo@Sun.COM /*
6179353SSamuel.Tu@Sun.COM * ixgbe_get_copper_link_capabilities_generic - Determines link capabilities
6189353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
6199353SSamuel.Tu@Sun.COM * @speed: pointer to link speed
6209353SSamuel.Tu@Sun.COM * @autoneg: boolean auto-negotiation value
6219353SSamuel.Tu@Sun.COM *
6229353SSamuel.Tu@Sun.COM * Determines the link capabilities by reading the AUTOC register.
6239353SSamuel.Tu@Sun.COM */
62410998SChenlu.Chen@Sun.COM s32
ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw * hw,ixgbe_link_speed * speed,bool * autoneg)62510998SChenlu.Chen@Sun.COM ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
6269353SSamuel.Tu@Sun.COM ixgbe_link_speed *speed, bool *autoneg)
6279353SSamuel.Tu@Sun.COM {
6289353SSamuel.Tu@Sun.COM s32 status = IXGBE_ERR_LINK_SETUP;
6299353SSamuel.Tu@Sun.COM u16 speed_ability;
6309353SSamuel.Tu@Sun.COM
63110998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_get_copper_link_capabilities_generic");
63210998SChenlu.Chen@Sun.COM
6339353SSamuel.Tu@Sun.COM *speed = 0;
6349353SSamuel.Tu@Sun.COM *autoneg = true;
6359353SSamuel.Tu@Sun.COM
6369353SSamuel.Tu@Sun.COM status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
6379353SSamuel.Tu@Sun.COM IXGBE_MDIO_PMA_PMD_DEV_TYPE, &speed_ability);
6389353SSamuel.Tu@Sun.COM
6399353SSamuel.Tu@Sun.COM if (status == IXGBE_SUCCESS) {
6409353SSamuel.Tu@Sun.COM if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
6419353SSamuel.Tu@Sun.COM *speed |= IXGBE_LINK_SPEED_10GB_FULL;
6429353SSamuel.Tu@Sun.COM if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
6439353SSamuel.Tu@Sun.COM *speed |= IXGBE_LINK_SPEED_1GB_FULL;
64410305SPaul.Guo@Sun.COM if (speed_ability & IXGBE_MDIO_PHY_SPEED_100M)
64510305SPaul.Guo@Sun.COM *speed |= IXGBE_LINK_SPEED_100_FULL;
6469353SSamuel.Tu@Sun.COM }
6479353SSamuel.Tu@Sun.COM
6489353SSamuel.Tu@Sun.COM return (status);
6499353SSamuel.Tu@Sun.COM }
6509353SSamuel.Tu@Sun.COM
6519353SSamuel.Tu@Sun.COM /*
6528490SPaul.Guo@Sun.COM * ixgbe_check_phy_link_tnx - Determine link and speed status
6538490SPaul.Guo@Sun.COM * @hw: pointer to hardware structure
6548490SPaul.Guo@Sun.COM *
6558490SPaul.Guo@Sun.COM * Reads the VS1 register to determine if link is up and the current speed for
6568490SPaul.Guo@Sun.COM * the PHY.
6578490SPaul.Guo@Sun.COM */
6588490SPaul.Guo@Sun.COM s32
ixgbe_check_phy_link_tnx(struct ixgbe_hw * hw,ixgbe_link_speed * speed,bool * link_up)6598490SPaul.Guo@Sun.COM ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
6608490SPaul.Guo@Sun.COM bool *link_up)
6618490SPaul.Guo@Sun.COM {
6628490SPaul.Guo@Sun.COM s32 status = IXGBE_SUCCESS;
6638490SPaul.Guo@Sun.COM u32 time_out;
6648490SPaul.Guo@Sun.COM u32 max_time_out = 10;
6658490SPaul.Guo@Sun.COM u16 phy_link = 0;
6668490SPaul.Guo@Sun.COM u16 phy_speed = 0;
6678490SPaul.Guo@Sun.COM u16 phy_data = 0;
6688490SPaul.Guo@Sun.COM
66910998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_check_phy_link_tnx");
67010998SChenlu.Chen@Sun.COM
6718490SPaul.Guo@Sun.COM /* Initialize speed and link to default case */
6728490SPaul.Guo@Sun.COM *link_up = false;
6738490SPaul.Guo@Sun.COM *speed = IXGBE_LINK_SPEED_10GB_FULL;
6748490SPaul.Guo@Sun.COM
6758490SPaul.Guo@Sun.COM /*
6768490SPaul.Guo@Sun.COM * Check current speed and link status of the PHY register.
6778490SPaul.Guo@Sun.COM * This is a vendor specific register and may have to
6788490SPaul.Guo@Sun.COM * be changed for other copper PHYs.
6798490SPaul.Guo@Sun.COM */
6808490SPaul.Guo@Sun.COM for (time_out = 0; time_out < max_time_out; time_out++) {
6818490SPaul.Guo@Sun.COM usec_delay(10);
6828490SPaul.Guo@Sun.COM status = hw->phy.ops.read_reg(hw,
6838490SPaul.Guo@Sun.COM IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
6848490SPaul.Guo@Sun.COM IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
6858490SPaul.Guo@Sun.COM &phy_data);
6868490SPaul.Guo@Sun.COM phy_link = phy_data &
6878490SPaul.Guo@Sun.COM IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
6888490SPaul.Guo@Sun.COM phy_speed = phy_data &
6898490SPaul.Guo@Sun.COM IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
6908490SPaul.Guo@Sun.COM if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
6918490SPaul.Guo@Sun.COM *link_up = true;
6928490SPaul.Guo@Sun.COM if (phy_speed ==
6938490SPaul.Guo@Sun.COM IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
6948490SPaul.Guo@Sun.COM *speed = IXGBE_LINK_SPEED_1GB_FULL;
6958490SPaul.Guo@Sun.COM break;
6968490SPaul.Guo@Sun.COM }
6978490SPaul.Guo@Sun.COM }
6988490SPaul.Guo@Sun.COM
6998490SPaul.Guo@Sun.COM return (status);
7008490SPaul.Guo@Sun.COM }
7018490SPaul.Guo@Sun.COM
7028490SPaul.Guo@Sun.COM /*
70310998SChenlu.Chen@Sun.COM * ixgbe_setup_phy_link_tnx - Set and restart autoneg
70410998SChenlu.Chen@Sun.COM * @hw: pointer to hardware structure
70510998SChenlu.Chen@Sun.COM *
70610998SChenlu.Chen@Sun.COM * Restart autonegotiation and PHY and waits for completion.
70710998SChenlu.Chen@Sun.COM */
70810998SChenlu.Chen@Sun.COM s32
ixgbe_setup_phy_link_tnx(struct ixgbe_hw * hw)70910998SChenlu.Chen@Sun.COM ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw)
71010998SChenlu.Chen@Sun.COM {
71110998SChenlu.Chen@Sun.COM s32 status = IXGBE_SUCCESS;
71210998SChenlu.Chen@Sun.COM u32 time_out;
71310998SChenlu.Chen@Sun.COM u32 max_time_out = 10;
71410998SChenlu.Chen@Sun.COM u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
71510998SChenlu.Chen@Sun.COM bool autoneg = false;
71610998SChenlu.Chen@Sun.COM ixgbe_link_speed speed;
71710998SChenlu.Chen@Sun.COM
71810998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_setup_phy_link_tnx");
71910998SChenlu.Chen@Sun.COM
72010998SChenlu.Chen@Sun.COM (void) ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg);
72110998SChenlu.Chen@Sun.COM
72210998SChenlu.Chen@Sun.COM if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
72310998SChenlu.Chen@Sun.COM /* Set or unset auto-negotiation 10G advertisement */
72410998SChenlu.Chen@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
72510998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
72610998SChenlu.Chen@Sun.COM &autoneg_reg);
72710998SChenlu.Chen@Sun.COM
72810998SChenlu.Chen@Sun.COM autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE;
72910998SChenlu.Chen@Sun.COM if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
73010998SChenlu.Chen@Sun.COM autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE;
73110998SChenlu.Chen@Sun.COM
73210998SChenlu.Chen@Sun.COM hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
73310998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
73410998SChenlu.Chen@Sun.COM autoneg_reg);
73510998SChenlu.Chen@Sun.COM }
73610998SChenlu.Chen@Sun.COM
73710998SChenlu.Chen@Sun.COM if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
73810998SChenlu.Chen@Sun.COM /* Set or unset auto-negotiation 1G advertisement */
73910998SChenlu.Chen@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG,
74010998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
74110998SChenlu.Chen@Sun.COM &autoneg_reg);
74210998SChenlu.Chen@Sun.COM
74310998SChenlu.Chen@Sun.COM autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX;
74410998SChenlu.Chen@Sun.COM if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
74510998SChenlu.Chen@Sun.COM autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX;
74610998SChenlu.Chen@Sun.COM
74710998SChenlu.Chen@Sun.COM hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG,
74810998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
74910998SChenlu.Chen@Sun.COM autoneg_reg);
75010998SChenlu.Chen@Sun.COM }
75110998SChenlu.Chen@Sun.COM
75210998SChenlu.Chen@Sun.COM if (speed & IXGBE_LINK_SPEED_100_FULL) {
75310998SChenlu.Chen@Sun.COM /* Set or unset auto-negotiation 100M advertisement */
75410998SChenlu.Chen@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
75510998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
75610998SChenlu.Chen@Sun.COM &autoneg_reg);
75710998SChenlu.Chen@Sun.COM
75810998SChenlu.Chen@Sun.COM autoneg_reg &= ~IXGBE_MII_100BASE_T_ADVERTISE;
75910998SChenlu.Chen@Sun.COM if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
76010998SChenlu.Chen@Sun.COM autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE;
76110998SChenlu.Chen@Sun.COM
76210998SChenlu.Chen@Sun.COM hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
76310998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
76410998SChenlu.Chen@Sun.COM autoneg_reg);
76510998SChenlu.Chen@Sun.COM }
76610998SChenlu.Chen@Sun.COM
76710998SChenlu.Chen@Sun.COM /* Restart PHY autonegotiation and wait for completion */
76810998SChenlu.Chen@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
76910998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
77010998SChenlu.Chen@Sun.COM
77110998SChenlu.Chen@Sun.COM autoneg_reg |= IXGBE_MII_RESTART;
77210998SChenlu.Chen@Sun.COM
77310998SChenlu.Chen@Sun.COM hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
77410998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
77510998SChenlu.Chen@Sun.COM
77610998SChenlu.Chen@Sun.COM /* Wait for autonegotiation to finish */
77710998SChenlu.Chen@Sun.COM for (time_out = 0; time_out < max_time_out; time_out++) {
77810998SChenlu.Chen@Sun.COM usec_delay(10);
77910998SChenlu.Chen@Sun.COM /* Restart PHY autonegotiation and wait for completion */
78010998SChenlu.Chen@Sun.COM status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
78110998SChenlu.Chen@Sun.COM IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
78210998SChenlu.Chen@Sun.COM &autoneg_reg);
78310998SChenlu.Chen@Sun.COM
78410998SChenlu.Chen@Sun.COM autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE;
78510998SChenlu.Chen@Sun.COM if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) {
78610998SChenlu.Chen@Sun.COM break;
78710998SChenlu.Chen@Sun.COM }
78810998SChenlu.Chen@Sun.COM }
78910998SChenlu.Chen@Sun.COM
79010998SChenlu.Chen@Sun.COM if (time_out == max_time_out) {
79110998SChenlu.Chen@Sun.COM status = IXGBE_ERR_LINK_SETUP;
79210998SChenlu.Chen@Sun.COM DEBUGOUT("ixgbe_setup_phy_link_tnx: time out");
79310998SChenlu.Chen@Sun.COM }
79410998SChenlu.Chen@Sun.COM
79510998SChenlu.Chen@Sun.COM return (status);
79610998SChenlu.Chen@Sun.COM }
79710998SChenlu.Chen@Sun.COM
79810998SChenlu.Chen@Sun.COM /*
7998490SPaul.Guo@Sun.COM * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version
8008490SPaul.Guo@Sun.COM * @hw: pointer to hardware structure
8018490SPaul.Guo@Sun.COM * @firmware_version: pointer to the PHY Firmware Version
8028490SPaul.Guo@Sun.COM */
8038490SPaul.Guo@Sun.COM s32
ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw * hw,u16 * firmware_version)8048490SPaul.Guo@Sun.COM ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, u16 *firmware_version)
8058490SPaul.Guo@Sun.COM {
8068490SPaul.Guo@Sun.COM s32 status = IXGBE_SUCCESS;
8078490SPaul.Guo@Sun.COM
80810998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_get_phy_firmware_version_tnx");
80910998SChenlu.Chen@Sun.COM
8108490SPaul.Guo@Sun.COM status = hw->phy.ops.read_reg(hw, TNX_FW_REV,
8118490SPaul.Guo@Sun.COM IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, firmware_version);
8128490SPaul.Guo@Sun.COM
8138490SPaul.Guo@Sun.COM return (status);
8148490SPaul.Guo@Sun.COM }
8158490SPaul.Guo@Sun.COM
8168490SPaul.Guo@Sun.COM /*
81710998SChenlu.Chen@Sun.COM * ixgbe_get_phy_firmware_version_generic - Gets the PHY Firmware Version
81810305SPaul.Guo@Sun.COM * @hw: pointer to hardware structure
81910305SPaul.Guo@Sun.COM * @firmware_version: pointer to the PHY Firmware Version
82010305SPaul.Guo@Sun.COM */
82110305SPaul.Guo@Sun.COM s32
ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw * hw,u16 * firmware_version)82210998SChenlu.Chen@Sun.COM ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw,
82310998SChenlu.Chen@Sun.COM u16 *firmware_version)
82410305SPaul.Guo@Sun.COM {
82510305SPaul.Guo@Sun.COM s32 status = IXGBE_SUCCESS;
82610305SPaul.Guo@Sun.COM
82710998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_get_phy_firmware_version_generic");
82810998SChenlu.Chen@Sun.COM
82910305SPaul.Guo@Sun.COM status = hw->phy.ops.read_reg(hw, AQ_FW_REV,
83010305SPaul.Guo@Sun.COM IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, firmware_version);
83110305SPaul.Guo@Sun.COM
83210305SPaul.Guo@Sun.COM return (status);
83310305SPaul.Guo@Sun.COM }
83410305SPaul.Guo@Sun.COM
83510305SPaul.Guo@Sun.COM /*
8368490SPaul.Guo@Sun.COM * ixgbe_reset_phy_nl - Performs a PHY reset
8378490SPaul.Guo@Sun.COM * @hw: pointer to hardware structure
8388490SPaul.Guo@Sun.COM */
8398490SPaul.Guo@Sun.COM s32
ixgbe_reset_phy_nl(struct ixgbe_hw * hw)8408490SPaul.Guo@Sun.COM ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
8418490SPaul.Guo@Sun.COM {
8428490SPaul.Guo@Sun.COM u16 phy_offset, control, eword, edata, block_crc;
8438490SPaul.Guo@Sun.COM bool end_data = false;
8448490SPaul.Guo@Sun.COM u16 list_offset, data_offset;
8458490SPaul.Guo@Sun.COM u16 phy_data = 0;
8468490SPaul.Guo@Sun.COM s32 ret_val = IXGBE_SUCCESS;
8478490SPaul.Guo@Sun.COM u32 i;
8488490SPaul.Guo@Sun.COM
84910998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_reset_phy_nl");
85010998SChenlu.Chen@Sun.COM
8518490SPaul.Guo@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
8528490SPaul.Guo@Sun.COM IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
8538490SPaul.Guo@Sun.COM
8548490SPaul.Guo@Sun.COM /* reset the PHY and poll for completion */
8558490SPaul.Guo@Sun.COM hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
8568490SPaul.Guo@Sun.COM IXGBE_MDIO_PHY_XS_DEV_TYPE,
8578490SPaul.Guo@Sun.COM (phy_data | IXGBE_MDIO_PHY_XS_RESET));
8588490SPaul.Guo@Sun.COM
8598490SPaul.Guo@Sun.COM for (i = 0; i < 100; i++) {
8608490SPaul.Guo@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
8618490SPaul.Guo@Sun.COM IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
8628490SPaul.Guo@Sun.COM if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0)
8638490SPaul.Guo@Sun.COM break;
8648490SPaul.Guo@Sun.COM msec_delay(10);
8658490SPaul.Guo@Sun.COM }
8668490SPaul.Guo@Sun.COM
8678490SPaul.Guo@Sun.COM if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) {
8688490SPaul.Guo@Sun.COM DEBUGOUT("PHY reset did not complete.\n");
8698490SPaul.Guo@Sun.COM ret_val = IXGBE_ERR_PHY;
8708490SPaul.Guo@Sun.COM goto out;
8718490SPaul.Guo@Sun.COM }
8728490SPaul.Guo@Sun.COM
8738490SPaul.Guo@Sun.COM /* Get init offsets */
8748490SPaul.Guo@Sun.COM ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
8758490SPaul.Guo@Sun.COM &data_offset);
8768490SPaul.Guo@Sun.COM if (ret_val != IXGBE_SUCCESS)
8778490SPaul.Guo@Sun.COM goto out;
8788490SPaul.Guo@Sun.COM
8798490SPaul.Guo@Sun.COM ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc);
8808490SPaul.Guo@Sun.COM data_offset++;
8818490SPaul.Guo@Sun.COM while (!end_data) {
8828490SPaul.Guo@Sun.COM /*
8838490SPaul.Guo@Sun.COM * Read control word from PHY init contents offset
8848490SPaul.Guo@Sun.COM */
8858490SPaul.Guo@Sun.COM ret_val = hw->eeprom.ops.read(hw, data_offset, &eword);
8868490SPaul.Guo@Sun.COM control = (eword & IXGBE_CONTROL_MASK_NL) >>
8878490SPaul.Guo@Sun.COM IXGBE_CONTROL_SHIFT_NL;
8888490SPaul.Guo@Sun.COM edata = eword & IXGBE_DATA_MASK_NL;
8898490SPaul.Guo@Sun.COM switch (control) {
8908490SPaul.Guo@Sun.COM case IXGBE_DELAY_NL:
8918490SPaul.Guo@Sun.COM data_offset++;
8928490SPaul.Guo@Sun.COM DEBUGOUT1("DELAY: %d MS\n", edata);
8938490SPaul.Guo@Sun.COM msec_delay(edata);
8948490SPaul.Guo@Sun.COM break;
8958490SPaul.Guo@Sun.COM case IXGBE_DATA_NL:
8968490SPaul.Guo@Sun.COM DEBUGOUT("DATA: \n");
8978490SPaul.Guo@Sun.COM data_offset++;
8988490SPaul.Guo@Sun.COM hw->eeprom.ops.read(hw, data_offset++, &phy_offset);
8998490SPaul.Guo@Sun.COM for (i = 0; i < edata; i++) {
9008490SPaul.Guo@Sun.COM hw->eeprom.ops.read(hw, data_offset, &eword);
9018490SPaul.Guo@Sun.COM hw->phy.ops.write_reg(hw, phy_offset,
9028490SPaul.Guo@Sun.COM IXGBE_TWINAX_DEV, eword);
9038490SPaul.Guo@Sun.COM DEBUGOUT2("Wrote %4.4x to %4.4x\n", eword,
9048490SPaul.Guo@Sun.COM phy_offset);
9058490SPaul.Guo@Sun.COM data_offset++;
9068490SPaul.Guo@Sun.COM phy_offset++;
9078490SPaul.Guo@Sun.COM }
9088490SPaul.Guo@Sun.COM break;
9098490SPaul.Guo@Sun.COM case IXGBE_CONTROL_NL:
9108490SPaul.Guo@Sun.COM data_offset++;
9118490SPaul.Guo@Sun.COM DEBUGOUT("CONTROL: \n");
9128490SPaul.Guo@Sun.COM if (edata == IXGBE_CONTROL_EOL_NL) {
9138490SPaul.Guo@Sun.COM DEBUGOUT("EOL\n");
9148490SPaul.Guo@Sun.COM end_data = true;
9158490SPaul.Guo@Sun.COM } else if (edata == IXGBE_CONTROL_SOL_NL) {
9168490SPaul.Guo@Sun.COM DEBUGOUT("SOL\n");
9178490SPaul.Guo@Sun.COM } else {
9188490SPaul.Guo@Sun.COM DEBUGOUT("Bad control value\n");
9198490SPaul.Guo@Sun.COM ret_val = IXGBE_ERR_PHY;
9208490SPaul.Guo@Sun.COM goto out;
9218490SPaul.Guo@Sun.COM }
9228490SPaul.Guo@Sun.COM break;
9238490SPaul.Guo@Sun.COM default:
9248490SPaul.Guo@Sun.COM DEBUGOUT("Bad control type\n");
9258490SPaul.Guo@Sun.COM ret_val = IXGBE_ERR_PHY;
9268490SPaul.Guo@Sun.COM goto out;
9278490SPaul.Guo@Sun.COM }
9288490SPaul.Guo@Sun.COM }
9298490SPaul.Guo@Sun.COM
9308490SPaul.Guo@Sun.COM out:
9318490SPaul.Guo@Sun.COM return (ret_val);
9328490SPaul.Guo@Sun.COM }
9338490SPaul.Guo@Sun.COM
9348490SPaul.Guo@Sun.COM /*
9359353SSamuel.Tu@Sun.COM * ixgbe_identify_sfp_module_generic - Identifies SFP module
9368490SPaul.Guo@Sun.COM * @hw: pointer to hardware structure
9378490SPaul.Guo@Sun.COM *
9389353SSamuel.Tu@Sun.COM * Searches for and identifies the SFP module and assigns appropriate PHY type.
9398490SPaul.Guo@Sun.COM */
9408490SPaul.Guo@Sun.COM s32
ixgbe_identify_sfp_module_generic(struct ixgbe_hw * hw)9418490SPaul.Guo@Sun.COM ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
9428490SPaul.Guo@Sun.COM {
9438490SPaul.Guo@Sun.COM s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
9448490SPaul.Guo@Sun.COM u32 vendor_oui = 0;
9459353SSamuel.Tu@Sun.COM enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
9468490SPaul.Guo@Sun.COM u8 identifier = 0;
9478490SPaul.Guo@Sun.COM u8 comp_codes_1g = 0;
9488490SPaul.Guo@Sun.COM u8 comp_codes_10g = 0;
9499353SSamuel.Tu@Sun.COM u8 oui_bytes[3] = {0, 0, 0};
95010305SPaul.Guo@Sun.COM u8 cable_tech = 0;
951*13006SChenlu.Chen@Sun.COM u8 cable_spec = 0;
9529353SSamuel.Tu@Sun.COM u16 enforce_sfp = 0;
9538490SPaul.Guo@Sun.COM
95410998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_identify_sfp_module_generic");
95510998SChenlu.Chen@Sun.COM
95610305SPaul.Guo@Sun.COM if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) {
95710305SPaul.Guo@Sun.COM hw->phy.sfp_type = ixgbe_sfp_type_not_present;
95810305SPaul.Guo@Sun.COM status = IXGBE_ERR_SFP_NOT_PRESENT;
95910305SPaul.Guo@Sun.COM goto out;
96010305SPaul.Guo@Sun.COM }
96110305SPaul.Guo@Sun.COM
9628490SPaul.Guo@Sun.COM status = hw->phy.ops.read_i2c_eeprom(hw,
9638490SPaul.Guo@Sun.COM IXGBE_SFF_IDENTIFIER, &identifier);
9648490SPaul.Guo@Sun.COM
9659353SSamuel.Tu@Sun.COM if (status == IXGBE_ERR_SFP_NOT_PRESENT || status == IXGBE_ERR_I2C) {
9669353SSamuel.Tu@Sun.COM status = IXGBE_ERR_SFP_NOT_PRESENT;
9678490SPaul.Guo@Sun.COM hw->phy.sfp_type = ixgbe_sfp_type_not_present;
9689353SSamuel.Tu@Sun.COM if (hw->phy.type != ixgbe_phy_nl) {
9699353SSamuel.Tu@Sun.COM hw->phy.id = 0;
9709353SSamuel.Tu@Sun.COM hw->phy.type = ixgbe_phy_unknown;
9719353SSamuel.Tu@Sun.COM }
9728490SPaul.Guo@Sun.COM goto out;
9738490SPaul.Guo@Sun.COM }
9748490SPaul.Guo@Sun.COM
9759353SSamuel.Tu@Sun.COM /* LAN ID is needed for sfp_type determination */
9769353SSamuel.Tu@Sun.COM hw->mac.ops.set_lan_id(hw);
9779353SSamuel.Tu@Sun.COM
97810305SPaul.Guo@Sun.COM if (identifier != IXGBE_SFF_IDENTIFIER_SFP) {
97910305SPaul.Guo@Sun.COM hw->phy.type = ixgbe_phy_sfp_unsupported;
98010305SPaul.Guo@Sun.COM status = IXGBE_ERR_SFP_NOT_SUPPORTED;
98110305SPaul.Guo@Sun.COM } else {
9828490SPaul.Guo@Sun.COM hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES,
9838490SPaul.Guo@Sun.COM &comp_codes_1g);
9848490SPaul.Guo@Sun.COM hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES,
9858490SPaul.Guo@Sun.COM &comp_codes_10g);
98610305SPaul.Guo@Sun.COM hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_CABLE_TECHNOLOGY,
98710305SPaul.Guo@Sun.COM &cable_tech);
9888490SPaul.Guo@Sun.COM
9898490SPaul.Guo@Sun.COM /*
9908490SPaul.Guo@Sun.COM * ID Module
9918490SPaul.Guo@Sun.COM * ============
9928490SPaul.Guo@Sun.COM * 0 SFP_DA_CU
9938490SPaul.Guo@Sun.COM * 1 SFP_SR
9948490SPaul.Guo@Sun.COM * 2 SFP_LR
9959353SSamuel.Tu@Sun.COM * 3 SFP_DA_CORE0 - 82599-specific
9969353SSamuel.Tu@Sun.COM * 4 SFP_DA_CORE1 - 82599-specific
9979353SSamuel.Tu@Sun.COM * 5 SFP_SR/LR_CORE0 - 82599-specific
9989353SSamuel.Tu@Sun.COM * 6 SFP_SR/LR_CORE1 - 82599-specific
999*13006SChenlu.Chen@Sun.COM * 7 SFP_act_lmt_DA_CORE0 - 82599-specific
1000*13006SChenlu.Chen@Sun.COM * 8 SFP_act_lmt_DA_CORE1 - 82599-specific
1001*13006SChenlu.Chen@Sun.COM * 9 SFP_1g_cu_CORE0 - 82599-specific
1002*13006SChenlu.Chen@Sun.COM * 10 SFP_1g_cu_CORE1 - 82599-specific
10038490SPaul.Guo@Sun.COM */
10049353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82598EB) {
100510305SPaul.Guo@Sun.COM if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
10069353SSamuel.Tu@Sun.COM hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
10079353SSamuel.Tu@Sun.COM else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
10089353SSamuel.Tu@Sun.COM hw->phy.sfp_type = ixgbe_sfp_type_sr;
10099353SSamuel.Tu@Sun.COM else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
10109353SSamuel.Tu@Sun.COM hw->phy.sfp_type = ixgbe_sfp_type_lr;
10119353SSamuel.Tu@Sun.COM else
10129353SSamuel.Tu@Sun.COM hw->phy.sfp_type = ixgbe_sfp_type_unknown;
10139353SSamuel.Tu@Sun.COM } else if (hw->mac.type == ixgbe_mac_82599EB) {
1014*13006SChenlu.Chen@Sun.COM if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) {
10159353SSamuel.Tu@Sun.COM if (hw->bus.lan_id == 0)
10169353SSamuel.Tu@Sun.COM hw->phy.sfp_type =
10179353SSamuel.Tu@Sun.COM ixgbe_sfp_type_da_cu_core0;
10189353SSamuel.Tu@Sun.COM else
10199353SSamuel.Tu@Sun.COM hw->phy.sfp_type =
10209353SSamuel.Tu@Sun.COM ixgbe_sfp_type_da_cu_core1;
1021*13006SChenlu.Chen@Sun.COM } else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) {
1022*13006SChenlu.Chen@Sun.COM hw->phy.ops.read_i2c_eeprom(
1023*13006SChenlu.Chen@Sun.COM hw, IXGBE_SFF_CABLE_SPEC_COMP, &cable_spec);
1024*13006SChenlu.Chen@Sun.COM if (cable_spec &
1025*13006SChenlu.Chen@Sun.COM IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) {
1026*13006SChenlu.Chen@Sun.COM if (hw->bus.lan_id == 0)
1027*13006SChenlu.Chen@Sun.COM hw->phy.sfp_type =
1028*13006SChenlu.Chen@Sun.COM ixgbe_sfp_type_da_act_lmt_core0;
1029*13006SChenlu.Chen@Sun.COM else
1030*13006SChenlu.Chen@Sun.COM hw->phy.sfp_type =
1031*13006SChenlu.Chen@Sun.COM ixgbe_sfp_type_da_act_lmt_core1;
1032*13006SChenlu.Chen@Sun.COM } else
1033*13006SChenlu.Chen@Sun.COM hw->phy.sfp_type =
1034*13006SChenlu.Chen@Sun.COM ixgbe_sfp_type_unknown;
1035*13006SChenlu.Chen@Sun.COM } else if (comp_codes_10g &
1036*13006SChenlu.Chen@Sun.COM (IXGBE_SFF_10GBASESR_CAPABLE |
1037*13006SChenlu.Chen@Sun.COM IXGBE_SFF_10GBASELR_CAPABLE)) {
10389353SSamuel.Tu@Sun.COM if (hw->bus.lan_id == 0)
10399353SSamuel.Tu@Sun.COM hw->phy.sfp_type =
10409353SSamuel.Tu@Sun.COM ixgbe_sfp_type_srlr_core0;
10419353SSamuel.Tu@Sun.COM else
10429353SSamuel.Tu@Sun.COM hw->phy.sfp_type =
10439353SSamuel.Tu@Sun.COM ixgbe_sfp_type_srlr_core1;
1044*13006SChenlu.Chen@Sun.COM } else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) {
10459353SSamuel.Tu@Sun.COM if (hw->bus.lan_id == 0)
10469353SSamuel.Tu@Sun.COM hw->phy.sfp_type =
1047*13006SChenlu.Chen@Sun.COM ixgbe_sfp_type_1g_cu_core0;
10489353SSamuel.Tu@Sun.COM else
10499353SSamuel.Tu@Sun.COM hw->phy.sfp_type =
1050*13006SChenlu.Chen@Sun.COM ixgbe_sfp_type_1g_cu_core1;
1051*13006SChenlu.Chen@Sun.COM } else {
10529353SSamuel.Tu@Sun.COM hw->phy.sfp_type = ixgbe_sfp_type_unknown;
1053*13006SChenlu.Chen@Sun.COM }
10549353SSamuel.Tu@Sun.COM }
10559353SSamuel.Tu@Sun.COM
10569353SSamuel.Tu@Sun.COM if (hw->phy.sfp_type != stored_sfp_type)
10579353SSamuel.Tu@Sun.COM hw->phy.sfp_setup_needed = true;
10589353SSamuel.Tu@Sun.COM
10599353SSamuel.Tu@Sun.COM /* Determine if the SFP+ PHY is dual speed or not. */
106010305SPaul.Guo@Sun.COM hw->phy.multispeed_fiber = false;
10619353SSamuel.Tu@Sun.COM if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) &&
10629353SSamuel.Tu@Sun.COM (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) ||
10639353SSamuel.Tu@Sun.COM ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) &&
10649353SSamuel.Tu@Sun.COM (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)))
10659353SSamuel.Tu@Sun.COM hw->phy.multispeed_fiber = true;
10668490SPaul.Guo@Sun.COM
10678490SPaul.Guo@Sun.COM /* Determine PHY vendor */
10689353SSamuel.Tu@Sun.COM if (hw->phy.type != ixgbe_phy_nl) {
10698490SPaul.Guo@Sun.COM hw->phy.id = identifier;
10708490SPaul.Guo@Sun.COM hw->phy.ops.read_i2c_eeprom(hw,
10718490SPaul.Guo@Sun.COM IXGBE_SFF_VENDOR_OUI_BYTE0, &oui_bytes[0]);
10728490SPaul.Guo@Sun.COM hw->phy.ops.read_i2c_eeprom(hw,
10738490SPaul.Guo@Sun.COM IXGBE_SFF_VENDOR_OUI_BYTE1, &oui_bytes[1]);
10748490SPaul.Guo@Sun.COM hw->phy.ops.read_i2c_eeprom(hw,
10758490SPaul.Guo@Sun.COM IXGBE_SFF_VENDOR_OUI_BYTE2, &oui_bytes[2]);
10768490SPaul.Guo@Sun.COM
10778490SPaul.Guo@Sun.COM vendor_oui =
10788490SPaul.Guo@Sun.COM ((oui_bytes[0] <<
10798490SPaul.Guo@Sun.COM IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
10808490SPaul.Guo@Sun.COM (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
10818490SPaul.Guo@Sun.COM (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
10828490SPaul.Guo@Sun.COM
10838490SPaul.Guo@Sun.COM switch (vendor_oui) {
10848490SPaul.Guo@Sun.COM case IXGBE_SFF_VENDOR_OUI_TYCO:
108510305SPaul.Guo@Sun.COM if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
1086*13006SChenlu.Chen@Sun.COM hw->phy.type =
1087*13006SChenlu.Chen@Sun.COM ixgbe_phy_sfp_passive_tyco;
10888490SPaul.Guo@Sun.COM break;
10898490SPaul.Guo@Sun.COM case IXGBE_SFF_VENDOR_OUI_FTL:
1090*13006SChenlu.Chen@Sun.COM if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
1091*13006SChenlu.Chen@Sun.COM hw->phy.type = ixgbe_phy_sfp_ftl_active;
1092*13006SChenlu.Chen@Sun.COM else
1093*13006SChenlu.Chen@Sun.COM hw->phy.type = ixgbe_phy_sfp_ftl;
10948490SPaul.Guo@Sun.COM break;
10958490SPaul.Guo@Sun.COM case IXGBE_SFF_VENDOR_OUI_AVAGO:
10968490SPaul.Guo@Sun.COM hw->phy.type = ixgbe_phy_sfp_avago;
10978490SPaul.Guo@Sun.COM break;
10989353SSamuel.Tu@Sun.COM case IXGBE_SFF_VENDOR_OUI_INTEL:
10999353SSamuel.Tu@Sun.COM hw->phy.type = ixgbe_phy_sfp_intel;
11009353SSamuel.Tu@Sun.COM break;
11018490SPaul.Guo@Sun.COM default:
110210305SPaul.Guo@Sun.COM if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
1103*13006SChenlu.Chen@Sun.COM hw->phy.type =
1104*13006SChenlu.Chen@Sun.COM ixgbe_phy_sfp_passive_unknown;
1105*13006SChenlu.Chen@Sun.COM else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
1106*13006SChenlu.Chen@Sun.COM hw->phy.type =
1107*13006SChenlu.Chen@Sun.COM ixgbe_phy_sfp_active_unknown;
11088490SPaul.Guo@Sun.COM else
11098490SPaul.Guo@Sun.COM hw->phy.type = ixgbe_phy_sfp_unknown;
11108490SPaul.Guo@Sun.COM break;
11118490SPaul.Guo@Sun.COM }
11128490SPaul.Guo@Sun.COM }
11139353SSamuel.Tu@Sun.COM
1114*13006SChenlu.Chen@Sun.COM /* Allow any DA cable vendor */
1115*13006SChenlu.Chen@Sun.COM if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE |
1116*13006SChenlu.Chen@Sun.COM IXGBE_SFF_DA_ACTIVE_CABLE)) {
111710305SPaul.Guo@Sun.COM status = IXGBE_SUCCESS;
111810305SPaul.Guo@Sun.COM goto out;
111910305SPaul.Guo@Sun.COM }
112010305SPaul.Guo@Sun.COM
1121*13006SChenlu.Chen@Sun.COM /* Verify supporteed 1G SFP modules */
1122*13006SChenlu.Chen@Sun.COM if (comp_codes_10g == 0 &&
1123*13006SChenlu.Chen@Sun.COM !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
1124*13006SChenlu.Chen@Sun.COM hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0)) {
112510305SPaul.Guo@Sun.COM hw->phy.type = ixgbe_phy_sfp_unsupported;
112610305SPaul.Guo@Sun.COM status = IXGBE_ERR_SFP_NOT_SUPPORTED;
112710305SPaul.Guo@Sun.COM goto out;
112810305SPaul.Guo@Sun.COM }
112910305SPaul.Guo@Sun.COM
113010305SPaul.Guo@Sun.COM /* Anything else 82598-based is supported */
113110305SPaul.Guo@Sun.COM if (hw->mac.type == ixgbe_mac_82598EB) {
11329353SSamuel.Tu@Sun.COM status = IXGBE_SUCCESS;
11339353SSamuel.Tu@Sun.COM goto out;
11349353SSamuel.Tu@Sun.COM }
11359353SSamuel.Tu@Sun.COM
11369353SSamuel.Tu@Sun.COM (void) ixgbe_get_device_caps(hw, &enforce_sfp);
1137*13006SChenlu.Chen@Sun.COM if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) &&
1138*13006SChenlu.Chen@Sun.COM !((hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0) ||
1139*13006SChenlu.Chen@Sun.COM (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1))) {
11409353SSamuel.Tu@Sun.COM /* Make sure we're a supported PHY type */
11419353SSamuel.Tu@Sun.COM if (hw->phy.type == ixgbe_phy_sfp_intel) {
11429353SSamuel.Tu@Sun.COM status = IXGBE_SUCCESS;
11439353SSamuel.Tu@Sun.COM } else {
11449353SSamuel.Tu@Sun.COM DEBUGOUT("SFP+ module not supported\n");
11459353SSamuel.Tu@Sun.COM hw->phy.type = ixgbe_phy_sfp_unsupported;
11469353SSamuel.Tu@Sun.COM status = IXGBE_ERR_SFP_NOT_SUPPORTED;
11479353SSamuel.Tu@Sun.COM }
11489353SSamuel.Tu@Sun.COM } else {
11499353SSamuel.Tu@Sun.COM status = IXGBE_SUCCESS;
11509353SSamuel.Tu@Sun.COM }
11518490SPaul.Guo@Sun.COM }
11528490SPaul.Guo@Sun.COM
11538490SPaul.Guo@Sun.COM out:
11548490SPaul.Guo@Sun.COM return (status);
11558490SPaul.Guo@Sun.COM }
11568490SPaul.Guo@Sun.COM
11578490SPaul.Guo@Sun.COM
11588490SPaul.Guo@Sun.COM /*
11599353SSamuel.Tu@Sun.COM * ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence
11608490SPaul.Guo@Sun.COM * @hw: pointer to hardware structure
11618490SPaul.Guo@Sun.COM * @list_offset: offset to the SFP ID list
11628490SPaul.Guo@Sun.COM * @data_offset: offset to the SFP data block
11639353SSamuel.Tu@Sun.COM *
11649353SSamuel.Tu@Sun.COM * Checks the MAC's EEPROM to see if it supports a given SFP+ module type, if
11659353SSamuel.Tu@Sun.COM * so it returns the offsets to the phy init sequence block.
11668490SPaul.Guo@Sun.COM */
ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw * hw,u16 * list_offset,u16 * data_offset)11678490SPaul.Guo@Sun.COM s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
11688490SPaul.Guo@Sun.COM u16 *list_offset, u16 *data_offset)
11698490SPaul.Guo@Sun.COM {
11708490SPaul.Guo@Sun.COM u16 sfp_id;
1171*13006SChenlu.Chen@Sun.COM u16 sfp_type = hw->phy.sfp_type;
11728490SPaul.Guo@Sun.COM
117310998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_get_sfp_init_sequence_offsets");
117410998SChenlu.Chen@Sun.COM
11758490SPaul.Guo@Sun.COM if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
11768490SPaul.Guo@Sun.COM return (IXGBE_ERR_SFP_NOT_SUPPORTED);
11778490SPaul.Guo@Sun.COM
11788490SPaul.Guo@Sun.COM if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
11798490SPaul.Guo@Sun.COM return (IXGBE_ERR_SFP_NOT_PRESENT);
11808490SPaul.Guo@Sun.COM
11818490SPaul.Guo@Sun.COM if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) &&
11828490SPaul.Guo@Sun.COM (hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
11838490SPaul.Guo@Sun.COM return (IXGBE_ERR_SFP_NOT_SUPPORTED);
11848490SPaul.Guo@Sun.COM
1185*13006SChenlu.Chen@Sun.COM /*
1186*13006SChenlu.Chen@Sun.COM * Limiting active cables and 1G Phys must be initialized as
1187*13006SChenlu.Chen@Sun.COM * SR modules
1188*13006SChenlu.Chen@Sun.COM */
1189*13006SChenlu.Chen@Sun.COM if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
1190*13006SChenlu.Chen@Sun.COM sfp_type == ixgbe_sfp_type_1g_cu_core0)
1191*13006SChenlu.Chen@Sun.COM sfp_type = ixgbe_sfp_type_srlr_core0;
1192*13006SChenlu.Chen@Sun.COM else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
1193*13006SChenlu.Chen@Sun.COM sfp_type == ixgbe_sfp_type_1g_cu_core1)
1194*13006SChenlu.Chen@Sun.COM sfp_type = ixgbe_sfp_type_srlr_core1;
1195*13006SChenlu.Chen@Sun.COM
11968490SPaul.Guo@Sun.COM /* Read offset to PHY init contents */
11978490SPaul.Guo@Sun.COM hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset);
11988490SPaul.Guo@Sun.COM
11998490SPaul.Guo@Sun.COM if ((!*list_offset) || (*list_offset == 0xFFFF))
12009353SSamuel.Tu@Sun.COM return (IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT);
12018490SPaul.Guo@Sun.COM
12028490SPaul.Guo@Sun.COM /* Shift offset to first ID word */
12038490SPaul.Guo@Sun.COM (*list_offset)++;
12048490SPaul.Guo@Sun.COM
12058490SPaul.Guo@Sun.COM /*
12068490SPaul.Guo@Sun.COM * Find the matching SFP ID in the EEPROM
12078490SPaul.Guo@Sun.COM * and program the init sequence
12088490SPaul.Guo@Sun.COM */
12098490SPaul.Guo@Sun.COM hw->eeprom.ops.read(hw, *list_offset, &sfp_id);
12108490SPaul.Guo@Sun.COM
12118490SPaul.Guo@Sun.COM while (sfp_id != IXGBE_PHY_INIT_END_NL) {
1212*13006SChenlu.Chen@Sun.COM if (sfp_id == sfp_type) {
12138490SPaul.Guo@Sun.COM (*list_offset)++;
12148490SPaul.Guo@Sun.COM hw->eeprom.ops.read(hw, *list_offset, data_offset);
12158490SPaul.Guo@Sun.COM if ((!*data_offset) || (*data_offset == 0xFFFF)) {
12168490SPaul.Guo@Sun.COM DEBUGOUT("SFP+ module not supported\n");
12178490SPaul.Guo@Sun.COM return (IXGBE_ERR_SFP_NOT_SUPPORTED);
12188490SPaul.Guo@Sun.COM } else {
12198490SPaul.Guo@Sun.COM break;
12208490SPaul.Guo@Sun.COM }
12218490SPaul.Guo@Sun.COM } else {
12228490SPaul.Guo@Sun.COM (*list_offset) += 2;
12238490SPaul.Guo@Sun.COM if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id))
12248490SPaul.Guo@Sun.COM return (IXGBE_ERR_PHY);
12258490SPaul.Guo@Sun.COM }
12268490SPaul.Guo@Sun.COM }
12278490SPaul.Guo@Sun.COM
12288490SPaul.Guo@Sun.COM if (sfp_id == IXGBE_PHY_INIT_END_NL) {
12298490SPaul.Guo@Sun.COM DEBUGOUT("No matching SFP+ module found\n");
12308490SPaul.Guo@Sun.COM return (IXGBE_ERR_SFP_NOT_SUPPORTED);
12318490SPaul.Guo@Sun.COM }
12328490SPaul.Guo@Sun.COM
12338490SPaul.Guo@Sun.COM return (IXGBE_SUCCESS);
12348490SPaul.Guo@Sun.COM }
12359353SSamuel.Tu@Sun.COM
12369353SSamuel.Tu@Sun.COM /*
12379353SSamuel.Tu@Sun.COM * ixgbe_read_i2c_eeprom_generic - Reads 8 bit EEPROM word over I2C interface
12389353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
12399353SSamuel.Tu@Sun.COM * @byte_offset: EEPROM byte offset to read
12409353SSamuel.Tu@Sun.COM * @eeprom_data: value read
12419353SSamuel.Tu@Sun.COM *
12429353SSamuel.Tu@Sun.COM * Performs byte read operation to SFP module's EEPROM over I2C interface.
12439353SSamuel.Tu@Sun.COM */
12449353SSamuel.Tu@Sun.COM s32
ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 * eeprom_data)12459353SSamuel.Tu@Sun.COM ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
12469353SSamuel.Tu@Sun.COM u8 *eeprom_data)
12479353SSamuel.Tu@Sun.COM {
12489353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_read_i2c_eeprom_generic");
12499353SSamuel.Tu@Sun.COM
12509353SSamuel.Tu@Sun.COM return (hw->phy.ops.read_i2c_byte(hw, byte_offset,
12519353SSamuel.Tu@Sun.COM IXGBE_I2C_EEPROM_DEV_ADDR, eeprom_data));
12529353SSamuel.Tu@Sun.COM }
12539353SSamuel.Tu@Sun.COM
12549353SSamuel.Tu@Sun.COM /*
12559353SSamuel.Tu@Sun.COM * ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface
12569353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
12579353SSamuel.Tu@Sun.COM * @byte_offset: EEPROM byte offset to write
12589353SSamuel.Tu@Sun.COM * @eeprom_data: value to write
12599353SSamuel.Tu@Sun.COM *
12609353SSamuel.Tu@Sun.COM * Performs byte write operation to SFP module's EEPROM over I2C interface.
12619353SSamuel.Tu@Sun.COM */
ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 eeprom_data)12629353SSamuel.Tu@Sun.COM s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
12639353SSamuel.Tu@Sun.COM u8 eeprom_data)
12649353SSamuel.Tu@Sun.COM {
12659353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_write_i2c_eeprom_generic");
12669353SSamuel.Tu@Sun.COM
12679353SSamuel.Tu@Sun.COM return (hw->phy.ops.write_i2c_byte(hw, byte_offset,
12689353SSamuel.Tu@Sun.COM IXGBE_I2C_EEPROM_DEV_ADDR, eeprom_data));
12699353SSamuel.Tu@Sun.COM }
12709353SSamuel.Tu@Sun.COM
12719353SSamuel.Tu@Sun.COM /*
12729353SSamuel.Tu@Sun.COM * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
12739353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
12749353SSamuel.Tu@Sun.COM * @byte_offset: byte offset to read
12759353SSamuel.Tu@Sun.COM * @data: value read
12769353SSamuel.Tu@Sun.COM *
12779353SSamuel.Tu@Sun.COM * Performs byte read operation to SFP module's EEPROM over I2C interface at
12789353SSamuel.Tu@Sun.COM * a specified deivce address.
12799353SSamuel.Tu@Sun.COM */
12809353SSamuel.Tu@Sun.COM s32
ixgbe_read_i2c_byte_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 * data)12819353SSamuel.Tu@Sun.COM ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
12829353SSamuel.Tu@Sun.COM u8 dev_addr, u8 *data)
12839353SSamuel.Tu@Sun.COM {
12849353SSamuel.Tu@Sun.COM s32 status = IXGBE_SUCCESS;
128510305SPaul.Guo@Sun.COM u32 max_retry = 10;
12869353SSamuel.Tu@Sun.COM u32 retry = 0;
12879353SSamuel.Tu@Sun.COM u16 swfw_mask = 0;
12889353SSamuel.Tu@Sun.COM bool nack = 1;
12899353SSamuel.Tu@Sun.COM
12909353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_read_i2c_byte_generic");
12919353SSamuel.Tu@Sun.COM
12929353SSamuel.Tu@Sun.COM if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
12939353SSamuel.Tu@Sun.COM swfw_mask = IXGBE_GSSR_PHY1_SM;
12949353SSamuel.Tu@Sun.COM else
12959353SSamuel.Tu@Sun.COM swfw_mask = IXGBE_GSSR_PHY0_SM;
12969353SSamuel.Tu@Sun.COM
129710305SPaul.Guo@Sun.COM do {
129810305SPaul.Guo@Sun.COM if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != IXGBE_SUCCESS) {
129910305SPaul.Guo@Sun.COM status = IXGBE_ERR_SWFW_SYNC;
130010305SPaul.Guo@Sun.COM goto read_byte_out;
130110305SPaul.Guo@Sun.COM }
13029353SSamuel.Tu@Sun.COM
13039353SSamuel.Tu@Sun.COM ixgbe_i2c_start(hw);
13049353SSamuel.Tu@Sun.COM
13059353SSamuel.Tu@Sun.COM /* Device Address and write indication */
13069353SSamuel.Tu@Sun.COM status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
13079353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
13089353SSamuel.Tu@Sun.COM goto fail;
13099353SSamuel.Tu@Sun.COM
13109353SSamuel.Tu@Sun.COM status = ixgbe_get_i2c_ack(hw);
13119353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
13129353SSamuel.Tu@Sun.COM goto fail;
13139353SSamuel.Tu@Sun.COM
13149353SSamuel.Tu@Sun.COM status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
13159353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
13169353SSamuel.Tu@Sun.COM goto fail;
13179353SSamuel.Tu@Sun.COM
13189353SSamuel.Tu@Sun.COM status = ixgbe_get_i2c_ack(hw);
13199353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
13209353SSamuel.Tu@Sun.COM goto fail;
13219353SSamuel.Tu@Sun.COM
13229353SSamuel.Tu@Sun.COM ixgbe_i2c_start(hw);
13239353SSamuel.Tu@Sun.COM
13249353SSamuel.Tu@Sun.COM /* Device Address and read indication */
13259353SSamuel.Tu@Sun.COM status = ixgbe_clock_out_i2c_byte(hw, (dev_addr | 0x1));
13269353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
13279353SSamuel.Tu@Sun.COM goto fail;
13289353SSamuel.Tu@Sun.COM
13299353SSamuel.Tu@Sun.COM status = ixgbe_get_i2c_ack(hw);
13309353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
13319353SSamuel.Tu@Sun.COM goto fail;
13329353SSamuel.Tu@Sun.COM
13339353SSamuel.Tu@Sun.COM status = ixgbe_clock_in_i2c_byte(hw, data);
13349353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
13359353SSamuel.Tu@Sun.COM goto fail;
13369353SSamuel.Tu@Sun.COM
13379353SSamuel.Tu@Sun.COM status = ixgbe_clock_out_i2c_bit(hw, nack);
13389353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
13399353SSamuel.Tu@Sun.COM goto fail;
13409353SSamuel.Tu@Sun.COM
13419353SSamuel.Tu@Sun.COM ixgbe_i2c_stop(hw);
13429353SSamuel.Tu@Sun.COM break;
13439353SSamuel.Tu@Sun.COM
13449353SSamuel.Tu@Sun.COM fail:
134510305SPaul.Guo@Sun.COM ixgbe_release_swfw_sync(hw, swfw_mask);
134610305SPaul.Guo@Sun.COM msec_delay(100);
13479353SSamuel.Tu@Sun.COM ixgbe_i2c_bus_clear(hw);
13489353SSamuel.Tu@Sun.COM retry++;
13499353SSamuel.Tu@Sun.COM if (retry < max_retry)
13509353SSamuel.Tu@Sun.COM DEBUGOUT("I2C byte read error - Retrying.\n");
13519353SSamuel.Tu@Sun.COM else
13529353SSamuel.Tu@Sun.COM DEBUGOUT("I2C byte read error.\n");
13539353SSamuel.Tu@Sun.COM } while (retry < max_retry);
13549353SSamuel.Tu@Sun.COM
13559353SSamuel.Tu@Sun.COM ixgbe_release_swfw_sync(hw, swfw_mask);
13569353SSamuel.Tu@Sun.COM
13579353SSamuel.Tu@Sun.COM read_byte_out:
13589353SSamuel.Tu@Sun.COM return (status);
13599353SSamuel.Tu@Sun.COM }
13609353SSamuel.Tu@Sun.COM
13619353SSamuel.Tu@Sun.COM /*
13629353SSamuel.Tu@Sun.COM * ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
13639353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
13649353SSamuel.Tu@Sun.COM * @byte_offset: byte offset to write
13659353SSamuel.Tu@Sun.COM * @data: value to write
13669353SSamuel.Tu@Sun.COM *
13679353SSamuel.Tu@Sun.COM * Performs byte write operation to SFP module's EEPROM over I2C interface at
13689353SSamuel.Tu@Sun.COM * a specified device address.
13699353SSamuel.Tu@Sun.COM */
13709353SSamuel.Tu@Sun.COM s32
ixgbe_write_i2c_byte_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 data)13719353SSamuel.Tu@Sun.COM ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
13729353SSamuel.Tu@Sun.COM u8 dev_addr, u8 data)
13739353SSamuel.Tu@Sun.COM {
13749353SSamuel.Tu@Sun.COM s32 status = IXGBE_SUCCESS;
13759353SSamuel.Tu@Sun.COM u32 max_retry = 1;
13769353SSamuel.Tu@Sun.COM u32 retry = 0;
13779353SSamuel.Tu@Sun.COM u16 swfw_mask = 0;
13789353SSamuel.Tu@Sun.COM
13799353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_write_i2c_byte_generic");
13809353SSamuel.Tu@Sun.COM
13819353SSamuel.Tu@Sun.COM if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
13829353SSamuel.Tu@Sun.COM swfw_mask = IXGBE_GSSR_PHY1_SM;
13839353SSamuel.Tu@Sun.COM else
13849353SSamuel.Tu@Sun.COM swfw_mask = IXGBE_GSSR_PHY0_SM;
13859353SSamuel.Tu@Sun.COM
13869353SSamuel.Tu@Sun.COM if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != IXGBE_SUCCESS) {
13879353SSamuel.Tu@Sun.COM status = IXGBE_ERR_SWFW_SYNC;
13889353SSamuel.Tu@Sun.COM goto write_byte_out;
13899353SSamuel.Tu@Sun.COM }
13909353SSamuel.Tu@Sun.COM
13919353SSamuel.Tu@Sun.COM do {
13929353SSamuel.Tu@Sun.COM ixgbe_i2c_start(hw);
13939353SSamuel.Tu@Sun.COM
13949353SSamuel.Tu@Sun.COM status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
13959353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
13969353SSamuel.Tu@Sun.COM goto fail;
13979353SSamuel.Tu@Sun.COM
13989353SSamuel.Tu@Sun.COM status = ixgbe_get_i2c_ack(hw);
13999353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
14009353SSamuel.Tu@Sun.COM goto fail;
14019353SSamuel.Tu@Sun.COM
14029353SSamuel.Tu@Sun.COM status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
14039353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
14049353SSamuel.Tu@Sun.COM goto fail;
14059353SSamuel.Tu@Sun.COM
14069353SSamuel.Tu@Sun.COM status = ixgbe_get_i2c_ack(hw);
14079353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
14089353SSamuel.Tu@Sun.COM goto fail;
14099353SSamuel.Tu@Sun.COM
14109353SSamuel.Tu@Sun.COM status = ixgbe_clock_out_i2c_byte(hw, data);
14119353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
14129353SSamuel.Tu@Sun.COM goto fail;
14139353SSamuel.Tu@Sun.COM
14149353SSamuel.Tu@Sun.COM status = ixgbe_get_i2c_ack(hw);
14159353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
14169353SSamuel.Tu@Sun.COM goto fail;
14179353SSamuel.Tu@Sun.COM
14189353SSamuel.Tu@Sun.COM ixgbe_i2c_stop(hw);
14199353SSamuel.Tu@Sun.COM break;
14209353SSamuel.Tu@Sun.COM
14219353SSamuel.Tu@Sun.COM fail:
14229353SSamuel.Tu@Sun.COM ixgbe_i2c_bus_clear(hw);
14239353SSamuel.Tu@Sun.COM retry++;
14249353SSamuel.Tu@Sun.COM if (retry < max_retry)
14259353SSamuel.Tu@Sun.COM DEBUGOUT("I2C byte write error - Retrying.\n");
14269353SSamuel.Tu@Sun.COM else
14279353SSamuel.Tu@Sun.COM DEBUGOUT("I2C byte write error.\n");
14289353SSamuel.Tu@Sun.COM } while (retry < max_retry);
14299353SSamuel.Tu@Sun.COM
14309353SSamuel.Tu@Sun.COM ixgbe_release_swfw_sync(hw, swfw_mask);
14319353SSamuel.Tu@Sun.COM
14329353SSamuel.Tu@Sun.COM write_byte_out:
14339353SSamuel.Tu@Sun.COM return (status);
14349353SSamuel.Tu@Sun.COM }
14359353SSamuel.Tu@Sun.COM
14369353SSamuel.Tu@Sun.COM /*
14379353SSamuel.Tu@Sun.COM * ixgbe_i2c_start - Sets I2C start condition
14389353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
14399353SSamuel.Tu@Sun.COM *
14409353SSamuel.Tu@Sun.COM * Sets I2C start condition (High -> Low on SDA while SCL is High)
14419353SSamuel.Tu@Sun.COM */
14429353SSamuel.Tu@Sun.COM static void
ixgbe_i2c_start(struct ixgbe_hw * hw)14439353SSamuel.Tu@Sun.COM ixgbe_i2c_start(struct ixgbe_hw *hw)
14449353SSamuel.Tu@Sun.COM {
14459353SSamuel.Tu@Sun.COM u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
14469353SSamuel.Tu@Sun.COM
14479353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_i2c_start");
14489353SSamuel.Tu@Sun.COM
14499353SSamuel.Tu@Sun.COM /* Start condition must begin with data and clock high */
14509353SSamuel.Tu@Sun.COM (void) ixgbe_set_i2c_data(hw, &i2cctl, 1);
14519353SSamuel.Tu@Sun.COM (void) ixgbe_raise_i2c_clk(hw, &i2cctl);
14529353SSamuel.Tu@Sun.COM
14539353SSamuel.Tu@Sun.COM /* Setup time for start condition (4.7us) */
14549353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_SU_STA);
14559353SSamuel.Tu@Sun.COM
14569353SSamuel.Tu@Sun.COM (void) ixgbe_set_i2c_data(hw, &i2cctl, 0);
14579353SSamuel.Tu@Sun.COM
14589353SSamuel.Tu@Sun.COM /* Hold time for start condition (4us) */
14599353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_HD_STA);
14609353SSamuel.Tu@Sun.COM
14619353SSamuel.Tu@Sun.COM ixgbe_lower_i2c_clk(hw, &i2cctl);
14629353SSamuel.Tu@Sun.COM
14639353SSamuel.Tu@Sun.COM /* Minimum low period of clock is 4.7 us */
14649353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_LOW);
14659353SSamuel.Tu@Sun.COM }
14669353SSamuel.Tu@Sun.COM
14679353SSamuel.Tu@Sun.COM /*
14689353SSamuel.Tu@Sun.COM * ixgbe_i2c_stop - Sets I2C stop condition
14699353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
14709353SSamuel.Tu@Sun.COM *
14719353SSamuel.Tu@Sun.COM * Sets I2C stop condition (Low -> High on SDA while SCL is High)
14729353SSamuel.Tu@Sun.COM */
14739353SSamuel.Tu@Sun.COM static void
ixgbe_i2c_stop(struct ixgbe_hw * hw)14749353SSamuel.Tu@Sun.COM ixgbe_i2c_stop(struct ixgbe_hw *hw)
14759353SSamuel.Tu@Sun.COM {
14769353SSamuel.Tu@Sun.COM u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
14779353SSamuel.Tu@Sun.COM
14789353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_i2c_stop");
14799353SSamuel.Tu@Sun.COM
14809353SSamuel.Tu@Sun.COM /* Stop condition must begin with data low and clock high */
14819353SSamuel.Tu@Sun.COM (void) ixgbe_set_i2c_data(hw, &i2cctl, 0);
14829353SSamuel.Tu@Sun.COM (void) ixgbe_raise_i2c_clk(hw, &i2cctl);
14839353SSamuel.Tu@Sun.COM
14849353SSamuel.Tu@Sun.COM /* Setup time for stop condition (4us) */
14859353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_SU_STO);
14869353SSamuel.Tu@Sun.COM
14879353SSamuel.Tu@Sun.COM (void) ixgbe_set_i2c_data(hw, &i2cctl, 1);
14889353SSamuel.Tu@Sun.COM
14899353SSamuel.Tu@Sun.COM /* bus free time between stop and start (4.7us) */
14909353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_BUF);
14919353SSamuel.Tu@Sun.COM }
14929353SSamuel.Tu@Sun.COM
14939353SSamuel.Tu@Sun.COM /*
14949353SSamuel.Tu@Sun.COM * ixgbe_clock_in_i2c_byte - Clocks in one byte via I2C
14959353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
14969353SSamuel.Tu@Sun.COM * @data: data byte to clock in
14979353SSamuel.Tu@Sun.COM *
14989353SSamuel.Tu@Sun.COM * Clocks in one byte data via I2C data/clock
14999353SSamuel.Tu@Sun.COM */
15009353SSamuel.Tu@Sun.COM static s32
ixgbe_clock_in_i2c_byte(struct ixgbe_hw * hw,u8 * data)15019353SSamuel.Tu@Sun.COM ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data)
15029353SSamuel.Tu@Sun.COM {
15039353SSamuel.Tu@Sun.COM s32 status = IXGBE_SUCCESS;
15049353SSamuel.Tu@Sun.COM s32 i;
15059353SSamuel.Tu@Sun.COM bool bit = 0;
15069353SSamuel.Tu@Sun.COM
15079353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_clock_in_i2c_byte");
15089353SSamuel.Tu@Sun.COM
15099353SSamuel.Tu@Sun.COM for (i = 7; i >= 0; i--) {
15109353SSamuel.Tu@Sun.COM status = ixgbe_clock_in_i2c_bit(hw, &bit);
15119353SSamuel.Tu@Sun.COM *data |= bit<<i;
15129353SSamuel.Tu@Sun.COM
15139353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
15149353SSamuel.Tu@Sun.COM break;
15159353SSamuel.Tu@Sun.COM }
15169353SSamuel.Tu@Sun.COM
15179353SSamuel.Tu@Sun.COM return (status);
15189353SSamuel.Tu@Sun.COM }
15199353SSamuel.Tu@Sun.COM
15209353SSamuel.Tu@Sun.COM /*
15219353SSamuel.Tu@Sun.COM * ixgbe_clock_out_i2c_byte - Clocks out one byte via I2C
15229353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
15239353SSamuel.Tu@Sun.COM * @data: data byte clocked out
15249353SSamuel.Tu@Sun.COM *
15259353SSamuel.Tu@Sun.COM * Clocks out one byte data via I2C data/clock
15269353SSamuel.Tu@Sun.COM */
15279353SSamuel.Tu@Sun.COM static s32
ixgbe_clock_out_i2c_byte(struct ixgbe_hw * hw,u8 data)15289353SSamuel.Tu@Sun.COM ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
15299353SSamuel.Tu@Sun.COM {
15309353SSamuel.Tu@Sun.COM s32 status = IXGBE_SUCCESS;
15319353SSamuel.Tu@Sun.COM s32 i;
15329353SSamuel.Tu@Sun.COM u32 i2cctl;
15339353SSamuel.Tu@Sun.COM bool bit = 0;
15349353SSamuel.Tu@Sun.COM
15359353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_clock_out_i2c_byte");
15369353SSamuel.Tu@Sun.COM
15379353SSamuel.Tu@Sun.COM for (i = 7; i >= 0; i--) {
15389353SSamuel.Tu@Sun.COM bit = (data >> i) & 0x1;
15399353SSamuel.Tu@Sun.COM status = ixgbe_clock_out_i2c_bit(hw, bit);
15409353SSamuel.Tu@Sun.COM
15419353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
15429353SSamuel.Tu@Sun.COM break;
15439353SSamuel.Tu@Sun.COM }
15449353SSamuel.Tu@Sun.COM
15459353SSamuel.Tu@Sun.COM /* Release SDA line (set high) */
15469353SSamuel.Tu@Sun.COM i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
15479353SSamuel.Tu@Sun.COM i2cctl |= IXGBE_I2C_DATA_OUT;
15489353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, i2cctl);
15499353SSamuel.Tu@Sun.COM
15509353SSamuel.Tu@Sun.COM return (status);
15519353SSamuel.Tu@Sun.COM }
15529353SSamuel.Tu@Sun.COM
15539353SSamuel.Tu@Sun.COM /*
15549353SSamuel.Tu@Sun.COM * ixgbe_get_i2c_ack - Polls for I2C ACK
15559353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
15569353SSamuel.Tu@Sun.COM *
15579353SSamuel.Tu@Sun.COM * Clocks in/out one bit via I2C data/clock
15589353SSamuel.Tu@Sun.COM */
15599353SSamuel.Tu@Sun.COM static s32
ixgbe_get_i2c_ack(struct ixgbe_hw * hw)15609353SSamuel.Tu@Sun.COM ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
15619353SSamuel.Tu@Sun.COM {
15629353SSamuel.Tu@Sun.COM s32 status;
15639353SSamuel.Tu@Sun.COM u32 i = 0;
15649353SSamuel.Tu@Sun.COM u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
15659353SSamuel.Tu@Sun.COM u32 timeout = 10;
15669353SSamuel.Tu@Sun.COM bool ack = 1;
15679353SSamuel.Tu@Sun.COM
15689353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_get_i2c_ack");
15699353SSamuel.Tu@Sun.COM
15709353SSamuel.Tu@Sun.COM status = ixgbe_raise_i2c_clk(hw, &i2cctl);
15719353SSamuel.Tu@Sun.COM
15729353SSamuel.Tu@Sun.COM if (status != IXGBE_SUCCESS)
15739353SSamuel.Tu@Sun.COM goto out;
15749353SSamuel.Tu@Sun.COM
15759353SSamuel.Tu@Sun.COM /* Minimum high period of clock is 4us */
15769353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_HIGH);
15779353SSamuel.Tu@Sun.COM
15789353SSamuel.Tu@Sun.COM /*
15799353SSamuel.Tu@Sun.COM * Poll for ACK. Note that ACK in I2C spec is
15809353SSamuel.Tu@Sun.COM * transition from 1 to 0
15819353SSamuel.Tu@Sun.COM */
15829353SSamuel.Tu@Sun.COM for (i = 0; i < timeout; i++) {
15839353SSamuel.Tu@Sun.COM i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
15849353SSamuel.Tu@Sun.COM ack = ixgbe_get_i2c_data(&i2cctl);
15859353SSamuel.Tu@Sun.COM
15869353SSamuel.Tu@Sun.COM usec_delay(1);
15879353SSamuel.Tu@Sun.COM if (ack == 0)
15889353SSamuel.Tu@Sun.COM break;
15899353SSamuel.Tu@Sun.COM }
15909353SSamuel.Tu@Sun.COM
15919353SSamuel.Tu@Sun.COM if (ack == 1) {
15929353SSamuel.Tu@Sun.COM DEBUGOUT("I2C ack was not received.\n");
15939353SSamuel.Tu@Sun.COM status = IXGBE_ERR_I2C;
15949353SSamuel.Tu@Sun.COM }
15959353SSamuel.Tu@Sun.COM
15969353SSamuel.Tu@Sun.COM ixgbe_lower_i2c_clk(hw, &i2cctl);
15979353SSamuel.Tu@Sun.COM
15989353SSamuel.Tu@Sun.COM /* Minimum low period of clock is 4.7 us */
15999353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_LOW);
16009353SSamuel.Tu@Sun.COM
16019353SSamuel.Tu@Sun.COM out:
16029353SSamuel.Tu@Sun.COM return (status);
16039353SSamuel.Tu@Sun.COM }
16049353SSamuel.Tu@Sun.COM
16059353SSamuel.Tu@Sun.COM /*
16069353SSamuel.Tu@Sun.COM * ixgbe_clock_in_i2c_bit - Clocks in one bit via I2C data/clock
16079353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
16089353SSamuel.Tu@Sun.COM * @data: read data value
16099353SSamuel.Tu@Sun.COM *
16109353SSamuel.Tu@Sun.COM * Clocks in one bit via I2C data/clock
16119353SSamuel.Tu@Sun.COM */
16129353SSamuel.Tu@Sun.COM static s32
ixgbe_clock_in_i2c_bit(struct ixgbe_hw * hw,bool * data)16139353SSamuel.Tu@Sun.COM ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
16149353SSamuel.Tu@Sun.COM {
16159353SSamuel.Tu@Sun.COM s32 status;
16169353SSamuel.Tu@Sun.COM u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
16179353SSamuel.Tu@Sun.COM
161810998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_clock_in_i2c_bit");
161910998SChenlu.Chen@Sun.COM
16209353SSamuel.Tu@Sun.COM status = ixgbe_raise_i2c_clk(hw, &i2cctl);
16219353SSamuel.Tu@Sun.COM
16229353SSamuel.Tu@Sun.COM /* Minimum high period of clock is 4us */
16239353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_HIGH);
16249353SSamuel.Tu@Sun.COM
16259353SSamuel.Tu@Sun.COM i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
16269353SSamuel.Tu@Sun.COM *data = ixgbe_get_i2c_data(&i2cctl);
16279353SSamuel.Tu@Sun.COM
16289353SSamuel.Tu@Sun.COM ixgbe_lower_i2c_clk(hw, &i2cctl);
16299353SSamuel.Tu@Sun.COM
16309353SSamuel.Tu@Sun.COM /* Minimum low period of clock is 4.7 us */
16319353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_LOW);
16329353SSamuel.Tu@Sun.COM
16339353SSamuel.Tu@Sun.COM return (status);
16349353SSamuel.Tu@Sun.COM }
16359353SSamuel.Tu@Sun.COM
16369353SSamuel.Tu@Sun.COM /*
16379353SSamuel.Tu@Sun.COM * ixgbe_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock
16389353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
16399353SSamuel.Tu@Sun.COM * @data: data value to write
16409353SSamuel.Tu@Sun.COM *
16419353SSamuel.Tu@Sun.COM * Clocks out one bit via I2C data/clock
16429353SSamuel.Tu@Sun.COM */
16439353SSamuel.Tu@Sun.COM static s32
ixgbe_clock_out_i2c_bit(struct ixgbe_hw * hw,bool data)16449353SSamuel.Tu@Sun.COM ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
16459353SSamuel.Tu@Sun.COM {
16469353SSamuel.Tu@Sun.COM s32 status;
16479353SSamuel.Tu@Sun.COM u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
16489353SSamuel.Tu@Sun.COM
164910998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_clock_out_i2c_bit");
165010998SChenlu.Chen@Sun.COM
16519353SSamuel.Tu@Sun.COM status = ixgbe_set_i2c_data(hw, &i2cctl, data);
16529353SSamuel.Tu@Sun.COM if (status == IXGBE_SUCCESS) {
16539353SSamuel.Tu@Sun.COM status = ixgbe_raise_i2c_clk(hw, &i2cctl);
16549353SSamuel.Tu@Sun.COM
16559353SSamuel.Tu@Sun.COM /* Minimum high period of clock is 4us */
16569353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_HIGH);
16579353SSamuel.Tu@Sun.COM
16589353SSamuel.Tu@Sun.COM ixgbe_lower_i2c_clk(hw, &i2cctl);
16599353SSamuel.Tu@Sun.COM
16609353SSamuel.Tu@Sun.COM /*
16619353SSamuel.Tu@Sun.COM * Minimum low period of clock is 4.7 us.
16629353SSamuel.Tu@Sun.COM * This also takes care of the data hold time.
16639353SSamuel.Tu@Sun.COM */
16649353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_LOW);
16659353SSamuel.Tu@Sun.COM } else {
16669353SSamuel.Tu@Sun.COM status = IXGBE_ERR_I2C;
16679353SSamuel.Tu@Sun.COM DEBUGOUT1("I2C data was not set to %X\n", data);
16689353SSamuel.Tu@Sun.COM }
16699353SSamuel.Tu@Sun.COM
16709353SSamuel.Tu@Sun.COM return (status);
16719353SSamuel.Tu@Sun.COM }
16729353SSamuel.Tu@Sun.COM
16739353SSamuel.Tu@Sun.COM /*
16749353SSamuel.Tu@Sun.COM * ixgbe_raise_i2c_clk - Raises the I2C SCL clock
16759353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
16769353SSamuel.Tu@Sun.COM * @i2cctl: Current value of I2CCTL register
16779353SSamuel.Tu@Sun.COM *
16789353SSamuel.Tu@Sun.COM * Raises the I2C clock line '0'->'1'
16799353SSamuel.Tu@Sun.COM */
16809353SSamuel.Tu@Sun.COM static s32
ixgbe_raise_i2c_clk(struct ixgbe_hw * hw,u32 * i2cctl)16819353SSamuel.Tu@Sun.COM ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
16829353SSamuel.Tu@Sun.COM {
16839353SSamuel.Tu@Sun.COM s32 status = IXGBE_SUCCESS;
16849353SSamuel.Tu@Sun.COM
168510998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_raise_i2c_clk");
168610998SChenlu.Chen@Sun.COM
16879353SSamuel.Tu@Sun.COM *i2cctl |= IXGBE_I2C_CLK_OUT;
16889353SSamuel.Tu@Sun.COM
16899353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
16909353SSamuel.Tu@Sun.COM
16919353SSamuel.Tu@Sun.COM /* SCL rise time (1000ns) */
16929353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_RISE);
16939353SSamuel.Tu@Sun.COM
16949353SSamuel.Tu@Sun.COM return (status);
16959353SSamuel.Tu@Sun.COM }
16969353SSamuel.Tu@Sun.COM
16979353SSamuel.Tu@Sun.COM /*
16989353SSamuel.Tu@Sun.COM * ixgbe_lower_i2c_clk - Lowers the I2C SCL clock
16999353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
17009353SSamuel.Tu@Sun.COM * @i2cctl: Current value of I2CCTL register
17019353SSamuel.Tu@Sun.COM *
17029353SSamuel.Tu@Sun.COM * Lowers the I2C clock line '1'->'0'
17039353SSamuel.Tu@Sun.COM */
17049353SSamuel.Tu@Sun.COM static void
ixgbe_lower_i2c_clk(struct ixgbe_hw * hw,u32 * i2cctl)17059353SSamuel.Tu@Sun.COM ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
17069353SSamuel.Tu@Sun.COM {
170710998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_lower_i2c_clk");
170810998SChenlu.Chen@Sun.COM
17099353SSamuel.Tu@Sun.COM *i2cctl &= ~IXGBE_I2C_CLK_OUT;
17109353SSamuel.Tu@Sun.COM
17119353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
17129353SSamuel.Tu@Sun.COM
17139353SSamuel.Tu@Sun.COM /* SCL fall time (300ns) */
17149353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_FALL);
17159353SSamuel.Tu@Sun.COM }
17169353SSamuel.Tu@Sun.COM
17179353SSamuel.Tu@Sun.COM /*
17189353SSamuel.Tu@Sun.COM * ixgbe_set_i2c_data - Sets the I2C data bit
17199353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
17209353SSamuel.Tu@Sun.COM * @i2cctl: Current value of I2CCTL register
17219353SSamuel.Tu@Sun.COM * @data: I2C data value (0 or 1) to set
17229353SSamuel.Tu@Sun.COM *
17239353SSamuel.Tu@Sun.COM * Sets the I2C data bit
17249353SSamuel.Tu@Sun.COM */
17259353SSamuel.Tu@Sun.COM static s32
ixgbe_set_i2c_data(struct ixgbe_hw * hw,u32 * i2cctl,bool data)17269353SSamuel.Tu@Sun.COM ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
17279353SSamuel.Tu@Sun.COM {
17289353SSamuel.Tu@Sun.COM s32 status = IXGBE_SUCCESS;
17299353SSamuel.Tu@Sun.COM
173010998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_set_i2c_data");
173110998SChenlu.Chen@Sun.COM
17329353SSamuel.Tu@Sun.COM if (data)
17339353SSamuel.Tu@Sun.COM *i2cctl |= IXGBE_I2C_DATA_OUT;
17349353SSamuel.Tu@Sun.COM else
17359353SSamuel.Tu@Sun.COM *i2cctl &= ~IXGBE_I2C_DATA_OUT;
17369353SSamuel.Tu@Sun.COM
17379353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
17389353SSamuel.Tu@Sun.COM
17399353SSamuel.Tu@Sun.COM /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
17409353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
17419353SSamuel.Tu@Sun.COM
17429353SSamuel.Tu@Sun.COM /* Verify data was set correctly */
17439353SSamuel.Tu@Sun.COM *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
17449353SSamuel.Tu@Sun.COM if (data != ixgbe_get_i2c_data(i2cctl)) {
17459353SSamuel.Tu@Sun.COM status = IXGBE_ERR_I2C;
17469353SSamuel.Tu@Sun.COM DEBUGOUT1("Error - I2C data was not set to %X.\n", data);
17479353SSamuel.Tu@Sun.COM }
17489353SSamuel.Tu@Sun.COM
17499353SSamuel.Tu@Sun.COM return (status);
17509353SSamuel.Tu@Sun.COM }
17519353SSamuel.Tu@Sun.COM
17529353SSamuel.Tu@Sun.COM /*
17539353SSamuel.Tu@Sun.COM * ixgbe_get_i2c_data - Reads the I2C SDA data bit
17549353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
17559353SSamuel.Tu@Sun.COM * @i2cctl: Current value of I2CCTL register
17569353SSamuel.Tu@Sun.COM *
17579353SSamuel.Tu@Sun.COM * Returns the I2C data bit value
17589353SSamuel.Tu@Sun.COM */
17599353SSamuel.Tu@Sun.COM static bool
ixgbe_get_i2c_data(u32 * i2cctl)17609353SSamuel.Tu@Sun.COM ixgbe_get_i2c_data(u32 *i2cctl)
17619353SSamuel.Tu@Sun.COM {
17629353SSamuel.Tu@Sun.COM bool data;
17639353SSamuel.Tu@Sun.COM
176410998SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_get_i2c_data");
176510998SChenlu.Chen@Sun.COM
17669353SSamuel.Tu@Sun.COM if (*i2cctl & IXGBE_I2C_DATA_IN)
17679353SSamuel.Tu@Sun.COM data = 1;
17689353SSamuel.Tu@Sun.COM else
17699353SSamuel.Tu@Sun.COM data = 0;
17709353SSamuel.Tu@Sun.COM
17719353SSamuel.Tu@Sun.COM return (data);
17729353SSamuel.Tu@Sun.COM }
17739353SSamuel.Tu@Sun.COM
17749353SSamuel.Tu@Sun.COM /*
17759353SSamuel.Tu@Sun.COM * ixgbe_i2c_bus_clear - Clears the I2C bus
17769353SSamuel.Tu@Sun.COM * @hw: pointer to hardware structure
17779353SSamuel.Tu@Sun.COM *
17789353SSamuel.Tu@Sun.COM * Clears the I2C bus by sending nine clock pulses.
17799353SSamuel.Tu@Sun.COM * Used when data line is stuck low.
17809353SSamuel.Tu@Sun.COM */
17819353SSamuel.Tu@Sun.COM void
ixgbe_i2c_bus_clear(struct ixgbe_hw * hw)17829353SSamuel.Tu@Sun.COM ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
17839353SSamuel.Tu@Sun.COM {
17849353SSamuel.Tu@Sun.COM u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
17859353SSamuel.Tu@Sun.COM u32 i;
17869353SSamuel.Tu@Sun.COM
17879353SSamuel.Tu@Sun.COM DEBUGFUNC("ixgbe_i2c_bus_clear");
17889353SSamuel.Tu@Sun.COM
17899353SSamuel.Tu@Sun.COM ixgbe_i2c_start(hw);
17909353SSamuel.Tu@Sun.COM
17919353SSamuel.Tu@Sun.COM (void) ixgbe_set_i2c_data(hw, &i2cctl, 1);
17929353SSamuel.Tu@Sun.COM
17939353SSamuel.Tu@Sun.COM for (i = 0; i < 9; i++) {
17949353SSamuel.Tu@Sun.COM (void) ixgbe_raise_i2c_clk(hw, &i2cctl);
17959353SSamuel.Tu@Sun.COM
17969353SSamuel.Tu@Sun.COM /* Min high period of clock is 4us */
17979353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_HIGH);
17989353SSamuel.Tu@Sun.COM
17999353SSamuel.Tu@Sun.COM ixgbe_lower_i2c_clk(hw, &i2cctl);
18009353SSamuel.Tu@Sun.COM
18019353SSamuel.Tu@Sun.COM /* Min low period of clock is 4.7us */
18029353SSamuel.Tu@Sun.COM usec_delay(IXGBE_I2C_T_LOW);
18039353SSamuel.Tu@Sun.COM }
18049353SSamuel.Tu@Sun.COM
18059353SSamuel.Tu@Sun.COM ixgbe_i2c_start(hw);
18069353SSamuel.Tu@Sun.COM
18079353SSamuel.Tu@Sun.COM /* Put the i2c bus back to default state */
18089353SSamuel.Tu@Sun.COM ixgbe_i2c_stop(hw);
18099353SSamuel.Tu@Sun.COM }
1810*13006SChenlu.Chen@Sun.COM
1811*13006SChenlu.Chen@Sun.COM /*
1812*13006SChenlu.Chen@Sun.COM * ixgbe_tn_check_overtemp - Checks if an overtemp occured.
1813*13006SChenlu.Chen@Sun.COM * @hw: pointer to hardware structure
1814*13006SChenlu.Chen@Sun.COM *
1815*13006SChenlu.Chen@Sun.COM * Checks if the LASI temp alarm status was triggered due to overtemp
1816*13006SChenlu.Chen@Sun.COM */
1817*13006SChenlu.Chen@Sun.COM s32
ixgbe_tn_check_overtemp(struct ixgbe_hw * hw)1818*13006SChenlu.Chen@Sun.COM ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
1819*13006SChenlu.Chen@Sun.COM {
1820*13006SChenlu.Chen@Sun.COM s32 status = IXGBE_SUCCESS;
1821*13006SChenlu.Chen@Sun.COM u16 phy_data = 0;
1822*13006SChenlu.Chen@Sun.COM
1823*13006SChenlu.Chen@Sun.COM DEBUGFUNC("ixgbe_tn_check_overtemp");
1824*13006SChenlu.Chen@Sun.COM
1825*13006SChenlu.Chen@Sun.COM if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
1826*13006SChenlu.Chen@Sun.COM goto out;
1827*13006SChenlu.Chen@Sun.COM
1828*13006SChenlu.Chen@Sun.COM /* Check that the LASI temp alarm status was triggered */
1829*13006SChenlu.Chen@Sun.COM hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
1830*13006SChenlu.Chen@Sun.COM IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_data);
1831*13006SChenlu.Chen@Sun.COM
1832*13006SChenlu.Chen@Sun.COM if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM))
1833*13006SChenlu.Chen@Sun.COM goto out;
1834*13006SChenlu.Chen@Sun.COM
1835*13006SChenlu.Chen@Sun.COM status = IXGBE_ERR_OVERTEMP;
1836*13006SChenlu.Chen@Sun.COM out:
1837*13006SChenlu.Chen@Sun.COM return (status);
1838*13006SChenlu.Chen@Sun.COM }
1839