Commit e3d8178c authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'part-2-of-sja1105-dsa-driver-preparation-for-new-switch-introduction-sja1110'

Vladimir Oltean says:

====================
Part 2 of SJA1105 DSA driver preparation for new switch introduction (SJA1110)

This series is a continuation of:
https://patchwork.kernel.org/project/netdevbpf/cover/20210524131421.1030789-1-olteanv@gmail.com/

even though it isn't the first time these patches are submitted (they
were part of the group previously called "Add NXP SJA1110 support to the
sja1105 DSA driver"):
https://patchwork.kernel.org/project/netdevbpf/cover/20210526135535.2515123-1-vladimir.oltean@nxp.com/

but I broke that up again since these patches are already reviewed, for
the most part. There are no changes compared to v2 and v1.

This series of patches contains:

- an adaptation of the driver to the new "ethernet-ports" OF node name
- an adaptation of the driver to support more than 1 SGMII port
- a generalization of the supported phy_interface_t values per port
- an adaptation to encode SPEED_10, SPEED_100, SPEED_1000 into the
  hardware registers differently depending on switch revision
- a consolidation of the PHY interface type used for RGMII and another
  one for the API exposed for sja1105_dynamic_config_read()
====================

Link: https://lore.kernel.org/r/20210530225939.772553-1-olteanv@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 44fdd2ed 96c85f51
...@@ -48,7 +48,6 @@ struct sja1105_regs { ...@@ -48,7 +48,6 @@ struct sja1105_regs {
u64 rgu; u64 rgu;
u64 vl_status; u64 vl_status;
u64 config; u64 config;
u64 sgmii;
u64 rmii_pll1; u64 rmii_pll1;
u64 ptppinst; u64 ptppinst;
u64 ptppindur; u64 ptppindur;
...@@ -73,6 +72,15 @@ struct sja1105_regs { ...@@ -73,6 +72,15 @@ struct sja1105_regs {
u64 stats[__MAX_SJA1105_STATS_AREA][SJA1105_MAX_NUM_PORTS]; u64 stats[__MAX_SJA1105_STATS_AREA][SJA1105_MAX_NUM_PORTS];
}; };
enum {
SJA1105_SPEED_AUTO,
SJA1105_SPEED_10MBPS,
SJA1105_SPEED_100MBPS,
SJA1105_SPEED_1000MBPS,
SJA1105_SPEED_2500MBPS,
SJA1105_SPEED_MAX,
};
struct sja1105_info { struct sja1105_info {
u64 device_id; u64 device_id;
/* Needed for distinction between P and R, and between Q and S /* Needed for distinction between P and R, and between Q and S
...@@ -112,6 +120,12 @@ struct sja1105_info { ...@@ -112,6 +120,12 @@ struct sja1105_info {
enum packing_op op); enum packing_op op);
int (*clocking_setup)(struct sja1105_private *priv); int (*clocking_setup)(struct sja1105_private *priv);
const char *name; const char *name;
bool supports_mii[SJA1105_MAX_NUM_PORTS];
bool supports_rmii[SJA1105_MAX_NUM_PORTS];
bool supports_rgmii[SJA1105_MAX_NUM_PORTS];
bool supports_sgmii[SJA1105_MAX_NUM_PORTS];
bool supports_2500basex[SJA1105_MAX_NUM_PORTS];
const u64 port_speed[SJA1105_SPEED_MAX];
}; };
enum sja1105_key_type { enum sja1105_key_type {
...@@ -211,6 +225,7 @@ struct sja1105_private { ...@@ -211,6 +225,7 @@ struct sja1105_private {
struct sja1105_static_config static_config; struct sja1105_static_config static_config;
bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS]; bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS];
bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS]; bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS];
phy_interface_t phy_mode[SJA1105_MAX_NUM_PORTS];
bool best_effort_vlan_filtering; bool best_effort_vlan_filtering;
unsigned long learn_ena; unsigned long learn_ena;
unsigned long ucast_egress_floods; unsigned long ucast_egress_floods;
...@@ -309,13 +324,6 @@ typedef enum { ...@@ -309,13 +324,6 @@ typedef enum {
XMII_MODE_SGMII = 3, XMII_MODE_SGMII = 3,
} sja1105_phy_interface_t; } sja1105_phy_interface_t;
typedef enum {
SJA1105_SPEED_10MBPS = 3,
SJA1105_SPEED_100MBPS = 2,
SJA1105_SPEED_1000MBPS = 1,
SJA1105_SPEED_AUTO = 0,
} sja1105_speed_t;
int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port); int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
int sja1105_clocking_setup_port(struct sja1105_private *priv, int port); int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
int sja1105_clocking_setup(struct sja1105_private *priv); int sja1105_clocking_setup(struct sja1105_private *priv);
......
...@@ -328,7 +328,7 @@ sja1105_cgu_pll_control_packing(void *buf, struct sja1105_cgu_pll_ctrl *cmd, ...@@ -328,7 +328,7 @@ sja1105_cgu_pll_control_packing(void *buf, struct sja1105_cgu_pll_ctrl *cmd,
} }
static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv, static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
int port, sja1105_speed_t speed) int port, u64 speed)
{ {
const struct sja1105_regs *regs = priv->info->regs; const struct sja1105_regs *regs = priv->info->regs;
struct sja1105_cgu_mii_ctrl txc; struct sja1105_cgu_mii_ctrl txc;
...@@ -338,7 +338,7 @@ static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv, ...@@ -338,7 +338,7 @@ static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
if (regs->rgmii_tx_clk[port] == SJA1105_RSV_ADDR) if (regs->rgmii_tx_clk[port] == SJA1105_RSV_ADDR)
return 0; return 0;
if (speed == SJA1105_SPEED_1000MBPS) { if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
clksrc = CLKSRC_PLL0; clksrc = CLKSRC_PLL0;
} else { } else {
int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2, int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2,
...@@ -524,35 +524,31 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port, ...@@ -524,35 +524,31 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
{ {
struct device *dev = priv->ds->dev; struct device *dev = priv->ds->dev;
struct sja1105_mac_config_entry *mac; struct sja1105_mac_config_entry *mac;
sja1105_speed_t speed; u64 speed;
int rc; int rc;
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
speed = mac[port].speed; speed = mac[port].speed;
dev_dbg(dev, "Configuring port %d RGMII at speed %dMbps\n", dev_dbg(dev, "Configuring port %d RGMII at speed %lldMbps\n",
port, speed); port, speed);
switch (speed) { if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
case SJA1105_SPEED_1000MBPS:
/* 1000Mbps, IDIV disabled (125 MHz) */ /* 1000Mbps, IDIV disabled (125 MHz) */
rc = sja1105_cgu_idiv_config(priv, port, false, 1); rc = sja1105_cgu_idiv_config(priv, port, false, 1);
break; } else if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS]) {
case SJA1105_SPEED_100MBPS:
/* 100Mbps, IDIV enabled, divide by 1 (25 MHz) */ /* 100Mbps, IDIV enabled, divide by 1 (25 MHz) */
rc = sja1105_cgu_idiv_config(priv, port, true, 1); rc = sja1105_cgu_idiv_config(priv, port, true, 1);
break; } else if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS]) {
case SJA1105_SPEED_10MBPS:
/* 10Mbps, IDIV enabled, divide by 10 (2.5 MHz) */ /* 10Mbps, IDIV enabled, divide by 10 (2.5 MHz) */
rc = sja1105_cgu_idiv_config(priv, port, true, 10); rc = sja1105_cgu_idiv_config(priv, port, true, 10);
break; } else if (speed == priv->info->port_speed[SJA1105_SPEED_AUTO]) {
case SJA1105_SPEED_AUTO:
/* Skip CGU configuration if there is no speed available /* Skip CGU configuration if there is no speed available
* (e.g. link is not established yet) * (e.g. link is not established yet)
*/ */
dev_dbg(dev, "Speed not available, skipping CGU config\n"); dev_dbg(dev, "Speed not available, skipping CGU config\n");
return 0; return 0;
default: } else {
rc = -EINVAL; rc = -EINVAL;
} }
...@@ -570,14 +566,9 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port, ...@@ -570,14 +566,9 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
dev_err(dev, "Failed to configure Tx pad registers\n"); dev_err(dev, "Failed to configure Tx pad registers\n");
return rc; return rc;
} }
if (!priv->info->setup_rgmii_delay) if (!priv->info->setup_rgmii_delay)
return 0; return 0;
/* The role has no hardware effect for RGMII. However we use it as
* a proxy for this interface being a MAC-to-MAC connection, with
* the RGMII internal delays needing to be applied by us.
*/
if (role == XMII_MAC)
return 0;
return priv->info->setup_rgmii_delay(priv, port); return priv->info->setup_rgmii_delay(priv, port);
} }
......
...@@ -78,6 +78,9 @@ ...@@ -78,6 +78,9 @@
* on its ENTRY portion, as a result of a SPI write command. * on its ENTRY portion, as a result of a SPI write command.
* Only the TCAM-based FDB table on SJA1105 P/Q/R/S supports * Only the TCAM-based FDB table on SJA1105 P/Q/R/S supports
* this. * this.
* OP_VALID_ANYWAY: Reading some tables through the dynamic config
* interface is possible even if the VALIDENT bit is not
* set in the writeback. So don't error out in that case.
* - .max_entry_count: The number of entries, counting from zero, that can be * - .max_entry_count: The number of entries, counting from zero, that can be
* reconfigured through the dynamic interface. If a static * reconfigured through the dynamic interface. If a static
* table can be reconfigured at all dynamically, this * table can be reconfigured at all dynamically, this
...@@ -651,6 +654,7 @@ static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr, ...@@ -651,6 +654,7 @@ static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
#define OP_WRITE BIT(1) #define OP_WRITE BIT(1)
#define OP_DEL BIT(2) #define OP_DEL BIT(2)
#define OP_SEARCH BIT(3) #define OP_SEARCH BIT(3)
#define OP_VALID_ANYWAY BIT(4)
/* SJA1105E/T: First generation */ /* SJA1105E/T: First generation */
const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
...@@ -673,7 +677,7 @@ const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { ...@@ -673,7 +677,7 @@ const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
[BLK_IDX_MGMT_ROUTE] = { [BLK_IDX_MGMT_ROUTE] = {
.entry_packing = sja1105et_mgmt_route_entry_packing, .entry_packing = sja1105et_mgmt_route_entry_packing,
.cmd_packing = sja1105et_mgmt_route_cmd_packing, .cmd_packing = sja1105et_mgmt_route_cmd_packing,
.access = (OP_READ | OP_WRITE), .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
.max_entry_count = SJA1105_NUM_PORTS, .max_entry_count = SJA1105_NUM_PORTS,
.packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD, .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
.addr = 0x20, .addr = 0x20,
...@@ -757,7 +761,7 @@ const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = { ...@@ -757,7 +761,7 @@ const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
[BLK_IDX_MGMT_ROUTE] = { [BLK_IDX_MGMT_ROUTE] = {
.entry_packing = sja1105pqrs_mgmt_route_entry_packing, .entry_packing = sja1105pqrs_mgmt_route_entry_packing,
.cmd_packing = sja1105pqrs_mgmt_route_cmd_packing, .cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH), .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH | OP_VALID_ANYWAY),
.max_entry_count = SJA1105_NUM_PORTS, .max_entry_count = SJA1105_NUM_PORTS,
.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD, .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
.addr = 0x24, .addr = 0x24,
...@@ -911,11 +915,8 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv, ...@@ -911,11 +915,8 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv,
cmd = (struct sja1105_dyn_cmd) {0}; cmd = (struct sja1105_dyn_cmd) {0};
ops->cmd_packing(packed_buf, &cmd, UNPACK); ops->cmd_packing(packed_buf, &cmd, UNPACK);
/* UM10944: [valident] will always be found cleared
* during a read access with MGMTROUTE set. if (!cmd.valident && !(ops->access & OP_VALID_ANYWAY))
* So don't error out in that case.
*/
if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE)
return -ENOENT; return -ENOENT;
cpu_relax(); cpu_relax();
} while (cmd.valid && --retries); } while (cmd.valid && --retries);
......
...@@ -80,7 +80,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) ...@@ -80,7 +80,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
/* Always put the MAC speed in automatic mode, where it can be /* Always put the MAC speed in automatic mode, where it can be
* adjusted at runtime by PHYLINK. * adjusted at runtime by PHYLINK.
*/ */
.speed = SJA1105_SPEED_AUTO, .speed = priv->info->port_speed[SJA1105_SPEED_AUTO],
/* No static correction for 1-step 1588 events */ /* No static correction for 1-step 1588 events */
.tp_delin = 0, .tp_delin = 0,
.tp_delout = 0, .tp_delout = 0,
...@@ -143,21 +143,6 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) ...@@ -143,21 +143,6 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
return 0; return 0;
} }
static bool sja1105_supports_sgmii(struct sja1105_private *priv, int port)
{
if (priv->info->part_no != SJA1105R_PART_NO &&
priv->info->part_no != SJA1105S_PART_NO)
return false;
if (port != SJA1105_SGMII_PORT)
return false;
if (dsa_is_unused_port(priv->ds, port))
return false;
return true;
}
static int sja1105_init_mii_settings(struct sja1105_private *priv, static int sja1105_init_mii_settings(struct sja1105_private *priv,
struct sja1105_dt_port *ports) struct sja1105_dt_port *ports)
{ {
...@@ -191,33 +176,56 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv, ...@@ -191,33 +176,56 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
switch (ports[i].phy_mode) { switch (ports[i].phy_mode) {
case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_MII:
if (!priv->info->supports_mii[i])
goto unsupported;
mii->xmii_mode[i] = XMII_MODE_MII; mii->xmii_mode[i] = XMII_MODE_MII;
break; break;
case PHY_INTERFACE_MODE_RMII: case PHY_INTERFACE_MODE_RMII:
if (!priv->info->supports_rmii[i])
goto unsupported;
mii->xmii_mode[i] = XMII_MODE_RMII; mii->xmii_mode[i] = XMII_MODE_RMII;
break; break;
case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_RGMII_TXID:
if (!priv->info->supports_rgmii[i])
goto unsupported;
mii->xmii_mode[i] = XMII_MODE_RGMII; mii->xmii_mode[i] = XMII_MODE_RGMII;
break; break;
case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_SGMII:
if (!sja1105_supports_sgmii(priv, i)) if (!priv->info->supports_sgmii[i])
return -EINVAL; goto unsupported;
mii->xmii_mode[i] = XMII_MODE_SGMII; mii->xmii_mode[i] = XMII_MODE_SGMII;
break; break;
case PHY_INTERFACE_MODE_2500BASEX:
if (!priv->info->supports_2500basex[i])
goto unsupported;
mii->xmii_mode[i] = XMII_MODE_SGMII;
break;
unsupported:
default: default:
dev_err(dev, "Unsupported PHY mode %s!\n", dev_err(dev, "Unsupported PHY mode %s on port %d!\n",
phy_modes(ports[i].phy_mode)); phy_modes(ports[i].phy_mode), i);
return -EINVAL; return -EINVAL;
} }
/* Even though the SerDes port is able to drive SGMII autoneg /* Even though the SerDes port is able to drive SGMII autoneg
* like a PHY would, from the perspective of the XMII tables, * like a PHY would, from the perspective of the XMII tables,
* the SGMII port should always be put in MAC mode. * the SGMII port should always be put in MAC mode.
* Similarly, RGMII is a symmetric protocol electrically
* speaking, and the 'RGMII PHY' role does not mean anything to
* hardware. Just keep the 'PHY role' notation relevant to the
* driver to mean 'the switch port should apply RGMII delays',
* but unconditionally put the port in the MAC role.
*/ */
if (ports[i].phy_mode == PHY_INTERFACE_MODE_SGMII) if (ports[i].phy_mode == PHY_INTERFACE_MODE_SGMII ||
phy_interface_mode_is_rgmii(ports[i].phy_mode))
mii->phy_mac[i] = XMII_MAC; mii->phy_mac[i] = XMII_MAC;
else else
mii->phy_mac[i] = ports[i].role; mii->phy_mac[i] = ports[i].role;
...@@ -871,6 +879,8 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, ...@@ -871,6 +879,8 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
ports[index].role = XMII_MAC; ports[index].role = XMII_MAC;
else if (of_property_read_bool(child, "sja1105,role-phy")) else if (of_property_read_bool(child, "sja1105,role-phy"))
ports[index].role = XMII_PHY; ports[index].role = XMII_PHY;
priv->phy_mode[index] = phy_mode;
} }
return 0; return 0;
...@@ -885,6 +895,8 @@ static int sja1105_parse_dt(struct sja1105_private *priv, ...@@ -885,6 +895,8 @@ static int sja1105_parse_dt(struct sja1105_private *priv,
int rc; int rc;
ports_node = of_get_child_by_name(switch_node, "ports"); ports_node = of_get_child_by_name(switch_node, "ports");
if (!ports_node)
ports_node = of_get_child_by_name(switch_node, "ethernet-ports");
if (!ports_node) { if (!ports_node) {
dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); dev_err(dev, "Incorrect bindings: absent \"ports\" node\n");
return -ENODEV; return -ENODEV;
...@@ -896,36 +908,41 @@ static int sja1105_parse_dt(struct sja1105_private *priv, ...@@ -896,36 +908,41 @@ static int sja1105_parse_dt(struct sja1105_private *priv,
return rc; return rc;
} }
static int sja1105_sgmii_read(struct sja1105_private *priv, int pcs_reg) static int sja1105_sgmii_read(struct sja1105_private *priv, int port, int mmd,
int pcs_reg)
{ {
const struct sja1105_regs *regs = priv->info->regs; u64 addr = (mmd << 16) | pcs_reg;
u32 val; u32 val;
int rc; int rc;
rc = sja1105_xfer_u32(priv, SPI_READ, regs->sgmii + pcs_reg, &val, if (port != SJA1105_SGMII_PORT)
NULL); return -ENODEV;
rc = sja1105_xfer_u32(priv, SPI_READ, addr, &val, NULL);
if (rc < 0) if (rc < 0)
return rc; return rc;
return val; return val;
} }
static int sja1105_sgmii_write(struct sja1105_private *priv, int pcs_reg, static int sja1105_sgmii_write(struct sja1105_private *priv, int port, int mmd,
u16 pcs_val) int pcs_reg, u16 pcs_val)
{ {
const struct sja1105_regs *regs = priv->info->regs; u64 addr = (mmd << 16) | pcs_reg;
u32 val = pcs_val; u32 val = pcs_val;
int rc; int rc;
rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->sgmii + pcs_reg, &val, if (port != SJA1105_SGMII_PORT)
NULL); return -ENODEV;
rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &val, NULL);
if (rc < 0) if (rc < 0)
return rc; return rc;
return val; return val;
} }
static void sja1105_sgmii_pcs_config(struct sja1105_private *priv, static void sja1105_sgmii_pcs_config(struct sja1105_private *priv, int port,
bool an_enabled, bool an_master) bool an_enabled, bool an_master)
{ {
u16 ac = SJA1105_AC_AUTONEG_MODE_SGMII; u16 ac = SJA1105_AC_AUTONEG_MODE_SGMII;
...@@ -934,27 +951,29 @@ static void sja1105_sgmii_pcs_config(struct sja1105_private *priv, ...@@ -934,27 +951,29 @@ static void sja1105_sgmii_pcs_config(struct sja1105_private *priv,
* stop the clock during LPI mode, make the MAC reconfigure * stop the clock during LPI mode, make the MAC reconfigure
* autonomously after PCS autoneg is done, flush the internal FIFOs. * autonomously after PCS autoneg is done, flush the internal FIFOs.
*/ */
sja1105_sgmii_write(priv, SJA1105_DC1, SJA1105_DC1_EN_VSMMD1 | sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, SJA1105_DC1,
SJA1105_DC1_CLOCK_STOP_EN | SJA1105_DC1_EN_VSMMD1 |
SJA1105_DC1_MAC_AUTO_SW | SJA1105_DC1_CLOCK_STOP_EN |
SJA1105_DC1_INIT); SJA1105_DC1_MAC_AUTO_SW |
SJA1105_DC1_INIT);
/* DIGITAL_CONTROL_2: No polarity inversion for TX and RX lanes */ /* DIGITAL_CONTROL_2: No polarity inversion for TX and RX lanes */
sja1105_sgmii_write(priv, SJA1105_DC2, SJA1105_DC2_TX_POL_INV_DISABLE); sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, SJA1105_DC2,
SJA1105_DC2_TX_POL_INV_DISABLE);
/* AUTONEG_CONTROL: Use SGMII autoneg */ /* AUTONEG_CONTROL: Use SGMII autoneg */
if (an_master) if (an_master)
ac |= SJA1105_AC_PHY_MODE | SJA1105_AC_SGMII_LINK; ac |= SJA1105_AC_PHY_MODE | SJA1105_AC_SGMII_LINK;
sja1105_sgmii_write(priv, SJA1105_AC, ac); sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, SJA1105_AC, ac);
/* BASIC_CONTROL: enable in-band AN now, if requested. Otherwise, /* BASIC_CONTROL: enable in-band AN now, if requested. Otherwise,
* sja1105_sgmii_pcs_force_speed must be called later for the link * sja1105_sgmii_pcs_force_speed must be called later for the link
* to become operational. * to become operational.
*/ */
if (an_enabled) if (an_enabled)
sja1105_sgmii_write(priv, MII_BMCR, sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1,
BMCR_ANENABLE | BMCR_ANRESTART); BMCR_ANENABLE | BMCR_ANRESTART);
} }
static void sja1105_sgmii_pcs_force_speed(struct sja1105_private *priv, static void sja1105_sgmii_pcs_force_speed(struct sja1105_private *priv,
int speed) int port, int speed)
{ {
int pcs_speed; int pcs_speed;
...@@ -972,26 +991,32 @@ static void sja1105_sgmii_pcs_force_speed(struct sja1105_private *priv, ...@@ -972,26 +991,32 @@ static void sja1105_sgmii_pcs_force_speed(struct sja1105_private *priv,
dev_err(priv->ds->dev, "Invalid speed %d\n", speed); dev_err(priv->ds->dev, "Invalid speed %d\n", speed);
return; return;
} }
sja1105_sgmii_write(priv, MII_BMCR, pcs_speed | BMCR_FULLDPLX); sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1,
pcs_speed | BMCR_FULLDPLX);
} }
/* Convert link speed from SJA1105 to ethtool encoding */ /* Convert link speed from SJA1105 to ethtool encoding */
static int sja1105_speed[] = { static int sja1105_port_speed_to_ethtool(struct sja1105_private *priv,
[SJA1105_SPEED_AUTO] = SPEED_UNKNOWN, u64 speed)
[SJA1105_SPEED_10MBPS] = SPEED_10, {
[SJA1105_SPEED_100MBPS] = SPEED_100, if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS])
[SJA1105_SPEED_1000MBPS] = SPEED_1000, return SPEED_10;
}; if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS])
return SPEED_100;
if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS])
return SPEED_1000;
if (speed == priv->info->port_speed[SJA1105_SPEED_2500MBPS])
return SPEED_2500;
return SPEED_UNKNOWN;
}
/* Set link speed in the MAC configuration for a specific port. */ /* Set link speed in the MAC configuration for a specific port. */
static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
int speed_mbps) int speed_mbps)
{ {
struct sja1105_xmii_params_entry *mii;
struct sja1105_mac_config_entry *mac; struct sja1105_mac_config_entry *mac;
struct device *dev = priv->ds->dev; struct device *dev = priv->ds->dev;
sja1105_phy_interface_t phy_mode; u64 speed;
sja1105_speed_t speed;
int rc; int rc;
/* On P/Q/R/S, one can read from the device via the MAC reconfiguration /* On P/Q/R/S, one can read from the device via the MAC reconfiguration
...@@ -1001,7 +1026,6 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, ...@@ -1001,7 +1026,6 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* reasonable approximation for both E/T and P/Q/R/S. * reasonable approximation for both E/T and P/Q/R/S.
*/ */
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
switch (speed_mbps) { switch (speed_mbps) {
case SPEED_UNKNOWN: case SPEED_UNKNOWN:
...@@ -1012,16 +1036,16 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, ...@@ -1012,16 +1036,16 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* ok for power consumption in case AN will never complete - * ok for power consumption in case AN will never complete -
* otherwise PHYLINK should come back with a new update. * otherwise PHYLINK should come back with a new update.
*/ */
speed = SJA1105_SPEED_AUTO; speed = priv->info->port_speed[SJA1105_SPEED_AUTO];
break; break;
case SPEED_10: case SPEED_10:
speed = SJA1105_SPEED_10MBPS; speed = priv->info->port_speed[SJA1105_SPEED_10MBPS];
break; break;
case SPEED_100: case SPEED_100:
speed = SJA1105_SPEED_100MBPS; speed = priv->info->port_speed[SJA1105_SPEED_100MBPS];
break; break;
case SPEED_1000: case SPEED_1000:
speed = SJA1105_SPEED_1000MBPS; speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
break; break;
default: default:
dev_err(dev, "Invalid speed %iMbps\n", speed_mbps); dev_err(dev, "Invalid speed %iMbps\n", speed_mbps);
...@@ -1035,8 +1059,8 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, ...@@ -1035,8 +1059,8 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* Actually for the SGMII port, the MAC is fixed at 1 Gbps and * Actually for the SGMII port, the MAC is fixed at 1 Gbps and
* we need to configure the PCS only (if even that). * we need to configure the PCS only (if even that).
*/ */
if (sja1105_supports_sgmii(priv, port)) if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII)
mac[port].speed = SJA1105_SPEED_1000MBPS; mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
else else
mac[port].speed = speed; mac[port].speed = speed;
...@@ -1054,8 +1078,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, ...@@ -1054,8 +1078,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* the clock setup does interrupt the clock signal for a certain time * the clock setup does interrupt the clock signal for a certain time
* which causes trouble for all PHYs relying on this signal. * which causes trouble for all PHYs relying on this signal.
*/ */
phy_mode = mii->xmii_mode[port]; if (!phy_interface_mode_is_rgmii(priv->phy_mode[port]))
if (phy_mode != XMII_MODE_RGMII)
return 0; return 0;
return sja1105_clocking_setup_port(priv, port); return sja1105_clocking_setup_port(priv, port);
...@@ -1071,27 +1094,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, ...@@ -1071,27 +1094,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
static bool sja1105_phy_mode_mismatch(struct sja1105_private *priv, int port, static bool sja1105_phy_mode_mismatch(struct sja1105_private *priv, int port,
phy_interface_t interface) phy_interface_t interface)
{ {
struct sja1105_xmii_params_entry *mii; return priv->phy_mode[port] != interface;
sja1105_phy_interface_t phy_mode;
mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
phy_mode = mii->xmii_mode[port];
switch (interface) {
case PHY_INTERFACE_MODE_MII:
return (phy_mode != XMII_MODE_MII);
case PHY_INTERFACE_MODE_RMII:
return (phy_mode != XMII_MODE_RMII);
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
return (phy_mode != XMII_MODE_RGMII);
case PHY_INTERFACE_MODE_SGMII:
return (phy_mode != XMII_MODE_SGMII);
default:
return true;
}
} }
static void sja1105_mac_config(struct dsa_switch *ds, int port, static void sja1105_mac_config(struct dsa_switch *ds, int port,
...@@ -1099,7 +1102,9 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port, ...@@ -1099,7 +1102,9 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port,
const struct phylink_link_state *state) const struct phylink_link_state *state)
{ {
struct sja1105_private *priv = ds->priv; struct sja1105_private *priv = ds->priv;
bool is_sgmii = sja1105_supports_sgmii(priv, port); bool is_sgmii;
is_sgmii = (state->interface == PHY_INTERFACE_MODE_SGMII);
if (sja1105_phy_mode_mismatch(priv, port, state->interface)) { if (sja1105_phy_mode_mismatch(priv, port, state->interface)) {
dev_err(ds->dev, "Changing PHY mode to %s not supported!\n", dev_err(ds->dev, "Changing PHY mode to %s not supported!\n",
...@@ -1113,7 +1118,8 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port, ...@@ -1113,7 +1118,8 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port,
} }
if (is_sgmii) if (is_sgmii)
sja1105_sgmii_pcs_config(priv, phylink_autoneg_inband(mode), sja1105_sgmii_pcs_config(priv, port,
phylink_autoneg_inband(mode),
false); false);
} }
...@@ -1135,8 +1141,9 @@ static void sja1105_mac_link_up(struct dsa_switch *ds, int port, ...@@ -1135,8 +1141,9 @@ static void sja1105_mac_link_up(struct dsa_switch *ds, int port,
sja1105_adjust_port_config(priv, port, speed); sja1105_adjust_port_config(priv, port, speed);
if (sja1105_supports_sgmii(priv, port) && !phylink_autoneg_inband(mode)) if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII &&
sja1105_sgmii_pcs_force_speed(priv, speed); !phylink_autoneg_inband(mode))
sja1105_sgmii_pcs_force_speed(priv, port, speed);
sja1105_inhibit_tx(priv, BIT(port), false); sja1105_inhibit_tx(priv, BIT(port), false);
} }
...@@ -1189,7 +1196,7 @@ static int sja1105_mac_pcs_get_state(struct dsa_switch *ds, int port, ...@@ -1189,7 +1196,7 @@ static int sja1105_mac_pcs_get_state(struct dsa_switch *ds, int port,
int ais; int ais;
/* Read the vendor-specific AUTONEG_INTR_STATUS register */ /* Read the vendor-specific AUTONEG_INTR_STATUS register */
ais = sja1105_sgmii_read(priv, SJA1105_AIS); ais = sja1105_sgmii_read(priv, port, MDIO_MMD_VEND2, SJA1105_AIS);
if (ais < 0) if (ais < 0)
return ais; return ais;
...@@ -1871,11 +1878,11 @@ int sja1105_static_config_reload(struct sja1105_private *priv, ...@@ -1871,11 +1878,11 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
struct ptp_system_timestamp ptp_sts_before; struct ptp_system_timestamp ptp_sts_before;
struct ptp_system_timestamp ptp_sts_after; struct ptp_system_timestamp ptp_sts_after;
int speed_mbps[SJA1105_MAX_NUM_PORTS]; int speed_mbps[SJA1105_MAX_NUM_PORTS];
u16 bmcr[SJA1105_MAX_NUM_PORTS] = {0};
struct sja1105_mac_config_entry *mac; struct sja1105_mac_config_entry *mac;
struct dsa_switch *ds = priv->ds; struct dsa_switch *ds = priv->ds;
s64 t1, t2, t3, t4; s64 t1, t2, t3, t4;
s64 t12, t34; s64 t12, t34;
u16 bmcr = 0;
int rc, i; int rc, i;
s64 now; s64 now;
...@@ -1889,12 +1896,15 @@ int sja1105_static_config_reload(struct sja1105_private *priv, ...@@ -1889,12 +1896,15 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
* change it through the dynamic interface later. * change it through the dynamic interface later.
*/ */
for (i = 0; i < ds->num_ports; i++) { for (i = 0; i < ds->num_ports; i++) {
speed_mbps[i] = sja1105_speed[mac[i].speed]; speed_mbps[i] = sja1105_port_speed_to_ethtool(priv,
mac[i].speed = SJA1105_SPEED_AUTO; mac[i].speed);
} mac[i].speed = priv->info->port_speed[SJA1105_SPEED_AUTO];
if (sja1105_supports_sgmii(priv, SJA1105_SGMII_PORT)) if (priv->phy_mode[i] == PHY_INTERFACE_MODE_SGMII)
bmcr = sja1105_sgmii_read(priv, MII_BMCR); bmcr[i] = sja1105_sgmii_read(priv, i,
MDIO_MMD_VEND2,
MDIO_CTRL1);
}
/* No PTP operations can run right now */ /* No PTP operations can run right now */
mutex_lock(&priv->ptp_data.lock); mutex_lock(&priv->ptp_data.lock);
...@@ -1941,27 +1951,30 @@ int sja1105_static_config_reload(struct sja1105_private *priv, ...@@ -1941,27 +1951,30 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
goto out; goto out;
for (i = 0; i < ds->num_ports; i++) { for (i = 0; i < ds->num_ports; i++) {
bool an_enabled;
rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]); rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]);
if (rc < 0) if (rc < 0)
goto out; goto out;
}
if (sja1105_supports_sgmii(priv, SJA1105_SGMII_PORT)) { if (priv->phy_mode[i] != PHY_INTERFACE_MODE_SGMII)
bool an_enabled = !!(bmcr & BMCR_ANENABLE); continue;
an_enabled = !!(bmcr[i] & BMCR_ANENABLE);
sja1105_sgmii_pcs_config(priv, an_enabled, false); sja1105_sgmii_pcs_config(priv, i, an_enabled, false);
if (!an_enabled) { if (!an_enabled) {
int speed = SPEED_UNKNOWN; int speed = SPEED_UNKNOWN;
if (bmcr & BMCR_SPEED1000) if (bmcr[i] & BMCR_SPEED1000)
speed = SPEED_1000; speed = SPEED_1000;
else if (bmcr & BMCR_SPEED100) else if (bmcr[i] & BMCR_SPEED100)
speed = SPEED_100; speed = SPEED_100;
else else
speed = SPEED_10; speed = SPEED_10;
sja1105_sgmii_pcs_force_speed(priv, speed); sja1105_sgmii_pcs_force_speed(priv, i, speed);
} }
} }
......
...@@ -440,7 +440,6 @@ static struct sja1105_regs sja1105pqrs_regs = { ...@@ -440,7 +440,6 @@ static struct sja1105_regs sja1105pqrs_regs = {
.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808}, .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
.pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809}, .pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
.pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814}, .pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
.sgmii = 0x1F0000,
.rmii_pll1 = 0x10000A, .rmii_pll1 = 0x10000A,
.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F}, .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
.stats[MAC] = {0x200, 0x202, 0x204, 0x206, 0x208}, .stats[MAC] = {0x200, 0x202, 0x204, 0x206, 0x208},
...@@ -483,6 +482,16 @@ const struct sja1105_info sja1105e_info = { ...@@ -483,6 +482,16 @@ const struct sja1105_info sja1105e_info = {
.ptp_cmd_packing = sja1105et_ptp_cmd_packing, .ptp_cmd_packing = sja1105et_ptp_cmd_packing,
.clocking_setup = sja1105_clocking_setup, .clocking_setup = sja1105_clocking_setup,
.regs = &sja1105et_regs, .regs = &sja1105et_regs,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 3,
[SJA1105_SPEED_100MBPS] = 2,
[SJA1105_SPEED_1000MBPS] = 1,
[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
},
.supports_mii = {true, true, true, true, true},
.supports_rmii = {true, true, true, true, true},
.supports_rgmii = {true, true, true, true, true},
.name = "SJA1105E", .name = "SJA1105E",
}; };
...@@ -503,6 +512,16 @@ const struct sja1105_info sja1105t_info = { ...@@ -503,6 +512,16 @@ const struct sja1105_info sja1105t_info = {
.ptp_cmd_packing = sja1105et_ptp_cmd_packing, .ptp_cmd_packing = sja1105et_ptp_cmd_packing,
.clocking_setup = sja1105_clocking_setup, .clocking_setup = sja1105_clocking_setup,
.regs = &sja1105et_regs, .regs = &sja1105et_regs,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 3,
[SJA1105_SPEED_100MBPS] = 2,
[SJA1105_SPEED_1000MBPS] = 1,
[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
},
.supports_mii = {true, true, true, true, true},
.supports_rmii = {true, true, true, true, true},
.supports_rgmii = {true, true, true, true, true},
.name = "SJA1105T", .name = "SJA1105T",
}; };
...@@ -524,6 +543,16 @@ const struct sja1105_info sja1105p_info = { ...@@ -524,6 +543,16 @@ const struct sja1105_info sja1105p_info = {
.ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
.clocking_setup = sja1105_clocking_setup, .clocking_setup = sja1105_clocking_setup,
.regs = &sja1105pqrs_regs, .regs = &sja1105pqrs_regs,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 3,
[SJA1105_SPEED_100MBPS] = 2,
[SJA1105_SPEED_1000MBPS] = 1,
[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
},
.supports_mii = {true, true, true, true, true},
.supports_rmii = {true, true, true, true, true},
.supports_rgmii = {true, true, true, true, true},
.name = "SJA1105P", .name = "SJA1105P",
}; };
...@@ -545,6 +574,16 @@ const struct sja1105_info sja1105q_info = { ...@@ -545,6 +574,16 @@ const struct sja1105_info sja1105q_info = {
.ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
.clocking_setup = sja1105_clocking_setup, .clocking_setup = sja1105_clocking_setup,
.regs = &sja1105pqrs_regs, .regs = &sja1105pqrs_regs,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 3,
[SJA1105_SPEED_100MBPS] = 2,
[SJA1105_SPEED_1000MBPS] = 1,
[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
},
.supports_mii = {true, true, true, true, true},
.supports_rmii = {true, true, true, true, true},
.supports_rgmii = {true, true, true, true, true},
.name = "SJA1105Q", .name = "SJA1105Q",
}; };
...@@ -566,6 +605,17 @@ const struct sja1105_info sja1105r_info = { ...@@ -566,6 +605,17 @@ const struct sja1105_info sja1105r_info = {
.ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
.clocking_setup = sja1105_clocking_setup, .clocking_setup = sja1105_clocking_setup,
.regs = &sja1105pqrs_regs, .regs = &sja1105pqrs_regs,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 3,
[SJA1105_SPEED_100MBPS] = 2,
[SJA1105_SPEED_1000MBPS] = 1,
[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
},
.supports_mii = {true, true, true, true, true},
.supports_rmii = {true, true, true, true, true},
.supports_rgmii = {true, true, true, true, true},
.supports_sgmii = {false, false, false, false, true},
.name = "SJA1105R", .name = "SJA1105R",
}; };
...@@ -587,5 +637,16 @@ const struct sja1105_info sja1105s_info = { ...@@ -587,5 +637,16 @@ const struct sja1105_info sja1105s_info = {
.fdb_del_cmd = sja1105pqrs_fdb_del, .fdb_del_cmd = sja1105pqrs_fdb_del,
.ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
.clocking_setup = sja1105_clocking_setup, .clocking_setup = sja1105_clocking_setup,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 3,
[SJA1105_SPEED_100MBPS] = 2,
[SJA1105_SPEED_1000MBPS] = 1,
[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
},
.supports_mii = {true, true, true, true, true},
.supports_rmii = {true, true, true, true, true},
.supports_rgmii = {true, true, true, true, true},
.supports_sgmii = {false, false, false, false, true},
.name = "SJA1105S", .name = "SJA1105S",
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment