Commit 78fb23d7 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'add-pcs-support-for-renesas-rz-t2h-n2h-socs'

Lad Prabhakar says:

====================
Add PCS support for Renesas RZ/{T2H,N2H} SoCs

This series aims to add PCS support for the Renesas RZ/T2H and RZ/N2H SoCs
These SoCs include a MII converter (MIIC) that converts MII to RMII/RGMII
or can be set in pass-through mode for MII similar to the RZ/N1 SoC. The
MIIC is used in conjunction with the Ethernet switch (ETHSW) available on
these SoCs.
====================

Link: https://patch.msgid.link/20250910204132.319975-1-prabhakar.mahadev-lad.rj@bp.renesas.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 943a4fd7 08f89e42
Loading
Loading
Loading
Loading
+129 −48
Original line number Diff line number Diff line
@@ -4,14 +4,15 @@
$id: http://devicetree.org/schemas/net/pcs/renesas,rzn1-miic.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Renesas RZ/N1 MII converter
title: Renesas RZ/N1, RZ/N2H and RZ/T2H MII converter

maintainers:
  - Clément Léger <clement.leger@bootlin.com>
  - Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

description: |
  This MII converter is present on the Renesas RZ/N1 SoC family. It is
  responsible to do MII passthrough or convert it to RMII/RGMII.
  This MII converter is present on the Renesas RZ/N1, RZ/N2H and RZ/T2H SoC
  families. It is responsible to do MII passthrough or convert it to RMII/RGMII.

properties:
  '#address-cells':
@@ -21,10 +22,16 @@ properties:
    const: 0

  compatible:
    items:
    oneOf:
      - items:
          - enum:
              - renesas,r9a06g032-miic
          - const: renesas,rzn1-miic
      - items:
          - const: renesas,r9a09g077-miic # RZ/T2H
      - items:
          - const: renesas,r9a09g087-miic # RZ/N2H
          - const: renesas,r9a09g077-miic

  reg:
    maxItems: 1
@@ -43,11 +50,22 @@ properties:
      - const: rmii_ref
      - const: hclk

  resets:
    items:
      - description: Converter register reset
      - description: Converter reset

  reset-names:
    items:
      - const: rst
      - const: crst

  renesas,miic-switch-portin:
    description: MII Switch PORTIN configuration. This value should use one of
      the values defined in dt-bindings/net/pcs-rzn1-miic.h.
      the values defined in dt-bindings/net/pcs-rzn1-miic.h for RZ/N1 SoC and
      include/dt-bindings/net/renesas,r9a09g077-pcs-miic.h for RZ/N2H, RZ/T2H SoCs.
    $ref: /schemas/types.yaml#/definitions/uint32
    enum: [1, 2]
    enum: [0, 1, 2]

  power-domains:
    maxItems: 1
@@ -60,11 +78,12 @@ patternProperties:
    properties:
      reg:
        description: MII Converter port number.
        enum: [1, 2, 3, 4, 5]
        enum: [0, 1, 2, 3, 4, 5]

      renesas,miic-input:
        description: Converter input port configuration. This value should use
          one of the values defined in dt-bindings/net/pcs-rzn1-miic.h.
          one of the values defined in dt-bindings/net/pcs-rzn1-miic.h for RZ/N1 SoC
          and include/dt-bindings/net/renesas,r9a09g077-pcs-miic.h for RZ/N2H, RZ/T2H SoCs.
        $ref: /schemas/types.yaml#/definitions/uint32

    required:
@@ -73,6 +92,23 @@ patternProperties:

    additionalProperties: false

allOf:
  - if:
      properties:
        compatible:
          contains:
            const: renesas,rzn1-miic
    then:
      properties:
        renesas,miic-switch-portin:
          enum: [1, 2]
        resets: false
        reset-names: false
      patternProperties:
        "^mii-conv@[0-5]$":
          properties:
            reg:
              enum: [1, 2, 3, 4, 5]
          allOf:
            - if:
                properties:
@@ -114,6 +150,51 @@ patternProperties:
                properties:
                  renesas,miic-input:
                    enum: [3, 5, 8, 12]
    else:
      properties:
        renesas,miic-switch-portin:
          const: 0
      required:
        - resets
        - reset-names
      patternProperties:
        "^mii-conv@[0-5]$":
          properties:
            reg:
              enum: [0, 1, 2, 3]
          allOf:
            - if:
                properties:
                  reg:
                    const: 0
              then:
                properties:
                  renesas,miic-input:
                    enum: [0, 3, 6]
            - if:
                properties:
                  reg:
                    const: 1
              then:
                properties:
                  renesas,miic-input:
                    enum: [1, 4, 7]
            - if:
                properties:
                  reg:
                    const: 2
              then:
                properties:
                  renesas,miic-input:
                    enum: [2, 5, 8]
            - if:
                properties:
                  reg:
                    const: 3
              then:
                properties:
                  renesas,miic-input:
                    const: 1

required:
  - '#address-cells'
+6 −5
Original line number Diff line number Diff line
@@ -26,11 +26,12 @@ config PCS_MTK_LYNXI
	  which is part of MediaTek's SoC and Ethernet switch ICs.

config PCS_RZN1_MIIC
	tristate "Renesas RZ/N1 MII converter"
	depends on OF && (ARCH_RZN1 || COMPILE_TEST)
	tristate "Renesas RZ/N1, RZ/N2H, RZ/T2H MII converter"
	depends on OF
	depends on ARCH_RZN1 || ARCH_R9A09G077 || ARCH_R9A09G087 || COMPILE_TEST
	help
	  This module provides a driver for the MII converter that is available
	  on RZ/N1 SoCs. This PCS converts MII to RMII/RGMII or can be set in
	  pass-through mode for MII.
	  This module provides a driver for the MII converter available on
	  Renesas RZ/N1, RZ/N2H, and RZ/T2H SoCs. This PCS converts MII to
	  RMII/RGMII, or can be set in pass-through mode for MII.

endmenu
+269 −48
Original line number Diff line number Diff line
@@ -5,8 +5,12 @@
 * Clément Léger <clement.leger@bootlin.com>
 */

#include <linux/array_size.h>
#include <linux/bits.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/device/devres.h>
#include <linux/mdio.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -14,13 +18,15 @@
#include <linux/phylink.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <dt-bindings/net/pcs-rzn1-miic.h>
#include <dt-bindings/net/renesas,r9a09g077-pcs-miic.h>

#define MIIC_PRCMD			0x0
#define MIIC_ESID_CODE			0x4

#define MIIC_MODCTRL			0x8
#define MIIC_MODCTRL_SW_MODE		GENMASK(4, 0)

#define MIIC_CONVCTRL(port)		(0x100 + (port) * 4)

@@ -46,21 +52,23 @@
#define MIIC_SWCTRL			0x304
#define MIIC_SWDUPC			0x308

#define MIIC_MAX_NR_PORTS		5

#define MIIC_MODCTRL_CONF_CONV_NUM	6
#define MIIC_MODCTRL_CONF_CONV_MAX	6
#define MIIC_MODCTRL_CONF_NONE		-1

#define MIIC_MAX_NUM_RSTS		2

/**
 * struct modctrl_match - Matching table entry for  convctrl configuration
 *			  See section 8.2.1 of manual.
 * @mode_cfg: Configuration value for convctrl
 * @conv: Configuration of ethernet port muxes. First index is SWITCH_PORTIN,
 *	  then index 1 - 5 are CONV1 - CONV5.
 *	  then index 1 - 5 are CONV1 - CONV5 for RZ/N1 SoCs. In case
 *	  of RZ/T2H and RZ/N2H SoCs, the first index is SWITCH_PORTIN then
 *	  index 0 - 3 are CONV0 - CONV3.
 */
struct modctrl_match {
	u32 mode_cfg;
	u8 conv[MIIC_MODCTRL_CONF_CONV_NUM];
	u8 conv[MIIC_MODCTRL_CONF_CONV_MAX];
};

static struct modctrl_match modctrl_match_table[] = {
@@ -109,7 +117,7 @@ static const char * const conf_to_string[] = {
	[MIIC_HSR_PORTB]	= "HSR_PORTB",
};

static const char *index_to_string[MIIC_MODCTRL_CONF_CONV_NUM] = {
static const char * const index_to_string[] = {
	"SWITCH_PORTIN",
	"CONV1",
	"CONV2",
@@ -118,16 +126,106 @@ static const char *index_to_string[MIIC_MODCTRL_CONF_CONV_NUM] = {
	"CONV5",
};

static struct modctrl_match rzt2h_modctrl_match_table[] = {
	{0x0, {ETHSS_GMAC0_PORT, ETHSS_ETHSW_PORT0, ETHSS_ETHSW_PORT1,
	       ETHSS_ETHSW_PORT2, ETHSS_GMAC1_PORT}},

	{0x1, {MIIC_MODCTRL_CONF_NONE, ETHSS_ESC_PORT0, ETHSS_ESC_PORT1,
	       ETHSS_GMAC2_PORT, ETHSS_GMAC1_PORT}},

	{0x2, {ETHSS_GMAC0_PORT, ETHSS_ESC_PORT0, ETHSS_ESC_PORT1,
		ETHSS_ETHSW_PORT2, ETHSS_GMAC1_PORT}},

	{0x3, {MIIC_MODCTRL_CONF_NONE, ETHSS_ESC_PORT0, ETHSS_ESC_PORT1,
	       ETHSS_ESC_PORT2, ETHSS_GMAC1_PORT}},

	{0x4, {ETHSS_GMAC0_PORT, ETHSS_ETHSW_PORT0, ETHSS_ESC_PORT1,
	       ETHSS_ESC_PORT2, ETHSS_GMAC1_PORT}},

	{0x5, {ETHSS_GMAC0_PORT, ETHSS_ETHSW_PORT0, ETHSS_ESC_PORT1,
	       ETHSS_ETHSW_PORT2, ETHSS_GMAC1_PORT}},

	{0x6, {ETHSS_GMAC0_PORT, ETHSS_ETHSW_PORT0, ETHSS_ETHSW_PORT1,
	       ETHSS_GMAC2_PORT, ETHSS_GMAC1_PORT}},

	{0x7, {MIIC_MODCTRL_CONF_NONE, ETHSS_GMAC0_PORT, ETHSS_GMAC1_PORT,
		ETHSS_GMAC2_PORT, MIIC_MODCTRL_CONF_NONE}}
};

static const char * const rzt2h_conf_to_string[] = {
	[ETHSS_GMAC0_PORT]	= "GMAC0_PORT",
	[ETHSS_GMAC1_PORT]	= "GMAC1_PORT",
	[ETHSS_GMAC2_PORT]	= "GMAC2_PORT",
	[ETHSS_ESC_PORT0]	= "ETHERCAT_PORT0",
	[ETHSS_ESC_PORT1]	= "ETHERCAT_PORT1",
	[ETHSS_ESC_PORT2]	= "ETHERCAT_PORT2",
	[ETHSS_ETHSW_PORT0]	= "SWITCH_PORT0",
	[ETHSS_ETHSW_PORT1]	= "SWITCH_PORT1",
	[ETHSS_ETHSW_PORT2]	= "SWITCH_PORT2",
};

static const char * const rzt2h_index_to_string[] = {
	"SWITCH_PORTIN",
	"CONV0",
	"CONV1",
	"CONV2",
	"CONV3",
};

static const char * const rzt2h_reset_ids[] = {
	"rst",
	"crst",
};

/**
 * struct miic - MII converter structure
 * @base: base address of the MII converter
 * @dev: Device associated to the MII converter
 * @lock: Lock used for read-modify-write access
 * @rsts: Reset controls for the MII converter
 * @of_data: Pointer to OF data
 */
struct miic {
	void __iomem *base;
	struct device *dev;
	spinlock_t lock;
	struct reset_control_bulk_data rsts[MIIC_MAX_NUM_RSTS];
	const struct miic_of_data *of_data;
};

/**
 * struct miic_of_data - OF data for MII converter
 * @match_table: Matching table for convctrl configuration
 * @match_table_count: Number of entries in the matching table
 * @conf_conv_count: Number of entries in the conf_conv array
 * @conf_to_string: String representations of the configuration values
 * @conf_to_string_count: Number of entries in the conf_to_string array
 * @index_to_string: String representations of the index values
 * @index_to_string_count: Number of entries in the index_to_string array
 * @miic_port_start: MIIC port start number
 * @miic_port_max: Maximum MIIC supported
 * @sw_mode_mask: Switch mode mask
 * @reset_ids: Reset names array
 * @reset_count: Number of entries in the reset_ids array
 * @init_unlock_lock_regs: Flag to indicate if registers need to be unlocked
 *  before access.
 * @miic_write: Function pointer to write a value to a MIIC register
 */
struct miic_of_data {
	struct modctrl_match *match_table;
	u8 match_table_count;
	u8 conf_conv_count;
	const char * const *conf_to_string;
	u8 conf_to_string_count;
	const char * const *index_to_string;
	u8 index_to_string_count;
	u8 miic_port_start;
	u8 miic_port_max;
	u8 sw_mode_mask;
	const char * const *reset_ids;
	u8 reset_count;
	bool init_unlock_lock_regs;
	void (*miic_write)(struct miic *miic, int offset, u32 value);
};

/**
@@ -149,11 +247,38 @@ static struct miic_port *phylink_pcs_to_miic_port(struct phylink_pcs *pcs)
	return container_of(pcs, struct miic_port, pcs);
}

static void miic_reg_writel(struct miic *miic, int offset, u32 value)
static void miic_unlock_regs(struct miic *miic)
{
	/* Unprotect register writes */
	writel(0x00A5, miic->base + MIIC_PRCMD);
	writel(0x0001, miic->base + MIIC_PRCMD);
	writel(0xFFFE, miic->base + MIIC_PRCMD);
	writel(0x0001, miic->base + MIIC_PRCMD);
}

static void miic_lock_regs(struct miic *miic)
{
	/* Protect register writes */
	writel(0x0000, miic->base + MIIC_PRCMD);
}

static void miic_reg_writel_unlocked(struct miic *miic, int offset, u32 value)
{
	writel(value, miic->base + offset);
}

static void miic_reg_writel_locked(struct miic *miic, int offset, u32 value)
{
	miic_unlock_regs(miic);
	writel(value, miic->base + offset);
	miic_lock_regs(miic);
}

static void miic_reg_writel(struct miic *miic, int offset, u32 value)
{
	miic->of_data->miic_write(miic, offset, value);
}

static u32 miic_reg_readl(struct miic *miic, int offset)
{
	return readl(miic->base + offset);
@@ -303,6 +428,7 @@ static const struct phylink_pcs_ops miic_phylink_ops = {

struct phylink_pcs *miic_create(struct device *dev, struct device_node *np)
{
	const struct miic_of_data *of_data;
	struct platform_device *pdev;
	struct miic_port *miic_port;
	struct device_node *pcs_np;
@@ -315,9 +441,6 @@ struct phylink_pcs *miic_create(struct device *dev, struct device_node *np)
	if (of_property_read_u32(np, "reg", &port))
		return ERR_PTR(-EINVAL);

	if (port > MIIC_MAX_NR_PORTS || port < 1)
		return ERR_PTR(-EINVAL);

	/* The PCS pdev is attached to the parent node */
	pcs_np = of_get_parent(np);
	if (!pcs_np)
@@ -336,18 +459,24 @@ struct phylink_pcs *miic_create(struct device *dev, struct device_node *np)
		return ERR_PTR(-EPROBE_DEFER);
	}

	miic = platform_get_drvdata(pdev);
	of_data = miic->of_data;
	if (port > of_data->miic_port_max || port < of_data->miic_port_start) {
		put_device(&pdev->dev);
		return ERR_PTR(-EINVAL);
	}

	miic_port = kzalloc(sizeof(*miic_port), GFP_KERNEL);
	if (!miic_port) {
		put_device(&pdev->dev);
		return ERR_PTR(-ENOMEM);
	}

	miic = platform_get_drvdata(pdev);
	device_link_add(dev, miic->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
	put_device(&pdev->dev);

	miic_port->miic = miic;
	miic_port->port = port - 1;
	miic_port->port = port - of_data->miic_port_start;
	miic_port->pcs.ops = &miic_phylink_ops;

	phy_interface_set_rgmii(miic_port->pcs.supported_interfaces);
@@ -369,21 +498,23 @@ EXPORT_SYMBOL(miic_destroy);

static int miic_init_hw(struct miic *miic, u32 cfg_mode)
{
	u8 sw_mode_mask = miic->of_data->sw_mode_mask;
	int port;

	/* Unlock write access to accessory registers (cf datasheet). If this
	 * is going to be used in conjunction with the Cortex-M3, this sequence
	 * will have to be moved in register write
	 */
	miic_reg_writel(miic, MIIC_PRCMD, 0x00A5);
	miic_reg_writel(miic, MIIC_PRCMD, 0x0001);
	miic_reg_writel(miic, MIIC_PRCMD, 0xFFFE);
	miic_reg_writel(miic, MIIC_PRCMD, 0x0001);
	if (miic->of_data->init_unlock_lock_regs)
		miic_unlock_regs(miic);

	/* TODO: Replace with FIELD_PREP() when compile-time constant
	 * restriction is lifted. Currently __ffs() returns 0 for sw_mode_mask.
	 */
	miic_reg_writel(miic, MIIC_MODCTRL,
			FIELD_PREP(MIIC_MODCTRL_SW_MODE, cfg_mode));
			((cfg_mode << __ffs(sw_mode_mask)) & sw_mode_mask));

	for (port = 0; port < MIIC_MAX_NR_PORTS; port++) {
	for (port = 0; port < miic->of_data->miic_port_max; port++) {
		miic_converter_enable(miic, port, 0);
		/* Disable speed/duplex control from these registers, datasheet
		 * says switch registers should be used to setup switch port
@@ -396,12 +527,11 @@ static int miic_init_hw(struct miic *miic, u32 cfg_mode)
	return 0;
}

static bool miic_modctrl_match(s8 table_val[MIIC_MODCTRL_CONF_CONV_NUM],
			       s8 dt_val[MIIC_MODCTRL_CONF_CONV_NUM])
static bool miic_modctrl_match(s8 *table_val, s8 *dt_val, u8 count)
{
	int i;

	for (i = 0; i < MIIC_MODCTRL_CONF_CONV_NUM; i++) {
	for (i = 0; i < count; i++) {
		if (dt_val[i] == MIIC_MODCTRL_CONF_NONE)
			continue;

@@ -412,53 +542,59 @@ static bool miic_modctrl_match(s8 table_val[MIIC_MODCTRL_CONF_CONV_NUM],
	return true;
}

static void miic_dump_conf(struct device *dev,
			   s8 conf[MIIC_MODCTRL_CONF_CONV_NUM])
static void miic_dump_conf(struct miic *miic, s8 *conf)
{
	const struct miic_of_data *of_data = miic->of_data;
	const char *conf_name;
	int i;

	for (i = 0; i < MIIC_MODCTRL_CONF_CONV_NUM; i++) {
	for (i = 0; i < of_data->conf_conv_count; i++) {
		if (conf[i] != MIIC_MODCTRL_CONF_NONE)
			conf_name = conf_to_string[conf[i]];
			conf_name = of_data->conf_to_string[conf[i]];
		else
			conf_name = "NONE";

		dev_err(dev, "%s: %s\n", index_to_string[i], conf_name);
		dev_err(miic->dev, "%s: %s\n",
			of_data->index_to_string[i], conf_name);
	}
}

static int miic_match_dt_conf(struct device *dev,
			      s8 dt_val[MIIC_MODCTRL_CONF_CONV_NUM],
			      u32 *mode_cfg)
static int miic_match_dt_conf(struct miic *miic, s8 *dt_val, u32 *mode_cfg)
{
	const struct miic_of_data *of_data = miic->of_data;
	struct modctrl_match *table_entry;
	int i;

	for (i = 0; i < ARRAY_SIZE(modctrl_match_table); i++) {
		table_entry = &modctrl_match_table[i];
	for (i = 0; i < of_data->match_table_count; i++) {
		table_entry = &of_data->match_table[i];

		if (miic_modctrl_match(table_entry->conv, dt_val)) {
		if (miic_modctrl_match(table_entry->conv, dt_val,
				       miic->of_data->conf_conv_count)) {
			*mode_cfg = table_entry->mode_cfg;
			return 0;
		}
	}

	dev_err(dev, "Failed to apply requested configuration\n");
	miic_dump_conf(dev, dt_val);
	dev_err(miic->dev, "Failed to apply requested configuration\n");
	miic_dump_conf(miic, dt_val);

	return -EINVAL;
}

static int miic_parse_dt(struct device *dev, u32 *mode_cfg)
static int miic_parse_dt(struct miic *miic, u32 *mode_cfg)
{
	s8 dt_val[MIIC_MODCTRL_CONF_CONV_NUM];
	struct device_node *np = dev->of_node;
	struct device_node *np = miic->dev->of_node;
	struct device_node *conv;
	int port, ret;
	s8 *dt_val;
	u32 conf;
	int port;

	memset(dt_val, MIIC_MODCTRL_CONF_NONE, sizeof(dt_val));
	dt_val = kmalloc_array(miic->of_data->conf_conv_count,
			       sizeof(*dt_val), GFP_KERNEL);
	if (!dt_val)
		return -ENOMEM;

	memset(dt_val, MIIC_MODCTRL_CONF_NONE, sizeof(*dt_val));

	if (of_property_read_u32(np, "renesas,miic-switch-portin", &conf) == 0)
		dt_val[0] = conf;
@@ -467,11 +603,58 @@ static int miic_parse_dt(struct device *dev, u32 *mode_cfg)
		if (of_property_read_u32(conv, "reg", &port))
			continue;

		/* Adjust for 0 based index */
		port += !miic->of_data->miic_port_start;
		if (of_property_read_u32(conv, "renesas,miic-input", &conf) == 0)
			dt_val[port] = conf;
	}

	return miic_match_dt_conf(dev, dt_val, mode_cfg);
	ret = miic_match_dt_conf(miic, dt_val, mode_cfg);
	kfree(dt_val);

	return ret;
}

static void miic_reset_control_bulk_assert(void *data)
{
	struct miic *miic = data;
	int ret;

	ret = reset_control_bulk_assert(miic->of_data->reset_count, miic->rsts);
	if (ret)
		dev_err(miic->dev, "failed to assert reset lines\n");
}

static int miic_reset_control_init(struct miic *miic)
{
	const struct miic_of_data *of_data = miic->of_data;
	struct device *dev = miic->dev;
	int ret;
	u8 i;

	if (!of_data->reset_count)
		return 0;

	for (i = 0; i < of_data->reset_count; i++)
		miic->rsts[i].id = of_data->reset_ids[i];

	ret = devm_reset_control_bulk_get_exclusive(dev, of_data->reset_count,
						    miic->rsts);
	if (ret)
		return dev_err_probe(dev, ret,
				     "failed to get bulk reset lines\n");

	ret = reset_control_bulk_deassert(of_data->reset_count, miic->rsts);
	if (ret)
		return dev_err_probe(dev, ret,
				     "failed to deassert reset lines\n");

	ret = devm_add_action_or_reset(dev, miic_reset_control_bulk_assert,
				       miic);
	if (ret)
		return dev_err_probe(dev, ret, "failed to add reset action\n");

	return 0;
}

static int miic_probe(struct platform_device *pdev)
@@ -481,20 +664,26 @@ static int miic_probe(struct platform_device *pdev)
	u32 mode_cfg;
	int ret;

	ret = miic_parse_dt(dev, &mode_cfg);
	if (ret < 0)
		return ret;

	miic = devm_kzalloc(dev, sizeof(*miic), GFP_KERNEL);
	if (!miic)
		return -ENOMEM;

	spin_lock_init(&miic->lock);
	miic->of_data = of_device_get_match_data(dev);
	miic->dev = dev;

	ret = miic_parse_dt(miic, &mode_cfg);
	if (ret < 0)
		return ret;

	spin_lock_init(&miic->lock);
	miic->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(miic->base))
		return PTR_ERR(miic->base);

	ret = miic_reset_control_init(miic);
	if (ret)
		return ret;

	ret = devm_pm_runtime_enable(dev);
	if (ret < 0)
		return ret;
@@ -527,9 +716,41 @@ static void miic_remove(struct platform_device *pdev)
	pm_runtime_put(&pdev->dev);
}

static struct miic_of_data rzn1_miic_of_data = {
	.match_table = modctrl_match_table,
	.match_table_count = ARRAY_SIZE(modctrl_match_table),
	.conf_conv_count = MIIC_MODCTRL_CONF_CONV_MAX,
	.conf_to_string = conf_to_string,
	.conf_to_string_count = ARRAY_SIZE(conf_to_string),
	.index_to_string = index_to_string,
	.index_to_string_count = ARRAY_SIZE(index_to_string),
	.miic_port_start = 1,
	.miic_port_max = 5,
	.sw_mode_mask = GENMASK(4, 0),
	.init_unlock_lock_regs = true,
	.miic_write = miic_reg_writel_unlocked,
};

static struct miic_of_data rzt2h_miic_of_data = {
	.match_table = rzt2h_modctrl_match_table,
	.match_table_count = ARRAY_SIZE(rzt2h_modctrl_match_table),
	.conf_conv_count = 5,
	.conf_to_string = rzt2h_conf_to_string,
	.conf_to_string_count = ARRAY_SIZE(rzt2h_conf_to_string),
	.index_to_string = rzt2h_index_to_string,
	.index_to_string_count = ARRAY_SIZE(rzt2h_index_to_string),
	.miic_port_start = 0,
	.miic_port_max = 4,
	.sw_mode_mask = GENMASK(2, 0),
	.reset_ids = rzt2h_reset_ids,
	.reset_count = ARRAY_SIZE(rzt2h_reset_ids),
	.miic_write = miic_reg_writel_locked,
};

static const struct of_device_id miic_of_mtable[] = {
	{ .compatible = "renesas,rzn1-miic" },
	{ /* sentinel */ },
	{ .compatible = "renesas,r9a09g077-miic", .data = &rzt2h_miic_of_data },
	{ .compatible = "renesas,rzn1-miic", .data = &rzn1_miic_of_data },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, miic_of_mtable);

+36 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/*
 * Copyright (C) 2025 Renesas Electronics Corporation.
 */

#ifndef _DT_BINDINGS_RENASAS_R9A09G077_PCS_MIIC_H
#define _DT_BINDINGS_RENASAS_R9A09G077_PCS_MIIC_H

/*
 * Media Interface Connection Matrix
 * ===========================================================
 *
 * Selects the function of the Media interface of the MAC to be used
 *
 * SW_MODE[2:0] | Port 0      | Port 1      | Port 2      | Port 3
 * -------------|-------------|-------------|-------------|-------------
 * 000b         | ETHSW Port0 | ETHSW Port1 | ETHSW Port2 | GMAC1
 * 001b         | ESC Port0   | ESC Port1   | GMAC2       | GMAC1
 * 010b         | ESC Port0   | ESC Port1   | ETHSW Port2 | GMAC1
 * 011b         | ESC Port0   | ESC Port1   | ESC Port2   | GMAC1
 * 100b         | ETHSW Port0 | ESC Port1   | ESC Port2   | GMAC1
 * 101b         | ETHSW Port0 | ESC Port1   | ETHSW Port2 | GMAC1
 * 110b         | ETHSW Port0 | ETHSW Port1 | GMAC2       | GMAC1
 * 111b         | GMAC0       | GMAC1       | GMAC2       | -
 */
#define ETHSS_GMAC0_PORT		0
#define ETHSS_GMAC1_PORT		1
#define ETHSS_GMAC2_PORT		2
#define ETHSS_ESC_PORT0			3
#define ETHSS_ESC_PORT1			4
#define ETHSS_ESC_PORT2			5
#define ETHSS_ETHSW_PORT0		6
#define ETHSS_ETHSW_PORT1		7
#define ETHSS_ETHSW_PORT2		8

#endif