#define RTSDS_930X_PLL_LC 0x3
#define RTSDS_930X_PLL_RING 0x1
-/* This lock protects the state of the SoC automatically polling the PHYs over the SMI
- * bus to detect e.g. link and media changes. For operations on the PHYs such as
- * patching or other configuration changes such as EEE, polling needs to be disabled
- * since otherwise these operations may fails or lead to unpredictable results.
- */
-DEFINE_MUTEX(poll_lock);
-
static const struct firmware rtl838x_8380_fw;
static const struct firmware rtl838x_8214fc_fw;
static const struct firmware rtl838x_8218b_fw;
return get_package_phy(phydev, 0);
}
-static u64 disable_polling(int port)
-{
- u64 saved_state;
-
- mutex_lock(&poll_lock);
-
- switch (soc_info.family) {
- case RTL8380_FAMILY_ID:
- saved_state = sw_r32(RTL838X_SMI_POLL_CTRL);
- sw_w32_mask(BIT(port), 0, RTL838X_SMI_POLL_CTRL);
- break;
- case RTL8390_FAMILY_ID:
- saved_state = sw_r32(RTL839X_SMI_PORT_POLLING_CTRL + 4);
- saved_state <<= 32;
- saved_state |= sw_r32(RTL839X_SMI_PORT_POLLING_CTRL);
- sw_w32_mask(BIT(port % 32), 0,
- RTL839X_SMI_PORT_POLLING_CTRL + ((port >> 5) << 2));
- break;
- case RTL9300_FAMILY_ID:
- saved_state = sw_r32(RTL930X_SMI_POLL_CTRL);
- sw_w32_mask(BIT(port), 0, RTL930X_SMI_POLL_CTRL);
- break;
- case RTL9310_FAMILY_ID:
- saved_state = sw_r32(RTL931X_SMI_PORT_POLLING_CTRL + 4);
- saved_state <<= 32;
- saved_state |= sw_r32(RTL931X_SMI_PORT_POLLING_CTRL);
- sw_w32_mask(BIT(port % 32), 0, RTL931X_SMI_PORT_POLLING_CTRL + ((port >> 5) << 2));
- break;
- }
-
- mutex_unlock(&poll_lock);
-
- return saved_state;
-}
-
-static int resume_polling(u64 saved_state)
-{
- mutex_lock(&poll_lock);
-
- switch (soc_info.family) {
- case RTL8380_FAMILY_ID:
- sw_w32(saved_state, RTL838X_SMI_POLL_CTRL);
- break;
- case RTL8390_FAMILY_ID:
- sw_w32(saved_state >> 32, RTL839X_SMI_PORT_POLLING_CTRL + 4);
- sw_w32(saved_state, RTL839X_SMI_PORT_POLLING_CTRL);
- break;
- case RTL9300_FAMILY_ID:
- sw_w32(saved_state, RTL930X_SMI_POLL_CTRL);
- break;
- case RTL9310_FAMILY_ID:
- sw_w32(saved_state >> 32, RTL931X_SMI_PORT_POLLING_CTRL + 4);
- sw_w32(saved_state, RTL931X_SMI_PORT_POLLING_CTRL);
- break;
- }
-
- mutex_unlock(&poll_lock);
-
- return 0;
-}
-
static int rtl821x_match_phy_device(struct phy_device *phydev)
{
int oldpage, oldxpage, chip_mode, chip_cfg_mode;
return __phy_write(phydev, RTL8XXX_PAGE_SELECT, page);
}
-static int rtl8226_read_status(struct phy_device *phydev)
-{
- int ret = 0;
- u32 val;
-
-/* TODO: ret = genphy_read_status(phydev);
- * if (ret < 0) {
- * pr_info("%s: genphy_read_status failed\n", __func__);
- * return ret;
- * }
- */
-
- /* Link status must be read twice */
- for (int i = 0; i < 2; i++)
- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA402);
-
- phydev->link = val & BIT(2) ? 1 : 0;
- if (!phydev->link)
- goto out;
-
- /* Read duplex status */
- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434);
- if (val < 0)
- goto out;
- phydev->duplex = !!(val & BIT(3));
-
- /* Read speed */
- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434);
- switch (val & 0x0630) {
- case 0x0000:
- phydev->speed = SPEED_10;
- break;
- case 0x0010:
- phydev->speed = SPEED_100;
- break;
- case 0x0020:
- phydev->speed = SPEED_1000;
- break;
- case 0x0200:
- phydev->speed = SPEED_10000;
- break;
- case 0x0210:
- phydev->speed = SPEED_2500;
- break;
- case 0x0220:
- phydev->speed = SPEED_5000;
- break;
- default:
- break;
- }
-
-out:
- return ret;
-}
-
-static int rtl8226_advertise_aneg(struct phy_device *phydev)
-{
- int ret = 0;
- u32 v;
-
- pr_info("In %s\n", __func__);
-
- v = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (v < 0)
- goto out;
-
- v |= ADVERTISE_10HALF;
- v |= ADVERTISE_10FULL;
- v |= ADVERTISE_100HALF;
- v |= ADVERTISE_100FULL;
-
- ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, v);
-
- /* Allow 1GBit */
- v = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA412);
- if (v < 0)
- goto out;
- v |= ADVERTISE_1000FULL;
-
- ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xA412, v);
- if (ret < 0)
- goto out;
-
- /* Allow 2.5G */
- v = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);
- if (v < 0)
- goto out;
-
- v |= MDIO_AN_10GBT_CTRL_ADV2_5G;
- ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, v);
-
-out:
- return ret;
-}
-
-static int rtl8226_config_aneg(struct phy_device *phydev)
-{
- int ret = 0;
- u32 v;
-
- pr_debug("In %s\n", __func__);
- if (phydev->autoneg == AUTONEG_ENABLE) {
- ret = rtl8226_advertise_aneg(phydev);
- if (ret)
- goto out;
- /* AutoNegotiationEnable */
- v = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
- if (v < 0)
- goto out;
-
- v |= MDIO_AN_CTRL1_ENABLE; /* Enable AN */
- ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, v);
- if (ret < 0)
- goto out;
-
- /* RestartAutoNegotiation */
- v = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA400);
- if (v < 0)
- goto out;
- v |= MDIO_AN_CTRL1_RESTART;
-
- ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xA400, v);
- }
-
-/* TODO: ret = __genphy_config_aneg(phydev, ret); */
-
-out:
- return ret;
-}
-
-static int rtl8226_get_eee(struct phy_device *phydev, struct ethtool_keee *e)
-{
- u32 val;
- int addr = phydev->mdio.addr;
-
- pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
-
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV);
- if (e->eee_enabled) {
- e->eee_enabled = !!(val & MDIO_EEE_100TX);
- if (!e->eee_enabled) {
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2);
- e->eee_enabled = !!(val & MDIO_EEE_2_5GT);
- }
- }
- pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
-
- return 0;
-}
-
-static int rtl8226_set_eee(struct phy_device *phydev, struct ethtool_keee *e)
-{
- int port = phydev->mdio.addr;
- u64 poll_state;
- bool an_enabled;
- u32 val;
-
- pr_info("In %s, port %d, enabled %d\n", __func__, port, e->eee_enabled);
-
- poll_state = disable_polling(port);
-
- /* Remember aneg state */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
- an_enabled = !!(val & MDIO_AN_CTRL1_ENABLE);
-
- /* Setup 100/1000MBit */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV);
- if (e->eee_enabled)
- val |= (MDIO_EEE_100TX | MDIO_EEE_1000T);
- else
- val &= (MDIO_EEE_100TX | MDIO_EEE_1000T);
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
-
- /* Setup 2.5GBit */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2);
- if (e->eee_enabled)
- val |= MDIO_EEE_2_5GT;
- else
- val &= MDIO_EEE_2_5GT;
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2, val);
-
- /* RestartAutoNegotiation */
- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA400);
- val |= MDIO_AN_CTRL1_RESTART;
- phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xA400, val);
-
- resume_polling(poll_state);
-
- return 0;
-}
-
static struct fw_header *rtl838x_request_fw(struct phy_device *phydev,
const struct firmware *fw,
const char *name)
.write_mmd = rtl821x_write_mmd,
.write_page = rtl821x_write_page,
},
- {
- PHY_ID_MATCH_MODEL(PHY_ID_RTL8221B),
- .name = "REALTEK RTL8221B",
- .features = PHY_GBIT_FEATURES,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- .read_status = rtl8226_read_status,
- .config_aneg = rtl8226_config_aneg,
- .set_eee = rtl8226_set_eee,
- .get_eee = rtl8226_get_eee,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_RTL8226),
- .name = "REALTEK RTL8226",
- .features = PHY_GBIT_FEATURES,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- .read_status = rtl8226_read_status,
- .config_aneg = rtl8226_config_aneg,
- .set_eee = rtl8226_set_eee,
- .get_eee = rtl8226_get_eee,
- },
{
PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I),
.name = "Realtek RTL8380 SERDES",