return 0;
}
-__maybe_unused
static void rtmdio_get_phy_info(struct mii_bus *bus, int addr, struct rtmdio_phy_info *phyinfo)
{
struct rtmdio_bus_priv *priv = bus->priv;
return 0;
}
-u8 mac_type_bit[RTMDIO_MAX_PORT] = {0, 0, 0, 0, 2, 2, 2, 2, 4, 4, 4, 4, 6, 6, 6, 6,
- 8, 8, 8, 8, 10, 10, 10, 10, 12, 15, 18, 21};
-
static int rtmdio_930x_reset(struct mii_bus *bus)
{
struct rtmdio_bus_priv *priv = bus->priv;
- bool uses_usxgmii = false; /* For the Aquantia PHYs */
- bool uses_hisgmii = false; /* For the RTL8221/8226 */
- u32 private_poll_mask = 0;
- u32 poll_sel[2] = { 0 };
- u32 poll_ctrl = 0;
- u32 c45_mask = 0;
- u32 v = 0;
+ struct rtmdio_phy_info phyinfo;
+ unsigned int reg, mask, val;
/* Define bus topology */
for (int addr = 0; addr < priv->cfg->cpu_port; addr++) {
- int pos;
-
if (priv->smi_bus[addr] < 0)
continue;
- pos = (addr % 6) * 5;
- sw_w32_mask(0x1f << pos, priv->smi_addr[addr] << pos,
- RTMDIO_930X_SMI_PORT0_5_ADDR + (addr / 6) * 4);
+ reg = (addr / 6) * 4;
+ mask = 0x1f << ((addr % 6) * 5);
+ val = priv->smi_addr[addr] << (ffs(mask) - 1);
+ sw_w32_mask(mask, val, RTMDIO_930X_SMI_PORT0_5_ADDR + reg);
- pos = (addr * 2) % 32;
- poll_sel[addr / 16] |= priv->smi_bus[addr] << pos;
- poll_ctrl |= BIT(20 + priv->smi_bus[addr]);
+ reg = (addr / 16) * 4;
+ mask = 0x3 << ((addr % 16) * 2);
+ val = priv->smi_bus[addr] << (ffs(mask) - 1);
+ sw_w32_mask(mask, val, RTMDIO_930X_SMI_PORT0_15_POLLING_SEL + reg);
}
- /* Configure which SMI bus is behind which port number */
- sw_w32(poll_sel[0], RTMDIO_930X_SMI_PORT0_15_POLLING_SEL);
- sw_w32(poll_sel[1], RTMDIO_930X_SMI_PORT16_27_POLLING_SEL);
-
- /* Disable POLL_SEL for any SMI bus with a normal PHY (not RTL8295R for SFP+) */
- sw_w32_mask(poll_ctrl, 0, RTMDIO_930X_SMI_GLB_CTRL);
-
/* Define c22/c45 bus polling */
- for (int addr = 0; addr < RTMDIO_MAX_SMI_BUS; addr++)
- if (priv->smi_bus_isc45[addr])
- c45_mask |= BIT(addr + 16);
-
- pr_info("c45_mask: %08x\n", c45_mask);
- sw_w32_mask(GENMASK(19, 16), c45_mask, RTMDIO_930X_SMI_GLB_CTRL);
+ for (int addr = 0; addr < RTMDIO_MAX_SMI_BUS; addr++) {
+ mask = BIT(16 + addr);
+ val = priv->smi_bus_isc45[addr] ? mask : 0;
+ sw_w32_mask(mask, val, RTMDIO_930X_SMI_GLB_CTRL);
+ }
/* Define PHY specific polling parameters */
for (int addr = 0; addr < priv->cfg->cpu_port; addr++) {
if (priv->smi_bus[addr] < 0)
continue;
- switch (priv->interfaces[addr]) {
- case PHY_INTERFACE_MODE_10GBASER:
- break; /* Serdes: Value = 0 */
- case PHY_INTERFACE_MODE_USXGMII:
- v |= BIT(mac_type_bit[addr]);
- uses_usxgmii = true;
- break;
- case PHY_INTERFACE_MODE_QSGMII:
- private_poll_mask |= BIT(addr);
- v |= 3 << mac_type_bit[addr];
- break;
- default:
- break;
+ rtmdio_get_phy_info(bus, addr, &phyinfo);
+ if (phyinfo.phy_unknown) {
+ pr_warn("skip polling setup for unknown PHY %08x on port %d\n",
+ phyinfo.phy_id, addr);
+ continue;
}
- }
- sw_w32(v, RTMDIO_930X_SMI_MAC_TYPE_CTRL);
- /* Set the private polling mask for all Realtek PHYs (i.e. not the 10GBit Aquantia ones) */
- sw_w32(private_poll_mask, RTMDIO_930X_SMI_PRVTE_POLLING_CTRL);
-
- /* The following magic values are found in the port configuration, they seem to
- * define different ways of polling a PHY. The below is for the Aquantia PHYs of
- * the XGS1250 and the RTL8226 of the XGS1210
- */
- if (uses_usxgmii) {
- sw_w32(0x01010000, RTMDIO_930X_SMI_10G_POLLING_REG0_CFG);
- sw_w32(0x01E7C400, RTMDIO_930X_SMI_10G_POLLING_REG9_CFG);
- sw_w32(0x01E7E820, RTMDIO_930X_SMI_10G_POLLING_REG10_CFG);
- }
- if (uses_hisgmii) {
- sw_w32(0x011FA400, RTMDIO_930X_SMI_10G_POLLING_REG0_CFG);
- sw_w32(0x013FA412, RTMDIO_930X_SMI_10G_POLLING_REG9_CFG);
- sw_w32(0x017FA414, RTMDIO_930X_SMI_10G_POLLING_REG10_CFG);
+ /* port MAC type */
+ mask = addr > 23 ? 0x7 << ((addr - 24) * 3 + 12): 0x3 << ((addr / 4) * 2);
+ val = phyinfo.mac_type << (ffs(mask) - 1);
+ sw_w32_mask(mask, val, RTMDIO_930X_SMI_MAC_TYPE_CTRL);
+
+ /* polling via standard or resolution register */
+ mask = BIT(20 + priv->smi_bus[addr]);
+ val = phyinfo.has_res_reg ? mask : 0;
+ sw_w32_mask(mask, val, RTMDIO_930X_SMI_GLB_CTRL);
+
+ /* proprietary Realtek 1G/2.5 lite polling */
+ mask = BIT(addr);
+ val = phyinfo.has_giga_lite ? mask : 0;
+ sw_w32_mask(mask, val, RTMDIO_930X_SMI_PRVTE_POLLING_CTRL);
+
+ /* special duplex/advertisement polling registers */
+ if (phyinfo.poll_duplex || phyinfo.poll_adv_1000 || phyinfo.poll_lpa_1000) {
+ sw_w32(phyinfo.poll_duplex, RTMDIO_930X_SMI_10G_POLLING_REG0_CFG);
+ sw_w32(phyinfo.poll_adv_1000, RTMDIO_930X_SMI_10G_POLLING_REG9_CFG);
+ sw_w32(phyinfo.poll_lpa_1000, RTMDIO_930X_SMI_10G_POLLING_REG10_CFG);
+ }
}
pr_debug("%s: RTMDIO_930X_SMI_GLB_CTRL %08x\n", __func__,