diff options
79 files changed, 2032 insertions, 669 deletions
| diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt new file mode 100644 index 000000000000..44aa3c451ccf --- /dev/null +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt @@ -0,0 +1,14 @@ +Freescale Vybrid Miscellaneous System Control - CPU Configuration + +The MSCM IP contains multiple sub modules, this binding describes the first +block of registers which contains CPU configuration information. + +Required properties: +- compatible:	"fsl,vf610-mscm-cpucfg", "syscon" +- reg:		the register range of the MSCM CPU configuration registers + +Example: +	mscm_cpucfg: cpucfg@40001000 { +		compatible = "fsl,vf610-mscm-cpucfg", "syscon"; +		reg = <0x40001000 0x800>; +	} diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt new file mode 100644 index 000000000000..669808b2af49 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt @@ -0,0 +1,33 @@ +Freescale Vybrid Miscellaneous System Control - Interrupt Router + +The MSCM IP contains multiple sub modules, this binding describes the second +block of registers which control the interrupt router. The interrupt router +allows to configure the recipient of each peripheral interrupt. Furthermore +it controls the directed processor interrupts. The module is available in all +Vybrid SoC's but is only really useful in dual core configurations (VF6xx +which comes with a Cortex-A5/Cortex-M4 combination). + +Required properties: +- compatible:		"fsl,vf610-mscm-ir" +- reg:			the register range of the MSCM Interrupt Router +- fsl,cpucfg:		The handle to the MSCM CPU configuration node, required +			to get the current CPU ID +- interrupt-controller:	Identifies the node as an interrupt controller +- #interrupt-cells:	Two cells, interrupt number and cells. +			The hardware interrupt number according to interrupt +			assignment of the interrupt router is required. +			Flags get passed only when using GIC as parent. Flags +			encoding as documented by the GIC bindings. +- interrupt-parent:	Should be the phandle for the interrupt controller of +			the CPU the device tree is intended to be used on. This +			is either the node of the GIC or NVIC controller. + +Example: +	mscm_ir: interrupt-controller@40001800 { +		compatible = "fsl,vf610-mscm-ir"; +		reg = <0x40001800 0x400>; +		fsl,cpucfg = <&mscm_cpucfg>; +		interrupt-controller; +		#interrupt-cells = <2>; +		interrupt-parent = <&intc>; +	} diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index c97484b73e72..1e0d21201d3a 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -56,11 +56,6 @@ Optional    regions, used when the GIC doesn't have banked registers. The offset is    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:  	intc: interrupt-controller@fff11000 { @@ -68,7 +63,6 @@ Example:  		#interrupt-cells = <3>;  		#address-cells = <1>;  		interrupt-controller; -		arm,routable-irqs = <160>;  		reg = <0xfff11000 0x1000>,  		      <0xfff10100 0x100>;  	}; diff --git a/Documentation/devicetree/bindings/arm/omap/crossbar.txt b/Documentation/devicetree/bindings/arm/omap/crossbar.txt index 4139db353d0a..a9b28d74d902 100644 --- a/Documentation/devicetree/bindings/arm/omap/crossbar.txt +++ b/Documentation/devicetree/bindings/arm/omap/crossbar.txt @@ -9,7 +9,9 @@ inputs.  Required properties:  - compatible : Should be "ti,irq-crossbar"  - 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,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. @@ -27,13 +29,13 @@ Optional properties:    when the interrupt controller irq is unused (when not provided, default is 0)  Examples: -		crossbar_mpu: @4a020000 { +		crossbar_mpu: crossbar@4a002a48 {  			compatible = "ti,irq-crossbar";  			reg = <0x4a002a48 0x130>;  			ti,max-irqs = <160>;  			ti,max-crossbar-sources = <400>;  			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>;  		}; @@ -44,10 +46,6 @@ Documentation/devicetree/bindings/arm/gic.txt for further details.  An interrupt consumer on an SoC using crossbar will use:  	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:  	device_x@0x4a023000 { @@ -55,9 +53,3 @@ Example:  		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>; -		... -	}; diff --git a/Documentation/devicetree/bindings/arm/samsung/pmu.txt b/Documentation/devicetree/bindings/arm/samsung/pmu.txt index 67b211381f2b..2d6356d8daf4 100644 --- a/Documentation/devicetree/bindings/arm/samsung/pmu.txt +++ b/Documentation/devicetree/bindings/arm/samsung/pmu.txt @@ -29,10 +29,27 @@ Properties:   - clocks : list of phandles and specifiers to all input clocks listed in  		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 :  pmu_system_controller: system-controller@10040000 {  	compatible = "samsung,exynos5250-pmu", "syscon";  	reg = <0x10040000 0x5000>; +	interrupt-controller; +	#interrupt-cells = <3>; +	interrupt-parent = <&gic>;  	#clock-cells = <1>;  	clock-names = "clkout0", "clkout1", "clkout2", "clkout3",  			"clkout4", "clkout8", "clkout9"; diff --git a/Documentation/devicetree/bindings/interrupt-controller/nvidia,tegra-ictlr.txt b/Documentation/devicetree/bindings/interrupt-controller/nvidia,tegra-ictlr.txt new file mode 100644 index 000000000000..1099fe0788fa --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/nvidia,tegra-ictlr.txt @@ -0,0 +1,43 @@ +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>; +	}; diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt index 1a88e62228e5..63633bdea7e4 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt @@ -4,7 +4,7 @@ Required properties:  - compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback.    Examples with soctypes are: -    - "renesas,irqc-r8a73a4" (R-Mobile AP6) +    - "renesas,irqc-r8a73a4" (R-Mobile APE6)      - "renesas,irqc-r8a7790" (R-Car H2)      - "renesas,irqc-r8a7791" (R-Car M2-W)      - "renesas,irqc-r8a7792" (R-Car V2H) @@ -12,6 +12,7 @@ Required properties:      - "renesas,irqc-r8a7794" (R-Car E2)  - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in    interrupts.txt in this directory +- clocks: Must contain a reference to the functional clock.  Optional properties: @@ -29,4 +30,5 @@ Example:  			     <0 1 IRQ_TYPE_LEVEL_HIGH>,  			     <0 2 IRQ_TYPE_LEVEL_HIGH>,  			     <0 3 IRQ_TYPE_LEVEL_HIGH>; +		clocks = <&mstp4_clks R8A7790_CLK_IRQC>;  	}; diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,sti-irq-syscfg.txt b/Documentation/devicetree/bindings/interrupt-controller/st,sti-irq-syscfg.txt new file mode 100644 index 000000000000..ced6014061a3 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/st,sti-irq-syscfg.txt @@ -0,0 +1,35 @@ +STMicroelectronics STi System Configuration Controlled IRQs +----------------------------------------------------------- + +On STi based systems; External, CTI (Core Sight), PMU (Performance Management), +and PL310 L2 Cache IRQs are controlled using System Configuration registers. +This driver is used to unmask them prior to use. + +Required properties: +- compatible	: Should be set to one of: +			"st,stih415-irq-syscfg" +			"st,stih416-irq-syscfg" +			"st,stih407-irq-syscfg" +			"st,stid127-irq-syscfg" +- st,syscfg	: Phandle to Cortex-A9 IRQ system config registers +- st,irq-device	: Array of IRQs to enable - should be 2 in length +- st,fiq-device	: Array of FIQs to enable - should be 2 in length + +Optional properties: +- st,invert-ext	: External IRQs can be inverted at will.  This property inverts +		  these IRQs using bitwise logic.  A number of defines have been +		  provided for convenience: +			ST_IRQ_SYSCFG_EXT_1_INV +			ST_IRQ_SYSCFG_EXT_2_INV +			ST_IRQ_SYSCFG_EXT_3_INV +Example: + +irq-syscfg { +	compatible    = "st,stih416-irq-syscfg"; +	st,syscfg     = <&syscfg_cpu>; +	st,irq-device = <ST_IRQ_SYSCFG_PMU_0>, +			<ST_IRQ_SYSCFG_PMU_1>; +	st,fiq-device = <ST_IRQ_SYSCFG_DISABLED>, +			<ST_IRQ_SYSCFG_DISABLED>; +	st,invert-ext = <(ST_IRQ_SYSCFG_EXT_1_INV | ST_IRQ_SYSCFG_EXT_3_INV)>; +}; diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,omap4-wugen-mpu b/Documentation/devicetree/bindings/interrupt-controller/ti,omap4-wugen-mpu new file mode 100644 index 000000000000..43effa0a4fe7 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/ti,omap4-wugen-mpu @@ -0,0 +1,33 @@ +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>; +       }; diff --git a/Documentation/scsi/ncr53c8xx.txt b/Documentation/scsi/ncr53c8xx.txt index 1d508dcbf859..8586efff1e99 100644 --- a/Documentation/scsi/ncr53c8xx.txt +++ b/Documentation/scsi/ncr53c8xx.txt @@ -786,7 +786,6 @@ port address 0x1400.          irqm:1     same as initial settings (assumed BIOS settings)          irqm:2     always totem pole          irqm:0x10  driver will not use IRQF_SHARED flag when requesting irq -        irqm:0x20  driver will not use IRQF_DISABLED flag when requesting irq      (Bits 0x10 and 0x20 can be combined with hardware irq mode option) @@ -1231,30 +1230,6 @@ they only refer to system buffers that are well aligned. So, a work around  may only be needed under Linux when a scatter/gather list is not used and   when the SCSI DATA IN phase is reentered after a phase mismatch. -14.5 IRQ sharing problems - -When an IRQ is shared by devices that are handled by different drivers, it  -may happen that one driver complains about the request of the IRQ having  -failed. Inder Linux-2.0, this may be due to one driver having requested the  -IRQ using the IRQF_DISABLED flag but some other having requested the same IRQ -without this flag. Under both Linux-2.0 and linux-2.2, this may be caused by  -one driver not having requested the IRQ with the IRQF_SHARED flag. - -By default, the ncr53c8xx and sym53c8xx drivers request IRQs with both the  -IRQF_DISABLED and the IRQF_SHARED flag under Linux-2.0 and with only the IRQF_SHARED -flag under Linux-2.2. - -Under Linux-2.0, you can disable use of IRQF_DISABLED flag from the boot -command line by using the following option: - -     ncr53c8xx=irqm:0x20   (for the generic ncr53c8xx driver) -     sym53c8xx=irqm:0x20   (for the sym53c8xx driver) - -If this does not fix the problem, then you may want to check how all other  -drivers are requesting the IRQ and report the problem. Note that if at least  -a single driver does not request the IRQ with the IRQF_SHARED flag (share IRQ), -then the request of the IRQ obviously will not succeed for all the drivers. -  15. SCSI problem troubleshooting  15.1 Problem tracking diff --git a/Documentation/scsi/tmscsim.txt b/Documentation/scsi/tmscsim.txt index 0810132772a8..0e0322bf0020 100644 --- a/Documentation/scsi/tmscsim.txt +++ b/Documentation/scsi/tmscsim.txt @@ -107,10 +107,6 @@ produced errors and started to corrupt my disks. So don't do that! A 37.50  MHz PCI bus works for me, though, but I don't recommend using higher clocks  than the 33.33 MHz being in the PCI spec. -If you want to share the IRQ with another device and the driver refuses to -do so, you might succeed with changing the DC390_IRQ type in tmscsim.c to  -IRQF_SHARED | IRQF_DISABLED. -  3.Features  ---------- diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 1943fc333e7c..8a099bc10c1e 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -15,7 +15,7 @@  / {  	compatible = "ti,am4372", "ti,am43"; -	interrupt-parent = <&gic>; +	interrupt-parent = <&wakeupgen>;  	aliases { @@ -48,6 +48,15 @@  		#interrupt-cells = <3>;  		reg = <0x48241000 0x1000>,  		      <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 { diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index f84d9715a4a9..26956cb50835 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -352,7 +352,6 @@  		reg = <0x24>;  		compatible = "ti,tps65218";  		interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* NMIn */ -		interrupt-parent = <&gic>;  		interrupt-controller;  		#interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 832d24318f62..8ae29c955c11 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -392,7 +392,6 @@  	tps@24 {  		compatible = "ti,tps65218";  		reg = <0x24>; -		interrupt-parent = <&gic>;  		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;  		interrupt-controller;  		#interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts index 257c099c347e..1d7109196872 100644 --- a/arch/arm/boot/dts/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/am43x-epos-evm.dts @@ -369,7 +369,6 @@  		reg = <0x24>;  		compatible = "ti,tps65218";  		interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* NMIn */ -		interrupt-parent = <&gic>;  		interrupt-controller;  		#interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts index 6463f9ef2b54..bd48dba16748 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15.dts +++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts @@ -454,7 +454,6 @@  	mcp_rtc: rtc@6f {  		compatible = "microchip,mcp7941x";  		reg = <0x6f>; -		interrupt-parent = <&gic>;  		interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>;  /* IRQ_SYS_1N */  		pinctrl-names = "default"; @@ -477,7 +476,7 @@  &uart3 {  	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>;  	pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts index 7563d7ce01bb..b1bd06c6c2a8 100644 --- a/arch/arm/boot/dts/dra7-evm.dts +++ b/arch/arm/boot/dts/dra7-evm.dts @@ -444,7 +444,7 @@  	status = "okay";  	pinctrl-names = "default";  	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>;  }; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index c4659a979c41..a0afce7ad482 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -13,14 +13,13 @@  #include "skeleton.dtsi"  #define MAX_SOURCES 400 -#define DIRECT_IRQ(irq) (MAX_SOURCES + irq)  / {  	#address-cells = <1>;  	#size-cells = <1>;  	compatible = "ti,dra7xx"; -	interrupt-parent = <&gic>; +	interrupt-parent = <&crossbar_mpu>;  	aliases {  		i2c0 = &i2c1; @@ -50,18 +49,27 @@  			     <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 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>; +		interrupt-parent = <&gic>;  	};  	gic: interrupt-controller@48211000 {  		compatible = "arm,cortex-a15-gic";  		interrupt-controller;  		#interrupt-cells = <3>; -		arm,routable-irqs = <192>;  		reg = <0x48211000 0x1000>,  		      <0x48212000 0x1000>,  		      <0x48214000 0x2000>,  		      <0x48216000 0x2000>;  		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 @@  		ti,hwmods = "l3_main_1", "l3_main_2";  		reg = <0x44000000 0x1000000>,  		      <0x45000000 0x1000>; -		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, -			     <GIC_SPI DIRECT_IRQ(10) IRQ_TYPE_LEVEL_HIGH>; +		interrupts-extended = <&crossbar_mpu GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, +				      <&wakeupgen GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;  		prm: prm@4ae06000 {  			compatible = "ti,dra7-prm"; @@ -344,7 +352,7 @@  		uart1: serial@4806a000 {  			compatible = "ti,omap4-uart";  			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";  			clock-frequency = <48000000>;  			status = "disabled"; @@ -355,7 +363,7 @@  		uart2: serial@4806c000 {  			compatible = "ti,omap4-uart";  			reg = <0x4806c000 0x100>; -			interrupts-extended = <&gic GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart2";  			clock-frequency = <48000000>;  			status = "disabled"; @@ -366,7 +374,7 @@  		uart3: serial@48020000 {  			compatible = "ti,omap4-uart";  			reg = <0x48020000 0x100>; -			interrupts-extended = <&gic GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart3";  			clock-frequency = <48000000>;  			status = "disabled"; @@ -377,7 +385,7 @@  		uart4: serial@4806e000 {  			compatible = "ti,omap4-uart";  			reg = <0x4806e000 0x100>; -			interrupts-extended = <&gic GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart4";  			clock-frequency = <48000000>;                          status = "disabled"; @@ -388,7 +396,7 @@  		uart5: serial@48066000 {  			compatible = "ti,omap4-uart";  			reg = <0x48066000 0x100>; -			interrupts-extended = <&gic GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart5";  			clock-frequency = <48000000>;  			status = "disabled"; @@ -399,7 +407,7 @@  		uart6: serial@48068000 {  			compatible = "ti,omap4-uart";  			reg = <0x48068000 0x100>; -			interrupts-extended = <&gic GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart6";  			clock-frequency = <48000000>;  			status = "disabled"; @@ -410,7 +418,7 @@  		uart7: serial@48420000 {  			compatible = "ti,omap4-uart";  			reg = <0x48420000 0x100>; -			interrupts-extended = <&gic GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart7";  			clock-frequency = <48000000>;  			status = "disabled"; @@ -419,7 +427,7 @@  		uart8: serial@48422000 {  			compatible = "ti,omap4-uart";  			reg = <0x48422000 0x100>; -			interrupts-extended = <&gic GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart8";  			clock-frequency = <48000000>;  			status = "disabled"; @@ -428,7 +436,7 @@  		uart9: serial@48424000 {  			compatible = "ti,omap4-uart";  			reg = <0x48424000 0x100>; -			interrupts-extended = <&gic GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart9";  			clock-frequency = <48000000>;  			status = "disabled"; @@ -437,7 +445,7 @@  		uart10: serial@4ae2b000 {  			compatible = "ti,omap4-uart";  			reg = <0x4ae2b000 0x100>; -			interrupts-extended = <&gic GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart10";  			clock-frequency = <48000000>;  			status = "disabled"; @@ -1335,9 +1343,12 @@  			status = "disabled";  		}; -		crossbar_mpu: crossbar@4a020000 { +		crossbar_mpu: crossbar@4a002a48 {  			compatible = "ti,irq-crossbar";  			reg = <0x4a002a48 0x130>; +			interrupt-controller; +			interrupt-parent = <&wakeupgen>; +			#interrupt-cells = <3>;  			ti,max-irqs = <160>;  			ti,max-crossbar-sources = <MAX_SOURCES>;  			ti,reg-size = <2>; diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts index 40ed539ce474..daf28110d487 100644 --- a/arch/arm/boot/dts/dra72-evm.dts +++ b/arch/arm/boot/dts/dra72-evm.dts @@ -158,7 +158,6 @@  		pinctrl-0 = <&tps65917_pins_default>;  		interrupts = <GIC_SPI 2 IRQ_TYPE_NONE>;  /* IRQ_SYS_1N */ -		interrupt-parent = <&gic>;  		interrupt-controller;  		#interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/dra72x.dtsi b/arch/arm/boot/dts/dra72x.dtsi index e5a3d23a3df1..f7fb0d0ef25a 100644 --- a/arch/arm/boot/dts/dra72x.dtsi +++ b/arch/arm/boot/dts/dra72x.dtsi @@ -25,6 +25,7 @@  	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>;  	};  }; diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi index 10173fab1a15..00eeed789b4b 100644 --- a/arch/arm/boot/dts/dra74x.dtsi +++ b/arch/arm/boot/dts/dra74x.dtsi @@ -41,8 +41,9 @@  	pmu {  		compatible = "arm,cortex-a15-pmu"; -		interrupts = <GIC_SPI DIRECT_IRQ(131) IRQ_TYPE_LEVEL_HIGH>, -			     <GIC_SPI DIRECT_IRQ(132) IRQ_TYPE_LEVEL_HIGH>; +		interrupt-parent = <&wakeupgen>; +		interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, +			     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;  	};  	ocp { diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi index ac6b0ae42caf..14ab515aa83c 100644 --- a/arch/arm/boot/dts/exynos3250.dtsi +++ b/arch/arm/boot/dts/exynos3250.dtsi @@ -131,6 +131,9 @@  		pmu_system_controller: system-controller@10020000 {  			compatible = "samsung,exynos3250-pmu", "syscon";  			reg = <0x10020000 0x4000>; +			interrupt-controller; +			#interrupt-cells = <3>; +			interrupt-parent = <&gic>;  		};  		mipi_phy: video-phy@10020710 { @@ -185,6 +188,7 @@  			compatible = "samsung,exynos3250-rtc";  			reg = <0x10070000 0x100>;  			interrupts = <0 73 0>, <0 74 0>; +			interrupt-parent = <&pmu_system_controller>;  			status = "disabled";  		}; diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 77ea547768f4..e20cdc24c3bb 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -154,6 +154,9 @@  	pmu_system_controller: system-controller@10020000 {  		compatible = "samsung,exynos4210-pmu", "syscon";  		reg = <0x10020000 0x4000>; +		interrupt-controller; +		#interrupt-cells = <3>; +		interrupt-parent = <&gic>;  	};  	dsi_0: dsi@11C80000 { @@ -266,6 +269,7 @@  	rtc@10070000 {  		compatible = "samsung,s3c6410-rtc";  		reg = <0x10070000 0x100>; +		interrupt-parent = <&pmu_system_controller>;  		interrupts = <0 44 0>, <0 45 0>;  		clocks = <&clock CLK_RTC>;  		clock-names = "rtc"; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index adbde1adad95..77f656eb8e6b 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -205,6 +205,9 @@  		clock-names = "clkout16";  		clocks = <&clock CLK_FIN_PLL>;  		#clock-cells = <1>; +		interrupt-controller; +		#interrupt-cells = <3>; +		interrupt-parent = <&gic>;  	};  	sysreg_system_controller: syscon@10050000 { @@ -241,6 +244,7 @@  	rtc: rtc@101E0000 {  		clocks = <&clock CLK_RTC>;  		clock-names = "rtc"; +		interrupt-parent = <&pmu_system_controller>;  		status = "disabled";  	}; diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index c0e98cf3514f..b3d2d53820e3 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -327,6 +327,7 @@  	rtc: rtc@101E0000 {  		clocks = <&clock CLK_RTC>;  		clock-names = "rtc"; +		interrupt-parent = <&pmu_system_controller>;  		status = "disabled";  	}; @@ -770,6 +771,9 @@  		clock-names = "clkout16";  		clocks = <&clock CLK_FIN_PLL>;  		#clock-cells = <1>; +		interrupt-controller; +		#interrupt-cells = <3>; +		interrupt-parent = <&gic>;  	};  	sysreg_system_controller: syscon@10050000 { diff --git a/arch/arm/boot/dts/omap4-duovero.dtsi b/arch/arm/boot/dts/omap4-duovero.dtsi index e860ccd9d09c..f2a94fa62552 100644 --- a/arch/arm/boot/dts/omap4-duovero.dtsi +++ b/arch/arm/boot/dts/omap4-duovero.dtsi @@ -173,14 +173,12 @@  	twl: twl@48 {  		reg = <0x48>;  		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;		/* IRQ_SYS_1N cascaded to gic */ -		interrupt-parent = <&gic>;  	};  	twl6040: twl@4b {  		compatible = "ti,twl6040";  		reg = <0x4b>;  		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 */  		vio-supply = <&v1v8>; diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi index 150513506c19..7c15fb2e2fe4 100644 --- a/arch/arm/boot/dts/omap4-panda-common.dtsi +++ b/arch/arm/boot/dts/omap4-panda-common.dtsi @@ -372,7 +372,6 @@  		reg = <0x48>;  		/* IRQ# = 7 */  		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */ -		interrupt-parent = <&gic>;  	};  	twl6040: twl@4b { @@ -384,7 +383,6 @@  		/* IRQ# = 119 */  		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 */  		vio-supply = <&v1v8>; @@ -479,17 +477,17 @@  };  &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>;  };  &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>;  };  &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>;  }; diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index 3e1da43068f6..8aca8dae968a 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -363,7 +363,6 @@  		reg = <0x48>;  		/* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */  		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */ -		interrupt-parent = <&gic>;  	};  	twl6040: twl@4b { @@ -375,7 +374,6 @@  		/* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */  		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 */  		vio-supply = <&v1v8>; @@ -570,21 +568,21 @@  };  &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>;  	pinctrl-names = "default";  	pinctrl-0 = <&uart2_pins>;  };  &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>;  	pinctrl-names = "default";  	pinctrl-0 = <&uart3_pins>;  };  &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>;  	pinctrl-names = "default";  	pinctrl-0 = <&uart4_pins>; diff --git a/arch/arm/boot/dts/omap4-var-som-om44.dtsi b/arch/arm/boot/dts/omap4-var-som-om44.dtsi index 062701e1a898..a4f1ba2e1903 100644 --- a/arch/arm/boot/dts/omap4-var-som-om44.dtsi +++ b/arch/arm/boot/dts/omap4-var-som-om44.dtsi @@ -185,7 +185,6 @@  		reg = <0x48>;  		/* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */  		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */ -		interrupt-parent = <&gic>;  	};  	twl6040: twl@4b { @@ -197,7 +196,6 @@  		/* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */  		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 */  		vio-supply = <&v1v8>; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 87401d9f4d8b..f2091d1c9c36 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -14,7 +14,7 @@  / {  	compatible = "ti,omap4430", "ti,omap4"; -	interrupt-parent = <&gic>; +	interrupt-parent = <&wakeupgen>;  	aliases {  		i2c0 = &i2c1; @@ -56,6 +56,7 @@  		#interrupt-cells = <3>;  		reg = <0x48241000 0x1000>,  		      <0x48240100 0x0100>; +		interrupt-parent = <&gic>;  	};  	L2: l2-cache-controller@48242000 { @@ -70,6 +71,15 @@  		clocks = <&mpu_periphclk>;  		reg = <0x48240600 0x20>;  		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 @@  		uart2: serial@4806c000 {  			compatible = "ti,omap4-uart";  			reg = <0x4806c000 0x100>; -			interrupts-extended = <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart2";  			clock-frequency = <48000000>;  		}; @@ -327,7 +337,7 @@  		uart3: serial@48020000 {  			compatible = "ti,omap4-uart";  			reg = <0x48020000 0x100>; -			interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart3";  			clock-frequency = <48000000>;  		}; @@ -335,7 +345,7 @@  		uart4: serial@4806e000 {  			compatible = "ti,omap4-uart";  			reg = <0x4806e000 0x100>; -			interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart4";  			clock-frequency = <48000000>;  		}; diff --git a/arch/arm/boot/dts/omap5-cm-t54.dts b/arch/arm/boot/dts/omap5-cm-t54.dts index b54b271e153b..61ad2ea34720 100644 --- a/arch/arm/boot/dts/omap5-cm-t54.dts +++ b/arch/arm/boot/dts/omap5-cm-t54.dts @@ -412,7 +412,6 @@  	palmas: palmas@48 {  		compatible = "ti,palmas";  		interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */ -		interrupt-parent = <&gic>;  		reg = <0x48>;  		interrupt-controller;  		#interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts index 159720d6c956..74777a6e200a 100644 --- a/arch/arm/boot/dts/omap5-uevm.dts +++ b/arch/arm/boot/dts/omap5-uevm.dts @@ -311,7 +311,6 @@  	palmas: palmas@48 {  		compatible = "ti,palmas";  		interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */ -		interrupt-parent = <&gic>;  		reg = <0x48>;  		interrupt-controller;  		#interrupt-cells = <2>; @@ -521,7 +520,6 @@  		pinctrl-0 = <&twl6040_pins>;  		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 */  		vio-supply = <&smps7_reg>; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 4a485b63a141..77b5f70d0ebc 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -18,7 +18,7 @@  	#size-cells = <1>;  	compatible = "ti,omap5"; -	interrupt-parent = <&gic>; +	interrupt-parent = <&wakeupgen>;  	aliases {  		i2c0 = &i2c1; @@ -79,6 +79,7 @@  			     <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 10 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_LOW)>; +		interrupt-parent = <&gic>;  	};  	pmu { @@ -95,6 +96,15 @@  		      <0x48212000 0x1000>,  		      <0x48214000 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 @@  		uart1: serial@4806a000 {  			compatible = "ti,omap4-uart";  			reg = <0x4806a000 0x100>; -			interrupts-extended = <&gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart1";  			clock-frequency = <48000000>;  		}; @@ -466,7 +476,7 @@  		uart2: serial@4806c000 {  			compatible = "ti,omap4-uart";  			reg = <0x4806c000 0x100>; -			interrupts-extended = <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart2";  			clock-frequency = <48000000>;  		}; @@ -474,7 +484,7 @@  		uart3: serial@48020000 {  			compatible = "ti,omap4-uart";  			reg = <0x48020000 0x100>; -			interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart3";  			clock-frequency = <48000000>;  		}; @@ -482,7 +492,7 @@  		uart4: serial@4806e000 {  			compatible = "ti,omap4-uart";  			reg = <0x4806e000 0x100>; -			interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart4";  			clock-frequency = <48000000>;  		}; @@ -490,7 +500,7 @@  		uart5: serial@48066000 {  			compatible = "ti,omap4-uart";  			reg = <0x48066000 0x100>; -			interrupts-extended = <&gic GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart5";  			clock-frequency = <48000000>;  		}; @@ -498,7 +508,7 @@  		uart6: serial@48068000 {  			compatible = "ti,omap4-uart";  			reg = <0x48068000 0x100>; -			interrupts-extended = <&gic GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>; +			interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;  			ti,hwmods = "uart6";  			clock-frequency = <48000000>;  		}; @@ -883,14 +893,12 @@  			usbhsohci: ohci@4a064800 {  				compatible = "ti,ohci-omap3";  				reg = <0x4a064800 0x400>; -				interrupt-parent = <&gic>;  				interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;  			};  			usbhsehci: ehci@4a064c00 {  				compatible = "ti,ehci-omap";  				reg = <0x4a064c00 0x400>; -				interrupt-parent = <&gic>;  				interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;  			};  		}; diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 4296b5398bf5..f58a3d9d5f13 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -8,7 +8,7 @@  / {  	compatible = "nvidia,tegra114"; -	interrupt-parent = <&gic>; +	interrupt-parent = <&lic>;  	host1x@50000000 {  		compatible = "nvidia,tegra114-host1x", "simple-bus"; @@ -134,6 +134,19 @@  		      <0x50046000 0x2000>;  		interrupts = <GIC_PPI 9  			(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 { @@ -766,5 +779,6 @@  				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,  			<GIC_PPI 10  				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; +		interrupt-parent = <&gic>;  	};  }; diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi index 4be06c6ea0c8..db85695aa7aa 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -10,7 +10,7 @@  / {  	compatible = "nvidia,tegra124"; -	interrupt-parent = <&gic>; +	interrupt-parent = <&lic>;  	#address-cells = <2>;  	#size-cells = <2>; @@ -173,6 +173,7 @@  		      <0x0 0x50046000 0x0 0x2000>;  		interrupts = <GIC_PPI 9  			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; +		interrupt-parent = <&gic>;  	};  	gpu@0,57000000 { @@ -190,6 +191,18 @@  		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 {  		compatible = "nvidia,tegra124-timer", "nvidia,tegra20-timer";  		reg = <0x0 0x60005000 0x0 0x400>; @@ -955,5 +968,6 @@  				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,  			     <GIC_PPI 10  				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; +		interrupt-parent = <&gic>;  	};  }; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index e5527f742696..adf6b048d0bb 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -7,7 +7,7 @@  / {  	compatible = "nvidia,tegra20"; -	interrupt-parent = <&intc>; +	interrupt-parent = <&lic>;  	host1x@50000000 {  		compatible = "nvidia,tegra20-host1x", "simple-bus"; @@ -142,6 +142,7 @@  	timer@50040600 {  		compatible = "arm,cortex-a9-twd-timer"; +		interrupt-parent = <&intc>;  		reg = <0x50040600 0x20>;  		interrupts = <GIC_PPI 13  			(GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; @@ -154,6 +155,7 @@  		       0x50040100 0x0100>;  		interrupt-controller;  		#interrupt-cells = <3>; +		interrupt-parent = <&intc>;  	};  	cache-controller@50043000 { @@ -165,6 +167,17 @@  		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 {  		compatible = "nvidia,tegra20-timer";  		reg = <0x60005000 0x60>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index db4810df142c..60e205a0f63d 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -8,7 +8,7 @@  / {  	compatible = "nvidia,tegra30"; -	interrupt-parent = <&intc>; +	interrupt-parent = <&lic>;  	pcie-controller@00003000 {  		compatible = "nvidia,tegra30-pcie"; @@ -228,6 +228,7 @@  	timer@50040600 {  		compatible = "arm,cortex-a9-twd-timer";  		reg = <0x50040600 0x20>; +		interrupt-parent = <&intc>;  		interrupts = <GIC_PPI 13  			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;  		clocks = <&tegra_car TEGRA30_CLK_TWD>; @@ -239,6 +240,7 @@  		       0x50040100 0x0100>;  		interrupt-controller;  		#interrupt-cells = <3>; +		interrupt-parent = <&intc>;  	};  	cache-controller@50043000 { @@ -250,6 +252,18 @@  		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 {  		compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer";  		reg = <0x60005000 0x400>; diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 9e9dfdfad9d7..f44c2e05c82e 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -166,16 +166,14 @@ static void __init exynos_init_io(void)  	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[] = { -	{ .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,exynos5410-pmu" }, -	{ .compatible = "samsung,exynos5420-pmu" },  	{ /*sentinel*/ },  }; @@ -186,9 +184,6 @@ static void exynos_map_pmu(void)  	np = of_find_matching_node(NULL, exynos_dt_pmu_match);  	if (np)  		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) diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index 318d127df147..2146d918aedd 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -18,7 +18,9 @@  #include <linux/syscore_ops.h>  #include <linux/cpu_pm.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/regulator/machine.h> @@ -43,8 +45,8 @@  #define EXYNOS5420_CPU_STATE	0x28  /** - * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping - * @hwirq: Hardware IRQ signal of the GIC + * struct exynos_wkup_irq - PMU IRQ to mask mapping + * @hwirq: Hardware IRQ signal of the PMU   * @mask: Mask in PMU wake-up mask register   */  struct exynos_wkup_irq { @@ -93,14 +95,14 @@ static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {  };  static const struct exynos_wkup_irq exynos4_wkup_irq[] = { -	{ 76, BIT(1) }, /* RTC alarm */ -	{ 77, BIT(2) }, /* RTC tick */ +	{ 44, BIT(1) }, /* RTC alarm */ +	{ 45, BIT(2) }, /* RTC tick */  	{ /* sentinel */ },  };  static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { -	{ 75, BIT(1) }, /* RTC alarm */ -	{ 76, BIT(2) }, /* RTC tick */ +	{ 43, BIT(1) }, /* RTC alarm */ +	{ 44, BIT(2) }, /* RTC tick */  	{ /* sentinel */ },  }; @@ -167,6 +169,113 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)  	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)  {  	/* issue the standby signal into the pm unit. */ @@ -615,17 +724,19 @@ static struct syscore_ops exynos_pm_syscore_ops;  void __init exynos_pm_init(void)  {  	const struct of_device_id *match; +	struct device_node *np;  	u32 tmp; -	of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); -	if (!match) { +	np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); +	if (!np) {  		pr_err("Failed to find PMU node\n");  		return;  	} -	pm_data = (struct exynos_pm_data *) match->data; -	/* Platform-specific GIC callback */ -	gic_arch_extn.irq_set_wake = exynos_irq_set_wake; +	if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) +		pr_warn("Outdated DT detected, suspend/resume will NOT work\n"); + +	pm_data = (struct exynos_pm_data *) match->data;  	/* All wakeup disable */  	tmp = pmu_raw_readl(S5P_WAKEUP_MASK); diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index e8627e04e1e6..c8dffcee9736 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -631,6 +631,7 @@ config SOC_IMX6SX  config SOC_VF610  	bool "Vybrid Family VF610 support" +	select IRQ_DOMAIN_HIERARCHY  	select ARM_GIC  	select PINCTRL_VF610  	select PL310_ERRATA_769419 if CACHE_L2X0 diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index f961c46453b9..3b56722dfd8a 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -20,11 +20,12 @@  #include <linux/init.h>  #include <linux/io.h>  #include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/of_address.h>  #include <linux/platform_device.h>  #include <linux/cpu.h>  #include <linux/notifier.h>  #include <linux/cpu_pm.h> -#include <linux/irqchip/arm-gic.h>  #include "omap-wakeupgen.h"  #include "omap-secure.h" @@ -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)  { -	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.  	 * i.e. 1 bit per SPI IRQ  	 */ -	*reg_index = spi_irq >> 5; -	*bit_posn = spi_irq %= 32; +	*reg_index = irq >> 5; +	*bit_posn = irq %= 32;  	return 0;  } @@ -141,6 +125,7 @@ static void wakeupgen_mask(struct irq_data *d)  	raw_spin_lock_irqsave(&wakeupgen_lock, flags);  	_wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]);  	raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); +	irq_chip_mask_parent(d);  }  /* @@ -153,6 +138,7 @@ static void wakeupgen_unmask(struct irq_data *d)  	raw_spin_lock_irqsave(&wakeupgen_lock, flags);  	_wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]);  	raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); +	irq_chip_unmask_parent(d);  }  #ifdef CONFIG_HOTPLUG_CPU @@ -400,15 +386,91 @@ int omap_secure_apis_support(void)  	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.   */ -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;  	unsigned int boot_cpu = smp_processor_id();  	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 */  	if (omap_rev() == OMAP4430_REV_ES1_0) {  		WARN(1, "WakeupGen: Not supported on OMAP4430 ES1.0\n"); @@ -416,7 +478,7 @@ int __init omap_wakeupgen_init(void)  	}  	/* Static mapping, never released */ -	wakeupgen_base = ioremap(OMAP_WKUPGEN_BASE, SZ_4K); +	wakeupgen_base = of_iomap(node, 0);  	if (WARN_ON(!wakeupgen_base))  		return -ENOMEM; @@ -429,6 +491,14 @@ int __init omap_wakeupgen_init(void)  		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 */  	for (i = 0; i < irq_banks; i++) {  		wakeupgen_writel(0, i, CPU0_ID); @@ -437,14 +507,6 @@ int __init omap_wakeupgen_init(void)  	}  	/* -	 * 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  	 * GIC code has necessary hooks in place.  	 */ @@ -474,3 +536,9 @@ int __init omap_wakeupgen_init(void)  	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); diff --git a/arch/arm/mach-omap2/omap-wakeupgen.h b/arch/arm/mach-omap2/omap-wakeupgen.h index b3c8eccfae79..a3491ad12368 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.h +++ b/arch/arm/mach-omap2/omap-wakeupgen.h @@ -33,7 +33,6 @@  #define OMAP_TIMESTAMPCYCLELO			0xc08  #define OMAP_TIMESTAMPCYCLEHI			0xc0c -extern int __init omap_wakeupgen_init(void);  extern void __iomem *omap_get_wakeupgen_base(void);  extern int omap_secure_apis_support(void);  #endif diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index cee0fe1ee6ff..7bb116a6f86f 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -22,7 +22,6 @@  #include <linux/of_platform.h>  #include <linux/export.h>  #include <linux/irqchip/arm-gic.h> -#include <linux/irqchip/irq-crossbar.h>  #include <linux/of_address.h>  #include <linux/reboot.h>  #include <linux/genalloc.h> @@ -242,26 +241,26 @@ static int __init omap4_sar_ram_init(void)  }  omap_early_initcall(omap4_sar_ram_init); -static const struct of_device_id gic_match[] = { -	{ .compatible = "arm,cortex-a9-gic", }, -	{ .compatible = "arm,cortex-a15-gic", }, +static const struct of_device_id intc_match[] = { +	{ .compatible = "ti,omap4-wugen-mpu", }, +	{ .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)  {  	struct of_phandle_args irq_data;  	unsigned int irq; -	if (!gic_node) -		gic_node = of_find_matching_node(NULL, gic_match); +	if (!intc_node) +		intc_node = of_find_matching_node(NULL, intc_match); -	if (WARN_ON(!gic_node)) +	if (WARN_ON(!intc_node))  		return hwirq; -	irq_data.np = gic_node; +	irq_data.np = intc_node;  	irq_data.args_count = 3;  	irq_data.args[0] = 0;  	irq_data.args[1] = hwirq - OMAP44XX_IRQ_GIC_START; @@ -278,6 +277,12 @@ void __init omap_gic_of_init(void)  {  	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 */  	if (!cpu_is_omap446x())  		goto skip_errata_init; @@ -291,9 +296,5 @@ void __init omap_gic_of_init(void)  	WARN_ON(!twd_base);  skip_errata_init: -	omap_wakeupgen_init(); -#ifdef CONFIG_IRQ_CROSSBAR -	irqcrossbar_init(); -#endif  	irqchip_init();  } diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index 9e3618028acc..fd63ae6532fc 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -252,11 +252,6 @@ static irqreturn_t sh73a0_intcs_demux(int irq, void *dev_id)  	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 PINTER1_PHYS 0xe69000a4  #define PINTER0_VIRT IOMEM(0xe69000a0) @@ -318,8 +313,8 @@ void __init sh73a0_init_irq(void)  	void __iomem *gic_cpu_base = IOMEM(0xf0000100);  	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_arch_extn.irq_set_wake = sh73a0_set_wake;  	register_intc_controller(&intcs_desc);  	register_intc_controller(&intc_pint0_desc); diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index 27dceaf9e688..c03e562be12b 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -713,18 +713,13 @@ void __init r8a7779_init_late(void)  }  #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)  {  #ifdef CONFIG_ARCH_SHMOBILE_LEGACY  	void __iomem *gic_dist_base = ioremap_nocache(0xf0001000, 0x1000);  	void __iomem *gic_cpu_base = ioremap_nocache(0xf0000100, 0x1000);  #endif -	gic_arch_extn.irq_set_wake = r8a7779_set_wake; +	gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE);  #ifdef CONFIG_ARCH_SHMOBILE_LEGACY  	gic_init(0, 29, gic_dist_base, gic_cpu_base); diff --git a/arch/arm/mach-tegra/iomap.h b/arch/arm/mach-tegra/iomap.h index ee79808e93a3..81dc950b4881 100644 --- a/arch/arm/mach-tegra/iomap.h +++ b/arch/arm/mach-tegra/iomap.h @@ -31,21 +31,6 @@  #define TEGRA_ARM_INT_DIST_BASE		0x50041000  #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_SIZE			SZ_8 diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index ab95f5391a2b..3b9098d27ea5 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -30,43 +30,9 @@  #include "board.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 -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 -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;  #endif @@ -83,140 +49,7 @@ bool tegra_pending_sgi(void)  	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 -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,  			      unsigned long cmd, void *v)  { @@ -251,45 +84,19 @@ static void tegra114_gic_cpu_pm_registration(void)  	cpu_pm_register_notifier(&tegra_gic_notifier_block);  }  #else -#define tegra_set_wake NULL  static void tegra114_gic_cpu_pm_registration(void) { }  #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)  { -	int i; -	void __iomem *distbase; - -	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)); +	if (WARN_ON(!of_find_matching_node(NULL, tegra_ictlr_match))) +		pr_warn("Outdated DT detected, suspend/resume will NOT work\n");  	tegra114_gic_cpu_pm_registration();  } diff --git a/arch/arm/mach-tegra/irq.h b/arch/arm/mach-tegra/irq.h index bc05ce5613fb..5142649bba05 100644 --- a/arch/arm/mach-tegra/irq.h +++ b/arch/arm/mach-tegra/irq.h @@ -19,10 +19,4 @@  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 diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 914341bcef25..861d88486dbe 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -82,7 +82,6 @@ static void __init tegra_dt_init_irq(void)  {  	tegra_init_irq();  	irqchip_init(); -	tegra_legacy_irq_syscore_init();  }  static void __init tegra_dt_init(void) diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index dbb2970ee7da..6ced0f680262 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -52,7 +52,7 @@ void ux500_restart(enum reboot_mode mode, const char *cmd)  */  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();  	/* diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index c887196cfdbe..58ef2a700414 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -186,7 +186,7 @@ static void __init zynq_map_io(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();  } diff --git a/arch/mips/loongson/loongson-3/hpet.c b/arch/mips/loongson/loongson-3/hpet.c index e898d68668a9..5c21cd3bd339 100644 --- a/arch/mips/loongson/loongson-3/hpet.c +++ b/arch/mips/loongson/loongson-3/hpet.c @@ -162,7 +162,7 @@ static irqreturn_t hpet_irq_handler(int irq, void *data)  static struct irqaction hpet_irq = {  	.handler = hpet_irq_handler, -	.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER, +	.flags = IRQF_NOBALANCING | IRQF_TIMER,  	.name = "hpet",  }; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 2b9440384536..f749df9e15cd 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -405,8 +405,8 @@ static int cpqarray_register_ctlr(int i, struct pci_dev *pdev)  		goto Enomem4;  	}  	hba[i]->access.set_intr_mask(hba[i], 0); -	if (request_irq(hba[i]->intr, do_ida_intr, -		IRQF_DISABLED|IRQF_SHARED, hba[i]->devname, hba[i])) +	if (request_irq(hba[i]->intr, do_ida_intr, IRQF_SHARED, +			hba[i]->devname, hba[i]))  	{  		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",  				hba[i]->intr, hba[i]->devname); diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 029bc73de001..11f7982cbdb3 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -284,7 +284,7 @@ static int omap_l3_probe(struct platform_device *pdev)  	 */  	l3->debug_irq = platform_get_irq(pdev, 0);  	ret = devm_request_irq(l3->dev, l3->debug_irq, l3_interrupt_handler, -			       IRQF_DISABLED, "l3-dbg-irq", l3); +			       0x0, "l3-dbg-irq", l3);  	if (ret) {  		dev_err(l3->dev, "request_irq failed for %d\n",  			l3->debug_irq); @@ -293,7 +293,7 @@ static int omap_l3_probe(struct platform_device *pdev)  	l3->app_irq = platform_get_irq(pdev, 1);  	ret = devm_request_irq(l3->dev, l3->app_irq, l3_interrupt_handler, -			       IRQF_DISABLED, "l3-app-irq", l3); +			       0x0, "l3-app-irq", l3);  	if (ret)  		dev_err(l3->dev, "request_irq failed for %d\n", l3->app_irq); diff --git a/drivers/bus/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c index 597fdaee7315..360a5c0a4ee0 100644 --- a/drivers/bus/omap_l3_smx.c +++ b/drivers/bus/omap_l3_smx.c @@ -251,18 +251,16 @@ static int omap3_l3_probe(struct platform_device *pdev)  	}  	l3->debug_irq = platform_get_irq(pdev, 0); -	ret = request_irq(l3->debug_irq, omap3_l3_app_irq, -		IRQF_DISABLED | IRQF_TRIGGER_RISING, -		"l3-debug-irq", l3); +	ret = request_irq(l3->debug_irq, omap3_l3_app_irq, IRQF_TRIGGER_RISING, +			  "l3-debug-irq", l3);  	if (ret) {  		dev_err(&pdev->dev, "couldn't request debug irq\n");  		goto err1;  	}  	l3->app_irq = platform_get_irq(pdev, 1); -	ret = request_irq(l3->app_irq, omap3_l3_app_irq, -		IRQF_DISABLED | IRQF_TRIGGER_RISING, -		"l3-app-irq", l3); +	ret = request_irq(l3->app_irq, omap3_l3_app_irq, IRQF_TRIGGER_RISING, +			  "l3-app-irq", l3);  	if (ret) {  		dev_err(&pdev->dev, "couldn't request app irq\n");  		goto err2; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index cc79d2a5a8c2..c8d260e33a90 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -110,6 +110,13 @@ config RENESAS_IRQC  	bool  	select IRQ_DOMAIN +config ST_IRQCHIP +	bool +	select REGMAP +	select MFD_SYSCON +	help +	  Enables SysCfg Controlled IRQs on STi based platforms. +  config TB10X_IRQC  	bool  	select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 42965d2476bb..552a74027601 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_HIP04)		+= irq-hip04.o  obj-$(CONFIG_ARCH_MMP)			+= irq-mmp.o  obj-$(CONFIG_ARCH_MVEBU)		+= irq-armada-370-xp.o  obj-$(CONFIG_ARCH_MXS)			+= irq-mxs.o +obj-$(CONFIG_ARCH_TEGRA)		+= irq-tegra.o  obj-$(CONFIG_ARCH_S3C24XX)		+= irq-s3c24xx.o  obj-$(CONFIG_DW_APB_ICTL)		+= irq-dw-apb-ictl.o  obj-$(CONFIG_METAG)			+= irq-metag-ext.o @@ -33,10 +34,12 @@ obj-$(CONFIG_RENESAS_IRQC)		+= irq-renesas-irqc.o  obj-$(CONFIG_VERSATILE_FPGA_IRQ)	+= irq-versatile-fpga.o  obj-$(CONFIG_ARCH_NSPIRE)		+= irq-zevio.o  obj-$(CONFIG_ARCH_VT8500)		+= irq-vt8500.o +obj-$(CONFIG_ST_IRQCHIP)		+= irq-st.o  obj-$(CONFIG_TB10X_IRQC)		+= irq-tb10x.o  obj-$(CONFIG_XTENSA)			+= irq-xtensa-pic.o  obj-$(CONFIG_XTENSA_MX)			+= irq-xtensa-mx.o  obj-$(CONFIG_IRQ_CROSSBAR)		+= irq-crossbar.o +obj-$(CONFIG_SOC_VF610)			+= irq-vf610-mscm-ir.o  obj-$(CONFIG_BCM7120_L2_IRQ)		+= irq-bcm7120-l2.o  obj-$(CONFIG_BRCMSTB_L2_IRQ)		+= irq-brcmstb-l2.o  obj-$(CONFIG_KEYSTONE_IRQ)		+= irq-keystone.o diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 4387dae14e45..daccc8bdbb42 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -38,6 +38,8 @@  /* Interrupt Controller Registers Map */  #define ARMADA_370_XP_INT_SET_MASK_OFFS		(0x48)  #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS	(0x4C) +#define ARMADA_370_XP_INT_FABRIC_MASK_OFFS	(0x54) +#define ARMADA_370_XP_INT_CAUSE_PERF(cpu)	(1 << cpu)  #define ARMADA_370_XP_INT_CONTROL		(0x00)  #define ARMADA_370_XP_INT_SET_ENABLE_OFFS	(0x30) @@ -56,6 +58,7 @@  #define ARMADA_370_XP_MAX_PER_CPU_IRQS		(28)  #define ARMADA_370_XP_TIMER0_PER_CPU_IRQ	(5) +#define ARMADA_370_XP_FABRIC_IRQ		(3)  #define IPI_DOORBELL_START                      (0)  #define IPI_DOORBELL_END                        (8) @@ -77,6 +80,17 @@ static DEFINE_MUTEX(msi_used_lock);  static phys_addr_t msi_doorbell_addr;  #endif +static inline bool is_percpu_irq(irq_hw_number_t irq) +{ +	switch (irq) { +	case ARMADA_370_XP_TIMER0_PER_CPU_IRQ: +	case ARMADA_370_XP_FABRIC_IRQ: +		return true; +	default: +		return false; +	} +} +  /*   * In SMP mode:   * For shared global interrupts, mask/unmask global enable bit @@ -86,7 +100,7 @@ static void armada_370_xp_irq_mask(struct irq_data *d)  {  	irq_hw_number_t hwirq = irqd_to_hwirq(d); -	if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) +	if (!is_percpu_irq(hwirq))  		writel(hwirq, main_int_base +  				ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);  	else @@ -98,7 +112,7 @@ static void armada_370_xp_irq_unmask(struct irq_data *d)  {  	irq_hw_number_t hwirq = irqd_to_hwirq(d); -	if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) +	if (!is_percpu_irq(hwirq))  		writel(hwirq, main_int_base +  				ARMADA_370_XP_INT_SET_ENABLE_OFFS);  	else @@ -281,20 +295,21 @@ static struct irq_chip armada_370_xp_irq_chip = {  #ifdef CONFIG_SMP  	.irq_set_affinity = armada_xp_set_affinity,  #endif +	.flags		= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,  };  static int armada_370_xp_mpic_irq_map(struct irq_domain *h,  				      unsigned int virq, irq_hw_number_t hw)  {  	armada_370_xp_irq_mask(irq_get_irq_data(virq)); -	if (hw != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) +	if (!is_percpu_irq(hw))  		writel(hw, per_cpu_int_base +  			ARMADA_370_XP_INT_CLEAR_MASK_OFFS);  	else  		writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);  	irq_set_status_flags(virq, IRQ_LEVEL); -	if (hw == ARMADA_370_XP_TIMER0_PER_CPU_IRQ) { +	if (is_percpu_irq(hw)) {  		irq_set_percpu_devid(virq);  		irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,  					handle_percpu_devid_irq); @@ -308,28 +323,6 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h,  	return 0;  } -#ifdef CONFIG_SMP -static void armada_mpic_send_doorbell(const struct cpumask *mask, -				      unsigned int irq) -{ -	int cpu; -	unsigned long map = 0; - -	/* Convert our logical CPU mask into a physical one. */ -	for_each_cpu(cpu, mask) -		map |= 1 << cpu_logical_map(cpu); - -	/* -	 * Ensure that stores to Normal memory are visible to the -	 * other CPUs before issuing the IPI. -	 */ -	dsb(); - -	/* submit softirq */ -	writel((map << 8) | irq, main_int_base + -		ARMADA_370_XP_SW_TRIG_INT_OFFS); -} -  static void armada_xp_mpic_smp_cpu_init(void)  {  	u32 control; @@ -352,11 +345,44 @@ static void armada_xp_mpic_smp_cpu_init(void)  	writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);  } +static void armada_xp_mpic_perf_init(void) +{ +	unsigned long cpuid = cpu_logical_map(smp_processor_id()); + +	/* Enable Performance Counter Overflow interrupts */ +	writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid), +	       per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS); +} + +#ifdef CONFIG_SMP +static void armada_mpic_send_doorbell(const struct cpumask *mask, +				      unsigned int irq) +{ +	int cpu; +	unsigned long map = 0; + +	/* Convert our logical CPU mask into a physical one. */ +	for_each_cpu(cpu, mask) +		map |= 1 << cpu_logical_map(cpu); + +	/* +	 * Ensure that stores to Normal memory are visible to the +	 * other CPUs before issuing the IPI. +	 */ +	dsb(); + +	/* submit softirq */ +	writel((map << 8) | irq, main_int_base + +		ARMADA_370_XP_SW_TRIG_INT_OFFS); +} +  static int armada_xp_mpic_secondary_init(struct notifier_block *nfb,  					 unsigned long action, void *hcpu)  { -	if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) +	if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) { +		armada_xp_mpic_perf_init();  		armada_xp_mpic_smp_cpu_init(); +	}  	return NOTIFY_OK;  } @@ -369,8 +395,10 @@ static struct notifier_block armada_370_xp_mpic_cpu_notifier = {  static int mpic_cascaded_secondary_init(struct notifier_block *nfb,  					unsigned long action, void *hcpu)  { -	if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) +	if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) { +		armada_xp_mpic_perf_init();  		enable_percpu_irq(parent_irq, IRQ_TYPE_NONE); +	}  	return NOTIFY_OK;  } @@ -379,7 +407,6 @@ static struct notifier_block mpic_cascaded_cpu_notifier = {  	.notifier_call = mpic_cascaded_secondary_init,  	.priority = 100,  }; -  #endif /* CONFIG_SMP */  static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { @@ -588,9 +615,9 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,  	BUG_ON(!armada_370_xp_mpic_domain); -#ifdef CONFIG_SMP +	/* Setup for the boot CPU */ +	armada_xp_mpic_perf_init();  	armada_xp_mpic_smp_cpu_init(); -#endif  	armada_370_xp_msi_init(node, main_int_res.start); diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c index bbbaf5de65d2..692fe2bc8197 100644 --- a/drivers/irqchip/irq-crossbar.c +++ b/drivers/irqchip/irq-crossbar.c @@ -11,11 +11,12 @@   */  #include <linux/err.h>  #include <linux/io.h> +#include <linux/irqdomain.h>  #include <linux/of_address.h>  #include <linux/of_irq.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_RESERVED	-2 @@ -24,6 +25,7 @@  /**   * struct crossbar_device - crossbar device description + * @lock: spinlock serializing access to @irq_map   * @int_max: maximum number of supported interrupts   * @safe_map: safe default value to initialize the crossbar   * @max_crossbar_sources: Maximum number of crossbar sources @@ -33,6 +35,7 @@   * @write: register write function pointer   */  struct crossbar_device { +	raw_spinlock_t lock;  	uint int_max;  	uint safe_map;  	uint max_crossbar_sources; @@ -44,72 +47,101 @@ struct crossbar_device {  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]);  } -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]);  } -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]);  } -static inline int get_prev_map_irq(int cb_no) -{ -	int i; - -	for (i = cb->int_max - 1; i >= 0; i--) -		if (cb->irq_map[i] == cb_no) -			return i; - -	return -ENODEV; -} +static struct irq_chip crossbar_chip = { +	.name			= "CBAR", +	.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		= irq_chip_set_wake_parent, +#ifdef CONFIG_SMP +	.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 err; +	raw_spin_lock(&cb->lock);  	for (i = cb->int_max - 1; i >= 0; i--) {  		if (cb->irq_map[i] == IRQ_FREE) { -			cb->irq_map[i] = cb_no; -			return i; +			cb->irq_map[i] = hwirq; +			break;  		}  	} +	raw_spin_unlock(&cb->lock); -	return -ENODEV; -} +	if (i < 0) +		return -ENODEV; -static inline bool needs_crossbar_write(irq_hw_number_t hw) -{ -	int cb_no; +	args.np = domain->parent->of_node; +	args.args_count = 3; +	args.args[0] = 0;	/* SPI */ +	args.args[1] = i; +	args.args[2] = IRQ_TYPE_LEVEL_HIGH; -	if (hw > GIC_IRQ_START) { -		cb_no = cb->irq_map[hw - GIC_IRQ_START]; -		if (cb_no != IRQ_RESERVED && cb_no != IRQ_SKIP) -			return true; -	} +	err = irq_domain_alloc_irqs_parent(domain, virq, 1, &args); +	if (err) +		cb->irq_map[i] = IRQ_FREE; +	else +		cb->write(i, hwirq); -	return false; +	return err;  } -static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, -			       irq_hw_number_t hw) +static int crossbar_domain_alloc(struct irq_domain *d, unsigned int virq, +				 unsigned int nr_irqs, void *data)  { -	if (needs_crossbar_write(hw)) -		cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]); +	struct of_phandle_args *args = data; +	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;  }  /** - * crossbar_domain_unmap - unmap a crossbar<->irq connection - * @d: domain of irq to unmap - * @irq: virq number + * crossbar_domain_free - unmap/free a crossbar<->irq connection + * @domain: domain of irq to unmap + * @virq: virq number + * @nr_irqs: number of irqs to free   *   * 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 @@ -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 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)) { -		cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE; -		cb->write(hw - GIC_IRQ_START, cb->safe_map); +	raw_spin_lock(&cb->lock); +	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); +		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, @@ -133,44 +171,22 @@ static int crossbar_domain_xlate(struct irq_domain *d,  				 unsigned long *out_hwirq,  				 unsigned int *out_type)  { -	int ret; -	int req_num = intspec[1]; -	int direct_map_num; - -	if (req_num >= cb->max_crossbar_sources) { -		direct_map_num = req_num - cb->max_crossbar_sources; -		if (direct_map_num < cb->int_max) { -			ret = cb->irq_map[direct_map_num]; -			if (ret == IRQ_RESERVED || ret == IRQ_SKIP) { -				/* 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; +	if (d->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 const struct irq_domain_ops routable_irq_domain_ops = { -	.map = crossbar_domain_map, -	.unmap = crossbar_domain_unmap, -	.xlate = crossbar_domain_xlate +static const struct irq_domain_ops crossbar_domain_ops = { +	.alloc	= crossbar_domain_alloc, +	.free	= crossbar_domain_free, +	.xlate	= crossbar_domain_xlate,  };  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);  	} -	register_routable_domain_ops(&routable_irq_domain_ops); +	raw_spin_lock_init(&cb->lock); +  	return 0;  err_reg_offset: @@ -309,18 +326,37 @@ err_cb:  	return ret;  } -static const struct of_device_id crossbar_match[] __initconst = { -	{ .compatible = "ti,irq-crossbar" }, -	{} -}; - -int __init irqcrossbar_init(void) +static int __init irqcrossbar_init(struct device_node *node, +				   struct device_node *parent)  { -	struct device_node *np; -	np = of_find_matching_node(NULL, crossbar_match); -	if (!np) +	struct irq_domain *parent_domain, *domain; +	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; +	} + +	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;  } + +IRQCHIP_DECLARE(ti_irqcrossbar, "ti,irq-crossbar", irqcrossbar_init); diff --git a/drivers/irqchip/irq-digicolor.c b/drivers/irqchip/irq-digicolor.c index 930a2a2fac7f..3cbc658afe27 100644 --- a/drivers/irqchip/irq-digicolor.c +++ b/drivers/irqchip/irq-digicolor.c @@ -55,8 +55,8 @@ static void __exception_irq_entry digicolor_handle_irq(struct pt_regs *regs)  	} while (1);  } -static void digicolor_set_gc(void __iomem *reg_base, unsigned irq_base, -			     unsigned en_reg, unsigned ack_reg) +static void __init digicolor_set_gc(void __iomem *reg_base, unsigned irq_base, +				    unsigned en_reg, unsigned ack_reg)  {  	struct irq_chip_generic *gc; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index fd8850def1b8..4f2fb62e6f37 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -195,6 +195,19 @@ static void gic_enable_redist(bool enable)  /*   * Routines to disable, enable, EOI and route interrupts   */ +static int gic_peek_irq(struct irq_data *d, u32 offset) +{ +	u32 mask = 1 << (gic_irq(d) % 32); +	void __iomem *base; + +	if (gic_irq_in_rdist(d)) +		base = gic_data_rdist_sgi_base(); +	else +		base = gic_data.dist_base; + +	return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask); +} +  static void gic_poke_irq(struct irq_data *d, u32 offset)  {  	u32 mask = 1 << (gic_irq(d) % 32); @@ -223,6 +236,61 @@ static void gic_unmask_irq(struct irq_data *d)  	gic_poke_irq(d, GICD_ISENABLER);  } +static int gic_irq_set_irqchip_state(struct irq_data *d, +				     enum irqchip_irq_state which, bool val) +{ +	u32 reg; + +	if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ +		return -EINVAL; + +	switch (which) { +	case IRQCHIP_STATE_PENDING: +		reg = val ? GICD_ISPENDR : GICD_ICPENDR; +		break; + +	case IRQCHIP_STATE_ACTIVE: +		reg = val ? GICD_ISACTIVER : GICD_ICACTIVER; +		break; + +	case IRQCHIP_STATE_MASKED: +		reg = val ? GICD_ICENABLER : GICD_ISENABLER; +		break; + +	default: +		return -EINVAL; +	} + +	gic_poke_irq(d, reg); +	return 0; +} + +static int gic_irq_get_irqchip_state(struct irq_data *d, +				     enum irqchip_irq_state which, bool *val) +{ +	if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ +		return -EINVAL; + +	switch (which) { +	case IRQCHIP_STATE_PENDING: +		*val = gic_peek_irq(d, GICD_ISPENDR); +		break; + +	case IRQCHIP_STATE_ACTIVE: +		*val = gic_peek_irq(d, GICD_ISACTIVER); +		break; + +	case IRQCHIP_STATE_MASKED: +		*val = !gic_peek_irq(d, GICD_ISENABLER); +		break; + +	default: +		return -EINVAL; +	} + +	return 0; +} +  static void gic_eoi_irq(struct irq_data *d)  {  	gic_write_eoir(gic_irq(d)); @@ -418,19 +486,6 @@ static void gic_cpu_init(void)  }  #ifdef CONFIG_SMP -static int gic_peek_irq(struct irq_data *d, u32 offset) -{ -	u32 mask = 1 << (gic_irq(d) % 32); -	void __iomem *base; - -	if (gic_irq_in_rdist(d)) -		base = gic_data_rdist_sgi_base(); -	else -		base = gic_data.dist_base; - -	return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask); -} -  static int gic_secondary_init(struct notifier_block *nfb,  			      unsigned long action, void *hcpu)  { @@ -601,6 +656,8 @@ static struct irq_chip gic_chip = {  	.irq_eoi		= gic_eoi_irq,  	.irq_set_type		= gic_set_type,  	.irq_set_affinity	= gic_set_affinity, +	.irq_get_irqchip_state	= gic_irq_get_irqchip_state, +	.irq_set_irqchip_state	= gic_irq_set_irqchip_state,  };  #define GIC_ID_NR		(1U << gic_data.rdists.id_bits) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 471e1cdc1933..a6ce3476834e 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -151,13 +151,24 @@ static inline unsigned int gic_irq(struct irq_data *d)  /*   * Routines to acknowledge, disable and enable interrupts   */ -static void gic_mask_irq(struct irq_data *d) +static void gic_poke_irq(struct irq_data *d, u32 offset)  {  	u32 mask = 1 << (gic_irq(d) % 32); +	writel_relaxed(mask, gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4); +} + +static int gic_peek_irq(struct irq_data *d, u32 offset) +{ +	u32 mask = 1 << (gic_irq(d) % 32); +	return !!(readl_relaxed(gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4) & mask); +} + +static void gic_mask_irq(struct irq_data *d) +{  	unsigned long flags;  	raw_spin_lock_irqsave(&irq_controller_lock, flags); -	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); +	gic_poke_irq(d, GIC_DIST_ENABLE_CLEAR);  	if (gic_arch_extn.irq_mask)  		gic_arch_extn.irq_mask(d);  	raw_spin_unlock_irqrestore(&irq_controller_lock, flags); @@ -165,13 +176,12 @@ static void gic_mask_irq(struct irq_data *d)  static void gic_unmask_irq(struct irq_data *d)  { -	u32 mask = 1 << (gic_irq(d) % 32);  	unsigned long flags;  	raw_spin_lock_irqsave(&irq_controller_lock, flags);  	if (gic_arch_extn.irq_unmask)  		gic_arch_extn.irq_unmask(d); -	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4); +	gic_poke_irq(d, GIC_DIST_ENABLE_SET);  	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);  } @@ -186,6 +196,55 @@ static void gic_eoi_irq(struct irq_data *d)  	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);  } +static int gic_irq_set_irqchip_state(struct irq_data *d, +				     enum irqchip_irq_state which, bool val) +{ +	u32 reg; + +	switch (which) { +	case IRQCHIP_STATE_PENDING: +		reg = val ? GIC_DIST_PENDING_SET : GIC_DIST_PENDING_CLEAR; +		break; + +	case IRQCHIP_STATE_ACTIVE: +		reg = val ? GIC_DIST_ACTIVE_SET : GIC_DIST_ACTIVE_CLEAR; +		break; + +	case IRQCHIP_STATE_MASKED: +		reg = val ? GIC_DIST_ENABLE_CLEAR : GIC_DIST_ENABLE_SET; +		break; + +	default: +		return -EINVAL; +	} + +	gic_poke_irq(d, reg); +	return 0; +} + +static int gic_irq_get_irqchip_state(struct irq_data *d, +				      enum irqchip_irq_state which, bool *val) +{ +	switch (which) { +	case IRQCHIP_STATE_PENDING: +		*val = gic_peek_irq(d, GIC_DIST_PENDING_SET); +		break; + +	case IRQCHIP_STATE_ACTIVE: +		*val = gic_peek_irq(d, GIC_DIST_ACTIVE_SET); +		break; + +	case IRQCHIP_STATE_MASKED: +		*val = !gic_peek_irq(d, GIC_DIST_ENABLE_SET); +		break; + +	default: +		return -EINVAL; +	} + +	return 0; +} +  static int gic_set_type(struct irq_data *d, unsigned int type)  {  	void __iomem *base = gic_dist_base(d); @@ -329,6 +388,8 @@ static struct irq_chip gic_chip = {  	.irq_set_affinity	= gic_set_affinity,  #endif  	.irq_set_wake		= gic_set_wake, +	.irq_get_irqchip_state	= gic_irq_get_irqchip_state, +	.irq_set_irqchip_state	= gic_irq_set_irqchip_state,  };  void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) @@ -353,7 +414,7 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)  			break;  	} -	if (!mask) +	if (!mask && num_possible_cpus() > 1)  		pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");  	return mask; @@ -802,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,  				    handle_fasteoi_irq, NULL, NULL);  		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - -		gic_routable_irq_domain_ops->map(d, irq, hw);  	}  	return 0;  }  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, @@ -829,16 +887,8 @@ static int gic_irq_domain_xlate(struct irq_domain *d,  	*out_hwirq = intspec[1] + 16;  	/* For SPIs, we need to add 16 more to get the GIC irq ID number */ -	if (!intspec[0]) { -		ret = gic_routable_irq_domain_ops->xlate(d, controller, -							 intspec, -							 intsize, -							 out_hwirq, -							 out_type); - -		if (IS_ERR_VALUE(ret)) -			return ret; -	} +	if (!intspec[0]) +		*out_hwirq += 16;  	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; @@ -895,37 +945,11 @@ static const struct irq_domain_ops gic_irq_domain_ops = {  	.xlate = gic_irq_domain_xlate,  }; -/* Default functions for routable irq domain */ -static int gic_routable_irq_domain_map(struct irq_domain *d, unsigned int irq, -			      irq_hw_number_t hw) +void gic_set_irqchip_flags(unsigned long flags)  { -	return 0; +	gic_chip.flags |= flags;  } -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; -	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 __iomem *dist_base, void __iomem *cpu_base,  			   u32 percpu_offset, struct device_node *node) @@ -933,7 +957,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,  	irq_hw_number_t hwirq_base;  	struct gic_chip_data *gic;  	int gic_irqs, irq_base, i; -	int nr_routable_irqs;  	BUG_ON(gic_nr >= MAX_GIC_NR); @@ -989,15 +1012,9 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,  	gic->gic_irqs = gic_irqs;  	if (node) {		/* DT case */ -		const struct irq_domain_ops *ops = &gic_irq_domain_hierarchy_ops; - -		if (!of_property_read_u32(node, "arm,routable-irqs", -					  &nr_routable_irqs)) { -			ops = &gic_irq_domain_ops; -			gic_irqs = nr_routable_irqs; -		} - -		gic->domain = irq_domain_add_linear(node, gic_irqs, ops, gic); +		gic->domain = irq_domain_add_linear(node, gic_irqs, +						    &gic_irq_domain_hierarchy_ops, +						    gic);  	} else {		/* Non-DT case */  		/*  		 * For primary GICs, skip over SGIs. diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 9acdc080e7ec..f2d269bca789 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -166,6 +166,27 @@ cycle_t gic_read_compare(void)  	return (((cycle_t) hi) << 32) + lo;  } + +void gic_start_count(void) +{ +	u32 gicconfig; + +	/* Start the counter */ +	gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG)); +	gicconfig &= ~(1 << GIC_SH_CONFIG_COUNTSTOP_SHF); +	gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); +} + +void gic_stop_count(void) +{ +	u32 gicconfig; + +	/* Stop the counter */ +	gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG)); +	gicconfig |= 1 << GIC_SH_CONFIG_COUNTSTOP_SHF; +	gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); +} +  #endif  static bool gic_local_irq_is_routable(int intr) diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 384e6ed61d7c..cdf80b7794cd 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -17,6 +17,7 @@   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   */ +#include <linux/clk.h>  #include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/spinlock.h> @@ -29,15 +30,26 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/platform_data/irq-renesas-irqc.h> +#include <linux/pm_runtime.h> -#define IRQC_IRQ_MAX 32 /* maximum 32 interrupts per driver instance */ +#define IRQC_IRQ_MAX	32	/* maximum 32 interrupts per driver instance */ -#define IRQC_REQ_STS 0x00 -#define IRQC_EN_STS 0x04 -#define IRQC_EN_SET 0x08 +#define IRQC_REQ_STS	0x00	/* Interrupt Request Status Register */ +#define IRQC_EN_STS	0x04	/* Interrupt Enable Status Register */ +#define IRQC_EN_SET	0x08	/* Interrupt Enable Set Register */  #define IRQC_INT_CPU_BASE(n) (0x000 + ((n) * 0x10)) -#define DETECT_STATUS 0x100 +				/* SYS-CPU vs. RT-CPU */ +#define DETECT_STATUS	0x100	/* IRQn Detect Status Register */ +#define MONITOR		0x104	/* IRQn Signal Level Monitor Register */ +#define HLVL_STS	0x108	/* IRQn High Level Detect Status Register */ +#define LLVL_STS	0x10c	/* IRQn Low Level Detect Status Register */ +#define S_R_EDGE_STS	0x110	/* IRQn Sync Rising Edge Detect Status Reg. */ +#define S_F_EDGE_STS	0x114	/* IRQn Sync Falling Edge Detect Status Reg. */ +#define A_R_EDGE_STS	0x118	/* IRQn Async Rising Edge Detect Status Reg. */ +#define A_F_EDGE_STS	0x11c	/* IRQn Async Falling Edge Detect Status Reg. */ +#define CHTEN_STS	0x120	/* Chattering Reduction Status Register */  #define IRQC_CONFIG(n) (0x180 + ((n) * 0x04)) +				/* IRQn Configuration Register */  struct irqc_irq {  	int hw_irq; @@ -55,6 +67,7 @@ struct irqc_priv {  	struct platform_device *pdev;  	struct irq_chip irq_chip;  	struct irq_domain *irq_domain; +	struct clk *clk;  };  static void irqc_dbg(struct irqc_irq *i, char *str) @@ -94,7 +107,7 @@ static int irqc_irq_set_type(struct irq_data *d, unsigned int type)  	struct irqc_priv *p = irq_data_get_irq_chip_data(d);  	int hw_irq = irqd_to_hwirq(d);  	unsigned char value = irqc_sense[type & IRQ_TYPE_SENSE_MASK]; -	unsigned long tmp; +	u32 tmp;  	irqc_dbg(&p->irq[hw_irq], "sense"); @@ -108,11 +121,26 @@ static int irqc_irq_set_type(struct irq_data *d, unsigned int type)  	return 0;  } +static int irqc_irq_set_wake(struct irq_data *d, unsigned int on) +{ +	struct irqc_priv *p = irq_data_get_irq_chip_data(d); + +	if (!p->clk) +		return 0; + +	if (on) +		clk_enable(p->clk); +	else +		clk_disable(p->clk); + +	return 0; +} +  static irqreturn_t irqc_irq_handler(int irq, void *dev_id)  {  	struct irqc_irq *i = dev_id;  	struct irqc_priv *p = i->p; -	unsigned long bit = BIT(i->hw_irq); +	u32 bit = BIT(i->hw_irq);  	irqc_dbg(i, "demux1"); @@ -170,6 +198,15 @@ static int irqc_probe(struct platform_device *pdev)  	p->pdev = pdev;  	platform_set_drvdata(pdev, p); +	p->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(p->clk)) { +		dev_warn(&pdev->dev, "unable to get clock\n"); +		p->clk = NULL; +	} + +	pm_runtime_enable(&pdev->dev); +	pm_runtime_get_sync(&pdev->dev); +  	/* get hold of manadatory IOMEM */  	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!io) { @@ -210,7 +247,8 @@ static int irqc_probe(struct platform_device *pdev)  	irq_chip->irq_mask = irqc_irq_disable;  	irq_chip->irq_unmask = irqc_irq_enable;  	irq_chip->irq_set_type = irqc_irq_set_type; -	irq_chip->flags	= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; +	irq_chip->irq_set_wake = irqc_irq_set_wake; +	irq_chip->flags	= IRQCHIP_MASK_ON_SUSPEND;  	p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,  					      p->number_of_irqs, @@ -250,6 +288,8 @@ err3:  err2:  	iounmap(p->iomem);  err1: +	pm_runtime_put(&pdev->dev); +	pm_runtime_disable(&pdev->dev);  	kfree(p);  err0:  	return ret; @@ -265,6 +305,8 @@ static int irqc_remove(struct platform_device *pdev)  	irq_domain_remove(p->irq_domain);  	iounmap(p->iomem); +	pm_runtime_put(&pdev->dev); +	pm_runtime_disable(&pdev->dev);  	kfree(p);  	return 0;  } diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c new file mode 100644 index 000000000000..9af48a85c16f --- /dev/null +++ b/drivers/irqchip/irq-st.c @@ -0,0 +1,206 @@ +/* + *  Copyright (C) 2014 STMicroelectronics – All Rights Reserved + * + *  Author: Lee Jones <lee.jones@linaro.org> + * + *  This is a re-write of Christophe Kerello's PMU driver. + * + * 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. + */ + +#include <dt-bindings/interrupt-controller/irq-st.h> +#include <linux/err.h> +#include <linux/mfd/syscon.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#define STIH415_SYSCFG_642		0x0a8 +#define STIH416_SYSCFG_7543		0x87c +#define STIH407_SYSCFG_5102		0x198 +#define STID127_SYSCFG_734		0x088 + +#define ST_A9_IRQ_MASK			0x001FFFFF +#define ST_A9_IRQ_MAX_CHANS		2 + +#define ST_A9_IRQ_EN_CTI_0		BIT(0) +#define ST_A9_IRQ_EN_CTI_1		BIT(1) +#define ST_A9_IRQ_EN_PMU_0		BIT(2) +#define ST_A9_IRQ_EN_PMU_1		BIT(3) +#define ST_A9_IRQ_EN_PL310_L2		BIT(4) +#define ST_A9_IRQ_EN_EXT_0		BIT(5) +#define ST_A9_IRQ_EN_EXT_1		BIT(6) +#define ST_A9_IRQ_EN_EXT_2		BIT(7) + +#define ST_A9_FIQ_N_SEL(dev, chan)	(dev << (8  + (chan * 3))) +#define ST_A9_IRQ_N_SEL(dev, chan)	(dev << (14 + (chan * 3))) +#define ST_A9_EXTIRQ_INV_SEL(dev)	(dev << 20) + +struct st_irq_syscfg { +	struct regmap *regmap; +	unsigned int syscfg; +	unsigned int config; +	bool ext_inverted; +}; + +static const struct of_device_id st_irq_syscfg_match[] = { +	{ +		.compatible = "st,stih415-irq-syscfg", +		.data = (void *)STIH415_SYSCFG_642, +	}, +	{ +		.compatible = "st,stih416-irq-syscfg", +		.data = (void *)STIH416_SYSCFG_7543, +	}, +	{ +		.compatible = "st,stih407-irq-syscfg", +		.data = (void *)STIH407_SYSCFG_5102, +	}, +	{ +		.compatible = "st,stid127-irq-syscfg", +		.data = (void *)STID127_SYSCFG_734, +	}, +	{} +}; + +static int st_irq_xlate(struct platform_device *pdev, +			int device, int channel, bool irq) +{ +	struct st_irq_syscfg *ddata = dev_get_drvdata(&pdev->dev); + +	/* Set the device enable bit. */ +	switch (device) { +	case ST_IRQ_SYSCFG_EXT_0: +		ddata->config |= ST_A9_IRQ_EN_EXT_0; +		break; +	case ST_IRQ_SYSCFG_EXT_1: +		ddata->config |= ST_A9_IRQ_EN_EXT_1; +		break; +	case ST_IRQ_SYSCFG_EXT_2: +		ddata->config |= ST_A9_IRQ_EN_EXT_2; +		break; +	case ST_IRQ_SYSCFG_CTI_0: +		ddata->config |= ST_A9_IRQ_EN_CTI_0; +		break; +	case ST_IRQ_SYSCFG_CTI_1: +		ddata->config |= ST_A9_IRQ_EN_CTI_1; +		break; +	case ST_IRQ_SYSCFG_PMU_0: +		ddata->config |= ST_A9_IRQ_EN_PMU_0; +		break; +	case ST_IRQ_SYSCFG_PMU_1: +		ddata->config |= ST_A9_IRQ_EN_PMU_1; +		break; +	case ST_IRQ_SYSCFG_pl310_L2: +		ddata->config |= ST_A9_IRQ_EN_PL310_L2; +		break; +	case ST_IRQ_SYSCFG_DISABLED: +		return 0; +	default: +		dev_err(&pdev->dev, "Unrecognised device %d\n", device); +		return -EINVAL; +	} + +	/* Select IRQ/FIQ channel for device. */ +	ddata->config |= irq ? +		ST_A9_IRQ_N_SEL(device, channel) : +		ST_A9_FIQ_N_SEL(device, channel); + +	return 0; +} + +static int st_irq_syscfg_enable(struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	struct st_irq_syscfg *ddata = dev_get_drvdata(&pdev->dev); +	int channels, ret, i; +	u32 device, invert; + +	channels = of_property_count_u32_elems(np, "st,irq-device"); +	if (channels != ST_A9_IRQ_MAX_CHANS) { +		dev_err(&pdev->dev, "st,enable-irq-device must have 2 elems\n"); +		return -EINVAL; +	} + +	channels = of_property_count_u32_elems(np, "st,fiq-device"); +	if (channels != ST_A9_IRQ_MAX_CHANS) { +		dev_err(&pdev->dev, "st,enable-fiq-device must have 2 elems\n"); +		return -EINVAL; +	} + +	for (i = 0; i < ST_A9_IRQ_MAX_CHANS; i++) { +		of_property_read_u32_index(np, "st,irq-device", i, &device); + +		ret = st_irq_xlate(pdev, device, i, true); +		if (ret) +			return ret; + +		of_property_read_u32_index(np, "st,fiq-device", i, &device); + +		ret = st_irq_xlate(pdev, device, i, false); +		if (ret) +			return ret; +	} + +	/* External IRQs may be inverted. */ +	of_property_read_u32(np, "st,invert-ext", &invert); +	ddata->config |= ST_A9_EXTIRQ_INV_SEL(invert); + +	return regmap_update_bits(ddata->regmap, ddata->syscfg, +				  ST_A9_IRQ_MASK, ddata->config); +} + +static int st_irq_syscfg_probe(struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	const struct of_device_id *match; +	struct st_irq_syscfg *ddata; + +	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); +	if (!ddata) +		return -ENOMEM; + +	match = of_match_device(st_irq_syscfg_match, &pdev->dev); +	if (!match) +		return -ENODEV; + +	ddata->syscfg = (unsigned int)match->data; + +	ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); +	if (IS_ERR(ddata->regmap)) { +		dev_err(&pdev->dev, "syscfg phandle missing\n"); +		return PTR_ERR(ddata->regmap); +	} + +	dev_set_drvdata(&pdev->dev, ddata); + +	return st_irq_syscfg_enable(pdev); +} + +static int st_irq_syscfg_resume(struct device *dev) +{ +	struct st_irq_syscfg *ddata = dev_get_drvdata(dev); + +	return regmap_update_bits(ddata->regmap, ddata->syscfg, +				  ST_A9_IRQ_MASK, ddata->config); +} + +static SIMPLE_DEV_PM_OPS(st_irq_syscfg_pm_ops, NULL, st_irq_syscfg_resume); + +static struct platform_driver st_irq_syscfg_driver = { +	.driver = { +		.name = "st_irq_syscfg", +		.pm = &st_irq_syscfg_pm_ops, +		.of_match_table = st_irq_syscfg_match, +	}, +	.probe = st_irq_syscfg_probe, +}; + +static int __init st_irq_syscfg_init(void) +{ +	return platform_driver_register(&st_irq_syscfg_driver); +} +core_initcall(st_irq_syscfg_init); diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c new file mode 100644 index 000000000000..51c485d9a877 --- /dev/null +++ b/drivers/irqchip/irq-tegra.c @@ -0,0 +1,377 @@ +/* + * 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); diff --git a/drivers/irqchip/irq-vf610-mscm-ir.c b/drivers/irqchip/irq-vf610-mscm-ir.c new file mode 100644 index 000000000000..9521057d4744 --- /dev/null +++ b/drivers/irqchip/irq-vf610-mscm-ir.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2014-2015 Toradex AG + * Author: Stefan Agner <stefan@agner.ch> + * + * 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. + * + * + * IRQ chip driver for MSCM interrupt router available on Vybrid SoC's. + * The interrupt router is between the CPU's interrupt controller and the + * peripheral. The router allows to route the peripheral interrupts to + * one of the two available CPU's on Vybrid VF6xx SoC's (Cortex-A5 or + * Cortex-M4). The router will be configured transparently on a IRQ + * request. + * + * o All peripheral interrupts of the Vybrid SoC can be routed to + *   CPU 0, CPU 1 or both. The routing is useful for dual-core + *   variants of Vybrid SoC such as VF6xx. This driver routes the + *   requested interrupt to the CPU currently running on. + * + * o It is required to setup the interrupt router even on single-core + *   variants of Vybrid. + */ + +#include <linux/cpu_pm.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/mfd/syscon.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/slab.h> +#include <linux/regmap.h> + +#include "irqchip.h" + +#define MSCM_CPxNUM		0x4 + +#define MSCM_IRSPRC(n)		(0x80 + 2 * (n)) +#define MSCM_IRSPRC_CPEN_MASK	0x3 + +#define MSCM_IRSPRC_NUM		112 + +struct vf610_mscm_ir_chip_data { +	void __iomem *mscm_ir_base; +	u16 cpu_mask; +	u16 saved_irsprc[MSCM_IRSPRC_NUM]; +}; + +static struct vf610_mscm_ir_chip_data *mscm_ir_data; + +static inline void vf610_mscm_ir_save(struct vf610_mscm_ir_chip_data *data) +{ +	int i; + +	for (i = 0; i < MSCM_IRSPRC_NUM; i++) +		data->saved_irsprc[i] = readw_relaxed(data->mscm_ir_base + MSCM_IRSPRC(i)); +} + +static inline void vf610_mscm_ir_restore(struct vf610_mscm_ir_chip_data *data) +{ +	int i; + +	for (i = 0; i < MSCM_IRSPRC_NUM; i++) +		writew_relaxed(data->saved_irsprc[i], data->mscm_ir_base + MSCM_IRSPRC(i)); +} + +static int vf610_mscm_ir_notifier(struct notifier_block *self, +				  unsigned long cmd, void *v) +{ +	switch (cmd) { +	case CPU_CLUSTER_PM_ENTER: +		vf610_mscm_ir_save(mscm_ir_data); +		break; +	case CPU_CLUSTER_PM_ENTER_FAILED: +	case CPU_CLUSTER_PM_EXIT: +		vf610_mscm_ir_restore(mscm_ir_data); +		break; +	} + +	return NOTIFY_OK; +} + +static struct notifier_block mscm_ir_notifier_block = { +	.notifier_call = vf610_mscm_ir_notifier, +}; + +static void vf610_mscm_ir_enable(struct irq_data *data) +{ +	irq_hw_number_t hwirq = data->hwirq; +	struct vf610_mscm_ir_chip_data *chip_data = data->chip_data; +	u16 irsprc; + +	irsprc = readw_relaxed(chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); +	irsprc &= MSCM_IRSPRC_CPEN_MASK; + +	WARN_ON(irsprc & ~chip_data->cpu_mask); + +	writew_relaxed(chip_data->cpu_mask, +		       chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); + +	irq_chip_unmask_parent(data); +} + +static void vf610_mscm_ir_disable(struct irq_data *data) +{ +	irq_hw_number_t hwirq = data->hwirq; +	struct vf610_mscm_ir_chip_data *chip_data = data->chip_data; + +	writew_relaxed(0x0, chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); + +	irq_chip_mask_parent(data); +} + +static struct irq_chip vf610_mscm_ir_irq_chip = { +	.name			= "mscm-ir", +	.irq_mask		= irq_chip_mask_parent, +	.irq_unmask		= irq_chip_unmask_parent, +	.irq_eoi		= irq_chip_eoi_parent, +	.irq_enable		= vf610_mscm_ir_enable, +	.irq_disable		= vf610_mscm_ir_disable, +	.irq_retrigger		= irq_chip_retrigger_hierarchy, +	.irq_set_affinity	= irq_chip_set_affinity_parent, +}; + +static int vf610_mscm_ir_domain_alloc(struct irq_domain *domain, unsigned int virq, +				      unsigned int nr_irqs, void *arg) +{ +	int i; +	irq_hw_number_t hwirq; +	struct of_phandle_args *irq_data = arg; +	struct of_phandle_args gic_data; + +	if (irq_data->args_count != 2) +		return -EINVAL; + +	hwirq = irq_data->args[0]; +	for (i = 0; i < nr_irqs; i++) +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, +					      &vf610_mscm_ir_irq_chip, +					      domain->host_data); + +	gic_data.np = domain->parent->of_node; +	gic_data.args_count = 3; +	gic_data.args[0] = GIC_SPI; +	gic_data.args[1] = irq_data->args[0]; +	gic_data.args[2] = irq_data->args[1]; +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_data); +} + +static const struct irq_domain_ops mscm_irq_domain_ops = { +	.xlate = irq_domain_xlate_twocell, +	.alloc = vf610_mscm_ir_domain_alloc, +	.free = irq_domain_free_irqs_common, +}; + +static int __init vf610_mscm_ir_of_init(struct device_node *node, +			       struct device_node *parent) +{ +	struct irq_domain *domain, *domain_parent; +	struct regmap *mscm_cp_regmap; +	int ret, cpuid; + +	domain_parent = irq_find_host(parent); +	if (!domain_parent) { +		pr_err("vf610_mscm_ir: interrupt-parent not found\n"); +		return -EINVAL; +	} + +	mscm_ir_data = kzalloc(sizeof(*mscm_ir_data), GFP_KERNEL); +	if (!mscm_ir_data) +		return -ENOMEM; + +	mscm_ir_data->mscm_ir_base = of_io_request_and_map(node, 0, "mscm-ir"); + +	if (!mscm_ir_data->mscm_ir_base) { +		pr_err("vf610_mscm_ir: unable to map mscm register\n"); +		ret = -ENOMEM; +		goto out_free; +	} + +	mscm_cp_regmap = syscon_regmap_lookup_by_phandle(node, "fsl,cpucfg"); +	if (IS_ERR(mscm_cp_regmap)) { +		ret = PTR_ERR(mscm_cp_regmap); +		pr_err("vf610_mscm_ir: regmap lookup for cpucfg failed\n"); +		goto out_unmap; +	} + +	regmap_read(mscm_cp_regmap, MSCM_CPxNUM, &cpuid); +	mscm_ir_data->cpu_mask = 0x1 << cpuid; + +	domain = irq_domain_add_hierarchy(domain_parent, 0, +					  MSCM_IRSPRC_NUM, node, +					  &mscm_irq_domain_ops, mscm_ir_data); +	if (!domain) { +		ret = -ENOMEM; +		goto out_unmap; +	} + +	cpu_pm_register_notifier(&mscm_ir_notifier_block); + +	return 0; + +out_unmap: +	iounmap(mscm_ir_data->mscm_ir_base); +out_free: +	kfree(mscm_ir_data); +	return ret; +} +IRQCHIP_DECLARE(vf610_mscm_ir, "fsl,vf610-mscm-ir", vf610_mscm_ir_of_init); diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c index 289ad3ac3e80..8dcc7b8fee40 100644 --- a/drivers/mtd/nand/hisi504_nand.c +++ b/drivers/mtd/nand/hisi504_nand.c @@ -758,8 +758,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)  	hisi_nfc_host_init(host); -	ret = devm_request_irq(dev, irq, hinfc_irq_handle, IRQF_DISABLED, -				"nandc", host); +	ret = devm_request_irq(dev, irq, hinfc_irq_handle, 0x0, "nandc", host);  	if (ret) {  		dev_err(dev, "failed to request IRQ\n");  		goto err_res; diff --git a/include/dt-bindings/interrupt-controller/irq-st.h b/include/dt-bindings/interrupt-controller/irq-st.h new file mode 100644 index 000000000000..4c59aceb9be0 --- /dev/null +++ b/include/dt-bindings/interrupt-controller/irq-st.h @@ -0,0 +1,30 @@ +/* + *  include/linux/irqchip/irq-st.h + * + *  Copyright (C) 2014 STMicroelectronics – All Rights Reserved + * + *  Author: Lee Jones <lee.jones@linaro.org> + * + * 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. + */ + +#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_ST_H +#define _DT_BINDINGS_INTERRUPT_CONTROLLER_ST_H + +#define ST_IRQ_SYSCFG_EXT_0		0 +#define ST_IRQ_SYSCFG_EXT_1		1 +#define ST_IRQ_SYSCFG_EXT_2		2 +#define ST_IRQ_SYSCFG_CTI_0		3 +#define ST_IRQ_SYSCFG_CTI_1		4 +#define ST_IRQ_SYSCFG_PMU_0		5 +#define ST_IRQ_SYSCFG_PMU_1		6 +#define ST_IRQ_SYSCFG_pl310_L2		7 +#define ST_IRQ_SYSCFG_DISABLED		0xFFFFFFFF + +#define ST_IRQ_SYSCFG_EXT_1_INV		0x1 +#define ST_IRQ_SYSCFG_EXT_2_INV		0x2 +#define ST_IRQ_SYSCFG_EXT_3_INV		0x4 + +#endif diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index cba442ec3c66..f4af03404b97 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -9,7 +9,7 @@  extern void synchronize_irq(unsigned int irq); -extern void synchronize_hardirq(unsigned int irq); +extern bool synchronize_hardirq(unsigned int irq);  #if defined(CONFIG_TINY_RCU) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 2e88580194f0..950ae4501826 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -39,8 +39,6 @@   * These flags used only by the kernel as part of the   * irq handling routines.   * - * IRQF_DISABLED - keep irqs disabled when calling the action handler. - *                 DEPRECATED. This flag is a NOOP and scheduled to be removed   * IRQF_SHARED - allow sharing the irq among several devices   * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur   * IRQF_TIMER - Flag to mark this interrupt as timer interrupt @@ -64,7 +62,6 @@   *                wakeup devices users need to implement wakeup detection in   *                their interrupt handlers.   */ -#define IRQF_DISABLED		0x00000020  #define IRQF_SHARED		0x00000080  #define IRQF_PROBE_SHARED	0x00000100  #define __IRQF_TIMER		0x00000200 @@ -191,6 +188,7 @@ extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);  #endif  extern void disable_irq_nosync(unsigned int irq); +extern bool disable_hardirq(unsigned int irq);  extern void disable_irq(unsigned int irq);  extern void disable_percpu_irq(unsigned int irq);  extern void enable_irq(unsigned int irq); @@ -363,6 +361,20 @@ static inline int disable_irq_wake(unsigned int irq)  	return irq_set_irq_wake(irq, 0);  } +/* + * irq_get_irqchip_state/irq_set_irqchip_state specific flags + */ +enum irqchip_irq_state { +	IRQCHIP_STATE_PENDING,		/* Is interrupt pending? */ +	IRQCHIP_STATE_ACTIVE,		/* Is interrupt in progress? */ +	IRQCHIP_STATE_MASKED,		/* Is interrupt masked? */ +	IRQCHIP_STATE_LINE_LEVEL,	/* Is IRQ line high? */ +}; + +extern int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, +				 bool *state); +extern int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, +				 bool state);  #ifdef CONFIG_IRQ_FORCED_THREADING  extern bool force_irqthreads; diff --git a/include/linux/irq.h b/include/linux/irq.h index d09ec7a1243e..62c6901cab55 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -30,6 +30,7 @@  struct seq_file;  struct module;  struct msi_msg; +enum irqchip_irq_state;  /*   * IRQ line status. @@ -324,6 +325,8 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)   *				irq_request_resources   * @irq_compose_msi_msg:	optional to compose message content for MSI   * @irq_write_msi_msg:	optional to write message content for MSI + * @irq_get_irqchip_state:	return the internal state of an interrupt + * @irq_set_irqchip_state:	set the internal state of a interrupt   * @flags:		chip specific flags   */  struct irq_chip { @@ -363,6 +366,9 @@ struct irq_chip {  	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);  	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg); +	int		(*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state); +	int		(*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state); +  	unsigned long	flags;  }; @@ -460,6 +466,7 @@ extern void irq_chip_eoi_parent(struct irq_data *data);  extern int irq_chip_set_affinity_parent(struct irq_data *data,  					const struct cpumask *dest,  					bool force); +extern int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on);  #endif  /* Handling of unhandled and spurious interrupts: */ diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 71d706d5f169..36ec4ae74634 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -97,6 +97,7 @@ struct device_node;  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 *,  		    u32 offset, struct device_node *);  void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); @@ -115,11 +116,5 @@ int gic_get_cpu_id(unsigned int cpu);  void gic_migrate_target(unsigned int new_cpu_id);  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 diff --git a/include/linux/irqchip/irq-crossbar.h b/include/linux/irqchip/irq-crossbar.h deleted file mode 100644 index e5537b81df8d..000000000000 --- a/include/linux/irqchip/irq-crossbar.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - *  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); diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h index e6a6aac451db..3ea2e4754c40 100644 --- a/include/linux/irqchip/mips-gic.h +++ b/include/linux/irqchip/mips-gic.h @@ -240,6 +240,8 @@ extern unsigned int gic_get_count_width(void);  extern cycle_t gic_read_compare(void);  extern void gic_write_compare(cycle_t cnt);  extern void gic_write_cpu_compare(cycle_t cnt, int cpu); +extern void gic_start_count(void); +extern void gic_stop_count(void);  extern void gic_send_ipi(unsigned int intr);  extern unsigned int plat_ipi_call_int_xlate(unsigned int);  extern unsigned int plat_ipi_resched_int_xlate(unsigned int); diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index d176d658fe25..5dd1272d1ab2 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h @@ -85,7 +85,7 @@   * The local_irq_*() APIs are equal to the raw_local_irq*()   * if !TRACE_IRQFLAGS.   */ -#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT +#ifdef CONFIG_TRACE_IRQFLAGS  #define local_irq_enable() \  	do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0)  #define local_irq_disable() \ @@ -107,22 +107,6 @@  			raw_local_irq_restore(flags);	\  		}					\  	} while (0) -#define local_save_flags(flags)				\ -	do {						\ -		raw_local_save_flags(flags);		\ -	} while (0) - -#define irqs_disabled_flags(flags)			\ -	({						\ -		raw_irqs_disabled_flags(flags);		\ -	}) - -#define irqs_disabled()					\ -	({						\ -		unsigned long _flags;			\ -		raw_local_save_flags(_flags);		\ -		raw_irqs_disabled_flags(_flags);	\ -	})  #define safe_halt()				\  	do {					\ @@ -131,7 +115,7 @@  	} while (0) -#else /* !CONFIG_TRACE_IRQFLAGS_SUPPORT */ +#else /* !CONFIG_TRACE_IRQFLAGS */  #define local_irq_enable()	do { raw_local_irq_enable(); } while (0)  #define local_irq_disable()	do { raw_local_irq_disable(); } while (0) @@ -140,11 +124,28 @@  		raw_local_irq_save(flags);			\  	} while (0)  #define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0) -#define local_save_flags(flags)	do { raw_local_save_flags(flags); } while (0) -#define irqs_disabled()		(raw_irqs_disabled()) -#define irqs_disabled_flags(flags) (raw_irqs_disabled_flags(flags))  #define safe_halt()		do { raw_safe_halt(); } while (0) +#endif /* CONFIG_TRACE_IRQFLAGS */ + +#define local_save_flags(flags)	raw_local_save_flags(flags) + +/* + * Some architectures don't define arch_irqs_disabled(), so even if either + * definition would be fine we need to use different ones for the time being + * to avoid build issues. + */ +#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT +#define irqs_disabled()					\ +	({						\ +		unsigned long _flags;			\ +		raw_local_save_flags(_flags);		\ +		raw_irqs_disabled_flags(_flags);	\ +	}) +#else /* !CONFIG_TRACE_IRQFLAGS_SUPPORT */ +#define irqs_disabled()	raw_irqs_disabled()  #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ +#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags) +  #endif diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 6f1c7a566b95..eb9a4ea394ab 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -948,6 +948,22 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data)  	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  /** diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 886d09e691d5..e68932bb308e 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -68,14 +68,20 @@ static void __synchronize_hardirq(struct irq_desc *desc)   *	Do not use this for shutdown scenarios where you must be sure   *	that all parts (hardirq and threaded handler) have completed.   * + *	Returns: false if a threaded handler is active. + *   *	This function may be called - with care - from IRQ context.   */ -void synchronize_hardirq(unsigned int irq) +bool synchronize_hardirq(unsigned int irq)  {  	struct irq_desc *desc = irq_to_desc(irq); -	if (desc) +	if (desc) {  		__synchronize_hardirq(desc); +		return !atomic_read(&desc->threads_active); +	} + +	return true;  }  EXPORT_SYMBOL(synchronize_hardirq); @@ -440,6 +446,32 @@ void disable_irq(unsigned int irq)  }  EXPORT_SYMBOL(disable_irq); +/** + *	disable_hardirq - disables an irq and waits for hardirq completion + *	@irq: Interrupt to disable + * + *	Disable the selected interrupt line.  Enables and Disables are + *	nested. + *	This function waits for any pending hard IRQ handlers for this + *	interrupt to complete before returning. If you use this function while + *	holding a resource the hard IRQ handler may need you will deadlock. + * + *	When used to optimistically disable an interrupt from atomic context + *	the return value must be checked. + * + *	Returns: false if a threaded handler is active. + * + *	This function may be called - with care - from IRQ context. + */ +bool disable_hardirq(unsigned int irq) +{ +	if (!__disable_irq_nosync(irq)) +		return synchronize_hardirq(irq); + +	return false; +} +EXPORT_SYMBOL_GPL(disable_hardirq); +  void __enable_irq(struct irq_desc *desc, unsigned int irq)  {  	switch (desc->depth) { @@ -1766,3 +1798,94 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler,  	return retval;  } + +/** + *	irq_get_irqchip_state - returns the irqchip state of a interrupt. + *	@irq: Interrupt line that is forwarded to a VM + *	@which: One of IRQCHIP_STATE_* the caller wants to know about + *	@state: a pointer to a boolean where the state is to be storeed + * + *	This call snapshots the internal irqchip state of an + *	interrupt, returning into @state the bit corresponding to + *	stage @which + * + *	This function should be called with preemption disabled if the + *	interrupt controller has per-cpu registers. + */ +int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, +			  bool *state) +{ +	struct irq_desc *desc; +	struct irq_data *data; +	struct irq_chip *chip; +	unsigned long flags; +	int err = -EINVAL; + +	desc = irq_get_desc_buslock(irq, &flags, 0); +	if (!desc) +		return err; + +	data = irq_desc_get_irq_data(desc); + +	do { +		chip = irq_data_get_irq_chip(data); +		if (chip->irq_get_irqchip_state) +			break; +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +		data = data->parent_data; +#else +		data = NULL; +#endif +	} while (data); + +	if (data) +		err = chip->irq_get_irqchip_state(data, which, state); + +	irq_put_desc_busunlock(desc, flags); +	return err; +} + +/** + *	irq_set_irqchip_state - set the state of a forwarded interrupt. + *	@irq: Interrupt line that is forwarded to a VM + *	@which: State to be restored (one of IRQCHIP_STATE_*) + *	@val: Value corresponding to @which + * + *	This call sets the internal irqchip state of an interrupt, + *	depending on the value of @which. + * + *	This function should be called with preemption disabled if the + *	interrupt controller has per-cpu registers. + */ +int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, +			  bool val) +{ +	struct irq_desc *desc; +	struct irq_data *data; +	struct irq_chip *chip; +	unsigned long flags; +	int err = -EINVAL; + +	desc = irq_get_desc_buslock(irq, &flags, 0); +	if (!desc) +		return err; + +	data = irq_desc_get_irq_data(desc); + +	do { +		chip = irq_data_get_irq_chip(data); +		if (chip->irq_set_irqchip_state) +			break; +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +		data = data->parent_data; +#else +		data = NULL; +#endif +	} while (data); + +	if (data) +		err = chip->irq_set_irqchip_state(data, which, val); + +	irq_put_desc_busunlock(desc, flags); +	return err; +} diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 3e18163f336f..474de5cb394d 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -310,8 +310,15 @@ void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)  	struct msi_desc *desc;  	for_each_msi_entry(desc, dev) { -		irq_domain_free_irqs(desc->irq, desc->nvec_used); -		desc->irq = 0; +		/* +		 * We might have failed to allocate an MSI early +		 * enough that there is no IRQ associated to this +		 * entry. If that's the case, don't do anything. +		 */ +		if (desc->irq) { +			irq_domain_free_irqs(desc->irq, desc->nvec_used); +			desc->irq = 0; +		}  	}  } | 
