Drop patches that have been merged upstream.
Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
[drop patch 308, 316 containing workarounds fixed elsewhere]
Signed-off-by: Sander Vanheule <sander@svanheule.net>
+++ /dev/null
-From 293903b9dfe43520f01374dc1661be11d6838c49 Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <sander@svanheule.net>
-Date: Thu, 18 Nov 2021 17:29:52 +0100
-Subject: watchdog: Add Realtek Otto watchdog timer
-
-Realtek MIPS SoCs (platform name Otto) have a watchdog timer with
-pretimeout notifitication support. The WDT can (partially) hard reset,
-or soft reset the SoC.
-
-This driver implements all features as described in the devicetree
-binding, except the phase2 interrupt, and also functions as a restart
-handler. The cpu reset mode is considered to be a "warm" restart, since
-this mode does not reset all peripherals. Being an embedded system
-though, the "cpu" and "software" modes will still cause the bootloader
-to run on restart.
-
-It is not known how a forced system reset can be disabled on the
-supported platforms. This means that the phase2 interrupt will only fire
-at the same time as reset, so implementing phase2 is of little use.
-
-Signed-off-by: Sander Vanheule <sander@svanheule.net>
-Reviewed-by: Guenter Roeck <linux@roeck-us.net>
-Link: https://lore.kernel.org/r/6d060bccbdcc709cfa79203485db85aad3c3beb5.1637252610.git.sander@svanheule.net
-Signed-off-by: Guenter Roeck <linux@roeck-us.net>
----
- MAINTAINERS | 7 +
- drivers/watchdog/Kconfig | 13 ++
- drivers/watchdog/Makefile | 1 +
- drivers/watchdog/realtek_otto_wdt.c | 384 ++++++++++++++++++++++++++++++++++++
- 4 files changed, 405 insertions(+)
- create mode 100644 drivers/watchdog/realtek_otto_wdt.c
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -15902,6 +15902,13 @@ S: Maintained
- F: include/sound/rt*.h
- F: sound/soc/codecs/rt*
-
-+REALTEK OTTO WATCHDOG
-+M: Sander Vanheule <sander@svanheule.net>
-+L: linux-watchdog@vger.kernel.org
-+S: Maintained
-+F: Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml
-+F: driver/watchdog/realtek_otto_wdt.c
-+
- REALTEK RTL83xx SMI DSA ROUTER CHIPS
- M: Linus Walleij <linus.walleij@linaro.org>
- S: Maintained
---- a/drivers/watchdog/Kconfig
-+++ b/drivers/watchdog/Kconfig
-@@ -954,6 +954,19 @@ config RTD119X_WATCHDOG
- Say Y here to include support for the watchdog timer in
- Realtek RTD1295 SoCs.
-
-+config REALTEK_OTTO_WDT
-+ tristate "Realtek Otto MIPS watchdog support"
-+ depends on MACH_REALTEK_RTL || COMPILE_TEST
-+ depends on COMMON_CLK
-+ select WATCHDOG_CORE
-+ default MACH_REALTEK_RTL
-+ help
-+ Say Y here to include support for the watchdog timer on Realtek
-+ RTL838x, RTL839x, RTL930x SoCs. This watchdog has pretimeout
-+ notifications and system reset on timeout.
-+
-+ When built as a module this will be called realtek_otto_wdt.
-+
- config SPRD_WATCHDOG
- tristate "Spreadtrum watchdog support"
- depends on ARCH_SPRD || COMPILE_TEST
---- a/drivers/watchdog/Makefile
-+++ b/drivers/watchdog/Makefile
-@@ -171,6 +171,7 @@ obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o
- obj-$(CONFIG_MT7621_WDT) += mt7621_wdt.o
- obj-$(CONFIG_PIC32_WDT) += pic32-wdt.o
- obj-$(CONFIG_PIC32_DMT) += pic32-dmt.o
-+obj-$(CONFIG_REALTEK_OTTO_WDT) += realtek_otto_wdt.o
-
- # PARISC Architecture
-
---- /dev/null
-+++ b/drivers/watchdog/realtek_otto_wdt.c
-@@ -0,0 +1,384 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+
-+/*
-+ * Realtek Otto MIPS platform watchdog
-+ *
-+ * Watchdog timer that will reset the system after timeout, using the selected
-+ * reset mode.
-+ *
-+ * Counter scaling and timeouts:
-+ * - Base prescale of (2 << 25), providing tick duration T_0: 168ms @ 200MHz
-+ * - PRESCALE: logarithmic prescaler adding a factor of {1, 2, 4, 8}
-+ * - Phase 1: Times out after (PHASE1 + 1) × PRESCALE × T_0
-+ * Generates an interrupt, WDT cannot be stopped after phase 1
-+ * - Phase 2: starts after phase 1, times out after (PHASE2 + 1) × PRESCALE × T_0
-+ * Resets the system according to RST_MODE
-+ */
-+
-+#include <linux/bits.h>
-+#include <linux/bitfield.h>
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/math.h>
-+#include <linux/minmax.h>
-+#include <linux/module.h>
-+#include <linux/mod_devicetable.h>
-+#include <linux/platform_device.h>
-+#include <linux/property.h>
-+#include <linux/reboot.h>
-+#include <linux/watchdog.h>
-+
-+#define OTTO_WDT_REG_CNTR 0x0
-+#define OTTO_WDT_CNTR_PING BIT(31)
-+
-+#define OTTO_WDT_REG_INTR 0x4
-+#define OTTO_WDT_INTR_PHASE_1 BIT(31)
-+#define OTTO_WDT_INTR_PHASE_2 BIT(30)
-+
-+#define OTTO_WDT_REG_CTRL 0x8
-+#define OTTO_WDT_CTRL_ENABLE BIT(31)
-+#define OTTO_WDT_CTRL_PRESCALE GENMASK(30, 29)
-+#define OTTO_WDT_CTRL_PHASE1 GENMASK(26, 22)
-+#define OTTO_WDT_CTRL_PHASE2 GENMASK(19, 15)
-+#define OTTO_WDT_CTRL_RST_MODE GENMASK(1, 0)
-+#define OTTO_WDT_MODE_SOC 0
-+#define OTTO_WDT_MODE_CPU 1
-+#define OTTO_WDT_MODE_SOFTWARE 2
-+#define OTTO_WDT_CTRL_DEFAULT OTTO_WDT_MODE_CPU
-+
-+#define OTTO_WDT_PRESCALE_MAX 3
-+
-+/*
-+ * One higher than the max values contained in PHASE{1,2}, since a value of 0
-+ * corresponds to one tick.
-+ */
-+#define OTTO_WDT_PHASE_TICKS_MAX 32
-+
-+/*
-+ * The maximum reset delay is actually 2×32 ticks, but that would require large
-+ * pretimeout values for timeouts longer than 32 ticks. Limit the maximum timeout
-+ * to 32 + 1 to ensure small pretimeout values can be configured as expected.
-+ */
-+#define OTTO_WDT_TIMEOUT_TICKS_MAX (OTTO_WDT_PHASE_TICKS_MAX + 1)
-+
-+struct otto_wdt_ctrl {
-+ struct watchdog_device wdev;
-+ struct device *dev;
-+ void __iomem *base;
-+ unsigned int clk_rate_khz;
-+ int irq_phase1;
-+};
-+
-+static int otto_wdt_start(struct watchdog_device *wdev)
-+{
-+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
-+ u32 v;
-+
-+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
-+ v |= OTTO_WDT_CTRL_ENABLE;
-+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
-+
-+ return 0;
-+}
-+
-+static int otto_wdt_stop(struct watchdog_device *wdev)
-+{
-+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
-+ u32 v;
-+
-+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
-+ v &= ~OTTO_WDT_CTRL_ENABLE;
-+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
-+
-+ return 0;
-+}
-+
-+static int otto_wdt_ping(struct watchdog_device *wdev)
-+{
-+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
-+
-+ iowrite32(OTTO_WDT_CNTR_PING, ctrl->base + OTTO_WDT_REG_CNTR);
-+
-+ return 0;
-+}
-+
-+static int otto_wdt_tick_ms(struct otto_wdt_ctrl *ctrl, int prescale)
-+{
-+ return DIV_ROUND_CLOSEST(1 << (25 + prescale), ctrl->clk_rate_khz);
-+}
-+
-+/*
-+ * The timer asserts the PHASE1/PHASE2 IRQs when the number of ticks exceeds
-+ * the value stored in those fields. This means each phase will run for at least
-+ * one tick, so small values need to be clamped to correctly reflect the timeout.
-+ */
-+static inline unsigned int div_round_ticks(unsigned int val, unsigned int tick_duration,
-+ unsigned int min_ticks)
-+{
-+ return max(min_ticks, DIV_ROUND_UP(val, tick_duration));
-+}
-+
-+static int otto_wdt_determine_timeouts(struct watchdog_device *wdev, unsigned int timeout,
-+ unsigned int pretimeout)
-+{
-+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
-+ unsigned int pretimeout_ms = pretimeout * 1000;
-+ unsigned int timeout_ms = timeout * 1000;
-+ unsigned int prescale_next = 0;
-+ unsigned int phase1_ticks;
-+ unsigned int phase2_ticks;
-+ unsigned int total_ticks;
-+ unsigned int prescale;
-+ unsigned int tick_ms;
-+ u32 v;
-+
-+ do {
-+ prescale = prescale_next;
-+ if (prescale > OTTO_WDT_PRESCALE_MAX)
-+ return -EINVAL;
-+
-+ tick_ms = otto_wdt_tick_ms(ctrl, prescale);
-+ total_ticks = div_round_ticks(timeout_ms, tick_ms, 2);
-+ phase1_ticks = div_round_ticks(timeout_ms - pretimeout_ms, tick_ms, 1);
-+ phase2_ticks = total_ticks - phase1_ticks;
-+
-+ prescale_next++;
-+ } while (phase1_ticks > OTTO_WDT_PHASE_TICKS_MAX
-+ || phase2_ticks > OTTO_WDT_PHASE_TICKS_MAX);
-+
-+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
-+
-+ v &= ~(OTTO_WDT_CTRL_PRESCALE | OTTO_WDT_CTRL_PHASE1 | OTTO_WDT_CTRL_PHASE2);
-+ v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE1, phase1_ticks - 1);
-+ v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE2, phase2_ticks - 1);
-+ v |= FIELD_PREP(OTTO_WDT_CTRL_PRESCALE, prescale);
-+
-+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
-+
-+ timeout_ms = total_ticks * tick_ms;
-+ ctrl->wdev.timeout = timeout_ms / 1000;
-+
-+ pretimeout_ms = phase2_ticks * tick_ms;
-+ ctrl->wdev.pretimeout = pretimeout_ms / 1000;
-+
-+ return 0;
-+}
-+
-+static int otto_wdt_set_timeout(struct watchdog_device *wdev, unsigned int val)
-+{
-+ return otto_wdt_determine_timeouts(wdev, val, min(wdev->pretimeout, val - 1));
-+}
-+
-+static int otto_wdt_set_pretimeout(struct watchdog_device *wdev, unsigned int val)
-+{
-+ return otto_wdt_determine_timeouts(wdev, wdev->timeout, val);
-+}
-+
-+static int otto_wdt_restart(struct watchdog_device *wdev, unsigned long reboot_mode,
-+ void *data)
-+{
-+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
-+ u32 reset_mode;
-+ u32 v;
-+
-+ disable_irq(ctrl->irq_phase1);
-+
-+ switch (reboot_mode) {
-+ case REBOOT_SOFT:
-+ reset_mode = OTTO_WDT_MODE_SOFTWARE;
-+ break;
-+ case REBOOT_WARM:
-+ reset_mode = OTTO_WDT_MODE_CPU;
-+ break;
-+ default:
-+ reset_mode = OTTO_WDT_MODE_SOC;
-+ break;
-+ }
-+
-+ /* Configure for shortest timeout and wait for reset to occur */
-+ v = FIELD_PREP(OTTO_WDT_CTRL_RST_MODE, reset_mode) | OTTO_WDT_CTRL_ENABLE;
-+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
-+
-+ mdelay(3 * otto_wdt_tick_ms(ctrl, 0));
-+
-+ return 0;
-+}
-+
-+static irqreturn_t otto_wdt_phase1_isr(int irq, void *dev_id)
-+{
-+ struct otto_wdt_ctrl *ctrl = dev_id;
-+
-+ iowrite32(OTTO_WDT_INTR_PHASE_1, ctrl->base + OTTO_WDT_REG_INTR);
-+ dev_crit(ctrl->dev, "phase 1 timeout\n");
-+ watchdog_notify_pretimeout(&ctrl->wdev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static const struct watchdog_ops otto_wdt_ops = {
-+ .owner = THIS_MODULE,
-+ .start = otto_wdt_start,
-+ .stop = otto_wdt_stop,
-+ .ping = otto_wdt_ping,
-+ .set_timeout = otto_wdt_set_timeout,
-+ .set_pretimeout = otto_wdt_set_pretimeout,
-+ .restart = otto_wdt_restart,
-+};
-+
-+static const struct watchdog_info otto_wdt_info = {
-+ .identity = "Realtek Otto watchdog timer",
-+ .options = WDIOF_KEEPALIVEPING |
-+ WDIOF_MAGICCLOSE |
-+ WDIOF_SETTIMEOUT |
-+ WDIOF_PRETIMEOUT,
-+};
-+
-+static void otto_wdt_clock_action(void *data)
-+{
-+ clk_disable_unprepare(data);
-+}
-+
-+static int otto_wdt_probe_clk(struct otto_wdt_ctrl *ctrl)
-+{
-+ struct clk *clk = devm_clk_get(ctrl->dev, NULL);
-+ int ret;
-+
-+ if (IS_ERR(clk))
-+ return dev_err_probe(ctrl->dev, PTR_ERR(clk), "Failed to get clock\n");
-+
-+ ret = clk_prepare_enable(clk);
-+ if (ret)
-+ return dev_err_probe(ctrl->dev, ret, "Failed to enable clock\n");
-+
-+ ret = devm_add_action_or_reset(ctrl->dev, otto_wdt_clock_action, clk);
-+ if (ret)
-+ return ret;
-+
-+ ctrl->clk_rate_khz = clk_get_rate(clk) / 1000;
-+ if (ctrl->clk_rate_khz == 0)
-+ return dev_err_probe(ctrl->dev, -ENXIO, "Failed to get clock rate\n");
-+
-+ return 0;
-+}
-+
-+static int otto_wdt_probe_reset_mode(struct otto_wdt_ctrl *ctrl)
-+{
-+ static const char *mode_property = "realtek,reset-mode";
-+ const struct fwnode_handle *node = ctrl->dev->fwnode;
-+ int mode_count;
-+ u32 mode;
-+ u32 v;
-+
-+ if (!node)
-+ return -ENXIO;
-+
-+ mode_count = fwnode_property_string_array_count(node, mode_property);
-+ if (mode_count < 0)
-+ return mode_count;
-+ else if (mode_count == 0)
-+ return 0;
-+ else if (mode_count != 1)
-+ return -EINVAL;
-+
-+ if (fwnode_property_match_string(node, mode_property, "soc") == 0)
-+ mode = OTTO_WDT_MODE_SOC;
-+ else if (fwnode_property_match_string(node, mode_property, "cpu") == 0)
-+ mode = OTTO_WDT_MODE_CPU;
-+ else if (fwnode_property_match_string(node, mode_property, "software") == 0)
-+ mode = OTTO_WDT_MODE_SOFTWARE;
-+ else
-+ return -EINVAL;
-+
-+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
-+ v &= ~OTTO_WDT_CTRL_RST_MODE;
-+ v |= FIELD_PREP(OTTO_WDT_CTRL_RST_MODE, mode);
-+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
-+
-+ return 0;
-+}
-+
-+static int otto_wdt_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct otto_wdt_ctrl *ctrl;
-+ unsigned int max_tick_ms;
-+ int ret;
-+
-+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
-+ if (!ctrl)
-+ return -ENOMEM;
-+
-+ ctrl->dev = dev;
-+ ctrl->base = devm_platform_ioremap_resource(pdev, 0);
-+ if (IS_ERR(ctrl->base))
-+ return PTR_ERR(ctrl->base);
-+
-+ /* Clear any old interrupts and reset initial state */
-+ iowrite32(OTTO_WDT_INTR_PHASE_1 | OTTO_WDT_INTR_PHASE_2,
-+ ctrl->base + OTTO_WDT_REG_INTR);
-+ iowrite32(OTTO_WDT_CTRL_DEFAULT, ctrl->base + OTTO_WDT_REG_CTRL);
-+
-+ ret = otto_wdt_probe_clk(ctrl);
-+ if (ret)
-+ return ret;
-+
-+ ctrl->irq_phase1 = platform_get_irq_byname(pdev, "phase1");
-+ if (ctrl->irq_phase1 < 0)
-+ return ctrl->irq_phase1;
-+
-+ ret = devm_request_irq(dev, ctrl->irq_phase1, otto_wdt_phase1_isr, 0,
-+ "realtek-otto-wdt", ctrl);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to get IRQ for phase1\n");
-+
-+ ret = otto_wdt_probe_reset_mode(ctrl);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Invalid reset mode specified\n");
-+
-+ ctrl->wdev.parent = dev;
-+ ctrl->wdev.info = &otto_wdt_info;
-+ ctrl->wdev.ops = &otto_wdt_ops;
-+
-+ /*
-+ * Since pretimeout cannot be disabled, min. timeout is twice the
-+ * subsystem resolution. Max. timeout is ca. 43s at a bus clock of 200MHz.
-+ */
-+ ctrl->wdev.min_timeout = 2;
-+ max_tick_ms = otto_wdt_tick_ms(ctrl, OTTO_WDT_PRESCALE_MAX);
-+ ctrl->wdev.max_hw_heartbeat_ms = max_tick_ms * OTTO_WDT_TIMEOUT_TICKS_MAX;
-+ ctrl->wdev.timeout = min(30U, ctrl->wdev.max_hw_heartbeat_ms / 1000);
-+
-+ watchdog_set_drvdata(&ctrl->wdev, ctrl);
-+ watchdog_init_timeout(&ctrl->wdev, 0, dev);
-+ watchdog_stop_on_reboot(&ctrl->wdev);
-+ watchdog_set_restart_priority(&ctrl->wdev, 128);
-+
-+ ret = otto_wdt_determine_timeouts(&ctrl->wdev, ctrl->wdev.timeout, 1);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to set timeout\n");
-+
-+ return devm_watchdog_register_device(dev, &ctrl->wdev);
-+}
-+
-+static const struct of_device_id otto_wdt_ids[] = {
-+ { .compatible = "realtek,rtl8380-wdt" },
-+ { .compatible = "realtek,rtl8390-wdt" },
-+ { .compatible = "realtek,rtl9300-wdt" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, otto_wdt_ids);
-+
-+static struct platform_driver otto_wdt_driver = {
-+ .probe = otto_wdt_probe,
-+ .driver = {
-+ .name = "realtek-otto-watchdog",
-+ .of_match_table = otto_wdt_ids,
-+ },
-+};
-+module_platform_driver(otto_wdt_driver);
-+
-+MODULE_LICENSE("GPL v2");
-+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
-+MODULE_DESCRIPTION("Realtek Otto watchdog timer driver");
+++ /dev/null
-From c6af53f038aa32cec12e8a305ba07c7ef168f1b0 Mon Sep 17 00:00:00 2001
-From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
-Date: Tue, 4 Jan 2022 12:07:00 +0000
-Subject: [PATCH 2/3] net: mdio: add helpers to extract clause 45 regad and
- devad fields
-
-Add a couple of helpers and definitions to extract the clause 45 regad
-and devad fields from the regnum passed into MDIO drivers.
-
-Tested-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- include/linux/mdio.h | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/include/linux/mdio.h
-+++ b/include/linux/mdio.h
-@@ -7,6 +7,7 @@
- #define __LINUX_MDIO_H__
-
- #include <uapi/linux/mdio.h>
-+#include <linux/bitfield.h>
- #include <linux/mod_devicetable.h>
-
- /* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
-@@ -14,6 +15,7 @@
- */
- #define MII_ADDR_C45 (1<<30)
- #define MII_DEVADDR_C45_SHIFT 16
-+#define MII_DEVADDR_C45_MASK GENMASK(20, 16)
- #define MII_REGADDR_C45_MASK GENMASK(15, 0)
-
- struct gpio_desc;
-@@ -355,6 +357,16 @@ static inline u32 mdiobus_c45_addr(int d
- return MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum;
- }
-
-+static inline u16 mdiobus_c45_regad(u32 regnum)
-+{
-+ return FIELD_GET(MII_REGADDR_C45_MASK, regnum);
-+}
-+
-+static inline u16 mdiobus_c45_devad(u32 regnum)
-+{
-+ return FIELD_GET(MII_DEVADDR_C45_MASK, regnum);
-+}
-+
- static inline int __mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
- u16 regnum)
- {
+++ /dev/null
-From 512c5be35223d9baa2629efa1084cf5210eaee80 Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <sander@svanheule.net>
-Date: Sat, 9 Apr 2022 21:55:47 +0200
-Subject: [PATCH 2/6] gpio: realtek-otto: Support reversed port layouts
-
-The GPIO port layout on the RTL930x SoC series is reversed compared to
-the RTL838x and RTL839x SoC series. Add new port offset calculator
-functions to ensure the correct order is used when reading port IRQ
-data, and ensure bgpio uses the right byte ordering.
-
-Signed-off-by: Sander Vanheule <sander@svanheule.net>
-Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
----
- drivers/gpio/gpio-realtek-otto.c | 55 +++++++++++++++++++++++++++++---
- 1 file changed, 51 insertions(+), 4 deletions(-)
-
---- a/drivers/gpio/gpio-realtek-otto.c
-+++ b/drivers/gpio/gpio-realtek-otto.c
-@@ -58,6 +58,8 @@ struct realtek_gpio_ctrl {
- raw_spinlock_t lock;
- u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
- u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
-+ unsigned int (*port_offset_u8)(unsigned int port);
-+ unsigned int (*port_offset_u16)(unsigned int port);
- };
-
- /* Expand with more flags as devices with other quirks are added */
-@@ -69,6 +71,11 @@ enum realtek_gpio_flags {
- * line the IRQ handler was assigned to, causing uncaught interrupts.
- */
- GPIO_INTERRUPTS_DISABLED = BIT(0),
-+ /*
-+ * Port order is reversed, meaning DCBA register layout for 1-bit
-+ * fields, and [BA, DC] for 2-bit fields.
-+ */
-+ GPIO_PORTS_REVERSED = BIT(1),
- };
-
- static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
-@@ -86,21 +93,50 @@ static struct realtek_gpio_ctrl *irq_dat
- * port. The two interrupt mask registers store two bits per GPIO, so use u16
- * values.
- */
-+static unsigned int realtek_gpio_port_offset_u8(unsigned int port)
-+{
-+ return port;
-+}
-+
-+static unsigned int realtek_gpio_port_offset_u16(unsigned int port)
-+{
-+ return 2 * port;
-+}
-+
-+/*
-+ * Reversed port order register access
-+ *
-+ * For registers with one bit per GPIO, all ports are stored as u8-s in one
-+ * register in reversed order. The two interrupt mask registers store two bits
-+ * per GPIO, so use u16 values. The first register contains ports 1 and 0, the
-+ * second ports 3 and 2.
-+ */
-+static unsigned int realtek_gpio_port_offset_u8_rev(unsigned int port)
-+{
-+ return 3 - port;
-+}
-+
-+static unsigned int realtek_gpio_port_offset_u16_rev(unsigned int port)
-+{
-+ return 2 * (port ^ 1);
-+}
-+
- static void realtek_gpio_write_imr(struct realtek_gpio_ctrl *ctrl,
- unsigned int port, u16 irq_type, u16 irq_mask)
- {
-- iowrite16(irq_type & irq_mask, ctrl->base + REALTEK_GPIO_REG_IMR + 2 * port);
-+ iowrite16(irq_type & irq_mask,
-+ ctrl->base + REALTEK_GPIO_REG_IMR + ctrl->port_offset_u16(port));
- }
-
- static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl,
- unsigned int port, u8 mask)
- {
-- iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + port);
-+ iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
- }
-
- static u8 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl, unsigned int port)
- {
-- return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + port);
-+ return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
- }
-
- /* Set the rising and falling edge mask bits for a GPIO port pin */
-@@ -250,6 +286,7 @@ MODULE_DEVICE_TABLE(of, realtek_gpio_of_
- static int realtek_gpio_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
-+ unsigned long bgpio_flags;
- unsigned int dev_flags;
- struct gpio_irq_chip *girq;
- struct realtek_gpio_ctrl *ctrl;
-@@ -277,10 +314,20 @@ static int realtek_gpio_probe(struct pla
-
- raw_spin_lock_init(&ctrl->lock);
-
-+ if (dev_flags & GPIO_PORTS_REVERSED) {
-+ bgpio_flags = 0;
-+ ctrl->port_offset_u8 = realtek_gpio_port_offset_u8_rev;
-+ ctrl->port_offset_u16 = realtek_gpio_port_offset_u16_rev;
-+ } else {
-+ bgpio_flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
-+ ctrl->port_offset_u8 = realtek_gpio_port_offset_u8;
-+ ctrl->port_offset_u16 = realtek_gpio_port_offset_u16;
-+ }
-+
- err = bgpio_init(&ctrl->gc, dev, 4,
- ctrl->base + REALTEK_GPIO_REG_DATA, NULL, NULL,
- ctrl->base + REALTEK_GPIO_REG_DIR, NULL,
-- BGPIOF_BIG_ENDIAN_BYTE_ORDER);
-+ bgpio_flags);
- if (err) {
- dev_err(dev, "unable to init generic GPIO");
- return err;
+++ /dev/null
-From 95fa6dbe58f286a8f87cb37b7516232eb678de2d Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <sander@svanheule.net>
-Date: Sat, 9 Apr 2022 21:55:48 +0200
-Subject: [PATCH 3/6] gpio: realtek-otto: Support per-cpu interrupts
-
-On SoCs with multiple cores, it is possible that the GPIO interrupt
-controller supports assigning specific pins to one or more cores.
-
-IRQ balancing can be performed on a line-by-line basis if the parent
-interrupt is routed to all available cores, which is the default upon
-initialisation.
-
-Signed-off-by: Sander Vanheule <sander@svanheule.net>
-Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
----
- drivers/gpio/gpio-realtek-otto.c | 75 +++++++++++++++++++++++++++++++-
- 1 file changed, 74 insertions(+), 1 deletion(-)
-
---- a/drivers/gpio/gpio-realtek-otto.c
-+++ b/drivers/gpio/gpio-realtek-otto.c
-@@ -1,6 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0-only
-
- #include <linux/gpio/driver.h>
-+#include <linux/cpumask.h>
- #include <linux/irq.h>
- #include <linux/minmax.h>
- #include <linux/mod_devicetable.h>
-@@ -55,6 +56,8 @@
- struct realtek_gpio_ctrl {
- struct gpio_chip gc;
- void __iomem *base;
-+ void __iomem *cpumask_base;
-+ struct cpumask cpu_irq_maskable;
- raw_spinlock_t lock;
- u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
- u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
-@@ -76,6 +79,11 @@ enum realtek_gpio_flags {
- * fields, and [BA, DC] for 2-bit fields.
- */
- GPIO_PORTS_REVERSED = BIT(1),
-+ /*
-+ * Interrupts can be enabled per cpu. This requires a secondary IO
-+ * range, where the per-cpu enable masks are located.
-+ */
-+ GPIO_INTERRUPTS_PER_CPU = BIT(2),
- };
-
- static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
-@@ -247,14 +255,61 @@ static void realtek_gpio_irq_handler(str
- chained_irq_exit(irq_chip, desc);
- }
-
-+static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl,
-+ unsigned int port, int cpu)
-+{
-+ return ctrl->cpumask_base + ctrl->port_offset_u8(port) +
-+ REALTEK_GPIO_PORTS_PER_BANK * cpu;
-+}
-+
-+static int realtek_gpio_irq_set_affinity(struct irq_data *data,
-+ const struct cpumask *dest, bool force)
-+{
-+ struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
-+ unsigned int line = irqd_to_hwirq(data);
-+ unsigned int port = line / 8;
-+ unsigned int port_pin = line % 8;
-+ void __iomem *irq_cpu_mask;
-+ unsigned long flags;
-+ int cpu;
-+ u8 v;
-+
-+ if (!ctrl->cpumask_base)
-+ return -ENXIO;
-+
-+ raw_spin_lock_irqsave(&ctrl->lock, flags);
-+
-+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
-+ irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
-+ v = ioread8(irq_cpu_mask);
-+
-+ if (cpumask_test_cpu(cpu, dest))
-+ v |= BIT(port_pin);
-+ else
-+ v &= ~BIT(port_pin);
-+
-+ iowrite8(v, irq_cpu_mask);
-+ }
-+
-+ raw_spin_unlock_irqrestore(&ctrl->lock, flags);
-+
-+ irq_data_update_effective_affinity(data, dest);
-+
-+ return 0;
-+}
-+
- static int realtek_gpio_irq_init(struct gpio_chip *gc)
- {
- struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
- unsigned int port;
-+ int cpu;
-
- for (port = 0; (port * 8) < gc->ngpio; port++) {
- realtek_gpio_write_imr(ctrl, port, 0, 0);
- realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
-+
-+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable)
-+ iowrite8(GENMASK(7, 0), realtek_gpio_irq_cpu_mask(ctrl, port, cpu));
- }
-
- return 0;
-@@ -266,6 +321,7 @@ static struct irq_chip realtek_gpio_irq_
- .irq_mask = realtek_gpio_irq_mask,
- .irq_unmask = realtek_gpio_irq_unmask,
- .irq_set_type = realtek_gpio_irq_set_type,
-+ .irq_set_affinity = realtek_gpio_irq_set_affinity,
- };
-
- static const struct of_device_id realtek_gpio_of_match[] = {
-@@ -290,8 +346,10 @@ static int realtek_gpio_probe(struct pla
- unsigned int dev_flags;
- struct gpio_irq_chip *girq;
- struct realtek_gpio_ctrl *ctrl;
-+ struct resource *res;
- u32 ngpios;
-- int err, irq;
-+ unsigned int nr_cpus;
-+ int cpu, err, irq;
-
- ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
- if (!ctrl)
-@@ -352,6 +410,21 @@ static int realtek_gpio_probe(struct pla
- girq->init_hw = realtek_gpio_irq_init;
- }
-
-+ cpumask_clear(&ctrl->cpu_irq_maskable);
-+
-+ if ((dev_flags & GPIO_INTERRUPTS_PER_CPU) && irq > 0) {
-+ ctrl->cpumask_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
-+ if (IS_ERR(ctrl->cpumask_base))
-+ return dev_err_probe(dev, PTR_ERR(ctrl->cpumask_base),
-+ "missing CPU IRQ mask registers");
-+
-+ nr_cpus = resource_size(res) / REALTEK_GPIO_PORTS_PER_BANK;
-+ nr_cpus = min(nr_cpus, num_present_cpus());
-+
-+ for (cpu = 0; cpu < nr_cpus; cpu++)
-+ cpumask_set_cpu(cpu, &ctrl->cpu_irq_maskable);
-+ }
-+
- return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
- }
-
+++ /dev/null
-From deaf1cecdeb052cdb5e92fd642016198724b44a4 Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <sander@svanheule.net>
-Date: Sat, 9 Apr 2022 21:55:49 +0200
-Subject: [PATCH 4/6] gpio: realtek-otto: Add RTL930x support
-
-The RTL930x SoC series has support for 24 GPIOs, with the port order
-reversed compared to RTL838x and RTL839x. The RTL930x series also has
-two CPUs (VPEs) and can distribute individual GPIO interrupts between
-them.
-
-Signed-off-by: Sander Vanheule <sander@svanheule.net>
-Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
----
- drivers/gpio/gpio-realtek-otto.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/gpio/gpio-realtek-otto.c
-+++ b/drivers/gpio/gpio-realtek-otto.c
-@@ -335,6 +335,10 @@ static const struct of_device_id realtek
- {
- .compatible = "realtek,rtl8390-gpio",
- },
-+ {
-+ .compatible = "realtek,rtl9300-gpio",
-+ .data = (void *)(GPIO_PORTS_REVERSED | GPIO_INTERRUPTS_PER_CPU)
-+ },
- {}
- };
- MODULE_DEVICE_TABLE(of, realtek_gpio_of_match);
+++ /dev/null
-From d3bf3dc4bbbf6109bd9b4bd60089d36205ec4a37 Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <sander@svanheule.net>
-Date: Sat, 9 Apr 2022 21:55:51 +0200
-Subject: [PATCH 6/6] gpio: realtek-otto: Add RTL931x support
-
-The RTL931x SoC series has support for 32 GPIOs, although not all lines
-may be broken out to a physical pad.
-
-The GPIO bank's parent interrupt can be routed to either or both of the
-SoC's CPU cores by the GIC. Line-by-line IRQ balancing is not possible
-on these SoCs.
-
-Signed-off-by: Sander Vanheule <sander@svanheule.net>
-Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
----
- drivers/gpio/gpio-realtek-otto.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/gpio/gpio-realtek-otto.c
-+++ b/drivers/gpio/gpio-realtek-otto.c
-@@ -339,6 +339,9 @@ static const struct of_device_id realtek
- .compatible = "realtek,rtl9300-gpio",
- .data = (void *)(GPIO_PORTS_REVERSED | GPIO_INTERRUPTS_PER_CPU)
- },
-+ {
-+ .compatible = "realtek,rtl9310-gpio",
-+ },
- {}
- };
- MODULE_DEVICE_TABLE(of, realtek_gpio_of_match);
+++ /dev/null
-From b8fc5eecdc5d33cf261986436597b5482ab856da Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <sander@svanheule.net>
-Date: Sun, 14 Nov 2021 19:45:32 +0100
-Subject: [PATCH] realtek: Backport Realtek Otto WDT driver
-
-Add patch submitted upstream to linux-watchdog and replace the MIPS
-architecture symbols. Requires one extra patch for the DIV_ROUND_*
-macros, which have moved to a different header since 5.10.
-
-Submitted-by: Sander Vanheule <sander@svanheule.net>
-Tested-by: Stijn Segers <foss@volatilesystems.org>
-Tested-by: Paul Fertser <fercerpav@gmail.com>
-Tested-by: Stijn Tintel <stijn@linux-ipv6.be>
----
- drivers/watchdog/realtek_otto_wdt.c | 2 +-
- 1 files changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/watchdog/realtek_otto_wdt.c
-+++ b/drivers/watchdog/realtek_otto_wdt.c
-@@ -21,7 +21,7 @@
- #include <linux/delay.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
--#include <linux/math.h>
-+#include <linux/kernel.h>
- #include <linux/minmax.h>
- #include <linux/module.h>
- #include <linux/mod_devicetable.h>
+++ /dev/null
-From bde6311569ef25a00c3beaeabfd6b78b19651872 Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <sander@svanheule.net>
-Date: Sun, 29 May 2022 19:38:09 +0200
-Subject: [PATCH] realtek: don't unmask non-maskable GPIO IRQs
-
-On uniprocessor builds, for_each_cpu(cpu, mask) will assume 'mask'
-always contains exactly one CPU, and ignore the actual mask contents.
-This causes the loop to run, even when it shouldn't on an empty mask,
-and tries to access an uninitialised pointer.
-
-Fix this by wrapping the loop in a cpumask_empty() check, to ensure it
-will not run on uniprocessor builds if the CPU mask is empty.
-
-Fixes: af6cd37f42f3 ("realtek: replace RTL93xx GPIO patches")
-Reported-by: INAGAKI Hiroshi <musashino.open@gmail.com>
-Reported-by: Robert Marko <robimarko@gmail.com>
-Tested-by: Robert Marko <robimarko@gmail.com>
-Submitted-by: Sander Vanheule <sander@svanheule.net>
----
- drivers/gpio/gpio-realtek-otto.c | 9 +++++++++++--
- 1 file changed, 11 insertions(+), 2 deletions(-)
-
---- a/drivers/gpio/gpio-realtek-otto.c
-+++ b/drivers/gpio/gpio-realtek-otto.c
-@@ -301,6 +301,7 @@ static int realtek_gpio_irq_set_affinity
- static int realtek_gpio_irq_init(struct gpio_chip *gc)
- {
- struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
-+ void __iomem *irq_cpu_mask;
- unsigned int port;
- int cpu;
-
-@@ -308,8 +309,16 @@ static int realtek_gpio_irq_init(struct
- realtek_gpio_write_imr(ctrl, port, 0, 0);
- realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
-
-- for_each_cpu(cpu, &ctrl->cpu_irq_maskable)
-- iowrite8(GENMASK(7, 0), realtek_gpio_irq_cpu_mask(ctrl, port, cpu));
-+ /*
-+ * Uniprocessor builds assume a mask always contains one CPU,
-+ * so only start the loop if we have at least one maskable CPU.
-+ */
-+ if(!cpumask_empty(&ctrl->cpu_irq_maskable)) {
-+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
-+ irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
-+ iowrite8(GENMASK(7, 0), irq_cpu_mask);
-+ }
-+ }
- }
-
- return 0;
+++ /dev/null
-From ee0175b3b44288c74d5292c2a9c2c154f6c0317e Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <sander@svanheule.net>
-Date: Sun, 7 Aug 2022 21:21:15 +0200
-Subject: [PATCH] gpio: realtek-otto: switch to 32-bit I/O
-
-By using 16-bit I/O on the GPIO peripheral, which is apparently not safe
-on MIPS, the IMR can end up containing garbage. This then results in
-interrupt triggers for lines that don't have an interrupt handler
-associated. The irq_desc lookup fails, and the ISR will not be cleared,
-keeping the CPU busy until reboot, or until another IMR operation
-restores the correct value. This situation appears to happen very
-rarely, for < 0.5% of IMR writes.
-
-Instead of using 8-bit or 16-bit I/O operations on the 32-bit memory
-mapped peripheral registers, switch to using 32-bit I/O only, operating
-on the entire bank for all single bit line settings. For 2-bit line
-settings, with 16-bit port values, stick to manual (un)packing.
-
-This issue has been seen on RTL8382M (HPE 1920-16G), RTL8391M (Netgear
-GS728TP v2), and RTL8393M (D-Link DGS-1210-52 F3, Zyxel GS1900-48).
-
-Reported-by: Luiz Angelo Daros de Luca <luizluca@gmail.com> # DGS-1210-52
-Reported-by: Birger Koblitz <mail@birger-koblitz.de> # GS728TP
-Reported-by: Jan Hoffmann <jan@3e8.eu> # 1920-16G
-Fixes: 0d82fb1127fb ("gpio: Add Realtek Otto GPIO support")
-Signed-off-by: Sander Vanheule <sander@svanheule.net>
-Cc: Paul Cercueil <paul@crapouillou.net>
-Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
-Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
-
-Update patch for missing upstream changes:
- - commit a01a40e33499 ("gpio: realtek-otto: Make the irqchip immutable")
-Signed-off-by: Sander Vanheule <sander@svanheule.net>
-
----
- drivers/gpio/gpio-realtek-otto.c | 166 ++++++++++++++++---------------
- 1 file changed, 85 insertions(+), 81 deletions(-)
-
---- a/drivers/gpio/gpio-realtek-otto.c
-+++ b/drivers/gpio/gpio-realtek-otto.c
-@@ -46,10 +46,20 @@
- * @lock: Lock for accessing the IRQ registers and values
- * @intr_mask: Mask for interrupts lines
- * @intr_type: Interrupt type selection
-+ * @bank_read: Read a bank setting as a single 32-bit value
-+ * @bank_write: Write a bank setting as a single 32-bit value
-+ * @imr_line_pos: Bit shift of an IRQ line's IMR value.
-+ *
-+ * The DIR, DATA, and ISR registers consist of four 8-bit port values, packed
-+ * into a single 32-bit register. Use @bank_read (@bank_write) to get (assign)
-+ * a value from (to) these registers. The IMR register consists of four 16-bit
-+ * port values, packed into two 32-bit registers. Use @imr_line_pos to get the
-+ * bit shift of the 2-bit field for a line's IMR settings. Shifts larger than
-+ * 32 overflow into the second register.
- *
- * Because the interrupt mask register (IMR) combines the function of IRQ type
- * selection and masking, two extra values are stored. @intr_mask is used to
-- * mask/unmask the interrupts for a GPIO port, and @intr_type is used to store
-+ * mask/unmask the interrupts for a GPIO line, and @intr_type is used to store
- * the selected interrupt types. The logical AND of these values is written to
- * IMR on changes.
- */
-@@ -59,10 +69,11 @@ struct realtek_gpio_ctrl {
- void __iomem *cpumask_base;
- struct cpumask cpu_irq_maskable;
- raw_spinlock_t lock;
-- u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
-- u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
-- unsigned int (*port_offset_u8)(unsigned int port);
-- unsigned int (*port_offset_u16)(unsigned int port);
-+ u8 intr_mask[REALTEK_GPIO_MAX];
-+ u8 intr_type[REALTEK_GPIO_MAX];
-+ u32 (*bank_read)(void __iomem *reg);
-+ void (*bank_write)(void __iomem *reg, u32 value);
-+ unsigned int (*line_imr_pos)(unsigned int line);
- };
-
- /* Expand with more flags as devices with other quirks are added */
-@@ -101,14 +112,22 @@ static struct realtek_gpio_ctrl *irq_dat
- * port. The two interrupt mask registers store two bits per GPIO, so use u16
- * values.
- */
--static unsigned int realtek_gpio_port_offset_u8(unsigned int port)
-+static u32 realtek_gpio_bank_read_swapped(void __iomem *reg)
-+{
-+ return ioread32be(reg);
-+}
-+
-+static void realtek_gpio_bank_write_swapped(void __iomem *reg, u32 value)
- {
-- return port;
-+ iowrite32be(value, reg);
- }
-
--static unsigned int realtek_gpio_port_offset_u16(unsigned int port)
-+static unsigned int realtek_gpio_line_imr_pos_swapped(unsigned int line)
- {
-- return 2 * port;
-+ unsigned int port_pin = line % 8;
-+ unsigned int port = line / 8;
-+
-+ return 2 * (8 * (port ^ 1) + port_pin);
- }
-
- /*
-@@ -119,64 +138,65 @@ static unsigned int realtek_gpio_port_of
- * per GPIO, so use u16 values. The first register contains ports 1 and 0, the
- * second ports 3 and 2.
- */
--static unsigned int realtek_gpio_port_offset_u8_rev(unsigned int port)
-+static u32 realtek_gpio_bank_read(void __iomem *reg)
- {
-- return 3 - port;
-+ return ioread32(reg);
- }
-
--static unsigned int realtek_gpio_port_offset_u16_rev(unsigned int port)
-+static void realtek_gpio_bank_write(void __iomem *reg, u32 value)
- {
-- return 2 * (port ^ 1);
-+ iowrite32(value, reg);
- }
-
--static void realtek_gpio_write_imr(struct realtek_gpio_ctrl *ctrl,
-- unsigned int port, u16 irq_type, u16 irq_mask)
-+static unsigned int realtek_gpio_line_imr_pos(unsigned int line)
- {
-- iowrite16(irq_type & irq_mask,
-- ctrl->base + REALTEK_GPIO_REG_IMR + ctrl->port_offset_u16(port));
-+ return 2 * line;
- }
-
--static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl,
-- unsigned int port, u8 mask)
-+static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl, u32 mask)
- {
-- iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
-+ ctrl->bank_write(ctrl->base + REALTEK_GPIO_REG_ISR, mask);
- }
-
--static u8 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl, unsigned int port)
-+static u32 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl)
- {
-- return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
-+ return ctrl->bank_read(ctrl->base + REALTEK_GPIO_REG_ISR);
- }
-
--/* Set the rising and falling edge mask bits for a GPIO port pin */
--static u16 realtek_gpio_imr_bits(unsigned int pin, u16 value)
-+/* Set the rising and falling edge mask bits for a GPIO pin */
-+static void realtek_gpio_update_line_imr(struct realtek_gpio_ctrl *ctrl, unsigned int line)
- {
-- return (value & REALTEK_GPIO_IMR_LINE_MASK) << 2 * pin;
-+ void __iomem *reg = ctrl->base + REALTEK_GPIO_REG_IMR;
-+ unsigned int line_shift = ctrl->line_imr_pos(line);
-+ unsigned int shift = line_shift % 32;
-+ u32 irq_type = ctrl->intr_type[line];
-+ u32 irq_mask = ctrl->intr_mask[line];
-+ u32 reg_val;
-+
-+ reg += 4 * (line_shift / 32);
-+ reg_val = ioread32(reg);
-+ reg_val &= ~(REALTEK_GPIO_IMR_LINE_MASK << shift);
-+ reg_val |= (irq_type & irq_mask & REALTEK_GPIO_IMR_LINE_MASK) << shift;
-+ iowrite32(reg_val, reg);
- }
-
- static void realtek_gpio_irq_ack(struct irq_data *data)
- {
- struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
- irq_hw_number_t line = irqd_to_hwirq(data);
-- unsigned int port = line / 8;
-- unsigned int port_pin = line % 8;
-
-- realtek_gpio_clear_isr(ctrl, port, BIT(port_pin));
-+ realtek_gpio_clear_isr(ctrl, BIT(line));
- }
-
- static void realtek_gpio_irq_unmask(struct irq_data *data)
- {
- struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
- unsigned int line = irqd_to_hwirq(data);
-- unsigned int port = line / 8;
-- unsigned int port_pin = line % 8;
- unsigned long flags;
-- u16 m;
-
- raw_spin_lock_irqsave(&ctrl->lock, flags);
-- m = ctrl->intr_mask[port];
-- m |= realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
-- ctrl->intr_mask[port] = m;
-- realtek_gpio_write_imr(ctrl, port, ctrl->intr_type[port], m);
-+ ctrl->intr_mask[line] = REALTEK_GPIO_IMR_LINE_MASK;
-+ realtek_gpio_update_line_imr(ctrl, line);
- raw_spin_unlock_irqrestore(&ctrl->lock, flags);
- }
-
-@@ -184,16 +204,11 @@ static void realtek_gpio_irq_mask(struct
- {
- struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
- unsigned int line = irqd_to_hwirq(data);
-- unsigned int port = line / 8;
-- unsigned int port_pin = line % 8;
- unsigned long flags;
-- u16 m;
-
- raw_spin_lock_irqsave(&ctrl->lock, flags);
-- m = ctrl->intr_mask[port];
-- m &= ~realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
-- ctrl->intr_mask[port] = m;
-- realtek_gpio_write_imr(ctrl, port, ctrl->intr_type[port], m);
-+ ctrl->intr_mask[line] = 0;
-+ realtek_gpio_update_line_imr(ctrl, line);
- raw_spin_unlock_irqrestore(&ctrl->lock, flags);
- }
-
-@@ -201,10 +216,8 @@ static int realtek_gpio_irq_set_type(str
- {
- struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
- unsigned int line = irqd_to_hwirq(data);
-- unsigned int port = line / 8;
-- unsigned int port_pin = line % 8;
- unsigned long flags;
-- u16 type, t;
-+ u8 type;
-
- switch (flow_type & IRQ_TYPE_SENSE_MASK) {
- case IRQ_TYPE_EDGE_FALLING:
-@@ -223,11 +236,8 @@ static int realtek_gpio_irq_set_type(str
- irq_set_handler_locked(data, handle_edge_irq);
-
- raw_spin_lock_irqsave(&ctrl->lock, flags);
-- t = ctrl->intr_type[port];
-- t &= ~realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
-- t |= realtek_gpio_imr_bits(port_pin, type);
-- ctrl->intr_type[port] = t;
-- realtek_gpio_write_imr(ctrl, port, t, ctrl->intr_mask[port]);
-+ ctrl->intr_type[line] = type;
-+ realtek_gpio_update_line_imr(ctrl, line);
- raw_spin_unlock_irqrestore(&ctrl->lock, flags);
-
- return 0;
-@@ -238,28 +248,21 @@ static void realtek_gpio_irq_handler(str
- struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
- struct irq_chip *irq_chip = irq_desc_get_chip(desc);
-- unsigned int lines_done;
-- unsigned int port_pin_count;
- unsigned long status;
- int offset;
-
- chained_irq_enter(irq_chip, desc);
-
-- for (lines_done = 0; lines_done < gc->ngpio; lines_done += 8) {
-- status = realtek_gpio_read_isr(ctrl, lines_done / 8);
-- port_pin_count = min(gc->ngpio - lines_done, 8U);
-- for_each_set_bit(offset, &status, port_pin_count)
-- generic_handle_domain_irq(gc->irq.domain, offset + lines_done);
-- }
-+ status = realtek_gpio_read_isr(ctrl);
-+ for_each_set_bit(offset, &status, gc->ngpio)
-+ generic_handle_domain_irq(gc->irq.domain, offset);
-
- chained_irq_exit(irq_chip, desc);
- }
-
--static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl,
-- unsigned int port, int cpu)
-+static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl, int cpu)
- {
-- return ctrl->cpumask_base + ctrl->port_offset_u8(port) +
-- REALTEK_GPIO_PORTS_PER_BANK * cpu;
-+ return ctrl->cpumask_base + REALTEK_GPIO_PORTS_PER_BANK * cpu;
- }
-
- static int realtek_gpio_irq_set_affinity(struct irq_data *data,
-@@ -267,12 +270,10 @@ static int realtek_gpio_irq_set_affinity
- {
- struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
- unsigned int line = irqd_to_hwirq(data);
-- unsigned int port = line / 8;
-- unsigned int port_pin = line % 8;
- void __iomem *irq_cpu_mask;
- unsigned long flags;
- int cpu;
-- u8 v;
-+ u32 v;
-
- if (!ctrl->cpumask_base)
- return -ENXIO;
-@@ -280,15 +281,15 @@ static int realtek_gpio_irq_set_affinity
- raw_spin_lock_irqsave(&ctrl->lock, flags);
-
- for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
-- irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
-- v = ioread8(irq_cpu_mask);
-+ irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, cpu);
-+ v = ctrl->bank_read(irq_cpu_mask);
-
- if (cpumask_test_cpu(cpu, dest))
-- v |= BIT(port_pin);
-+ v |= BIT(line);
- else
-- v &= ~BIT(port_pin);
-+ v &= ~BIT(line);
-
-- iowrite8(v, irq_cpu_mask);
-+ ctrl->bank_write(irq_cpu_mask, v);
- }
-
- raw_spin_unlock_irqrestore(&ctrl->lock, flags);
-@@ -302,22 +303,23 @@ static int realtek_gpio_irq_init(struct
- {
- struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
- void __iomem *irq_cpu_mask;
-- unsigned int port;
-+ u32 mask_all = GENMASK(gc->ngpio - 1, 0);
-+ unsigned int line;
- int cpu;
-
-- for (port = 0; (port * 8) < gc->ngpio; port++) {
-- realtek_gpio_write_imr(ctrl, port, 0, 0);
-- realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
--
-- /*
-- * Uniprocessor builds assume a mask always contains one CPU,
-- * so only start the loop if we have at least one maskable CPU.
-- */
-- if(!cpumask_empty(&ctrl->cpu_irq_maskable)) {
-- for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
-- irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
-- iowrite8(GENMASK(7, 0), irq_cpu_mask);
-- }
-+ for (line = 0; line < gc->ngpio; line++)
-+ realtek_gpio_update_line_imr(ctrl, line);
-+
-+ realtek_gpio_clear_isr(ctrl, mask_all);
-+
-+ /*
-+ * Uniprocessor builds assume a mask always contains one CPU,
-+ * so only start the loop if we have at least one maskable CPU.
-+ */
-+ if(!cpumask_empty(&ctrl->cpu_irq_maskable)) {
-+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
-+ irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, cpu);
-+ ctrl->bank_write(irq_cpu_mask, mask_all);
- }
- }
-
-@@ -390,12 +392,14 @@ static int realtek_gpio_probe(struct pla
-
- if (dev_flags & GPIO_PORTS_REVERSED) {
- bgpio_flags = 0;
-- ctrl->port_offset_u8 = realtek_gpio_port_offset_u8_rev;
-- ctrl->port_offset_u16 = realtek_gpio_port_offset_u16_rev;
-+ ctrl->bank_read = realtek_gpio_bank_read;
-+ ctrl->bank_write = realtek_gpio_bank_write;
-+ ctrl->line_imr_pos = realtek_gpio_line_imr_pos;
- } else {
- bgpio_flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
-- ctrl->port_offset_u8 = realtek_gpio_port_offset_u8;
-- ctrl->port_offset_u16 = realtek_gpio_port_offset_u16;
-+ ctrl->bank_read = realtek_gpio_bank_read_swapped;
-+ ctrl->bank_write = realtek_gpio_bank_write_swapped;
-+ ctrl->line_imr_pos = realtek_gpio_line_imr_pos_swapped;
- }
-
- err = bgpio_init(&ctrl->gc, dev, 4,