Commit 552238b5 authored by Vivien Didelot's avatar Vivien Didelot Committed by David S. Miller

net: dsa: mv88e6xxx: factorize switch reset

Add a MV88E6XXX_FLAG_PPU_ACTIVE flag to describe how to reset the
switch, and merge the reset call to the common setup code.
Signed-off-by: default avatarVivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2672f825
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -2559,6 +2559,68 @@ static int _mv88e6xxx_phy_page_read(struct mv88e6xxx_priv_state *ps,
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 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds)
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);
......
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment