1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2012 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> 4 * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de> 5 */ 6 7 #include <linux/mdio.h> 8 #include <linux/module.h> 9 #include <linux/phy.h> 10 #include <linux/of.h> 11 #include <linux/bitfield.h> 12 13 #define XWAY_MDIO_ERRCNT 0x15 /* error counter */ 14 #define XWAY_MDIO_MIICTRL 0x17 /* mii control */ 15 #define XWAY_MDIO_IMASK 0x19 /* interrupt mask */ 16 #define XWAY_MDIO_ISTAT 0x1A /* interrupt status */ 17 #define XWAY_MDIO_LED 0x1B /* led control */ 18 19 #define XWAY_MDIO_GCTRL_TM_MASK GENMASK(15, 13) 20 #define XWAY_MDIO_GCTRL_TM(mode) FIELD_PREP(XWAY_MDIO_GCTRL_TM_MASK, (mode)) 21 #define XWAY_MDIO_GCTRL_TM_NOP XWAY_MDIO_GCTRL_TM(0) /* Normal operation */ 22 #define XWAY_MDIO_GCTRL_TM_CDIAG XWAY_MDIO_GCTRL_TM(6) /* Cable diagnostics */ 23 24 #define XWAY_MDIO_ERRCNT_SEL GENMASK(11, 8) 25 #define XWAY_MDIO_ERRCNT_COUNT GENMASK(7, 0) 26 #define XWAY_MDIO_ERRCNT_SEL_RXERR 0 27 28 #define XWAY_MDIO_MIICTRL_RXSKEW_MASK GENMASK(14, 12) 29 #define XWAY_MDIO_MIICTRL_TXSKEW_MASK GENMASK(10, 8) 30 31 /* bit 15:12 are reserved */ 32 #define XWAY_MDIO_LED_LED3_EN BIT(11) /* Enable the integrated function of LED3 */ 33 #define XWAY_MDIO_LED_LED2_EN BIT(10) /* Enable the integrated function of LED2 */ 34 #define XWAY_MDIO_LED_LED1_EN BIT(9) /* Enable the integrated function of LED1 */ 35 #define XWAY_MDIO_LED_LED0_EN BIT(8) /* Enable the integrated function of LED0 */ 36 /* bit 7:4 are reserved */ 37 #define XWAY_MDIO_LED_LED3_DA BIT(3) /* Direct Access to LED3 */ 38 #define XWAY_MDIO_LED_LED2_DA BIT(2) /* Direct Access to LED2 */ 39 #define XWAY_MDIO_LED_LED1_DA BIT(1) /* Direct Access to LED1 */ 40 #define XWAY_MDIO_LED_LED0_DA BIT(0) /* Direct Access to LED0 */ 41 42 #define XWAY_MDIO_INIT_WOL BIT(15) /* Wake-On-LAN */ 43 #define XWAY_MDIO_INIT_MSRE BIT(14) 44 #define XWAY_MDIO_INIT_NPRX BIT(13) 45 #define XWAY_MDIO_INIT_NPTX BIT(12) 46 #define XWAY_MDIO_INIT_ANE BIT(11) /* Auto-Neg error */ 47 #define XWAY_MDIO_INIT_ANC BIT(10) /* Auto-Neg complete */ 48 #define XWAY_MDIO_INIT_ADSC BIT(5) /* Link auto-downspeed detect */ 49 #define XWAY_MDIO_INIT_MPIPC BIT(4) 50 #define XWAY_MDIO_INIT_MDIXC BIT(3) 51 #define XWAY_MDIO_INIT_DXMC BIT(2) /* Duplex mode change */ 52 #define XWAY_MDIO_INIT_LSPC BIT(1) /* Link speed change */ 53 #define XWAY_MDIO_INIT_LSTC BIT(0) /* Link state change */ 54 #define XWAY_MDIO_INIT_MASK (XWAY_MDIO_INIT_LSTC | \ 55 XWAY_MDIO_INIT_ADSC) 56 57 #define ADVERTISED_MPD BIT(10) /* Multi-port device */ 58 59 /* LED Configuration */ 60 #define XWAY_MMD_LEDCH 0x01E0 61 /* Inverse of SCAN Function */ 62 #define XWAY_MMD_LEDCH_NACS_NONE 0x0000 63 #define XWAY_MMD_LEDCH_NACS_LINK 0x0001 64 #define XWAY_MMD_LEDCH_NACS_PDOWN 0x0002 65 #define XWAY_MMD_LEDCH_NACS_EEE 0x0003 66 #define XWAY_MMD_LEDCH_NACS_ANEG 0x0004 67 #define XWAY_MMD_LEDCH_NACS_ABIST 0x0005 68 #define XWAY_MMD_LEDCH_NACS_CDIAG 0x0006 69 #define XWAY_MMD_LEDCH_NACS_TEST 0x0007 70 /* Slow Blink Frequency */ 71 #define XWAY_MMD_LEDCH_SBF_F02HZ 0x0000 72 #define XWAY_MMD_LEDCH_SBF_F04HZ 0x0010 73 #define XWAY_MMD_LEDCH_SBF_F08HZ 0x0020 74 #define XWAY_MMD_LEDCH_SBF_F16HZ 0x0030 75 /* Fast Blink Frequency */ 76 #define XWAY_MMD_LEDCH_FBF_F02HZ 0x0000 77 #define XWAY_MMD_LEDCH_FBF_F04HZ 0x0040 78 #define XWAY_MMD_LEDCH_FBF_F08HZ 0x0080 79 #define XWAY_MMD_LEDCH_FBF_F16HZ 0x00C0 80 /* LED Configuration */ 81 #define XWAY_MMD_LEDCL 0x01E1 82 /* Complex Blinking Configuration */ 83 #define XWAY_MMD_LEDCH_CBLINK_NONE 0x0000 84 #define XWAY_MMD_LEDCH_CBLINK_LINK 0x0001 85 #define XWAY_MMD_LEDCH_CBLINK_PDOWN 0x0002 86 #define XWAY_MMD_LEDCH_CBLINK_EEE 0x0003 87 #define XWAY_MMD_LEDCH_CBLINK_ANEG 0x0004 88 #define XWAY_MMD_LEDCH_CBLINK_ABIST 0x0005 89 #define XWAY_MMD_LEDCH_CBLINK_CDIAG 0x0006 90 #define XWAY_MMD_LEDCH_CBLINK_TEST 0x0007 91 /* Complex SCAN Configuration */ 92 #define XWAY_MMD_LEDCH_SCAN_NONE 0x0000 93 #define XWAY_MMD_LEDCH_SCAN_LINK 0x0010 94 #define XWAY_MMD_LEDCH_SCAN_PDOWN 0x0020 95 #define XWAY_MMD_LEDCH_SCAN_EEE 0x0030 96 #define XWAY_MMD_LEDCH_SCAN_ANEG 0x0040 97 #define XWAY_MMD_LEDCH_SCAN_ABIST 0x0050 98 #define XWAY_MMD_LEDCH_SCAN_CDIAG 0x0060 99 #define XWAY_MMD_LEDCH_SCAN_TEST 0x0070 100 /* Configuration for LED Pin x */ 101 #define XWAY_MMD_LED0H 0x01E2 102 /* Fast Blinking Configuration */ 103 #define XWAY_MMD_LEDxH_BLINKF_MASK 0x000F 104 #define XWAY_MMD_LEDxH_BLINKF_NONE 0x0000 105 #define XWAY_MMD_LEDxH_BLINKF_LINK10 0x0001 106 #define XWAY_MMD_LEDxH_BLINKF_LINK100 0x0002 107 #define XWAY_MMD_LEDxH_BLINKF_LINK10X 0x0003 108 #define XWAY_MMD_LEDxH_BLINKF_LINK1000 0x0004 109 #define XWAY_MMD_LEDxH_BLINKF_LINK10_0 0x0005 110 #define XWAY_MMD_LEDxH_BLINKF_LINK100X 0x0006 111 #define XWAY_MMD_LEDxH_BLINKF_LINK10XX 0x0007 112 #define XWAY_MMD_LEDxH_BLINKF_PDOWN 0x0008 113 #define XWAY_MMD_LEDxH_BLINKF_EEE 0x0009 114 #define XWAY_MMD_LEDxH_BLINKF_ANEG 0x000A 115 #define XWAY_MMD_LEDxH_BLINKF_ABIST 0x000B 116 #define XWAY_MMD_LEDxH_BLINKF_CDIAG 0x000C 117 /* Constant On Configuration */ 118 #define XWAY_MMD_LEDxH_CON_MASK 0x00F0 119 #define XWAY_MMD_LEDxH_CON_NONE 0x0000 120 #define XWAY_MMD_LEDxH_CON_LINK10 0x0010 121 #define XWAY_MMD_LEDxH_CON_LINK100 0x0020 122 #define XWAY_MMD_LEDxH_CON_LINK10X 0x0030 123 #define XWAY_MMD_LEDxH_CON_LINK1000 0x0040 124 #define XWAY_MMD_LEDxH_CON_LINK10_0 0x0050 125 #define XWAY_MMD_LEDxH_CON_LINK100X 0x0060 126 #define XWAY_MMD_LEDxH_CON_LINK10XX 0x0070 127 #define XWAY_MMD_LEDxH_CON_PDOWN 0x0080 128 #define XWAY_MMD_LEDxH_CON_EEE 0x0090 129 #define XWAY_MMD_LEDxH_CON_ANEG 0x00A0 130 #define XWAY_MMD_LEDxH_CON_ABIST 0x00B0 131 #define XWAY_MMD_LEDxH_CON_CDIAG 0x00C0 132 #define XWAY_MMD_LEDxH_CON_COPPER 0x00D0 133 #define XWAY_MMD_LEDxH_CON_FIBER 0x00E0 134 /* Configuration for LED Pin x */ 135 #define XWAY_MMD_LED0L 0x01E3 136 /* Pulsing Configuration */ 137 #define XWAY_MMD_LEDxL_PULSE_MASK 0x000F 138 #define XWAY_MMD_LEDxL_PULSE_NONE 0x0000 139 #define XWAY_MMD_LEDxL_PULSE_TXACT 0x0001 140 #define XWAY_MMD_LEDxL_PULSE_RXACT 0x0002 141 #define XWAY_MMD_LEDxL_PULSE_COL 0x0004 142 /* Slow Blinking Configuration */ 143 #define XWAY_MMD_LEDxL_BLINKS_MASK 0x00F0 144 #define XWAY_MMD_LEDxL_BLINKS_NONE 0x0000 145 #define XWAY_MMD_LEDxL_BLINKS_LINK10 0x0010 146 #define XWAY_MMD_LEDxL_BLINKS_LINK100 0x0020 147 #define XWAY_MMD_LEDxL_BLINKS_LINK10X 0x0030 148 #define XWAY_MMD_LEDxL_BLINKS_LINK1000 0x0040 149 #define XWAY_MMD_LEDxL_BLINKS_LINK10_0 0x0050 150 #define XWAY_MMD_LEDxL_BLINKS_LINK100X 0x0060 151 #define XWAY_MMD_LEDxL_BLINKS_LINK10XX 0x0070 152 #define XWAY_MMD_LEDxL_BLINKS_PDOWN 0x0080 153 #define XWAY_MMD_LEDxL_BLINKS_EEE 0x0090 154 #define XWAY_MMD_LEDxL_BLINKS_ANEG 0x00A0 155 #define XWAY_MMD_LEDxL_BLINKS_ABIST 0x00B0 156 #define XWAY_MMD_LEDxL_BLINKS_CDIAG 0x00C0 157 #define XWAY_MMD_LED1H 0x01E4 158 #define XWAY_MMD_LED1L 0x01E5 159 #define XWAY_MMD_LED2H 0x01E6 160 #define XWAY_MMD_LED2L 0x01E7 161 #define XWAY_MMD_LED3H 0x01E8 162 #define XWAY_MMD_LED3L 0x01E9 163 164 #define XWAY_GPHY_MAX_LEDS 3 165 #define XWAY_GPHY_LED_INV(idx) BIT(12 + (idx)) 166 #define XWAY_GPHY_LED_EN(idx) BIT(8 + (idx)) 167 #define XWAY_GPHY_LED_DA(idx) BIT(idx) 168 #define XWAY_MMD_LEDxH(idx) (XWAY_MMD_LED0H + 2 * (idx)) 169 #define XWAY_MMD_LEDxL(idx) (XWAY_MMD_LED0L + 2 * (idx)) 170 171 #define PHY_ID_PHY11G_1_3 0x030260D1 172 #define PHY_ID_PHY22F_1_3 0x030260E1 173 #define PHY_ID_PHY11G_1_4 0xD565A400 174 #define PHY_ID_PHY22F_1_4 0xD565A410 175 #define PHY_ID_PHY11G_1_5 0xD565A401 176 #define PHY_ID_PHY22F_1_5 0xD565A411 177 #define PHY_ID_PHY11G_VR9_1_1 0xD565A408 178 #define PHY_ID_PHY22F_VR9_1_1 0xD565A418 179 #define PHY_ID_PHY11G_VR9_1_2 0xD565A409 180 #define PHY_ID_PHY22F_VR9_1_2 0xD565A419 181 182 struct xway_gphy_priv { 183 u64 rx_errors; 184 }; 185 186 static const int xway_internal_delay[] = {0, 500, 1000, 1500, 2000, 2500, 187 3000, 3500}; 188 189 static int xway_gphy_rgmii_init(struct phy_device *phydev) 190 { 191 unsigned int delay_size = ARRAY_SIZE(xway_internal_delay); 192 s32 int_delay; 193 int val = 0; 194 195 if (!phy_interface_is_rgmii(phydev)) 196 return 0; 197 198 /* Existing behavior was to use default pin strapping delay in rgmii 199 * mode, but rgmii should have meant no delay. Warn existing users, 200 * but do not change anything at the moment. 201 */ 202 if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { 203 u16 txskew, rxskew; 204 205 val = phy_read(phydev, XWAY_MDIO_MIICTRL); 206 if (val < 0) 207 return val; 208 209 txskew = FIELD_GET(XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); 210 rxskew = FIELD_GET(XWAY_MDIO_MIICTRL_RXSKEW_MASK, val); 211 212 if (txskew > 0 || rxskew > 0) 213 phydev_warn(phydev, 214 "PHY has delays (e.g. via pin strapping), but phy-mode = 'rgmii'\n" 215 "Should be 'rgmii-id' to use internal delays txskew:%d ps rxskew:%d ps\n", 216 xway_internal_delay[txskew], 217 xway_internal_delay[rxskew]); 218 return 0; 219 } 220 221 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 222 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 223 int_delay = phy_get_internal_delay(phydev, xway_internal_delay, 224 delay_size, true); 225 226 /* if rx-internal-delay-ps is missing, use default of 2.0 ns */ 227 if (int_delay < 0) 228 int_delay = 4; /* 2000 ps */ 229 230 val |= FIELD_PREP(XWAY_MDIO_MIICTRL_RXSKEW_MASK, int_delay); 231 } 232 233 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 234 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 235 int_delay = phy_get_internal_delay(phydev, xway_internal_delay, 236 delay_size, false); 237 238 /* if tx-internal-delay-ps is missing, use default of 2.0 ns */ 239 if (int_delay < 0) 240 int_delay = 4; /* 2000 ps */ 241 242 val |= FIELD_PREP(XWAY_MDIO_MIICTRL_TXSKEW_MASK, int_delay); 243 } 244 245 return phy_modify(phydev, XWAY_MDIO_MIICTRL, 246 XWAY_MDIO_MIICTRL_RXSKEW_MASK | 247 XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); 248 } 249 250 static int xway_gphy_init_leds(struct phy_device *phydev) 251 { 252 int err; 253 u32 ledxh; 254 u32 ledxl; 255 256 /* Ensure that integrated led function is enabled for all leds */ 257 err = phy_write(phydev, XWAY_MDIO_LED, 258 XWAY_MDIO_LED_LED0_EN | 259 XWAY_MDIO_LED_LED1_EN | 260 XWAY_MDIO_LED_LED2_EN | 261 XWAY_MDIO_LED_LED3_EN); 262 if (err) 263 return err; 264 265 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCH, 266 XWAY_MMD_LEDCH_NACS_NONE | 267 XWAY_MMD_LEDCH_SBF_F02HZ | 268 XWAY_MMD_LEDCH_FBF_F16HZ); 269 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCL, 270 XWAY_MMD_LEDCH_CBLINK_NONE | 271 XWAY_MMD_LEDCH_SCAN_NONE); 272 273 /** 274 * In most cases only one LED is connected to this phy, so 275 * configure them all to constant on and pulse mode. LED3 is 276 * only available in some packages, leave it in its reset 277 * configuration. 278 */ 279 ledxh = XWAY_MMD_LEDxH_BLINKF_NONE | XWAY_MMD_LEDxH_CON_LINK10XX; 280 ledxl = XWAY_MMD_LEDxL_PULSE_TXACT | XWAY_MMD_LEDxL_PULSE_RXACT | 281 XWAY_MMD_LEDxL_BLINKS_NONE; 282 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0H, ledxh); 283 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0L, ledxl); 284 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1H, ledxh); 285 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1L, ledxl); 286 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh); 287 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl); 288 289 return 0; 290 } 291 292 static int xway_gphy_config_init(struct phy_device *phydev) 293 { 294 struct device_node *np; 295 int err; 296 297 /* Mask all interrupts */ 298 err = phy_write(phydev, XWAY_MDIO_IMASK, 0); 299 if (err) 300 return err; 301 302 /* Use default LED configuration if 'leds' node isn't defined */ 303 np = of_get_child_by_name(phydev->mdio.dev.of_node, "leds"); 304 if (np) 305 of_node_put(np); 306 else 307 xway_gphy_init_leds(phydev); 308 309 /* Clear all pending interrupts */ 310 phy_read(phydev, XWAY_MDIO_ISTAT); 311 312 err = xway_gphy_rgmii_init(phydev); 313 if (err) 314 return err; 315 316 /* Count MDI RX errors (SymbolErrorDuringCarrier) */ 317 return phy_write(phydev, XWAY_MDIO_ERRCNT, 318 FIELD_PREP(XWAY_MDIO_ERRCNT_SEL, XWAY_MDIO_ERRCNT_SEL_RXERR)); 319 } 320 321 static int xway_gphy_probe(struct phy_device *phydev) 322 { 323 struct device *dev = &phydev->mdio.dev; 324 struct xway_gphy_priv *priv; 325 326 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 327 if (!priv) 328 return -ENOMEM; 329 phydev->priv = priv; 330 331 return 0; 332 } 333 334 static int xway_11g_int_config_init(struct phy_device *phydev) 335 { 336 int err; 337 338 /* An issue has been sporadically observed after device power-on on the 339 * first link-up attempt in 100BASE-TX mode resulting in either the 340 * link-up taking a long time, or failing to link-up altogether. 341 * 342 * Workaround: 343 * After power-on, enable Cable Diagnostic Mode for all ports and 344 * disable it. 345 */ 346 err = phy_modify(phydev, MII_CTRL1000, XWAY_MDIO_GCTRL_TM_MASK, XWAY_MDIO_GCTRL_TM_CDIAG); 347 if (err) 348 return err; 349 err = phy_modify(phydev, MII_CTRL1000, XWAY_MDIO_GCTRL_TM_MASK, XWAY_MDIO_GCTRL_TM_NOP); 350 if (err) 351 return err; 352 353 return xway_gphy_config_init(phydev); 354 } 355 356 static int xway_gphy14_config_aneg(struct phy_device *phydev) 357 { 358 int reg, err; 359 360 /* Advertise as multi-port device, see IEEE802.3-2002 40.5.1.1 */ 361 /* This is a workaround for an errata in rev < 1.5 devices */ 362 reg = phy_read(phydev, MII_CTRL1000); 363 reg |= ADVERTISED_MPD; 364 err = phy_write(phydev, MII_CTRL1000, reg); 365 if (err) 366 return err; 367 368 return genphy_config_aneg(phydev); 369 } 370 371 static int xway_gphy_ack_interrupt(struct phy_device *phydev) 372 { 373 int reg; 374 375 reg = phy_read(phydev, XWAY_MDIO_ISTAT); 376 return (reg < 0) ? reg : 0; 377 } 378 379 static int xway_gphy_config_intr(struct phy_device *phydev) 380 { 381 u16 mask = 0; 382 int err; 383 384 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 385 err = xway_gphy_ack_interrupt(phydev); 386 if (err) 387 return err; 388 389 mask = XWAY_MDIO_INIT_MASK; 390 err = phy_write(phydev, XWAY_MDIO_IMASK, mask); 391 } else { 392 err = phy_write(phydev, XWAY_MDIO_IMASK, mask); 393 if (err) 394 return err; 395 396 err = xway_gphy_ack_interrupt(phydev); 397 } 398 399 return err; 400 } 401 402 static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev) 403 { 404 int irq_status; 405 406 irq_status = phy_read(phydev, XWAY_MDIO_ISTAT); 407 if (irq_status < 0) { 408 phy_error(phydev); 409 return IRQ_NONE; 410 } 411 412 if (!(irq_status & XWAY_MDIO_INIT_MASK)) 413 return IRQ_NONE; 414 415 phy_trigger_machine(phydev); 416 417 return IRQ_HANDLED; 418 } 419 420 static int xway_gphy_led_brightness_set(struct phy_device *phydev, 421 u8 index, enum led_brightness value) 422 { 423 int ret; 424 425 if (index >= XWAY_GPHY_MAX_LEDS) 426 return -EINVAL; 427 428 /* clear EN and set manual LED state */ 429 ret = phy_modify(phydev, XWAY_MDIO_LED, 430 ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) | 431 XWAY_GPHY_LED_DA(index), 432 (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index)); 433 if (ret) 434 return ret; 435 436 /* clear HW LED setup */ 437 if (value == LED_OFF) { 438 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0); 439 if (ret) 440 return ret; 441 442 return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0); 443 } else { 444 return 0; 445 } 446 } 447 448 static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | 449 BIT(TRIGGER_NETDEV_LINK_10) | 450 BIT(TRIGGER_NETDEV_LINK_100) | 451 BIT(TRIGGER_NETDEV_LINK_1000) | 452 BIT(TRIGGER_NETDEV_RX) | 453 BIT(TRIGGER_NETDEV_TX)); 454 455 static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index, 456 unsigned long rules) 457 { 458 if (index >= XWAY_GPHY_MAX_LEDS) 459 return -EINVAL; 460 461 /* activity triggers are not possible without combination with a link 462 * trigger. 463 */ 464 if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) && 465 !(rules & (BIT(TRIGGER_NETDEV_LINK) | 466 BIT(TRIGGER_NETDEV_LINK_10) | 467 BIT(TRIGGER_NETDEV_LINK_100) | 468 BIT(TRIGGER_NETDEV_LINK_1000)))) 469 return -EOPNOTSUPP; 470 471 /* All other combinations of the supported triggers are allowed */ 472 if (rules & ~supported_triggers) 473 return -EOPNOTSUPP; 474 475 return 0; 476 } 477 478 static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index, 479 unsigned long *rules) 480 { 481 int lval, hval; 482 483 if (index >= XWAY_GPHY_MAX_LEDS) 484 return -EINVAL; 485 486 hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index)); 487 if (hval < 0) 488 return hval; 489 490 lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index)); 491 if (lval < 0) 492 return lval; 493 494 if (hval & XWAY_MMD_LEDxH_CON_LINK10) 495 *rules |= BIT(TRIGGER_NETDEV_LINK_10); 496 497 if (hval & XWAY_MMD_LEDxH_CON_LINK100) 498 *rules |= BIT(TRIGGER_NETDEV_LINK_100); 499 500 if (hval & XWAY_MMD_LEDxH_CON_LINK1000) 501 *rules |= BIT(TRIGGER_NETDEV_LINK_1000); 502 503 if ((hval & XWAY_MMD_LEDxH_CON_LINK10) && 504 (hval & XWAY_MMD_LEDxH_CON_LINK100) && 505 (hval & XWAY_MMD_LEDxH_CON_LINK1000)) 506 *rules |= BIT(TRIGGER_NETDEV_LINK); 507 508 if (lval & XWAY_MMD_LEDxL_PULSE_TXACT) 509 *rules |= BIT(TRIGGER_NETDEV_TX); 510 511 if (lval & XWAY_MMD_LEDxL_PULSE_RXACT) 512 *rules |= BIT(TRIGGER_NETDEV_RX); 513 514 return 0; 515 } 516 517 static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index, 518 unsigned long rules) 519 { 520 u16 hval = 0, lval = 0; 521 int ret; 522 523 if (index >= XWAY_GPHY_MAX_LEDS) 524 return -EINVAL; 525 526 if (rules & BIT(TRIGGER_NETDEV_LINK) || 527 rules & BIT(TRIGGER_NETDEV_LINK_10)) 528 hval |= XWAY_MMD_LEDxH_CON_LINK10; 529 530 if (rules & BIT(TRIGGER_NETDEV_LINK) || 531 rules & BIT(TRIGGER_NETDEV_LINK_100)) 532 hval |= XWAY_MMD_LEDxH_CON_LINK100; 533 534 if (rules & BIT(TRIGGER_NETDEV_LINK) || 535 rules & BIT(TRIGGER_NETDEV_LINK_1000)) 536 hval |= XWAY_MMD_LEDxH_CON_LINK1000; 537 538 if (rules & BIT(TRIGGER_NETDEV_TX)) 539 lval |= XWAY_MMD_LEDxL_PULSE_TXACT; 540 541 if (rules & BIT(TRIGGER_NETDEV_RX)) 542 lval |= XWAY_MMD_LEDxL_PULSE_RXACT; 543 544 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval); 545 if (ret) 546 return ret; 547 548 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval); 549 if (ret) 550 return ret; 551 552 return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index)); 553 } 554 555 static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index, 556 unsigned long modes) 557 { 558 bool force_active_low = false, force_active_high = false; 559 u32 mode; 560 561 if (index >= XWAY_GPHY_MAX_LEDS) 562 return -EINVAL; 563 564 for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { 565 switch (mode) { 566 case PHY_LED_ACTIVE_LOW: 567 force_active_low = true; 568 break; 569 case PHY_LED_ACTIVE_HIGH: 570 force_active_high = true; 571 break; 572 default: 573 return -EINVAL; 574 } 575 } 576 577 if (force_active_low) 578 return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); 579 580 if (force_active_high) 581 return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); 582 583 return -EINVAL; 584 } 585 586 static int xway_gphy_update_stats(struct phy_device *phydev) 587 { 588 struct xway_gphy_priv *priv = phydev->priv; 589 int ret; 590 591 /* XWAY_MDIO_ERRCNT: 8-bit read-clear counter, SEL set to RXERR */ 592 ret = phy_read(phydev, XWAY_MDIO_ERRCNT); 593 if (ret < 0) 594 return ret; 595 596 priv->rx_errors += FIELD_GET(XWAY_MDIO_ERRCNT_COUNT, ret); 597 598 return 0; 599 } 600 601 static void xway_gphy_get_phy_stats(struct phy_device *phydev, 602 struct ethtool_eth_phy_stats *eth_stats, 603 struct ethtool_phy_stats *stats) 604 { 605 struct xway_gphy_priv *priv = phydev->priv; 606 607 eth_stats->SymbolErrorDuringCarrier = priv->rx_errors; 608 stats->rx_errors = priv->rx_errors; 609 } 610 611 static struct phy_driver xway_gphy[] = { 612 { 613 .phy_id = PHY_ID_PHY11G_1_3, 614 .phy_id_mask = 0xffffffff, 615 .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.3", 616 /* PHY_GBIT_FEATURES */ 617 .config_init = xway_gphy_config_init, 618 .probe = xway_gphy_probe, 619 .config_aneg = xway_gphy14_config_aneg, 620 .handle_interrupt = xway_gphy_handle_interrupt, 621 .config_intr = xway_gphy_config_intr, 622 .suspend = genphy_suspend, 623 .resume = genphy_resume, 624 .led_brightness_set = xway_gphy_led_brightness_set, 625 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 626 .led_hw_control_get = xway_gphy_led_hw_control_get, 627 .led_hw_control_set = xway_gphy_led_hw_control_set, 628 .led_polarity_set = xway_gphy_led_polarity_set, 629 .update_stats = xway_gphy_update_stats, 630 .get_phy_stats = xway_gphy_get_phy_stats, 631 }, { 632 .phy_id = PHY_ID_PHY22F_1_3, 633 .phy_id_mask = 0xffffffff, 634 .name = "Intel XWAY PHY22F (PEF 7061) v1.3", 635 /* PHY_BASIC_FEATURES */ 636 .config_init = xway_gphy_config_init, 637 .probe = xway_gphy_probe, 638 .config_aneg = xway_gphy14_config_aneg, 639 .handle_interrupt = xway_gphy_handle_interrupt, 640 .config_intr = xway_gphy_config_intr, 641 .suspend = genphy_suspend, 642 .resume = genphy_resume, 643 .led_brightness_set = xway_gphy_led_brightness_set, 644 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 645 .led_hw_control_get = xway_gphy_led_hw_control_get, 646 .led_hw_control_set = xway_gphy_led_hw_control_set, 647 .led_polarity_set = xway_gphy_led_polarity_set, 648 .update_stats = xway_gphy_update_stats, 649 .get_phy_stats = xway_gphy_get_phy_stats, 650 }, { 651 .phy_id = PHY_ID_PHY11G_1_4, 652 .phy_id_mask = 0xffffffff, 653 .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.4", 654 /* PHY_GBIT_FEATURES */ 655 .config_init = xway_gphy_config_init, 656 .probe = xway_gphy_probe, 657 .config_aneg = xway_gphy14_config_aneg, 658 .handle_interrupt = xway_gphy_handle_interrupt, 659 .config_intr = xway_gphy_config_intr, 660 .suspend = genphy_suspend, 661 .resume = genphy_resume, 662 .led_brightness_set = xway_gphy_led_brightness_set, 663 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 664 .led_hw_control_get = xway_gphy_led_hw_control_get, 665 .led_hw_control_set = xway_gphy_led_hw_control_set, 666 .led_polarity_set = xway_gphy_led_polarity_set, 667 .update_stats = xway_gphy_update_stats, 668 .get_phy_stats = xway_gphy_get_phy_stats, 669 }, { 670 .phy_id = PHY_ID_PHY22F_1_4, 671 .phy_id_mask = 0xffffffff, 672 .name = "Intel XWAY PHY22F (PEF 7061) v1.4", 673 /* PHY_BASIC_FEATURES */ 674 .config_init = xway_gphy_config_init, 675 .probe = xway_gphy_probe, 676 .config_aneg = xway_gphy14_config_aneg, 677 .handle_interrupt = xway_gphy_handle_interrupt, 678 .config_intr = xway_gphy_config_intr, 679 .suspend = genphy_suspend, 680 .resume = genphy_resume, 681 .led_brightness_set = xway_gphy_led_brightness_set, 682 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 683 .led_hw_control_get = xway_gphy_led_hw_control_get, 684 .led_hw_control_set = xway_gphy_led_hw_control_set, 685 .led_polarity_set = xway_gphy_led_polarity_set, 686 .update_stats = xway_gphy_update_stats, 687 .get_phy_stats = xway_gphy_get_phy_stats, 688 }, { 689 .phy_id = PHY_ID_PHY11G_1_5, 690 .phy_id_mask = 0xffffffff, 691 .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6", 692 /* PHY_GBIT_FEATURES */ 693 .config_init = xway_gphy_config_init, 694 .probe = xway_gphy_probe, 695 .handle_interrupt = xway_gphy_handle_interrupt, 696 .config_intr = xway_gphy_config_intr, 697 .suspend = genphy_suspend, 698 .resume = genphy_resume, 699 .led_brightness_set = xway_gphy_led_brightness_set, 700 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 701 .led_hw_control_get = xway_gphy_led_hw_control_get, 702 .led_hw_control_set = xway_gphy_led_hw_control_set, 703 .led_polarity_set = xway_gphy_led_polarity_set, 704 .update_stats = xway_gphy_update_stats, 705 .get_phy_stats = xway_gphy_get_phy_stats, 706 }, { 707 .phy_id = PHY_ID_PHY22F_1_5, 708 .phy_id_mask = 0xffffffff, 709 .name = "Intel XWAY PHY22F (PEF 7061) v1.5 / v1.6", 710 /* PHY_BASIC_FEATURES */ 711 .config_init = xway_gphy_config_init, 712 .probe = xway_gphy_probe, 713 .handle_interrupt = xway_gphy_handle_interrupt, 714 .config_intr = xway_gphy_config_intr, 715 .suspend = genphy_suspend, 716 .resume = genphy_resume, 717 .led_brightness_set = xway_gphy_led_brightness_set, 718 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 719 .led_hw_control_get = xway_gphy_led_hw_control_get, 720 .led_hw_control_set = xway_gphy_led_hw_control_set, 721 .led_polarity_set = xway_gphy_led_polarity_set, 722 .update_stats = xway_gphy_update_stats, 723 .get_phy_stats = xway_gphy_get_phy_stats, 724 }, { 725 .phy_id = PHY_ID_PHY11G_VR9_1_1, 726 .phy_id_mask = 0xffffffff, 727 .name = "Intel XWAY PHY11G (xRX v1.1 integrated)", 728 /* PHY_GBIT_FEATURES */ 729 .config_init = xway_gphy_config_init, 730 .probe = xway_gphy_probe, 731 .handle_interrupt = xway_gphy_handle_interrupt, 732 .config_intr = xway_gphy_config_intr, 733 .suspend = genphy_suspend, 734 .resume = genphy_resume, 735 .led_brightness_set = xway_gphy_led_brightness_set, 736 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 737 .led_hw_control_get = xway_gphy_led_hw_control_get, 738 .led_hw_control_set = xway_gphy_led_hw_control_set, 739 .led_polarity_set = xway_gphy_led_polarity_set, 740 .update_stats = xway_gphy_update_stats, 741 .get_phy_stats = xway_gphy_get_phy_stats, 742 }, { 743 .phy_id = PHY_ID_PHY22F_VR9_1_1, 744 .phy_id_mask = 0xffffffff, 745 .name = "Intel XWAY PHY22F (xRX v1.1 integrated)", 746 /* PHY_BASIC_FEATURES */ 747 .config_init = xway_gphy_config_init, 748 .probe = xway_gphy_probe, 749 .handle_interrupt = xway_gphy_handle_interrupt, 750 .config_intr = xway_gphy_config_intr, 751 .suspend = genphy_suspend, 752 .resume = genphy_resume, 753 .led_brightness_set = xway_gphy_led_brightness_set, 754 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 755 .led_hw_control_get = xway_gphy_led_hw_control_get, 756 .led_hw_control_set = xway_gphy_led_hw_control_set, 757 .led_polarity_set = xway_gphy_led_polarity_set, 758 .update_stats = xway_gphy_update_stats, 759 .get_phy_stats = xway_gphy_get_phy_stats, 760 }, { 761 .phy_id = PHY_ID_PHY11G_VR9_1_2, 762 .phy_id_mask = 0xffffffff, 763 .name = "Intel XWAY PHY11G (xRX v1.2 integrated)", 764 /* PHY_GBIT_FEATURES */ 765 .config_init = xway_11g_int_config_init, 766 .probe = xway_gphy_probe, 767 .handle_interrupt = xway_gphy_handle_interrupt, 768 .config_intr = xway_gphy_config_intr, 769 .suspend = genphy_suspend, 770 .resume = genphy_resume, 771 .led_brightness_set = xway_gphy_led_brightness_set, 772 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 773 .led_hw_control_get = xway_gphy_led_hw_control_get, 774 .led_hw_control_set = xway_gphy_led_hw_control_set, 775 .led_polarity_set = xway_gphy_led_polarity_set, 776 .update_stats = xway_gphy_update_stats, 777 .get_phy_stats = xway_gphy_get_phy_stats, 778 }, { 779 .phy_id = PHY_ID_PHY22F_VR9_1_2, 780 .phy_id_mask = 0xffffffff, 781 .name = "Intel XWAY PHY22F (xRX v1.2 integrated)", 782 /* PHY_BASIC_FEATURES */ 783 .config_init = xway_gphy_config_init, 784 .probe = xway_gphy_probe, 785 .handle_interrupt = xway_gphy_handle_interrupt, 786 .config_intr = xway_gphy_config_intr, 787 .suspend = genphy_suspend, 788 .resume = genphy_resume, 789 .led_brightness_set = xway_gphy_led_brightness_set, 790 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 791 .led_hw_control_get = xway_gphy_led_hw_control_get, 792 .led_hw_control_set = xway_gphy_led_hw_control_set, 793 .led_polarity_set = xway_gphy_led_polarity_set, 794 .update_stats = xway_gphy_update_stats, 795 .get_phy_stats = xway_gphy_get_phy_stats, 796 }, 797 }; 798 module_phy_driver(xway_gphy); 799 800 static const struct mdio_device_id __maybe_unused xway_gphy_tbl[] = { 801 { PHY_ID_PHY11G_1_3, 0xffffffff }, 802 { PHY_ID_PHY22F_1_3, 0xffffffff }, 803 { PHY_ID_PHY11G_1_4, 0xffffffff }, 804 { PHY_ID_PHY22F_1_4, 0xffffffff }, 805 { PHY_ID_PHY11G_1_5, 0xffffffff }, 806 { PHY_ID_PHY22F_1_5, 0xffffffff }, 807 { PHY_ID_PHY11G_VR9_1_1, 0xffffffff }, 808 { PHY_ID_PHY22F_VR9_1_1, 0xffffffff }, 809 { PHY_ID_PHY11G_VR9_1_2, 0xffffffff }, 810 { PHY_ID_PHY22F_VR9_1_2, 0xffffffff }, 811 { } 812 }; 813 MODULE_DEVICE_TABLE(mdio, xway_gphy_tbl); 814 815 MODULE_DESCRIPTION("Intel XWAY PHY driver"); 816 MODULE_LICENSE("GPL"); 817