[PATCH v3 01/13] realtek: add switch core MFD driver

Sander Vanheule sander at svanheule.net
Sun Oct 30 11:30:54 PDT 2022


Realtek managed switch SoCs such as the RTL8380 consist of a MIPS CPU
with a number of basic peripherals, and an ethernet switch peripheral.
Besides performing ethernet related tasks, this switch core also
provides SoC management features. These switch core features are badly
separated, and cannot be divided into distinct IO ranges.

This MFD core driver is intended to manage the switch core regmap, and
to expose some limited features that don't warrant their own driver,
such as SoC identification.

Currently the driver is left disabled on rtl930x and rtl931x since these
are not yet supported.

Signed-off-by: Sander Vanheule <sander at svanheule.net>
---
Changes in v3:
- Merge symbol selection updates to ease bisecting
---
 .../drivers/mfd/realtek-switchcore.c          | 217 ++++++++++++++++++
 ...0-mfd-add-Realtek-switch-core-driver.patch |  46 ++++
 target/linux/realtek/rtl838x/config-5.10      |   2 +
 target/linux/realtek/rtl839x/config-5.10      |   2 +
 target/linux/realtek/rtl930x/config-5.10      |   1 +
 target/linux/realtek/rtl931x/config-5.10      |   1 +
 6 files changed, 269 insertions(+)
 create mode 100644 target/linux/realtek/files-5.10/drivers/mfd/realtek-switchcore.c
 create mode 100644 target/linux/realtek/patches-5.10/200-mfd-add-Realtek-switch-core-driver.patch

diff --git a/target/linux/realtek/files-5.10/drivers/mfd/realtek-switchcore.c b/target/linux/realtek/files-5.10/drivers/mfd/realtek-switchcore.c
new file mode 100644
index 000000000000..be9d96b8cb0a
--- /dev/null
+++ b/target/linux/realtek/files-5.10/drivers/mfd/realtek-switchcore.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+struct realtek_switchcore_ctrl;
+
+struct realtek_switchcore_data {
+	const struct mfd_cell *mfd_devices;
+	unsigned int mfd_device_count;
+	void (*probe_model_name)(const struct realtek_switchcore_ctrl *ctrl);
+};
+
+struct realtek_switchcore_ctrl {
+	struct device *dev;
+	struct regmap *map;
+	const struct realtek_switchcore_data *data;
+};
+
+/*
+ * Model name probe
+ *
+ * Reads the family-specific MODEL_NAME_INFO register
+ * to identify the SoC model and revision
+ */
+#define MODEL_NAME_CHAR_XLATE(val)	((val) ? 'A' + (val) - 1 : '\0')
+
+#define RTL83XX_MODEL_NAME_ID		GENMASK(31, 16)
+#define RTL83XX_MODEL_NAME_CHAR		GENMASK(15, 11)
+
+#define RTL83XX_CHIP_INFO_UNLOCK	GENMASK(31, 28)
+#define RTL83XX_CHIP_INFO_UNLOCK_CODE	0xa
+#define RTL83XX_CHIP_INFO_CHIP_REV	GENMASK(20, 16)
+#define RTL83XX_CHIP_INFO_RLID		GENMASK(15, 0)
+
+/* Maple registers */
+#define RTL838X_REG_MODEL_NAME_INFO	0x00d4
+#define RTL838X_REG_CHIP_INFO		0x00d8
+
+#define RTL838X_REG_INT_RW_CTRL		0x0058
+#define RTL838X_REG_MODE_DEFINE_CTL	0x1024
+
+/* Cypress registers */
+#define RTL839X_REG_MODEL_NAME_INFO	0x0ff0
+#define RTL839X_REG_CHIP_INFO		0x0ff4
+
+static void rtl83xx_read_chip_name(struct regmap *map, unsigned int reg,
+				   unsigned int *model_id, char *model_first_char)
+{
+	u32 val = 0;
+
+	regmap_read(map, reg, &val);
+	*model_id = FIELD_GET(RTL83XX_MODEL_NAME_ID, val);
+	*model_first_char = MODEL_NAME_CHAR_XLATE(FIELD_GET(RTL83XX_MODEL_NAME_CHAR, val));
+}
+
+static void rtl83xx_read_chip_info(struct regmap *map, unsigned int reg,
+				   unsigned int *chip_rev, unsigned int *rl_id)
+{
+	u32 val = 0;
+
+	val = FIELD_PREP(RTL83XX_CHIP_INFO_UNLOCK, RTL83XX_CHIP_INFO_UNLOCK_CODE);
+	regmap_write(map, reg, val);
+
+	regmap_read(map, reg, &val);
+	*chip_rev = FIELD_GET(RTL83XX_CHIP_INFO_CHIP_REV, val);
+	*rl_id = FIELD_GET(RTL83XX_CHIP_INFO_RLID, val);
+}
+
+static void rtl_swcore_chip_print(struct device *dev, unsigned int model_id, char model_suffix,
+				  unsigned int chip_rev, unsigned int rl_id)
+{
+	dev_info(dev, "found RTL%04x%c rev. %c, RL:%04x\n",
+		 model_id, model_suffix, 'A' + (char) chip_rev, rl_id);
+}
+
+static void rtl838x_probe_model_name(const struct realtek_switchcore_ctrl *ctrl)
+{
+	unsigned int model_id = 0;
+	unsigned int chip_rev = 0;
+	char model_suffix = ' ';
+	unsigned int rl_id = 0;
+	u32 val = 0;
+
+	/*
+	 * CHIP_INFO register requires global register lock to be disabled.
+	 * Leave the lock disabled as a side effect, to allow other switch core R/W operations.
+	 */
+	regmap_write(ctrl->map, RTL838X_REG_INT_RW_CTRL, 0x3);
+
+	rtl83xx_read_chip_name(ctrl->map, RTL838X_REG_MODEL_NAME_INFO, &model_id, &model_suffix);
+
+	if (model_id == 0x8380) {
+		regmap_read(ctrl->map, RTL838X_REG_MODE_DEFINE_CTL, &val);
+		/*
+		 * Undocumented bit which is only set on RTL8380M.
+		 * Possibly related to the presence of QSGMII ports for external phy.
+		 */
+		if (!(val & BIT(23)))
+			model_id = 0x8381;
+	}
+
+	rtl83xx_read_chip_info(ctrl->map, RTL838X_REG_CHIP_INFO, &chip_rev, &rl_id);
+	/* 'A' cut is denoted by revision 1, etc. Non-838x revisions start at 0. */
+	if (chip_rev > 0)
+		chip_rev--;
+
+	rtl_swcore_chip_print(ctrl->dev, model_id, model_suffix, chip_rev, rl_id);
+}
+
+static void rtl839x_probe_model_name(const struct realtek_switchcore_ctrl *ctrl)
+{
+	unsigned int model_id = 0;
+	unsigned int chip_rev = 0;
+	char model_suffix = ' ';
+	unsigned int rl_id = 0;
+
+	rtl83xx_read_chip_name(ctrl->map, RTL839X_REG_MODEL_NAME_INFO, &model_id, &model_suffix);
+	rtl83xx_read_chip_info(ctrl->map, RTL839X_REG_CHIP_INFO, &chip_rev, &rl_id);
+	rtl_swcore_chip_print(ctrl->dev, model_id, model_suffix, chip_rev, rl_id);
+}
+
+static const struct mfd_cell rtl838x_mfd_devices[] = {
+	{
+		.name = "realtek-switchcore-sys-led",
+		.of_compatible = "realtek,maple-sys-led",
+	},
+	{
+		.name = "realtek-switchcore-port-leds",
+		.of_compatible = "realtek,maple-port-led",
+	},
+	{
+		.name = "realtek-switchcore-pinctrl",
+		.of_compatible = "realtek,maple-pinctrl",
+	},
+};
+
+static const struct realtek_switchcore_data rtl838x_switchcore_data = {
+	.mfd_devices = rtl838x_mfd_devices,
+	.mfd_device_count = ARRAY_SIZE(rtl838x_mfd_devices),
+	.probe_model_name = rtl838x_probe_model_name,
+};
+
+static const struct mfd_cell rtl839x_mfd_devices[] = {
+	{
+		.name = "realtek-switchcore-sys-led",
+		.of_compatible = "realtek,cypress-sys-led",
+	},
+	{
+		.name = "realtek-switchcore-port-leds",
+		.of_compatible = "realtek,cypress-port-led",
+	},
+	{
+		.name = "realtek-switchcore-pinctrl",
+		.of_compatible = "realtek,cypress-pinctrl",
+	},
+};
+
+static const struct realtek_switchcore_data rtl839x_switchcore_data = {
+	.mfd_devices = rtl839x_mfd_devices,
+	.mfd_device_count = ARRAY_SIZE(rtl839x_mfd_devices),
+	.probe_model_name = rtl839x_probe_model_name,
+};
+
+static const struct of_device_id of_realtek_switchcore_match[] = {
+	{
+		.compatible = "realtek,maple-switchcore",
+		.data = &rtl838x_switchcore_data,
+	},
+	{
+		.compatible = "realtek,cypress-switchcore",
+		.data = &rtl839x_switchcore_data,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_realtek_switchcore_match);
+
+static int realtek_switchcore_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct realtek_switchcore_ctrl *ctrl;
+
+	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	ctrl->dev = dev;
+	ctrl->data = device_get_match_data(dev);
+	ctrl->map = syscon_node_to_regmap(dev->of_node);
+	if (!ctrl->map)
+		return dev_err_probe(dev, -ENXIO, "failed to get regmap\n");
+
+	ctrl->data->probe_model_name(ctrl);
+
+	return mfd_add_devices(dev, 0, ctrl->data->mfd_devices,
+			       ctrl->data->mfd_device_count, NULL, 0, NULL);
+}
+
+static struct platform_driver realtek_switchcore_driver = {
+	.probe = realtek_switchcore_probe,
+	.driver = {
+		.name = "realtek-switchcore",
+		.of_match_table = of_realtek_switchcore_match
+	}
+};
+module_platform_driver(realtek_switchcore_driver);
+
+MODULE_AUTHOR("Sander Vanheule <sander at svanheule.net>");
+MODULE_DESCRIPTION("Realtek SoC switch core driver");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/realtek/patches-5.10/200-mfd-add-Realtek-switch-core-driver.patch b/target/linux/realtek/patches-5.10/200-mfd-add-Realtek-switch-core-driver.patch
new file mode 100644
index 000000000000..17bb79cf2d1b
--- /dev/null
+++ b/target/linux/realtek/patches-5.10/200-mfd-add-Realtek-switch-core-driver.patch
@@ -0,0 +1,46 @@
+From 2b4df5433baaa10eeb23a58012329d4ec47216ba Mon Sep 17 00:00:00 2001
+From: Sander Vanheule <sander at svanheule.net>
+Date: Mon, 11 Jul 2022 09:24:18 +0200
+Subject: mfd: add Realtek switch core driver
+
+Realtek managed switch SoCs such as the RTL8380 consist of a MIPS CPU
+with a number of basic peripherals, and an ethernet switch peripheral.
+Besides performing ethernet related tasks, this switch core also
+provides SoC management features. These switch core features are badly
+separated, and cannot be divided into distinct IO ranges.
+
+This MFD core driver is intended to manage the switch core regmap, and
+to expose some limited features that don't warrant their own driver,
+such as SoC identification.
+
+Signed-off-by: Sander Vanheule <sander at svanheule.net>
+---
+
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -1000,6 +1000,17 @@ config MFD_RETU
+ 	  Retu and Tahvo are a multi-function devices found on Nokia
+ 	  Internet Tablets (770, N800 and N810).
+ 
++config MFD_REALTEK_SWITCHCORE
++	bool "Realtek switch core driver"
++	select MFD_CORE
++	select REGMAP_MMIO
++	default RTL83XX
++	help
++	  Say yes here if you want to support the switch core found in RTL838x,
++	  RTL839x, RTL930x, and RTL931x SoCs. The switch core provides ethernet
++	  functionality, and management features for the SoC like pin control.
++	  The mfd cell drivers have to be selected separately.
++
+ config MFD_PCF50633
+ 	tristate "NXP PCF50633"
+ 	depends on I2C
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -267,3 +267,5 @@ obj-$(CONFIG_MFD_KHADAS_MCU) 	+= khadas-
+ obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
+ obj-$(CONFIG_MFD_SIMPLE_MFD_I2C)	+= simple-mfd-i2c.o
+ obj-$(CONFIG_MFD_INTEL_M10_BMC)   += intel-m10-bmc.o
++
++obj-$(CONFIG_MFD_REALTEK_SWITCHCORE)	+= realtek-switchcore.o
diff --git a/target/linux/realtek/rtl838x/config-5.10 b/target/linux/realtek/rtl838x/config-5.10
index d69345e30120..a642be8b2aee 100644
--- a/target/linux/realtek/rtl838x/config-5.10
+++ b/target/linux/realtek/rtl838x/config-5.10
@@ -126,6 +126,8 @@ CONFIG_MDIO_DEVICE=y
 CONFIG_MDIO_DEVRES=y
 CONFIG_MDIO_I2C=y
 CONFIG_MEMFD_CREATE=y
+CONFIG_MFD_CORE=y
+CONFIG_MFD_REALTEK_SWITCHCORE=y
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
 CONFIG_MIPS=y
diff --git a/target/linux/realtek/rtl839x/config-5.10 b/target/linux/realtek/rtl839x/config-5.10
index 57eded97fcd9..51e6d5e8e072 100644
--- a/target/linux/realtek/rtl839x/config-5.10
+++ b/target/linux/realtek/rtl839x/config-5.10
@@ -120,6 +120,8 @@ CONFIG_MDIO_DEVICE=y
 CONFIG_MDIO_DEVRES=y
 CONFIG_MDIO_I2C=y
 CONFIG_MEMFD_CREATE=y
+CONFIG_MFD_CORE=y
+CONFIG_MFD_REALTEK_SWITCHCORE=y
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
 CONFIG_MIPS=y
diff --git a/target/linux/realtek/rtl930x/config-5.10 b/target/linux/realtek/rtl930x/config-5.10
index 3b2b327f08fb..ab31186ae134 100644
--- a/target/linux/realtek/rtl930x/config-5.10
+++ b/target/linux/realtek/rtl930x/config-5.10
@@ -112,6 +112,7 @@ CONFIG_MDIO_DEVRES=y
 CONFIG_MDIO_I2C=y
 CONFIG_MDIO_SMBUS=y
 CONFIG_MEMFD_CREATE=y
+# CONFIG_MFD_REALTEK_SWITCHCORE is not set
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
 CONFIG_MIPS=y
diff --git a/target/linux/realtek/rtl931x/config-5.10 b/target/linux/realtek/rtl931x/config-5.10
index 567421c8d4a7..00f751ce855a 100644
--- a/target/linux/realtek/rtl931x/config-5.10
+++ b/target/linux/realtek/rtl931x/config-5.10
@@ -113,6 +113,7 @@ CONFIG_MDIO_DEVRES=y
 CONFIG_MDIO_I2C=y
 CONFIG_MDIO_SMBUS=y
 CONFIG_MEMFD_CREATE=y
+# CONFIG_MFD_REALTEK_SWITCHCORE is not set
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
 CONFIG_MIPS=y
-- 
2.38.1




More information about the openwrt-devel mailing list