|
60 | 60 | #define RTL_LPADV_5000FULL BIT(6) |
61 | 61 | #define RTL_LPADV_2500FULL BIT(5) |
62 | 62 |
|
| 63 | +#define RTL9000A_GINMR 0x14 |
| 64 | +#define RTL9000A_GINMR_LINK_STATUS BIT(4) |
| 65 | + |
63 | 66 | #define RTLGEN_SPEED_MASK 0x0630 |
64 | 67 |
|
65 | 68 | #define RTL_GENERIC_PHYID 0x001cc800 |
@@ -655,6 +658,122 @@ static int rtlgen_resume(struct phy_device *phydev) |
655 | 658 | return ret; |
656 | 659 | } |
657 | 660 |
|
| 661 | +static int rtl9000a_config_init(struct phy_device *phydev) |
| 662 | +{ |
| 663 | + phydev->autoneg = AUTONEG_DISABLE; |
| 664 | + phydev->speed = SPEED_100; |
| 665 | + phydev->duplex = DUPLEX_FULL; |
| 666 | + |
| 667 | + return 0; |
| 668 | +} |
| 669 | + |
| 670 | +static int rtl9000a_config_aneg(struct phy_device *phydev) |
| 671 | +{ |
| 672 | + int ret; |
| 673 | + u16 ctl = 0; |
| 674 | + |
| 675 | + switch (phydev->master_slave_set) { |
| 676 | + case MASTER_SLAVE_CFG_MASTER_FORCE: |
| 677 | + ctl |= CTL1000_AS_MASTER; |
| 678 | + break; |
| 679 | + case MASTER_SLAVE_CFG_SLAVE_FORCE: |
| 680 | + break; |
| 681 | + case MASTER_SLAVE_CFG_UNKNOWN: |
| 682 | + case MASTER_SLAVE_CFG_UNSUPPORTED: |
| 683 | + return 0; |
| 684 | + default: |
| 685 | + phydev_warn(phydev, "Unsupported Master/Slave mode\n"); |
| 686 | + return -EOPNOTSUPP; |
| 687 | + } |
| 688 | + |
| 689 | + ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl); |
| 690 | + if (ret == 1) |
| 691 | + ret = genphy_soft_reset(phydev); |
| 692 | + |
| 693 | + return ret; |
| 694 | +} |
| 695 | + |
| 696 | +static int rtl9000a_read_status(struct phy_device *phydev) |
| 697 | +{ |
| 698 | + int ret; |
| 699 | + |
| 700 | + phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; |
| 701 | + phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; |
| 702 | + |
| 703 | + ret = genphy_update_link(phydev); |
| 704 | + if (ret) |
| 705 | + return ret; |
| 706 | + |
| 707 | + ret = phy_read(phydev, MII_CTRL1000); |
| 708 | + if (ret < 0) |
| 709 | + return ret; |
| 710 | + if (ret & CTL1000_AS_MASTER) |
| 711 | + phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; |
| 712 | + else |
| 713 | + phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; |
| 714 | + |
| 715 | + ret = phy_read(phydev, MII_STAT1000); |
| 716 | + if (ret < 0) |
| 717 | + return ret; |
| 718 | + if (ret & LPA_1000MSRES) |
| 719 | + phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; |
| 720 | + else |
| 721 | + phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; |
| 722 | + |
| 723 | + return 0; |
| 724 | +} |
| 725 | + |
| 726 | +static int rtl9000a_ack_interrupt(struct phy_device *phydev) |
| 727 | +{ |
| 728 | + int err; |
| 729 | + |
| 730 | + err = phy_read(phydev, RTL8211F_INSR); |
| 731 | + |
| 732 | + return (err < 0) ? err : 0; |
| 733 | +} |
| 734 | + |
| 735 | +static int rtl9000a_config_intr(struct phy_device *phydev) |
| 736 | +{ |
| 737 | + u16 val; |
| 738 | + int err; |
| 739 | + |
| 740 | + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { |
| 741 | + err = rtl9000a_ack_interrupt(phydev); |
| 742 | + if (err) |
| 743 | + return err; |
| 744 | + |
| 745 | + val = (u16)~RTL9000A_GINMR_LINK_STATUS; |
| 746 | + err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); |
| 747 | + } else { |
| 748 | + val = ~0; |
| 749 | + err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); |
| 750 | + if (err) |
| 751 | + return err; |
| 752 | + |
| 753 | + err = rtl9000a_ack_interrupt(phydev); |
| 754 | + } |
| 755 | + |
| 756 | + return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); |
| 757 | +} |
| 758 | + |
| 759 | +static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) |
| 760 | +{ |
| 761 | + int irq_status; |
| 762 | + |
| 763 | + irq_status = phy_read(phydev, RTL8211F_INSR); |
| 764 | + if (irq_status < 0) { |
| 765 | + phy_error(phydev); |
| 766 | + return IRQ_NONE; |
| 767 | + } |
| 768 | + |
| 769 | + if (!(irq_status & RTL8211F_INER_LINK_STATUS)) |
| 770 | + return IRQ_NONE; |
| 771 | + |
| 772 | + phy_trigger_machine(phydev); |
| 773 | + |
| 774 | + return IRQ_HANDLED; |
| 775 | +} |
| 776 | + |
658 | 777 | static struct phy_driver realtek_drvs[] = { |
659 | 778 | { |
660 | 779 | PHY_ID_MATCH_EXACT(0x00008201), |
@@ -823,6 +942,19 @@ static struct phy_driver realtek_drvs[] = { |
823 | 942 | .handle_interrupt = genphy_handle_interrupt_no_ack, |
824 | 943 | .suspend = genphy_suspend, |
825 | 944 | .resume = genphy_resume, |
| 945 | + }, { |
| 946 | + PHY_ID_MATCH_EXACT(0x001ccb00), |
| 947 | + .name = "RTL9000AA_RTL9000AN Ethernet", |
| 948 | + .features = PHY_BASIC_T1_FEATURES, |
| 949 | + .config_init = rtl9000a_config_init, |
| 950 | + .config_aneg = rtl9000a_config_aneg, |
| 951 | + .read_status = rtl9000a_read_status, |
| 952 | + .config_intr = rtl9000a_config_intr, |
| 953 | + .handle_interrupt = rtl9000a_handle_interrupt, |
| 954 | + .suspend = genphy_suspend, |
| 955 | + .resume = genphy_resume, |
| 956 | + .read_page = rtl821x_read_page, |
| 957 | + .write_page = rtl821x_write_page, |
826 | 958 | }, |
827 | 959 | }; |
828 | 960 |
|
|
0 commit comments