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

Merge branch 'renesas-eswitch'

Yoshihiro Shimoda says:

====================
net: ethernet: renesas: Add support for "Ethernet Switch"

This patch series is based on next-20221027.

Add initial support for Renesas "Ethernet Switch" device of R-Car S4-8.
The hardware has features about forwarding for an ethernet switch
device. But, for now, it acts as ethernet controllers so that any
forwarding offload features are not supported. So, any switchdev
header files and DSA framework are not used.

Notes that this driver requires some special settings on marvell10g,
Especially host mactype and host speed. And, I need further investigation
to modify the marvell10g driver for upstream. But, the special settings
are applied, this rswitch driver can work correcfly without any changes
of this rswitch driver. So, I believe the rswitch driver can go for
upstream.

Changes from v6:
https://lore.kernel.org/all/20221028065458.2417293-1-yoshihiro.shimoda.uh@renesas.com/
 - Add Reviewed-by tag in the patch [1/3].
 - Fix ordering of initialization because NFS root can start mounting
   the filesystem before register_netdev() even returns

Changes from v5:
https://lore.kernel.org/all/20221027134034.2343230-1-yoshihiro.shimoda.uh@renesas.com/
 - Add maxItems for the ethernet-port/port/reg property.

Changes from v4:
https://lore.kernel.org/all/20221019083518.933070-1-yoshihiro.shimoda.uh@renesas.com/


 - Rebased on next-20221027.
 - Drop some unneeded properties on the dt-bindings doc.
 - Change the subject and commit descriptions on the patch [2/3].
 - Use phylink instead of phylib.
 - Modify struct rswitch_*_desc to remove similar functions ([gs]et_dptr).

====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d312bad4 6c6fa1a0
Loading
Loading
Loading
Loading
+262 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/renesas,r8a779f0-ether-switch.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Renesas Ethernet Switch

maintainers:
  - Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>

properties:
  compatible:
    const: renesas,r8a779f0-ether-switch

  reg:
    maxItems: 2

  reg-names:
    items:
      - const: base
      - const: secure_base

  interrupts:
    maxItems: 47

  interrupt-names:
    items:
      - const: mfwd_error
      - const: race_error
      - const: coma_error
      - const: gwca0_error
      - const: gwca1_error
      - const: etha0_error
      - const: etha1_error
      - const: etha2_error
      - const: gptp0_status
      - const: gptp1_status
      - const: mfwd_status
      - const: race_status
      - const: coma_status
      - const: gwca0_status
      - const: gwca1_status
      - const: etha0_status
      - const: etha1_status
      - const: etha2_status
      - const: rmac0_status
      - const: rmac1_status
      - const: rmac2_status
      - const: gwca0_rxtx0
      - const: gwca0_rxtx1
      - const: gwca0_rxtx2
      - const: gwca0_rxtx3
      - const: gwca0_rxtx4
      - const: gwca0_rxtx5
      - const: gwca0_rxtx6
      - const: gwca0_rxtx7
      - const: gwca1_rxtx0
      - const: gwca1_rxtx1
      - const: gwca1_rxtx2
      - const: gwca1_rxtx3
      - const: gwca1_rxtx4
      - const: gwca1_rxtx5
      - const: gwca1_rxtx6
      - const: gwca1_rxtx7
      - const: gwca0_rxts0
      - const: gwca0_rxts1
      - const: gwca1_rxts0
      - const: gwca1_rxts1
      - const: rmac0_mdio
      - const: rmac1_mdio
      - const: rmac2_mdio
      - const: rmac0_phy
      - const: rmac1_phy
      - const: rmac2_phy

  clocks:
    maxItems: 1

  resets:
    maxItems: 1

  iommus:
    maxItems: 16

  power-domains:
    maxItems: 1

  ethernet-ports:
    type: object
    additionalProperties: false

    properties:
      '#address-cells':
        description: Port number of ETHA (TSNA).
        const: 1

      '#size-cells':
        const: 0

    patternProperties:
      "^port@[0-9a-f]+$":
        type: object
        $ref: /schemas/net/ethernet-controller.yaml#
        unevaluatedProperties: false

        properties:
          reg:
            maxItems: 1
            description:
              Port number of ETHA (TSNA).

          phys:
            maxItems: 1
            description:
              Phandle of an Ethernet SERDES.

          mdio:
            $ref: /schemas/net/mdio.yaml#
            unevaluatedProperties: false

        required:
          - reg
          - phy-handle
          - phy-mode
          - phys
          - mdio

required:
  - compatible
  - reg
  - reg-names
  - interrupts
  - interrupt-names
  - clocks
  - resets
  - power-domains
  - ethernet-ports

additionalProperties: false

examples:
  - |
    #include <dt-bindings/clock/r8a779f0-cpg-mssr.h>
    #include <dt-bindings/interrupt-controller/arm-gic.h>
    #include <dt-bindings/power/r8a779f0-sysc.h>

    ethernet@e6880000 {
        compatible = "renesas,r8a779f0-ether-switch";
        reg = <0xe6880000 0x20000>, <0xe68c0000 0x20000>;
        reg-names = "base", "secure_base";
        interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 284 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 291 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 292 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 294 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 295 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 296 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
        interrupt-names = "mfwd_error", "race_error",
                          "coma_error", "gwca0_error",
                          "gwca1_error", "etha0_error",
                          "etha1_error", "etha2_error",
                          "gptp0_status", "gptp1_status",
                          "mfwd_status", "race_status",
                          "coma_status", "gwca0_status",
                          "gwca1_status", "etha0_status",
                          "etha1_status", "etha2_status",
                          "rmac0_status", "rmac1_status",
                          "rmac2_status",
                          "gwca0_rxtx0", "gwca0_rxtx1",
                          "gwca0_rxtx2", "gwca0_rxtx3",
                          "gwca0_rxtx4", "gwca0_rxtx5",
                          "gwca0_rxtx6", "gwca0_rxtx7",
                          "gwca1_rxtx0", "gwca1_rxtx1",
                          "gwca1_rxtx2", "gwca1_rxtx3",
                          "gwca1_rxtx4", "gwca1_rxtx5",
                          "gwca1_rxtx6", "gwca1_rxtx7",
                          "gwca0_rxts0", "gwca0_rxts1",
                          "gwca1_rxts0", "gwca1_rxts1",
                          "rmac0_mdio", "rmac1_mdio",
                          "rmac2_mdio",
                          "rmac0_phy", "rmac1_phy",
                          "rmac2_phy";
        clocks = <&cpg CPG_MOD 1505>;
        power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
        resets = <&cpg 1505>;

        ethernet-ports {
            #address-cells = <1>;
            #size-cells = <0>;
            port@0 {
                reg = <0>;
                phy-handle = <&eth_phy0>;
                phy-mode = "sgmii";
                phys = <&eth_serdes 0>;
                mdio {
                    #address-cells = <1>;
                    #size-cells = <0>;
                };
            };
            port@1 {
                reg = <1>;
                phy-handle = <&eth_phy1>;
                phy-mode = "sgmii";
                phys = <&eth_serdes 1>;
                mdio {
                    #address-cells = <1>;
                    #size-cells = <0>;
                };
            };
            port@2 {
                reg = <2>;
                phy-handle = <&eth_phy2>;
                phy-mode = "sgmii";
                phys = <&eth_serdes 2>;
                mdio {
                    #address-cells = <1>;
                    #size-cells = <0>;
                };
            };
        };
    };
+11 −0
Original line number Diff line number Diff line
@@ -42,4 +42,15 @@ config RAVB
	  This driver supports the following SoCs:
		- R8A779x.

config RENESAS_ETHER_SWITCH
	tristate "Renesas Ethernet Switch support"
	depends on ARCH_RENESAS || COMPILE_TEST
	select CRC32
	select MII
	select PHYLINK
	help
	  Renesas Ethernet Switch device driver.
	  This driver supports the following SoCs:
		- R8A779Fx.

endif # NET_VENDOR_RENESAS
+4 −0
Original line number Diff line number Diff line
@@ -8,3 +8,7 @@ obj-$(CONFIG_SH_ETH) += sh_eth.o
ravb-objs := ravb_main.o ravb_ptp.o

obj-$(CONFIG_RAVB) += ravb.o

rswitch_drv-objs := rswitch.o rcar_gen4_ptp.o

obj-$(CONFIG_RENESAS_ETHER_SWITCH) += rswitch_drv.o
+181 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Renesas R-Car Gen4 gPTP device driver
 *
 * Copyright (C) 2022 Renesas Electronics Corporation
 */

#include <linux/err.h>
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

#include "rcar_gen4_ptp.h"
#define ptp_to_priv(ptp)	container_of(ptp, struct rcar_gen4_ptp_private, info)

static const struct rcar_gen4_ptp_reg_offset s4_offs = {
	.enable = PTPTMEC,
	.disable = PTPTMDC,
	.increment = PTPTIVC0,
	.config_t0 = PTPTOVC00,
	.config_t1 = PTPTOVC10,
	.config_t2 = PTPTOVC20,
	.monitor_t0 = PTPGPTPTM00,
	.monitor_t1 = PTPGPTPTM10,
	.monitor_t2 = PTPGPTPTM20,
};

static int rcar_gen4_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
	bool neg_adj = scaled_ppm < 0 ? true : false;
	s64 addend = ptp_priv->default_addend;
	s64 diff;

	if (neg_adj)
		scaled_ppm = -scaled_ppm;
	diff = div_s64(addend * scaled_ppm_to_ppb(scaled_ppm), NSEC_PER_SEC);
	addend = neg_adj ? addend - diff : addend + diff;

	iowrite32(addend, ptp_priv->addr + ptp_priv->offs->increment);

	return 0;
}

/* Caller must hold the lock */
static void _rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp,
				   struct timespec64 *ts)
{
	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);

	ts->tv_nsec = ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t0);
	ts->tv_sec = ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t1) |
		     ((s64)ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t2) << 32);
}

static int rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp,
				 struct timespec64 *ts)
{
	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
	unsigned long flags;

	spin_lock_irqsave(&ptp_priv->lock, flags);
	_rcar_gen4_ptp_gettime(ptp, ts);
	spin_unlock_irqrestore(&ptp_priv->lock, flags);

	return 0;
}

/* Caller must hold the lock */
static void _rcar_gen4_ptp_settime(struct ptp_clock_info *ptp,
				   const struct timespec64 *ts)
{
	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);

	iowrite32(1, ptp_priv->addr + ptp_priv->offs->disable);
	iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t2);
	iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t1);
	iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t0);
	iowrite32(1, ptp_priv->addr + ptp_priv->offs->enable);
	iowrite32(ts->tv_sec >> 32, ptp_priv->addr + ptp_priv->offs->config_t2);
	iowrite32(ts->tv_sec, ptp_priv->addr + ptp_priv->offs->config_t1);
	iowrite32(ts->tv_nsec, ptp_priv->addr + ptp_priv->offs->config_t0);
}

static int rcar_gen4_ptp_settime(struct ptp_clock_info *ptp,
				 const struct timespec64 *ts)
{
	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
	unsigned long flags;

	spin_lock_irqsave(&ptp_priv->lock, flags);
	_rcar_gen4_ptp_settime(ptp, ts);
	spin_unlock_irqrestore(&ptp_priv->lock, flags);

	return 0;
}

static int rcar_gen4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
	struct timespec64 ts;
	unsigned long flags;
	s64 now;

	spin_lock_irqsave(&ptp_priv->lock, flags);
	_rcar_gen4_ptp_gettime(ptp, &ts);
	now = ktime_to_ns(timespec64_to_ktime(ts));
	ts = ns_to_timespec64(now + delta);
	_rcar_gen4_ptp_settime(ptp, &ts);
	spin_unlock_irqrestore(&ptp_priv->lock, flags);

	return 0;
}

static int rcar_gen4_ptp_enable(struct ptp_clock_info *ptp,
				struct ptp_clock_request *rq, int on)
{
	return -EOPNOTSUPP;
}

static struct ptp_clock_info rcar_gen4_ptp_info = {
	.owner = THIS_MODULE,
	.name = "rcar_gen4_ptp",
	.max_adj = 50000000,
	.adjfine = rcar_gen4_ptp_adjfine,
	.adjtime = rcar_gen4_ptp_adjtime,
	.gettime64 = rcar_gen4_ptp_gettime,
	.settime64 = rcar_gen4_ptp_settime,
	.enable = rcar_gen4_ptp_enable,
};

static void rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv,
				   enum rcar_gen4_ptp_reg_layout layout)
{
	WARN_ON(layout != RCAR_GEN4_PTP_REG_LAYOUT_S4);

	ptp_priv->offs = &s4_offs;
}

int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv,
			   enum rcar_gen4_ptp_reg_layout layout, u32 clock)
{
	if (ptp_priv->initialized)
		return 0;

	spin_lock_init(&ptp_priv->lock);

	rcar_gen4_ptp_set_offs(ptp_priv, layout);

	ptp_priv->default_addend = clock;
	iowrite32(ptp_priv->default_addend, ptp_priv->addr + ptp_priv->offs->increment);
	ptp_priv->clock = ptp_clock_register(&ptp_priv->info, NULL);
	if (IS_ERR(ptp_priv->clock))
		return PTR_ERR(ptp_priv->clock);

	iowrite32(0x01, ptp_priv->addr + ptp_priv->offs->enable);
	ptp_priv->initialized = true;

	return 0;
}

int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv)
{
	iowrite32(1, ptp_priv->addr + ptp_priv->offs->disable);

	return ptp_clock_unregister(ptp_priv->clock);
}

struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev)
{
	struct rcar_gen4_ptp_private *ptp;

	ptp = devm_kzalloc(&pdev->dev, sizeof(*ptp), GFP_KERNEL);
	if (!ptp)
		return NULL;

	ptp->info = rcar_gen4_ptp_info;

	return ptp;
}
+72 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Renesas R-Car Gen4 gPTP device driver
 *
 * Copyright (C) 2022 Renesas Electronics Corporation
 */

#ifndef __RCAR_GEN4_PTP_H__
#define __RCAR_GEN4_PTP_H__

#include <linux/ptp_clock_kernel.h>

#define PTPTIVC_INIT			0x19000000	/* 320MHz */
#define RCAR_GEN4_PTP_CLOCK_S4		PTPTIVC_INIT
#define RCAR_GEN4_GPTP_OFFSET_S4	0x00018000

/* for rcar_gen4_ptp_init */
enum rcar_gen4_ptp_reg_layout {
	RCAR_GEN4_PTP_REG_LAYOUT_S4
};

/* driver's definitions */
#define RCAR_GEN4_RXTSTAMP_ENABLED		BIT(0)
#define RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT	BIT(1)
#define RCAR_GEN4_RXTSTAMP_TYPE_ALL		(RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT | BIT(2))
#define RCAR_GEN4_RXTSTAMP_TYPE			RCAR_GEN4_RXTSTAMP_TYPE_ALL

#define RCAR_GEN4_TXTSTAMP_ENABLED		BIT(0)

#define PTPRO				0

enum rcar_gen4_ptp_reg_s4 {
	PTPTMEC		= PTPRO + 0x0010,
	PTPTMDC		= PTPRO + 0x0014,
	PTPTIVC0	= PTPRO + 0x0020,
	PTPTOVC00	= PTPRO + 0x0030,
	PTPTOVC10	= PTPRO + 0x0034,
	PTPTOVC20	= PTPRO + 0x0038,
	PTPGPTPTM00	= PTPRO + 0x0050,
	PTPGPTPTM10	= PTPRO + 0x0054,
	PTPGPTPTM20	= PTPRO + 0x0058,
};

struct rcar_gen4_ptp_reg_offset {
	u16 enable;
	u16 disable;
	u16 increment;
	u16 config_t0;
	u16 config_t1;
	u16 config_t2;
	u16 monitor_t0;
	u16 monitor_t1;
	u16 monitor_t2;
};

struct rcar_gen4_ptp_private {
	void __iomem *addr;
	struct ptp_clock *clock;
	struct ptp_clock_info info;
	const struct rcar_gen4_ptp_reg_offset *offs;
	spinlock_t lock;	/* For multiple registers access */
	u32 tstamp_tx_ctrl;
	u32 tstamp_rx_ctrl;
	s64 default_addend;
	bool initialized;
};

int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv,
			   enum rcar_gen4_ptp_reg_layout layout, u32 clock);
int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv);
struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev);

#endif	/* #ifndef __RCAR_GEN4_PTP_H__ */
Loading