realtek: 6.6: MDIO post fixes
authorMarkus Stockhausen <markus.stockhausen@gmx.de>
Sat, 14 Sep 2024 20:39:12 +0000 (16:39 -0400)
committerRobert Marko <robimarko@gmail.com>
Mon, 16 Sep 2024 08:33:28 +0000 (10:33 +0200)
Merging of the realtek 6.6 series forgot to include some final fixes
for the new MDIO driver. What was changed in last second?

1. The MDIO driver used wrong constants to make use of the raw
page (for direct register access). Provide a rawpage variable in
the bus private structure, populate it during initialization and
make use of it at the proper places

2. We always used the variable portaddr for the bus index. Usually
our driver uses either addr or port for the same meaning. Remove the
duplication and reuse the normal addr variable.

3. Drop functions rtmdio_write_page() and rtmdio_read_page(). These
only call the PHY driver read/write page functions. We know that
these will only access page 0x1f. As we have only Realtek PHYs
and our driver only reacts to this special page, just hardcode it.
Benefit is that we can use these functions for PHY detection when
read/write page functions are not yet assigned.

4. Add two new helper functions phy_port_read_paged() and
phy_port_write_paged(). These allow to access arbitrary ports on
the MDIO bus when the packages are not initialized. These will be
needed for proper RTL8218B and RTL8214FC detection in forthcoming
patches.

5. The port tracking wrongly used index 0 to mark "normal" access.
This does not allow to make a "special" access to port 0. Use
index -1 to mark "normal" access.

Provide the fix for 5.15 and 6.6 to allow for easy version
comparison.

Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/16391
Signed-off-by: Robert Marko <robimarko@gmail.com>
target/linux/realtek/files-5.15/drivers/net/ethernet/rtl838x_eth.c
target/linux/realtek/files-5.15/drivers/net/ethernet/rtl838x_eth.h
target/linux/realtek/files-5.15/drivers/net/phy/rtl83xx-phy.c
target/linux/realtek/files-6.6/drivers/net/ethernet/rtl838x_eth.c
target/linux/realtek/files-6.6/drivers/net/ethernet/rtl838x_eth.h
target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c

index e6c06c4452221b847aa889acb08c4fd1519f9a25..7ad9b5f0291d9c1fb12b152c3f9a192ffa4db0e3 100644 (file)
@@ -1622,7 +1622,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
 }
 
 /*
- * On all RealTek switch platforms the hardware periodically reads the link status of all
+ * 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, ...
@@ -1639,7 +1639,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  * 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
+ * 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.
  *
@@ -1648,9 +1648,9 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  * 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 PHYs consist of 8 ports that all can be programmed
- * individually. Writing to port 0 can configure the whole why while other operations
- * need to be replicated per port.
+ * 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
@@ -1661,7 +1661,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  * 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, RTL821X_PAGE_SELECT, 12)  : store internal page 12 in driver
+ * 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
@@ -1670,8 +1670,8 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  *
  * The port selection works as follows and must be called under a held mdio bus lock
  *
- * __mdiobus_write(bus, RTL821X_PORT_SELECT, 4)        : switch to port paddr
- * __phy_write(phydev, RTL821X_PAGE_SELECT, 11)        : store internal page 11 in driver
+ * __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
@@ -1689,75 +1689,57 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  *   return __phy_write(phydev, RTL821X_PAGE_SELECT, page);
  * }
  *
- * In case there are non Realtek PHYs attached to the logic might need to be
+ * 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 RTL821X_PAGE_SELECT    0x1f
-#define RTL821X_PORT_SELECT    0x2000
-#define RTL838X_PAGE_RAW       0xfff
-#define RTL839X_PAGE_RAW       0x1fff
-#define RTL930X_PAGE_RAW       0xfff
-#define RTL931X_PAGE_RAW       0x1fff
-#define RTMDIO_READ            0x0
-#define RTMDIO_WRITE           0x1
+#define RTMDIO_PAGE_SELECT     0x1f
+#define RTMDIO_PORT_SELECT     0x2000
+#define RTMDIO_READ            0x1
+#define RTMDIO_WRITE           0x2
+#define RTMDIO_ABS             0x4
+#define RTMDIO_PKG             0x8
 
 /*
- * Provide a generic read/write function so we can access multiple ports on a shared PHY
- * package of the bus with separate addresses individually. This basically resembles the
+ * 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
- * workin on a not default port (8, 16, 24, ...) we send a RTL821X_PORT_SELECT command
- * at the beginning and the end to switch the port handling logic.
+ * 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_read_page(struct phy_device *phydev)
-{
-       if (WARN_ONCE(!phydev->drv->read_page,
-                     "read_page callback not available, PHY driver not loaded?\n"))
-               return -EOPNOTSUPP;
-
-       return phydev->drv->read_page(phydev);
-}
-
-static int rtmdio_write_page(struct phy_device *phydev, int page)
-{
-       if (WARN_ONCE(!phydev->drv->write_page,
-                     "write_page callback not available, PHY driver not loaded?\n"))
-               return -EOPNOTSUPP;
-
-       return phydev->drv->write_page(phydev, page);
-}
-
-static int rtmdio_package_rw(struct phy_device *phydev, int op, int port,
-                            int page, u32 regnum, u16 val)
+static int rtmdio_access(struct phy_device *phydev, int op, int port,
+                        int page, u32 regnum, u16 val)
 {
        int r, ret = 0, oldpage;
-       struct phy_package_shared *shared = phydev->shared;
 
-       if (!shared)
-               return -EIO;
+       if (op & RTMDIO_PKG) {
+               if (!phydev->shared)
+                       return -EIO;
+               port = phydev->shared->addr + port;
+       }
 
        /* lock and inform bus about non default addressing */
        phy_lock_mdio_bus(phydev);
        __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
-                       RTL821X_PORT_SELECT, shared->addr + port);
+                       RTMDIO_PORT_SELECT, port);
 
-       oldpage = ret = rtmdio_read_page(phydev);
+       oldpage = ret = __phy_read(phydev, RTMDIO_PAGE_SELECT);
        if (oldpage >= 0 && oldpage != page) {
-               ret = rtmdio_write_page(phydev, page);
+               ret = __phy_write(phydev, RTMDIO_PAGE_SELECT, page);
                if (ret < 0)
                        oldpage = ret;
        }
 
        if (oldpage >= 0) {
-               if (op == RTMDIO_WRITE)
+               if (op & RTMDIO_WRITE)
                        ret = __phy_write(phydev, regnum, val);
                else
                        ret = __phy_read(phydev, regnum);
        }
 
        if (oldpage >= 0) {
-               r = rtmdio_write_page(phydev, oldpage);
+               r = __phy_write(phydev, RTMDIO_PAGE_SELECT, oldpage);
                if (ret >= 0 && r < 0)
                        ret = r;
        } else
@@ -1765,7 +1747,7 @@ static int rtmdio_package_rw(struct phy_device *phydev, int op, int port,
 
        /* reset bus to default adressing and unlock it */
        __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
-                       RTL821X_PORT_SELECT, 0);
+                       RTMDIO_PORT_SELECT, -1);
        phy_unlock_mdio_bus(phydev);
 
        return ret;
@@ -1775,40 +1757,53 @@ static int rtmdio_package_rw(struct phy_device *phydev, int op, int port,
  * 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
- * individually.
+ * 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_package_rw(phydev, RTMDIO_WRITE, port, page, regnum, 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_package_rw(phydev, RTMDIO_WRITE, 0, page, regnum, 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)
 {
-       return rtmdio_package_rw(phydev, RTMDIO_READ, port, page, regnum, 0);
+       return rtmdio_access(phydev, RTMDIO_READ | RTMDIO_PKG, port, page, regnum, 0);
 }
 
 int phy_package_read_paged(struct phy_device *phydev, int page, u32 regnum)
 {
-       return rtmdio_package_rw(phydev, RTMDIO_READ, 0, page, regnum, 0);
+       return rtmdio_access(phydev, RTMDIO_READ | RTMDIO_PKG, 0, page, regnum, 0);
 }
 
-/* These are the core functions of our fancy Realtek SoC MDIO bus. */
+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);
+}
+
+/* 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)
 {
        int err, val;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
 
-       err = (*bus_priv->read_mmd_phy)(portaddr, devnum, regnum, &val);
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+
+       err = (*bus_priv->read_mmd_phy)(addr, devnum, regnum, &val);
        pr_debug("rd_MMD(adr=%d, dev=%d, reg=%d) = %d, err = %d\n",
-                portaddr, devnum, regnum, val, err);
+                addr, devnum, regnum, val, err);
        return err ? err : val;
 }
 
@@ -1817,21 +1812,23 @@ static int rtmdio_83xx_read(struct mii_bus *bus, int addr, int regnum)
        int err, val;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
        struct rtl838x_eth_priv *eth_priv = bus_priv->eth_priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
 
-       if (portaddr >= 24 && portaddr <= 27 && eth_priv->id == 0x8380)
-               return rtl838x_read_sds_phy(portaddr, regnum);
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
 
-       if (eth_priv->family_id == RTL8390_FAMILY_ID && eth_priv->phy_is_internal[portaddr])
-               return rtl839x_read_sds_phy(portaddr, regnum);
+       if (addr >= 24 && addr <= 27 && eth_priv->id == 0x8380)
+               return rtl838x_read_sds_phy(addr, regnum);
 
-       if (regnum == RTL821X_PAGE_SELECT && bus_priv->page[portaddr] != RTL838X_PAGE_RAW)
-               return bus_priv->page[portaddr];
+       if (eth_priv->family_id == RTL8390_FAMILY_ID && eth_priv->phy_is_internal[addr])
+               return rtl839x_read_sds_phy(addr, regnum);
 
-       bus_priv->raw[portaddr] = (bus_priv->page[portaddr] == RTL838X_PAGE_RAW);
-       err = (*bus_priv->read_phy)(portaddr, bus_priv->page[portaddr], regnum, &val);
+       if (regnum == RTMDIO_PAGE_SELECT && bus_priv->page[addr] != bus_priv->rawpage)
+               return bus_priv->page[addr];
+
+       bus_priv->raw[addr] = (bus_priv->page[addr] == bus_priv->rawpage);
+       err = (*bus_priv->read_phy)(addr, bus_priv->page[addr], regnum, &val);
        pr_debug("rd_PHY(adr=%d, pag=%d, reg=%d) = %d, err = %d\n",
-                portaddr, bus_priv->page[portaddr], regnum, val, err);
+                addr, bus_priv->page[addr], regnum, val, err);
        return err ? err : val;
 }
 
@@ -1840,24 +1837,26 @@ static int rtmdio_93xx_read(struct mii_bus *bus, int addr, int regnum)
        int err, val;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
        struct rtl838x_eth_priv *eth_priv = bus_priv->eth_priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
 
-       if (regnum == RTL821X_PAGE_SELECT && bus_priv->page[portaddr] != RTL930X_PAGE_RAW)
-               return bus_priv->page[portaddr];
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+
+       if (regnum == RTMDIO_PAGE_SELECT && bus_priv->page[addr] != bus_priv->rawpage)
+               return bus_priv->page[addr];
 
-       bus_priv->raw[portaddr] = (bus_priv->page[portaddr] == RTL930X_PAGE_RAW);
-       if (eth_priv->phy_is_internal[portaddr]) {
+       bus_priv->raw[addr] = (bus_priv->page[addr] == bus_priv->rawpage);
+       if (eth_priv->phy_is_internal[addr]) {
                if (eth_priv->family_id == RTL9300_FAMILY_ID)
-                       return rtl930x_read_sds_phy(eth_priv->sds_id[portaddr],
-                                                   bus_priv->page[portaddr], regnum);
+                       return rtl930x_read_sds_phy(eth_priv->sds_id[addr],
+                                                   bus_priv->page[addr], regnum);
                else
-                       return rtl931x_read_sds_phy(eth_priv->sds_id[portaddr],
-                                                   bus_priv->page[portaddr], regnum);
+                       return rtl931x_read_sds_phy(eth_priv->sds_id[addr],
+                                                   bus_priv->page[addr], regnum);
        }
 
-       err = (*bus_priv->read_phy)(portaddr, bus_priv->page[portaddr], regnum, &val);
+       err = (*bus_priv->read_phy)(addr, bus_priv->page[addr], regnum, &val);
        pr_debug("rd_PHY(adr=%d, pag=%d, reg=%d) = %d, err = %d\n",
-                portaddr, bus_priv->page[portaddr], regnum, val, err);
+                addr, bus_priv->page[addr], regnum, val, err);
        return err ? err : val;
 }
 
@@ -1865,83 +1864,91 @@ static int rtmdio_write_c45(struct mii_bus *bus, int addr, int devnum, int regnu
 {
        int err;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
 
-       err = (*bus_priv->write_mmd_phy)(portaddr, devnum, regnum, val);
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+
+       err = (*bus_priv->write_mmd_phy)(addr, devnum, regnum, val);
        pr_debug("wr_MMD(adr=%d, dev=%d, reg=%d, val=%d) err = %d\n",
-                portaddr, devnum, regnum, val, err);
+                addr, devnum, regnum, val, err);
        return err;
 }
 
 static int rtmdio_83xx_write(struct mii_bus *bus, int addr, int regnum, u16 val)
 {
+       int err, page, offset = 0;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
        struct rtl838x_eth_priv *eth_priv = bus_priv->eth_priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
-       int err, page = bus_priv->page[portaddr], offset = 0;
 
-       if (regnum == RTL821X_PORT_SELECT) {
-               bus_priv->portaddr = val;
+       if (regnum == RTMDIO_PORT_SELECT) {
+               bus_priv->extaddr = (s16)val;
                return 0;
        }
 
-       if (portaddr >= 24 && portaddr <= 27 && eth_priv->id == 0x8380) {
-               if (portaddr == 26)
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+       page = bus_priv->page[addr];
+
+       if (addr >= 24 && addr <= 27 && eth_priv->id == 0x8380) {
+               if (addr == 26)
                        offset = 0x100;
                sw_w32(val, RTL838X_SDS4_FIB_REG0 + offset + (regnum << 2));
                return 0;
        }
 
-       if (eth_priv->family_id == RTL8390_FAMILY_ID && eth_priv->phy_is_internal[portaddr])
-               return rtl839x_write_sds_phy(portaddr, regnum, val);
+       if (eth_priv->family_id == RTL8390_FAMILY_ID && eth_priv->phy_is_internal[addr])
+               return rtl839x_write_sds_phy(addr, regnum, val);
 
-       if (regnum == RTL821X_PAGE_SELECT)
-               bus_priv->page[portaddr] = val;
+       if (regnum == RTMDIO_PAGE_SELECT)
+               bus_priv->page[addr] = val;
 
-       if (!bus_priv->raw[portaddr] && (regnum != RTL821X_PAGE_SELECT || page == RTL838X_PAGE_RAW)) {
-               bus_priv->raw[portaddr] = (page == RTL838X_PAGE_RAW);
-               err = (*bus_priv->write_phy)(portaddr, page, regnum, val);
+       if (!bus_priv->raw[addr] && (regnum != RTMDIO_PAGE_SELECT || page == bus_priv->rawpage)) {
+               bus_priv->raw[addr] = (page == bus_priv->rawpage);
+               err = (*bus_priv->write_phy)(addr, page, regnum, val);
                pr_debug("wr_PHY(adr=%d, pag=%d, reg=%d, val=%d) err = %d\n",
-                        portaddr, page, regnum, val, err);
+                        addr, page, regnum, val, err);
                return err;
        }
 
-       bus_priv->raw[portaddr] = false;
+       bus_priv->raw[addr] = false;
        return 0;
 }
 
 static int rtmdio_93xx_write(struct mii_bus *bus, int addr, int regnum, u16 val)
 {
+       int err, page;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
        struct rtl838x_eth_priv *eth_priv = bus_priv->eth_priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
-       int err, page = bus_priv->page[portaddr];
 
-       if (regnum == RTL821X_PORT_SELECT) {
-               bus_priv->portaddr = val;
+       if (regnum == RTMDIO_PORT_SELECT) {
+               bus_priv->extaddr = (s16)val;
                return 0;
        }
 
-       if (regnum == RTL821X_PAGE_SELECT)
-               bus_priv->page[portaddr] = val;
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+       page = bus_priv->page[addr];
+
+       if (regnum == RTMDIO_PAGE_SELECT)
+               bus_priv->page[addr] = val;
 
-       if (!bus_priv->raw[portaddr] && (regnum != RTL821X_PAGE_SELECT || page == RTL930X_PAGE_RAW)) {
-               bus_priv->raw[portaddr] = (page == RTL930X_PAGE_RAW);
-               if (eth_priv->phy_is_internal[portaddr]) {
+       if (!bus_priv->raw[addr] && (regnum != RTMDIO_PAGE_SELECT || page == bus_priv->rawpage)) {
+               bus_priv->raw[addr] = (page == bus_priv->rawpage);
+               if (eth_priv->phy_is_internal[addr]) {
                        if (eth_priv->family_id == RTL9300_FAMILY_ID)
-                               return rtl930x_write_sds_phy(eth_priv->sds_id[portaddr],
+                               return rtl930x_write_sds_phy(eth_priv->sds_id[addr],
                                                             page, regnum, val);
                        else
-                               return rtl931x_write_sds_phy(eth_priv->sds_id[portaddr],
+                               return rtl931x_write_sds_phy(eth_priv->sds_id[addr],
                                                             page, regnum, val);
                }
 
-               err = (*bus_priv->write_phy)(portaddr, page, regnum, val);
+               err = (*bus_priv->write_phy)(addr, page, regnum, val);
                pr_debug("wr_PHY(adr=%d, pag=%d, reg=%d, val=%d) err = %d\n",
-                        portaddr, page, regnum, val, err);
+                        addr, page, regnum, val, err);
        }
 
-       bus_priv->raw[portaddr] = false;
+       bus_priv->raw[addr] = false;
        return 0;
 }
 
@@ -2244,11 +2251,11 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
 
        bus_priv = priv->mii_bus->priv;
        bus_priv->eth_priv = priv;
-       for (i = 0; i < 64; i++) {
+       for (i=0; i < 64; i++) {
                bus_priv->page[i] = 0;
                bus_priv->raw[i] = false;
        }
-       bus_priv->portaddr = 0;
+       bus_priv->extaddr = -1;
 
        switch(priv->family_id) {
        case RTL8380_FAMILY_ID:
@@ -2260,6 +2267,7 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
                bus_priv->write_mmd_phy = rtl838x_write_mmd_phy;
                bus_priv->read_phy = rtl838x_read_phy;
                bus_priv->write_phy = rtl838x_write_phy;
+               bus_priv->rawpage = 0xfff;
                break;
        case RTL8390_FAMILY_ID:
                priv->mii_bus->name = "rtl839x-eth-mdio";
@@ -2270,6 +2278,7 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
                bus_priv->write_mmd_phy = rtl839x_write_mmd_phy;
                bus_priv->read_phy = rtl839x_read_phy;
                bus_priv->write_phy = rtl839x_write_phy;
+               bus_priv->rawpage = 0x1fff;
                break;
        case RTL9300_FAMILY_ID:
                priv->mii_bus->name = "rtl930x-eth-mdio";
@@ -2280,6 +2289,7 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
                bus_priv->write_mmd_phy = rtl930x_write_mmd_phy;
                bus_priv->read_phy = rtl930x_read_phy;
                bus_priv->write_phy = rtl930x_write_phy;
+               bus_priv->rawpage = 0xfff;
                priv->mii_bus->probe_capabilities = MDIOBUS_C22_C45;
                break;
        case RTL9310_FAMILY_ID:
@@ -2291,6 +2301,7 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
                bus_priv->write_mmd_phy = rtl931x_write_mmd_phy;
                bus_priv->read_phy = rtl931x_read_phy;
                bus_priv->write_phy = rtl931x_write_phy;
+               bus_priv->rawpage = 0x1fff;
                priv->mii_bus->probe_capabilities = MDIOBUS_C22_C45;
                break;
        }
index 0f49eae23da1e5680693a6d151245089c9fdc901..d6d88fc2ed01b8d7aa9c359c33a9f1707e1c4a4a 100644 (file)
@@ -410,7 +410,8 @@ struct dsa_tag;
 
 struct rtl838x_bus_priv {
        struct rtl838x_eth_priv *eth_priv;
-       int portaddr;
+       int extaddr;
+       int rawpage;
        int page[64];
        bool raw[64];
        int (*read_mmd_phy)(u32 port, u32 addr, u32 reg, u32 *val);
index 0c8b1dfd4dcd276822ab88a2ff463801fd7307b2..df5e2e444067abce1c4fc7aacd9676732fbc3df6 100644 (file)
@@ -22,8 +22,10 @@ extern struct rtl83xx_soc_info soc_info;
 extern struct mutex smi_lock;
 extern int phy_package_port_write_paged(struct phy_device *phydev, int port, int page, u32 regnum, u16 val);
 extern int phy_package_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val);
+extern int phy_port_write_paged(struct phy_device *phydev, int port, int page, u32 regnum, u16 val);
 extern int phy_package_port_read_paged(struct phy_device *phydev, int port, int page, u32 regnum);
 extern int phy_package_read_paged(struct phy_device *phydev, int page, u32 regnum);
+extern int phy_port_read_paged(struct phy_device *phydev, int port, int page, u32 regnum);
 
 #define PHY_PAGE_2     2
 #define PHY_PAGE_4     4
index 4439059345102d4b09c836aa0e73225e528b5377..07664f9f382f3a7a5db748cc6b1a71782e56e0a6 100644 (file)
@@ -1629,7 +1629,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
 }
 
 /*
- * On all RealTek switch platforms the hardware periodically reads the link status of all
+ * 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, ...
@@ -1646,7 +1646,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  * 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
+ * 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.
  *
@@ -1655,9 +1655,9 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  * 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 PHYs consist of 8 ports that all can be programmed
- * individually. Writing to port 0 can configure the whole why while other operations
- * need to be replicated per port.
+ * 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
@@ -1668,7 +1668,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  * 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, RTL821X_PAGE_SELECT, 12)  : store internal page 12 in driver
+ * 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
@@ -1677,8 +1677,8 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  *
  * The port selection works as follows and must be called under a held mdio bus lock
  *
- * __mdiobus_write(bus, RTL821X_PORT_SELECT, 4)        : switch to port paddr
- * __phy_write(phydev, RTL821X_PAGE_SELECT, 11)        : store internal page 11 in driver
+ * __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
@@ -1696,75 +1696,57 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
  *   return __phy_write(phydev, RTL821X_PAGE_SELECT, page);
  * }
  *
- * In case there are non Realtek PHYs attached to the logic might need to be
+ * 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 RTL821X_PAGE_SELECT    0x1f
-#define RTL821X_PORT_SELECT    0x2000
-#define RTL838X_PAGE_RAW       0xfff
-#define RTL839X_PAGE_RAW       0x1fff
-#define RTL930X_PAGE_RAW       0xfff
-#define RTL931X_PAGE_RAW       0x1fff
-#define RTMDIO_READ            0x0
-#define RTMDIO_WRITE           0x1
+#define RTMDIO_PAGE_SELECT     0x1f
+#define RTMDIO_PORT_SELECT     0x2000
+#define RTMDIO_READ            0x1
+#define RTMDIO_WRITE           0x2
+#define RTMDIO_ABS             0x4
+#define RTMDIO_PKG             0x8
 
 /*
- * Provide a generic read/write function so we can access multiple ports on a shared PHY
- * package of the bus with separate addresses individually. This basically resembles the
+ * 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
- * workin on a not default port (8, 16, 24, ...) we send a RTL821X_PORT_SELECT command
- * at the beginning and the end to switch the port handling logic.
+ * 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_read_page(struct phy_device *phydev)
-{
-       if (WARN_ONCE(!phydev->drv->read_page,
-                     "read_page callback not available, PHY driver not loaded?\n"))
-               return -EOPNOTSUPP;
-
-       return phydev->drv->read_page(phydev);
-}
-
-static int rtmdio_write_page(struct phy_device *phydev, int page)
-{
-       if (WARN_ONCE(!phydev->drv->write_page,
-                     "write_page callback not available, PHY driver not loaded?\n"))
-               return -EOPNOTSUPP;
-
-       return phydev->drv->write_page(phydev, page);
-}
-
-static int rtmdio_package_rw(struct phy_device *phydev, int op, int port,
-                            int page, u32 regnum, u16 val)
+static int rtmdio_access(struct phy_device *phydev, int op, int port,
+                        int page, u32 regnum, u16 val)
 {
        int r, ret = 0, oldpage;
-       struct phy_package_shared *shared = phydev->shared;
 
-       if (!shared)
-               return -EIO;
+       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,
-                       RTL821X_PORT_SELECT, shared->base_addr + port);
+                       RTMDIO_PORT_SELECT, port);
 
-       oldpage = ret = rtmdio_read_page(phydev);
+       oldpage = ret = __phy_read(phydev, RTMDIO_PAGE_SELECT);
        if (oldpage >= 0 && oldpage != page) {
-               ret = rtmdio_write_page(phydev, page);
+               ret = __phy_write(phydev, RTMDIO_PAGE_SELECT, page);
                if (ret < 0)
                        oldpage = ret;
        }
 
        if (oldpage >= 0) {
-               if (op == RTMDIO_WRITE)
+               if (op & RTMDIO_WRITE)
                        ret = __phy_write(phydev, regnum, val);
                else
                        ret = __phy_read(phydev, regnum);
        }
 
        if (oldpage >= 0) {
-               r = rtmdio_write_page(phydev, oldpage);
+               r = __phy_write(phydev, RTMDIO_PAGE_SELECT, oldpage);
                if (ret >= 0 && r < 0)
                        ret = r;
        } else
@@ -1772,7 +1754,7 @@ static int rtmdio_package_rw(struct phy_device *phydev, int op, int port,
 
        /* reset bus to default adressing and unlock it */
        __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
-                       RTL821X_PORT_SELECT, 0);
+                       RTMDIO_PORT_SELECT, -1);
        phy_unlock_mdio_bus(phydev);
 
        return ret;
@@ -1782,40 +1764,53 @@ static int rtmdio_package_rw(struct phy_device *phydev, int op, int port,
  * 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
- * individually.
+ * 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_package_rw(phydev, RTMDIO_WRITE, port, page, regnum, 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_package_rw(phydev, RTMDIO_WRITE, 0, page, regnum, 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)
 {
-       return rtmdio_package_rw(phydev, RTMDIO_READ, port, page, regnum, 0);
+       return rtmdio_access(phydev, RTMDIO_READ | RTMDIO_PKG, port, page, regnum, 0);
 }
 
 int phy_package_read_paged(struct phy_device *phydev, int page, u32 regnum)
 {
-       return rtmdio_package_rw(phydev, RTMDIO_READ, 0, page, regnum, 0);
+       return rtmdio_access(phydev, RTMDIO_READ | RTMDIO_PKG, 0, page, regnum, 0);
 }
 
-/* These are the core functions of our fancy Realtek SoC MDIO bus. */
+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);
+}
+
+/* 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)
 {
        int err, val;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
 
-       err = (*bus_priv->read_mmd_phy)(portaddr, devnum, regnum, &val);
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+
+       err = (*bus_priv->read_mmd_phy)(addr, devnum, regnum, &val);
        pr_debug("rd_MMD(adr=%d, dev=%d, reg=%d) = %d, err = %d\n",
-                portaddr, devnum, regnum, val, err);
+                addr, devnum, regnum, val, err);
        return err ? err : val;
 }
 
@@ -1824,21 +1819,23 @@ static int rtmdio_83xx_read(struct mii_bus *bus, int addr, int regnum)
        int err, val;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
        struct rtl838x_eth_priv *eth_priv = bus_priv->eth_priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
 
-       if (portaddr >= 24 && portaddr <= 27 && eth_priv->id == 0x8380)
-               return rtl838x_read_sds_phy(portaddr, regnum);
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
 
-       if (eth_priv->family_id == RTL8390_FAMILY_ID && eth_priv->phy_is_internal[portaddr])
-               return rtl839x_read_sds_phy(portaddr, regnum);
+       if (addr >= 24 && addr <= 27 && eth_priv->id == 0x8380)
+               return rtl838x_read_sds_phy(addr, regnum);
 
-       if (regnum == RTL821X_PAGE_SELECT && bus_priv->page[portaddr] != RTL838X_PAGE_RAW)
-               return bus_priv->page[portaddr];
+       if (eth_priv->family_id == RTL8390_FAMILY_ID && eth_priv->phy_is_internal[addr])
+               return rtl839x_read_sds_phy(addr, regnum);
 
-       bus_priv->raw[portaddr] = (bus_priv->page[portaddr] == RTL838X_PAGE_RAW);
-       err = (*bus_priv->read_phy)(portaddr, bus_priv->page[portaddr], regnum, &val);
+       if (regnum == RTMDIO_PAGE_SELECT && bus_priv->page[addr] != bus_priv->rawpage)
+               return bus_priv->page[addr];
+
+       bus_priv->raw[addr] = (bus_priv->page[addr] == bus_priv->rawpage);
+       err = (*bus_priv->read_phy)(addr, bus_priv->page[addr], regnum, &val);
        pr_debug("rd_PHY(adr=%d, pag=%d, reg=%d) = %d, err = %d\n",
-                portaddr, bus_priv->page[portaddr], regnum, val, err);
+                addr, bus_priv->page[addr], regnum, val, err);
        return err ? err : val;
 }
 
@@ -1847,24 +1844,26 @@ static int rtmdio_93xx_read(struct mii_bus *bus, int addr, int regnum)
        int err, val;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
        struct rtl838x_eth_priv *eth_priv = bus_priv->eth_priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
 
-       if (regnum == RTL821X_PAGE_SELECT && bus_priv->page[portaddr] != RTL930X_PAGE_RAW)
-               return bus_priv->page[portaddr];
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+
+       if (regnum == RTMDIO_PAGE_SELECT && bus_priv->page[addr] != bus_priv->rawpage)
+               return bus_priv->page[addr];
 
-       bus_priv->raw[portaddr] = (bus_priv->page[portaddr] == RTL930X_PAGE_RAW);
-       if (eth_priv->phy_is_internal[portaddr]) {
+       bus_priv->raw[addr] = (bus_priv->page[addr] == bus_priv->rawpage);
+       if (eth_priv->phy_is_internal[addr]) {
                if (eth_priv->family_id == RTL9300_FAMILY_ID)
-                       return rtl930x_read_sds_phy(eth_priv->sds_id[portaddr],
-                                                   bus_priv->page[portaddr], regnum);
+                       return rtl930x_read_sds_phy(eth_priv->sds_id[addr],
+                                                   bus_priv->page[addr], regnum);
                else
-                       return rtl931x_read_sds_phy(eth_priv->sds_id[portaddr],
-                                                   bus_priv->page[portaddr], regnum);
+                       return rtl931x_read_sds_phy(eth_priv->sds_id[addr],
+                                                   bus_priv->page[addr], regnum);
        }
 
-       err = (*bus_priv->read_phy)(portaddr, bus_priv->page[portaddr], regnum, &val);
+       err = (*bus_priv->read_phy)(addr, bus_priv->page[addr], regnum, &val);
        pr_debug("rd_PHY(adr=%d, pag=%d, reg=%d) = %d, err = %d\n",
-                portaddr, bus_priv->page[portaddr], regnum, val, err);
+                addr, bus_priv->page[addr], regnum, val, err);
        return err ? err : val;
 }
 
@@ -1872,83 +1871,91 @@ static int rtmdio_write_c45(struct mii_bus *bus, int addr, int devnum, int regnu
 {
        int err;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
 
-       err = (*bus_priv->write_mmd_phy)(portaddr, devnum, regnum, val);
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+
+       err = (*bus_priv->write_mmd_phy)(addr, devnum, regnum, val);
        pr_debug("wr_MMD(adr=%d, dev=%d, reg=%d, val=%d) err = %d\n",
-                portaddr, devnum, regnum, val, err);
+                addr, devnum, regnum, val, err);
        return err;
 }
 
 static int rtmdio_83xx_write(struct mii_bus *bus, int addr, int regnum, u16 val)
 {
+       int err, page, offset = 0;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
        struct rtl838x_eth_priv *eth_priv = bus_priv->eth_priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
-       int err, page = bus_priv->page[portaddr], offset = 0;
 
-       if (regnum == RTL821X_PORT_SELECT) {
-               bus_priv->portaddr = val;
+       if (regnum == RTMDIO_PORT_SELECT) {
+               bus_priv->extaddr = (s16)val;
                return 0;
        }
 
-       if (portaddr >= 24 && portaddr <= 27 && eth_priv->id == 0x8380) {
-               if (portaddr == 26)
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+       page = bus_priv->page[addr];
+
+       if (addr >= 24 && addr <= 27 && eth_priv->id == 0x8380) {
+               if (addr == 26)
                        offset = 0x100;
                sw_w32(val, RTL838X_SDS4_FIB_REG0 + offset + (regnum << 2));
                return 0;
        }
 
-       if (eth_priv->family_id == RTL8390_FAMILY_ID && eth_priv->phy_is_internal[portaddr])
-               return rtl839x_write_sds_phy(portaddr, regnum, val);
+       if (eth_priv->family_id == RTL8390_FAMILY_ID && eth_priv->phy_is_internal[addr])
+               return rtl839x_write_sds_phy(addr, regnum, val);
 
-       if (regnum == RTL821X_PAGE_SELECT)
-               bus_priv->page[portaddr] = val;
+       if (regnum == RTMDIO_PAGE_SELECT)
+               bus_priv->page[addr] = val;
 
-       if (!bus_priv->raw[portaddr] && (regnum != RTL821X_PAGE_SELECT || page == RTL838X_PAGE_RAW)) {
-               bus_priv->raw[portaddr] = (page == RTL838X_PAGE_RAW);
-               err = (*bus_priv->write_phy)(portaddr, page, regnum, val);
+       if (!bus_priv->raw[addr] && (regnum != RTMDIO_PAGE_SELECT || page == bus_priv->rawpage)) {
+               bus_priv->raw[addr] = (page == bus_priv->rawpage);
+               err = (*bus_priv->write_phy)(addr, page, regnum, val);
                pr_debug("wr_PHY(adr=%d, pag=%d, reg=%d, val=%d) err = %d\n",
-                        portaddr, page, regnum, val, err);
+                        addr, page, regnum, val, err);
                return err;
        }
 
-       bus_priv->raw[portaddr] = false;
+       bus_priv->raw[addr] = false;
        return 0;
 }
 
 static int rtmdio_93xx_write(struct mii_bus *bus, int addr, int regnum, u16 val)
 {
+       int err, page;
        struct rtl838x_bus_priv *bus_priv = bus->priv;
        struct rtl838x_eth_priv *eth_priv = bus_priv->eth_priv;
-       int portaddr = bus_priv->portaddr ? bus_priv->portaddr : addr;
-       int err, page = bus_priv->page[portaddr];
 
-       if (regnum == RTL821X_PORT_SELECT) {
-               bus_priv->portaddr = val;
+       if (regnum == RTMDIO_PORT_SELECT) {
+               bus_priv->extaddr = (s16)val;
                return 0;
        }
 
-       if (regnum == RTL821X_PAGE_SELECT)
-               bus_priv->page[portaddr] = val;
+       if (bus_priv->extaddr >= 0)
+               addr = bus_priv->extaddr;
+       page = bus_priv->page[addr];
+
+       if (regnum == RTMDIO_PAGE_SELECT)
+               bus_priv->page[addr] = val;
 
-       if (!bus_priv->raw[portaddr] && (regnum != RTL821X_PAGE_SELECT || page == RTL930X_PAGE_RAW)) {
-               bus_priv->raw[portaddr] = (page == RTL930X_PAGE_RAW);
-               if (eth_priv->phy_is_internal[portaddr]) {
+       if (!bus_priv->raw[addr] && (regnum != RTMDIO_PAGE_SELECT || page == bus_priv->rawpage)) {
+               bus_priv->raw[addr] = (page == bus_priv->rawpage);
+               if (eth_priv->phy_is_internal[addr]) {
                        if (eth_priv->family_id == RTL9300_FAMILY_ID)
-                               return rtl930x_write_sds_phy(eth_priv->sds_id[portaddr],
+                               return rtl930x_write_sds_phy(eth_priv->sds_id[addr],
                                                             page, regnum, val);
                        else
-                               return rtl931x_write_sds_phy(eth_priv->sds_id[portaddr],
+                               return rtl931x_write_sds_phy(eth_priv->sds_id[addr],
                                                             page, regnum, val);
                }
 
-               err = (*bus_priv->write_phy)(portaddr, page, regnum, val);
+               err = (*bus_priv->write_phy)(addr, page, regnum, val);
                pr_debug("wr_PHY(adr=%d, pag=%d, reg=%d, val=%d) err = %d\n",
-                        portaddr, page, regnum, val, err);
+                        addr, page, regnum, val, err);
        }
 
-       bus_priv->raw[portaddr] = false;
+       bus_priv->raw[addr] = false;
        return 0;
 }
 
@@ -2217,7 +2224,7 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
                bus_priv->page[i] = 0;
                bus_priv->raw[i] = false;
        }
-       bus_priv->portaddr = 0;
+       bus_priv->extaddr = -1;
 
        switch(priv->family_id) {
        case RTL8380_FAMILY_ID:
@@ -2229,6 +2236,7 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
                bus_priv->write_mmd_phy = rtl838x_write_mmd_phy;
                bus_priv->read_phy = rtl838x_read_phy;
                bus_priv->write_phy = rtl838x_write_phy;
+               bus_priv->rawpage = 0xfff;
                break;
        case RTL8390_FAMILY_ID:
                priv->mii_bus->name = "rtl839x-eth-mdio";
@@ -2239,6 +2247,7 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
                bus_priv->write_mmd_phy = rtl839x_write_mmd_phy;
                bus_priv->read_phy = rtl839x_read_phy;
                bus_priv->write_phy = rtl839x_write_phy;
+               bus_priv->rawpage = 0x1fff;
                break;
        case RTL9300_FAMILY_ID:
                priv->mii_bus->name = "rtl930x-eth-mdio";
@@ -2249,16 +2258,18 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
                bus_priv->write_mmd_phy = rtl930x_write_mmd_phy;
                bus_priv->read_phy = rtl930x_read_phy;
                bus_priv->write_phy = rtl930x_write_phy;
+               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;
+               priv->mii_bus->reset = rtmdio_931x_reset;
                bus_priv->read_mmd_phy = rtl931x_read_mmd_phy;
                bus_priv->write_mmd_phy = rtl931x_write_mmd_phy;
                bus_priv->read_phy = rtl931x_read_phy;
                bus_priv->write_phy = rtl931x_write_phy;
+               bus_priv->rawpage = 0x1fff;
                break;
        }
        priv->mii_bus->read_c45 = rtmdio_read_c45;
index 0f49eae23da1e5680693a6d151245089c9fdc901..d6d88fc2ed01b8d7aa9c359c33a9f1707e1c4a4a 100644 (file)
@@ -410,7 +410,8 @@ struct dsa_tag;
 
 struct rtl838x_bus_priv {
        struct rtl838x_eth_priv *eth_priv;
-       int portaddr;
+       int extaddr;
+       int rawpage;
        int page[64];
        bool raw[64];
        int (*read_mmd_phy)(u32 port, u32 addr, u32 reg, u32 *val);
index 0c8b1dfd4dcd276822ab88a2ff463801fd7307b2..df5e2e444067abce1c4fc7aacd9676732fbc3df6 100644 (file)
@@ -22,8 +22,10 @@ extern struct rtl83xx_soc_info soc_info;
 extern struct mutex smi_lock;
 extern int phy_package_port_write_paged(struct phy_device *phydev, int port, int page, u32 regnum, u16 val);
 extern int phy_package_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val);
+extern int phy_port_write_paged(struct phy_device *phydev, int port, int page, u32 regnum, u16 val);
 extern int phy_package_port_read_paged(struct phy_device *phydev, int port, int page, u32 regnum);
 extern int phy_package_read_paged(struct phy_device *phydev, int page, u32 regnum);
+extern int phy_port_read_paged(struct phy_device *phydev, int port, int page, u32 regnum);
 
 #define PHY_PAGE_2     2
 #define PHY_PAGE_4     4