0001
0002
0003
0004
0005
0006
0007 #include <linux/mdio.h>
0008 #include <linux/module.h>
0009 #include <linux/phy.h>
0010 #include <linux/of.h>
0011 #include <linux/bitfield.h>
0012
0013 #define XWAY_MDIO_MIICTRL 0x17
0014 #define XWAY_MDIO_IMASK 0x19
0015 #define XWAY_MDIO_ISTAT 0x1A
0016 #define XWAY_MDIO_LED 0x1B
0017
0018 #define XWAY_MDIO_MIICTRL_RXSKEW_MASK GENMASK(14, 12)
0019 #define XWAY_MDIO_MIICTRL_TXSKEW_MASK GENMASK(10, 8)
0020
0021
0022 #define XWAY_MDIO_LED_LED3_EN BIT(11)
0023 #define XWAY_MDIO_LED_LED2_EN BIT(10)
0024 #define XWAY_MDIO_LED_LED1_EN BIT(9)
0025 #define XWAY_MDIO_LED_LED0_EN BIT(8)
0026
0027 #define XWAY_MDIO_LED_LED3_DA BIT(3)
0028 #define XWAY_MDIO_LED_LED2_DA BIT(2)
0029 #define XWAY_MDIO_LED_LED1_DA BIT(1)
0030 #define XWAY_MDIO_LED_LED0_DA BIT(0)
0031
0032 #define XWAY_MDIO_INIT_WOL BIT(15)
0033 #define XWAY_MDIO_INIT_MSRE BIT(14)
0034 #define XWAY_MDIO_INIT_NPRX BIT(13)
0035 #define XWAY_MDIO_INIT_NPTX BIT(12)
0036 #define XWAY_MDIO_INIT_ANE BIT(11)
0037 #define XWAY_MDIO_INIT_ANC BIT(10)
0038 #define XWAY_MDIO_INIT_ADSC BIT(5)
0039 #define XWAY_MDIO_INIT_MPIPC BIT(4)
0040 #define XWAY_MDIO_INIT_MDIXC BIT(3)
0041 #define XWAY_MDIO_INIT_DXMC BIT(2)
0042 #define XWAY_MDIO_INIT_LSPC BIT(1)
0043 #define XWAY_MDIO_INIT_LSTC BIT(0)
0044 #define XWAY_MDIO_INIT_MASK (XWAY_MDIO_INIT_LSTC | \
0045 XWAY_MDIO_INIT_ADSC)
0046
0047 #define ADVERTISED_MPD BIT(10)
0048
0049
0050 #define XWAY_MMD_LEDCH 0x01E0
0051
0052 #define XWAY_MMD_LEDCH_NACS_NONE 0x0000
0053 #define XWAY_MMD_LEDCH_NACS_LINK 0x0001
0054 #define XWAY_MMD_LEDCH_NACS_PDOWN 0x0002
0055 #define XWAY_MMD_LEDCH_NACS_EEE 0x0003
0056 #define XWAY_MMD_LEDCH_NACS_ANEG 0x0004
0057 #define XWAY_MMD_LEDCH_NACS_ABIST 0x0005
0058 #define XWAY_MMD_LEDCH_NACS_CDIAG 0x0006
0059 #define XWAY_MMD_LEDCH_NACS_TEST 0x0007
0060
0061 #define XWAY_MMD_LEDCH_SBF_F02HZ 0x0000
0062 #define XWAY_MMD_LEDCH_SBF_F04HZ 0x0010
0063 #define XWAY_MMD_LEDCH_SBF_F08HZ 0x0020
0064 #define XWAY_MMD_LEDCH_SBF_F16HZ 0x0030
0065
0066 #define XWAY_MMD_LEDCH_FBF_F02HZ 0x0000
0067 #define XWAY_MMD_LEDCH_FBF_F04HZ 0x0040
0068 #define XWAY_MMD_LEDCH_FBF_F08HZ 0x0080
0069 #define XWAY_MMD_LEDCH_FBF_F16HZ 0x00C0
0070
0071 #define XWAY_MMD_LEDCL 0x01E1
0072
0073 #define XWAY_MMD_LEDCH_CBLINK_NONE 0x0000
0074 #define XWAY_MMD_LEDCH_CBLINK_LINK 0x0001
0075 #define XWAY_MMD_LEDCH_CBLINK_PDOWN 0x0002
0076 #define XWAY_MMD_LEDCH_CBLINK_EEE 0x0003
0077 #define XWAY_MMD_LEDCH_CBLINK_ANEG 0x0004
0078 #define XWAY_MMD_LEDCH_CBLINK_ABIST 0x0005
0079 #define XWAY_MMD_LEDCH_CBLINK_CDIAG 0x0006
0080 #define XWAY_MMD_LEDCH_CBLINK_TEST 0x0007
0081
0082 #define XWAY_MMD_LEDCH_SCAN_NONE 0x0000
0083 #define XWAY_MMD_LEDCH_SCAN_LINK 0x0010
0084 #define XWAY_MMD_LEDCH_SCAN_PDOWN 0x0020
0085 #define XWAY_MMD_LEDCH_SCAN_EEE 0x0030
0086 #define XWAY_MMD_LEDCH_SCAN_ANEG 0x0040
0087 #define XWAY_MMD_LEDCH_SCAN_ABIST 0x0050
0088 #define XWAY_MMD_LEDCH_SCAN_CDIAG 0x0060
0089 #define XWAY_MMD_LEDCH_SCAN_TEST 0x0070
0090
0091 #define XWAY_MMD_LED0H 0x01E2
0092
0093 #define XWAY_MMD_LEDxH_BLINKF_MASK 0x000F
0094 #define XWAY_MMD_LEDxH_BLINKF_NONE 0x0000
0095 #define XWAY_MMD_LEDxH_BLINKF_LINK10 0x0001
0096 #define XWAY_MMD_LEDxH_BLINKF_LINK100 0x0002
0097 #define XWAY_MMD_LEDxH_BLINKF_LINK10X 0x0003
0098 #define XWAY_MMD_LEDxH_BLINKF_LINK1000 0x0004
0099 #define XWAY_MMD_LEDxH_BLINKF_LINK10_0 0x0005
0100 #define XWAY_MMD_LEDxH_BLINKF_LINK100X 0x0006
0101 #define XWAY_MMD_LEDxH_BLINKF_LINK10XX 0x0007
0102 #define XWAY_MMD_LEDxH_BLINKF_PDOWN 0x0008
0103 #define XWAY_MMD_LEDxH_BLINKF_EEE 0x0009
0104 #define XWAY_MMD_LEDxH_BLINKF_ANEG 0x000A
0105 #define XWAY_MMD_LEDxH_BLINKF_ABIST 0x000B
0106 #define XWAY_MMD_LEDxH_BLINKF_CDIAG 0x000C
0107
0108 #define XWAY_MMD_LEDxH_CON_MASK 0x00F0
0109 #define XWAY_MMD_LEDxH_CON_NONE 0x0000
0110 #define XWAY_MMD_LEDxH_CON_LINK10 0x0010
0111 #define XWAY_MMD_LEDxH_CON_LINK100 0x0020
0112 #define XWAY_MMD_LEDxH_CON_LINK10X 0x0030
0113 #define XWAY_MMD_LEDxH_CON_LINK1000 0x0040
0114 #define XWAY_MMD_LEDxH_CON_LINK10_0 0x0050
0115 #define XWAY_MMD_LEDxH_CON_LINK100X 0x0060
0116 #define XWAY_MMD_LEDxH_CON_LINK10XX 0x0070
0117 #define XWAY_MMD_LEDxH_CON_PDOWN 0x0080
0118 #define XWAY_MMD_LEDxH_CON_EEE 0x0090
0119 #define XWAY_MMD_LEDxH_CON_ANEG 0x00A0
0120 #define XWAY_MMD_LEDxH_CON_ABIST 0x00B0
0121 #define XWAY_MMD_LEDxH_CON_CDIAG 0x00C0
0122 #define XWAY_MMD_LEDxH_CON_COPPER 0x00D0
0123 #define XWAY_MMD_LEDxH_CON_FIBER 0x00E0
0124
0125 #define XWAY_MMD_LED0L 0x01E3
0126
0127 #define XWAY_MMD_LEDxL_PULSE_MASK 0x000F
0128 #define XWAY_MMD_LEDxL_PULSE_NONE 0x0000
0129 #define XWAY_MMD_LEDxL_PULSE_TXACT 0x0001
0130 #define XWAY_MMD_LEDxL_PULSE_RXACT 0x0002
0131 #define XWAY_MMD_LEDxL_PULSE_COL 0x0004
0132
0133 #define XWAY_MMD_LEDxL_BLINKS_MASK 0x00F0
0134 #define XWAY_MMD_LEDxL_BLINKS_NONE 0x0000
0135 #define XWAY_MMD_LEDxL_BLINKS_LINK10 0x0010
0136 #define XWAY_MMD_LEDxL_BLINKS_LINK100 0x0020
0137 #define XWAY_MMD_LEDxL_BLINKS_LINK10X 0x0030
0138 #define XWAY_MMD_LEDxL_BLINKS_LINK1000 0x0040
0139 #define XWAY_MMD_LEDxL_BLINKS_LINK10_0 0x0050
0140 #define XWAY_MMD_LEDxL_BLINKS_LINK100X 0x0060
0141 #define XWAY_MMD_LEDxL_BLINKS_LINK10XX 0x0070
0142 #define XWAY_MMD_LEDxL_BLINKS_PDOWN 0x0080
0143 #define XWAY_MMD_LEDxL_BLINKS_EEE 0x0090
0144 #define XWAY_MMD_LEDxL_BLINKS_ANEG 0x00A0
0145 #define XWAY_MMD_LEDxL_BLINKS_ABIST 0x00B0
0146 #define XWAY_MMD_LEDxL_BLINKS_CDIAG 0x00C0
0147 #define XWAY_MMD_LED1H 0x01E4
0148 #define XWAY_MMD_LED1L 0x01E5
0149 #define XWAY_MMD_LED2H 0x01E6
0150 #define XWAY_MMD_LED2L 0x01E7
0151 #define XWAY_MMD_LED3H 0x01E8
0152 #define XWAY_MMD_LED3L 0x01E9
0153
0154 #define PHY_ID_PHY11G_1_3 0x030260D1
0155 #define PHY_ID_PHY22F_1_3 0x030260E1
0156 #define PHY_ID_PHY11G_1_4 0xD565A400
0157 #define PHY_ID_PHY22F_1_4 0xD565A410
0158 #define PHY_ID_PHY11G_1_5 0xD565A401
0159 #define PHY_ID_PHY22F_1_5 0xD565A411
0160 #define PHY_ID_PHY11G_VR9_1_1 0xD565A408
0161 #define PHY_ID_PHY22F_VR9_1_1 0xD565A418
0162 #define PHY_ID_PHY11G_VR9_1_2 0xD565A409
0163 #define PHY_ID_PHY22F_VR9_1_2 0xD565A419
0164
0165 static const int xway_internal_delay[] = {0, 500, 1000, 1500, 2000, 2500,
0166 3000, 3500};
0167
0168 static int xway_gphy_rgmii_init(struct phy_device *phydev)
0169 {
0170 struct device *dev = &phydev->mdio.dev;
0171 unsigned int delay_size = ARRAY_SIZE(xway_internal_delay);
0172 s32 int_delay;
0173 int val = 0;
0174
0175 if (!phy_interface_is_rgmii(phydev))
0176 return 0;
0177
0178
0179
0180
0181
0182 if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
0183 u16 txskew, rxskew;
0184
0185 val = phy_read(phydev, XWAY_MDIO_MIICTRL);
0186 if (val < 0)
0187 return val;
0188
0189 txskew = FIELD_GET(XWAY_MDIO_MIICTRL_TXSKEW_MASK, val);
0190 rxskew = FIELD_GET(XWAY_MDIO_MIICTRL_RXSKEW_MASK, val);
0191
0192 if (txskew > 0 || rxskew > 0)
0193 phydev_warn(phydev,
0194 "PHY has delays (e.g. via pin strapping), but phy-mode = 'rgmii'\n"
0195 "Should be 'rgmii-id' to use internal delays txskew:%d ps rxskew:%d ps\n",
0196 xway_internal_delay[txskew],
0197 xway_internal_delay[rxskew]);
0198 return 0;
0199 }
0200
0201 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
0202 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
0203 int_delay = phy_get_internal_delay(phydev, dev,
0204 xway_internal_delay,
0205 delay_size, true);
0206
0207
0208 if (int_delay < 0)
0209 int_delay = 4;
0210
0211 val |= FIELD_PREP(XWAY_MDIO_MIICTRL_RXSKEW_MASK, int_delay);
0212 }
0213
0214 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
0215 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
0216 int_delay = phy_get_internal_delay(phydev, dev,
0217 xway_internal_delay,
0218 delay_size, false);
0219
0220
0221 if (int_delay < 0)
0222 int_delay = 4;
0223
0224 val |= FIELD_PREP(XWAY_MDIO_MIICTRL_TXSKEW_MASK, int_delay);
0225 }
0226
0227 return phy_modify(phydev, XWAY_MDIO_MIICTRL,
0228 XWAY_MDIO_MIICTRL_RXSKEW_MASK |
0229 XWAY_MDIO_MIICTRL_TXSKEW_MASK, val);
0230 }
0231
0232 static int xway_gphy_config_init(struct phy_device *phydev)
0233 {
0234 int err;
0235 u32 ledxh;
0236 u32 ledxl;
0237
0238
0239 err = phy_write(phydev, XWAY_MDIO_IMASK, 0);
0240 if (err)
0241 return err;
0242
0243
0244 phy_read(phydev, XWAY_MDIO_ISTAT);
0245
0246
0247 err = phy_write(phydev, XWAY_MDIO_LED,
0248 XWAY_MDIO_LED_LED0_EN |
0249 XWAY_MDIO_LED_LED1_EN |
0250 XWAY_MDIO_LED_LED2_EN |
0251 XWAY_MDIO_LED_LED3_EN);
0252 if (err)
0253 return err;
0254
0255 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCH,
0256 XWAY_MMD_LEDCH_NACS_NONE |
0257 XWAY_MMD_LEDCH_SBF_F02HZ |
0258 XWAY_MMD_LEDCH_FBF_F16HZ);
0259 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCL,
0260 XWAY_MMD_LEDCH_CBLINK_NONE |
0261 XWAY_MMD_LEDCH_SCAN_NONE);
0262
0263
0264
0265
0266
0267
0268
0269 ledxh = XWAY_MMD_LEDxH_BLINKF_NONE | XWAY_MMD_LEDxH_CON_LINK10XX;
0270 ledxl = XWAY_MMD_LEDxL_PULSE_TXACT | XWAY_MMD_LEDxL_PULSE_RXACT |
0271 XWAY_MMD_LEDxL_BLINKS_NONE;
0272 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0H, ledxh);
0273 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0L, ledxl);
0274 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1H, ledxh);
0275 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1L, ledxl);
0276 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh);
0277 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl);
0278
0279 err = xway_gphy_rgmii_init(phydev);
0280 if (err)
0281 return err;
0282
0283 return 0;
0284 }
0285
0286 static int xway_gphy14_config_aneg(struct phy_device *phydev)
0287 {
0288 int reg, err;
0289
0290
0291
0292 reg = phy_read(phydev, MII_CTRL1000);
0293 reg |= ADVERTISED_MPD;
0294 err = phy_write(phydev, MII_CTRL1000, reg);
0295 if (err)
0296 return err;
0297
0298 return genphy_config_aneg(phydev);
0299 }
0300
0301 static int xway_gphy_ack_interrupt(struct phy_device *phydev)
0302 {
0303 int reg;
0304
0305 reg = phy_read(phydev, XWAY_MDIO_ISTAT);
0306 return (reg < 0) ? reg : 0;
0307 }
0308
0309 static int xway_gphy_config_intr(struct phy_device *phydev)
0310 {
0311 u16 mask = 0;
0312 int err;
0313
0314 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0315 err = xway_gphy_ack_interrupt(phydev);
0316 if (err)
0317 return err;
0318
0319 mask = XWAY_MDIO_INIT_MASK;
0320 err = phy_write(phydev, XWAY_MDIO_IMASK, mask);
0321 } else {
0322 err = phy_write(phydev, XWAY_MDIO_IMASK, mask);
0323 if (err)
0324 return err;
0325
0326 err = xway_gphy_ack_interrupt(phydev);
0327 }
0328
0329 return err;
0330 }
0331
0332 static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev)
0333 {
0334 int irq_status;
0335
0336 irq_status = phy_read(phydev, XWAY_MDIO_ISTAT);
0337 if (irq_status < 0) {
0338 phy_error(phydev);
0339 return IRQ_NONE;
0340 }
0341
0342 if (!(irq_status & XWAY_MDIO_INIT_MASK))
0343 return IRQ_NONE;
0344
0345 phy_trigger_machine(phydev);
0346
0347 return IRQ_HANDLED;
0348 }
0349
0350 static struct phy_driver xway_gphy[] = {
0351 {
0352 .phy_id = PHY_ID_PHY11G_1_3,
0353 .phy_id_mask = 0xffffffff,
0354 .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.3",
0355
0356 .config_init = xway_gphy_config_init,
0357 .config_aneg = xway_gphy14_config_aneg,
0358 .handle_interrupt = xway_gphy_handle_interrupt,
0359 .config_intr = xway_gphy_config_intr,
0360 .suspend = genphy_suspend,
0361 .resume = genphy_resume,
0362 }, {
0363 .phy_id = PHY_ID_PHY22F_1_3,
0364 .phy_id_mask = 0xffffffff,
0365 .name = "Intel XWAY PHY22F (PEF 7061) v1.3",
0366
0367 .config_init = xway_gphy_config_init,
0368 .config_aneg = xway_gphy14_config_aneg,
0369 .handle_interrupt = xway_gphy_handle_interrupt,
0370 .config_intr = xway_gphy_config_intr,
0371 .suspend = genphy_suspend,
0372 .resume = genphy_resume,
0373 }, {
0374 .phy_id = PHY_ID_PHY11G_1_4,
0375 .phy_id_mask = 0xffffffff,
0376 .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.4",
0377
0378 .config_init = xway_gphy_config_init,
0379 .config_aneg = xway_gphy14_config_aneg,
0380 .handle_interrupt = xway_gphy_handle_interrupt,
0381 .config_intr = xway_gphy_config_intr,
0382 .suspend = genphy_suspend,
0383 .resume = genphy_resume,
0384 }, {
0385 .phy_id = PHY_ID_PHY22F_1_4,
0386 .phy_id_mask = 0xffffffff,
0387 .name = "Intel XWAY PHY22F (PEF 7061) v1.4",
0388
0389 .config_init = xway_gphy_config_init,
0390 .config_aneg = xway_gphy14_config_aneg,
0391 .handle_interrupt = xway_gphy_handle_interrupt,
0392 .config_intr = xway_gphy_config_intr,
0393 .suspend = genphy_suspend,
0394 .resume = genphy_resume,
0395 }, {
0396 .phy_id = PHY_ID_PHY11G_1_5,
0397 .phy_id_mask = 0xffffffff,
0398 .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6",
0399
0400 .config_init = xway_gphy_config_init,
0401 .handle_interrupt = xway_gphy_handle_interrupt,
0402 .config_intr = xway_gphy_config_intr,
0403 .suspend = genphy_suspend,
0404 .resume = genphy_resume,
0405 }, {
0406 .phy_id = PHY_ID_PHY22F_1_5,
0407 .phy_id_mask = 0xffffffff,
0408 .name = "Intel XWAY PHY22F (PEF 7061) v1.5 / v1.6",
0409
0410 .config_init = xway_gphy_config_init,
0411 .handle_interrupt = xway_gphy_handle_interrupt,
0412 .config_intr = xway_gphy_config_intr,
0413 .suspend = genphy_suspend,
0414 .resume = genphy_resume,
0415 }, {
0416 .phy_id = PHY_ID_PHY11G_VR9_1_1,
0417 .phy_id_mask = 0xffffffff,
0418 .name = "Intel XWAY PHY11G (xRX v1.1 integrated)",
0419
0420 .config_init = xway_gphy_config_init,
0421 .handle_interrupt = xway_gphy_handle_interrupt,
0422 .config_intr = xway_gphy_config_intr,
0423 .suspend = genphy_suspend,
0424 .resume = genphy_resume,
0425 }, {
0426 .phy_id = PHY_ID_PHY22F_VR9_1_1,
0427 .phy_id_mask = 0xffffffff,
0428 .name = "Intel XWAY PHY22F (xRX v1.1 integrated)",
0429
0430 .config_init = xway_gphy_config_init,
0431 .handle_interrupt = xway_gphy_handle_interrupt,
0432 .config_intr = xway_gphy_config_intr,
0433 .suspend = genphy_suspend,
0434 .resume = genphy_resume,
0435 }, {
0436 .phy_id = PHY_ID_PHY11G_VR9_1_2,
0437 .phy_id_mask = 0xffffffff,
0438 .name = "Intel XWAY PHY11G (xRX v1.2 integrated)",
0439
0440 .config_init = xway_gphy_config_init,
0441 .handle_interrupt = xway_gphy_handle_interrupt,
0442 .config_intr = xway_gphy_config_intr,
0443 .suspend = genphy_suspend,
0444 .resume = genphy_resume,
0445 }, {
0446 .phy_id = PHY_ID_PHY22F_VR9_1_2,
0447 .phy_id_mask = 0xffffffff,
0448 .name = "Intel XWAY PHY22F (xRX v1.2 integrated)",
0449
0450 .config_init = xway_gphy_config_init,
0451 .handle_interrupt = xway_gphy_handle_interrupt,
0452 .config_intr = xway_gphy_config_intr,
0453 .suspend = genphy_suspend,
0454 .resume = genphy_resume,
0455 },
0456 };
0457 module_phy_driver(xway_gphy);
0458
0459 static struct mdio_device_id __maybe_unused xway_gphy_tbl[] = {
0460 { PHY_ID_PHY11G_1_3, 0xffffffff },
0461 { PHY_ID_PHY22F_1_3, 0xffffffff },
0462 { PHY_ID_PHY11G_1_4, 0xffffffff },
0463 { PHY_ID_PHY22F_1_4, 0xffffffff },
0464 { PHY_ID_PHY11G_1_5, 0xffffffff },
0465 { PHY_ID_PHY22F_1_5, 0xffffffff },
0466 { PHY_ID_PHY11G_VR9_1_1, 0xffffffff },
0467 { PHY_ID_PHY22F_VR9_1_1, 0xffffffff },
0468 { PHY_ID_PHY11G_VR9_1_2, 0xffffffff },
0469 { PHY_ID_PHY22F_VR9_1_2, 0xffffffff },
0470 { }
0471 };
0472 MODULE_DEVICE_TABLE(mdio, xway_gphy_tbl);
0473
0474 MODULE_DESCRIPTION("Intel XWAY PHY driver");
0475 MODULE_LICENSE("GPL");