Commit 4d8e5035 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sja1105-next'

Vladimir Oltean says:

====================
New RGMII delay DT bindings for the SJA1105 DSA driver

During recent reviews I've been telling people that new MAC drivers
should adopt a certain DT binding format for RGMII delays in order to
avoid conflicting interpretations. Some suggestions were better received
than others, and it appears we are still far from a consensus.

Part of the problem seems to be that there are still drivers that apply
RGMII delays based on an incorrect interpretation of the device tree,
and these serve as a bad example for others.
I happen to maintain one of those drivers and I am able to test it, so I
figure that one of the ways in which I can make a change is to stop
providing a bad example.

Therefore, this series adds support for the "rx-internal-delay-ps" and
"tx-internal-delay-ps" properties inside sja1105 switch port DT nodes,
and if these are present, they will decide what RGMII delays will the
driver apply.

The in-tree device trees are also updated to follow the new format, as
well as the schema validator.

I assume it's okay to get all changes merged in through the same tree
(net-next). Although the DTS changes could be split, if needed - the
driver works with or without them. There is one more DTS which should be
changed, which is in Shawn's tree but not in net-next:
https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git/tree/arch/arm64/boot/dts/freescale/fsl-lx2160a-bluebox3.dts?h=for-next


For that, I'd have to send a separate patch.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 816219a8 9ca482a2
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -46,6 +46,9 @@ patternProperties:
        type: object
        description: Ethernet switch ports

        allOf:
          - $ref: "http://devicetree.org/schemas/net/ethernet-controller.yaml#"

        properties:
          reg:
            description: Port number
@@ -94,6 +97,10 @@ patternProperties:

          managed: true

          rx-internal-delay-ps: true

          tx-internal-delay-ps: true

        required:
          - reg

+43 −0
Original line number Diff line number Diff line
@@ -74,10 +74,42 @@ properties:
          - compatible
          - reg

patternProperties:
  "^(ethernet-)?ports$":
    patternProperties:
      "^(ethernet-)?port@[0-9]+$":
        allOf:
          - if:
              properties:
                phy-mode:
                  contains:
                    enum:
                      - rgmii
                      - rgmii-rxid
                      - rgmii-txid
                      - rgmii-id
            then:
              properties:
                rx-internal-delay-ps:
                  $ref: "#/$defs/internal-delay-ps"
                tx-internal-delay-ps:
                  $ref: "#/$defs/internal-delay-ps"

required:
  - compatible
  - reg

$defs:
  internal-delay-ps:
    description:
      Disable tunable delay lines using 0 ps, or enable them and select
      the phase between 1640 ps (73.8 degree shift at 1Gbps) and 2260 ps
      (101.7 degree shift) in increments of 0.9 degrees (20 ps).
    enum:
      [0, 1640, 1660, 1680, 1700, 1720, 1740, 1760, 1780, 1800, 1820, 1840,
       1860, 1880, 1900, 1920, 1940, 1960, 1980, 2000, 2020, 2040, 2060, 2080,
       2100, 2120, 2140, 2160, 2180, 2200, 2220, 2240, 2260]

unevaluatedProperties: false

examples:
@@ -97,29 +129,40 @@ examples:
                            port@0 {
                                    phy-handle = <&rgmii_phy6>;
                                    phy-mode = "rgmii-id";
                                    rx-internal-delay-ps = <0>;
                                    tx-internal-delay-ps = <0>;
                                    reg = <0>;
                            };

                            port@1 {
                                    phy-handle = <&rgmii_phy3>;
                                    phy-mode = "rgmii-id";
                                    rx-internal-delay-ps = <0>;
                                    tx-internal-delay-ps = <0>;
                                    reg = <1>;
                            };

                            port@2 {
                                    phy-handle = <&rgmii_phy4>;
                                    phy-mode = "rgmii-id";
                                    rx-internal-delay-ps = <0>;
                                    tx-internal-delay-ps = <0>;
                                    reg = <2>;
                            };

                            port@3 {
                                    phy-handle = <&rgmii_phy4>;
                                    phy-mode = "rgmii-id";
                                    rx-internal-delay-ps = <0>;
                                    tx-internal-delay-ps = <0>;
                                    reg = <3>;
                            };

                            port@4 {
                                    ethernet = <&enet2>;
                                    phy-mode = "rgmii";
                                    rx-internal-delay-ps = <0>;
                                    tx-internal-delay-ps = <0>;
                                    reg = <4>;

                                    fixed-link {
+23 −2
Original line number Diff line number Diff line
@@ -20,6 +20,27 @@
#define SJA1105_AGEING_TIME_MS(ms)	((ms) / 10)
#define SJA1105_NUM_L2_POLICERS		SJA1110_MAX_L2_POLICING_COUNT

/* Calculated assuming 1Gbps, where the clock has 125 MHz (8 ns period)
 * To avoid floating point operations, we'll multiply the degrees by 10
 * to get a "phase" and get 1 decimal point precision.
 */
#define SJA1105_RGMII_DELAY_PS_TO_PHASE(ps) \
	(((ps) * 360) / 800)
#define SJA1105_RGMII_DELAY_PHASE_TO_PS(phase) \
	((800 * (phase)) / 360)
#define SJA1105_RGMII_DELAY_PHASE_TO_HW(phase) \
	(((phase) - 738) / 9)
#define SJA1105_RGMII_DELAY_PS_TO_HW(ps) \
	SJA1105_RGMII_DELAY_PHASE_TO_HW(SJA1105_RGMII_DELAY_PS_TO_PHASE(ps))

/* Valid range in degrees is a value between 73.8 and 101.7
 * in 0.9 degree increments
 */
#define SJA1105_RGMII_DELAY_MIN_PS \
	SJA1105_RGMII_DELAY_PHASE_TO_PS(738)
#define SJA1105_RGMII_DELAY_MAX_PS \
	SJA1105_RGMII_DELAY_PHASE_TO_PS(1017)

typedef enum {
	SPI_READ = 0,
	SPI_WRITE = 1,
@@ -222,8 +243,8 @@ struct sja1105_flow_block {

struct sja1105_private {
	struct sja1105_static_config static_config;
	bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS];
	bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS];
	int rgmii_rx_delay_ps[SJA1105_MAX_NUM_PORTS];
	int rgmii_tx_delay_ps[SJA1105_MAX_NUM_PORTS];
	phy_interface_t phy_mode[SJA1105_MAX_NUM_PORTS];
	bool fixed_link[SJA1105_MAX_NUM_PORTS];
	unsigned long ucast_egress_floods;
+14 −21
Original line number Diff line number Diff line
@@ -498,17 +498,6 @@ sja1110_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
	sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
}

/* Valid range in degrees is an integer between 73.8 and 101.7 */
static u64 sja1105_rgmii_delay(u64 phase)
{
	/* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9.
	 * To avoid floating point operations we'll multiply by 10
	 * and get 1 decimal point precision.
	 */
	phase *= 10;
	return (phase - 738) / 9;
}

/* The RGMII delay setup procedure is 2-step and gets called upon each
 * .phylink_mac_config. Both are strategic.
 * The reason is that the RX Tunable Delay Line of the SJA1105 MAC has issues
@@ -521,13 +510,15 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
	const struct sja1105_private *priv = ctx;
	const struct sja1105_regs *regs = priv->info->regs;
	struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
	int rx_delay = priv->rgmii_rx_delay_ps[port];
	int tx_delay = priv->rgmii_tx_delay_ps[port];
	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
	int rc;

	if (priv->rgmii_rx_delay[port])
		pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
	if (priv->rgmii_tx_delay[port])
		pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
	if (rx_delay)
		pad_mii_id.rxc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(rx_delay);
	if (tx_delay)
		pad_mii_id.txc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(tx_delay);

	/* Stage 1: Turn the RGMII delay lines off. */
	pad_mii_id.rxc_bypass = 1;
@@ -542,11 +533,11 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
		return rc;

	/* Stage 2: Turn the RGMII delay lines on. */
	if (priv->rgmii_rx_delay[port]) {
	if (rx_delay) {
		pad_mii_id.rxc_bypass = 0;
		pad_mii_id.rxc_pd = 0;
	}
	if (priv->rgmii_tx_delay[port]) {
	if (tx_delay) {
		pad_mii_id.txc_bypass = 0;
		pad_mii_id.txc_pd = 0;
	}
@@ -561,20 +552,22 @@ int sja1110_setup_rgmii_delay(const void *ctx, int port)
	const struct sja1105_private *priv = ctx;
	const struct sja1105_regs *regs = priv->info->regs;
	struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
	int rx_delay = priv->rgmii_rx_delay_ps[port];
	int tx_delay = priv->rgmii_tx_delay_ps[port];
	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};

	pad_mii_id.rxc_pd = 1;
	pad_mii_id.txc_pd = 1;

	if (priv->rgmii_rx_delay[port]) {
		pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
	if (rx_delay) {
		pad_mii_id.rxc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(rx_delay);
		/* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */
		pad_mii_id.rxc_bypass = 1;
		pad_mii_id.rxc_pd = 0;
	}

	if (priv->rgmii_tx_delay[port]) {
		pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
	if (tx_delay) {
		pad_mii_id.txc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(tx_delay);
		pad_mii_id.txc_bypass = 1;
		pad_mii_id.txc_pd = 0;
	}
+70 −24
Original line number Diff line number Diff line
@@ -1109,27 +1109,78 @@ static int sja1105_static_config_load(struct sja1105_private *priv)
	return sja1105_static_config_upload(priv);
}

static int sja1105_parse_rgmii_delays(struct sja1105_private *priv)
/* This is the "new way" for a MAC driver to configure its RGMII delay lines,
 * based on the explicit "rx-internal-delay-ps" and "tx-internal-delay-ps"
 * properties. It has the advantage of working with fixed links and with PHYs
 * that apply RGMII delays too, and the MAC driver needs not perform any
 * special checks.
 *
 * Previously we were acting upon the "phy-mode" property when we were
 * operating in fixed-link, basically acting as a PHY, but with a reversed
 * interpretation: PHY_INTERFACE_MODE_RGMII_TXID means that the MAC should
 * behave as if it is connected to a PHY which has applied RGMII delays in the
 * TX direction. So if anything, RX delays should have been added by the MAC,
 * but we were adding TX delays.
 *
 * If the "{rx,tx}-internal-delay-ps" properties are not specified, we fall
 * back to the legacy behavior and apply delays on fixed-link ports based on
 * the reverse interpretation of the phy-mode. This is a deviation from the
 * expected default behavior which is to simply apply no delays. To achieve
 * that behavior with the new bindings, it is mandatory to specify
 * "{rx,tx}-internal-delay-ps" with a value of 0.
 */
static int sja1105_parse_rgmii_delays(struct sja1105_private *priv, int port,
				      struct device_node *port_dn)
{
	struct dsa_switch *ds = priv->ds;
	int port;
	phy_interface_t phy_mode = priv->phy_mode[port];
	struct device *dev = &priv->spidev->dev;
	int rx_delay = -1, tx_delay = -1;

	for (port = 0; port < ds->num_ports; port++) {
		if (!priv->fixed_link[port])
			continue;
	if (!phy_interface_mode_is_rgmii(phy_mode))
		return 0;

		if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_RXID ||
		    priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID)
			priv->rgmii_rx_delay[port] = true;
	of_property_read_u32(port_dn, "rx-internal-delay-ps", &rx_delay);
	of_property_read_u32(port_dn, "tx-internal-delay-ps", &tx_delay);

		if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_TXID ||
		    priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID)
			priv->rgmii_tx_delay[port] = true;
	if (rx_delay == -1 && tx_delay == -1 && priv->fixed_link[port]) {
		dev_warn(dev,
			 "Port %d interpreting RGMII delay settings based on \"phy-mode\" property, "
			 "please update device tree to specify \"rx-internal-delay-ps\" and "
			 "\"tx-internal-delay-ps\"",
			 port);

		if (phy_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
		    phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
			rx_delay = 2000;

		if (phy_mode == PHY_INTERFACE_MODE_RGMII_TXID ||
		    phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
			tx_delay = 2000;
	}

		if ((priv->rgmii_rx_delay[port] || priv->rgmii_tx_delay[port]) &&
		    !priv->info->setup_rgmii_delay)
	if (rx_delay < 0)
		rx_delay = 0;
	if (tx_delay < 0)
		tx_delay = 0;

	if ((rx_delay || tx_delay) && !priv->info->setup_rgmii_delay) {
		dev_err(dev, "Chip cannot apply RGMII delays\n");
		return -EINVAL;
	}

	if ((rx_delay && rx_delay < SJA1105_RGMII_DELAY_MIN_PS) ||
	    (tx_delay && tx_delay < SJA1105_RGMII_DELAY_MIN_PS) ||
	    (rx_delay > SJA1105_RGMII_DELAY_MAX_PS) ||
	    (tx_delay > SJA1105_RGMII_DELAY_MAX_PS)) {
		dev_err(dev,
			"port %d RGMII delay values out of range, must be between %d and %d ps\n",
			port, SJA1105_RGMII_DELAY_MIN_PS, SJA1105_RGMII_DELAY_MAX_PS);
		return -ERANGE;
	}

	priv->rgmii_rx_delay_ps[port] = rx_delay;
	priv->rgmii_tx_delay_ps[port] = tx_delay;

	return 0;
}

@@ -1180,6 +1231,10 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
		}

		priv->phy_mode[index] = phy_mode;

		err = sja1105_parse_rgmii_delays(priv, index, child);
		if (err)
			return err;
	}

	return 0;
@@ -3317,15 +3372,6 @@ static int sja1105_probe(struct spi_device *spi)
		return rc;
	}

	/* Error out early if internal delays are required through DT
	 * and we can't apply them.
	 */
	rc = sja1105_parse_rgmii_delays(priv);
	if (rc < 0) {
		dev_err(ds->dev, "RGMII delay not supported\n");
		return rc;
	}

	if (IS_ENABLED(CONFIG_NET_SCH_CBS)) {
		priv->cbs = devm_kcalloc(dev, priv->info->num_cbs_shapers,
					 sizeof(struct sja1105_cbs_entry),