Commit b1df0f5c authored by David S. Miller's avatar David S. Miller

Merge branch 'mv88e6xxx-rework-reset-and-PPU-code'

Vivien Didelot says:

====================
net: dsa: mv88e6xxx: rework reset and PPU code

Old Marvell chips (like 88E6060) don't have a PHY Polling Unit (PPU).

Next chips (like 88E6185) have a PPU, which has exclusive access to the
PHY registers, thus must be disabled before access.

Newer chips (like 88E6352) have an indirect mechanism to access the PHY
registers whenever, thus loose control over the PPU (always enabled).

Here's a summary:

Model | PPU? | Has PPU ctrl?  | PPU state readable? | PHY access
----- | ---- | -------------- | ------------------- | ----------
 6060 | no   | no             | no                  | direct
 6185 | yes  | yes, PPUEn bit | yes, PPUState 2-bit | direct w/ PPU dis.
 6352 | yes  | no             | yes, PPUState 1-bit | indirect
 6390 | yes  | no             | yes, InitState bit  | indirect

Depending on the PPU control, a switch may have to restart the PPU when
resetting the switch. Once the switch is reset, we must wait for the PPU
state to be active polling again before accessing the registers.

For that purpose, add new operations to the chips to enable/disable the
PPU, and execute software reset. With these new ops in place, rework the
switch reset code and finally get rid of the MV88E6XXX_FLAG_PPU* flags.

Changes in v3:
  - consider 6097 as 6352 (no PPU ops and use mv88e6352_g1_reset).

Changes in v2:
  - wait in ppu/reset ops so that ppu_polling is not needed anymore.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9f9ffdff a199d8b6
This diff is collapsed.
......@@ -33,6 +33,184 @@ 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_disabled(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 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);
}
int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip)
{
u16 val;
int err;
err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
if (err)
return err;
val |= GLOBAL_CONTROL_PPU_ENABLE;
err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
if (err)
return err;
return mv88e6185_g1_wait_ppu_polling(chip);
}
int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip)
{
u16 val;
int err;
err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val);
if (err)
return err;
val &= ~GLOBAL_CONTROL_PPU_ENABLE;
err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val);
if (err)
return err;
return mv88e6185_g1_wait_ppu_disabled(chip);
}
/* Offset 0x1a: Monitor Control */
/* Offset 0x1a: Monitor & MGMT Control on some devices */
......
......@@ -19,6 +19,13 @@
int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val);
int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val);
int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask);
int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip);
int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip);
int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip);
int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip);
int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip);
int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
......
......@@ -193,12 +193,12 @@
#define GLOBAL_STATUS 0x00
#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */
/* Two bits for 6165, 6185 etc */
#define GLOBAL_STATUS_PPU_MASK (0x3 << 14)
#define GLOBAL_STATUS_PPU_DISABLED_RST (0x0 << 14)
#define GLOBAL_STATUS_PPU_INITIALIZING (0x1 << 14)
#define GLOBAL_STATUS_PPU_DISABLED (0x2 << 14)
#define GLOBAL_STATUS_PPU_POLLING (0x3 << 14)
#define GLOBAL_STATUS_PPU_STATE_MASK (0x3 << 14) /* 6165 6185 */
#define GLOBAL_STATUS_PPU_STATE_DISABLED_RST (0x0 << 14)
#define GLOBAL_STATUS_PPU_STATE_INITIALIZING (0x1 << 14)
#define GLOBAL_STATUS_PPU_STATE_DISABLED (0x2 << 14)
#define GLOBAL_STATUS_PPU_STATE_POLLING (0x3 << 14)
#define GLOBAL_STATUS_INIT_READY BIT(11)
#define GLOBAL_STATUS_IRQ_AVB 8
#define GLOBAL_STATUS_IRQ_DEVICE 7
#define GLOBAL_STATUS_IRQ_STATS 6
......@@ -490,12 +490,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_CAP_G2_PVT_DATA, /* (0x0c) Cross Chip Port VLAN Data */
MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */
/* PHY Polling Unit.
* See GLOBAL_CONTROL_PPU_ENABLE and GLOBAL_STATUS_PPU_POLLING.
*/
MV88E6XXX_CAP_PPU,
MV88E6XXX_CAP_PPU_ACTIVE,
/* Per VLAN Spanning Tree Unit (STU).
* The Port State database, if present, is accessed through VTU
* operations and dedicated SID registers. See GLOBAL_VTU_SID.
......@@ -537,8 +531,6 @@ enum mv88e6xxx_cap {
#define MV88E6XXX_FLAG_G2_PVT_DATA BIT_ULL(MV88E6XXX_CAP_G2_PVT_DATA)
#define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT)
#define MV88E6XXX_FLAG_PPU BIT_ULL(MV88E6XXX_CAP_PPU)
#define MV88E6XXX_FLAG_PPU_ACTIVE BIT_ULL(MV88E6XXX_CAP_PPU_ACTIVE)
#define MV88E6XXX_FLAG_STU BIT_ULL(MV88E6XXX_CAP_STU)
#define MV88E6XXX_FLAG_TEMP BIT_ULL(MV88E6XXX_CAP_TEMP)
#define MV88E6XXX_FLAG_TEMP_LIMIT BIT_ULL(MV88E6XXX_CAP_TEMP_LIMIT)
......@@ -567,7 +559,6 @@ enum mv88e6xxx_cap {
#define MV88E6XXX_FLAGS_FAMILY_6095 \
(MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_MULTI_CHIP)
......@@ -578,7 +569,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
......@@ -605,7 +595,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_INT | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAGS_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_VTU)
#define MV88E6XXX_FLAGS_FAMILY_6320 \
......@@ -614,7 +603,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_TEMP_LIMIT | \
MV88E6XXX_FLAG_VTU | \
......@@ -630,7 +618,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_VTU | \
......@@ -647,7 +634,6 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_TEMP_LIMIT | \
......@@ -662,7 +648,6 @@ struct mv88e6xxx_ops;
#define MV88E6XXX_FLAGS_FAMILY_6390 \
(MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_TEMP_LIMIT | \
......@@ -792,6 +777,13 @@ struct mv88e6xxx_ops {
int (*phy_write)(struct mv88e6xxx_chip *chip, int addr, int reg,
u16 val);
/* PHY Polling Unit (PPU) operations */
int (*ppu_enable)(struct mv88e6xxx_chip *chip);
int (*ppu_disable)(struct mv88e6xxx_chip *chip);
/* Switch Software Reset */
int (*reset)(struct mv88e6xxx_chip *chip);
/* RGMII Receive/Transmit Timing Control
* Add delay on PHY_INTERFACE_MODE_RGMII_*ID, no delay otherwise.
*/
......
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