return 0;
}
-static int rtl839x_smi_wait_op(int timeout)
-{
- int ret = 0;
- u32 val;
-
- ret = readx_poll_timeout(sw_r32, RTL839X_PHYREG_ACCESS_CTRL,
- val, !(val & 0x1), 20, timeout);
- if (ret)
- pr_err("%s: timeout\n", __func__);
-
- return ret;
-}
-
-int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
-{
- u32 v;
- int err = 0;
-
- if (port > 63 || page > 8191 || reg > 31)
- return -ENOTSUPP;
-
- /* Take bug on RTL839x Rev <= C into account */
- if (port >= RTL839X_CPU_PORT)
- return -EIO;
-
- mutex_lock(&smi_lock);
-
- sw_w32_mask(0xffff0000, port << 16, RTL839X_PHYREG_DATA_CTRL);
- v = reg << 5 | page << 10 | ((page == 0x1fff) ? 0x1f : 0) << 23;
- sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
-
- sw_w32(0x1ff, RTL839X_PHYREG_CTRL);
-
- v |= 1;
- sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
-
- err = rtl839x_smi_wait_op(100000);
- if (err)
- goto errout;
-
- *val = sw_r32(RTL839X_PHYREG_DATA_CTRL) & 0xffff;
-
-errout:
- mutex_unlock(&smi_lock);
-
- return err;
-}
-
-int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val)
-{
- u32 v;
- int err = 0;
-
- val &= 0xffff;
- if (port > 63 || page > 8191 || reg > 31)
- return -ENOTSUPP;
-
- /* Take bug on RTL839x Rev <= C into account */
- if (port >= RTL839X_CPU_PORT)
- return -EIO;
-
- mutex_lock(&smi_lock);
-
- /* Set PHY to access */
- rtl839x_set_port_reg_le(BIT_ULL(port), RTL839X_PHYREG_PORT_CTRL);
-
- sw_w32_mask(0xffff0000, val << 16, RTL839X_PHYREG_DATA_CTRL);
-
- v = reg << 5 | page << 10 | ((page == 0x1fff) ? 0x1f : 0) << 23;
- sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
-
- sw_w32(0x1ff, RTL839X_PHYREG_CTRL);
-
- v |= BIT(3) | 1; /* Write operation and execute */
- sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
-
- err = rtl839x_smi_wait_op(100000);
- if (err)
- goto errout;
-
- if (sw_r32(RTL839X_PHYREG_ACCESS_CTRL) & 0x2)
- err = -EIO;
-
-errout:
- mutex_unlock(&smi_lock);
-
- return err;
-}
-
-/* Read an mmd register of the PHY */
-int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
-{
- int err = 0;
- u32 v;
-
- /* Take bug on RTL839x Rev <= C into account */
- if (port >= RTL839X_CPU_PORT)
- return -EIO;
-
- mutex_lock(&smi_lock);
-
- /* Set PHY to access */
- sw_w32_mask(0xffff << 16, port << 16, RTL839X_PHYREG_DATA_CTRL);
-
- /* Set MMD device number and register to write to */
- sw_w32(devnum << 16 | (regnum & 0xffff), RTL839X_PHYREG_MMD_CTRL);
-
- v = BIT(2) | BIT(0); /* MMD-access | EXEC */
- sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
-
- err = rtl839x_smi_wait_op(100000);
- if (err)
- goto errout;
-
- /* There is no error-checking via BIT 1 of v, as it does not seem to be set correctly */
- *val = (sw_r32(RTL839X_PHYREG_DATA_CTRL) & 0xffff);
- pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err);
-
-errout:
- mutex_unlock(&smi_lock);
-
- return err;
-}
-
-/* Write to an mmd register of the PHY */
-int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
-{
- int err = 0;
- u32 v;
-
- /* Take bug on RTL839x Rev <= C into account */
- if (port >= RTL839X_CPU_PORT)
- return -EIO;
-
- mutex_lock(&smi_lock);
-
- /* Set PHY to access */
- rtl839x_set_port_reg_le(BIT_ULL(port), RTL839X_PHYREG_PORT_CTRL);
-
- /* Set data to write */
- sw_w32_mask(0xffff << 16, val << 16, RTL839X_PHYREG_DATA_CTRL);
-
- /* Set MMD device number and register to write to */
- sw_w32(devnum << 16 | (regnum & 0xffff), RTL839X_PHYREG_MMD_CTRL);
-
- v = BIT(3) | BIT(2) | BIT(0); /* WRITE | MMD-access | EXEC */
- sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
-
- err = rtl839x_smi_wait_op(100000);
- if (err)
- goto errout;
-
- pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err);
-
-errout:
- mutex_unlock(&smi_lock);
-
- return err;
-}
-
void rtl8390_get_version(struct rtl838x_switch_priv *priv)
{
u32 info, model;
extern int rtl83xx_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data);
-extern int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
-extern int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
-extern int rtl839x_read_sds_phy(int phy_addr, int phy_reg);
-extern int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
-extern int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val);
-extern int rtl839x_write_sds_phy(int phy_addr, int phy_reg, u16 v);
-
extern int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
extern int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
extern int rtl930x_read_sds_phy(int phy_addr, int page, int phy_reg);
#define RTMDIO_PKG BIT(3)
#define RTMDIO_838X_BASE (0xe780)
+#define RTMDIO_839X_BASE (0xa000)
struct p_hdr {
uint8_t *buf;
return err;
}
+/*
+ * The RTL839x has 14 SerDes starting at 0xbb00a000. 0-7, 10, 11 are 5GBit, 8, 9, 12, 13 are
+ * 10 GBit. Two adjacent SerDes are tightly coupled and share a 1024 bytes register area. Per 32
+ * bit address two registers are stored. The first register is stored in the lower 2 bytes ("on
+ * the right" due to big endian) and the second register in the upper 2 bytes. The following
+ * register areas are known:
+ *
+ * - XSG0 (4 pages @ offset 0x000): for even SerDes
+ * - XSG1 (4 pages @ offset 0x100): for odd SerDes
+ * - TGRX (4 pages @ offset 0x200): for even 10G SerDes
+ * - ANA_RG (2 pages @ offset 0x300): for even 5G SerDes
+ * - ANA_RG (2 pages @ offset 0x380): for odd 5G SerDes
+ * - ANA_TG (2 pages @ offset 0x300): for even 10G SerDes
+ * - ANA_TG (2 pages @ offset 0x380): for odd 10G SerDes
+ *
+ * The most consistent mapping that aligns to the RTL93xx devices is:
+ *
+ * even 5G SerDes odd 5G SerDes even 10G SerDes odd 10G SerDes
+ * Page 0: XSG0/0 XSG1/0 XSG0/0 XSG1/0
+ * Page 1: XSG0/1 XSG1/1 XSG0/1 XSG1/1
+ * Page 2: XSG0/2 XSG1/2 XSG0/2 XSG1/2
+ * Page 3: XSG0/3 XSG1/3 XSG0/3 XSG1/3
+ * Page 4: <zero> <zero> TGRX/0 <zero>
+ * Page 5: <zero> <zero> TGRX/1 <zero>
+ * Page 6: <zero> <zero> TGRX/2 <zero>
+ * Page 7: <zero> <zero> TGRX/3 <zero>
+ * Page 8: ANA_RG ANA_RG <zero> <zero>
+ * Page 9: ANA_RG_EXT ANA_RG_EXT <zero> <zero>
+ * Page 10: <zero> <zero> ANA_TG ANA_TG
+ * Page 11: <zero> <zero> ANA_TG_EXT ANA_TG_EXT
+ */
+
+static int rtmdio_839x_reg_offset(int sds, int page, int regnum)
+{
+ int offset = ((sds & 0xfe) << 9) + ((regnum & 0xfe) << 1) + (page << 6);
+ int sds5g = (GENMASK(11, 10) | GENMASK(7, 0)) & BIT(sds);
+
+ if (sds < 0 || sds > 13 || page < 0 || page > 11 || regnum < 0 || regnum > 31)
+ return -EIO;
+
+ if (page < 4)
+ return offset + ((sds & 1) << 8);
+ else if ((page & 4) && (sds == 8 || sds == 12))
+ return offset + 0x100;
+ else if (page >= 8 && page <= 9 && sds5g)
+ return offset + 0x100 + ((sds & 1) << 7);
+ else if (page >= 10 && !sds5g)
+ return offset + 0x80 + ((sds & 1) << 7);
+
+ return -EINVAL; /* hole */
+}
+
+static int rtmdio_839x_read_sds_phy(int sds, int page, int regnum)
+{
+ int bitpos = ((regnum << 4) & 0x10);
+ int offset;
+ u32 val;
+
+ offset = rtmdio_839x_reg_offset(sds, page, regnum);
+ if (offset == -EINVAL)
+ return 0;
+
+ if (offset < 0)
+ return offset;
+
+ /* phy id is empty so simulate one */
+ if (page == 2 && regnum == 2)
+ return 0x1c;
+ if (page == 2 && regnum == 3)
+ return 0x8393;
+
+ val = sw_r32(RTMDIO_839X_BASE + offset);
+ val = (val >> bitpos) & 0xffff;
+
+ return val;
+}
+
+static int rtmdio_839x_write_sds_phy(int sds, int page, int regnum, u16 val)
+{
+ u32 neighbor;
+ int offset;
+ u32 set;
+
+ offset = rtmdio_839x_reg_offset(sds, page, regnum);
+ if (offset == -EINVAL)
+ return 0;
+
+ if (offset < 0)
+ return 0;
+
+ neighbor = rtmdio_839x_read_sds_phy(sds, page, regnum ^ 1);
+ if (regnum & 1)
+ set = (val << 16) + neighbor;
+ else
+ set = (neighbor << 16) + val;
+
+ sw_w32(set, RTMDIO_839X_BASE + offset);
+
+ return 0;
+}
+
+/* RTL839x specific MDIO functions */
+
+static int rtmdio_839x_smi_wait_op(int timeout)
+{
+ int ret = 0;
+ u32 val;
+
+ ret = readx_poll_timeout(sw_r32, RTL839X_PHYREG_ACCESS_CTRL,
+ val, !(val & 0x1), 20, timeout);
+ if (ret)
+ pr_err("%s: timeout\n", __func__);
+
+ return ret;
+}
+
+static int rtmdio_839x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
+{
+ int err = 0;
+ u32 v;
+
+ if (port >= RTL839X_CPU_PORT || page > 8191 || reg > 31)
+ return -ENOTSUPP;
+
+ mutex_lock(&rtmdio_lock);
+
+ sw_w32_mask(0xffff0000, port << 16, RTL839X_PHYREG_DATA_CTRL);
+ v = reg << 5 | page << 10 | ((page == 0x1fff) ? 0x1f : 0) << 23;
+ sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
+
+ sw_w32(0x1ff, RTL839X_PHYREG_CTRL);
+
+ v |= 1;
+ sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
+
+ err = rtmdio_839x_smi_wait_op(100000);
+ if (err)
+ goto errout;
+
+ *val = sw_r32(RTL839X_PHYREG_DATA_CTRL) & 0xffff;
+
+errout:
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+static int rtmdio_839x_write_phy(u32 port, u32 page, u32 reg, u32 val)
+{
+ int err = 0;
+ u32 v;
+
+ val &= 0xffff;
+ if (port >= RTL839X_CPU_PORT || page > 8191 || reg > 31)
+ return -ENOTSUPP;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access */
+ sw_w32(BIT_ULL(port), RTL839X_PHYREG_PORT_CTRL);
+ sw_w32(BIT_ULL(port) >> 32, RTL839X_PHYREG_PORT_CTRL + 4);
+
+ sw_w32_mask(0xffff0000, val << 16, RTL839X_PHYREG_DATA_CTRL);
+
+ v = reg << 5 | page << 10 | ((page == 0x1fff) ? 0x1f : 0) << 23;
+ sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
+
+ sw_w32(0x1ff, RTL839X_PHYREG_CTRL);
+
+ v |= BIT(3) | 1; /* Write operation and execute */
+ sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
+
+ err = rtmdio_839x_smi_wait_op(100000);
+ if (err)
+ goto errout;
+
+ if (sw_r32(RTL839X_PHYREG_ACCESS_CTRL) & 0x2)
+ err = -EIO;
+
+errout:
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+/* Read an mmd register of the PHY */
+static int rtmdio_839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
+{
+ int err = 0;
+ u32 v;
+
+ /* Take bug on RTL839x Rev <= C into account */
+ if (port >= RTL839X_CPU_PORT)
+ return -EIO;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access */
+ sw_w32_mask(0xffff << 16, port << 16, RTL839X_PHYREG_DATA_CTRL);
+
+ /* Set MMD device number and register to write to */
+ sw_w32(devnum << 16 | (regnum & 0xffff), RTL839X_PHYREG_MMD_CTRL);
+
+ v = BIT(2) | BIT(0); /* MMD-access | EXEC */
+ sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
+
+ err = rtmdio_839x_smi_wait_op(100000);
+ if (err)
+ goto errout;
+
+ /* There is no error-checking via BIT 1 of v, as it does not seem to be set correctly */
+ *val = (sw_r32(RTL839X_PHYREG_DATA_CTRL) & 0xffff);
+ pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err);
+
+errout:
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+/* Write to an mmd register of the PHY */
+static int rtmdio_839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
+{
+ int err = 0;
+ u32 v;
+
+ /* Take bug on RTL839x Rev <= C into account */
+ if (port >= RTL839X_CPU_PORT)
+ return -EIO;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access */
+ sw_w32(BIT_ULL(port), RTL839X_PHYREG_PORT_CTRL);
+ sw_w32(BIT_ULL(port) >> 32, RTL839X_PHYREG_PORT_CTRL + 4);
+
+ /* Set data to write */
+ sw_w32_mask(0xffff << 16, val << 16, RTL839X_PHYREG_DATA_CTRL);
+
+ /* Set MMD device number and register to write to */
+ sw_w32(devnum << 16 | (regnum & 0xffff), RTL839X_PHYREG_MMD_CTRL);
+
+ v = BIT(3) | BIT(2) | BIT(0); /* WRITE | MMD-access | EXEC */
+ sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);
+
+ err = rtmdio_839x_smi_wait_op(100000);
+ if (err)
+ goto errout;
+
+ pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err);
+
+errout:
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
/* These are the core functions of our new Realtek SoC MDIO bus. */
static int rtmdio_read_c45(struct mii_bus *bus, int addr, int devnum, int regnum)
return priv->page[addr];
priv->raw[addr] = (priv->page[addr] == priv->rawpage);
- if ((priv->phy_is_internal[addr]) && (priv->sds_id[addr] >=0)) {
- if (priv->family_id == RTL8380_FAMILY_ID)
- return rtmdio_read_sds_phy(priv, priv->sds_id[addr],
- priv->page[addr], regnum);
- else
- return rtl839x_read_sds_phy(addr, regnum);
- }
+ if ((priv->phy_is_internal[addr]) && (priv->sds_id[addr] >= 0))
+ return rtmdio_read_sds_phy(priv, priv->sds_id[addr],
+ priv->page[addr], regnum);
err = (*priv->read_phy)(addr, priv->page[addr], regnum, &val);
pr_debug("rd_PHY(adr=%d, pag=%d, reg=%d) = %d, err = %d\n",
if (!priv->raw[addr] && (regnum != RTMDIO_PAGE_SELECT || page == priv->rawpage)) {
priv->raw[addr] = (page == priv->rawpage);
- if (priv->phy_is_internal[addr] && priv->sds_id[addr] >=0 ) {
- if (priv->family_id == RTL8380_FAMILY_ID)
- return rtmdio_write_sds_phy(priv, priv->sds_id[addr],
- priv->page[addr], regnum, val);
- else
- return rtl839x_write_sds_phy(addr, regnum, val);
- }
+ if (priv->phy_is_internal[addr] && priv->sds_id[addr] >= 0)
+ return rtmdio_write_sds_phy(priv, priv->sds_id[addr],
+ priv->page[addr], regnum, val);
err = (*priv->write_phy)(addr, page, regnum, val);
pr_debug("wr_PHY(adr=%d, pag=%d, reg=%d, val=%d) err = %d\n",
priv->mii_bus->read = rtmdio_83xx_read;
priv->mii_bus->write = rtmdio_83xx_write;
priv->mii_bus->reset = rtmdio_839x_reset;
- bus_priv->read_mmd_phy = rtl839x_read_mmd_phy;
- bus_priv->write_mmd_phy = rtl839x_write_mmd_phy;
- bus_priv->read_phy = rtl839x_read_phy;
- bus_priv->write_phy = rtl839x_write_phy;
+ bus_priv->read_sds_phy = rtmdio_839x_read_sds_phy;
+ bus_priv->write_sds_phy = rtmdio_839x_write_sds_phy;
+ bus_priv->read_mmd_phy = rtmdio_839x_read_mmd_phy;
+ bus_priv->write_mmd_phy = rtmdio_839x_write_mmd_phy;
+ bus_priv->read_phy = rtmdio_839x_read_phy;
+ bus_priv->write_phy = rtmdio_839x_write_phy;
bus_priv->cpu_port = RTL839X_CPU_PORT;
bus_priv->rawpage = 0x1fff;
break;