Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (C) 2018 Microchip Technology
0003 
0004 #include <linux/kernel.h>
0005 #include <linux/module.h>
0006 #include <linux/delay.h>
0007 #include <linux/mii.h>
0008 #include <linux/phy.h>
0009 #include <linux/ethtool.h>
0010 #include <linux/ethtool_netlink.h>
0011 #include <linux/bitfield.h>
0012 
0013 #define PHY_ID_LAN87XX              0x0007c150
0014 #define PHY_ID_LAN937X              0x0007c180
0015 
0016 /* External Register Control Register */
0017 #define LAN87XX_EXT_REG_CTL                     (0x14)
0018 #define LAN87XX_EXT_REG_CTL_RD_CTL              (0x1000)
0019 #define LAN87XX_EXT_REG_CTL_WR_CTL              (0x0800)
0020 #define LAN87XX_REG_BANK_SEL_MASK       GENMASK(10, 8)
0021 #define LAN87XX_REG_ADDR_MASK           GENMASK(7, 0)
0022 
0023 /* External Register Read Data Register */
0024 #define LAN87XX_EXT_REG_RD_DATA                 (0x15)
0025 
0026 /* External Register Write Data Register */
0027 #define LAN87XX_EXT_REG_WR_DATA                 (0x16)
0028 
0029 /* Interrupt Source Register */
0030 #define LAN87XX_INTERRUPT_SOURCE                (0x18)
0031 #define LAN87XX_INTERRUPT_SOURCE_2              (0x08)
0032 
0033 /* Interrupt Mask Register */
0034 #define LAN87XX_INTERRUPT_MASK                  (0x19)
0035 #define LAN87XX_MASK_LINK_UP                    (0x0004)
0036 #define LAN87XX_MASK_LINK_DOWN                  (0x0002)
0037 
0038 #define LAN87XX_INTERRUPT_MASK_2                (0x09)
0039 #define LAN87XX_MASK_COMM_RDY           BIT(10)
0040 
0041 /* MISC Control 1 Register */
0042 #define LAN87XX_CTRL_1                          (0x11)
0043 #define LAN87XX_MASK_RGMII_TXC_DLY_EN           (0x4000)
0044 #define LAN87XX_MASK_RGMII_RXC_DLY_EN           (0x2000)
0045 
0046 /* phyaccess nested types */
0047 #define PHYACC_ATTR_MODE_READ       0
0048 #define PHYACC_ATTR_MODE_WRITE      1
0049 #define PHYACC_ATTR_MODE_MODIFY     2
0050 #define PHYACC_ATTR_MODE_POLL       3
0051 
0052 #define PHYACC_ATTR_BANK_SMI        0
0053 #define PHYACC_ATTR_BANK_MISC       1
0054 #define PHYACC_ATTR_BANK_PCS        2
0055 #define PHYACC_ATTR_BANK_AFE        3
0056 #define PHYACC_ATTR_BANK_DSP        4
0057 #define PHYACC_ATTR_BANK_MAX        7
0058 
0059 /* measurement defines */
0060 #define LAN87XX_CABLE_TEST_OK       0
0061 #define LAN87XX_CABLE_TEST_OPEN 1
0062 #define LAN87XX_CABLE_TEST_SAME_SHORT   2
0063 
0064 /* T1 Registers */
0065 #define T1_AFE_PORT_CFG1_REG        0x0B
0066 #define T1_POWER_DOWN_CONTROL_REG   0x1A
0067 #define T1_SLV_FD_MULT_CFG_REG      0x18
0068 #define T1_CDR_CFG_PRE_LOCK_REG     0x05
0069 #define T1_CDR_CFG_POST_LOCK_REG    0x06
0070 #define T1_LCK_STG2_MUFACT_CFG_REG  0x1A
0071 #define T1_LCK_STG3_MUFACT_CFG_REG  0x1B
0072 #define T1_POST_LCK_MUFACT_CFG_REG  0x1C
0073 #define T1_TX_RX_FIFO_CFG_REG       0x02
0074 #define T1_TX_LPF_FIR_CFG_REG       0x55
0075 #define T1_COEF_CLK_PWR_DN_CFG      0x04
0076 #define T1_COEF_RW_CTL_CFG      0x0D
0077 #define T1_SQI_CONFIG_REG       0x2E
0078 #define T1_SQI_CONFIG2_REG      0x4A
0079 #define T1_DCQ_SQI_REG          0xC3
0080 #define T1_DCQ_SQI_MSK          GENMASK(3, 1)
0081 #define T1_MDIO_CONTROL2_REG        0x10
0082 #define T1_INTERRUPT_SOURCE_REG     0x18
0083 #define T1_INTERRUPT2_SOURCE_REG    0x08
0084 #define T1_EQ_FD_STG1_FRZ_CFG       0x69
0085 #define T1_EQ_FD_STG2_FRZ_CFG       0x6A
0086 #define T1_EQ_FD_STG3_FRZ_CFG       0x6B
0087 #define T1_EQ_FD_STG4_FRZ_CFG       0x6C
0088 #define T1_EQ_WT_FD_LCK_FRZ_CFG     0x6D
0089 #define T1_PST_EQ_LCK_STG1_FRZ_CFG  0x6E
0090 
0091 #define T1_MODE_STAT_REG        0x11
0092 #define T1_LINK_UP_MSK          BIT(0)
0093 
0094 /* SQI defines */
0095 #define LAN87XX_MAX_SQI         0x07
0096 
0097 #define DRIVER_AUTHOR   "Nisar Sayed <nisar.sayed@microchip.com>"
0098 #define DRIVER_DESC "Microchip LAN87XX/LAN937x T1 PHY driver"
0099 
0100 struct access_ereg_val {
0101     u8  mode;
0102     u8  bank;
0103     u8  offset;
0104     u16 val;
0105     u16 mask;
0106 };
0107 
0108 static int lan937x_dsp_workaround(struct phy_device *phydev, u16 ereg, u8 bank)
0109 {
0110     u8 prev_bank;
0111     int rc = 0;
0112     u16 val;
0113 
0114     mutex_lock(&phydev->lock);
0115     /* Read previous selected bank */
0116     rc = phy_read(phydev, LAN87XX_EXT_REG_CTL);
0117     if (rc < 0)
0118         goto out_unlock;
0119 
0120     /* store the prev_bank */
0121     prev_bank = FIELD_GET(LAN87XX_REG_BANK_SEL_MASK, rc);
0122 
0123     if (bank != prev_bank && bank == PHYACC_ATTR_BANK_DSP) {
0124         val = ereg & ~LAN87XX_REG_ADDR_MASK;
0125 
0126         val &= ~LAN87XX_EXT_REG_CTL_WR_CTL;
0127         val |= LAN87XX_EXT_REG_CTL_RD_CTL;
0128 
0129         /* access twice for DSP bank change,dummy access */
0130         rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, val);
0131     }
0132 
0133 out_unlock:
0134     mutex_unlock(&phydev->lock);
0135 
0136     return rc;
0137 }
0138 
0139 static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank,
0140                u8 offset, u16 val)
0141 {
0142     u16 ereg = 0;
0143     int rc = 0;
0144 
0145     if (mode > PHYACC_ATTR_MODE_WRITE || bank > PHYACC_ATTR_BANK_MAX)
0146         return -EINVAL;
0147 
0148     if (bank == PHYACC_ATTR_BANK_SMI) {
0149         if (mode == PHYACC_ATTR_MODE_WRITE)
0150             rc = phy_write(phydev, offset, val);
0151         else
0152             rc = phy_read(phydev, offset);
0153         return rc;
0154     }
0155 
0156     if (mode == PHYACC_ATTR_MODE_WRITE) {
0157         ereg = LAN87XX_EXT_REG_CTL_WR_CTL;
0158         rc = phy_write(phydev, LAN87XX_EXT_REG_WR_DATA, val);
0159         if (rc < 0)
0160             return rc;
0161     } else {
0162         ereg = LAN87XX_EXT_REG_CTL_RD_CTL;
0163     }
0164 
0165     ereg |= (bank << 8) | offset;
0166 
0167     /* DSP bank access workaround for lan937x */
0168     if (phydev->phy_id == PHY_ID_LAN937X) {
0169         rc = lan937x_dsp_workaround(phydev, ereg, bank);
0170         if (rc < 0)
0171             return rc;
0172     }
0173 
0174     rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, ereg);
0175     if (rc < 0)
0176         return rc;
0177 
0178     if (mode == PHYACC_ATTR_MODE_READ)
0179         rc = phy_read(phydev, LAN87XX_EXT_REG_RD_DATA);
0180 
0181     return rc;
0182 }
0183 
0184 static int access_ereg_modify_changed(struct phy_device *phydev,
0185                       u8 bank, u8 offset, u16 val, u16 mask)
0186 {
0187     int new = 0, rc = 0;
0188 
0189     if (bank > PHYACC_ATTR_BANK_MAX)
0190         return -EINVAL;
0191 
0192     rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, bank, offset, val);
0193     if (rc < 0)
0194         return rc;
0195 
0196     new = val | (rc & (mask ^ 0xFFFF));
0197     rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE, bank, offset, new);
0198 
0199     return rc;
0200 }
0201 
0202 static int access_smi_poll_timeout(struct phy_device *phydev,
0203                    u8 offset, u16 mask, u16 clr)
0204 {
0205     int val;
0206 
0207     return phy_read_poll_timeout(phydev, offset, val, (val & mask) == clr,
0208                      150, 30000, true);
0209 }
0210 
0211 static int lan87xx_config_rgmii_delay(struct phy_device *phydev)
0212 {
0213     int rc;
0214 
0215     if (!phy_interface_is_rgmii(phydev))
0216         return 0;
0217 
0218     rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0219              PHYACC_ATTR_BANK_MISC, LAN87XX_CTRL_1, 0);
0220     if (rc < 0)
0221         return rc;
0222 
0223     switch (phydev->interface) {
0224     case PHY_INTERFACE_MODE_RGMII:
0225         rc &= ~LAN87XX_MASK_RGMII_TXC_DLY_EN;
0226         rc &= ~LAN87XX_MASK_RGMII_RXC_DLY_EN;
0227         break;
0228     case PHY_INTERFACE_MODE_RGMII_ID:
0229         rc |= LAN87XX_MASK_RGMII_TXC_DLY_EN;
0230         rc |= LAN87XX_MASK_RGMII_RXC_DLY_EN;
0231         break;
0232     case PHY_INTERFACE_MODE_RGMII_RXID:
0233         rc &= ~LAN87XX_MASK_RGMII_TXC_DLY_EN;
0234         rc |= LAN87XX_MASK_RGMII_RXC_DLY_EN;
0235         break;
0236     case PHY_INTERFACE_MODE_RGMII_TXID:
0237         rc |= LAN87XX_MASK_RGMII_TXC_DLY_EN;
0238         rc &= ~LAN87XX_MASK_RGMII_RXC_DLY_EN;
0239         break;
0240     default:
0241         return 0;
0242     }
0243 
0244     return access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
0245                PHYACC_ATTR_BANK_MISC, LAN87XX_CTRL_1, rc);
0246 }
0247 
0248 static int lan87xx_phy_init(struct phy_device *phydev)
0249 {
0250     static const struct access_ereg_val init[] = {
0251         /* TXPD/TXAMP6 Configs */
0252         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_AFE,
0253           T1_AFE_PORT_CFG1_REG,       0x002D,  0 },
0254         /* HW_Init Hi and Force_ED */
0255         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
0256           T1_POWER_DOWN_CONTROL_REG,  0x0308,  0 },
0257         /* Equalizer Full Duplex Freeze - T1 Slave */
0258         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0259           T1_EQ_FD_STG1_FRZ_CFG,     0x0002,  0 },
0260         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0261           T1_EQ_FD_STG2_FRZ_CFG,     0x0002,  0 },
0262         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0263           T1_EQ_FD_STG3_FRZ_CFG,     0x0002,  0 },
0264         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0265           T1_EQ_FD_STG4_FRZ_CFG,     0x0002,  0 },
0266         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0267           T1_EQ_WT_FD_LCK_FRZ_CFG,    0x0002,  0 },
0268         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0269           T1_PST_EQ_LCK_STG1_FRZ_CFG, 0x0002,  0 },
0270         /* Slave Full Duplex Multi Configs */
0271         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0272           T1_SLV_FD_MULT_CFG_REG,     0x0D53,  0 },
0273         /* CDR Pre and Post Lock Configs */
0274         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0275           T1_CDR_CFG_PRE_LOCK_REG,    0x0AB2,  0 },
0276         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0277           T1_CDR_CFG_POST_LOCK_REG,   0x0AB3,  0 },
0278         /* Lock Stage 2-3 Multi Factor Config */
0279         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0280           T1_LCK_STG2_MUFACT_CFG_REG, 0x0AEA,  0 },
0281         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0282           T1_LCK_STG3_MUFACT_CFG_REG, 0x0AEB,  0 },
0283         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0284           T1_POST_LCK_MUFACT_CFG_REG, 0x0AEB,  0 },
0285         /* Pointer delay */
0286         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0287           T1_TX_RX_FIFO_CFG_REG, 0x1C00, 0 },
0288         /* Tx iir edits */
0289         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0290           T1_TX_LPF_FIR_CFG_REG, 0x1000, 0 },
0291         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0292           T1_TX_LPF_FIR_CFG_REG, 0x1861, 0 },
0293         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0294           T1_TX_LPF_FIR_CFG_REG, 0x1061, 0 },
0295         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0296           T1_TX_LPF_FIR_CFG_REG, 0x1922, 0 },
0297         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0298           T1_TX_LPF_FIR_CFG_REG, 0x1122, 0 },
0299         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0300           T1_TX_LPF_FIR_CFG_REG, 0x1983, 0 },
0301         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0302           T1_TX_LPF_FIR_CFG_REG, 0x1183, 0 },
0303         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0304           T1_TX_LPF_FIR_CFG_REG, 0x1944, 0 },
0305         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0306           T1_TX_LPF_FIR_CFG_REG, 0x1144, 0 },
0307         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0308           T1_TX_LPF_FIR_CFG_REG, 0x18c5, 0 },
0309         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0310           T1_TX_LPF_FIR_CFG_REG, 0x10c5, 0 },
0311         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0312           T1_TX_LPF_FIR_CFG_REG, 0x1846, 0 },
0313         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0314           T1_TX_LPF_FIR_CFG_REG, 0x1046, 0 },
0315         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0316           T1_TX_LPF_FIR_CFG_REG, 0x1807, 0 },
0317         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0318           T1_TX_LPF_FIR_CFG_REG, 0x1007, 0 },
0319         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0320           T1_TX_LPF_FIR_CFG_REG, 0x1808, 0 },
0321         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0322           T1_TX_LPF_FIR_CFG_REG, 0x1008, 0 },
0323         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0324           T1_TX_LPF_FIR_CFG_REG, 0x1809, 0 },
0325         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0326           T1_TX_LPF_FIR_CFG_REG, 0x1009, 0 },
0327         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0328           T1_TX_LPF_FIR_CFG_REG, 0x180A, 0 },
0329         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0330           T1_TX_LPF_FIR_CFG_REG, 0x100A, 0 },
0331         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0332           T1_TX_LPF_FIR_CFG_REG, 0x180B, 0 },
0333         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0334           T1_TX_LPF_FIR_CFG_REG, 0x100B, 0 },
0335         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0336           T1_TX_LPF_FIR_CFG_REG, 0x180C, 0 },
0337         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0338           T1_TX_LPF_FIR_CFG_REG, 0x100C, 0 },
0339         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0340           T1_TX_LPF_FIR_CFG_REG, 0x180D, 0 },
0341         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0342           T1_TX_LPF_FIR_CFG_REG, 0x100D, 0 },
0343         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0344           T1_TX_LPF_FIR_CFG_REG, 0x180E, 0 },
0345         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0346           T1_TX_LPF_FIR_CFG_REG, 0x100E, 0 },
0347         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0348           T1_TX_LPF_FIR_CFG_REG, 0x180F, 0 },
0349         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0350           T1_TX_LPF_FIR_CFG_REG, 0x100F, 0 },
0351         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0352           T1_TX_LPF_FIR_CFG_REG, 0x1810, 0 },
0353         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0354           T1_TX_LPF_FIR_CFG_REG, 0x1010, 0 },
0355         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0356           T1_TX_LPF_FIR_CFG_REG, 0x1811, 0 },
0357         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0358           T1_TX_LPF_FIR_CFG_REG, 0x1011, 0 },
0359         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0360           T1_TX_LPF_FIR_CFG_REG, 0x1000, 0 },
0361         /* Setup SQI measurement */
0362         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0363           T1_COEF_CLK_PWR_DN_CFG,   0x16d6, 0 },
0364         /* SQI enable */
0365         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0366           T1_SQI_CONFIG_REG,        0x9572, 0 },
0367         /* SQI select mode 5 */
0368         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0369           T1_SQI_CONFIG2_REG,       0x0001, 0 },
0370         /* Throws the first SQI reading */
0371         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0372           T1_COEF_RW_CTL_CFG,       0x0301, 0 },
0373         { PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_DSP,
0374           T1_DCQ_SQI_REG,       0,  0 },
0375         /* Flag LPS and WUR as idle errors */
0376         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
0377           T1_MDIO_CONTROL2_REG,     0x0014, 0 },
0378         /* HW_Init toggle, undo force ED, TXPD off */
0379         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
0380           T1_POWER_DOWN_CONTROL_REG,    0x0200, 0 },
0381         /* Reset PCS to trigger hardware initialization */
0382         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
0383           T1_MDIO_CONTROL2_REG,     0x0094, 0 },
0384         /* Poll till Hardware is initialized */
0385         { PHYACC_ATTR_MODE_POLL, PHYACC_ATTR_BANK_SMI,
0386           T1_MDIO_CONTROL2_REG,     0x0080, 0 },
0387         /* Tx AMP - 0x06  */
0388         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_AFE,
0389           T1_AFE_PORT_CFG1_REG,     0x000C, 0 },
0390         /* Read INTERRUPT_SOURCE Register */
0391         { PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI,
0392           T1_INTERRUPT_SOURCE_REG,  0,  0 },
0393         /* Read INTERRUPT_SOURCE Register */
0394         { PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_MISC,
0395           T1_INTERRUPT2_SOURCE_REG, 0,  0 },
0396         /* HW_Init Hi */
0397         { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
0398           T1_POWER_DOWN_CONTROL_REG,    0x0300, 0 },
0399     };
0400     int rc, i;
0401 
0402     /* phy Soft reset */
0403     rc = genphy_soft_reset(phydev);
0404     if (rc < 0)
0405         return rc;
0406 
0407     /* PHY Initialization */
0408     for (i = 0; i < ARRAY_SIZE(init); i++) {
0409         if (init[i].mode == PHYACC_ATTR_MODE_POLL &&
0410             init[i].bank == PHYACC_ATTR_BANK_SMI) {
0411             rc = access_smi_poll_timeout(phydev,
0412                              init[i].offset,
0413                              init[i].val,
0414                              init[i].mask);
0415         } else {
0416             rc = access_ereg(phydev, init[i].mode, init[i].bank,
0417                      init[i].offset, init[i].val);
0418         }
0419         if (rc < 0)
0420             return rc;
0421     }
0422 
0423     return lan87xx_config_rgmii_delay(phydev);
0424 }
0425 
0426 static int lan87xx_phy_config_intr(struct phy_device *phydev)
0427 {
0428     int rc, val = 0;
0429 
0430     if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0431         /* clear all interrupt */
0432         rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val);
0433         if (rc < 0)
0434             return rc;
0435 
0436         rc = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE);
0437         if (rc < 0)
0438             return rc;
0439 
0440         rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
0441                  PHYACC_ATTR_BANK_MISC,
0442                  LAN87XX_INTERRUPT_MASK_2, val);
0443         if (rc < 0)
0444             return rc;
0445 
0446         rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0447                  PHYACC_ATTR_BANK_MISC,
0448                  LAN87XX_INTERRUPT_SOURCE_2, 0);
0449         if (rc < 0)
0450             return rc;
0451 
0452         /* enable link down and comm ready interrupt */
0453         val = LAN87XX_MASK_LINK_DOWN;
0454         rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val);
0455         if (rc < 0)
0456             return rc;
0457 
0458         val = LAN87XX_MASK_COMM_RDY;
0459         rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
0460                  PHYACC_ATTR_BANK_MISC,
0461                  LAN87XX_INTERRUPT_MASK_2, val);
0462     } else {
0463         rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val);
0464         if (rc < 0)
0465             return rc;
0466 
0467         rc = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE);
0468         if (rc < 0)
0469             return rc;
0470 
0471         rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
0472                  PHYACC_ATTR_BANK_MISC,
0473                  LAN87XX_INTERRUPT_MASK_2, val);
0474         if (rc < 0)
0475             return rc;
0476 
0477         rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0478                  PHYACC_ATTR_BANK_MISC,
0479                  LAN87XX_INTERRUPT_SOURCE_2, 0);
0480     }
0481 
0482     return rc < 0 ? rc : 0;
0483 }
0484 
0485 static irqreturn_t lan87xx_handle_interrupt(struct phy_device *phydev)
0486 {
0487     int irq_status;
0488 
0489     irq_status  = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0490                   PHYACC_ATTR_BANK_MISC,
0491                   LAN87XX_INTERRUPT_SOURCE_2, 0);
0492     if (irq_status < 0) {
0493         phy_error(phydev);
0494         return IRQ_NONE;
0495     }
0496 
0497     irq_status = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE);
0498     if (irq_status < 0) {
0499         phy_error(phydev);
0500         return IRQ_NONE;
0501     }
0502 
0503     if (irq_status == 0)
0504         return IRQ_NONE;
0505 
0506     phy_trigger_machine(phydev);
0507 
0508     return IRQ_HANDLED;
0509 }
0510 
0511 static int lan87xx_config_init(struct phy_device *phydev)
0512 {
0513     int rc = lan87xx_phy_init(phydev);
0514 
0515     return rc < 0 ? rc : 0;
0516 }
0517 
0518 static int microchip_cable_test_start_common(struct phy_device *phydev)
0519 {
0520     int bmcr, bmsr, ret;
0521 
0522     /* If auto-negotiation is enabled, but not complete, the cable
0523      * test never completes. So disable auto-neg.
0524      */
0525     bmcr = phy_read(phydev, MII_BMCR);
0526     if (bmcr < 0)
0527         return bmcr;
0528 
0529     bmsr = phy_read(phydev, MII_BMSR);
0530 
0531     if (bmsr < 0)
0532         return bmsr;
0533 
0534     if (bmcr & BMCR_ANENABLE) {
0535         ret =  phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
0536         if (ret < 0)
0537             return ret;
0538         ret = genphy_soft_reset(phydev);
0539         if (ret < 0)
0540             return ret;
0541     }
0542 
0543     /* If the link is up, allow it some time to go down */
0544     if (bmsr & BMSR_LSTATUS)
0545         msleep(1500);
0546 
0547     return 0;
0548 }
0549 
0550 static int lan87xx_cable_test_start(struct phy_device *phydev)
0551 {
0552     static const struct access_ereg_val cable_test[] = {
0553         /* min wait */
0554         {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 93,
0555          0, 0},
0556         /* max wait */
0557         {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 94,
0558          10, 0},
0559         /* pulse cycle */
0560         {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 95,
0561          90, 0},
0562         /* cable diag thresh */
0563         {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 92,
0564          60, 0},
0565         /* max gain */
0566         {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 79,
0567          31, 0},
0568         /* clock align for each iteration */
0569         {PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_DSP, 55,
0570          0, 0x0038},
0571         /* max cycle wait config */
0572         {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 94,
0573          70, 0},
0574         /* start cable diag*/
0575         {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 90,
0576          1, 0},
0577     };
0578     int rc, i;
0579 
0580     rc = microchip_cable_test_start_common(phydev);
0581     if (rc < 0)
0582         return rc;
0583 
0584     /* start cable diag */
0585     /* check if part is alive - if not, return diagnostic error */
0586     rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI,
0587              0x00, 0);
0588     if (rc < 0)
0589         return rc;
0590 
0591     /* master/slave specific configs */
0592     rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI,
0593              0x0A, 0);
0594     if (rc < 0)
0595         return rc;
0596 
0597     if ((rc & 0x4000) != 0x4000) {
0598         /* DUT is Slave */
0599         rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_AFE,
0600                         0x0E, 0x5, 0x7);
0601         if (rc < 0)
0602             return rc;
0603         rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
0604                         0x1A, 0x8, 0x8);
0605         if (rc < 0)
0606             return rc;
0607     } else {
0608         /* DUT is Master */
0609         rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
0610                         0x10, 0x8, 0x40);
0611         if (rc < 0)
0612             return rc;
0613     }
0614 
0615     for (i = 0; i < ARRAY_SIZE(cable_test); i++) {
0616         if (cable_test[i].mode == PHYACC_ATTR_MODE_MODIFY) {
0617             rc = access_ereg_modify_changed(phydev,
0618                             cable_test[i].bank,
0619                             cable_test[i].offset,
0620                             cable_test[i].val,
0621                             cable_test[i].mask);
0622             /* wait 50ms */
0623             msleep(50);
0624         } else {
0625             rc = access_ereg(phydev, cable_test[i].mode,
0626                      cable_test[i].bank,
0627                      cable_test[i].offset,
0628                      cable_test[i].val);
0629         }
0630         if (rc < 0)
0631             return rc;
0632     }
0633     /* cable diag started */
0634 
0635     return 0;
0636 }
0637 
0638 static int lan87xx_cable_test_report_trans(u32 result)
0639 {
0640     switch (result) {
0641     case LAN87XX_CABLE_TEST_OK:
0642         return ETHTOOL_A_CABLE_RESULT_CODE_OK;
0643     case LAN87XX_CABLE_TEST_OPEN:
0644         return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
0645     case LAN87XX_CABLE_TEST_SAME_SHORT:
0646         return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
0647     default:
0648         /* DIAGNOSTIC_ERROR */
0649         return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
0650     }
0651 }
0652 
0653 static int lan87xx_cable_test_report(struct phy_device *phydev)
0654 {
0655     int pos_peak_cycle = 0, pos_peak_in_phases = 0, pos_peak_phase = 0;
0656     int neg_peak_cycle = 0, neg_peak_in_phases = 0, neg_peak_phase = 0;
0657     int noise_margin = 20, time_margin = 89, jitter_var = 30;
0658     int min_time_diff = 96, max_time_diff = 96 + time_margin;
0659     bool fault = false, check_a = false, check_b = false;
0660     int gain_idx = 0, pos_peak = 0, neg_peak = 0;
0661     int pos_peak_time = 0, neg_peak_time = 0;
0662     int pos_peak_in_phases_hybrid = 0;
0663     int detect = -1;
0664 
0665     gain_idx = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0666                    PHYACC_ATTR_BANK_DSP, 151, 0);
0667     /* read non-hybrid results */
0668     pos_peak = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0669                    PHYACC_ATTR_BANK_DSP, 153, 0);
0670     neg_peak = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0671                    PHYACC_ATTR_BANK_DSP, 154, 0);
0672     pos_peak_time = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0673                     PHYACC_ATTR_BANK_DSP, 156, 0);
0674     neg_peak_time = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0675                     PHYACC_ATTR_BANK_DSP, 157, 0);
0676 
0677     pos_peak_cycle = (pos_peak_time >> 7) & 0x7F;
0678     /* calculate non-hybrid values */
0679     pos_peak_phase = pos_peak_time & 0x7F;
0680     pos_peak_in_phases = (pos_peak_cycle * 96) + pos_peak_phase;
0681     neg_peak_cycle = (neg_peak_time >> 7) & 0x7F;
0682     neg_peak_phase = neg_peak_time & 0x7F;
0683     neg_peak_in_phases = (neg_peak_cycle * 96) + neg_peak_phase;
0684 
0685     /* process values */
0686     check_a =
0687         ((pos_peak_in_phases - neg_peak_in_phases) >= min_time_diff) &&
0688         ((pos_peak_in_phases - neg_peak_in_phases) < max_time_diff) &&
0689         pos_peak_in_phases_hybrid < pos_peak_in_phases &&
0690         (pos_peak_in_phases_hybrid < (neg_peak_in_phases + jitter_var));
0691     check_b =
0692         ((neg_peak_in_phases - pos_peak_in_phases) >= min_time_diff) &&
0693         ((neg_peak_in_phases - pos_peak_in_phases) < max_time_diff) &&
0694         pos_peak_in_phases_hybrid < neg_peak_in_phases &&
0695         (pos_peak_in_phases_hybrid < (pos_peak_in_phases + jitter_var));
0696 
0697     if (pos_peak_in_phases > neg_peak_in_phases && check_a)
0698         detect = 2;
0699     else if ((neg_peak_in_phases > pos_peak_in_phases) && check_b)
0700         detect = 1;
0701 
0702     if (pos_peak > noise_margin && neg_peak > noise_margin &&
0703         gain_idx >= 0) {
0704         if (detect == 1 || detect == 2)
0705             fault = true;
0706     }
0707 
0708     if (!fault)
0709         detect = 0;
0710 
0711     ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
0712                 lan87xx_cable_test_report_trans(detect));
0713 
0714     return 0;
0715 }
0716 
0717 static int lan87xx_cable_test_get_status(struct phy_device *phydev,
0718                      bool *finished)
0719 {
0720     int rc = 0;
0721 
0722     *finished = false;
0723 
0724     /* check if cable diag was finished */
0725     rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_DSP,
0726              90, 0);
0727     if (rc < 0)
0728         return rc;
0729 
0730     if ((rc & 2) == 2) {
0731         /* stop cable diag*/
0732         rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
0733                  PHYACC_ATTR_BANK_DSP,
0734                  90, 0);
0735         if (rc < 0)
0736             return rc;
0737 
0738         *finished = true;
0739 
0740         return lan87xx_cable_test_report(phydev);
0741     }
0742 
0743     return 0;
0744 }
0745 
0746 static int lan87xx_read_status(struct phy_device *phydev)
0747 {
0748     int rc = 0;
0749 
0750     rc = phy_read(phydev, T1_MODE_STAT_REG);
0751     if (rc < 0)
0752         return rc;
0753 
0754     if (rc & T1_LINK_UP_MSK)
0755         phydev->link = 1;
0756     else
0757         phydev->link = 0;
0758 
0759     phydev->speed = SPEED_UNKNOWN;
0760     phydev->duplex = DUPLEX_UNKNOWN;
0761     phydev->pause = 0;
0762     phydev->asym_pause = 0;
0763 
0764     rc = genphy_read_master_slave(phydev);
0765     if (rc < 0)
0766         return rc;
0767 
0768     rc = genphy_read_status_fixed(phydev);
0769     if (rc < 0)
0770         return rc;
0771 
0772     return rc;
0773 }
0774 
0775 static int lan87xx_config_aneg(struct phy_device *phydev)
0776 {
0777     u16 ctl = 0;
0778 
0779     switch (phydev->master_slave_set) {
0780     case MASTER_SLAVE_CFG_MASTER_FORCE:
0781         ctl |= CTL1000_AS_MASTER;
0782         break;
0783     case MASTER_SLAVE_CFG_SLAVE_FORCE:
0784         break;
0785     case MASTER_SLAVE_CFG_UNKNOWN:
0786     case MASTER_SLAVE_CFG_UNSUPPORTED:
0787         return 0;
0788     default:
0789         phydev_warn(phydev, "Unsupported Master/Slave mode\n");
0790         return -EOPNOTSUPP;
0791     }
0792 
0793     return phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl);
0794 }
0795 
0796 static int lan87xx_get_sqi(struct phy_device *phydev)
0797 {
0798     u8 sqi_value = 0;
0799     int rc;
0800 
0801     rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
0802              PHYACC_ATTR_BANK_DSP, T1_COEF_RW_CTL_CFG, 0x0301);
0803     if (rc < 0)
0804         return rc;
0805 
0806     rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
0807              PHYACC_ATTR_BANK_DSP, T1_DCQ_SQI_REG, 0x0);
0808     if (rc < 0)
0809         return rc;
0810 
0811     sqi_value = FIELD_GET(T1_DCQ_SQI_MSK, rc);
0812 
0813     return sqi_value;
0814 }
0815 
0816 static int lan87xx_get_sqi_max(struct phy_device *phydev)
0817 {
0818     return LAN87XX_MAX_SQI;
0819 }
0820 
0821 static struct phy_driver microchip_t1_phy_driver[] = {
0822     {
0823         PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX),
0824         .name           = "Microchip LAN87xx T1",
0825         .flags          = PHY_POLL_CABLE_TEST,
0826         .features       = PHY_BASIC_T1_FEATURES,
0827         .config_init    = lan87xx_config_init,
0828         .config_intr    = lan87xx_phy_config_intr,
0829         .handle_interrupt = lan87xx_handle_interrupt,
0830         .suspend        = genphy_suspend,
0831         .resume         = genphy_resume,
0832         .config_aneg    = lan87xx_config_aneg,
0833         .read_status    = lan87xx_read_status,
0834         .get_sqi    = lan87xx_get_sqi,
0835         .get_sqi_max    = lan87xx_get_sqi_max,
0836         .cable_test_start = lan87xx_cable_test_start,
0837         .cable_test_get_status = lan87xx_cable_test_get_status,
0838     },
0839     {
0840         PHY_ID_MATCH_MODEL(PHY_ID_LAN937X),
0841         .name       = "Microchip LAN937x T1",
0842         .flags          = PHY_POLL_CABLE_TEST,
0843         .features   = PHY_BASIC_T1_FEATURES,
0844         .config_init    = lan87xx_config_init,
0845         .config_intr    = lan87xx_phy_config_intr,
0846         .handle_interrupt = lan87xx_handle_interrupt,
0847         .suspend    = genphy_suspend,
0848         .resume     = genphy_resume,
0849         .config_aneg    = lan87xx_config_aneg,
0850         .read_status    = lan87xx_read_status,
0851         .get_sqi    = lan87xx_get_sqi,
0852         .get_sqi_max    = lan87xx_get_sqi_max,
0853         .cable_test_start = lan87xx_cable_test_start,
0854         .cable_test_get_status = lan87xx_cable_test_get_status,
0855     }
0856 };
0857 
0858 module_phy_driver(microchip_t1_phy_driver);
0859 
0860 static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
0861     { PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX) },
0862     { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X) },
0863     { }
0864 };
0865 
0866 MODULE_DEVICE_TABLE(mdio, microchip_t1_tbl);
0867 
0868 MODULE_AUTHOR(DRIVER_AUTHOR);
0869 MODULE_DESCRIPTION(DRIVER_DESC);
0870 MODULE_LICENSE("GPL");