Skip to content

Commit

Permalink
net: dsa: mv88x6xxx: mv88e6390 errata
Browse files Browse the repository at this point in the history
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 <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Andrew Lunn authored and David S. Miller committed Jan 10, 2019
1 parent 001e465 commit ea89098
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 0 deletions.
113 changes: 113 additions & 0 deletions drivers/net/dsa/mv88e6xxx/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/dsa/mv88e6xxx/chip.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
10 changes: 10 additions & 0 deletions drivers/net/dsa/mv88e6xxx/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit ea89098

Please sign in to comment.