diff options
author | Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 2016-12-05 23:30:27 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-12-06 17:32:28 +0100 |
commit | 17e708baf7f24192cb1c7c8dd6b32d1941dfb0e8 (patch) | |
tree | c713e9ecc6ddddbb0790078fe379e05371a5fdac /drivers/net/dsa/mv88e6xxx/global1.c | |
parent | net: dsa: mv88e6xxx: add helper to hardware reset (diff) | |
download | linux-17e708baf7f24192cb1c7c8dd6b32d1941dfb0e8.tar.xz linux-17e708baf7f24192cb1c7c8dd6b32d1941dfb0e8.zip |
net: dsa: mv88e6xxx: add a soft reset operation
Marvell chips have different way to issue a software reset.
Old chips (such as 88E6060) have a reset bit in an ATU control register.
Newer chips moved this bit in a Global control register. Chips with
controllable PPU should reset the PPU when resetting the switch.
Add a new reset operation to implement these differences and introduce a
mv88e6xxx_software_reset() helper to wrap it conveniently.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx/global1.c')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/global1.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 44136ee015c3..c868eb06497f 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -33,6 +33,127 @@ int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask) return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask); } +/* Offset 0x00: Switch Global Status Register */ + +static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip) +{ + u16 state; + int i, err; + + for (i = 0; i < 16; ++i) { + err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state); + if (err) + return err; + + /* Check the value of the PPUState bits 15:14 */ + state &= GLOBAL_STATUS_PPU_STATE_MASK; + if (state == GLOBAL_STATUS_PPU_STATE_POLLING) + return 0; + + usleep_range(1000, 2000); + } + + return -ETIMEDOUT; +} + +static int mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip) +{ + u16 state; + int i, err; + + for (i = 0; i < 16; ++i) { + err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state); + if (err) + return err; + + /* Check the value of the PPUState (or InitState) bit 15 */ + if (state & GLOBAL_STATUS_PPU_STATE) + return 0; + + usleep_range(1000, 2000); + } + + return -ETIMEDOUT; +} + +static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip) +{ + const unsigned long timeout = jiffies + 1 * HZ; + u16 val; + int err; + + /* Wait up to 1 second for the switch to be ready. The InitReady bit 11 + * is set to a one when all units inside the device (ATU, VTU, etc.) + * have finished their initialization and are ready to accept frames. + */ + while (time_before(jiffies, timeout)) { + err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val); + if (err) + return err; + + if (val & GLOBAL_STATUS_INIT_READY) + break; + + usleep_range(1000, 2000); + } + + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + return 0; +} + +/* Offset 0x04: Switch Global Control Register */ + +int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip) +{ + u16 val; + int err; + + /* Set the SWReset bit 15 along with the PPUEn bit 14, to also restart + * the PPU, including re-doing PHY detection and initialization + */ + err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); + if (err) + return err; + + val |= GLOBAL_CONTROL_SW_RESET; + val |= GLOBAL_CONTROL_PPU_ENABLE; + + err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); + if (err) + return err; + + err = mv88e6xxx_g1_wait_init_ready(chip); + if (err) + return err; + + return mv88e6185_g1_wait_ppu_polling(chip); +} + +int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip) +{ + u16 val; + int err; + + /* Set the SWReset bit 15 */ + err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); + if (err) + return err; + + val |= GLOBAL_CONTROL_SW_RESET; + + err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); + if (err) + return err; + + err = mv88e6xxx_g1_wait_init_ready(chip); + if (err) + return err; + + return mv88e6352_g1_wait_ppu_polling(chip); +} + /* Offset 0x1a: Monitor Control */ /* Offset 0x1a: Monitor & MGMT Control on some devices */ |