[PATCH v2 2/3] net: add r9a06g032 MIIC driver

Ralph Siemsen <[email protected]>
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <20260814-rzn1-2026-10-net-v2-2-ff03583dc2b0__22337.2097870865$1786732237$gmane$org@linaro.org>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.