diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/dsa/mv88e6123.c | 4 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6131.c | 4 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6171.c | 4 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6352.c | 4 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 137 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.h | 6 |
6 files changed, 76 insertions, 83 deletions
diff --git a/drivers/net/dsa/mv88e6123.c b/drivers/net/dsa/mv88e6123.c index 45cce4fa5f37..fadec7a0e6b5 100644 --- a/drivers/net/dsa/mv88e6123.c +++ b/drivers/net/dsa/mv88e6123.c @@ -99,10 +99,6 @@ static int mv88e6123_setup(struct dsa_switch *ds) if (ret < 0) return ret; - ret = mv88e6xxx_switch_reset(ps, false); - if (ret < 0) - return ret; - ret = mv88e6123_setup_global(ds); if (ret < 0) return ret; diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 5d252445e543..25ed82372df5 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -132,10 +132,6 @@ static int mv88e6131_setup(struct dsa_switch *ds) if (ret < 0) return ret; - ret = mv88e6xxx_switch_reset(ps, false); - if (ret < 0) - return ret; - ret = mv88e6131_setup_global(ds); if (ret < 0) return ret; diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index a98e7d3c0c64..caaa4b66abc1 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -108,10 +108,6 @@ static int mv88e6171_setup(struct dsa_switch *ds) if (ret < 0) return ret; - ret = mv88e6xxx_switch_reset(ps, true); - if (ret < 0) - return ret; - ret = mv88e6171_setup_global(ds); if (ret < 0) return ret; diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index d03c14a7ad1f..470789a3f8ec 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -125,10 +125,6 @@ static int mv88e6352_setup(struct dsa_switch *ds) if (ret < 0) return ret; - ret = mv88e6xxx_switch_reset(ps, true); - if (ret < 0) - return ret; - ret = mv88e6352_setup_global(ds); if (ret < 0) return ret; diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 037244b95e79..b631a5d07ba0 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -2559,6 +2559,68 @@ restore_page_0: return ret; } +static int mv88e6xxx_switch_reset(struct mv88e6xxx_priv_state *ps) +{ + bool ppu_active = mv88e6xxx_has(ps, MV88E6XXX_FLAG_PPU_ACTIVE); + u16 is_reset = (ppu_active ? 0x8800 : 0xc800); + struct gpio_desc *gpiod = ps->ds->pd->reset; + unsigned long timeout; + int ret; + int i; + + /* Set all ports to the disabled state. */ + for (i = 0; i < ps->info->num_ports; i++) { + ret = _mv88e6xxx_reg_read(ps, REG_PORT(i), PORT_CONTROL); + if (ret < 0) + return ret; + + ret = _mv88e6xxx_reg_write(ps, REG_PORT(i), PORT_CONTROL, + ret & 0xfffc); + if (ret) + return ret; + } + + /* Wait for transmit queues to drain. */ + usleep_range(2000, 4000); + + /* If there is a gpio connected to the reset pin, toggle it */ + if (gpiod) { + gpiod_set_value_cansleep(gpiod, 1); + usleep_range(10000, 20000); + gpiod_set_value_cansleep(gpiod, 0); + usleep_range(10000, 20000); + } + + /* Reset the switch. Keep the PPU active if requested. The PPU + * needs to be active to support indirect phy register access + * through global registers 0x18 and 0x19. + */ + if (ppu_active) + ret = _mv88e6xxx_reg_write(ps, REG_GLOBAL, 0x04, 0xc000); + else + ret = _mv88e6xxx_reg_write(ps, REG_GLOBAL, 0x04, 0xc400); + if (ret) + return ret; + + /* Wait up to one second for reset to complete. */ + timeout = jiffies + 1 * HZ; + while (time_before(jiffies, timeout)) { + ret = _mv88e6xxx_reg_read(ps, REG_GLOBAL, 0x00); + if (ret < 0) + return ret; + + if ((ret & is_reset) == is_reset) + break; + usleep_range(1000, 2000); + } + if (time_after(jiffies, timeout)) + ret = -ETIMEDOUT; + else + ret = 0; + + return ret; +} + static int mv88e6xxx_power_on_serdes(struct mv88e6xxx_priv_state *ps) { int ret; @@ -2860,6 +2922,8 @@ int mv88e6xxx_setup_ports(struct dsa_switch *ds) int mv88e6xxx_setup_common(struct mv88e6xxx_priv_state *ps) { + int err; + mutex_init(&ps->smi_mutex); INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work); @@ -2870,7 +2934,13 @@ int mv88e6xxx_setup_common(struct mv88e6xxx_priv_state *ps) if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_PPU)) mv88e6xxx_ppu_state_init(ps); - return 0; + mutex_lock(&ps->smi_mutex); + + err = mv88e6xxx_switch_reset(ps); + + mutex_unlock(&ps->smi_mutex); + + return err; } int mv88e6xxx_setup_global(struct dsa_switch *ds) @@ -3046,71 +3116,6 @@ unlock: return err; } -int mv88e6xxx_switch_reset(struct mv88e6xxx_priv_state *ps, bool ppu_active) -{ - u16 is_reset = (ppu_active ? 0x8800 : 0xc800); - struct gpio_desc *gpiod = ps->ds->pd->reset; - unsigned long timeout; - int ret; - int i; - - mutex_lock(&ps->smi_mutex); - - /* Set all ports to the disabled state. */ - for (i = 0; i < ps->info->num_ports; i++) { - ret = _mv88e6xxx_reg_read(ps, REG_PORT(i), PORT_CONTROL); - if (ret < 0) - goto unlock; - - ret = _mv88e6xxx_reg_write(ps, REG_PORT(i), PORT_CONTROL, - ret & 0xfffc); - if (ret) - goto unlock; - } - - /* Wait for transmit queues to drain. */ - usleep_range(2000, 4000); - - /* If there is a gpio connected to the reset pin, toggle it */ - if (gpiod) { - gpiod_set_value_cansleep(gpiod, 1); - usleep_range(10000, 20000); - gpiod_set_value_cansleep(gpiod, 0); - usleep_range(10000, 20000); - } - - /* Reset the switch. Keep the PPU active if requested. The PPU - * needs to be active to support indirect phy register access - * through global registers 0x18 and 0x19. - */ - if (ppu_active) - ret = _mv88e6xxx_reg_write(ps, REG_GLOBAL, 0x04, 0xc000); - else - ret = _mv88e6xxx_reg_write(ps, REG_GLOBAL, 0x04, 0xc400); - if (ret) - goto unlock; - - /* Wait up to one second for reset to complete. */ - timeout = jiffies + 1 * HZ; - while (time_before(jiffies, timeout)) { - ret = _mv88e6xxx_reg_read(ps, REG_GLOBAL, 0x00); - if (ret < 0) - goto unlock; - - if ((ret & is_reset) == is_reset) - break; - usleep_range(1000, 2000); - } - if (time_after(jiffies, timeout)) - ret = -ETIMEDOUT; - else - ret = 0; -unlock: - mutex_unlock(&ps->smi_mutex); - - return ret; -} - int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 192292f21c8a..efd6ebde8eb4 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -374,6 +374,7 @@ enum mv88e6xxx_cap { * See GLOBAL_CONTROL_PPU_ENABLE and GLOBAL_STATUS_PPU_POLLING. */ MV88E6XXX_CAP_PPU, + MV88E6XXX_CAP_PPU_ACTIVE, /* SMI PHY Command and Data registers. * This requires an indirect access to PHY registers through @@ -412,6 +413,7 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_EEPROM BIT(MV88E6XXX_CAP_EEPROM) #define MV88E6XXX_FLAG_PORTSTATE BIT(MV88E6XXX_CAP_PORTSTATE) #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) +#define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE) #define MV88E6XXX_FLAG_SMI_PHY BIT(MV88E6XXX_CAP_SMI_PHY) #define MV88E6XXX_FLAG_SWITCH_MAC BIT(MV88E6XXX_CAP_SWITCH_MAC_WOL_WOF) #define MV88E6XXX_FLAG_TEMP BIT(MV88E6XXX_CAP_TEMP) @@ -446,6 +448,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ MV88E6XXX_FLAG_PORTSTATE | \ + MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ @@ -456,6 +459,7 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAGS_FAMILY_6351 \ (MV88E6XXX_FLAG_ATU | \ MV88E6XXX_FLAG_PORTSTATE | \ + MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ @@ -467,6 +471,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ MV88E6XXX_FLAG_PORTSTATE | \ + MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ @@ -578,7 +583,6 @@ static inline bool mv88e6xxx_has(struct mv88e6xxx_priv_state *ps, return (ps->info->flags & flags) == flags; } -int mv88e6xxx_switch_reset(struct mv88e6xxx_priv_state *ps, bool ppu_active); const char *mv88e6xxx_drv_probe(struct device *dsa_dev, struct device *host_dev, int sw_addr, void **priv, const struct mv88e6xxx_info *table, |