Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Marvell 88e6xxx Ethernet switch PHY and PPU support
0004  *
0005  * Copyright (c) 2008 Marvell Semiconductor
0006  *
0007  * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
0008  */
0009 
0010 #include <linux/mdio.h>
0011 #include <linux/module.h>
0012 
0013 #include "chip.h"
0014 #include "phy.h"
0015 
0016 int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
0017                int addr, int reg, u16 *val)
0018 {
0019     return mv88e6xxx_read(chip, addr, reg, val);
0020 }
0021 
0022 int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
0023             int addr, int reg, u16 val)
0024 {
0025     return mv88e6xxx_write(chip, addr, reg, val);
0026 }
0027 
0028 int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, int reg, u16 *val)
0029 {
0030     int addr = phy; /* PHY devices addresses start at 0x0 */
0031     struct mii_bus *bus;
0032 
0033     bus = mv88e6xxx_default_mdio_bus(chip);
0034     if (!bus)
0035         return -EOPNOTSUPP;
0036 
0037     if (!chip->info->ops->phy_read)
0038         return -EOPNOTSUPP;
0039 
0040     return chip->info->ops->phy_read(chip, bus, addr, reg, val);
0041 }
0042 
0043 int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, int reg, u16 val)
0044 {
0045     int addr = phy; /* PHY devices addresses start at 0x0 */
0046     struct mii_bus *bus;
0047 
0048     bus = mv88e6xxx_default_mdio_bus(chip);
0049     if (!bus)
0050         return -EOPNOTSUPP;
0051 
0052     if (!chip->info->ops->phy_write)
0053         return -EOPNOTSUPP;
0054 
0055     return chip->info->ops->phy_write(chip, bus, addr, reg, val);
0056 }
0057 
0058 static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page)
0059 {
0060     return mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE, page);
0061 }
0062 
0063 static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy)
0064 {
0065     int err;
0066 
0067     /* Restore PHY page Copper 0x0 for access via the registered
0068      * MDIO bus
0069      */
0070     err = mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE,
0071                   MV88E6XXX_PHY_PAGE_COPPER);
0072     if (unlikely(err)) {
0073         dev_err(chip->dev,
0074             "failed to restore PHY %d page Copper (%d)\n",
0075             phy, err);
0076     }
0077 }
0078 
0079 int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
0080                 u8 page, int reg, u16 *val)
0081 {
0082     int err;
0083 
0084     /* There is no paging for registers 22 */
0085     if (reg == MV88E6XXX_PHY_PAGE)
0086         return -EINVAL;
0087 
0088     err = mv88e6xxx_phy_page_get(chip, phy, page);
0089     if (!err) {
0090         err = mv88e6xxx_phy_read(chip, phy, reg, val);
0091         mv88e6xxx_phy_page_put(chip, phy);
0092     }
0093 
0094     return err;
0095 }
0096 
0097 int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
0098                  u8 page, int reg, u16 val)
0099 {
0100     int err;
0101 
0102     /* There is no paging for registers 22 */
0103     if (reg == MV88E6XXX_PHY_PAGE)
0104         return -EINVAL;
0105 
0106     err = mv88e6xxx_phy_page_get(chip, phy, page);
0107     if (!err) {
0108         err = mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE, page);
0109         if (!err)
0110             err = mv88e6xxx_phy_write(chip, phy, reg, val);
0111 
0112         mv88e6xxx_phy_page_put(chip, phy);
0113     }
0114 
0115     return err;
0116 }
0117 
0118 static int mv88e6xxx_phy_ppu_disable(struct mv88e6xxx_chip *chip)
0119 {
0120     if (!chip->info->ops->ppu_disable)
0121         return 0;
0122 
0123     return chip->info->ops->ppu_disable(chip);
0124 }
0125 
0126 static int mv88e6xxx_phy_ppu_enable(struct mv88e6xxx_chip *chip)
0127 {
0128     if (!chip->info->ops->ppu_enable)
0129         return 0;
0130 
0131     return chip->info->ops->ppu_enable(chip);
0132 }
0133 
0134 static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly)
0135 {
0136     struct mv88e6xxx_chip *chip;
0137 
0138     chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work);
0139 
0140     mv88e6xxx_reg_lock(chip);
0141 
0142     if (mutex_trylock(&chip->ppu_mutex)) {
0143         if (mv88e6xxx_phy_ppu_enable(chip) == 0)
0144             chip->ppu_disabled = 0;
0145         mutex_unlock(&chip->ppu_mutex);
0146     }
0147 
0148     mv88e6xxx_reg_unlock(chip);
0149 }
0150 
0151 static void mv88e6xxx_phy_ppu_reenable_timer(struct timer_list *t)
0152 {
0153     struct mv88e6xxx_chip *chip = from_timer(chip, t, ppu_timer);
0154 
0155     schedule_work(&chip->ppu_work);
0156 }
0157 
0158 static int mv88e6xxx_phy_ppu_access_get(struct mv88e6xxx_chip *chip)
0159 {
0160     int ret;
0161 
0162     mutex_lock(&chip->ppu_mutex);
0163 
0164     /* If the PHY polling unit is enabled, disable it so that
0165      * we can access the PHY registers.  If it was already
0166      * disabled, cancel the timer that is going to re-enable
0167      * it.
0168      */
0169     if (!chip->ppu_disabled) {
0170         ret = mv88e6xxx_phy_ppu_disable(chip);
0171         if (ret < 0) {
0172             mutex_unlock(&chip->ppu_mutex);
0173             return ret;
0174         }
0175         chip->ppu_disabled = 1;
0176     } else {
0177         del_timer(&chip->ppu_timer);
0178         ret = 0;
0179     }
0180 
0181     return ret;
0182 }
0183 
0184 static void mv88e6xxx_phy_ppu_access_put(struct mv88e6xxx_chip *chip)
0185 {
0186     /* Schedule a timer to re-enable the PHY polling unit. */
0187     mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10));
0188     mutex_unlock(&chip->ppu_mutex);
0189 }
0190 
0191 static void mv88e6xxx_phy_ppu_state_init(struct mv88e6xxx_chip *chip)
0192 {
0193     mutex_init(&chip->ppu_mutex);
0194     INIT_WORK(&chip->ppu_work, mv88e6xxx_phy_ppu_reenable_work);
0195     timer_setup(&chip->ppu_timer, mv88e6xxx_phy_ppu_reenable_timer, 0);
0196 }
0197 
0198 static void mv88e6xxx_phy_ppu_state_destroy(struct mv88e6xxx_chip *chip)
0199 {
0200     del_timer_sync(&chip->ppu_timer);
0201 }
0202 
0203 int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
0204                int addr, int reg, u16 *val)
0205 {
0206     int err;
0207 
0208     err = mv88e6xxx_phy_ppu_access_get(chip);
0209     if (!err) {
0210         err = mv88e6xxx_read(chip, addr, reg, val);
0211         mv88e6xxx_phy_ppu_access_put(chip);
0212     }
0213 
0214     return err;
0215 }
0216 
0217 int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
0218                 int addr, int reg, u16 val)
0219 {
0220     int err;
0221 
0222     err = mv88e6xxx_phy_ppu_access_get(chip);
0223     if (!err) {
0224         err = mv88e6xxx_write(chip, addr, reg, val);
0225         mv88e6xxx_phy_ppu_access_put(chip);
0226     }
0227 
0228     return err;
0229 }
0230 
0231 void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip)
0232 {
0233     if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
0234         mv88e6xxx_phy_ppu_state_init(chip);
0235 }
0236 
0237 void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip)
0238 {
0239     if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
0240         mv88e6xxx_phy_ppu_state_destroy(chip);
0241 }
0242 
0243 int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip)
0244 {
0245     return mv88e6xxx_phy_ppu_enable(chip);
0246 }