From 62a5280b8b68656700534331f4b8c738418c06a3 Mon Sep 17 00:00:00 2001 From: Luiz Angelo Daros de Luca Date: Tue, 24 Oct 2023 15:56:03 -0300 Subject: [PATCH] kernel: modules: netdevices: add realtek DSA modules Uses upstream DSA switch modules (rtl8365mb, rtl8366), similar to RTL8367C and rtl8366rb swconfig drivers. The package dependencies exclude targets built without kernel CONFIG_OF. It also fixes the rtl8366rb LED support. Signed-off-by: Luiz Angelo Daros de Luca Link: https://github.com/openwrt/openwrt/pull/17182 Signed-off-by: Robert Marko --- package/kernel/linux/modules/netdevices.mk | 59 ++ ...-Convert-to-platform-remove-callback.patch | 66 ++ ...ealtek-drop-cleanup-from-realtek_ops.patch | 30 + ...ltek-introduce-REALTEK_DSA-namespace.patch | 146 +++ ...k-convert-variants-into-real-drivers.patch | 539 +++++++++++ ...keep-variant-reference-in-realtek_pr.patch | 91 ++ ...et-dsa-realtek-common-rtl83xx-module.patch | 875 ++++++++++++++++++ ...merge-rtl83xx-and-interface-modules-.patch | 93 ++ ...altek-get-internal-MDIO-node-by-name.patch | 34 + ...dsa-realtek-clean-user_mii_bus-setup.patch | 83 ++ ...migrate-user_mii_bus-setup-to-realte.patch | 198 ++++ ...use-the-same-mii-bus-driver-for-both.patch | 261 ++++++ ...k-embed-dsa_switch-into-realtek_priv.patch | 180 ++++ ...fix-digital-interface-select-macro-f.patch | 38 + ...dsa-realtek-reset-gpios-is-not-requi.patch | 34 + ...net-dsa-realtek-add-reset-controller.patch | 33 + ...dsa-realtek-support-reset-controller.patch | 123 +++ ...ealtek-do-not-assert-reset-on-remove.patch | 45 + ...ealtek-add-LED-drivers-for-rtl8366rb.patch | 396 ++++++++ 19 files changed, 3324 insertions(+) create mode 100644 target/linux/generic/backport-6.6/894-v6.7-net-dsa-realtek-Convert-to-platform-remove-callback.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0001-net-dsa-realtek-drop-cleanup-from-realtek_ops.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0002-net-dsa-realtek-introduce-REALTEK_DSA-namespace.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0003-net-dsa-realtek-convert-variants-into-real-drivers.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0004-net-dsa-realtek-keep-variant-reference-in-realtek_pr.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0005-net-dsa-realtek-common-rtl83xx-module.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0006-net-dsa-realtek-merge-rtl83xx-and-interface-modules-.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0007-net-dsa-realtek-get-internal-MDIO-node-by-name.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0008-net-dsa-realtek-clean-user_mii_bus-setup.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0009-net-dsa-realtek-migrate-user_mii_bus-setup-to-realte.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0010-net-dsa-realtek-use-the-same-mii-bus-driver-for-both.patch create mode 100644 target/linux/generic/backport-6.6/896-v6.9-0011-net-dsa-realtek-embed-dsa_switch-into-realtek_priv.patch create mode 100644 target/linux/generic/backport-6.6/897-v6.9-net-dsa-realtek-fix-digital-interface-select-macro-f.patch create mode 100644 target/linux/generic/backport-6.6/898-v6.9-0001-dt-bindings-net-dsa-realtek-reset-gpios-is-not-requi.patch create mode 100644 target/linux/generic/backport-6.6/898-v6.9-0002-dt-bindings-net-dsa-realtek-add-reset-controller.patch create mode 100644 target/linux/generic/backport-6.6/898-v6.9-0003-net-dsa-realtek-support-reset-controller.patch create mode 100644 target/linux/generic/backport-6.6/899-v6.10-0002-net-dsa-realtek-do-not-assert-reset-on-remove.patch create mode 100644 target/linux/generic/backport-6.6/899-v6.10-0003-net-dsa-realtek-add-LED-drivers-for-rtl8366rb.patch diff --git a/package/kernel/linux/modules/netdevices.mk b/package/kernel/linux/modules/netdevices.mk index 24a41c6b3f..d418701555 100644 --- a/package/kernel/linux/modules/netdevices.mk +++ b/package/kernel/linux/modules/netdevices.mk @@ -637,6 +637,65 @@ endef $(eval $(call KernelPackage,dsa-qca8k)) + +define KernelPackage/dsa-realtek + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Realtek common module RTL83xx DSA switch family + DEPENDS:=+kmod-dsa +kmod-phy-realtek +kmod-regmap-core @!TARGET_x86 @!TARGET_bcm47xx @!TARGET_uml + KCONFIG:= \ + CONFIG_NET_DSA_REALTEK \ + CONFIG_NET_DSA_REALTEK_MDIO=y \ + CONFIG_NET_DSA_REALTEK_SMI=y + FILES:= $(LINUX_DIR)/drivers/net/dsa/realtek/realtek_dsa.ko +endef + +define KernelPackage/dsa-realtek/description + Common kernel module for Realtek RTL83xx DSA switch family +endef + +$(eval $(call KernelPackage,dsa-realtek)) + + +define KernelPackage/dsa-rtl8366rb + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Realtek RTL8365MB switch DSA support + DEPENDS:=+kmod-dsa-realtek @!TARGET_x86 @!TARGET_bcm47xx @!TARGET_uml + KCONFIG:= \ + CONFIG_NET_DSA_REALTEK_RTL8366RB \ + CONFIG_NET_DSA_TAG_RTL4_A + FILES:= \ + $(LINUX_DIR)/drivers/net/dsa/realtek/rtl8366.ko \ + $(LINUX_DIR)/net/dsa/tag_rtl4_a.ko + AUTOLOAD:=$(call AutoLoad,42,rtl8366,1) +endef + +define KernelPackage/dsa-rtl8366rb/description + DSA based kernel modules for the Realtek RTL8366RB switch family +endef + +$(eval $(call KernelPackage,dsa-rtl8366rb)) + + +define KernelPackage/dsa-rtl8365mb + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Realtek RTL8365MB switch DSA support + DEPENDS:=+kmod-dsa-realtek @!TARGET_x86 @!TARGET_bcm47xx @!TARGET_uml + KCONFIG:= \ + CONFIG_NET_DSA_REALTEK_RTL8365MB \ + CONFIG_NET_DSA_TAG_RTL8_4 + FILES:= \ + $(LINUX_DIR)/drivers/net/dsa/realtek/rtl8365mb.ko \ + $(LINUX_DIR)/net/dsa/tag_rtl8_4.ko + AUTOLOAD:=$(call AutoLoad,42,rtl8365mb,1) +endef + +define KernelPackage/dsa-rtl8365mb/description + DSA based kernel modules for the Realtek RTL8365MB switch family +endef + +$(eval $(call KernelPackage,dsa-rtl8365mb)) + + define KernelPackage/swconfig SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=switch configuration API diff --git a/target/linux/generic/backport-6.6/894-v6.7-net-dsa-realtek-Convert-to-platform-remove-callback.patch b/target/linux/generic/backport-6.6/894-v6.7-net-dsa-realtek-Convert-to-platform-remove-callback.patch new file mode 100644 index 0000000000..d19338e7df --- /dev/null +++ b/target/linux/generic/backport-6.6/894-v6.7-net-dsa-realtek-Convert-to-platform-remove-callback.patch @@ -0,0 +1,66 @@ +From d48a5472b8f2b29800bb25913f9403765005f1bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= +Date: Mon, 18 Sep 2023 21:19:14 +0200 +Subject: [PATCH] net: dsa: realtek: Convert to platform remove callback + returning void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is ignored (apart +from emitting a warning) and this typically results in resource leaks. +To improve here there is a quest to make the remove callback return +void. In the first step of this quest all drivers are converted to +.remove_new() which already returns void. Eventually after all drivers +are converted, .remove_new() is renamed to .remove(). + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Reviewed-by: Alvin Šipraga +Signed-off-by: David S. Miller +Signed-off-by: Luiz Angelo Daros de Luca +--- + drivers/net/dsa/realtek/realtek-smi.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -506,12 +506,12 @@ static int realtek_smi_probe(struct plat + return 0; + } + +-static int realtek_smi_remove(struct platform_device *pdev) ++static void realtek_smi_remove(struct platform_device *pdev) + { + struct realtek_priv *priv = platform_get_drvdata(pdev); + + if (!priv) +- return 0; ++ return; + + dsa_unregister_switch(priv->ds); + if (priv->slave_mii_bus) +@@ -520,8 +520,6 @@ static int realtek_smi_remove(struct pla + /* leave the device reset asserted */ + if (priv->reset) + gpiod_set_value(priv->reset, 1); +- +- return 0; + } + + static void realtek_smi_shutdown(struct platform_device *pdev) +@@ -559,7 +557,7 @@ static struct platform_driver realtek_sm + .of_match_table = realtek_smi_of_match, + }, + .probe = realtek_smi_probe, +- .remove = realtek_smi_remove, ++ .remove_new = realtek_smi_remove, + .shutdown = realtek_smi_shutdown, + }; + module_platform_driver(realtek_smi_driver); diff --git a/target/linux/generic/backport-6.6/896-v6.9-0001-net-dsa-realtek-drop-cleanup-from-realtek_ops.patch b/target/linux/generic/backport-6.6/896-v6.9-0001-net-dsa-realtek-drop-cleanup-from-realtek_ops.patch new file mode 100644 index 0000000000..82958ecff8 --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0001-net-dsa-realtek-drop-cleanup-from-realtek_ops.patch @@ -0,0 +1,30 @@ +From 33f4336cbd32c21717b60d013693a0bd51a27db6 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:37 -0300 +Subject: net: dsa: realtek: drop cleanup from realtek_ops +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It was never used and never referenced. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Alvin Šipraga +Reviewed-by: Florian Fainelli +Reviewed-by: Linus Walleij +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/realtek.h | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -91,7 +91,6 @@ struct realtek_ops { + int (*detect)(struct realtek_priv *priv); + int (*reset_chip)(struct realtek_priv *priv); + int (*setup)(struct realtek_priv *priv); +- void (*cleanup)(struct realtek_priv *priv); + int (*get_mib_counter)(struct realtek_priv *priv, + int port, + struct rtl8366_mib_counter *mib, diff --git a/target/linux/generic/backport-6.6/896-v6.9-0002-net-dsa-realtek-introduce-REALTEK_DSA-namespace.patch b/target/linux/generic/backport-6.6/896-v6.9-0002-net-dsa-realtek-introduce-REALTEK_DSA-namespace.patch new file mode 100644 index 0000000000..d50ea1bb30 --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0002-net-dsa-realtek-introduce-REALTEK_DSA-namespace.patch @@ -0,0 +1,146 @@ +From ded3813b44fe11a3bbd2c9d7df8870e8c19a7ccd Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:38 -0300 +Subject: net: dsa: realtek: introduce REALTEK_DSA namespace + +Create a namespace to group the exported symbols. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/realtek-mdio.c | 1 + + drivers/net/dsa/realtek/realtek-smi.c | 1 + + drivers/net/dsa/realtek/rtl8365mb.c | 1 + + drivers/net/dsa/realtek/rtl8366-core.c | 22 +++++++++++----------- + drivers/net/dsa/realtek/rtl8366rb.c | 1 + + 5 files changed, 15 insertions(+), 11 deletions(-) + +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -288,3 +288,4 @@ mdio_module_driver(realtek_mdio_driver); + MODULE_AUTHOR("Luiz Angelo Daros de Luca "); + MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface"); + MODULE_LICENSE("GPL"); ++MODULE_IMPORT_NS(REALTEK_DSA); +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -565,3 +565,4 @@ module_platform_driver(realtek_smi_drive + MODULE_AUTHOR("Linus Walleij "); + MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface"); + MODULE_LICENSE("GPL"); ++MODULE_IMPORT_NS(REALTEK_DSA); +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -2178,3 +2178,4 @@ EXPORT_SYMBOL_GPL(rtl8365mb_variant); + MODULE_AUTHOR("Alvin Šipraga "); + MODULE_DESCRIPTION("Driver for RTL8365MB-VC ethernet switch"); + MODULE_LICENSE("GPL"); ++MODULE_IMPORT_NS(REALTEK_DSA); +--- a/drivers/net/dsa/realtek/rtl8366-core.c ++++ b/drivers/net/dsa/realtek/rtl8366-core.c +@@ -34,7 +34,7 @@ int rtl8366_mc_is_used(struct realtek_pr + + return 0; + } +-EXPORT_SYMBOL_GPL(rtl8366_mc_is_used); ++EXPORT_SYMBOL_NS_GPL(rtl8366_mc_is_used, REALTEK_DSA); + + /** + * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration +@@ -187,7 +187,7 @@ int rtl8366_set_vlan(struct realtek_priv + + return ret; + } +-EXPORT_SYMBOL_GPL(rtl8366_set_vlan); ++EXPORT_SYMBOL_NS_GPL(rtl8366_set_vlan, REALTEK_DSA); + + int rtl8366_set_pvid(struct realtek_priv *priv, unsigned int port, + unsigned int vid) +@@ -217,7 +217,7 @@ int rtl8366_set_pvid(struct realtek_priv + + return 0; + } +-EXPORT_SYMBOL_GPL(rtl8366_set_pvid); ++EXPORT_SYMBOL_NS_GPL(rtl8366_set_pvid, REALTEK_DSA); + + int rtl8366_enable_vlan4k(struct realtek_priv *priv, bool enable) + { +@@ -243,7 +243,7 @@ int rtl8366_enable_vlan4k(struct realtek + priv->vlan4k_enabled = enable; + return 0; + } +-EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k); ++EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan4k, REALTEK_DSA); + + int rtl8366_enable_vlan(struct realtek_priv *priv, bool enable) + { +@@ -265,7 +265,7 @@ int rtl8366_enable_vlan(struct realtek_p + + return ret; + } +-EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); ++EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan, REALTEK_DSA); + + int rtl8366_reset_vlan(struct realtek_priv *priv) + { +@@ -290,7 +290,7 @@ int rtl8366_reset_vlan(struct realtek_pr + + return 0; + } +-EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); ++EXPORT_SYMBOL_NS_GPL(rtl8366_reset_vlan, REALTEK_DSA); + + int rtl8366_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, +@@ -345,7 +345,7 @@ int rtl8366_vlan_add(struct dsa_switch * + + return 0; + } +-EXPORT_SYMBOL_GPL(rtl8366_vlan_add); ++EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_add, REALTEK_DSA); + + int rtl8366_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +@@ -389,7 +389,7 @@ int rtl8366_vlan_del(struct dsa_switch * + + return 0; + } +-EXPORT_SYMBOL_GPL(rtl8366_vlan_del); ++EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_del, REALTEK_DSA); + + void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, + uint8_t *data) +@@ -407,7 +407,7 @@ void rtl8366_get_strings(struct dsa_swit + mib->name, ETH_GSTRING_LEN); + } + } +-EXPORT_SYMBOL_GPL(rtl8366_get_strings); ++EXPORT_SYMBOL_NS_GPL(rtl8366_get_strings, REALTEK_DSA); + + int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset) + { +@@ -421,7 +421,7 @@ int rtl8366_get_sset_count(struct dsa_sw + + return priv->num_mib_counters; + } +-EXPORT_SYMBOL_GPL(rtl8366_get_sset_count); ++EXPORT_SYMBOL_NS_GPL(rtl8366_get_sset_count, REALTEK_DSA); + + void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) + { +@@ -445,4 +445,4 @@ void rtl8366_get_ethtool_stats(struct ds + data[i] = mibvalue; + } + } +-EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats); ++EXPORT_SYMBOL_NS_GPL(rtl8366_get_ethtool_stats, REALTEK_DSA); +--- a/drivers/net/dsa/realtek/rtl8366rb.c ++++ b/drivers/net/dsa/realtek/rtl8366rb.c +@@ -1852,3 +1852,4 @@ EXPORT_SYMBOL_GPL(rtl8366rb_variant); + MODULE_AUTHOR("Linus Walleij "); + MODULE_DESCRIPTION("Driver for RTL8366RB ethernet switch"); + MODULE_LICENSE("GPL"); ++MODULE_IMPORT_NS(REALTEK_DSA); diff --git a/target/linux/generic/backport-6.6/896-v6.9-0003-net-dsa-realtek-convert-variants-into-real-drivers.patch b/target/linux/generic/backport-6.6/896-v6.9-0003-net-dsa-realtek-convert-variants-into-real-drivers.patch new file mode 100644 index 0000000000..aa6dfcf7e6 --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0003-net-dsa-realtek-convert-variants-into-real-drivers.patch @@ -0,0 +1,539 @@ +From bce254b839abe67577bebdef0838796af409c229 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:39 -0300 +Subject: net: dsa: realtek: convert variants into real drivers + +Previously, the interface modules realtek-smi and realtek-mdio served as +a platform and an MDIO driver, respectively. Each interface module +redundantly specified the same compatible strings for both variants and +referenced symbols from the variants. + +Now, each variant module has been transformed into a unified driver +serving both as a platform and an MDIO driver. This modification +reverses the relationship between the interface and variant modules, +with the variant module now utilizing symbols from the interface +modules. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Vladimir Oltean +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/Kconfig | 20 +++---- + drivers/net/dsa/realtek/realtek-mdio.c | 68 +++++++++++++++--------- + drivers/net/dsa/realtek/realtek-mdio.h | 48 +++++++++++++++++ + drivers/net/dsa/realtek/realtek-smi.c | 73 +++++++++++++++----------- + drivers/net/dsa/realtek/realtek-smi.h | 48 +++++++++++++++++ + drivers/net/dsa/realtek/rtl8365mb.c | 54 ++++++++++++++++++- + drivers/net/dsa/realtek/rtl8366rb.c | 54 ++++++++++++++++++- + 7 files changed, 292 insertions(+), 73 deletions(-) + create mode 100644 drivers/net/dsa/realtek/realtek-mdio.h + create mode 100644 drivers/net/dsa/realtek/realtek-smi.h + +--- a/drivers/net/dsa/realtek/Kconfig ++++ b/drivers/net/dsa/realtek/Kconfig +@@ -16,37 +16,29 @@ menuconfig NET_DSA_REALTEK + if NET_DSA_REALTEK + + config NET_DSA_REALTEK_MDIO +- tristate "Realtek MDIO interface driver" ++ tristate "Realtek MDIO interface support" + depends on OF +- depends on NET_DSA_REALTEK_RTL8365MB || NET_DSA_REALTEK_RTL8366RB +- depends on NET_DSA_REALTEK_RTL8365MB || !NET_DSA_REALTEK_RTL8365MB +- depends on NET_DSA_REALTEK_RTL8366RB || !NET_DSA_REALTEK_RTL8366RB + help + Select to enable support for registering switches configured + through MDIO. + + config NET_DSA_REALTEK_SMI +- tristate "Realtek SMI interface driver" ++ tristate "Realtek SMI interface support" + depends on OF +- depends on NET_DSA_REALTEK_RTL8365MB || NET_DSA_REALTEK_RTL8366RB +- depends on NET_DSA_REALTEK_RTL8365MB || !NET_DSA_REALTEK_RTL8365MB +- depends on NET_DSA_REALTEK_RTL8366RB || !NET_DSA_REALTEK_RTL8366RB + help + Select to enable support for registering switches connected + through SMI. + + config NET_DSA_REALTEK_RTL8365MB +- tristate "Realtek RTL8365MB switch subdriver" +- imply NET_DSA_REALTEK_SMI +- imply NET_DSA_REALTEK_MDIO ++ tristate "Realtek RTL8365MB switch driver" ++ depends on NET_DSA_REALTEK_SMI || NET_DSA_REALTEK_MDIO + select NET_DSA_TAG_RTL8_4 + help + Select to enable support for Realtek RTL8365MB-VC and RTL8367S. + + config NET_DSA_REALTEK_RTL8366RB +- tristate "Realtek RTL8366RB switch subdriver" +- imply NET_DSA_REALTEK_SMI +- imply NET_DSA_REALTEK_MDIO ++ tristate "Realtek RTL8366RB switch driver" ++ depends on NET_DSA_REALTEK_SMI || NET_DSA_REALTEK_MDIO + select NET_DSA_TAG_RTL4_A + help + Select to enable support for Realtek RTL8366RB. +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -25,6 +25,7 @@ + #include + + #include "realtek.h" ++#include "realtek-mdio.h" + + /* Read/write via mdiobus */ + #define REALTEK_MDIO_CTRL0_REG 31 +@@ -140,7 +141,19 @@ static const struct regmap_config realte + .disable_locking = true, + }; + +-static int realtek_mdio_probe(struct mdio_device *mdiodev) ++/** ++ * realtek_mdio_probe() - Probe a platform device for an MDIO-connected switch ++ * @mdiodev: mdio_device to probe on. ++ * ++ * This function should be used as the .probe in an mdio_driver. It ++ * initializes realtek_priv and read data from the device-tree node. The switch ++ * is hard reset if a method is provided. It checks the switch chip ID and, ++ * finally, a DSA switch is registered. ++ * ++ * Context: Can sleep. Takes and releases priv->map_lock. ++ * Return: Returns 0 on success, a negative error on failure. ++ */ ++int realtek_mdio_probe(struct mdio_device *mdiodev) + { + struct realtek_priv *priv; + struct device *dev = &mdiodev->dev; +@@ -235,8 +248,20 @@ static int realtek_mdio_probe(struct mdi + + return 0; + } ++EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe, REALTEK_DSA); + +-static void realtek_mdio_remove(struct mdio_device *mdiodev) ++/** ++ * realtek_mdio_remove() - Remove the driver of an MDIO-connected switch ++ * @mdiodev: mdio_device to be removed. ++ * ++ * This function should be used as the .remove_new in an mdio_driver. First ++ * it unregisters the DSA switch and cleans internal data. If a method is ++ * provided, the hard reset is asserted to avoid traffic leakage. ++ * ++ * Context: Can sleep. ++ * Return: Nothing. ++ */ ++void realtek_mdio_remove(struct mdio_device *mdiodev) + { + struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev); + +@@ -249,8 +274,21 @@ static void realtek_mdio_remove(struct m + if (priv->reset) + gpiod_set_value(priv->reset, 1); + } ++EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, REALTEK_DSA); + +-static void realtek_mdio_shutdown(struct mdio_device *mdiodev) ++/** ++ * realtek_mdio_shutdown() - Shutdown the driver of a MDIO-connected switch ++ * @mdiodev: mdio_device shutting down. ++ * ++ * This function should be used as the .shutdown in an mdio_driver. It shuts ++ * down the DSA switch and cleans the platform driver data, to prevent ++ * realtek_mdio_remove() from running afterwards, which is possible if the ++ * parent bus implements its own .shutdown() as .remove(). ++ * ++ * Context: Can sleep. ++ * Return: Nothing. ++ */ ++void realtek_mdio_shutdown(struct mdio_device *mdiodev) + { + struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev); + +@@ -261,29 +299,7 @@ static void realtek_mdio_shutdown(struct + + dev_set_drvdata(&mdiodev->dev, NULL); + } +- +-static const struct of_device_id realtek_mdio_of_match[] = { +-#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB) +- { .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, }, +-#endif +-#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB) +- { .compatible = "realtek,rtl8365mb", .data = &rtl8365mb_variant, }, +-#endif +- { /* sentinel */ }, +-}; +-MODULE_DEVICE_TABLE(of, realtek_mdio_of_match); +- +-static struct mdio_driver realtek_mdio_driver = { +- .mdiodrv.driver = { +- .name = "realtek-mdio", +- .of_match_table = realtek_mdio_of_match, +- }, +- .probe = realtek_mdio_probe, +- .remove = realtek_mdio_remove, +- .shutdown = realtek_mdio_shutdown, +-}; +- +-mdio_module_driver(realtek_mdio_driver); ++EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA); + + MODULE_AUTHOR("Luiz Angelo Daros de Luca "); + MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface"); +--- /dev/null ++++ b/drivers/net/dsa/realtek/realtek-mdio.h +@@ -0,0 +1,48 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++ ++#ifndef _REALTEK_MDIO_H ++#define _REALTEK_MDIO_H ++ ++#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_MDIO) ++ ++static inline int realtek_mdio_driver_register(struct mdio_driver *drv) ++{ ++ return mdio_driver_register(drv); ++} ++ ++static inline void realtek_mdio_driver_unregister(struct mdio_driver *drv) ++{ ++ mdio_driver_unregister(drv); ++} ++ ++int realtek_mdio_probe(struct mdio_device *mdiodev); ++void realtek_mdio_remove(struct mdio_device *mdiodev); ++void realtek_mdio_shutdown(struct mdio_device *mdiodev); ++ ++#else /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_MDIO) */ ++ ++static inline int realtek_mdio_driver_register(struct mdio_driver *drv) ++{ ++ return 0; ++} ++ ++static inline void realtek_mdio_driver_unregister(struct mdio_driver *drv) ++{ ++} ++ ++static inline int realtek_mdio_probe(struct mdio_device *mdiodev) ++{ ++ return -ENOENT; ++} ++ ++static inline void realtek_mdio_remove(struct mdio_device *mdiodev) ++{ ++} ++ ++static inline void realtek_mdio_shutdown(struct mdio_device *mdiodev) ++{ ++} ++ ++#endif /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_MDIO) */ ++ ++#endif /* _REALTEK_MDIO_H */ +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -40,6 +40,7 @@ + #include + + #include "realtek.h" ++#include "realtek-smi.h" + + #define REALTEK_SMI_ACK_RETRY_COUNT 5 + +@@ -408,7 +409,19 @@ err_put_node: + return ret; + } + +-static int realtek_smi_probe(struct platform_device *pdev) ++/** ++ * realtek_smi_probe() - Probe a platform device for an SMI-connected switch ++ * @pdev: platform_device to probe on. ++ * ++ * This function should be used as the .probe in a platform_driver. It ++ * initializes realtek_priv and read data from the device-tree node. The switch ++ * is hard reset if a method is provided. It checks the switch chip ID and, ++ * finally, a DSA switch is registered. ++ * ++ * Context: Can sleep. Takes and releases priv->map_lock. ++ * Return: Returns 0 on success, a negative error on failure. ++ */ ++int realtek_smi_probe(struct platform_device *pdev) + { + const struct realtek_variant *var; + struct device *dev = &pdev->dev; +@@ -505,8 +518,20 @@ static int realtek_smi_probe(struct plat + } + return 0; + } ++EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA); + +-static void realtek_smi_remove(struct platform_device *pdev) ++/** ++ * realtek_smi_remove() - Remove the driver of a SMI-connected switch ++ * @pdev: platform_device to be removed. ++ * ++ * This function should be used as the .remove_new in a platform_driver. First ++ * it unregisters the DSA switch and cleans internal data. If a method is ++ * provided, the hard reset is asserted to avoid traffic leakage. ++ * ++ * Context: Can sleep. ++ * Return: Nothing. ++ */ ++void realtek_smi_remove(struct platform_device *pdev) + { + struct realtek_priv *priv = platform_get_drvdata(pdev); + +@@ -521,8 +546,21 @@ static void realtek_smi_remove(struct pl + if (priv->reset) + gpiod_set_value(priv->reset, 1); + } ++EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); + +-static void realtek_smi_shutdown(struct platform_device *pdev) ++/** ++ * realtek_smi_shutdown() - Shutdown the driver of a SMI-connected switch ++ * @pdev: platform_device shutting down. ++ * ++ * This function should be used as the .shutdown in a platform_driver. It shuts ++ * down the DSA switch and cleans the platform driver data, to prevent ++ * realtek_smi_remove() from running afterwards, which is possible if the ++ * parent bus implements its own .shutdown() as .remove(). ++ * ++ * Context: Can sleep. ++ * Return: Nothing. ++ */ ++void realtek_smi_shutdown(struct platform_device *pdev) + { + struct realtek_priv *priv = platform_get_drvdata(pdev); + +@@ -533,34 +571,7 @@ static void realtek_smi_shutdown(struct + + platform_set_drvdata(pdev, NULL); + } +- +-static const struct of_device_id realtek_smi_of_match[] = { +-#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB) +- { +- .compatible = "realtek,rtl8366rb", +- .data = &rtl8366rb_variant, +- }, +-#endif +-#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB) +- { +- .compatible = "realtek,rtl8365mb", +- .data = &rtl8365mb_variant, +- }, +-#endif +- { /* sentinel */ }, +-}; +-MODULE_DEVICE_TABLE(of, realtek_smi_of_match); +- +-static struct platform_driver realtek_smi_driver = { +- .driver = { +- .name = "realtek-smi", +- .of_match_table = realtek_smi_of_match, +- }, +- .probe = realtek_smi_probe, +- .remove_new = realtek_smi_remove, +- .shutdown = realtek_smi_shutdown, +-}; +-module_platform_driver(realtek_smi_driver); ++EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA); + + MODULE_AUTHOR("Linus Walleij "); + MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface"); +--- /dev/null ++++ b/drivers/net/dsa/realtek/realtek-smi.h +@@ -0,0 +1,48 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++ ++#ifndef _REALTEK_SMI_H ++#define _REALTEK_SMI_H ++ ++#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_SMI) ++ ++static inline int realtek_smi_driver_register(struct platform_driver *drv) ++{ ++ return platform_driver_register(drv); ++} ++ ++static inline void realtek_smi_driver_unregister(struct platform_driver *drv) ++{ ++ platform_driver_unregister(drv); ++} ++ ++int realtek_smi_probe(struct platform_device *pdev); ++void realtek_smi_remove(struct platform_device *pdev); ++void realtek_smi_shutdown(struct platform_device *pdev); ++ ++#else /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_SMI) */ ++ ++static inline int realtek_smi_driver_register(struct platform_driver *drv) ++{ ++ return 0; ++} ++ ++static inline void realtek_smi_driver_unregister(struct platform_driver *drv) ++{ ++} ++ ++static inline int realtek_smi_probe(struct platform_device *pdev) ++{ ++ return -ENOENT; ++} ++ ++static inline void realtek_smi_remove(struct platform_device *pdev) ++{ ++} ++ ++static inline void realtek_smi_shutdown(struct platform_device *pdev) ++{ ++} ++ ++#endif /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_SMI) */ ++ ++#endif /* _REALTEK_SMI_H */ +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -101,6 +101,8 @@ + #include + + #include "realtek.h" ++#include "realtek-smi.h" ++#include "realtek-mdio.h" + + /* Family-specific data and limits */ + #define RTL8365MB_PHYADDRMAX 7 +@@ -2173,7 +2175,57 @@ const struct realtek_variant rtl8365mb_v + .cmd_write = 0xb8, + .chip_data_sz = sizeof(struct rtl8365mb), + }; +-EXPORT_SYMBOL_GPL(rtl8365mb_variant); ++ ++static const struct of_device_id rtl8365mb_of_match[] = { ++ { .compatible = "realtek,rtl8365mb", .data = &rtl8365mb_variant, }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, rtl8365mb_of_match); ++ ++static struct platform_driver rtl8365mb_smi_driver = { ++ .driver = { ++ .name = "rtl8365mb-smi", ++ .of_match_table = rtl8365mb_of_match, ++ }, ++ .probe = realtek_smi_probe, ++ .remove_new = realtek_smi_remove, ++ .shutdown = realtek_smi_shutdown, ++}; ++ ++static struct mdio_driver rtl8365mb_mdio_driver = { ++ .mdiodrv.driver = { ++ .name = "rtl8365mb-mdio", ++ .of_match_table = rtl8365mb_of_match, ++ }, ++ .probe = realtek_mdio_probe, ++ .remove = realtek_mdio_remove, ++ .shutdown = realtek_mdio_shutdown, ++}; ++ ++static int rtl8365mb_init(void) ++{ ++ int ret; ++ ++ ret = realtek_mdio_driver_register(&rtl8365mb_mdio_driver); ++ if (ret) ++ return ret; ++ ++ ret = realtek_smi_driver_register(&rtl8365mb_smi_driver); ++ if (ret) { ++ realtek_mdio_driver_unregister(&rtl8365mb_mdio_driver); ++ return ret; ++ } ++ ++ return 0; ++} ++module_init(rtl8365mb_init); ++ ++static void __exit rtl8365mb_exit(void) ++{ ++ realtek_smi_driver_unregister(&rtl8365mb_smi_driver); ++ realtek_mdio_driver_unregister(&rtl8365mb_mdio_driver); ++} ++module_exit(rtl8365mb_exit); + + MODULE_AUTHOR("Alvin Šipraga "); + MODULE_DESCRIPTION("Driver for RTL8365MB-VC ethernet switch"); +--- a/drivers/net/dsa/realtek/rtl8366rb.c ++++ b/drivers/net/dsa/realtek/rtl8366rb.c +@@ -22,6 +22,8 @@ + #include + + #include "realtek.h" ++#include "realtek-smi.h" ++#include "realtek-mdio.h" + + #define RTL8366RB_PORT_NUM_CPU 5 + #define RTL8366RB_NUM_PORTS 6 +@@ -1847,7 +1849,57 @@ const struct realtek_variant rtl8366rb_v + .cmd_write = 0xa8, + .chip_data_sz = sizeof(struct rtl8366rb), + }; +-EXPORT_SYMBOL_GPL(rtl8366rb_variant); ++ ++static const struct of_device_id rtl8366rb_of_match[] = { ++ { .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, rtl8366rb_of_match); ++ ++static struct platform_driver rtl8366rb_smi_driver = { ++ .driver = { ++ .name = "rtl8366rb-smi", ++ .of_match_table = rtl8366rb_of_match, ++ }, ++ .probe = realtek_smi_probe, ++ .remove_new = realtek_smi_remove, ++ .shutdown = realtek_smi_shutdown, ++}; ++ ++static struct mdio_driver rtl8366rb_mdio_driver = { ++ .mdiodrv.driver = { ++ .name = "rtl8366rb-mdio", ++ .of_match_table = rtl8366rb_of_match, ++ }, ++ .probe = realtek_mdio_probe, ++ .remove = realtek_mdio_remove, ++ .shutdown = realtek_mdio_shutdown, ++}; ++ ++static int rtl8366rb_init(void) ++{ ++ int ret; ++ ++ ret = realtek_mdio_driver_register(&rtl8366rb_mdio_driver); ++ if (ret) ++ return ret; ++ ++ ret = realtek_smi_driver_register(&rtl8366rb_smi_driver); ++ if (ret) { ++ realtek_mdio_driver_unregister(&rtl8366rb_mdio_driver); ++ return ret; ++ } ++ ++ return 0; ++} ++module_init(rtl8366rb_init); ++ ++static void __exit rtl8366rb_exit(void) ++{ ++ realtek_smi_driver_unregister(&rtl8366rb_smi_driver); ++ realtek_mdio_driver_unregister(&rtl8366rb_mdio_driver); ++} ++module_exit(rtl8366rb_exit); + + MODULE_AUTHOR("Linus Walleij "); + MODULE_DESCRIPTION("Driver for RTL8366RB ethernet switch"); diff --git a/target/linux/generic/backport-6.6/896-v6.9-0004-net-dsa-realtek-keep-variant-reference-in-realtek_pr.patch b/target/linux/generic/backport-6.6/896-v6.9-0004-net-dsa-realtek-keep-variant-reference-in-realtek_pr.patch new file mode 100644 index 0000000000..b0e074b2c9 --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0004-net-dsa-realtek-keep-variant-reference-in-realtek_pr.patch @@ -0,0 +1,91 @@ +From 4667a1db2f550d23e01ba655fce331196ead6e92 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:40 -0300 +Subject: net: dsa: realtek: keep variant reference in + realtek_priv + +Instead of copying values from the variant, we can keep a reference in +realtek_priv. + +This is a preliminary change for sharing code betwen interfaces. It will +allow to move most of the probe into a common module while still allow +code specific to each interface to read variant fields. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/realtek-mdio.c | 4 +--- + drivers/net/dsa/realtek/realtek-smi.c | 10 ++++------ + drivers/net/dsa/realtek/realtek.h | 5 ++--- + 3 files changed, 7 insertions(+), 12 deletions(-) + +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -196,9 +196,7 @@ int realtek_mdio_probe(struct mdio_devic + priv->dev = &mdiodev->dev; + priv->chip_data = (void *)priv + sizeof(*priv); + +- priv->clk_delay = var->clk_delay; +- priv->cmd_read = var->cmd_read; +- priv->cmd_write = var->cmd_write; ++ priv->variant = var; + priv->ops = var->ops; + + priv->write_reg_noack = realtek_mdio_write; +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -46,7 +46,7 @@ + + static inline void realtek_smi_clk_delay(struct realtek_priv *priv) + { +- ndelay(priv->clk_delay); ++ ndelay(priv->variant->clk_delay); + } + + static void realtek_smi_start(struct realtek_priv *priv) +@@ -209,7 +209,7 @@ static int realtek_smi_read_reg(struct r + realtek_smi_start(priv); + + /* Send READ command */ +- ret = realtek_smi_write_byte(priv, priv->cmd_read); ++ ret = realtek_smi_write_byte(priv, priv->variant->cmd_read); + if (ret) + goto out; + +@@ -250,7 +250,7 @@ static int realtek_smi_write_reg(struct + realtek_smi_start(priv); + + /* Send WRITE command */ +- ret = realtek_smi_write_byte(priv, priv->cmd_write); ++ ret = realtek_smi_write_byte(priv, priv->variant->cmd_write); + if (ret) + goto out; + +@@ -459,9 +459,7 @@ int realtek_smi_probe(struct platform_de + + /* Link forward and backward */ + priv->dev = dev; +- priv->clk_delay = var->clk_delay; +- priv->cmd_read = var->cmd_read; +- priv->cmd_write = var->cmd_write; ++ priv->variant = var; + priv->ops = var->ops; + + priv->setup_interface = realtek_smi_setup_mdio; +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -58,9 +58,8 @@ struct realtek_priv { + struct mii_bus *bus; + int mdio_addr; + +- unsigned int clk_delay; +- u8 cmd_read; +- u8 cmd_write; ++ const struct realtek_variant *variant; ++ + spinlock_t lock; /* Locks around command writes */ + struct dsa_switch *ds; + struct irq_domain *irqdomain; diff --git a/target/linux/generic/backport-6.6/896-v6.9-0005-net-dsa-realtek-common-rtl83xx-module.patch b/target/linux/generic/backport-6.6/896-v6.9-0005-net-dsa-realtek-common-rtl83xx-module.patch new file mode 100644 index 0000000000..544b1b2992 --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0005-net-dsa-realtek-common-rtl83xx-module.patch @@ -0,0 +1,875 @@ +From 8be040ecd94c1a9a137927d18534edfae0a9b68a Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:41 -0300 +Subject: net: dsa: realtek: common rtl83xx module + +Some code can be shared between both interface modules (MDIO and SMI) +and among variants. These interface functions migrated to a common +module: + +- rtl83xx_lock +- rtl83xx_unlock +- rtl83xx_probe +- rtl83xx_register_switch +- rtl83xx_unregister_switch +- rtl83xx_shutdown +- rtl83xx_remove + +The reset during probe was moved to the end of the common probe. This way, +we avoid a reset if anything else fails. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/Makefile | 2 + + drivers/net/dsa/realtek/realtek-mdio.c | 152 +++------------- + drivers/net/dsa/realtek/realtek-smi.c | 166 ++++------------- + drivers/net/dsa/realtek/realtek.h | 1 + + drivers/net/dsa/realtek/rtl8365mb.c | 9 +- + drivers/net/dsa/realtek/rtl8366rb.c | 9 +- + drivers/net/dsa/realtek/rtl83xx.c | 235 +++++++++++++++++++++++++ + drivers/net/dsa/realtek/rtl83xx.h | 21 +++ + 8 files changed, 322 insertions(+), 273 deletions(-) + create mode 100644 drivers/net/dsa/realtek/rtl83xx.c + create mode 100644 drivers/net/dsa/realtek/rtl83xx.h + +--- a/drivers/net/dsa/realtek/Makefile ++++ b/drivers/net/dsa/realtek/Makefile +@@ -1,4 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_NET_DSA_REALTEK) += realtek_dsa.o ++realtek_dsa-objs := rtl83xx.o + obj-$(CONFIG_NET_DSA_REALTEK_MDIO) += realtek-mdio.o + obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o + obj-$(CONFIG_NET_DSA_REALTEK_RTL8366RB) += rtl8366.o +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -26,6 +26,7 @@ + + #include "realtek.h" + #include "realtek-mdio.h" ++#include "rtl83xx.h" + + /* Read/write via mdiobus */ + #define REALTEK_MDIO_CTRL0_REG 31 +@@ -100,147 +101,41 @@ out_unlock: + return ret; + } + +-static void realtek_mdio_lock(void *ctx) +-{ +- struct realtek_priv *priv = ctx; +- +- mutex_lock(&priv->map_lock); +-} +- +-static void realtek_mdio_unlock(void *ctx) +-{ +- struct realtek_priv *priv = ctx; +- +- mutex_unlock(&priv->map_lock); +-} +- +-static const struct regmap_config realtek_mdio_regmap_config = { +- .reg_bits = 10, /* A4..A0 R4..R0 */ +- .val_bits = 16, +- .reg_stride = 1, +- /* PHY regs are at 0x8000 */ +- .max_register = 0xffff, +- .reg_format_endian = REGMAP_ENDIAN_BIG, ++static const struct realtek_interface_info realtek_mdio_info = { + .reg_read = realtek_mdio_read, + .reg_write = realtek_mdio_write, +- .cache_type = REGCACHE_NONE, +- .lock = realtek_mdio_lock, +- .unlock = realtek_mdio_unlock, +-}; +- +-static const struct regmap_config realtek_mdio_nolock_regmap_config = { +- .reg_bits = 10, /* A4..A0 R4..R0 */ +- .val_bits = 16, +- .reg_stride = 1, +- /* PHY regs are at 0x8000 */ +- .max_register = 0xffff, +- .reg_format_endian = REGMAP_ENDIAN_BIG, +- .reg_read = realtek_mdio_read, +- .reg_write = realtek_mdio_write, +- .cache_type = REGCACHE_NONE, +- .disable_locking = true, + }; + + /** + * realtek_mdio_probe() - Probe a platform device for an MDIO-connected switch + * @mdiodev: mdio_device to probe on. + * +- * This function should be used as the .probe in an mdio_driver. It +- * initializes realtek_priv and read data from the device-tree node. The switch +- * is hard reset if a method is provided. It checks the switch chip ID and, +- * finally, a DSA switch is registered. ++ * This function should be used as the .probe in an mdio_driver. After ++ * calling the common probe function for both interfaces, it initializes the ++ * values specific for MDIO-connected devices. Finally, it calls a common ++ * function to register the DSA switch. + * + * Context: Can sleep. Takes and releases priv->map_lock. + * Return: Returns 0 on success, a negative error on failure. + */ + int realtek_mdio_probe(struct mdio_device *mdiodev) + { +- struct realtek_priv *priv; + struct device *dev = &mdiodev->dev; +- const struct realtek_variant *var; +- struct regmap_config rc; +- struct device_node *np; ++ struct realtek_priv *priv; + int ret; + +- var = of_device_get_match_data(dev); +- if (!var) +- return -EINVAL; +- +- priv = devm_kzalloc(&mdiodev->dev, +- size_add(sizeof(*priv), var->chip_data_sz), +- GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- mutex_init(&priv->map_lock); +- +- rc = realtek_mdio_regmap_config; +- rc.lock_arg = priv; +- priv->map = devm_regmap_init(dev, NULL, priv, &rc); +- if (IS_ERR(priv->map)) { +- ret = PTR_ERR(priv->map); +- dev_err(dev, "regmap init failed: %d\n", ret); +- return ret; +- } ++ priv = rtl83xx_probe(dev, &realtek_mdio_info); ++ if (IS_ERR(priv)) ++ return PTR_ERR(priv); + +- rc = realtek_mdio_nolock_regmap_config; +- priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); +- if (IS_ERR(priv->map_nolock)) { +- ret = PTR_ERR(priv->map_nolock); +- dev_err(dev, "regmap init failed: %d\n", ret); +- return ret; +- } +- +- priv->mdio_addr = mdiodev->addr; + priv->bus = mdiodev->bus; +- priv->dev = &mdiodev->dev; +- priv->chip_data = (void *)priv + sizeof(*priv); +- +- priv->variant = var; +- priv->ops = var->ops; +- ++ priv->mdio_addr = mdiodev->addr; + priv->write_reg_noack = realtek_mdio_write; ++ priv->ds_ops = priv->variant->ds_ops_mdio; + +- np = dev->of_node; +- +- dev_set_drvdata(dev, priv); +- +- /* TODO: if power is software controlled, set up any regulators here */ +- priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds"); +- +- priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); +- if (IS_ERR(priv->reset)) { +- dev_err(dev, "failed to get RESET GPIO\n"); +- return PTR_ERR(priv->reset); +- } +- +- if (priv->reset) { +- gpiod_set_value(priv->reset, 1); +- dev_dbg(dev, "asserted RESET\n"); +- msleep(REALTEK_HW_STOP_DELAY); +- gpiod_set_value(priv->reset, 0); +- msleep(REALTEK_HW_START_DELAY); +- dev_dbg(dev, "deasserted RESET\n"); +- } +- +- ret = priv->ops->detect(priv); +- if (ret) { +- dev_err(dev, "unable to detect switch\n"); +- return ret; +- } +- +- priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); +- if (!priv->ds) +- return -ENOMEM; +- +- priv->ds->dev = dev; +- priv->ds->num_ports = priv->num_ports; +- priv->ds->priv = priv; +- priv->ds->ops = var->ds_ops_mdio; +- +- ret = dsa_register_switch(priv->ds); ++ ret = rtl83xx_register_switch(priv); + if (ret) { +- dev_err(priv->dev, "unable to register switch ret = %d\n", ret); ++ rtl83xx_remove(priv); + return ret; + } + +@@ -253,8 +148,7 @@ EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe, + * @mdiodev: mdio_device to be removed. + * + * This function should be used as the .remove_new in an mdio_driver. First +- * it unregisters the DSA switch and cleans internal data. If a method is +- * provided, the hard reset is asserted to avoid traffic leakage. ++ * it unregisters the DSA switch and then it calls the common remove function. + * + * Context: Can sleep. + * Return: Nothing. +@@ -266,11 +160,9 @@ void realtek_mdio_remove(struct mdio_dev + if (!priv) + return; + +- dsa_unregister_switch(priv->ds); ++ rtl83xx_unregister_switch(priv); + +- /* leave the device reset asserted */ +- if (priv->reset) +- gpiod_set_value(priv->reset, 1); ++ rtl83xx_remove(priv); + } + EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, REALTEK_DSA); + +@@ -278,10 +170,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove + * realtek_mdio_shutdown() - Shutdown the driver of a MDIO-connected switch + * @mdiodev: mdio_device shutting down. + * +- * This function should be used as the .shutdown in an mdio_driver. It shuts +- * down the DSA switch and cleans the platform driver data, to prevent +- * realtek_mdio_remove() from running afterwards, which is possible if the +- * parent bus implements its own .shutdown() as .remove(). ++ * This function should be used as the .shutdown in a platform_driver. It calls ++ * the common shutdown function. + * + * Context: Can sleep. + * Return: Nothing. +@@ -293,9 +183,7 @@ void realtek_mdio_shutdown(struct mdio_d + if (!priv) + return; + +- dsa_switch_shutdown(priv->ds); +- +- dev_set_drvdata(&mdiodev->dev, NULL); ++ rtl83xx_shutdown(priv); + } + EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA); + +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -41,6 +41,7 @@ + + #include "realtek.h" + #include "realtek-smi.h" ++#include "rtl83xx.h" + + #define REALTEK_SMI_ACK_RETRY_COUNT 5 + +@@ -311,47 +312,6 @@ static int realtek_smi_read(void *ctx, u + return realtek_smi_read_reg(priv, reg, val); + } + +-static void realtek_smi_lock(void *ctx) +-{ +- struct realtek_priv *priv = ctx; +- +- mutex_lock(&priv->map_lock); +-} +- +-static void realtek_smi_unlock(void *ctx) +-{ +- struct realtek_priv *priv = ctx; +- +- mutex_unlock(&priv->map_lock); +-} +- +-static const struct regmap_config realtek_smi_regmap_config = { +- .reg_bits = 10, /* A4..A0 R4..R0 */ +- .val_bits = 16, +- .reg_stride = 1, +- /* PHY regs are at 0x8000 */ +- .max_register = 0xffff, +- .reg_format_endian = REGMAP_ENDIAN_BIG, +- .reg_read = realtek_smi_read, +- .reg_write = realtek_smi_write, +- .cache_type = REGCACHE_NONE, +- .lock = realtek_smi_lock, +- .unlock = realtek_smi_unlock, +-}; +- +-static const struct regmap_config realtek_smi_nolock_regmap_config = { +- .reg_bits = 10, /* A4..A0 R4..R0 */ +- .val_bits = 16, +- .reg_stride = 1, +- /* PHY regs are at 0x8000 */ +- .max_register = 0xffff, +- .reg_format_endian = REGMAP_ENDIAN_BIG, +- .reg_read = realtek_smi_read, +- .reg_write = realtek_smi_write, +- .cache_type = REGCACHE_NONE, +- .disable_locking = true, +-}; +- + static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) + { + struct realtek_priv *priv = bus->priv; +@@ -409,111 +369,56 @@ err_put_node: + return ret; + } + ++static const struct realtek_interface_info realtek_smi_info = { ++ .reg_read = realtek_smi_read, ++ .reg_write = realtek_smi_write, ++}; ++ + /** + * realtek_smi_probe() - Probe a platform device for an SMI-connected switch + * @pdev: platform_device to probe on. + * +- * This function should be used as the .probe in a platform_driver. It +- * initializes realtek_priv and read data from the device-tree node. The switch +- * is hard reset if a method is provided. It checks the switch chip ID and, +- * finally, a DSA switch is registered. ++ * This function should be used as the .probe in a platform_driver. After ++ * calling the common probe function for both interfaces, it initializes the ++ * values specific for SMI-connected devices. Finally, it calls a common ++ * function to register the DSA switch. + * + * Context: Can sleep. Takes and releases priv->map_lock. + * Return: Returns 0 on success, a negative error on failure. + */ + int realtek_smi_probe(struct platform_device *pdev) + { +- const struct realtek_variant *var; + struct device *dev = &pdev->dev; + struct realtek_priv *priv; +- struct regmap_config rc; +- struct device_node *np; + int ret; + +- var = of_device_get_match_data(dev); +- np = dev->of_node; +- +- priv = devm_kzalloc(dev, sizeof(*priv) + var->chip_data_sz, GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- priv->chip_data = (void *)priv + sizeof(*priv); +- +- mutex_init(&priv->map_lock); +- +- rc = realtek_smi_regmap_config; +- rc.lock_arg = priv; +- priv->map = devm_regmap_init(dev, NULL, priv, &rc); +- if (IS_ERR(priv->map)) { +- ret = PTR_ERR(priv->map); +- dev_err(dev, "regmap init failed: %d\n", ret); +- return ret; +- } +- +- rc = realtek_smi_nolock_regmap_config; +- priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); +- if (IS_ERR(priv->map_nolock)) { +- ret = PTR_ERR(priv->map_nolock); +- dev_err(dev, "regmap init failed: %d\n", ret); +- return ret; +- } +- +- /* Link forward and backward */ +- priv->dev = dev; +- priv->variant = var; +- priv->ops = var->ops; +- +- priv->setup_interface = realtek_smi_setup_mdio; +- priv->write_reg_noack = realtek_smi_write_reg_noack; +- +- dev_set_drvdata(dev, priv); +- spin_lock_init(&priv->lock); +- +- /* TODO: if power is software controlled, set up any regulators here */ +- +- priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); +- if (IS_ERR(priv->reset)) { +- dev_err(dev, "failed to get RESET GPIO\n"); +- return PTR_ERR(priv->reset); +- } +- if (priv->reset) { +- gpiod_set_value(priv->reset, 1); +- dev_dbg(dev, "asserted RESET\n"); +- msleep(REALTEK_HW_STOP_DELAY); +- gpiod_set_value(priv->reset, 0); +- msleep(REALTEK_HW_START_DELAY); +- dev_dbg(dev, "deasserted RESET\n"); +- } ++ priv = rtl83xx_probe(dev, &realtek_smi_info); ++ if (IS_ERR(priv)) ++ return PTR_ERR(priv); + + /* Fetch MDIO pins */ + priv->mdc = devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW); +- if (IS_ERR(priv->mdc)) ++ if (IS_ERR(priv->mdc)) { ++ rtl83xx_remove(priv); + return PTR_ERR(priv->mdc); ++ } ++ + priv->mdio = devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW); +- if (IS_ERR(priv->mdio)) ++ if (IS_ERR(priv->mdio)) { ++ rtl83xx_remove(priv); + return PTR_ERR(priv->mdio); +- +- priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds"); +- +- ret = priv->ops->detect(priv); +- if (ret) { +- dev_err(dev, "unable to detect switch\n"); +- return ret; + } + +- priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); +- if (!priv->ds) +- return -ENOMEM; +- +- priv->ds->dev = dev; +- priv->ds->num_ports = priv->num_ports; +- priv->ds->priv = priv; ++ priv->write_reg_noack = realtek_smi_write_reg_noack; ++ priv->setup_interface = realtek_smi_setup_mdio; ++ priv->ds_ops = priv->variant->ds_ops_smi; + +- priv->ds->ops = var->ds_ops_smi; +- ret = dsa_register_switch(priv->ds); ++ ret = rtl83xx_register_switch(priv); + if (ret) { +- dev_err_probe(dev, ret, "unable to register switch\n"); ++ rtl83xx_remove(priv); + return ret; + } ++ + return 0; + } + EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA); +@@ -523,8 +428,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, + * @pdev: platform_device to be removed. + * + * This function should be used as the .remove_new in a platform_driver. First +- * it unregisters the DSA switch and cleans internal data. If a method is +- * provided, the hard reset is asserted to avoid traffic leakage. ++ * it unregisters the DSA switch and cleans internal data. Finally, it calls ++ * the common remove function. + * + * Context: Can sleep. + * Return: Nothing. +@@ -536,13 +441,12 @@ void realtek_smi_remove(struct platform_ + if (!priv) + return; + +- dsa_unregister_switch(priv->ds); ++ rtl83xx_unregister_switch(priv); ++ + if (priv->slave_mii_bus) + of_node_put(priv->slave_mii_bus->dev.of_node); + +- /* leave the device reset asserted */ +- if (priv->reset) +- gpiod_set_value(priv->reset, 1); ++ rtl83xx_remove(priv); + } + EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); + +@@ -550,10 +454,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, + * realtek_smi_shutdown() - Shutdown the driver of a SMI-connected switch + * @pdev: platform_device shutting down. + * +- * This function should be used as the .shutdown in a platform_driver. It shuts +- * down the DSA switch and cleans the platform driver data, to prevent +- * realtek_smi_remove() from running afterwards, which is possible if the +- * parent bus implements its own .shutdown() as .remove(). ++ * This function should be used as the .shutdown in a platform_driver. It calls ++ * the common shutdown function. + * + * Context: Can sleep. + * Return: Nothing. +@@ -565,9 +467,7 @@ void realtek_smi_shutdown(struct platfor + if (!priv) + return; + +- dsa_switch_shutdown(priv->ds); +- +- platform_set_drvdata(pdev, NULL); ++ rtl83xx_shutdown(priv); + } + EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA); + +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -62,6 +62,7 @@ struct realtek_priv { + + spinlock_t lock; /* Locks around command writes */ + struct dsa_switch *ds; ++ const struct dsa_switch_ops *ds_ops; + struct irq_domain *irqdomain; + bool leds_disabled; + +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -103,6 +103,7 @@ + #include "realtek.h" + #include "realtek-smi.h" + #include "realtek-mdio.h" ++#include "rtl83xx.h" + + /* Family-specific data and limits */ + #define RTL8365MB_PHYADDRMAX 7 +@@ -691,7 +692,7 @@ static int rtl8365mb_phy_ocp_read(struct + u32 val; + int ret; + +- mutex_lock(&priv->map_lock); ++ rtl83xx_lock(priv); + + ret = rtl8365mb_phy_poll_busy(priv); + if (ret) +@@ -724,7 +725,7 @@ static int rtl8365mb_phy_ocp_read(struct + *data = val & 0xFFFF; + + out: +- mutex_unlock(&priv->map_lock); ++ rtl83xx_unlock(priv); + + return ret; + } +@@ -735,7 +736,7 @@ static int rtl8365mb_phy_ocp_write(struc + u32 val; + int ret; + +- mutex_lock(&priv->map_lock); ++ rtl83xx_lock(priv); + + ret = rtl8365mb_phy_poll_busy(priv); + if (ret) +@@ -766,7 +767,7 @@ static int rtl8365mb_phy_ocp_write(struc + goto out; + + out: +- mutex_unlock(&priv->map_lock); ++ rtl83xx_unlock(priv); + + return 0; + } +--- a/drivers/net/dsa/realtek/rtl8366rb.c ++++ b/drivers/net/dsa/realtek/rtl8366rb.c +@@ -24,6 +24,7 @@ + #include "realtek.h" + #include "realtek-smi.h" + #include "realtek-mdio.h" ++#include "rtl83xx.h" + + #define RTL8366RB_PORT_NUM_CPU 5 + #define RTL8366RB_NUM_PORTS 6 +@@ -1634,7 +1635,7 @@ static int rtl8366rb_phy_read(struct rea + if (phy > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + +- mutex_lock(&priv->map_lock); ++ rtl83xx_lock(priv); + + ret = regmap_write(priv->map_nolock, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_READ); +@@ -1662,7 +1663,7 @@ static int rtl8366rb_phy_read(struct rea + phy, regnum, reg, val); + + out: +- mutex_unlock(&priv->map_lock); ++ rtl83xx_unlock(priv); + + return ret; + } +@@ -1676,7 +1677,7 @@ static int rtl8366rb_phy_write(struct re + if (phy > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + +- mutex_lock(&priv->map_lock); ++ rtl83xx_lock(priv); + + ret = regmap_write(priv->map_nolock, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_WRITE); +@@ -1693,7 +1694,7 @@ static int rtl8366rb_phy_write(struct re + goto out; + + out: +- mutex_unlock(&priv->map_lock); ++ rtl83xx_unlock(priv); + + return ret; + } +--- /dev/null ++++ b/drivers/net/dsa/realtek/rtl83xx.c +@@ -0,0 +1,236 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++ ++#include ++#include ++#include /* krnl 6.1 only */ ++ ++#include "realtek.h" ++#include "rtl83xx.h" ++ ++/** ++ * rtl83xx_lock() - Locks the mutex used by regmaps ++ * @ctx: realtek_priv pointer ++ * ++ * This function is passed to regmap to be used as the lock function. ++ * It is also used externally to block regmap before executing multiple ++ * operations that must happen in sequence (which will use ++ * realtek_priv.map_nolock instead). ++ * ++ * Context: Can sleep. Holds priv->map_lock lock. ++ * Return: nothing ++ */ ++void rtl83xx_lock(void *ctx) ++{ ++ struct realtek_priv *priv = ctx; ++ ++ mutex_lock(&priv->map_lock); ++} ++EXPORT_SYMBOL_NS_GPL(rtl83xx_lock, REALTEK_DSA); ++ ++/** ++ * rtl83xx_unlock() - Unlocks the mutex used by regmaps ++ * @ctx: realtek_priv pointer ++ * ++ * This function unlocks the lock acquired by rtl83xx_lock. ++ * ++ * Context: Releases priv->map_lock lock. ++ * Return: nothing ++ */ ++void rtl83xx_unlock(void *ctx) ++{ ++ struct realtek_priv *priv = ctx; ++ ++ mutex_unlock(&priv->map_lock); ++} ++EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA); ++ ++/** ++ * rtl83xx_probe() - probe a Realtek switch ++ * @dev: the device being probed ++ * @interface_info: specific management interface info. ++ * ++ * This function initializes realtek_priv and reads data from the device tree ++ * node. The switch is hard resetted if a method is provided. ++ * ++ * Context: Can sleep. ++ * Return: Pointer to the realtek_priv or ERR_PTR() in case of failure. ++ * ++ * The realtek_priv pointer does not need to be freed as it is controlled by ++ * devres. ++ */ ++struct realtek_priv * ++rtl83xx_probe(struct device *dev, ++ const struct realtek_interface_info *interface_info) ++{ ++ const struct realtek_variant *var; ++ struct realtek_priv *priv; ++ struct regmap_config rc = { ++ .reg_bits = 10, /* A4..A0 R4..R0 */ ++ .val_bits = 16, ++ .reg_stride = 1, ++ .max_register = 0xffff, ++ .reg_format_endian = REGMAP_ENDIAN_BIG, ++ .reg_read = interface_info->reg_read, ++ .reg_write = interface_info->reg_write, ++ .cache_type = REGCACHE_NONE, ++ .lock = rtl83xx_lock, ++ .unlock = rtl83xx_unlock, ++ }; ++ int ret; ++ ++ var = of_device_get_match_data(dev); ++ if (!var) ++ return ERR_PTR(-EINVAL); ++ ++ priv = devm_kzalloc(dev, size_add(sizeof(*priv), var->chip_data_sz), ++ GFP_KERNEL); ++ if (!priv) ++ return ERR_PTR(-ENOMEM); ++ ++ mutex_init(&priv->map_lock); ++ ++ rc.lock_arg = priv; ++ priv->map = devm_regmap_init(dev, NULL, priv, &rc); ++ if (IS_ERR(priv->map)) { ++ ret = PTR_ERR(priv->map); ++ dev_err(dev, "regmap init failed: %d\n", ret); ++ return ERR_PTR(ret); ++ } ++ ++ rc.disable_locking = true; ++ priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); ++ if (IS_ERR(priv->map_nolock)) { ++ ret = PTR_ERR(priv->map_nolock); ++ dev_err(dev, "regmap init failed: %d\n", ret); ++ return ERR_PTR(ret); ++ } ++ ++ /* Link forward and backward */ ++ priv->dev = dev; ++ priv->variant = var; ++ priv->ops = var->ops; ++ priv->chip_data = (void *)priv + sizeof(*priv); ++ ++ spin_lock_init(&priv->lock); ++ ++ priv->leds_disabled = of_property_read_bool(dev->of_node, ++ "realtek,disable-leds"); ++ ++ /* TODO: if power is software controlled, set up any regulators here */ ++ priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); ++ if (IS_ERR(priv->reset)) { ++ dev_err(dev, "failed to get RESET GPIO\n"); ++ return ERR_CAST(priv->reset); ++ } ++ ++ dev_set_drvdata(dev, priv); ++ ++ if (priv->reset) { ++ gpiod_set_value(priv->reset, 1); ++ dev_dbg(dev, "asserted RESET\n"); ++ msleep(REALTEK_HW_STOP_DELAY); ++ gpiod_set_value(priv->reset, 0); ++ msleep(REALTEK_HW_START_DELAY); ++ dev_dbg(dev, "deasserted RESET\n"); ++ } ++ ++ return priv; ++} ++EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REALTEK_DSA); ++ ++/** ++ * rtl83xx_register_switch() - detects and register a switch ++ * @priv: realtek_priv pointer ++ * ++ * This function first checks the switch chip ID and register a DSA ++ * switch. ++ * ++ * Context: Can sleep. Takes and releases priv->map_lock. ++ * Return: 0 on success, negative value for failure. ++ */ ++int rtl83xx_register_switch(struct realtek_priv *priv) ++{ ++ struct dsa_switch *ds; ++ int ret; ++ ++ ret = priv->ops->detect(priv); ++ if (ret) { ++ dev_err_probe(priv->dev, ret, "unable to detect switch\n"); ++ return ret; ++ } ++ ++ ds = devm_kzalloc(priv->dev, sizeof(*ds), GFP_KERNEL); ++ if (!ds) ++ return -ENOMEM; ++ ++ ds->priv = priv; ++ ds->dev = priv->dev; ++ ds->ops = priv->ds_ops; ++ ds->num_ports = priv->num_ports; ++ priv->ds = ds; ++ ++ ret = dsa_register_switch(ds); ++ if (ret) { ++ dev_err_probe(priv->dev, ret, "unable to register switch\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, REALTEK_DSA); ++ ++/** ++ * rtl83xx_unregister_switch() - unregister a switch ++ * @priv: realtek_priv pointer ++ * ++ * This function unregister a DSA switch. ++ * ++ * Context: Can sleep. ++ * Return: Nothing. ++ */ ++void rtl83xx_unregister_switch(struct realtek_priv *priv) ++{ ++ dsa_unregister_switch(priv->ds); ++} ++EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA); ++ ++/** ++ * rtl83xx_shutdown() - shutdown a switch ++ * @priv: realtek_priv pointer ++ * ++ * This function shuts down the DSA switch and cleans the platform driver data, ++ * to prevent realtek_{smi,mdio}_remove() from running afterwards, which is ++ * possible if the parent bus implements its own .shutdown() as .remove(). ++ * ++ * Context: Can sleep. ++ * Return: Nothing. ++ */ ++void rtl83xx_shutdown(struct realtek_priv *priv) ++{ ++ dsa_switch_shutdown(priv->ds); ++ ++ dev_set_drvdata(priv->dev, NULL); ++} ++EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA); ++ ++/** ++ * rtl83xx_remove() - Cleanup a realtek switch driver ++ * @priv: realtek_priv pointer ++ * ++ * If a method is provided, this function asserts the hard reset of the switch ++ * in order to avoid leaking traffic when the driver is gone. ++ * ++ * Context: Might sleep if priv->gdev->chip->can_sleep. ++ * Return: nothing ++ */ ++void rtl83xx_remove(struct realtek_priv *priv) ++{ ++ /* leave the device reset asserted */ ++ if (priv->reset) ++ gpiod_set_value(priv->reset, 1); ++} ++EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); ++ ++MODULE_AUTHOR("Luiz Angelo Daros de Luca "); ++MODULE_DESCRIPTION("Realtek DSA switches common module"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/net/dsa/realtek/rtl83xx.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++ ++#ifndef _RTL83XX_H ++#define _RTL83XX_H ++ ++struct realtek_interface_info { ++ int (*reg_read)(void *ctx, u32 reg, u32 *val); ++ int (*reg_write)(void *ctx, u32 reg, u32 val); ++}; ++ ++void rtl83xx_lock(void *ctx); ++void rtl83xx_unlock(void *ctx); ++struct realtek_priv * ++rtl83xx_probe(struct device *dev, ++ const struct realtek_interface_info *interface_info); ++int rtl83xx_register_switch(struct realtek_priv *priv); ++void rtl83xx_unregister_switch(struct realtek_priv *priv); ++void rtl83xx_shutdown(struct realtek_priv *priv); ++void rtl83xx_remove(struct realtek_priv *priv); ++ ++#endif /* _RTL83XX_H */ diff --git a/target/linux/generic/backport-6.6/896-v6.9-0006-net-dsa-realtek-merge-rtl83xx-and-interface-modules-.patch b/target/linux/generic/backport-6.6/896-v6.9-0006-net-dsa-realtek-merge-rtl83xx-and-interface-modules-.patch new file mode 100644 index 0000000000..2754b62319 --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0006-net-dsa-realtek-merge-rtl83xx-and-interface-modules-.patch @@ -0,0 +1,93 @@ +From 98b75c1c149c653ad11a440636213eb070325158 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:42 -0300 +Subject: net: dsa: realtek: merge rtl83xx and interface + modules into realtek_dsa + +Since rtl83xx and realtek-{smi,mdio} are always loaded together, +we can optimize resource usage by consolidating them into a single +module. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/Kconfig | 4 ++-- + drivers/net/dsa/realtek/Makefile | 11 +++++++++-- + drivers/net/dsa/realtek/realtek-mdio.c | 5 ----- + drivers/net/dsa/realtek/realtek-smi.c | 5 ----- + drivers/net/dsa/realtek/rtl83xx.c | 1 + + 5 files changed, 12 insertions(+), 14 deletions(-) + +--- a/drivers/net/dsa/realtek/Kconfig ++++ b/drivers/net/dsa/realtek/Kconfig +@@ -16,14 +16,14 @@ menuconfig NET_DSA_REALTEK + if NET_DSA_REALTEK + + config NET_DSA_REALTEK_MDIO +- tristate "Realtek MDIO interface support" ++ bool "Realtek MDIO interface support" + depends on OF + help + Select to enable support for registering switches configured + through MDIO. + + config NET_DSA_REALTEK_SMI +- tristate "Realtek SMI interface support" ++ bool "Realtek SMI interface support" + depends on OF + help + Select to enable support for registering switches connected +--- a/drivers/net/dsa/realtek/Makefile ++++ b/drivers/net/dsa/realtek/Makefile +@@ -1,8 +1,15 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_NET_DSA_REALTEK) += realtek_dsa.o + realtek_dsa-objs := rtl83xx.o +-obj-$(CONFIG_NET_DSA_REALTEK_MDIO) += realtek-mdio.o +-obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o ++ ++ifdef CONFIG_NET_DSA_REALTEK_MDIO ++realtek_dsa-objs += realtek-mdio.o ++endif ++ ++ifdef CONFIG_NET_DSA_REALTEK_SMI ++realtek_dsa-objs += realtek-smi.o ++endif ++ + obj-$(CONFIG_NET_DSA_REALTEK_RTL8366RB) += rtl8366.o + rtl8366-objs := rtl8366-core.o rtl8366rb.o + obj-$(CONFIG_NET_DSA_REALTEK_RTL8365MB) += rtl8365mb.o +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -186,8 +186,3 @@ void realtek_mdio_shutdown(struct mdio_d + rtl83xx_shutdown(priv); + } + EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA); +- +-MODULE_AUTHOR("Luiz Angelo Daros de Luca "); +-MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface"); +-MODULE_LICENSE("GPL"); +-MODULE_IMPORT_NS(REALTEK_DSA); +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -470,8 +470,3 @@ void realtek_smi_shutdown(struct platfor + rtl83xx_shutdown(priv); + } + EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA); +- +-MODULE_AUTHOR("Linus Walleij "); +-MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface"); +-MODULE_LICENSE("GPL"); +-MODULE_IMPORT_NS(REALTEK_DSA); +--- a/drivers/net/dsa/realtek/rtl83xx.c ++++ b/drivers/net/dsa/realtek/rtl83xx.c +@@ -232,5 +232,6 @@ void rtl83xx_remove(struct realtek_priv + EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); + + MODULE_AUTHOR("Luiz Angelo Daros de Luca "); ++MODULE_AUTHOR("Linus Walleij "); + MODULE_DESCRIPTION("Realtek DSA switches common module"); + MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.6/896-v6.9-0007-net-dsa-realtek-get-internal-MDIO-node-by-name.patch b/target/linux/generic/backport-6.6/896-v6.9-0007-net-dsa-realtek-get-internal-MDIO-node-by-name.patch new file mode 100644 index 0000000000..423e7500d7 --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0007-net-dsa-realtek-get-internal-MDIO-node-by-name.patch @@ -0,0 +1,34 @@ +From 8685c98d45c54346caf005de69988e13c731c533 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:43 -0300 +Subject: net: dsa: realtek: get internal MDIO node by name + +The binding docs requires for SMI-connected devices that the switch +must have a child node named "mdio" and with a compatible string of +"realtek,smi-mdio". Meanwile, for MDIO-connected switches, the binding +docs only requires a child node named "mdio". + +This patch changes the driver to use the common denominator for both +interfaces, looking for the MDIO node by name, ignoring the compatible +string. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/realtek-smi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -333,7 +333,7 @@ static int realtek_smi_setup_mdio(struct + struct device_node *mdio_np; + int ret; + +- mdio_np = of_get_compatible_child(priv->dev->of_node, "realtek,smi-mdio"); ++ mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio"); + if (!mdio_np) { + dev_err(priv->dev, "no MDIO bus node\n"); + return -ENODEV; diff --git a/target/linux/generic/backport-6.6/896-v6.9-0008-net-dsa-realtek-clean-user_mii_bus-setup.patch b/target/linux/generic/backport-6.6/896-v6.9-0008-net-dsa-realtek-clean-user_mii_bus-setup.patch new file mode 100644 index 0000000000..1958c7feb4 --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0008-net-dsa-realtek-clean-user_mii_bus-setup.patch @@ -0,0 +1,83 @@ +From 68c66d8d8a19088967a0ab6bb98cb5ecc80ca0be Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:44 -0300 +Subject: net: dsa: realtek: clean slave_mii_bus setup + +Remove the line assigning dev.of_node in mdio_bus as subsequent +of_mdiobus_register will always overwrite it. + +As discussed in [1], allow the DSA core to be simplified, by not +assigning ds->slave_mii_bus when the MDIO bus is described in OF, as it +is unnecessary. + +Since commit 3b73a7b8ec38 ("net: mdio_bus: add refcounting for fwnodes +to mdiobus"), we can put the "mdio" node just after the MDIO bus +registration. + +[1] https://lkml.kernel.org/netdev/20231213120656.x46fyad6ls7sqyzv@skbuf/T/#u + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Vladimir Oltean +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/realtek-smi.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -331,7 +331,7 @@ static int realtek_smi_setup_mdio(struct + { + struct realtek_priv *priv = ds->priv; + struct device_node *mdio_np; +- int ret; ++ int ret = 0; + + mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio"); + if (!mdio_np) { +@@ -344,15 +344,14 @@ static int realtek_smi_setup_mdio(struct + ret = -ENOMEM; + goto err_put_node; + } ++ + priv->slave_mii_bus->priv = priv; + priv->slave_mii_bus->name = "SMI slave MII"; + priv->slave_mii_bus->read = realtek_smi_mdio_read; + priv->slave_mii_bus->write = realtek_smi_mdio_write; + snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d", + ds->index); +- priv->slave_mii_bus->dev.of_node = mdio_np; + priv->slave_mii_bus->parent = priv->dev; +- ds->slave_mii_bus = priv->slave_mii_bus; + + ret = devm_of_mdiobus_register(priv->dev, priv->slave_mii_bus, mdio_np); + if (ret) { +@@ -361,8 +360,6 @@ static int realtek_smi_setup_mdio(struct + goto err_put_node; + } + +- return 0; +- + err_put_node: + of_node_put(mdio_np); + +@@ -428,8 +425,7 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, + * @pdev: platform_device to be removed. + * + * This function should be used as the .remove_new in a platform_driver. First +- * it unregisters the DSA switch and cleans internal data. Finally, it calls +- * the common remove function. ++ * it unregisters the DSA switch and then it calls the common remove function. + * + * Context: Can sleep. + * Return: Nothing. +@@ -443,9 +439,6 @@ void realtek_smi_remove(struct platform_ + + rtl83xx_unregister_switch(priv); + +- if (priv->slave_mii_bus) +- of_node_put(priv->slave_mii_bus->dev.of_node); +- + rtl83xx_remove(priv); + } + EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); diff --git a/target/linux/generic/backport-6.6/896-v6.9-0009-net-dsa-realtek-migrate-user_mii_bus-setup-to-realte.patch b/target/linux/generic/backport-6.6/896-v6.9-0009-net-dsa-realtek-migrate-user_mii_bus-setup-to-realte.patch new file mode 100644 index 0000000000..50e96d7eef --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0009-net-dsa-realtek-migrate-user_mii_bus-setup-to-realte.patch @@ -0,0 +1,198 @@ +From b4bd77971f3c290c4694ed710cc6967593b10bc2 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:45 -0300 +Subject: net: dsa: realtek: migrate slave_mii_bus setup to + realtek_dsa + +In the user MDIO driver, despite numerous references to SMI, including +its compatible string, there's nothing inherently specific about the SMI +interface in the user MDIO bus. Consequently, the code has been migrated +to the rtl83xx module. All references to SMI have been eliminated. + +The MDIO bus id was changed from Realtek- to the switch +devname suffixed with :slave_mii, giving more information about the bus +it is referencing. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/realtek-smi.c | 57 +--------------------- + drivers/net/dsa/realtek/rtl83xx.c | 68 +++++++++++++++++++++++++++ + drivers/net/dsa/realtek/rtl83xx.h | 1 + + 3 files changed, 70 insertions(+), 56 deletions(-) + +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -31,7 +31,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -312,60 +311,6 @@ static int realtek_smi_read(void *ctx, u + return realtek_smi_read_reg(priv, reg, val); + } + +-static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) +-{ +- struct realtek_priv *priv = bus->priv; +- +- return priv->ops->phy_read(priv, addr, regnum); +-} +- +-static int realtek_smi_mdio_write(struct mii_bus *bus, int addr, int regnum, +- u16 val) +-{ +- struct realtek_priv *priv = bus->priv; +- +- return priv->ops->phy_write(priv, addr, regnum, val); +-} +- +-static int realtek_smi_setup_mdio(struct dsa_switch *ds) +-{ +- struct realtek_priv *priv = ds->priv; +- struct device_node *mdio_np; +- int ret = 0; +- +- mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio"); +- if (!mdio_np) { +- dev_err(priv->dev, "no MDIO bus node\n"); +- return -ENODEV; +- } +- +- priv->slave_mii_bus = devm_mdiobus_alloc(priv->dev); +- if (!priv->slave_mii_bus) { +- ret = -ENOMEM; +- goto err_put_node; +- } +- +- priv->slave_mii_bus->priv = priv; +- priv->slave_mii_bus->name = "SMI slave MII"; +- priv->slave_mii_bus->read = realtek_smi_mdio_read; +- priv->slave_mii_bus->write = realtek_smi_mdio_write; +- snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d", +- ds->index); +- priv->slave_mii_bus->parent = priv->dev; +- +- ret = devm_of_mdiobus_register(priv->dev, priv->slave_mii_bus, mdio_np); +- if (ret) { +- dev_err(priv->dev, "unable to register MDIO bus %s\n", +- priv->slave_mii_bus->id); +- goto err_put_node; +- } +- +-err_put_node: +- of_node_put(mdio_np); +- +- return ret; +-} +- + static const struct realtek_interface_info realtek_smi_info = { + .reg_read = realtek_smi_read, + .reg_write = realtek_smi_write, +@@ -407,7 +352,7 @@ int realtek_smi_probe(struct platform_de + } + + priv->write_reg_noack = realtek_smi_write_reg_noack; +- priv->setup_interface = realtek_smi_setup_mdio; ++ priv->setup_interface = rtl83xx_setup_user_mdio; + priv->ds_ops = priv->variant->ds_ops_smi; + + ret = rtl83xx_register_switch(priv); +--- a/drivers/net/dsa/realtek/rtl83xx.c ++++ b/drivers/net/dsa/realtek/rtl83xx.c +@@ -3,6 +3,7 @@ + #include + #include + #include /* krnl 6.1 only */ ++#include + + #include "realtek.h" + #include "rtl83xx.h" +@@ -44,6 +45,73 @@ void rtl83xx_unlock(void *ctx) + } + EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA); + ++static int rtl83xx_user_mdio_read(struct mii_bus *bus, int addr, int regnum) ++{ ++ struct realtek_priv *priv = bus->priv; ++ ++ return priv->ops->phy_read(priv, addr, regnum); ++} ++ ++static int rtl83xx_user_mdio_write(struct mii_bus *bus, int addr, int regnum, ++ u16 val) ++{ ++ struct realtek_priv *priv = bus->priv; ++ ++ return priv->ops->phy_write(priv, addr, regnum, val); ++} ++ ++/** ++ * rtl83xx_setup_user_mdio() - register the user mii bus driver ++ * @ds: DSA switch associated with this slave_mii_bus ++ * ++ * Registers the MDIO bus for built-in Ethernet PHYs, and associates it with ++ * the mandatory 'mdio' child OF node of the switch. ++ * ++ * Context: Can sleep. ++ * Return: 0 on success, negative value for failure. ++ */ ++int rtl83xx_setup_user_mdio(struct dsa_switch *ds) ++{ ++ struct realtek_priv *priv = ds->priv; ++ struct device_node *mdio_np; ++ struct mii_bus *bus; ++ int ret = 0; ++ ++ mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio"); ++ if (!mdio_np) { ++ dev_err(priv->dev, "no MDIO bus node\n"); ++ return -ENODEV; ++ } ++ ++ bus = devm_mdiobus_alloc(priv->dev); ++ if (!bus) { ++ ret = -ENOMEM; ++ goto err_put_node; ++ } ++ ++ bus->priv = priv; ++ bus->name = "Realtek user MII"; ++ bus->read = rtl83xx_user_mdio_read; ++ bus->write = rtl83xx_user_mdio_write; ++ snprintf(bus->id, MII_BUS_ID_SIZE, "%s:slave_mii", dev_name(priv->dev)); ++ bus->parent = priv->dev; ++ ++ ret = devm_of_mdiobus_register(priv->dev, bus, mdio_np); ++ if (ret) { ++ dev_err(priv->dev, "unable to register MDIO bus %s\n", ++ bus->id); ++ goto err_put_node; ++ } ++ ++ priv->slave_mii_bus = bus; ++ ++err_put_node: ++ of_node_put(mdio_np); ++ ++ return ret; ++} ++EXPORT_SYMBOL_NS_GPL(rtl83xx_setup_user_mdio, REALTEK_DSA); ++ + /** + * rtl83xx_probe() - probe a Realtek switch + * @dev: the device being probed +--- a/drivers/net/dsa/realtek/rtl83xx.h ++++ b/drivers/net/dsa/realtek/rtl83xx.h +@@ -10,6 +10,7 @@ struct realtek_interface_info { + + void rtl83xx_lock(void *ctx); + void rtl83xx_unlock(void *ctx); ++int rtl83xx_setup_user_mdio(struct dsa_switch *ds); + struct realtek_priv * + rtl83xx_probe(struct device *dev, + const struct realtek_interface_info *interface_info); diff --git a/target/linux/generic/backport-6.6/896-v6.9-0010-net-dsa-realtek-use-the-same-mii-bus-driver-for-both.patch b/target/linux/generic/backport-6.6/896-v6.9-0010-net-dsa-realtek-use-the-same-mii-bus-driver-for-both.patch new file mode 100644 index 0000000000..b50a33590b --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0010-net-dsa-realtek-use-the-same-mii-bus-driver-for-both.patch @@ -0,0 +1,261 @@ +From bba140a566ed075304c49c52ab32c0016cab624a Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:46 -0300 +Subject: net: dsa: realtek: use the same mii bus driver for + both interfaces + +The realtek-mdio will now use this driver instead of the generic DSA +driver ("dsa user smi"), which should not be used with OF[1]. + +With a single ds_ops for both interfaces, the ds_ops in realtek_priv is +no longer necessary. Now, the realtek_variant.ds_ops can be used +directly. + +The realtek_priv.setup_interface() has been removed as we can directly +call the new common function. + +[1] https://lkml.kernel.org/netdev/20220630200423.tieprdu5fpabflj7@bang-olufsen.dk/T/ + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Vladimir Oltean +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/realtek-mdio.c | 1 - + drivers/net/dsa/realtek/realtek-smi.c | 2 - + drivers/net/dsa/realtek/realtek.h | 5 +-- + drivers/net/dsa/realtek/rtl8365mb.c | 49 +++--------------------- + drivers/net/dsa/realtek/rtl8366rb.c | 52 +++----------------------- + drivers/net/dsa/realtek/rtl83xx.c | 2 +- + 6 files changed, 14 insertions(+), 97 deletions(-) + +--- a/drivers/net/dsa/realtek/realtek-mdio.c ++++ b/drivers/net/dsa/realtek/realtek-mdio.c +@@ -131,7 +131,6 @@ int realtek_mdio_probe(struct mdio_devic + priv->bus = mdiodev->bus; + priv->mdio_addr = mdiodev->addr; + priv->write_reg_noack = realtek_mdio_write; +- priv->ds_ops = priv->variant->ds_ops_mdio; + + ret = rtl83xx_register_switch(priv); + if (ret) { +--- a/drivers/net/dsa/realtek/realtek-smi.c ++++ b/drivers/net/dsa/realtek/realtek-smi.c +@@ -352,8 +352,6 @@ int realtek_smi_probe(struct platform_de + } + + priv->write_reg_noack = realtek_smi_write_reg_noack; +- priv->setup_interface = rtl83xx_setup_user_mdio; +- priv->ds_ops = priv->variant->ds_ops_smi; + + ret = rtl83xx_register_switch(priv); + if (ret) { +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -62,7 +62,6 @@ struct realtek_priv { + + spinlock_t lock; /* Locks around command writes */ + struct dsa_switch *ds; +- const struct dsa_switch_ops *ds_ops; + struct irq_domain *irqdomain; + bool leds_disabled; + +@@ -73,7 +72,6 @@ struct realtek_priv { + struct rtl8366_mib_counter *mib_counters; + + const struct realtek_ops *ops; +- int (*setup_interface)(struct dsa_switch *ds); + int (*write_reg_noack)(void *ctx, u32 addr, u32 data); + + int vlan_enabled; +@@ -115,8 +113,7 @@ struct realtek_ops { + }; + + struct realtek_variant { +- const struct dsa_switch_ops *ds_ops_smi; +- const struct dsa_switch_ops *ds_ops_mdio; ++ const struct dsa_switch_ops *ds_ops; + const struct realtek_ops *ops; + unsigned int clk_delay; + u8 cmd_read; +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -828,17 +828,6 @@ static int rtl8365mb_phy_write(struct re + return 0; + } + +-static int rtl8365mb_dsa_phy_read(struct dsa_switch *ds, int phy, int regnum) +-{ +- return rtl8365mb_phy_read(ds->priv, phy, regnum); +-} +- +-static int rtl8365mb_dsa_phy_write(struct dsa_switch *ds, int phy, int regnum, +- u16 val) +-{ +- return rtl8365mb_phy_write(ds->priv, phy, regnum, val); +-} +- + static const struct rtl8365mb_extint * + rtl8365mb_get_port_extint(struct realtek_priv *priv, int port) + { +@@ -2018,12 +2007,10 @@ static int rtl8365mb_setup(struct dsa_sw + if (ret) + goto out_teardown_irq; + +- if (priv->setup_interface) { +- ret = priv->setup_interface(ds); +- if (ret) { +- dev_err(priv->dev, "could not set up MDIO bus\n"); +- goto out_teardown_irq; +- } ++ ret = rtl83xx_setup_user_mdio(ds); ++ if (ret) { ++ dev_err(priv->dev, "could not set up MDIO bus\n"); ++ goto out_teardown_irq; + } + + /* Start statistics counter polling */ +@@ -2117,28 +2104,7 @@ static int rtl8365mb_detect(struct realt + return 0; + } + +-static const struct dsa_switch_ops rtl8365mb_switch_ops_smi = { +- .get_tag_protocol = rtl8365mb_get_tag_protocol, +- .change_tag_protocol = rtl8365mb_change_tag_protocol, +- .setup = rtl8365mb_setup, +- .teardown = rtl8365mb_teardown, +- .phylink_get_caps = rtl8365mb_phylink_get_caps, +- .phylink_mac_config = rtl8365mb_phylink_mac_config, +- .phylink_mac_link_down = rtl8365mb_phylink_mac_link_down, +- .phylink_mac_link_up = rtl8365mb_phylink_mac_link_up, +- .port_stp_state_set = rtl8365mb_port_stp_state_set, +- .get_strings = rtl8365mb_get_strings, +- .get_ethtool_stats = rtl8365mb_get_ethtool_stats, +- .get_sset_count = rtl8365mb_get_sset_count, +- .get_eth_phy_stats = rtl8365mb_get_phy_stats, +- .get_eth_mac_stats = rtl8365mb_get_mac_stats, +- .get_eth_ctrl_stats = rtl8365mb_get_ctrl_stats, +- .get_stats64 = rtl8365mb_get_stats64, +- .port_change_mtu = rtl8365mb_port_change_mtu, +- .port_max_mtu = rtl8365mb_port_max_mtu, +-}; +- +-static const struct dsa_switch_ops rtl8365mb_switch_ops_mdio = { ++static const struct dsa_switch_ops rtl8365mb_switch_ops = { + .get_tag_protocol = rtl8365mb_get_tag_protocol, + .change_tag_protocol = rtl8365mb_change_tag_protocol, + .setup = rtl8365mb_setup, +@@ -2147,8 +2113,6 @@ static const struct dsa_switch_ops rtl83 + .phylink_mac_config = rtl8365mb_phylink_mac_config, + .phylink_mac_link_down = rtl8365mb_phylink_mac_link_down, + .phylink_mac_link_up = rtl8365mb_phylink_mac_link_up, +- .phy_read = rtl8365mb_dsa_phy_read, +- .phy_write = rtl8365mb_dsa_phy_write, + .port_stp_state_set = rtl8365mb_port_stp_state_set, + .get_strings = rtl8365mb_get_strings, + .get_ethtool_stats = rtl8365mb_get_ethtool_stats, +@@ -2168,8 +2132,7 @@ static const struct realtek_ops rtl8365m + }; + + const struct realtek_variant rtl8365mb_variant = { +- .ds_ops_smi = &rtl8365mb_switch_ops_smi, +- .ds_ops_mdio = &rtl8365mb_switch_ops_mdio, ++ .ds_ops = &rtl8365mb_switch_ops, + .ops = &rtl8365mb_ops, + .clk_delay = 10, + .cmd_read = 0xb9, +--- a/drivers/net/dsa/realtek/rtl8366rb.c ++++ b/drivers/net/dsa/realtek/rtl8366rb.c +@@ -1035,12 +1035,10 @@ static int rtl8366rb_setup(struct dsa_sw + if (ret) + dev_info(priv->dev, "no interrupt support\n"); + +- if (priv->setup_interface) { +- ret = priv->setup_interface(ds); +- if (ret) { +- dev_err(priv->dev, "could not set up MDIO bus\n"); +- return -ENODEV; +- } ++ ret = rtl83xx_setup_user_mdio(ds); ++ if (ret) { ++ dev_err(priv->dev, "could not set up MDIO bus\n"); ++ return -ENODEV; + } + + return 0; +@@ -1699,17 +1697,6 @@ out: + return ret; + } + +-static int rtl8366rb_dsa_phy_read(struct dsa_switch *ds, int phy, int regnum) +-{ +- return rtl8366rb_phy_read(ds->priv, phy, regnum); +-} +- +-static int rtl8366rb_dsa_phy_write(struct dsa_switch *ds, int phy, int regnum, +- u16 val) +-{ +- return rtl8366rb_phy_write(ds->priv, phy, regnum, val); +-} +- + static int rtl8366rb_reset_chip(struct realtek_priv *priv) + { + int timeout = 10; +@@ -1775,35 +1762,9 @@ static int rtl8366rb_detect(struct realt + return 0; + } + +-static const struct dsa_switch_ops rtl8366rb_switch_ops_smi = { +- .get_tag_protocol = rtl8366_get_tag_protocol, +- .setup = rtl8366rb_setup, +- .phylink_get_caps = rtl8366rb_phylink_get_caps, +- .phylink_mac_link_up = rtl8366rb_mac_link_up, +- .phylink_mac_link_down = rtl8366rb_mac_link_down, +- .get_strings = rtl8366_get_strings, +- .get_ethtool_stats = rtl8366_get_ethtool_stats, +- .get_sset_count = rtl8366_get_sset_count, +- .port_bridge_join = rtl8366rb_port_bridge_join, +- .port_bridge_leave = rtl8366rb_port_bridge_leave, +- .port_vlan_filtering = rtl8366rb_vlan_filtering, +- .port_vlan_add = rtl8366_vlan_add, +- .port_vlan_del = rtl8366_vlan_del, +- .port_enable = rtl8366rb_port_enable, +- .port_disable = rtl8366rb_port_disable, +- .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, +- .port_bridge_flags = rtl8366rb_port_bridge_flags, +- .port_stp_state_set = rtl8366rb_port_stp_state_set, +- .port_fast_age = rtl8366rb_port_fast_age, +- .port_change_mtu = rtl8366rb_change_mtu, +- .port_max_mtu = rtl8366rb_max_mtu, +-}; +- +-static const struct dsa_switch_ops rtl8366rb_switch_ops_mdio = { ++static const struct dsa_switch_ops rtl8366rb_switch_ops = { + .get_tag_protocol = rtl8366_get_tag_protocol, + .setup = rtl8366rb_setup, +- .phy_read = rtl8366rb_dsa_phy_read, +- .phy_write = rtl8366rb_dsa_phy_write, + .phylink_get_caps = rtl8366rb_phylink_get_caps, + .phylink_mac_link_up = rtl8366rb_mac_link_up, + .phylink_mac_link_down = rtl8366rb_mac_link_down, +@@ -1842,8 +1803,7 @@ static const struct realtek_ops rtl8366r + }; + + const struct realtek_variant rtl8366rb_variant = { +- .ds_ops_smi = &rtl8366rb_switch_ops_smi, +- .ds_ops_mdio = &rtl8366rb_switch_ops_mdio, ++ .ds_ops = &rtl8366rb_switch_ops, + .ops = &rtl8366rb_ops, + .clk_delay = 10, + .cmd_read = 0xa9, +--- a/drivers/net/dsa/realtek/rtl83xx.c ++++ b/drivers/net/dsa/realtek/rtl83xx.c +@@ -233,7 +233,7 @@ int rtl83xx_register_switch(struct realt + + ds->priv = priv; + ds->dev = priv->dev; +- ds->ops = priv->ds_ops; ++ ds->ops = priv->variant->ds_ops; + ds->num_ports = priv->num_ports; + priv->ds = ds; + diff --git a/target/linux/generic/backport-6.6/896-v6.9-0011-net-dsa-realtek-embed-dsa_switch-into-realtek_priv.patch b/target/linux/generic/backport-6.6/896-v6.9-0011-net-dsa-realtek-embed-dsa_switch-into-realtek_priv.patch new file mode 100644 index 0000000000..4cb55f2da9 --- /dev/null +++ b/target/linux/generic/backport-6.6/896-v6.9-0011-net-dsa-realtek-embed-dsa_switch-into-realtek_priv.patch @@ -0,0 +1,180 @@ +From 9fc469b2943d9b1ff2a7800f823e7cd7a5cac0ca Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Fri, 9 Feb 2024 02:03:47 -0300 +Subject: net: dsa: realtek: embed dsa_switch into realtek_priv +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Embed dsa_switch within realtek_priv to eliminate the need for a second +memory allocation. + +Suggested-by: Alvin Šipraga +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Vladimir Oltean +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/realtek.h | 2 +- + drivers/net/dsa/realtek/rtl8365mb.c | 15 +++++++++------ + drivers/net/dsa/realtek/rtl8366rb.c | 3 ++- + drivers/net/dsa/realtek/rtl83xx.c | 15 +++++++-------- + 4 files changed, 19 insertions(+), 16 deletions(-) + +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -61,7 +61,7 @@ struct realtek_priv { + const struct realtek_variant *variant; + + spinlock_t lock; /* Locks around command writes */ +- struct dsa_switch *ds; ++ struct dsa_switch ds; + struct irq_domain *irqdomain; + bool leds_disabled; + +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -870,6 +870,7 @@ static int rtl8365mb_ext_config_rgmii(st + { + const struct rtl8365mb_extint *extint = + rtl8365mb_get_port_extint(priv, port); ++ struct dsa_switch *ds = &priv->ds; + struct device_node *dn; + struct dsa_port *dp; + int tx_delay = 0; +@@ -880,7 +881,7 @@ static int rtl8365mb_ext_config_rgmii(st + if (!extint) + return -ENODEV; + +- dp = dsa_to_port(priv->ds, port); ++ dp = dsa_to_port(ds, port); + dn = dp->dn; + + /* Set the RGMII TX/RX delay +@@ -1534,6 +1535,7 @@ static void rtl8365mb_get_stats64(struct + static void rtl8365mb_stats_setup(struct realtek_priv *priv) + { + struct rtl8365mb *mb = priv->chip_data; ++ struct dsa_switch *ds = &priv->ds; + int i; + + /* Per-chip global mutex to protect MIB counter access, since doing +@@ -1544,7 +1546,7 @@ static void rtl8365mb_stats_setup(struct + for (i = 0; i < priv->num_ports; i++) { + struct rtl8365mb_port *p = &mb->ports[i]; + +- if (dsa_is_unused_port(priv->ds, i)) ++ if (dsa_is_unused_port(ds, i)) + continue; + + /* Per-port spinlock to protect the stats64 data */ +@@ -1560,12 +1562,13 @@ static void rtl8365mb_stats_setup(struct + static void rtl8365mb_stats_teardown(struct realtek_priv *priv) + { + struct rtl8365mb *mb = priv->chip_data; ++ struct dsa_switch *ds = &priv->ds; + int i; + + for (i = 0; i < priv->num_ports; i++) { + struct rtl8365mb_port *p = &mb->ports[i]; + +- if (dsa_is_unused_port(priv->ds, i)) ++ if (dsa_is_unused_port(ds, i)) + continue; + + cancel_delayed_work_sync(&p->mib_work); +@@ -1964,7 +1967,7 @@ static int rtl8365mb_setup(struct dsa_sw + dev_info(priv->dev, "no interrupt support\n"); + + /* Configure CPU tagging */ +- dsa_switch_for_each_cpu_port(cpu_dp, priv->ds) { ++ dsa_switch_for_each_cpu_port(cpu_dp, ds) { + cpu->mask |= BIT(cpu_dp->index); + + if (cpu->trap_port == RTL8365MB_MAX_NUM_PORTS) +@@ -1979,7 +1982,7 @@ static int rtl8365mb_setup(struct dsa_sw + for (i = 0; i < priv->num_ports; i++) { + struct rtl8365mb_port *p = &mb->ports[i]; + +- if (dsa_is_unused_port(priv->ds, i)) ++ if (dsa_is_unused_port(ds, i)) + continue; + + /* Forward only to the CPU */ +@@ -1996,7 +1999,7 @@ static int rtl8365mb_setup(struct dsa_sw + * ports will still forward frames to the CPU despite being + * administratively down by default. + */ +- rtl8365mb_port_stp_state_set(priv->ds, i, BR_STATE_DISABLED); ++ rtl8365mb_port_stp_state_set(ds, i, BR_STATE_DISABLED); + + /* Set up per-port private data */ + p->priv = priv; +--- a/drivers/net/dsa/realtek/rtl8366rb.c ++++ b/drivers/net/dsa/realtek/rtl8366rb.c +@@ -1565,6 +1565,7 @@ static int rtl8366rb_get_mc_index(struct + + static int rtl8366rb_set_mc_index(struct realtek_priv *priv, int port, int index) + { ++ struct dsa_switch *ds = &priv->ds; + struct rtl8366rb *rb; + bool pvid_enabled; + int ret; +@@ -1589,7 +1590,7 @@ static int rtl8366rb_set_mc_index(struct + * not drop any untagged or C-tagged frames. Make sure to update the + * filtering setting. + */ +- if (dsa_port_is_vlan_filtering(dsa_to_port(priv->ds, port))) ++ if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) + ret = rtl8366rb_drop_untagged(priv, port, !pvid_enabled); + + return ret; +--- a/drivers/net/dsa/realtek/rtl83xx.c ++++ b/drivers/net/dsa/realtek/rtl83xx.c +@@ -218,7 +218,7 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REAL + */ + int rtl83xx_register_switch(struct realtek_priv *priv) + { +- struct dsa_switch *ds; ++ struct dsa_switch *ds = &priv->ds; + int ret; + + ret = priv->ops->detect(priv); +@@ -227,15 +227,10 @@ int rtl83xx_register_switch(struct realt + return ret; + } + +- ds = devm_kzalloc(priv->dev, sizeof(*ds), GFP_KERNEL); +- if (!ds) +- return -ENOMEM; +- + ds->priv = priv; + ds->dev = priv->dev; + ds->ops = priv->variant->ds_ops; + ds->num_ports = priv->num_ports; +- priv->ds = ds; + + ret = dsa_register_switch(ds); + if (ret) { +@@ -258,7 +253,9 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_register_sw + */ + void rtl83xx_unregister_switch(struct realtek_priv *priv) + { +- dsa_unregister_switch(priv->ds); ++ struct dsa_switch *ds = &priv->ds; ++ ++ dsa_unregister_switch(ds); + } + EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA); + +@@ -275,7 +272,9 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_ + */ + void rtl83xx_shutdown(struct realtek_priv *priv) + { +- dsa_switch_shutdown(priv->ds); ++ struct dsa_switch *ds = &priv->ds; ++ ++ dsa_switch_shutdown(ds); + + dev_set_drvdata(priv->dev, NULL); + } diff --git a/target/linux/generic/backport-6.6/897-v6.9-net-dsa-realtek-fix-digital-interface-select-macro-f.patch b/target/linux/generic/backport-6.6/897-v6.9-net-dsa-realtek-fix-digital-interface-select-macro-f.patch new file mode 100644 index 0000000000..a3ccf5d4ad --- /dev/null +++ b/target/linux/generic/backport-6.6/897-v6.9-net-dsa-realtek-fix-digital-interface-select-macro-f.patch @@ -0,0 +1,38 @@ +From 32e4a5447ed9fa904a2dfcf4609c64bce053b4e8 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Mon, 12 Feb 2024 18:34:33 -0300 +Subject: [PATCH] net: dsa: realtek: fix digital interface select macro for + EXT0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While no supported devices currently utilize EXT0, the register reserves +the bits for an EXT0. EXT0 is utilized by devices from the generation +prior to rtl8365mb, such as those supported by the driver library +rtl8367b. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Alvin Šipraga +Reviewed-by: Linus Walleij +Link: https://lore.kernel.org/r/20240212-realtek-fix_ext0-v1-1-f3d2536d191a@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/realtek/rtl8365mb.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -209,10 +209,10 @@ + #define RTL8365MB_EXT_PORT_MODE_100FX 13 + + /* External interface mode configuration registers 0~1 */ +-#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 0x1305 /* EXT1 */ ++#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 0x1305 /* EXT0,EXT1 */ + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 0x13C3 /* EXT2 */ + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(_extint) \ +- ((_extint) == 1 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 : \ ++ ((_extint) <= 1 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 : \ + (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ + 0x0) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \ diff --git a/target/linux/generic/backport-6.6/898-v6.9-0001-dt-bindings-net-dsa-realtek-reset-gpios-is-not-requi.patch b/target/linux/generic/backport-6.6/898-v6.9-0001-dt-bindings-net-dsa-realtek-reset-gpios-is-not-requi.patch new file mode 100644 index 0000000000..e42dfc5d4d --- /dev/null +++ b/target/linux/generic/backport-6.6/898-v6.9-0001-dt-bindings-net-dsa-realtek-reset-gpios-is-not-requi.patch @@ -0,0 +1,34 @@ +From 28001bb1955fcfa63e535848c4289fcd7bb88daf Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Sun, 25 Feb 2024 13:29:53 -0300 +Subject: [PATCH 1/3] dt-bindings: net: dsa: realtek: reset-gpios is not + required +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The 'reset-gpios' should not be mandatory. although they might be +required for some devices if the switch reset was left asserted by a +previous driver, such as the bootloader. + +Signed-off-by: Luiz Angelo Daros de Luca +Cc: devicetree@vger.kernel.org +Acked-by: Arınç ÜNAL +Acked-by: Rob Herring +Reviewed-by: Linus Walleij +Reviewed-by: Alvin Šipraga +Signed-off-by: David S. Miller +--- + Documentation/devicetree/bindings/net/dsa/realtek.yaml | 1 - + 1 file changed, 1 deletion(-) + +--- a/Documentation/devicetree/bindings/net/dsa/realtek.yaml ++++ b/Documentation/devicetree/bindings/net/dsa/realtek.yaml +@@ -125,7 +125,6 @@ else: + - mdc-gpios + - mdio-gpios + - mdio +- - reset-gpios + + required: + - compatible diff --git a/target/linux/generic/backport-6.6/898-v6.9-0002-dt-bindings-net-dsa-realtek-add-reset-controller.patch b/target/linux/generic/backport-6.6/898-v6.9-0002-dt-bindings-net-dsa-realtek-add-reset-controller.patch new file mode 100644 index 0000000000..7e8a240626 --- /dev/null +++ b/target/linux/generic/backport-6.6/898-v6.9-0002-dt-bindings-net-dsa-realtek-add-reset-controller.patch @@ -0,0 +1,33 @@ +From 5fc2d68fc81801162188995e4d3dc0b26747dd76 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Sun, 25 Feb 2024 13:29:54 -0300 +Subject: [PATCH 2/3] dt-bindings: net: dsa: realtek: add reset controller +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Realtek switches can use a reset controller instead of reset-gpios. + +Signed-off-by: Luiz Angelo Daros de Luca +Cc: devicetree@vger.kernel.org +Acked-by: Arınç ÜNAL +Reviewed-by: Linus Walleij +Reviewed-by: Alvin Šipraga +Acked-by: Rob Herring +Signed-off-by: David S. Miller +--- + Documentation/devicetree/bindings/net/dsa/realtek.yaml | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/Documentation/devicetree/bindings/net/dsa/realtek.yaml ++++ b/Documentation/devicetree/bindings/net/dsa/realtek.yaml +@@ -59,6 +59,9 @@ properties: + description: GPIO to be used to reset the whole device + maxItems: 1 + ++ resets: ++ maxItems: 1 ++ + realtek,disable-leds: + type: boolean + description: | diff --git a/target/linux/generic/backport-6.6/898-v6.9-0003-net-dsa-realtek-support-reset-controller.patch b/target/linux/generic/backport-6.6/898-v6.9-0003-net-dsa-realtek-support-reset-controller.patch new file mode 100644 index 0000000000..7a280bf7ad --- /dev/null +++ b/target/linux/generic/backport-6.6/898-v6.9-0003-net-dsa-realtek-support-reset-controller.patch @@ -0,0 +1,123 @@ +From 56998aa6b7f0f31ce8df23c00701af2d8e8a1f1a Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Sun, 25 Feb 2024 13:29:55 -0300 +Subject: [PATCH 3/3] net: dsa: realtek: support reset controller +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add support for resetting the device using a reset controller, +complementing the existing GPIO reset functionality (reset-gpios). + +Although the reset is optional and the driver performs a soft reset +during setup, if the initial reset pin state was asserted, the driver +will not detect the device until the reset is deasserted. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Linus Walleij +Reviewed-by: Alvin Šipraga +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/realtek.h | 2 ++ + drivers/net/dsa/realtek/rtl83xx.c | 42 +++++++++++++++++++++++++++---- + drivers/net/dsa/realtek/rtl83xx.h | 2 ++ + 3 files changed, 41 insertions(+), 5 deletions(-) + +--- a/drivers/net/dsa/realtek/realtek.h ++++ b/drivers/net/dsa/realtek/realtek.h +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #define REALTEK_HW_STOP_DELAY 25 /* msecs */ + #define REALTEK_HW_START_DELAY 100 /* msecs */ +@@ -48,6 +49,7 @@ struct rtl8366_vlan_4k { + + struct realtek_priv { + struct device *dev; ++ struct reset_control *reset_ctl; + struct gpio_desc *reset; + struct gpio_desc *mdc; + struct gpio_desc *mdio; +--- a/drivers/net/dsa/realtek/rtl83xx.c ++++ b/drivers/net/dsa/realtek/rtl83xx.c +@@ -185,6 +185,13 @@ rtl83xx_probe(struct device *dev, + "realtek,disable-leds"); + + /* TODO: if power is software controlled, set up any regulators here */ ++ priv->reset_ctl = devm_reset_control_get_optional(dev, NULL); ++ if (IS_ERR(priv->reset_ctl)) { ++ ret = PTR_ERR(priv->reset_ctl); ++ dev_err_probe(dev, ret, "failed to get reset control\n"); ++ return ERR_CAST(priv->reset_ctl); ++ } ++ + priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(priv->reset)) { + dev_err(dev, "failed to get RESET GPIO\n"); +@@ -193,11 +200,11 @@ rtl83xx_probe(struct device *dev, + + dev_set_drvdata(dev, priv); + +- if (priv->reset) { +- gpiod_set_value(priv->reset, 1); ++ if (priv->reset_ctl || priv->reset) { ++ rtl83xx_reset_assert(priv); + dev_dbg(dev, "asserted RESET\n"); + msleep(REALTEK_HW_STOP_DELAY); +- gpiod_set_value(priv->reset, 0); ++ rtl83xx_reset_deassert(priv); + msleep(REALTEK_HW_START_DELAY); + dev_dbg(dev, "deasserted RESET\n"); + } +@@ -293,11 +300,36 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, R + void rtl83xx_remove(struct realtek_priv *priv) + { + /* leave the device reset asserted */ +- if (priv->reset) +- gpiod_set_value(priv->reset, 1); ++ rtl83xx_reset_assert(priv); + } + EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); + ++void rtl83xx_reset_assert(struct realtek_priv *priv) ++{ ++ int ret; ++ ++ ret = reset_control_assert(priv->reset_ctl); ++ if (ret) ++ dev_warn(priv->dev, ++ "Failed to assert the switch reset control: %pe\n", ++ ERR_PTR(ret)); ++ ++ gpiod_set_value(priv->reset, true); ++} ++ ++void rtl83xx_reset_deassert(struct realtek_priv *priv) ++{ ++ int ret; ++ ++ ret = reset_control_deassert(priv->reset_ctl); ++ if (ret) ++ dev_warn(priv->dev, ++ "Failed to deassert the switch reset control: %pe\n", ++ ERR_PTR(ret)); ++ ++ gpiod_set_value(priv->reset, false); ++} ++ + MODULE_AUTHOR("Luiz Angelo Daros de Luca "); + MODULE_AUTHOR("Linus Walleij "); + MODULE_DESCRIPTION("Realtek DSA switches common module"); +--- a/drivers/net/dsa/realtek/rtl83xx.h ++++ b/drivers/net/dsa/realtek/rtl83xx.h +@@ -18,5 +18,7 @@ int rtl83xx_register_switch(struct realt + void rtl83xx_unregister_switch(struct realtek_priv *priv); + void rtl83xx_shutdown(struct realtek_priv *priv); + void rtl83xx_remove(struct realtek_priv *priv); ++void rtl83xx_reset_assert(struct realtek_priv *priv); ++void rtl83xx_reset_deassert(struct realtek_priv *priv); + + #endif /* _RTL83XX_H */ diff --git a/target/linux/generic/backport-6.6/899-v6.10-0002-net-dsa-realtek-do-not-assert-reset-on-remove.patch b/target/linux/generic/backport-6.6/899-v6.10-0002-net-dsa-realtek-do-not-assert-reset-on-remove.patch new file mode 100644 index 0000000000..7299a25e37 --- /dev/null +++ b/target/linux/generic/backport-6.6/899-v6.10-0002-net-dsa-realtek-do-not-assert-reset-on-remove.patch @@ -0,0 +1,45 @@ +From 4f580e9aced1816398c1c64f178302a22b8ea6e2 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Sat, 27 Apr 2024 02:11:29 -0300 +Subject: [PATCH 2/3] net: dsa: realtek: do not assert reset on remove + +The necessity of asserting the reset on removal was previously +questioned, as DSA's own cleanup methods should suffice to prevent +traffic leakage[1]. + +When a driver has subdrivers controlled by devres, they will be +unregistered after the main driver's .remove is executed. If it asserts +a reset, the subdrivers will be unable to communicate with the hardware +during their cleanup. For LEDs, this means that they will fail to turn +off, resulting in a timeout error. + +[1] https://lore.kernel.org/r/20240123215606.26716-9-luizluca@gmail.com/ + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/rtl83xx.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +--- a/drivers/net/dsa/realtek/rtl83xx.c ++++ b/drivers/net/dsa/realtek/rtl83xx.c +@@ -291,16 +291,13 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, R + * rtl83xx_remove() - Cleanup a realtek switch driver + * @priv: realtek_priv pointer + * +- * If a method is provided, this function asserts the hard reset of the switch +- * in order to avoid leaking traffic when the driver is gone. ++ * Placehold for common cleanup procedures. + * +- * Context: Might sleep if priv->gdev->chip->can_sleep. ++ * Context: Any + * Return: nothing + */ + void rtl83xx_remove(struct realtek_priv *priv) + { +- /* leave the device reset asserted */ +- rtl83xx_reset_assert(priv); + } + EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); + diff --git a/target/linux/generic/backport-6.6/899-v6.10-0003-net-dsa-realtek-add-LED-drivers-for-rtl8366rb.patch b/target/linux/generic/backport-6.6/899-v6.10-0003-net-dsa-realtek-add-LED-drivers-for-rtl8366rb.patch new file mode 100644 index 0000000000..4c9ea7fe12 --- /dev/null +++ b/target/linux/generic/backport-6.6/899-v6.10-0003-net-dsa-realtek-add-LED-drivers-for-rtl8366rb.patch @@ -0,0 +1,396 @@ +From 32d617005475a71ebcc4ec8b2791e8d1481e9a10 Mon Sep 17 00:00:00 2001 +From: Luiz Angelo Daros de Luca +Date: Sat, 27 Apr 2024 02:11:30 -0300 +Subject: [PATCH 3/3] net: dsa: realtek: add LED drivers for rtl8366rb + +This commit introduces LED drivers for rtl8366rb, enabling LEDs to be +described in the device tree using the same format as qca8k. Each port +can configure up to 4 LEDs. + +If all LEDs in a group use the default state "keep", they will use the +default behavior after a reset. Changing the brightness of one LED, +either manually or by a trigger, will disable the default hardware +trigger and switch the entire LED group to manually controlled LEDs. +Once in this mode, there is no way to revert to hardware-controlled LEDs +(except by resetting the switch). + +Software triggers function as expected with manually controlled LEDs. + +Signed-off-by: Luiz Angelo Daros de Luca +Reviewed-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek/rtl8366rb.c | 304 ++++++++++++++++++++++++---- + 1 file changed, 265 insertions(+), 39 deletions(-) + +--- a/drivers/net/dsa/realtek/rtl8366rb.c ++++ b/drivers/net/dsa/realtek/rtl8366rb.c +@@ -180,6 +180,7 @@ + #define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f + + /* LED control registers */ ++/* The LED blink rate is global; it is used by all triggers in all groups. */ + #define RTL8366RB_LED_BLINKRATE_REG 0x0430 + #define RTL8366RB_LED_BLINKRATE_MASK 0x0007 + #define RTL8366RB_LED_BLINKRATE_28MS 0x0000 +@@ -195,31 +196,21 @@ + (4 * (led_group)) + #define RTL8366RB_LED_CTRL_MASK(led_group) \ + (0xf << RTL8366RB_LED_CTRL_OFFSET(led_group)) +-#define RTL8366RB_LED_OFF 0x0 +-#define RTL8366RB_LED_DUP_COL 0x1 +-#define RTL8366RB_LED_LINK_ACT 0x2 +-#define RTL8366RB_LED_SPD1000 0x3 +-#define RTL8366RB_LED_SPD100 0x4 +-#define RTL8366RB_LED_SPD10 0x5 +-#define RTL8366RB_LED_SPD1000_ACT 0x6 +-#define RTL8366RB_LED_SPD100_ACT 0x7 +-#define RTL8366RB_LED_SPD10_ACT 0x8 +-#define RTL8366RB_LED_SPD100_10_ACT 0x9 +-#define RTL8366RB_LED_FIBER 0xa +-#define RTL8366RB_LED_AN_FAULT 0xb +-#define RTL8366RB_LED_LINK_RX 0xc +-#define RTL8366RB_LED_LINK_TX 0xd +-#define RTL8366RB_LED_MASTER 0xe +-#define RTL8366RB_LED_FORCE 0xf + + /* The RTL8366RB_LED_X_X registers are used to manually set the LED state only + * when the corresponding LED group in RTL8366RB_LED_CTRL_REG is +- * RTL8366RB_LED_FORCE. Otherwise, it is ignored. ++ * RTL8366RB_LEDGROUP_FORCE. Otherwise, it is ignored. + */ + #define RTL8366RB_LED_0_1_CTRL_REG 0x0432 +-#define RTL8366RB_LED_1_OFFSET 6 + #define RTL8366RB_LED_2_3_CTRL_REG 0x0433 +-#define RTL8366RB_LED_3_OFFSET 6 ++#define RTL8366RB_LED_X_X_CTRL_REG(led_group) \ ++ ((led_group) <= 1 ? \ ++ RTL8366RB_LED_0_1_CTRL_REG : \ ++ RTL8366RB_LED_2_3_CTRL_REG) ++#define RTL8366RB_LED_0_X_CTRL_MASK GENMASK(5, 0) ++#define RTL8366RB_LED_X_1_CTRL_MASK GENMASK(11, 6) ++#define RTL8366RB_LED_2_X_CTRL_MASK GENMASK(5, 0) ++#define RTL8366RB_LED_X_3_CTRL_MASK GENMASK(11, 6) + + #define RTL8366RB_MIB_COUNT 33 + #define RTL8366RB_GLOBAL_MIB_COUNT 1 +@@ -363,14 +354,44 @@ + #define RTL8366RB_GREEN_FEATURE_TX BIT(0) + #define RTL8366RB_GREEN_FEATURE_RX BIT(2) + ++enum rtl8366_ledgroup_mode { ++ RTL8366RB_LEDGROUP_OFF = 0x0, ++ RTL8366RB_LEDGROUP_DUP_COL = 0x1, ++ RTL8366RB_LEDGROUP_LINK_ACT = 0x2, ++ RTL8366RB_LEDGROUP_SPD1000 = 0x3, ++ RTL8366RB_LEDGROUP_SPD100 = 0x4, ++ RTL8366RB_LEDGROUP_SPD10 = 0x5, ++ RTL8366RB_LEDGROUP_SPD1000_ACT = 0x6, ++ RTL8366RB_LEDGROUP_SPD100_ACT = 0x7, ++ RTL8366RB_LEDGROUP_SPD10_ACT = 0x8, ++ RTL8366RB_LEDGROUP_SPD100_10_ACT = 0x9, ++ RTL8366RB_LEDGROUP_FIBER = 0xa, ++ RTL8366RB_LEDGROUP_AN_FAULT = 0xb, ++ RTL8366RB_LEDGROUP_LINK_RX = 0xc, ++ RTL8366RB_LEDGROUP_LINK_TX = 0xd, ++ RTL8366RB_LEDGROUP_MASTER = 0xe, ++ RTL8366RB_LEDGROUP_FORCE = 0xf, ++ ++ __RTL8366RB_LEDGROUP_MODE_MAX ++}; ++ ++struct rtl8366rb_led { ++ u8 port_num; ++ u8 led_group; ++ struct realtek_priv *priv; ++ struct led_classdev cdev; ++}; ++ + /** + * struct rtl8366rb - RTL8366RB-specific data + * @max_mtu: per-port max MTU setting + * @pvid_enabled: if PVID is set for respective port ++ * @leds: per-port and per-ledgroup led info + */ + struct rtl8366rb { + unsigned int max_mtu[RTL8366RB_NUM_PORTS]; + bool pvid_enabled[RTL8366RB_NUM_PORTS]; ++ struct rtl8366rb_led leds[RTL8366RB_NUM_PORTS][RTL8366RB_NUM_LEDGROUPS]; + }; + + static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { +@@ -813,6 +834,217 @@ static int rtl8366rb_jam_table(const str + return 0; + } + ++static int rb8366rb_set_ledgroup_mode(struct realtek_priv *priv, ++ u8 led_group, ++ enum rtl8366_ledgroup_mode mode) ++{ ++ int ret; ++ u32 val; ++ ++ val = mode << RTL8366RB_LED_CTRL_OFFSET(led_group); ++ ++ ret = regmap_update_bits(priv->map, ++ RTL8366RB_LED_CTRL_REG, ++ RTL8366RB_LED_CTRL_MASK(led_group), ++ val); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static inline u32 rtl8366rb_led_group_port_mask(u8 led_group, u8 port) ++{ ++ switch (led_group) { ++ case 0: ++ return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port)); ++ case 1: ++ return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port)); ++ case 2: ++ return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port)); ++ case 3: ++ return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port)); ++ default: ++ return 0; ++ } ++} ++ ++static int rb8366rb_get_port_led(struct rtl8366rb_led *led) ++{ ++ struct realtek_priv *priv = led->priv; ++ u8 led_group = led->led_group; ++ u8 port_num = led->port_num; ++ int ret; ++ u32 val; ++ ++ ret = regmap_read(priv->map, RTL8366RB_LED_X_X_CTRL_REG(led_group), ++ &val); ++ if (ret) { ++ dev_err(priv->dev, "error reading LED on port %d group %d\n", ++ led_group, port_num); ++ return ret; ++ } ++ ++ return !!(val & rtl8366rb_led_group_port_mask(led_group, port_num)); ++} ++ ++static int rb8366rb_set_port_led(struct rtl8366rb_led *led, bool enable) ++{ ++ struct realtek_priv *priv = led->priv; ++ u8 led_group = led->led_group; ++ u8 port_num = led->port_num; ++ int ret; ++ ++ ret = regmap_update_bits(priv->map, ++ RTL8366RB_LED_X_X_CTRL_REG(led_group), ++ rtl8366rb_led_group_port_mask(led_group, ++ port_num), ++ enable ? 0xffff : 0); ++ if (ret) { ++ dev_err(priv->dev, "error updating LED on port %d group %d\n", ++ led_group, port_num); ++ return ret; ++ } ++ ++ /* Change the LED group to manual controlled LEDs if required */ ++ ret = rb8366rb_set_ledgroup_mode(priv, led_group, ++ RTL8366RB_LEDGROUP_FORCE); ++ ++ if (ret) { ++ dev_err(priv->dev, "error updating LED GROUP group %d\n", ++ led_group); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ++rtl8366rb_cled_brightness_set_blocking(struct led_classdev *ldev, ++ enum led_brightness brightness) ++{ ++ struct rtl8366rb_led *led = container_of(ldev, struct rtl8366rb_led, ++ cdev); ++ ++ return rb8366rb_set_port_led(led, brightness == LED_ON); ++} ++ ++static int rtl8366rb_setup_led(struct realtek_priv *priv, struct dsa_port *dp, ++ struct fwnode_handle *led_fwnode) ++{ ++ struct rtl8366rb *rb = priv->chip_data; ++ struct led_init_data init_data = { }; ++ enum led_default_state state; ++ struct rtl8366rb_led *led; ++ u32 led_group; ++ int ret; ++ ++ ret = fwnode_property_read_u32(led_fwnode, "reg", &led_group); ++ if (ret) ++ return ret; ++ ++ if (led_group >= RTL8366RB_NUM_LEDGROUPS) { ++ dev_warn(priv->dev, "Invalid LED reg %d defined for port %d", ++ led_group, dp->index); ++ return -EINVAL; ++ } ++ ++ led = &rb->leds[dp->index][led_group]; ++ led->port_num = dp->index; ++ led->led_group = led_group; ++ led->priv = priv; ++ ++ state = led_init_default_state_get(led_fwnode); ++ switch (state) { ++ case LEDS_DEFSTATE_ON: ++ led->cdev.brightness = 1; ++ rb8366rb_set_port_led(led, 1); ++ break; ++ case LEDS_DEFSTATE_KEEP: ++ led->cdev.brightness = ++ rb8366rb_get_port_led(led); ++ break; ++ case LEDS_DEFSTATE_OFF: ++ default: ++ led->cdev.brightness = 0; ++ rb8366rb_set_port_led(led, 0); ++ } ++ ++ led->cdev.max_brightness = 1; ++ led->cdev.brightness_set_blocking = ++ rtl8366rb_cled_brightness_set_blocking; ++ init_data.fwnode = led_fwnode; ++ init_data.devname_mandatory = true; ++ ++ init_data.devicename = kasprintf(GFP_KERNEL, "Realtek-%d:0%d:%d", ++ dp->ds->index, dp->index, led_group); ++ if (!init_data.devicename) ++ return -ENOMEM; ++ ++ ret = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data); ++ if (ret) { ++ dev_warn(priv->dev, "Failed to init LED %d for port %d", ++ led_group, dp->index); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rtl8366rb_setup_all_leds_off(struct realtek_priv *priv) ++{ ++ int ret = 0; ++ int i; ++ ++ regmap_update_bits(priv->map, ++ RTL8366RB_INTERRUPT_CONTROL_REG, ++ RTL8366RB_P4_RGMII_LED, ++ 0); ++ ++ for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) { ++ ret = rb8366rb_set_ledgroup_mode(priv, i, ++ RTL8366RB_LEDGROUP_OFF); ++ if (ret) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static int rtl8366rb_setup_leds(struct realtek_priv *priv) ++{ ++ struct device_node *leds_np, *led_np; ++ struct dsa_switch *ds = &priv->ds; ++ struct dsa_port *dp; ++ int ret = 0; ++ ++ dsa_switch_for_each_port(dp, ds) { ++ if (!dp->dn) ++ continue; ++ ++ leds_np = of_get_child_by_name(dp->dn, "leds"); ++ if (!leds_np) { ++ dev_dbg(priv->dev, "No leds defined for port %d", ++ dp->index); ++ continue; ++ } ++ ++ for_each_child_of_node(leds_np, led_np) { ++ ret = rtl8366rb_setup_led(priv, dp, ++ of_fwnode_handle(led_np)); ++ if (ret) { ++ of_node_put(led_np); ++ break; ++ } ++ } ++ ++ of_node_put(leds_np); ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ + static int rtl8366rb_setup(struct dsa_switch *ds) + { + struct realtek_priv *priv = ds->priv; +@@ -821,7 +1053,6 @@ static int rtl8366rb_setup(struct dsa_sw + u32 chip_ver = 0; + u32 chip_id = 0; + int jam_size; +- u32 val; + int ret; + int i; + +@@ -997,7 +1228,9 @@ static int rtl8366rb_setup(struct dsa_sw + if (ret) + return ret; + +- /* Set blinking, TODO: make this configurable */ ++ /* Set blinking, used by all LED groups using HW triggers. ++ * TODO: make this configurable ++ */ + ret = regmap_update_bits(priv->map, RTL8366RB_LED_BLINKRATE_REG, + RTL8366RB_LED_BLINKRATE_MASK, + RTL8366RB_LED_BLINKRATE_56MS); +@@ -1005,26 +1238,19 @@ static int rtl8366rb_setup(struct dsa_sw + return ret; + + /* Set up LED activity: +- * Each port has 4 LEDs, we configure all ports to the same +- * behaviour (no individual config) but we can set up each +- * LED separately. ++ * Each port has 4 LEDs on fixed groups. Each group shares the same ++ * hardware trigger across all ports. LEDs can only be indiviually ++ * controlled setting the LED group to fixed mode and using the driver ++ * to toggle them LEDs on/off. + */ + if (priv->leds_disabled) { +- /* Turn everything off */ +- regmap_update_bits(priv->map, +- RTL8366RB_INTERRUPT_CONTROL_REG, +- RTL8366RB_P4_RGMII_LED, +- 0); +- +- for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) { +- val = RTL8366RB_LED_OFF << RTL8366RB_LED_CTRL_OFFSET(i); +- ret = regmap_update_bits(priv->map, +- RTL8366RB_LED_CTRL_REG, +- RTL8366RB_LED_CTRL_MASK(i), +- val); +- if (ret) +- return ret; +- } ++ ret = rtl8366rb_setup_all_leds_off(priv); ++ if (ret) ++ return ret; ++ } else { ++ ret = rtl8366rb_setup_leds(priv); ++ if (ret) ++ return ret; + } + + ret = rtl8366_reset_vlan(priv); -- 2.30.2