From: Birger Koblitz Date: Mon, 17 Jan 2022 18:32:54 +0000 (+0100) Subject: realtek: Add GPIO support for RTL930X and RTL931X X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=2314ba725b2b33cd679d46eba42b73f854427632;p=openwrt%2Fstaging%2Faparcar.git 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 Signed-off-by: Birger Koblitz --- 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); + } +