| 1 | // SPDX-License-Identifier: GPL-2.0+ | 
|---|
| 2 | /* drivers/net/phy/realtek.c | 
|---|
| 3 | * | 
|---|
| 4 | * Driver for Realtek PHYs | 
|---|
| 5 | * | 
|---|
| 6 | * Author: Johnson Leung <r58129@freescale.com> | 
|---|
| 7 | * | 
|---|
| 8 | * Copyright (c) 2004 Freescale Semiconductor, Inc. | 
|---|
| 9 | */ | 
|---|
| 10 | #include <linux/bitops.h> | 
|---|
| 11 | #include <linux/of.h> | 
|---|
| 12 | #include <linux/phy.h> | 
|---|
| 13 | #include <linux/pm_wakeirq.h> | 
|---|
| 14 | #include <linux/netdevice.h> | 
|---|
| 15 | #include <linux/module.h> | 
|---|
| 16 | #include <linux/delay.h> | 
|---|
| 17 | #include <linux/clk.h> | 
|---|
| 18 | #include <linux/string_choices.h> | 
|---|
| 19 |  | 
|---|
| 20 | #include "realtek.h" | 
|---|
| 21 |  | 
|---|
| 22 | #define RTL8201F_IER				0x13 | 
|---|
| 23 |  | 
|---|
| 24 | #define RTL8201F_ISR				0x1e | 
|---|
| 25 | #define RTL8201F_ISR_ANERR			BIT(15) | 
|---|
| 26 | #define RTL8201F_ISR_DUPLEX			BIT(13) | 
|---|
| 27 | #define RTL8201F_ISR_LINK			BIT(11) | 
|---|
| 28 | #define RTL8201F_ISR_MASK			(RTL8201F_ISR_ANERR | \ | 
|---|
| 29 | RTL8201F_ISR_DUPLEX | \ | 
|---|
| 30 | RTL8201F_ISR_LINK) | 
|---|
| 31 |  | 
|---|
| 32 | #define RTL821x_INER				0x12 | 
|---|
| 33 | #define RTL8211B_INER_INIT			0x6400 | 
|---|
| 34 | #define RTL8211E_INER_LINK_STATUS		BIT(10) | 
|---|
| 35 | #define RTL8211F_INER_PME			BIT(7) | 
|---|
| 36 | #define RTL8211F_INER_LINK_STATUS		BIT(4) | 
|---|
| 37 |  | 
|---|
| 38 | #define RTL821x_INSR				0x13 | 
|---|
| 39 |  | 
|---|
| 40 | #define RTL821x_EXT_PAGE_SELECT			0x1e | 
|---|
| 41 |  | 
|---|
| 42 | #define RTL821x_PAGE_SELECT			0x1f | 
|---|
| 43 | #define RTL821x_SET_EXT_PAGE			0x07 | 
|---|
| 44 |  | 
|---|
| 45 | /* RTL8211E extension page 44/0x2c */ | 
|---|
| 46 | #define RTL8211E_LEDCR_EXT_PAGE			0x2c | 
|---|
| 47 | #define RTL8211E_LEDCR1				0x1a | 
|---|
| 48 | #define RTL8211E_LEDCR1_ACT_TXRX		BIT(4) | 
|---|
| 49 | #define RTL8211E_LEDCR1_MASK			BIT(4) | 
|---|
| 50 | #define RTL8211E_LEDCR1_SHIFT			1 | 
|---|
| 51 |  | 
|---|
| 52 | #define RTL8211E_LEDCR2				0x1c | 
|---|
| 53 | #define RTL8211E_LEDCR2_LINK_1000		BIT(2) | 
|---|
| 54 | #define RTL8211E_LEDCR2_LINK_100		BIT(1) | 
|---|
| 55 | #define RTL8211E_LEDCR2_LINK_10			BIT(0) | 
|---|
| 56 | #define RTL8211E_LEDCR2_MASK			GENMASK(2, 0) | 
|---|
| 57 | #define RTL8211E_LEDCR2_SHIFT			4 | 
|---|
| 58 |  | 
|---|
| 59 | /* RTL8211E extension page 164/0xa4 */ | 
|---|
| 60 | #define RTL8211E_RGMII_EXT_PAGE			0xa4 | 
|---|
| 61 | #define RTL8211E_RGMII_DELAY			0x1c | 
|---|
| 62 | #define RTL8211E_CTRL_DELAY			BIT(13) | 
|---|
| 63 | #define RTL8211E_TX_DELAY			BIT(12) | 
|---|
| 64 | #define RTL8211E_RX_DELAY			BIT(11) | 
|---|
| 65 | #define RTL8211E_DELAY_MASK			GENMASK(13, 11) | 
|---|
| 66 |  | 
|---|
| 67 | /* RTL8211F PHY configuration */ | 
|---|
| 68 | #define RTL8211F_PHYCR_PAGE			0xa43 | 
|---|
| 69 | #define RTL8211F_PHYCR1				0x18 | 
|---|
| 70 | #define RTL8211F_ALDPS_PLL_OFF			BIT(1) | 
|---|
| 71 | #define RTL8211F_ALDPS_ENABLE			BIT(2) | 
|---|
| 72 | #define RTL8211F_ALDPS_XTAL_OFF			BIT(12) | 
|---|
| 73 |  | 
|---|
| 74 | #define RTL8211F_PHYCR2				0x19 | 
|---|
| 75 | #define RTL8211F_CLKOUT_EN			BIT(0) | 
|---|
| 76 | #define RTL8211F_PHYCR2_PHY_EEE_ENABLE		BIT(5) | 
|---|
| 77 |  | 
|---|
| 78 | #define RTL8211F_INSR_PAGE			0xa43 | 
|---|
| 79 | #define RTL8211F_INSR				0x1d | 
|---|
| 80 |  | 
|---|
| 81 | /* RTL8211F LED configuration */ | 
|---|
| 82 | #define RTL8211F_LEDCR_PAGE			0xd04 | 
|---|
| 83 | #define RTL8211F_LEDCR				0x10 | 
|---|
| 84 | #define RTL8211F_LEDCR_MODE			BIT(15) | 
|---|
| 85 | #define RTL8211F_LEDCR_ACT_TXRX			BIT(4) | 
|---|
| 86 | #define RTL8211F_LEDCR_LINK_1000		BIT(3) | 
|---|
| 87 | #define RTL8211F_LEDCR_LINK_100			BIT(1) | 
|---|
| 88 | #define RTL8211F_LEDCR_LINK_10			BIT(0) | 
|---|
| 89 | #define RTL8211F_LEDCR_MASK			GENMASK(4, 0) | 
|---|
| 90 | #define RTL8211F_LEDCR_SHIFT			5 | 
|---|
| 91 |  | 
|---|
| 92 | /* RTL8211F RGMII configuration */ | 
|---|
| 93 | #define RTL8211F_RGMII_PAGE			0xd08 | 
|---|
| 94 |  | 
|---|
| 95 | #define RTL8211F_TXCR				0x11 | 
|---|
| 96 | #define RTL8211F_TX_DELAY			BIT(8) | 
|---|
| 97 |  | 
|---|
| 98 | #define RTL8211F_RXCR				0x15 | 
|---|
| 99 | #define RTL8211F_RX_DELAY			BIT(3) | 
|---|
| 100 |  | 
|---|
| 101 | /* RTL8211F WOL settings */ | 
|---|
| 102 | #define RTL8211F_WOL_PAGE		0xd8a | 
|---|
| 103 | #define RTL8211F_WOL_SETTINGS_EVENTS		16 | 
|---|
| 104 | #define RTL8211F_WOL_EVENT_MAGIC		BIT(12) | 
|---|
| 105 | #define RTL8211F_WOL_RST_RMSQ		17 | 
|---|
| 106 | #define RTL8211F_WOL_RG_RSTB			BIT(15) | 
|---|
| 107 | #define RTL8211F_WOL_RMSQ			0x1fff | 
|---|
| 108 |  | 
|---|
| 109 | /* RTL8211F Unique phyiscal and multicast address (WOL) */ | 
|---|
| 110 | #define RTL8211F_PHYSICAL_ADDR_PAGE		0xd8c | 
|---|
| 111 | #define RTL8211F_PHYSICAL_ADDR_WORD0		16 | 
|---|
| 112 | #define RTL8211F_PHYSICAL_ADDR_WORD1		17 | 
|---|
| 113 | #define RTL8211F_PHYSICAL_ADDR_WORD2		18 | 
|---|
| 114 |  | 
|---|
| 115 | #define RTL822X_VND1_SERDES_OPTION			0x697a | 
|---|
| 116 | #define RTL822X_VND1_SERDES_OPTION_MODE_MASK		GENMASK(5, 0) | 
|---|
| 117 | #define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII		0 | 
|---|
| 118 | #define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX		2 | 
|---|
| 119 |  | 
|---|
| 120 | #define RTL822X_VND1_SERDES_CTRL3			0x7580 | 
|---|
| 121 | #define RTL822X_VND1_SERDES_CTRL3_MODE_MASK		GENMASK(5, 0) | 
|---|
| 122 | #define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII			0x02 | 
|---|
| 123 | #define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX		0x16 | 
|---|
| 124 |  | 
|---|
| 125 | /* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 | 
|---|
| 126 | * is set, they cannot be accessed by C45-over-C22. | 
|---|
| 127 | */ | 
|---|
| 128 | #define RTL822X_VND2_C22_REG(reg)		(0xa400 + 2 * (reg)) | 
|---|
| 129 |  | 
|---|
| 130 | #define RTL8366RB_POWER_SAVE			0x15 | 
|---|
| 131 | #define RTL8366RB_POWER_SAVE_ON			BIT(12) | 
|---|
| 132 |  | 
|---|
| 133 | #define RTL9000A_GINMR				0x14 | 
|---|
| 134 | #define RTL9000A_GINMR_LINK_STATUS		BIT(4) | 
|---|
| 135 |  | 
|---|
| 136 | #define RTL_VND2_PHYSR				0xa434 | 
|---|
| 137 | #define RTL_VND2_PHYSR_DUPLEX			BIT(3) | 
|---|
| 138 | #define RTL_VND2_PHYSR_SPEEDL			GENMASK(5, 4) | 
|---|
| 139 | #define RTL_VND2_PHYSR_SPEEDH			GENMASK(10, 9) | 
|---|
| 140 | #define RTL_VND2_PHYSR_MASTER			BIT(11) | 
|---|
| 141 | #define RTL_VND2_PHYSR_SPEED_MASK		(RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) | 
|---|
| 142 |  | 
|---|
| 143 | #define	RTL_MDIO_PCS_EEE_ABLE			0xa5c4 | 
|---|
| 144 | #define	RTL_MDIO_AN_EEE_ADV			0xa5d0 | 
|---|
| 145 | #define	RTL_MDIO_AN_EEE_LPABLE			0xa5d2 | 
|---|
| 146 | #define	RTL_MDIO_AN_10GBT_CTRL			0xa5d4 | 
|---|
| 147 | #define	RTL_MDIO_AN_10GBT_STAT			0xa5d6 | 
|---|
| 148 | #define	RTL_MDIO_PMA_SPEED			0xa616 | 
|---|
| 149 | #define	RTL_MDIO_AN_EEE_LPABLE2			0xa6d0 | 
|---|
| 150 | #define	RTL_MDIO_AN_EEE_ADV2			0xa6d4 | 
|---|
| 151 | #define	RTL_MDIO_PCS_EEE_ABLE2			0xa6ec | 
|---|
| 152 |  | 
|---|
| 153 | #define RTL_GENERIC_PHYID			0x001cc800 | 
|---|
| 154 | #define RTL_8211FVD_PHYID			0x001cc878 | 
|---|
| 155 | #define RTL_8221B				0x001cc840 | 
|---|
| 156 | #define RTL_8221B_VB_CG				0x001cc849 | 
|---|
| 157 | #define RTL_8221B_VN_CG				0x001cc84a | 
|---|
| 158 | #define RTL_8251B				0x001cc862 | 
|---|
| 159 | #define RTL_8261C				0x001cc890 | 
|---|
| 160 |  | 
|---|
| 161 | /* RTL8211E and RTL8211F support up to three LEDs */ | 
|---|
| 162 | #define RTL8211x_LED_COUNT			3 | 
|---|
| 163 |  | 
|---|
| 164 | MODULE_DESCRIPTION( "Realtek PHY driver"); | 
|---|
| 165 | MODULE_AUTHOR( "Johnson Leung"); | 
|---|
| 166 | MODULE_LICENSE( "GPL"); | 
|---|
| 167 |  | 
|---|
| 168 | struct rtl821x_priv { | 
|---|
| 169 | u16 phycr1; | 
|---|
| 170 | u16 phycr2; | 
|---|
| 171 | bool has_phycr2; | 
|---|
| 172 | struct clk *clk; | 
|---|
| 173 | /* rtl8211f */ | 
|---|
| 174 | u16 iner; | 
|---|
| 175 | }; | 
|---|
| 176 |  | 
|---|
| 177 | static int rtl821x_read_page(struct phy_device *phydev) | 
|---|
| 178 | { | 
|---|
| 179 | return __phy_read(phydev, RTL821x_PAGE_SELECT); | 
|---|
| 180 | } | 
|---|
| 181 |  | 
|---|
| 182 | static int rtl821x_write_page(struct phy_device *phydev, int page) | 
|---|
| 183 | { | 
|---|
| 184 | return __phy_write(phydev, RTL821x_PAGE_SELECT, val: page); | 
|---|
| 185 | } | 
|---|
| 186 |  | 
|---|
| 187 | static int rtl821x_read_ext_page(struct phy_device *phydev, u16 ext_page, | 
|---|
| 188 | u32 regnum) | 
|---|
| 189 | { | 
|---|
| 190 | int oldpage, ret = 0; | 
|---|
| 191 |  | 
|---|
| 192 | oldpage = phy_select_page(phydev, RTL821x_SET_EXT_PAGE); | 
|---|
| 193 | if (oldpage >= 0) { | 
|---|
| 194 | ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, val: ext_page); | 
|---|
| 195 | if (ret == 0) | 
|---|
| 196 | ret = __phy_read(phydev, regnum); | 
|---|
| 197 | } | 
|---|
| 198 |  | 
|---|
| 199 | return phy_restore_page(phydev, oldpage, ret); | 
|---|
| 200 | } | 
|---|
| 201 |  | 
|---|
| 202 | static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page, | 
|---|
| 203 | u32 regnum, u16 mask, u16 set) | 
|---|
| 204 | { | 
|---|
| 205 | int oldpage, ret = 0; | 
|---|
| 206 |  | 
|---|
| 207 | oldpage = phy_select_page(phydev, RTL821x_SET_EXT_PAGE); | 
|---|
| 208 | if (oldpage >= 0) { | 
|---|
| 209 | ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, val: ext_page); | 
|---|
| 210 | if (ret == 0) | 
|---|
| 211 | ret = __phy_modify(phydev, regnum, mask, set); | 
|---|
| 212 | } | 
|---|
| 213 |  | 
|---|
| 214 | return phy_restore_page(phydev, oldpage, ret); | 
|---|
| 215 | } | 
|---|
| 216 |  | 
|---|
| 217 | static int rtl821x_probe(struct phy_device *phydev) | 
|---|
| 218 | { | 
|---|
| 219 | struct device *dev = &phydev->mdio.dev; | 
|---|
| 220 | struct rtl821x_priv *priv; | 
|---|
| 221 | u32 phy_id = phydev->drv->phy_id; | 
|---|
| 222 | int ret; | 
|---|
| 223 |  | 
|---|
| 224 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); | 
|---|
| 225 | if (!priv) | 
|---|
| 226 | return -ENOMEM; | 
|---|
| 227 |  | 
|---|
| 228 | priv->clk = devm_clk_get_optional_enabled(dev, NULL); | 
|---|
| 229 | if (IS_ERR(ptr: priv->clk)) | 
|---|
| 230 | return dev_err_probe(dev, err: PTR_ERR(ptr: priv->clk), | 
|---|
| 231 | fmt: "failed to get phy clock\n"); | 
|---|
| 232 |  | 
|---|
| 233 | ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1); | 
|---|
| 234 | if (ret < 0) | 
|---|
| 235 | return ret; | 
|---|
| 236 |  | 
|---|
| 237 | priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); | 
|---|
| 238 | if (of_property_read_bool(np: dev->of_node, propname: "realtek,aldps-enable")) | 
|---|
| 239 | priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; | 
|---|
| 240 |  | 
|---|
| 241 | priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); | 
|---|
| 242 | if (priv->has_phycr2) { | 
|---|
| 243 | ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2); | 
|---|
| 244 | if (ret < 0) | 
|---|
| 245 | return ret; | 
|---|
| 246 |  | 
|---|
| 247 | priv->phycr2 = ret & RTL8211F_CLKOUT_EN; | 
|---|
| 248 | if (of_property_read_bool(np: dev->of_node, propname: "realtek,clkout-disable")) | 
|---|
| 249 | priv->phycr2 &= ~RTL8211F_CLKOUT_EN; | 
|---|
| 250 | } | 
|---|
| 251 |  | 
|---|
| 252 | phydev->priv = priv; | 
|---|
| 253 |  | 
|---|
| 254 | return 0; | 
|---|
| 255 | } | 
|---|
| 256 |  | 
|---|
| 257 | static int rtl8211f_probe(struct phy_device *phydev) | 
|---|
| 258 | { | 
|---|
| 259 | struct device *dev = &phydev->mdio.dev; | 
|---|
| 260 | int ret; | 
|---|
| 261 |  | 
|---|
| 262 | ret = rtl821x_probe(phydev); | 
|---|
| 263 | if (ret < 0) | 
|---|
| 264 | return ret; | 
|---|
| 265 |  | 
|---|
| 266 | /* Disable all PME events */ | 
|---|
| 267 | ret = phy_write_paged(phydev, RTL8211F_WOL_PAGE, | 
|---|
| 268 | RTL8211F_WOL_SETTINGS_EVENTS, val: 0); | 
|---|
| 269 | if (ret < 0) | 
|---|
| 270 | return ret; | 
|---|
| 271 |  | 
|---|
| 272 | /* Mark this PHY as wakeup capable and register the interrupt as a | 
|---|
| 273 | * wakeup IRQ if the PHY is marked as a wakeup source in firmware, | 
|---|
| 274 | * and the interrupt is valid. | 
|---|
| 275 | */ | 
|---|
| 276 | if (device_property_read_bool(dev, propname: "wakeup-source") && | 
|---|
| 277 | phy_interrupt_is_valid(phydev)) { | 
|---|
| 278 | device_set_wakeup_capable(dev, capable: true); | 
|---|
| 279 | devm_pm_set_wake_irq(dev, irq: phydev->irq); | 
|---|
| 280 | } | 
|---|
| 281 |  | 
|---|
| 282 | return ret; | 
|---|
| 283 | } | 
|---|
| 284 |  | 
|---|
| 285 | static int rtl8201_ack_interrupt(struct phy_device *phydev) | 
|---|
| 286 | { | 
|---|
| 287 | int err; | 
|---|
| 288 |  | 
|---|
| 289 | err = phy_read(phydev, RTL8201F_ISR); | 
|---|
| 290 |  | 
|---|
| 291 | return (err < 0) ? err : 0; | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 | static int rtl821x_ack_interrupt(struct phy_device *phydev) | 
|---|
| 295 | { | 
|---|
| 296 | int err; | 
|---|
| 297 |  | 
|---|
| 298 | err = phy_read(phydev, RTL821x_INSR); | 
|---|
| 299 |  | 
|---|
| 300 | return (err < 0) ? err : 0; | 
|---|
| 301 | } | 
|---|
| 302 |  | 
|---|
| 303 | static int rtl8211f_ack_interrupt(struct phy_device *phydev) | 
|---|
| 304 | { | 
|---|
| 305 | int err; | 
|---|
| 306 |  | 
|---|
| 307 | err = phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR); | 
|---|
| 308 |  | 
|---|
| 309 | return (err < 0) ? err : 0; | 
|---|
| 310 | } | 
|---|
| 311 |  | 
|---|
| 312 | static int rtl8201_config_intr(struct phy_device *phydev) | 
|---|
| 313 | { | 
|---|
| 314 | u16 val; | 
|---|
| 315 | int err; | 
|---|
| 316 |  | 
|---|
| 317 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { | 
|---|
| 318 | err = rtl8201_ack_interrupt(phydev); | 
|---|
| 319 | if (err) | 
|---|
| 320 | return err; | 
|---|
| 321 |  | 
|---|
| 322 | val = BIT(13) | BIT(12) | BIT(11); | 
|---|
| 323 | err = phy_write_paged(phydev, page: 0x7, RTL8201F_IER, val); | 
|---|
| 324 | } else { | 
|---|
| 325 | val = 0; | 
|---|
| 326 | err = phy_write_paged(phydev, page: 0x7, RTL8201F_IER, val); | 
|---|
| 327 | if (err) | 
|---|
| 328 | return err; | 
|---|
| 329 |  | 
|---|
| 330 | err = rtl8201_ack_interrupt(phydev); | 
|---|
| 331 | } | 
|---|
| 332 |  | 
|---|
| 333 | return err; | 
|---|
| 334 | } | 
|---|
| 335 |  | 
|---|
| 336 | static int rtl8211b_config_intr(struct phy_device *phydev) | 
|---|
| 337 | { | 
|---|
| 338 | int err; | 
|---|
| 339 |  | 
|---|
| 340 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { | 
|---|
| 341 | err = rtl821x_ack_interrupt(phydev); | 
|---|
| 342 | if (err) | 
|---|
| 343 | return err; | 
|---|
| 344 |  | 
|---|
| 345 | err = phy_write(phydev, RTL821x_INER, | 
|---|
| 346 | RTL8211B_INER_INIT); | 
|---|
| 347 | } else { | 
|---|
| 348 | err = phy_write(phydev, RTL821x_INER, val: 0); | 
|---|
| 349 | if (err) | 
|---|
| 350 | return err; | 
|---|
| 351 |  | 
|---|
| 352 | err = rtl821x_ack_interrupt(phydev); | 
|---|
| 353 | } | 
|---|
| 354 |  | 
|---|
| 355 | return err; | 
|---|
| 356 | } | 
|---|
| 357 |  | 
|---|
| 358 | static int rtl8211e_config_intr(struct phy_device *phydev) | 
|---|
| 359 | { | 
|---|
| 360 | int err; | 
|---|
| 361 |  | 
|---|
| 362 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { | 
|---|
| 363 | err = rtl821x_ack_interrupt(phydev); | 
|---|
| 364 | if (err) | 
|---|
| 365 | return err; | 
|---|
| 366 |  | 
|---|
| 367 | err = phy_write(phydev, RTL821x_INER, | 
|---|
| 368 | RTL8211E_INER_LINK_STATUS); | 
|---|
| 369 | } else { | 
|---|
| 370 | err = phy_write(phydev, RTL821x_INER, val: 0); | 
|---|
| 371 | if (err) | 
|---|
| 372 | return err; | 
|---|
| 373 |  | 
|---|
| 374 | err = rtl821x_ack_interrupt(phydev); | 
|---|
| 375 | } | 
|---|
| 376 |  | 
|---|
| 377 | return err; | 
|---|
| 378 | } | 
|---|
| 379 |  | 
|---|
| 380 | static int rtl8211f_config_intr(struct phy_device *phydev) | 
|---|
| 381 | { | 
|---|
| 382 | struct rtl821x_priv *priv = phydev->priv; | 
|---|
| 383 | u16 val; | 
|---|
| 384 | int err; | 
|---|
| 385 |  | 
|---|
| 386 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { | 
|---|
| 387 | err = rtl8211f_ack_interrupt(phydev); | 
|---|
| 388 | if (err) | 
|---|
| 389 | return err; | 
|---|
| 390 |  | 
|---|
| 391 | val = RTL8211F_INER_LINK_STATUS; | 
|---|
| 392 | err = phy_write_paged(phydev, page: 0xa42, RTL821x_INER, val); | 
|---|
| 393 | if (err == 0) | 
|---|
| 394 | priv->iner = val; | 
|---|
| 395 | } else { | 
|---|
| 396 | priv->iner = val = 0; | 
|---|
| 397 | err = phy_write_paged(phydev, page: 0xa42, RTL821x_INER, val); | 
|---|
| 398 | if (err) | 
|---|
| 399 | return err; | 
|---|
| 400 |  | 
|---|
| 401 | err = rtl8211f_ack_interrupt(phydev); | 
|---|
| 402 | } | 
|---|
| 403 |  | 
|---|
| 404 | return err; | 
|---|
| 405 | } | 
|---|
| 406 |  | 
|---|
| 407 | static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev) | 
|---|
| 408 | { | 
|---|
| 409 | int irq_status; | 
|---|
| 410 |  | 
|---|
| 411 | irq_status = phy_read(phydev, RTL8201F_ISR); | 
|---|
| 412 | if (irq_status < 0) { | 
|---|
| 413 | phy_error(phydev); | 
|---|
| 414 | return IRQ_NONE; | 
|---|
| 415 | } | 
|---|
| 416 |  | 
|---|
| 417 | if (!(irq_status & RTL8201F_ISR_MASK)) | 
|---|
| 418 | return IRQ_NONE; | 
|---|
| 419 |  | 
|---|
| 420 | phy_trigger_machine(phydev); | 
|---|
| 421 |  | 
|---|
| 422 | return IRQ_HANDLED; | 
|---|
| 423 | } | 
|---|
| 424 |  | 
|---|
| 425 | static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev) | 
|---|
| 426 | { | 
|---|
| 427 | int irq_status, irq_enabled; | 
|---|
| 428 |  | 
|---|
| 429 | irq_status = phy_read(phydev, RTL821x_INSR); | 
|---|
| 430 | if (irq_status < 0) { | 
|---|
| 431 | phy_error(phydev); | 
|---|
| 432 | return IRQ_NONE; | 
|---|
| 433 | } | 
|---|
| 434 |  | 
|---|
| 435 | irq_enabled = phy_read(phydev, RTL821x_INER); | 
|---|
| 436 | if (irq_enabled < 0) { | 
|---|
| 437 | phy_error(phydev); | 
|---|
| 438 | return IRQ_NONE; | 
|---|
| 439 | } | 
|---|
| 440 |  | 
|---|
| 441 | if (!(irq_status & irq_enabled)) | 
|---|
| 442 | return IRQ_NONE; | 
|---|
| 443 |  | 
|---|
| 444 | phy_trigger_machine(phydev); | 
|---|
| 445 |  | 
|---|
| 446 | return IRQ_HANDLED; | 
|---|
| 447 | } | 
|---|
| 448 |  | 
|---|
| 449 | static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) | 
|---|
| 450 | { | 
|---|
| 451 | int irq_status; | 
|---|
| 452 |  | 
|---|
| 453 | irq_status = phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR); | 
|---|
| 454 | if (irq_status < 0) { | 
|---|
| 455 | phy_error(phydev); | 
|---|
| 456 | return IRQ_NONE; | 
|---|
| 457 | } | 
|---|
| 458 |  | 
|---|
| 459 | if (irq_status & RTL8211F_INER_LINK_STATUS) { | 
|---|
| 460 | phy_trigger_machine(phydev); | 
|---|
| 461 | return IRQ_HANDLED; | 
|---|
| 462 | } | 
|---|
| 463 |  | 
|---|
| 464 | if (irq_status & RTL8211F_INER_PME) { | 
|---|
| 465 | pm_wakeup_event(dev: &phydev->mdio.dev, msec: 0); | 
|---|
| 466 | return IRQ_HANDLED; | 
|---|
| 467 | } | 
|---|
| 468 |  | 
|---|
| 469 | return IRQ_NONE; | 
|---|
| 470 | } | 
|---|
| 471 |  | 
|---|
| 472 | static void rtl8211f_get_wol(struct phy_device *dev, struct ethtool_wolinfo *wol) | 
|---|
| 473 | { | 
|---|
| 474 | int wol_events; | 
|---|
| 475 |  | 
|---|
| 476 | /* If the PHY is not capable of waking the system, then WoL can not | 
|---|
| 477 | * be supported. | 
|---|
| 478 | */ | 
|---|
| 479 | if (!device_can_wakeup(dev: &dev->mdio.dev)) { | 
|---|
| 480 | wol->supported = 0; | 
|---|
| 481 | return; | 
|---|
| 482 | } | 
|---|
| 483 |  | 
|---|
| 484 | wol->supported = WAKE_MAGIC; | 
|---|
| 485 |  | 
|---|
| 486 | wol_events = phy_read_paged(phydev: dev, RTL8211F_WOL_PAGE, RTL8211F_WOL_SETTINGS_EVENTS); | 
|---|
| 487 | if (wol_events < 0) | 
|---|
| 488 | return; | 
|---|
| 489 |  | 
|---|
| 490 | if (wol_events & RTL8211F_WOL_EVENT_MAGIC) | 
|---|
| 491 | wol->wolopts = WAKE_MAGIC; | 
|---|
| 492 | } | 
|---|
| 493 |  | 
|---|
| 494 | static int rtl8211f_set_wol(struct phy_device *dev, struct ethtool_wolinfo *wol) | 
|---|
| 495 | { | 
|---|
| 496 | const u8 *mac_addr = dev->attached_dev->dev_addr; | 
|---|
| 497 | int oldpage; | 
|---|
| 498 |  | 
|---|
| 499 | if (!device_can_wakeup(dev: &dev->mdio.dev)) | 
|---|
| 500 | return -EOPNOTSUPP; | 
|---|
| 501 |  | 
|---|
| 502 | oldpage = phy_save_page(phydev: dev); | 
|---|
| 503 | if (oldpage < 0) | 
|---|
| 504 | goto err; | 
|---|
| 505 |  | 
|---|
| 506 | if (wol->wolopts & WAKE_MAGIC) { | 
|---|
| 507 | /* Store the device address for the magic packet */ | 
|---|
| 508 | rtl821x_write_page(phydev: dev, RTL8211F_PHYSICAL_ADDR_PAGE); | 
|---|
| 509 | __phy_write(phydev: dev, RTL8211F_PHYSICAL_ADDR_WORD0, val: mac_addr[1] << 8 | (mac_addr[0])); | 
|---|
| 510 | __phy_write(phydev: dev, RTL8211F_PHYSICAL_ADDR_WORD1, val: mac_addr[3] << 8 | (mac_addr[2])); | 
|---|
| 511 | __phy_write(phydev: dev, RTL8211F_PHYSICAL_ADDR_WORD2, val: mac_addr[5] << 8 | (mac_addr[4])); | 
|---|
| 512 |  | 
|---|
| 513 | /* Enable magic packet matching */ | 
|---|
| 514 | rtl821x_write_page(phydev: dev, RTL8211F_WOL_PAGE); | 
|---|
| 515 | __phy_write(phydev: dev, RTL8211F_WOL_SETTINGS_EVENTS, RTL8211F_WOL_EVENT_MAGIC); | 
|---|
| 516 | /* Set the maximum packet size, and assert WoL reset */ | 
|---|
| 517 | __phy_write(phydev: dev, RTL8211F_WOL_RST_RMSQ, RTL8211F_WOL_RMSQ); | 
|---|
| 518 | } else { | 
|---|
| 519 | /* Disable magic packet matching */ | 
|---|
| 520 | rtl821x_write_page(phydev: dev, RTL8211F_WOL_PAGE); | 
|---|
| 521 | __phy_write(phydev: dev, RTL8211F_WOL_SETTINGS_EVENTS, val: 0); | 
|---|
| 522 |  | 
|---|
| 523 | /* Place WoL in reset */ | 
|---|
| 524 | __phy_clear_bits(phydev: dev, RTL8211F_WOL_RST_RMSQ, | 
|---|
| 525 | RTL8211F_WOL_RG_RSTB); | 
|---|
| 526 | } | 
|---|
| 527 |  | 
|---|
| 528 | device_set_wakeup_enable(dev: &dev->mdio.dev, enable: !!(wol->wolopts & WAKE_MAGIC)); | 
|---|
| 529 |  | 
|---|
| 530 | err: | 
|---|
| 531 | return phy_restore_page(phydev: dev, oldpage, ret: 0); | 
|---|
| 532 | } | 
|---|
| 533 |  | 
|---|
| 534 | static int rtl8211_config_aneg(struct phy_device *phydev) | 
|---|
| 535 | { | 
|---|
| 536 | int ret; | 
|---|
| 537 |  | 
|---|
| 538 | ret = genphy_config_aneg(phydev); | 
|---|
| 539 | if (ret < 0) | 
|---|
| 540 | return ret; | 
|---|
| 541 |  | 
|---|
| 542 | /* Quirk was copied from vendor driver. Unfortunately it includes no | 
|---|
| 543 | * description of the magic numbers. | 
|---|
| 544 | */ | 
|---|
| 545 | if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) { | 
|---|
| 546 | phy_write(phydev, regnum: 0x17, val: 0x2138); | 
|---|
| 547 | phy_write(phydev, regnum: 0x0e, val: 0x0260); | 
|---|
| 548 | } else { | 
|---|
| 549 | phy_write(phydev, regnum: 0x17, val: 0x2108); | 
|---|
| 550 | phy_write(phydev, regnum: 0x0e, val: 0x0000); | 
|---|
| 551 | } | 
|---|
| 552 |  | 
|---|
| 553 | return 0; | 
|---|
| 554 | } | 
|---|
| 555 |  | 
|---|
| 556 | static int rtl8211c_config_init(struct phy_device *phydev) | 
|---|
| 557 | { | 
|---|
| 558 | /* RTL8211C has an issue when operating in Gigabit slave mode */ | 
|---|
| 559 | return phy_set_bits(phydev, MII_CTRL1000, | 
|---|
| 560 | CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); | 
|---|
| 561 | } | 
|---|
| 562 |  | 
|---|
| 563 | static int rtl8211f_config_init(struct phy_device *phydev) | 
|---|
| 564 | { | 
|---|
| 565 | struct rtl821x_priv *priv = phydev->priv; | 
|---|
| 566 | struct device *dev = &phydev->mdio.dev; | 
|---|
| 567 | u16 val_txdly, val_rxdly; | 
|---|
| 568 | int ret; | 
|---|
| 569 |  | 
|---|
| 570 | ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1, | 
|---|
| 571 | RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, | 
|---|
| 572 | set: priv->phycr1); | 
|---|
| 573 | if (ret < 0) { | 
|---|
| 574 | dev_err(dev, "aldps mode  configuration failed: %pe\n", | 
|---|
| 575 | ERR_PTR(ret)); | 
|---|
| 576 | return ret; | 
|---|
| 577 | } | 
|---|
| 578 |  | 
|---|
| 579 | switch (phydev->interface) { | 
|---|
| 580 | case PHY_INTERFACE_MODE_RGMII: | 
|---|
| 581 | val_txdly = 0; | 
|---|
| 582 | val_rxdly = 0; | 
|---|
| 583 | break; | 
|---|
| 584 |  | 
|---|
| 585 | case PHY_INTERFACE_MODE_RGMII_RXID: | 
|---|
| 586 | val_txdly = 0; | 
|---|
| 587 | val_rxdly = RTL8211F_RX_DELAY; | 
|---|
| 588 | break; | 
|---|
| 589 |  | 
|---|
| 590 | case PHY_INTERFACE_MODE_RGMII_TXID: | 
|---|
| 591 | val_txdly = RTL8211F_TX_DELAY; | 
|---|
| 592 | val_rxdly = 0; | 
|---|
| 593 | break; | 
|---|
| 594 |  | 
|---|
| 595 | case PHY_INTERFACE_MODE_RGMII_ID: | 
|---|
| 596 | val_txdly = RTL8211F_TX_DELAY; | 
|---|
| 597 | val_rxdly = RTL8211F_RX_DELAY; | 
|---|
| 598 | break; | 
|---|
| 599 |  | 
|---|
| 600 | default: /* the rest of the modes imply leaving delay as is. */ | 
|---|
| 601 | return 0; | 
|---|
| 602 | } | 
|---|
| 603 |  | 
|---|
| 604 | ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE, | 
|---|
| 605 | RTL8211F_TXCR, RTL8211F_TX_DELAY, | 
|---|
| 606 | set: val_txdly); | 
|---|
| 607 | if (ret < 0) { | 
|---|
| 608 | dev_err(dev, "Failed to update the TX delay register\n"); | 
|---|
| 609 | return ret; | 
|---|
| 610 | } else if (ret) { | 
|---|
| 611 | dev_dbg(dev, | 
|---|
| 612 | "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", | 
|---|
| 613 | str_enable_disable(val_txdly)); | 
|---|
| 614 | } else { | 
|---|
| 615 | dev_dbg(dev, | 
|---|
| 616 | "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", | 
|---|
| 617 | str_enabled_disabled(val_txdly)); | 
|---|
| 618 | } | 
|---|
| 619 |  | 
|---|
| 620 | ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE, | 
|---|
| 621 | RTL8211F_RXCR, RTL8211F_RX_DELAY, | 
|---|
| 622 | set: val_rxdly); | 
|---|
| 623 | if (ret < 0) { | 
|---|
| 624 | dev_err(dev, "Failed to update the RX delay register\n"); | 
|---|
| 625 | return ret; | 
|---|
| 626 | } else if (ret) { | 
|---|
| 627 | dev_dbg(dev, | 
|---|
| 628 | "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", | 
|---|
| 629 | str_enable_disable(val_rxdly)); | 
|---|
| 630 | } else { | 
|---|
| 631 | dev_dbg(dev, | 
|---|
| 632 | "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", | 
|---|
| 633 | str_enabled_disabled(val_rxdly)); | 
|---|
| 634 | } | 
|---|
| 635 |  | 
|---|
| 636 | /* Disable PHY-mode EEE so LPI is passed to the MAC */ | 
|---|
| 637 | ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2, | 
|---|
| 638 | RTL8211F_PHYCR2_PHY_EEE_ENABLE, set: 0); | 
|---|
| 639 | if (ret) | 
|---|
| 640 | return ret; | 
|---|
| 641 |  | 
|---|
| 642 | if (priv->has_phycr2) { | 
|---|
| 643 | ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, | 
|---|
| 644 | RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, | 
|---|
| 645 | set: priv->phycr2); | 
|---|
| 646 | if (ret < 0) { | 
|---|
| 647 | dev_err(dev, "clkout configuration failed: %pe\n", | 
|---|
| 648 | ERR_PTR(ret)); | 
|---|
| 649 | return ret; | 
|---|
| 650 | } | 
|---|
| 651 |  | 
|---|
| 652 | return genphy_soft_reset(phydev); | 
|---|
| 653 | } | 
|---|
| 654 |  | 
|---|
| 655 | return 0; | 
|---|
| 656 | } | 
|---|
| 657 |  | 
|---|
| 658 | static int rtl821x_suspend(struct phy_device *phydev) | 
|---|
| 659 | { | 
|---|
| 660 | struct rtl821x_priv *priv = phydev->priv; | 
|---|
| 661 | int ret = 0; | 
|---|
| 662 |  | 
|---|
| 663 | if (!phydev->wol_enabled) { | 
|---|
| 664 | ret = genphy_suspend(phydev); | 
|---|
| 665 |  | 
|---|
| 666 | if (ret) | 
|---|
| 667 | return ret; | 
|---|
| 668 |  | 
|---|
| 669 | clk_disable_unprepare(clk: priv->clk); | 
|---|
| 670 | } | 
|---|
| 671 |  | 
|---|
| 672 | return ret; | 
|---|
| 673 | } | 
|---|
| 674 |  | 
|---|
| 675 | static int rtl8211f_suspend(struct phy_device *phydev) | 
|---|
| 676 | { | 
|---|
| 677 | u16 wol_rst; | 
|---|
| 678 | int ret; | 
|---|
| 679 |  | 
|---|
| 680 | ret = rtl821x_suspend(phydev); | 
|---|
| 681 | if (ret < 0) | 
|---|
| 682 | return ret; | 
|---|
| 683 |  | 
|---|
| 684 | /* If a PME event is enabled, then configure the interrupt for | 
|---|
| 685 | * PME events only, disabling link interrupt. We avoid switching | 
|---|
| 686 | * to PMEB mode as we don't have a status bit for that. | 
|---|
| 687 | */ | 
|---|
| 688 | if (device_may_wakeup(dev: &phydev->mdio.dev)) { | 
|---|
| 689 | ret = phy_write_paged(phydev, page: 0xa42, RTL821x_INER, | 
|---|
| 690 | RTL8211F_INER_PME); | 
|---|
| 691 | if (ret < 0) | 
|---|
| 692 | goto err; | 
|---|
| 693 |  | 
|---|
| 694 | /* Read the INSR to clear any pending interrupt */ | 
|---|
| 695 | phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR); | 
|---|
| 696 |  | 
|---|
| 697 | /* Reset the WoL to ensure that an event is picked up. | 
|---|
| 698 | * Unless we do this, even if we receive another packet, | 
|---|
| 699 | * we may not have a PME interrupt raised. | 
|---|
| 700 | */ | 
|---|
| 701 | ret = phy_read_paged(phydev, RTL8211F_WOL_PAGE, | 
|---|
| 702 | RTL8211F_WOL_RST_RMSQ); | 
|---|
| 703 | if (ret < 0) | 
|---|
| 704 | goto err; | 
|---|
| 705 |  | 
|---|
| 706 | wol_rst = ret & ~RTL8211F_WOL_RG_RSTB; | 
|---|
| 707 | ret = phy_write_paged(phydev, RTL8211F_WOL_PAGE, | 
|---|
| 708 | RTL8211F_WOL_RST_RMSQ, val: wol_rst); | 
|---|
| 709 | if (ret < 0) | 
|---|
| 710 | goto err; | 
|---|
| 711 |  | 
|---|
| 712 | wol_rst |= RTL8211F_WOL_RG_RSTB; | 
|---|
| 713 | ret = phy_write_paged(phydev, RTL8211F_WOL_PAGE, | 
|---|
| 714 | RTL8211F_WOL_RST_RMSQ, val: wol_rst); | 
|---|
| 715 | } | 
|---|
| 716 |  | 
|---|
| 717 | err: | 
|---|
| 718 | return ret; | 
|---|
| 719 | } | 
|---|
| 720 |  | 
|---|
| 721 | static int rtl821x_resume(struct phy_device *phydev) | 
|---|
| 722 | { | 
|---|
| 723 | struct rtl821x_priv *priv = phydev->priv; | 
|---|
| 724 | int ret; | 
|---|
| 725 |  | 
|---|
| 726 | if (!phydev->wol_enabled) | 
|---|
| 727 | clk_prepare_enable(clk: priv->clk); | 
|---|
| 728 |  | 
|---|
| 729 | ret = genphy_resume(phydev); | 
|---|
| 730 | if (ret < 0) | 
|---|
| 731 | return ret; | 
|---|
| 732 |  | 
|---|
| 733 | msleep(msecs: 20); | 
|---|
| 734 |  | 
|---|
| 735 | return 0; | 
|---|
| 736 | } | 
|---|
| 737 |  | 
|---|
| 738 | static int rtl8211f_resume(struct phy_device *phydev) | 
|---|
| 739 | { | 
|---|
| 740 | struct rtl821x_priv *priv = phydev->priv; | 
|---|
| 741 | int ret; | 
|---|
| 742 |  | 
|---|
| 743 | ret = rtl821x_resume(phydev); | 
|---|
| 744 | if (ret < 0) | 
|---|
| 745 | return ret; | 
|---|
| 746 |  | 
|---|
| 747 | /* If the device was programmed for a PME event, restore the interrupt | 
|---|
| 748 | * enable so phylib can receive link state interrupts. | 
|---|
| 749 | */ | 
|---|
| 750 | if (device_may_wakeup(dev: &phydev->mdio.dev)) | 
|---|
| 751 | ret = phy_write_paged(phydev, page: 0xa42, RTL821x_INER, val: priv->iner); | 
|---|
| 752 |  | 
|---|
| 753 | return ret; | 
|---|
| 754 | } | 
|---|
| 755 |  | 
|---|
| 756 | static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index, | 
|---|
| 757 | unsigned long rules) | 
|---|
| 758 | { | 
|---|
| 759 | const unsigned long mask = BIT(TRIGGER_NETDEV_LINK) | | 
|---|
| 760 | BIT(TRIGGER_NETDEV_LINK_10) | | 
|---|
| 761 | BIT(TRIGGER_NETDEV_LINK_100) | | 
|---|
| 762 | BIT(TRIGGER_NETDEV_LINK_1000) | | 
|---|
| 763 | BIT(TRIGGER_NETDEV_RX) | | 
|---|
| 764 | BIT(TRIGGER_NETDEV_TX); | 
|---|
| 765 |  | 
|---|
| 766 | /* The RTL8211F PHY supports these LED settings on up to three LEDs: | 
|---|
| 767 | * - Link: Configurable subset of 10/100/1000 link rates | 
|---|
| 768 | * - Active: Blink on activity, RX or TX is not differentiated | 
|---|
| 769 | * The Active option has two modes, A and B: | 
|---|
| 770 | * - A: Link and Active indication at configurable, but matching, | 
|---|
| 771 | *      subset of 10/100/1000 link rates | 
|---|
| 772 | * - B: Link indication at configurable subset of 10/100/1000 link | 
|---|
| 773 | *      rates and Active indication always at all three 10+100+1000 | 
|---|
| 774 | *      link rates. | 
|---|
| 775 | * This code currently uses mode B only. | 
|---|
| 776 | * | 
|---|
| 777 | * RTL8211E PHY LED has one mode, which works like RTL8211F mode B. | 
|---|
| 778 | */ | 
|---|
| 779 |  | 
|---|
| 780 | if (index >= RTL8211x_LED_COUNT) | 
|---|
| 781 | return -EINVAL; | 
|---|
| 782 |  | 
|---|
| 783 | /* Filter out any other unsupported triggers. */ | 
|---|
| 784 | if (rules & ~mask) | 
|---|
| 785 | return -EOPNOTSUPP; | 
|---|
| 786 |  | 
|---|
| 787 | /* RX and TX are not differentiated, either both are set or not set. */ | 
|---|
| 788 | if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX))) | 
|---|
| 789 | return -EOPNOTSUPP; | 
|---|
| 790 |  | 
|---|
| 791 | return 0; | 
|---|
| 792 | } | 
|---|
| 793 |  | 
|---|
| 794 | static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, | 
|---|
| 795 | unsigned long *rules) | 
|---|
| 796 | { | 
|---|
| 797 | int val; | 
|---|
| 798 |  | 
|---|
| 799 | if (index >= RTL8211x_LED_COUNT) | 
|---|
| 800 | return -EINVAL; | 
|---|
| 801 |  | 
|---|
| 802 | val = phy_read_paged(phydev, page: 0xd04, RTL8211F_LEDCR); | 
|---|
| 803 | if (val < 0) | 
|---|
| 804 | return val; | 
|---|
| 805 |  | 
|---|
| 806 | val >>= RTL8211F_LEDCR_SHIFT * index; | 
|---|
| 807 | val &= RTL8211F_LEDCR_MASK; | 
|---|
| 808 |  | 
|---|
| 809 | if (val & RTL8211F_LEDCR_LINK_10) | 
|---|
| 810 | __set_bit(TRIGGER_NETDEV_LINK_10, rules); | 
|---|
| 811 |  | 
|---|
| 812 | if (val & RTL8211F_LEDCR_LINK_100) | 
|---|
| 813 | __set_bit(TRIGGER_NETDEV_LINK_100, rules); | 
|---|
| 814 |  | 
|---|
| 815 | if (val & RTL8211F_LEDCR_LINK_1000) | 
|---|
| 816 | __set_bit(TRIGGER_NETDEV_LINK_1000, rules); | 
|---|
| 817 |  | 
|---|
| 818 | if ((val & RTL8211F_LEDCR_LINK_10) && | 
|---|
| 819 | (val & RTL8211F_LEDCR_LINK_100) && | 
|---|
| 820 | (val & RTL8211F_LEDCR_LINK_1000)) { | 
|---|
| 821 | __set_bit(TRIGGER_NETDEV_LINK, rules); | 
|---|
| 822 | } | 
|---|
| 823 |  | 
|---|
| 824 | if (val & RTL8211F_LEDCR_ACT_TXRX) { | 
|---|
| 825 | __set_bit(TRIGGER_NETDEV_RX, rules); | 
|---|
| 826 | __set_bit(TRIGGER_NETDEV_TX, rules); | 
|---|
| 827 | } | 
|---|
| 828 |  | 
|---|
| 829 | return 0; | 
|---|
| 830 | } | 
|---|
| 831 |  | 
|---|
| 832 | static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, | 
|---|
| 833 | unsigned long rules) | 
|---|
| 834 | { | 
|---|
| 835 | const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); | 
|---|
| 836 | u16 reg = 0; | 
|---|
| 837 |  | 
|---|
| 838 | if (index >= RTL8211x_LED_COUNT) | 
|---|
| 839 | return -EINVAL; | 
|---|
| 840 |  | 
|---|
| 841 | if (test_bit(TRIGGER_NETDEV_LINK, &rules) || | 
|---|
| 842 | test_bit(TRIGGER_NETDEV_LINK_10, &rules)) { | 
|---|
| 843 | reg |= RTL8211F_LEDCR_LINK_10; | 
|---|
| 844 | } | 
|---|
| 845 |  | 
|---|
| 846 | if (test_bit(TRIGGER_NETDEV_LINK, &rules) || | 
|---|
| 847 | test_bit(TRIGGER_NETDEV_LINK_100, &rules)) { | 
|---|
| 848 | reg |= RTL8211F_LEDCR_LINK_100; | 
|---|
| 849 | } | 
|---|
| 850 |  | 
|---|
| 851 | if (test_bit(TRIGGER_NETDEV_LINK, &rules) || | 
|---|
| 852 | test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) { | 
|---|
| 853 | reg |= RTL8211F_LEDCR_LINK_1000; | 
|---|
| 854 | } | 
|---|
| 855 |  | 
|---|
| 856 | if (test_bit(TRIGGER_NETDEV_RX, &rules) || | 
|---|
| 857 | test_bit(TRIGGER_NETDEV_TX, &rules)) { | 
|---|
| 858 | reg |= RTL8211F_LEDCR_ACT_TXRX; | 
|---|
| 859 | } | 
|---|
| 860 |  | 
|---|
| 861 | reg <<= RTL8211F_LEDCR_SHIFT * index; | 
|---|
| 862 | reg |= RTL8211F_LEDCR_MODE;	 /* Mode B */ | 
|---|
| 863 |  | 
|---|
| 864 | return phy_modify_paged(phydev, page: 0xd04, RTL8211F_LEDCR, mask, set: reg); | 
|---|
| 865 | } | 
|---|
| 866 |  | 
|---|
| 867 | static int rtl8211e_led_hw_control_get(struct phy_device *phydev, u8 index, | 
|---|
| 868 | unsigned long *rules) | 
|---|
| 869 | { | 
|---|
| 870 | int ret; | 
|---|
| 871 | u16 cr1, cr2; | 
|---|
| 872 |  | 
|---|
| 873 | if (index >= RTL8211x_LED_COUNT) | 
|---|
| 874 | return -EINVAL; | 
|---|
| 875 |  | 
|---|
| 876 | ret = rtl821x_read_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, | 
|---|
| 877 | RTL8211E_LEDCR1); | 
|---|
| 878 | if (ret < 0) | 
|---|
| 879 | return ret; | 
|---|
| 880 |  | 
|---|
| 881 | cr1 = ret >> RTL8211E_LEDCR1_SHIFT * index; | 
|---|
| 882 | if (cr1 & RTL8211E_LEDCR1_ACT_TXRX) { | 
|---|
| 883 | __set_bit(TRIGGER_NETDEV_RX, rules); | 
|---|
| 884 | __set_bit(TRIGGER_NETDEV_TX, rules); | 
|---|
| 885 | } | 
|---|
| 886 |  | 
|---|
| 887 | ret = rtl821x_read_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, | 
|---|
| 888 | RTL8211E_LEDCR2); | 
|---|
| 889 | if (ret < 0) | 
|---|
| 890 | return ret; | 
|---|
| 891 |  | 
|---|
| 892 | cr2 = ret >> RTL8211E_LEDCR2_SHIFT * index; | 
|---|
| 893 | if (cr2 & RTL8211E_LEDCR2_LINK_10) | 
|---|
| 894 | __set_bit(TRIGGER_NETDEV_LINK_10, rules); | 
|---|
| 895 |  | 
|---|
| 896 | if (cr2 & RTL8211E_LEDCR2_LINK_100) | 
|---|
| 897 | __set_bit(TRIGGER_NETDEV_LINK_100, rules); | 
|---|
| 898 |  | 
|---|
| 899 | if (cr2 & RTL8211E_LEDCR2_LINK_1000) | 
|---|
| 900 | __set_bit(TRIGGER_NETDEV_LINK_1000, rules); | 
|---|
| 901 |  | 
|---|
| 902 | if ((cr2 & RTL8211E_LEDCR2_LINK_10) && | 
|---|
| 903 | (cr2 & RTL8211E_LEDCR2_LINK_100) && | 
|---|
| 904 | (cr2 & RTL8211E_LEDCR2_LINK_1000)) { | 
|---|
| 905 | __set_bit(TRIGGER_NETDEV_LINK, rules); | 
|---|
| 906 | } | 
|---|
| 907 |  | 
|---|
| 908 | return ret; | 
|---|
| 909 | } | 
|---|
| 910 |  | 
|---|
| 911 | static int rtl8211e_led_hw_control_set(struct phy_device *phydev, u8 index, | 
|---|
| 912 | unsigned long rules) | 
|---|
| 913 | { | 
|---|
| 914 | const u16 cr1mask = | 
|---|
| 915 | RTL8211E_LEDCR1_MASK << (RTL8211E_LEDCR1_SHIFT * index); | 
|---|
| 916 | const u16 cr2mask = | 
|---|
| 917 | RTL8211E_LEDCR2_MASK << (RTL8211E_LEDCR2_SHIFT * index); | 
|---|
| 918 | u16 cr1 = 0, cr2 = 0; | 
|---|
| 919 | int ret; | 
|---|
| 920 |  | 
|---|
| 921 | if (index >= RTL8211x_LED_COUNT) | 
|---|
| 922 | return -EINVAL; | 
|---|
| 923 |  | 
|---|
| 924 | if (test_bit(TRIGGER_NETDEV_RX, &rules) || | 
|---|
| 925 | test_bit(TRIGGER_NETDEV_TX, &rules)) { | 
|---|
| 926 | cr1 |= RTL8211E_LEDCR1_ACT_TXRX; | 
|---|
| 927 | } | 
|---|
| 928 |  | 
|---|
| 929 | cr1 <<= RTL8211E_LEDCR1_SHIFT * index; | 
|---|
| 930 | ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, | 
|---|
| 931 | RTL8211E_LEDCR1, mask: cr1mask, set: cr1); | 
|---|
| 932 | if (ret < 0) | 
|---|
| 933 | return ret; | 
|---|
| 934 |  | 
|---|
| 935 | if (test_bit(TRIGGER_NETDEV_LINK, &rules) || | 
|---|
| 936 | test_bit(TRIGGER_NETDEV_LINK_10, &rules)) { | 
|---|
| 937 | cr2 |= RTL8211E_LEDCR2_LINK_10; | 
|---|
| 938 | } | 
|---|
| 939 |  | 
|---|
| 940 | if (test_bit(TRIGGER_NETDEV_LINK, &rules) || | 
|---|
| 941 | test_bit(TRIGGER_NETDEV_LINK_100, &rules)) { | 
|---|
| 942 | cr2 |= RTL8211E_LEDCR2_LINK_100; | 
|---|
| 943 | } | 
|---|
| 944 |  | 
|---|
| 945 | if (test_bit(TRIGGER_NETDEV_LINK, &rules) || | 
|---|
| 946 | test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) { | 
|---|
| 947 | cr2 |= RTL8211E_LEDCR2_LINK_1000; | 
|---|
| 948 | } | 
|---|
| 949 |  | 
|---|
| 950 | cr2 <<= RTL8211E_LEDCR2_SHIFT * index; | 
|---|
| 951 | ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, | 
|---|
| 952 | RTL8211E_LEDCR2, mask: cr2mask, set: cr2); | 
|---|
| 953 |  | 
|---|
| 954 | return ret; | 
|---|
| 955 | } | 
|---|
| 956 |  | 
|---|
| 957 | static int rtl8211e_config_init(struct phy_device *phydev) | 
|---|
| 958 | { | 
|---|
| 959 | u16 val; | 
|---|
| 960 |  | 
|---|
| 961 | /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ | 
|---|
| 962 | switch (phydev->interface) { | 
|---|
| 963 | case PHY_INTERFACE_MODE_RGMII: | 
|---|
| 964 | val = RTL8211E_CTRL_DELAY | 0; | 
|---|
| 965 | break; | 
|---|
| 966 | case PHY_INTERFACE_MODE_RGMII_ID: | 
|---|
| 967 | val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; | 
|---|
| 968 | break; | 
|---|
| 969 | case PHY_INTERFACE_MODE_RGMII_RXID: | 
|---|
| 970 | val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY; | 
|---|
| 971 | break; | 
|---|
| 972 | case PHY_INTERFACE_MODE_RGMII_TXID: | 
|---|
| 973 | val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY; | 
|---|
| 974 | break; | 
|---|
| 975 | default: /* the rest of the modes imply leaving delays as is. */ | 
|---|
| 976 | return 0; | 
|---|
| 977 | } | 
|---|
| 978 |  | 
|---|
| 979 | /* According to a sample driver there is a 0x1c config register on the | 
|---|
| 980 | * 0xa4 extension page (0x7) layout. It can be used to disable/enable | 
|---|
| 981 | * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. | 
|---|
| 982 | * The configuration register definition: | 
|---|
| 983 | * 14 = reserved | 
|---|
| 984 | * 13 = Force Tx RX Delay controlled by bit12 bit11, | 
|---|
| 985 | * 12 = RX Delay, 11 = TX Delay | 
|---|
| 986 | * 10:0 = Test && debug settings reserved by realtek | 
|---|
| 987 | */ | 
|---|
| 988 | return rtl821x_modify_ext_page(phydev, RTL8211E_RGMII_EXT_PAGE, | 
|---|
| 989 | RTL8211E_RGMII_DELAY, | 
|---|
| 990 | RTL8211E_DELAY_MASK, set: val); | 
|---|
| 991 | } | 
|---|
| 992 |  | 
|---|
| 993 | static int rtl8211b_suspend(struct phy_device *phydev) | 
|---|
| 994 | { | 
|---|
| 995 | phy_write(phydev, MII_MMD_DATA, BIT(9)); | 
|---|
| 996 |  | 
|---|
| 997 | return genphy_suspend(phydev); | 
|---|
| 998 | } | 
|---|
| 999 |  | 
|---|
| 1000 | static int rtl8211b_resume(struct phy_device *phydev) | 
|---|
| 1001 | { | 
|---|
| 1002 | phy_write(phydev, MII_MMD_DATA, val: 0); | 
|---|
| 1003 |  | 
|---|
| 1004 | return genphy_resume(phydev); | 
|---|
| 1005 | } | 
|---|
| 1006 |  | 
|---|
| 1007 | static int rtl8366rb_config_init(struct phy_device *phydev) | 
|---|
| 1008 | { | 
|---|
| 1009 | int ret; | 
|---|
| 1010 |  | 
|---|
| 1011 | ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE, | 
|---|
| 1012 | RTL8366RB_POWER_SAVE_ON); | 
|---|
| 1013 | if (ret) { | 
|---|
| 1014 | dev_err(&phydev->mdio.dev, | 
|---|
| 1015 | "error enabling power management\n"); | 
|---|
| 1016 | } | 
|---|
| 1017 |  | 
|---|
| 1018 | return ret; | 
|---|
| 1019 | } | 
|---|
| 1020 |  | 
|---|
| 1021 | /* get actual speed to cover the downshift case */ | 
|---|
| 1022 | static void rtlgen_decode_physr(struct phy_device *phydev, int val) | 
|---|
| 1023 | { | 
|---|
| 1024 | /* bit 3 | 
|---|
| 1025 | * 0: Half Duplex | 
|---|
| 1026 | * 1: Full Duplex | 
|---|
| 1027 | */ | 
|---|
| 1028 | if (val & RTL_VND2_PHYSR_DUPLEX) | 
|---|
| 1029 | phydev->duplex = DUPLEX_FULL; | 
|---|
| 1030 | else | 
|---|
| 1031 | phydev->duplex = DUPLEX_HALF; | 
|---|
| 1032 |  | 
|---|
| 1033 | switch (val & RTL_VND2_PHYSR_SPEED_MASK) { | 
|---|
| 1034 | case 0x0000: | 
|---|
| 1035 | phydev->speed = SPEED_10; | 
|---|
| 1036 | break; | 
|---|
| 1037 | case 0x0010: | 
|---|
| 1038 | phydev->speed = SPEED_100; | 
|---|
| 1039 | break; | 
|---|
| 1040 | case 0x0020: | 
|---|
| 1041 | phydev->speed = SPEED_1000; | 
|---|
| 1042 | break; | 
|---|
| 1043 | case 0x0200: | 
|---|
| 1044 | phydev->speed = SPEED_10000; | 
|---|
| 1045 | break; | 
|---|
| 1046 | case 0x0210: | 
|---|
| 1047 | phydev->speed = SPEED_2500; | 
|---|
| 1048 | break; | 
|---|
| 1049 | case 0x0220: | 
|---|
| 1050 | phydev->speed = SPEED_5000; | 
|---|
| 1051 | break; | 
|---|
| 1052 | default: | 
|---|
| 1053 | break; | 
|---|
| 1054 | } | 
|---|
| 1055 |  | 
|---|
| 1056 | /* bit 11 | 
|---|
| 1057 | * 0: Slave Mode | 
|---|
| 1058 | * 1: Master Mode | 
|---|
| 1059 | */ | 
|---|
| 1060 | if (phydev->speed >= 1000) { | 
|---|
| 1061 | if (val & RTL_VND2_PHYSR_MASTER) | 
|---|
| 1062 | phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; | 
|---|
| 1063 | else | 
|---|
| 1064 | phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; | 
|---|
| 1065 | } else { | 
|---|
| 1066 | phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; | 
|---|
| 1067 | } | 
|---|
| 1068 | } | 
|---|
| 1069 |  | 
|---|
| 1070 | static int rtlgen_read_status(struct phy_device *phydev) | 
|---|
| 1071 | { | 
|---|
| 1072 | int ret, val; | 
|---|
| 1073 |  | 
|---|
| 1074 | ret = genphy_read_status(phydev); | 
|---|
| 1075 | if (ret < 0) | 
|---|
| 1076 | return ret; | 
|---|
| 1077 |  | 
|---|
| 1078 | if (!phydev->link) | 
|---|
| 1079 | return 0; | 
|---|
| 1080 |  | 
|---|
| 1081 | val = phy_read_paged(phydev, page: 0xa43, regnum: 0x12); | 
|---|
| 1082 | if (val < 0) | 
|---|
| 1083 | return val; | 
|---|
| 1084 |  | 
|---|
| 1085 | rtlgen_decode_physr(phydev, val); | 
|---|
| 1086 |  | 
|---|
| 1087 | return 0; | 
|---|
| 1088 | } | 
|---|
| 1089 |  | 
|---|
| 1090 | static int rtlgen_read_vend2(struct phy_device *phydev, int regnum) | 
|---|
| 1091 | { | 
|---|
| 1092 | return __mdiobus_c45_read(bus: phydev->mdio.bus, addr: 0, MDIO_MMD_VEND2, regnum); | 
|---|
| 1093 | } | 
|---|
| 1094 |  | 
|---|
| 1095 | static int rtlgen_write_vend2(struct phy_device *phydev, int regnum, u16 val) | 
|---|
| 1096 | { | 
|---|
| 1097 | return __mdiobus_c45_write(bus: phydev->mdio.bus, addr: 0, MDIO_MMD_VEND2, regnum, | 
|---|
| 1098 | val); | 
|---|
| 1099 | } | 
|---|
| 1100 |  | 
|---|
| 1101 | static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) | 
|---|
| 1102 | { | 
|---|
| 1103 | int ret; | 
|---|
| 1104 |  | 
|---|
| 1105 | if (devnum == MDIO_MMD_VEND2) | 
|---|
| 1106 | ret = rtlgen_read_vend2(phydev, regnum); | 
|---|
| 1107 | else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) | 
|---|
| 1108 | ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE); | 
|---|
| 1109 | else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) | 
|---|
| 1110 | ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV); | 
|---|
| 1111 | else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) | 
|---|
| 1112 | ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE); | 
|---|
| 1113 | else | 
|---|
| 1114 | ret = -EOPNOTSUPP; | 
|---|
| 1115 |  | 
|---|
| 1116 | return ret; | 
|---|
| 1117 | } | 
|---|
| 1118 |  | 
|---|
| 1119 | static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, | 
|---|
| 1120 | u16 val) | 
|---|
| 1121 | { | 
|---|
| 1122 | int ret; | 
|---|
| 1123 |  | 
|---|
| 1124 | if (devnum == MDIO_MMD_VEND2) | 
|---|
| 1125 | ret = rtlgen_write_vend2(phydev, regnum, val); | 
|---|
| 1126 | else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) | 
|---|
| 1127 | ret = rtlgen_write_vend2(phydev, regnum, RTL_MDIO_AN_EEE_ADV); | 
|---|
| 1128 | else | 
|---|
| 1129 | ret = -EOPNOTSUPP; | 
|---|
| 1130 |  | 
|---|
| 1131 | return ret; | 
|---|
| 1132 | } | 
|---|
| 1133 |  | 
|---|
| 1134 | static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) | 
|---|
| 1135 | { | 
|---|
| 1136 | int ret = rtlgen_read_mmd(phydev, devnum, regnum); | 
|---|
| 1137 |  | 
|---|
| 1138 | if (ret != -EOPNOTSUPP) | 
|---|
| 1139 | return ret; | 
|---|
| 1140 |  | 
|---|
| 1141 | if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) | 
|---|
| 1142 | ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE2); | 
|---|
| 1143 | else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) | 
|---|
| 1144 | ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV2); | 
|---|
| 1145 | else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) | 
|---|
| 1146 | ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE2); | 
|---|
| 1147 |  | 
|---|
| 1148 | return ret; | 
|---|
| 1149 | } | 
|---|
| 1150 |  | 
|---|
| 1151 | static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, | 
|---|
| 1152 | u16 val) | 
|---|
| 1153 | { | 
|---|
| 1154 | int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); | 
|---|
| 1155 |  | 
|---|
| 1156 | if (ret != -EOPNOTSUPP) | 
|---|
| 1157 | return ret; | 
|---|
| 1158 |  | 
|---|
| 1159 | if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) | 
|---|
| 1160 | ret = rtlgen_write_vend2(phydev, RTL_MDIO_AN_EEE_ADV2, val); | 
|---|
| 1161 |  | 
|---|
| 1162 | return ret; | 
|---|
| 1163 | } | 
|---|
| 1164 |  | 
|---|
| 1165 | static int rtl822x_probe(struct phy_device *phydev) | 
|---|
| 1166 | { | 
|---|
| 1167 | if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) && | 
|---|
| 1168 | phydev->phy_id != RTL_GENERIC_PHYID) | 
|---|
| 1169 | return rtl822x_hwmon_init(phydev); | 
|---|
| 1170 |  | 
|---|
| 1171 | return 0; | 
|---|
| 1172 | } | 
|---|
| 1173 |  | 
|---|
| 1174 | static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) | 
|---|
| 1175 | { | 
|---|
| 1176 | bool has_2500, has_sgmii; | 
|---|
| 1177 | u16 mode; | 
|---|
| 1178 | int ret; | 
|---|
| 1179 |  | 
|---|
| 1180 | has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, | 
|---|
| 1181 | phydev->host_interfaces) || | 
|---|
| 1182 | phydev->interface == PHY_INTERFACE_MODE_2500BASEX; | 
|---|
| 1183 |  | 
|---|
| 1184 | has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII, | 
|---|
| 1185 | phydev->host_interfaces) || | 
|---|
| 1186 | phydev->interface == PHY_INTERFACE_MODE_SGMII; | 
|---|
| 1187 |  | 
|---|
| 1188 | /* fill in possible interfaces */ | 
|---|
| 1189 | __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, | 
|---|
| 1190 | has_2500); | 
|---|
| 1191 | __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces, | 
|---|
| 1192 | has_sgmii); | 
|---|
| 1193 |  | 
|---|
| 1194 | if (!has_2500 && !has_sgmii) | 
|---|
| 1195 | return 0; | 
|---|
| 1196 |  | 
|---|
| 1197 | /* determine SerDes option mode */ | 
|---|
| 1198 | if (has_2500 && !has_sgmii) { | 
|---|
| 1199 | mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX; | 
|---|
| 1200 | phydev->rate_matching = RATE_MATCH_PAUSE; | 
|---|
| 1201 | } else { | 
|---|
| 1202 | mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII; | 
|---|
| 1203 | phydev->rate_matching = RATE_MATCH_NONE; | 
|---|
| 1204 | } | 
|---|
| 1205 |  | 
|---|
| 1206 | /* the following sequence with magic numbers sets up the SerDes | 
|---|
| 1207 | * option mode | 
|---|
| 1208 | */ | 
|---|
| 1209 |  | 
|---|
| 1210 | if (!gen1) { | 
|---|
| 1211 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, regnum: 0x75f3, val: 0); | 
|---|
| 1212 | if (ret < 0) | 
|---|
| 1213 | return ret; | 
|---|
| 1214 | } | 
|---|
| 1215 |  | 
|---|
| 1216 | ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, | 
|---|
| 1217 | RTL822X_VND1_SERDES_OPTION, | 
|---|
| 1218 | RTL822X_VND1_SERDES_OPTION_MODE_MASK, | 
|---|
| 1219 | set: mode); | 
|---|
| 1220 | if (gen1 || ret < 0) | 
|---|
| 1221 | return ret; | 
|---|
| 1222 |  | 
|---|
| 1223 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, regnum: 0x6a04, val: 0x0503); | 
|---|
| 1224 | if (ret < 0) | 
|---|
| 1225 | return ret; | 
|---|
| 1226 |  | 
|---|
| 1227 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, regnum: 0x6f10, val: 0xd455); | 
|---|
| 1228 | if (ret < 0) | 
|---|
| 1229 | return ret; | 
|---|
| 1230 |  | 
|---|
| 1231 | return phy_write_mmd(phydev, MDIO_MMD_VEND1, regnum: 0x6f11, val: 0x8020); | 
|---|
| 1232 | } | 
|---|
| 1233 |  | 
|---|
| 1234 | static int rtl822x_config_init(struct phy_device *phydev) | 
|---|
| 1235 | { | 
|---|
| 1236 | return rtl822x_set_serdes_option_mode(phydev, gen1: true); | 
|---|
| 1237 | } | 
|---|
| 1238 |  | 
|---|
| 1239 | static int rtl822xb_config_init(struct phy_device *phydev) | 
|---|
| 1240 | { | 
|---|
| 1241 | return rtl822x_set_serdes_option_mode(phydev, gen1: false); | 
|---|
| 1242 | } | 
|---|
| 1243 |  | 
|---|
| 1244 | static int rtl822xb_get_rate_matching(struct phy_device *phydev, | 
|---|
| 1245 | phy_interface_t iface) | 
|---|
| 1246 | { | 
|---|
| 1247 | int val; | 
|---|
| 1248 |  | 
|---|
| 1249 | /* Only rate matching at 2500base-x */ | 
|---|
| 1250 | if (iface != PHY_INTERFACE_MODE_2500BASEX) | 
|---|
| 1251 | return RATE_MATCH_NONE; | 
|---|
| 1252 |  | 
|---|
| 1253 | val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION); | 
|---|
| 1254 | if (val < 0) | 
|---|
| 1255 | return val; | 
|---|
| 1256 |  | 
|---|
| 1257 | if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) == | 
|---|
| 1258 | RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX) | 
|---|
| 1259 | return RATE_MATCH_PAUSE; | 
|---|
| 1260 |  | 
|---|
| 1261 | /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */ | 
|---|
| 1262 | return RATE_MATCH_NONE; | 
|---|
| 1263 | } | 
|---|
| 1264 |  | 
|---|
| 1265 | static int rtl822x_get_features(struct phy_device *phydev) | 
|---|
| 1266 | { | 
|---|
| 1267 | int val; | 
|---|
| 1268 |  | 
|---|
| 1269 | val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_PMA_SPEED); | 
|---|
| 1270 | if (val < 0) | 
|---|
| 1271 | return val; | 
|---|
| 1272 |  | 
|---|
| 1273 | linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, | 
|---|
| 1274 | phydev->supported, val & MDIO_PMA_SPEED_2_5G); | 
|---|
| 1275 | linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, | 
|---|
| 1276 | phydev->supported, val & MDIO_PMA_SPEED_5G); | 
|---|
| 1277 | linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, | 
|---|
| 1278 | phydev->supported, val & MDIO_SPEED_10G); | 
|---|
| 1279 |  | 
|---|
| 1280 | return genphy_read_abilities(phydev); | 
|---|
| 1281 | } | 
|---|
| 1282 |  | 
|---|
| 1283 | static int rtl822x_config_aneg(struct phy_device *phydev) | 
|---|
| 1284 | { | 
|---|
| 1285 | int ret = 0; | 
|---|
| 1286 |  | 
|---|
| 1287 | if (phydev->autoneg == AUTONEG_ENABLE) { | 
|---|
| 1288 | u16 adv = linkmode_adv_to_mii_10gbt_adv_t(advertising: phydev->advertising); | 
|---|
| 1289 |  | 
|---|
| 1290 | ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, | 
|---|
| 1291 | RTL_MDIO_AN_10GBT_CTRL, | 
|---|
| 1292 | MDIO_AN_10GBT_CTRL_ADV2_5G | | 
|---|
| 1293 | MDIO_AN_10GBT_CTRL_ADV5G, set: adv); | 
|---|
| 1294 | if (ret < 0) | 
|---|
| 1295 | return ret; | 
|---|
| 1296 | } | 
|---|
| 1297 |  | 
|---|
| 1298 | return __genphy_config_aneg(phydev, changed: ret); | 
|---|
| 1299 | } | 
|---|
| 1300 |  | 
|---|
| 1301 | static void rtl822xb_update_interface(struct phy_device *phydev) | 
|---|
| 1302 | { | 
|---|
| 1303 | int val; | 
|---|
| 1304 |  | 
|---|
| 1305 | if (!phydev->link) | 
|---|
| 1306 | return; | 
|---|
| 1307 |  | 
|---|
| 1308 | /* Change interface according to serdes mode */ | 
|---|
| 1309 | val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3); | 
|---|
| 1310 | if (val < 0) | 
|---|
| 1311 | return; | 
|---|
| 1312 |  | 
|---|
| 1313 | switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) { | 
|---|
| 1314 | case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX: | 
|---|
| 1315 | phydev->interface = PHY_INTERFACE_MODE_2500BASEX; | 
|---|
| 1316 | break; | 
|---|
| 1317 | case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII: | 
|---|
| 1318 | phydev->interface = PHY_INTERFACE_MODE_SGMII; | 
|---|
| 1319 | break; | 
|---|
| 1320 | } | 
|---|
| 1321 | } | 
|---|
| 1322 |  | 
|---|
| 1323 | static int rtl822x_read_status(struct phy_device *phydev) | 
|---|
| 1324 | { | 
|---|
| 1325 | int lpadv, ret; | 
|---|
| 1326 |  | 
|---|
| 1327 | mii_10gbt_stat_mod_linkmode_lpa_t(advertising: phydev->lp_advertising, lpa: 0); | 
|---|
| 1328 |  | 
|---|
| 1329 | ret = rtlgen_read_status(phydev); | 
|---|
| 1330 | if (ret < 0) | 
|---|
| 1331 | return ret; | 
|---|
| 1332 |  | 
|---|
| 1333 | if (phydev->autoneg == AUTONEG_DISABLE || | 
|---|
| 1334 | !phydev->autoneg_complete) | 
|---|
| 1335 | return 0; | 
|---|
| 1336 |  | 
|---|
| 1337 | lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_AN_10GBT_STAT); | 
|---|
| 1338 | if (lpadv < 0) | 
|---|
| 1339 | return lpadv; | 
|---|
| 1340 |  | 
|---|
| 1341 | mii_10gbt_stat_mod_linkmode_lpa_t(advertising: phydev->lp_advertising, lpa: lpadv); | 
|---|
| 1342 |  | 
|---|
| 1343 | return 0; | 
|---|
| 1344 | } | 
|---|
| 1345 |  | 
|---|
| 1346 | static int rtl822xb_read_status(struct phy_device *phydev) | 
|---|
| 1347 | { | 
|---|
| 1348 | int ret; | 
|---|
| 1349 |  | 
|---|
| 1350 | ret = rtl822x_read_status(phydev); | 
|---|
| 1351 | if (ret < 0) | 
|---|
| 1352 | return ret; | 
|---|
| 1353 |  | 
|---|
| 1354 | rtl822xb_update_interface(phydev); | 
|---|
| 1355 |  | 
|---|
| 1356 | return 0; | 
|---|
| 1357 | } | 
|---|
| 1358 |  | 
|---|
| 1359 | static int rtl822x_c45_get_features(struct phy_device *phydev) | 
|---|
| 1360 | { | 
|---|
| 1361 | linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, | 
|---|
| 1362 | phydev->supported); | 
|---|
| 1363 |  | 
|---|
| 1364 | return genphy_c45_pma_read_abilities(phydev); | 
|---|
| 1365 | } | 
|---|
| 1366 |  | 
|---|
| 1367 | static int rtl822x_c45_config_aneg(struct phy_device *phydev) | 
|---|
| 1368 | { | 
|---|
| 1369 | bool changed = false; | 
|---|
| 1370 | int ret, val; | 
|---|
| 1371 |  | 
|---|
| 1372 | if (phydev->autoneg == AUTONEG_DISABLE) | 
|---|
| 1373 | return genphy_c45_pma_setup_forced(phydev); | 
|---|
| 1374 |  | 
|---|
| 1375 | ret = genphy_c45_an_config_aneg(phydev); | 
|---|
| 1376 | if (ret < 0) | 
|---|
| 1377 | return ret; | 
|---|
| 1378 | if (ret > 0) | 
|---|
| 1379 | changed = true; | 
|---|
| 1380 |  | 
|---|
| 1381 | val = linkmode_adv_to_mii_ctrl1000_t(advertising: phydev->advertising); | 
|---|
| 1382 |  | 
|---|
| 1383 | /* Vendor register as C45 has no standardized support for 1000BaseT */ | 
|---|
| 1384 | ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, | 
|---|
| 1385 | RTL822X_VND2_C22_REG(MII_CTRL1000), | 
|---|
| 1386 | ADVERTISE_1000FULL, set: val); | 
|---|
| 1387 | if (ret < 0) | 
|---|
| 1388 | return ret; | 
|---|
| 1389 | if (ret > 0) | 
|---|
| 1390 | changed = true; | 
|---|
| 1391 |  | 
|---|
| 1392 | return genphy_c45_check_and_restart_aneg(phydev, restart: changed); | 
|---|
| 1393 | } | 
|---|
| 1394 |  | 
|---|
| 1395 | static int rtl822x_c45_read_status(struct phy_device *phydev) | 
|---|
| 1396 | { | 
|---|
| 1397 | int ret, val; | 
|---|
| 1398 |  | 
|---|
| 1399 | /* Vendor register as C45 has no standardized support for 1000BaseT */ | 
|---|
| 1400 | if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { | 
|---|
| 1401 | val = phy_read_mmd(phydev, MDIO_MMD_VEND2, | 
|---|
| 1402 | RTL822X_VND2_C22_REG(MII_STAT1000)); | 
|---|
| 1403 | if (val < 0) | 
|---|
| 1404 | return val; | 
|---|
| 1405 | } else { | 
|---|
| 1406 | val = 0; | 
|---|
| 1407 | } | 
|---|
| 1408 | mii_stat1000_mod_linkmode_lpa_t(advertising: phydev->lp_advertising, lpa: val); | 
|---|
| 1409 |  | 
|---|
| 1410 | ret = genphy_c45_read_status(phydev); | 
|---|
| 1411 | if (ret < 0) | 
|---|
| 1412 | return ret; | 
|---|
| 1413 |  | 
|---|
| 1414 | if (!phydev->link) { | 
|---|
| 1415 | phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; | 
|---|
| 1416 | return 0; | 
|---|
| 1417 | } | 
|---|
| 1418 |  | 
|---|
| 1419 | /* Read actual speed from vendor register. */ | 
|---|
| 1420 | val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); | 
|---|
| 1421 | if (val < 0) | 
|---|
| 1422 | return val; | 
|---|
| 1423 |  | 
|---|
| 1424 | rtlgen_decode_physr(phydev, val); | 
|---|
| 1425 |  | 
|---|
| 1426 | return 0; | 
|---|
| 1427 | } | 
|---|
| 1428 |  | 
|---|
| 1429 | static int rtl822x_c45_soft_reset(struct phy_device *phydev) | 
|---|
| 1430 | { | 
|---|
| 1431 | int ret, val; | 
|---|
| 1432 |  | 
|---|
| 1433 | ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, | 
|---|
| 1434 | MDIO_CTRL1_RESET, MDIO_CTRL1_RESET); | 
|---|
| 1435 | if (ret < 0) | 
|---|
| 1436 | return ret; | 
|---|
| 1437 |  | 
|---|
| 1438 | return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, | 
|---|
| 1439 | MDIO_CTRL1, val, | 
|---|
| 1440 | !(val & MDIO_CTRL1_RESET), | 
|---|
| 1441 | 5000, 100000, true); | 
|---|
| 1442 | } | 
|---|
| 1443 |  | 
|---|
| 1444 | static int rtl822xb_c45_read_status(struct phy_device *phydev) | 
|---|
| 1445 | { | 
|---|
| 1446 | int ret; | 
|---|
| 1447 |  | 
|---|
| 1448 | ret = rtl822x_c45_read_status(phydev); | 
|---|
| 1449 | if (ret < 0) | 
|---|
| 1450 | return ret; | 
|---|
| 1451 |  | 
|---|
| 1452 | rtl822xb_update_interface(phydev); | 
|---|
| 1453 |  | 
|---|
| 1454 | return 0; | 
|---|
| 1455 | } | 
|---|
| 1456 |  | 
|---|
| 1457 | static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) | 
|---|
| 1458 | { | 
|---|
| 1459 | int val; | 
|---|
| 1460 |  | 
|---|
| 1461 | phy_write(phydev, RTL821x_PAGE_SELECT, val: 0xa61); | 
|---|
| 1462 | val = phy_read(phydev, regnum: 0x13); | 
|---|
| 1463 | phy_write(phydev, RTL821x_PAGE_SELECT, val: 0); | 
|---|
| 1464 |  | 
|---|
| 1465 | return val >= 0 && val & MDIO_PMA_SPEED_2_5G; | 
|---|
| 1466 | } | 
|---|
| 1467 |  | 
|---|
| 1468 | /* On internal PHY's MMD reads over C22 always return 0. | 
|---|
| 1469 | * Check a MMD register which is known to be non-zero. | 
|---|
| 1470 | */ | 
|---|
| 1471 | static bool rtlgen_supports_mmd(struct phy_device *phydev) | 
|---|
| 1472 | { | 
|---|
| 1473 | int val; | 
|---|
| 1474 |  | 
|---|
| 1475 | phy_lock_mdio_bus(phydev); | 
|---|
| 1476 | __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); | 
|---|
| 1477 | __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); | 
|---|
| 1478 | __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); | 
|---|
| 1479 | val = __phy_read(phydev, MII_MMD_DATA); | 
|---|
| 1480 | phy_unlock_mdio_bus(phydev); | 
|---|
| 1481 |  | 
|---|
| 1482 | return val > 0; | 
|---|
| 1483 | } | 
|---|
| 1484 |  | 
|---|
| 1485 | static int rtlgen_match_phy_device(struct phy_device *phydev, | 
|---|
| 1486 | const struct phy_driver *phydrv) | 
|---|
| 1487 | { | 
|---|
| 1488 | return phydev->phy_id == RTL_GENERIC_PHYID && | 
|---|
| 1489 | !rtlgen_supports_2_5gbps(phydev); | 
|---|
| 1490 | } | 
|---|
| 1491 |  | 
|---|
| 1492 | static int rtl8226_match_phy_device(struct phy_device *phydev, | 
|---|
| 1493 | const struct phy_driver *phydrv) | 
|---|
| 1494 | { | 
|---|
| 1495 | return phydev->phy_id == RTL_GENERIC_PHYID && | 
|---|
| 1496 | rtlgen_supports_2_5gbps(phydev) && | 
|---|
| 1497 | rtlgen_supports_mmd(phydev); | 
|---|
| 1498 | } | 
|---|
| 1499 |  | 
|---|
| 1500 | static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, | 
|---|
| 1501 | bool is_c45) | 
|---|
| 1502 | { | 
|---|
| 1503 | if (phydev->is_c45) | 
|---|
| 1504 | return is_c45 && (id == phydev->c45_ids.device_ids[1]); | 
|---|
| 1505 | else | 
|---|
| 1506 | return !is_c45 && (id == phydev->phy_id); | 
|---|
| 1507 | } | 
|---|
| 1508 |  | 
|---|
| 1509 | static int rtl8221b_match_phy_device(struct phy_device *phydev, | 
|---|
| 1510 | const struct phy_driver *phydrv) | 
|---|
| 1511 | { | 
|---|
| 1512 | return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); | 
|---|
| 1513 | } | 
|---|
| 1514 |  | 
|---|
| 1515 | static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev, | 
|---|
| 1516 | const struct phy_driver *phydrv) | 
|---|
| 1517 | { | 
|---|
| 1518 | return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, is_c45: false); | 
|---|
| 1519 | } | 
|---|
| 1520 |  | 
|---|
| 1521 | static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev, | 
|---|
| 1522 | const struct phy_driver *phydrv) | 
|---|
| 1523 | { | 
|---|
| 1524 | return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, is_c45: true); | 
|---|
| 1525 | } | 
|---|
| 1526 |  | 
|---|
| 1527 | static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev, | 
|---|
| 1528 | const struct phy_driver *phydrv) | 
|---|
| 1529 | { | 
|---|
| 1530 | return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, is_c45: false); | 
|---|
| 1531 | } | 
|---|
| 1532 |  | 
|---|
| 1533 | static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev, | 
|---|
| 1534 | const struct phy_driver *phydrv) | 
|---|
| 1535 | { | 
|---|
| 1536 | return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, is_c45: true); | 
|---|
| 1537 | } | 
|---|
| 1538 |  | 
|---|
| 1539 | static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev, | 
|---|
| 1540 | const struct phy_driver *phydrv) | 
|---|
| 1541 | { | 
|---|
| 1542 | if (phydev->is_c45) | 
|---|
| 1543 | return false; | 
|---|
| 1544 |  | 
|---|
| 1545 | switch (phydev->phy_id) { | 
|---|
| 1546 | case RTL_GENERIC_PHYID: | 
|---|
| 1547 | case RTL_8221B: | 
|---|
| 1548 | case RTL_8251B: | 
|---|
| 1549 | case RTL_8261C: | 
|---|
| 1550 | case 0x001cc841: | 
|---|
| 1551 | break; | 
|---|
| 1552 | default: | 
|---|
| 1553 | return false; | 
|---|
| 1554 | } | 
|---|
| 1555 |  | 
|---|
| 1556 | return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); | 
|---|
| 1557 | } | 
|---|
| 1558 |  | 
|---|
| 1559 | static int rtl8251b_c45_match_phy_device(struct phy_device *phydev, | 
|---|
| 1560 | const struct phy_driver *phydrv) | 
|---|
| 1561 | { | 
|---|
| 1562 | return rtlgen_is_c45_match(phydev, RTL_8251B, is_c45: true); | 
|---|
| 1563 | } | 
|---|
| 1564 |  | 
|---|
| 1565 | static int rtlgen_resume(struct phy_device *phydev) | 
|---|
| 1566 | { | 
|---|
| 1567 | int ret = genphy_resume(phydev); | 
|---|
| 1568 |  | 
|---|
| 1569 | /* Internal PHY's from RTL8168h up may not be instantly ready */ | 
|---|
| 1570 | msleep(msecs: 20); | 
|---|
| 1571 |  | 
|---|
| 1572 | return ret; | 
|---|
| 1573 | } | 
|---|
| 1574 |  | 
|---|
| 1575 | static int rtlgen_c45_resume(struct phy_device *phydev) | 
|---|
| 1576 | { | 
|---|
| 1577 | int ret = genphy_c45_pma_resume(phydev); | 
|---|
| 1578 |  | 
|---|
| 1579 | msleep(msecs: 20); | 
|---|
| 1580 |  | 
|---|
| 1581 | return ret; | 
|---|
| 1582 | } | 
|---|
| 1583 |  | 
|---|
| 1584 | static int rtl9000a_config_init(struct phy_device *phydev) | 
|---|
| 1585 | { | 
|---|
| 1586 | phydev->autoneg = AUTONEG_DISABLE; | 
|---|
| 1587 | phydev->speed = SPEED_100; | 
|---|
| 1588 | phydev->duplex = DUPLEX_FULL; | 
|---|
| 1589 |  | 
|---|
| 1590 | return 0; | 
|---|
| 1591 | } | 
|---|
| 1592 |  | 
|---|
| 1593 | static int rtl9000a_config_aneg(struct phy_device *phydev) | 
|---|
| 1594 | { | 
|---|
| 1595 | int ret; | 
|---|
| 1596 | u16 ctl = 0; | 
|---|
| 1597 |  | 
|---|
| 1598 | switch (phydev->master_slave_set) { | 
|---|
| 1599 | case MASTER_SLAVE_CFG_MASTER_FORCE: | 
|---|
| 1600 | ctl |= CTL1000_AS_MASTER; | 
|---|
| 1601 | break; | 
|---|
| 1602 | case MASTER_SLAVE_CFG_SLAVE_FORCE: | 
|---|
| 1603 | break; | 
|---|
| 1604 | case MASTER_SLAVE_CFG_UNKNOWN: | 
|---|
| 1605 | case MASTER_SLAVE_CFG_UNSUPPORTED: | 
|---|
| 1606 | return 0; | 
|---|
| 1607 | default: | 
|---|
| 1608 | phydev_warn(phydev, "Unsupported Master/Slave mode\n"); | 
|---|
| 1609 | return -EOPNOTSUPP; | 
|---|
| 1610 | } | 
|---|
| 1611 |  | 
|---|
| 1612 | ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, set: ctl); | 
|---|
| 1613 | if (ret == 1) | 
|---|
| 1614 | ret = genphy_soft_reset(phydev); | 
|---|
| 1615 |  | 
|---|
| 1616 | return ret; | 
|---|
| 1617 | } | 
|---|
| 1618 |  | 
|---|
| 1619 | static int rtl9000a_read_status(struct phy_device *phydev) | 
|---|
| 1620 | { | 
|---|
| 1621 | int ret; | 
|---|
| 1622 |  | 
|---|
| 1623 | phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; | 
|---|
| 1624 | phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; | 
|---|
| 1625 |  | 
|---|
| 1626 | ret = genphy_update_link(phydev); | 
|---|
| 1627 | if (ret) | 
|---|
| 1628 | return ret; | 
|---|
| 1629 |  | 
|---|
| 1630 | ret = phy_read(phydev, MII_CTRL1000); | 
|---|
| 1631 | if (ret < 0) | 
|---|
| 1632 | return ret; | 
|---|
| 1633 | if (ret & CTL1000_AS_MASTER) | 
|---|
| 1634 | phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; | 
|---|
| 1635 | else | 
|---|
| 1636 | phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; | 
|---|
| 1637 |  | 
|---|
| 1638 | ret = phy_read(phydev, MII_STAT1000); | 
|---|
| 1639 | if (ret < 0) | 
|---|
| 1640 | return ret; | 
|---|
| 1641 | if (ret & LPA_1000MSRES) | 
|---|
| 1642 | phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; | 
|---|
| 1643 | else | 
|---|
| 1644 | phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; | 
|---|
| 1645 |  | 
|---|
| 1646 | return 0; | 
|---|
| 1647 | } | 
|---|
| 1648 |  | 
|---|
| 1649 | static int rtl9000a_ack_interrupt(struct phy_device *phydev) | 
|---|
| 1650 | { | 
|---|
| 1651 | int err; | 
|---|
| 1652 |  | 
|---|
| 1653 | err = phy_read(phydev, RTL8211F_INSR); | 
|---|
| 1654 |  | 
|---|
| 1655 | return (err < 0) ? err : 0; | 
|---|
| 1656 | } | 
|---|
| 1657 |  | 
|---|
| 1658 | static int rtl9000a_config_intr(struct phy_device *phydev) | 
|---|
| 1659 | { | 
|---|
| 1660 | u16 val; | 
|---|
| 1661 | int err; | 
|---|
| 1662 |  | 
|---|
| 1663 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { | 
|---|
| 1664 | err = rtl9000a_ack_interrupt(phydev); | 
|---|
| 1665 | if (err) | 
|---|
| 1666 | return err; | 
|---|
| 1667 |  | 
|---|
| 1668 | val = (u16)~RTL9000A_GINMR_LINK_STATUS; | 
|---|
| 1669 | err = phy_write_paged(phydev, page: 0xa42, RTL9000A_GINMR, val); | 
|---|
| 1670 | } else { | 
|---|
| 1671 | val = ~0; | 
|---|
| 1672 | err = phy_write_paged(phydev, page: 0xa42, RTL9000A_GINMR, val); | 
|---|
| 1673 | if (err) | 
|---|
| 1674 | return err; | 
|---|
| 1675 |  | 
|---|
| 1676 | err = rtl9000a_ack_interrupt(phydev); | 
|---|
| 1677 | } | 
|---|
| 1678 |  | 
|---|
| 1679 | return phy_write_paged(phydev, page: 0xa42, RTL9000A_GINMR, val); | 
|---|
| 1680 | } | 
|---|
| 1681 |  | 
|---|
| 1682 | static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) | 
|---|
| 1683 | { | 
|---|
| 1684 | int irq_status; | 
|---|
| 1685 |  | 
|---|
| 1686 | irq_status = phy_read(phydev, RTL8211F_INSR); | 
|---|
| 1687 | if (irq_status < 0) { | 
|---|
| 1688 | phy_error(phydev); | 
|---|
| 1689 | return IRQ_NONE; | 
|---|
| 1690 | } | 
|---|
| 1691 |  | 
|---|
| 1692 | if (!(irq_status & RTL8211F_INER_LINK_STATUS)) | 
|---|
| 1693 | return IRQ_NONE; | 
|---|
| 1694 |  | 
|---|
| 1695 | phy_trigger_machine(phydev); | 
|---|
| 1696 |  | 
|---|
| 1697 | return IRQ_HANDLED; | 
|---|
| 1698 | } | 
|---|
| 1699 |  | 
|---|
| 1700 | static struct phy_driver realtek_drvs[] = { | 
|---|
| 1701 | { | 
|---|
| 1702 | PHY_ID_MATCH_EXACT(0x00008201), | 
|---|
| 1703 | .name           = "RTL8201CP Ethernet", | 
|---|
| 1704 | .read_page	= rtl821x_read_page, | 
|---|
| 1705 | .write_page	= rtl821x_write_page, | 
|---|
| 1706 | }, { | 
|---|
| 1707 | PHY_ID_MATCH_EXACT(0x001cc816), | 
|---|
| 1708 | .name		= "RTL8201F Fast Ethernet", | 
|---|
| 1709 | .config_intr	= &rtl8201_config_intr, | 
|---|
| 1710 | .handle_interrupt = rtl8201_handle_interrupt, | 
|---|
| 1711 | .suspend	= genphy_suspend, | 
|---|
| 1712 | .resume		= genphy_resume, | 
|---|
| 1713 | .read_page	= rtl821x_read_page, | 
|---|
| 1714 | .write_page	= rtl821x_write_page, | 
|---|
| 1715 | }, { | 
|---|
| 1716 | PHY_ID_MATCH_MODEL(0x001cc880), | 
|---|
| 1717 | .name		= "RTL8208 Fast Ethernet", | 
|---|
| 1718 | .read_mmd	= genphy_read_mmd_unsupported, | 
|---|
| 1719 | .write_mmd	= genphy_write_mmd_unsupported, | 
|---|
| 1720 | .suspend	= genphy_suspend, | 
|---|
| 1721 | .resume		= genphy_resume, | 
|---|
| 1722 | .read_page	= rtl821x_read_page, | 
|---|
| 1723 | .write_page	= rtl821x_write_page, | 
|---|
| 1724 | }, { | 
|---|
| 1725 | PHY_ID_MATCH_EXACT(0x001cc910), | 
|---|
| 1726 | .name		= "RTL8211 Gigabit Ethernet", | 
|---|
| 1727 | .config_aneg	= rtl8211_config_aneg, | 
|---|
| 1728 | .read_mmd	= &genphy_read_mmd_unsupported, | 
|---|
| 1729 | .write_mmd	= &genphy_write_mmd_unsupported, | 
|---|
| 1730 | .read_page	= rtl821x_read_page, | 
|---|
| 1731 | .write_page	= rtl821x_write_page, | 
|---|
| 1732 | }, { | 
|---|
| 1733 | PHY_ID_MATCH_EXACT(0x001cc912), | 
|---|
| 1734 | .name		= "RTL8211B Gigabit Ethernet", | 
|---|
| 1735 | .config_intr	= &rtl8211b_config_intr, | 
|---|
| 1736 | .handle_interrupt = rtl821x_handle_interrupt, | 
|---|
| 1737 | .read_mmd	= &genphy_read_mmd_unsupported, | 
|---|
| 1738 | .write_mmd	= &genphy_write_mmd_unsupported, | 
|---|
| 1739 | .suspend	= rtl8211b_suspend, | 
|---|
| 1740 | .resume		= rtl8211b_resume, | 
|---|
| 1741 | .read_page	= rtl821x_read_page, | 
|---|
| 1742 | .write_page	= rtl821x_write_page, | 
|---|
| 1743 | }, { | 
|---|
| 1744 | PHY_ID_MATCH_EXACT(0x001cc913), | 
|---|
| 1745 | .name		= "RTL8211C Gigabit Ethernet", | 
|---|
| 1746 | .config_init	= rtl8211c_config_init, | 
|---|
| 1747 | .read_mmd	= &genphy_read_mmd_unsupported, | 
|---|
| 1748 | .write_mmd	= &genphy_write_mmd_unsupported, | 
|---|
| 1749 | .read_page	= rtl821x_read_page, | 
|---|
| 1750 | .write_page	= rtl821x_write_page, | 
|---|
| 1751 | }, { | 
|---|
| 1752 | PHY_ID_MATCH_EXACT(0x001cc914), | 
|---|
| 1753 | .name		= "RTL8211DN Gigabit Ethernet", | 
|---|
| 1754 | .config_intr	= rtl8211e_config_intr, | 
|---|
| 1755 | .handle_interrupt = rtl821x_handle_interrupt, | 
|---|
| 1756 | .suspend	= genphy_suspend, | 
|---|
| 1757 | .resume		= genphy_resume, | 
|---|
| 1758 | .read_page	= rtl821x_read_page, | 
|---|
| 1759 | .write_page	= rtl821x_write_page, | 
|---|
| 1760 | }, { | 
|---|
| 1761 | PHY_ID_MATCH_EXACT(0x001cc915), | 
|---|
| 1762 | .name		= "RTL8211E Gigabit Ethernet", | 
|---|
| 1763 | .config_init	= &rtl8211e_config_init, | 
|---|
| 1764 | .config_intr	= &rtl8211e_config_intr, | 
|---|
| 1765 | .handle_interrupt = rtl821x_handle_interrupt, | 
|---|
| 1766 | .suspend	= genphy_suspend, | 
|---|
| 1767 | .resume		= genphy_resume, | 
|---|
| 1768 | .read_page	= rtl821x_read_page, | 
|---|
| 1769 | .write_page	= rtl821x_write_page, | 
|---|
| 1770 | .led_hw_is_supported = rtl8211x_led_hw_is_supported, | 
|---|
| 1771 | .led_hw_control_get = rtl8211e_led_hw_control_get, | 
|---|
| 1772 | .led_hw_control_set = rtl8211e_led_hw_control_set, | 
|---|
| 1773 | }, { | 
|---|
| 1774 | PHY_ID_MATCH_EXACT(0x001cc916), | 
|---|
| 1775 | .name		= "RTL8211F Gigabit Ethernet", | 
|---|
| 1776 | .probe		= rtl8211f_probe, | 
|---|
| 1777 | .config_init	= &rtl8211f_config_init, | 
|---|
| 1778 | .read_status	= rtlgen_read_status, | 
|---|
| 1779 | .config_intr	= &rtl8211f_config_intr, | 
|---|
| 1780 | .handle_interrupt = rtl8211f_handle_interrupt, | 
|---|
| 1781 | .set_wol	= rtl8211f_set_wol, | 
|---|
| 1782 | .get_wol	= rtl8211f_get_wol, | 
|---|
| 1783 | .suspend	= rtl8211f_suspend, | 
|---|
| 1784 | .resume		= rtl8211f_resume, | 
|---|
| 1785 | .read_page	= rtl821x_read_page, | 
|---|
| 1786 | .write_page	= rtl821x_write_page, | 
|---|
| 1787 | .flags		= PHY_ALWAYS_CALL_SUSPEND, | 
|---|
| 1788 | .led_hw_is_supported = rtl8211x_led_hw_is_supported, | 
|---|
| 1789 | .led_hw_control_get = rtl8211f_led_hw_control_get, | 
|---|
| 1790 | .led_hw_control_set = rtl8211f_led_hw_control_set, | 
|---|
| 1791 | }, { | 
|---|
| 1792 | PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), | 
|---|
| 1793 | .name		= "RTL8211F-VD Gigabit Ethernet", | 
|---|
| 1794 | .probe		= rtl821x_probe, | 
|---|
| 1795 | .config_init	= &rtl8211f_config_init, | 
|---|
| 1796 | .read_status	= rtlgen_read_status, | 
|---|
| 1797 | .config_intr	= &rtl8211f_config_intr, | 
|---|
| 1798 | .handle_interrupt = rtl8211f_handle_interrupt, | 
|---|
| 1799 | .suspend	= rtl821x_suspend, | 
|---|
| 1800 | .resume		= rtl821x_resume, | 
|---|
| 1801 | .read_page	= rtl821x_read_page, | 
|---|
| 1802 | .write_page	= rtl821x_write_page, | 
|---|
| 1803 | .flags		= PHY_ALWAYS_CALL_SUSPEND, | 
|---|
| 1804 | }, { | 
|---|
| 1805 | .name		= "Generic FE-GE Realtek PHY", | 
|---|
| 1806 | .match_phy_device = rtlgen_match_phy_device, | 
|---|
| 1807 | .read_status	= rtlgen_read_status, | 
|---|
| 1808 | .suspend	= genphy_suspend, | 
|---|
| 1809 | .resume		= rtlgen_resume, | 
|---|
| 1810 | .read_page	= rtl821x_read_page, | 
|---|
| 1811 | .write_page	= rtl821x_write_page, | 
|---|
| 1812 | .read_mmd	= rtlgen_read_mmd, | 
|---|
| 1813 | .write_mmd	= rtlgen_write_mmd, | 
|---|
| 1814 | }, { | 
|---|
| 1815 | .name		= "RTL8226 2.5Gbps PHY", | 
|---|
| 1816 | .match_phy_device = rtl8226_match_phy_device, | 
|---|
| 1817 | .get_features	= rtl822x_get_features, | 
|---|
| 1818 | .config_aneg	= rtl822x_config_aneg, | 
|---|
| 1819 | .read_status	= rtl822x_read_status, | 
|---|
| 1820 | .suspend	= genphy_suspend, | 
|---|
| 1821 | .resume		= rtlgen_resume, | 
|---|
| 1822 | .read_page	= rtl821x_read_page, | 
|---|
| 1823 | .write_page	= rtl821x_write_page, | 
|---|
| 1824 | }, { | 
|---|
| 1825 | .match_phy_device = rtl8221b_match_phy_device, | 
|---|
| 1826 | .name		= "RTL8226B_RTL8221B 2.5Gbps PHY", | 
|---|
| 1827 | .get_features	= rtl822x_get_features, | 
|---|
| 1828 | .config_aneg	= rtl822x_config_aneg, | 
|---|
| 1829 | .config_init    = rtl822xb_config_init, | 
|---|
| 1830 | .get_rate_matching = rtl822xb_get_rate_matching, | 
|---|
| 1831 | .read_status	= rtl822xb_read_status, | 
|---|
| 1832 | .suspend	= genphy_suspend, | 
|---|
| 1833 | .resume		= rtlgen_resume, | 
|---|
| 1834 | .read_page	= rtl821x_read_page, | 
|---|
| 1835 | .write_page	= rtl821x_write_page, | 
|---|
| 1836 | }, { | 
|---|
| 1837 | PHY_ID_MATCH_EXACT(0x001cc838), | 
|---|
| 1838 | .name           = "RTL8226-CG 2.5Gbps PHY", | 
|---|
| 1839 | .soft_reset     = rtl822x_c45_soft_reset, | 
|---|
| 1840 | .get_features   = rtl822x_c45_get_features, | 
|---|
| 1841 | .config_aneg    = rtl822x_c45_config_aneg, | 
|---|
| 1842 | .config_init    = rtl822x_config_init, | 
|---|
| 1843 | .read_status    = rtl822xb_c45_read_status, | 
|---|
| 1844 | .suspend        = genphy_c45_pma_suspend, | 
|---|
| 1845 | .resume         = rtlgen_c45_resume, | 
|---|
| 1846 | }, { | 
|---|
| 1847 | PHY_ID_MATCH_EXACT(0x001cc848), | 
|---|
| 1848 | .name           = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", | 
|---|
| 1849 | .get_features   = rtl822x_get_features, | 
|---|
| 1850 | .config_aneg    = rtl822x_config_aneg, | 
|---|
| 1851 | .config_init    = rtl822xb_config_init, | 
|---|
| 1852 | .get_rate_matching = rtl822xb_get_rate_matching, | 
|---|
| 1853 | .read_status    = rtl822xb_read_status, | 
|---|
| 1854 | .suspend        = genphy_suspend, | 
|---|
| 1855 | .resume         = rtlgen_resume, | 
|---|
| 1856 | .read_page      = rtl821x_read_page, | 
|---|
| 1857 | .write_page     = rtl821x_write_page, | 
|---|
| 1858 | }, { | 
|---|
| 1859 | .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, | 
|---|
| 1860 | .name           = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", | 
|---|
| 1861 | .probe		= rtl822x_probe, | 
|---|
| 1862 | .get_features   = rtl822x_get_features, | 
|---|
| 1863 | .config_aneg    = rtl822x_config_aneg, | 
|---|
| 1864 | .config_init    = rtl822xb_config_init, | 
|---|
| 1865 | .get_rate_matching = rtl822xb_get_rate_matching, | 
|---|
| 1866 | .read_status    = rtl822xb_read_status, | 
|---|
| 1867 | .suspend        = genphy_suspend, | 
|---|
| 1868 | .resume         = rtlgen_resume, | 
|---|
| 1869 | .read_page      = rtl821x_read_page, | 
|---|
| 1870 | .write_page     = rtl821x_write_page, | 
|---|
| 1871 | }, { | 
|---|
| 1872 | .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, | 
|---|
| 1873 | .name           = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", | 
|---|
| 1874 | .probe		= rtl822x_probe, | 
|---|
| 1875 | .config_init    = rtl822xb_config_init, | 
|---|
| 1876 | .get_rate_matching = rtl822xb_get_rate_matching, | 
|---|
| 1877 | .get_features   = rtl822x_c45_get_features, | 
|---|
| 1878 | .config_aneg    = rtl822x_c45_config_aneg, | 
|---|
| 1879 | .read_status    = rtl822xb_c45_read_status, | 
|---|
| 1880 | .suspend        = genphy_c45_pma_suspend, | 
|---|
| 1881 | .resume         = rtlgen_c45_resume, | 
|---|
| 1882 | }, { | 
|---|
| 1883 | .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, | 
|---|
| 1884 | .name           = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", | 
|---|
| 1885 | .probe		= rtl822x_probe, | 
|---|
| 1886 | .get_features   = rtl822x_get_features, | 
|---|
| 1887 | .config_aneg    = rtl822x_config_aneg, | 
|---|
| 1888 | .config_init    = rtl822xb_config_init, | 
|---|
| 1889 | .get_rate_matching = rtl822xb_get_rate_matching, | 
|---|
| 1890 | .read_status    = rtl822xb_read_status, | 
|---|
| 1891 | .suspend        = genphy_suspend, | 
|---|
| 1892 | .resume         = rtlgen_resume, | 
|---|
| 1893 | .read_page      = rtl821x_read_page, | 
|---|
| 1894 | .write_page     = rtl821x_write_page, | 
|---|
| 1895 | }, { | 
|---|
| 1896 | .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, | 
|---|
| 1897 | .name           = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", | 
|---|
| 1898 | .probe		= rtl822x_probe, | 
|---|
| 1899 | .config_init    = rtl822xb_config_init, | 
|---|
| 1900 | .get_rate_matching = rtl822xb_get_rate_matching, | 
|---|
| 1901 | .get_features   = rtl822x_c45_get_features, | 
|---|
| 1902 | .config_aneg    = rtl822x_c45_config_aneg, | 
|---|
| 1903 | .read_status    = rtl822xb_c45_read_status, | 
|---|
| 1904 | .suspend        = genphy_c45_pma_suspend, | 
|---|
| 1905 | .resume         = rtlgen_c45_resume, | 
|---|
| 1906 | }, { | 
|---|
| 1907 | .match_phy_device = rtl8251b_c45_match_phy_device, | 
|---|
| 1908 | .name           = "RTL8251B 5Gbps PHY", | 
|---|
| 1909 | .probe		= rtl822x_probe, | 
|---|
| 1910 | .get_features   = rtl822x_get_features, | 
|---|
| 1911 | .config_aneg    = rtl822x_config_aneg, | 
|---|
| 1912 | .read_status    = rtl822x_read_status, | 
|---|
| 1913 | .suspend        = genphy_suspend, | 
|---|
| 1914 | .resume         = rtlgen_resume, | 
|---|
| 1915 | .read_page      = rtl821x_read_page, | 
|---|
| 1916 | .write_page     = rtl821x_write_page, | 
|---|
| 1917 | }, { | 
|---|
| 1918 | .match_phy_device = rtl_internal_nbaset_match_phy_device, | 
|---|
| 1919 | .name           = "Realtek Internal NBASE-T PHY", | 
|---|
| 1920 | .flags		= PHY_IS_INTERNAL, | 
|---|
| 1921 | .probe		= rtl822x_probe, | 
|---|
| 1922 | .get_features   = rtl822x_get_features, | 
|---|
| 1923 | .config_aneg    = rtl822x_config_aneg, | 
|---|
| 1924 | .read_status    = rtl822x_read_status, | 
|---|
| 1925 | .suspend        = genphy_suspend, | 
|---|
| 1926 | .resume         = rtlgen_resume, | 
|---|
| 1927 | .read_page      = rtl821x_read_page, | 
|---|
| 1928 | .write_page     = rtl821x_write_page, | 
|---|
| 1929 | .read_mmd	= rtl822x_read_mmd, | 
|---|
| 1930 | .write_mmd	= rtl822x_write_mmd, | 
|---|
| 1931 | }, { | 
|---|
| 1932 | PHY_ID_MATCH_EXACT(0x001ccad0), | 
|---|
| 1933 | .name		= "RTL8224 2.5Gbps PHY", | 
|---|
| 1934 | .get_features   = rtl822x_c45_get_features, | 
|---|
| 1935 | .config_aneg    = rtl822x_c45_config_aneg, | 
|---|
| 1936 | .read_status    = rtl822x_c45_read_status, | 
|---|
| 1937 | .suspend        = genphy_c45_pma_suspend, | 
|---|
| 1938 | .resume         = rtlgen_c45_resume, | 
|---|
| 1939 | }, { | 
|---|
| 1940 | PHY_ID_MATCH_EXACT(0x001cc961), | 
|---|
| 1941 | .name		= "RTL8366RB Gigabit Ethernet", | 
|---|
| 1942 | .config_init	= &rtl8366rb_config_init, | 
|---|
| 1943 | /* These interrupts are handled by the irq controller | 
|---|
| 1944 | * embedded inside the RTL8366RB, they get unmasked when the | 
|---|
| 1945 | * irq is requested and ACKed by reading the status register, | 
|---|
| 1946 | * which is done by the irqchip code. | 
|---|
| 1947 | */ | 
|---|
| 1948 | .config_intr	= genphy_no_config_intr, | 
|---|
| 1949 | .handle_interrupt = genphy_handle_interrupt_no_ack, | 
|---|
| 1950 | .suspend	= genphy_suspend, | 
|---|
| 1951 | .resume		= genphy_resume, | 
|---|
| 1952 | }, { | 
|---|
| 1953 | PHY_ID_MATCH_EXACT(0x001ccb00), | 
|---|
| 1954 | .name		= "RTL9000AA_RTL9000AN Ethernet", | 
|---|
| 1955 | .features       = PHY_BASIC_T1_FEATURES, | 
|---|
| 1956 | .config_init	= rtl9000a_config_init, | 
|---|
| 1957 | .config_aneg	= rtl9000a_config_aneg, | 
|---|
| 1958 | .read_status	= rtl9000a_read_status, | 
|---|
| 1959 | .config_intr	= rtl9000a_config_intr, | 
|---|
| 1960 | .handle_interrupt = rtl9000a_handle_interrupt, | 
|---|
| 1961 | .suspend	= genphy_suspend, | 
|---|
| 1962 | .resume		= genphy_resume, | 
|---|
| 1963 | .read_page	= rtl821x_read_page, | 
|---|
| 1964 | .write_page	= rtl821x_write_page, | 
|---|
| 1965 | }, { | 
|---|
| 1966 | PHY_ID_MATCH_EXACT(0x001cc942), | 
|---|
| 1967 | .name		= "RTL8365MB-VC Gigabit Ethernet", | 
|---|
| 1968 | /* Interrupt handling analogous to RTL8366RB */ | 
|---|
| 1969 | .config_intr	= genphy_no_config_intr, | 
|---|
| 1970 | .handle_interrupt = genphy_handle_interrupt_no_ack, | 
|---|
| 1971 | .suspend	= genphy_suspend, | 
|---|
| 1972 | .resume		= genphy_resume, | 
|---|
| 1973 | }, { | 
|---|
| 1974 | PHY_ID_MATCH_EXACT(0x001cc960), | 
|---|
| 1975 | .name		= "RTL8366S Gigabit Ethernet", | 
|---|
| 1976 | .suspend	= genphy_suspend, | 
|---|
| 1977 | .resume		= genphy_resume, | 
|---|
| 1978 | .read_mmd	= genphy_read_mmd_unsupported, | 
|---|
| 1979 | .write_mmd	= genphy_write_mmd_unsupported, | 
|---|
| 1980 | }, | 
|---|
| 1981 | }; | 
|---|
| 1982 |  | 
|---|
| 1983 | module_phy_driver(realtek_drvs); | 
|---|
| 1984 |  | 
|---|
| 1985 | static const struct mdio_device_id __maybe_unused realtek_tbl[] = { | 
|---|
| 1986 | { PHY_ID_MATCH_VENDOR(0x001cc800) }, | 
|---|
| 1987 | { } | 
|---|
| 1988 | }; | 
|---|
| 1989 |  | 
|---|
| 1990 | MODULE_DEVICE_TABLE(mdio, realtek_tbl); | 
|---|
| 1991 |  | 
|---|