Is this errata documented somewhere? What happends without that magic wirtes? Software reset doen't clear registers into initial state?
Max. ср, 9 янв. 2019 г. в 02:40, Andrew Lunn <and...@lunn.ch>: > > The 6390 copper ports have an errata which require poking magic values > into undocumented magic registers and then performing a software > reset. > > Signed-off-by: Andrew Lunn <and...@lunn.ch> > --- > drivers/net/dsa/mv88e6xxx/chip.c | 113 +++++++++++++++++++++++++++++++ > drivers/net/dsa/mv88e6xxx/chip.h | 5 ++ > drivers/net/dsa/mv88e6xxx/port.h | 10 +++ > 3 files changed, 128 insertions(+) > > diff --git a/drivers/net/dsa/mv88e6xxx/chip.c > b/drivers/net/dsa/mv88e6xxx/chip.c > index 8a517d8fb9d1..8dca2c949e73 100644 > --- a/drivers/net/dsa/mv88e6xxx/chip.c > +++ b/drivers/net/dsa/mv88e6xxx/chip.c > @@ -2403,6 +2403,107 @@ static int mv88e6xxx_stats_setup(struct > mv88e6xxx_chip *chip) > return mv88e6xxx_g1_stats_clear(chip); > } > > +/* The mv88e6390 has some hidden registers used for debug and > + * development. The errata also makes use of them. > + */ > +static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port, > + int reg, u16 val) > +{ > + u16 ctrl; > + int err; > + > + err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_DATA_PORT, > + PORT_RESERVED_1A, val); > + if (err) > + return err; > + > + ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_WRITE | > + PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | > + reg; > + > + return mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, > + PORT_RESERVED_1A, ctrl); > +} > + > +static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip) > +{ > + return mv88e6xxx_wait(chip, PORT_RESERVED_1A_CTRL_PORT, > + PORT_RESERVED_1A, PORT_RESERVED_1A_BUSY); > +} > + > + > +static int mv88e6390_hidden_read(struct mv88e6xxx_chip *chip, int port, > + int reg, u16 *val) > +{ > + u16 ctrl; > + int err; > + > + ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_READ | > + PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | > + reg; > + > + err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, > + PORT_RESERVED_1A, ctrl); > + if (err) > + return err; > + > + err = mv88e6390_hidden_wait(chip); > + if (err) > + return err; > + > + return mv88e6xxx_port_read(chip, PORT_RESERVED_1A_DATA_PORT, > + PORT_RESERVED_1A, val); > +} > + > +/* Check if the errata has already been applied. */ > +static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) > +{ > + int port; > + int err; > + u16 val; > + > + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { > + err = mv88e6390_hidden_read(chip, port, 0, &val); > + if (err) { > + dev_err(chip->dev, > + "Error reading hidden register: %d\n", err); > + return false; > + } > + if (val != 0x01c0) > + return false; > + } > + > + return true; > +} > + > +/* The 6390 copper ports have an errata which require poking magic > + * values into undocumented hidden registers and then performing a > + * software reset. > + */ > +static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) > +{ > + int port; > + int err; > + > + if (mv88e6390_setup_errata_applied(chip)) > + return 0; > + > + /* Set the ports into blocking mode */ > + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { > + err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); > + if (err) > + return err; > + } > + > + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { > + err = mv88e6390_hidden_write(chip, port, 0, 0x01c0); > + if (err) > + return err; > + } > + > + return mv88e6xxx_software_reset(chip); > +} > + > static int mv88e6xxx_setup(struct dsa_switch *ds) > { > struct mv88e6xxx_chip *chip = ds->priv; > @@ -2415,6 +2516,12 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) > > mutex_lock(&chip->reg_lock); > > + if (chip->info->ops->setup_errata) { > + err = chip->info->ops->setup_errata(chip); > + if (err) > + goto unlock; > + } > + > /* Cache the cmode of each port. */ > for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { > if (chip->info->ops->port_get_cmode) { > @@ -3226,6 +3333,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { > > static const struct mv88e6xxx_ops mv88e6190_ops = { > /* MV88E6XXX_FAMILY_6390 */ > + .setup_errata = mv88e6390_setup_errata, > .irl_init_all = mv88e6390_g2_irl_init_all, > .get_eeprom = mv88e6xxx_g2_get_eeprom8, > .set_eeprom = mv88e6xxx_g2_set_eeprom8, > @@ -3269,6 +3377,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { > > static const struct mv88e6xxx_ops mv88e6190x_ops = { > /* MV88E6XXX_FAMILY_6390 */ > + .setup_errata = mv88e6390_setup_errata, > .irl_init_all = mv88e6390_g2_irl_init_all, > .get_eeprom = mv88e6xxx_g2_get_eeprom8, > .set_eeprom = mv88e6xxx_g2_set_eeprom8, > @@ -3312,6 +3421,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { > > static const struct mv88e6xxx_ops mv88e6191_ops = { > /* MV88E6XXX_FAMILY_6390 */ > + .setup_errata = mv88e6390_setup_errata, > .irl_init_all = mv88e6390_g2_irl_init_all, > .get_eeprom = mv88e6xxx_g2_get_eeprom8, > .set_eeprom = mv88e6xxx_g2_set_eeprom8, > @@ -3404,6 +3514,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { > > static const struct mv88e6xxx_ops mv88e6290_ops = { > /* MV88E6XXX_FAMILY_6390 */ > + .setup_errata = mv88e6390_setup_errata, > .irl_init_all = mv88e6390_g2_irl_init_all, > .get_eeprom = mv88e6xxx_g2_get_eeprom8, > .set_eeprom = mv88e6xxx_g2_set_eeprom8, > @@ -3709,6 +3820,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { > > static const struct mv88e6xxx_ops mv88e6390_ops = { > /* MV88E6XXX_FAMILY_6390 */ > + .setup_errata = mv88e6390_setup_errata, > .irl_init_all = mv88e6390_g2_irl_init_all, > .get_eeprom = mv88e6xxx_g2_get_eeprom8, > .set_eeprom = mv88e6xxx_g2_set_eeprom8, > @@ -3756,6 +3868,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { > > static const struct mv88e6xxx_ops mv88e6390x_ops = { > /* MV88E6XXX_FAMILY_6390 */ > + .setup_errata = mv88e6390_setup_errata, > .irl_init_all = mv88e6390_g2_irl_init_all, > .get_eeprom = mv88e6xxx_g2_get_eeprom8, > .set_eeprom = mv88e6xxx_g2_set_eeprom8, > diff --git a/drivers/net/dsa/mv88e6xxx/chip.h > b/drivers/net/dsa/mv88e6xxx/chip.h > index f9ecb7872d32..546651d8c3e1 100644 > --- a/drivers/net/dsa/mv88e6xxx/chip.h > +++ b/drivers/net/dsa/mv88e6xxx/chip.h > @@ -300,6 +300,11 @@ struct mv88e6xxx_mdio_bus { > }; > > struct mv88e6xxx_ops { > + /* Switch Setup Errata, called early in the switch setup to > + * allow any errata actions to be performed > + */ > + int (*setup_errata)(struct mv88e6xxx_chip *chip); > + > int (*ieee_pri_map)(struct mv88e6xxx_chip *chip); > int (*ip_pri_map)(struct mv88e6xxx_chip *chip); > > diff --git a/drivers/net/dsa/mv88e6xxx/port.h > b/drivers/net/dsa/mv88e6xxx/port.h > index 0d81866d0e4a..e583641de758 100644 > --- a/drivers/net/dsa/mv88e6xxx/port.h > +++ b/drivers/net/dsa/mv88e6xxx/port.h > @@ -251,6 +251,16 @@ > /* Offset 0x19: Port IEEE Priority Remapping Registers (4-7) */ > #define MV88E6095_PORT_IEEE_PRIO_REMAP_4567 0x19 > > +/* Offset 0x1a: Magic undocumented errata register */ > +#define PORT_RESERVED_1A 0x1a > +#define PORT_RESERVED_1A_BUSY BIT(15) > +#define PORT_RESERVED_1A_WRITE BIT(14) > +#define PORT_RESERVED_1A_READ 0 > +#define PORT_RESERVED_1A_PORT_SHIFT 5 > +#define PORT_RESERVED_1A_BLOCK (0xf << 10) > +#define PORT_RESERVED_1A_CTRL_PORT 4 > +#define PORT_RESERVED_1A_DATA_PORT 5 > + > int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, > u16 *val); > int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, > -- > 2.19.1 > -- Best regards, Maxim Uvarov