1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2018 Microchip Technology 3 4 #include <linux/kernel.h> 5 #include <linux/module.h> 6 #include <linux/delay.h> 7 #include <linux/mii.h> 8 #include <linux/phy.h> 9 #include <linux/ethtool.h> 10 #include <linux/ethtool_netlink.h> 11 #include <linux/bitfield.h> 12 13 #define PHY_ID_LAN87XX 0x0007c150 14 #define PHY_ID_LAN937X 0x0007c180 15 16 /* External Register Control Register */ 17 #define LAN87XX_EXT_REG_CTL (0x14) 18 #define LAN87XX_EXT_REG_CTL_RD_CTL (0x1000) 19 #define LAN87XX_EXT_REG_CTL_WR_CTL (0x0800) 20 #define LAN87XX_REG_BANK_SEL_MASK GENMASK(10, 8) 21 #define LAN87XX_REG_ADDR_MASK GENMASK(7, 0) 22 23 /* External Register Read Data Register */ 24 #define LAN87XX_EXT_REG_RD_DATA (0x15) 25 26 /* External Register Write Data Register */ 27 #define LAN87XX_EXT_REG_WR_DATA (0x16) 28 29 /* Interrupt Source Register */ 30 #define LAN87XX_INTERRUPT_SOURCE (0x18) 31 32 /* Interrupt Mask Register */ 33 #define LAN87XX_INTERRUPT_MASK (0x19) 34 #define LAN87XX_MASK_LINK_UP (0x0004) 35 #define LAN87XX_MASK_LINK_DOWN (0x0002) 36 37 /* MISC Control 1 Register */ 38 #define LAN87XX_CTRL_1 (0x11) 39 #define LAN87XX_MASK_RGMII_TXC_DLY_EN (0x4000) 40 #define LAN87XX_MASK_RGMII_RXC_DLY_EN (0x2000) 41 42 /* phyaccess nested types */ 43 #define PHYACC_ATTR_MODE_READ 0 44 #define PHYACC_ATTR_MODE_WRITE 1 45 #define PHYACC_ATTR_MODE_MODIFY 2 46 #define PHYACC_ATTR_MODE_POLL 3 47 48 #define PHYACC_ATTR_BANK_SMI 0 49 #define PHYACC_ATTR_BANK_MISC 1 50 #define PHYACC_ATTR_BANK_PCS 2 51 #define PHYACC_ATTR_BANK_AFE 3 52 #define PHYACC_ATTR_BANK_DSP 4 53 #define PHYACC_ATTR_BANK_MAX 7 54 55 /* measurement defines */ 56 #define LAN87XX_CABLE_TEST_OK 0 57 #define LAN87XX_CABLE_TEST_OPEN 1 58 #define LAN87XX_CABLE_TEST_SAME_SHORT 2 59 60 /* T1 Registers */ 61 #define T1_AFE_PORT_CFG1_REG 0x0B 62 #define T1_POWER_DOWN_CONTROL_REG 0x1A 63 #define T1_SLV_FD_MULT_CFG_REG 0x18 64 #define T1_CDR_CFG_PRE_LOCK_REG 0x05 65 #define T1_CDR_CFG_POST_LOCK_REG 0x06 66 #define T1_LCK_STG2_MUFACT_CFG_REG 0x1A 67 #define T1_LCK_STG3_MUFACT_CFG_REG 0x1B 68 #define T1_POST_LCK_MUFACT_CFG_REG 0x1C 69 #define T1_TX_RX_FIFO_CFG_REG 0x02 70 #define T1_TX_LPF_FIR_CFG_REG 0x55 71 #define T1_SQI_CONFIG_REG 0x2E 72 #define T1_MDIO_CONTROL2_REG 0x10 73 #define T1_INTERRUPT_SOURCE_REG 0x18 74 #define T1_INTERRUPT2_SOURCE_REG 0x08 75 #define T1_EQ_FD_STG1_FRZ_CFG 0x69 76 #define T1_EQ_FD_STG2_FRZ_CFG 0x6A 77 #define T1_EQ_FD_STG3_FRZ_CFG 0x6B 78 #define T1_EQ_FD_STG4_FRZ_CFG 0x6C 79 #define T1_EQ_WT_FD_LCK_FRZ_CFG 0x6D 80 #define T1_PST_EQ_LCK_STG1_FRZ_CFG 0x6E 81 82 #define T1_MODE_STAT_REG 0x11 83 #define T1_LINK_UP_MSK BIT(0) 84 85 #define DRIVER_AUTHOR "Nisar Sayed <nisar.sayed@microchip.com>" 86 #define DRIVER_DESC "Microchip LAN87XX/LAN937x T1 PHY driver" 87 88 struct access_ereg_val { 89 u8 mode; 90 u8 bank; 91 u8 offset; 92 u16 val; 93 u16 mask; 94 }; 95 96 static int lan937x_dsp_workaround(struct phy_device *phydev, u16 ereg, u8 bank) 97 { 98 u8 prev_bank; 99 int rc = 0; 100 u16 val; 101 102 mutex_lock(&phydev->lock); 103 /* Read previous selected bank */ 104 rc = phy_read(phydev, LAN87XX_EXT_REG_CTL); 105 if (rc < 0) 106 goto out_unlock; 107 108 /* store the prev_bank */ 109 prev_bank = FIELD_GET(LAN87XX_REG_BANK_SEL_MASK, rc); 110 111 if (bank != prev_bank && bank == PHYACC_ATTR_BANK_DSP) { 112 val = ereg & ~LAN87XX_REG_ADDR_MASK; 113 114 val &= ~LAN87XX_EXT_REG_CTL_WR_CTL; 115 val |= LAN87XX_EXT_REG_CTL_RD_CTL; 116 117 /* access twice for DSP bank change,dummy access */ 118 rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, val); 119 } 120 121 out_unlock: 122 mutex_unlock(&phydev->lock); 123 124 return rc; 125 } 126 127 static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank, 128 u8 offset, u16 val) 129 { 130 u16 ereg = 0; 131 int rc = 0; 132 133 if (mode > PHYACC_ATTR_MODE_WRITE || bank > PHYACC_ATTR_BANK_MAX) 134 return -EINVAL; 135 136 if (bank == PHYACC_ATTR_BANK_SMI) { 137 if (mode == PHYACC_ATTR_MODE_WRITE) 138 rc = phy_write(phydev, offset, val); 139 else 140 rc = phy_read(phydev, offset); 141 return rc; 142 } 143 144 if (mode == PHYACC_ATTR_MODE_WRITE) { 145 ereg = LAN87XX_EXT_REG_CTL_WR_CTL; 146 rc = phy_write(phydev, LAN87XX_EXT_REG_WR_DATA, val); 147 if (rc < 0) 148 return rc; 149 } else { 150 ereg = LAN87XX_EXT_REG_CTL_RD_CTL; 151 } 152 153 ereg |= (bank << 8) | offset; 154 155 /* DSP bank access workaround for lan937x */ 156 if (phydev->phy_id == PHY_ID_LAN937X) { 157 rc = lan937x_dsp_workaround(phydev, ereg, bank); 158 if (rc < 0) 159 return rc; 160 } 161 162 rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, ereg); 163 if (rc < 0) 164 return rc; 165 166 if (mode == PHYACC_ATTR_MODE_READ) 167 rc = phy_read(phydev, LAN87XX_EXT_REG_RD_DATA); 168 169 return rc; 170 } 171 172 static int access_ereg_modify_changed(struct phy_device *phydev, 173 u8 bank, u8 offset, u16 val, u16 mask) 174 { 175 int new = 0, rc = 0; 176 177 if (bank > PHYACC_ATTR_BANK_MAX) 178 return -EINVAL; 179 180 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, bank, offset, val); 181 if (rc < 0) 182 return rc; 183 184 new = val | (rc & (mask ^ 0xFFFF)); 185 rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE, bank, offset, new); 186 187 return rc; 188 } 189 190 static int access_smi_poll_timeout(struct phy_device *phydev, 191 u8 offset, u16 mask, u16 clr) 192 { 193 int val; 194 195 return phy_read_poll_timeout(phydev, offset, val, (val & mask) == clr, 196 150, 30000, true); 197 } 198 199 static int lan87xx_config_rgmii_delay(struct phy_device *phydev) 200 { 201 int rc; 202 203 if (!phy_interface_is_rgmii(phydev)) 204 return 0; 205 206 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, 207 PHYACC_ATTR_BANK_MISC, LAN87XX_CTRL_1, 0); 208 if (rc < 0) 209 return rc; 210 211 switch (phydev->interface) { 212 case PHY_INTERFACE_MODE_RGMII: 213 rc &= ~LAN87XX_MASK_RGMII_TXC_DLY_EN; 214 rc &= ~LAN87XX_MASK_RGMII_RXC_DLY_EN; 215 break; 216 case PHY_INTERFACE_MODE_RGMII_ID: 217 rc |= LAN87XX_MASK_RGMII_TXC_DLY_EN; 218 rc |= LAN87XX_MASK_RGMII_RXC_DLY_EN; 219 break; 220 case PHY_INTERFACE_MODE_RGMII_RXID: 221 rc &= ~LAN87XX_MASK_RGMII_TXC_DLY_EN; 222 rc |= LAN87XX_MASK_RGMII_RXC_DLY_EN; 223 break; 224 case PHY_INTERFACE_MODE_RGMII_TXID: 225 rc |= LAN87XX_MASK_RGMII_TXC_DLY_EN; 226 rc &= ~LAN87XX_MASK_RGMII_RXC_DLY_EN; 227 break; 228 default: 229 return 0; 230 } 231 232 return access_ereg(phydev, PHYACC_ATTR_MODE_WRITE, 233 PHYACC_ATTR_BANK_MISC, LAN87XX_CTRL_1, rc); 234 } 235 236 static int lan87xx_phy_init(struct phy_device *phydev) 237 { 238 static const struct access_ereg_val init[] = { 239 /* TXPD/TXAMP6 Configs */ 240 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_AFE, 241 T1_AFE_PORT_CFG1_REG, 0x002D, 0 }, 242 /* HW_Init Hi and Force_ED */ 243 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, 244 T1_POWER_DOWN_CONTROL_REG, 0x0308, 0 }, 245 /* Equalizer Full Duplex Freeze - T1 Slave */ 246 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 247 T1_EQ_FD_STG1_FRZ_CFG, 0x0002, 0 }, 248 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 249 T1_EQ_FD_STG2_FRZ_CFG, 0x0002, 0 }, 250 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 251 T1_EQ_FD_STG3_FRZ_CFG, 0x0002, 0 }, 252 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 253 T1_EQ_FD_STG4_FRZ_CFG, 0x0002, 0 }, 254 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 255 T1_EQ_WT_FD_LCK_FRZ_CFG, 0x0002, 0 }, 256 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 257 T1_PST_EQ_LCK_STG1_FRZ_CFG, 0x0002, 0 }, 258 /* Slave Full Duplex Multi Configs */ 259 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 260 T1_SLV_FD_MULT_CFG_REG, 0x0D53, 0 }, 261 /* CDR Pre and Post Lock Configs */ 262 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 263 T1_CDR_CFG_PRE_LOCK_REG, 0x0AB2, 0 }, 264 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 265 T1_CDR_CFG_POST_LOCK_REG, 0x0AB3, 0 }, 266 /* Lock Stage 2-3 Multi Factor Config */ 267 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 268 T1_LCK_STG2_MUFACT_CFG_REG, 0x0AEA, 0 }, 269 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 270 T1_LCK_STG3_MUFACT_CFG_REG, 0x0AEB, 0 }, 271 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 272 T1_POST_LCK_MUFACT_CFG_REG, 0x0AEB, 0 }, 273 /* Pointer delay */ 274 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 275 T1_TX_RX_FIFO_CFG_REG, 0x1C00, 0 }, 276 /* Tx iir edits */ 277 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 278 T1_TX_LPF_FIR_CFG_REG, 0x1000, 0 }, 279 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 280 T1_TX_LPF_FIR_CFG_REG, 0x1861, 0 }, 281 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 282 T1_TX_LPF_FIR_CFG_REG, 0x1061, 0 }, 283 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 284 T1_TX_LPF_FIR_CFG_REG, 0x1922, 0 }, 285 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 286 T1_TX_LPF_FIR_CFG_REG, 0x1122, 0 }, 287 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 288 T1_TX_LPF_FIR_CFG_REG, 0x1983, 0 }, 289 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 290 T1_TX_LPF_FIR_CFG_REG, 0x1183, 0 }, 291 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 292 T1_TX_LPF_FIR_CFG_REG, 0x1944, 0 }, 293 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 294 T1_TX_LPF_FIR_CFG_REG, 0x1144, 0 }, 295 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 296 T1_TX_LPF_FIR_CFG_REG, 0x18c5, 0 }, 297 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 298 T1_TX_LPF_FIR_CFG_REG, 0x10c5, 0 }, 299 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 300 T1_TX_LPF_FIR_CFG_REG, 0x1846, 0 }, 301 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 302 T1_TX_LPF_FIR_CFG_REG, 0x1046, 0 }, 303 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 304 T1_TX_LPF_FIR_CFG_REG, 0x1807, 0 }, 305 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 306 T1_TX_LPF_FIR_CFG_REG, 0x1007, 0 }, 307 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 308 T1_TX_LPF_FIR_CFG_REG, 0x1808, 0 }, 309 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 310 T1_TX_LPF_FIR_CFG_REG, 0x1008, 0 }, 311 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 312 T1_TX_LPF_FIR_CFG_REG, 0x1809, 0 }, 313 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 314 T1_TX_LPF_FIR_CFG_REG, 0x1009, 0 }, 315 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 316 T1_TX_LPF_FIR_CFG_REG, 0x180A, 0 }, 317 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 318 T1_TX_LPF_FIR_CFG_REG, 0x100A, 0 }, 319 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 320 T1_TX_LPF_FIR_CFG_REG, 0x180B, 0 }, 321 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 322 T1_TX_LPF_FIR_CFG_REG, 0x100B, 0 }, 323 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 324 T1_TX_LPF_FIR_CFG_REG, 0x180C, 0 }, 325 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 326 T1_TX_LPF_FIR_CFG_REG, 0x100C, 0 }, 327 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 328 T1_TX_LPF_FIR_CFG_REG, 0x180D, 0 }, 329 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 330 T1_TX_LPF_FIR_CFG_REG, 0x100D, 0 }, 331 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 332 T1_TX_LPF_FIR_CFG_REG, 0x180E, 0 }, 333 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 334 T1_TX_LPF_FIR_CFG_REG, 0x100E, 0 }, 335 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 336 T1_TX_LPF_FIR_CFG_REG, 0x180F, 0 }, 337 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 338 T1_TX_LPF_FIR_CFG_REG, 0x100F, 0 }, 339 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 340 T1_TX_LPF_FIR_CFG_REG, 0x1810, 0 }, 341 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 342 T1_TX_LPF_FIR_CFG_REG, 0x1010, 0 }, 343 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 344 T1_TX_LPF_FIR_CFG_REG, 0x1811, 0 }, 345 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 346 T1_TX_LPF_FIR_CFG_REG, 0x1011, 0 }, 347 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 348 T1_TX_LPF_FIR_CFG_REG, 0x1000, 0 }, 349 /* SQI enable */ 350 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 351 T1_SQI_CONFIG_REG, 0x9572, 0 }, 352 /* Flag LPS and WUR as idle errors */ 353 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, 354 T1_MDIO_CONTROL2_REG, 0x0014, 0 }, 355 /* HW_Init toggle, undo force ED, TXPD off */ 356 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, 357 T1_POWER_DOWN_CONTROL_REG, 0x0200, 0 }, 358 /* Reset PCS to trigger hardware initialization */ 359 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, 360 T1_MDIO_CONTROL2_REG, 0x0094, 0 }, 361 /* Poll till Hardware is initialized */ 362 { PHYACC_ATTR_MODE_POLL, PHYACC_ATTR_BANK_SMI, 363 T1_MDIO_CONTROL2_REG, 0x0080, 0 }, 364 /* Tx AMP - 0x06 */ 365 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_AFE, 366 T1_AFE_PORT_CFG1_REG, 0x000C, 0 }, 367 /* Read INTERRUPT_SOURCE Register */ 368 { PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI, 369 T1_INTERRUPT_SOURCE_REG, 0, 0 }, 370 /* Read INTERRUPT_SOURCE Register */ 371 { PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_MISC, 372 T1_INTERRUPT2_SOURCE_REG, 0, 0 }, 373 /* HW_Init Hi */ 374 { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI, 375 T1_POWER_DOWN_CONTROL_REG, 0x0300, 0 }, 376 }; 377 int rc, i; 378 379 /* phy Soft reset */ 380 rc = genphy_soft_reset(phydev); 381 if (rc < 0) 382 return rc; 383 384 /* PHY Initialization */ 385 for (i = 0; i < ARRAY_SIZE(init); i++) { 386 if (init[i].mode == PHYACC_ATTR_MODE_POLL && 387 init[i].bank == PHYACC_ATTR_BANK_SMI) { 388 rc = access_smi_poll_timeout(phydev, 389 init[i].offset, 390 init[i].val, 391 init[i].mask); 392 } else { 393 rc = access_ereg(phydev, init[i].mode, init[i].bank, 394 init[i].offset, init[i].val); 395 } 396 if (rc < 0) 397 return rc; 398 } 399 400 return lan87xx_config_rgmii_delay(phydev); 401 } 402 403 static int lan87xx_phy_config_intr(struct phy_device *phydev) 404 { 405 int rc, val = 0; 406 407 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 408 /* unmask all source and clear them before enable */ 409 rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, 0x7FFF); 410 rc = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE); 411 val = LAN87XX_MASK_LINK_UP | LAN87XX_MASK_LINK_DOWN; 412 rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val); 413 } else { 414 rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val); 415 if (rc) 416 return rc; 417 418 rc = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE); 419 } 420 421 return rc < 0 ? rc : 0; 422 } 423 424 static irqreturn_t lan87xx_handle_interrupt(struct phy_device *phydev) 425 { 426 int irq_status; 427 428 irq_status = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE); 429 if (irq_status < 0) { 430 phy_error(phydev); 431 return IRQ_NONE; 432 } 433 434 if (irq_status == 0) 435 return IRQ_NONE; 436 437 phy_trigger_machine(phydev); 438 439 return IRQ_HANDLED; 440 } 441 442 static int lan87xx_config_init(struct phy_device *phydev) 443 { 444 int rc = lan87xx_phy_init(phydev); 445 446 return rc < 0 ? rc : 0; 447 } 448 449 static int microchip_cable_test_start_common(struct phy_device *phydev) 450 { 451 int bmcr, bmsr, ret; 452 453 /* If auto-negotiation is enabled, but not complete, the cable 454 * test never completes. So disable auto-neg. 455 */ 456 bmcr = phy_read(phydev, MII_BMCR); 457 if (bmcr < 0) 458 return bmcr; 459 460 bmsr = phy_read(phydev, MII_BMSR); 461 462 if (bmsr < 0) 463 return bmsr; 464 465 if (bmcr & BMCR_ANENABLE) { 466 ret = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0); 467 if (ret < 0) 468 return ret; 469 ret = genphy_soft_reset(phydev); 470 if (ret < 0) 471 return ret; 472 } 473 474 /* If the link is up, allow it some time to go down */ 475 if (bmsr & BMSR_LSTATUS) 476 msleep(1500); 477 478 return 0; 479 } 480 481 static int lan87xx_cable_test_start(struct phy_device *phydev) 482 { 483 static const struct access_ereg_val cable_test[] = { 484 /* min wait */ 485 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 93, 486 0, 0}, 487 /* max wait */ 488 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 94, 489 10, 0}, 490 /* pulse cycle */ 491 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 95, 492 90, 0}, 493 /* cable diag thresh */ 494 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 92, 495 60, 0}, 496 /* max gain */ 497 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 79, 498 31, 0}, 499 /* clock align for each iteration */ 500 {PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_DSP, 55, 501 0, 0x0038}, 502 /* max cycle wait config */ 503 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 94, 504 70, 0}, 505 /* start cable diag*/ 506 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 90, 507 1, 0}, 508 }; 509 int rc, i; 510 511 rc = microchip_cable_test_start_common(phydev); 512 if (rc < 0) 513 return rc; 514 515 /* start cable diag */ 516 /* check if part is alive - if not, return diagnostic error */ 517 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI, 518 0x00, 0); 519 if (rc < 0) 520 return rc; 521 522 /* master/slave specific configs */ 523 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI, 524 0x0A, 0); 525 if (rc < 0) 526 return rc; 527 528 if ((rc & 0x4000) != 0x4000) { 529 /* DUT is Slave */ 530 rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_AFE, 531 0x0E, 0x5, 0x7); 532 if (rc < 0) 533 return rc; 534 rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI, 535 0x1A, 0x8, 0x8); 536 if (rc < 0) 537 return rc; 538 } else { 539 /* DUT is Master */ 540 rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI, 541 0x10, 0x8, 0x40); 542 if (rc < 0) 543 return rc; 544 } 545 546 for (i = 0; i < ARRAY_SIZE(cable_test); i++) { 547 if (cable_test[i].mode == PHYACC_ATTR_MODE_MODIFY) { 548 rc = access_ereg_modify_changed(phydev, 549 cable_test[i].bank, 550 cable_test[i].offset, 551 cable_test[i].val, 552 cable_test[i].mask); 553 /* wait 50ms */ 554 msleep(50); 555 } else { 556 rc = access_ereg(phydev, cable_test[i].mode, 557 cable_test[i].bank, 558 cable_test[i].offset, 559 cable_test[i].val); 560 } 561 if (rc < 0) 562 return rc; 563 } 564 /* cable diag started */ 565 566 return 0; 567 } 568 569 static int lan87xx_cable_test_report_trans(u32 result) 570 { 571 switch (result) { 572 case LAN87XX_CABLE_TEST_OK: 573 return ETHTOOL_A_CABLE_RESULT_CODE_OK; 574 case LAN87XX_CABLE_TEST_OPEN: 575 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 576 case LAN87XX_CABLE_TEST_SAME_SHORT: 577 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 578 default: 579 /* DIAGNOSTIC_ERROR */ 580 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 581 } 582 } 583 584 static int lan87xx_cable_test_report(struct phy_device *phydev) 585 { 586 int pos_peak_cycle = 0, pos_peak_in_phases = 0, pos_peak_phase = 0; 587 int neg_peak_cycle = 0, neg_peak_in_phases = 0, neg_peak_phase = 0; 588 int noise_margin = 20, time_margin = 89, jitter_var = 30; 589 int min_time_diff = 96, max_time_diff = 96 + time_margin; 590 bool fault = false, check_a = false, check_b = false; 591 int gain_idx = 0, pos_peak = 0, neg_peak = 0; 592 int pos_peak_time = 0, neg_peak_time = 0; 593 int pos_peak_in_phases_hybrid = 0; 594 int detect = -1; 595 596 gain_idx = access_ereg(phydev, PHYACC_ATTR_MODE_READ, 597 PHYACC_ATTR_BANK_DSP, 151, 0); 598 /* read non-hybrid results */ 599 pos_peak = access_ereg(phydev, PHYACC_ATTR_MODE_READ, 600 PHYACC_ATTR_BANK_DSP, 153, 0); 601 neg_peak = access_ereg(phydev, PHYACC_ATTR_MODE_READ, 602 PHYACC_ATTR_BANK_DSP, 154, 0); 603 pos_peak_time = access_ereg(phydev, PHYACC_ATTR_MODE_READ, 604 PHYACC_ATTR_BANK_DSP, 156, 0); 605 neg_peak_time = access_ereg(phydev, PHYACC_ATTR_MODE_READ, 606 PHYACC_ATTR_BANK_DSP, 157, 0); 607 608 pos_peak_cycle = (pos_peak_time >> 7) & 0x7F; 609 /* calculate non-hybrid values */ 610 pos_peak_phase = pos_peak_time & 0x7F; 611 pos_peak_in_phases = (pos_peak_cycle * 96) + pos_peak_phase; 612 neg_peak_cycle = (neg_peak_time >> 7) & 0x7F; 613 neg_peak_phase = neg_peak_time & 0x7F; 614 neg_peak_in_phases = (neg_peak_cycle * 96) + neg_peak_phase; 615 616 /* process values */ 617 check_a = 618 ((pos_peak_in_phases - neg_peak_in_phases) >= min_time_diff) && 619 ((pos_peak_in_phases - neg_peak_in_phases) < max_time_diff) && 620 pos_peak_in_phases_hybrid < pos_peak_in_phases && 621 (pos_peak_in_phases_hybrid < (neg_peak_in_phases + jitter_var)); 622 check_b = 623 ((neg_peak_in_phases - pos_peak_in_phases) >= min_time_diff) && 624 ((neg_peak_in_phases - pos_peak_in_phases) < max_time_diff) && 625 pos_peak_in_phases_hybrid < neg_peak_in_phases && 626 (pos_peak_in_phases_hybrid < (pos_peak_in_phases + jitter_var)); 627 628 if (pos_peak_in_phases > neg_peak_in_phases && check_a) 629 detect = 2; 630 else if ((neg_peak_in_phases > pos_peak_in_phases) && check_b) 631 detect = 1; 632 633 if (pos_peak > noise_margin && neg_peak > noise_margin && 634 gain_idx >= 0) { 635 if (detect == 1 || detect == 2) 636 fault = true; 637 } 638 639 if (!fault) 640 detect = 0; 641 642 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, 643 lan87xx_cable_test_report_trans(detect)); 644 645 return 0; 646 } 647 648 static int lan87xx_cable_test_get_status(struct phy_device *phydev, 649 bool *finished) 650 { 651 int rc = 0; 652 653 *finished = false; 654 655 /* check if cable diag was finished */ 656 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_DSP, 657 90, 0); 658 if (rc < 0) 659 return rc; 660 661 if ((rc & 2) == 2) { 662 /* stop cable diag*/ 663 rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE, 664 PHYACC_ATTR_BANK_DSP, 665 90, 0); 666 if (rc < 0) 667 return rc; 668 669 *finished = true; 670 671 return lan87xx_cable_test_report(phydev); 672 } 673 674 return 0; 675 } 676 677 static int lan87xx_read_status(struct phy_device *phydev) 678 { 679 int rc = 0; 680 681 rc = phy_read(phydev, T1_MODE_STAT_REG); 682 if (rc < 0) 683 return rc; 684 685 if (rc & T1_LINK_UP_MSK) 686 phydev->link = 1; 687 else 688 phydev->link = 0; 689 690 phydev->speed = SPEED_UNKNOWN; 691 phydev->duplex = DUPLEX_UNKNOWN; 692 phydev->pause = 0; 693 phydev->asym_pause = 0; 694 695 rc = genphy_read_master_slave(phydev); 696 if (rc < 0) 697 return rc; 698 699 rc = genphy_read_status_fixed(phydev); 700 if (rc < 0) 701 return rc; 702 703 return rc; 704 } 705 706 static int lan87xx_config_aneg(struct phy_device *phydev) 707 { 708 u16 ctl = 0; 709 710 switch (phydev->master_slave_set) { 711 case MASTER_SLAVE_CFG_MASTER_FORCE: 712 ctl |= CTL1000_AS_MASTER; 713 break; 714 case MASTER_SLAVE_CFG_SLAVE_FORCE: 715 break; 716 case MASTER_SLAVE_CFG_UNKNOWN: 717 case MASTER_SLAVE_CFG_UNSUPPORTED: 718 return 0; 719 default: 720 phydev_warn(phydev, "Unsupported Master/Slave mode\n"); 721 return -EOPNOTSUPP; 722 } 723 724 return phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl); 725 } 726 727 static struct phy_driver microchip_t1_phy_driver[] = { 728 { 729 PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX), 730 .name = "Microchip LAN87xx T1", 731 .flags = PHY_POLL_CABLE_TEST, 732 .features = PHY_BASIC_T1_FEATURES, 733 .config_init = lan87xx_config_init, 734 .config_intr = lan87xx_phy_config_intr, 735 .handle_interrupt = lan87xx_handle_interrupt, 736 .suspend = genphy_suspend, 737 .resume = genphy_resume, 738 .config_aneg = lan87xx_config_aneg, 739 .read_status = lan87xx_read_status, 740 .cable_test_start = lan87xx_cable_test_start, 741 .cable_test_get_status = lan87xx_cable_test_get_status, 742 }, 743 { 744 PHY_ID_MATCH_MODEL(PHY_ID_LAN937X), 745 .name = "Microchip LAN937x T1", 746 .flags = PHY_POLL_CABLE_TEST, 747 .features = PHY_BASIC_T1_FEATURES, 748 .config_init = lan87xx_config_init, 749 .suspend = genphy_suspend, 750 .resume = genphy_resume, 751 .config_aneg = lan87xx_config_aneg, 752 .read_status = lan87xx_read_status, 753 .cable_test_start = lan87xx_cable_test_start, 754 .cable_test_get_status = lan87xx_cable_test_get_status, 755 } 756 }; 757 758 module_phy_driver(microchip_t1_phy_driver); 759 760 static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = { 761 { PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX) }, 762 { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X) }, 763 { } 764 }; 765 766 MODULE_DEVICE_TABLE(mdio, microchip_t1_tbl); 767 768 MODULE_AUTHOR(DRIVER_AUTHOR); 769 MODULE_DESCRIPTION(DRIVER_DESC); 770 MODULE_LICENSE("GPL"); 771