0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/mii.h>
0012 #include <linux/ethtool.h>
0013 #include <linux/phy.h>
0014 #include <linux/netdevice.h>
0015 #include <linux/bitfield.h>
0016
0017 #define TSTCNTL 20
0018 #define TSTCNTL_READ BIT(15)
0019 #define TSTCNTL_WRITE BIT(14)
0020 #define TSTCNTL_REG_BANK_SEL GENMASK(12, 11)
0021 #define TSTCNTL_TEST_MODE BIT(10)
0022 #define TSTCNTL_READ_ADDRESS GENMASK(9, 5)
0023 #define TSTCNTL_WRITE_ADDRESS GENMASK(4, 0)
0024 #define TSTREAD1 21
0025 #define TSTWRITE 23
0026 #define INTSRC_FLAG 29
0027 #define INTSRC_ANEG_PR BIT(1)
0028 #define INTSRC_PARALLEL_FAULT BIT(2)
0029 #define INTSRC_ANEG_LP_ACK BIT(3)
0030 #define INTSRC_LINK_DOWN BIT(4)
0031 #define INTSRC_REMOTE_FAULT BIT(5)
0032 #define INTSRC_ANEG_COMPLETE BIT(6)
0033 #define INTSRC_ENERGY_DETECT BIT(7)
0034 #define INTSRC_MASK 30
0035
0036 #define INT_SOURCES (INTSRC_LINK_DOWN | INTSRC_ANEG_COMPLETE | \
0037 INTSRC_ENERGY_DETECT)
0038
0039 #define BANK_ANALOG_DSP 0
0040 #define BANK_WOL 1
0041 #define BANK_BIST 3
0042
0043
0044 #define LPI_STATUS 0xc
0045 #define LPI_STATUS_RSV12 BIT(12)
0046
0047
0048 #define FR_PLL_CONTROL 0x1b
0049 #define FR_PLL_DIV0 0x1c
0050 #define FR_PLL_DIV1 0x1d
0051
0052 static int meson_gxl_open_banks(struct phy_device *phydev)
0053 {
0054 int ret;
0055
0056
0057
0058
0059 ret = phy_write(phydev, TSTCNTL, 0);
0060 if (ret)
0061 return ret;
0062 ret = phy_write(phydev, TSTCNTL, TSTCNTL_TEST_MODE);
0063 if (ret)
0064 return ret;
0065 ret = phy_write(phydev, TSTCNTL, 0);
0066 if (ret)
0067 return ret;
0068 return phy_write(phydev, TSTCNTL, TSTCNTL_TEST_MODE);
0069 }
0070
0071 static void meson_gxl_close_banks(struct phy_device *phydev)
0072 {
0073 phy_write(phydev, TSTCNTL, 0);
0074 }
0075
0076 static int meson_gxl_read_reg(struct phy_device *phydev,
0077 unsigned int bank, unsigned int reg)
0078 {
0079 int ret;
0080
0081 ret = meson_gxl_open_banks(phydev);
0082 if (ret)
0083 goto out;
0084
0085 ret = phy_write(phydev, TSTCNTL, TSTCNTL_READ |
0086 FIELD_PREP(TSTCNTL_REG_BANK_SEL, bank) |
0087 TSTCNTL_TEST_MODE |
0088 FIELD_PREP(TSTCNTL_READ_ADDRESS, reg));
0089 if (ret)
0090 goto out;
0091
0092 ret = phy_read(phydev, TSTREAD1);
0093 out:
0094
0095 meson_gxl_close_banks(phydev);
0096 return ret;
0097 }
0098
0099 static int meson_gxl_write_reg(struct phy_device *phydev,
0100 unsigned int bank, unsigned int reg,
0101 uint16_t value)
0102 {
0103 int ret;
0104
0105 ret = meson_gxl_open_banks(phydev);
0106 if (ret)
0107 goto out;
0108
0109 ret = phy_write(phydev, TSTWRITE, value);
0110 if (ret)
0111 goto out;
0112
0113 ret = phy_write(phydev, TSTCNTL, TSTCNTL_WRITE |
0114 FIELD_PREP(TSTCNTL_REG_BANK_SEL, bank) |
0115 TSTCNTL_TEST_MODE |
0116 FIELD_PREP(TSTCNTL_WRITE_ADDRESS, reg));
0117
0118 out:
0119
0120 meson_gxl_close_banks(phydev);
0121 return ret;
0122 }
0123
0124 static int meson_gxl_config_init(struct phy_device *phydev)
0125 {
0126 int ret;
0127
0128
0129 ret = meson_gxl_write_reg(phydev, BANK_BIST, FR_PLL_CONTROL, 0x5);
0130 if (ret)
0131 return ret;
0132
0133
0134 ret = meson_gxl_write_reg(phydev, BANK_BIST, FR_PLL_DIV1, 0x029a);
0135 if (ret)
0136 return ret;
0137
0138
0139 ret = meson_gxl_write_reg(phydev, BANK_BIST, FR_PLL_DIV0, 0xaaaa);
0140 if (ret)
0141 return ret;
0142
0143 return 0;
0144 }
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 static int meson_gxl_read_status(struct phy_device *phydev)
0163 {
0164 int ret, wol, lpa, exp;
0165
0166 if (phydev->autoneg == AUTONEG_ENABLE) {
0167 ret = genphy_aneg_done(phydev);
0168 if (ret < 0)
0169 return ret;
0170 else if (!ret)
0171 goto read_status_continue;
0172
0173
0174 wol = meson_gxl_read_reg(phydev, BANK_WOL, LPI_STATUS);
0175 if (wol < 0)
0176 return wol;
0177
0178 lpa = phy_read(phydev, MII_LPA);
0179 if (lpa < 0)
0180 return lpa;
0181
0182 exp = phy_read(phydev, MII_EXPANSION);
0183 if (exp < 0)
0184 return exp;
0185
0186 if (!(wol & LPI_STATUS_RSV12) ||
0187 ((exp & EXPANSION_NWAY) && !(lpa & LPA_LPACK))) {
0188
0189 phydev_dbg(phydev, "LPA corruption - aneg restart\n");
0190 return genphy_restart_aneg(phydev);
0191 }
0192 }
0193
0194 read_status_continue:
0195 return genphy_read_status(phydev);
0196 }
0197
0198 static int meson_gxl_ack_interrupt(struct phy_device *phydev)
0199 {
0200 int ret = phy_read(phydev, INTSRC_FLAG);
0201
0202 return ret < 0 ? ret : 0;
0203 }
0204
0205 static int meson_gxl_config_intr(struct phy_device *phydev)
0206 {
0207 int ret;
0208
0209 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0210
0211 ret = meson_gxl_ack_interrupt(phydev);
0212 if (ret)
0213 return ret;
0214
0215 ret = phy_write(phydev, INTSRC_MASK, INT_SOURCES);
0216 } else {
0217 ret = phy_write(phydev, INTSRC_MASK, 0);
0218
0219
0220 ret = meson_gxl_ack_interrupt(phydev);
0221 }
0222
0223 return ret;
0224 }
0225
0226 static irqreturn_t meson_gxl_handle_interrupt(struct phy_device *phydev)
0227 {
0228 int irq_status;
0229
0230 irq_status = phy_read(phydev, INTSRC_FLAG);
0231 if (irq_status < 0) {
0232 phy_error(phydev);
0233 return IRQ_NONE;
0234 }
0235
0236 irq_status &= INT_SOURCES;
0237
0238 if (irq_status == 0)
0239 return IRQ_NONE;
0240
0241
0242 if (phydev->autoneg == AUTONEG_ENABLE &&
0243 irq_status == INTSRC_ENERGY_DETECT)
0244 return IRQ_HANDLED;
0245
0246 phy_trigger_machine(phydev);
0247
0248 return IRQ_HANDLED;
0249 }
0250
0251 static struct phy_driver meson_gxl_phy[] = {
0252 {
0253 PHY_ID_MATCH_EXACT(0x01814400),
0254 .name = "Meson GXL Internal PHY",
0255
0256 .flags = PHY_IS_INTERNAL,
0257 .soft_reset = genphy_soft_reset,
0258 .config_init = meson_gxl_config_init,
0259 .read_status = meson_gxl_read_status,
0260 .config_intr = meson_gxl_config_intr,
0261 .handle_interrupt = meson_gxl_handle_interrupt,
0262 .suspend = genphy_suspend,
0263 .resume = genphy_resume,
0264 }, {
0265 PHY_ID_MATCH_EXACT(0x01803301),
0266 .name = "Meson G12A Internal PHY",
0267
0268 .flags = PHY_IS_INTERNAL,
0269 .soft_reset = genphy_soft_reset,
0270 .config_intr = meson_gxl_config_intr,
0271 .handle_interrupt = meson_gxl_handle_interrupt,
0272 .suspend = genphy_suspend,
0273 .resume = genphy_resume,
0274 },
0275 };
0276
0277 static struct mdio_device_id __maybe_unused meson_gxl_tbl[] = {
0278 { PHY_ID_MATCH_VENDOR(0x01814400) },
0279 { PHY_ID_MATCH_VENDOR(0x01803301) },
0280 { }
0281 };
0282
0283 module_phy_driver(meson_gxl_phy);
0284
0285 MODULE_DEVICE_TABLE(mdio, meson_gxl_tbl);
0286
0287 MODULE_DESCRIPTION("Amlogic Meson GXL Internal PHY driver");
0288 MODULE_AUTHOR("Baoqi wang");
0289 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0290 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
0291 MODULE_LICENSE("GPL");