diff mbox series

[RFC,2/3] gpio: rcar: Add support for GPIO alternative interrupt

Message ID 20200422101026.9220-3-erosca@de.adit-jv.com (mailing list archive)
State RFC
Delegated to: Geert Uytterhoeven
Headers show
Series gpio: rcar: Add support for GPIO alternative interrupt | expand

Commit Message

Eugeniu Rosca April 22, 2020, 10:10 a.m. UTC
From: Torii Kenichi <torii.ken1@jp.fujitsu.com>

INTC-AP accepts both GPIO interrupt and GPIO alternative interrupt,
but INTC-RT can only handle GPIO interrupt, as depicted in below excerpt
from 'Figure 7.1 GPIO Block Configuration (1)' of
'R-Car3 HW User's Manual Rev.2.00, Jul 2019':

  +------------------------------+
  | Interrupt  display register  +----> GPIO.ch*  (to INTC-AP, INTC-RT)
  |           (INTDTn)           +----> GPIO.ch*A (to INTC-AP)
  +------------------------------+

It seems to be also the case for earlier Renesas SoCs like RZ/G,
as per 'Figure 6.1 GPIO Block Configuration' in
'RZ/G Series User’s Manual: Hardware Rev.1.00 Sep 2016' [1].

To reduce the interference between RT domain (CR7/SH) and the AP domain
(Cortex A5x) and to independently control GPIO interrupts in these two
domains, add support for processing GPIO alternative interrupts in AP.

This allows handling normal GPIO interrupts exclusively by INTC-RT.
The change is DT-driven and depends on the enablement of the
'use-alternative-interrupt' DTS property.

One caveat is that the 'interrupts' property update must go hand in hand
with the newly added 'use-alternative-interrupt' property.

[1] https://www.renesas.com/eu/en/products/microcontrollers-microprocessors/rz/rzg/rzg1m.html#documents

Signed-off-by: Torii Kenichi <torii.ken1@jp.fujitsu.com>
[erosca: enrich commit description]
Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
---
 drivers/gpio/gpio-rcar.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

Comments

Geert Uytterhoeven April 24, 2020, 8:36 a.m. UTC | #1
Hi Eugeniu,

CC devicetree
CC Stefano

Thanks for forwarding this patch!

On Wed, Apr 22, 2020 at 12:11 PM Eugeniu Rosca <erosca@de.adit-jv.com> wrote:
> From: Torii Kenichi <torii.ken1@jp.fujitsu.com>
>
> INTC-AP accepts both GPIO interrupt and GPIO alternative interrupt,
> but INTC-RT can only handle GPIO interrupt, as depicted in below excerpt
> from 'Figure 7.1 GPIO Block Configuration (1)' of
> 'R-Car3 HW User's Manual Rev.2.00, Jul 2019':
>
>   +------------------------------+
>   | Interrupt  display register  +----> GPIO.ch*  (to INTC-AP, INTC-RT)
>   |           (INTDTn)           +----> GPIO.ch*A (to INTC-AP)
>   +------------------------------+

Note that GPIO.ch[67]A seem to be available on INTC-RT, too. But for
the other channels, you're right in that the "A" variants are connected
to INTC-AP only.

> It seems to be also the case for earlier Renesas SoCs like RZ/G,
> as per 'Figure 6.1 GPIO Block Configuration' in
> 'RZ/G Series User’s Manual: Hardware Rev.1.00 Sep 2016' [1].

On R-Car Gen2, they're called "EXT_INT" resp. "EXT_ALT_INT" instead of
"GPIO.ch*" and "GPIO.ch*A".

> To reduce the interference between RT domain (CR7/SH) and the AP domain
> (Cortex A5x) and to independently control GPIO interrupts in these two
> domains, add support for processing GPIO alternative interrupts in AP.
>
> This allows handling normal GPIO interrupts exclusively by INTC-RT.
> The change is DT-driven and depends on the enablement of the
> 'use-alternative-interrupt' DTS property.
>
> One caveat is that the 'interrupts' property update must go hand in hand
> with the newly added 'use-alternative-interrupt' property.

As I replied to the DT bindings patch, I think the "interrupts" property
should contain both, so "use-alternative-interrupt" can pick the one it
needs.

> Signed-off-by: Torii Kenichi <torii.ken1@jp.fujitsu.com>
> [erosca: enrich commit description]
> Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>

[actual patch[1] deleted, as it doesn't really matter for the discussion].

You may want to look at "LTD20-205 System Device Tree Project"[2],
where Stefano talks about using DT to describe the full system
(I've read the slides, but haven't watched the video yet).

Your patch shows that the assumption "All devices have interrupts routed
to both interrupt controllers" isn't always true.

[1] https://lore.kernel.org/linux-gpio/20200422101026.9220-3-erosca@de.adit-jv.com/
[2] https://connect.linaro.org/resources/ltd20/ltd20-205/

Gr{oetje,eeting}s,

                        Geert


--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
diff mbox series

Patch

diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 7284473c9fe3..6bbab447bba8 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -43,6 +43,8 @@  struct gpio_rcar_priv {
 	bool has_outdtsel;
 	bool has_both_edge_trigger;
 	struct gpio_rcar_bank_info bank_info;
+	int intmsk;
+	int mskclr;
 };
 
 #define IOINTSEL 0x00	/* General IO/Interrupt Switching Register */
@@ -56,6 +58,8 @@  struct gpio_rcar_priv {
 #define POSNEG 0x20	/* Positive/Negative Logic Select Register */
 #define EDGLEVEL 0x24	/* Edge/level Select Register */
 #define FILONOFF 0x28	/* Chattering Prevention On/Off Register */
+#define INTMSKS 0x38	/* Interrupt Sub Mask Register */
+#define MSKCLRS 0x3c	/* Interrupt Sub Mask Clear Register */
 #define OUTDTSEL 0x40	/* Output Data Select Register */
 #define BOTHEDGE 0x4c	/* One Edge/Both Edge Select Register */
 
@@ -90,7 +94,7 @@  static void gpio_rcar_irq_disable(struct irq_data *d)
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 	struct gpio_rcar_priv *p = gpiochip_get_data(gc);
 
-	gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d)));
+	gpio_rcar_write(p, p->intmsk, ~BIT(irqd_to_hwirq(d)));
 }
 
 static void gpio_rcar_irq_enable(struct irq_data *d)
@@ -98,7 +102,7 @@  static void gpio_rcar_irq_enable(struct irq_data *d)
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 	struct gpio_rcar_priv *p = gpiochip_get_data(gc);
 
-	gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d)));
+	gpio_rcar_write(p, p->mskclr, BIT(irqd_to_hwirq(d)));
 }
 
 static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
@@ -203,7 +207,7 @@  static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
 	unsigned int offset, irqs_handled = 0;
 
 	while ((pending = gpio_rcar_read(p, INTDT) &
-			  gpio_rcar_read(p, INTMSK))) {
+			  gpio_rcar_read(p, p->intmsk))) {
 		offset = __ffs(pending);
 		gpio_rcar_write(p, INTCLR, BIT(offset));
 		generic_handle_irq(irq_find_mapping(p->gpio_chip.irq.domain,
@@ -427,6 +431,14 @@  static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
 		*npins = RCAR_MAX_GPIO_PER_BANK;
 	}
 
+	if (of_get_property(np, "use-alternative-interrupt", NULL)) {
+		p->intmsk = INTMSKS;
+		p->mskclr = MSKCLRS;
+	} else {
+		p->intmsk = INTMSK;
+		p->mskclr = MSKCLR;
+	}
+
 	return 0;
 }
 
@@ -544,7 +556,7 @@  static int gpio_rcar_suspend(struct device *dev)
 	p->bank_info.iointsel = gpio_rcar_read(p, IOINTSEL);
 	p->bank_info.inoutsel = gpio_rcar_read(p, INOUTSEL);
 	p->bank_info.outdt = gpio_rcar_read(p, OUTDT);
-	p->bank_info.intmsk = gpio_rcar_read(p, INTMSK);
+	p->bank_info.intmsk = gpio_rcar_read(p, p->intmsk);
 	p->bank_info.posneg = gpio_rcar_read(p, POSNEG);
 	p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL);
 	if (p->has_both_edge_trigger)
@@ -586,7 +598,7 @@  static int gpio_rcar_resume(struct device *dev)
 				!!(p->bank_info.bothedge & mask));
 
 			if (p->bank_info.intmsk & mask)
-				gpio_rcar_write(p, MSKCLR, mask);
+				gpio_rcar_write(p, p->mskclr, mask);
 		}
 	}