[PATCH 06/17] net: add r9a06g032 MIIC driver

Ralph Siemsen <[email protected]> Fri, 31 Jul 2026 12:33:35 -0400
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <[email protected]>
Driver for the MII/GMII/RGMII media converter blocks found in the
Renesas RZ/N1 SoC. These converters sit in the Ethernet data path,
and need to be configured with speed/duplex as detected by the PHY.

Signed-off-by: Ralph Siemsen <[email protected]>
---
 drivers/net/Kconfig     |   6 ++
 drivers/net/Makefile    |   1 +
 drivers/net/rzn1_miic.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 200 insertions(+)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index edc4cb29598..659e9fd82d0 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -886,6 +886,12 @@ config RZN1_A5PSW
 	  Support the Advanced 5-Port ethernet switch (A5PSW) found in
 	  the Renesas RZ/N1 SoC.
 
+config RZN1_MIIC
+	bool "Renesas RZ/N1 MIIC ethernet accessory"
+	help
+	  Support the MIIC ethernet accessory found in Renesas RZ/N1 SoC.
+	  These are media converters for MII/GMII/RGMII.
+
 config MPC8XX_FEC
 	bool "Fast Ethernet Controller on MPC8XX"
 	depends on MPC8xx
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b8f270ae233..049212b1fd2 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o
 obj-$(CONFIG_RENESAS_ETHER_SWITCH) += rswitch.o
 obj-$(CONFIG_RENESAS_RAVB) += ravb.o
 obj-$(CONFIG_RZN1_A5PSW) += rzn1_a5psw.o
+obj-$(CONFIG_RZN1_MIIC) += rzn1_miic.o
 obj-$(CONFIG_RTL8139) += rtl8139.o
 obj-$(CONFIG_RTL8169) += rtl8169.o
 obj-$(CONFIG_SH_ETHER) += sh_eth.o
diff --git a/drivers/net/rzn1_miic.c b/drivers/net/rzn1_miic.c
new file mode 100644
index 00000000000..491923d8511
--- /dev/null
+++ b/drivers/net/rzn1_miic.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MII/GMII/RGMII converter support
+ *
+ * Based loosely on Linux drivers/net/pcs/pcs-rzn1-miic.c
+ * and the older driver in Renesas u-boot.
+ */
+
+#include <clk.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/of_extra.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <miiphy.h>
+#include <net/dsa.h>
+#include <regmap.h>
+
+struct rzn1_miic_plat {
+	struct clk_bulk bulk;
+	struct regmap *regmap;
+};
+
+/* RIN Ether Accessory (Switch Control) regs */
+#define PRCMD			0x0		/* Ethernet Protect */
+#define IDCODE			0x4		/* EtherSwitch IDCODE */
+#define MODCTRL			0x8		/* Mode Control */
+#define PTP_MODE_CTRL		0xc		/* PTP Mode Control */
+#define PHY_LINK_MODE		0x14		/* Ethernet PHY Link Mode */
+
+/* RIN RGMII/RMII Converter regs */
+#define CONVCTRL(x)		(0x100 + ((x)) * 4) /* RGMII/RMII Converter */
+#define  CONVCTRL_10_MBPS		0
+#define  CONVCTRL_100_MBPS		BIT(0)
+#define  CONVCTRL_1000_MBPS		BIT(1)
+#define  CONVCTRL_MII			0
+#define  CONVCTRL_RMII			BIT(2)
+#define  CONVCTRL_RGMII			BIT(3)
+#define  CONVCTRL_REF_CLK_OUT		BIT(4)
+#define  CONVCTRL_HALF_DUPLEX		0
+#define  CONVCTRL_FULL_DUPLEX		BIT(8)
+#define CONVRST			0x114		/* RGMII/RMII Converter RST */
+#define  PHYIF_RST(x)			BIT(x)
+
+static void rzn1_rin_prot_writel(struct udevice *dev, u32 reg, u32 val)
+{
+	struct rzn1_miic_plat *plat = dev_get_plat(dev);
+	struct regmap *regmap = plat->regmap;
+
+	/* RIN: Unprotect register writes */
+	regmap_write(regmap, PRCMD, 0x00a5);
+	regmap_write(regmap, PRCMD, 0x0001);
+	regmap_write(regmap, PRCMD, 0xfffe);
+	regmap_write(regmap, PRCMD, 0x0001);
+
+	/* Do the write */
+	regmap_write(regmap, reg, val);
+
+	/* Re-enable protection */
+	regmap_write(regmap, PRCMD, 0x0000);
+}
+
+/*
+ * RIN RGMII/RMII Converter set speed
+ * RGMII/RMII Converter number: 0..4
+ * speed: 10, 100, 1000
+ */
+void rzn1_rgmii_rmii_conv_speed(struct udevice *dev, int phy,
+				int full_duplex, int speed)
+{
+	struct rzn1_miic_plat *plat = dev_get_plat(dev);
+	struct regmap *regmap = plat->regmap;
+	u32 val = 0;
+
+	regmap_read(regmap, CONVCTRL(phy), &val);
+
+	val &= CONVCTRL_MII | CONVCTRL_RMII | CONVCTRL_RGMII |
+		CONVCTRL_REF_CLK_OUT;
+
+	/* The interface type and speed bits are somewhat intertwined */
+	if (val != CONVCTRL_MII) {
+		if (speed == SPEED_1000)
+			val |= CONVCTRL_1000_MBPS;
+		else if (speed == SPEED_100)
+			val |= CONVCTRL_100_MBPS;
+		else if (speed == SPEED_10)
+			val |= CONVCTRL_10_MBPS;
+	}
+
+	if (full_duplex)
+		val |= CONVCTRL_FULL_DUPLEX;
+
+	regmap_write(regmap, CONVCTRL(phy), val);
+}
+
+/*
+ * RIN RGMII/RMII Converter setup one
+ * RGMII/RMII Converter number: 0..4
+ * if_type: Type of PHY interface, see phy_interface_t
+ */
+void rzn1_rgmii_rmii_conv_setup(struct udevice *dev, int phy,
+				u32 if_type, int rmii_ref_clk_out)
+{
+	struct rzn1_miic_plat *plat = dev_get_plat(dev);
+	struct regmap *regmap = plat->regmap;
+	u32 val = 0;
+	int speed = SPEED_100;
+
+	switch (if_type) {
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		val |= CONVCTRL_RGMII;
+		speed = SPEED_1000;
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		val |= CONVCTRL_RMII;
+		break;
+	case PHY_INTERFACE_MODE_MII:
+		val |= CONVCTRL_MII;
+		break;
+	};
+
+	if (if_type == PHY_INTERFACE_MODE_RMII && rmii_ref_clk_out)
+		val |= CONVCTRL_REF_CLK_OUT;
+
+	regmap_write(regmap, CONVCTRL(phy), val);
+
+	rzn1_rgmii_rmii_conv_speed(dev, phy, DUPLEX_FULL, speed);
+
+	/* reset */
+	regmap_read(regmap, CONVRST, &val);
+	val &= ~PHYIF_RST(phy);
+	rzn1_rin_prot_writel(dev, CONVRST, val);
+	udelay(1000);
+	val |= PHYIF_RST(phy);
+	rzn1_rin_prot_writel(dev, CONVRST, val);
+}
+
+static int rzn1_miic_probe(struct udevice *dev)
+{
+	struct rzn1_miic_plat *plat = dev_get_plat(dev);
+	int ret;
+
+	dev_warn(dev, "%s:%d\n", __func__, __LINE__);
+
+	/* Enable clocks */
+	ret = clk_get_bulk(dev, &plat->bulk);
+	if (ret) {
+		dev_err(dev, "Failed to get clocks\n");
+		return ret;
+	}
+	ret = clk_enable_bulk(&plat->bulk);
+	if (ret) {
+		dev_err(dev, "Failed to enable clocks\n");
+		return ret;
+	}
+
+	/* Access the registers */
+	ret = regmap_init_mem(dev_ofnode(dev), &plat->regmap);
+	if (ret) {
+		dev_err(dev, "Failed to get regmap\n");
+		return ret;
+	}
+
+	/* Set PTP to use 125MHz PLL clock */
+	rzn1_rin_prot_writel(dev, PTP_MODE_CTRL, 0x2);
+
+	/* Setup RGMII/RMII Converters */
+	rzn1_rgmii_rmii_conv_setup(dev, 3, PHY_INTERFACE_MODE_RGMII_ID, 0);
+	rzn1_rgmii_rmii_conv_setup(dev, 4, PHY_INTERFACE_MODE_RGMII_ID, 0);
+
+	/* RIN: Mode Control - GMAC1 on all Switch ports */
+	rzn1_rin_prot_writel(dev, MODCTRL, 0x13);
+
+	return 0;
+}
+
+static const struct udevice_id rzn1_miic_ids[] = {
+	{ .compatible = "renesas,rzn1-miic" },
+	{ }
+};
+
+U_BOOT_DRIVER(rzn1_miic) = {
+	.name		= "rzn1_miic",
+	.id		= UCLASS_MISC,
+	.of_match	= rzn1_miic_ids,
+	.probe		= rzn1_miic_probe,
+	.plat_auto	= sizeof(struct rzn1_miic_plat),
+};

-- 
2.55.0