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