Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: OMAP5+: Fix inverted nirq pin interrupts with irq_set_type

Commit 83a86fbb5b56 ("irqchip/gic: Loudly complain about the use of
IRQ_TYPE_NONE") started warning about incorrect dts usage for irqs.
ARM GIC only supports active-high interrupts for SPI (Shared Peripheral
Interrupts), and the Palmas PMIC by default is active-low.

Palmas PMIC allows changing the interrupt polarity using register
PALMAS_POLARITY_CTRL_INT_POLARITY, but configuring sys_nirq1 with
a pull-down and setting PALMAS_POLARITY_CTRL_INT_POLARITY made the
Palmas RTC interrupts stop working. This can be easily tested with
kernel tools rtctest.c.

Turns out the SoC inverts the sys_nirq pins for GIC as they do not go
through a peripheral device but go directly to the MPUSS wakeupgen.
I've verified this by muxing the interrupt line temporarily to gpio_wk16
instead of sys_nirq1. with a gpio, the interrupt works fine both
active-low and active-high with the SoC internal pull configured and
palmas polarity configured. But as sys_nirq1, the interrupt only works
when configured ACTIVE_LOW for palmas, and ACTIVE_HIGH for GIC.

Note that there was a similar issue earlier with tegra114 and palmas
interrupt polarity that got fixed by commit df545d1cd01a ("mfd: palmas:
Provide irq flags through DT/platform data"). However, the difference
between omap5 and tegra114 is that tegra inverts the palmas interrupt
twice, once when entering tegra PMC, and again when exiting tegra PMC
to GIC.

Let's fix the issue by adding a custom wakeupgen_irq_set_type() for
wakeupgen and invert any interrupts with wrong polarity. Let's also
warn about any non-sysnirq pins using wrong polarity. Note that we
also need to update the dts for the level as IRQ_TYPE_NONE never
has irq_set_type() called, and let's add some comments and use proper
pin nameing to avoid more confusion later on.

Cc: Belisko Marek <marek.belisko@gmail.com>
Cc: Dmitry Lifshitz <lifshitz@compulab.co.il>
Cc: "Dr. H. Nikolaus Schaller" <hns@goldelico.com>
Cc: Jon Hunter <jonathanh@nvidia.com>
Cc: Keerthy <j-keerthy@ti.com>
Cc: Laxman Dewangan <ldewangan@nvidia.com>
Cc: Nishanth Menon <nm@ti.com>
Cc: Peter Ujfalusi <peter.ujfalusi@ti.com>
Cc: Richard Woodruff <r-woodruff2@ti.com>
Cc: Santosh Shilimkar <ssantosh@kernel.org>
Cc: Tero Kristo <t-kristo@ti.com>
Cc: Thierry Reding <treding@nvidia.com>
Cc: stable@vger.kernel.org # v4.17+
Reported-by: Belisko Marek <marek.belisko@gmail.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>

+52 -5
+6 -3
arch/arm/boot/dts/omap5-board-common.dtsi
··· 317 317 318 318 palmas_sys_nirq_pins: pinmux_palmas_sys_nirq_pins { 319 319 pinctrl-single,pins = < 320 - OMAP5_IOPAD(0x068, PIN_INPUT_PULLUP | MUX_MODE0) /* sys_nirq1 */ 320 + /* sys_nirq1 is pulled down as the SoC is inverting it for GIC */ 321 + OMAP5_IOPAD(0x068, PIN_INPUT_PULLUP | MUX_MODE0) 321 322 >; 322 323 }; 323 324 ··· 386 385 387 386 palmas: palmas@48 { 388 387 compatible = "ti,palmas"; 389 - interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */ 388 + /* sys_nirq/ext_sys_irq pins get inverted at mpuss wakeupgen */ 389 + interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_LOW>; 390 390 reg = <0x48>; 391 391 interrupt-controller; 392 392 #interrupt-cells = <2>; ··· 653 651 pinctrl-names = "default"; 654 652 pinctrl-0 = <&twl6040_pins>; 655 653 656 - interrupts = <GIC_SPI 119 IRQ_TYPE_NONE>; /* IRQ_SYS_2N cascaded to gic */ 654 + /* sys_nirq/ext_sys_irq pins get inverted at mpuss wakeupgen */ 655 + interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_LOW>; 657 656 658 657 /* audpwron gpio defined in the board specific dts */ 659 658
+11 -1
arch/arm/boot/dts/omap5-cm-t54.dts
··· 181 181 OMAP5_IOPAD(0x0042, PIN_INPUT_PULLDOWN | MUX_MODE6) /* llib_wakereqin.gpio1_wk15 */ 182 182 >; 183 183 }; 184 + 185 + palmas_sys_nirq_pins: pinmux_palmas_sys_nirq_pins { 186 + pinctrl-single,pins = < 187 + /* sys_nirq1 is pulled down as the SoC is inverting it for GIC */ 188 + OMAP5_IOPAD(0x068, PIN_INPUT_PULLUP | MUX_MODE0) 189 + >; 190 + }; 184 191 }; 185 192 186 193 &omap5_pmx_core { ··· 421 414 422 415 palmas: palmas@48 { 423 416 compatible = "ti,palmas"; 424 - interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */ 425 417 reg = <0x48>; 418 + pinctrl-0 = <&palmas_sys_nirq_pins>; 419 + pinctrl-names = "default"; 420 + /* sys_nirq/ext_sys_irq pins get inverted at mpuss wakeupgen */ 421 + interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_LOW>; 426 422 interrupt-controller; 427 423 #interrupt-cells = <2>; 428 424 ti,system-power-controller;
+35 -1
arch/arm/mach-omap2/omap-wakeupgen.c
··· 50 50 #define OMAP4_NR_BANKS 4 51 51 #define OMAP4_NR_IRQS 128 52 52 53 + #define SYS_NIRQ1_EXT_SYS_IRQ_1 7 54 + #define SYS_NIRQ2_EXT_SYS_IRQ_2 119 55 + 53 56 static void __iomem *wakeupgen_base; 54 57 static void __iomem *sar_base; 55 58 static DEFINE_RAW_SPINLOCK(wakeupgen_lock); ··· 154 151 _wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]); 155 152 raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); 156 153 irq_chip_unmask_parent(d); 154 + } 155 + 156 + /* 157 + * The sys_nirq pins bypass peripheral modules and are wired directly 158 + * to MPUSS wakeupgen. They get automatically inverted for GIC. 159 + */ 160 + static int wakeupgen_irq_set_type(struct irq_data *d, unsigned int type) 161 + { 162 + bool inverted = false; 163 + 164 + switch (type) { 165 + case IRQ_TYPE_LEVEL_LOW: 166 + type &= ~IRQ_TYPE_LEVEL_MASK; 167 + type |= IRQ_TYPE_LEVEL_HIGH; 168 + inverted = true; 169 + break; 170 + case IRQ_TYPE_EDGE_FALLING: 171 + type &= ~IRQ_TYPE_EDGE_BOTH; 172 + type |= IRQ_TYPE_EDGE_RISING; 173 + inverted = true; 174 + break; 175 + default: 176 + break; 177 + } 178 + 179 + if (inverted && d->hwirq != SYS_NIRQ1_EXT_SYS_IRQ_1 && 180 + d->hwirq != SYS_NIRQ2_EXT_SYS_IRQ_2) 181 + pr_warn("wakeupgen: irq%li polarity inverted in dts\n", 182 + d->hwirq); 183 + 184 + return irq_chip_set_type_parent(d, type); 157 185 } 158 186 159 187 #ifdef CONFIG_HOTPLUG_CPU ··· 480 446 .irq_mask = wakeupgen_mask, 481 447 .irq_unmask = wakeupgen_unmask, 482 448 .irq_retrigger = irq_chip_retrigger_hierarchy, 483 - .irq_set_type = irq_chip_set_type_parent, 449 + .irq_set_type = wakeupgen_irq_set_type, 484 450 .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, 485 451 #ifdef CONFIG_SMP 486 452 .irq_set_affinity = irq_chip_set_affinity_parent,