Loading Documentation/devicetree/bindings/arm/omap/crossbar.txt +36 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ 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. - 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. - ti,irqs-reserved: List of the reserved irq lines that are not muxed using Loading @@ -17,11 +18,46 @@ Required properties: so crossbar bar driver should not consider them as free lines. Optional properties: - ti,irqs-skip: This is similar to "ti,irqs-reserved", but these are for SOC-specific hard-wiring of those irqs which unexpectedly bypasses the crossbar. These irqs have a crossbar register, but still cannot be used. - ti,irqs-safe-map: integer which maps to a safe configuration to use when the interrupt controller irq is unused (when not provided, default is 0) Examples: crossbar_mpu: @4a020000 { 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-skip = <10 133 139 140>; }; Consumer: ======== See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt and 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 { /* Crossbar 8 used */ 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>; ... }; arch/arm/boot/dts/dra7.dtsi +81 −58 Original line number Diff line number Diff line Loading @@ -12,6 +12,9 @@ #include "skeleton.dtsi" #define MAX_SOURCES 400 #define DIRECT_IRQ(irq) (MAX_SOURCES + irq) / { #address-cells = <1>; #size-cells = <1>; Loading Loading @@ -45,6 +48,7 @@ compatible = "arm,cortex-a15-gic"; interrupt-controller; #interrupt-cells = <3>; arm,routable-irqs = <192>; reg = <0x48211000 0x1000>, <0x48212000 0x1000>, <0x48214000 0x2000>, Loading Loading @@ -79,8 +83,8 @@ ti,hwmods = "l3_main_1", "l3_main_2"; reg = <0x44000000 0x1000000>, <0x45000000 0x1000>; interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI DIRECT_IRQ(10) IRQ_TYPE_LEVEL_HIGH>; prm: prm@4ae06000 { compatible = "ti,dra7-prm"; Loading Loading @@ -155,10 +159,10 @@ sdma: dma-controller@4a056000 { compatible = "ti,omap4430-sdma"; reg = <0x4a056000 0x1000>; interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; #dma-cells = <1>; #dma-channels = <32>; #dma-requests = <127>; Loading @@ -167,7 +171,7 @@ gpio1: gpio@4ae10000 { compatible = "ti,omap4-gpio"; reg = <0x4ae10000 0x200>; interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio1"; gpio-controller; #gpio-cells = <2>; Loading @@ -178,7 +182,7 @@ gpio2: gpio@48055000 { compatible = "ti,omap4-gpio"; reg = <0x48055000 0x200>; interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio2"; gpio-controller; #gpio-cells = <2>; Loading @@ -189,7 +193,7 @@ gpio3: gpio@48057000 { compatible = "ti,omap4-gpio"; reg = <0x48057000 0x200>; interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio3"; gpio-controller; #gpio-cells = <2>; Loading @@ -200,7 +204,7 @@ gpio4: gpio@48059000 { compatible = "ti,omap4-gpio"; reg = <0x48059000 0x200>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio4"; gpio-controller; #gpio-cells = <2>; Loading @@ -211,7 +215,7 @@ gpio5: gpio@4805b000 { compatible = "ti,omap4-gpio"; reg = <0x4805b000 0x200>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio5"; gpio-controller; #gpio-cells = <2>; Loading @@ -222,7 +226,7 @@ gpio6: gpio@4805d000 { compatible = "ti,omap4-gpio"; reg = <0x4805d000 0x200>; interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio6"; gpio-controller; #gpio-cells = <2>; Loading @@ -233,7 +237,7 @@ gpio7: gpio@48051000 { compatible = "ti,omap4-gpio"; reg = <0x48051000 0x200>; interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio7"; gpio-controller; #gpio-cells = <2>; Loading @@ -244,7 +248,7 @@ gpio8: gpio@48053000 { compatible = "ti,omap4-gpio"; reg = <0x48053000 0x200>; interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio8"; gpio-controller; #gpio-cells = <2>; Loading @@ -255,7 +259,7 @@ uart1: serial@4806a000 { compatible = "ti,omap4-uart"; reg = <0x4806a000 0x100>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart1"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -264,7 +268,7 @@ uart2: serial@4806c000 { compatible = "ti,omap4-uart"; reg = <0x4806c000 0x100>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart2"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -273,7 +277,7 @@ uart3: serial@48020000 { compatible = "ti,omap4-uart"; reg = <0x48020000 0x100>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart3"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -282,7 +286,7 @@ uart4: serial@4806e000 { compatible = "ti,omap4-uart"; reg = <0x4806e000 0x100>; interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart4"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -291,7 +295,7 @@ uart5: serial@48066000 { compatible = "ti,omap4-uart"; reg = <0x48066000 0x100>; interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart5"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -300,7 +304,7 @@ uart6: serial@48068000 { compatible = "ti,omap4-uart"; reg = <0x48068000 0x100>; interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart6"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -309,6 +313,7 @@ uart7: serial@48420000 { compatible = "ti,omap4-uart"; reg = <0x48420000 0x100>; interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart7"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -317,6 +322,7 @@ uart8: serial@48422000 { compatible = "ti,omap4-uart"; reg = <0x48422000 0x100>; interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart8"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -325,6 +331,7 @@ uart9: serial@48424000 { compatible = "ti,omap4-uart"; reg = <0x48424000 0x100>; interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart9"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -333,6 +340,7 @@ uart10: serial@4ae2b000 { compatible = "ti,omap4-uart"; reg = <0x4ae2b000 0x100>; interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart10"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -341,7 +349,7 @@ timer1: timer@4ae18000 { compatible = "ti,omap5430-timer"; reg = <0x4ae18000 0x80>; interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer1"; ti,timer-alwon; }; Loading @@ -349,28 +357,28 @@ timer2: timer@48032000 { compatible = "ti,omap5430-timer"; reg = <0x48032000 0x80>; interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer2"; }; timer3: timer@48034000 { compatible = "ti,omap5430-timer"; reg = <0x48034000 0x80>; interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer3"; }; timer4: timer@48036000 { compatible = "ti,omap5430-timer"; reg = <0x48036000 0x80>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer4"; }; timer5: timer@48820000 { compatible = "ti,omap5430-timer"; reg = <0x48820000 0x80>; interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer5"; ti,timer-dsp; }; Loading @@ -378,7 +386,7 @@ timer6: timer@48822000 { compatible = "ti,omap5430-timer"; reg = <0x48822000 0x80>; interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer6"; ti,timer-dsp; ti,timer-pwm; Loading @@ -387,7 +395,7 @@ timer7: timer@48824000 { compatible = "ti,omap5430-timer"; reg = <0x48824000 0x80>; interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer7"; ti,timer-dsp; }; Loading @@ -395,7 +403,7 @@ timer8: timer@48826000 { compatible = "ti,omap5430-timer"; reg = <0x48826000 0x80>; interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer8"; ti,timer-dsp; ti,timer-pwm; Loading @@ -404,21 +412,21 @@ timer9: timer@4803e000 { compatible = "ti,omap5430-timer"; reg = <0x4803e000 0x80>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer9"; }; timer10: timer@48086000 { compatible = "ti,omap5430-timer"; reg = <0x48086000 0x80>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer10"; }; timer11: timer@48088000 { compatible = "ti,omap5430-timer"; reg = <0x48088000 0x80>; interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer11"; ti,timer-pwm; }; Loading @@ -426,6 +434,7 @@ timer13: timer@48828000 { compatible = "ti,omap5430-timer"; reg = <0x48828000 0x80>; interrupts = <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer13"; status = "disabled"; }; Loading @@ -433,6 +442,7 @@ timer14: timer@4882a000 { compatible = "ti,omap5430-timer"; reg = <0x4882a000 0x80>; interrupts = <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer14"; status = "disabled"; }; Loading @@ -440,6 +450,7 @@ timer15: timer@4882c000 { compatible = "ti,omap5430-timer"; reg = <0x4882c000 0x80>; interrupts = <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer15"; status = "disabled"; }; Loading @@ -447,6 +458,7 @@ timer16: timer@4882e000 { compatible = "ti,omap5430-timer"; reg = <0x4882e000 0x80>; interrupts = <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer16"; status = "disabled"; }; Loading @@ -454,7 +466,7 @@ wdt2: wdt@4ae14000 { compatible = "ti,omap4-wdt"; reg = <0x4ae14000 0x80>; interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "wd_timer2"; }; Loading @@ -468,14 +480,14 @@ dmm@4e000000 { compatible = "ti,omap5-dmm"; reg = <0x4e000000 0x800>; interrupts = <0 113 0x4>; interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "dmm"; }; i2c1: i2c@48070000 { compatible = "ti,omap4-i2c"; reg = <0x48070000 0x100>; interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c1"; Loading @@ -485,7 +497,7 @@ i2c2: i2c@48072000 { compatible = "ti,omap4-i2c"; reg = <0x48072000 0x100>; interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c2"; Loading @@ -495,7 +507,7 @@ i2c3: i2c@48060000 { compatible = "ti,omap4-i2c"; reg = <0x48060000 0x100>; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c3"; Loading @@ -505,7 +517,7 @@ i2c4: i2c@4807a000 { compatible = "ti,omap4-i2c"; reg = <0x4807a000 0x100>; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c4"; Loading @@ -515,7 +527,7 @@ i2c5: i2c@4807c000 { compatible = "ti,omap4-i2c"; reg = <0x4807c000 0x100>; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c5"; Loading @@ -525,7 +537,7 @@ mmc1: mmc@4809c000 { compatible = "ti,omap4-hsmmc"; reg = <0x4809c000 0x400>; interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc1"; ti,dual-volt; ti,needs-special-reset; Loading @@ -538,7 +550,7 @@ mmc2: mmc@480b4000 { compatible = "ti,omap4-hsmmc"; reg = <0x480b4000 0x400>; interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc2"; ti,needs-special-reset; dmas = <&sdma 47>, <&sdma 48>; Loading @@ -549,7 +561,7 @@ mmc3: mmc@480ad000 { compatible = "ti,omap4-hsmmc"; reg = <0x480ad000 0x400>; interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc3"; ti,needs-special-reset; dmas = <&sdma 77>, <&sdma 78>; Loading @@ -560,7 +572,7 @@ mmc4: mmc@480d1000 { compatible = "ti,omap4-hsmmc"; reg = <0x480d1000 0x400>; interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc4"; ti,needs-special-reset; dmas = <&sdma 57>, <&sdma 58>; Loading Loading @@ -703,7 +715,7 @@ mcspi1: spi@48098000 { compatible = "ti,omap4-mcspi"; reg = <0x48098000 0x200>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi1"; Loading @@ -724,7 +736,7 @@ mcspi2: spi@4809a000 { compatible = "ti,omap4-mcspi"; reg = <0x4809a000 0x200>; interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi2"; Loading @@ -740,7 +752,7 @@ mcspi3: spi@480b8000 { compatible = "ti,omap4-mcspi"; reg = <0x480b8000 0x200>; interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi3"; Loading @@ -753,7 +765,7 @@ mcspi4: spi@480ba000 { compatible = "ti,omap4-mcspi"; reg = <0x480ba000 0x200>; interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi4"; Loading @@ -773,7 +785,7 @@ clocks = <&qspi_gfclk_div>; clock-names = "fck"; num-cs = <4>; interrupts = <0 343 0x4>; interrupts = <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; Loading Loading @@ -809,7 +821,7 @@ sata: sata@4a141100 { compatible = "snps,dwc-ahci"; reg = <0x4a140000 0x1100>, <0x4a141100 0x7>; interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>; phys = <&sata_phy>; phy-names = "sata-phy"; clocks = <&sata_ref_clk>; Loading Loading @@ -886,7 +898,7 @@ compatible = "ti,dwc3"; ti,hwmods = "usb_otg_ss1"; reg = <0x48880000 0x10000>; interrupts = <0 77 4>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <1>; utmi-mode = <2>; Loading @@ -894,7 +906,7 @@ usb1: usb@48890000 { compatible = "snps,dwc3"; reg = <0x48890000 0x17000>; interrupts = <0 76 4>; interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; phys = <&usb2_phy1>, <&usb3_phy1>; phy-names = "usb2-phy", "usb3-phy"; tx-fifo-resize; Loading @@ -907,7 +919,7 @@ compatible = "ti,dwc3"; ti,hwmods = "usb_otg_ss2"; reg = <0x488c0000 0x10000>; interrupts = <0 92 4>; interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <1>; utmi-mode = <2>; Loading @@ -915,7 +927,7 @@ usb2: usb@488d0000 { compatible = "snps,dwc3"; reg = <0x488d0000 0x17000>; interrupts = <0 78 4>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; phys = <&usb2_phy2>; phy-names = "usb2-phy"; tx-fifo-resize; Loading @@ -929,7 +941,7 @@ compatible = "ti,dwc3"; ti,hwmods = "usb_otg_ss3"; reg = <0x48900000 0x10000>; /* interrupts = <0 TBD 4>; */ interrupts = <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <1>; utmi-mode = <2>; Loading @@ -938,7 +950,7 @@ usb3: usb@48910000 { compatible = "snps,dwc3"; reg = <0x48910000 0x17000>; /* interrupts = <0 93 4>; */ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; tx-fifo-resize; maximum-speed = "high-speed"; dr_mode = "otg"; Loading @@ -949,7 +961,7 @@ compatible = "ti,dwc3"; ti,hwmods = "usb_otg_ss4"; reg = <0x48940000 0x10000>; /* interrupts = <0 TBD 4>; */ interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <1>; utmi-mode = <2>; Loading @@ -958,7 +970,7 @@ usb4: usb@48950000 { compatible = "snps,dwc3"; reg = <0x48950000 0x17000>; /* interrupts = <0 TBD 4>; */ interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>; tx-fifo-resize; maximum-speed = "high-speed"; dr_mode = "otg"; Loading @@ -968,7 +980,7 @@ elm: elm@48078000 { compatible = "ti,am3352-elm"; reg = <0x48078000 0xfc0>; /* device IO registers */ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "elm"; status = "disabled"; }; Loading @@ -977,13 +989,24 @@ compatible = "ti,am3352-gpmc"; ti,hwmods = "gpmc"; reg = <0x50000000 0x37c>; /* device IO registers */ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; gpmc,num-cs = <8>; gpmc,num-waitpins = <2>; #address-cells = <2>; #size-cells = <1>; status = "disabled"; }; crossbar_mpu: crossbar@4a020000 { compatible = "ti,irq-crossbar"; reg = <0x4a002a48 0x130>; ti,max-irqs = <160>; ti,max-crossbar-sources = <MAX_SOURCES>; ti,reg-size = <2>; ti,irqs-reserved = <0 1 2 3 5 6 131 132>; ti,irqs-skip = <10 133 139 140>; ti,irqs-safe-map = <0>; }; }; }; Loading drivers/irqchip/irq-crossbar.c +143 −25 Original line number Diff line number Diff line Loading @@ -15,18 +15,27 @@ #include <linux/of_irq.h> #include <linux/slab.h> #include <linux/irqchip/arm-gic.h> #include <linux/irqchip/irq-crossbar.h> #define IRQ_FREE -1 #define IRQ_RESERVED -2 #define IRQ_SKIP -3 #define GIC_IRQ_START 32 /* /** * struct crossbar_device - crossbar device description * @int_max: maximum number of supported interrupts * @safe_map: safe default value to initialize the crossbar * @max_crossbar_sources: Maximum number of crossbar sources * @irq_map: array of interrupts to crossbar number mapping * @crossbar_base: crossbar base address * @register_offsets: offsets for each irq number * @write: register write function pointer */ struct crossbar_device { uint int_max; uint safe_map; uint max_crossbar_sources; uint *irq_map; void __iomem *crossbar_base; int *register_offsets; Loading @@ -50,11 +59,22 @@ static inline 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 inline int allocate_free_irq(int cb_no) { int i; for (i = 0; i < cb->int_max; i++) { for (i = cb->int_max - 1; i >= 0; i--) { if (cb->irq_map[i] == IRQ_FREE) { cb->irq_map[i] = cb_no; return i; Loading @@ -64,19 +84,47 @@ static inline int allocate_free_irq(int cb_no) return -ENODEV; } static inline bool needs_crossbar_write(irq_hw_number_t hw) { int cb_no; 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; } return false; } static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { if (needs_crossbar_write(hw)) cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]); return 0; } /** * crossbar_domain_unmap - unmap a crossbar<->irq connection * @d: domain of irq to unmap * @irq: virq number * * 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 * unmapped. This is because unmap is called during irq_dispose_mapping(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) { irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq; if (hw > GIC_IRQ_START) if (needs_crossbar_write(hw)) { cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE; cb->write(hw - GIC_IRQ_START, cb->safe_map); } } static int crossbar_domain_xlate(struct irq_domain *d, Loading @@ -85,18 +133,41 @@ static int crossbar_domain_xlate(struct irq_domain *d, unsigned long *out_hwirq, unsigned int *out_type) { unsigned long ret; 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 = allocate_free_irq(intspec[1]); ret = get_prev_map_irq(req_num); if (ret >= 0) goto found; if (IS_ERR_VALUE(ret)) ret = allocate_free_irq(req_num); if (ret < 0) return ret; found: *out_hwirq = ret + GIC_IRQ_START; return 0; } const struct irq_domain_ops routable_irq_domain_ops = { static const struct irq_domain_ops routable_irq_domain_ops = { .map = crossbar_domain_map, .unmap = crossbar_domain_unmap, .xlate = crossbar_domain_xlate Loading @@ -104,22 +175,36 @@ const struct irq_domain_ops routable_irq_domain_ops = { static int __init crossbar_of_init(struct device_node *node) { int i, size, max, reserved = 0, entry; int i, size, max = 0, reserved = 0, entry; const __be32 *irqsr; int ret = -ENOMEM; cb = kzalloc(sizeof(*cb), GFP_KERNEL); if (!cb) return -ENOMEM; return ret; cb->crossbar_base = of_iomap(node, 0); if (!cb->crossbar_base) goto err1; goto err_cb; of_property_read_u32(node, "ti,max-crossbar-sources", &cb->max_crossbar_sources); if (!cb->max_crossbar_sources) { pr_err("missing 'ti,max-crossbar-sources' property\n"); ret = -EINVAL; goto err_base; } of_property_read_u32(node, "ti,max-irqs", &max); cb->irq_map = kzalloc(max * sizeof(int), GFP_KERNEL); if (!max) { pr_err("missing 'ti,max-irqs' property\n"); ret = -EINVAL; goto err_base; } cb->irq_map = kcalloc(max, sizeof(int), GFP_KERNEL); if (!cb->irq_map) goto err2; goto err_base; cb->int_max = max; Loading @@ -137,15 +222,35 @@ static int __init crossbar_of_init(struct device_node *node) i, &entry); if (entry > max) { pr_err("Invalid reserved entry\n"); goto err3; ret = -EINVAL; goto err_irq_map; } cb->irq_map[entry] = 0; cb->irq_map[entry] = IRQ_RESERVED; } } cb->register_offsets = kzalloc(max * sizeof(int), GFP_KERNEL); /* Skip irqs hardwired to bypass the crossbar */ irqsr = of_get_property(node, "ti,irqs-skip", &size); if (irqsr) { size /= sizeof(__be32); for (i = 0; i < size; i++) { of_property_read_u32_index(node, "ti,irqs-skip", i, &entry); if (entry > max) { pr_err("Invalid skip entry\n"); ret = -EINVAL; goto err_irq_map; } cb->irq_map[entry] = IRQ_SKIP; } } cb->register_offsets = kcalloc(max, sizeof(int), GFP_KERNEL); if (!cb->register_offsets) goto err3; goto err_irq_map; of_property_read_u32(node, "ti,reg-size", &size); Loading @@ -161,7 +266,8 @@ static int __init crossbar_of_init(struct device_node *node) break; default: pr_err("Invalid reg-size property\n"); goto err4; ret = -EINVAL; goto err_reg_offset; break; } Loading @@ -170,25 +276,37 @@ static int __init crossbar_of_init(struct device_node *node) * reserved irqs. so find and store the offsets once. */ for (i = 0; i < max; i++) { if (!cb->irq_map[i]) if (cb->irq_map[i] == IRQ_RESERVED) continue; cb->register_offsets[i] = reserved; reserved += size; } of_property_read_u32(node, "ti,irqs-safe-map", &cb->safe_map); /* Initialize the crossbar with safe map to start with */ for (i = 0; i < max; i++) { if (cb->irq_map[i] == IRQ_RESERVED || cb->irq_map[i] == IRQ_SKIP) continue; cb->write(i, cb->safe_map); } register_routable_domain_ops(&routable_irq_domain_ops); return 0; err4: err_reg_offset: kfree(cb->register_offsets); err3: err_irq_map: kfree(cb->irq_map); err2: err_base: iounmap(cb->crossbar_base); err1: err_cb: kfree(cb); return -ENOMEM; cb = NULL; return ret; } static const struct of_device_id crossbar_match[] __initconst = { Loading Loading
Documentation/devicetree/bindings/arm/omap/crossbar.txt +36 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ 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. - 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. - ti,irqs-reserved: List of the reserved irq lines that are not muxed using Loading @@ -17,11 +18,46 @@ Required properties: so crossbar bar driver should not consider them as free lines. Optional properties: - ti,irqs-skip: This is similar to "ti,irqs-reserved", but these are for SOC-specific hard-wiring of those irqs which unexpectedly bypasses the crossbar. These irqs have a crossbar register, but still cannot be used. - ti,irqs-safe-map: integer which maps to a safe configuration to use when the interrupt controller irq is unused (when not provided, default is 0) Examples: crossbar_mpu: @4a020000 { 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-skip = <10 133 139 140>; }; Consumer: ======== See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt and 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 { /* Crossbar 8 used */ 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>; ... };
arch/arm/boot/dts/dra7.dtsi +81 −58 Original line number Diff line number Diff line Loading @@ -12,6 +12,9 @@ #include "skeleton.dtsi" #define MAX_SOURCES 400 #define DIRECT_IRQ(irq) (MAX_SOURCES + irq) / { #address-cells = <1>; #size-cells = <1>; Loading Loading @@ -45,6 +48,7 @@ compatible = "arm,cortex-a15-gic"; interrupt-controller; #interrupt-cells = <3>; arm,routable-irqs = <192>; reg = <0x48211000 0x1000>, <0x48212000 0x1000>, <0x48214000 0x2000>, Loading Loading @@ -79,8 +83,8 @@ ti,hwmods = "l3_main_1", "l3_main_2"; reg = <0x44000000 0x1000000>, <0x45000000 0x1000>; interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI DIRECT_IRQ(10) IRQ_TYPE_LEVEL_HIGH>; prm: prm@4ae06000 { compatible = "ti,dra7-prm"; Loading Loading @@ -155,10 +159,10 @@ sdma: dma-controller@4a056000 { compatible = "ti,omap4430-sdma"; reg = <0x4a056000 0x1000>; interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; #dma-cells = <1>; #dma-channels = <32>; #dma-requests = <127>; Loading @@ -167,7 +171,7 @@ gpio1: gpio@4ae10000 { compatible = "ti,omap4-gpio"; reg = <0x4ae10000 0x200>; interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio1"; gpio-controller; #gpio-cells = <2>; Loading @@ -178,7 +182,7 @@ gpio2: gpio@48055000 { compatible = "ti,omap4-gpio"; reg = <0x48055000 0x200>; interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio2"; gpio-controller; #gpio-cells = <2>; Loading @@ -189,7 +193,7 @@ gpio3: gpio@48057000 { compatible = "ti,omap4-gpio"; reg = <0x48057000 0x200>; interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio3"; gpio-controller; #gpio-cells = <2>; Loading @@ -200,7 +204,7 @@ gpio4: gpio@48059000 { compatible = "ti,omap4-gpio"; reg = <0x48059000 0x200>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio4"; gpio-controller; #gpio-cells = <2>; Loading @@ -211,7 +215,7 @@ gpio5: gpio@4805b000 { compatible = "ti,omap4-gpio"; reg = <0x4805b000 0x200>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio5"; gpio-controller; #gpio-cells = <2>; Loading @@ -222,7 +226,7 @@ gpio6: gpio@4805d000 { compatible = "ti,omap4-gpio"; reg = <0x4805d000 0x200>; interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio6"; gpio-controller; #gpio-cells = <2>; Loading @@ -233,7 +237,7 @@ gpio7: gpio@48051000 { compatible = "ti,omap4-gpio"; reg = <0x48051000 0x200>; interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio7"; gpio-controller; #gpio-cells = <2>; Loading @@ -244,7 +248,7 @@ gpio8: gpio@48053000 { compatible = "ti,omap4-gpio"; reg = <0x48053000 0x200>; interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "gpio8"; gpio-controller; #gpio-cells = <2>; Loading @@ -255,7 +259,7 @@ uart1: serial@4806a000 { compatible = "ti,omap4-uart"; reg = <0x4806a000 0x100>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart1"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -264,7 +268,7 @@ uart2: serial@4806c000 { compatible = "ti,omap4-uart"; reg = <0x4806c000 0x100>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart2"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -273,7 +277,7 @@ uart3: serial@48020000 { compatible = "ti,omap4-uart"; reg = <0x48020000 0x100>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart3"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -282,7 +286,7 @@ uart4: serial@4806e000 { compatible = "ti,omap4-uart"; reg = <0x4806e000 0x100>; interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart4"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -291,7 +295,7 @@ uart5: serial@48066000 { compatible = "ti,omap4-uart"; reg = <0x48066000 0x100>; interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart5"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -300,7 +304,7 @@ uart6: serial@48068000 { compatible = "ti,omap4-uart"; reg = <0x48068000 0x100>; interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart6"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -309,6 +313,7 @@ uart7: serial@48420000 { compatible = "ti,omap4-uart"; reg = <0x48420000 0x100>; interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart7"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -317,6 +322,7 @@ uart8: serial@48422000 { compatible = "ti,omap4-uart"; reg = <0x48422000 0x100>; interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart8"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -325,6 +331,7 @@ uart9: serial@48424000 { compatible = "ti,omap4-uart"; reg = <0x48424000 0x100>; interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart9"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -333,6 +340,7 @@ uart10: serial@4ae2b000 { compatible = "ti,omap4-uart"; reg = <0x4ae2b000 0x100>; interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart10"; clock-frequency = <48000000>; status = "disabled"; Loading @@ -341,7 +349,7 @@ timer1: timer@4ae18000 { compatible = "ti,omap5430-timer"; reg = <0x4ae18000 0x80>; interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer1"; ti,timer-alwon; }; Loading @@ -349,28 +357,28 @@ timer2: timer@48032000 { compatible = "ti,omap5430-timer"; reg = <0x48032000 0x80>; interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer2"; }; timer3: timer@48034000 { compatible = "ti,omap5430-timer"; reg = <0x48034000 0x80>; interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer3"; }; timer4: timer@48036000 { compatible = "ti,omap5430-timer"; reg = <0x48036000 0x80>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer4"; }; timer5: timer@48820000 { compatible = "ti,omap5430-timer"; reg = <0x48820000 0x80>; interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer5"; ti,timer-dsp; }; Loading @@ -378,7 +386,7 @@ timer6: timer@48822000 { compatible = "ti,omap5430-timer"; reg = <0x48822000 0x80>; interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer6"; ti,timer-dsp; ti,timer-pwm; Loading @@ -387,7 +395,7 @@ timer7: timer@48824000 { compatible = "ti,omap5430-timer"; reg = <0x48824000 0x80>; interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer7"; ti,timer-dsp; }; Loading @@ -395,7 +403,7 @@ timer8: timer@48826000 { compatible = "ti,omap5430-timer"; reg = <0x48826000 0x80>; interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer8"; ti,timer-dsp; ti,timer-pwm; Loading @@ -404,21 +412,21 @@ timer9: timer@4803e000 { compatible = "ti,omap5430-timer"; reg = <0x4803e000 0x80>; interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer9"; }; timer10: timer@48086000 { compatible = "ti,omap5430-timer"; reg = <0x48086000 0x80>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer10"; }; timer11: timer@48088000 { compatible = "ti,omap5430-timer"; reg = <0x48088000 0x80>; interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer11"; ti,timer-pwm; }; Loading @@ -426,6 +434,7 @@ timer13: timer@48828000 { compatible = "ti,omap5430-timer"; reg = <0x48828000 0x80>; interrupts = <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer13"; status = "disabled"; }; Loading @@ -433,6 +442,7 @@ timer14: timer@4882a000 { compatible = "ti,omap5430-timer"; reg = <0x4882a000 0x80>; interrupts = <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer14"; status = "disabled"; }; Loading @@ -440,6 +450,7 @@ timer15: timer@4882c000 { compatible = "ti,omap5430-timer"; reg = <0x4882c000 0x80>; interrupts = <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer15"; status = "disabled"; }; Loading @@ -447,6 +458,7 @@ timer16: timer@4882e000 { compatible = "ti,omap5430-timer"; reg = <0x4882e000 0x80>; interrupts = <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "timer16"; status = "disabled"; }; Loading @@ -454,7 +466,7 @@ wdt2: wdt@4ae14000 { compatible = "ti,omap4-wdt"; reg = <0x4ae14000 0x80>; interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "wd_timer2"; }; Loading @@ -468,14 +480,14 @@ dmm@4e000000 { compatible = "ti,omap5-dmm"; reg = <0x4e000000 0x800>; interrupts = <0 113 0x4>; interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "dmm"; }; i2c1: i2c@48070000 { compatible = "ti,omap4-i2c"; reg = <0x48070000 0x100>; interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c1"; Loading @@ -485,7 +497,7 @@ i2c2: i2c@48072000 { compatible = "ti,omap4-i2c"; reg = <0x48072000 0x100>; interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c2"; Loading @@ -495,7 +507,7 @@ i2c3: i2c@48060000 { compatible = "ti,omap4-i2c"; reg = <0x48060000 0x100>; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c3"; Loading @@ -505,7 +517,7 @@ i2c4: i2c@4807a000 { compatible = "ti,omap4-i2c"; reg = <0x4807a000 0x100>; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c4"; Loading @@ -515,7 +527,7 @@ i2c5: i2c@4807c000 { compatible = "ti,omap4-i2c"; reg = <0x4807c000 0x100>; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c5"; Loading @@ -525,7 +537,7 @@ mmc1: mmc@4809c000 { compatible = "ti,omap4-hsmmc"; reg = <0x4809c000 0x400>; interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc1"; ti,dual-volt; ti,needs-special-reset; Loading @@ -538,7 +550,7 @@ mmc2: mmc@480b4000 { compatible = "ti,omap4-hsmmc"; reg = <0x480b4000 0x400>; interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc2"; ti,needs-special-reset; dmas = <&sdma 47>, <&sdma 48>; Loading @@ -549,7 +561,7 @@ mmc3: mmc@480ad000 { compatible = "ti,omap4-hsmmc"; reg = <0x480ad000 0x400>; interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc3"; ti,needs-special-reset; dmas = <&sdma 77>, <&sdma 78>; Loading @@ -560,7 +572,7 @@ mmc4: mmc@480d1000 { compatible = "ti,omap4-hsmmc"; reg = <0x480d1000 0x400>; interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc4"; ti,needs-special-reset; dmas = <&sdma 57>, <&sdma 58>; Loading Loading @@ -703,7 +715,7 @@ mcspi1: spi@48098000 { compatible = "ti,omap4-mcspi"; reg = <0x48098000 0x200>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi1"; Loading @@ -724,7 +736,7 @@ mcspi2: spi@4809a000 { compatible = "ti,omap4-mcspi"; reg = <0x4809a000 0x200>; interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi2"; Loading @@ -740,7 +752,7 @@ mcspi3: spi@480b8000 { compatible = "ti,omap4-mcspi"; reg = <0x480b8000 0x200>; interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi3"; Loading @@ -753,7 +765,7 @@ mcspi4: spi@480ba000 { compatible = "ti,omap4-mcspi"; reg = <0x480ba000 0x200>; interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi4"; Loading @@ -773,7 +785,7 @@ clocks = <&qspi_gfclk_div>; clock-names = "fck"; num-cs = <4>; interrupts = <0 343 0x4>; interrupts = <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; Loading Loading @@ -809,7 +821,7 @@ sata: sata@4a141100 { compatible = "snps,dwc-ahci"; reg = <0x4a140000 0x1100>, <0x4a141100 0x7>; interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>; phys = <&sata_phy>; phy-names = "sata-phy"; clocks = <&sata_ref_clk>; Loading Loading @@ -886,7 +898,7 @@ compatible = "ti,dwc3"; ti,hwmods = "usb_otg_ss1"; reg = <0x48880000 0x10000>; interrupts = <0 77 4>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <1>; utmi-mode = <2>; Loading @@ -894,7 +906,7 @@ usb1: usb@48890000 { compatible = "snps,dwc3"; reg = <0x48890000 0x17000>; interrupts = <0 76 4>; interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; phys = <&usb2_phy1>, <&usb3_phy1>; phy-names = "usb2-phy", "usb3-phy"; tx-fifo-resize; Loading @@ -907,7 +919,7 @@ compatible = "ti,dwc3"; ti,hwmods = "usb_otg_ss2"; reg = <0x488c0000 0x10000>; interrupts = <0 92 4>; interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <1>; utmi-mode = <2>; Loading @@ -915,7 +927,7 @@ usb2: usb@488d0000 { compatible = "snps,dwc3"; reg = <0x488d0000 0x17000>; interrupts = <0 78 4>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; phys = <&usb2_phy2>; phy-names = "usb2-phy"; tx-fifo-resize; Loading @@ -929,7 +941,7 @@ compatible = "ti,dwc3"; ti,hwmods = "usb_otg_ss3"; reg = <0x48900000 0x10000>; /* interrupts = <0 TBD 4>; */ interrupts = <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <1>; utmi-mode = <2>; Loading @@ -938,7 +950,7 @@ usb3: usb@48910000 { compatible = "snps,dwc3"; reg = <0x48910000 0x17000>; /* interrupts = <0 93 4>; */ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; tx-fifo-resize; maximum-speed = "high-speed"; dr_mode = "otg"; Loading @@ -949,7 +961,7 @@ compatible = "ti,dwc3"; ti,hwmods = "usb_otg_ss4"; reg = <0x48940000 0x10000>; /* interrupts = <0 TBD 4>; */ interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <1>; utmi-mode = <2>; Loading @@ -958,7 +970,7 @@ usb4: usb@48950000 { compatible = "snps,dwc3"; reg = <0x48950000 0x17000>; /* interrupts = <0 TBD 4>; */ interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>; tx-fifo-resize; maximum-speed = "high-speed"; dr_mode = "otg"; Loading @@ -968,7 +980,7 @@ elm: elm@48078000 { compatible = "ti,am3352-elm"; reg = <0x48078000 0xfc0>; /* device IO registers */ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "elm"; status = "disabled"; }; Loading @@ -977,13 +989,24 @@ compatible = "ti,am3352-gpmc"; ti,hwmods = "gpmc"; reg = <0x50000000 0x37c>; /* device IO registers */ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; gpmc,num-cs = <8>; gpmc,num-waitpins = <2>; #address-cells = <2>; #size-cells = <1>; status = "disabled"; }; crossbar_mpu: crossbar@4a020000 { compatible = "ti,irq-crossbar"; reg = <0x4a002a48 0x130>; ti,max-irqs = <160>; ti,max-crossbar-sources = <MAX_SOURCES>; ti,reg-size = <2>; ti,irqs-reserved = <0 1 2 3 5 6 131 132>; ti,irqs-skip = <10 133 139 140>; ti,irqs-safe-map = <0>; }; }; }; Loading
drivers/irqchip/irq-crossbar.c +143 −25 Original line number Diff line number Diff line Loading @@ -15,18 +15,27 @@ #include <linux/of_irq.h> #include <linux/slab.h> #include <linux/irqchip/arm-gic.h> #include <linux/irqchip/irq-crossbar.h> #define IRQ_FREE -1 #define IRQ_RESERVED -2 #define IRQ_SKIP -3 #define GIC_IRQ_START 32 /* /** * struct crossbar_device - crossbar device description * @int_max: maximum number of supported interrupts * @safe_map: safe default value to initialize the crossbar * @max_crossbar_sources: Maximum number of crossbar sources * @irq_map: array of interrupts to crossbar number mapping * @crossbar_base: crossbar base address * @register_offsets: offsets for each irq number * @write: register write function pointer */ struct crossbar_device { uint int_max; uint safe_map; uint max_crossbar_sources; uint *irq_map; void __iomem *crossbar_base; int *register_offsets; Loading @@ -50,11 +59,22 @@ static inline 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 inline int allocate_free_irq(int cb_no) { int i; for (i = 0; i < cb->int_max; i++) { for (i = cb->int_max - 1; i >= 0; i--) { if (cb->irq_map[i] == IRQ_FREE) { cb->irq_map[i] = cb_no; return i; Loading @@ -64,19 +84,47 @@ static inline int allocate_free_irq(int cb_no) return -ENODEV; } static inline bool needs_crossbar_write(irq_hw_number_t hw) { int cb_no; 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; } return false; } static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { if (needs_crossbar_write(hw)) cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]); return 0; } /** * crossbar_domain_unmap - unmap a crossbar<->irq connection * @d: domain of irq to unmap * @irq: virq number * * 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 * unmapped. This is because unmap is called during irq_dispose_mapping(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) { irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq; if (hw > GIC_IRQ_START) if (needs_crossbar_write(hw)) { cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE; cb->write(hw - GIC_IRQ_START, cb->safe_map); } } static int crossbar_domain_xlate(struct irq_domain *d, Loading @@ -85,18 +133,41 @@ static int crossbar_domain_xlate(struct irq_domain *d, unsigned long *out_hwirq, unsigned int *out_type) { unsigned long ret; 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 = allocate_free_irq(intspec[1]); ret = get_prev_map_irq(req_num); if (ret >= 0) goto found; if (IS_ERR_VALUE(ret)) ret = allocate_free_irq(req_num); if (ret < 0) return ret; found: *out_hwirq = ret + GIC_IRQ_START; return 0; } const struct irq_domain_ops routable_irq_domain_ops = { static const struct irq_domain_ops routable_irq_domain_ops = { .map = crossbar_domain_map, .unmap = crossbar_domain_unmap, .xlate = crossbar_domain_xlate Loading @@ -104,22 +175,36 @@ const struct irq_domain_ops routable_irq_domain_ops = { static int __init crossbar_of_init(struct device_node *node) { int i, size, max, reserved = 0, entry; int i, size, max = 0, reserved = 0, entry; const __be32 *irqsr; int ret = -ENOMEM; cb = kzalloc(sizeof(*cb), GFP_KERNEL); if (!cb) return -ENOMEM; return ret; cb->crossbar_base = of_iomap(node, 0); if (!cb->crossbar_base) goto err1; goto err_cb; of_property_read_u32(node, "ti,max-crossbar-sources", &cb->max_crossbar_sources); if (!cb->max_crossbar_sources) { pr_err("missing 'ti,max-crossbar-sources' property\n"); ret = -EINVAL; goto err_base; } of_property_read_u32(node, "ti,max-irqs", &max); cb->irq_map = kzalloc(max * sizeof(int), GFP_KERNEL); if (!max) { pr_err("missing 'ti,max-irqs' property\n"); ret = -EINVAL; goto err_base; } cb->irq_map = kcalloc(max, sizeof(int), GFP_KERNEL); if (!cb->irq_map) goto err2; goto err_base; cb->int_max = max; Loading @@ -137,15 +222,35 @@ static int __init crossbar_of_init(struct device_node *node) i, &entry); if (entry > max) { pr_err("Invalid reserved entry\n"); goto err3; ret = -EINVAL; goto err_irq_map; } cb->irq_map[entry] = 0; cb->irq_map[entry] = IRQ_RESERVED; } } cb->register_offsets = kzalloc(max * sizeof(int), GFP_KERNEL); /* Skip irqs hardwired to bypass the crossbar */ irqsr = of_get_property(node, "ti,irqs-skip", &size); if (irqsr) { size /= sizeof(__be32); for (i = 0; i < size; i++) { of_property_read_u32_index(node, "ti,irqs-skip", i, &entry); if (entry > max) { pr_err("Invalid skip entry\n"); ret = -EINVAL; goto err_irq_map; } cb->irq_map[entry] = IRQ_SKIP; } } cb->register_offsets = kcalloc(max, sizeof(int), GFP_KERNEL); if (!cb->register_offsets) goto err3; goto err_irq_map; of_property_read_u32(node, "ti,reg-size", &size); Loading @@ -161,7 +266,8 @@ static int __init crossbar_of_init(struct device_node *node) break; default: pr_err("Invalid reg-size property\n"); goto err4; ret = -EINVAL; goto err_reg_offset; break; } Loading @@ -170,25 +276,37 @@ static int __init crossbar_of_init(struct device_node *node) * reserved irqs. so find and store the offsets once. */ for (i = 0; i < max; i++) { if (!cb->irq_map[i]) if (cb->irq_map[i] == IRQ_RESERVED) continue; cb->register_offsets[i] = reserved; reserved += size; } of_property_read_u32(node, "ti,irqs-safe-map", &cb->safe_map); /* Initialize the crossbar with safe map to start with */ for (i = 0; i < max; i++) { if (cb->irq_map[i] == IRQ_RESERVED || cb->irq_map[i] == IRQ_SKIP) continue; cb->write(i, cb->safe_map); } register_routable_domain_ops(&routable_irq_domain_ops); return 0; err4: err_reg_offset: kfree(cb->register_offsets); err3: err_irq_map: kfree(cb->irq_map); err2: err_base: iounmap(cb->crossbar_base); err1: err_cb: kfree(cb); return -ENOMEM; cb = NULL; return ret; } static const struct of_device_id crossbar_match[] __initconst = { Loading