#define BCM54140_DEFAULT_DOWNSHIFT 5
 #define BCM54140_MAX_DOWNSHIFT 9
 
+enum bcm54140_global_phy {
+       BCM54140_BASE_ADDR = 0,
+};
+
 struct bcm54140_priv {
        int port;
        int base_addr;
        int ret;
 
        phy_lock_mdio_bus(phydev);
-       ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
+       ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
+                                 MII_BCM54XX_RDB_ADDR, rdb);
        if (ret < 0)
                goto out;
 
-       ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
+       ret = __phy_package_read(phydev, BCM54140_BASE_ADDR,
+                                MII_BCM54XX_RDB_DATA);
 
 out:
        phy_unlock_mdio_bus(phydev);
        int ret;
 
        phy_lock_mdio_bus(phydev);
-       ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
+       ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
+                                 MII_BCM54XX_RDB_ADDR, rdb);
        if (ret < 0)
                goto out;
 
-       ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val);
+       ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
+                                 MII_BCM54XX_RDB_DATA, val);
 
 out:
        phy_unlock_mdio_bus(phydev);
 
  * gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO
  * is shared.
  */
+
+enum vsc85xx_global_phy {
+       VSC88XX_BASE_ADDR = 0,
+};
+
 struct vsc85xx_shared_private {
        struct mutex gpio_lock;
 };
 
                dump_stack();
        }
 
-       return __phy_package_write(phydev, regnum, val);
+       return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val);
 }
 
 /* phydev->bus->mdio_lock should be locked when using this function */
                dump_stack();
        }
 
-       return __phy_package_read(phydev, regnum);
+       return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum);
 }
 
 u32 vsc85xx_csr_read(struct phy_device *phydev,
 
 /**
  * phy_package_join - join a common PHY group
  * @phydev: target phy_device struct
- * @addr: cookie and PHY address for global register access
+ * @base_addr: cookie and base PHY address of PHY package for offset
+ *   calculation of global register access
  * @priv_size: if non-zero allocate this amount of bytes for private data
  *
  * This joins a PHY group and provides a shared storage for all phydevs in
  * this group. This is intended to be used for packages which contain
  * more than one PHY, for example a quad PHY transceiver.
  *
- * The addr parameter serves as a cookie which has to have the same value
- * for all members of one group and as a PHY address to access generic
- * registers of a PHY package. Usually, one of the PHY addresses of the
- * different PHYs in the package provides access to these global registers.
+ * The base_addr parameter serves as cookie which has to have the same values
+ * for all members of one group and as the base PHY address of the PHY package
+ * for offset calculation to access generic registers of a PHY package.
+ * Usually, one of the PHY addresses of the different PHYs in the package
+ * provides access to these global registers.
  * The address which is given here, will be used in the phy_package_read()
- * and phy_package_write() convenience functions. If your PHY doesn't have
- * global registers you can just pick any of the PHY addresses.
+ * and phy_package_write() convenience functions as base and added to the
+ * passed offset in those functions.
  *
  * This will set the shared pointer of the phydev to the shared storage.
  * If this is the first call for a this cookie the shared storage will be
  * Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
  * with the same cookie but a different priv_size is an error.
  */
-int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
+int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
 {
        struct mii_bus *bus = phydev->mdio.bus;
        struct phy_package_shared *shared;
        int ret;
 
-       if (addr < 0 || addr >= PHY_MAX_ADDR)
+       if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
                return -EINVAL;
 
        mutex_lock(&bus->shared_lock);
-       shared = bus->shared[addr];
+       shared = bus->shared[base_addr];
        if (!shared) {
                ret = -ENOMEM;
                shared = kzalloc(sizeof(*shared), GFP_KERNEL);
                                goto err_free;
                        shared->priv_size = priv_size;
                }
-               shared->addr = addr;
+               shared->base_addr = base_addr;
                refcount_set(&shared->refcnt, 1);
-               bus->shared[addr] = shared;
+               bus->shared[base_addr] = shared;
        } else {
                ret = -EINVAL;
                if (priv_size && priv_size != shared->priv_size)
                return;
 
        if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
-               bus->shared[shared->addr] = NULL;
+               bus->shared[shared->base_addr] = NULL;
                mutex_unlock(&bus->shared_lock);
                kfree(shared->priv);
                kfree(shared);
  * devm_phy_package_join - resource managed phy_package_join()
  * @dev: device that is registering this PHY package
  * @phydev: target phy_device struct
- * @addr: cookie and PHY address for global register access
+ * @base_addr: cookie and base PHY address of PHY package for offset
+ *   calculation of global register access
  * @priv_size: if non-zero allocate this amount of bytes for private data
  *
  * Managed phy_package_join(). Shared storage fetched by this function,
  * phy_package_join() for more information.
  */
 int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
-                         int addr, size_t priv_size)
+                         int base_addr, size_t priv_size)
 {
        struct phy_device **ptr;
        int ret;
        if (!ptr)
                return -ENOMEM;
 
-       ret = phy_package_join(phydev, addr, priv_size);
+       ret = phy_package_join(phydev, base_addr, priv_size);
 
        if (!ret) {
                *ptr = phydev;
 
 
 /**
  * struct phy_package_shared - Shared information in PHY packages
- * @addr: Common PHY address used to combine PHYs in one package
+ * @base_addr: Base PHY address of PHY package used to combine PHYs
+ *   in one package and for offset calculation of phy_package_read/write
  * @refcnt: Number of PHYs connected to this shared data
  * @flags: Initialization of PHY package
  * @priv_size: Size of the shared private data @priv
  * phy_package_leave().
  */
 struct phy_package_shared {
-       u8 addr;
+       u8 base_addr;
        refcount_t refcnt;
        unsigned long flags;
        size_t priv_size;
 int phy_ethtool_set_link_ksettings(struct net_device *ndev,
                                   const struct ethtool_link_ksettings *cmd);
 int phy_ethtool_nway_reset(struct net_device *ndev);
-int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size);
+int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);
 void phy_package_leave(struct phy_device *phydev);
 int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
-                         int addr, size_t priv_size);
+                         int base_addr, size_t priv_size);
 
 int __init mdio_bus_init(void);
 void mdio_bus_exit(void);
                       struct kernel_hwtstamp_config *config,
                       struct netlink_ext_ack *extack);
 
-static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
+static inline int phy_package_address(struct phy_device *phydev,
+                                     unsigned int addr_offset)
 {
        struct phy_package_shared *shared = phydev->shared;
+       u8 base_addr = shared->base_addr;
 
-       if (!shared)
+       if (addr_offset >= PHY_MAX_ADDR - base_addr)
                return -EIO;
 
-       return mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
+       /* we know that addr will be in the range 0..31 and thus the
+        * implicit cast to a signed int is not a problem.
+        */
+       return base_addr + addr_offset;
 }
 
-static inline int __phy_package_read(struct phy_device *phydev, u32 regnum)
+static inline int phy_package_read(struct phy_device *phydev,
+                                  unsigned int addr_offset, u32 regnum)
 {
-       struct phy_package_shared *shared = phydev->shared;
+       int addr = phy_package_address(phydev, addr_offset);
 
-       if (!shared)
-               return -EIO;
+       if (addr < 0)
+               return addr;
+
+       return mdiobus_read(phydev->mdio.bus, addr, regnum);
+}
+
+static inline int __phy_package_read(struct phy_device *phydev,
+                                    unsigned int addr_offset, u32 regnum)
+{
+       int addr = phy_package_address(phydev, addr_offset);
+
+       if (addr < 0)
+               return addr;
 
-       return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
+       return __mdiobus_read(phydev->mdio.bus, addr, regnum);
 }
 
 static inline int phy_package_write(struct phy_device *phydev,
-                                   u32 regnum, u16 val)
+                                   unsigned int addr_offset, u32 regnum,
+                                   u16 val)
 {
-       struct phy_package_shared *shared = phydev->shared;
+       int addr = phy_package_address(phydev, addr_offset);
 
-       if (!shared)
-               return -EIO;
+       if (addr < 0)
+               return addr;
 
-       return mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
+       return mdiobus_write(phydev->mdio.bus, addr, regnum, val);
 }
 
 static inline int __phy_package_write(struct phy_device *phydev,
-                                     u32 regnum, u16 val)
+                                     unsigned int addr_offset, u32 regnum,
+                                     u16 val)
 {
-       struct phy_package_shared *shared = phydev->shared;
+       int addr = phy_package_address(phydev, addr_offset);
 
-       if (!shared)
-               return -EIO;
+       if (addr < 0)
+               return addr;
 
-       return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
+       return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
 }
 
 static inline bool __phy_package_set_once(struct phy_device *phydev,