Commit 06d62113 authored by David S. Miller's avatar David S. Miller

Merge branch 'sja1105-yaml'

Vladimir Oltean says:

====================
Convert NXP SJA1105 DSA driver to YAML

This is an attempt to convert the SJA1105 driver to the YAML schema.

The SJA1105 driver has some custom device tree properties which caused
validation problems in the previous attempt:
https://patchwork.kernel.org/project/netdevbpf/patch/20210531234735.1582031-1-olteanv@gmail.com/

So now we are removing them, hoping that this will make the conversion
easier to accept.

In order to do that, we introduce a new PHY interface type, "reverse RMII",
which is like "reverse MII" (aka MII as a PHY) but for the reduced data
width version of the protocol. This is a direct replacement for an rmii
fixed-link. Now, rmii fixed-link interfaces behave as a MAC, and rev-rmii
fixed-link interfaces behave as a PHY.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1a42624a 62568bdb
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/dsa/nxp,sja1105.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP SJA1105 Automotive Ethernet Switch Family Device Tree Bindings
description:
The SJA1105 SPI interface requires a CS-to-CLK time (t2 in UM10944.pdf) of at
least one half of t_CLK. At an SPI frequency of 1MHz, this means a minimum
cs_sck_delay of 500ns. Ensuring that this SPI timing requirement is observed
depends on the SPI bus master driver.
allOf:
- $ref: "dsa.yaml#"
maintainers:
- Vladimir Oltean <vladimir.oltean@nxp.com>
properties:
compatible:
enum:
- nxp,sja1105e
- nxp,sja1105t
- nxp,sja1105p
- nxp,sja1105q
- nxp,sja1105r
- nxp,sja1105s
reg:
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
ethernet-switch@1 {
reg = <0x1>;
compatible = "nxp,sja1105t";
ethernet-ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
phy-handle = <&rgmii_phy6>;
phy-mode = "rgmii-id";
reg = <0>;
};
port@1 {
phy-handle = <&rgmii_phy3>;
phy-mode = "rgmii-id";
reg = <1>;
};
port@2 {
phy-handle = <&rgmii_phy4>;
phy-mode = "rgmii-id";
reg = <2>;
};
port@3 {
phy-mode = "rgmii-id";
reg = <3>;
};
port@4 {
ethernet = <&enet2>;
phy-mode = "rgmii";
reg = <4>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
};
NXP SJA1105 switch driver
=========================
Required properties:
- compatible:
Must be one of:
- "nxp,sja1105e"
- "nxp,sja1105t"
- "nxp,sja1105p"
- "nxp,sja1105q"
- "nxp,sja1105r"
- "nxp,sja1105s"
Although the device ID could be detected at runtime, explicit bindings
are required in order to be able to statically check their validity.
For example, SGMII can only be specified on port 4 of R and S devices,
and the non-SGMII devices, while pin-compatible, are not equal in terms
of support for RGMII internal delays (supported on P/Q/R/S, but not on
E/T).
Optional properties:
- sja1105,role-mac:
- sja1105,role-phy:
Boolean properties that can be assigned under each port node. By
default (unless otherwise specified) a port is configured as MAC if it
is driving a PHY (phy-handle is present) or as PHY if it is PHY-less
(fixed-link specified, presumably because it is connected to a MAC).
The effect of this property (in either its implicit or explicit form)
is:
- In the case of MII or RMII it specifies whether the SJA1105 port is a
clock source or sink for this interface (not applicable for RGMII
where there is a Tx and an Rx clock).
- In the case of RGMII it affects the behavior regarding internal
delays:
1. If sja1105,role-mac is specified, and the phy-mode property is one
of "rgmii-id", "rgmii-txid" or "rgmii-rxid", then the entity
designated to apply the delay/clock skew necessary for RGMII
is the PHY. The SJA1105 MAC does not apply any internal delays.
2. If sja1105,role-phy is specified, and the phy-mode property is one
of the above, the designated entity to apply the internal delays
is the SJA1105 MAC (if hardware-supported). This is only supported
by the second-generation (P/Q/R/S) hardware. On a first-generation
E or T device, it is an error to specify an RGMII phy-mode other
than "rgmii" for a port that is in fixed-link mode. In that case,
the clock skew must either be added by the MAC at the other end of
the fixed-link, or by PCB serpentine traces on the board.
These properties are required, for example, in the case where SJA1105
ports are at both ends of a MII/RMII PHY-less setup. One end would need
to have sja1105,role-mac, while the other sja1105,role-phy.
See Documentation/devicetree/bindings/net/dsa/dsa.txt for the list of standard
DSA required and optional properties.
Other observations
------------------
The SJA1105 SPI interface requires a CS-to-CLK time (t2 in UM10944) of at least
one half of t_CLK. At an SPI frequency of 1MHz, this means a minimum
cs_sck_delay of 500ns. Ensuring that this SPI timing requirement is observed
depends on the SPI bus master driver.
Example
-------
Ethernet switch connected via SPI to the host, CPU port wired to enet2:
arch/arm/boot/dts/ls1021a-tsn.dts:
/* SPI controller of the LS1021 */
&dspi0 {
sja1105@1 {
reg = <0x1>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "nxp,sja1105t";
spi-max-frequency = <4000000>;
fsl,spi-cs-sck-delay = <1000>;
fsl,spi-sck-cs-delay = <1000>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
/* ETH5 written on chassis */
label = "swp5";
phy-handle = <&rgmii_phy6>;
phy-mode = "rgmii-id";
reg = <0>;
/* Implicit "sja1105,role-mac;" */
};
port@1 {
/* ETH2 written on chassis */
label = "swp2";
phy-handle = <&rgmii_phy3>;
phy-mode = "rgmii-id";
reg = <1>;
/* Implicit "sja1105,role-mac;" */
};
port@2 {
/* ETH3 written on chassis */
label = "swp3";
phy-handle = <&rgmii_phy4>;
phy-mode = "rgmii-id";
reg = <2>;
/* Implicit "sja1105,role-mac;" */
};
port@3 {
/* ETH4 written on chassis */
phy-handle = <&rgmii_phy5>;
label = "swp4";
phy-mode = "rgmii-id";
reg = <3>;
/* Implicit "sja1105,role-mac;" */
};
port@4 {
/* Internal port connected to eth2 */
ethernet = <&enet2>;
phy-mode = "rgmii";
reg = <4>;
/* Implicit "sja1105,role-phy;" */
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
};
/* MDIO controller of the LS1021 */
&mdio0 {
/* BCM5464 */
rgmii_phy3: ethernet-phy@3 {
reg = <0x3>;
};
rgmii_phy4: ethernet-phy@4 {
reg = <0x4>;
};
rgmii_phy5: ethernet-phy@5 {
reg = <0x5>;
};
rgmii_phy6: ethernet-phy@6 {
reg = <0x6>;
};
};
/* Ethernet master port of the LS1021 */
&enet2 {
phy-connection-type = "rgmii";
status = "ok";
fixed-link {
speed = <1000>;
full-duplex;
};
};
...@@ -68,6 +68,7 @@ properties: ...@@ -68,6 +68,7 @@ properties:
- tbi - tbi
- rev-mii - rev-mii
- rmii - rmii
- rev-rmii
# RX and TX delays are added by the MAC when required # RX and TX delays are added by the MAC when required
- rgmii - rgmii
......
...@@ -226,6 +226,7 @@ struct sja1105_private { ...@@ -226,6 +226,7 @@ struct sja1105_private {
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]; phy_interface_t phy_mode[SJA1105_MAX_NUM_PORTS];
bool fixed_link[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;
......
...@@ -57,14 +57,6 @@ static bool sja1105_can_forward(struct sja1105_l2_forwarding_entry *l2_fwd, ...@@ -57,14 +57,6 @@ static bool sja1105_can_forward(struct sja1105_l2_forwarding_entry *l2_fwd,
return !!(l2_fwd[from].reach_port & BIT(to)); return !!(l2_fwd[from].reach_port & BIT(to));
} }
/* Structure used to temporarily transport device tree
* settings into sja1105_setup
*/
struct sja1105_dt_port {
phy_interface_t phy_mode;
sja1105_mii_role_t role;
};
static int sja1105_init_mac_settings(struct sja1105_private *priv) static int sja1105_init_mac_settings(struct sja1105_private *priv)
{ {
struct sja1105_mac_config_entry default_mac = { struct sja1105_mac_config_entry default_mac = {
...@@ -143,8 +135,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) ...@@ -143,8 +135,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
return 0; return 0;
} }
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 device *dev = &priv->spidev->dev; struct device *dev = &priv->spidev->dev;
struct sja1105_xmii_params_entry *mii; struct sja1105_xmii_params_entry *mii;
...@@ -171,16 +162,24 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv, ...@@ -171,16 +162,24 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
mii = table->entries; mii = table->entries;
for (i = 0; i < ds->num_ports; i++) { for (i = 0; i < ds->num_ports; i++) {
sja1105_mii_role_t role = XMII_MAC;
if (dsa_is_unused_port(priv->ds, i)) if (dsa_is_unused_port(priv->ds, i))
continue; continue;
switch (ports[i].phy_mode) { switch (priv->phy_mode[i]) {
case PHY_INTERFACE_MODE_REVMII:
role = XMII_PHY;
fallthrough;
case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_MII:
if (!priv->info->supports_mii[i]) if (!priv->info->supports_mii[i])
goto unsupported; goto unsupported;
mii->xmii_mode[i] = XMII_MODE_MII; mii->xmii_mode[i] = XMII_MODE_MII;
break; break;
case PHY_INTERFACE_MODE_REVRMII:
role = XMII_PHY;
fallthrough;
case PHY_INTERFACE_MODE_RMII: case PHY_INTERFACE_MODE_RMII:
if (!priv->info->supports_rmii[i]) if (!priv->info->supports_rmii[i])
goto unsupported; goto unsupported;
...@@ -211,24 +210,11 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv, ...@@ -211,24 +210,11 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
unsupported: unsupported:
default: default:
dev_err(dev, "Unsupported PHY mode %s on port %d!\n", dev_err(dev, "Unsupported PHY mode %s on port %d!\n",
phy_modes(ports[i].phy_mode), i); phy_modes(priv->phy_mode[i]), i);
return -EINVAL; return -EINVAL;
} }
/* Even though the SerDes port is able to drive SGMII autoneg mii->phy_mac[i] = role;
* like a PHY would, from the perspective of the XMII tables,
* 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 ||
phy_interface_mode_is_rgmii(ports[i].phy_mode))
mii->phy_mac[i] = XMII_MAC;
else
mii->phy_mac[i] = ports[i].role;
} }
return 0; return 0;
} }
...@@ -751,8 +737,7 @@ static int sja1105_init_l2_policing(struct sja1105_private *priv) ...@@ -751,8 +737,7 @@ static int sja1105_init_l2_policing(struct sja1105_private *priv)
return 0; return 0;
} }
static int sja1105_static_config_load(struct sja1105_private *priv, static int sja1105_static_config_load(struct sja1105_private *priv)
struct sja1105_dt_port *ports)
{ {
int rc; int rc;
...@@ -767,7 +752,7 @@ static int sja1105_static_config_load(struct sja1105_private *priv, ...@@ -767,7 +752,7 @@ static int sja1105_static_config_load(struct sja1105_private *priv,
rc = sja1105_init_mac_settings(priv); rc = sja1105_init_mac_settings(priv);
if (rc < 0) if (rc < 0)
return rc; return rc;
rc = sja1105_init_mii_settings(priv, ports); rc = sja1105_init_mii_settings(priv);
if (rc < 0) if (rc < 0)
return rc; return rc;
rc = sja1105_init_static_fdb(priv); rc = sja1105_init_static_fdb(priv);
...@@ -799,33 +784,31 @@ static int sja1105_static_config_load(struct sja1105_private *priv, ...@@ -799,33 +784,31 @@ static int sja1105_static_config_load(struct sja1105_private *priv,
return sja1105_static_config_upload(priv); return sja1105_static_config_upload(priv);
} }
static int sja1105_parse_rgmii_delays(struct sja1105_private *priv, static int sja1105_parse_rgmii_delays(struct sja1105_private *priv)
const struct sja1105_dt_port *ports)
{ {
struct dsa_switch *ds = priv->ds; struct dsa_switch *ds = priv->ds;
int i; int port;
for (i = 0; i < ds->num_ports; i++) { for (port = 0; port < ds->num_ports; port++) {
if (ports[i].role == XMII_MAC) if (!priv->fixed_link[port])
continue; continue;
if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_RXID || if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_RXID ||
ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID) priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID)
priv->rgmii_rx_delay[i] = true; priv->rgmii_rx_delay[port] = true;
if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_TXID || if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_TXID ||
ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID) priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID)
priv->rgmii_tx_delay[i] = true; priv->rgmii_tx_delay[port] = true;
if ((priv->rgmii_rx_delay[i] || priv->rgmii_tx_delay[i]) && if ((priv->rgmii_rx_delay[port] || priv->rgmii_tx_delay[port]) &&
!priv->info->setup_rgmii_delay) !priv->info->setup_rgmii_delay)
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
static int sja1105_parse_ports_node(struct sja1105_private *priv, static int sja1105_parse_ports_node(struct sja1105_private *priv,
struct sja1105_dt_port *ports,
struct device_node *ports_node) struct device_node *ports_node)
{ {
struct device *dev = &priv->spidev->dev; struct device *dev = &priv->spidev->dev;
...@@ -854,7 +837,6 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, ...@@ -854,7 +837,6 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
of_node_put(child); of_node_put(child);
return -ENODEV; return -ENODEV;
} }
ports[index].phy_mode = phy_mode;
phy_node = of_parse_phandle(child, "phy-handle", 0); phy_node = of_parse_phandle(child, "phy-handle", 0);
if (!phy_node) { if (!phy_node) {
...@@ -867,27 +849,18 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, ...@@ -867,27 +849,18 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
/* phy-handle is missing, but fixed-link isn't. /* phy-handle is missing, but fixed-link isn't.
* So it's a fixed link. Default to PHY role. * So it's a fixed link. Default to PHY role.
*/ */
ports[index].role = XMII_PHY; priv->fixed_link[index] = true;
} else { } else {
/* phy-handle present => put port in MAC role */
ports[index].role = XMII_MAC;
of_node_put(phy_node); of_node_put(phy_node);
} }
/* The MAC/PHY role can be overridden with explicit bindings */
if (of_property_read_bool(child, "sja1105,role-mac"))
ports[index].role = XMII_MAC;
else if (of_property_read_bool(child, "sja1105,role-phy"))
ports[index].role = XMII_PHY;
priv->phy_mode[index] = phy_mode; priv->phy_mode[index] = phy_mode;
} }
return 0; return 0;
} }
static int sja1105_parse_dt(struct sja1105_private *priv, static int sja1105_parse_dt(struct sja1105_private *priv)
struct sja1105_dt_port *ports)
{ {
struct device *dev = &priv->spidev->dev; struct device *dev = &priv->spidev->dev;
struct device_node *switch_node = dev->of_node; struct device_node *switch_node = dev->of_node;
...@@ -902,7 +875,7 @@ static int sja1105_parse_dt(struct sja1105_private *priv, ...@@ -902,7 +875,7 @@ static int sja1105_parse_dt(struct sja1105_private *priv,
return -ENODEV; return -ENODEV;
} }
rc = sja1105_parse_ports_node(priv, ports, ports_node); rc = sja1105_parse_ports_node(priv, ports_node);
of_node_put(ports_node); of_node_put(ports_node);
return rc; return rc;
...@@ -3008,11 +2981,10 @@ static const struct dsa_8021q_ops sja1105_dsa_8021q_ops = { ...@@ -3008,11 +2981,10 @@ static const struct dsa_8021q_ops sja1105_dsa_8021q_ops = {
*/ */
static int sja1105_setup(struct dsa_switch *ds) static int sja1105_setup(struct dsa_switch *ds)
{ {
struct sja1105_dt_port ports[SJA1105_MAX_NUM_PORTS];
struct sja1105_private *priv = ds->priv; struct sja1105_private *priv = ds->priv;
int rc; int rc;
rc = sja1105_parse_dt(priv, ports); rc = sja1105_parse_dt(priv);
if (rc < 0) { if (rc < 0) {
dev_err(ds->dev, "Failed to parse DT: %d\n", rc); dev_err(ds->dev, "Failed to parse DT: %d\n", rc);
return rc; return rc;
...@@ -3021,7 +2993,7 @@ static int sja1105_setup(struct dsa_switch *ds) ...@@ -3021,7 +2993,7 @@ static int sja1105_setup(struct dsa_switch *ds)
/* Error out early if internal delays are required through DT /* Error out early if internal delays are required through DT
* and we can't apply them. * and we can't apply them.
*/ */
rc = sja1105_parse_rgmii_delays(priv, ports); rc = sja1105_parse_rgmii_delays(priv);
if (rc < 0) { if (rc < 0) {
dev_err(ds->dev, "RGMII delay not supported\n"); dev_err(ds->dev, "RGMII delay not supported\n");
return rc; return rc;
...@@ -3033,7 +3005,7 @@ static int sja1105_setup(struct dsa_switch *ds) ...@@ -3033,7 +3005,7 @@ static int sja1105_setup(struct dsa_switch *ds)
return rc; return rc;
} }
/* Create and send configuration down to device */ /* Create and send configuration down to device */
rc = sja1105_static_config_load(priv, ports); rc = sja1105_static_config_load(priv);
if (rc < 0) { if (rc < 0) {
dev_err(ds->dev, "Failed to load static config: %d\n", rc); dev_err(ds->dev, "Failed to load static config: %d\n", rc);
goto out_ptp_clock_unregister; goto out_ptp_clock_unregister;
......
...@@ -93,6 +93,7 @@ extern const int phy_10gbit_features_array[1]; ...@@ -93,6 +93,7 @@ extern const int phy_10gbit_features_array[1];
* @PHY_INTERFACE_MODE_TBI: Ten Bit Interface * @PHY_INTERFACE_MODE_TBI: Ten Bit Interface
* @PHY_INTERFACE_MODE_REVMII: Reverse Media Independent Interface * @PHY_INTERFACE_MODE_REVMII: Reverse Media Independent Interface
* @PHY_INTERFACE_MODE_RMII: Reduced Media Independent Interface * @PHY_INTERFACE_MODE_RMII: Reduced Media Independent Interface
* @PHY_INTERFACE_MODE_REVRMII: Reduced Media Independent Interface in PHY role
* @PHY_INTERFACE_MODE_RGMII: Reduced gigabit media-independent interface * @PHY_INTERFACE_MODE_RGMII: Reduced gigabit media-independent interface
* @PHY_INTERFACE_MODE_RGMII_ID: RGMII with Internal RX+TX delay * @PHY_INTERFACE_MODE_RGMII_ID: RGMII with Internal RX+TX delay
* @PHY_INTERFACE_MODE_RGMII_RXID: RGMII with Internal RX delay * @PHY_INTERFACE_MODE_RGMII_RXID: RGMII with Internal RX delay
...@@ -126,6 +127,7 @@ typedef enum { ...@@ -126,6 +127,7 @@ typedef enum {
PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_TBI,
PHY_INTERFACE_MODE_REVMII, PHY_INTERFACE_MODE_REVMII,
PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RMII,
PHY_INTERFACE_MODE_REVRMII,
PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_RGMII,
PHY_INTERFACE_MODE_RGMII_ID, PHY_INTERFACE_MODE_RGMII_ID,
PHY_INTERFACE_MODE_RGMII_RXID, PHY_INTERFACE_MODE_RGMII_RXID,
...@@ -185,6 +187,8 @@ static inline const char *phy_modes(phy_interface_t interface) ...@@ -185,6 +187,8 @@ static inline const char *phy_modes(phy_interface_t interface)
return "rev-mii"; return "rev-mii";
case PHY_INTERFACE_MODE_RMII: case PHY_INTERFACE_MODE_RMII:
return "rmii"; return "rmii";
case PHY_INTERFACE_MODE_REVRMII:
return "rev-rmii";
case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII:
return "rgmii"; return "rgmii";
case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_ID:
......
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