On Thu, 29 Oct 2020 15:42:29 +1000
Pavana Sharma <[email protected]> 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)
>
> Co-developed-by: Ashkan Boldaji <[email protected]>
> Signed-off-by: Ashkan Boldaji <[email protected]>
> 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, v6:
> - 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 | 234 ++++++++++++++++++++++++++++
> drivers/net/dsa/mv88e6xxx/port.h | 43 ++++-
> drivers/net/dsa/mv88e6xxx/serdes.c | 225 ++++++++++++++++++++++++++
> drivers/net/dsa/mv88e6xxx/serdes.h | 39 +++++
> 8 files changed, 644 insertions(+), 2 deletions(-)
>
> 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 */
Is this a TODO comment? If so, it should be marked as such.
> + .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,
> + },
> +
Why not add 6393X here as well?
> [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
Since the family is called 6393X, please use MV88E6393X prefix for these
macros.
> #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
> +
Here you are using prefix with 6393X, but above you used 6193X, ...
> /* 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..8e36a69d8cad 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,6 +399,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, ®);
> + 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 +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;
> }
> @@ -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..fbe16168ac09 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
Different indentation (the first uses spaces, the second uses tabs)
> #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)*/
Space missing before end of comment */
> +#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
>
> @@ -288,7 +316,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
> u16 *val);
> int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
> u16 val);
> -
> +int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
> + int bit, int val);
> int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
> int pause);
> int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
> @@ -312,7 +341,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 +376,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 +399,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..9148dd0f4555 100644
> --- a/drivers/net/dsa/mv88e6xxx/serdes.c
> +++ b/drivers/net/dsa/mv88e6xxx/serdes.c
> @@ -526,6 +526,26 @@ 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.
> + */
> +u8 mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
> +{
> + u8 cmode = chip->ports[port].cmode;
> + u8 lane = 0;
> +
> + 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 +936,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 +1064,163 @@ 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, u8 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);
Thanks for the review.
Here's updated patchset.
Pavana Sharma (4):
dt-bindings: net: Add 5GBASER phy interface mode
net: phy: Add 5GBASER interface mode
net: dsa: mv88e6xxx: Change serdes lane parameter from u8 type to int
net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell
.../bindings/net/ethernet-controller.yaml | 2 +
drivers/net/dsa/mv88e6xxx/chip.c | 164 +++++++++-
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 | 43 ++-
drivers/net/dsa/mv88e6xxx/serdes.c | 299 +++++++++++++++---
drivers/net/dsa/mv88e6xxx/serdes.h | 91 ++++--
include/linux/phy.h | 4 +
10 files changed, 782 insertions(+), 91 deletions(-)
--
2.17.1
Add 5GBASE-R phy interface mode
Signed-off-by: Pavana Sharma <[email protected]>
---
include/linux/phy.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 3a09d2bf69ea..977b94a44e15 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -105,6 +105,8 @@ typedef enum {
PHY_INTERFACE_MODE_TRGMII,
PHY_INTERFACE_MODE_1000BASEX,
PHY_INTERFACE_MODE_2500BASEX,
+ /* 5GBASE-R mode */
+ PHY_INTERFACE_MODE_5GBASER,
PHY_INTERFACE_MODE_RXAUI,
PHY_INTERFACE_MODE_XAUI,
/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
@@ -183,6 +185,8 @@ static inline const char *phy_modes(phy_interface_t interface)
return "1000base-x";
case PHY_INTERFACE_MODE_2500BASEX:
return "2500base-x";
+ case PHY_INTERFACE_MODE_5GBASER:
+ return "5gbase-r";
case PHY_INTERFACE_MODE_RXAUI:
return "rxaui";
case PHY_INTERFACE_MODE_XAUI:
--
2.17.1
Add 5gbase-r PHY interface mode.
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..701ea18f811d 100644
--- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml
+++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
@@ -89,6 +89,8 @@ properties:
- trgmii
- 1000base-x
- 2500base-x
+ # 5GBASE-R
+ - 5gbase-r
- rxaui
- xaui
--
2.17.1
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 | 76 +++++++++++++++---------------
drivers/net/dsa/mv88e6xxx/serdes.h | 50 ++++++++++----------
5 files changed, 88 insertions(+), 88 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index f0dbc05e30a4..4994b8eee659 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 = -ENODEV;
int err;
mv88e6xxx_reg_lock(chip);
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane && chip->info->ops->serdes_pcs_get_state)
+ if ((lane >= 0) && 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 = -ENODEV;
if (ops->serdes_pcs_config) {
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane >= 0)
return ops->serdes_pcs_config(chip, port, lane, mode,
interface, advertise);
}
@@ -521,15 +521,15 @@ 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 lane = -ENODEV;
int err = 0;
- u8 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 >= 0)
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 = -ENODEV;
if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane >= 0)
return ops->serdes_pcs_link_up(chip, port, lane,
speed, duplex);
}
@@ -2424,11 +2424,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 = -ENODEV;
mv88e6xxx_reg_lock(chip);
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane)
+ if (lane >= 0)
ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -2436,7 +2436,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 +2465,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 +2490,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 = -ENODEV;
int err;
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (!lane)
+ if (lane < 0)
return 0;
if (on) {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 823ae89e5fca..c9acc6b01595 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -490,30 +490,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 8128dc607cf4..48b7654a8140 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -393,7 +393,7 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
- u8 lane;
+ int lane = -ENODEV;
u16 cmode;
u16 reg;
int err;
@@ -430,7 +430,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 >= 0) {
if (chip->ports[port].serdes_irq) {
err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
if (err)
@@ -459,7 +459,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 < 0)
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 9c07b4f3d345..787861f9a33d 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) >= 0)
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:
@@ -527,7 +527,7 @@ u8 mv88e6390x_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;
@@ -554,7 +554,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 +590,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
@@ -602,7 +602,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) < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -635,11 +635,11 @@ int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
{
struct mv88e6390_serdes_hw_stat *stat;
- int lane;
+ int lane = -ENODEV;
int i;
lane = mv88e6390_serdes_get_lane(chip, port);
- if (lane == 0)
+ if (lane < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -650,7 +650,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 +665,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 +690,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 +749,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 +772,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 +792,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 +811,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 +827,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 +861,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 +878,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 +890,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 +906,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;
@@ -917,7 +917,7 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
}
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 +976,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
@@ -985,12 +985,12 @@ 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)
{
u16 *p = _p;
- int lane;
+ int lane = -ENODEV;
u16 reg;
int i;
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane == 0)
+ if (lane < 0)
return;
for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index 14315f26228a..e6797472faef 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -73,46 +73,46 @@
#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);
+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 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 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);
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);
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);
@@ -129,18 +129,18 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
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. */
+/* Return the (first) SERDES lane address a port is using, ERROR otherwise. */
static inline u8 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 +149,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 +167,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 +176,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 +185,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
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)
Co-developed-by: Ashkan Boldaji <[email protected]>
Signed-off-by: Ashkan Boldaji <[email protected]>
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-v7:
- Incorporated feedback from maintainers.
---
drivers/net/dsa/mv88e6xxx/chip.c | 136 ++++++++++++++++
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 | 234 ++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 43 ++++-
drivers/net/dsa/mv88e6xxx/serdes.c | 225 +++++++++++++++++++++++++-
drivers/net/dsa/mv88e6xxx/serdes.h | 41 ++++-
8 files changed, 689 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 4994b8eee659..35aeeff49b21 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,55 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.phylink_validate = mv88e6390_phylink_validate,
};
+static const struct mv88e6xxx_ops mv88e6393x_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,
+ .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,52 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6191_ops,
},
+ [MV88E6191X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6191X",
+ .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 = &mv88e6393x_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 = &mv88e6393x_ops,
+ },
+
[MV88E6220] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
.family = MV88E6XXX_FAMILY_6250,
@@ -5363,6 +5476,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ptp_support = true,
.ops = &mv88e6390x_ops,
},
+
+ [MV88E6393X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6393X",
+ .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 = &mv88e6393x_ops,
+ },
};
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index c9acc6b01595..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;
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 1e3546f8b072..6d6c59d594a0 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 MV88E6393X_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 MV88E6393X_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 48b7654a8140..512fa842162c 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,6 +399,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, ®);
+ 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)
{
@@ -414,6 +504,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
case PHY_INTERFACE_MODE_2500BASEX:
cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
break;
+ case PHY_INTERFACE_MODE_5GBASER:
+ cmode = MV88E6XXX_PORT_STS_CMODE_5GBASER;
+ break;
case PHY_INTERFACE_MODE_XGMII:
case PHY_INTERFACE_MODE_XAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
@@ -421,6 +514,13 @@ 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_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 +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..2ed1eef15bca 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
@@ -288,7 +316,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
u16 *val);
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
u16 val);
-
+int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
+ int bit, int val);
int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
int pause);
int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
@@ -312,7 +341,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 +376,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 +399,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 787861f9a33d..7c7a853627be 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -526,6 +526,26 @@ int 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, int lane,
bool up)
@@ -916,6 +936,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,
+ 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,
int lane)
{
@@ -984,8 +1049,8 @@ 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)
{
- u16 *p = _p;
int lane = -ENODEV;
+ u16 *p = _p;
u16 reg;
int i;
@@ -999,3 +1064,161 @@ 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 e6797472faef..fe08dd5764b8 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)
+
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,
int lane, unsigned int mode,
phy_interface_t interface,
@@ -105,14 +137,21 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
+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, 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,
int lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
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,7 +169,7 @@ 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, ERROR 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)
--
2.17.1
On Mon, Nov 02, 2020 at 04:42:06PM +1000, Pavana Sharma wrote:
> Add 5GBASE-R phy interface mode
>
> Signed-off-by: Pavana Sharma <[email protected]>
How many times have i asked for you to add kerneldoc for this new
value? How many times have you not done so?
NACK.
If you don't understand a comment, please ask.
Andrew
On Mon, Nov 02, 2020 at 04:40:02PM +1000, Pavana Sharma wrote:
> Thanks for the review.
> Here's updated patchset.
Please include a short description of what you have changed since the
last version. It helps us as maintainers see if you have attempted to
make the changes we have requested, or not.
Andrew
> @@ -985,12 +985,12 @@ 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)
> {
> u16 *p = _p;
> - int lane;
> + int lane = -ENODEV;
> u16 reg;
> int i;
The reverse christmas tree is wrong here.
Andrew
On Mon, Nov 02, 2020 at 04:43:09PM +1000, Pavana Sharma wrote:
> 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 | 76 +++++++++++++++---------------
> drivers/net/dsa/mv88e6xxx/serdes.h | 50 ++++++++++----------
> 5 files changed, 88 insertions(+), 88 deletions(-)
>
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
> index f0dbc05e30a4..4994b8eee659 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 = -ENODEV;
> int err;
You have added a lot of initialises which are not needed.
>
> mv88e6xxx_reg_lock(chip);
> lane = mv88e6xxx_serdes_get_lane(chip, port);
lane is always set, so there is no point in setting it to -ENODEV
first.
> - if (lane && chip->info->ops->serdes_pcs_get_state)
> + if ((lane >= 0) && 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 = -ENODEV;
>
> if (ops->serdes_pcs_config) {
> lane = mv88e6xxx_serdes_get_lane(chip, port);
> - if (lane)
> + if (lane >= 0)
> return ops->serdes_pcs_config(chip, port, lane, mode,
> interface, advertise);
> }
> @@ -521,15 +521,15 @@ 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 lane = -ENODEV;
> int err = 0;
> - u8 lane;
>
> ops = chip->info->ops;
>
> if (ops->serdes_pcs_an_restart) {
> mv88e6xxx_reg_lock(chip);
> lane = mv88e6xxx_serdes_get_lane(chip, port);
> - if (lane)
lane is always set inside this if statement, and is never used outside
of it.
> + if (lane >= 0)
> 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 = -ENODEV;
>
> if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
> lane = mv88e6xxx_serdes_get_lane(chip, port);
> - if (lane)
> + if (lane >= 0)
> return ops->serdes_pcs_link_up(chip, port, lane,
lane is always set, and never used outside of the if ....
Andrew
> How many times have i asked for you to add kerneldoc for this new
> value? How many times have you not done so?
I have added kerneldoc comment for the new value added.
> NACK.
> If you don't understand a comment, please ask.
Ok, explain what do you expect by that comment.
On 11/2/2020 5:34 PM, Pavana Sharma wrote:
>> How many times have i asked for you to add kerneldoc for this new
>> value? How many times have you not done so?
>
> I have added kerneldoc comment for the new value added.
>
>> NACK.
>
>> If you don't understand a comment, please ask.
>
> Ok, explain what do you expect by that comment.
What Andrew wants you to do is add a comment like this:
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/include/linux/phy.h#n88
--
Florian
On Mon, Nov 02, 2020 at 06:12:32PM -0800, Florian Fainelli wrote:
>
>
> On 11/2/2020 5:34 PM, Pavana Sharma wrote:
> >> How many times have i asked for you to add kerneldoc for this new
> >> value? How many times have you not done so?
> >
> > I have added kerneldoc comment for the new value added.
> >
> >> NACK.
> >
> >> If you don't understand a comment, please ask.
> >
> > Ok, explain what do you expect by that comment.
>
> What Andrew wants you to do is add a comment like this:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/include/linux/phy.h#n88
Hi Pavana
This should also help:
https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html
And please compile the kernel with the W=1 flag. Make sure changes you
make don't add new warnings. You will see a warning from this new enum
valu you are adding because it is not correctly documented.
Andrew
Updated patchset with following changes.
- Add kerneldoc for 5GBASER phy interface
- Remove lane param initialization wherever is it not needed.
Pavana Sharma (4):
dt-bindings: net: Add 5GBASER phy interface mode
net: phy: Add 5GBASER interface mode
net: dsa: mv88e6xxx: Change serdes lane parameter from u8 type to int
net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell
.../bindings/net/ethernet-controller.yaml | 2 +
drivers/net/dsa/mv88e6xxx/chip.c | 164 +++++++++-
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 | 43 ++-
drivers/net/dsa/mv88e6xxx/serdes.c | 295 +++++++++++++++---
drivers/net/dsa/mv88e6xxx/serdes.h | 91 ++++--
include/linux/phy.h | 5 +
10 files changed, 781 insertions(+), 89 deletions(-)
--
2.17.1
Add 5gbase-r PHY interface mode.
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 fdf709817218..aa6ae7851de9 100644
--- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml
+++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
@@ -89,6 +89,8 @@ properties:
- trgmii
- 1000base-x
- 2500base-x
+ # 5GBASE-R
+ - 5gbase-r
- rxaui
- xaui
--
2.17.1
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 | 74 +++++++++++++++---------------
drivers/net/dsa/mv88e6xxx/serdes.h | 50 ++++++++++----------
5 files changed, 87 insertions(+), 87 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index bd297ae7cf9e..d32731a7c658 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -485,12 +485,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 >= 0) && chip->info->ops->serdes_pcs_get_state)
err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
state);
else
@@ -506,11 +506,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 >= 0)
return ops->serdes_pcs_config(chip, port, lane, mode,
interface, advertise);
}
@@ -522,15 +522,15 @@ 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 lane;
int err = 0;
- u8 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 >= 0)
err = ops->serdes_pcs_an_restart(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -544,11 +544,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 >= 0)
return ops->serdes_pcs_link_up(chip, port, lane,
speed, duplex);
}
@@ -2422,11 +2422,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 >= 0)
ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -2434,7 +2434,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;
@@ -2463,7 +2463,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;
@@ -2488,11 +2488,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 < 0)
return 0;
if (on) {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 81c244fc0419..d81f586d67e8 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -506,30 +506,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 8128dc607cf4..89d4c16fbbb5 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -393,8 +393,8 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
- u8 lane;
u16 cmode;
+ int lane;
u16 reg;
int err;
@@ -430,7 +430,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 >= 0) {
if (chip->ports[port].serdes_irq) {
err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
if (err)
@@ -459,7 +459,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 < 0)
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 9c07b4f3d345..25d2d1b4f631 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) >= 0)
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:
@@ -527,7 +527,7 @@ u8 mv88e6390x_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;
@@ -554,7 +554,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 +590,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
@@ -602,7 +602,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) < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -639,7 +639,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 < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -650,7 +650,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 +665,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 +690,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 +749,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 +772,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 +792,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 +811,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 +827,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 +861,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 +878,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 +890,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 +906,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;
@@ -917,7 +917,7 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
}
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 +976,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
@@ -984,13 +984,13 @@ 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)
{
- u16 *p = _p;
int lane;
+ u16 *p = _p;
u16 reg;
int i;
lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane == 0)
+ if (lane < 0)
return;
for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index 14315f26228a..e6797472faef 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -73,46 +73,46 @@
#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);
+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 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 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);
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);
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);
@@ -129,18 +129,18 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
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. */
+/* Return the (first) SERDES lane address a port is using, ERROR otherwise. */
static inline u8 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 +149,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 +167,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 +176,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 +185,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
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)
Co-developed-by: Ashkan Boldaji <[email protected]>
Signed-off-by: Ashkan Boldaji <[email protected]>
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-v8:
- Incorporated feedback from maintainers.
---
drivers/net/dsa/mv88e6xxx/chip.c | 136 ++++++++++++++++
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 | 234 ++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 43 ++++-
drivers/net/dsa/mv88e6xxx/serdes.c | 225 +++++++++++++++++++++++++-
drivers/net/dsa/mv88e6xxx/serdes.h | 41 ++++-
8 files changed, 689 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index d32731a7c658..bfcbe70affa3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -635,6 +635,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)
@@ -3906,6 +3924,55 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.phylink_validate = mv88e6390_phylink_validate,
};
+static const struct mv88e6xxx_ops mv88e6393x_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,
+ .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,
@@ -4838,6 +4905,52 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6191_ops,
},
+ [MV88E6191X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6191X",
+ .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 = &mv88e6393x_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 = &mv88e6393x_ops,
+ },
+
[MV88E6220] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
.family = MV88E6XXX_FAMILY_6250,
@@ -5128,6 +5241,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ptp_support = true,
.ops = &mv88e6390x_ops,
},
+
+ [MV88E6393X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6393X",
+ .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 = &mv88e6393x_ops,
+ },
};
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index d81f586d67e8..2264394633c0 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..6d6c59d594a0 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 MV88E6393X_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 MV88E6393X_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 89d4c16fbbb5..709f4c50cc9e 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,6 +399,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, ®);
+ 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)
{
@@ -414,6 +504,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
case PHY_INTERFACE_MODE_2500BASEX:
cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
break;
+ case PHY_INTERFACE_MODE_5GBASER:
+ cmode = MV88E6XXX_PORT_STS_CMODE_5GBASER;
+ break;
case PHY_INTERFACE_MODE_XGMII:
case PHY_INTERFACE_MODE_XAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
@@ -421,6 +514,13 @@ 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_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 +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..2ed1eef15bca 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
@@ -288,7 +316,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
u16 *val);
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
u16 val);
-
+int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
+ int bit, int val);
int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
int pause);
int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
@@ -312,7 +341,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 +376,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 +399,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 25d2d1b4f631..ca7b2575aedc 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -526,6 +526,26 @@ int 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, int lane,
bool up)
@@ -916,6 +936,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,
+ 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,
int lane)
{
@@ -984,8 +1049,8 @@ 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)
{
- int lane;
u16 *p = _p;
+ int lane;
u16 reg;
int i;
@@ -999,3 +1064,161 @@ 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 e6797472faef..fe08dd5764b8 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)
+
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,
int lane, unsigned int mode,
phy_interface_t interface,
@@ -105,14 +137,21 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
+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, 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,
int lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
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,7 +169,7 @@ 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, ERROR 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)
--
2.17.1
Add 5GBASE-R phy interface mode
Signed-off-by: Pavana Sharma <[email protected]>
---
include/linux/phy.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index eb3cb1a98b45..71e280059ec5 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -106,6 +106,7 @@ extern const int phy_10gbit_features_array[1];
* @PHY_INTERFACE_MODE_TRGMII: Turbo RGMII
* @PHY_INTERFACE_MODE_1000BASEX: 1000 BaseX
* @PHY_INTERFACE_MODE_2500BASEX: 2500 BaseX
+ * @PHY_INTERFACE_MODE_5GBASER: 5G BaseR
* @PHY_INTERFACE_MODE_RXAUI: Reduced XAUI
* @PHY_INTERFACE_MODE_XAUI: 10 Gigabit Attachment Unit Interface
* @PHY_INTERFACE_MODE_10GBASER: 10G BaseR
@@ -137,6 +138,8 @@ typedef enum {
PHY_INTERFACE_MODE_TRGMII,
PHY_INTERFACE_MODE_1000BASEX,
PHY_INTERFACE_MODE_2500BASEX,
+ /* 5GBASE-R mode */
+ PHY_INTERFACE_MODE_5GBASER,
PHY_INTERFACE_MODE_RXAUI,
PHY_INTERFACE_MODE_XAUI,
/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
@@ -215,6 +218,8 @@ static inline const char *phy_modes(phy_interface_t interface)
return "1000base-x";
case PHY_INTERFACE_MODE_2500BASEX:
return "2500base-x";
+ case PHY_INTERFACE_MODE_5GBASER:
+ return "5gbase-r";
case PHY_INTERFACE_MODE_RXAUI:
return "rxaui";
case PHY_INTERFACE_MODE_XAUI:
--
2.17.1
On Tue, 3 Nov 2020 18:50:02 +1000 Pavana Sharma wrote:
> 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]>
> mv88e6xxx_reg_lock(chip);
> lane = mv88e6xxx_serdes_get_lane(chip, port);
> - if (lane && chip->info->ops->serdes_pcs_get_state)
> + if ((lane >= 0) && chip->info->ops->serdes_pcs_get_state)
unnecessary parenthesis, checkpatch even warns about this
> err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
> state);
> else
> @@ -522,15 +522,15 @@ 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 lane;
> int err = 0;
Please keep the reverse xmas tree order of variables
int lane; should be after int err = 0;
We're ordering full lines, not just the type and name.
> - u8 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 >= 0)
> err = ops->serdes_pcs_an_restart(chip, port, lane);
> mv88e6xxx_reg_unlock(chip);
> void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
> {
> - u16 *p = _p;
> int lane;
> + u16 *p = _p;
> u16 reg;
> int i;
ditto
> @@ -129,18 +129,18 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
> 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. */
> +/* Return the (first) SERDES lane address a port is using, ERROR otherwise. */
The usual notation is -errno, instead of ERROR.
On Tue, 3 Nov 2020 18:49:02 +1000 Pavana Sharma wrote:
> Add 5gbase-r PHY interface mode.
>
> Signed-off-by: Pavana Sharma <[email protected]>
Please always CC device tree maintainers and list on patches which
touch bindings. Even if there is no need for review Rob has a bot
which will catch any formatting errors.
On Tue, 3 Nov 2020 18:50:38 +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 fix all checkpatch --strict --min-conf-desc-length=80 warnings
and what I point out below
> Co-developed-by: Ashkan Boldaji <[email protected]>
> Signed-off-by: Ashkan Boldaji <[email protected]>
> Signed-off-by: Pavana Sharma <[email protected]>
> + reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
> + MV88E6390_PORT_MAC_CTL_ALTSPEED |
> + MV88E6390_PORT_MAC_CTL_FORCE_SPEED);
Align the continuation lines under the opening bracket, like the kernel
coding style require, please.
> +
> + 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;
no need to set err, just directly do:
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL,
reg);
> +}
> +
> static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
> phy_interface_t mode, bool force)
> {
> +/* Offset 0x0E: Policy & MGMT Control Register for FAMILY 6191X 6193X 6393X*/
Missing space at the end of that comment.
> +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;
did you mean to exit here? this assignment looks pointless
> + }
> + 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_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;
return mv...
> +}
> +
> + err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
> + if (err)
> + return err;
> +
> + return 0;
ditto
> +}
> +
> +int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
> + bool on)
> +{
> + if (port == 0 || port == 9 || port == 10) {
Flip the condition, return early. Entire body of a function should not
have to be indented.
> + 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;
> +}
> @@ -130,7 +169,7 @@ 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, ERROR 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)
Looks like this should be in patch 3?
> {
> if (!chip->info->ops->serdes_get_lane)
Thanks for the review.
Here's updated patchset.
All possible checkpatch 'checks' are attended.
Pavana Sharma (4):
dt-bindings: net: Add 5GBASER phy interface mode
net: phy: Add 5GBASER interface mode
net: dsa: mv88e6xxx: Change serdes lane parameter from u8 type to int
net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell
.../bindings/net/ethernet-controller.yaml | 2 +
drivers/net/dsa/mv88e6xxx/chip.c | 164 +++++++++-
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 | 43 ++-
drivers/net/dsa/mv88e6xxx/serdes.c | 296 +++++++++++++++---
drivers/net/dsa/mv88e6xxx/serdes.h | 93 ++++--
include/linux/phy.h | 5 +
10 files changed, 781 insertions(+), 92 deletions(-)
--
2.17.1
Add 5GBASE-R phy interface mode
Signed-off-by: Pavana Sharma <[email protected]>
---
include/linux/phy.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index eb3cb1a98b45..71e280059ec5 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -106,6 +106,7 @@ extern const int phy_10gbit_features_array[1];
* @PHY_INTERFACE_MODE_TRGMII: Turbo RGMII
* @PHY_INTERFACE_MODE_1000BASEX: 1000 BaseX
* @PHY_INTERFACE_MODE_2500BASEX: 2500 BaseX
+ * @PHY_INTERFACE_MODE_5GBASER: 5G BaseR
* @PHY_INTERFACE_MODE_RXAUI: Reduced XAUI
* @PHY_INTERFACE_MODE_XAUI: 10 Gigabit Attachment Unit Interface
* @PHY_INTERFACE_MODE_10GBASER: 10G BaseR
@@ -137,6 +138,8 @@ typedef enum {
PHY_INTERFACE_MODE_TRGMII,
PHY_INTERFACE_MODE_1000BASEX,
PHY_INTERFACE_MODE_2500BASEX,
+ /* 5GBASE-R mode */
+ PHY_INTERFACE_MODE_5GBASER,
PHY_INTERFACE_MODE_RXAUI,
PHY_INTERFACE_MODE_XAUI,
/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
@@ -215,6 +218,8 @@ static inline const char *phy_modes(phy_interface_t interface)
return "1000base-x";
case PHY_INTERFACE_MODE_2500BASEX:
return "2500base-x";
+ case PHY_INTERFACE_MODE_5GBASER:
+ return "5gbase-r";
case PHY_INTERFACE_MODE_RXAUI:
return "rxaui";
case PHY_INTERFACE_MODE_XAUI:
--
2.17.1
Add 5gbase-r PHY interface mode.
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 fdf709817218..aa6ae7851de9 100644
--- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml
+++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
@@ -89,6 +89,8 @@ properties:
- trgmii
- 1000base-x
- 2500base-x
+ # 5GBASE-R
+ - 5gbase-r
- rxaui
- xaui
--
2.17.1
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)
Co-developed-by: Ashkan Boldaji <[email protected]>
Signed-off-by: Ashkan Boldaji <[email protected]>
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-v9:
- Incorporated feedback from maintainers.
---
drivers/net/dsa/mv88e6xxx/chip.c | 136 ++++++++++++++++
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 | 234 +++++++++++++++++++++++++++-
drivers/net/dsa/mv88e6xxx/port.h | 43 ++++-
drivers/net/dsa/mv88e6xxx/serdes.c | 224 ++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/serdes.h | 39 +++++
8 files changed, 686 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 57b6ce785629..4bde9754ea8a 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -635,6 +635,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)
@@ -3906,6 +3924,55 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.phylink_validate = mv88e6390_phylink_validate,
};
+static const struct mv88e6xxx_ops mv88e6393x_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,
+ .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,
@@ -4838,6 +4905,52 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6191_ops,
},
+ [MV88E6191X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6191X",
+ .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 = &mv88e6393x_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 = &mv88e6393x_ops,
+ },
+
[MV88E6220] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
.family = MV88E6XXX_FAMILY_6250,
@@ -5128,6 +5241,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ptp_support = true,
.ops = &mv88e6390x_ops,
},
+
+ [MV88E6393X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6393X",
+ .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 = &mv88e6393x_ops,
+ },
};
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index d81f586d67e8..2264394633c0 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..6d6c59d594a0 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 MV88E6393X_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 MV88E6393X_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 89d4c16fbbb5..e3737246ba57 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)
{
@@ -222,8 +231,8 @@ static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,
return err;
reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
- MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
- MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
+ MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
+ MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
if (alt_bit)
reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
@@ -390,6 +399,84 @@ 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, ®);
+ 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;
+
+ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+
+}
+
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
@@ -414,6 +501,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
case PHY_INTERFACE_MODE_2500BASEX:
cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
break;
+ case PHY_INTERFACE_MODE_5GBASER:
+ cmode = MV88E6XXX_PORT_STS_CMODE_5GBASER;
+ break;
case PHY_INTERFACE_MODE_XGMII:
case PHY_INTERFACE_MODE_XAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
@@ -421,6 +511,13 @@ 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_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 +602,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 +1234,130 @@ 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);
+ return -EINVAL;
+ }
+ reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL, reg);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+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;
+
+ return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
+}
+
/* 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..2ed1eef15bca 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
@@ -288,7 +316,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
u16 *val);
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
u16 val);
-
+int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
+ int bit, int val);
int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
int pause);
int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
@@ -312,7 +341,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 +376,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 +399,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 058cce01c01e..9a6822eaf3b9 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -526,6 +526,26 @@ int 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, int lane,
bool up)
@@ -916,6 +936,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,
+ 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,
int lane)
{
@@ -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)
+ return -EOPNOTSUPP;
+
+ 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 ed3181e82da9..d508978e5944 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)
+
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,
int lane, unsigned int mode,
phy_interface_t interface,
@@ -105,14 +137,21 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
+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, 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,
int lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
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);
--
2.17.1
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 -errno (-ENODEV or -EOPNOTSUPP).
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 | 72 +++++++++++++++---------------
drivers/net/dsa/mv88e6xxx/serdes.h | 54 +++++++++++-----------
5 files changed, 88 insertions(+), 88 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index bd297ae7cf9e..57b6ce785629 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -485,12 +485,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 >= 0 && chip->info->ops->serdes_pcs_get_state)
err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
state);
else
@@ -506,11 +506,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 >= 0)
return ops->serdes_pcs_config(chip, port, lane, mode,
interface, advertise);
}
@@ -523,14 +523,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 >= 0)
err = ops->serdes_pcs_an_restart(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -544,11 +544,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 >= 0)
return ops->serdes_pcs_link_up(chip, port, lane,
speed, duplex);
}
@@ -2422,11 +2422,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 >= 0)
ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -2434,7 +2434,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;
@@ -2463,7 +2463,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;
@@ -2488,11 +2488,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 < 0)
return 0;
if (on) {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 81c244fc0419..d81f586d67e8 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -506,30 +506,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 8128dc607cf4..89d4c16fbbb5 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -393,8 +393,8 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
- u8 lane;
u16 cmode;
+ int lane;
u16 reg;
int err;
@@ -430,7 +430,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 >= 0) {
if (chip->ports[port].serdes_irq) {
err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
if (err)
@@ -459,7 +459,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 < 0)
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 9c07b4f3d345..058cce01c01e 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) >= 0)
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:
@@ -527,7 +527,7 @@ u8 mv88e6390x_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;
@@ -554,7 +554,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 +590,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
@@ -602,7 +602,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) < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -639,7 +639,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 < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -650,7 +650,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 +665,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 +690,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 +749,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 +772,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 +792,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 +811,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 +827,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 +861,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 +878,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 +890,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 +906,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;
@@ -917,7 +917,7 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
}
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 +976,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
@@ -990,7 +990,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 < 0)
return;
for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index 14315f26228a..ed3181e82da9 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -73,46 +73,46 @@
#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);
+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 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 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);
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);
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);
@@ -129,18 +129,18 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
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,
- int port)
+/* Return the (first) SERDES lane address a port is using, -errno otherwise. */
+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 +149,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 +167,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 +176,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 +185,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
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 v5.10-rc4 next-20201119]
[cannot apply to sparc-next/master]
[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/20201119-160915
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: sh-allmodconfig (attached as .config)
compiler: sh4-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/2b347d8ede029475baf73ac8e08ea38dad2526e4
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/20201119-160915
git checkout 2b347d8ede029475baf73ac8e08ea38dad2526e4
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=sh
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/serdes.c: In function 'mv88e6393x_serdes_power':
>> drivers/net/dsa/mv88e6xxx/serdes.c:1212:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
1212 | u8 cmode = chip->ports[port].cmode;
| ^~
vim +1212 drivers/net/dsa/mv88e6xxx/serdes.c
1205
1206 int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
1207 bool on)
1208 {
1209 if (port != 0 && port != 9 && port != 10)
1210 return -EOPNOTSUPP;
1211
> 1212 u8 cmode = chip->ports[port].cmode;
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]
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 v5.10-rc4 next-20201119]
[cannot apply to sparc-next/master]
[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/20201119-160915
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: x86_64-randconfig-a004-20201119 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project b2613fb2f0f53691dd0211895afbb9413457fca7)
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/2b347d8ede029475baf73ac8e08ea38dad2526e4
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/20201119-160915
git checkout 2b347d8ede029475baf73ac8e08ea38dad2526e4
# 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/serdes.c:1212:5: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
u8 cmode = chip->ports[port].cmode;
^
1 warning generated.
vim +1212 drivers/net/dsa/mv88e6xxx/serdes.c
1205
1206 int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
1207 bool on)
1208 {
1209 if (port != 0 && port != 9 && port != 10)
1210 return -EOPNOTSUPP;
1211
> 1212 u8 cmode = chip->ports[port].cmode;
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]
Updated patchset after fixing a warning.
Pavana Sharma (4):
dt-bindings: net: Add 5GBASER phy interface mode
net: phy: Add 5GBASER interface mode
net: dsa: mv88e6xxx: Change serdes lane parameter from u8 type to int
net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell
.../bindings/net/ethernet-controller.yaml | 2 +
drivers/net/dsa/mv88e6xxx/chip.c | 164 +++++++++-
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 | 43 ++-
drivers/net/dsa/mv88e6xxx/serdes.c | 298 +++++++++++++++---
drivers/net/dsa/mv88e6xxx/serdes.h | 93 ++++--
include/linux/phy.h | 5 +
10 files changed, 783 insertions(+), 92 deletions(-)
--
2.17.1
Add 5gbase-r PHY interface mode.
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 fdf709817218..aa6ae7851de9 100644
--- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml
+++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
@@ -89,6 +89,8 @@ properties:
- trgmii
- 1000base-x
- 2500base-x
+ # 5GBASE-R
+ - 5gbase-r
- rxaui
- xaui
--
2.17.1
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)
Co-developed-by: Ashkan Boldaji <[email protected]>
Signed-off-by: Ashkan Boldaji <[email protected]>
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-v9:
- Incorporated feedback from maintainers.
Changes in v10:
- Fix ISO C90 forbids mixing declarations and code warning
---
drivers/net/dsa/mv88e6xxx/chip.c | 136 ++++++++++++++++
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 | 234 +++++++++++++++++++++++++++-
drivers/net/dsa/mv88e6xxx/port.h | 43 ++++-
drivers/net/dsa/mv88e6xxx/serdes.c | 226 +++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/serdes.h | 39 +++++
8 files changed, 688 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 57b6ce785629..4bde9754ea8a 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -635,6 +635,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)
@@ -3906,6 +3924,55 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.phylink_validate = mv88e6390_phylink_validate,
};
+static const struct mv88e6xxx_ops mv88e6393x_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,
+ .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,
@@ -4838,6 +4905,52 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6191_ops,
},
+ [MV88E6191X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6191X",
+ .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 = &mv88e6393x_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 = &mv88e6393x_ops,
+ },
+
[MV88E6220] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
.family = MV88E6XXX_FAMILY_6250,
@@ -5128,6 +5241,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ptp_support = true,
.ops = &mv88e6390x_ops,
},
+
+ [MV88E6393X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6393X",
+ .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 = &mv88e6393x_ops,
+ },
};
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index d81f586d67e8..2264394633c0 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..6d6c59d594a0 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 MV88E6393X_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 MV88E6393X_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 89d4c16fbbb5..e3737246ba57 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)
{
@@ -222,8 +231,8 @@ static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,
return err;
reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
- MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
- MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
+ MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
+ MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
if (alt_bit)
reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
@@ -390,6 +399,84 @@ 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, ®);
+ 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;
+
+ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+
+}
+
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
@@ -414,6 +501,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
case PHY_INTERFACE_MODE_2500BASEX:
cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
break;
+ case PHY_INTERFACE_MODE_5GBASER:
+ cmode = MV88E6XXX_PORT_STS_CMODE_5GBASER;
+ break;
case PHY_INTERFACE_MODE_XGMII:
case PHY_INTERFACE_MODE_XAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
@@ -421,6 +511,13 @@ 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_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 +602,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 +1234,130 @@ 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);
+ return -EINVAL;
+ }
+ reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL, reg);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+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;
+
+ return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
+}
+
/* 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..2ed1eef15bca 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
@@ -288,7 +316,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
u16 *val);
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
u16 val);
-
+int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
+ int bit, int val);
int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
int pause);
int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
@@ -312,7 +341,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 +376,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 +399,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 058cce01c01e..3ad256518b30 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -526,6 +526,26 @@ int 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, int lane,
bool up)
@@ -916,6 +936,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,
+ 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,
int lane)
{
@@ -999,3 +1064,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, int lane,
+ bool on)
+{
+ u8 cmode;
+
+ if (port != 0 && port != 9 && port != 10)
+ return -EOPNOTSUPP;
+
+ 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 ed3181e82da9..d508978e5944 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)
+
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,
int lane, unsigned int mode,
phy_interface_t interface,
@@ -105,14 +137,21 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
+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, 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,
int lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
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);
--
2.17.1
Add 5GBASE-R phy interface mode
Signed-off-by: Pavana Sharma <[email protected]>
---
include/linux/phy.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index eb3cb1a98b45..71e280059ec5 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -106,6 +106,7 @@ extern const int phy_10gbit_features_array[1];
* @PHY_INTERFACE_MODE_TRGMII: Turbo RGMII
* @PHY_INTERFACE_MODE_1000BASEX: 1000 BaseX
* @PHY_INTERFACE_MODE_2500BASEX: 2500 BaseX
+ * @PHY_INTERFACE_MODE_5GBASER: 5G BaseR
* @PHY_INTERFACE_MODE_RXAUI: Reduced XAUI
* @PHY_INTERFACE_MODE_XAUI: 10 Gigabit Attachment Unit Interface
* @PHY_INTERFACE_MODE_10GBASER: 10G BaseR
@@ -137,6 +138,8 @@ typedef enum {
PHY_INTERFACE_MODE_TRGMII,
PHY_INTERFACE_MODE_1000BASEX,
PHY_INTERFACE_MODE_2500BASEX,
+ /* 5GBASE-R mode */
+ PHY_INTERFACE_MODE_5GBASER,
PHY_INTERFACE_MODE_RXAUI,
PHY_INTERFACE_MODE_XAUI,
/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
@@ -215,6 +218,8 @@ static inline const char *phy_modes(phy_interface_t interface)
return "1000base-x";
case PHY_INTERFACE_MODE_2500BASEX:
return "2500base-x";
+ case PHY_INTERFACE_MODE_5GBASER:
+ return "5gbase-r";
case PHY_INTERFACE_MODE_RXAUI:
return "rxaui";
case PHY_INTERFACE_MODE_XAUI:
--
2.17.1
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 -errno (-ENODEV or -EOPNOTSUPP).
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 | 72 +++++++++++++++---------------
drivers/net/dsa/mv88e6xxx/serdes.h | 54 +++++++++++-----------
5 files changed, 88 insertions(+), 88 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index bd297ae7cf9e..57b6ce785629 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -485,12 +485,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 >= 0 && chip->info->ops->serdes_pcs_get_state)
err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
state);
else
@@ -506,11 +506,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 >= 0)
return ops->serdes_pcs_config(chip, port, lane, mode,
interface, advertise);
}
@@ -523,14 +523,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 >= 0)
err = ops->serdes_pcs_an_restart(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -544,11 +544,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 >= 0)
return ops->serdes_pcs_link_up(chip, port, lane,
speed, duplex);
}
@@ -2422,11 +2422,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 >= 0)
ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -2434,7 +2434,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;
@@ -2463,7 +2463,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;
@@ -2488,11 +2488,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 < 0)
return 0;
if (on) {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 81c244fc0419..d81f586d67e8 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -506,30 +506,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 8128dc607cf4..89d4c16fbbb5 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -393,8 +393,8 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
- u8 lane;
u16 cmode;
+ int lane;
u16 reg;
int err;
@@ -430,7 +430,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 >= 0) {
if (chip->ports[port].serdes_irq) {
err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
if (err)
@@ -459,7 +459,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 < 0)
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 9c07b4f3d345..058cce01c01e 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) >= 0)
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:
@@ -527,7 +527,7 @@ u8 mv88e6390x_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;
@@ -554,7 +554,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 +590,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
@@ -602,7 +602,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) < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -639,7 +639,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 < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -650,7 +650,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 +665,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 +690,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 +749,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 +772,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 +792,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 +811,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 +827,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 +861,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 +878,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 +890,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 +906,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;
@@ -917,7 +917,7 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
}
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 +976,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
@@ -990,7 +990,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 < 0)
return;
for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index 14315f26228a..ed3181e82da9 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -73,46 +73,46 @@
#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);
+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 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 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);
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);
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);
@@ -129,18 +129,18 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
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,
- int port)
+/* Return the (first) SERDES lane address a port is using, -errno otherwise. */
+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 +149,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 +167,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 +176,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 +185,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
On Fri, Nov 20, 2020 at 10:25:01AM +1000, Pavana Sharma wrote:
> Add 5gbase-r PHY interface mode.
>
> 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 fdf709817218..aa6ae7851de9 100644
> --- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml
> +++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
> @@ -89,6 +89,8 @@ properties:
> - trgmii
> - 1000base-x
> - 2500base-x
> + # 5GBASE-R
> + - 5gbase-r
> - rxaui
> - xaui
Since you are respinning anyway. What value does the comment add?
Andrew
On Fri, Nov 20, 2020 at 10:25:33AM +1000, Pavana Sharma wrote:
> Add 5GBASE-R phy interface mode
>
> Signed-off-by: Pavana Sharma <[email protected]>
> ---
> include/linux/phy.h | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/include/linux/phy.h b/include/linux/phy.h
> index eb3cb1a98b45..71e280059ec5 100644
> --- a/include/linux/phy.h
> +++ b/include/linux/phy.h
> @@ -106,6 +106,7 @@ extern const int phy_10gbit_features_array[1];
> * @PHY_INTERFACE_MODE_TRGMII: Turbo RGMII
> * @PHY_INTERFACE_MODE_1000BASEX: 1000 BaseX
> * @PHY_INTERFACE_MODE_2500BASEX: 2500 BaseX
> + * @PHY_INTERFACE_MODE_5GBASER: 5G BaseR
> * @PHY_INTERFACE_MODE_RXAUI: Reduced XAUI
> * @PHY_INTERFACE_MODE_XAUI: 10 Gigabit Attachment Unit Interface
> * @PHY_INTERFACE_MODE_10GBASER: 10G BaseR
> @@ -137,6 +138,8 @@ typedef enum {
> PHY_INTERFACE_MODE_TRGMII,
> PHY_INTERFACE_MODE_1000BASEX,
> PHY_INTERFACE_MODE_2500BASEX,
> + /* 5GBASE-R mode */
> + PHY_INTERFACE_MODE_5GBASER,
Again, what is the value of the comment? 10GBASE-R has a comment
because it is different from the rest, XFI and SFI caused a of
discussion, and it was used wrong. But there does not seem to be
anything special for 5GBASE-R.
Andrew
> @@ -459,7 +459,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 < 0)
> return -ENODEV;
return lane
since lane is an errno.
Other than that:
Reviewed-by: Andrew Lunn <[email protected]>
Andrew
> @@ -222,8 +231,8 @@ static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,
> return err;
>
> reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
> - MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
> - MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
> + MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
> + MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
This looks like a white space change?
> if (alt_bit)
> reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
> @@ -390,6 +399,84 @@ 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;
Maybe i'm missing something, but it looks like at this point you can
call
return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true, duplex);
> +/* 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);
> + return -EINVAL;
> + }
/* Mark certain ports as invalid. This is required for example for the
* MV88E6220 (which is in general a MV88E6250 with 7 ports) but the
* ports 2-4 are not routed to pins.
*/
unsigned int invalid_port_mask;
You have not set this in the info structure of the 6393x devices, so
you can skip this check.
> +/* 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) {
Maybe
if (port != 0 && port != 9 && port == 10)
return -ENODEV
> + 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)
Indentation is messed up.
> + lane = port;
return port;
Andrew
Hi Andrew,
On Fri, 20 Nov 2020 02:29:06 +0100
Andrew Lunn <[email protected]> wrote:
> > + if (speed >= 2500 && port > 0 && port < 9)
> > + return -EOPNOTSUPP;
>
> Maybe i'm missing something, but it looks like at this point you can
> call
>
> return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true, duplex);
He can't. That function does not support speed 5000. You can't simply
add it, because it clashes with register value for speed 2500 on
previous switches (Peridot, Topaz).
Amethyst reg val Peridot + Topaz reg val
2500 SPD_1000 | ALT_BIT SPD_10000 | ALT_BIT
5000 SPD_10000 | ALT_BIT not supported
10000 SPD_UNFORCED SPD_UNFORCED
When I sent my proposal for Amethyst I somehow did it, and you
commented [1]:
> This is getting more and more complex. Maybe it is time to refactor it?
And I agree :)
Marek
[1] https://www.spinics.net/lists/netdev/msg678090.html
On Fri, Nov 20, 2020 at 02:43:11AM +0100, Marek Behun wrote:
> Hi Andrew,
>
> On Fri, 20 Nov 2020 02:29:06 +0100
> Andrew Lunn <[email protected]> wrote:
>
> > > + if (speed >= 2500 && port > 0 && port < 9)
> > > + return -EOPNOTSUPP;
> >
> > Maybe i'm missing something, but it looks like at this point you can
> > call
> >
> > return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true, duplex);
>
> He can't. That function does not support speed 5000. You can't simply
> add it, because it clashes with register value for speed 2500 on
> previous switches (Peridot, Topaz).
>
> Amethyst reg val Peridot + Topaz reg val
> 2500 SPD_1000 | ALT_BIT SPD_10000 | ALT_BIT
> 5000 SPD_10000 | ALT_BIT not supported
> 10000 SPD_UNFORCED SPD_UNFORCED
Hi Marek
O.K, as i said, i might be missing something :-)
I think a comment would be nice, pointing this out. Otherwise somebody
might try refactoring it, and make the same mistake!
Andrew
Updated patchset after incorporating feedback.
Pavana Sharma (4):
dt-bindings: net: Add 5GBASER phy interface mode
net: phy: Add 5GBASER interface mode
net: dsa: mv88e6xxx: Change serdes lane parameter type from u8 type
to int
net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell
.../bindings/net/ethernet-controller.yaml | 2 +
drivers/net/dsa/mv88e6xxx/chip.c | 164 +++++++++-
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 | 238 +++++++++++++-
drivers/net/dsa/mv88e6xxx/port.h | 43 ++-
drivers/net/dsa/mv88e6xxx/serdes.c | 299 +++++++++++++++---
drivers/net/dsa/mv88e6xxx/serdes.h | 93 ++++--
include/linux/phy.h | 5 +
10 files changed, 783 insertions(+), 91 deletions(-)
--
2.17.1
Add 5gbase-r PHY interface mode.
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 fdf709817218..aa6ae7851de9 100644
--- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml
+++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
@@ -89,6 +89,8 @@ properties:
- trgmii
- 1000base-x
- 2500base-x
+ # 5GBASE-R
+ - 5gbase-r
- rxaui
- xaui
--
2.17.1
Add 5GBASE-R phy interface mode
Signed-off-by: Pavana Sharma <[email protected]>
---
include/linux/phy.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 56563e5e0dc7..8151e6ecf1b9 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -106,6 +106,7 @@ extern const int phy_10gbit_features_array[1];
* @PHY_INTERFACE_MODE_TRGMII: Turbo RGMII
* @PHY_INTERFACE_MODE_1000BASEX: 1000 BaseX
* @PHY_INTERFACE_MODE_2500BASEX: 2500 BaseX
+ * @PHY_INTERFACE_MODE_5GBASER: 5G BaseR
* @PHY_INTERFACE_MODE_RXAUI: Reduced XAUI
* @PHY_INTERFACE_MODE_XAUI: 10 Gigabit Attachment Unit Interface
* @PHY_INTERFACE_MODE_10GBASER: 10G BaseR
@@ -137,6 +138,8 @@ typedef enum {
PHY_INTERFACE_MODE_TRGMII,
PHY_INTERFACE_MODE_1000BASEX,
PHY_INTERFACE_MODE_2500BASEX,
+ /* 5GBASE-R mode */
+ PHY_INTERFACE_MODE_5GBASER,
PHY_INTERFACE_MODE_RXAUI,
PHY_INTERFACE_MODE_XAUI,
/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
@@ -207,6 +210,8 @@ static inline const char *phy_modes(phy_interface_t interface)
return "1000base-x";
case PHY_INTERFACE_MODE_2500BASEX:
return "2500base-x";
+ case PHY_INTERFACE_MODE_5GBASER:
+ return "5gbase-r";
case PHY_INTERFACE_MODE_RXAUI:
return "rxaui";
case PHY_INTERFACE_MODE_XAUI:
--
2.17.1
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 -errno (-ENODEV or -EOPNOTSUPP).
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 | 8 ++--
drivers/net/dsa/mv88e6xxx/serdes.c | 72 +++++++++++++++---------------
drivers/net/dsa/mv88e6xxx/serdes.h | 54 +++++++++++-----------
5 files changed, 89 insertions(+), 89 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 34cca0a4b31c..367f69bd4c82 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -485,12 +485,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 >= 0 && chip->info->ops->serdes_pcs_get_state)
err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
state);
else
@@ -506,11 +506,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 >= 0)
return ops->serdes_pcs_config(chip, port, lane, mode,
interface, advertise);
}
@@ -523,14 +523,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 >= 0)
err = ops->serdes_pcs_an_restart(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -544,11 +544,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 >= 0)
return ops->serdes_pcs_link_up(chip, port, lane,
speed, duplex);
}
@@ -2424,11 +2424,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 >= 0)
ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -2436,7 +2436,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 +2465,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 +2490,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 < 0)
return 0;
if (on) {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 81c244fc0419..d81f586d67e8 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -506,30 +506,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 8128dc607cf4..8c4114d0eb4e 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -393,8 +393,8 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
- u8 lane;
u16 cmode;
+ int lane;
u16 reg;
int err;
@@ -430,7 +430,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 >= 0) {
if (chip->ports[port].serdes_irq) {
err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
if (err)
@@ -459,8 +459,8 @@ 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)
- return -ENODEV;
+ if (lane < 0)
+ return lane;
err = mv88e6xxx_serdes_power_up(chip, port, lane);
if (err)
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 9c07b4f3d345..058cce01c01e 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) >= 0)
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:
@@ -527,7 +527,7 @@ u8 mv88e6390x_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;
@@ -554,7 +554,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 +590,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
@@ -602,7 +602,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) < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -639,7 +639,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 < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -650,7 +650,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 +665,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 +690,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 +749,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 +772,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 +792,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 +811,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 +827,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 +861,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 +878,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 +890,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 +906,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;
@@ -917,7 +917,7 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
}
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 +976,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
@@ -990,7 +990,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 < 0)
return;
for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index 14315f26228a..ed3181e82da9 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -73,46 +73,46 @@
#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);
+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 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 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);
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);
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);
@@ -129,18 +129,18 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
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,
- int port)
+/* Return the (first) SERDES lane address a port is using, -errno otherwise. */
+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 +149,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 +167,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 +176,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 +185,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
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)
Co-developed-by: Ashkan Boldaji <[email protected]>
Signed-off-by: Ashkan Boldaji <[email protected]>
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-v9:
- Incorporated feedback from maintainers.
Changes in v10:
- Fix ISO C90 forbids mixing declarations and code warning
Changes in v11:
- Add comment for clarity, regarding configuring speed 5000 (supported
by mv88e6393x family)
---
drivers/net/dsa/mv88e6xxx/chip.c | 136 ++++++++++++++++
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 | 230 ++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 43 +++++-
drivers/net/dsa/mv88e6xxx/serdes.c | 227 +++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/serdes.h | 39 +++++
8 files changed, 687 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 367f69bd4c82..da7077ac0f29 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -635,6 +635,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)
@@ -3908,6 +3926,55 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.phylink_validate = mv88e6390_phylink_validate,
};
+static const struct mv88e6xxx_ops mv88e6393x_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,
+ .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,
@@ -4840,6 +4907,52 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6191_ops,
},
+ [MV88E6191X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6191X",
+ .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 = &mv88e6393x_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 = &mv88e6393x_ops,
+ },
+
[MV88E6220] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
.family = MV88E6XXX_FAMILY_6250,
@@ -5130,6 +5243,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ptp_support = true,
.ops = &mv88e6390x_ops,
},
+
+ [MV88E6393X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6393X",
+ .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 = &mv88e6393x_ops,
+ },
};
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index d81f586d67e8..2264394633c0 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 e05abe61fa11..8e0fd54cd295 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 MV88E6393X_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 MV88E6393X_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 8c4114d0eb4e..1d61046d30a8 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,6 +399,89 @@ 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)
+ * This function adds new speed 5000 supported by Amethyst family.
+ * Function mv88e6xxx_port_set_speed_duplex() can't be used as the register
+ * values for speeds 2500 & 5000 conflict.
+ */
+
+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, ®);
+ 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;
+
+ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+
+}
+
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
@@ -414,6 +506,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
case PHY_INTERFACE_MODE_2500BASEX:
cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
break;
+ case PHY_INTERFACE_MODE_5GBASER:
+ cmode = MV88E6XXX_PORT_STS_CMODE_5GBASER;
+ break;
case PHY_INTERFACE_MODE_XGMII:
case PHY_INTERFACE_MODE_XAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
@@ -421,6 +516,13 @@ 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_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 +607,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 +1239,125 @@ 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;
+
+ reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL, reg);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+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;
+
+ return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
+}
+
/* 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..2ed1eef15bca 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
@@ -288,7 +316,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
u16 *val);
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
u16 val);
-
+int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
+ int bit, int val);
int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
int pause);
int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
@@ -312,7 +341,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 +376,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 +399,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 058cce01c01e..ece2781e987b 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -526,6 +526,27 @@ int 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)
+ return -EOPNOTSUPP;
+
+ 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, int 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,
+ 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,
int 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, int lane,
+ bool on)
+{
+ u8 cmode;
+
+ if (port != 0 && port != 9 && port != 10)
+ return -EOPNOTSUPP;
+
+ 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 ed3181e82da9..d508978e5944 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)
+
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,
int lane, unsigned int mode,
phy_interface_t interface,
@@ -105,14 +137,21 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
+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, 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,
int lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
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);
--
2.17.1
On Wed, 9 Dec 2020 15:02:54 +1000 Pavana Sharma wrote:
> Updated patchset after incorporating feedback.
This set does not apply to net-next. Please rebase.
On Wed, Dec 09, 2020 at 03:03:47PM +1000, Pavana Sharma wrote:
> Add 5gbase-r PHY interface mode.
>
> 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 fdf709817218..aa6ae7851de9 100644
> --- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml
> +++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
> @@ -89,6 +89,8 @@ properties:
> - trgmii
> - 1000base-x
> - 2500base-x
> + # 5GBASE-R
> + - 5gbase-r
> - rxaui
> - xaui
Hi Pavana
For v10 i said:
> What value does the comment add?
I don't remember you replying. Why is 5gbase-r special and it needs a
comment, saying the same thing in CAPS LETTERS? What value is there in
the CAPS LETTERS string?
Thanks
Andrew
> +/* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X)
> + * This function adds new speed 5000 supported by Amethyst family.
> + * Function mv88e6xxx_port_set_speed_duplex() can't be used as the register
> + * values for speeds 2500 & 5000 conflict.
> + */
Thanks, that should stop my or somebody else trying to wrong combine
them.
> +/* 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);
> +}
To follow the naming convention, this should really be called mv88e6393x_port_epc_wait_ready
> +int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
> + int lane, bool enable)
It can be hard to tell in a diff, but the indentation looks wrong
here. 'int lane' should line up with 'struct'.
> +{
> + 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)
Maybe here as well?
> +int mv88e6393x_setup_errata(struct mv88e6xxx_chip *chip)
It should have _serdes_ in the name to follow the naming convention.
Andrew
On Wed, Dec 09, 2020 at 03:04:23PM +1000, Pavana Sharma wrote:
> Add 5GBASE-R phy interface mode
>
> Signed-off-by: Pavana Sharma <[email protected]>
> ---
> include/linux/phy.h | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/include/linux/phy.h b/include/linux/phy.h
> index 56563e5e0dc7..8151e6ecf1b9 100644
> --- a/include/linux/phy.h
> +++ b/include/linux/phy.h
> @@ -106,6 +106,7 @@ extern const int phy_10gbit_features_array[1];
> * @PHY_INTERFACE_MODE_TRGMII: Turbo RGMII
> * @PHY_INTERFACE_MODE_1000BASEX: 1000 BaseX
> * @PHY_INTERFACE_MODE_2500BASEX: 2500 BaseX
> + * @PHY_INTERFACE_MODE_5GBASER: 5G BaseR
> * @PHY_INTERFACE_MODE_RXAUI: Reduced XAUI
> * @PHY_INTERFACE_MODE_XAUI: 10 Gigabit Attachment Unit Interface
> * @PHY_INTERFACE_MODE_10GBASER: 10G BaseR
> @@ -137,6 +138,8 @@ typedef enum {
> PHY_INTERFACE_MODE_TRGMII,
> PHY_INTERFACE_MODE_1000BASEX,
> PHY_INTERFACE_MODE_2500BASEX,
> + /* 5GBASE-R mode */
> + PHY_INTERFACE_MODE_5GBASER,
> PHY_INTERFACE_MODE_RXAUI,
> PHY_INTERFACE_MODE_XAUI,
For v10 i said:
> Again, what is the value of the comment? 10GBASE-R has a comment
> because it is different from the rest, XFI and SFI caused a of
> discussion, and it was used wrong. But there does not seem to be
> anything special for 5GBASE-R.
Please don't ignore comments. If you don't understand, please ask. If
you think the comments are wrong, please explain why, so we can
discuss it.
Andrew
>On Wed, Dec 09, 2020 at 03:05:17PM +1000, Pavana Sharma wrote:
> 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 -errno (-ENODEV or -EOPNOTSUPP).
>
> Signed-off-by: Pavana Sharma <[email protected]>
I see here you did actually act on my comment. Thanks.
But i also said:
> Other than that:
>
> Reviewed-by: Andrew Lunn <[email protected]>
Please add such tags to new versions of the patches. It then makes it
easier for everybody to know the review state of the patches, which
have been reviewed and deemed O.K, and which need more review.
Thanks
Andrew
Hi Andrew,
> For v10 i said:
> > What value does the comment add?
> I don't remember you replying. Why is 5gbase-r special and it needs a
> comment, saying the same thing in CAPS LETTERS? What value is there in
> the CAPS LETTERS string?
There isn't anything special regarding 5gbase-r apart from another supported
speed.
So, I will remove the comment from [PATCH 1 & 2] and keep it similar to other
(1000/2500) speed options.
Thanks,
Pavana
Updated patchset after rebasing and incorporating feedback.
Pavana Sharma (4):
dt-bindings: net: Add 5GBASER phy interface mode
net: phy: Add 5GBASER interface mode
net: dsa: mv88e6xxx: Change serdes lane parameter type from u8 type
to int
net: dsa: mv88e6xxx: Add support for mv88e6393x family of Marvell
.../bindings/net/ethernet-controller.yaml | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 164 +++++++++-
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 | 238 +++++++++++++-
drivers/net/dsa/mv88e6xxx/port.h | 43 ++-
drivers/net/dsa/mv88e6xxx/serdes.c | 309 +++++++++++++++---
drivers/net/dsa/mv88e6xxx/serdes.h | 103 ++++--
include/linux/phy.h | 4 +
10 files changed, 791 insertions(+), 101 deletions(-)
--
2.17.1
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 -errno (-ENODEV or -EOPNOTSUPP).
Signed-off-by: Pavana Sharma <[email protected]>
Reviewed-by: Andrew Lunn <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 28 +++++-----
drivers/net/dsa/mv88e6xxx/chip.h | 16 +++---
drivers/net/dsa/mv88e6xxx/port.c | 8 +--
drivers/net/dsa/mv88e6xxx/serdes.c | 82 +++++++++++++++---------------
drivers/net/dsa/mv88e6xxx/serdes.h | 64 +++++++++++------------
5 files changed, 99 insertions(+), 99 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index e7f68ac0c7e3..038bae71648d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -485,12 +485,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 >= 0 && chip->info->ops->serdes_pcs_get_state)
err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
state);
else
@@ -506,11 +506,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 >= 0)
return ops->serdes_pcs_config(chip, port, lane, mode,
interface, advertise);
}
@@ -523,14 +523,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 >= 0)
err = ops->serdes_pcs_an_restart(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -544,11 +544,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 >= 0)
return ops->serdes_pcs_link_up(chip, port, lane,
speed, duplex);
}
@@ -2424,11 +2424,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 >= 0)
ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
mv88e6xxx_reg_unlock(chip);
@@ -2436,7 +2436,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 +2465,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 +2490,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 < 0)
return 0;
if (on) {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 3543055bcb51..1ac8338d2256 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -511,30 +511,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 77a5fd1798cd..0af596957b97 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -429,8 +429,8 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
- u8 lane;
u16 cmode;
+ int lane;
u16 reg;
int err;
@@ -466,7 +466,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 >= 0) {
if (chip->ports[port].serdes_irq) {
err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
if (err)
@@ -495,8 +495,8 @@ 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)
- return -ENODEV;
+ if (lane < 0)
+ return lane;
err = mv88e6xxx_serdes_power_up(chip, port, lane);
if (err)
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 3195936dc5be..e48260c5c6ba 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) >= 0)
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;
@@ -413,10 +413,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:
@@ -430,7 +430,7 @@ u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}
-int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool up)
{
/* The serdes power can't be controlled on this switch chip but we need
@@ -440,7 +440,7 @@ int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
return 0;
}
-u8 mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
+int mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
/* There are no configurable serdes lanes on this switch chip but we
* need to return non-zero so that callers of
@@ -456,7 +456,7 @@ u8 mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
}
int mv88e6185_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 err;
u16 status;
@@ -492,7 +492,7 @@ int mv88e6185_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
return 0;
}
-int mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable)
{
u8 cmode = chip->ports[port].cmode;
@@ -525,7 +525,7 @@ static void mv88e6097_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
}
irqreturn_t mv88e6097_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane)
+ int lane)
{
u8 cmode = chip->ports[port].cmode;
@@ -539,10 +539,10 @@ irqreturn_t mv88e6097_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
return IRQ_NONE;
}
-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:
@@ -562,12 +562,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:
@@ -638,7 +638,7 @@ u8 mv88e6390x_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;
@@ -665,7 +665,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;
@@ -701,7 +701,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
@@ -713,7 +713,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) < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -750,7 +750,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 < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -761,7 +761,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;
@@ -776,7 +776,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;
@@ -801,7 +801,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)
{
@@ -860,7 +860,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;
@@ -883,7 +883,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;
@@ -903,7 +903,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:
@@ -922,7 +922,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;
@@ -938,7 +938,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;
@@ -972,7 +972,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;
@@ -989,7 +989,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;
@@ -1001,7 +1001,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;
@@ -1017,7 +1017,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;
@@ -1028,7 +1028,7 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
}
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;
@@ -1087,7 +1087,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) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
@@ -1102,7 +1102,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 < 0)
return;
for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index 93822ef9bab8..a1a51a6d6c1f 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -73,55 +73,55 @@
#define MV88E6390_PG_CONTROL 0xf010
#define MV88E6390_PG_CONTROL_ENABLE_PC BIT(0)
-u8 mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-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);
+int mv88e6185_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 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 mv88e6185_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_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 mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool up);
-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 mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
+int mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable);
-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);
irqreturn_t mv88e6097_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- u8 lane);
+ int lane);
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);
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);
@@ -138,18 +138,18 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
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,
- int port)
+/* Return the (first) SERDES lane address a port is using, -errno otherwise. */
+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;
@@ -158,7 +158,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;
@@ -176,7 +176,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;
@@ -185,7 +185,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;
@@ -194,7 +194,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
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)
Co-developed-by: Ashkan Boldaji <[email protected]>
Signed-off-by: Ashkan Boldaji <[email protected]>
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-v9:
- Incorporated feedback from maintainers.
Changes in v10:
- Fix ISO C90 forbids mixing declarations and code warning
Changes in v11:
- Add comment for clarity, regarding configuring speed 5000 (supported
by mv88e6393x family)
Changes in v12:
- Rebase to net-next
- Remove 5GBASE-R comments from patch 1 & 2 of this patchset
- Make function name to the convention
---
drivers/net/dsa/mv88e6xxx/chip.c | 136 ++++++++++++++++
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 | 230 ++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 43 +++++-
drivers/net/dsa/mv88e6xxx/serdes.c | 227 +++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/serdes.h | 39 +++++
8 files changed, 687 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 038bae71648d..0b2faed38324 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -635,6 +635,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)
@@ -3937,6 +3955,55 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.phylink_validate = mv88e6390_phylink_validate,
};
+static const struct mv88e6xxx_ops mv88e6393x_ops = {
+ /* MV88E6XXX_FAMILY_6393 */
+ .setup_errata = mv88e6393x_serdes_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,
+ .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,
@@ -4880,6 +4947,52 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6191_ops,
},
+ [MV88E6191X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6191X",
+ .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 = &mv88e6393x_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 = &mv88e6393x_ops,
+ },
+
[MV88E6220] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
.family = MV88E6XXX_FAMILY_6250,
@@ -5170,6 +5283,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ptp_support = true,
.ops = &mv88e6390x_ops,
},
+
+ [MV88E6393X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
+ .family = MV88E6XXX_FAMILY_6393,
+ .name = "Marvell 88E6393X",
+ .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 = &mv88e6393x_ops,
+ },
};
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 1ac8338d2256..bf1bc540be79 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 80a182c5b98a..5b084f4015f6 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 MV88E6393X_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 MV88E6393X_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 0af596957b97..c38fcb8163ce 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)
{
@@ -426,6 +435,89 @@ 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)
+ * This function adds new speed 5000 supported by Amethyst family.
+ * Function mv88e6xxx_port_set_speed_duplex() can't be used as the register
+ * values for speeds 2500 & 5000 conflict.
+ */
+
+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, ®);
+ 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;
+
+ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+
+}
+
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
@@ -450,6 +542,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
case PHY_INTERFACE_MODE_2500BASEX:
cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
break;
+ case PHY_INTERFACE_MODE_5GBASER:
+ cmode = MV88E6XXX_PORT_STS_CMODE_5GBASER;
+ break;
case PHY_INTERFACE_MODE_XGMII:
case PHY_INTERFACE_MODE_XAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
@@ -457,6 +552,13 @@ 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_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;
}
@@ -541,6 +643,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)
{
@@ -1164,6 +1275,125 @@ 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;
+
+ reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL, reg);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+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_port_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_port_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;
+
+ return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
+}
+
/* 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 500e1d4896ff..051665fa22d5 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
@@ -288,7 +316,8 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
u16 *val);
int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
u16 val);
-
+int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
+ int bit, int val);
int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
int pause);
int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
@@ -315,7 +344,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);
@@ -349,6 +379,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,
@@ -365,6 +402,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 e48260c5c6ba..622fe6df2ff9 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -637,6 +637,27 @@ int 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)
+ return -EOPNOTSUPP;
+
+ 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, int lane,
bool up)
@@ -1027,6 +1048,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,
+ 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,
int lane)
{
@@ -1112,3 +1178,164 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
p[i] = reg;
}
}
+
+int mv88e6393x_serdes_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)
+{
+ u8 cmode;
+
+ if (port != 0 && port != 9 && port != 10)
+ return -EOPNOTSUPP;
+
+ 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 a1a51a6d6c1f..f17ddbb70127 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -68,16 +68,48 @@
#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)
+
int mv88e6185_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,
int lane, unsigned int mode,
phy_interface_t interface,
@@ -110,18 +142,25 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
bool on);
+int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
+ bool on);
+int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip);
int mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
bool enable);
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, int lane,
bool enable);
+int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
+ int lane, bool enable);
irqreturn_t mv88e6097_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
int lane);
irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
int lane);
irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
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);
--
2.17.1
Add 5GBASE-R phy interface mode
Signed-off-by: Pavana Sharma <[email protected]>
---
include/linux/phy.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 381a95732b6a..868ee5cf7fce 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -106,6 +106,7 @@ extern const int phy_10gbit_features_array[1];
* @PHY_INTERFACE_MODE_TRGMII: Turbo RGMII
* @PHY_INTERFACE_MODE_1000BASEX: 1000 BaseX
* @PHY_INTERFACE_MODE_2500BASEX: 2500 BaseX
+ * @PHY_INTERFACE_MODE_5GBASER: 5G BaseR
* @PHY_INTERFACE_MODE_RXAUI: Reduced XAUI
* @PHY_INTERFACE_MODE_XAUI: 10 Gigabit Attachment Unit Interface
* @PHY_INTERFACE_MODE_10GBASER: 10G BaseR
@@ -137,6 +138,7 @@ typedef enum {
PHY_INTERFACE_MODE_TRGMII,
PHY_INTERFACE_MODE_1000BASEX,
PHY_INTERFACE_MODE_2500BASEX,
+ PHY_INTERFACE_MODE_5GBASER,
PHY_INTERFACE_MODE_RXAUI,
PHY_INTERFACE_MODE_XAUI,
/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
@@ -207,6 +209,8 @@ static inline const char *phy_modes(phy_interface_t interface)
return "1000base-x";
case PHY_INTERFACE_MODE_2500BASEX:
return "2500base-x";
+ case PHY_INTERFACE_MODE_5GBASER:
+ return "5gbase-r";
case PHY_INTERFACE_MODE_RXAUI:
return "rxaui";
case PHY_INTERFACE_MODE_XAUI:
--
2.17.1
On Fri, 11 Dec 2020 22:51:01 +1000
Pavana Sharma <[email protected]> wrote:
> +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);
> + }
This is wrong. IRQ for 5gbase-r and 10gbase-r is enabled differently.
Please look at how I did it in my proposal
https://www.mail-archive.com/[email protected]/msg347854.html
Please look at the following functions in that patch:
mv88e6393x_serdes_irq_enable_10g()
mv88e6393x_serdes_irq_enable()
mv88e6393x_serdes_irq_status_10g()
irqreturn_t mv88e6393x_serdes_irq_status()
and also at the constants added to serdes.h in that patch
#define MV88E6393X_10G_INT_ENABLE 0x9000
#define MV88E6393X_10G_INT_LINK_CHANGE BIT(2)
#define MV88E6393X_10G_INT_STATUS 0x9001
Thanks Marek for catching this.
I will have a closer look and update the patchset.
On Wed, 6 Jan 2021 10:45:30 +1000
Pavana Sharma <[email protected]> wrote:
> Thanks Marek for catching this.
>
> I will have a closer look and update the patchset.
I also sent a reply patch with subject
"patch fixing mv88e6393x SERDES IRQ for Pavana's series"
it contains the changes necessary to your series. Please look at that.
You can apply it to your commit via
patch -p1 <patch_from_marek.patch
git commit --amend drivers/net/dsa/mv88e6xxx/{chip.c,serdes.c,serdes.h}
Marek