1 /**************************************************************************
3 Copyright (c) 2007-2008, Chelsio Inc.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
12 2. Neither the name of the Chelsio Corporation nor the names of its
13 contributors may be used to endorse or promote products derived from
14 this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 POSSIBILITY OF SUCH DAMAGE.
28 ***************************************************************************/
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
34 #include <cxgb_include.h>
36 #include <dev/cxgb/cxgb_include.h>
40 #define msleep t3_os_sleep
43 PMD_RSD = 10, /* PMA/PMD receive signal detect register */
44 PCS_STAT1_X = 24, /* 10GBASE-X PCS status 1 register */
45 PCS_STAT1_R = 32, /* 10GBASE-R PCS status 1 register */
46 XS_LN_STAT = 24 /* XS lane status register */
50 AEL100X_TX_DISABLE = 9,
51 AEL100X_TX_CONFIG1 = 0xc002,
52 AEL1002_PWR_DOWN_HI = 0xc011,
53 AEL1002_PWR_DOWN_LO = 0xc012,
54 AEL1002_XFI_EQL = 0xc015,
55 AEL1002_LB_EN = 0xc017,
56 AEL_OPT_SETTINGS = 0xc017,
57 AEL_I2C_CTRL = 0xc30a,
58 AEL_I2C_DATA = 0xc30b,
59 AEL_I2C_STAT = 0xc30c,
60 AEL2005_GPIO_CTRL = 0xc214,
61 AEL2005_GPIO_STAT = 0xc215,
64 enum { edc_none, edc_sr, edc_twinax };
66 /* PHY module I2C device address */
67 #define MODULE_DEV_ADDR 0xa0
69 #define AEL2005_MODDET_IRQ 4
72 unsigned short mmd_addr;
73 unsigned short reg_addr;
74 unsigned short clear_bits;
75 unsigned short set_bits;
78 static int set_phy_regs(struct cphy *phy, const struct reg_val *rv)
82 for (err = 0; rv->mmd_addr && !err; rv++) {
83 if (rv->clear_bits == 0xffff)
84 err = mdio_write(phy, rv->mmd_addr, rv->reg_addr,
87 err = t3_mdio_change_bits(phy, rv->mmd_addr,
88 rv->reg_addr, rv->clear_bits,
94 static void ael100x_txon(struct cphy *phy)
96 int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
99 t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
103 static int ael1002_power_down(struct cphy *phy, int enable)
107 err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
109 err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
110 BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
114 static int ael1002_reset(struct cphy *phy, int wait)
118 if ((err = ael1002_power_down(phy, 0)) ||
119 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
120 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
121 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
122 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
123 (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
129 static int ael1002_intr_noop(struct cphy *phy)
135 * Get link status for a 10GBASE-R device.
137 static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed,
138 int *duplex, int *fc)
141 unsigned int stat0, stat1, stat2;
142 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0);
145 err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_R, &stat1);
147 err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2);
150 *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1;
153 *speed = SPEED_10000;
155 *duplex = DUPLEX_FULL;
159 #ifdef C99_NOT_SUPPORTED
160 static struct cphy_ops ael1002_ops = {
175 static struct cphy_ops ael1002_ops = {
176 .reset = ael1002_reset,
177 .intr_enable = ael1002_intr_noop,
178 .intr_disable = ael1002_intr_noop,
179 .intr_clear = ael1002_intr_noop,
180 .intr_handler = ael1002_intr_noop,
181 .get_link_status = get_link_status_r,
182 .power_down = ael1002_power_down,
186 int t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
187 const struct mdio_ops *mdio_ops)
189 cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops,
190 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
196 static int ael1006_reset(struct cphy *phy, int wait)
199 t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
200 /* Hack to reset the phy correctly */
201 /* Read out the current value */
202 gpio_out = t3_read_reg(phy->adapter, A_T3DBG_GPIO_EN);
204 gpio_out &= ~F_GPIO6_OUT_VAL;
205 t3_write_reg(phy->adapter, A_T3DBG_GPIO_EN, gpio_out);
207 /* Take the phy out of reset */
208 gpio_out |= F_GPIO6_OUT_VAL;
209 t3_write_reg(phy->adapter, A_T3DBG_GPIO_EN, gpio_out);
211 t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
213 /* Phy loopback work around for ael1006 */
214 /* Soft reset phy by toggling loopback */
216 /* Put phy into local loopback */
217 t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 0, 1);
219 /* Take phy out of local loopback */
220 t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 1, 0);
225 static int ael1006_power_down(struct cphy *phy, int enable)
227 return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
228 BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
231 #ifdef C99_NOT_SUPPORTED
232 static struct cphy_ops ael1006_ops = {
234 t3_phy_lasi_intr_enable,
235 t3_phy_lasi_intr_disable,
236 t3_phy_lasi_intr_clear,
237 t3_phy_lasi_intr_handler,
247 static struct cphy_ops ael1006_ops = {
248 .reset = ael1006_reset,
249 .intr_enable = t3_phy_lasi_intr_enable,
250 .intr_disable = t3_phy_lasi_intr_disable,
251 .intr_clear = t3_phy_lasi_intr_clear,
252 .intr_handler = t3_phy_lasi_intr_handler,
253 .get_link_status = get_link_status_r,
254 .power_down = ael1006_power_down,
258 int t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
259 const struct mdio_ops *mdio_ops)
261 cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops,
262 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
268 static int ael2005_setup_sr_edc(struct cphy *phy)
270 static struct reg_val regs[] = {
271 { MDIO_DEV_PMA_PMD, 0xc003, 0xffff, 0x181 },
272 { MDIO_DEV_PMA_PMD, 0xc010, 0xffff, 0x448a },
273 { MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5200 },
276 static u16 sr_edc[] = {
551 err = set_phy_regs(phy, regs);
557 for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2)
558 err = mdio_write(phy, MDIO_DEV_PMA_PMD, sr_edc[i],
565 static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
567 static struct reg_val regs[] = {
568 { MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5a00 },
571 static struct reg_val preemphasis[] = {
572 { MDIO_DEV_PMA_PMD, 0xc014, 0xffff, 0xfe16 },
573 { MDIO_DEV_PMA_PMD, 0xc015, 0xffff, 0xa000 },
576 static u16 twinax_edc[] = {
946 err = set_phy_regs(phy, regs);
947 if (!err && modtype == phy_modtype_twinax_long)
948 err = set_phy_regs(phy, preemphasis);
954 for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
955 err = mdio_write(phy, MDIO_DEV_PMA_PMD, twinax_edc[i],
958 phy->priv = edc_twinax;
962 static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
965 unsigned int stat, data;
967 err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL_I2C_CTRL,
968 (dev_addr << 8) | (1 << 8) | word_addr);
972 for (i = 0; i < 5; i++) {
974 err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_STAT, &stat);
977 if ((stat & 3) == 1) {
978 err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_DATA,
985 CH_WARN(phy->adapter, "PHY %u I2C read of addr %u timed out\n",
986 phy->addr, word_addr);
990 static int get_module_type(struct cphy *phy, int delay_ms)
995 v = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, &stat);
999 if (stat & (1 << 8)) /* module absent */
1000 return phy_modtype_none;
1005 /* see SFF-8472 for below */
1006 v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3);
1011 return phy_modtype_sr;
1013 return phy_modtype_lr;
1015 return phy_modtype_lrm;
1017 v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6);
1023 v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10);
1028 v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
1031 return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax;
1034 return phy_modtype_unknown;
1037 static int ael2005_intr_enable(struct cphy *phy)
1039 int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x200);
1040 return err ? err : t3_phy_lasi_intr_enable(phy);
1043 static int ael2005_intr_disable(struct cphy *phy)
1045 int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x100);
1046 return err ? err : t3_phy_lasi_intr_disable(phy);
1049 static int ael2005_intr_clear(struct cphy *phy)
1051 int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0xd00);
1052 return err ? err : t3_phy_lasi_intr_clear(phy);
1055 static int ael2005_reset(struct cphy *phy, int wait)
1057 static struct reg_val regs0[] = {
1058 { MDIO_DEV_PMA_PMD, 0xc001, 0, 1 << 5 },
1059 { MDIO_DEV_PMA_PMD, 0xc017, 0, 1 << 5 },
1060 { MDIO_DEV_PMA_PMD, 0xc013, 0xffff, 0xf341 },
1061 { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 },
1062 { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8100 },
1063 { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 },
1064 { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0 },
1067 static struct reg_val regs1[] = {
1068 { MDIO_DEV_PMA_PMD, 0xca00, 0xffff, 0x0080 },
1069 { MDIO_DEV_PMA_PMD, 0xca12, 0xffff, 0 },
1075 err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, &lasi_ctrl);
1079 err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, 0);
1084 phy->priv = edc_none;
1085 err = set_phy_regs(phy, regs0);
1091 err = get_module_type(phy, 0);
1094 phy->modtype = (u8)err;
1096 if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
1097 err = ael2005_setup_twinax_edc(phy, err);
1099 err = ael2005_setup_sr_edc(phy);
1103 err = set_phy_regs(phy, regs1);
1107 /* reset wipes out interrupts, reenable them if they were on */
1109 err = ael2005_intr_enable(phy);
1113 static int ael2005_intr_handler(struct cphy *phy)
1116 int ret, edc_needed, cause = 0;
1118 ret = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_STAT, &stat);
1122 if (stat & AEL2005_MODDET_IRQ) {
1123 ret = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL,
1128 /* modules have max 300 ms init time after hot plug */
1129 ret = get_module_type(phy, 300);
1133 phy->modtype = (u8)ret;
1134 if (ret == phy_modtype_none)
1135 edc_needed = phy->priv; /* on unplug retain EDC */
1136 else if (ret == phy_modtype_twinax ||
1137 ret == phy_modtype_twinax_long)
1138 edc_needed = edc_twinax;
1140 edc_needed = edc_sr;
1142 if (edc_needed != phy->priv) {
1143 ret = ael2005_reset(phy, 0);
1144 return ret ? ret : cphy_cause_module_change;
1146 cause = cphy_cause_module_change;
1149 ret = t3_phy_lasi_intr_handler(phy);
1150 return ret < 0 ? ret : ret + cause;
1153 #ifdef C99_NOT_SUPPORTED
1154 static struct cphy_ops ael2005_ops = {
1156 ael2005_intr_enable,
1157 ael2005_intr_disable,
1159 ael2005_intr_handler,
1169 static struct cphy_ops ael2005_ops = {
1170 .reset = ael2005_reset,
1171 .intr_enable = ael2005_intr_enable,
1172 .intr_disable = ael2005_intr_disable,
1173 .intr_clear = ael2005_intr_clear,
1174 .intr_handler = ael2005_intr_handler,
1175 .get_link_status = get_link_status_r,
1176 .power_down = ael1002_power_down,
1180 int t3_ael2005_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
1181 const struct mdio_ops *mdio_ops)
1183 cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops,
1184 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
1185 SUPPORTED_IRQ, "10GBASE-R");
1187 return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL_OPT_SETTINGS, 0,
1192 * Get link status for a 10GBASE-X device.
1194 static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed,
1195 int *duplex, int *fc)
1198 unsigned int stat0, stat1, stat2;
1199 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0);
1202 err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_X, &stat1);
1204 err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2);
1207 *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1;
1210 *speed = SPEED_10000;
1212 *duplex = DUPLEX_FULL;
1216 #ifdef C99_NOT_SUPPORTED
1217 static struct cphy_ops qt2045_ops = {
1219 t3_phy_lasi_intr_enable,
1220 t3_phy_lasi_intr_disable,
1221 t3_phy_lasi_intr_clear,
1222 t3_phy_lasi_intr_handler,
1232 static struct cphy_ops qt2045_ops = {
1233 .reset = ael1006_reset,
1234 .intr_enable = t3_phy_lasi_intr_enable,
1235 .intr_disable = t3_phy_lasi_intr_disable,
1236 .intr_clear = t3_phy_lasi_intr_clear,
1237 .intr_handler = t3_phy_lasi_intr_handler,
1238 .get_link_status = get_link_status_x,
1239 .power_down = ael1006_power_down,
1243 int t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
1244 const struct mdio_ops *mdio_ops)
1248 cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops,
1249 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
1253 * Some cards where the PHY is supposed to be at address 0 actually
1256 if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
1262 static int xaui_direct_reset(struct cphy *phy, int wait)
1267 static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
1268 int *speed, int *duplex, int *fc)
1271 unsigned int status;
1273 status = t3_read_reg(phy->adapter,
1274 XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) |
1275 t3_read_reg(phy->adapter,
1276 XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) |
1277 t3_read_reg(phy->adapter,
1278 XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) |
1279 t3_read_reg(phy->adapter,
1280 XGM_REG(A_XGM_SERDES_STAT3, phy->addr));
1281 *link_ok = !(status & F_LOWSIG0);
1284 *speed = SPEED_10000;
1286 *duplex = DUPLEX_FULL;
1290 static int xaui_direct_power_down(struct cphy *phy, int enable)
1295 #ifdef C99_NOT_SUPPORTED
1296 static struct cphy_ops xaui_direct_ops = {
1307 xaui_direct_get_link_status,
1308 xaui_direct_power_down,
1311 static struct cphy_ops xaui_direct_ops = {
1312 .reset = xaui_direct_reset,
1313 .intr_enable = ael1002_intr_noop,
1314 .intr_disable = ael1002_intr_noop,
1315 .intr_clear = ael1002_intr_noop,
1316 .intr_handler = ael1002_intr_noop,
1317 .get_link_status = xaui_direct_get_link_status,
1318 .power_down = xaui_direct_power_down,
1322 int t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
1323 const struct mdio_ops *mdio_ops)
1325 cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops,
1326 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,