#define RTMDIO_931X_SMI_PORT_POLLING_SEL (0x0C9C)
#define RTMDIO_931X_SMI_PORT_ADDR (0x0C74)
-/* MDIO SerDes registers */
-#define RTMDIO_838X_BASE (0xe780)
-
-#define RTMDIO_839X_BASE (0xa000)
-
-#define RTMDIO_930X_SDS_INDACS_CMD (0x03B0)
-#define RTMDIO_930X_SDS_INDACS_DATA (0x03B4)
-
-#define RTMDIO_931X_SERDES_INDRT_ACCESS_CTRL (0x5638)
-#define RTMDIO_931X_SERDES_INDRT_DATA_CTRL (0x563C)
-
#define sw_r32(reg) readl(RTMDIO_SW_BASE + reg)
#define sw_w32(val, reg) writel(val, RTMDIO_SW_BASE + reg)
#define sw_w32_mask(clear, set, reg) sw_w32((sw_r32(reg) & ~(clear)) | (set), reg)
*/
DEFINE_MUTEX(rtmdio_lock);
-DEFINE_MUTEX(rtmdio_lock_sds);
struct rtmdio_bus_priv {
const struct rtmdio_config *cfg;
bool raw[RTMDIO_MAX_PORT];
int smi_bus[RTMDIO_MAX_PORT];
u8 smi_addr[RTMDIO_MAX_PORT];
- int sds_id[RTMDIO_MAX_PORT];
bool smi_bus_isc45[RTMDIO_MAX_SMI_BUS];
- bool phy_is_internal[RTMDIO_MAX_PORT];
phy_interface_t interfaces[RTMDIO_MAX_PORT];
};
int raw_page;
int (*read_mmd_phy)(u32 port, u32 addr, u32 reg, u32 *val);
int (*read_phy)(u32 port, u32 page, u32 reg, u32 *val);
- int (*read_sds_phy)(int sds, int page, int regnum);
int (*reset)(struct mii_bus *bus);
int (*write_mmd_phy)(u32 port, u32 addr, u32 reg, u32 val);
int (*write_phy)(u32 port, u32 page, u32 reg, u32 val);
- int (*write_sds_phy)(int sds, int page, int regnum, u16 val);
};
-/* SerDes reader/writer functions for the ports without external phy. */
-
-/*
- * The RTL838x has 6 SerDes. The 16 bit registers start at 0xbb00e780 and are mapped directly into
- * 32 bit memory addresses. High 16 bits are always empty. A "lower" memory block serves pages 0/3
- * a "higher" memory block pages 1/2.
- */
-
-static int rtmdio_838x_reg_offset(int sds, int page, int regnum)
-{
- if (sds < 0 || sds > 5)
- return -EINVAL;
-
- if (page == 0 || page == 3)
- return (sds << 9) + (page << 7) + (regnum << 2);
- else if (page == 1 || page == 2)
- return 0xb80 + (sds << 8) + (page << 7) + (regnum << 2);
-
- return -EINVAL;
-}
-
-static int rtmdio_838x_read_sds_phy(int sds, int page, int regnum)
-{
- int offset = rtmdio_838x_reg_offset(sds, page, regnum);
-
- if (offset < 0)
- return offset;
-
- return sw_r32(RTMDIO_838X_BASE + offset) & GENMASK(15, 0);
-}
-
-static int rtmdio_838x_write_sds_phy(int sds, int page, int regnum, u16 val)
-{
- int offset = rtmdio_838x_reg_offset(sds, page, regnum);
-
- if (offset < 0)
- return offset;
-
- sw_w32(val, RTMDIO_838X_BASE + offset);
-
- return 0;
-}
-
/* RTL838x specific MDIO functions */
static int rtmdio_838x_smi_wait_op(int timeout)
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)
return err;
}
-/*
- * The RTL930x family has 12 SerDes of three types. They are accessed through two IO registers at
- * 0xbb0003b0 which simulate commands to an internal MDIO bus:
- *
- * - SerDes 0-1 exist on the RTL9301 and 9302B and are QSGMII capable
- * - SerDes 2-9 are USXGMII capabable with either quad or single configuration
- * - SerDes 10-11 are 10GBase-R capable
- */
-
-static int rtmdio_930x_read_sds_phy(int sds, int page, int regnum)
-{
- int i, ret = -EIO;
- u32 cmd;
-
- if (sds < 0 || sds > 11 || page < 0 || page > 63 || regnum < 0 || regnum > 31)
- return -EIO;
-
- mutex_lock(&rtmdio_lock_sds);
-
- cmd = sds << 2 | page << 7 | regnum << 13 | 1;
- sw_w32(cmd, RTMDIO_930X_SDS_INDACS_CMD);
-
- for (i = 0; i < 100; i++) {
- if (!(sw_r32(RTMDIO_930X_SDS_INDACS_CMD) & 0x1))
- break;
- mdelay(1);
- }
-
- if (i < 100)
- ret = sw_r32(RTMDIO_930X_SDS_INDACS_DATA) & 0xffff;
-
- mutex_unlock(&rtmdio_lock_sds);
-
- return ret;
-}
-
-static int rtmdio_930x_write_sds_phy(int sds, int page, int regnum, u16 val)
-{
- int i, ret = -EIO;
- u32 cmd;
-
- if (sds < 0 || sds > 11 || page < 0 || page > 63 || regnum < 0 || regnum > 31)
- return -EIO;
-
- mutex_lock(&rtmdio_lock_sds);
-
- cmd = sds << 2 | page << 7 | regnum << 13 | 0x3;
- sw_w32(val, RTMDIO_930X_SDS_INDACS_DATA);
- sw_w32(cmd, RTMDIO_930X_SDS_INDACS_CMD);
-
- for (i = 0; i < 100; i++) {
- if (!(sw_r32(RTMDIO_930X_SDS_INDACS_CMD) & 0x1))
- break;
- mdelay(1);
- }
-
- mutex_unlock(&rtmdio_lock_sds);
-
- if (i < 100)
- ret = 0;
-
- return ret;
-}
-
/* RTL930x specific MDIO functions */
static int rtmdio_930x_write_phy(u32 port, u32 page, u32 reg, u32 val)
return err;
}
-/*
- * The RTL931x family has 14 "frontend" SerDes that are cascaded. All operations (e.g. reset) work
- * on this frontend view while their registers are distributed over a total of least 26 background
- * SerDes with 64 pages and 32 registers. Three types of SerDes exist:
- *
- * - Serdes 0,1 are "simple" and work on one background serdes.
- * - "Even" SerDes with numbers 2, 4, 6, 8, 10, 12 work on two background SerDes. One analog and
- * one digital.
- * - "Odd" SerDes with numbers 3, 5, 7, 9, 11, 13 work on a total of 3 background SerDes (one analog
- * and two digital)
- *
- * This maps to:
- *
- * Frontend SerDes | 0 1 2 3 4 5 6 7 8 9 10 11 12 13
- * -----------------+------------------------------------------
- * Backend SerDes 1 | 0 1 2 3 6 7 10 11 14 15 18 19 22 23
- * Backend SerDes 2 | 0 1 2 4 6 8 10 12 14 16 18 20 22 24
- * Backend SerDes 3 | 0 1 3 5 7 9 11 13 15 17 19 21 23 25
- *
- * Note: In Realtek proprietary XSGMII mode (10G pumped SGMII) the frontend SerDes works on the
- * two digital SerDes while in all other modes it works on the analog and the first digital SerDes.
- * Overlapping (e.g. backend SerDes 7 can be analog or digital 2) is avoided by the existing
- * hardware designs.
- *
- * Align this for readability by simulating a total of 576 pages and mix them as follows.
- *
- * frontend page "even" frontend SerDes "odd" frontend SerDes
- * page 0x000-0x03f (analog): page 0x000-0x03f back SDS page 0x000-0x03f back SDS
- * page 0x100-0x13f (digi 1): page 0x000-0x03f back SDS page 0x000-0x03f back SDS+1
- * page 0x200-0x23f (digi 2): page 0x000-0x03f back SDS+1 page 0x000-0x03f back SDS+2
- */
-
-static int rtsds_931x_get_backing_sds(int sds, int page)
-{
- int map[] = {0, 1, 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23};
- int back = map[sds];
-
- if (page & 0xc0)
- return -EINVAL; /* hole */
-
- if (sds >= 2) {
- if (sds & 1)
- back += (page >> 8); /* distribute "odd" to 3 background SerDes */
- else
- back += (page >> 9); /* distribute "even" to 2 background SerDes */
- }
-
- return back;
-}
-
-static int rtsds_931x_read(int sds, int page, int regnum)
-{
- int backsds, i, cmd, ret = -EIO;
- int backpage = page & 0x3f;
-
- if (sds < 0 || sds > 13 || page < 0 || page > 575 || regnum < 0 || regnum > 31)
- return -EIO;
-
- backsds = rtsds_931x_get_backing_sds(sds, page);
- if (backsds == -EINVAL)
- return 0;
-
- mutex_lock(&rtmdio_lock_sds);
-
- cmd = backsds << 2 | backpage << 7 | regnum << 13 | 0x1;
- sw_w32(cmd, RTMDIO_931X_SERDES_INDRT_ACCESS_CTRL);
-
- for (i = 0; i < 100; i++) {
- if (!(sw_r32(RTMDIO_931X_SERDES_INDRT_ACCESS_CTRL) & 0x1)) {
- ret = sw_r32(RTMDIO_931X_SERDES_INDRT_DATA_CTRL) & 0xffff;
- break;
- }
- mdelay(1);
- }
-
- mutex_unlock(&rtmdio_lock_sds);
-
- return ret;
-}
-
-static int rtsds_931x_write(int sds, int page, int regnum, u16 val)
-{
- int backsds, i, cmd, ret = -EIO;
- int backpage = page & 0x3f;
-
- if (sds < 0 || sds > 13 || page < 0 || page > 575 || regnum < 0 || regnum > 31)
- return -EIO;
-
- backsds = rtsds_931x_get_backing_sds(sds, page);
- if (backsds == -EINVAL)
- return 0;
-
- mutex_lock(&rtmdio_lock_sds);
-
- cmd = backsds << 2 | backpage << 7 | regnum << 13 | 0x3;
- sw_w32(val, RTMDIO_931X_SERDES_INDRT_DATA_CTRL);
- sw_w32(cmd, RTMDIO_931X_SERDES_INDRT_ACCESS_CTRL);
-
- for (i = 0; i < 100; i++) {
- if (!(sw_r32(RTMDIO_931X_SERDES_INDRT_ACCESS_CTRL) & 0x1)) {
- ret = 0;
- break;
- }
- mdelay(1);
- }
-
- mutex_unlock(&rtmdio_lock_sds);
-
- return ret;
-}
-
-__always_unused
-static int rtsds_931x_write_field(int sds, int page, int reg, int end_bit, int start_bit, u16 val)
-{
- int l = end_bit - start_bit + 1;
- u32 data = val;
-
- if (l < 32) {
- u32 mask = BIT(l) - 1;
-
- data = rtsds_931x_read(sds, page, reg);
- data &= ~(mask << start_bit);
- data |= (val & mask) << start_bit;
- }
-
- return rtsds_931x_write(sds, page, reg, data);
-}
-
-__always_unused
-static int rtsds_931x_read_field(int sds, int page, int reg, int end_bit, int start_bit)
-{
- int l = end_bit - start_bit + 1;
- u32 v = rtsds_931x_read(sds, page, reg);
-
- if (l >= 32)
- return v;
-
- return (v >> start_bit) & (BIT(l) - 1);
-}
-
/* RTL931x specific MDIO functions */
static int rtmdio_931x_write_phy(u32 port, u32 page, u32 reg, u32 val)
return err ? err : val;
}
-static int rtmdio_map_sds_register(int page, int regnum, int *sds_page, int *sds_regnum)
-{
- /*
- * For the SerDes PHY simulate a register mapping like common RealTek PHYs do. Always
- * keep the common registers 0x00-0x0f in place and map the SerDes registers into the
- * upper vendor specific registers 0x10-0x17 according to the page select register
- * (0x1f). That gives a register mapping as follows:
- *
- * +-----------------------+-----------------------+---------------+-----------------+
- * | reg 0x00-0x0f | reg 0x10-0x17 | reg 0x18-0x1e | reg 0x1f |
- * +-----------------------+-----------------------+---------------+-----------------+
- * | SerDes fiber page (2) | real SerDes registers | zero | SerDes page |
- * | registers 0x00-0x0f | in packages of 8 | | select register |
- * +-----------------------+-----------------------+---------------+-----------------+
- */
-
- if (regnum < 16) {
- *sds_page = 2;
- *sds_regnum = regnum;
- } else if (regnum < 24) {
- *sds_page = page / 4;
- *sds_regnum = 8 * (page % 4) + (regnum - 16);
- } else
- return 0;
-
- return 1;
-}
-
-static int rtmdio_read_sds_phy(struct rtmdio_bus_priv *priv, int sds, int page, int regnum)
-{
- int ret, sds_page, sds_regnum;
-
- ret = rtmdio_map_sds_register(page, regnum, &sds_page, &sds_regnum);
- if (ret)
- ret = priv->cfg->read_sds_phy(sds, sds_page, sds_regnum);
- pr_debug("rd_SDS(sds=%d, pag=%d, reg=%d) = %d\n", sds, page, regnum, ret);
-
- return ret;
-}
-
-static int rtmdio_write_sds_phy(struct rtmdio_bus_priv *priv, int sds, int page, int regnum, u16 val)
-{
- int ret, sds_page, sds_regnum;
-
- ret = rtmdio_map_sds_register(page, regnum, &sds_page, &sds_regnum);
- if (ret)
- ret = priv->cfg->write_sds_phy(sds, sds_page, sds_regnum, val);
- pr_debug("wr_SDS(sds=%d, pag=%d, reg=%d, val=%d) err = %d\n", sds, page, regnum, val, ret);
-
- return ret;
-}
-
static int rtmdio_read(struct mii_bus *bus, int addr, int regnum)
{
struct rtmdio_bus_priv *priv = bus->priv;
return priv->page[addr];
priv->raw[addr] = (priv->page[addr] == priv->cfg->raw_page);
- 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->cfg->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->cfg->raw_page)) {
priv->raw[addr] = (page == priv->cfg->raw_page);
- 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->cfg->write_phy)(addr, page, regnum, val);
pr_debug("wr_PHY(adr=%d, pag=%d, reg=%d, val=%d) err = %d\n",
static int rtmdio_probe(struct platform_device *pdev)
{
- struct device_node *dn, *mii_np, *pcs_node;
+ struct device_node *dn, *mii_np;
struct device *dev = &pdev->dev;
struct rtmdio_bus_priv *priv;
struct mii_bus *bus;
return -ENODEV;
}
- priv->phy_is_internal[pn] = of_property_read_bool(dn, "phy-is-integrated");
-
if (of_device_is_compatible(dn, "ethernet-phy-ieee802.3-c45"))
priv->smi_bus_isc45[priv->smi_bus[pn]] = true;
}
if (of_get_phy_mode(dn, &priv->interfaces[pn]))
priv->interfaces[pn] = PHY_INTERFACE_MODE_NA;
dev_dbg(dev, "phy mode of port %d is %s\n", pn, phy_modes(priv->interfaces[pn]));
-
- /*
- * TODO: The MDIO driver does not need any info about the SerDes. As long as
- * the PCS driver cannot completely control the SerDes, look up the information
- * via the pcs-handle of the switch port node.
- */
-
- priv->sds_id[pn] = -1;
- pcs_node = of_parse_phandle(dn, "pcs-handle", 0);
- if (pcs_node)
- of_property_read_u32(pcs_node, "reg", &priv->sds_id[pn]);
- if (priv->phy_is_internal[pn] && priv->sds_id[pn] >= 0)
- priv->smi_bus[pn] = -1;
- if (priv->sds_id[pn] >= 0)
- dev_dbg(dev, "PHY %d has SDS %d\n", pn, priv->sds_id[pn]);
}
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
.raw_page = 4095,
.read_mmd_phy = rtmdio_838x_read_mmd_phy,
.read_phy = rtmdio_838x_read_phy,
- .read_sds_phy = rtmdio_838x_read_sds_phy,
.reset = rtmdio_838x_reset,
.write_mmd_phy = rtmdio_838x_write_mmd_phy,
.write_phy = rtmdio_838x_write_phy,
- .write_sds_phy = rtmdio_838x_write_sds_phy,
};
static const struct rtmdio_config rtmdio_839x_cfg = {
.raw_page = 8191,
.read_mmd_phy = rtmdio_839x_read_mmd_phy,
.read_phy = rtmdio_839x_read_phy,
- .read_sds_phy = rtmdio_839x_read_sds_phy,
.reset = rtmdio_839x_reset,
.write_mmd_phy = rtmdio_839x_write_mmd_phy,
.write_phy = rtmdio_839x_write_phy,
- .write_sds_phy = rtmdio_839x_write_sds_phy,
};
static const struct rtmdio_config rtmdio_930x_cfg = {
.raw_page = 4095,
.read_mmd_phy = rtmdio_930x_read_mmd_phy,
.read_phy = rtmdio_930x_read_phy,
- .read_sds_phy = rtmdio_930x_read_sds_phy,
.reset = rtmdio_930x_reset,
.write_mmd_phy = rtmdio_930x_write_mmd_phy,
.write_phy = rtmdio_930x_write_phy,
- .write_sds_phy = rtmdio_930x_write_sds_phy,
};
static const struct rtmdio_config rtmdio_931x_cfg = {
.raw_page = 8191,
.read_mmd_phy = rtmdio_931x_read_mmd_phy,
.read_phy = rtmdio_931x_read_phy,
- .read_sds_phy = rtsds_931x_read,
.reset = rtmdio_931x_reset,
.write_mmd_phy = rtmdio_931x_write_mmd_phy,
.write_phy = rtmdio_931x_write_phy,
- .write_sds_phy = rtsds_931x_write,
};
static const struct of_device_id rtmdio_ids[] = {