extern int rtl83xx_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data);
-extern int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
-extern int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
-extern int rtl931x_read_sds_phy(int phy_addr, int page, int phy_reg);
-extern int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
-extern int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val);
-extern int rtl931x_write_sds_phy(int phy_addr, int page, int phy_reg, u16 v);
-
/* Maximum number of RX rings is 8 on RTL83XX and 32 on the 93XX
* The ring is assigned by switch based on packet/port priortity
* Maximum number of TX rings is 2, Ring 2 being the high priority
#define WRAP 0x2
#define RING_BUFFER 1600
-#define RTMDIO_MAX_PORT 57
-#define RTMDIO_MAX_SMI_BUS 4
-#define RTMDIO_PAGE_SELECT 0x1f
-#define RTMDIO_PORT_SELECT 0x2000
-
-#define RTMDIO_READ BIT(0)
-#define RTMDIO_WRITE BIT(1)
-#define RTMDIO_ABS BIT(2)
-#define RTMDIO_PKG BIT(3)
-
-/* 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)
-
struct p_hdr {
uint8_t *buf;
uint16_t reserved;
return phylink_ethtool_ksettings_set(priv->phylink, cmd);
}
-/*
- * On all Realtek switch platforms the hardware periodically reads the link status of all
- * PHYs. This is to some degree programmable, so that one can tell the hardware to read
- * specific C22 registers from specific pages, or C45 registers, to determine the current
- * link speed, duplex, flow-control, ...
- *
- * This happens without any need for the driver to do anything at runtime, completely
- * invisible and in a parallel hardware thread, independent of the CPU running Linux.
- * All one needs to do is to set it up once. Having the MAC link settings automatically
- * follow the PHY link status also happens to be the only way to control MAC port status
- * in a meaningful way, or at least it's the only way we fully understand, as this is
- * what every vendor firmware is doing.
- *
- * The hardware PHY polling unit doesn't care about bus locking, it just assumes that all
- * paged PHY operations are also done via the same hardware unit offering this PHY access
- * abstractions.
- *
- * Additionally at least the RTL838x and RTL839x devices are known to have a so called
- * raw mode. Using the special MAX_PAGE-1 with the MDIO controller found in Realtek
- * SoCs allows to access the PHY in raw mode, ie. bypassing the cache and paging engine
- * of the MDIO controller. E.g. for RTL838x this is 0xfff.
- *
- * On the other hand Realtek PHYs usually make use of select register 0x1f to switch
- * pages. There is no problem to issue separate page and access bus calls to the PHYs
- * when they are not attached to an Realtek SoC. The paradigm should be to keep the PHY
- * implementation bus independent.
- *
- * As if this is not enough the PHY packages consist of 4 or 8 ports that all can be
- * programmed individually. Some registers are only available on port 0 and configure
- * the whole package.
- *
- * To bring all this together we need a tricky bus design that intercepts select page
- * calls but lets raw page accesses through. And especially knows how to handle raw
- * accesses to the select register. Additionally we need the possibility to write to
- * all 8 ports of the PHY individually.
- *
- * While the C45 clause stuff is pretty standard the legacy functions basically track
- * the accesses and the state of the bus with the attributes page[], raw[] and portaddr
- * of the bus_priv structure. The page selection works as follows:
- *
- * phy_write(phydev, RTMDIO_PAGE_SELECT, 12) : store internal page 12 in driver
- * phy_write(phydev, 7, 33) : write page=12, reg=7, val=33
- *
- * or simply
- *
- * phy_write_paged(phydev, 12, 7, 33) : write page=12, reg=7, val=33
- *
- * The port selection works as follows and must be called under a held mdio bus lock
- *
- * __mdiobus_write(bus, RTMDIO_PORT_SELECT, 4) : switch to port 4
- * __phy_write(phydev, RTMDIO_PAGE_SELECT, 11) : store internal page 11 in driver
- * __phy_write(phydev, 8, 19) : write page=11, reg=8, val=19, port=4
- *
- * Any Realtek PHY that will be connected to this bus must simply provide the standard
- * page functions:
- *
- * define RTL821X_PAGE_SELECT 0x1f
- *
- * static int rtl821x_read_page(struct phy_device *phydev)
- * {
- * return __phy_read(phydev, RTL821X_PAGE_SELECT);
- * }
- *
- * static int rtl821x_write_page(struct phy_device *phydev, int page)
- * {
- * return __phy_write(phydev, RTL821X_PAGE_SELECT, page);
- * }
- *
- * In case there are non Realtek PHYs attached to the bus the logic might need to be
- * reimplemented. For now it should be sufficient.
- */
-
-DEFINE_MUTEX(rtmdio_lock);
-DEFINE_MUTEX(rtmdio_lock_sds);
-
-struct rtmdio_bus_priv {
- u16 id;
- u16 family_id;
- int extaddr;
- int rawpage;
- int cpu_port;
- int page[RTMDIO_MAX_PORT];
- 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 (*read_mmd_phy)(u32 port, u32 addr, u32 reg, u32 *val);
- int (*write_mmd_phy)(u32 port, u32 addr, u32 reg, u32 val);
- int (*read_phy)(u32 port, u32 page, u32 reg, u32 *val);
- int (*write_phy)(u32 port, u32 page, u32 reg, u32 val);
- int (*read_sds_phy)(int sds, int page, int regnum);
- int (*write_sds_phy)(int sds, int page, int regnum, u16 val);
-};
-
-/*
- * Provide a generic read/write function so we can access arbitrary ports on the bus.
- * E.g. other ports of a PHY package on the bus. This basically resembles the kernel
- * phy_read_paged() and phy_write_paged() functions. To inform the bus that we are
- * working on a not default port send a RTMDIO_PORT_SELECT command at the beginning
- * and the end to switch the port handling logic.
- */
-
-static int rtmdio_access(struct phy_device *phydev, int op, int port,
- int page, u32 regnum, u16 val)
-{
- int r, ret = 0, oldpage;
-
- if (op & RTMDIO_PKG) {
- if (!phydev->shared)
- return -EIO;
- port = phydev->shared->base_addr + port;
- }
-
- /* lock and inform bus about non default addressing */
- phy_lock_mdio_bus(phydev);
- __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
- RTMDIO_PORT_SELECT, port);
-
- oldpage = ret = __phy_read(phydev, RTMDIO_PAGE_SELECT);
- if (oldpage >= 0 && oldpage != page) {
- ret = __phy_write(phydev, RTMDIO_PAGE_SELECT, page);
- if (ret < 0)
- oldpage = ret;
- }
-
- if (oldpage >= 0) {
- if (op & RTMDIO_WRITE)
- ret = __phy_write(phydev, regnum, val);
- else
- ret = __phy_read(phydev, regnum);
- }
-
- if (oldpage >= 0) {
- r = __phy_write(phydev, RTMDIO_PAGE_SELECT, oldpage);
- if (ret >= 0 && r < 0)
- ret = r;
- } else
- ret = oldpage;
-
- /* reset bus to default adressing and unlock it */
- __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
- RTMDIO_PORT_SELECT, -1);
- phy_unlock_mdio_bus(phydev);
-
- return ret;
-}
-
-/*
- * To make use of the shared package functions provide wrappers that align with kernel
- * naming conventions. The package() functions are useful to change settings on the
- * package as a whole. The package_port() functions will allow to target the PHYs
- * of a package individually. The port() only functions allow to access arbitrary ports
- * on the bus through a PHY.
- */
-
-int phy_package_port_write_paged(struct phy_device *phydev, int port, int page, u32 regnum, u16 val)
-{
- return rtmdio_access(phydev, RTMDIO_WRITE | RTMDIO_PKG, port, page, regnum, val);
-}
-
-int phy_package_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val)
-{
- return rtmdio_access(phydev, RTMDIO_WRITE | RTMDIO_PKG, 0, page, regnum, val);
-}
-
-int phy_port_write_paged(struct phy_device *phydev, int port, int page, u32 regnum, u16 val)
-{
- return rtmdio_access(phydev, RTMDIO_WRITE | RTMDIO_ABS, port, page, regnum, val);
-}
-
-int phy_package_port_read_paged(struct phy_device *phydev, int port, int page, u32 regnum)
+static int rtl931x_chip_init(struct rtl838x_eth_priv *priv)
{
- return rtmdio_access(phydev, RTMDIO_READ | RTMDIO_PKG, port, page, regnum, 0);
-}
+ pr_info("In %s\n", __func__);
-int phy_package_read_paged(struct phy_device *phydev, int page, u32 regnum)
-{
- return rtmdio_access(phydev, RTMDIO_READ | RTMDIO_PKG, 0, page, regnum, 0);
-}
+ /* Initialize Encapsulation memory and wait until finished */
+ sw_w32(0x1, RTL931X_MEM_ENCAP_INIT);
+ do { } while (sw_r32(RTL931X_MEM_ENCAP_INIT) & 1);
+ pr_info("%s: init ENCAP done\n", __func__);
-int phy_port_read_paged(struct phy_device *phydev, int port, int page, u32 regnum)
-{
- return rtmdio_access(phydev, RTMDIO_READ | RTMDIO_ABS, port, page, regnum, 0);
-}
+ /* Initialize Managemen Information Base memory and wait until finished */
+ sw_w32(0x1, RTL931X_MEM_MIB_INIT);
+ do { } while (sw_r32(RTL931X_MEM_MIB_INIT) & 1);
+ pr_info("%s: init MIB done\n", __func__);
-/* SerDes reader/writer functions for the ports without external phy. */
+ /* Initialize ACL (PIE) memory and wait until finished */
+ sw_w32(0x1, RTL931X_MEM_ACL_INIT);
+ do { } while (sw_r32(RTL931X_MEM_ACL_INIT) & 1);
+ pr_info("%s: init ACL done\n", __func__);
-/*
- * 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.
- */
+ /* Initialize ALE memory and wait until finished */
+ sw_w32(0xFFFFFFFF, RTL931X_MEM_ALE_INIT_0);
+ do { } while (sw_r32(RTL931X_MEM_ALE_INIT_0));
+ sw_w32(0x7F, RTL931X_MEM_ALE_INIT_1);
+ sw_w32(0x7ff, RTL931X_MEM_ALE_INIT_2);
+ do { } while (sw_r32(RTL931X_MEM_ALE_INIT_2) & 0x7ff);
+ pr_info("%s: init ALE done\n", __func__);
-static int rtmdio_838x_reg_offset(int sds, int page, int regnum)
-{
- if (sds < 0 || sds > 5)
- return -EINVAL;
+ /* Enable ESD auto recovery */
+ sw_w32(0x1, RTL931X_MDX_CTRL_RSVD);
- 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);
+ /* Init SPI, is this for thermal control or what? */
+ sw_w32_mask(0x7 << 11, 0x2 << 11, RTL931X_SPI_CTRL0);
- return -EINVAL;
+ return 0;
}
-static int rtmdio_838x_read_sds_phy(int sds, int page, int regnum)
+static netdev_features_t rtl838x_fix_features(struct net_device *dev,
+ netdev_features_t features)
{
- int offset = rtmdio_838x_reg_offset(sds, page, regnum);
-
- if (offset < 0)
- return offset;
-
- return sw_r32(RTMDIO_838X_BASE + offset) & GENMASK(15, 0);
+ return features;
}
-static int rtmdio_838x_write_sds_phy(int sds, int page, int regnum, u16 val)
+static int rtl83xx_set_features(struct net_device *dev, netdev_features_t features)
{
- int offset = rtmdio_838x_reg_offset(sds, page, regnum);
-
- if (offset < 0)
- return offset;
+ struct rtl838x_eth_priv *priv = netdev_priv(dev);
- sw_w32(val, RTMDIO_838X_BASE + offset);
+ if ((features ^ dev->features) & NETIF_F_RXCSUM) {
+ if (!(features & NETIF_F_RXCSUM))
+ sw_w32_mask(BIT(3), 0, priv->r->mac_port_ctrl(priv->cpu_port));
+ else
+ sw_w32_mask(0, BIT(3), priv->r->mac_port_ctrl(priv->cpu_port));
+ }
return 0;
}
-/* RTL838x specific MDIO functions */
-
-static int rtmdio_838x_smi_wait_op(int timeout)
-{
- int ret = 0;
- u32 val;
-
- ret = readx_poll_timeout(sw_r32, RTL838X_SMI_ACCESS_PHY_CTRL_1,
- val, !(val & 0x1), 20, timeout);
- if (ret)
- pr_err("%s: timeout\n", __func__);
-
- return ret;
-}
-
-/* Reads a register in a page from the PHY */
-int rtmdio_838x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
+static int rtl93xx_set_features(struct net_device *dev, netdev_features_t features)
{
- u32 v, park_page = 0x1f << 15;
- int err;
+ struct rtl838x_eth_priv *priv = netdev_priv(dev);
- if (port > 31) {
- *val = 0xffff;
- return 0;
+ if ((features ^ dev->features) & NETIF_F_RXCSUM) {
+ if (!(features & NETIF_F_RXCSUM))
+ sw_w32_mask(BIT(4), 0, priv->r->mac_port_ctrl(priv->cpu_port));
+ else
+ sw_w32_mask(0, BIT(4), priv->r->mac_port_ctrl(priv->cpu_port));
}
- if (page > 4095 || reg > 31)
- return -ENOTSUPP;
-
- mutex_lock(&rtmdio_lock);
-
- sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
- v = reg << 20 | page << 3;
- sw_w32(v | park_page, RTL838X_SMI_ACCESS_PHY_CTRL_1);
- sw_w32_mask(0, 1, RTL838X_SMI_ACCESS_PHY_CTRL_1);
-
- err = rtmdio_838x_smi_wait_op(100000);
- if (err)
- goto errout;
-
- *val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
-errout:
- mutex_unlock(&rtmdio_lock);
-
- return err;
+ return 0;
}
-/* Write to a register in a page of the PHY */
-int rtmdio_838x_write_phy(u32 port, u32 page, u32 reg, u32 val)
+static struct phylink_pcs *rtl838x_mac_select_pcs(struct phylink_config *config,
+ phy_interface_t interface)
{
- u32 v, park_page = 0x1f << 15;
- int err;
-
- val &= 0xffff;
- if (port > 31 || page > 4095 || reg > 31)
- return -ENOTSUPP;
-
- mutex_lock(&rtmdio_lock);
-
- sw_w32(BIT(port), RTL838X_SMI_ACCESS_PHY_CTRL_0);
- sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
-
- v = reg << 20 | page << 3 | 0x4;
- sw_w32(v | park_page, RTL838X_SMI_ACCESS_PHY_CTRL_1);
- sw_w32_mask(0, 1, RTL838X_SMI_ACCESS_PHY_CTRL_1);
-
- err = rtmdio_838x_smi_wait_op(100000);
- mutex_unlock(&rtmdio_lock);
+ struct net_device *dev = to_net_dev(config->dev);
+ struct rtl838x_eth_priv *priv = netdev_priv(dev);
- return err;
+ return &priv->pcs;
}
-/* Read an mmd register of a PHY */
-static int rtmdio_838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val)
-{
- int err;
- u32 v;
-
- mutex_lock(&rtmdio_lock);
+static const struct net_device_ops rtl838x_eth_netdev_ops = {
+ .ndo_open = rtl838x_eth_open,
+ .ndo_stop = rtl838x_eth_stop,
+ .ndo_start_xmit = rtl838x_eth_tx,
+ .ndo_select_queue = rtl83xx_pick_tx_queue,
+ .ndo_set_mac_address = rtl838x_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_rx_mode = rtl838x_eth_set_multicast_list,
+ .ndo_tx_timeout = rtl838x_eth_tx_timeout,
+ .ndo_set_features = rtl83xx_set_features,
+ .ndo_fix_features = rtl838x_fix_features,
+ .ndo_setup_tc = rtl83xx_setup_tc,
+};
- sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0);
- sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
+static const struct net_device_ops rtl839x_eth_netdev_ops = {
+ .ndo_open = rtl838x_eth_open,
+ .ndo_stop = rtl838x_eth_stop,
+ .ndo_start_xmit = rtl838x_eth_tx,
+ .ndo_select_queue = rtl83xx_pick_tx_queue,
+ .ndo_set_mac_address = rtl838x_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_rx_mode = rtl839x_eth_set_multicast_list,
+ .ndo_tx_timeout = rtl838x_eth_tx_timeout,
+ .ndo_set_features = rtl83xx_set_features,
+ .ndo_fix_features = rtl838x_fix_features,
+ .ndo_setup_tc = rtl83xx_setup_tc,
+};
- v = addr << 16 | reg;
- sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_3);
+static const struct net_device_ops rtl930x_eth_netdev_ops = {
+ .ndo_open = rtl838x_eth_open,
+ .ndo_stop = rtl838x_eth_stop,
+ .ndo_start_xmit = rtl838x_eth_tx,
+ .ndo_select_queue = rtl93xx_pick_tx_queue,
+ .ndo_set_mac_address = rtl838x_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_rx_mode = rtl930x_eth_set_multicast_list,
+ .ndo_tx_timeout = rtl838x_eth_tx_timeout,
+ .ndo_set_features = rtl93xx_set_features,
+ .ndo_fix_features = rtl838x_fix_features,
+ .ndo_setup_tc = rtl83xx_setup_tc,
+};
- /* mmd-access | read | cmd-start */
- v = 1 << 1 | 0 << 2 | 1;
- sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1);
+static const struct net_device_ops rtl931x_eth_netdev_ops = {
+ .ndo_open = rtl838x_eth_open,
+ .ndo_stop = rtl838x_eth_stop,
+ .ndo_start_xmit = rtl838x_eth_tx,
+ .ndo_select_queue = rtl93xx_pick_tx_queue,
+ .ndo_set_mac_address = rtl838x_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_rx_mode = rtl931x_eth_set_multicast_list,
+ .ndo_tx_timeout = rtl838x_eth_tx_timeout,
+ .ndo_set_features = rtl93xx_set_features,
+ .ndo_fix_features = rtl838x_fix_features,
+};
- err = rtmdio_838x_smi_wait_op(100000);
- if (err)
- goto errout;
+static const struct phylink_pcs_ops rtl838x_pcs_ops = {
+ .pcs_get_state = rtl838x_pcs_get_state,
+ .pcs_an_restart = rtl838x_pcs_an_restart,
+ .pcs_config = rtl838x_pcs_config,
+};
- *val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
-errout:
- mutex_unlock(&rtmdio_lock);
+static const struct phylink_mac_ops rtl838x_phylink_ops = {
+ .mac_select_pcs = rtl838x_mac_select_pcs,
+ .mac_config = rtl838x_mac_config,
+ .mac_link_down = rtl838x_mac_link_down,
+ .mac_link_up = rtl838x_mac_link_up,
+};
- return err;
-}
+static const struct ethtool_ops rtl838x_ethtool_ops = {
+ .get_link_ksettings = rtl838x_get_link_ksettings,
+ .set_link_ksettings = rtl838x_set_link_ksettings,
+};
-/* Write to an mmd register of a PHY */
-static int rtmdio_838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val)
+static int __init rtl838x_eth_probe(struct platform_device *pdev)
{
- int err;
- u32 v;
-
- pr_debug("MMD write: port %d, dev %d, reg %d, val %x\n", port, addr, reg, val);
- val &= 0xffff;
- mutex_lock(&rtmdio_lock);
-
- sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0);
- sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
- sw_w32_mask(0x1f << 16, addr << 16, RTL838X_SMI_ACCESS_PHY_CTRL_3);
- sw_w32_mask(0xffff, reg, RTL838X_SMI_ACCESS_PHY_CTRL_3);
- /* mmd-access | write | cmd-start */
- v = 1 << 1 | 1 << 2 | 1;
- sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1);
+ struct net_device *dev;
+ struct device_node *dn = pdev->dev.of_node;
+ struct rtl838x_eth_priv *priv;
+ struct resource *res, *mem;
+ phy_interface_t phy_mode;
+ struct phylink *phylink;
+ u8 mac_addr[ETH_ALEN];
+ int err = 0, rxrings, rxringlen;
+ struct ring_b *ring;
- err = rtmdio_838x_smi_wait_op(100000);
- mutex_unlock(&rtmdio_lock);
+ pr_info("Probing RTL838X eth device pdev: %x, dev: %x\n",
+ (u32)pdev, (u32)(&(pdev->dev)));
- return err;
-}
+ if (!dn) {
+ dev_err(&pdev->dev, "No DT found\n");
+ return -EINVAL;
+ }
-/*
- * 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
- */
+ rxrings = (soc_info.family == RTL8380_FAMILY_ID
+ || soc_info.family == RTL8390_FAMILY_ID) ? 8 : 32;
+ rxrings = rxrings > MAX_RXRINGS ? MAX_RXRINGS : rxrings;
+ rxringlen = MAX_ENTRIES / rxrings;
+ rxringlen = rxringlen > MAX_RXLEN ? MAX_RXLEN : rxringlen;
-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 */
-}
+ dev = devm_alloc_etherdev_mqs(&pdev->dev, sizeof(struct rtl838x_eth_priv), TXRINGS, rxrings);
+ if (!dev)
+ return -ENOMEM;
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ priv = netdev_priv(dev);
-static int rtmdio_839x_read_sds_phy(int sds, int page, int regnum)
-{
- int bitpos = ((regnum << 4) & 0x10);
- int offset;
- u32 val;
+ /* obtain buffer memory space */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ mem = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), res->name);
+ if (!mem) {
+ dev_err(&pdev->dev, "cannot request memory space\n");
+ return -ENXIO;
+ }
- offset = rtmdio_839x_reg_offset(sds, page, regnum);
- if (offset == -EINVAL)
- return 0;
+ dev->mem_start = mem->start;
+ dev->mem_end = mem->end;
+ } else {
+ dev_err(&pdev->dev, "cannot request IO resource\n");
+ return -ENXIO;
+ }
- if (offset < 0)
- return offset;
+ /* Allocate buffer memory */
+ priv->membase = dmam_alloc_coherent(&pdev->dev, rxrings * rxringlen * RING_BUFFER +
+ sizeof(struct ring_b) + sizeof(struct notify_b),
+ (void *)&dev->mem_start, GFP_KERNEL);
+ if (!priv->membase) {
+ dev_err(&pdev->dev, "cannot allocate DMA buffer\n");
+ return -ENOMEM;
+ }
- /* phy id is empty so simulate one */
- if (page == 2 && regnum == 2)
- return 0x1c;
- if (page == 2 && regnum == 3)
- return 0x8393;
+ /* Allocate ring-buffer space at the end of the allocated memory */
+ ring = priv->membase;
+ ring->rx_space = priv->membase + sizeof(struct ring_b) + sizeof(struct notify_b);
- val = sw_r32(RTMDIO_839X_BASE + offset);
- val = (val >> bitpos) & 0xffff;
+ spin_lock_init(&priv->lock);
- 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;
-}
-
-/*
- * 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
- */
-
-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;
-}
-
-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)
-{
- u32 v;
- int err = 0;
-
- pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, val);
-
- if (port > 63 || page > 4095 || reg > 31)
- return -ENOTSUPP;
-
- val &= 0xffff;
- mutex_lock(&rtmdio_lock);
-
- sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0);
- sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2);
- v = reg << 20 | page << 3 | 0x1f << 15 | BIT(2) | BIT(0);
- sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1);
-
- do {
- v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1);
- } while (v & 0x1);
-
- if (v & 0x2)
- err = -EIO;
-
- mutex_unlock(&rtmdio_lock);
-
- return err;
-}
-
-static int rtmdio_930x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
-{
- u32 v;
- int err = 0;
-
- if (port > 63 || page > 4095 || reg > 31)
- return -ENOTSUPP;
-
- mutex_lock(&rtmdio_lock);
-
- sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2);
- v = reg << 20 | page << 3 | 0x1f << 15 | 1;
- sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1);
-
- do {
- v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1);
- } while ( v & 0x1);
-
- if (v & BIT(25)) {
- pr_debug("Error reading phy %d, register %d\n", port, reg);
- err = -EIO;
- }
- *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff);
-
- pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, *val);
-
- mutex_unlock(&rtmdio_lock);
-
- return err;
-}
-
-/* Write to an mmd register of the PHY */
-static int rtmdio_930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
-{
- int err = 0;
- u32 v;
-
- mutex_lock(&rtmdio_lock);
-
- /* Set PHY to access */
- sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0);
-
- /* Set data to write */
- sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2);
-
- /* Set MMD device number and register to write to */
- sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3);
-
- v = BIT(2) | BIT(1) | BIT(0); /* WRITE | MMD-access | EXEC */
- sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1);
-
- do {
- v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1);
- } while (v & BIT(0));
-
- pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err);
- mutex_unlock(&rtmdio_lock);
- return err;
-}
-
-/* Read an mmd register of the PHY */
-static int rtmdio_930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
-{
- int err = 0;
- u32 v;
-
- mutex_lock(&rtmdio_lock);
-
- /* Set PHY to access */
- sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2);
-
- /* Set MMD device number and register to write to */
- sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3);
-
- v = BIT(1) | BIT(0); /* MMD-access | EXEC */
- sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1);
-
- do {
- v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1);
- } while (v & BIT(0));
- /* There is no error-checking via BIT 25 of v, as it does not seem to be set correctly */
- *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff);
- pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err);
-
- mutex_unlock(&rtmdio_lock);
-
- 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 rtmdio_931x_get_backing_sds(u32 sds, u32 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 rtmdio_931x_read_sds_phy(int sds, int page, int regnum)
-{
- u32 cmd = sds << 2 | page << 7 | regnum << 13 | 1;
- int i, ret = -EIO;
-
- pr_debug("%s: phy_addr(SDS-ID) %d, phy_reg: %d\n", __func__, sds, regnum);
-
- mutex_lock(&rtmdio_lock_sds);
- 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))
- break;
- mdelay(1);
- }
-
- if (i < 100)
- ret = sw_r32(RTMDIO_931X_SERDES_INDRT_DATA_CTRL) & 0xffff;
-
- mutex_unlock(&rtmdio_lock_sds);
-
- pr_debug("%s: returning %08x\n", __func__, ret);
-
- return ret;
-}
-
-int rtmdio_931x_read_sds_phy_new(int sds, int page, int regnum)
-{
- int backsds = rtmdio_931x_get_backing_sds(sds, page);
-
- return backsds < 0 ? 0 : rtmdio_931x_read_sds_phy(backsds, page & 0x3f, regnum);
-}
-
-static int rtmdio_931x_write_sds_phy(int sds, int page, int regnum, u16 val)
-{
- u32 cmd = sds << 2 | page << 7 | regnum << 13;;
- int i, ret = -EIO;
-
- mutex_lock(&rtmdio_lock_sds);
- sw_w32(cmd, RTMDIO_931X_SERDES_INDRT_ACCESS_CTRL);
- sw_w32(val, RTMDIO_931X_SERDES_INDRT_DATA_CTRL);
-
- cmd = sw_r32(RTMDIO_931X_SERDES_INDRT_ACCESS_CTRL) | 0x3;
- 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))
- break;
- mdelay(1);
- }
-
- mutex_unlock(&rtmdio_lock_sds);
-
- if (i < 100)
- ret = 0;
-
- return ret;
-}
-
-int rtmdio_931x_write_sds_phy_new(int sds, int page, int regnum, u16 val)
-{
- int backsds = rtmdio_931x_get_backing_sds(sds, page);
-
- return backsds < 0 ? 0 : rtmdio_931x_write_sds_phy(backsds, page & 0x3f, regnum, val);
-}
-
-/* RTL931x specific MDIO functions */
-
-static int rtmdio_931x_write_phy(u32 port, u32 page, u32 reg, u32 val)
-{
- u32 v;
- int err = 0;
-
- val &= 0xffff;
- if (port > 63 || page > 4095 || reg > 31)
- return -ENOTSUPP;
-
- mutex_lock(&rtmdio_lock);
- pr_debug("%s: writing to phy %d %d %d %d\n", __func__, port, page, reg, val);
- /* Clear both port registers */
- sw_w32(0, RTL931X_SMI_INDRT_ACCESS_CTRL_2);
- sw_w32(0, RTL931X_SMI_INDRT_ACCESS_CTRL_2 + 4);
- sw_w32_mask(0, BIT(port % 32), RTL931X_SMI_INDRT_ACCESS_CTRL_2 + (port / 32) * 4);
-
- sw_w32_mask(0xffff, val, RTL931X_SMI_INDRT_ACCESS_CTRL_3);
-
- v = reg << 6 | page << 11 ;
- sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0);
-
- sw_w32(0x1ff, RTL931X_SMI_INDRT_ACCESS_CTRL_1);
-
- v |= BIT(4) | 1; /* Write operation and execute */
- sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0);
-
- do {
- } while (sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0) & 0x1);
-
- if (sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0) & 0x2)
- err = -EIO;
-
- mutex_unlock(&rtmdio_lock);
-
- return err;
-}
-
-static int rtmdio_931x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
-{
- u32 v;
-
- if (port > 63 || page > 4095 || reg > 31)
- return -ENOTSUPP;
-
- mutex_lock(&rtmdio_lock);
-
- sw_w32(port << 5, RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL);
-
- v = reg << 6 | page << 11 | 1;
- sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0);
-
- do {
- } while (sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0) & 0x1);
-
- v = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0);
- *val = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_3);
- *val = (*val & 0xffff0000) >> 16;
-
- pr_debug("%s: port %d, page: %d, reg: %x, val: %x, v: %08x\n",
- __func__, port, page, reg, *val, v);
-
- mutex_unlock(&rtmdio_lock);
-
- return 0;
-}
-
-/* Read an mmd register of the PHY */
-static int rtmdio_931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
-{
- int err = 0;
- u32 v;
- /* Select PHY register type
- * If select 1G/10G MMD register type, registers EXT_PAGE, MAIN_PAGE and REG settings are don’t care.
- * 0x0 Normal register (Clause 22)
- * 0x1: 1G MMD register (MMD via Clause 22 registers 13 and 14)
- * 0x2: 10G MMD register (MMD via Clause 45)
- */
- int type = 2;
-
- mutex_lock(&rtmdio_lock);
-
- /* Set PHY to access via port-number */
- sw_w32(port << 5, RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL);
-
- /* Set MMD device number and register to write to */
- sw_w32(devnum << 16 | regnum, RTL931X_SMI_INDRT_ACCESS_MMD_CTRL);
-
- v = type << 2 | BIT(0); /* MMD-access-type | EXEC */
- sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0);
-
- do {
- v = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0);
- } while (v & BIT(0));
-
- /* Check for error condition */
- if (v & BIT(1))
- err = -EIO;
-
- *val = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_3) >> 16;
-
- pr_debug("%s: port %d, dev: %x, regnum: %x, val: %x (err %d)\n", __func__,
- port, devnum, regnum, *val, err);
-
- mutex_unlock(&rtmdio_lock);
-
- return err;
-}
-
-/* Write to an mmd register of the PHY */
-static int rtmdio_931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
-{
- int err = 0;
- u32 v;
- int type = 2;
- u64 pm;
-
- mutex_lock(&rtmdio_lock);
-
- /* Set PHY to access via port-mask */
- pm = (u64)1 << port;
- sw_w32((u32)pm, RTL931X_SMI_INDRT_ACCESS_CTRL_2);
- sw_w32((u32)(pm >> 32), RTL931X_SMI_INDRT_ACCESS_CTRL_2 + 4);
-
- /* Set data to write */
- sw_w32_mask(0xffff, val, RTL931X_SMI_INDRT_ACCESS_CTRL_3);
-
- /* Set MMD device number and register to write to */
- sw_w32(devnum << 16 | regnum, RTL931X_SMI_INDRT_ACCESS_MMD_CTRL);
-
- v = BIT(4) | type << 2 | BIT(0); /* WRITE | MMD-access-type | EXEC */
- sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0);
-
- do {
- v = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0);
- } while (v & BIT(0));
-
- pr_debug("%s: port %d, dev: %x, regnum: %x, val: %x (err %d)\n", __func__,
- port, devnum, regnum, val, err);
- 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)
-{
- struct rtmdio_bus_priv *priv = bus->priv;
- int err, val;
-
- if (priv->extaddr >= 0)
- addr = priv->extaddr;
-
- if (addr >= priv->cpu_port)
- return -ENODEV;
-
- err = (*priv->read_mmd_phy)(addr, devnum, regnum, &val);
- pr_debug("rd_MMD(adr=%d, dev=%d, reg=%d) = %d, err = %d\n",
- addr, devnum, regnum, val, err);
- 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->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->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;
- int err, val;
-
- if (priv->extaddr >= 0)
- addr = priv->extaddr;
-
- if (addr >= priv->cpu_port)
- return -ENODEV;
-
- if (regnum == RTMDIO_PAGE_SELECT && priv->page[addr] != priv->rawpage)
- return priv->page[addr];
-
- priv->raw[addr] = (priv->page[addr] == priv->rawpage);
- 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",
- addr, priv->page[addr], regnum, val, err);
- return err ? err : val;
-}
-
-static int rtmdio_93xx_read(struct mii_bus *bus, int addr, int regnum)
-{
- struct rtmdio_bus_priv *priv = bus->priv;
- int err, val;
-
- if (priv->extaddr >= 0)
- addr = priv->extaddr;
-
- if (addr >= priv->cpu_port)
- return -ENODEV;
-
- if (regnum == RTMDIO_PAGE_SELECT && priv->page[addr] != priv->rawpage)
- return priv->page[addr];
-
- priv->raw[addr] = (priv->page[addr] == priv->rawpage);
- if (priv->phy_is_internal[addr]) {
- return rtmdio_931x_read_sds_phy(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",
- addr, priv->page[addr], regnum, val, err);
- return err ? err : val;
-}
-
-static int rtmdio_write_c45(struct mii_bus *bus, int addr, int devnum, int regnum, u16 val)
-{
- struct rtmdio_bus_priv *priv = bus->priv;
- int err;
-
- if (priv->extaddr >= 0)
- addr = priv->extaddr;
-
- if (addr >= priv->cpu_port)
- return -ENODEV;
-
- err = (*priv->write_mmd_phy)(addr, devnum, regnum, val);
- pr_debug("wr_MMD(adr=%d, dev=%d, reg=%d, val=%d) err = %d\n",
- addr, devnum, regnum, val, err);
- return err;
-}
-
-static int rtmdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
-{
- struct rtmdio_bus_priv *priv = bus->priv;
- int err, page;
-
- if (regnum == RTMDIO_PORT_SELECT) {
- priv->extaddr = (s16)val;
- return 0;
- }
-
- if (priv->extaddr >= 0)
- addr = priv->extaddr;
-
- if (addr >= priv->cpu_port)
- return -ENODEV;
-
- page = priv->page[addr];
-
- if (regnum == RTMDIO_PAGE_SELECT)
- priv->page[addr] = val;
-
- 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)
- 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",
- addr, page, regnum, val, err);
- return err;
- }
-
- priv->raw[addr] = false;
- return 0;
-}
-
-static int rtmdio_93xx_write(struct mii_bus *bus, int addr, int regnum, u16 val)
-{
- struct rtmdio_bus_priv *priv = bus->priv;
- int err, page;
-
- if (regnum == RTMDIO_PORT_SELECT) {
- priv->extaddr = (s16)val;
- return 0;
- }
-
- if (priv->extaddr >= 0)
- addr = priv->extaddr;
-
- if (addr >= priv->cpu_port)
- return -ENODEV;
-
- page = priv->page[addr];
-
- if (regnum == RTMDIO_PAGE_SELECT)
- priv->page[addr] = val;
-
- if (!priv->raw[addr] && (regnum != RTMDIO_PAGE_SELECT || page == priv->rawpage)) {
- priv->raw[addr] = (page == priv->rawpage);
- if (priv->phy_is_internal[addr]) {
- return rtmdio_931x_write_sds_phy(priv->sds_id[addr],
- page, 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",
- addr, page, regnum, val, err);
- }
-
- priv->raw[addr] = false;
- return 0;
-}
-
-static int rtmdio_838x_reset(struct mii_bus *bus)
-{
- pr_debug("%s called\n", __func__);
- /* Disable MAC polling the PHY so that we can start configuration */
- sw_w32(0x00000000, RTL838X_SMI_POLL_CTRL);
-
- /* Enable PHY control via SoC */
- sw_w32_mask(0, 1 << 15, RTL838X_SMI_GLB_CTRL);
-
- /* Probably should reset all PHYs here... */
- return 0;
-}
-
-static int rtmdio_839x_reset(struct mii_bus *bus)
-{
- return 0;
-
- pr_debug("%s called\n", __func__);
- /* BUG: The following does not work, but should! */
- /* Disable MAC polling the PHY so that we can start configuration */
- sw_w32(0x00000000, RTL839X_SMI_PORT_POLLING_CTRL);
- sw_w32(0x00000000, RTL839X_SMI_PORT_POLLING_CTRL + 4);
- /* Disable PHY polling via SoC */
- sw_w32_mask(1 << 7, 0, RTL839X_SMI_GLB_CTRL);
-
- /* Probably should reset all PHYs here... */
- return 0;
-}
-
-u8 mac_type_bit[RTL930X_CPU_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;
-
- /* Mapping of port to phy-addresses on an SMI bus */
- for (int i = 0; i < RTL930X_CPU_PORT; i++) {
- int pos;
-
- if (priv->smi_bus[i] < 0)
- continue;
-
- pos = (i % 6) * 5;
- sw_w32_mask(0x1f << pos, priv->smi_addr[i] << pos,
- RTL930X_SMI_PORT0_5_ADDR + (i / 6) * 4);
-
- pos = (i * 2) % 32;
- poll_sel[i / 16] |= priv->smi_bus[i] << pos;
- poll_ctrl |= BIT(20 + priv->smi_bus[i]);
- }
-
- /* Configure which SMI bus is behind which port number */
- sw_w32(poll_sel[0], RTL930X_SMI_PORT0_15_POLLING_SEL);
- sw_w32(poll_sel[1], RTL930X_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, RTL930X_SMI_GLB_CTRL);
-
- /* Configure which SMI busses are polled in c45 based on a c45 PHY being on that bus */
- for (int i = 0; i < RTMDIO_MAX_SMI_BUS; i++)
- if (priv->smi_bus_isc45[i])
- c45_mask |= BIT(i + 16);
-
- pr_info("c45_mask: %08x\n", c45_mask);
- sw_w32_mask(GENMASK(19, 16), c45_mask, RTL930X_SMI_GLB_CTRL);
-
- /* Set the MAC type of each port according to the PHY-interface */
- /* Values are FE: 2, GE: 3, XGE/2.5G: 0(SERDES) or 1(otherwise), SXGE: 0 */
- v = 0;
- for (int i = 0; i < RTL930X_CPU_PORT; i++) {
- switch (priv->interfaces[i]) {
- case PHY_INTERFACE_MODE_10GBASER:
- break; /* Serdes: Value = 0 */
- case PHY_INTERFACE_MODE_HSGMII:
- private_poll_mask |= BIT(i);
- fallthrough;
- case PHY_INTERFACE_MODE_USXGMII:
- v |= BIT(mac_type_bit[i]);
- uses_usxgmii = true;
- break;
- case PHY_INTERFACE_MODE_QSGMII:
- private_poll_mask |= BIT(i);
- v |= 3 << mac_type_bit[i];
- break;
- default:
- break;
- }
- }
- sw_w32(v, RTL930X_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, RTL930X_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, RTL930X_SMI_10GPHY_POLLING_REG0_CFG);
- sw_w32(0x01E7C400, RTL930X_SMI_10GPHY_POLLING_REG9_CFG);
- sw_w32(0x01E7E820, RTL930X_SMI_10GPHY_POLLING_REG10_CFG);
- }
- if (uses_hisgmii) {
- sw_w32(0x011FA400, RTL930X_SMI_10GPHY_POLLING_REG0_CFG);
- sw_w32(0x013FA412, RTL930X_SMI_10GPHY_POLLING_REG9_CFG);
- sw_w32(0x017FA414, RTL930X_SMI_10GPHY_POLLING_REG10_CFG);
- }
-
- pr_debug("%s: RTL930X_SMI_GLB_CTRL %08x\n", __func__,
- sw_r32(RTL930X_SMI_GLB_CTRL));
- pr_debug("%s: RTL930X_SMI_PORT0_15_POLLING_SEL %08x\n", __func__,
- sw_r32(RTL930X_SMI_PORT0_15_POLLING_SEL));
- pr_debug("%s: RTL930X_SMI_PORT16_27_POLLING_SEL %08x\n", __func__,
- sw_r32(RTL930X_SMI_PORT16_27_POLLING_SEL));
- pr_debug("%s: RTL930X_SMI_MAC_TYPE_CTRL %08x\n", __func__,
- sw_r32(RTL930X_SMI_MAC_TYPE_CTRL));
- pr_debug("%s: RTL930X_SMI_10GPHY_POLLING_REG0_CFG %08x\n", __func__,
- sw_r32(RTL930X_SMI_10GPHY_POLLING_REG0_CFG));
- pr_debug("%s: RTL930X_SMI_10GPHY_POLLING_REG9_CFG %08x\n", __func__,
- sw_r32(RTL930X_SMI_10GPHY_POLLING_REG9_CFG));
- pr_debug("%s: RTL930X_SMI_10GPHY_POLLING_REG10_CFG %08x\n", __func__,
- sw_r32(RTL930X_SMI_10GPHY_POLLING_REG10_CFG));
- pr_debug("%s: RTL930X_SMI_PRVTE_POLLING_CTRL %08x\n", __func__,
- sw_r32(RTL930X_SMI_PRVTE_POLLING_CTRL));
-
- return 0;
-}
-
-static int rtmdio_931x_reset(struct mii_bus *bus)
-{
- struct rtmdio_bus_priv *priv = bus->priv;
- u32 poll_sel[4] = { 0 };
- u32 poll_ctrl = 0;
- u32 c45_mask = 0;
-
- pr_info("%s called\n", __func__);
- /* Disable port polling for configuration purposes */
- sw_w32(0, RTL931X_SMI_PORT_POLLING_CTRL);
- sw_w32(0, RTL931X_SMI_PORT_POLLING_CTRL + 4);
- msleep(100);
-
- /* Mapping of port to phy-addresses on an SMI bus */
- for (int i = 0; i < RTL931X_CPU_PORT; i++) {
- u32 pos;
-
- if (priv->smi_bus[i] < 0)
- continue;
-
- pos = (i % 6) * 5;
- sw_w32_mask(0x1f << pos, priv->smi_addr[i] << pos, RTL931X_SMI_PORT_ADDR + (i / 6) * 4);
- pos = (i * 2) % 32;
- poll_sel[i / 16] |= priv->smi_bus[i] << pos;
- poll_ctrl |= BIT(20 + priv->smi_bus[i]);
- }
-
- /* Configure which SMI bus is behind which port number */
- for (int i = 0; i < RTMDIO_MAX_SMI_BUS; i++) {
- pr_info("poll sel %d, %08x\n", i, poll_sel[i]);
- sw_w32(poll_sel[i], RTL931X_SMI_PORT_POLLING_SEL + (i * 4));
- }
-
- /* Configure which SMI busses */
- pr_info("c45_mask: %08x, RTL931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTL931X_SMI_GLB_CTRL0));
- for (int i = 0; i < RTMDIO_MAX_SMI_BUS; i++) {
- /* bus is polled in c45 */
- if (priv->smi_bus_isc45[i])
- c45_mask |= 0x2 << (i * 2); /* Std. C45, non-standard is 0x3 */
- }
-
- pr_info("c45_mask: %08x, RTL931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTL931X_SMI_GLB_CTRL0));
-
- /* We have a 10G PHY enable polling
- * sw_w32(0x01010000, RTL931X_SMI_10GPHY_POLLING_SEL2);
- * sw_w32(0x01E7C400, RTL931X_SMI_10GPHY_POLLING_SEL3);
- * sw_w32(0x01E7E820, RTL931X_SMI_10GPHY_POLLING_SEL4);
- */
- sw_w32_mask(GENMASK(7, 0), c45_mask, RTL931X_SMI_GLB_CTRL1);
-
- return 0;
-}
-
-static int rtl931x_chip_init(struct rtl838x_eth_priv *priv)
-{
- pr_info("In %s\n", __func__);
-
- /* Initialize Encapsulation memory and wait until finished */
- sw_w32(0x1, RTL931X_MEM_ENCAP_INIT);
- do { } while (sw_r32(RTL931X_MEM_ENCAP_INIT) & 1);
- pr_info("%s: init ENCAP done\n", __func__);
-
- /* Initialize Managemen Information Base memory and wait until finished */
- sw_w32(0x1, RTL931X_MEM_MIB_INIT);
- do { } while (sw_r32(RTL931X_MEM_MIB_INIT) & 1);
- pr_info("%s: init MIB done\n", __func__);
-
- /* Initialize ACL (PIE) memory and wait until finished */
- sw_w32(0x1, RTL931X_MEM_ACL_INIT);
- do { } while (sw_r32(RTL931X_MEM_ACL_INIT) & 1);
- pr_info("%s: init ACL done\n", __func__);
-
- /* Initialize ALE memory and wait until finished */
- sw_w32(0xFFFFFFFF, RTL931X_MEM_ALE_INIT_0);
- do { } while (sw_r32(RTL931X_MEM_ALE_INIT_0));
- sw_w32(0x7F, RTL931X_MEM_ALE_INIT_1);
- sw_w32(0x7ff, RTL931X_MEM_ALE_INIT_2);
- do { } while (sw_r32(RTL931X_MEM_ALE_INIT_2) & 0x7ff);
- pr_info("%s: init ALE done\n", __func__);
-
- /* Enable ESD auto recovery */
- sw_w32(0x1, RTL931X_MDX_CTRL_RSVD);
-
- /* Init SPI, is this for thermal control or what? */
- sw_w32_mask(0x7 << 11, 0x2 << 11, RTL931X_SPI_CTRL0);
-
- return 0;
-}
-
-static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
-{
- struct rtmdio_bus_priv *bus_priv;
- struct device_node *mii_np, *dn;
- int i, ret;
- u32 pn;
-
- pr_debug("%s called\n", __func__);
- mii_np = of_get_child_by_name(priv->pdev->dev.of_node, "mdio-bus");
-
- if (!mii_np) {
- dev_err(&priv->pdev->dev, "no %s child node found", "mdio-bus");
- return -ENODEV;
- }
-
- if (!of_device_is_available(mii_np)) {
- ret = -ENODEV;
- goto err_put_node;
- }
-
- priv->mii_bus = devm_mdiobus_alloc_size(&priv->pdev->dev, sizeof(*bus_priv));
- if (!priv->mii_bus) {
- ret = -ENOMEM;
- goto err_put_node;
- }
-
- bus_priv = priv->mii_bus->priv;
- bus_priv->id = soc_info.id;
- bus_priv->family_id = soc_info.family;
- for (i=0; i < RTMDIO_MAX_PORT; i++) {
- bus_priv->page[i] = 0;
- bus_priv->raw[i] = false;
- }
- bus_priv->extaddr = -1;
-
- switch(priv->family_id) {
- case RTL8380_FAMILY_ID:
- priv->mii_bus->name = "rtl838x-eth-mdio";
- priv->mii_bus->read = rtmdio_read;
- priv->mii_bus->write = rtmdio_write;
- priv->mii_bus->reset = rtmdio_838x_reset;
- bus_priv->read_sds_phy = rtmdio_838x_read_sds_phy;
- bus_priv->write_sds_phy = rtmdio_838x_write_sds_phy;
- bus_priv->read_mmd_phy = rtmdio_838x_read_mmd_phy;
- bus_priv->write_mmd_phy = rtmdio_838x_write_mmd_phy;
- bus_priv->read_phy = rtmdio_838x_read_phy;
- bus_priv->write_phy = rtmdio_838x_write_phy;
- bus_priv->cpu_port = RTL838X_CPU_PORT;
- bus_priv->rawpage = 0xfff;
- break;
- case RTL8390_FAMILY_ID:
- priv->mii_bus->name = "rtl839x-eth-mdio";
- priv->mii_bus->read = rtmdio_read;
- priv->mii_bus->write = rtmdio_write;
- priv->mii_bus->reset = rtmdio_839x_reset;
- 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;
- case RTL9300_FAMILY_ID:
- priv->mii_bus->name = "rtl930x-eth-mdio";
- priv->mii_bus->read = rtmdio_read;
- priv->mii_bus->write = rtmdio_write;
- priv->mii_bus->reset = rtmdio_930x_reset;
- bus_priv->read_sds_phy = rtmdio_930x_read_sds_phy;
- bus_priv->write_sds_phy = rtmdio_930x_write_sds_phy;
- bus_priv->read_mmd_phy = rtmdio_930x_read_mmd_phy;
- bus_priv->write_mmd_phy = rtmdio_930x_write_mmd_phy;
- bus_priv->read_phy = rtmdio_930x_read_phy;
- bus_priv->write_phy = rtmdio_930x_write_phy;
- bus_priv->cpu_port = RTL930X_CPU_PORT;
- bus_priv->rawpage = 0xfff;
- break;
- case RTL9310_FAMILY_ID:
- priv->mii_bus->name = "rtl931x-eth-mdio";
- priv->mii_bus->read = rtmdio_93xx_read;
- priv->mii_bus->write = rtmdio_93xx_write;
- priv->mii_bus->reset = rtmdio_931x_reset;
- bus_priv->read_mmd_phy = rtmdio_931x_read_mmd_phy;
- bus_priv->write_mmd_phy = rtmdio_931x_write_mmd_phy;
- bus_priv->read_phy = rtmdio_931x_read_phy;
- bus_priv->write_phy = rtmdio_931x_write_phy;
- bus_priv->cpu_port = RTL931X_CPU_PORT;
- bus_priv->rawpage = 0x1fff;
- break;
- }
- priv->mii_bus->read_c45 = rtmdio_read_c45;
- priv->mii_bus->write_c45 = rtmdio_write_c45;
- priv->mii_bus->parent = &priv->pdev->dev;
- priv->mii_bus->phy_mask = ~(BIT_ULL(bus_priv->cpu_port) - 1ULL);
-
- for_each_node_by_name(dn, "ethernet-phy") {
- u32 smi_addr[2];
-
- if (of_property_read_u32(dn, "reg", &pn))
- continue;
-
- if (pn >= RTMDIO_MAX_PORT) {
- pr_err("%s: illegal port number %d\n", __func__, pn);
- return -ENODEV;
- }
-
- if (of_property_read_u32(dn, "sds", &bus_priv->sds_id[pn]))
- bus_priv->sds_id[pn] = -1;
- else
- pr_info("set sds port %d to %d\n", pn, bus_priv->sds_id[pn]);
-
- if (of_property_read_u32_array(dn, "rtl9300,smi-address", &smi_addr[0], 2)) {
- bus_priv->smi_bus[pn] = 0;
- bus_priv->smi_addr[pn] = pn;
- } else {
- bus_priv->smi_bus[pn] = smi_addr[0];
- bus_priv->smi_addr[pn] = smi_addr[1];
- }
-
- if (bus_priv->smi_bus[pn] >= RTMDIO_MAX_SMI_BUS) {
- pr_err("%s: illegal SMI bus number %d\n", __func__, bus_priv->smi_bus[pn]);
- return -ENODEV;
- }
-
- bus_priv->phy_is_internal[pn] = of_property_read_bool(dn, "phy-is-integrated");
-
- if (bus_priv->phy_is_internal[pn] && bus_priv->sds_id[pn] >= 0)
- bus_priv->smi_bus[pn]= -1;
- else if (of_device_is_compatible(dn, "ethernet-phy-ieee802.3-c45"))
- bus_priv->smi_bus_isc45[bus_priv->smi_bus[pn]] = true;
- }
-
- dn = of_find_compatible_node(NULL, NULL, "realtek,rtl83xx-switch");
- if (!dn) {
- dev_err(&priv->pdev->dev, "No RTL switch node in DTS\n");
- return -ENODEV;
- }
-
- for_each_node_by_name(dn, "port") {
- if (of_property_read_u32(dn, "reg", &pn))
- continue;
- pr_debug("%s Looking at port %d\n", __func__, pn);
- if (pn > priv->cpu_port)
- continue;
- if (of_get_phy_mode(dn, &bus_priv->interfaces[pn]))
- bus_priv->interfaces[pn] = PHY_INTERFACE_MODE_NA;
- pr_debug("%s phy mode of port %d is %s\n",
- __func__, pn, phy_modes(bus_priv->interfaces[pn]));
- }
-
- snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np);
- ret = devm_of_mdiobus_register(&priv->pdev->dev, priv->mii_bus, mii_np);
-
-err_put_node:
- of_node_put(mii_np);
-
- return ret;
-}
-
-static netdev_features_t rtl838x_fix_features(struct net_device *dev,
- netdev_features_t features)
-{
- return features;
-}
-
-static int rtl83xx_set_features(struct net_device *dev, netdev_features_t features)
-{
- struct rtl838x_eth_priv *priv = netdev_priv(dev);
-
- if ((features ^ dev->features) & NETIF_F_RXCSUM) {
- if (!(features & NETIF_F_RXCSUM))
- sw_w32_mask(BIT(3), 0, priv->r->mac_port_ctrl(priv->cpu_port));
- else
- sw_w32_mask(0, BIT(3), priv->r->mac_port_ctrl(priv->cpu_port));
- }
-
- return 0;
-}
-
-static int rtl93xx_set_features(struct net_device *dev, netdev_features_t features)
-{
- struct rtl838x_eth_priv *priv = netdev_priv(dev);
-
- if ((features ^ dev->features) & NETIF_F_RXCSUM) {
- if (!(features & NETIF_F_RXCSUM))
- sw_w32_mask(BIT(4), 0, priv->r->mac_port_ctrl(priv->cpu_port));
- else
- sw_w32_mask(0, BIT(4), priv->r->mac_port_ctrl(priv->cpu_port));
- }
-
- return 0;
-}
-
-static struct phylink_pcs *rtl838x_mac_select_pcs(struct phylink_config *config,
- phy_interface_t interface)
-{
- struct net_device *dev = to_net_dev(config->dev);
- struct rtl838x_eth_priv *priv = netdev_priv(dev);
-
- return &priv->pcs;
-}
-
-static const struct net_device_ops rtl838x_eth_netdev_ops = {
- .ndo_open = rtl838x_eth_open,
- .ndo_stop = rtl838x_eth_stop,
- .ndo_start_xmit = rtl838x_eth_tx,
- .ndo_select_queue = rtl83xx_pick_tx_queue,
- .ndo_set_mac_address = rtl838x_set_mac_address,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_rx_mode = rtl838x_eth_set_multicast_list,
- .ndo_tx_timeout = rtl838x_eth_tx_timeout,
- .ndo_set_features = rtl83xx_set_features,
- .ndo_fix_features = rtl838x_fix_features,
- .ndo_setup_tc = rtl83xx_setup_tc,
-};
-
-static const struct net_device_ops rtl839x_eth_netdev_ops = {
- .ndo_open = rtl838x_eth_open,
- .ndo_stop = rtl838x_eth_stop,
- .ndo_start_xmit = rtl838x_eth_tx,
- .ndo_select_queue = rtl83xx_pick_tx_queue,
- .ndo_set_mac_address = rtl838x_set_mac_address,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_rx_mode = rtl839x_eth_set_multicast_list,
- .ndo_tx_timeout = rtl838x_eth_tx_timeout,
- .ndo_set_features = rtl83xx_set_features,
- .ndo_fix_features = rtl838x_fix_features,
- .ndo_setup_tc = rtl83xx_setup_tc,
-};
-
-static const struct net_device_ops rtl930x_eth_netdev_ops = {
- .ndo_open = rtl838x_eth_open,
- .ndo_stop = rtl838x_eth_stop,
- .ndo_start_xmit = rtl838x_eth_tx,
- .ndo_select_queue = rtl93xx_pick_tx_queue,
- .ndo_set_mac_address = rtl838x_set_mac_address,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_rx_mode = rtl930x_eth_set_multicast_list,
- .ndo_tx_timeout = rtl838x_eth_tx_timeout,
- .ndo_set_features = rtl93xx_set_features,
- .ndo_fix_features = rtl838x_fix_features,
- .ndo_setup_tc = rtl83xx_setup_tc,
-};
-
-static const struct net_device_ops rtl931x_eth_netdev_ops = {
- .ndo_open = rtl838x_eth_open,
- .ndo_stop = rtl838x_eth_stop,
- .ndo_start_xmit = rtl838x_eth_tx,
- .ndo_select_queue = rtl93xx_pick_tx_queue,
- .ndo_set_mac_address = rtl838x_set_mac_address,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_rx_mode = rtl931x_eth_set_multicast_list,
- .ndo_tx_timeout = rtl838x_eth_tx_timeout,
- .ndo_set_features = rtl93xx_set_features,
- .ndo_fix_features = rtl838x_fix_features,
-};
-
-static const struct phylink_pcs_ops rtl838x_pcs_ops = {
- .pcs_get_state = rtl838x_pcs_get_state,
- .pcs_an_restart = rtl838x_pcs_an_restart,
- .pcs_config = rtl838x_pcs_config,
-};
-
-static const struct phylink_mac_ops rtl838x_phylink_ops = {
- .mac_select_pcs = rtl838x_mac_select_pcs,
- .mac_config = rtl838x_mac_config,
- .mac_link_down = rtl838x_mac_link_down,
- .mac_link_up = rtl838x_mac_link_up,
-};
-
-static const struct ethtool_ops rtl838x_ethtool_ops = {
- .get_link_ksettings = rtl838x_get_link_ksettings,
- .set_link_ksettings = rtl838x_set_link_ksettings,
-};
-
-static int __init rtl838x_eth_probe(struct platform_device *pdev)
-{
- struct net_device *dev;
- struct device_node *dn = pdev->dev.of_node;
- struct rtl838x_eth_priv *priv;
- struct resource *res, *mem;
- phy_interface_t phy_mode;
- struct phylink *phylink;
- u8 mac_addr[ETH_ALEN];
- int err = 0, rxrings, rxringlen;
- struct ring_b *ring;
-
- pr_info("Probing RTL838X eth device pdev: %x, dev: %x\n",
- (u32)pdev, (u32)(&(pdev->dev)));
-
- if (!dn) {
- dev_err(&pdev->dev, "No DT found\n");
- return -EINVAL;
- }
-
- rxrings = (soc_info.family == RTL8380_FAMILY_ID
- || soc_info.family == RTL8390_FAMILY_ID) ? 8 : 32;
- rxrings = rxrings > MAX_RXRINGS ? MAX_RXRINGS : rxrings;
- rxringlen = MAX_ENTRIES / rxrings;
- rxringlen = rxringlen > MAX_RXLEN ? MAX_RXLEN : rxringlen;
-
- dev = devm_alloc_etherdev_mqs(&pdev->dev, sizeof(struct rtl838x_eth_priv), TXRINGS, rxrings);
- if (!dev)
- return -ENOMEM;
- SET_NETDEV_DEV(dev, &pdev->dev);
- priv = netdev_priv(dev);
-
- /* obtain buffer memory space */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res) {
- mem = devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), res->name);
- if (!mem) {
- dev_err(&pdev->dev, "cannot request memory space\n");
- return -ENXIO;
- }
-
- dev->mem_start = mem->start;
- dev->mem_end = mem->end;
- } else {
- dev_err(&pdev->dev, "cannot request IO resource\n");
- return -ENXIO;
- }
-
- /* Allocate buffer memory */
- priv->membase = dmam_alloc_coherent(&pdev->dev, rxrings * rxringlen * RING_BUFFER +
- sizeof(struct ring_b) + sizeof(struct notify_b),
- (void *)&dev->mem_start, GFP_KERNEL);
- if (!priv->membase) {
- dev_err(&pdev->dev, "cannot allocate DMA buffer\n");
- return -ENOMEM;
- }
-
- /* Allocate ring-buffer space at the end of the allocated memory */
- ring = priv->membase;
- ring->rx_space = priv->membase + sizeof(struct ring_b) + sizeof(struct notify_b);
-
- spin_lock_init(&priv->lock);
-
- dev->ethtool_ops = &rtl838x_ethtool_ops;
- dev->min_mtu = ETH_ZLEN;
- dev->max_mtu = DEFAULT_MTU;
- dev->features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM;
- dev->hw_features = NETIF_F_RXCSUM;
+ dev->ethtool_ops = &rtl838x_ethtool_ops;
+ dev->min_mtu = ETH_ZLEN;
+ dev->max_mtu = DEFAULT_MTU;
+ dev->features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM;
+ dev->hw_features = NETIF_F_RXCSUM;
priv->id = soc_info.id;
priv->family_id = soc_info.family;
priv->pdev = pdev;
priv->netdev = dev;
- err = rtl838x_mdio_init(priv);
- if (err)
- return err;
-
for (int i = 0; i < priv->rxrings; i++) {
priv->rx_qs[i].id = i;
priv->rx_qs[i].priv = priv;
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/mutex.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#define RTMDIO_MAX_PORT 57
+#define RTMDIO_MAX_SMI_BUS 4
+#define RTMDIO_PAGE_SELECT 0x1f
+
+#define RTMDIO_838X_CPU_PORT 28
+#define RTMDIO_838X_FAMILY_ID 0x8380
+
+#define RTMDIO_839X_CPU_PORT 52
+#define RTMDIO_839X_FAMILY_ID 0x8390
+
+#define RTMDIO_930X_CPU_PORT 28
+#define RTMDIO_930X_FAMILY_ID 0x9300
+
+#define RTMDIO_931X_CPU_PORT 56
+#define RTMDIO_931X_FAMILY_ID 0x9310
+
+/* Register base */
+#define RTMDIO_SW_BASE ((volatile void *) 0xBB000000)
+
+/* MDIO bus registers */
+#define RTMDIO_838X_SMI_GLB_CTRL (0xa100)
+#define RTMDIO_838X_SMI_ACCESS_PHY_CTRL_0 (0xa1b8)
+#define RTMDIO_838X_SMI_ACCESS_PHY_CTRL_1 (0xa1bc)
+#define RTMDIO_838X_SMI_ACCESS_PHY_CTRL_2 (0xa1c0)
+#define RTMDIO_838X_SMI_ACCESS_PHY_CTRL_3 (0xa1c4)
+#define RTMDIO_838X_SMI_POLL_CTRL (0xa17c)
+
+#define RTMDIO_839X_PHYREG_CTRL (0x03E0)
+#define RTMDIO_839X_PHYREG_PORT_CTRL (0x03E4)
+#define RTMDIO_839X_PHYREG_ACCESS_CTRL (0x03DC)
+#define RTMDIO_839X_PHYREG_DATA_CTRL (0x03F0)
+#define RTMDIO_839X_PHYREG_MMD_CTRL (0x03F4)
+#define RTMDIO_839X_SMI_PORT_POLLING_CTRL (0x03fc)
+#define RTMDIO_839X_SMI_GLB_CTRL (0x03f8)
+
+#define RTMDIO_930X_SMI_GLB_CTRL (0xCA00)
+#define RTMDIO_930X_SMI_ACCESS_PHY_CTRL_0 (0xCB70)
+#define RTMDIO_930X_SMI_ACCESS_PHY_CTRL_1 (0xCB74)
+#define RTMDIO_930X_SMI_ACCESS_PHY_CTRL_2 (0xCB78)
+#define RTMDIO_930X_SMI_ACCESS_PHY_CTRL_3 (0xCB7C)
+#define RTMDIO_930X_SMI_PORT0_15_POLLING_SEL (0xCA08)
+#define RTMDIO_930X_SMI_PORT16_27_POLLING_SEL (0xCA0C)
+#define RTMDIO_930X_SMI_MAC_TYPE_CTRL (0xCA04)
+#define RTMDIO_930X_SMI_PRVTE_POLLING_CTRL (0xCA10)
+#define RTMDIO_930X_SMI_10G_POLLING_REG0_CFG (0xCBB4)
+#define RTMDIO_930X_SMI_10G_POLLING_REG9_CFG (0xCBB8)
+#define RTMDIO_930X_SMI_10G_POLLING_REG10_CFG (0xCBBC)
+#define RTMDIO_930X_SMI_PORT0_5_ADDR (0xCB80)
+
+#define RTMDIO_931X_SMI_PORT_POLLING_CTRL (0x0CCC)
+#define RTMDIO_931X_SMI_INDRT_ACCESS_BC_CTRL (0x0C14)
+#define RTMDIO_931X_SMI_GLB_CTRL0 (0x0CC0)
+#define RTMDIO_931X_SMI_GLB_CTRL1 (0x0CBC)
+#define RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0 (0x0C00)
+#define RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_1 (0x0C04)
+#define RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_2 (0x0C08)
+#define RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_3 (0x0C10)
+#define RTMDIO_931X_SMI_INDRT_ACCESS_MMD_CTRL (0x0C18)
+#define RTMDIO_931X_MAC_L2_GLOBAL_CTRL2 (0x1358)
+#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)
+
+/* Other registers */
+#define RTMDIO_839X_MODEL_NAME_INFO_REG (0x0ff0)
+#define RTMDIO_93XX_MODEL_NAME_INFO_REG (0x0004)
+
+#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)
+
+int rtmdio_930x_read_sds_phy(int sds, int page, int regnum);
+int rtmdio_930x_write_sds_phy(int sds, int page, int regnum, u16 val);
+
+int rtmdio_931x_read_sds_phy_new(int sds, int page, int regnum);
+int rtmdio_931x_write_sds_phy_new(int sds, int page, int regnum, u16 val);
+
+/*
+ * On all Realtek switch platforms the hardware periodically reads the link status of all
+ * PHYs. This is to some degree programmable, so that one can tell the hardware to read
+ * specific C22 registers from specific pages, or C45 registers, to determine the current
+ * link speed, duplex, flow-control, ...
+ *
+ * This happens without any need for the driver to do anything at runtime, completely
+ * invisible and in a parallel hardware thread, independent of the CPU running Linux.
+ * All one needs to do is to set it up once. Having the MAC link settings automatically
+ * follow the PHY link status also happens to be the only way to control MAC port status
+ * in a meaningful way, or at least it's the only way we fully understand, as this is
+ * what every vendor firmware is doing.
+ *
+ * The hardware PHY polling unit doesn't care about bus locking, it just assumes that all
+ * paged PHY operations are also done via the same hardware unit offering this PHY access
+ * abstractions.
+ *
+ * Additionally at least the RTL838x and RTL839x devices are known to have a so called
+ * raw mode. Using the special MAX_PAGE-1 with the MDIO controller found in Realtek
+ * SoCs allows to access the PHY in raw mode, ie. bypassing the cache and paging engine
+ * of the MDIO controller. E.g. for RTL838x this is 0xfff.
+ *
+ * On the other hand Realtek PHYs usually make use of select register 0x1f to switch
+ * pages. There is no problem to issue separate page and access bus calls to the PHYs
+ * when they are not attached to an Realtek SoC. The paradigm should be to keep the PHY
+ * implementation bus independent.
+ *
+ * As if this is not enough the PHY packages consist of 4 or 8 ports that all can be
+ * programmed individually. Some registers are only available on port 0 and configure
+ * the whole package.
+ *
+ * To bring all this together we need a tricky bus design that intercepts select page
+ * calls but lets raw page accesses through. And especially knows how to handle raw
+ * accesses to the select register. Additionally we need the possibility to write to
+ * all 8 ports of the PHY individually.
+ *
+ * While the C45 clause stuff is pretty standard the legacy functions basically track
+ * the accesses and the state of the bus with the attributes page[], raw[] and portaddr
+ * of the bus_priv structure. The page selection works as follows:
+ *
+ * phy_write(phydev, RTMDIO_PAGE_SELECT, 12) : store internal page 12 in driver
+ * phy_write(phydev, 7, 33) : write page=12, reg=7, val=33
+ *
+ * or simply
+ *
+ * phy_write_paged(phydev, 12, 7, 33) : write page=12, reg=7, val=33
+ *
+ * Any Realtek PHY that will be connected to this bus must simply provide the standard
+ * page functions:
+ *
+ * define RTL821X_PAGE_SELECT 0x1f
+ *
+ * static int rtl821x_read_page(struct phy_device *phydev)
+ * {
+ * return __phy_read(phydev, RTL821X_PAGE_SELECT);
+ * }
+ *
+ * static int rtl821x_write_page(struct phy_device *phydev, int page)
+ * {
+ * return __phy_write(phydev, RTL821X_PAGE_SELECT, page);
+ * }
+ *
+ * In case there are non Realtek PHYs attached to the bus the logic might need to be
+ * reimplemented. For now it should be sufficient.
+ */
+
+DEFINE_MUTEX(rtmdio_lock);
+DEFINE_MUTEX(rtmdio_lock_sds);
+
+struct rtmdio_bus_priv {
+ u16 id;
+ u16 family_id;
+ int rawpage;
+ int cpu_port;
+ int page[RTMDIO_MAX_PORT];
+ 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 (*read_mmd_phy)(u32 port, u32 addr, u32 reg, u32 *val);
+ int (*write_mmd_phy)(u32 port, u32 addr, u32 reg, u32 val);
+ int (*read_phy)(u32 port, u32 page, u32 reg, u32 *val);
+ int (*write_phy)(u32 port, u32 page, u32 reg, u32 val);
+ int (*read_sds_phy)(int sds, int page, int regnum);
+ 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)
+{
+ int ret = 0;
+ u32 val;
+
+ ret = readx_poll_timeout(sw_r32, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_1,
+ val, !(val & 0x1), 20, timeout);
+ if (ret)
+ pr_err("%s: timeout\n", __func__);
+
+ return ret;
+}
+
+/* Reads a register in a page from the PHY */
+static int rtmdio_838x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
+{
+ u32 v, park_page = 0x1f << 15;
+ int err;
+
+ if (port > 31) {
+ *val = 0xffff;
+ return 0;
+ }
+
+ if (page > 4095 || reg > 31)
+ return -ENOTSUPP;
+
+ mutex_lock(&rtmdio_lock);
+
+ sw_w32_mask(0xffff0000, port << 16, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_2);
+ v = reg << 20 | page << 3;
+ sw_w32(v | park_page, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_1);
+ sw_w32_mask(0, 1, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_1);
+
+ err = rtmdio_838x_smi_wait_op(100000);
+ if (err)
+ goto errout;
+
+ *val = sw_r32(RTMDIO_838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
+errout:
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+/* Write to a register in a page of the PHY */
+static int rtmdio_838x_write_phy(u32 port, u32 page, u32 reg, u32 val)
+{
+ u32 v, park_page = 0x1f << 15;
+ int err;
+
+ val &= 0xffff;
+ if (port > 31 || page > 4095 || reg > 31)
+ return -ENOTSUPP;
+
+ mutex_lock(&rtmdio_lock);
+
+ sw_w32(BIT(port), RTMDIO_838X_SMI_ACCESS_PHY_CTRL_0);
+ sw_w32_mask(0xffff0000, val << 16, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_2);
+
+ v = reg << 20 | page << 3 | 0x4;
+ sw_w32(v | park_page, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_1);
+ sw_w32_mask(0, 1, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_1);
+
+ err = rtmdio_838x_smi_wait_op(100000);
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+/* Read an mmd register of a PHY */
+static int rtmdio_838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val)
+{
+ int err;
+ u32 v;
+
+ mutex_lock(&rtmdio_lock);
+
+ sw_w32(1 << port, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_0);
+ sw_w32_mask(0xffff0000, port << 16, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_2);
+
+ v = addr << 16 | reg;
+ sw_w32(v, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_3);
+
+ /* mmd-access | read | cmd-start */
+ v = 1 << 1 | 0 << 2 | 1;
+ sw_w32(v, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_1);
+
+ err = rtmdio_838x_smi_wait_op(100000);
+ if (err)
+ goto errout;
+
+ *val = sw_r32(RTMDIO_838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
+errout:
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+/* Write to an mmd register of a PHY */
+static int rtmdio_838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val)
+{
+ int err;
+ u32 v;
+
+ pr_debug("MMD write: port %d, dev %d, reg %d, val %x\n", port, addr, reg, val);
+ val &= 0xffff;
+ mutex_lock(&rtmdio_lock);
+
+ sw_w32(1 << port, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_0);
+ sw_w32_mask(0xffff0000, val << 16, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_2);
+ sw_w32_mask(0x1f << 16, addr << 16, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_3);
+ sw_w32_mask(0xffff, reg, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_3);
+ /* mmd-access | write | cmd-start */
+ v = 1 << 1 | 1 << 2 | 1;
+ sw_w32(v, RTMDIO_838X_SMI_ACCESS_PHY_CTRL_1);
+
+ err = rtmdio_838x_smi_wait_op(100000);
+ mutex_unlock(&rtmdio_lock);
+
+ 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, RTMDIO_839X_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 >= RTMDIO_839X_CPU_PORT || page > 8191 || reg > 31)
+ return -ENOTSUPP;
+
+ mutex_lock(&rtmdio_lock);
+
+ sw_w32_mask(0xffff0000, port << 16, RTMDIO_839X_PHYREG_DATA_CTRL);
+ v = reg << 5 | page << 10 | ((page == 0x1fff) ? 0x1f : 0) << 23;
+ sw_w32(v, RTMDIO_839X_PHYREG_ACCESS_CTRL);
+
+ sw_w32(0x1ff, RTMDIO_839X_PHYREG_CTRL);
+
+ v |= 1;
+ sw_w32(v, RTMDIO_839X_PHYREG_ACCESS_CTRL);
+
+ err = rtmdio_839x_smi_wait_op(100000);
+ if (err)
+ goto errout;
+
+ *val = sw_r32(RTMDIO_839X_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 >= RTMDIO_839X_CPU_PORT || page > 8191 || reg > 31)
+ return -ENOTSUPP;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access */
+ sw_w32(BIT_ULL(port), RTMDIO_839X_PHYREG_PORT_CTRL);
+ sw_w32(BIT_ULL(port) >> 32, RTMDIO_839X_PHYREG_PORT_CTRL + 4);
+
+ sw_w32_mask(0xffff0000, val << 16, RTMDIO_839X_PHYREG_DATA_CTRL);
+
+ v = reg << 5 | page << 10 | ((page == 0x1fff) ? 0x1f : 0) << 23;
+ sw_w32(v, RTMDIO_839X_PHYREG_ACCESS_CTRL);
+
+ sw_w32(0x1ff, RTMDIO_839X_PHYREG_CTRL);
+
+ v |= BIT(3) | 1; /* Write operation and execute */
+ sw_w32(v, RTMDIO_839X_PHYREG_ACCESS_CTRL);
+
+ err = rtmdio_839x_smi_wait_op(100000);
+ if (err)
+ goto errout;
+
+ if (sw_r32(RTMDIO_839X_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 >= RTMDIO_839X_CPU_PORT)
+ return -EIO;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access */
+ sw_w32_mask(0xffff << 16, port << 16, RTMDIO_839X_PHYREG_DATA_CTRL);
+
+ /* Set MMD device number and register to write to */
+ sw_w32(devnum << 16 | (regnum & 0xffff), RTMDIO_839X_PHYREG_MMD_CTRL);
+
+ v = BIT(2) | BIT(0); /* MMD-access | EXEC */
+ sw_w32(v, RTMDIO_839X_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(RTMDIO_839X_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 >= RTMDIO_839X_CPU_PORT)
+ return -EIO;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access */
+ sw_w32(BIT_ULL(port), RTMDIO_839X_PHYREG_PORT_CTRL);
+ sw_w32(BIT_ULL(port) >> 32, RTMDIO_839X_PHYREG_PORT_CTRL + 4);
+
+ /* Set data to write */
+ sw_w32_mask(0xffff << 16, val << 16, RTMDIO_839X_PHYREG_DATA_CTRL);
+
+ /* Set MMD device number and register to write to */
+ sw_w32(devnum << 16 | (regnum & 0xffff), RTMDIO_839X_PHYREG_MMD_CTRL);
+
+ v = BIT(3) | BIT(2) | BIT(0); /* WRITE | MMD-access | EXEC */
+ sw_w32(v, RTMDIO_839X_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;
+}
+
+/*
+ * 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
+ */
+
+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;
+}
+
+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)
+{
+ u32 v;
+ int err = 0;
+
+ pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, val);
+
+ if (port > 63 || page > 4095 || reg > 31)
+ return -ENOTSUPP;
+
+ val &= 0xffff;
+ mutex_lock(&rtmdio_lock);
+
+ sw_w32(BIT(port), RTMDIO_930X_SMI_ACCESS_PHY_CTRL_0);
+ sw_w32_mask(0xffff << 16, val << 16, RTMDIO_930X_SMI_ACCESS_PHY_CTRL_2);
+ v = reg << 20 | page << 3 | 0x1f << 15 | BIT(2) | BIT(0);
+ sw_w32(v, RTMDIO_930X_SMI_ACCESS_PHY_CTRL_1);
+
+ do {
+ v = sw_r32(RTMDIO_930X_SMI_ACCESS_PHY_CTRL_1);
+ } while (v & 0x1);
+
+ if (v & 0x2)
+ err = -EIO;
+
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+static int rtmdio_930x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
+{
+ u32 v;
+ int err = 0;
+
+ if (port > 63 || page > 4095 || reg > 31)
+ return -ENOTSUPP;
+
+ mutex_lock(&rtmdio_lock);
+
+ sw_w32_mask(0xffff << 16, port << 16, RTMDIO_930X_SMI_ACCESS_PHY_CTRL_2);
+ v = reg << 20 | page << 3 | 0x1f << 15 | 1;
+ sw_w32(v, RTMDIO_930X_SMI_ACCESS_PHY_CTRL_1);
+
+ do {
+ v = sw_r32(RTMDIO_930X_SMI_ACCESS_PHY_CTRL_1);
+ } while ( v & 0x1);
+
+ if (v & BIT(25)) {
+ pr_debug("Error reading phy %d, register %d\n", port, reg);
+ err = -EIO;
+ }
+ *val = (sw_r32(RTMDIO_930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff);
+
+ pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, *val);
+
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+/* Write to an mmd register of the PHY */
+static int rtmdio_930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
+{
+ int err = 0;
+ u32 v;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access */
+ sw_w32(BIT(port), RTMDIO_930X_SMI_ACCESS_PHY_CTRL_0);
+
+ /* Set data to write */
+ sw_w32_mask(0xffff << 16, val << 16, RTMDIO_930X_SMI_ACCESS_PHY_CTRL_2);
+
+ /* Set MMD device number and register to write to */
+ sw_w32(devnum << 16 | (regnum & 0xffff), RTMDIO_930X_SMI_ACCESS_PHY_CTRL_3);
+
+ v = BIT(2) | BIT(1) | BIT(0); /* WRITE | MMD-access | EXEC */
+ sw_w32(v, RTMDIO_930X_SMI_ACCESS_PHY_CTRL_1);
+
+ do {
+ v = sw_r32(RTMDIO_930X_SMI_ACCESS_PHY_CTRL_1);
+ } while (v & BIT(0));
+
+ pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err);
+ mutex_unlock(&rtmdio_lock);
+ return err;
+}
+
+/* Read an mmd register of the PHY */
+static int rtmdio_930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
+{
+ int err = 0;
+ u32 v;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access */
+ sw_w32_mask(0xffff << 16, port << 16, RTMDIO_930X_SMI_ACCESS_PHY_CTRL_2);
+
+ /* Set MMD device number and register to write to */
+ sw_w32(devnum << 16 | (regnum & 0xffff), RTMDIO_930X_SMI_ACCESS_PHY_CTRL_3);
+
+ v = BIT(1) | BIT(0); /* MMD-access | EXEC */
+ sw_w32(v, RTMDIO_930X_SMI_ACCESS_PHY_CTRL_1);
+
+ do {
+ v = sw_r32(RTMDIO_930X_SMI_ACCESS_PHY_CTRL_1);
+ } while (v & BIT(0));
+ /* There is no error-checking via BIT 25 of v, as it does not seem to be set correctly */
+ *val = (sw_r32(RTMDIO_930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff);
+ pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err);
+
+ mutex_unlock(&rtmdio_lock);
+
+ 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 rtmdio_931x_get_backing_sds(u32 sds, u32 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 rtmdio_931x_read_sds_phy(int sds, int page, int regnum)
+{
+ u32 cmd = sds << 2 | page << 7 | regnum << 13 | 1;
+ int i, ret = -EIO;
+
+ pr_debug("%s: phy_addr(SDS-ID) %d, phy_reg: %d\n", __func__, sds, regnum);
+
+ mutex_lock(&rtmdio_lock_sds);
+ 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))
+ break;
+ mdelay(1);
+ }
+
+ if (i < 100)
+ ret = sw_r32(RTMDIO_931X_SERDES_INDRT_DATA_CTRL) & 0xffff;
+
+ mutex_unlock(&rtmdio_lock_sds);
+
+ pr_debug("%s: returning %08x\n", __func__, ret);
+
+ return ret;
+}
+
+int rtmdio_931x_read_sds_phy_new(int sds, int page, int regnum)
+{
+ int backsds = rtmdio_931x_get_backing_sds(sds, page);
+
+ return backsds < 0 ? 0 : rtmdio_931x_read_sds_phy(backsds, page & 0x3f, regnum);
+}
+
+static int rtmdio_931x_write_sds_phy(int sds, int page, int regnum, u16 val)
+{
+ u32 cmd = sds << 2 | page << 7 | regnum << 13;;
+ int i, ret = -EIO;
+
+ mutex_lock(&rtmdio_lock_sds);
+ sw_w32(cmd, RTMDIO_931X_SERDES_INDRT_ACCESS_CTRL);
+ sw_w32(val, RTMDIO_931X_SERDES_INDRT_DATA_CTRL);
+
+ cmd = sw_r32(RTMDIO_931X_SERDES_INDRT_ACCESS_CTRL) | 0x3;
+ 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))
+ break;
+ mdelay(1);
+ }
+
+ mutex_unlock(&rtmdio_lock_sds);
+
+ if (i < 100)
+ ret = 0;
+
+ return ret;
+}
+
+int rtmdio_931x_write_sds_phy_new(int sds, int page, int regnum, u16 val)
+{
+ int backsds = rtmdio_931x_get_backing_sds(sds, page);
+
+ return backsds < 0 ? 0 : rtmdio_931x_write_sds_phy(backsds, page & 0x3f, regnum, val);
+}
+
+/* RTL931x specific MDIO functions */
+
+static int rtmdio_931x_write_phy(u32 port, u32 page, u32 reg, u32 val)
+{
+ u32 v;
+ int err = 0;
+
+ val &= 0xffff;
+ if (port > 63 || page > 4095 || reg > 31)
+ return -ENOTSUPP;
+
+ mutex_lock(&rtmdio_lock);
+ pr_debug("%s: writing to phy %d %d %d %d\n", __func__, port, page, reg, val);
+ /* Clear both port registers */
+ sw_w32(0, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_2);
+ sw_w32(0, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_2 + 4);
+ sw_w32_mask(0, BIT(port % 32), RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_2 + (port / 32) * 4);
+
+ sw_w32_mask(0xffff, val, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_3);
+
+ v = reg << 6 | page << 11 ;
+ sw_w32(v, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0);
+
+ sw_w32(0x1ff, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_1);
+
+ v |= BIT(4) | 1; /* Write operation and execute */
+ sw_w32(v, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0);
+
+ do {
+ } while (sw_r32(RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0) & 0x1);
+
+ if (sw_r32(RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0) & 0x2)
+ err = -EIO;
+
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+static int rtmdio_931x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
+{
+ u32 v;
+
+ if (port > 63 || page > 4095 || reg > 31)
+ return -ENOTSUPP;
+
+ mutex_lock(&rtmdio_lock);
+
+ sw_w32(port << 5, RTMDIO_931X_SMI_INDRT_ACCESS_BC_CTRL);
+
+ v = reg << 6 | page << 11 | 1;
+ sw_w32(v, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0);
+
+ do {
+ } while (sw_r32(RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0) & 0x1);
+
+ v = sw_r32(RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0);
+ *val = sw_r32(RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_3);
+ *val = (*val & 0xffff0000) >> 16;
+
+ pr_debug("%s: port %d, page: %d, reg: %x, val: %x, v: %08x\n",
+ __func__, port, page, reg, *val, v);
+
+ mutex_unlock(&rtmdio_lock);
+
+ return 0;
+}
+
+/* Read an mmd register of the PHY */
+static int rtmdio_931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
+{
+ int err = 0;
+ u32 v;
+ /* Select PHY register type
+ * If select 1G/10G MMD register type, registers EXT_PAGE, MAIN_PAGE and REG settings are don’t care.
+ * 0x0 Normal register (Clause 22)
+ * 0x1: 1G MMD register (MMD via Clause 22 registers 13 and 14)
+ * 0x2: 10G MMD register (MMD via Clause 45)
+ */
+ int type = 2;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access via port-number */
+ sw_w32(port << 5, RTMDIO_931X_SMI_INDRT_ACCESS_BC_CTRL);
+
+ /* Set MMD device number and register to write to */
+ sw_w32(devnum << 16 | regnum, RTMDIO_931X_SMI_INDRT_ACCESS_MMD_CTRL);
+
+ v = type << 2 | BIT(0); /* MMD-access-type | EXEC */
+ sw_w32(v, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0);
+
+ do {
+ v = sw_r32(RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0);
+ } while (v & BIT(0));
+
+ /* Check for error condition */
+ if (v & BIT(1))
+ err = -EIO;
+
+ *val = sw_r32(RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_3) >> 16;
+
+ pr_debug("%s: port %d, dev: %x, regnum: %x, val: %x (err %d)\n", __func__,
+ port, devnum, regnum, *val, err);
+
+ mutex_unlock(&rtmdio_lock);
+
+ return err;
+}
+
+/* Write to an mmd register of the PHY */
+static int rtmdio_931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
+{
+ int err = 0;
+ u32 v;
+ int type = 2;
+ u64 pm;
+
+ mutex_lock(&rtmdio_lock);
+
+ /* Set PHY to access via port-mask */
+ pm = (u64)1 << port;
+ sw_w32((u32)pm, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_2);
+ sw_w32((u32)(pm >> 32), RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_2 + 4);
+
+ /* Set data to write */
+ sw_w32_mask(0xffff, val, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_3);
+
+ /* Set MMD device number and register to write to */
+ sw_w32(devnum << 16 | regnum, RTMDIO_931X_SMI_INDRT_ACCESS_MMD_CTRL);
+
+ v = BIT(4) | type << 2 | BIT(0); /* WRITE | MMD-access-type | EXEC */
+ sw_w32(v, RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0);
+
+ do {
+ v = sw_r32(RTMDIO_931X_SMI_INDRT_ACCESS_CTRL_0);
+ } while (v & BIT(0));
+
+ pr_debug("%s: port %d, dev: %x, regnum: %x, val: %x (err %d)\n", __func__,
+ port, devnum, regnum, val, err);
+ 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)
+{
+ struct rtmdio_bus_priv *priv = bus->priv;
+ int err, val;
+
+ if (addr >= priv->cpu_port)
+ return -ENODEV;
+
+ err = (*priv->read_mmd_phy)(addr, devnum, regnum, &val);
+ pr_debug("rd_MMD(adr=%d, dev=%d, reg=%d) = %d, err = %d\n",
+ addr, devnum, regnum, val, err);
+ 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->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->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;
+ int err, val;
+
+ if (addr >= priv->cpu_port)
+ return -ENODEV;
+
+ if (regnum == RTMDIO_PAGE_SELECT && priv->page[addr] != priv->rawpage)
+ return priv->page[addr];
+
+ priv->raw[addr] = (priv->page[addr] == priv->rawpage);
+ 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",
+ addr, priv->page[addr], regnum, val, err);
+ return err ? err : val;
+}
+
+static int rtmdio_93xx_read(struct mii_bus *bus, int addr, int regnum)
+{
+ struct rtmdio_bus_priv *priv = bus->priv;
+ int err, val;
+
+ if (addr >= priv->cpu_port)
+ return -ENODEV;
+
+ if (regnum == RTMDIO_PAGE_SELECT && priv->page[addr] != priv->rawpage)
+ return priv->page[addr];
+
+ priv->raw[addr] = (priv->page[addr] == priv->rawpage);
+ if (priv->phy_is_internal[addr]) {
+ return rtmdio_931x_read_sds_phy(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",
+ addr, priv->page[addr], regnum, val, err);
+ return err ? err : val;
+}
+
+static int rtmdio_write_c45(struct mii_bus *bus, int addr, int devnum, int regnum, u16 val)
+{
+ struct rtmdio_bus_priv *priv = bus->priv;
+ int err;
+
+ if (addr >= priv->cpu_port)
+ return -ENODEV;
+
+ err = (*priv->write_mmd_phy)(addr, devnum, regnum, val);
+ pr_debug("wr_MMD(adr=%d, dev=%d, reg=%d, val=%d) err = %d\n",
+ addr, devnum, regnum, val, err);
+ return err;
+}
+
+static int rtmdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
+{
+ struct rtmdio_bus_priv *priv = bus->priv;
+ int err, page;
+
+ if (addr >= priv->cpu_port)
+ return -ENODEV;
+
+ page = priv->page[addr];
+
+ if (regnum == RTMDIO_PAGE_SELECT)
+ priv->page[addr] = val;
+
+ 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)
+ 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",
+ addr, page, regnum, val, err);
+ return err;
+ }
+
+ priv->raw[addr] = false;
+ return 0;
+}
+
+static int rtmdio_93xx_write(struct mii_bus *bus, int addr, int regnum, u16 val)
+{
+ struct rtmdio_bus_priv *priv = bus->priv;
+ int err, page;
+
+ if (addr >= priv->cpu_port)
+ return -ENODEV;
+
+ page = priv->page[addr];
+
+ if (regnum == RTMDIO_PAGE_SELECT)
+ priv->page[addr] = val;
+
+ if (!priv->raw[addr] && (regnum != RTMDIO_PAGE_SELECT || page == priv->rawpage)) {
+ priv->raw[addr] = (page == priv->rawpage);
+ if (priv->phy_is_internal[addr]) {
+ return rtmdio_931x_write_sds_phy(priv->sds_id[addr],
+ page, 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",
+ addr, page, regnum, val, err);
+ }
+
+ priv->raw[addr] = false;
+ return 0;
+}
+
+static int rtmdio_838x_reset(struct mii_bus *bus)
+{
+ pr_debug("%s called\n", __func__);
+ /* Disable MAC polling the PHY so that we can start configuration */
+ sw_w32(0x00000000, RTMDIO_838X_SMI_POLL_CTRL);
+
+ /* Enable PHY control via SoC */
+ sw_w32_mask(0, 1 << 15, RTMDIO_838X_SMI_GLB_CTRL);
+
+ /* Probably should reset all PHYs here... */
+ return 0;
+}
+
+static int rtmdio_839x_reset(struct mii_bus *bus)
+{
+ return 0;
+
+ pr_debug("%s called\n", __func__);
+ /* BUG: The following does not work, but should! */
+ /* Disable MAC polling the PHY so that we can start configuration */
+ sw_w32(0x00000000, RTMDIO_839X_SMI_PORT_POLLING_CTRL);
+ sw_w32(0x00000000, RTMDIO_839X_SMI_PORT_POLLING_CTRL + 4);
+ /* Disable PHY polling via SoC */
+ sw_w32_mask(1 << 7, 0, RTMDIO_839X_SMI_GLB_CTRL);
+
+ /* Probably should reset all PHYs here... */
+ return 0;
+}
+
+u8 mac_type_bit[RTMDIO_930X_CPU_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;
+
+ /* Mapping of port to phy-addresses on an SMI bus */
+ for (int i = 0; i < RTMDIO_930X_CPU_PORT; i++) {
+ int pos;
+
+ if (priv->smi_bus[i] < 0)
+ continue;
+
+ pos = (i % 6) * 5;
+ sw_w32_mask(0x1f << pos, priv->smi_addr[i] << pos,
+ RTMDIO_930X_SMI_PORT0_5_ADDR + (i / 6) * 4);
+
+ pos = (i * 2) % 32;
+ poll_sel[i / 16] |= priv->smi_bus[i] << pos;
+ poll_ctrl |= BIT(20 + priv->smi_bus[i]);
+ }
+
+ /* 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);
+
+ /* Configure which SMI busses are polled in c45 based on a c45 PHY being on that bus */
+ for (int i = 0; i < RTMDIO_MAX_SMI_BUS; i++)
+ if (priv->smi_bus_isc45[i])
+ c45_mask |= BIT(i + 16);
+
+ pr_info("c45_mask: %08x\n", c45_mask);
+ sw_w32_mask(GENMASK(19, 16), c45_mask, RTMDIO_930X_SMI_GLB_CTRL);
+
+ /* Set the MAC type of each port according to the PHY-interface */
+ /* Values are FE: 2, GE: 3, XGE/2.5G: 0(SERDES) or 1(otherwise), SXGE: 0 */
+ v = 0;
+ for (int i = 0; i < RTMDIO_930X_CPU_PORT; i++) {
+ switch (priv->interfaces[i]) {
+ case PHY_INTERFACE_MODE_10GBASER:
+ break; /* Serdes: Value = 0 */
+ case PHY_INTERFACE_MODE_HSGMII:
+ private_poll_mask |= BIT(i);
+ fallthrough;
+ case PHY_INTERFACE_MODE_USXGMII:
+ v |= BIT(mac_type_bit[i]);
+ uses_usxgmii = true;
+ break;
+ case PHY_INTERFACE_MODE_QSGMII:
+ private_poll_mask |= BIT(i);
+ v |= 3 << mac_type_bit[i];
+ break;
+ default:
+ break;
+ }
+ }
+ 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);
+ }
+
+ pr_debug("%s: RTMDIO_930X_SMI_GLB_CTRL %08x\n", __func__,
+ sw_r32(RTMDIO_930X_SMI_GLB_CTRL));
+ pr_debug("%s: RTMDIO_930X_SMI_PORT0_15_POLLING_SEL %08x\n", __func__,
+ sw_r32(RTMDIO_930X_SMI_PORT0_15_POLLING_SEL));
+ pr_debug("%s: RTMDIO_930X_SMI_PORT16_27_POLLING_SEL %08x\n", __func__,
+ sw_r32(RTMDIO_930X_SMI_PORT16_27_POLLING_SEL));
+ pr_debug("%s: RTMDIO_930X_SMI_MAC_TYPE_CTRL %08x\n", __func__,
+ sw_r32(RTMDIO_930X_SMI_MAC_TYPE_CTRL));
+ pr_debug("%s: RTMDIO_930X_SMI_10G_POLLING_REG0_CFG %08x\n", __func__,
+ sw_r32(RTMDIO_930X_SMI_10G_POLLING_REG0_CFG));
+ pr_debug("%s: RTMDIO_930X_SMI_10G_POLLING_REG9_CFG %08x\n", __func__,
+ sw_r32(RTMDIO_930X_SMI_10G_POLLING_REG9_CFG));
+ pr_debug("%s: RTMDIO_930X_SMI_10G_POLLING_REG10_CFG %08x\n", __func__,
+ sw_r32(RTMDIO_930X_SMI_10G_POLLING_REG10_CFG));
+ pr_debug("%s: RTMDIO_930X_SMI_PRVTE_POLLING_CTRL %08x\n", __func__,
+ sw_r32(RTMDIO_930X_SMI_PRVTE_POLLING_CTRL));
+
+ return 0;
+}
+
+static int rtmdio_931x_reset(struct mii_bus *bus)
+{
+ struct rtmdio_bus_priv *priv = bus->priv;
+ u32 poll_sel[4] = { 0 };
+ u32 poll_ctrl = 0;
+ u32 c45_mask = 0;
+
+ pr_info("%s called\n", __func__);
+ /* Disable port polling for configuration purposes */
+ sw_w32(0, RTMDIO_931X_SMI_PORT_POLLING_CTRL);
+ sw_w32(0, RTMDIO_931X_SMI_PORT_POLLING_CTRL + 4);
+ msleep(100);
+
+ /* Mapping of port to phy-addresses on an SMI bus */
+ for (int i = 0; i < RTMDIO_931X_CPU_PORT; i++) {
+ u32 pos;
+
+ if (priv->smi_bus[i] < 0)
+ continue;
+
+ pos = (i % 6) * 5;
+ sw_w32_mask(0x1f << pos, priv->smi_addr[i] << pos, RTMDIO_931X_SMI_PORT_ADDR + (i / 6) * 4);
+ pos = (i * 2) % 32;
+ poll_sel[i / 16] |= priv->smi_bus[i] << pos;
+ poll_ctrl |= BIT(20 + priv->smi_bus[i]);
+ }
+
+ /* Configure which SMI bus is behind which port number */
+ for (int i = 0; i < RTMDIO_MAX_SMI_BUS; i++) {
+ pr_info("poll sel %d, %08x\n", i, poll_sel[i]);
+ sw_w32(poll_sel[i], RTMDIO_931X_SMI_PORT_POLLING_SEL + (i * 4));
+ }
+
+ /* Configure which SMI busses */
+ pr_info("c45_mask: %08x, RTMDIO_931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTMDIO_931X_SMI_GLB_CTRL0));
+ for (int i = 0; i < RTMDIO_MAX_SMI_BUS; i++) {
+ /* bus is polled in c45 */
+ if (priv->smi_bus_isc45[i])
+ c45_mask |= 0x2 << (i * 2); /* Std. C45, non-standard is 0x3 */
+ }
+
+ pr_info("c45_mask: %08x, RTL931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTMDIO_931X_SMI_GLB_CTRL0));
+
+ /* We have a 10G PHY enable polling
+ * sw_w32(0x01010000, RTL931X_SMI_10GPHY_POLLING_SEL2);
+ * sw_w32(0x01E7C400, RTL931X_SMI_10GPHY_POLLING_SEL3);
+ * sw_w32(0x01E7E820, RTL931X_SMI_10GPHY_POLLING_SEL4);
+ */
+ sw_w32_mask(GENMASK(7, 0), c45_mask, RTMDIO_931X_SMI_GLB_CTRL1);
+
+ return 0;
+}
+
+/*
+ * TODO: This is a tiny leftover from the central SoC include. For now try to detect the
+ * Realtek SoC automatically. This needs to be changed to a proper DTS compatible in a
+ * future driver version.
+ */
+static int rtmdio_get_family(void)
+{
+ unsigned int val;
+
+ val = sw_r32(RTMDIO_93XX_MODEL_NAME_INFO_REG);
+ if ((val & 0xfffc0000) == 0x93000000)
+ return RTMDIO_930X_FAMILY_ID;
+ if ((val & 0xfffc0000) == 0x93100000)
+ return RTMDIO_931X_FAMILY_ID;
+
+ val = sw_r32(RTMDIO_839X_MODEL_NAME_INFO_REG);
+ if ((val & 0xfff80000) == 0x83900000)
+ return RTMDIO_839X_FAMILY_ID;
+
+ return RTMDIO_838X_FAMILY_ID;
+}
+
+static int rtmdio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rtmdio_bus_priv *priv;
+ struct device_node *dn;
+ struct mii_bus *bus;
+ int i, ret, family;
+ u32 pn;
+
+ family = rtmdio_get_family();
+ dev_info(dev, "probing RTL%04x family mdio bus\n", family);
+
+ bus = devm_mdiobus_alloc_size(dev, sizeof(*priv));
+ if (!bus)
+ return -ENOMEM;
+
+ priv = bus->priv;
+ for (i=0; i < RTMDIO_MAX_PORT; i++) {
+ priv->page[i] = 0;
+ priv->raw[i] = false;
+ }
+
+ switch(family) {
+ case RTMDIO_838X_FAMILY_ID:
+ bus->name = "rtl838x-eth-mdio";
+ bus->read = rtmdio_read;
+ bus->write = rtmdio_write;
+ bus->reset = rtmdio_838x_reset;
+ priv->read_sds_phy = rtmdio_838x_read_sds_phy;
+ priv->write_sds_phy = rtmdio_838x_write_sds_phy;
+ priv->read_mmd_phy = rtmdio_838x_read_mmd_phy;
+ priv->write_mmd_phy = rtmdio_838x_write_mmd_phy;
+ priv->read_phy = rtmdio_838x_read_phy;
+ priv->write_phy = rtmdio_838x_write_phy;
+ priv->cpu_port = RTMDIO_838X_CPU_PORT;
+ priv->rawpage = 0xfff;
+ break;
+ case RTMDIO_839X_FAMILY_ID:
+ bus->name = "rtl839x-eth-mdio";
+ bus->read = rtmdio_read;
+ bus->write = rtmdio_write;
+ bus->reset = rtmdio_839x_reset;
+ priv->read_sds_phy = rtmdio_839x_read_sds_phy;
+ priv->write_sds_phy = rtmdio_839x_write_sds_phy;
+ priv->read_mmd_phy = rtmdio_839x_read_mmd_phy;
+ priv->write_mmd_phy = rtmdio_839x_write_mmd_phy;
+ priv->read_phy = rtmdio_839x_read_phy;
+ priv->write_phy = rtmdio_839x_write_phy;
+ priv->cpu_port = RTMDIO_839X_CPU_PORT;
+ priv->rawpage = 0x1fff;
+ break;
+ case RTMDIO_930X_FAMILY_ID:
+ bus->name = "rtl930x-eth-mdio";
+ bus->read = rtmdio_read;
+ bus->write = rtmdio_write;
+ bus->reset = rtmdio_930x_reset;
+ priv->read_sds_phy = rtmdio_930x_read_sds_phy;
+ priv->write_sds_phy = rtmdio_930x_write_sds_phy;
+ priv->read_mmd_phy = rtmdio_930x_read_mmd_phy;
+ priv->write_mmd_phy = rtmdio_930x_write_mmd_phy;
+ priv->read_phy = rtmdio_930x_read_phy;
+ priv->write_phy = rtmdio_930x_write_phy;
+ priv->cpu_port = RTMDIO_930X_CPU_PORT;
+ priv->rawpage = 0xfff;
+ break;
+ case RTMDIO_931X_FAMILY_ID:
+ bus->name = "rtl931x-eth-mdio";
+ bus->read = rtmdio_93xx_read;
+ bus->write = rtmdio_93xx_write;
+ bus->reset = rtmdio_931x_reset;
+ priv->read_mmd_phy = rtmdio_931x_read_mmd_phy;
+ priv->write_mmd_phy = rtmdio_931x_write_mmd_phy;
+ priv->read_phy = rtmdio_931x_read_phy;
+ priv->write_phy = rtmdio_931x_write_phy;
+ priv->cpu_port = RTMDIO_931X_CPU_PORT;
+ priv->rawpage = 0x1fff;
+ break;
+ }
+ bus->read_c45 = rtmdio_read_c45;
+ bus->write_c45 = rtmdio_write_c45;
+ bus->parent = dev;
+ bus->phy_mask = ~(BIT_ULL(priv->cpu_port) - 1ULL);
+
+ for_each_node_by_name(dn, "ethernet-phy") {
+ u32 smi_addr[2];
+
+ if (of_property_read_u32(dn, "reg", &pn))
+ continue;
+
+ if (pn >= RTMDIO_MAX_PORT) {
+ pr_err("%s: illegal port number %d\n", __func__, pn);
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(dn, "sds", &priv->sds_id[pn]))
+ priv->sds_id[pn] = -1;
+ else
+ pr_info("set sds port %d to %d\n", pn, priv->sds_id[pn]);
+
+ if (of_property_read_u32_array(dn, "rtl9300,smi-address", &smi_addr[0], 2)) {
+ priv->smi_bus[pn] = 0;
+ priv->smi_addr[pn] = pn;
+ } else {
+ priv->smi_bus[pn] = smi_addr[0];
+ priv->smi_addr[pn] = smi_addr[1];
+ }
+
+ if (priv->smi_bus[pn] >= RTMDIO_MAX_SMI_BUS) {
+ pr_err("%s: illegal SMI bus number %d\n", __func__, priv->smi_bus[pn]);
+ return -ENODEV;
+ }
+
+ priv->phy_is_internal[pn] = of_property_read_bool(dn, "phy-is-integrated");
+
+ if (priv->phy_is_internal[pn] && priv->sds_id[pn] >= 0)
+ priv->smi_bus[pn]= -1;
+ else if (of_device_is_compatible(dn, "ethernet-phy-ieee802.3-c45"))
+ priv->smi_bus_isc45[priv->smi_bus[pn]] = true;
+ }
+
+ dn = of_find_compatible_node(NULL, NULL, "realtek,rtl83xx-switch");
+ if (!dn) {
+ dev_err(dev, "No RTL switch node in DTS\n");
+ return -ENODEV;
+ }
+
+ for_each_node_by_name(dn, "port") {
+ if (of_property_read_u32(dn, "reg", &pn))
+ continue;
+ pr_debug("%s Looking at port %d\n", __func__, pn);
+ if (pn > priv->cpu_port)
+ continue;
+ if (of_get_phy_mode(dn, &priv->interfaces[pn]))
+ priv->interfaces[pn] = PHY_INTERFACE_MODE_NA;
+ pr_debug("%s phy mode of port %d is %s\n",
+ __func__, pn, phy_modes(priv->interfaces[pn]));
+ }
+
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
+ ret = devm_of_mdiobus_register(dev, bus, dev->of_node);
+
+ return ret;
+}
+
+
+static const struct of_device_id rtmdio_ids[] = {
+ { .compatible = "realtek,rtl838x-mdio" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rtmdio_ids);
+
+static struct platform_driver rtmdio_driver = {
+ .probe = rtmdio_probe,
+ .driver = {
+ .name = "mdio-rtl-otto",
+ .of_match_table = rtmdio_ids,
+ },
+};
+
+module_platform_driver(rtmdio_driver);
+
+/*
+ * TODO: The below initialization function is only needed because the mdio bus
+ * is a subnode of the ethernet node. That means detection via platform driver
+ * will not work out of the box. Until this is solved, populate the platform
+ * data manually.
+ */
+static int __init rtmdio_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "realtek,rtl838x-eth");
+ if (!np) {
+ pr_err("realtek,rtl838x-eth compatible device not found\n");
+ return -ENODEV;
+ }
+
+ pr_info("populating rtl838x-mdio device manually\n");
+ of_platform_populate(np, NULL, NULL, NULL);
+ of_node_put(np);
+
+ return 0;
+}
+module_init(rtmdio_init);
+
+MODULE_DESCRIPTION("RTL83xx/RTL93xx MDIO driver");
+MODULE_LICENSE("GPL");