| .. | .. |
|---|
| 8 | 8 | #include <linux/kernel.h> |
|---|
| 9 | 9 | #include <linux/module.h> |
|---|
| 10 | 10 | #include <linux/netdevice.h> |
|---|
| 11 | +#include <linux/of_device.h> |
|---|
| 11 | 12 | #include <linux/phy.h> |
|---|
| 12 | 13 | |
|---|
| 13 | 14 | #define PHY_ID_YT8511 0x0000010a |
|---|
| 15 | +#define PHY_ID_YT8512 0x00000118 |
|---|
| 16 | +#define PHY_ID_YT8512B 0x00000128 |
|---|
| 14 | 17 | #define PHY_ID_YT8531S 0x4f51e91a |
|---|
| 15 | 18 | #define PHY_ID_YT8531 0x4f51e91b |
|---|
| 16 | 19 | |
|---|
| .. | .. |
|---|
| 40 | 43 | #define YT8511_DELAY_GE_TX_DIS (0x2 << 4) |
|---|
| 41 | 44 | #define YT8511_DELAY_FE_TX_EN (0xf << 12) |
|---|
| 42 | 45 | #define YT8511_DELAY_FE_TX_DIS (0x2 << 12) |
|---|
| 46 | + |
|---|
| 47 | +#define YT8512_EXTREG_AFE_PLL 0x50 |
|---|
| 48 | +#define YT8512_EXTREG_EXTEND_COMBO 0x4000 |
|---|
| 49 | +#define YT8512_EXTREG_LED0 0x40c0 |
|---|
| 50 | +#define YT8512_EXTREG_LED1 0x40c3 |
|---|
| 51 | + |
|---|
| 52 | +#define YT8512_EXTREG_SLEEP_CONTROL1 0x2027 |
|---|
| 53 | + |
|---|
| 54 | +#define YT_SOFTWARE_RESET 0x8000 |
|---|
| 55 | + |
|---|
| 56 | +#define YT8512_CONFIG_PLL_REFCLK_SEL_EN 0x0040 |
|---|
| 57 | +#define YT8512_CONTROL1_RMII_EN 0x0001 |
|---|
| 58 | +#define YT8512_LED0_ACT_BLK_IND 0x1000 |
|---|
| 59 | +#define YT8512_LED0_DIS_LED_AN_TRY 0x0001 |
|---|
| 60 | +#define YT8512_LED0_BT_BLK_EN 0x0002 |
|---|
| 61 | +#define YT8512_LED0_HT_BLK_EN 0x0004 |
|---|
| 62 | +#define YT8512_LED0_COL_BLK_EN 0x0008 |
|---|
| 63 | +#define YT8512_LED0_BT_ON_EN 0x0010 |
|---|
| 64 | +#define YT8512_LED1_BT_ON_EN 0x0010 |
|---|
| 65 | +#define YT8512_LED1_TXACT_BLK_EN 0x0100 |
|---|
| 66 | +#define YT8512_LED1_RXACT_BLK_EN 0x0200 |
|---|
| 67 | +#define YT8512_SPEED_MODE 0xc000 |
|---|
| 68 | +#define YT8512_DUPLEX 0x2000 |
|---|
| 69 | + |
|---|
| 70 | +#define YT8512_SPEED_MODE_BIT 14 |
|---|
| 71 | +#define YT8512_DUPLEX_BIT 13 |
|---|
| 72 | +#define YT8512_EN_SLEEP_SW_BIT 15 |
|---|
| 43 | 73 | |
|---|
| 44 | 74 | /* if system depends on ethernet packet to restore from sleep, |
|---|
| 45 | 75 | * please define this macro to 1 otherwise, define it to 0. |
|---|
| .. | .. |
|---|
| 153 | 183 | return phy_restore_page(phydev, oldpage, ret); |
|---|
| 154 | 184 | } |
|---|
| 155 | 185 | |
|---|
| 156 | | -static inline void phy_lock_mdio_bus(struct phy_device *phydev) |
|---|
| 157 | | -{ |
|---|
| 158 | | - mutex_lock(&phydev->mdio.bus->mdio_lock); |
|---|
| 159 | | -} |
|---|
| 160 | | - |
|---|
| 161 | | -static inline void phy_unlock_mdio_bus(struct phy_device *phydev) |
|---|
| 162 | | -{ |
|---|
| 163 | | - mutex_unlock(&phydev->mdio.bus->mdio_lock); |
|---|
| 164 | | -} |
|---|
| 165 | | - |
|---|
| 166 | 186 | static u32 ytphy_read_ext(struct phy_device *phydev, u32 regnum) |
|---|
| 167 | 187 | { |
|---|
| 168 | 188 | int ret; |
|---|
| .. | .. |
|---|
| 212 | 232 | return ret; |
|---|
| 213 | 233 | |
|---|
| 214 | 234 | return ret; |
|---|
| 235 | +} |
|---|
| 236 | + |
|---|
| 237 | +static int yt8512_clk_init(struct phy_device *phydev) |
|---|
| 238 | +{ |
|---|
| 239 | + struct device_node *node = phydev->mdio.dev.of_node; |
|---|
| 240 | + const char *strings = NULL; |
|---|
| 241 | + int ret; |
|---|
| 242 | + int val; |
|---|
| 243 | + |
|---|
| 244 | + if (node && node->parent && node->parent->parent) { |
|---|
| 245 | + ret = of_property_read_string(node->parent->parent, |
|---|
| 246 | + "clock_in_out", &strings); |
|---|
| 247 | + if (!ret) { |
|---|
| 248 | + if (!strcmp(strings, "input")) |
|---|
| 249 | + return 0; |
|---|
| 250 | + } |
|---|
| 251 | + } |
|---|
| 252 | + |
|---|
| 253 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_AFE_PLL); |
|---|
| 254 | + if (val < 0) |
|---|
| 255 | + return val; |
|---|
| 256 | + |
|---|
| 257 | + val |= YT8512_CONFIG_PLL_REFCLK_SEL_EN; |
|---|
| 258 | + |
|---|
| 259 | + ret = ytphy_write_ext(phydev, YT8512_EXTREG_AFE_PLL, val); |
|---|
| 260 | + if (ret < 0) |
|---|
| 261 | + return ret; |
|---|
| 262 | + |
|---|
| 263 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_EXTEND_COMBO); |
|---|
| 264 | + if (val < 0) |
|---|
| 265 | + return val; |
|---|
| 266 | + |
|---|
| 267 | + val |= YT8512_CONTROL1_RMII_EN; |
|---|
| 268 | + |
|---|
| 269 | + ret = ytphy_write_ext(phydev, YT8512_EXTREG_EXTEND_COMBO, val); |
|---|
| 270 | + if (ret < 0) |
|---|
| 271 | + return ret; |
|---|
| 272 | + |
|---|
| 273 | + val = phy_read(phydev, MII_BMCR); |
|---|
| 274 | + if (val < 0) |
|---|
| 275 | + return val; |
|---|
| 276 | + |
|---|
| 277 | + val |= YT_SOFTWARE_RESET; |
|---|
| 278 | + ret = phy_write(phydev, MII_BMCR, val); |
|---|
| 279 | + |
|---|
| 280 | + return ret; |
|---|
| 281 | +} |
|---|
| 282 | + |
|---|
| 283 | +static int yt8512_led_init(struct phy_device *phydev) |
|---|
| 284 | +{ |
|---|
| 285 | + int ret; |
|---|
| 286 | + int val; |
|---|
| 287 | + int mask; |
|---|
| 288 | + |
|---|
| 289 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_LED0); |
|---|
| 290 | + if (val < 0) |
|---|
| 291 | + return val; |
|---|
| 292 | + |
|---|
| 293 | + val |= YT8512_LED0_ACT_BLK_IND; |
|---|
| 294 | + |
|---|
| 295 | + mask = YT8512_LED0_DIS_LED_AN_TRY | YT8512_LED0_BT_BLK_EN | |
|---|
| 296 | + YT8512_LED0_HT_BLK_EN | YT8512_LED0_COL_BLK_EN | |
|---|
| 297 | + YT8512_LED0_BT_ON_EN; |
|---|
| 298 | + val &= ~mask; |
|---|
| 299 | + |
|---|
| 300 | + ret = ytphy_write_ext(phydev, YT8512_EXTREG_LED0, val); |
|---|
| 301 | + if (ret < 0) |
|---|
| 302 | + return ret; |
|---|
| 303 | + |
|---|
| 304 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_LED1); |
|---|
| 305 | + if (val < 0) |
|---|
| 306 | + return val; |
|---|
| 307 | + |
|---|
| 308 | + val |= YT8512_LED1_BT_ON_EN; |
|---|
| 309 | + |
|---|
| 310 | + mask = YT8512_LED1_TXACT_BLK_EN | YT8512_LED1_RXACT_BLK_EN; |
|---|
| 311 | + val &= ~mask; |
|---|
| 312 | + |
|---|
| 313 | + ret = ytphy_write_ext(phydev, YT8512_LED1_BT_ON_EN, val); |
|---|
| 314 | + |
|---|
| 315 | + return ret; |
|---|
| 316 | +} |
|---|
| 317 | + |
|---|
| 318 | +static int yt8512_config_init(struct phy_device *phydev) |
|---|
| 319 | +{ |
|---|
| 320 | + int ret; |
|---|
| 321 | + int val; |
|---|
| 322 | + |
|---|
| 323 | + ret = yt8512_clk_init(phydev); |
|---|
| 324 | + if (ret < 0) |
|---|
| 325 | + return ret; |
|---|
| 326 | + |
|---|
| 327 | + ret = yt8512_led_init(phydev); |
|---|
| 328 | + if (ret < 0) |
|---|
| 329 | + return ret; |
|---|
| 330 | + |
|---|
| 331 | + /* disable auto sleep */ |
|---|
| 332 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1); |
|---|
| 333 | + if (val < 0) |
|---|
| 334 | + return val; |
|---|
| 335 | + |
|---|
| 336 | + val &= (~BIT(YT8512_EN_SLEEP_SW_BIT)); |
|---|
| 337 | + |
|---|
| 338 | + ret = ytphy_write_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1, val); |
|---|
| 339 | + if (ret < 0) |
|---|
| 340 | + return ret; |
|---|
| 341 | + |
|---|
| 342 | + return ret; |
|---|
| 343 | +} |
|---|
| 344 | + |
|---|
| 345 | +static int yt8512_read_status(struct phy_device *phydev) |
|---|
| 346 | +{ |
|---|
| 347 | + int ret; |
|---|
| 348 | + int val; |
|---|
| 349 | + int speed, speed_mode, duplex; |
|---|
| 350 | + |
|---|
| 351 | + ret = genphy_update_link(phydev); |
|---|
| 352 | + if (ret) |
|---|
| 353 | + return ret; |
|---|
| 354 | + |
|---|
| 355 | + val = phy_read(phydev, REG_PHY_SPEC_STATUS); |
|---|
| 356 | + if (val < 0) |
|---|
| 357 | + return val; |
|---|
| 358 | + |
|---|
| 359 | + duplex = (val & YT8512_DUPLEX) >> YT8512_DUPLEX_BIT; |
|---|
| 360 | + speed_mode = (val & YT8512_SPEED_MODE) >> YT8512_SPEED_MODE_BIT; |
|---|
| 361 | + switch (speed_mode) { |
|---|
| 362 | + case 0: |
|---|
| 363 | + speed = SPEED_10; |
|---|
| 364 | + break; |
|---|
| 365 | + case 1: |
|---|
| 366 | + speed = SPEED_100; |
|---|
| 367 | + break; |
|---|
| 368 | + case 2: |
|---|
| 369 | + case 3: |
|---|
| 370 | + default: |
|---|
| 371 | + speed = SPEED_UNKNOWN; |
|---|
| 372 | + break; |
|---|
| 373 | + } |
|---|
| 374 | + |
|---|
| 375 | + phydev->speed = speed; |
|---|
| 376 | + phydev->duplex = duplex; |
|---|
| 377 | + |
|---|
| 378 | + return 0; |
|---|
| 215 | 379 | } |
|---|
| 216 | 380 | |
|---|
| 217 | 381 | static int yt8521_soft_reset(struct phy_device *phydev) |
|---|
| .. | .. |
|---|
| 573 | 737 | |
|---|
| 574 | 738 | static int yt8531_config_init(struct phy_device *phydev) |
|---|
| 575 | 739 | { |
|---|
| 576 | | - int ret = 0; |
|---|
| 740 | + int ret = 0, val; |
|---|
| 577 | 741 | |
|---|
| 578 | 742 | #if (YTPHY8531A_XTAL_INIT) |
|---|
| 579 | 743 | ret = yt8531a_xtal_init(phydev); |
|---|
| .. | .. |
|---|
| 591 | 755 | return ret; |
|---|
| 592 | 756 | |
|---|
| 593 | 757 | /* RXC, PHY_CLK_OUT and RXData Drive strength: |
|---|
| 594 | | - * Drive strength of RXC = 4, PHY_CLK_OUT = 3, RXD0 = 4 (default) |
|---|
| 595 | | - * If the io voltage is 3.3v, PHY_CLK_OUT = 2, set 0xa010 = 0x9acf |
|---|
| 758 | + * Drive strength of RXC = 6, PHY_CLK_OUT = 3, RXD0 = 4 (default 1.8v) |
|---|
| 759 | + * If the io voltage is 3.3v, PHY_CLK_OUT = 2, set 0xa010 = 0xdacf |
|---|
| 596 | 760 | */ |
|---|
| 597 | | - ret = ytphy_write_ext(phydev, 0xa010, 0x9bcf); |
|---|
| 761 | + ret = ytphy_write_ext(phydev, 0xa010, 0xdbcf); |
|---|
| 762 | + if (ret < 0) |
|---|
| 763 | + return ret; |
|---|
| 764 | + |
|---|
| 765 | + /* Change 100M default BGS voltage from 0x294c to 0x274c */ |
|---|
| 766 | + val = ytphy_read_ext(phydev, 0x57); |
|---|
| 767 | + val = (val & ~(0xf << 8)) | (7 << 8); |
|---|
| 768 | + ret = ytphy_write_ext(phydev, 0x57, val); |
|---|
| 598 | 769 | if (ret < 0) |
|---|
| 599 | 770 | return ret; |
|---|
| 600 | 771 | |
|---|
| .. | .. |
|---|
| 610 | 781 | .resume = genphy_resume, |
|---|
| 611 | 782 | .read_page = yt8511_read_page, |
|---|
| 612 | 783 | .write_page = yt8511_write_page, |
|---|
| 784 | + }, { |
|---|
| 785 | + PHY_ID_MATCH_EXACT(PHY_ID_YT8512), |
|---|
| 786 | + .name = "YT8512 Ethernet", |
|---|
| 787 | + .config_init = yt8512_config_init, |
|---|
| 788 | + .read_status = yt8512_read_status, |
|---|
| 789 | + .suspend = genphy_suspend, |
|---|
| 790 | + .resume = genphy_resume, |
|---|
| 791 | + }, { |
|---|
| 792 | + PHY_ID_MATCH_EXACT(PHY_ID_YT8512B), |
|---|
| 793 | + .name = "YT8512B Ethernet", |
|---|
| 794 | + .config_init = yt8512_config_init, |
|---|
| 795 | + .read_status = yt8512_read_status, |
|---|
| 796 | + .suspend = genphy_suspend, |
|---|
| 797 | + .resume = genphy_resume, |
|---|
| 613 | 798 | }, { |
|---|
| 614 | 799 | /* same as 8521 */ |
|---|
| 615 | 800 | PHY_ID_MATCH_EXACT(PHY_ID_YT8531S), |
|---|
| .. | .. |
|---|
| 648 | 833 | |
|---|
| 649 | 834 | static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { |
|---|
| 650 | 835 | { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, |
|---|
| 836 | + { PHY_ID_MATCH_EXACT(PHY_ID_YT8512) }, |
|---|
| 837 | + { PHY_ID_MATCH_EXACT(PHY_ID_YT8512B) }, |
|---|
| 651 | 838 | { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, |
|---|
| 652 | 839 | { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) }, |
|---|
| 653 | 840 | { /* sentinal */ } |
|---|