Commit b7dccbea authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'irqchip-core-4.1-3' of git://git.infradead.org/users/jcooper/linux into irq/core

irqchip core change for v4.1 (round 3) from Jason Cooper

 Purge the gic_arch_extn hacks and abuse by using the new stacked domains

   NOTE: Due to the nature of these changes, patches crossing subsystems have
         been kept together in their own branches.

    - tegra
       - Handle the LIC properly

    - omap
       - Convert crossbar to stacked domains
       - kill arm,routable-irqs in GIC binding

    - exynos
       - Convert PMU wakeup to stacked domains

    - shmobile, ux500, zynq (irq_set_wake branch)
       - Switch from abusing gic_arch_extn to using gic_set_irqchip_flags
parents 425b655c a01e7b32
...@@ -56,11 +56,6 @@ Optional ...@@ -56,11 +56,6 @@ Optional
regions, used when the GIC doesn't have banked registers. The offset is regions, used when the GIC doesn't have banked registers. The offset is
cpu-offset * cpu-nr. cpu-offset * cpu-nr.
- arm,routable-irqs : Total number of gic irq inputs which are not directly
connected from the peripherals, but are routed dynamically
by a crossbar/multiplexer preceding the GIC. The GIC irq
input line is assigned dynamically when the corresponding
peripheral's crossbar line is mapped.
Example: Example:
intc: interrupt-controller@fff11000 { intc: interrupt-controller@fff11000 {
...@@ -68,7 +63,6 @@ Example: ...@@ -68,7 +63,6 @@ Example:
#interrupt-cells = <3>; #interrupt-cells = <3>;
#address-cells = <1>; #address-cells = <1>;
interrupt-controller; interrupt-controller;
arm,routable-irqs = <160>;
reg = <0xfff11000 0x1000>, reg = <0xfff11000 0x1000>,
<0xfff10100 0x100>; <0xfff10100 0x100>;
}; };
......
...@@ -9,7 +9,9 @@ inputs. ...@@ -9,7 +9,9 @@ inputs.
Required properties: Required properties:
- compatible : Should be "ti,irq-crossbar" - compatible : Should be "ti,irq-crossbar"
- reg: Base address and the size of the crossbar registers. - reg: Base address and the size of the crossbar registers.
- ti,max-irqs: Total number of irqs available at the interrupt controller. - interrupt-controller: indicates that this block is an interrupt controller.
- interrupt-parent: the interrupt controller this block is connected to.
- ti,max-irqs: Total number of irqs available at the parent interrupt controller.
- ti,max-crossbar-sources: Maximum number of crossbar sources that can be routed. - ti,max-crossbar-sources: Maximum number of crossbar sources that can be routed.
- ti,reg-size: Size of a individual register in bytes. Every individual - ti,reg-size: Size of a individual register in bytes. Every individual
register is assumed to be of same size. Valid sizes are 1, 2, 4. register is assumed to be of same size. Valid sizes are 1, 2, 4.
...@@ -27,13 +29,13 @@ Optional properties: ...@@ -27,13 +29,13 @@ Optional properties:
when the interrupt controller irq is unused (when not provided, default is 0) when the interrupt controller irq is unused (when not provided, default is 0)
Examples: Examples:
crossbar_mpu: @4a020000 { crossbar_mpu: crossbar@4a002a48 {
compatible = "ti,irq-crossbar"; compatible = "ti,irq-crossbar";
reg = <0x4a002a48 0x130>; reg = <0x4a002a48 0x130>;
ti,max-irqs = <160>; ti,max-irqs = <160>;
ti,max-crossbar-sources = <400>; ti,max-crossbar-sources = <400>;
ti,reg-size = <2>; ti,reg-size = <2>;
ti,irqs-reserved = <0 1 2 3 5 6 131 132 139 140>; ti,irqs-reserved = <0 1 2 3 5 6 131 132>;
ti,irqs-skip = <10 133 139 140>; ti,irqs-skip = <10 133 139 140>;
}; };
...@@ -44,10 +46,6 @@ Documentation/devicetree/bindings/arm/gic.txt for further details. ...@@ -44,10 +46,6 @@ Documentation/devicetree/bindings/arm/gic.txt for further details.
An interrupt consumer on an SoC using crossbar will use: An interrupt consumer on an SoC using crossbar will use:
interrupts = <GIC_SPI request_number interrupt_level> interrupts = <GIC_SPI request_number interrupt_level>
When the request number is between 0 to that described by
"ti,max-crossbar-sources", it is assumed to be a crossbar mapping. If the
request_number is greater than "ti,max-crossbar-sources", then it is mapped as a
quirky hardware mapping direct to GIC.
Example: Example:
device_x@0x4a023000 { device_x@0x4a023000 {
...@@ -55,9 +53,3 @@ Example: ...@@ -55,9 +53,3 @@ Example:
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
... ...
}; };
device_y@0x4a033000 {
/* Direct mapped GIC SPI 1 used */
interrupts = <GIC_SPI DIRECT_IRQ(1) IRQ_TYPE_LEVEL_HIGH>;
...
};
...@@ -29,10 +29,27 @@ Properties: ...@@ -29,10 +29,27 @@ Properties:
- clocks : list of phandles and specifiers to all input clocks listed in - clocks : list of phandles and specifiers to all input clocks listed in
clock-names property. clock-names property.
Optional properties:
Some PMUs are capable of behaving as an interrupt controller (mostly
to wake up a suspended PMU). In which case, they can have the
following properties:
- interrupt-controller: indicate that said PMU is an interrupt controller
- #interrupt-cells: must be identical to the that of the parent interrupt
controller.
- interrupt-parent: a phandle indicating which interrupt controller
this PMU signals interrupts to.
Example : Example :
pmu_system_controller: system-controller@10040000 { pmu_system_controller: system-controller@10040000 {
compatible = "samsung,exynos5250-pmu", "syscon"; compatible = "samsung,exynos5250-pmu", "syscon";
reg = <0x10040000 0x5000>; reg = <0x10040000 0x5000>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
#clock-cells = <1>; #clock-cells = <1>;
clock-names = "clkout0", "clkout1", "clkout2", "clkout3", clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
"clkout4", "clkout8", "clkout9"; "clkout4", "clkout8", "clkout9";
......
NVIDIA Legacy Interrupt Controller
All Tegra SoCs contain a legacy interrupt controller that routes
interrupts to the GIC, and also serves as a wakeup source. It is also
referred to as "ictlr", hence the name of the binding.
The HW block exposes a number of interrupt controllers, each
implementing a set of 32 interrupts.
Required properties:
- compatible : should be: "nvidia,tegra<chip>-ictlr". The LIC on
subsequent SoCs remained backwards-compatible with Tegra30, so on
Tegra generations later than Tegra30 the compatible value should
include "nvidia,tegra30-ictlr".
- reg : Specifies base physical address and size of the registers.
Each controller must be described separately (Tegra20 has 4 of them,
whereas Tegra30 and later have 5"
- interrupt-controller : Identifies the node as an interrupt controller.
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt source. The value must be 3.
- interrupt-parent : a phandle to the GIC these interrupts are routed
to.
Notes:
- Because this HW ultimately routes interrupts to the GIC, the
interrupt specifier must be that of the GIC.
- Only SPIs can use the ictlr as an interrupt parent. SGIs and PPIs
are explicitly forbidden.
Example:
ictlr: interrupt-controller@60004000 {
compatible = "nvidia,tegra20-ictlr", "nvidia,tegra-ictlr";
reg = <0x60004000 64>,
<0x60004100 64>,
<0x60004200 64>,
<0x60004300 64>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&intc>;
};
TI OMAP4 Wake-up Generator
All TI OMAP4/5 (and their derivatives) an interrupt controller that
routes interrupts to the GIC, and also serves as a wakeup source. It
is also referred to as "WUGEN-MPU", hence the name of the binding.
Reguired properties:
- compatible : should contain at least "ti,omap4-wugen-mpu" or
"ti,omap5-wugen-mpu"
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller.
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt source. The value must be 3.
- interrupt-parent : a phandle to the GIC these interrupts are routed
to.
Notes:
- Because this HW ultimately routes interrupts to the GIC, the
interrupt specifier must be that of the GIC.
- Only SPIs can use the WUGEN as an interrupt parent. SGIs and PPIs
are explicitly forbiden.
Example:
wakeupgen: interrupt-controller@48281000 {
compatible = "ti,omap5-wugen-mpu", "ti,omap4-wugen-mpu";
interrupt-controller;
#interrupt-cells = <3>;
reg = <0x48281000 0x1000>;
interrupt-parent = <&gic>;
};
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
/ { / {
compatible = "ti,am4372", "ti,am43"; compatible = "ti,am4372", "ti,am43";
interrupt-parent = <&gic>; interrupt-parent = <&wakeupgen>;
aliases { aliases {
...@@ -48,6 +48,15 @@ gic: interrupt-controller@48241000 { ...@@ -48,6 +48,15 @@ gic: interrupt-controller@48241000 {
#interrupt-cells = <3>; #interrupt-cells = <3>;
reg = <0x48241000 0x1000>, reg = <0x48241000 0x1000>,
<0x48240100 0x0100>; <0x48240100 0x0100>;
interrupt-parent = <&gic>;
};
wakeupgen: interrupt-controller@48281000 {
compatible = "ti,omap4-wugen-mpu";
interrupt-controller;
#interrupt-cells = <3>;
reg = <0x48281000 0x1000>;
interrupt-parent = <&gic>;
}; };
l2-cache-controller@48242000 { l2-cache-controller@48242000 {
......
...@@ -352,7 +352,6 @@ tps65218: tps65218@24 { ...@@ -352,7 +352,6 @@ tps65218: tps65218@24 {
reg = <0x24>; reg = <0x24>;
compatible = "ti,tps65218"; compatible = "ti,tps65218";
interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* NMIn */ interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* NMIn */
interrupt-parent = <&gic>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
......
...@@ -392,7 +392,6 @@ &i2c0 { ...@@ -392,7 +392,6 @@ &i2c0 {
tps@24 { tps@24 {
compatible = "ti,tps65218"; compatible = "ti,tps65218";
reg = <0x24>; reg = <0x24>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
......
...@@ -369,7 +369,6 @@ tps65218: tps65218@24 { ...@@ -369,7 +369,6 @@ tps65218: tps65218@24 {
reg = <0x24>; reg = <0x24>;
compatible = "ti,tps65218"; compatible = "ti,tps65218";
interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* NMIn */ interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* NMIn */
interrupt-parent = <&gic>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
......
...@@ -454,7 +454,6 @@ &i2c3 { ...@@ -454,7 +454,6 @@ &i2c3 {
mcp_rtc: rtc@6f { mcp_rtc: rtc@6f {
compatible = "microchip,mcp7941x"; compatible = "microchip,mcp7941x";
reg = <0x6f>; reg = <0x6f>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>; /* IRQ_SYS_1N */ interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>; /* IRQ_SYS_1N */
pinctrl-names = "default"; pinctrl-names = "default";
...@@ -477,7 +476,7 @@ &cpu0 { ...@@ -477,7 +476,7 @@ &cpu0 {
&uart3 { &uart3 {
status = "okay"; status = "okay";
interrupts-extended = <&gic GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>, interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
<&dra7_pmx_core 0x248>; <&dra7_pmx_core 0x248>;
pinctrl-names = "default"; pinctrl-names = "default";
......
...@@ -444,7 +444,7 @@ &uart1 { ...@@ -444,7 +444,7 @@ &uart1 {
status = "okay"; status = "okay";
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&uart1_pins>; pinctrl-0 = <&uart1_pins>;
interrupts-extended = <&gic GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>, interrupts-extended = <&crossbar_mpu GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
<&dra7_pmx_core 0x3e0>; <&dra7_pmx_core 0x3e0>;
}; };
......
...@@ -13,14 +13,13 @@ ...@@ -13,14 +13,13 @@
#include "skeleton.dtsi" #include "skeleton.dtsi"
#define MAX_SOURCES 400 #define MAX_SOURCES 400
#define DIRECT_IRQ(irq) (MAX_SOURCES + irq)
/ { / {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
compatible = "ti,dra7xx"; compatible = "ti,dra7xx";
interrupt-parent = <&gic>; interrupt-parent = <&crossbar_mpu>;
aliases { aliases {
i2c0 = &i2c1; i2c0 = &i2c1;
...@@ -50,18 +49,27 @@ timer { ...@@ -50,18 +49,27 @@ timer {
<GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>; <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
interrupt-parent = <&gic>;
}; };
gic: interrupt-controller@48211000 { gic: interrupt-controller@48211000 {
compatible = "arm,cortex-a15-gic"; compatible = "arm,cortex-a15-gic";
interrupt-controller; interrupt-controller;
#interrupt-cells = <3>; #interrupt-cells = <3>;
arm,routable-irqs = <192>;
reg = <0x48211000 0x1000>, reg = <0x48211000 0x1000>,
<0x48212000 0x1000>, <0x48212000 0x1000>,
<0x48214000 0x2000>, <0x48214000 0x2000>,
<0x48216000 0x2000>; <0x48216000 0x2000>;
interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
interrupt-parent = <&gic>;
};
wakeupgen: interrupt-controller@48281000 {
compatible = "ti,omap5-wugen-mpu", "ti,omap4-wugen-mpu";
interrupt-controller;
#interrupt-cells = <3>;
reg = <0x48281000 0x1000>;
interrupt-parent = <&gic>;
}; };
/* /*
...@@ -91,8 +99,8 @@ ocp { ...@@ -91,8 +99,8 @@ ocp {
ti,hwmods = "l3_main_1", "l3_main_2"; ti,hwmods = "l3_main_1", "l3_main_2";
reg = <0x44000000 0x1000000>, reg = <0x44000000 0x1000000>,
<0x45000000 0x1000>; <0x45000000 0x1000>;
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, interrupts-extended = <&crossbar_mpu GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI DIRECT_IRQ(10) IRQ_TYPE_LEVEL_HIGH>; <&wakeupgen GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
prm: prm@4ae06000 { prm: prm@4ae06000 {
compatible = "ti,dra7-prm"; compatible = "ti,dra7-prm";
...@@ -344,7 +352,7 @@ gpio8: gpio@48053000 { ...@@ -344,7 +352,7 @@ gpio8: gpio@48053000 {
uart1: serial@4806a000 { uart1: serial@4806a000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x4806a000 0x100>; reg = <0x4806a000 0x100>;
interrupts-extended = <&gic GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; interrupts-extended = <&crossbar_mpu GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart1"; ti,hwmods = "uart1";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -355,7 +363,7 @@ uart1: serial@4806a000 { ...@@ -355,7 +363,7 @@ uart1: serial@4806a000 {
uart2: serial@4806c000 { uart2: serial@4806c000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x4806c000 0x100>; reg = <0x4806c000 0x100>;
interrupts-extended = <&gic GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart2"; ti,hwmods = "uart2";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -366,7 +374,7 @@ uart2: serial@4806c000 { ...@@ -366,7 +374,7 @@ uart2: serial@4806c000 {
uart3: serial@48020000 { uart3: serial@48020000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48020000 0x100>; reg = <0x48020000 0x100>;
interrupts-extended = <&gic GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart3"; ti,hwmods = "uart3";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -377,7 +385,7 @@ uart3: serial@48020000 { ...@@ -377,7 +385,7 @@ uart3: serial@48020000 {
uart4: serial@4806e000 { uart4: serial@4806e000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x4806e000 0x100>; reg = <0x4806e000 0x100>;
interrupts-extended = <&gic GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart4"; ti,hwmods = "uart4";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -388,7 +396,7 @@ uart4: serial@4806e000 { ...@@ -388,7 +396,7 @@ uart4: serial@4806e000 {
uart5: serial@48066000 { uart5: serial@48066000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48066000 0x100>; reg = <0x48066000 0x100>;
interrupts-extended = <&gic GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart5"; ti,hwmods = "uart5";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -399,7 +407,7 @@ uart5: serial@48066000 { ...@@ -399,7 +407,7 @@ uart5: serial@48066000 {
uart6: serial@48068000 { uart6: serial@48068000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48068000 0x100>; reg = <0x48068000 0x100>;
interrupts-extended = <&gic GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart6"; ti,hwmods = "uart6";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -410,7 +418,7 @@ uart6: serial@48068000 { ...@@ -410,7 +418,7 @@ uart6: serial@48068000 {
uart7: serial@48420000 { uart7: serial@48420000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48420000 0x100>; reg = <0x48420000 0x100>;
interrupts-extended = <&gic GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart7"; ti,hwmods = "uart7";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -419,7 +427,7 @@ uart7: serial@48420000 { ...@@ -419,7 +427,7 @@ uart7: serial@48420000 {
uart8: serial@48422000 { uart8: serial@48422000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48422000 0x100>; reg = <0x48422000 0x100>;
interrupts-extended = <&gic GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart8"; ti,hwmods = "uart8";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -428,7 +436,7 @@ uart8: serial@48422000 { ...@@ -428,7 +436,7 @@ uart8: serial@48422000 {
uart9: serial@48424000 { uart9: serial@48424000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48424000 0x100>; reg = <0x48424000 0x100>;
interrupts-extended = <&gic GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart9"; ti,hwmods = "uart9";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -437,7 +445,7 @@ uart9: serial@48424000 { ...@@ -437,7 +445,7 @@ uart9: serial@48424000 {
uart10: serial@4ae2b000 { uart10: serial@4ae2b000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x4ae2b000 0x100>; reg = <0x4ae2b000 0x100>;
interrupts-extended = <&gic GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart10"; ti,hwmods = "uart10";
clock-frequency = <48000000>; clock-frequency = <48000000>;
status = "disabled"; status = "disabled";
...@@ -1335,9 +1343,12 @@ atl: atl@4843c000 { ...@@ -1335,9 +1343,12 @@ atl: atl@4843c000 {
status = "disabled"; status = "disabled";
}; };
crossbar_mpu: crossbar@4a020000 { crossbar_mpu: crossbar@4a002a48 {
compatible = "ti,irq-crossbar"; compatible = "ti,irq-crossbar";
reg = <0x4a002a48 0x130>; reg = <0x4a002a48 0x130>;
interrupt-controller;
interrupt-parent = <&wakeupgen>;
#interrupt-cells = <3>;
ti,max-irqs = <160>; ti,max-irqs = <160>;
ti,max-crossbar-sources = <MAX_SOURCES>; ti,max-crossbar-sources = <MAX_SOURCES>;
ti,reg-size = <2>; ti,reg-size = <2>;
......
...@@ -158,7 +158,6 @@ tps65917: tps65917@58 { ...@@ -158,7 +158,6 @@ tps65917: tps65917@58 {
pinctrl-0 = <&tps65917_pins_default>; pinctrl-0 = <&tps65917_pins_default>;
interrupts = <GIC_SPI 2 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */ interrupts = <GIC_SPI 2 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */
interrupt-parent = <&gic>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
......
...@@ -25,6 +25,7 @@ cpu0: cpu@0 { ...@@ -25,6 +25,7 @@ cpu0: cpu@0 {
pmu { pmu {
compatible = "arm,cortex-a15-pmu"; compatible = "arm,cortex-a15-pmu";
interrupts = <GIC_SPI DIRECT_IRQ(131) IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&wakeupgen>;
interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
}; };
}; };
...@@ -41,8 +41,9 @@ cpu@1 { ...@@ -41,8 +41,9 @@ cpu@1 {
pmu { pmu {
compatible = "arm,cortex-a15-pmu"; compatible = "arm,cortex-a15-pmu";
interrupts = <GIC_SPI DIRECT_IRQ(131) IRQ_TYPE_LEVEL_HIGH>, interrupt-parent = <&wakeupgen>;
<GIC_SPI DIRECT_IRQ(132) IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
}; };
ocp { ocp {
......
...@@ -131,6 +131,9 @@ sys_reg: syscon@10010000 { ...@@ -131,6 +131,9 @@ sys_reg: syscon@10010000 {
pmu_system_controller: system-controller@10020000 { pmu_system_controller: system-controller@10020000 {
compatible = "samsung,exynos3250-pmu", "syscon"; compatible = "samsung,exynos3250-pmu", "syscon";
reg = <0x10020000 0x4000>; reg = <0x10020000 0x4000>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
}; };
mipi_phy: video-phy@10020710 { mipi_phy: video-phy@10020710 {
...@@ -185,6 +188,7 @@ rtc: rtc@10070000 { ...@@ -185,6 +188,7 @@ rtc: rtc@10070000 {
compatible = "samsung,exynos3250-rtc"; compatible = "samsung,exynos3250-rtc";
reg = <0x10070000 0x100>; reg = <0x10070000 0x100>;
interrupts = <0 73 0>, <0 74 0>; interrupts = <0 73 0>, <0 74 0>;
interrupt-parent = <&pmu_system_controller>;
status = "disabled"; status = "disabled";
}; };
......
...@@ -154,6 +154,9 @@ sys_reg: syscon@10010000 { ...@@ -154,6 +154,9 @@ sys_reg: syscon@10010000 {
pmu_system_controller: system-controller@10020000 { pmu_system_controller: system-controller@10020000 {
compatible = "samsung,exynos4210-pmu", "syscon"; compatible = "samsung,exynos4210-pmu", "syscon";
reg = <0x10020000 0x4000>; reg = <0x10020000 0x4000>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
}; };
dsi_0: dsi@11C80000 { dsi_0: dsi@11C80000 {
...@@ -266,6 +269,7 @@ watchdog@10060000 { ...@@ -266,6 +269,7 @@ watchdog@10060000 {
rtc@10070000 { rtc@10070000 {
compatible = "samsung,s3c6410-rtc"; compatible = "samsung,s3c6410-rtc";
reg = <0x10070000 0x100>; reg = <0x10070000 0x100>;
interrupt-parent = <&pmu_system_controller>;
interrupts = <0 44 0>, <0 45 0>; interrupts = <0 44 0>, <0 45 0>;
clocks = <&clock CLK_RTC>; clocks = <&clock CLK_RTC>;
clock-names = "rtc"; clock-names = "rtc";
......
...@@ -205,6 +205,9 @@ pmu_system_controller: system-controller@10040000 { ...@@ -205,6 +205,9 @@ pmu_system_controller: system-controller@10040000 {
clock-names = "clkout16"; clock-names = "clkout16";
clocks = <&clock CLK_FIN_PLL>; clocks = <&clock CLK_FIN_PLL>;
#clock-cells = <1>; #clock-cells = <1>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
}; };
sysreg_system_controller: syscon@10050000 { sysreg_system_controller: syscon@10050000 {
...@@ -241,6 +244,7 @@ mfc: codec@11000000 { ...@@ -241,6 +244,7 @@ mfc: codec@11000000 {
rtc: rtc@101E0000 { rtc: rtc@101E0000 {
clocks = <&clock CLK_RTC>; clocks = <&clock CLK_RTC>;
clock-names = "rtc"; clock-names = "rtc";
interrupt-parent = <&pmu_system_controller>;
status = "disabled"; status = "disabled";
}; };
......
...@@ -327,6 +327,7 @@ pinctrl_4: pinctrl@03860000 { ...@@ -327,6 +327,7 @@ pinctrl_4: pinctrl@03860000 {
rtc: rtc@101E0000 { rtc: rtc@101E0000 {
clocks = <&clock CLK_RTC>; clocks = <&clock CLK_RTC>;
clock-names = "rtc"; clock-names = "rtc";
interrupt-parent = <&pmu_system_controller>;
status = "disabled"; status = "disabled";
}; };
...@@ -770,6 +771,9 @@ pmu_system_controller: system-controller@10040000 { ...@@ -770,6 +771,9 @@ pmu_system_controller: system-controller@10040000 {
clock-names = "clkout16"; clock-names = "clkout16";
clocks = <&clock CLK_FIN_PLL>; clocks = <&clock CLK_FIN_PLL>;
#clock-cells = <1>; #clock-cells = <1>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
}; };
sysreg_system_controller: syscon@10050000 { sysreg_system_controller: syscon@10050000 {
......
...@@ -173,14 +173,12 @@ &i2c1 { ...@@ -173,14 +173,12 @@ &i2c1 {
twl: twl@48 { twl: twl@48 {
reg = <0x48>; reg = <0x48>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */
interrupt-parent = <&gic>;
}; };
twl6040: twl@4b { twl6040: twl@4b {
compatible = "ti,twl6040"; compatible = "ti,twl6040";
reg = <0x4b>; reg = <0x4b>;
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */ interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */
interrupt-parent = <&gic>;
ti,audpwron-gpio = <&gpio6 0 GPIO_ACTIVE_HIGH>; /* gpio_160 */ ti,audpwron-gpio = <&gpio6 0 GPIO_ACTIVE_HIGH>; /* gpio_160 */
vio-supply = <&v1v8>; vio-supply = <&v1v8>;
......
...@@ -372,7 +372,6 @@ twl: twl@48 { ...@@ -372,7 +372,6 @@ twl: twl@48 {
reg = <0x48>; reg = <0x48>;
/* IRQ# = 7 */ /* IRQ# = 7 */
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */
interrupt-parent = <&gic>;
}; };
twl6040: twl@4b { twl6040: twl@4b {
...@@ -384,7 +383,6 @@ twl6040: twl@4b { ...@@ -384,7 +383,6 @@ twl6040: twl@4b {
/* IRQ# = 119 */ /* IRQ# = 119 */
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */ interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */
interrupt-parent = <&gic>;
ti,audpwron-gpio = <&gpio4 31 GPIO_ACTIVE_HIGH>; /* gpio line 127 */ ti,audpwron-gpio = <&gpio4 31 GPIO_ACTIVE_HIGH>; /* gpio line 127 */
vio-supply = <&v1v8>; vio-supply = <&v1v8>;
...@@ -479,17 +477,17 @@ &twl_usb_comparator { ...@@ -479,17 +477,17 @@ &twl_usb_comparator {
}; };
&uart2 { &uart2 {
interrupts-extended = <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH interrupts-extended = <&wakeupgen GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH
&omap4_pmx_core OMAP4_UART2_RX>; &omap4_pmx_core OMAP4_UART2_RX>;
}; };
&uart3 { &uart3 {
interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH
&omap4_pmx_core OMAP4_UART3_RX>; &omap4_pmx_core OMAP4_UART3_RX>;
}; };
&uart4 { &uart4 {
interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH interrupts-extended = <&wakeupgen GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH
&omap4_pmx_core OMAP4_UART4_RX>; &omap4_pmx_core OMAP4_UART4_RX>;
}; };
......
...@@ -363,7 +363,6 @@ twl: twl@48 { ...@@ -363,7 +363,6 @@ twl: twl@48 {
reg = <0x48>; reg = <0x48>;
/* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */ /* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */
interrupt-parent = <&gic>;
}; };
twl6040: twl@4b { twl6040: twl@4b {
...@@ -375,7 +374,6 @@ twl6040: twl@4b { ...@@ -375,7 +374,6 @@ twl6040: twl@4b {
/* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */ /* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */ interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */
interrupt-parent = <&gic>;
ti,audpwron-gpio = <&gpio4 31 0>; /* gpio line 127 */ ti,audpwron-gpio = <&gpio4 31 0>; /* gpio line 127 */
vio-supply = <&v1v8>; vio-supply = <&v1v8>;
...@@ -570,21 +568,21 @@ &keypad { ...@@ -570,21 +568,21 @@ &keypad {
}; };
&uart2 { &uart2 {
interrupts-extended = <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH interrupts-extended = <&wakeupgen GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH
&omap4_pmx_core OMAP4_UART2_RX>; &omap4_pmx_core OMAP4_UART2_RX>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&uart2_pins>; pinctrl-0 = <&uart2_pins>;
}; };
&uart3 { &uart3 {
interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH
&omap4_pmx_core OMAP4_UART3_RX>; &omap4_pmx_core OMAP4_UART3_RX>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&uart3_pins>; pinctrl-0 = <&uart3_pins>;
}; };
&uart4 { &uart4 {
interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH interrupts-extended = <&wakeupgen GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH
&omap4_pmx_core OMAP4_UART4_RX>; &omap4_pmx_core OMAP4_UART4_RX>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&uart4_pins>; pinctrl-0 = <&uart4_pins>;
......
...@@ -185,7 +185,6 @@ twl: twl@48 { ...@@ -185,7 +185,6 @@ twl: twl@48 {
reg = <0x48>; reg = <0x48>;
/* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */ /* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */
interrupt-parent = <&gic>;
}; };
twl6040: twl@4b { twl6040: twl@4b {
...@@ -197,7 +196,6 @@ twl6040: twl@4b { ...@@ -197,7 +196,6 @@ twl6040: twl@4b {
/* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */ /* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */ interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */
interrupt-parent = <&gic>;
ti,audpwron-gpio = <&gpio6 22 0>; /* gpio 182 */ ti,audpwron-gpio = <&gpio6 22 0>; /* gpio 182 */
vio-supply = <&v1v8>; vio-supply = <&v1v8>;
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
/ { / {
compatible = "ti,omap4430", "ti,omap4"; compatible = "ti,omap4430", "ti,omap4";
interrupt-parent = <&gic>; interrupt-parent = <&wakeupgen>;
aliases { aliases {
i2c0 = &i2c1; i2c0 = &i2c1;
...@@ -56,6 +56,7 @@ gic: interrupt-controller@48241000 { ...@@ -56,6 +56,7 @@ gic: interrupt-controller@48241000 {
#interrupt-cells = <3>; #interrupt-cells = <3>;
reg = <0x48241000 0x1000>, reg = <0x48241000 0x1000>,
<0x48240100 0x0100>; <0x48240100 0x0100>;
interrupt-parent = <&gic>;
}; };
L2: l2-cache-controller@48242000 { L2: l2-cache-controller@48242000 {
...@@ -70,6 +71,15 @@ local-timer@48240600 { ...@@ -70,6 +71,15 @@ local-timer@48240600 {
clocks = <&mpu_periphclk>; clocks = <&mpu_periphclk>;
reg = <0x48240600 0x20>; reg = <0x48240600 0x20>;
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_HIGH)>; interrupts = <GIC_PPI 13 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_HIGH)>;
interrupt-parent = <&gic>;
};
wakeupgen: interrupt-controller@48281000 {
compatible = "ti,omap4-wugen-mpu";
interrupt-controller;
#interrupt-cells = <3>;
reg = <0x48281000 0x1000>;
interrupt-parent = <&gic>;
}; };
/* /*
...@@ -319,7 +329,7 @@ uart1: serial@4806a000 { ...@@ -319,7 +329,7 @@ uart1: serial@4806a000 {
uart2: serial@4806c000 { uart2: serial@4806c000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x4806c000 0x100>; reg = <0x4806c000 0x100>;
interrupts-extended = <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart2"; ti,hwmods = "uart2";
clock-frequency = <48000000>; clock-frequency = <48000000>;
}; };
...@@ -327,7 +337,7 @@ uart2: serial@4806c000 { ...@@ -327,7 +337,7 @@ uart2: serial@4806c000 {
uart3: serial@48020000 { uart3: serial@48020000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48020000 0x100>; reg = <0x48020000 0x100>;
interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart3"; ti,hwmods = "uart3";
clock-frequency = <48000000>; clock-frequency = <48000000>;
}; };
...@@ -335,7 +345,7 @@ uart3: serial@48020000 { ...@@ -335,7 +345,7 @@ uart3: serial@48020000 {
uart4: serial@4806e000 { uart4: serial@4806e000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x4806e000 0x100>; reg = <0x4806e000 0x100>;
interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart4"; ti,hwmods = "uart4";
clock-frequency = <48000000>; clock-frequency = <48000000>;
}; };
......
...@@ -412,7 +412,6 @@ at24@50 { ...@@ -412,7 +412,6 @@ at24@50 {
palmas: palmas@48 { palmas: palmas@48 {
compatible = "ti,palmas"; compatible = "ti,palmas";
interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */ interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */
interrupt-parent = <&gic>;
reg = <0x48>; reg = <0x48>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
......
...@@ -311,7 +311,6 @@ &i2c1 { ...@@ -311,7 +311,6 @@ &i2c1 {
palmas: palmas@48 { palmas: palmas@48 {
compatible = "ti,palmas"; compatible = "ti,palmas";
interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */ interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */
interrupt-parent = <&gic>;
reg = <0x48>; reg = <0x48>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
...@@ -521,7 +520,6 @@ twl6040: twl@4b { ...@@ -521,7 +520,6 @@ twl6040: twl@4b {
pinctrl-0 = <&twl6040_pins>; pinctrl-0 = <&twl6040_pins>;
interrupts = <GIC_SPI 119 IRQ_TYPE_NONE>; /* IRQ_SYS_2N cascaded to gic */ interrupts = <GIC_SPI 119 IRQ_TYPE_NONE>; /* IRQ_SYS_2N cascaded to gic */
interrupt-parent = <&gic>;
ti,audpwron-gpio = <&gpio5 13 0>; /* gpio line 141 */ ti,audpwron-gpio = <&gpio5 13 0>; /* gpio line 141 */
vio-supply = <&smps7_reg>; vio-supply = <&smps7_reg>;
......
...@@ -18,7 +18,7 @@ / { ...@@ -18,7 +18,7 @@ / {
#size-cells = <1>; #size-cells = <1>;
compatible = "ti,omap5"; compatible = "ti,omap5";
interrupt-parent = <&gic>; interrupt-parent = <&wakeupgen>;
aliases { aliases {
i2c0 = &i2c1; i2c0 = &i2c1;
...@@ -79,6 +79,7 @@ timer { ...@@ -79,6 +79,7 @@ timer {
<GIC_PPI 14 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 14 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 11 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 11 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_LOW)>; <GIC_PPI 10 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_LOW)>;
interrupt-parent = <&gic>;
}; };
pmu { pmu {
...@@ -95,6 +96,15 @@ gic: interrupt-controller@48211000 { ...@@ -95,6 +96,15 @@ gic: interrupt-controller@48211000 {
<0x48212000 0x1000>, <0x48212000 0x1000>,
<0x48214000 0x2000>, <0x48214000 0x2000>,
<0x48216000 0x2000>; <0x48216000 0x2000>;
interrupt-parent = <&gic>;
};
wakeupgen: interrupt-controller@48281000 {
compatible = "ti,omap5-wugen-mpu", "ti,omap4-wugen-mpu";
interrupt-controller;
#interrupt-cells = <3>;
reg = <0x48281000 0x1000>;
interrupt-parent = <&gic>;
}; };
/* /*
...@@ -458,7 +468,7 @@ mcspi4: spi@480ba000 { ...@@ -458,7 +468,7 @@ mcspi4: spi@480ba000 {
uart1: serial@4806a000 { uart1: serial@4806a000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x4806a000 0x100>; reg = <0x4806a000 0x100>;
interrupts-extended = <&gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart1"; ti,hwmods = "uart1";
clock-frequency = <48000000>; clock-frequency = <48000000>;
}; };
...@@ -466,7 +476,7 @@ uart1: serial@4806a000 { ...@@ -466,7 +476,7 @@ uart1: serial@4806a000 {
uart2: serial@4806c000 { uart2: serial@4806c000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x4806c000 0x100>; reg = <0x4806c000 0x100>;
interrupts-extended = <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart2"; ti,hwmods = "uart2";
clock-frequency = <48000000>; clock-frequency = <48000000>;
}; };
...@@ -474,7 +484,7 @@ uart2: serial@4806c000 { ...@@ -474,7 +484,7 @@ uart2: serial@4806c000 {
uart3: serial@48020000 { uart3: serial@48020000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48020000 0x100>; reg = <0x48020000 0x100>;
interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart3"; ti,hwmods = "uart3";
clock-frequency = <48000000>; clock-frequency = <48000000>;
}; };
...@@ -482,7 +492,7 @@ uart3: serial@48020000 { ...@@ -482,7 +492,7 @@ uart3: serial@48020000 {
uart4: serial@4806e000 { uart4: serial@4806e000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x4806e000 0x100>; reg = <0x4806e000 0x100>;
interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart4"; ti,hwmods = "uart4";
clock-frequency = <48000000>; clock-frequency = <48000000>;
}; };
...@@ -490,7 +500,7 @@ uart4: serial@4806e000 { ...@@ -490,7 +500,7 @@ uart4: serial@4806e000 {
uart5: serial@48066000 { uart5: serial@48066000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48066000 0x100>; reg = <0x48066000 0x100>;
interrupts-extended = <&gic GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart5"; ti,hwmods = "uart5";
clock-frequency = <48000000>; clock-frequency = <48000000>;
}; };
...@@ -498,7 +508,7 @@ uart5: serial@48066000 { ...@@ -498,7 +508,7 @@ uart5: serial@48066000 {
uart6: serial@48068000 { uart6: serial@48068000 {
compatible = "ti,omap4-uart"; compatible = "ti,omap4-uart";
reg = <0x48068000 0x100>; reg = <0x48068000 0x100>;
interrupts-extended = <&gic GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart6"; ti,hwmods = "uart6";
clock-frequency = <48000000>; clock-frequency = <48000000>;
}; };
...@@ -883,14 +893,12 @@ usbhshost: usbhshost@4a064000 { ...@@ -883,14 +893,12 @@ usbhshost: usbhshost@4a064000 {
usbhsohci: ohci@4a064800 { usbhsohci: ohci@4a064800 {
compatible = "ti,ohci-omap3"; compatible = "ti,ohci-omap3";
reg = <0x4a064800 0x400>; reg = <0x4a064800 0x400>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
}; };
usbhsehci: ehci@4a064c00 { usbhsehci: ehci@4a064c00 {
compatible = "ti,ehci-omap"; compatible = "ti,ehci-omap";
reg = <0x4a064c00 0x400>; reg = <0x4a064c00 0x400>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
}; };
}; };
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
/ { / {
compatible = "nvidia,tegra114"; compatible = "nvidia,tegra114";
interrupt-parent = <&gic>; interrupt-parent = <&lic>;
host1x@50000000 { host1x@50000000 {
compatible = "nvidia,tegra114-host1x", "simple-bus"; compatible = "nvidia,tegra114-host1x", "simple-bus";
...@@ -134,6 +134,19 @@ gic: interrupt-controller@50041000 { ...@@ -134,6 +134,19 @@ gic: interrupt-controller@50041000 {
<0x50046000 0x2000>; <0x50046000 0x2000>;
interrupts = <GIC_PPI 9 interrupts = <GIC_PPI 9
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
interrupt-parent = <&gic>;
};
lic: interrupt-controller@60004000 {
compatible = "nvidia,tegra114-ictlr", "nvidia,tegra30-ictlr";
reg = <0x60004000 0x100>,
<0x60004100 0x50>,
<0x60004200 0x50>,
<0x60004300 0x50>,
<0x60004400 0x50>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
}; };
timer@60005000 { timer@60005000 {
...@@ -766,5 +779,6 @@ timer { ...@@ -766,5 +779,6 @@ timer {
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 <GIC_PPI 10
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
interrupt-parent = <&gic>;
}; };
}; };
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
/ { / {
compatible = "nvidia,tegra124"; compatible = "nvidia,tegra124";
interrupt-parent = <&gic>; interrupt-parent = <&lic>;
#address-cells = <2>; #address-cells = <2>;
#size-cells = <2>; #size-cells = <2>;
...@@ -173,6 +173,7 @@ gic: interrupt-controller@0,50041000 { ...@@ -173,6 +173,7 @@ gic: interrupt-controller@0,50041000 {
<0x0 0x50046000 0x0 0x2000>; <0x0 0x50046000 0x0 0x2000>;
interrupts = <GIC_PPI 9 interrupts = <GIC_PPI 9
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
interrupt-parent = <&gic>;
}; };
gpu@0,57000000 { gpu@0,57000000 {
...@@ -190,6 +191,18 @@ gpu@0,57000000 { ...@@ -190,6 +191,18 @@ gpu@0,57000000 {
status = "disabled"; status = "disabled";
}; };
lic: interrupt-controller@60004000 {
compatible = "nvidia,tegra124-ictlr", "nvidia,tegra30-ictlr";
reg = <0x0 0x60004000 0x0 0x100>,
<0x0 0x60004100 0x0 0x100>,
<0x0 0x60004200 0x0 0x100>,
<0x0 0x60004300 0x0 0x100>,
<0x0 0x60004400 0x0 0x100>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
};
timer@0,60005000 { timer@0,60005000 {
compatible = "nvidia,tegra124-timer", "nvidia,tegra20-timer"; compatible = "nvidia,tegra124-timer", "nvidia,tegra20-timer";
reg = <0x0 0x60005000 0x0 0x400>; reg = <0x0 0x60005000 0x0 0x400>;
...@@ -955,5 +968,6 @@ timer { ...@@ -955,5 +968,6 @@ timer {
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 <GIC_PPI 10
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
interrupt-parent = <&gic>;
}; };
}; };
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
/ { / {
compatible = "nvidia,tegra20"; compatible = "nvidia,tegra20";
interrupt-parent = <&intc>; interrupt-parent = <&lic>;
host1x@50000000 { host1x@50000000 {
compatible = "nvidia,tegra20-host1x", "simple-bus"; compatible = "nvidia,tegra20-host1x", "simple-bus";
...@@ -142,6 +142,7 @@ dsi@54300000 { ...@@ -142,6 +142,7 @@ dsi@54300000 {
timer@50040600 { timer@50040600 {
compatible = "arm,cortex-a9-twd-timer"; compatible = "arm,cortex-a9-twd-timer";
interrupt-parent = <&intc>;
reg = <0x50040600 0x20>; reg = <0x50040600 0x20>;
interrupts = <GIC_PPI 13 interrupts = <GIC_PPI 13
(GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
...@@ -154,6 +155,7 @@ intc: interrupt-controller@50041000 { ...@@ -154,6 +155,7 @@ intc: interrupt-controller@50041000 {
0x50040100 0x0100>; 0x50040100 0x0100>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <3>; #interrupt-cells = <3>;
interrupt-parent = <&intc>;
}; };
cache-controller@50043000 { cache-controller@50043000 {
...@@ -165,6 +167,17 @@ cache-controller@50043000 { ...@@ -165,6 +167,17 @@ cache-controller@50043000 {
cache-level = <2>; cache-level = <2>;
}; };
lic: interrupt-controller@60004000 {
compatible = "nvidia,tegra20-ictlr";
reg = <0x60004000 0x100>,
<0x60004100 0x50>,
<0x60004200 0x50>,
<0x60004300 0x50>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&intc>;
};
timer@60005000 { timer@60005000 {
compatible = "nvidia,tegra20-timer"; compatible = "nvidia,tegra20-timer";
reg = <0x60005000 0x60>; reg = <0x60005000 0x60>;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
/ { / {
compatible = "nvidia,tegra30"; compatible = "nvidia,tegra30";
interrupt-parent = <&intc>; interrupt-parent = <&lic>;
pcie-controller@00003000 { pcie-controller@00003000 {
compatible = "nvidia,tegra30-pcie"; compatible = "nvidia,tegra30-pcie";
...@@ -228,6 +228,7 @@ dsi@54300000 { ...@@ -228,6 +228,7 @@ dsi@54300000 {
timer@50040600 { timer@50040600 {
compatible = "arm,cortex-a9-twd-timer"; compatible = "arm,cortex-a9-twd-timer";
reg = <0x50040600 0x20>; reg = <0x50040600 0x20>;
interrupt-parent = <&intc>;
interrupts = <GIC_PPI 13 interrupts = <GIC_PPI 13
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
clocks = <&tegra_car TEGRA30_CLK_TWD>; clocks = <&tegra_car TEGRA30_CLK_TWD>;
...@@ -239,6 +240,7 @@ intc: interrupt-controller@50041000 { ...@@ -239,6 +240,7 @@ intc: interrupt-controller@50041000 {
0x50040100 0x0100>; 0x50040100 0x0100>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <3>; #interrupt-cells = <3>;
interrupt-parent = <&intc>;
}; };
cache-controller@50043000 { cache-controller@50043000 {
...@@ -250,6 +252,18 @@ cache-controller@50043000 { ...@@ -250,6 +252,18 @@ cache-controller@50043000 {
cache-level = <2>; cache-level = <2>;
}; };
lic: interrupt-controller@60004000 {
compatible = "nvidia,tegra30-ictlr";
reg = <0x60004000 0x100>,
<0x60004100 0x50>,
<0x60004200 0x50>,
<0x60004300 0x50>,
<0x60004400 0x50>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&intc>;
};
timer@60005000 { timer@60005000 {
compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer"; compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer";
reg = <0x60005000 0x400>; reg = <0x60005000 0x400>;
......
...@@ -166,16 +166,14 @@ static void __init exynos_init_io(void) ...@@ -166,16 +166,14 @@ static void __init exynos_init_io(void)
exynos_map_io(); exynos_map_io();
} }
/*
* Apparently, these SoCs are not able to wake-up from suspend using
* the PMU. Too bad. Should they suddenly become capable of such a
* feat, the matches below should be moved to suspend.c.
*/
static const struct of_device_id exynos_dt_pmu_match[] = { static const struct of_device_id exynos_dt_pmu_match[] = {
{ .compatible = "samsung,exynos3250-pmu" },
{ .compatible = "samsung,exynos4210-pmu" },
{ .compatible = "samsung,exynos4212-pmu" },
{ .compatible = "samsung,exynos4412-pmu" },
{ .compatible = "samsung,exynos4415-pmu" },
{ .compatible = "samsung,exynos5250-pmu" },
{ .compatible = "samsung,exynos5260-pmu" }, { .compatible = "samsung,exynos5260-pmu" },
{ .compatible = "samsung,exynos5410-pmu" }, { .compatible = "samsung,exynos5410-pmu" },
{ .compatible = "samsung,exynos5420-pmu" },
{ /*sentinel*/ }, { /*sentinel*/ },
}; };
...@@ -186,9 +184,6 @@ static void exynos_map_pmu(void) ...@@ -186,9 +184,6 @@ static void exynos_map_pmu(void)
np = of_find_matching_node(NULL, exynos_dt_pmu_match); np = of_find_matching_node(NULL, exynos_dt_pmu_match);
if (np) if (np)
pmu_base_addr = of_iomap(np, 0); pmu_base_addr = of_iomap(np, 0);
if (!pmu_base_addr)
panic("failed to find exynos pmu register\n");
} }
static void __init exynos_init_irq(void) static void __init exynos_init_irq(void)
......
...@@ -18,7 +18,9 @@ ...@@ -18,7 +18,9 @@
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/cpu_pm.h> #include <linux/cpu_pm.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqchip/arm-gic.h> #include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
...@@ -43,8 +45,8 @@ ...@@ -43,8 +45,8 @@
#define EXYNOS5420_CPU_STATE 0x28 #define EXYNOS5420_CPU_STATE 0x28
/** /**
* struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping * struct exynos_wkup_irq - PMU IRQ to mask mapping
* @hwirq: Hardware IRQ signal of the GIC * @hwirq: Hardware IRQ signal of the PMU
* @mask: Mask in PMU wake-up mask register * @mask: Mask in PMU wake-up mask register
*/ */
struct exynos_wkup_irq { struct exynos_wkup_irq {
...@@ -93,14 +95,14 @@ static const struct exynos_wkup_irq exynos3250_wkup_irq[] = { ...@@ -93,14 +95,14 @@ static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
}; };
static const struct exynos_wkup_irq exynos4_wkup_irq[] = { static const struct exynos_wkup_irq exynos4_wkup_irq[] = {
{ 76, BIT(1) }, /* RTC alarm */ { 44, BIT(1) }, /* RTC alarm */
{ 77, BIT(2) }, /* RTC tick */ { 45, BIT(2) }, /* RTC tick */
{ /* sentinel */ }, { /* sentinel */ },
}; };
static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
{ 75, BIT(1) }, /* RTC alarm */ { 43, BIT(1) }, /* RTC alarm */
{ 76, BIT(2) }, /* RTC tick */ { 44, BIT(2) }, /* RTC tick */
{ /* sentinel */ }, { /* sentinel */ },
}; };
...@@ -167,6 +169,113 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) ...@@ -167,6 +169,113 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
return -ENOENT; return -ENOENT;
} }
static struct irq_chip exynos_pmu_chip = {
.name = "PMU",
.irq_eoi = irq_chip_eoi_parent,
.irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_set_wake = exynos_irq_set_wake,
#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
#endif
};
static int exynos_pmu_domain_xlate(struct irq_domain *domain,
struct device_node *controller,
const u32 *intspec,
unsigned int intsize,
unsigned long *out_hwirq,
unsigned int *out_type)
{
if (domain->of_node != controller)
return -EINVAL; /* Shouldn't happen, really... */
if (intsize != 3)
return -EINVAL; /* Not GIC compliant */
if (intspec[0] != 0)
return -EINVAL; /* No PPI should point to this domain */
*out_hwirq = intspec[1];
*out_type = intspec[2];
return 0;
}
static int exynos_pmu_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs, void *data)
{
struct of_phandle_args *args = data;
struct of_phandle_args parent_args;
irq_hw_number_t hwirq;
int i;
if (args->args_count != 3)
return -EINVAL; /* Not GIC compliant */
if (args->args[0] != 0)
return -EINVAL; /* No PPI should point to this domain */
hwirq = args->args[1];
for (i = 0; i < nr_irqs; i++)
irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
&exynos_pmu_chip, NULL);
parent_args = *args;
parent_args.np = domain->parent->of_node;
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args);
}
static struct irq_domain_ops exynos_pmu_domain_ops = {
.xlate = exynos_pmu_domain_xlate,
.alloc = exynos_pmu_domain_alloc,
.free = irq_domain_free_irqs_common,
};
static int __init exynos_pmu_irq_init(struct device_node *node,
struct device_node *parent)
{
struct irq_domain *parent_domain, *domain;
if (!parent) {
pr_err("%s: no parent, giving up\n", node->full_name);
return -ENODEV;
}
parent_domain = irq_find_host(parent);
if (!parent_domain) {
pr_err("%s: unable to obtain parent domain\n", node->full_name);
return -ENXIO;
}
pmu_base_addr = of_iomap(node, 0);
if (!pmu_base_addr) {
pr_err("%s: failed to find exynos pmu register\n",
node->full_name);
return -ENOMEM;
}
domain = irq_domain_add_hierarchy(parent_domain, 0, 0,
node, &exynos_pmu_domain_ops,
NULL);
if (!domain) {
iounmap(pmu_base_addr);
return -ENOMEM;
}
return 0;
}
#define EXYNOS_PMU_IRQ(symbol, name) OF_DECLARE_2(irqchip, symbol, name, exynos_pmu_irq_init)
EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu");
EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu");
EXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu");
EXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu");
EXYNOS_PMU_IRQ(exynos4415_pmu_irq, "samsung,exynos4415-pmu");
EXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu");
EXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu");
static int exynos_cpu_do_idle(void) static int exynos_cpu_do_idle(void)
{ {
/* issue the standby signal into the pm unit. */ /* issue the standby signal into the pm unit. */
...@@ -615,17 +724,19 @@ static struct syscore_ops exynos_pm_syscore_ops; ...@@ -615,17 +724,19 @@ static struct syscore_ops exynos_pm_syscore_ops;
void __init exynos_pm_init(void) void __init exynos_pm_init(void)
{ {
const struct of_device_id *match; const struct of_device_id *match;
struct device_node *np;
u32 tmp; u32 tmp;
of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match);
if (!match) { if (!np) {
pr_err("Failed to find PMU node\n"); pr_err("Failed to find PMU node\n");
return; return;
} }
pm_data = (struct exynos_pm_data *) match->data;
/* Platform-specific GIC callback */ if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL)))
gic_arch_extn.irq_set_wake = exynos_irq_set_wake; pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
pm_data = (struct exynos_pm_data *) match->data;
/* All wakeup disable */ /* All wakeup disable */
tmp = pmu_raw_readl(S5P_WAKEUP_MASK); tmp = pmu_raw_readl(S5P_WAKEUP_MASK);
......
...@@ -20,11 +20,12 @@ ...@@ -20,11 +20,12 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/cpu_pm.h> #include <linux/cpu_pm.h>
#include <linux/irqchip/arm-gic.h>
#include "omap-wakeupgen.h" #include "omap-wakeupgen.h"
#include "omap-secure.h" #include "omap-secure.h"
...@@ -78,29 +79,12 @@ static inline void sar_writel(u32 val, u32 offset, u8 idx) ...@@ -78,29 +79,12 @@ static inline void sar_writel(u32 val, u32 offset, u8 idx)
static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index) static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index)
{ {
unsigned int spi_irq;
/*
* PPIs and SGIs are not supported.
*/
if (irq < OMAP44XX_IRQ_GIC_START)
return -EINVAL;
/*
* Subtract the GIC offset.
*/
spi_irq = irq - OMAP44XX_IRQ_GIC_START;
if (spi_irq > MAX_IRQS) {
pr_err("omap wakeupGen: Invalid IRQ%d\n", irq);
return -EINVAL;
}
/* /*
* Each WakeupGen register controls 32 interrupt. * Each WakeupGen register controls 32 interrupt.
* i.e. 1 bit per SPI IRQ * i.e. 1 bit per SPI IRQ
*/ */
*reg_index = spi_irq >> 5; *reg_index = irq >> 5;
*bit_posn = spi_irq %= 32; *bit_posn = irq %= 32;
return 0; return 0;
} }
...@@ -141,6 +125,7 @@ static void wakeupgen_mask(struct irq_data *d) ...@@ -141,6 +125,7 @@ static void wakeupgen_mask(struct irq_data *d)
raw_spin_lock_irqsave(&wakeupgen_lock, flags); raw_spin_lock_irqsave(&wakeupgen_lock, flags);
_wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]); _wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]);
raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
irq_chip_mask_parent(d);
} }
/* /*
...@@ -153,6 +138,7 @@ static void wakeupgen_unmask(struct irq_data *d) ...@@ -153,6 +138,7 @@ static void wakeupgen_unmask(struct irq_data *d)
raw_spin_lock_irqsave(&wakeupgen_lock, flags); raw_spin_lock_irqsave(&wakeupgen_lock, flags);
_wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]); _wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]);
raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
irq_chip_unmask_parent(d);
} }
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
...@@ -400,15 +386,91 @@ int omap_secure_apis_support(void) ...@@ -400,15 +386,91 @@ int omap_secure_apis_support(void)
return omap_secure_apis; return omap_secure_apis;
} }
static struct irq_chip wakeupgen_chip = {
.name = "WUGEN",
.irq_eoi = irq_chip_eoi_parent,
.irq_mask = wakeupgen_mask,
.irq_unmask = wakeupgen_unmask,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
#endif
};
static int wakeupgen_domain_xlate(struct irq_domain *domain,
struct device_node *controller,
const u32 *intspec,
unsigned int intsize,
unsigned long *out_hwirq,
unsigned int *out_type)
{
if (domain->of_node != controller)
return -EINVAL; /* Shouldn't happen, really... */
if (intsize != 3)
return -EINVAL; /* Not GIC compliant */
if (intspec[0] != 0)
return -EINVAL; /* No PPI should point to this domain */
*out_hwirq = intspec[1];
*out_type = intspec[2];
return 0;
}
static int wakeupgen_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs, void *data)
{
struct of_phandle_args *args = data;
struct of_phandle_args parent_args;
irq_hw_number_t hwirq;
int i;
if (args->args_count != 3)
return -EINVAL; /* Not GIC compliant */
if (args->args[0] != 0)
return -EINVAL; /* No PPI should point to this domain */
hwirq = args->args[1];
if (hwirq >= MAX_IRQS)
return -EINVAL; /* Can't deal with this */
for (i = 0; i < nr_irqs; i++)
irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
&wakeupgen_chip, NULL);
parent_args = *args;
parent_args.np = domain->parent->of_node;
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args);
}
static struct irq_domain_ops wakeupgen_domain_ops = {
.xlate = wakeupgen_domain_xlate,
.alloc = wakeupgen_domain_alloc,
.free = irq_domain_free_irqs_common,
};
/* /*
* Initialise the wakeupgen module. * Initialise the wakeupgen module.
*/ */
int __init omap_wakeupgen_init(void) static int __init wakeupgen_init(struct device_node *node,
struct device_node *parent)
{ {
struct irq_domain *parent_domain, *domain;
int i; int i;
unsigned int boot_cpu = smp_processor_id(); unsigned int boot_cpu = smp_processor_id();
u32 val; u32 val;
if (!parent) {
pr_err("%s: no parent, giving up\n", node->full_name);
return -ENODEV;
}
parent_domain = irq_find_host(parent);
if (!parent_domain) {
pr_err("%s: unable to obtain parent domain\n", node->full_name);
return -ENXIO;
}
/* Not supported on OMAP4 ES1.0 silicon */ /* Not supported on OMAP4 ES1.0 silicon */
if (omap_rev() == OMAP4430_REV_ES1_0) { if (omap_rev() == OMAP4430_REV_ES1_0) {
WARN(1, "WakeupGen: Not supported on OMAP4430 ES1.0\n"); WARN(1, "WakeupGen: Not supported on OMAP4430 ES1.0\n");
...@@ -416,7 +478,7 @@ int __init omap_wakeupgen_init(void) ...@@ -416,7 +478,7 @@ int __init omap_wakeupgen_init(void)
} }
/* Static mapping, never released */ /* Static mapping, never released */
wakeupgen_base = ioremap(OMAP_WKUPGEN_BASE, SZ_4K); wakeupgen_base = of_iomap(node, 0);
if (WARN_ON(!wakeupgen_base)) if (WARN_ON(!wakeupgen_base))
return -ENOMEM; return -ENOMEM;
...@@ -429,6 +491,14 @@ int __init omap_wakeupgen_init(void) ...@@ -429,6 +491,14 @@ int __init omap_wakeupgen_init(void)
max_irqs = AM43XX_IRQS; max_irqs = AM43XX_IRQS;
} }
domain = irq_domain_add_hierarchy(parent_domain, 0, max_irqs,
node, &wakeupgen_domain_ops,
NULL);
if (!domain) {
iounmap(wakeupgen_base);
return -ENOMEM;
}
/* Clear all IRQ bitmasks at wakeupGen level */ /* Clear all IRQ bitmasks at wakeupGen level */
for (i = 0; i < irq_banks; i++) { for (i = 0; i < irq_banks; i++) {
wakeupgen_writel(0, i, CPU0_ID); wakeupgen_writel(0, i, CPU0_ID);
...@@ -436,14 +506,6 @@ int __init omap_wakeupgen_init(void) ...@@ -436,14 +506,6 @@ int __init omap_wakeupgen_init(void)
wakeupgen_writel(0, i, CPU1_ID); wakeupgen_writel(0, i, CPU1_ID);
} }
/*
* Override GIC architecture specific functions to add
* OMAP WakeupGen interrupt controller along with GIC
*/
gic_arch_extn.irq_mask = wakeupgen_mask;
gic_arch_extn.irq_unmask = wakeupgen_unmask;
gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE;
/* /*
* FIXME: Add support to set_smp_affinity() once the core * FIXME: Add support to set_smp_affinity() once the core
* GIC code has necessary hooks in place. * GIC code has necessary hooks in place.
...@@ -474,3 +536,9 @@ int __init omap_wakeupgen_init(void) ...@@ -474,3 +536,9 @@ int __init omap_wakeupgen_init(void)
return 0; return 0;
} }
/*
* We cannot use the IRQCHIP_DECLARE macro that lives in
* drivers/irqchip, so we're forced to roll our own. Not very nice.
*/
OF_DECLARE_2(irqchip, ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init);
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#define OMAP_TIMESTAMPCYCLELO 0xc08 #define OMAP_TIMESTAMPCYCLELO 0xc08
#define OMAP_TIMESTAMPCYCLEHI 0xc0c #define OMAP_TIMESTAMPCYCLEHI 0xc0c
extern int __init omap_wakeupgen_init(void);
extern void __iomem *omap_get_wakeupgen_base(void); extern void __iomem *omap_get_wakeupgen_base(void);
extern int omap_secure_apis_support(void); extern int omap_secure_apis_support(void);
#endif #endif
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic.h>
#include <linux/irqchip/irq-crossbar.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/genalloc.h> #include <linux/genalloc.h>
...@@ -242,26 +241,26 @@ static int __init omap4_sar_ram_init(void) ...@@ -242,26 +241,26 @@ static int __init omap4_sar_ram_init(void)
} }
omap_early_initcall(omap4_sar_ram_init); omap_early_initcall(omap4_sar_ram_init);
static const struct of_device_id gic_match[] = { static const struct of_device_id intc_match[] = {
{ .compatible = "arm,cortex-a9-gic", }, { .compatible = "ti,omap4-wugen-mpu", },
{ .compatible = "arm,cortex-a15-gic", }, { .compatible = "ti,omap5-wugen-mpu", },
{ }, { },
}; };
static struct device_node *gic_node; static struct device_node *intc_node;
unsigned int omap4_xlate_irq(unsigned int hwirq) unsigned int omap4_xlate_irq(unsigned int hwirq)
{ {
struct of_phandle_args irq_data; struct of_phandle_args irq_data;
unsigned int irq; unsigned int irq;
if (!gic_node) if (!intc_node)
gic_node = of_find_matching_node(NULL, gic_match); intc_node = of_find_matching_node(NULL, intc_match);
if (WARN_ON(!gic_node)) if (WARN_ON(!intc_node))
return hwirq; return hwirq;
irq_data.np = gic_node; irq_data.np = intc_node;
irq_data.args_count = 3; irq_data.args_count = 3;
irq_data.args[0] = 0; irq_data.args[0] = 0;
irq_data.args[1] = hwirq - OMAP44XX_IRQ_GIC_START; irq_data.args[1] = hwirq - OMAP44XX_IRQ_GIC_START;
...@@ -278,6 +277,12 @@ void __init omap_gic_of_init(void) ...@@ -278,6 +277,12 @@ void __init omap_gic_of_init(void)
{ {
struct device_node *np; struct device_node *np;
intc_node = of_find_matching_node(NULL, intc_match);
if (WARN_ON(!intc_node)) {
pr_err("No WUGEN found in DT, system will misbehave.\n");
pr_err("UPDATE YOUR DEVICE TREE!\n");
}
/* Extract GIC distributor and TWD bases for OMAP4460 ROM Errata WA */ /* Extract GIC distributor and TWD bases for OMAP4460 ROM Errata WA */
if (!cpu_is_omap446x()) if (!cpu_is_omap446x())
goto skip_errata_init; goto skip_errata_init;
...@@ -291,9 +296,5 @@ void __init omap_gic_of_init(void) ...@@ -291,9 +296,5 @@ void __init omap_gic_of_init(void)
WARN_ON(!twd_base); WARN_ON(!twd_base);
skip_errata_init: skip_errata_init:
omap_wakeupgen_init();
#ifdef CONFIG_IRQ_CROSSBAR
irqcrossbar_init();
#endif
irqchip_init(); irqchip_init();
} }
...@@ -252,11 +252,6 @@ static irqreturn_t sh73a0_intcs_demux(int irq, void *dev_id) ...@@ -252,11 +252,6 @@ static irqreturn_t sh73a0_intcs_demux(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int sh73a0_set_wake(struct irq_data *data, unsigned int on)
{
return 0; /* always allow wakeup */
}
#define PINTER0_PHYS 0xe69000a0 #define PINTER0_PHYS 0xe69000a0
#define PINTER1_PHYS 0xe69000a4 #define PINTER1_PHYS 0xe69000a4
#define PINTER0_VIRT IOMEM(0xe69000a0) #define PINTER0_VIRT IOMEM(0xe69000a0)
...@@ -318,8 +313,8 @@ void __init sh73a0_init_irq(void) ...@@ -318,8 +313,8 @@ void __init sh73a0_init_irq(void)
void __iomem *gic_cpu_base = IOMEM(0xf0000100); void __iomem *gic_cpu_base = IOMEM(0xf0000100);
void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE);
gic_init(0, 29, gic_dist_base, gic_cpu_base); gic_init(0, 29, gic_dist_base, gic_cpu_base);
gic_arch_extn.irq_set_wake = sh73a0_set_wake;
register_intc_controller(&intcs_desc); register_intc_controller(&intcs_desc);
register_intc_controller(&intc_pint0_desc); register_intc_controller(&intc_pint0_desc);
......
...@@ -713,18 +713,13 @@ void __init r8a7779_init_late(void) ...@@ -713,18 +713,13 @@ void __init r8a7779_init_late(void)
} }
#ifdef CONFIG_USE_OF #ifdef CONFIG_USE_OF
static int r8a7779_set_wake(struct irq_data *data, unsigned int on)
{
return 0; /* always allow wakeup */
}
void __init r8a7779_init_irq_dt(void) void __init r8a7779_init_irq_dt(void)
{ {
#ifdef CONFIG_ARCH_SHMOBILE_LEGACY #ifdef CONFIG_ARCH_SHMOBILE_LEGACY
void __iomem *gic_dist_base = ioremap_nocache(0xf0001000, 0x1000); void __iomem *gic_dist_base = ioremap_nocache(0xf0001000, 0x1000);
void __iomem *gic_cpu_base = ioremap_nocache(0xf0000100, 0x1000); void __iomem *gic_cpu_base = ioremap_nocache(0xf0000100, 0x1000);
#endif #endif
gic_arch_extn.irq_set_wake = r8a7779_set_wake; gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE);
#ifdef CONFIG_ARCH_SHMOBILE_LEGACY #ifdef CONFIG_ARCH_SHMOBILE_LEGACY
gic_init(0, 29, gic_dist_base, gic_cpu_base); gic_init(0, 29, gic_dist_base, gic_cpu_base);
......
...@@ -31,21 +31,6 @@ ...@@ -31,21 +31,6 @@
#define TEGRA_ARM_INT_DIST_BASE 0x50041000 #define TEGRA_ARM_INT_DIST_BASE 0x50041000
#define TEGRA_ARM_INT_DIST_SIZE SZ_4K #define TEGRA_ARM_INT_DIST_SIZE SZ_4K
#define TEGRA_PRIMARY_ICTLR_BASE 0x60004000
#define TEGRA_PRIMARY_ICTLR_SIZE SZ_64
#define TEGRA_SECONDARY_ICTLR_BASE 0x60004100
#define TEGRA_SECONDARY_ICTLR_SIZE SZ_64
#define TEGRA_TERTIARY_ICTLR_BASE 0x60004200
#define TEGRA_TERTIARY_ICTLR_SIZE SZ_64
#define TEGRA_QUATERNARY_ICTLR_BASE 0x60004300
#define TEGRA_QUATERNARY_ICTLR_SIZE SZ_64
#define TEGRA_QUINARY_ICTLR_BASE 0x60004400
#define TEGRA_QUINARY_ICTLR_SIZE SZ_64
#define TEGRA_TMR1_BASE 0x60005000 #define TEGRA_TMR1_BASE 0x60005000
#define TEGRA_TMR1_SIZE SZ_8 #define TEGRA_TMR1_SIZE SZ_8
......
...@@ -30,43 +30,9 @@ ...@@ -30,43 +30,9 @@
#include "board.h" #include "board.h"
#include "iomap.h" #include "iomap.h"
#define ICTLR_CPU_IEP_VFIQ 0x08
#define ICTLR_CPU_IEP_FIR 0x14
#define ICTLR_CPU_IEP_FIR_SET 0x18
#define ICTLR_CPU_IEP_FIR_CLR 0x1c
#define ICTLR_CPU_IER 0x20
#define ICTLR_CPU_IER_SET 0x24
#define ICTLR_CPU_IER_CLR 0x28
#define ICTLR_CPU_IEP_CLASS 0x2C
#define ICTLR_COP_IER 0x30
#define ICTLR_COP_IER_SET 0x34
#define ICTLR_COP_IER_CLR 0x38
#define ICTLR_COP_IEP_CLASS 0x3c
#define FIRST_LEGACY_IRQ 32
#define TEGRA_MAX_NUM_ICTLRS 5
#define SGI_MASK 0xFFFF #define SGI_MASK 0xFFFF
static int num_ictlrs;
static void __iomem *ictlr_reg_base[] = {
IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
};
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static u32 cop_ier[TEGRA_MAX_NUM_ICTLRS];
static u32 cop_iep[TEGRA_MAX_NUM_ICTLRS];
static u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS];
static u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS];
static u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS];
static void __iomem *tegra_gic_cpu_base; static void __iomem *tegra_gic_cpu_base;
#endif #endif
...@@ -83,140 +49,7 @@ bool tegra_pending_sgi(void) ...@@ -83,140 +49,7 @@ bool tegra_pending_sgi(void)
return false; return false;
} }
static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
{
void __iomem *base;
u32 mask;
BUG_ON(irq < FIRST_LEGACY_IRQ ||
irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32);
base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32];
mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
__raw_writel(mask, base + reg);
}
static void tegra_mask(struct irq_data *d)
{
if (d->hwirq < FIRST_LEGACY_IRQ)
return;
tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_CLR);
}
static void tegra_unmask(struct irq_data *d)
{
if (d->hwirq < FIRST_LEGACY_IRQ)
return;
tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_SET);
}
static void tegra_ack(struct irq_data *d)
{
if (d->hwirq < FIRST_LEGACY_IRQ)
return;
tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR);
}
static void tegra_eoi(struct irq_data *d)
{
if (d->hwirq < FIRST_LEGACY_IRQ)
return;
tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR);
}
static int tegra_retrigger(struct irq_data *d)
{
if (d->hwirq < FIRST_LEGACY_IRQ)
return 0;
tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_SET);
return 1;
}
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int tegra_set_wake(struct irq_data *d, unsigned int enable)
{
u32 irq = d->hwirq;
u32 index, mask;
if (irq < FIRST_LEGACY_IRQ ||
irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32)
return -EINVAL;
index = ((irq - FIRST_LEGACY_IRQ) / 32);
mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
if (enable)
ictlr_wake_mask[index] |= mask;
else
ictlr_wake_mask[index] &= ~mask;
return 0;
}
static int tegra_legacy_irq_suspend(void)
{
unsigned long flags;
int i;
local_irq_save(flags);
for (i = 0; i < num_ictlrs; i++) {
void __iomem *ictlr = ictlr_reg_base[i];
/* Save interrupt state */
cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER);
cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS);
cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER);
cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS);
/* Disable COP interrupts */
writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
/* Disable CPU interrupts */
writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
/* Enable the wakeup sources of ictlr */
writel_relaxed(ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET);
}
local_irq_restore(flags);
return 0;
}
static void tegra_legacy_irq_resume(void)
{
unsigned long flags;
int i;
local_irq_save(flags);
for (i = 0; i < num_ictlrs; i++) {
void __iomem *ictlr = ictlr_reg_base[i];
writel_relaxed(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
writel_relaxed(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
writel_relaxed(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS);
writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
writel_relaxed(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
}
local_irq_restore(flags);
}
static struct syscore_ops tegra_legacy_irq_syscore_ops = {
.suspend = tegra_legacy_irq_suspend,
.resume = tegra_legacy_irq_resume,
};
int tegra_legacy_irq_syscore_init(void)
{
register_syscore_ops(&tegra_legacy_irq_syscore_ops);
return 0;
}
static int tegra_gic_notifier(struct notifier_block *self, static int tegra_gic_notifier(struct notifier_block *self,
unsigned long cmd, void *v) unsigned long cmd, void *v)
{ {
...@@ -251,45 +84,19 @@ static void tegra114_gic_cpu_pm_registration(void) ...@@ -251,45 +84,19 @@ static void tegra114_gic_cpu_pm_registration(void)
cpu_pm_register_notifier(&tegra_gic_notifier_block); cpu_pm_register_notifier(&tegra_gic_notifier_block);
} }
#else #else
#define tegra_set_wake NULL
static void tegra114_gic_cpu_pm_registration(void) { } static void tegra114_gic_cpu_pm_registration(void) { }
#endif #endif
static const struct of_device_id tegra_ictlr_match[] __initconst = {
{ .compatible = "nvidia,tegra20-ictlr" },
{ .compatible = "nvidia,tegra30-ictlr" },
{ }
};
void __init tegra_init_irq(void) void __init tegra_init_irq(void)
{ {
int i; if (WARN_ON(!of_find_matching_node(NULL, tegra_ictlr_match)))
void __iomem *distbase; pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE);
num_ictlrs = readl_relaxed(distbase + GIC_DIST_CTR) & 0x1f;
if (num_ictlrs > ARRAY_SIZE(ictlr_reg_base)) {
WARN(1, "Too many (%d) interrupt controllers found. Maximum is %d.",
num_ictlrs, ARRAY_SIZE(ictlr_reg_base));
num_ictlrs = ARRAY_SIZE(ictlr_reg_base);
}
for (i = 0; i < num_ictlrs; i++) {
void __iomem *ictlr = ictlr_reg_base[i];
writel(~0, ictlr + ICTLR_CPU_IER_CLR);
writel(0, ictlr + ICTLR_CPU_IEP_CLASS);
}
gic_arch_extn.irq_ack = tegra_ack;
gic_arch_extn.irq_eoi = tegra_eoi;
gic_arch_extn.irq_mask = tegra_mask;
gic_arch_extn.irq_unmask = tegra_unmask;
gic_arch_extn.irq_retrigger = tegra_retrigger;
gic_arch_extn.irq_set_wake = tegra_set_wake;
gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
/*
* Check if there is a devicetree present, since the GIC will be
* initialized elsewhere under DT.
*/
if (!of_have_populated_dt())
gic_init(0, 29, distbase,
IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
tegra114_gic_cpu_pm_registration(); tegra114_gic_cpu_pm_registration();
} }
...@@ -19,10 +19,4 @@ ...@@ -19,10 +19,4 @@
bool tegra_pending_sgi(void); bool tegra_pending_sgi(void);
#ifdef CONFIG_PM_SLEEP
int tegra_legacy_irq_syscore_init(void);
#else
static inline int tegra_legacy_irq_syscore_init(void) { return 0; }
#endif
#endif #endif
...@@ -82,7 +82,6 @@ static void __init tegra_dt_init_irq(void) ...@@ -82,7 +82,6 @@ static void __init tegra_dt_init_irq(void)
{ {
tegra_init_irq(); tegra_init_irq();
irqchip_init(); irqchip_init();
tegra_legacy_irq_syscore_init();
} }
static void __init tegra_dt_init(void) static void __init tegra_dt_init(void)
......
...@@ -52,7 +52,7 @@ void ux500_restart(enum reboot_mode mode, const char *cmd) ...@@ -52,7 +52,7 @@ void ux500_restart(enum reboot_mode mode, const char *cmd)
*/ */
void __init ux500_init_irq(void) void __init ux500_init_irq(void)
{ {
gic_arch_extn.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND);
irqchip_init(); irqchip_init();
/* /*
......
...@@ -186,7 +186,7 @@ static void __init zynq_map_io(void) ...@@ -186,7 +186,7 @@ static void __init zynq_map_io(void)
static void __init zynq_irq_init(void) static void __init zynq_irq_init(void)
{ {
gic_arch_extn.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND);
irqchip_init(); irqchip_init();
} }
......
...@@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o ...@@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o
obj-$(CONFIG_ARCH_MMP) += irq-mmp.o obj-$(CONFIG_ARCH_MMP) += irq-mmp.o
obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o
obj-$(CONFIG_ARCH_MXS) += irq-mxs.o obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o
obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o
obj-$(CONFIG_METAG) += irq-metag-ext.o obj-$(CONFIG_METAG) += irq-metag-ext.o
......
...@@ -11,11 +11,12 @@ ...@@ -11,11 +11,12 @@
*/ */
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/irqchip/irq-crossbar.h> #include "irqchip.h"
#define IRQ_FREE -1 #define IRQ_FREE -1
#define IRQ_RESERVED -2 #define IRQ_RESERVED -2
...@@ -24,6 +25,7 @@ ...@@ -24,6 +25,7 @@
/** /**
* struct crossbar_device - crossbar device description * struct crossbar_device - crossbar device description
* @lock: spinlock serializing access to @irq_map
* @int_max: maximum number of supported interrupts * @int_max: maximum number of supported interrupts
* @safe_map: safe default value to initialize the crossbar * @safe_map: safe default value to initialize the crossbar
* @max_crossbar_sources: Maximum number of crossbar sources * @max_crossbar_sources: Maximum number of crossbar sources
...@@ -33,6 +35,7 @@ ...@@ -33,6 +35,7 @@
* @write: register write function pointer * @write: register write function pointer
*/ */
struct crossbar_device { struct crossbar_device {
raw_spinlock_t lock;
uint int_max; uint int_max;
uint safe_map; uint safe_map;
uint max_crossbar_sources; uint max_crossbar_sources;
...@@ -44,72 +47,101 @@ struct crossbar_device { ...@@ -44,72 +47,101 @@ struct crossbar_device {
static struct crossbar_device *cb; static struct crossbar_device *cb;
static inline void crossbar_writel(int irq_no, int cb_no) static void crossbar_writel(int irq_no, int cb_no)
{ {
writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
} }
static inline void crossbar_writew(int irq_no, int cb_no) static void crossbar_writew(int irq_no, int cb_no)
{ {
writew(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); writew(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
} }
static inline void crossbar_writeb(int irq_no, int cb_no) static void crossbar_writeb(int irq_no, int cb_no)
{ {
writeb(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); writeb(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
} }
static inline int get_prev_map_irq(int cb_no) static struct irq_chip crossbar_chip = {
{ .name = "CBAR",
int i; .irq_eoi = irq_chip_eoi_parent,
.irq_mask = irq_chip_mask_parent,
for (i = cb->int_max - 1; i >= 0; i--) .irq_unmask = irq_chip_unmask_parent,
if (cb->irq_map[i] == cb_no) .irq_retrigger = irq_chip_retrigger_hierarchy,
return i; .irq_set_wake = irq_chip_set_wake_parent,
#ifdef CONFIG_SMP
return -ENODEV; .irq_set_affinity = irq_chip_set_affinity_parent,
} #endif
};
static inline int allocate_free_irq(int cb_no) static int allocate_gic_irq(struct irq_domain *domain, unsigned virq,
irq_hw_number_t hwirq)
{ {
struct of_phandle_args args;
int i; int i;
int err;
raw_spin_lock(&cb->lock);
for (i = cb->int_max - 1; i >= 0; i--) { for (i = cb->int_max - 1; i >= 0; i--) {
if (cb->irq_map[i] == IRQ_FREE) { if (cb->irq_map[i] == IRQ_FREE) {
cb->irq_map[i] = cb_no; cb->irq_map[i] = hwirq;
return i; break;
} }
} }
raw_spin_unlock(&cb->lock);
return -ENODEV; if (i < 0)
} return -ENODEV;
static inline bool needs_crossbar_write(irq_hw_number_t hw) args.np = domain->parent->of_node;
{ args.args_count = 3;
int cb_no; args.args[0] = 0; /* SPI */
args.args[1] = i;
args.args[2] = IRQ_TYPE_LEVEL_HIGH;
if (hw > GIC_IRQ_START) { err = irq_domain_alloc_irqs_parent(domain, virq, 1, &args);
cb_no = cb->irq_map[hw - GIC_IRQ_START]; if (err)
if (cb_no != IRQ_RESERVED && cb_no != IRQ_SKIP) cb->irq_map[i] = IRQ_FREE;
return true; else
} cb->write(i, hwirq);
return false; return err;
} }
static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, static int crossbar_domain_alloc(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw) unsigned int nr_irqs, void *data)
{ {
if (needs_crossbar_write(hw)) struct of_phandle_args *args = data;
cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]); irq_hw_number_t hwirq;
int i;
if (args->args_count != 3)
return -EINVAL; /* Not GIC compliant */
if (args->args[0] != 0)
return -EINVAL; /* No PPI should point to this domain */
hwirq = args->args[1];
if ((hwirq + nr_irqs) > cb->max_crossbar_sources)
return -EINVAL; /* Can't deal with this */
for (i = 0; i < nr_irqs; i++) {
int err = allocate_gic_irq(d, virq + i, hwirq + i);
if (err)
return err;
irq_domain_set_hwirq_and_chip(d, virq + i, hwirq + i,
&crossbar_chip, NULL);
}
return 0; return 0;
} }
/** /**
* crossbar_domain_unmap - unmap a crossbar<->irq connection * crossbar_domain_free - unmap/free a crossbar<->irq connection
* @d: domain of irq to unmap * @domain: domain of irq to unmap
* @irq: virq number * @virq: virq number
* @nr_irqs: number of irqs to free
* *
* We do not maintain a use count of total number of map/unmap * We do not maintain a use count of total number of map/unmap
* calls for a particular irq to find out if a irq can be really * calls for a particular irq to find out if a irq can be really
...@@ -117,14 +149,20 @@ static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, ...@@ -117,14 +149,20 @@ static int crossbar_domain_map(struct irq_domain *d, unsigned int irq,
* after which irq is anyways unusable. So an explicit map has to be called * after which irq is anyways unusable. So an explicit map has to be called
* after that. * after that.
*/ */
static void crossbar_domain_unmap(struct irq_domain *d, unsigned int irq) static void crossbar_domain_free(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs)
{ {
irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq; int i;
if (needs_crossbar_write(hw)) { raw_spin_lock(&cb->lock);
cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE; for (i = 0; i < nr_irqs; i++) {
cb->write(hw - GIC_IRQ_START, cb->safe_map); struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
irq_domain_reset_irq_data(d);
cb->irq_map[d->hwirq] = IRQ_FREE;
cb->write(d->hwirq, cb->safe_map);
} }
raw_spin_unlock(&cb->lock);
} }
static int crossbar_domain_xlate(struct irq_domain *d, static int crossbar_domain_xlate(struct irq_domain *d,
...@@ -133,44 +171,22 @@ static int crossbar_domain_xlate(struct irq_domain *d, ...@@ -133,44 +171,22 @@ static int crossbar_domain_xlate(struct irq_domain *d,
unsigned long *out_hwirq, unsigned long *out_hwirq,
unsigned int *out_type) unsigned int *out_type)
{ {
int ret; if (d->of_node != controller)
int req_num = intspec[1]; return -EINVAL; /* Shouldn't happen, really... */
int direct_map_num; if (intsize != 3)
return -EINVAL; /* Not GIC compliant */
if (req_num >= cb->max_crossbar_sources) { if (intspec[0] != 0)
direct_map_num = req_num - cb->max_crossbar_sources; return -EINVAL; /* No PPI should point to this domain */
if (direct_map_num < cb->int_max) {
ret = cb->irq_map[direct_map_num]; *out_hwirq = intspec[1];
if (ret == IRQ_RESERVED || ret == IRQ_SKIP) { *out_type = intspec[2];
/* We use the interrupt num as h/w irq num */
ret = direct_map_num;
goto found;
}
}
pr_err("%s: requested crossbar number %d > max %d\n",
__func__, req_num, cb->max_crossbar_sources);
return -EINVAL;
}
ret = get_prev_map_irq(req_num);
if (ret >= 0)
goto found;
ret = allocate_free_irq(req_num);
if (ret < 0)
return ret;
found:
*out_hwirq = ret + GIC_IRQ_START;
return 0; return 0;
} }
static const struct irq_domain_ops routable_irq_domain_ops = { static const struct irq_domain_ops crossbar_domain_ops = {
.map = crossbar_domain_map, .alloc = crossbar_domain_alloc,
.unmap = crossbar_domain_unmap, .free = crossbar_domain_free,
.xlate = crossbar_domain_xlate .xlate = crossbar_domain_xlate,
}; };
static int __init crossbar_of_init(struct device_node *node) static int __init crossbar_of_init(struct device_node *node)
...@@ -293,7 +309,8 @@ static int __init crossbar_of_init(struct device_node *node) ...@@ -293,7 +309,8 @@ static int __init crossbar_of_init(struct device_node *node)
cb->write(i, cb->safe_map); cb->write(i, cb->safe_map);
} }
register_routable_domain_ops(&routable_irq_domain_ops); raw_spin_lock_init(&cb->lock);
return 0; return 0;
err_reg_offset: err_reg_offset:
...@@ -309,18 +326,37 @@ static int __init crossbar_of_init(struct device_node *node) ...@@ -309,18 +326,37 @@ static int __init crossbar_of_init(struct device_node *node)
return ret; return ret;
} }
static const struct of_device_id crossbar_match[] __initconst = { static int __init irqcrossbar_init(struct device_node *node,
{ .compatible = "ti,irq-crossbar" }, struct device_node *parent)
{}
};
int __init irqcrossbar_init(void)
{ {
struct device_node *np; struct irq_domain *parent_domain, *domain;
np = of_find_matching_node(NULL, crossbar_match); int err;
if (!np)
if (!parent) {
pr_err("%s: no parent, giving up\n", node->full_name);
return -ENODEV; return -ENODEV;
}
parent_domain = irq_find_host(parent);
if (!parent_domain) {
pr_err("%s: unable to obtain parent domain\n", node->full_name);
return -ENXIO;
}
err = crossbar_of_init(node);
if (err)
return err;
domain = irq_domain_add_hierarchy(parent_domain, 0,
cb->max_crossbar_sources,
node, &crossbar_domain_ops,
NULL);
if (!domain) {
pr_err("%s: failed to allocated domain\n", node->full_name);
return -ENOMEM;
}
crossbar_of_init(np);
return 0; return 0;
} }
IRQCHIP_DECLARE(ti_irqcrossbar, "ti,irq-crossbar", irqcrossbar_init);
...@@ -863,15 +863,12 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, ...@@ -863,15 +863,12 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data, irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data,
handle_fasteoi_irq, NULL, NULL); handle_fasteoi_irq, NULL, NULL);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
gic_routable_irq_domain_ops->map(d, irq, hw);
} }
return 0; return 0;
} }
static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq) static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
{ {
gic_routable_irq_domain_ops->unmap(d, irq);
} }
static int gic_irq_domain_xlate(struct irq_domain *d, static int gic_irq_domain_xlate(struct irq_domain *d,
...@@ -890,16 +887,8 @@ static int gic_irq_domain_xlate(struct irq_domain *d, ...@@ -890,16 +887,8 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
*out_hwirq = intspec[1] + 16; *out_hwirq = intspec[1] + 16;
/* For SPIs, we need to add 16 more to get the GIC irq ID number */ /* For SPIs, we need to add 16 more to get the GIC irq ID number */
if (!intspec[0]) { if (!intspec[0])
ret = gic_routable_irq_domain_ops->xlate(d, controller, *out_hwirq += 16;
intspec,
intsize,
out_hwirq,
out_type);
if (IS_ERR_VALUE(ret))
return ret;
}
*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
...@@ -956,37 +945,11 @@ static const struct irq_domain_ops gic_irq_domain_ops = { ...@@ -956,37 +945,11 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
.xlate = gic_irq_domain_xlate, .xlate = gic_irq_domain_xlate,
}; };
/* Default functions for routable irq domain */ void gic_set_irqchip_flags(unsigned long flags)
static int gic_routable_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
return 0;
}
static void gic_routable_irq_domain_unmap(struct irq_domain *d,
unsigned int irq)
{
}
static int gic_routable_irq_domain_xlate(struct irq_domain *d,
struct device_node *controller,
const u32 *intspec, unsigned int intsize,
unsigned long *out_hwirq,
unsigned int *out_type)
{ {
*out_hwirq += 16; gic_chip.flags |= flags;
return 0;
} }
static const struct irq_domain_ops gic_default_routable_irq_domain_ops = {
.map = gic_routable_irq_domain_map,
.unmap = gic_routable_irq_domain_unmap,
.xlate = gic_routable_irq_domain_xlate,
};
const struct irq_domain_ops *gic_routable_irq_domain_ops =
&gic_default_routable_irq_domain_ops;
void __init gic_init_bases(unsigned int gic_nr, int irq_start, void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base, void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset, struct device_node *node) u32 percpu_offset, struct device_node *node)
...@@ -994,7 +957,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, ...@@ -994,7 +957,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
irq_hw_number_t hwirq_base; irq_hw_number_t hwirq_base;
struct gic_chip_data *gic; struct gic_chip_data *gic;
int gic_irqs, irq_base, i; int gic_irqs, irq_base, i;
int nr_routable_irqs;
BUG_ON(gic_nr >= MAX_GIC_NR); BUG_ON(gic_nr >= MAX_GIC_NR);
...@@ -1050,15 +1012,9 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, ...@@ -1050,15 +1012,9 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
gic->gic_irqs = gic_irqs; gic->gic_irqs = gic_irqs;
if (node) { /* DT case */ if (node) { /* DT case */
const struct irq_domain_ops *ops = &gic_irq_domain_hierarchy_ops; gic->domain = irq_domain_add_linear(node, gic_irqs,
&gic_irq_domain_hierarchy_ops,
if (!of_property_read_u32(node, "arm,routable-irqs", gic);
&nr_routable_irqs)) {
ops = &gic_irq_domain_ops;
gic_irqs = nr_routable_irqs;
}
gic->domain = irq_domain_add_linear(node, gic_irqs, ops, gic);
} else { /* Non-DT case */ } else { /* Non-DT case */
/* /*
* For primary GICs, skip over SGIs. * For primary GICs, skip over SGIs.
......
/*
* Driver code for Tegra's Legacy Interrupt Controller
*
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
* Heavily based on the original arch/arm/mach-tegra/irq.c code:
* Copyright (C) 2011 Google, Inc.
*
* Author:
* Colin Cross <ccross@android.com>
*
* Copyright (C) 2010,2013, NVIDIA Corporation
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/syscore_ops.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "irqchip.h"
#define ICTLR_CPU_IEP_VFIQ 0x08
#define ICTLR_CPU_IEP_FIR 0x14
#define ICTLR_CPU_IEP_FIR_SET 0x18
#define ICTLR_CPU_IEP_FIR_CLR 0x1c
#define ICTLR_CPU_IER 0x20
#define ICTLR_CPU_IER_SET 0x24
#define ICTLR_CPU_IER_CLR 0x28
#define ICTLR_CPU_IEP_CLASS 0x2C
#define ICTLR_COP_IER 0x30
#define ICTLR_COP_IER_SET 0x34
#define ICTLR_COP_IER_CLR 0x38
#define ICTLR_COP_IEP_CLASS 0x3c
#define TEGRA_MAX_NUM_ICTLRS 6
static unsigned int num_ictlrs;
struct tegra_ictlr_soc {
unsigned int num_ictlrs;
};
static const struct tegra_ictlr_soc tegra20_ictlr_soc = {
.num_ictlrs = 4,
};
static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
.num_ictlrs = 5,
};
static const struct tegra_ictlr_soc tegra210_ictlr_soc = {
.num_ictlrs = 6,
};
static const struct of_device_id ictlr_matches[] = {
{ .compatible = "nvidia,tegra210-ictlr", .data = &tegra210_ictlr_soc },
{ .compatible = "nvidia,tegra30-ictlr", .data = &tegra30_ictlr_soc },
{ .compatible = "nvidia,tegra20-ictlr", .data = &tegra20_ictlr_soc },
{ }
};
struct tegra_ictlr_info {
void __iomem *base[TEGRA_MAX_NUM_ICTLRS];
#ifdef CONFIG_PM_SLEEP
u32 cop_ier[TEGRA_MAX_NUM_ICTLRS];
u32 cop_iep[TEGRA_MAX_NUM_ICTLRS];
u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS];
u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS];
u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS];
#endif
};
static struct tegra_ictlr_info *lic;
static inline void tegra_ictlr_write_mask(struct irq_data *d, unsigned long reg)
{
void __iomem *base = d->chip_data;
u32 mask;
mask = BIT(d->hwirq % 32);
writel_relaxed(mask, base + reg);
}
static void tegra_mask(struct irq_data *d)
{
tegra_ictlr_write_mask(d, ICTLR_CPU_IER_CLR);
irq_chip_mask_parent(d);
}
static void tegra_unmask(struct irq_data *d)
{
tegra_ictlr_write_mask(d, ICTLR_CPU_IER_SET);
irq_chip_unmask_parent(d);
}
static void tegra_eoi(struct irq_data *d)
{
tegra_ictlr_write_mask(d, ICTLR_CPU_IEP_FIR_CLR);
irq_chip_eoi_parent(d);
}
static int tegra_retrigger(struct irq_data *d)
{
tegra_ictlr_write_mask(d, ICTLR_CPU_IEP_FIR_SET);
return irq_chip_retrigger_hierarchy(d);
}
#ifdef CONFIG_PM_SLEEP
static int tegra_set_wake(struct irq_data *d, unsigned int enable)
{
u32 irq = d->hwirq;
u32 index, mask;
index = (irq / 32);
mask = BIT(irq % 32);
if (enable)
lic->ictlr_wake_mask[index] |= mask;
else
lic->ictlr_wake_mask[index] &= ~mask;
/*
* Do *not* call into the parent, as the GIC doesn't have any
* wake-up facility...
*/
return 0;
}
static int tegra_ictlr_suspend(void)
{
unsigned long flags;
unsigned int i;
local_irq_save(flags);
for (i = 0; i < num_ictlrs; i++) {
void __iomem *ictlr = lic->base[i];
/* Save interrupt state */
lic->cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER);
lic->cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS);
lic->cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER);
lic->cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS);
/* Disable COP interrupts */
writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
/* Disable CPU interrupts */
writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
/* Enable the wakeup sources of ictlr */
writel_relaxed(lic->ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET);
}
local_irq_restore(flags);
return 0;
}
static void tegra_ictlr_resume(void)
{
unsigned long flags;
unsigned int i;
local_irq_save(flags);
for (i = 0; i < num_ictlrs; i++) {
void __iomem *ictlr = lic->base[i];
writel_relaxed(lic->cpu_iep[i],
ictlr + ICTLR_CPU_IEP_CLASS);
writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
writel_relaxed(lic->cpu_ier[i],
ictlr + ICTLR_CPU_IER_SET);
writel_relaxed(lic->cop_iep[i],
ictlr + ICTLR_COP_IEP_CLASS);
writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
writel_relaxed(lic->cop_ier[i],
ictlr + ICTLR_COP_IER_SET);
}
local_irq_restore(flags);
}
static struct syscore_ops tegra_ictlr_syscore_ops = {
.suspend = tegra_ictlr_suspend,
.resume = tegra_ictlr_resume,
};
static void tegra_ictlr_syscore_init(void)
{
register_syscore_ops(&tegra_ictlr_syscore_ops);
}
#else
#define tegra_set_wake NULL
static inline void tegra_ictlr_syscore_init(void) {}
#endif
static struct irq_chip tegra_ictlr_chip = {
.name = "LIC",
.irq_eoi = tegra_eoi,
.irq_mask = tegra_mask,
.irq_unmask = tegra_unmask,
.irq_retrigger = tegra_retrigger,
.irq_set_wake = tegra_set_wake,
.flags = IRQCHIP_MASK_ON_SUSPEND,
#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
#endif
};
static int tegra_ictlr_domain_xlate(struct irq_domain *domain,
struct device_node *controller,
const u32 *intspec,
unsigned int intsize,
unsigned long *out_hwirq,
unsigned int *out_type)
{
if (domain->of_node != controller)
return -EINVAL; /* Shouldn't happen, really... */
if (intsize != 3)
return -EINVAL; /* Not GIC compliant */
if (intspec[0] != GIC_SPI)
return -EINVAL; /* No PPI should point to this domain */
*out_hwirq = intspec[1];
*out_type = intspec[2];
return 0;
}
static int tegra_ictlr_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs, void *data)
{
struct of_phandle_args *args = data;
struct of_phandle_args parent_args;
struct tegra_ictlr_info *info = domain->host_data;
irq_hw_number_t hwirq;
unsigned int i;
if (args->args_count != 3)
return -EINVAL; /* Not GIC compliant */
if (args->args[0] != GIC_SPI)
return -EINVAL; /* No PPI should point to this domain */
hwirq = args->args[1];
if (hwirq >= (num_ictlrs * 32))
return -EINVAL;
for (i = 0; i < nr_irqs; i++) {
int ictlr = (hwirq + i) / 32;
irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
&tegra_ictlr_chip,
&info->base[ictlr]);
}
parent_args = *args;
parent_args.np = domain->parent->of_node;
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args);
}
static void tegra_ictlr_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs)
{
unsigned int i;
for (i = 0; i < nr_irqs; i++) {
struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
irq_domain_reset_irq_data(d);
}
}
static const struct irq_domain_ops tegra_ictlr_domain_ops = {
.xlate = tegra_ictlr_domain_xlate,
.alloc = tegra_ictlr_domain_alloc,
.free = tegra_ictlr_domain_free,
};
static int __init tegra_ictlr_init(struct device_node *node,
struct device_node *parent)
{
struct irq_domain *parent_domain, *domain;
const struct of_device_id *match;
const struct tegra_ictlr_soc *soc;
unsigned int i;
int err;
if (!parent) {
pr_err("%s: no parent, giving up\n", node->full_name);
return -ENODEV;
}
parent_domain = irq_find_host(parent);
if (!parent_domain) {
pr_err("%s: unable to obtain parent domain\n", node->full_name);
return -ENXIO;
}
match = of_match_node(ictlr_matches, node);
if (!match) /* Should never happen... */
return -ENODEV;
soc = match->data;
lic = kzalloc(sizeof(*lic), GFP_KERNEL);
if (!lic)
return -ENOMEM;
for (i = 0; i < TEGRA_MAX_NUM_ICTLRS; i++) {
void __iomem *base;
base = of_iomap(node, i);
if (!base)
break;
lic->base[i] = base;
/* Disable all interrupts */
writel_relaxed(~0UL, base + ICTLR_CPU_IER_CLR);
/* All interrupts target IRQ */
writel_relaxed(0, base + ICTLR_CPU_IEP_CLASS);
num_ictlrs++;
}
if (!num_ictlrs) {
pr_err("%s: no valid regions, giving up\n", node->full_name);
err = -ENOMEM;
goto out_free;
}
WARN(num_ictlrs != soc->num_ictlrs,
"%s: Found %u interrupt controllers in DT; expected %u.\n",
node->full_name, num_ictlrs, soc->num_ictlrs);
domain = irq_domain_add_hierarchy(parent_domain, 0, num_ictlrs * 32,
node, &tegra_ictlr_domain_ops,
lic);
if (!domain) {
pr_err("%s: failed to allocated domain\n", node->full_name);
err = -ENOMEM;
goto out_unmap;
}
tegra_ictlr_syscore_init();
pr_info("%s: %d interrupts forwarded to %s\n",
node->full_name, num_ictlrs * 32, parent->full_name);
return 0;
out_unmap:
for (i = 0; i < num_ictlrs; i++)
iounmap(lic->base[i]);
out_free:
kfree(lic);
return err;
}
IRQCHIP_DECLARE(tegra20_ictlr, "nvidia,tegra20-ictlr", tegra_ictlr_init);
IRQCHIP_DECLARE(tegra30_ictlr, "nvidia,tegra30-ictlr", tegra_ictlr_init);
IRQCHIP_DECLARE(tegra210_ictlr, "nvidia,tegra210-ictlr", tegra_ictlr_init);
...@@ -466,6 +466,7 @@ extern void irq_chip_eoi_parent(struct irq_data *data); ...@@ -466,6 +466,7 @@ extern void irq_chip_eoi_parent(struct irq_data *data);
extern int irq_chip_set_affinity_parent(struct irq_data *data, extern int irq_chip_set_affinity_parent(struct irq_data *data,
const struct cpumask *dest, const struct cpumask *dest,
bool force); bool force);
extern int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on);
#endif #endif
/* Handling of unhandled and spurious interrupts: */ /* Handling of unhandled and spurious interrupts: */
......
...@@ -97,6 +97,7 @@ struct device_node; ...@@ -97,6 +97,7 @@ struct device_node;
extern struct irq_chip gic_arch_extn; extern struct irq_chip gic_arch_extn;
void gic_set_irqchip_flags(unsigned long flags);
void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
u32 offset, struct device_node *); u32 offset, struct device_node *);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
...@@ -115,11 +116,5 @@ int gic_get_cpu_id(unsigned int cpu); ...@@ -115,11 +116,5 @@ int gic_get_cpu_id(unsigned int cpu);
void gic_migrate_target(unsigned int new_cpu_id); void gic_migrate_target(unsigned int new_cpu_id);
unsigned long gic_get_sgir_physaddr(void); unsigned long gic_get_sgir_physaddr(void);
extern const struct irq_domain_ops *gic_routable_irq_domain_ops;
static inline void __init register_routable_domain_ops
(const struct irq_domain_ops *ops)
{
gic_routable_irq_domain_ops = ops;
}
#endif /* __ASSEMBLY */ #endif /* __ASSEMBLY */
#endif #endif
/*
* drivers/irqchip/irq-crossbar.h
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
int irqcrossbar_init(void);
...@@ -948,6 +948,22 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data) ...@@ -948,6 +948,22 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data)
return -ENOSYS; return -ENOSYS;
} }
/**
* irq_chip_set_wake_parent - Set/reset wake-up on the parent interrupt
* @data: Pointer to interrupt specific data
* @on: Whether to set or reset the wake-up capability of this irq
*
* Conditional, as the underlying parent chip might not implement it.
*/
int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on)
{
data = data->parent_data;
if (data->chip->irq_set_wake)
return data->chip->irq_set_wake(data, on);
return -ENOSYS;
}
#endif #endif
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment