Multi-parent IRQ domains

From: Thierry Reding
Date: Thu Sep 13 2018 - 11:59:56 EST


Hi everyone,

I've been trying to implement a feature on recent Tegra chips that's
called "wake events". These wake events are implemented as part of the
power management controller (PMC) and they control which events can be
used to wake the system from suspend. Events include things like an
alarm interrupt from an RTC, or the GPIO interrupt hooked up to a
power button for example.

We already have a driver for a couple of other things that the PMC does,
so I thought it'd be natural to implement this functionality as an IRQ
chip in the PMC driver. The way that this would work is that for all the
devices that are wakeup sources, we'd end up specifying the PMC as the
interrupt parent and the PMC would then itself have the main GIC as its
parent. That way, the hierarchical IRQ domain infrastructure would take
care of pretty much everything.

Unfortunately I've run into some issues here. One problem that I'm
facing is that PMC could have more than one parent. For example, the RTC
alarm interrupt goes straight to the GIC, but the power button GPIO goes
through the GPIO controller first and then to the GIC. This doesn't seem
to be something that's currently possible.

The way I imagine this to work from a DT perspective is as follows:

rtc: rtc@c2a0000 {
compatible = "nvidia,tegra194-rtc", "nvidia,tegra20-rtc";
reg = <0x0c2a0000 0x10000>;
interrupt-parent = <&pmc>;
interrupts = <73 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};

pmc: pmc@c360000 {
compatible = "nvidia,tegra194-pmc";
reg = <0x0c360000 0x10000>,
<0x0c370000 0x10000>,
<0x0c380000 0x10000>,
<0x0c390000 0x10000>,
<0x0c3a0000 0x10000>;
reg-names = "pmc", "wake", "aotag", "scratch", "misc";

#interrupt-cells = <5>;
interrupt-controller;
};

gpio-keys {
compatible = "gpio-keys";

power {
label = "Power";
gpios = <&gpio_aon TEGRA194_AON_GPIO(EE, 4)
GPIO_ACTIVE_LOW>;
linux,input-type = <EV_KEY>;
linux,code = <KEY_POWER>;
debounce-interval = <10>;
interrupt-parent = <&pmc>;
interrupts = <29 &gpio_aon TEGRA194_AON_GPIO(EE, 4)
IRQ_TYPE_LEVEL_LOW 0>;
wakeup-source;
};
};

The above is somewhat brittle because the PMC needs to be able to cover
both GIC and GPIO interrupt specifiers, so it gets 5 interrupt cells
(one for the wake event ID, one for a phandle to the parent controller
and two or three for the parent specifier). It'd be nicer if we could
actually have specifiers that exactly match the bindings for the
respective parent controllers (so that the GPIO specifier didn't have to
contain the dummy 0 at the end), but I don't see a way how that can be
achieved, given how we have to "embed" the specifier in another. We
could probably make it work in code, but DTC would still flag these as
errors.

One thing I briefly looked into was using interrupt-map to implement
this, which would give us a nice way of mapping arbitrary parent
interrupts to wake events. However, since we need to program some of the
PMC registers at ->irq_set_wake() time, using simply an interrupt-map
wouldn't do the trick, since we wouldn't be implementing an IRQ chip and
hence wouldn't be able to install any callbacks.

Perhaps a simple way to implement this would be to just blindly enable
all wake events, but that's not really what we want. We really only want
to enable them for devices that can be wakeup sources. Otherwise we may
get wakeups for completely unrelated GPIO activity.

I tried implementing support for multiple parents within the PMC driver
by looking up the parent domain based on the phandle from the specifier
at IRQ domain ->alloc() and ->translate() time, but I run into deadlock
when I do that, so before I go and open up a can of worms I wanted to
get your input on what the best way forward would be.

Does anyone have any ideas on how to solve this? Perhaps there's a
better solution to this that doesn't involve IRQ infrastructure that I'm
not aware of?

Thanks,
Thierry

Attachment: signature.asc
Description: PGP signature