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

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
# 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>;
};
};
};
};
......@@ -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
......@@ -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
// 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;
}
/* 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__ */
This diff is collapsed.
This diff is collapsed.
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