2020-10-16 03:23:06

by Pavana Sharma

[permalink] [raw]
Subject: [PATCH v3] Add support for mv88e6393x family of Marvell.

The Marvell 88E6393X device is a single-chip integration of a 11-port
Ethernet switch with eight integrated Gigabit Ethernet (GbE) transceivers
and three 10-Gigabit interfaces.

This patch adds functionalities specific to mv88e6393x family (88E6393X,
88E6193X and 88E6191X)

Signed-off-by: Pavana Sharma <[email protected]>
---
Changes in v2:
- Fix a warning (Reported-by: kernel test robot <[email protected]>)
Changes in v3:
- Fix 'unused function' warning
---
drivers/net/dsa/mv88e6xxx/chip.c | 90 +++++++++
drivers/net/dsa/mv88e6xxx/chip.h | 2 +
drivers/net/dsa/mv88e6xxx/global1.h | 2 +
drivers/net/dsa/mv88e6xxx/global2.h | 8 +
drivers/net/dsa/mv88e6xxx/port.c | 302 ++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 39 +++-
drivers/net/dsa/mv88e6xxx/serdes.c | 239 ++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/serdes.h | 39 ++++
8 files changed, 720 insertions(+), 1 deletion(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index f0dbc05e30a4..241ff788b0b1 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -634,6 +634,23 @@ static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
mv88e6390_phylink_validate(chip, port, mask, state);
}

+static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
+ unsigned long *mask,
+ struct phylink_link_state *state)
+{
+ if (port == 0 || port >= 9) {
+ phylink_set(mask, 10000baseT_Full);
+ phylink_set(mask, 10000baseKR_Full);
+ phylink_set(mask, 2500baseX_Full);
+ phylink_set(mask, 2500baseT_Full);
+ }
+
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseX_Full);
+
+ mv88e6065_phylink_validate(chip, port, mask, state);
+}
+
static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
unsigned long *supported,
struct phylink_link_state *state)
@@ -4141,6 +4158,56 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.phylink_validate = mv88e6390_phylink_validate,
};

+static const struct mv88e6xxx_ops mv88e6193x_ops = {
+ /* MV88E6XXX_FAMILY_6393X */
+ .setup_errata = mv88e6393x_setup_errata,
+ .irl_init_all = mv88e6390_g2_irl_init_all,
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_floods = mv88e6352_port_set_egress_floods,
+ .port_set_ether_type = mv88e6393x_port_set_ether_type,
+ .port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
+ .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
+ .port_pause_limit = mv88e6390_port_pause_limit,
+ .port_set_cmode = mv88e6393x_port_set_cmode,
+ .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+ .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+ .port_get_cmode = mv88e6352_port_get_cmode,
+ .stats_snapshot = mv88e6390_g1_stats_snapshot,
+ .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
+ .stats_get_sset_count = mv88e6320_stats_get_sset_count,
+ .stats_get_strings = mv88e6320_stats_get_strings,
+ .stats_get_stats = mv88e6390_stats_get_stats,
+ .set_cpu_port = mv88e6393x_port_set_cpu_dest,
+ .set_egress_port = mv88e6393x_set_egress_port,
+ .watchdog_ops = &mv88e6390_watchdog_ops,
+ .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
+ .pot_clear = mv88e6xxx_g2_pot_clear,
+ .reset = mv88e6352_g1_reset,
+ .rmu_disable = mv88e6390_g1_rmu_disable,
+ .vtu_getnext = mv88e6390_g1_vtu_getnext,
+ .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
+ .serdes_power = mv88e6393x_serdes_power,
+ .serdes_get_lane = mv88e6393x_serdes_get_lane,
+ /* Check status register pause & lpa register */
+ .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
+ .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
+ .serdes_irq_enable = mv88e6393x_serdes_irq_enable,
+ .serdes_irq_status = mv88e6393x_serdes_irq_status,
+ .gpio_ops = &mv88e6352_gpio_ops,
+ .avb_ops = &mv88e6390_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
+ .phylink_validate = mv88e6393x_phylink_validate,
+};
+
static const struct mv88e6xxx_ops mv88e6240_ops = {
/* MV88E6XXX_FAMILY_6352 */
.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
@@ -5073,6 +5140,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6191_ops,
},

+ [MV88E6193X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X,
+ .family = MV88E6XXX_FAMILY_6393X,
+ .name = "Marvell 88E6193X",
+ .num_databases = 4096,
+ .num_ports = 11, /* 10 + Z80 */
+ .num_internal_phys = 9,
+ .max_vid = 8191,
+ .port_base_addr = 0x0,
+ .phy_base_addr = 0x0,
+ .global1_addr = 0x1b,
+ .global2_addr = 0x1c,
+ .age_time_coeff = 3750,
+ .g1_irqs = 10,
+ .g2_irqs = 14,
+ .atu_move_port_mask = 0x1f,
+ .pvt = true,
+ .multi_chip = true,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
+ .ptp_support = true,
+ .ops = &mv88e6193x_ops,
+ },
+
[MV88E6220] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
.family = MV88E6XXX_FAMILY_6250,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 823ae89e5fca..407d683c0fcf 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -63,6 +63,7 @@ enum mv88e6xxx_model {
MV88E6190,
MV88E6190X,
MV88E6191,
+ MV88E6193X,
MV88E6220,
MV88E6240,
MV88E6250,
@@ -90,6 +91,7 @@ enum mv88e6xxx_family {
MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */
MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */
+ MV88E6XXX_FAMILY_6393X, /* 6191X 6193X 6393X */
};

struct mv88e6xxx_ops;
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 1e3546f8b072..bd17eed15aad 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -22,6 +22,7 @@
#define MV88E6185_G1_STS_PPU_STATE_DISABLED 0x8000
#define MV88E6185_G1_STS_PPU_STATE_POLLING 0xc000
#define MV88E6XXX_G1_STS_INIT_READY 0x0800
+#define MV88E6193X_G1_STS_IRQ_DEVICE_2 9
#define MV88E6XXX_G1_STS_IRQ_AVB 8
#define MV88E6XXX_G1_STS_IRQ_DEVICE 7
#define MV88E6XXX_G1_STS_IRQ_STATS 6
@@ -59,6 +60,7 @@
#define MV88E6185_G1_CTL1_SCHED_PRIO 0x0800
#define MV88E6185_G1_CTL1_MAX_FRAME_1632 0x0400
#define MV88E6185_G1_CTL1_RELOAD_EEPROM 0x0200
+#define MV88E6193X_G1_CTL1_DEVICE2_EN 0x0200
#define MV88E6XXX_G1_CTL1_DEVICE_EN 0x0080
#define MV88E6XXX_G1_CTL1_STATS_DONE_EN 0x0040
#define MV88E6XXX_G1_CTL1_VTU_PROBLEM_EN 0x0020
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h
index 1f42ee656816..04696cb68971 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -38,9 +38,15 @@
/* Offset 0x02: MGMT Enable Register 2x */
#define MV88E6XXX_G2_MGMT_EN_2X 0x02

+/* Offset 0x02: MAC LINK change IRQ Register for MV88E6393X */
+#define MV88E6393X_G2_MACLINK_INT_SRC 0x02
+
/* Offset 0x03: MGMT Enable Register 0x */
#define MV88E6XXX_G2_MGMT_EN_0X 0x03

+/* Offset 0x03: MAC LINK change IRQ Mask Register for MV88E6393X */
+#define MV88E6393X_G2_MACLINK_INT_MASK 0x03
+
/* Offset 0x04: Flow Control Delay Register */
#define MV88E6XXX_G2_FLOW_CTL 0x04

@@ -52,6 +58,8 @@
#define MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI 0x0080
#define MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU 0x0008

+#define MV88E6393X_G2_EGRESS_MONITOR_DEST 0x05
+
/* Offset 0x06: Device Mapping Table Register */
#define MV88E6XXX_G2_DEVICE_MAPPING 0x06
#define MV88E6XXX_G2_DEVICE_MAPPING_UPDATE 0x8000
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 8128dc607cf4..081c26562275 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -14,6 +14,7 @@
#include <linux/phylink.h>

#include "chip.h"
+#include "global2.h"
#include "port.h"
#include "serdes.h"

@@ -390,6 +391,87 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
return PHY_INTERFACE_MODE_NA;
}

+/* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X) */
+int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
+ int speed, int duplex)
+{
+ u16 reg, ctrl;
+ int err;
+
+ if (speed == SPEED_MAX)
+ speed = (port > 0 && port < 9) ? 1000 : 10000;
+
+ if (speed == 200 && port != 0)
+ return -EOPNOTSUPP;
+
+ if (speed >= 2500 && port > 0 && port < 9)
+ return -EOPNOTSUPP;
+
+ switch (speed) {
+ case 10:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
+ break;
+ case 100:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
+ break;
+ case 200:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 1000:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
+ break;
+ case 2500:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 5000:
+ ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 10000:
+ case SPEED_UNFORCED:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ switch (duplex) {
+ case DUPLEX_HALF:
+ ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
+ break;
+ case DUPLEX_FULL:
+ ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
+ MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
+ break;
+ case DUPLEX_UNFORCED:
+ /* normal duplex detection */
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
+ if (err)
+ return err;
+
+ reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED |
+ MV88E6390_PORT_MAC_CTL_FORCE_SPEED);
+
+ if (speed != SPEED_UNFORCED)
+ reg |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
+
+ reg |= ctrl;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+ if (err)
+ return err;
+
+ return 0;
+}
+
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
@@ -505,6 +587,88 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
return mv88e6xxx_port_set_cmode(chip, port, mode, false);
}

+int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode)
+{
+ int lane;
+ u16 cmode;
+ u16 reg;
+ int err;
+
+ if (port != 0 && port != 9 && port != 10)
+ return -EOPNOTSUPP;
+
+ /* Default to a slow mode */
+ if (mode == PHY_INTERFACE_MODE_NA)
+ mode = PHY_INTERFACE_MODE_1000BASEX;
+
+ switch (mode) {
+ case PHY_INTERFACE_MODE_1000BASEX:
+ cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX;
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
+ break;
+ case PHY_INTERFACE_MODE_10GKR:
+ cmode = MV88E6XXX_PORT_STS_CMODE_10GBASER;
+ break;
+ default:
+ cmode = 0;
+ }
+
+ /* cmode doesn't change, nothing to do for us */
+ if (cmode == chip->ports[port].cmode)
+ return 0;
+
+ lane = mv88e6393x_serdes_get_lane(chip, port);
+ if (lane < 0 && lane != -ENODEV)
+ return lane;
+
+ if (lane >= 0) {
+ if (chip->ports[port].serdes_irq) {
+ err = mv88e6393x_serdes_irq_enable(chip, port, lane, false);
+ if (err)
+ return err;
+ }
+
+ err = mv88e6393x_serdes_power(chip, port, lane, false);
+ if (err)
+ return err;
+ }
+ chip->ports[port].cmode = 0;
+
+ if (cmode) {
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
+ if (err)
+ return err;
+
+ reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;
+ reg |= cmode;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
+ if (err)
+ return err;
+
+ chip->ports[port].cmode = cmode;
+
+ lane = mv88e6393x_serdes_get_lane(chip, port);
+ if (lane < 0)
+ return lane;
+
+ err = mv88e6393x_serdes_power(chip, port, lane, true);
+ if (err)
+ return err;
+
+ if (chip->ports[port].serdes_irq) {
+ err = mv88e6393x_serdes_irq_enable(chip, port, lane, true);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,
int port)
{
@@ -1128,6 +1292,144 @@ int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
}

+/* Offset 0x0E: Policy & MGMT Control Register for FAMILY 6191X 6193X 6393X*/
+
+static int mv88e6393x_port_policy_write(struct mv88e6xxx_chip *chip, u16 pointer,
+ u8 data)
+{
+ u16 reg;
+ int port;
+ int err = 0;
+
+ /* Setup per Port policy register */
+ for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
+ if (dsa_is_unused_port(chip->ds, port))
+ continue;
+
+ /* Prevent the use of an invalid port. */
+ if (mv88e6xxx_is_invalid_port(chip, port)) {
+ dev_err(chip->dev, "port %d is invalid\n", port);
+ err = -EINVAL;
+ }
+ reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL, reg);
+ }
+ return err;
+}
+
+int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
+ enum mv88e6xxx_egress_direction direction,
+ int port)
+{
+ u16 ptr;
+ int err;
+
+ switch (direction) {
+ case MV88E6XXX_EGRESS_DIR_INGRESS:
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST;
+ err = mv88e6393x_port_policy_write(chip, ptr, port);
+ if (err)
+ return err;
+ break;
+ case MV88E6XXX_EGRESS_DIR_EGRESS:
+ ptr = MV88E6393X_G2_EGRESS_MONITOR_DEST;
+ err = mv88e6xxx_g2_write(chip, ptr, port);
+ if (err)
+ return err;
+ break;
+ }
+ return 0;
+}
+
+int mv88e6393x_port_set_cpu_dest(struct mv88e6xxx_chip *chip, int port)
+{
+ u16 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST;
+ u8 data = MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI | port;
+
+ return mv88e6393x_port_policy_write(chip, ptr, data);
+}
+
+int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
+{
+ u16 ptr;
+ int err;
+
+ /* Consider the frames with reserved multicast destination
+ * addresses matching 01:80:c2:00:00:00 and
+ * 01:80:c2:00:00:02 as MGMT.
+ */
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* Offset 0x10 & 0x11: EPC */
+
+static int mv88e6393x_epc_wait_ready(struct mv88e6xxx_chip *chip, int port)
+{
+ const unsigned long timeout = jiffies + 1 * HZ;
+ u16 val;
+ int err;
+
+ while (time_before(jiffies, timeout)) {
+ err = mv88e6xxx_port_read(chip, port, MV88E6393X_PORT_EPC_CMD, &val);
+ if (err)
+ return err;
+ if (!(val & MV88E6393X_PORT_EPC_CMD_BUSY))
+ break;
+ usleep_range(1000, 2000);
+ }
+
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/* Port Ether type for 6393X family */
+
+int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
+ u16 etype)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6393x_epc_wait_ready(chip, port);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_DATA, etype);
+ if (err)
+ return err;
+
+ val = MV88E6393X_PORT_EPC_CMD_BUSY |
+ MV88E6393X_PORT_EPC_CMD_WRITE |
+ MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
+ if (err)
+ return err;
+
+ return 0;
+}
+
/* Offset 0x0f: Port Ether type */

int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index 44d76ac973f6..b3fb01b322e9 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -49,6 +49,9 @@
#define MV88E6XXX_PORT_STS_CMODE_2500BASEX 0x000b
#define MV88E6XXX_PORT_STS_CMODE_XAUI 0x000c
#define MV88E6XXX_PORT_STS_CMODE_RXAUI 0x000d
+#define MV88E6XXX_PORT_STS_CMODE_5GBASER 0x000c
+#define MV88E6XXX_PORT_STS_CMODE_10GBASER 0x000d
+#define MV88E6XXX_PORT_STS_CMODE_USXGMII 0x000e
#define MV88E6185_PORT_STS_CDUPLEX 0x0008
#define MV88E6185_PORT_STS_CMODE_MASK 0x0007
#define MV88E6185_PORT_STS_CMODE_GMII_FD 0x0000
@@ -117,6 +120,7 @@
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6176 0x1760
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6190 0x1900
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6191 0x1910
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6193X 0x1930
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6185 0x1a70
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6220 0x2200
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400
@@ -129,6 +133,7 @@
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6350 0x3710
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6351 0x3750
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6390 0x3900
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6393X 0x3930
#define MV88E6XXX_PORT_SWITCH_ID_REV_MASK 0x000f

/* Offset 0x04: Port Control Register */
@@ -236,6 +241,19 @@
#define MV88E6XXX_PORT_POLICY_CTL_TRAP 0x0002
#define MV88E6XXX_PORT_POLICY_CTL_DISCARD 0x0003

+/* Offset 0x0E: Policy & MGMT Control Register (FAMILY_6393X)*/
+#define MV88E6393X_PORT_POLICY_MGMT_CTL 0x0e
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE 0x8000
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_MASK 0x3f00
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO 0x2000
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI 0x2100
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO 0x2400
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI 0x2500
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST 0x3000
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST 0x3800
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_DATA_MASK 0x00ff
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI 0x00e0
+
/* Offset 0x0F: Port Special Ether Type */
#define MV88E6XXX_PORT_ETH_TYPE 0x0f
#define MV88E6XXX_PORT_ETH_TYPE_DEFAULT 0x9100
@@ -243,6 +261,15 @@
/* Offset 0x10: InDiscards Low Counter */
#define MV88E6XXX_PORT_IN_DISCARD_LO 0x10

+/* Offset 0x10: Extended Port Control Command */
+#define MV88E6393X_PORT_EPC_CMD 0x10
+#define MV88E6393X_PORT_EPC_CMD_BUSY 0x8000
+#define MV88E6393X_PORT_EPC_CMD_WRITE 0x0300
+#define MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE 0x02
+
+/* Offset 0x11: Extended Port Control Data */
+#define MV88E6393X_PORT_EPC_DATA 0x11
+
/* Offset 0x11: InDiscards High Counter */
#define MV88E6XXX_PORT_IN_DISCARD_HI 0x11

@@ -312,7 +339,8 @@ int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
int speed, int duplex);
int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
int speed, int duplex);
-
+int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
+ int speed, int duplex);
phy_interface_t mv88e6341_port_max_speed_mode(int port);
phy_interface_t mv88e6390_port_max_speed_mode(int port);
phy_interface_t mv88e6390x_port_max_speed_mode(int port);
@@ -346,6 +374,13 @@ int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,
enum mv88e6xxx_policy_action action);
int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
u16 etype);
+int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
+ enum mv88e6xxx_egress_direction direction,
+ int port);
+int mv88e6393x_port_set_cpu_dest(struct mv88e6xxx_chip *chip, int port);
+int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip);
+int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
+ u16 etype);
int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
bool message_port);
int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
@@ -362,6 +397,8 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode);
int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode);
+int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode);
int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 9c07b4f3d345..eb1241fdbaa6 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -526,6 +526,37 @@ u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}

+/* Return the SERDES lane address a port is using. Only Ports 0, 9 and 10
+ * have SERDES lanes. Returns -ENODEV if a port does not have a lane.
+ */
+u8 mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+{
+ u8 cmode = chip->ports[port].cmode;
+
+ switch (port) {
+ case 0:
+ if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_10GBASER)
+ return MV88E6393X_PORT0_LANE;
+ return ENODEV;
+ case 9:
+ if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_10GBASER)
+ return MV88E6393X_PORT9_LANE;
+ return ENODEV;
+ case 10:
+ if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_10GBASER)
+ return MV88E6393X_PORT10_LANE;
+ return ENODEV;
+ default:
+ return ENODEV;
+ }
+}
+
/* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
bool up)
@@ -916,6 +947,51 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
return err;
}

+int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
+ u8 lane, bool enable)
+{
+ u8 cmode = chip->ports[port].cmode;
+ int err = 0;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_SGMII:
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_5GBASER:
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ err = mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
+ }
+
+ return err;
+}
+
+irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
+ u8 lane)
+{
+ u8 cmode = chip->ports[port].cmode;
+ irqreturn_t ret = IRQ_NONE;
+ u16 status;
+ int err;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_SGMII:
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_5GBASER:
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
+ if (err)
+ return ret;
+ if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
+ MV88E6390_SGMII_INT_LINK_UP)) {
+ ret = IRQ_HANDLED;
+ mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
+ }
+ }
+
+ return ret;
+}
+
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
u8 lane)
{
@@ -999,3 +1075,166 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
p[i] = reg;
}
}
+
+int mv88e6393x_setup_errata(struct mv88e6xxx_chip *chip)
+{
+ u16 config0, config9, config10;
+ u16 pcs0, pcs9, pcs10;
+ int err = 0;
+
+ /* mv88e6393x family errata 3.8 :
+ * When a SERDES port is operating in 1000BASE-X or SGMII mode link may not
+ * come up after hardware reset or software reset of SERDES core.
+ * Workaround is to write SERDES register 4.F074.14 =1 for only those modes
+ * and 0 in all other modes.
+ */
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT0_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII, &config0);
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT9_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII, &config9);
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT10_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII, &config10);
+
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT0_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &pcs0);
+ pcs0 &= MV88E6393X_SERDES_POC_PCS_MODE_MASK;
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT9_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &pcs9);
+ pcs9 &= MV88E6393X_SERDES_POC_PCS_MODE_MASK;
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT10_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &pcs10);
+ pcs10 &= MV88E6393X_SERDES_POC_PCS_MODE_MASK;
+
+ if (pcs0 == MV88E6393X_PCS_SELECT_1000BASEX ||
+ pcs0 == MV88E6393X_PCS_SELECT_SGMII_PHY ||
+ pcs0 == MV88E6393X_PCS_SELECT_SGMII_MAC) {
+ config0 |= MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT0_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config0);
+ } else {
+ config0 &= ~MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT0_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config0);
+ }
+
+ if (pcs9 == MV88E6393X_PCS_SELECT_1000BASEX ||
+ pcs9 == MV88E6393X_PCS_SELECT_SGMII_PHY ||
+ pcs9 == MV88E6393X_PCS_SELECT_SGMII_MAC) {
+ config9 |= MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT9_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config9);
+ } else {
+ config9 &= ~MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT9_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config9);
+ }
+
+ if (pcs10 == MV88E6393X_PCS_SELECT_1000BASEX ||
+ pcs10 == MV88E6393X_PCS_SELECT_SGMII_PHY ||
+ pcs10 == MV88E6393X_PCS_SELECT_SGMII_MAC) {
+ config10 |= MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT10_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config10);
+ } else {
+ config10 &= ~MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT10_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config10);
+ }
+ return err;
+}
+
+static int mv88e6393x_serdes_port_config(struct mv88e6xxx_chip *chip, int lane,
+ bool on)
+{
+ u16 config, pcs;
+ u8 cmode = chip->ports[lane].cmode;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ pcs = MV88E6393X_PCS_SELECT_1000BASEX;
+ break;
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ pcs = MV88E6393X_PCS_SELECT_2500BASEX;
+ break;
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ pcs = MV88E6393X_PCS_SELECT_10GBASER;
+ break;
+ default:
+ pcs = MV88E6393X_PCS_SELECT_1000BASEX;
+ break;
+ }
+
+ if (on) {
+ /* mv88e6393x family errata 3.6 :
+ * When changing c_mode on Port 0 from [x]MII mode to any
+ * SERDES mode SERDES will not be operational.
+ * Workaround: Set Port0 SERDES register 4.F002.5=0
+ */
+ mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &config);
+ config &= ~(MV88E6393X_SERDES_POC_PCS_MODE_MASK |
+ MV88E6393X_SERDES_POC_PDOWN);
+ config |= pcs;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, config);
+ config |= MV88E6393X_SERDES_POC_RESET;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, config);
+
+ /* mv88e6393x family errata 3.7 :
+ * When changing cmode on SERDES port from any other mode to
+ * 1000BASE-X mode the link may not come up due to invalid
+ * 1000BASE-X advertisement.
+ * Workaround: Correct advertisement and reset PHY core.
+ */
+ config = MV88E6390_SGMII_ANAR_1000BASEX_FD;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_ANAR, config);
+
+ /* soft reset the PCS/PMA */
+ mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_CONTROL, &config);
+ config |= MV88E6390_SGMII_CONTROL_RESET;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_CONTROL, config);
+ }
+
+ return 0;
+}
+
+int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+ bool on)
+{
+ lane = mv88e6393x_serdes_get_lane(chip, port);
+ if (lane == ENODEV)
+ return -ENODEV;
+
+ if (port == 0 || port == 9 || port == 10) {
+ u8 cmode = chip->ports[port].cmode;
+
+ mv88e6393x_serdes_port_config(chip, lane, on);
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ return mv88e6390_serdes_power_sgmii(chip, lane, on);
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ return mv88e6390_serdes_power_10g(chip, lane, on);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index 14315f26228a..c3eaaaac8619 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -68,15 +68,47 @@
#define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10)
#define MV88E6390_SGMII_PHY_STATUS_TX_PAUSE BIT(3)
#define MV88E6390_SGMII_PHY_STATUS_RX_PAUSE BIT(2)
+#define MV88E6390_SGMII_STATUS_AN_ABLE BIT(3)
+#define MV88E6390_SGMII_ANAR 0x2004
+#define MV88E6390_SGMII_ANAR_1000BASEX_FD BIT(5)
+#define MV88E6390_SGMII_CONTROL 0x2000
+#define MV88E6390_SGMII_CONTROL_RESET BIT(15)
+#define MV88E6390_SGMII_CONTROL_LOOPBACK BIT(14)
+#define MV88E6390_SGMII_CONTROL_PDOWN BIT(11)
+#define MV88E6390_SGMII_STATUS 0x2001

/* Packet generator pad packet checker */
#define MV88E6390_PG_CONTROL 0xf010
#define MV88E6390_PG_CONTROL_ENABLE_PC BIT(0)

+#define MV88E6393X_PORT0_LANE 0x00
+#define MV88E6393X_PORT9_LANE 0x09
+#define MV88E6393X_PORT10_LANE 0x0a
+
+/* Port Operational Configuration */
+#define MV88E6393X_PCS_SELECT_1000BASEX 0x0000
+#define MV88E6393X_PCS_SELECT_2500BASEX 0x0001
+#define MV88E6393X_PCS_SELECT_SGMII_PHY 0x0002
+#define MV88E6393X_PCS_SELECT_SGMII_MAC 0x0003
+#define MV88E6393X_PCS_SELECT_5GBASER 0x0004
+#define MV88E6393X_PCS_SELECT_10GBASER 0x0005
+#define MV88E6393X_PCS_SELECT_USXGMII_PHY 0x0006
+#define MV88E6393X_PCS_SELECT_USXGMII_MAC 0x0007
+
+#define MV88E6393X_SERDES_POC 0xf002
+#define MV88E6393X_SERDES_POC_PCS_MODE_MASK 0x0007
+#define MV88E6393X_SERDES_POC_RESET BIT(15)
+#define MV88E6393X_SERDES_POC_PDOWN BIT(5)
+#define MV88E6393X_SERDES_POC_ANEG BIT(3)
+
+#define MV88E6393X_ERRATA_1000BASEX_SGMII 0xF074
+#define MV88E6393X_ERRATA_1000BASEX_SGMII_BIT BIT(14)
+
u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+u8 mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
u8 lane, unsigned int mode,
phy_interface_t interface,
@@ -105,14 +137,21 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
bool on);
+int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+ bool on);
+int mv88e6393x_setup_errata(struct mv88e6xxx_chip *chip);
int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
bool enable);
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
bool enable);
+int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
+ u8 lane, bool enable);
irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
u8 lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
u8 lane);
+irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
+ u8 lane);
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
int port, uint8_t *data);
--
2.17.1


2020-10-16 04:00:49

by Florian Fainelli

[permalink] [raw]
Subject: Re: [PATCH v3] Add support for mv88e6393x family of Marvell.



On 10/15/2020 7:09 PM, Pavana Sharma wrote:
> The Marvell 88E6393X device is a single-chip integration of a 11-port
> Ethernet switch with eight integrated Gigabit Ethernet (GbE) transceivers
> and three 10-Gigabit interfaces.
>
> This patch adds functionalities specific to mv88e6393x family (88E6393X,
> 88E6193X and 88E6191X)
>
> Signed-off-by: Pavana Sharma <[email protected]>

The subject of your patch should be:

net: dsa: mv88e6xxx: Add support for mv88e6393x family

to be consistent with the previous changes done to these files. I don't
have the datasheet for that switch so cannot confirm if the changes
appear to be correct or not, Vivien and Andrew might though.
--
Florian

2020-10-17 19:37:51

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH v3] Add support for mv88e6393x family of Marvell.

> +static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
> + unsigned long *mask,
> + struct phylink_link_state *state)
> +{
> + if (port == 0 || port >= 9) {
> + phylink_set(mask, 10000baseT_Full);
> + phylink_set(mask, 10000baseKR_Full);
> + phylink_set(mask, 2500baseX_Full);
> + phylink_set(mask, 2500baseT_Full);
> + }
> +
> + phylink_set(mask, 1000baseT_Full);
> + phylink_set(mask, 1000baseX_Full);
> +
> + mv88e6065_phylink_validate(chip, port, mask, state);
> +}
> +
> static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
> unsigned long *supported,
> struct phylink_link_state *state)
> @@ -4141,6 +4158,56 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
> .phylink_validate = mv88e6390_phylink_validate,
> };
>
> +static const struct mv88e6xxx_ops mv88e6193x_ops = {
> + /* MV88E6XXX_FAMILY_6393X */

Please add support for the 6393X and the 6391X. Most of the
differences are in mv88e6X93x_phylink_validate() functions, given the
different number of multiG ports. Just a best effort, since i guess
you do not have the hardware to test on.

> diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
> index 823ae89e5fca..407d683c0fcf 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.h
> +++ b/drivers/net/dsa/mv88e6xxx/chip.h
> @@ -63,6 +63,7 @@ enum mv88e6xxx_model {
> MV88E6190,
> MV88E6190X,
> MV88E6191,
> + MV88E6193X,
> MV88E6220,
> MV88E6240,
> MV88E6250,
> @@ -90,6 +91,7 @@ enum mv88e6xxx_family {
> MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
> MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */
> MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */
> + MV88E6XXX_FAMILY_6393X, /* 6191X 6193X 6393X */
> };

Are there any 6393 devices, i.e. not X? I just wondering if we want to
call the family plain 6393? In general, it would be nicer to use the
name 6393, not 6393X.

> +int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
> + phy_interface_t mode)
> +{
> + if (lane >= 0) {
> + if (chip->ports[port].serdes_irq) {
> + err = mv88e6393x_serdes_irq_enable(chip, port, lane, false);
> + if (err)
> + return err;
> + }
> +
> + err = mv88e6393x_serdes_power(chip, port, lane, false);
> + if (err)
> + return err;
> + }

Something wrong with the indentation here.

Please can you also look at trying to refactor
mv88e6xxx_port_set_cmode() so you don't have to duplicate so much.

> +/* Offset 0x0E: Policy & MGMT Control Register for FAMILY 6191X 6193X 6393X*/
> +
> +static int mv88e6393x_port_policy_write(struct mv88e6xxx_chip *chip, u16 pointer,
> + u8 data)
> +{
> + u16 reg;
> + int port;
> + int err = 0;

Reverse Christmas tree please, here and everywhere.

> +static int mv88e6393x_epc_wait_ready(struct mv88e6xxx_chip *chip, int port)
> +{
> + const unsigned long timeout = jiffies + 1 * HZ;
> + u16 val;
> + int err;
> +
> + while (time_before(jiffies, timeout)) {
> + err = mv88e6xxx_port_read(chip, port, MV88E6393X_PORT_EPC_CMD, &val);
> + if (err)
> + return err;
> + if (!(val & MV88E6393X_PORT_EPC_CMD_BUSY))
> + break;
> + usleep_range(1000, 2000);
> + }
> +
> + if (time_after(jiffies, timeout))
> + return -ETIMEDOUT;
> +
> + return 0;
> +}

Please build something on top of mv88e6xxx_wait_bit(). Look at
global1.c as an example for its _wait_ functions.

> +/* Return the SERDES lane address a port is using. Only Ports 0, 9 and 10
> + * have SERDES lanes. Returns -ENODEV if a port does not have a lane.
> + */
> +u8 mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
> +{
> + u8 cmode = chip->ports[port].cmode;
> +
> + switch (port) {
> + case 0:
> + if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
> + cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
> + cmode == MV88E6XXX_PORT_STS_CMODE_10GBASER)
> + return MV88E6393X_PORT0_LANE;
> + return ENODEV;

Missing the - in -ENODEV.

> + case 9:
> + if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
> + cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
> + cmode == MV88E6XXX_PORT_STS_CMODE_10GBASER)
> + return MV88E6393X_PORT9_LANE;
> + return ENODEV;
> + case 10:
> + if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
> + cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
> + cmode == MV88E6XXX_PORT_STS_CMODE_10GBASER)
> + return MV88E6393X_PORT10_LANE;
> + return ENODEV;
> + default:
> + return ENODEV;
> + }
> +}
> +

Andrew

2020-10-26 06:57:18

by Pavana Sharma

[permalink] [raw]
Subject: [PATCH v4 0/3] Add support for mv88e6393x family of Marvell.

Hi,

Thanks for the review.
Following is the updated patchset.

The 6393X family has MV88E6191X, MV88E6193X and MV88E6393X products listed in
Gigabit Ethernet and Gigabit 10G+ Ethernet categories. There are no 6393 devices
(without X) but there is 6191 device (without X)from a different family.
The product id is listed with the 'X' in the name so I prefer to retain the
product name 6393X in the driver whereas we can define the family name as
'MV88E6XXX_FAMILY_6393' without 'X'.

The patchset adds support for modes 5GBASE-R, 10GBASE-R and USXGMII on
ports 0, 9 and 10.

Tested on MV88E6193X device.

Pavana

Pavana Sharma (3):
Add support for mv88e6393x family of Marvell.
Add phy interface for 5GBASER mode
Change serdes lane parameter from u8 type to int.

drivers/net/dsa/mv88e6xxx/chip.c | 119 +++++++++--
drivers/net/dsa/mv88e6xxx/chip.h | 20 +-
drivers/net/dsa/mv88e6xxx/global1.h | 2 +
drivers/net/dsa/mv88e6xxx/global2.h | 8 +
drivers/net/dsa/mv88e6xxx/port.c | 239 +++++++++++++++++++++-
drivers/net/dsa/mv88e6xxx/port.h | 40 +++-
drivers/net/dsa/mv88e6xxx/serdes.c | 297 ++++++++++++++++++++++++----
drivers/net/dsa/mv88e6xxx/serdes.h | 89 ++++++---
include/linux/phy.h | 3 +
9 files changed, 730 insertions(+), 87 deletions(-)

--
2.17.1

2020-10-26 06:57:30

by Pavana Sharma

[permalink] [raw]
Subject: [PATCH v4 1/3] Add support for mv88e6393x family of Marvell.

The Marvell 88E6393X device is a single-chip integration of a 11-port
Ethernet switch with eight integrated Gigabit Ethernet (GbE) transceivers
and three 10-Gigabit interfaces.

This patch adds functionalities specific to mv88e6393x family (88E6393X,
88E6193X and 88E6191X)

Signed-off-by: Pavana Sharma <[email protected]>
---
Changes in v2:
- Fix a warning (Reported-by: kernel test robot <[email protected]>)
Changes in v3:
- Fix 'unused function' warning
Changes in v4:
- Incorporated feedback from maintainers.
---
drivers/net/dsa/mv88e6xxx/chip.c | 91 +++++++++++
drivers/net/dsa/mv88e6xxx/chip.h | 4 +
drivers/net/dsa/mv88e6xxx/global1.h | 2 +
drivers/net/dsa/mv88e6xxx/global2.h | 8 +
drivers/net/dsa/mv88e6xxx/port.c | 233 ++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 40 ++++-
drivers/net/dsa/mv88e6xxx/serdes.c | 227 +++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/serdes.h | 39 +++++
8 files changed, 643 insertions(+), 1 deletion(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index f0dbc05e30a4..de96fd08e77a 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -634,6 +634,24 @@ static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
mv88e6390_phylink_validate(chip, port, mask, state);
}

+static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
+ unsigned long *mask,
+ struct phylink_link_state *state)
+{
+ if (port == 0 || port == 9 || port == 10) {
+ phylink_set(mask, 10000baseT_Full);
+ phylink_set(mask, 10000baseKR_Full);
+ phylink_set(mask, 5000baseT_Full);
+ phylink_set(mask, 2500baseX_Full);
+ phylink_set(mask, 2500baseT_Full);
+ }
+
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseX_Full);
+
+ mv88e6065_phylink_validate(chip, port, mask, state);
+}
+
static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
unsigned long *supported,
struct phylink_link_state *state)
@@ -4141,6 +4159,56 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.phylink_validate = mv88e6390_phylink_validate,
};

+static const struct mv88e6xxx_ops mv88e6193x_ops = {
+ /* MV88E6XXX_FAMILY_6393 */
+ .setup_errata = mv88e6393x_setup_errata,
+ .irl_init_all = mv88e6390_g2_irl_init_all,
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_floods = mv88e6352_port_set_egress_floods,
+ .port_set_ether_type = mv88e6393x_port_set_ether_type,
+ .port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
+ .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
+ .port_pause_limit = mv88e6390_port_pause_limit,
+ .port_set_cmode = mv88e6393x_port_set_cmode,
+ .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+ .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+ .port_get_cmode = mv88e6352_port_get_cmode,
+ .stats_snapshot = mv88e6390_g1_stats_snapshot,
+ .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
+ .stats_get_sset_count = mv88e6320_stats_get_sset_count,
+ .stats_get_strings = mv88e6320_stats_get_strings,
+ .stats_get_stats = mv88e6390_stats_get_stats,
+ .set_cpu_port = mv88e6393x_port_set_cpu_dest,
+ .set_egress_port = mv88e6393x_set_egress_port,
+ .watchdog_ops = &mv88e6390_watchdog_ops,
+ .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
+ .pot_clear = mv88e6xxx_g2_pot_clear,
+ .reset = mv88e6352_g1_reset,
+ .rmu_disable = mv88e6390_g1_rmu_disable,
+ .vtu_getnext = mv88e6390_g1_vtu_getnext,
+ .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
+ .serdes_power = mv88e6393x_serdes_power,
+ .serdes_get_lane = mv88e6393x_serdes_get_lane,
+ /* Check status register pause & lpa register */
+ .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
+ .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
+ .serdes_irq_enable = mv88e6393x_serdes_irq_enable,
+ .serdes_irq_status = mv88e6393x_serdes_irq_status,
+ .gpio_ops = &mv88e6352_gpio_ops,
+ .avb_ops = &mv88e6390_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
+ .phylink_validate = mv88e6393x_phylink_validate,
+};
+
static const struct mv88e6xxx_ops mv88e6240_ops = {
/* MV88E6XXX_FAMILY_6352 */
.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
@@ -5073,6 +5141,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6191_ops,
},

+ [MV88E6193X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6193X",
+ .num_databases = 4096,
+ .num_ports = 11, /* 10 + Z80 */
+ .num_internal_phys = 9,
+ .max_vid = 8191,
+ .port_base_addr = 0x0,
+ .phy_base_addr = 0x0,
+ .global1_addr = 0x1b,
+ .global2_addr = 0x1c,
+ .age_time_coeff = 3750,
+ .g1_irqs = 10,
+ .g2_irqs = 14,
+ .atu_move_port_mask = 0x1f,
+ .pvt = true,
+ .multi_chip = true,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
+ .ptp_support = true,
+ .ops = &mv88e6193x_ops,
+ },
+
[MV88E6220] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
.family = MV88E6XXX_FAMILY_6250,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 823ae89e5fca..b7864a24a840 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -63,6 +63,8 @@ enum mv88e6xxx_model {
MV88E6190,
MV88E6190X,
MV88E6191,
+ MV88E6191X,
+ MV88E6193X,
MV88E6220,
MV88E6240,
MV88E6250,
@@ -75,6 +77,7 @@ enum mv88e6xxx_model {
MV88E6352,
MV88E6390,
MV88E6390X,
+ MV88E6393X,
};

enum mv88e6xxx_family {
@@ -90,6 +93,7 @@ enum mv88e6xxx_family {
MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */
MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */
+ MV88E6XXX_FAMILY_6393, /* 6191X 6193X 6393X */
};

struct mv88e6xxx_ops;
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 1e3546f8b072..bd17eed15aad 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -22,6 +22,7 @@
#define MV88E6185_G1_STS_PPU_STATE_DISABLED 0x8000
#define MV88E6185_G1_STS_PPU_STATE_POLLING 0xc000
#define MV88E6XXX_G1_STS_INIT_READY 0x0800
+#define MV88E6193X_G1_STS_IRQ_DEVICE_2 9
#define MV88E6XXX_G1_STS_IRQ_AVB 8
#define MV88E6XXX_G1_STS_IRQ_DEVICE 7
#define MV88E6XXX_G1_STS_IRQ_STATS 6
@@ -59,6 +60,7 @@
#define MV88E6185_G1_CTL1_SCHED_PRIO 0x0800
#define MV88E6185_G1_CTL1_MAX_FRAME_1632 0x0400
#define MV88E6185_G1_CTL1_RELOAD_EEPROM 0x0200
+#define MV88E6193X_G1_CTL1_DEVICE2_EN 0x0200
#define MV88E6XXX_G1_CTL1_DEVICE_EN 0x0080
#define MV88E6XXX_G1_CTL1_STATS_DONE_EN 0x0040
#define MV88E6XXX_G1_CTL1_VTU_PROBLEM_EN 0x0020
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h
index 1f42ee656816..04696cb68971 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -38,9 +38,15 @@
/* Offset 0x02: MGMT Enable Register 2x */
#define MV88E6XXX_G2_MGMT_EN_2X 0x02

+/* Offset 0x02: MAC LINK change IRQ Register for MV88E6393X */
+#define MV88E6393X_G2_MACLINK_INT_SRC 0x02
+
/* Offset 0x03: MGMT Enable Register 0x */
#define MV88E6XXX_G2_MGMT_EN_0X 0x03

+/* Offset 0x03: MAC LINK change IRQ Mask Register for MV88E6393X */
+#define MV88E6393X_G2_MACLINK_INT_MASK 0x03
+
/* Offset 0x04: Flow Control Delay Register */
#define MV88E6XXX_G2_FLOW_CTL 0x04

@@ -52,6 +58,8 @@
#define MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI 0x0080
#define MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU 0x0008

+#define MV88E6393X_G2_EGRESS_MONITOR_DEST 0x05
+
/* Offset 0x06: Device Mapping Table Register */
#define MV88E6XXX_G2_DEVICE_MAPPING 0x06
#define MV88E6XXX_G2_DEVICE_MAPPING_UPDATE 0x8000
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 8128dc607cf4..4089bfd4e8f4 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -14,6 +14,7 @@
#include <linux/phylink.h>

#include "chip.h"
+#include "global2.h"
#include "port.h"
#include "serdes.h"

@@ -25,6 +26,13 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
return mv88e6xxx_read(chip, addr, reg, val);
}

+int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
+ int bit, int val)
+{
+ int addr = chip->info->port_base_addr + port;
+ return mv88e6xxx_wait_bit(chip, addr, reg, bit, val);
+}
+
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
u16 val)
{
@@ -390,6 +398,87 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
return PHY_INTERFACE_MODE_NA;
}

+/* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X) */
+int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
+ int speed, int duplex)
+{
+ u16 reg, ctrl;
+ int err;
+
+ if (speed == SPEED_MAX)
+ speed = (port > 0 && port < 9) ? 1000 : 10000;
+
+ if (speed == 200 && port != 0)
+ return -EOPNOTSUPP;
+
+ if (speed >= 2500 && port > 0 && port < 9)
+ return -EOPNOTSUPP;
+
+ switch (speed) {
+ case 10:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
+ break;
+ case 100:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
+ break;
+ case 200:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 1000:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
+ break;
+ case 2500:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 5000:
+ ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 10000:
+ case SPEED_UNFORCED:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ switch (duplex) {
+ case DUPLEX_HALF:
+ ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
+ break;
+ case DUPLEX_FULL:
+ ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
+ MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
+ break;
+ case DUPLEX_UNFORCED:
+ /* normal duplex detection */
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
+ if (err)
+ return err;
+
+ reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED |
+ MV88E6390_PORT_MAC_CTL_FORCE_SPEED);
+
+ if (speed != SPEED_UNFORCED)
+ reg |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
+
+ reg |= ctrl;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+ if (err)
+ return err;
+
+ return 0;
+}
+
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
@@ -421,6 +510,16 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
case PHY_INTERFACE_MODE_RXAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
break;
+ case PHY_INTERFACE_MODE_5GBASER:
+ cmode = MV88E6XXX_PORT_STS_CMODE_5GBASER;
+ break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_10GKR:
+ cmode = MV88E6XXX_PORT_STS_CMODE_10GBASER;
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ cmode = MV88E6XXX_PORT_STS_CMODE_USXGMII;
+ break;
default:
cmode = 0;
}
@@ -505,6 +604,15 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
return mv88e6xxx_port_set_cmode(chip, port, mode, false);
}

+int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode)
+{
+ if (port != 0 && port != 9 && port != 10)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_cmode(chip, port, mode, false);
+}
+
static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,
int port)
{
@@ -1128,6 +1236,131 @@ int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
}

+/* Offset 0x0E: Policy & MGMT Control Register for FAMILY 6191X 6193X 6393X*/
+
+static int mv88e6393x_port_policy_write(struct mv88e6xxx_chip *chip, u16 pointer,
+ u8 data)
+{
+
+ int err = 0;
+ int port;
+ u16 reg;
+
+ /* Setup per Port policy register */
+ for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
+ if (dsa_is_unused_port(chip->ds, port))
+ continue;
+
+ /* Prevent the use of an invalid port. */
+ if (mv88e6xxx_is_invalid_port(chip, port)) {
+ dev_err(chip->dev, "port %d is invalid\n", port);
+ err = -EINVAL;
+ }
+ reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL, reg);
+ }
+ return err;
+}
+
+int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
+ enum mv88e6xxx_egress_direction direction,
+ int port)
+{
+ u16 ptr;
+ int err;
+
+ switch (direction) {
+ case MV88E6XXX_EGRESS_DIR_INGRESS:
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST;
+ err = mv88e6393x_port_policy_write(chip, ptr, port);
+ if (err)
+ return err;
+ break;
+ case MV88E6XXX_EGRESS_DIR_EGRESS:
+ ptr = MV88E6393X_G2_EGRESS_MONITOR_DEST;
+ err = mv88e6xxx_g2_write(chip, ptr, port);
+ if (err)
+ return err;
+ break;
+ }
+ return 0;
+}
+
+int mv88e6393x_port_set_cpu_dest(struct mv88e6xxx_chip *chip, int port)
+{
+ u16 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST;
+ u8 data = MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI | port;
+
+ return mv88e6393x_port_policy_write(chip, ptr, data);
+}
+
+int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
+{
+ u16 ptr;
+ int err;
+
+ /* Consider the frames with reserved multicast destination
+ * addresses matching 01:80:c2:00:00:00 and
+ * 01:80:c2:00:00:02 as MGMT.
+ */
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* Offset 0x10 & 0x11: EPC */
+
+static int mv88e6393x_epc_wait_ready(struct mv88e6xxx_chip *chip, int port)
+{
+ int bit = __bf_shf(MV88E6393X_PORT_EPC_CMD_BUSY);
+
+ return mv88e6xxx_port_wait_bit(chip, port, MV88E6393X_PORT_EPC_CMD, bit, 0);
+}
+
+/* Port Ether type for 6393X family */
+
+int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
+ u16 etype)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6393x_epc_wait_ready(chip, port);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_DATA, etype);
+ if (err)
+ return err;
+
+ val = MV88E6393X_PORT_EPC_CMD_BUSY |
+ MV88E6393X_PORT_EPC_CMD_WRITE |
+ MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
+ if (err)
+ return err;
+
+ return 0;
+}
+
/* Offset 0x0f: Port Ether type */

int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index 44d76ac973f6..3e4105637bb5 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -49,6 +49,9 @@
#define MV88E6XXX_PORT_STS_CMODE_2500BASEX 0x000b
#define MV88E6XXX_PORT_STS_CMODE_XAUI 0x000c
#define MV88E6XXX_PORT_STS_CMODE_RXAUI 0x000d
+#define MV88E6XXX_PORT_STS_CMODE_5GBASER 0x000c
+#define MV88E6XXX_PORT_STS_CMODE_10GBASER 0x000d
+#define MV88E6XXX_PORT_STS_CMODE_USXGMII 0x000e
#define MV88E6185_PORT_STS_CDUPLEX 0x0008
#define MV88E6185_PORT_STS_CMODE_MASK 0x0007
#define MV88E6185_PORT_STS_CMODE_GMII_FD 0x0000
@@ -117,6 +120,8 @@
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6176 0x1760
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6190 0x1900
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6191 0x1910
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6191X 0x1920
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6193X 0x1930
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6185 0x1a70
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6220 0x2200
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400
@@ -129,6 +134,7 @@
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6350 0x3710
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6351 0x3750
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6390 0x3900
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6393X 0x3930
#define MV88E6XXX_PORT_SWITCH_ID_REV_MASK 0x000f

/* Offset 0x04: Port Control Register */
@@ -236,6 +242,19 @@
#define MV88E6XXX_PORT_POLICY_CTL_TRAP 0x0002
#define MV88E6XXX_PORT_POLICY_CTL_DISCARD 0x0003

+/* Offset 0x0E: Policy & MGMT Control Register (FAMILY_6393X)*/
+#define MV88E6393X_PORT_POLICY_MGMT_CTL 0x0e
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE 0x8000
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_MASK 0x3f00
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO 0x2000
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI 0x2100
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO 0x2400
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI 0x2500
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST 0x3000
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST 0x3800
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_DATA_MASK 0x00ff
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI 0x00e0
+
/* Offset 0x0F: Port Special Ether Type */
#define MV88E6XXX_PORT_ETH_TYPE 0x0f
#define MV88E6XXX_PORT_ETH_TYPE_DEFAULT 0x9100
@@ -243,6 +262,15 @@
/* Offset 0x10: InDiscards Low Counter */
#define MV88E6XXX_PORT_IN_DISCARD_LO 0x10

+/* Offset 0x10: Extended Port Control Command */
+#define MV88E6393X_PORT_EPC_CMD 0x10
+#define MV88E6393X_PORT_EPC_CMD_BUSY 0x8000
+#define MV88E6393X_PORT_EPC_CMD_WRITE 0x0300
+#define MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE 0x02
+
+/* Offset 0x11: Extended Port Control Data */
+#define MV88E6393X_PORT_EPC_DATA 0x11
+
/* Offset 0x11: InDiscards High Counter */
#define MV88E6XXX_PORT_IN_DISCARD_HI 0x11

@@ -312,7 +340,8 @@ int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
int speed, int duplex);
int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
int speed, int duplex);
-
+int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
+ int speed, int duplex);
phy_interface_t mv88e6341_port_max_speed_mode(int port);
phy_interface_t mv88e6390_port_max_speed_mode(int port);
phy_interface_t mv88e6390x_port_max_speed_mode(int port);
@@ -346,6 +375,13 @@ int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,
enum mv88e6xxx_policy_action action);
int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
u16 etype);
+int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
+ enum mv88e6xxx_egress_direction direction,
+ int port);
+int mv88e6393x_port_set_cpu_dest(struct mv88e6xxx_chip *chip, int port);
+int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip);
+int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
+ u16 etype);
int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
bool message_port);
int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
@@ -362,6 +398,8 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode);
int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode);
+int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode);
int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 9c07b4f3d345..d0bdbd8ae055 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -526,6 +526,27 @@ u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}

+/* Only Ports 0, 9 and 10 have SERDES lanes. Return the SERDES lane address
+ * a port is using else Returns -ENODEV.
+ */
+int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+{
+ u8 cmode = chip->ports[port].cmode;
+ int lane = -ENODEV;
+
+ if (port == 0 || port == 9 || port == 10) {
+ if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_5GBASER ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_10GBASER ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_USXGMII) {
+ lane = port;
+ }
+ }
+ return lane;
+}
+
/* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
bool up)
@@ -916,6 +937,51 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
return err;
}

+int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
+ u8 lane, bool enable)
+{
+ u8 cmode = chip->ports[port].cmode;
+ int err = 0;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_SGMII:
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_5GBASER:
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ err = mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
+ }
+
+ return err;
+}
+
+irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
+ u8 lane)
+{
+ u8 cmode = chip->ports[port].cmode;
+ irqreturn_t ret = IRQ_NONE;
+ u16 status;
+ int err;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_SGMII:
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_5GBASER:
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
+ if (err)
+ return ret;
+ if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
+ MV88E6390_SGMII_INT_LINK_UP)) {
+ ret = IRQ_HANDLED;
+ mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
+ }
+ }
+
+ return ret;
+}
+
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
u8 lane)
{
@@ -999,3 +1065,164 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
p[i] = reg;
}
}
+
+int mv88e6393x_setup_errata(struct mv88e6xxx_chip *chip)
+{
+ u16 config0, config9, config10;
+ u16 pcs0, pcs9, pcs10;
+ int err = 0;
+
+ /* mv88e6393x family errata 3.8 :
+ * When a SERDES port is operating in 1000BASE-X or SGMII mode link may not
+ * come up after hardware reset or software reset of SERDES core.
+ * Workaround is to write SERDES register 4.F074.14 =1 for only those modes
+ * and 0 in all other modes.
+ */
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT0_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII, &config0);
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT9_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII, &config9);
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT10_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII, &config10);
+
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT0_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &pcs0);
+ pcs0 &= MV88E6393X_SERDES_POC_PCS_MODE_MASK;
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT9_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &pcs9);
+ pcs9 &= MV88E6393X_SERDES_POC_PCS_MODE_MASK;
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT10_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &pcs10);
+ pcs10 &= MV88E6393X_SERDES_POC_PCS_MODE_MASK;
+
+ if (pcs0 == MV88E6393X_PCS_SELECT_1000BASEX ||
+ pcs0 == MV88E6393X_PCS_SELECT_SGMII_PHY ||
+ pcs0 == MV88E6393X_PCS_SELECT_SGMII_MAC) {
+ config0 |= MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT0_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config0);
+ } else {
+ config0 &= ~MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT0_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config0);
+ }
+
+ if (pcs9 == MV88E6393X_PCS_SELECT_1000BASEX ||
+ pcs9 == MV88E6393X_PCS_SELECT_SGMII_PHY ||
+ pcs9 == MV88E6393X_PCS_SELECT_SGMII_MAC) {
+ config9 |= MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT9_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config9);
+ } else {
+ config9 &= ~MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT9_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config9);
+ }
+
+ if (pcs10 == MV88E6393X_PCS_SELECT_1000BASEX ||
+ pcs10 == MV88E6393X_PCS_SELECT_SGMII_PHY ||
+ pcs10 == MV88E6393X_PCS_SELECT_SGMII_MAC) {
+ config10 |= MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT10_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config10);
+ } else {
+ config10 &= ~MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT10_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config10);
+ }
+ return err;
+}
+
+static int mv88e6393x_serdes_port_config(struct mv88e6xxx_chip *chip, int lane,
+ bool on)
+{
+ u8 cmode = chip->ports[lane].cmode;
+ u16 config, pcs;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ pcs = MV88E6393X_PCS_SELECT_1000BASEX;
+ break;
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ pcs = MV88E6393X_PCS_SELECT_2500BASEX;
+ break;
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ pcs = MV88E6393X_PCS_SELECT_10GBASER;
+ break;
+ default:
+ pcs = MV88E6393X_PCS_SELECT_1000BASEX;
+ break;
+ }
+
+ if (on) {
+ /* mv88e6393x family errata 3.6 :
+ * When changing c_mode on Port 0 from [x]MII mode to any
+ * SERDES mode SERDES will not be operational.
+ * Workaround: Set Port0 SERDES register 4.F002.5=0
+ */
+ mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &config);
+ config &= ~(MV88E6393X_SERDES_POC_PCS_MODE_MASK |
+ MV88E6393X_SERDES_POC_PDOWN);
+ config |= pcs;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, config);
+ config |= MV88E6393X_SERDES_POC_RESET;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, config);
+
+ /* mv88e6393x family errata 3.7 :
+ * When changing cmode on SERDES port from any other mode to
+ * 1000BASE-X mode the link may not come up due to invalid
+ * 1000BASE-X advertisement.
+ * Workaround: Correct advertisement and reset PHY core.
+ */
+ config = MV88E6390_SGMII_ANAR_1000BASEX_FD;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_ANAR, config);
+
+ /* soft reset the PCS/PMA */
+ mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_CONTROL, &config);
+ config |= MV88E6390_SGMII_CONTROL_RESET;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_CONTROL, config);
+ }
+
+ return 0;
+}
+
+int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+ bool on)
+{
+ lane = mv88e6393x_serdes_get_lane(chip, port);
+
+ if (port == 0 || port == 9 || port == 10) {
+ u8 cmode = chip->ports[port].cmode;
+
+ mv88e6393x_serdes_port_config(chip, lane, on);
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ return mv88e6390_serdes_power_sgmii(chip, lane, on);
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ return mv88e6390_serdes_power_10g(chip, lane, on);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index 14315f26228a..c3eaaaac8619 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -68,15 +68,47 @@
#define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10)
#define MV88E6390_SGMII_PHY_STATUS_TX_PAUSE BIT(3)
#define MV88E6390_SGMII_PHY_STATUS_RX_PAUSE BIT(2)
+#define MV88E6390_SGMII_STATUS_AN_ABLE BIT(3)
+#define MV88E6390_SGMII_ANAR 0x2004
+#define MV88E6390_SGMII_ANAR_1000BASEX_FD BIT(5)
+#define MV88E6390_SGMII_CONTROL 0x2000
+#define MV88E6390_SGMII_CONTROL_RESET BIT(15)
+#define MV88E6390_SGMII_CONTROL_LOOPBACK BIT(14)
+#define MV88E6390_SGMII_CONTROL_PDOWN BIT(11)
+#define MV88E6390_SGMII_STATUS 0x2001

/* Packet generator pad packet checker */
#define MV88E6390_PG_CONTROL 0xf010
#define MV88E6390_PG_CONTROL_ENABLE_PC BIT(0)

+#define MV88E6393X_PORT0_LANE 0x00
+#define MV88E6393X_PORT9_LANE 0x09
+#define MV88E6393X_PORT10_LANE 0x0a
+
+/* Port Operational Configuration */
+#define MV88E6393X_PCS_SELECT_1000BASEX 0x0000
+#define MV88E6393X_PCS_SELECT_2500BASEX 0x0001
+#define MV88E6393X_PCS_SELECT_SGMII_PHY 0x0002
+#define MV88E6393X_PCS_SELECT_SGMII_MAC 0x0003
+#define MV88E6393X_PCS_SELECT_5GBASER 0x0004
+#define MV88E6393X_PCS_SELECT_10GBASER 0x0005
+#define MV88E6393X_PCS_SELECT_USXGMII_PHY 0x0006
+#define MV88E6393X_PCS_SELECT_USXGMII_MAC 0x0007
+
+#define MV88E6393X_SERDES_POC 0xf002
+#define MV88E6393X_SERDES_POC_PCS_MODE_MASK 0x0007
+#define MV88E6393X_SERDES_POC_RESET BIT(15)
+#define MV88E6393X_SERDES_POC_PDOWN BIT(5)
+#define MV88E6393X_SERDES_POC_ANEG BIT(3)
+
+#define MV88E6393X_ERRATA_1000BASEX_SGMII 0xF074
+#define MV88E6393X_ERRATA_1000BASEX_SGMII_BIT BIT(14)
+
u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+u8 mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
u8 lane, unsigned int mode,
phy_interface_t interface,
@@ -105,14 +137,21 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
bool on);
+int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+ bool on);
+int mv88e6393x_setup_errata(struct mv88e6xxx_chip *chip);
int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
bool enable);
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
bool enable);
+int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
+ u8 lane, bool enable);
irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
u8 lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
u8 lane);
+irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
+ u8 lane);
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
int port, uint8_t *data);
--
2.17.1

2020-10-26 06:58:08

by Pavana Sharma

[permalink] [raw]
Subject: [PATCH v4 2/3] Add phy interface for 5GBASER mode

Signed-off-by: Pavana Sharma <[email protected]>
---
include/linux/phy.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/include/linux/phy.h b/include/linux/phy.h
index 3a09d2bf69ea..9de7c57cfd38 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -107,6 +107,7 @@ typedef enum {
PHY_INTERFACE_MODE_2500BASEX,
PHY_INTERFACE_MODE_RXAUI,
PHY_INTERFACE_MODE_XAUI,
+ PHY_INTERFACE_MODE_5GBASER,
/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
PHY_INTERFACE_MODE_10GBASER,
PHY_INTERFACE_MODE_USXGMII,
@@ -187,6 +188,8 @@ static inline const char *phy_modes(phy_interface_t interface)
return "rxaui";
case PHY_INTERFACE_MODE_XAUI:
return "xaui";
+ case PHY_INTERFACE_MODE_5GBASER:
+ return "5gbase-r";
case PHY_INTERFACE_MODE_10GBASER:
return "10gbase-r";
case PHY_INTERFACE_MODE_USXGMII:
--
2.17.1

2020-10-26 07:00:05

by Pavana Sharma

[permalink] [raw]
Subject: [PATCH v4 3/3] Change serdes lane parameter from u8 type to int.

Returning 0 is no more an error case with MV88E6393 family
which has serdes lane numbers 0, 9 or 10.
So with this change .serdes_get_lane will return lane number
or error (-ENODEV).

Signed-off-by: Pavana Sharma <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 28 +++++------
drivers/net/dsa/mv88e6xxx/chip.h | 16 +++---
drivers/net/dsa/mv88e6xxx/port.c | 6 +--
drivers/net/dsa/mv88e6xxx/serdes.c | 80 +++++++++++++++---------------
drivers/net/dsa/mv88e6xxx/serdes.h | 58 +++++++++++-----------
5 files changed, 93 insertions(+), 95 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index de96fd08e77a..6e76c1c37700 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -484,12 +484,12 @@ static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port,
struct phylink_link_state *state)
{
struct mv88e6xxx_chip *chip = ds->priv;
- u8 lane;
+ int lane;
int err;

mv88e6xxx_reg_lock(chip);
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane && chip->info->ops->serdes_pcs_get_state)
+ if ((lane != -ENODEV) && chip->info->ops->serdes_pcs_get_state)
err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
state);
else
@@ -505,11 +505,11 @@ static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
const unsigned long *advertise)
{
const struct mv88e6xxx_ops *ops = chip->info->ops;
- u8 lane;
+ int lane;

if (ops->serdes_pcs_config) {
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane != -ENODEV)
return ops->serdes_pcs_config(chip, port, lane, mode,
interface, advertise);
}
@@ -522,14 +522,14 @@ static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port)
struct mv88e6xxx_chip *chip = ds->priv;
const struct mv88e6xxx_ops *ops;
int err = 0;
- u8 lane;
+ int lane;

ops = chip->info->ops;

if (ops->serdes_pcs_an_restart) {
mv88e6xxx_reg_lock(chip);
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane != -ENODEV)
err = ops->serdes_pcs_an_restart(chip, port, lane);
mv88e6xxx_reg_unlock(chip);

@@ -543,11 +543,11 @@ static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
int speed, int duplex)
{
const struct mv88e6xxx_ops *ops = chip->info->ops;
- u8 lane;
+ int lane;

if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane != -ENODEV)
return ops->serdes_pcs_link_up(chip, port, lane,
speed, duplex);
}
@@ -2442,11 +2442,11 @@ static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
struct mv88e6xxx_chip *chip = mvp->chip;
irqreturn_t ret = IRQ_NONE;
int port = mvp->port;
- u8 lane;
+ int lane;

mv88e6xxx_reg_lock(chip);
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane != -ENODEV)
ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
mv88e6xxx_reg_unlock(chip);

@@ -2454,7 +2454,7 @@ static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
}

static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
struct mv88e6xxx_port *dev_id = &chip->ports[port];
unsigned int irq;
@@ -2483,7 +2483,7 @@ static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
}

static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
struct mv88e6xxx_port *dev_id = &chip->ports[port];
unsigned int irq = dev_id->serdes_irq;
@@ -2508,11 +2508,11 @@ static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
bool on)
{
- u8 lane;
+ int lane;
int err;

lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (!lane)
+ if (lane == -ENODEV)
return 0;

if (on) {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index b7864a24a840..03c0466ab4ae 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -494,30 +494,30 @@ struct mv88e6xxx_ops {
int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip);

/* Power on/off a SERDES interface */
- int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, u8 lane,
+ int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, int lane,
bool up);

/* SERDES lane mapping */
- u8 (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port);
+ int (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port);

int (*serdes_pcs_get_state)(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state);
+ int lane, struct phylink_link_state *state);
int (*serdes_pcs_config)(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise);
int (*serdes_pcs_an_restart)(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
int (*serdes_pcs_link_up)(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex);
+ int lane, int speed, int duplex);

/* SERDES interrupt handling */
unsigned int (*serdes_irq_mapping)(struct mv88e6xxx_chip *chip,
int port);
- int (*serdes_irq_enable)(struct mv88e6xxx_chip *chip, int port, u8 lane,
+ int (*serdes_irq_enable)(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable);
irqreturn_t (*serdes_irq_status)(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);

/* Statistics from the SERDES interface */
int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 4089bfd4e8f4..9a21748bf50f 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -482,7 +482,7 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
- u8 lane;
+ int lane;
u16 cmode;
u16 reg;
int err;
@@ -529,7 +529,7 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
return 0;

lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane) {
+ if (lane != -ENODEV) {
if (chip->ports[port].serdes_irq) {
err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
if (err)
@@ -558,7 +558,7 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
chip->ports[port].cmode = cmode;

lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (!lane)
+ if (lane == -ENODEV)
return -ENODEV;

err = mv88e6xxx_serdes_power_up(chip, port, lane);
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index d0bdbd8ae055..3cfc996de8bd 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -95,7 +95,7 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
return 0;
}

-int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool up)
{
u16 val, new_val;
@@ -117,7 +117,7 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
}

int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise)
{
@@ -166,7 +166,7 @@ int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state)
+ int lane, struct phylink_link_state *state)
{
u16 lpa, status;
int err;
@@ -187,7 +187,7 @@ int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
u16 bmcr;
int err;
@@ -200,7 +200,7 @@ int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex)
+ int lane, int speed, int duplex)
{
u16 val, bmcr;
int err;
@@ -230,10 +230,10 @@ int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
return mv88e6352_serdes_write(chip, MII_BMCR, bmcr);
}

-u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode;
- u8 lane = 0;
+ int lane = -ENODEV;

if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
(cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
@@ -245,7 +245,7 @@ u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)

static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
{
- if (mv88e6xxx_serdes_get_lane(chip, port))
+ if (mv88e6xxx_serdes_get_lane(chip, port) != -ENODEV)
return true;

return false;
@@ -354,7 +354,7 @@ static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
}

irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
irqreturn_t ret = IRQ_NONE;
u16 status;
@@ -372,7 +372,7 @@ irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
return ret;
}

-int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable)
{
u16 val = 0;
@@ -411,10 +411,10 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
}
}

-u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode;
- u8 lane = 0;
+ int lane = -ENODEV;

switch (port) {
case 5:
@@ -428,10 +428,10 @@ u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}

-u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode;
- u8 lane = 0;
+ int lane = -ENODEV;

switch (port) {
case 9:
@@ -451,12 +451,12 @@ u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}

-u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode_port = chip->ports[port].cmode;
u8 cmode_port10 = chip->ports[10].cmode;
u8 cmode_port9 = chip->ports[9].cmode;
- u8 lane = 0;
+ int lane = -ENODEV;

switch (port) {
case 2:
@@ -548,7 +548,7 @@ int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
}

/* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
-static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
+static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane,
bool up)
{
u16 val, new_val;
@@ -575,7 +575,7 @@ static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
}

/* Set power up/down for SGMII and 1000Base-X */
-static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
+static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
bool up)
{
u16 val, new_val;
@@ -611,7 +611,7 @@ static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = {

int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
{
- if (mv88e6390_serdes_get_lane(chip, port) == 0)
+ if (mv88e6390_serdes_get_lane(chip, port) == -ENODEV)
return 0;

return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
@@ -623,7 +623,7 @@ int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip,
struct mv88e6390_serdes_hw_stat *stat;
int i;

- if (mv88e6390_serdes_get_lane(chip, port) == 0)
+ if (mv88e6390_serdes_get_lane(chip, port) == -ENODEV)
return 0;

for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -660,7 +660,7 @@ int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
int i;

lane = mv88e6390_serdes_get_lane(chip, port);
- if (lane == 0)
+ if (lane == -ENODEV)
return 0;

for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -671,7 +671,7 @@ int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
}

-static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, u8 lane)
+static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, int lane)
{
u16 reg;
int err;
@@ -686,7 +686,7 @@ static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, u8 lane)
MV88E6390_PG_CONTROL, reg);
}

-int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool up)
{
u8 cmode = chip->ports[port].cmode;
@@ -711,7 +711,7 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
}

int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise)
{
@@ -770,7 +770,7 @@ int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
}

static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
- int port, u8 lane, struct phylink_link_state *state)
+ int port, int lane, struct phylink_link_state *state)
{
u16 lpa, status;
int err;
@@ -793,7 +793,7 @@ static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
}

static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
- int port, u8 lane, struct phylink_link_state *state)
+ int port, int lane, struct phylink_link_state *state)
{
u16 status;
int err;
@@ -813,7 +813,7 @@ static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
}

int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state)
+ int lane, struct phylink_link_state *state)
{
switch (state->interface) {
case PHY_INTERFACE_MODE_SGMII:
@@ -832,7 +832,7 @@ int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
u16 bmcr;
int err;
@@ -848,7 +848,7 @@ int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex)
+ int lane, int speed, int duplex)
{
u16 val, bmcr;
int err;
@@ -882,7 +882,7 @@ int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
}

static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
u16 bmsr;
int err;
@@ -899,7 +899,7 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
}

static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
- u8 lane, bool enable)
+ int lane, bool enable)
{
u16 val = 0;

@@ -911,7 +911,7 @@ static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
MV88E6390_SGMII_INT_ENABLE, val);
}

-int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable)
{
u8 cmode = chip->ports[port].cmode;
@@ -927,7 +927,7 @@ int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
}

static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
- u8 lane, u16 *status)
+ int lane, u16 *status)
{
int err;

@@ -938,7 +938,7 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
}

int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
- u8 lane, bool enable)
+ int lane, bool enable)
{
u8 cmode = chip->ports[port].cmode;
int err = 0;
@@ -956,7 +956,7 @@ int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
}

irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
u8 cmode = chip->ports[port].cmode;
irqreturn_t ret = IRQ_NONE;
@@ -983,7 +983,7 @@ irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
}

irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
u8 cmode = chip->ports[port].cmode;
irqreturn_t ret = IRQ_NONE;
@@ -1042,7 +1042,7 @@ static const u16 mv88e6390_serdes_regs[] = {

int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port)
{
- if (mv88e6xxx_serdes_get_lane(chip, port) == 0)
+ if (mv88e6xxx_serdes_get_lane(chip, port) == -ENODEV)
return 0;

return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
@@ -1056,7 +1056,7 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
int i;

lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane == 0)
+ if (lane == -ENODEV)
return;

for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
@@ -1204,11 +1204,9 @@ static int mv88e6393x_serdes_port_config(struct mv88e6xxx_chip *chip, int lane,
return 0;
}

-int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on)
{
- lane = mv88e6393x_serdes_get_lane(chip, port);
-
if (port == 0 || port == 9 || port == 10) {
u8 cmode = chip->ports[port].cmode;

diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index c3eaaaac8619..150b2381b779 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -104,54 +104,54 @@
#define MV88E6393X_ERRATA_1000BASEX_SGMII 0xF074
#define MV88E6393X_ERRATA_1000BASEX_SGMII_BIT BIT(14)

-u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-u8 mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise);
int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise);
int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state);
+ int lane, struct phylink_link_state *state);
int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state);
+ int lane, struct phylink_link_state *state);
int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex);
+ int lane, int speed, int duplex);
int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex);
+ int lane, int speed, int duplex);
unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
int port);
unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
int port);
-int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
-int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
-int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
int mv88e6393x_setup_errata(struct mv88e6xxx_chip *chip);
-int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable);
-int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable);
int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
- u8 lane, bool enable);
+ int lane, bool enable);
irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
int port, uint8_t *data);
@@ -169,17 +169,17 @@ int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port);
void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);

/* Return the (first) SERDES lane address a port is using, 0 otherwise. */
-static inline u8 mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
+static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
int port)
{
if (!chip->info->ops->serdes_get_lane)
- return 0;
+ return -EOPNOTSUPP;

return chip->info->ops->serdes_get_lane(chip, port);
}

static inline int mv88e6xxx_serdes_power_up(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
if (!chip->info->ops->serdes_power)
return -EOPNOTSUPP;
@@ -188,7 +188,7 @@ static inline int mv88e6xxx_serdes_power_up(struct mv88e6xxx_chip *chip,
}

static inline int mv88e6xxx_serdes_power_down(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
if (!chip->info->ops->serdes_power)
return -EOPNOTSUPP;
@@ -206,7 +206,7 @@ mv88e6xxx_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
}

static inline int mv88e6xxx_serdes_irq_enable(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
if (!chip->info->ops->serdes_irq_enable)
return -EOPNOTSUPP;
@@ -215,7 +215,7 @@ static inline int mv88e6xxx_serdes_irq_enable(struct mv88e6xxx_chip *chip,
}

static inline int mv88e6xxx_serdes_irq_disable(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
if (!chip->info->ops->serdes_irq_enable)
return -EOPNOTSUPP;
@@ -224,7 +224,7 @@ static inline int mv88e6xxx_serdes_irq_disable(struct mv88e6xxx_chip *chip,
}

static inline irqreturn_t
-mv88e6xxx_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, u8 lane)
+mv88e6xxx_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, int lane)
{
if (!chip->info->ops->serdes_irq_status)
return IRQ_NONE;
--
2.17.1

2020-10-26 10:07:45

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 1/3] Add support for mv88e6393x family of Marvell.

Hi Pavana,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on sparc-next/master linux/master v5.10-rc1 next-20201026]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Pavana-Sharma/Add-support-for-mv88e6393x-family-of-Marvell/20201026-140237
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 3650b228f83adda7e5ee532e2b90429c03f7b9ec
config: xtensa-allyesconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/6bac8985349e1ceedb3d4e9bba18563fb15613c0
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Pavana-Sharma/Add-support-for-mv88e6393x-family-of-Marvell/20201026-140237
git checkout 6bac8985349e1ceedb3d4e9bba18563fb15613c0
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=xtensa

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> drivers/net/dsa/mv88e6xxx/port.c:29:5: warning: no previous prototype for 'mv88e6xxx_port_wait_bit' [-Wmissing-prototypes]
29 | int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/net/dsa/mv88e6xxx/port.c: In function 'mv88e6xxx_port_set_cmode':
drivers/net/dsa/mv88e6xxx/port.c:513:7: error: 'PHY_INTERFACE_MODE_5GBASER' undeclared (first use in this function); did you mean 'PHY_INTERFACE_MODE_10GBASER'?
513 | case PHY_INTERFACE_MODE_5GBASER:
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
| PHY_INTERFACE_MODE_10GBASER
drivers/net/dsa/mv88e6xxx/port.c:513:7: note: each undeclared identifier is reported only once for each function it appears in

vim +/mv88e6xxx_port_wait_bit +29 drivers/net/dsa/mv88e6xxx/port.c

28
> 29 int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
30 int bit, int val)
31 {
32 int addr = chip->info->port_base_addr + port;
33 return mv88e6xxx_wait_bit(chip, addr, reg, bit, val);
34 }
35

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (2.70 kB)
.config.gz (64.61 kB)
Download all attachments

2020-10-26 14:07:45

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH v4 2/3] Add phy interface for 5GBASER mode

On Mon, Oct 26, 2020 at 03:58:11PM +1000, Pavana Sharma wrote:
> Signed-off-by: Pavana Sharma <[email protected]>

Please swap the order of the patches so the build does not break.

Andrew

2020-10-26 16:44:47

by Florian Fainelli

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] Add support for mv88e6393x family of Marvell.



On 10/25/2020 10:52 PM, Pavana Sharma wrote:
> Hi,
>
> Thanks for the review.
> Following is the updated patchset.
>
> The 6393X family has MV88E6191X, MV88E6193X and MV88E6393X products listed in
> Gigabit Ethernet and Gigabit 10G+ Ethernet categories. There are no 6393 devices
> (without X) but there is 6191 device (without X)from a different family.
> The product id is listed with the 'X' in the name so I prefer to retain the
> product name 6393X in the driver whereas we can define the family name as
> 'MV88E6XXX_FAMILY_6393' without 'X'.
>
> The patchset adds support for modes 5GBASE-R, 10GBASE-R and USXGMII on
> ports 0, 9 and 10.
>
> Tested on MV88E6193X device.

Please subject your patches appropriately using "net: dsa: mv88e6xxx: "
for DSA changes to the driver and "net: phy: " for PHY subsystem changes.
--
Florian

2020-10-26 17:34:28

by Florian Fainelli

[permalink] [raw]
Subject: Re: [PATCH v4 2/3] Add phy interface for 5GBASER mode



On 10/25/2020 10:58 PM, Pavana Sharma wrote:
> Signed-off-by: Pavana Sharma <[email protected]>

Please subject this patch properly with "net: phy: Add 5GBASER interface
mode" and please also consider updating other files that are relevant here:

Documentation/devicetree/bindings/net/ethernet-controller.yaml
drivers/net/phy/phy-core.c
--
Florian

2020-10-28 20:33:19

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 1/3] Add support for mv88e6393x family of Marvell.

Hi Pavana,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on linux/master v5.10-rc1 next-20201027]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Pavana-Sharma/Add-support-for-mv88e6393x-family-of-Marvell/20201026-140237
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 3650b228f83adda7e5ee532e2b90429c03f7b9ec
config: arm-randconfig-r013-20201026 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project f2c25c70791de95d2466e09b5b58fc37f6ccd7a4)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install arm cross compiling tool for clang build
# apt-get install binutils-arm-linux-gnueabi
# https://github.com/0day-ci/linux/commit/6bac8985349e1ceedb3d4e9bba18563fb15613c0
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Pavana-Sharma/Add-support-for-mv88e6393x-family-of-Marvell/20201026-140237
git checkout 6bac8985349e1ceedb3d4e9bba18563fb15613c0
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=arm

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> drivers/net/dsa/mv88e6xxx/port.c:29:5: warning: no previous prototype for function 'mv88e6xxx_port_wait_bit' [-Wmissing-prototypes]
int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
^
drivers/net/dsa/mv88e6xxx/port.c:29:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
^
static
drivers/net/dsa/mv88e6xxx/port.c:513:7: error: use of undeclared identifier 'PHY_INTERFACE_MODE_5GBASER'; did you mean 'PHY_INTERFACE_MODE_10GBASER'?
case PHY_INTERFACE_MODE_5GBASER:
^~~~~~~~~~~~~~~~~~~~~~~~~~
PHY_INTERFACE_MODE_10GBASER
include/linux/phy.h:143:2: note: 'PHY_INTERFACE_MODE_10GBASER' declared here
PHY_INTERFACE_MODE_10GBASER,
^
drivers/net/dsa/mv88e6xxx/port.c:516:7: error: duplicate case value 'PHY_INTERFACE_MODE_10GBASER'
case PHY_INTERFACE_MODE_10GBASER:
^
drivers/net/dsa/mv88e6xxx/port.c:513:7: note: previous case defined here
case PHY_INTERFACE_MODE_5GBASER:
^
1 warning and 2 errors generated.

vim +/mv88e6xxx_port_wait_bit +29 drivers/net/dsa/mv88e6xxx/port.c

28
> 29 int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
30 int bit, int val)
31 {
32 int addr = chip->info->port_base_addr + port;
33 return mv88e6xxx_wait_bit(chip, addr, reg, bit, val);
34 }
35

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (3.33 kB)
.config.gz (32.70 kB)
Download all attachments

2020-10-28 21:41:56

by Pavana Sharma

[permalink] [raw]
Subject: [PATCH v5 0/3] Add support for mv88e6393x family of Marvell

Updated patchset.


Pavana Sharma (3):
net: phy: Add 5GBASER interface mode
dt-bindings: net: Add 5GBASER phy interface mode
net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell

.../bindings/net/ethernet-controller.yaml | 2 +
drivers/net/dsa/mv88e6xxx/chip.c | 119 ++++++-
drivers/net/dsa/mv88e6xxx/chip.h | 20 +-
drivers/net/dsa/mv88e6xxx/global1.h | 2 +
drivers/net/dsa/mv88e6xxx/global2.h | 8 +
drivers/net/dsa/mv88e6xxx/port.c | 240 +++++++++++++-
drivers/net/dsa/mv88e6xxx/port.h | 40 ++-
drivers/net/dsa/mv88e6xxx/serdes.c | 296 +++++++++++++++---
drivers/net/dsa/mv88e6xxx/serdes.h | 89 ++++--
include/linux/phy.h | 3 +
10 files changed, 732 insertions(+), 87 deletions(-)

--
2.17.1

2020-10-28 21:41:58

by Pavana Sharma

[permalink] [raw]
Subject: [PATCH v5 1/3] net: phy: Add 5GBASER interface mode

Add new mode supported by MV88E6393 family.

Signed-off-by: Pavana Sharma <[email protected]>
---
include/linux/phy.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/include/linux/phy.h b/include/linux/phy.h
index 3a09d2bf69ea..9de7c57cfd38 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -107,6 +107,7 @@ typedef enum {
PHY_INTERFACE_MODE_2500BASEX,
PHY_INTERFACE_MODE_RXAUI,
PHY_INTERFACE_MODE_XAUI,
+ PHY_INTERFACE_MODE_5GBASER,
/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
PHY_INTERFACE_MODE_10GBASER,
PHY_INTERFACE_MODE_USXGMII,
@@ -187,6 +188,8 @@ static inline const char *phy_modes(phy_interface_t interface)
return "rxaui";
case PHY_INTERFACE_MODE_XAUI:
return "xaui";
+ case PHY_INTERFACE_MODE_5GBASER:
+ return "5gbase-r";
case PHY_INTERFACE_MODE_10GBASER:
return "10gbase-r";
case PHY_INTERFACE_MODE_USXGMII:
--
2.17.1

2020-10-28 21:42:04

by Pavana Sharma

[permalink] [raw]
Subject: [PATCH v5 3/3] net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell

The Marvell 88E6393X device is a single-chip integration of a 11-port
Ethernet switch with eight integrated Gigabit Ethernet (GbE) transceivers
and three 10-Gigabit interfaces.

This patch adds functionalities specific to mv88e6393x family (88E6393X,
88E6193X and 88E6191X)

Signed-off-by: Pavana Sharma <[email protected]>
---
Changes in v2:
- Fix a warning (Reported-by: kernel test robot <[email protected]>)
Changes in v3:
- Fix 'unused function' warning
Changes in v4, v5:
- Incorporated feedback from maintainers.
---
drivers/net/dsa/mv88e6xxx/chip.c | 119 +++++++++--
drivers/net/dsa/mv88e6xxx/chip.h | 20 +-
drivers/net/dsa/mv88e6xxx/global1.h | 2 +
drivers/net/dsa/mv88e6xxx/global2.h | 8 +
drivers/net/dsa/mv88e6xxx/port.c | 240 +++++++++++++++++++++-
drivers/net/dsa/mv88e6xxx/port.h | 40 +++-
drivers/net/dsa/mv88e6xxx/serdes.c | 296 ++++++++++++++++++++++++----
drivers/net/dsa/mv88e6xxx/serdes.h | 89 ++++++---
8 files changed, 727 insertions(+), 87 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index f0dbc05e30a4..6e76c1c37700 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -484,12 +484,12 @@ static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port,
struct phylink_link_state *state)
{
struct mv88e6xxx_chip *chip = ds->priv;
- u8 lane;
+ int lane;
int err;

mv88e6xxx_reg_lock(chip);
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane && chip->info->ops->serdes_pcs_get_state)
+ if ((lane != -ENODEV) && chip->info->ops->serdes_pcs_get_state)
err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
state);
else
@@ -505,11 +505,11 @@ static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
const unsigned long *advertise)
{
const struct mv88e6xxx_ops *ops = chip->info->ops;
- u8 lane;
+ int lane;

if (ops->serdes_pcs_config) {
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane != -ENODEV)
return ops->serdes_pcs_config(chip, port, lane, mode,
interface, advertise);
}
@@ -522,14 +522,14 @@ static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port)
struct mv88e6xxx_chip *chip = ds->priv;
const struct mv88e6xxx_ops *ops;
int err = 0;
- u8 lane;
+ int lane;

ops = chip->info->ops;

if (ops->serdes_pcs_an_restart) {
mv88e6xxx_reg_lock(chip);
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane != -ENODEV)
err = ops->serdes_pcs_an_restart(chip, port, lane);
mv88e6xxx_reg_unlock(chip);

@@ -543,11 +543,11 @@ static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
int speed, int duplex)
{
const struct mv88e6xxx_ops *ops = chip->info->ops;
- u8 lane;
+ int lane;

if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane != -ENODEV)
return ops->serdes_pcs_link_up(chip, port, lane,
speed, duplex);
}
@@ -634,6 +634,24 @@ static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
mv88e6390_phylink_validate(chip, port, mask, state);
}

+static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
+ unsigned long *mask,
+ struct phylink_link_state *state)
+{
+ if (port == 0 || port == 9 || port == 10) {
+ phylink_set(mask, 10000baseT_Full);
+ phylink_set(mask, 10000baseKR_Full);
+ phylink_set(mask, 5000baseT_Full);
+ phylink_set(mask, 2500baseX_Full);
+ phylink_set(mask, 2500baseT_Full);
+ }
+
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseX_Full);
+
+ mv88e6065_phylink_validate(chip, port, mask, state);
+}
+
static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
unsigned long *supported,
struct phylink_link_state *state)
@@ -2424,11 +2442,11 @@ static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
struct mv88e6xxx_chip *chip = mvp->chip;
irqreturn_t ret = IRQ_NONE;
int port = mvp->port;
- u8 lane;
+ int lane;

mv88e6xxx_reg_lock(chip);
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane != -ENODEV)
ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
mv88e6xxx_reg_unlock(chip);

@@ -2436,7 +2454,7 @@ static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
}

static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
struct mv88e6xxx_port *dev_id = &chip->ports[port];
unsigned int irq;
@@ -2465,7 +2483,7 @@ static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
}

static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
struct mv88e6xxx_port *dev_id = &chip->ports[port];
unsigned int irq = dev_id->serdes_irq;
@@ -2490,11 +2508,11 @@ static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
bool on)
{
- u8 lane;
+ int lane;
int err;

lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (!lane)
+ if (lane == -ENODEV)
return 0;

if (on) {
@@ -4141,6 +4159,56 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.phylink_validate = mv88e6390_phylink_validate,
};

+static const struct mv88e6xxx_ops mv88e6193x_ops = {
+ /* MV88E6XXX_FAMILY_6393 */
+ .setup_errata = mv88e6393x_setup_errata,
+ .irl_init_all = mv88e6390_g2_irl_init_all,
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_floods = mv88e6352_port_set_egress_floods,
+ .port_set_ether_type = mv88e6393x_port_set_ether_type,
+ .port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
+ .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
+ .port_pause_limit = mv88e6390_port_pause_limit,
+ .port_set_cmode = mv88e6393x_port_set_cmode,
+ .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
+ .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+ .port_get_cmode = mv88e6352_port_get_cmode,
+ .stats_snapshot = mv88e6390_g1_stats_snapshot,
+ .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
+ .stats_get_sset_count = mv88e6320_stats_get_sset_count,
+ .stats_get_strings = mv88e6320_stats_get_strings,
+ .stats_get_stats = mv88e6390_stats_get_stats,
+ .set_cpu_port = mv88e6393x_port_set_cpu_dest,
+ .set_egress_port = mv88e6393x_set_egress_port,
+ .watchdog_ops = &mv88e6390_watchdog_ops,
+ .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
+ .pot_clear = mv88e6xxx_g2_pot_clear,
+ .reset = mv88e6352_g1_reset,
+ .rmu_disable = mv88e6390_g1_rmu_disable,
+ .vtu_getnext = mv88e6390_g1_vtu_getnext,
+ .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
+ .serdes_power = mv88e6393x_serdes_power,
+ .serdes_get_lane = mv88e6393x_serdes_get_lane,
+ /* Check status register pause & lpa register */
+ .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
+ .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
+ .serdes_irq_enable = mv88e6393x_serdes_irq_enable,
+ .serdes_irq_status = mv88e6393x_serdes_irq_status,
+ .gpio_ops = &mv88e6352_gpio_ops,
+ .avb_ops = &mv88e6390_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
+ .phylink_validate = mv88e6393x_phylink_validate,
+};
+
static const struct mv88e6xxx_ops mv88e6240_ops = {
/* MV88E6XXX_FAMILY_6352 */
.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
@@ -5073,6 +5141,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6191_ops,
},

+ [MV88E6193X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6193X",
+ .num_databases = 4096,
+ .num_ports = 11, /* 10 + Z80 */
+ .num_internal_phys = 9,
+ .max_vid = 8191,
+ .port_base_addr = 0x0,
+ .phy_base_addr = 0x0,
+ .global1_addr = 0x1b,
+ .global2_addr = 0x1c,
+ .age_time_coeff = 3750,
+ .g1_irqs = 10,
+ .g2_irqs = 14,
+ .atu_move_port_mask = 0x1f,
+ .pvt = true,
+ .multi_chip = true,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
+ .ptp_support = true,
+ .ops = &mv88e6193x_ops,
+ },
+
[MV88E6220] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
.family = MV88E6XXX_FAMILY_6250,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 823ae89e5fca..03c0466ab4ae 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -63,6 +63,8 @@ enum mv88e6xxx_model {
MV88E6190,
MV88E6190X,
MV88E6191,
+ MV88E6191X,
+ MV88E6193X,
MV88E6220,
MV88E6240,
MV88E6250,
@@ -75,6 +77,7 @@ enum mv88e6xxx_model {
MV88E6352,
MV88E6390,
MV88E6390X,
+ MV88E6393X,
};

enum mv88e6xxx_family {
@@ -90,6 +93,7 @@ enum mv88e6xxx_family {
MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */
MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */
+ MV88E6XXX_FAMILY_6393, /* 6191X 6193X 6393X */
};

struct mv88e6xxx_ops;
@@ -490,30 +494,30 @@ struct mv88e6xxx_ops {
int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip);

/* Power on/off a SERDES interface */
- int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, u8 lane,
+ int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, int lane,
bool up);

/* SERDES lane mapping */
- u8 (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port);
+ int (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port);

int (*serdes_pcs_get_state)(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state);
+ int lane, struct phylink_link_state *state);
int (*serdes_pcs_config)(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise);
int (*serdes_pcs_an_restart)(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
int (*serdes_pcs_link_up)(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex);
+ int lane, int speed, int duplex);

/* SERDES interrupt handling */
unsigned int (*serdes_irq_mapping)(struct mv88e6xxx_chip *chip,
int port);
- int (*serdes_irq_enable)(struct mv88e6xxx_chip *chip, int port, u8 lane,
+ int (*serdes_irq_enable)(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable);
irqreturn_t (*serdes_irq_status)(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);

/* Statistics from the SERDES interface */
int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 1e3546f8b072..bd17eed15aad 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -22,6 +22,7 @@
#define MV88E6185_G1_STS_PPU_STATE_DISABLED 0x8000
#define MV88E6185_G1_STS_PPU_STATE_POLLING 0xc000
#define MV88E6XXX_G1_STS_INIT_READY 0x0800
+#define MV88E6193X_G1_STS_IRQ_DEVICE_2 9
#define MV88E6XXX_G1_STS_IRQ_AVB 8
#define MV88E6XXX_G1_STS_IRQ_DEVICE 7
#define MV88E6XXX_G1_STS_IRQ_STATS 6
@@ -59,6 +60,7 @@
#define MV88E6185_G1_CTL1_SCHED_PRIO 0x0800
#define MV88E6185_G1_CTL1_MAX_FRAME_1632 0x0400
#define MV88E6185_G1_CTL1_RELOAD_EEPROM 0x0200
+#define MV88E6193X_G1_CTL1_DEVICE2_EN 0x0200
#define MV88E6XXX_G1_CTL1_DEVICE_EN 0x0080
#define MV88E6XXX_G1_CTL1_STATS_DONE_EN 0x0040
#define MV88E6XXX_G1_CTL1_VTU_PROBLEM_EN 0x0020
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h
index 1f42ee656816..04696cb68971 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -38,9 +38,15 @@
/* Offset 0x02: MGMT Enable Register 2x */
#define MV88E6XXX_G2_MGMT_EN_2X 0x02

+/* Offset 0x02: MAC LINK change IRQ Register for MV88E6393X */
+#define MV88E6393X_G2_MACLINK_INT_SRC 0x02
+
/* Offset 0x03: MGMT Enable Register 0x */
#define MV88E6XXX_G2_MGMT_EN_0X 0x03

+/* Offset 0x03: MAC LINK change IRQ Mask Register for MV88E6393X */
+#define MV88E6393X_G2_MACLINK_INT_MASK 0x03
+
/* Offset 0x04: Flow Control Delay Register */
#define MV88E6XXX_G2_FLOW_CTL 0x04

@@ -52,6 +58,8 @@
#define MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI 0x0080
#define MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU 0x0008

+#define MV88E6393X_G2_EGRESS_MONITOR_DEST 0x05
+
/* Offset 0x06: Device Mapping Table Register */
#define MV88E6XXX_G2_DEVICE_MAPPING 0x06
#define MV88E6XXX_G2_DEVICE_MAPPING_UPDATE 0x8000
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 8128dc607cf4..814c44a586b7 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -14,6 +14,7 @@
#include <linux/phylink.h>

#include "chip.h"
+#include "global2.h"
#include "port.h"
#include "serdes.h"

@@ -25,6 +26,14 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
return mv88e6xxx_read(chip, addr, reg, val);
}

+int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
+ int bit, int val)
+{
+ int addr = chip->info->port_base_addr + port;
+
+ return mv88e6xxx_wait_bit(chip, addr, reg, bit, val);
+}
+
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
u16 val)
{
@@ -390,10 +399,91 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
return PHY_INTERFACE_MODE_NA;
}

+/* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X) */
+int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
+ int speed, int duplex)
+{
+ u16 reg, ctrl;
+ int err;
+
+ if (speed == SPEED_MAX)
+ speed = (port > 0 && port < 9) ? 1000 : 10000;
+
+ if (speed == 200 && port != 0)
+ return -EOPNOTSUPP;
+
+ if (speed >= 2500 && port > 0 && port < 9)
+ return -EOPNOTSUPP;
+
+ switch (speed) {
+ case 10:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
+ break;
+ case 100:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
+ break;
+ case 200:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 1000:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
+ break;
+ case 2500:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 5000:
+ ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 10000:
+ case SPEED_UNFORCED:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ switch (duplex) {
+ case DUPLEX_HALF:
+ ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
+ break;
+ case DUPLEX_FULL:
+ ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
+ MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
+ break;
+ case DUPLEX_UNFORCED:
+ /* normal duplex detection */
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
+ if (err)
+ return err;
+
+ reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED |
+ MV88E6390_PORT_MAC_CTL_FORCE_SPEED);
+
+ if (speed != SPEED_UNFORCED)
+ reg |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
+
+ reg |= ctrl;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+ if (err)
+ return err;
+
+ return 0;
+}
+
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
- u8 lane;
+ int lane;
u16 cmode;
u16 reg;
int err;
@@ -421,6 +511,16 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
case PHY_INTERFACE_MODE_RXAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
break;
+ case PHY_INTERFACE_MODE_5GBASER:
+ cmode = MV88E6XXX_PORT_STS_CMODE_5GBASER;
+ break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_10GKR:
+ cmode = MV88E6XXX_PORT_STS_CMODE_10GBASER;
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ cmode = MV88E6XXX_PORT_STS_CMODE_USXGMII;
+ break;
default:
cmode = 0;
}
@@ -430,7 +530,7 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
return 0;

lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane) {
+ if (lane != -ENODEV) {
if (chip->ports[port].serdes_irq) {
err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
if (err)
@@ -459,7 +559,7 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
chip->ports[port].cmode = cmode;

lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (!lane)
+ if (lane == -ENODEV)
return -ENODEV;

err = mv88e6xxx_serdes_power_up(chip, port, lane);
@@ -505,6 +605,15 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
return mv88e6xxx_port_set_cmode(chip, port, mode, false);
}

+int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode)
+{
+ if (port != 0 && port != 9 && port != 10)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_cmode(chip, port, mode, false);
+}
+
static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,
int port)
{
@@ -1128,6 +1237,131 @@ int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
}

+/* Offset 0x0E: Policy & MGMT Control Register for FAMILY 6191X 6193X 6393X*/
+
+static int mv88e6393x_port_policy_write(struct mv88e6xxx_chip *chip, u16 pointer,
+ u8 data)
+{
+
+ int err = 0;
+ int port;
+ u16 reg;
+
+ /* Setup per Port policy register */
+ for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
+ if (dsa_is_unused_port(chip->ds, port))
+ continue;
+
+ /* Prevent the use of an invalid port. */
+ if (mv88e6xxx_is_invalid_port(chip, port)) {
+ dev_err(chip->dev, "port %d is invalid\n", port);
+ err = -EINVAL;
+ }
+ reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL, reg);
+ }
+ return err;
+}
+
+int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
+ enum mv88e6xxx_egress_direction direction,
+ int port)
+{
+ u16 ptr;
+ int err;
+
+ switch (direction) {
+ case MV88E6XXX_EGRESS_DIR_INGRESS:
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST;
+ err = mv88e6393x_port_policy_write(chip, ptr, port);
+ if (err)
+ return err;
+ break;
+ case MV88E6XXX_EGRESS_DIR_EGRESS:
+ ptr = MV88E6393X_G2_EGRESS_MONITOR_DEST;
+ err = mv88e6xxx_g2_write(chip, ptr, port);
+ if (err)
+ return err;
+ break;
+ }
+ return 0;
+}
+
+int mv88e6393x_port_set_cpu_dest(struct mv88e6xxx_chip *chip, int port)
+{
+ u16 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST;
+ u8 data = MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI | port;
+
+ return mv88e6393x_port_policy_write(chip, ptr, data);
+}
+
+int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
+{
+ u16 ptr;
+ int err;
+
+ /* Consider the frames with reserved multicast destination
+ * addresses matching 01:80:c2:00:00:00 and
+ * 01:80:c2:00:00:02 as MGMT.
+ */
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI;
+ err = mv88e6393x_port_policy_write(chip, ptr, 0xff);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* Offset 0x10 & 0x11: EPC */
+
+static int mv88e6393x_epc_wait_ready(struct mv88e6xxx_chip *chip, int port)
+{
+ int bit = __bf_shf(MV88E6393X_PORT_EPC_CMD_BUSY);
+
+ return mv88e6xxx_port_wait_bit(chip, port, MV88E6393X_PORT_EPC_CMD, bit, 0);
+}
+
+/* Port Ether type for 6393X family */
+
+int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
+ u16 etype)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6393x_epc_wait_ready(chip, port);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_DATA, etype);
+ if (err)
+ return err;
+
+ val = MV88E6393X_PORT_EPC_CMD_BUSY |
+ MV88E6393X_PORT_EPC_CMD_WRITE |
+ MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
+ if (err)
+ return err;
+
+ return 0;
+}
+
/* Offset 0x0f: Port Ether type */

int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index 44d76ac973f6..3e4105637bb5 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -49,6 +49,9 @@
#define MV88E6XXX_PORT_STS_CMODE_2500BASEX 0x000b
#define MV88E6XXX_PORT_STS_CMODE_XAUI 0x000c
#define MV88E6XXX_PORT_STS_CMODE_RXAUI 0x000d
+#define MV88E6XXX_PORT_STS_CMODE_5GBASER 0x000c
+#define MV88E6XXX_PORT_STS_CMODE_10GBASER 0x000d
+#define MV88E6XXX_PORT_STS_CMODE_USXGMII 0x000e
#define MV88E6185_PORT_STS_CDUPLEX 0x0008
#define MV88E6185_PORT_STS_CMODE_MASK 0x0007
#define MV88E6185_PORT_STS_CMODE_GMII_FD 0x0000
@@ -117,6 +120,8 @@
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6176 0x1760
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6190 0x1900
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6191 0x1910
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6191X 0x1920
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6193X 0x1930
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6185 0x1a70
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6220 0x2200
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400
@@ -129,6 +134,7 @@
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6350 0x3710
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6351 0x3750
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6390 0x3900
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6393X 0x3930
#define MV88E6XXX_PORT_SWITCH_ID_REV_MASK 0x000f

/* Offset 0x04: Port Control Register */
@@ -236,6 +242,19 @@
#define MV88E6XXX_PORT_POLICY_CTL_TRAP 0x0002
#define MV88E6XXX_PORT_POLICY_CTL_DISCARD 0x0003

+/* Offset 0x0E: Policy & MGMT Control Register (FAMILY_6393X)*/
+#define MV88E6393X_PORT_POLICY_MGMT_CTL 0x0e
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE 0x8000
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_MASK 0x3f00
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO 0x2000
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI 0x2100
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO 0x2400
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI 0x2500
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST 0x3000
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST 0x3800
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_DATA_MASK 0x00ff
+#define MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI 0x00e0
+
/* Offset 0x0F: Port Special Ether Type */
#define MV88E6XXX_PORT_ETH_TYPE 0x0f
#define MV88E6XXX_PORT_ETH_TYPE_DEFAULT 0x9100
@@ -243,6 +262,15 @@
/* Offset 0x10: InDiscards Low Counter */
#define MV88E6XXX_PORT_IN_DISCARD_LO 0x10

+/* Offset 0x10: Extended Port Control Command */
+#define MV88E6393X_PORT_EPC_CMD 0x10
+#define MV88E6393X_PORT_EPC_CMD_BUSY 0x8000
+#define MV88E6393X_PORT_EPC_CMD_WRITE 0x0300
+#define MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE 0x02
+
+/* Offset 0x11: Extended Port Control Data */
+#define MV88E6393X_PORT_EPC_DATA 0x11
+
/* Offset 0x11: InDiscards High Counter */
#define MV88E6XXX_PORT_IN_DISCARD_HI 0x11

@@ -312,7 +340,8 @@ int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
int speed, int duplex);
int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
int speed, int duplex);
-
+int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
+ int speed, int duplex);
phy_interface_t mv88e6341_port_max_speed_mode(int port);
phy_interface_t mv88e6390_port_max_speed_mode(int port);
phy_interface_t mv88e6390x_port_max_speed_mode(int port);
@@ -346,6 +375,13 @@ int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,
enum mv88e6xxx_policy_action action);
int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
u16 etype);
+int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
+ enum mv88e6xxx_egress_direction direction,
+ int port);
+int mv88e6393x_port_set_cpu_dest(struct mv88e6xxx_chip *chip, int port);
+int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip);
+int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
+ u16 etype);
int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
bool message_port);
int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
@@ -362,6 +398,8 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode);
int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode);
+int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode);
int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 9c07b4f3d345..21e986f929ae 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -95,7 +95,7 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
return 0;
}

-int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool up)
{
u16 val, new_val;
@@ -117,7 +117,7 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
}

int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise)
{
@@ -166,7 +166,7 @@ int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state)
+ int lane, struct phylink_link_state *state)
{
u16 lpa, status;
int err;
@@ -187,7 +187,7 @@ int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
u16 bmcr;
int err;
@@ -200,7 +200,7 @@ int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex)
+ int lane, int speed, int duplex)
{
u16 val, bmcr;
int err;
@@ -230,10 +230,10 @@ int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
return mv88e6352_serdes_write(chip, MII_BMCR, bmcr);
}

-u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode;
- u8 lane = 0;
+ int lane = -ENODEV;

if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
(cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
@@ -245,7 +245,7 @@ u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)

static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
{
- if (mv88e6xxx_serdes_get_lane(chip, port))
+ if (mv88e6xxx_serdes_get_lane(chip, port) != -ENODEV)
return true;

return false;
@@ -354,7 +354,7 @@ static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
}

irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
irqreturn_t ret = IRQ_NONE;
u16 status;
@@ -372,7 +372,7 @@ irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
return ret;
}

-int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable)
{
u16 val = 0;
@@ -411,10 +411,10 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
}
}

-u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode;
- u8 lane = 0;
+ int lane = -ENODEV;

switch (port) {
case 5:
@@ -428,10 +428,10 @@ u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}

-u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode;
- u8 lane = 0;
+ int lane = -ENODEV;

switch (port) {
case 9:
@@ -451,12 +451,12 @@ u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}

-u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode_port = chip->ports[port].cmode;
u8 cmode_port10 = chip->ports[10].cmode;
u8 cmode_port9 = chip->ports[9].cmode;
- u8 lane = 0;
+ int lane = -ENODEV;

switch (port) {
case 2:
@@ -526,8 +526,28 @@ u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}

+/* Only Ports 0, 9 and 10 have SERDES lanes. Return the SERDES lane address
+ * a port is using else Returns -ENODEV.
+ */
+int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+{
+ u8 cmode = chip->ports[port].cmode;
+ int lane = -ENODEV;
+
+ if (port == 0 || port == 9 || port == 10) {
+ if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_5GBASER ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_10GBASER ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_USXGMII)
+ lane = port;
+ }
+ return lane;
+}
+
/* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
-static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
+static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane,
bool up)
{
u16 val, new_val;
@@ -554,7 +574,7 @@ static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
}

/* Set power up/down for SGMII and 1000Base-X */
-static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
+static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
bool up)
{
u16 val, new_val;
@@ -590,7 +610,7 @@ static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = {

int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
{
- if (mv88e6390_serdes_get_lane(chip, port) == 0)
+ if (mv88e6390_serdes_get_lane(chip, port) == -ENODEV)
return 0;

return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
@@ -602,7 +622,7 @@ int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip,
struct mv88e6390_serdes_hw_stat *stat;
int i;

- if (mv88e6390_serdes_get_lane(chip, port) == 0)
+ if (mv88e6390_serdes_get_lane(chip, port) == -ENODEV)
return 0;

for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -639,7 +659,7 @@ int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
int i;

lane = mv88e6390_serdes_get_lane(chip, port);
- if (lane == 0)
+ if (lane == -ENODEV)
return 0;

for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -650,7 +670,7 @@ int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
}

-static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, u8 lane)
+static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, int lane)
{
u16 reg;
int err;
@@ -665,7 +685,7 @@ static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, u8 lane)
MV88E6390_PG_CONTROL, reg);
}

-int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool up)
{
u8 cmode = chip->ports[port].cmode;
@@ -690,7 +710,7 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
}

int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise)
{
@@ -749,7 +769,7 @@ int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
}

static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
- int port, u8 lane, struct phylink_link_state *state)
+ int port, int lane, struct phylink_link_state *state)
{
u16 lpa, status;
int err;
@@ -772,7 +792,7 @@ static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
}

static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
- int port, u8 lane, struct phylink_link_state *state)
+ int port, int lane, struct phylink_link_state *state)
{
u16 status;
int err;
@@ -792,7 +812,7 @@ static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
}

int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state)
+ int lane, struct phylink_link_state *state)
{
switch (state->interface) {
case PHY_INTERFACE_MODE_SGMII:
@@ -811,7 +831,7 @@ int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
u16 bmcr;
int err;
@@ -827,7 +847,7 @@ int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
}

int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex)
+ int lane, int speed, int duplex)
{
u16 val, bmcr;
int err;
@@ -861,7 +881,7 @@ int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
}

static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
u16 bmsr;
int err;
@@ -878,7 +898,7 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
}

static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
- u8 lane, bool enable)
+ int lane, bool enable)
{
u16 val = 0;

@@ -890,7 +910,7 @@ static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
MV88E6390_SGMII_INT_ENABLE, val);
}

-int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable)
{
u8 cmode = chip->ports[port].cmode;
@@ -906,7 +926,7 @@ int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
}

static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
- u8 lane, u16 *status)
+ int lane, u16 *status)
{
int err;

@@ -916,8 +936,53 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
return err;
}

+int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
+ int lane, bool enable)
+{
+ u8 cmode = chip->ports[port].cmode;
+ int err = 0;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_SGMII:
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_5GBASER:
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ err = mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
+ }
+
+ return err;
+}
+
+irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
+ int lane)
+{
+ u8 cmode = chip->ports[port].cmode;
+ irqreturn_t ret = IRQ_NONE;
+ u16 status;
+ int err;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_SGMII:
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_5GBASER:
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
+ if (err)
+ return ret;
+ if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
+ MV88E6390_SGMII_INT_LINK_UP)) {
+ ret = IRQ_HANDLED;
+ mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
+ }
+ }
+
+ return ret;
+}
+
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
u8 cmode = chip->ports[port].cmode;
irqreturn_t ret = IRQ_NONE;
@@ -976,7 +1041,7 @@ static const u16 mv88e6390_serdes_regs[] = {

int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port)
{
- if (mv88e6xxx_serdes_get_lane(chip, port) == 0)
+ if (mv88e6xxx_serdes_get_lane(chip, port) == -ENODEV)
return 0;

return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
@@ -990,7 +1055,7 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
int i;

lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane == 0)
+ if (lane == -ENODEV)
return;

for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
@@ -999,3 +1064,162 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
p[i] = reg;
}
}
+
+int mv88e6393x_setup_errata(struct mv88e6xxx_chip *chip)
+{
+ u16 config0, config9, config10;
+ u16 pcs0, pcs9, pcs10;
+ int err = 0;
+
+ /* mv88e6393x family errata 3.8 :
+ * When a SERDES port is operating in 1000BASE-X or SGMII mode link may not
+ * come up after hardware reset or software reset of SERDES core.
+ * Workaround is to write SERDES register 4.F074.14 =1 for only those modes
+ * and 0 in all other modes.
+ */
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT0_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII, &config0);
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT9_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII, &config9);
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT10_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII, &config10);
+
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT0_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &pcs0);
+ pcs0 &= MV88E6393X_SERDES_POC_PCS_MODE_MASK;
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT9_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &pcs9);
+ pcs9 &= MV88E6393X_SERDES_POC_PCS_MODE_MASK;
+ err = mv88e6390_serdes_read(chip, MV88E6393X_PORT10_LANE, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &pcs10);
+ pcs10 &= MV88E6393X_SERDES_POC_PCS_MODE_MASK;
+
+ if (pcs0 == MV88E6393X_PCS_SELECT_1000BASEX ||
+ pcs0 == MV88E6393X_PCS_SELECT_SGMII_PHY ||
+ pcs0 == MV88E6393X_PCS_SELECT_SGMII_MAC) {
+ config0 |= MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT0_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config0);
+ } else {
+ config0 &= ~MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT0_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config0);
+ }
+
+ if (pcs9 == MV88E6393X_PCS_SELECT_1000BASEX ||
+ pcs9 == MV88E6393X_PCS_SELECT_SGMII_PHY ||
+ pcs9 == MV88E6393X_PCS_SELECT_SGMII_MAC) {
+ config9 |= MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT9_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config9);
+ } else {
+ config9 &= ~MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT9_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config9);
+ }
+
+ if (pcs10 == MV88E6393X_PCS_SELECT_1000BASEX ||
+ pcs10 == MV88E6393X_PCS_SELECT_SGMII_PHY ||
+ pcs10 == MV88E6393X_PCS_SELECT_SGMII_MAC) {
+ config10 |= MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT10_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config10);
+ } else {
+ config10 &= ~MV88E6393X_ERRATA_1000BASEX_SGMII_BIT;
+ err = mv88e6390_serdes_write(chip, MV88E6393X_PORT10_LANE,
+ MDIO_MMD_PHYXS,
+ MV88E6393X_ERRATA_1000BASEX_SGMII,
+ config10);
+ }
+ return err;
+}
+
+static int mv88e6393x_serdes_port_config(struct mv88e6xxx_chip *chip, int lane,
+ bool on)
+{
+ u8 cmode = chip->ports[lane].cmode;
+ u16 config, pcs;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ pcs = MV88E6393X_PCS_SELECT_1000BASEX;
+ break;
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ pcs = MV88E6393X_PCS_SELECT_2500BASEX;
+ break;
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ pcs = MV88E6393X_PCS_SELECT_10GBASER;
+ break;
+ default:
+ pcs = MV88E6393X_PCS_SELECT_1000BASEX;
+ break;
+ }
+
+ if (on) {
+ /* mv88e6393x family errata 3.6 :
+ * When changing c_mode on Port 0 from [x]MII mode to any
+ * SERDES mode SERDES will not be operational.
+ * Workaround: Set Port0 SERDES register 4.F002.5=0
+ */
+ mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, &config);
+ config &= ~(MV88E6393X_SERDES_POC_PCS_MODE_MASK |
+ MV88E6393X_SERDES_POC_PDOWN);
+ config |= pcs;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, config);
+ config |= MV88E6393X_SERDES_POC_RESET;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6393X_SERDES_POC, config);
+
+ /* mv88e6393x family errata 3.7 :
+ * When changing cmode on SERDES port from any other mode to
+ * 1000BASE-X mode the link may not come up due to invalid
+ * 1000BASE-X advertisement.
+ * Workaround: Correct advertisement and reset PHY core.
+ */
+ config = MV88E6390_SGMII_ANAR_1000BASEX_FD;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_ANAR, config);
+
+ /* soft reset the PCS/PMA */
+ mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_CONTROL, &config);
+ config |= MV88E6390_SGMII_CONTROL_RESET;
+ mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_CONTROL, config);
+ }
+
+ return 0;
+}
+
+int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
+ bool on)
+{
+ if (port == 0 || port == 9 || port == 10) {
+ u8 cmode = chip->ports[port].cmode;
+
+ mv88e6393x_serdes_port_config(chip, lane, on);
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+ return mv88e6390_serdes_power_sgmii(chip, lane, on);
+ case MV88E6XXX_PORT_STS_CMODE_10GBASER:
+ return mv88e6390_serdes_power_10g(chip, lane, on);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index 14315f26228a..150b2381b779 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -68,51 +68,90 @@
#define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10)
#define MV88E6390_SGMII_PHY_STATUS_TX_PAUSE BIT(3)
#define MV88E6390_SGMII_PHY_STATUS_RX_PAUSE BIT(2)
+#define MV88E6390_SGMII_STATUS_AN_ABLE BIT(3)
+#define MV88E6390_SGMII_ANAR 0x2004
+#define MV88E6390_SGMII_ANAR_1000BASEX_FD BIT(5)
+#define MV88E6390_SGMII_CONTROL 0x2000
+#define MV88E6390_SGMII_CONTROL_RESET BIT(15)
+#define MV88E6390_SGMII_CONTROL_LOOPBACK BIT(14)
+#define MV88E6390_SGMII_CONTROL_PDOWN BIT(11)
+#define MV88E6390_SGMII_STATUS 0x2001

/* Packet generator pad packet checker */
#define MV88E6390_PG_CONTROL 0xf010
#define MV88E6390_PG_CONTROL_ENABLE_PC BIT(0)

-u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+#define MV88E6393X_PORT0_LANE 0x00
+#define MV88E6393X_PORT9_LANE 0x09
+#define MV88E6393X_PORT10_LANE 0x0a
+
+/* Port Operational Configuration */
+#define MV88E6393X_PCS_SELECT_1000BASEX 0x0000
+#define MV88E6393X_PCS_SELECT_2500BASEX 0x0001
+#define MV88E6393X_PCS_SELECT_SGMII_PHY 0x0002
+#define MV88E6393X_PCS_SELECT_SGMII_MAC 0x0003
+#define MV88E6393X_PCS_SELECT_5GBASER 0x0004
+#define MV88E6393X_PCS_SELECT_10GBASER 0x0005
+#define MV88E6393X_PCS_SELECT_USXGMII_PHY 0x0006
+#define MV88E6393X_PCS_SELECT_USXGMII_MAC 0x0007
+
+#define MV88E6393X_SERDES_POC 0xf002
+#define MV88E6393X_SERDES_POC_PCS_MODE_MASK 0x0007
+#define MV88E6393X_SERDES_POC_RESET BIT(15)
+#define MV88E6393X_SERDES_POC_PDOWN BIT(5)
+#define MV88E6393X_SERDES_POC_ANEG BIT(3)
+
+#define MV88E6393X_ERRATA_1000BASEX_SGMII 0xF074
+#define MV88E6393X_ERRATA_1000BASEX_SGMII_BIT BIT(14)
+
+int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise);
int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- u8 lane, unsigned int mode,
+ int lane, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertise);
int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state);
+ int lane, struct phylink_link_state *state);
int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- u8 lane, struct phylink_link_state *state);
+ int lane, struct phylink_link_state *state);
int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex);
+ int lane, int speed, int duplex);
int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- u8 lane, int speed, int duplex);
+ int lane, int speed, int duplex);
unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
int port);
unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
int port);
-int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
-int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
-int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
+ bool on);
+int mv88e6393x_setup_errata(struct mv88e6xxx_chip *chip);
+int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable);
-int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable);
+int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
+ int lane, bool enable);
irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
+irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
+ int lane);
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
int port, uint8_t *data);
@@ -130,17 +169,17 @@ int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port);
void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);

/* Return the (first) SERDES lane address a port is using, 0 otherwise. */
-static inline u8 mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
+static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
int port)
{
if (!chip->info->ops->serdes_get_lane)
- return 0;
+ return -EOPNOTSUPP;

return chip->info->ops->serdes_get_lane(chip, port);
}

static inline int mv88e6xxx_serdes_power_up(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
if (!chip->info->ops->serdes_power)
return -EOPNOTSUPP;
@@ -149,7 +188,7 @@ static inline int mv88e6xxx_serdes_power_up(struct mv88e6xxx_chip *chip,
}

static inline int mv88e6xxx_serdes_power_down(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
if (!chip->info->ops->serdes_power)
return -EOPNOTSUPP;
@@ -167,7 +206,7 @@ mv88e6xxx_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
}

static inline int mv88e6xxx_serdes_irq_enable(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
if (!chip->info->ops->serdes_irq_enable)
return -EOPNOTSUPP;
@@ -176,7 +215,7 @@ static inline int mv88e6xxx_serdes_irq_enable(struct mv88e6xxx_chip *chip,
}

static inline int mv88e6xxx_serdes_irq_disable(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
+ int port, int lane)
{
if (!chip->info->ops->serdes_irq_enable)
return -EOPNOTSUPP;
@@ -185,7 +224,7 @@ static inline int mv88e6xxx_serdes_irq_disable(struct mv88e6xxx_chip *chip,
}

static inline irqreturn_t
-mv88e6xxx_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, u8 lane)
+mv88e6xxx_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, int lane)
{
if (!chip->info->ops->serdes_irq_status)
return IRQ_NONE;
--
2.17.1

2020-10-28 21:43:54

by Pavana Sharma

[permalink] [raw]
Subject: [PATCH v5 2/3] dt-bindings: net: Add 5GBASER phy interface mode

Add 5GBASE-R phy interface mode supported by mv88e6393
family.

Signed-off-by: Pavana Sharma <[email protected]>
---
Documentation/devicetree/bindings/net/ethernet-controller.yaml | 2 ++
1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/ethernet-controller.yaml b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
index fa2baca8c726..068c16fd27dc 100644
--- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml
+++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
@@ -92,6 +92,8 @@ properties:
- rxaui
- xaui

+ # 5GBASE-R
+ - 5gbase-r
# 10GBASE-KR, XFI, SFI
- 10gbase-kr
- usxgmii
--
2.17.1

2020-10-28 23:16:41

by Jakub Kicinski

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell

On Wed, 28 Oct 2020 10:09:50 +1000 Pavana Sharma wrote:
> The Marvell 88E6393X device is a single-chip integration of a 11-port
> Ethernet switch with eight integrated Gigabit Ethernet (GbE) transceivers
> and three 10-Gigabit interfaces.
>
> This patch adds functionalities specific to mv88e6393x family (88E6393X,
> 88E6193X and 88E6191X)
>
> Signed-off-by: Pavana Sharma <[email protected]>
> ---
> Changes in v2:
> - Fix a warning (Reported-by: kernel test robot <[email protected]>)
> Changes in v3:
> - Fix 'unused function' warning
> Changes in v4, v5:
> - Incorporated feedback from maintainers.

drivers/net/dsa/mv88e6xxx/port.c:29:5: warning: no previous prototype for ‘mv88e6xxx_port_wait_bit’ [-Wmissing-prototypes]
29 | int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/net/dsa/mv88e6xxx/port.c:29:5: warning: symbol 'mv88e6xxx_port_wait_bit' was not declared. Should it be static?
drivers/net/dsa/mv88e6xxx/port.c:29:5: warning: no previous prototype for ‘mv88e6xxx_port_wait_bit’ [-Wmissing-prototypes]
29 | int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
| ^~~~~~~~~~~~~~~~~~~~~~~

2020-10-29 00:32:57

by Marek Behún

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell

Pavana,

please add me to Cc for this.

Does USXGMII mode work? There are some erratas for for 10gb serdes mode.

Also you should split this patch. The code that refactores the
serdes_get_lane methods should be in a separate patch.

I have a device with this switch and also a SFP module which can
operate with USXGMII. I would like to get USXGMII mode to work before
this support is added, if possible. For some reason though I was unable
to get it to work, I will have to look at those erratas.

Marek

2020-10-29 07:56:37

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH v5 1/3] net: phy: Add 5GBASER interface mode

On Wed, Oct 28, 2020 at 10:08:27AM +1000, Pavana Sharma wrote:
> Add new mode supported by MV88E6393 family.
>
> Signed-off-by: Pavana Sharma <[email protected]>
> ---
> include/linux/phy.h | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/include/linux/phy.h b/include/linux/phy.h
> index 3a09d2bf69ea..9de7c57cfd38 100644
> --- a/include/linux/phy.h
> +++ b/include/linux/phy.h
> @@ -107,6 +107,7 @@ typedef enum {
> PHY_INTERFACE_MODE_2500BASEX,
> PHY_INTERFACE_MODE_RXAUI,
> PHY_INTERFACE_MODE_XAUI,
> + PHY_INTERFACE_MODE_5GBASER,
> /* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
> PHY_INTERFACE_MODE_10GBASER,
> PHY_INTERFACE_MODE_USXGMII,


Hi Pavana

You need to add this new mode to the kerneldoc above the
typedef. Otherwise you will get a warning from W=1 and kernel
documentation build process.

Andrew

2020-10-29 09:00:18

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell

Hi Pavana,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on net-next/master net/master linus/master sparc-next/master v5.10-rc1 next-20201028]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Pavana-Sharma/Add-support-for-mv88e6393x-family-of-Marvell/20201028-094528
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: x86_64-randconfig-a002-20201028 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 772aaa602383cf82795572ebcd86b0e660f3579f)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# https://github.com/0day-ci/linux/commit/f94f949ebd95e4501f9af58a2e358e5c32761c67
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Pavana-Sharma/Add-support-for-mv88e6393x-family-of-Marvell/20201028-094528
git checkout f94f949ebd95e4501f9af58a2e358e5c32761c67
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> drivers/net/dsa/mv88e6xxx/port.c:29:5: warning: no previous prototype for function 'mv88e6xxx_port_wait_bit' [-Wmissing-prototypes]
int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
^
drivers/net/dsa/mv88e6xxx/port.c:29:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
^
static
1 warning generated.

vim +/mv88e6xxx_port_wait_bit +29 drivers/net/dsa/mv88e6xxx/port.c

28
> 29 int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
30 int bit, int val)
31 {
32 int addr = chip->info->port_base_addr + port;
33
34 return mv88e6xxx_wait_bit(chip, addr, reg, bit, val);
35 }
36

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (2.62 kB)
.config.gz (41.19 kB)
Download all attachments

2020-10-29 10:00:15

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell

On Wed, Oct 28, 2020 at 10:09:50AM +1000, Pavana Sharma wrote:
> The Marvell 88E6393X device is a single-chip integration of a 11-port
> Ethernet switch with eight integrated Gigabit Ethernet (GbE) transceivers
> and three 10-Gigabit interfaces.
>
> This patch adds functionalities specific to mv88e6393x family (88E6393X,
> 88E6193X and 88E6191X)

Please break this patch up a bit into preparation patches, and the
last patch actually adding support for the new family.

e.g. serdes_get_lane() returning -ENODEV should be a patch of its
own. That should hopefully answer the question which

ommit 5122d4ec9e8053a5944bf77db6bd6c89143531d7
Author: Vivien Didelot <[email protected]>
Date: Sat Aug 31 16:18:30 2019 -0400

net: dsa: mv88e6xxx: simplify .serdes_get_lane

Because the mapping between a SERDES interface and its lane is static,
we don't need to stick with negative error codes actually and we can
simply return 0 if there is no lane, just like the IRQ mapping.

This way we can keep a simple and intuitive API using unsigned lane
numbers while simplifying the implementations with single return
statements

raises.

> +static const struct mv88e6xxx_ops mv88e6193x_ops = {
> + /* MV88E6XXX_FAMILY_6393 */
> + .setup_errata = mv88e6393x_setup_errata,
> + .irl_init_all = mv88e6390_g2_irl_init_all,
> + .get_eeprom = mv88e6xxx_g2_get_eeprom8,
> + .set_eeprom = mv88e6xxx_g2_set_eeprom8,
> + .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
> + .phy_read = mv88e6xxx_g2_smi_phy_read,
> + .phy_write = mv88e6xxx_g2_smi_phy_write,
> + .port_set_link = mv88e6xxx_port_set_link,
> + .port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
> + .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
> + .port_tag_remap = mv88e6390_port_tag_remap,
> + .port_set_frame_mode = mv88e6351_port_set_frame_mode,
> + .port_set_egress_floods = mv88e6352_port_set_egress_floods,
> + .port_set_ether_type = mv88e6393x_port_set_ether_type,
> + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
> + .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
> + .port_pause_limit = mv88e6390_port_pause_limit,
> + .port_set_cmode = mv88e6393x_port_set_cmode,
> + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
> + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
> + .port_get_cmode = mv88e6352_port_get_cmode,
> + .stats_snapshot = mv88e6390_g1_stats_snapshot,
> + .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
> + .stats_get_sset_count = mv88e6320_stats_get_sset_count,
> + .stats_get_strings = mv88e6320_stats_get_strings,
> + .stats_get_stats = mv88e6390_stats_get_stats,
> + .set_cpu_port = mv88e6393x_port_set_cpu_dest,
> + .set_egress_port = mv88e6393x_set_egress_port,
> + .watchdog_ops = &mv88e6390_watchdog_ops,
> + .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
> + .pot_clear = mv88e6xxx_g2_pot_clear,
> + .reset = mv88e6352_g1_reset,
> + .rmu_disable = mv88e6390_g1_rmu_disable,
> + .vtu_getnext = mv88e6390_g1_vtu_getnext,
> + .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
> + .serdes_power = mv88e6393x_serdes_power,
> + .serdes_get_lane = mv88e6393x_serdes_get_lane,
> + /* Check status register pause & lpa register */
> + .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
> + .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
> + .serdes_irq_enable = mv88e6393x_serdes_irq_enable,
> + .serdes_irq_status = mv88e6393x_serdes_irq_status,
> + .gpio_ops = &mv88e6352_gpio_ops,
> + .avb_ops = &mv88e6390_avb_ops,
> + .ptp_ops = &mv88e6352_ptp_ops,
> + .phylink_validate = mv88e6393x_phylink_validate,
> +};

> diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
> index 823ae89e5fca..03c0466ab4ae 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.h
> +++ b/drivers/net/dsa/mv88e6xxx/chip.h
> @@ -63,6 +63,8 @@ enum mv88e6xxx_model {
> MV88E6190,
> MV88E6190X,
> MV88E6191,
> + MV88E6191X,

Is the 6191X part of the 6193 family? Not the 6390, like the 6191 is?
Or do we have the 6191 in the wrong family?

> + MV88E6193X,

You don't add any _ops structure for the 6193x. How is it different?
Can you make your best guess at the ops structure. Also, what about
the 6191X?

> MV88E6220,
> MV88E6240,
> MV88E6250,
> @@ -75,6 +77,7 @@ enum mv88e6xxx_model {
> MV88E6352,
> MV88E6390,
> MV88E6390X,
> + MV88E6393X,
> };
>
> enum mv88e6xxx_family {
> @@ -90,6 +93,7 @@ enum mv88e6xxx_family {
> MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
> MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */
> MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */
> + MV88E6XXX_FAMILY_6393, /* 6191X 6193X 6393X */
> };

Andrew

2020-10-29 10:01:28

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH v5 2/3] dt-bindings: net: Add 5GBASER phy interface mode

On Wed, Oct 28, 2020 at 10:09:12AM +1000, Pavana Sharma wrote:
> Add 5GBASE-R phy interface mode supported by mv88e6393
> family.
>
> Signed-off-by: Pavana Sharma <[email protected]>

Reviewed-by: Andrew Lunn <[email protected]>

Andrew