aboutsummaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
authorBirger Koblitz <git@birger-koblitz.de>2022-01-17 19:32:54 +0100
committerDaniel Golle <daniel@makrotopia.org>2022-02-17 15:21:46 +0000
commit2314ba725b2b33cd679d46eba42b73f854427632 (patch)
tree4802e092a03aac5e78b0d8310101de13adfaf8ab /target
parent58b82e6ca503aea3f67b4692f2c3196cb0a2ca2c (diff)
downloadupstream-2314ba725b2b33cd679d46eba42b73f854427632.tar.gz
upstream-2314ba725b2b33cd679d46eba42b73f854427632.tar.bz2
upstream-2314ba725b2b33cd679d46eba42b73f854427632.zip
realtek: Add GPIO support for RTL930X and RTL931X
We add support for the RTL930X and RTL931X architectures in the gpio-realtek-otto.c driver. Signed-off-by: Sebastian Gottschall <s.gottschall@dd-wrt.com> Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
Diffstat (limited to 'target')
-rw-r--r--target/linux/realtek/patches-5.10/320-gpio-add-support-for-RTL930X-and-RTL931X.patch165
1 files changed, 165 insertions, 0 deletions
diff --git a/target/linux/realtek/patches-5.10/320-gpio-add-support-for-RTL930X-and-RTL931X.patch b/target/linux/realtek/patches-5.10/320-gpio-add-support-for-RTL930X-and-RTL931X.patch
new file mode 100644
index 0000000000..bd4639433d
--- /dev/null
+++ b/target/linux/realtek/patches-5.10/320-gpio-add-support-for-RTL930X-and-RTL931X.patch
@@ -0,0 +1,165 @@
+--- a/drivers/gpio/gpio-realtek-otto.c
++++ b/drivers/gpio/gpio-realtek-otto.c
+@@ -55,9 +55,12 @@
+ struct realtek_gpio_ctrl {
+ struct gpio_chip gc;
+ void __iomem *base;
++ void __iomem *cpumap_base;
+ 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 +72,16 @@ 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),
++ /*
++ * 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)
+@@ -86,21 +99,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 */
+@@ -222,6 +264,12 @@ static int realtek_gpio_irq_init(struct
+ 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));
++
++ if (ctrl->cpumap_base) {
++ /* Default CPU affinity to the first CPU */
++ iowrite8(GENMASK(7, 0),
++ ctrl->cpumap_base + ctrl->port_offset_u8(port));
++ }
+ }
+
+ return 0;
+@@ -246,6 +294,13 @@ static const struct of_device_id realtek
+ {
+ .compatible = "realtek,rtl8390-gpio",
+ },
++ {
++ .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);
+@@ -253,12 +308,14 @@ 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;
+ u32 ngpios;
+ int err, irq;
+
++ pr_info("%s probing RTL GPIO\n", __func__);
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+@@ -280,10 +337,21 @@ 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;
+@@ -308,6 +376,13 @@ static int realtek_gpio_probe(struct pla
+ girq->init_hw = realtek_gpio_irq_init;
+ }
+
++ if (dev_flags & GPIO_INTERRUPTS_PER_CPU) {
++ ctrl->cpumap_base = devm_platform_ioremap_resource(pdev, 1);
++ if (IS_ERR(ctrl->cpumap_base))
++ return dev_err_probe(dev, PTR_ERR(ctrl->cpumap_base),
++ "IRQ CPU map registers not defined");
++ }
++
+ return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
+ }
+