1 1.1 jklos /************************************************************************** 2 1.1 jklos 3 1.1 jklos Copyright (c) 2007, Chelsio Inc. 4 1.1 jklos All rights reserved. 5 1.1 jklos 6 1.1 jklos Redistribution and use in source and binary forms, with or without 7 1.1 jklos modification, are permitted provided that the following conditions are met: 8 1.1 jklos 9 1.1 jklos 1. Redistributions of source code must retain the above copyright notice, 10 1.1 jklos this list of conditions and the following disclaimer. 11 1.1 jklos 12 1.1 jklos 2. Neither the name of the Chelsio Corporation nor the names of its 13 1.1 jklos contributors may be used to endorse or promote products derived from 14 1.1 jklos this software without specific prior written permission. 15 1.1 jklos 16 1.1 jklos THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 1.1 jklos AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 jklos IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 jklos ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 1.1 jklos LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 jklos CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 jklos SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 jklos INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 jklos CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 jklos ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 jklos POSSIBILITY OF SUCH DAMAGE. 27 1.1 jklos 28 1.1 jklos ***************************************************************************/ 29 1.1 jklos 30 1.1 jklos #include <sys/cdefs.h> 31 1.1 jklos __KERNEL_RCSID(0, "$NetBSD: cxgb_ael1002.c,v 1.1 2010/03/21 21:11:13 jklos Exp $"); 32 1.1 jklos 33 1.1 jklos #ifdef CONFIG_DEFINED 34 1.1 jklos #include <cxgb_include.h> 35 1.1 jklos #else 36 1.1 jklos #include <dev/pci/cxgb/cxgb_include.h> 37 1.1 jklos #endif 38 1.1 jklos 39 1.1 jklos enum { 40 1.1 jklos AEL100X_TX_DISABLE = 9, 41 1.1 jklos AEL100X_TX_CONFIG1 = 0xc002, 42 1.1 jklos AEL1002_PWR_DOWN_HI = 0xc011, 43 1.1 jklos AEL1002_PWR_DOWN_LO = 0xc012, 44 1.1 jklos AEL1002_XFI_EQL = 0xc015, 45 1.1 jklos AEL1002_LB_EN = 0xc017, 46 1.1 jklos 47 1.1 jklos LASI_CTRL = 0x9002, 48 1.1 jklos LASI_STAT = 0x9005 49 1.1 jklos }; 50 1.1 jklos 51 1.1 jklos static void ael100x_txon(struct cphy *phy) 52 1.1 jklos { 53 1.1 jklos int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; 54 1.1 jklos 55 1.1 jklos t3_os_sleep(100); 56 1.1 jklos t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio); 57 1.1 jklos t3_os_sleep(30); 58 1.1 jklos } 59 1.1 jklos 60 1.1 jklos static int ael1002_power_down(struct cphy *phy, int enable) 61 1.1 jklos { 62 1.1 jklos int err; 63 1.1 jklos 64 1.1 jklos err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable); 65 1.1 jklos if (!err) 66 1.1 jklos err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 67 1.1 jklos BMCR_PDOWN, enable ? BMCR_PDOWN : 0); 68 1.1 jklos return err; 69 1.1 jklos } 70 1.1 jklos 71 1.1 jklos static int ael1002_reset(struct cphy *phy, int wait) 72 1.1 jklos { 73 1.1 jklos int err; 74 1.1 jklos 75 1.1 jklos if ((err = ael1002_power_down(phy, 0)) || 76 1.1 jklos (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) || 77 1.1 jklos (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) || 78 1.1 jklos (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) || 79 1.1 jklos (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) || 80 1.1 jklos (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN, 81 1.1 jklos 0, 1 << 5))) 82 1.1 jklos return err; 83 1.1 jklos return 0; 84 1.1 jklos } 85 1.1 jklos 86 1.1 jklos static int ael1002_intr_noop(struct cphy *phy) 87 1.1 jklos { 88 1.1 jklos return 0; 89 1.1 jklos } 90 1.1 jklos 91 1.1 jklos static int ael100x_get_link_status(struct cphy *phy, int *link_ok, 92 1.1 jklos int *speed, int *duplex, int *fc) 93 1.1 jklos { 94 1.1 jklos if (link_ok) { 95 1.1 jklos unsigned int status; 96 1.1 jklos int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status); 97 1.1 jklos 98 1.1 jklos /* 99 1.1 jklos * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it 100 1.1 jklos * once more to get the current link state. 101 1.1 jklos */ 102 1.1 jklos if (!err && !(status & BMSR_LSTATUS)) 103 1.1 jklos err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, 104 1.1 jklos &status); 105 1.1 jklos if (err) 106 1.1 jklos return err; 107 1.1 jklos *link_ok = !!(status & BMSR_LSTATUS); 108 1.1 jklos } 109 1.1 jklos if (speed) 110 1.1 jklos *speed = SPEED_10000; 111 1.1 jklos if (duplex) 112 1.1 jklos *duplex = DUPLEX_FULL; 113 1.1 jklos return 0; 114 1.1 jklos } 115 1.1 jklos 116 1.1 jklos #ifdef C99_NOT_SUPPORTED 117 1.1 jklos static struct cphy_ops ael1002_ops = { 118 1.1 jklos NULL, 119 1.1 jklos ael1002_reset, 120 1.1 jklos ael1002_intr_noop, 121 1.1 jklos ael1002_intr_noop, 122 1.1 jklos ael1002_intr_noop, 123 1.1 jklos ael1002_intr_noop, 124 1.1 jklos NULL, 125 1.1 jklos NULL, 126 1.1 jklos NULL, 127 1.1 jklos NULL, 128 1.1 jklos NULL, 129 1.1 jklos ael100x_get_link_status, 130 1.1 jklos ael1002_power_down, 131 1.1 jklos }; 132 1.1 jklos #else 133 1.1 jklos static struct cphy_ops ael1002_ops = { 134 1.1 jklos .reset = ael1002_reset, 135 1.1 jklos .intr_enable = ael1002_intr_noop, 136 1.1 jklos .intr_disable = ael1002_intr_noop, 137 1.1 jklos .intr_clear = ael1002_intr_noop, 138 1.1 jklos .intr_handler = ael1002_intr_noop, 139 1.1 jklos .get_link_status = ael100x_get_link_status, 140 1.1 jklos .power_down = ael1002_power_down, 141 1.1 jklos }; 142 1.1 jklos #endif 143 1.1 jklos 144 1.1 jklos void t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 145 1.1 jklos const struct mdio_ops *mdio_ops) 146 1.1 jklos { 147 1.1 jklos cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops); 148 1.1 jklos ael100x_txon(phy); 149 1.1 jklos } 150 1.1 jklos 151 1.1 jklos static int ael1006_reset(struct cphy *phy, int wait) 152 1.1 jklos { 153 1.1 jklos return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); 154 1.1 jklos } 155 1.1 jklos 156 1.1 jklos static int ael1006_intr_enable(struct cphy *phy) 157 1.1 jklos { 158 1.1 jklos return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); 159 1.1 jklos } 160 1.1 jklos 161 1.1 jklos static int ael1006_intr_disable(struct cphy *phy) 162 1.1 jklos { 163 1.1 jklos return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); 164 1.1 jklos } 165 1.1 jklos 166 1.1 jklos static int ael1006_intr_clear(struct cphy *phy) 167 1.1 jklos { 168 1.1 jklos u32 val; 169 1.1 jklos 170 1.1 jklos return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); 171 1.1 jklos } 172 1.1 jklos 173 1.1 jklos static int ael1006_intr_handler(struct cphy *phy) 174 1.1 jklos { 175 1.1 jklos unsigned int status; 176 1.1 jklos int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); 177 1.1 jklos 178 1.1 jklos if (err) 179 1.1 jklos return err; 180 1.1 jklos return (status & 1) ? cphy_cause_link_change : 0; 181 1.1 jklos } 182 1.1 jklos 183 1.1 jklos static int ael1006_power_down(struct cphy *phy, int enable) 184 1.1 jklos { 185 1.1 jklos return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 186 1.1 jklos BMCR_PDOWN, enable ? BMCR_PDOWN : 0); 187 1.1 jklos } 188 1.1 jklos 189 1.1 jklos #ifdef C99_NOT_SUPPORTED 190 1.1 jklos static struct cphy_ops ael1006_ops = { 191 1.1 jklos NULL, 192 1.1 jklos ael1006_reset, 193 1.1 jklos ael1006_intr_enable, 194 1.1 jklos ael1006_intr_disable, 195 1.1 jklos ael1006_intr_clear, 196 1.1 jklos ael1006_intr_handler, 197 1.1 jklos NULL, 198 1.1 jklos NULL, 199 1.1 jklos NULL, 200 1.1 jklos NULL, 201 1.1 jklos NULL, 202 1.1 jklos ael100x_get_link_status, 203 1.1 jklos ael1006_power_down, 204 1.1 jklos }; 205 1.1 jklos #else 206 1.1 jklos static struct cphy_ops ael1006_ops = { 207 1.1 jklos .reset = ael1006_reset, 208 1.1 jklos .intr_enable = ael1006_intr_enable, 209 1.1 jklos .intr_disable = ael1006_intr_disable, 210 1.1 jklos .intr_clear = ael1006_intr_clear, 211 1.1 jklos .intr_handler = ael1006_intr_handler, 212 1.1 jklos .get_link_status = ael100x_get_link_status, 213 1.1 jklos .power_down = ael1006_power_down, 214 1.1 jklos }; 215 1.1 jklos #endif 216 1.1 jklos 217 1.1 jklos void t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 218 1.1 jklos const struct mdio_ops *mdio_ops) 219 1.1 jklos { 220 1.1 jklos cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops); 221 1.1 jklos ael100x_txon(phy); 222 1.1 jklos } 223 1.1 jklos 224 1.1 jklos #ifdef C99_NOT_SUPPORTED 225 1.1 jklos static struct cphy_ops qt2045_ops = { 226 1.1 jklos NULL, 227 1.1 jklos ael1006_reset, 228 1.1 jklos ael1006_intr_enable, 229 1.1 jklos ael1006_intr_disable, 230 1.1 jklos ael1006_intr_clear, 231 1.1 jklos ael1006_intr_handler, 232 1.1 jklos NULL, 233 1.1 jklos NULL, 234 1.1 jklos NULL, 235 1.1 jklos NULL, 236 1.1 jklos NULL, 237 1.1 jklos ael100x_get_link_status, 238 1.1 jklos ael1006_power_down, 239 1.1 jklos }; 240 1.1 jklos #else 241 1.1 jklos static struct cphy_ops qt2045_ops = { 242 1.1 jklos .reset = ael1006_reset, 243 1.1 jklos .intr_enable = ael1006_intr_enable, 244 1.1 jklos .intr_disable = ael1006_intr_disable, 245 1.1 jklos .intr_clear = ael1006_intr_clear, 246 1.1 jklos .intr_handler = ael1006_intr_handler, 247 1.1 jklos .get_link_status = ael100x_get_link_status, 248 1.1 jklos .power_down = ael1006_power_down, 249 1.1 jklos }; 250 1.1 jklos #endif 251 1.1 jklos 252 1.1 jklos void t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 253 1.1 jklos const struct mdio_ops *mdio_ops) 254 1.1 jklos { 255 1.1 jklos unsigned int stat; 256 1.1 jklos 257 1.1 jklos cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops); 258 1.1 jklos 259 1.1 jklos /* 260 1.1 jklos * Some cards where the PHY is supposed to be at address 0 actually 261 1.1 jklos * have it at 1. 262 1.1 jklos */ 263 1.1 jklos if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) && 264 1.1 jklos stat == 0xffff) 265 1.1 jklos phy->addr = 1; 266 1.1 jklos } 267 1.1 jklos 268 1.1 jklos static int xaui_direct_reset(struct cphy *phy, int wait) 269 1.1 jklos { 270 1.1 jklos return 0; 271 1.1 jklos } 272 1.1 jklos 273 1.1 jklos static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, 274 1.1 jklos int *speed, int *duplex, int *fc) 275 1.1 jklos { 276 1.1 jklos if (link_ok) { 277 1.1 jklos unsigned int status; 278 1.1 jklos 279 1.1 jklos status = t3_read_reg(phy->adapter, 280 1.1 jklos XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) | 281 1.1 jklos t3_read_reg(phy->adapter, 282 1.1 jklos XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) | 283 1.1 jklos t3_read_reg(phy->adapter, 284 1.1 jklos XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) | 285 1.1 jklos t3_read_reg(phy->adapter, 286 1.1 jklos XGM_REG(A_XGM_SERDES_STAT3, phy->addr)); 287 1.1 jklos *link_ok = !(status & F_LOWSIG0); 288 1.1 jklos } 289 1.1 jklos if (speed) 290 1.1 jklos *speed = SPEED_10000; 291 1.1 jklos if (duplex) 292 1.1 jklos *duplex = DUPLEX_FULL; 293 1.1 jklos return 0; 294 1.1 jklos } 295 1.1 jklos 296 1.1 jklos static int xaui_direct_power_down(struct cphy *phy, int enable) 297 1.1 jklos { 298 1.1 jklos return 0; 299 1.1 jklos } 300 1.1 jklos 301 1.1 jklos #ifdef C99_NOT_SUPPORTED 302 1.1 jklos static struct cphy_ops xaui_direct_ops = { 303 1.1 jklos NULL, 304 1.1 jklos xaui_direct_reset, 305 1.1 jklos ael1002_intr_noop, 306 1.1 jklos ael1002_intr_noop, 307 1.1 jklos ael1002_intr_noop, 308 1.1 jklos ael1002_intr_noop, 309 1.1 jklos NULL, 310 1.1 jklos NULL, 311 1.1 jklos NULL, 312 1.1 jklos NULL, 313 1.1 jklos NULL, 314 1.1 jklos xaui_direct_get_link_status, 315 1.1 jklos xaui_direct_power_down, 316 1.1 jklos }; 317 1.1 jklos #else 318 1.1 jklos static struct cphy_ops xaui_direct_ops = { 319 1.1 jklos .reset = xaui_direct_reset, 320 1.1 jklos .intr_enable = ael1002_intr_noop, 321 1.1 jklos .intr_disable = ael1002_intr_noop, 322 1.1 jklos .intr_clear = ael1002_intr_noop, 323 1.1 jklos .intr_handler = ael1002_intr_noop, 324 1.1 jklos .get_link_status = xaui_direct_get_link_status, 325 1.1 jklos .power_down = xaui_direct_power_down, 326 1.1 jklos }; 327 1.1 jklos #endif 328 1.1 jklos 329 1.1 jklos void t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 330 1.1 jklos const struct mdio_ops *mdio_ops) 331 1.1 jklos { 332 1.1 jklos cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops); 333 1.1 jklos } 334