From 886a451bd2491de3551c2aea2a2f155f159716c8 Mon Sep 17 00:00:00 2001 From: David Brown Date: Tue, 2 Aug 2011 09:02:49 -0700 Subject: [PATCH 01/13] msm_serial: Use relative resources for iomem Device tree iomem resources are only accessible by index, and not by name. The msm_serial devices always have either 1 or 2 iomem resources, that are always in the same order. Convert the platform_get_resource_byname into just platform_get_resource to facilitate device tree conversion. Change-Id: I4fd0f1037e07f2725a2a25c7b07dea2ca9397db7 Signed-off-by: David Brown --- drivers/tty/serial/msm_serial.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index e6ba83876508..d9863b2c2bc8 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -589,9 +589,8 @@ static void msm_release_port(struct uart_port *port) iowrite32(GSBI_PROTOCOL_IDLE, msm_port->gsbi_base + GSBI_CONTROL); - gsbi_resource = platform_get_resource_byname(pdev, - IORESOURCE_MEM, - "gsbi_resource"); + gsbi_resource = platform_get_resource(pdev, + IORESOURCE_MEM, 1); if (unlikely(!gsbi_resource)) return; @@ -612,8 +611,7 @@ static int msm_request_port(struct uart_port *port) resource_size_t size; int ret; - uart_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "uart_resource"); + uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!uart_resource)) return -ENXIO; @@ -628,8 +626,7 @@ static int msm_request_port(struct uart_port *port) goto fail_release_port; } - gsbi_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "gsbi_resource"); + gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1); /* Is this a GSBI-based port? */ if (gsbi_resource) { size = resource_size(gsbi_resource); @@ -875,7 +872,7 @@ static int __init msm_serial_probe(struct platform_device *pdev) port->dev = &pdev->dev; msm_port = UART_TO_MSM(port); - if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsbi_resource")) + if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) msm_port->is_uartdm = 1; else msm_port->is_uartdm = 0; @@ -899,8 +896,7 @@ static int __init msm_serial_probe(struct platform_device *pdev) printk(KERN_INFO "uartclk = %d\n", port->uartclk); - resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "uart_resource"); + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!resource)) return -ENXIO; port->mapbase = resource->start; From cfdad2aba7398021f6eec415b9271b9cb40065f9 Mon Sep 17 00:00:00 2001 From: David Brown Date: Thu, 4 Aug 2011 01:55:24 -0700 Subject: [PATCH 02/13] msm_serial: Add devicetree support Add devicetree support to the msm_serial driver. Clocks are still queried by direct name from the driver until device tree clock support is implemented. Change-Id: Ia6b2ddfcf1e5dc3bd25dd502662f971202e6d56f Signed-off-by: David Brown Acked-by: Arnd Bergmann --- .../bindings/tty/serial/msm_serial.txt | 27 +++++++++++++++++++ drivers/tty/serial/msm_serial.c | 14 ++++++++++ 2 files changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/tty/serial/msm_serial.txt diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial.txt new file mode 100644 index 000000000000..aef383eb8876 --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/msm_serial.txt @@ -0,0 +1,27 @@ +* Qualcomm MSM UART + +Required properties: +- compatible : + - "qcom,msm-uart", and one of "qcom,msm-hsuart" or + "qcom,msm-lsuart". +- reg : offset and length of the register set for the device + for the hsuart operating in compatible mode, there should be a + second pair describing the gsbi registers. +- interrupts : should contain the uart interrupt. + +There are two different UART blocks used in MSM devices, +"qcom,msm-hsuart" and "qcom,msm-lsuart". The msm-serial driver is +able to handle both of these, and matches against the "qcom,msm-uart" +as the compatibility. + +The registers for the "qcom,msm-hsuart" device need to specify both +register blocks, even for the common driver. + +Example: + + uart@19c400000 { + compatible = "qcom,msm-hsuart", "qcom,msm-uart"; + reg = <0x19c40000 0x1000>, + <0x19c00000 0x1000>; + interrupts = <195>; + }; diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index d9863b2c2bc8..776790272454 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -19,6 +19,7 @@ # define SUPPORT_SYSRQ #endif +#include #include #include #include @@ -33,6 +34,8 @@ #include #include #include +#include +#include #include "msm_serial.h" @@ -856,6 +859,8 @@ static struct uart_driver msm_uart_driver = { .cons = MSM_CONSOLE, }; +static atomic_t msm_uart_next_id = ATOMIC_INIT(0); + static int __init msm_serial_probe(struct platform_device *pdev) { struct msm_port *msm_port; @@ -863,6 +868,9 @@ static int __init msm_serial_probe(struct platform_device *pdev) struct uart_port *port; int irq; + if (pdev->id == -1) + pdev->id = atomic_inc_return(&msm_uart_next_id) - 1; + if (unlikely(pdev->id < 0 || pdev->id >= UART_NR)) return -ENXIO; @@ -920,11 +928,17 @@ static int __devexit msm_serial_remove(struct platform_device *pdev) return 0; } +static struct of_device_id msm_match_table[] = { + { .compatible = "qcom,msm-uart" }, + {} +}; + static struct platform_driver msm_platform_driver = { .remove = msm_serial_remove, .driver = { .name = "msm_serial", .owner = THIS_MODULE, + .of_match_table = msm_match_table, }, }; From 56e2d8a68803be438211130f58ff02c277a2daaf Mon Sep 17 00:00:00 2001 From: David Brown Date: Thu, 4 Aug 2011 02:01:02 -0700 Subject: [PATCH 03/13] ARM: msm: Add devicetree support for msm8660-surf Adds support for booting via device tree with a simple serial console. Change-Id: I7f175b8db21928cd13e0fb49f3eed74966a2696f Signed-off-by: David Brown Acked-by: Arnd Bergmann --- arch/arm/boot/dts/msm8660-surf.dts | 24 +++++++++++++ arch/arm/mach-msm/board-msm8x60.c | 58 ++++++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 arch/arm/boot/dts/msm8660-surf.dts diff --git a/arch/arm/boot/dts/msm8660-surf.dts b/arch/arm/boot/dts/msm8660-surf.dts new file mode 100644 index 000000000000..15ded0deaa79 --- /dev/null +++ b/arch/arm/boot/dts/msm8660-surf.dts @@ -0,0 +1,24 @@ +/dts-v1/; + +/include/ "skeleton.dtsi" + +/ { + model = "Qualcomm MSM8660 SURF"; + compatible = "qcom,msm8660-surf", "qcom,msm8660"; + interrupt-parent = <&intc>; + + intc: interrupt-controller@02080000 { + compatible = "qcom,msm-8660-qgic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = < 0x02080000 0x1000 >, + < 0x02081000 0x1000 >; + }; + + serial@19c400000 { + compatible = "qcom,msm-hsuart", "qcom,msm-uart"; + reg = <0x19c40000 0x1000>, + <0x19c00000 0x1000>; + interrupts = <195>; + }; +}; diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c index 1163b6fd05d2..10fa8f6e32c9 100644 --- a/arch/arm/mach-msm/board-msm8x60.c +++ b/arch/arm/mach-msm/board-msm8x60.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2010, 2011, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -8,18 +8,16 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * */ #include #include #include #include +#include +#include +#include +#include #include #include @@ -64,6 +62,41 @@ static void __init msm8x60_init(void) { } +#ifdef CONFIG_OF +static struct of_dev_auxdata msm_auxdata_lookup[] __initdata = { + {} +}; + +static struct of_device_id msm_dt_gic_match[] __initdata = { + { .compatible = "qcom,msm-8660-qgic", }, + {} +}; + +static void __init msm8x60_dt_init(void) +{ + struct device_node *node; + + node = of_find_matching_node_by_address(NULL, msm_dt_gic_match, + MSM8X60_QGIC_DIST_PHYS); + if (node) + irq_domain_add_simple(node, GIC_SPI_START); + + if (of_machine_is_compatible("qcom,msm8660-surf")) { + printk(KERN_INFO "Init surf UART registers\n"); + msm8x60_init_uart12dm(); + } + + of_platform_populate(NULL, of_default_bus_match_table, + msm_auxdata_lookup, NULL); +} + +static const char *msm8x60_fluid_match[] __initdata = { + "qcom,msm8660-fluid", + "qcom,msm8660-surf", + NULL +}; +#endif /* CONFIG_OF */ + MACHINE_START(MSM8X60_RUMI3, "QCT MSM8X60 RUMI3") .map_io = msm8x60_map_io, .init_irq = msm8x60_init_irq, @@ -91,3 +124,14 @@ MACHINE_START(MSM8X60_FFA, "QCT MSM8X60 FFA") .init_machine = msm8x60_init, .timer = &msm_timer, MACHINE_END + +#ifdef CONFIG_OF +/* TODO: General device tree support for all MSM. */ +DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)") + .map_io = msm8x60_map_io, + .init_irq = msm8x60_init_irq, + .init_machine = msm8x60_dt_init, + .timer = &msm_timer, + .dt_compat = msm8x60_fluid_match, +MACHINE_END +#endif /* CONFIG_OF */ From 73d2b4cdfc09a7a858b3ea1f32f6218b21439b96 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 17 Oct 2011 08:42:16 +0800 Subject: [PATCH 04/13] arm/mx5: add device tree support for imx53 boards It adds device tree support for imx53 boards. Signed-off-by: Shawn Guo Acked-by: Grant Likely Acked-by: Sascha Hauer Signed-off-by: Sascha Hauer --- Documentation/devicetree/bindings/arm/fsl.txt | 15 + arch/arm/boot/dts/imx53-ard.dts | 113 +++++++ arch/arm/boot/dts/imx53-evk.dts | 120 +++++++ arch/arm/boot/dts/imx53-qsb.dts | 125 ++++++++ arch/arm/boot/dts/imx53-smd.dts | 169 ++++++++++ arch/arm/boot/dts/imx53.dtsi | 301 ++++++++++++++++++ arch/arm/mach-mx5/Kconfig | 12 + arch/arm/mach-mx5/Makefile | 2 + arch/arm/mach-mx5/board-mx53_ard.c | 12 +- arch/arm/mach-mx5/board-mx53_evk.c | 9 +- arch/arm/mach-mx5/board-mx53_loco.c | 9 +- arch/arm/mach-mx5/board-mx53_smd.c | 9 +- arch/arm/mach-mx5/clock-mx51-mx53.c | 31 ++ arch/arm/mach-mx5/imx53-dt.c | 126 ++++++++ arch/arm/plat-mxc/include/mach/common.h | 6 + 15 files changed, 1049 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/fsl.txt create mode 100644 arch/arm/boot/dts/imx53-ard.dts create mode 100644 arch/arm/boot/dts/imx53-evk.dts create mode 100644 arch/arm/boot/dts/imx53-qsb.dts create mode 100644 arch/arm/boot/dts/imx53-smd.dts create mode 100644 arch/arm/boot/dts/imx53.dtsi create mode 100644 arch/arm/mach-mx5/imx53-dt.c diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt new file mode 100644 index 000000000000..d1e8d6f797ef --- /dev/null +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -0,0 +1,15 @@ +i.MX53 Automotive Reference Design Board +Required root node properties: + - compatible = "fsl,imx53-ard", "fsl,imx53"; + +i.MX53 Evaluation Kit +Required root node properties: + - compatible = "fsl,imx53-evk", "fsl,imx53"; + +i.MX53 Quick Start Board +Required root node properties: + - compatible = "fsl,imx53-qsb", "fsl,imx53"; + +i.MX53 Smart Mobile Reference Design Board +Required root node properties: + - compatible = "fsl,imx53-smd", "fsl,imx53"; diff --git a/arch/arm/boot/dts/imx53-ard.dts b/arch/arm/boot/dts/imx53-ard.dts new file mode 100644 index 000000000000..2ab7f80a0a35 --- /dev/null +++ b/arch/arm/boot/dts/imx53-ard.dts @@ -0,0 +1,113 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "imx53.dtsi" + +/ { + model = "Freescale i.MX53 Automotive Reference Design Board"; + compatible = "fsl,imx53-ard", "fsl,imx53"; + + chosen { + bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; + }; + + memory { + reg = <0x70000000 0x40000000>; + }; + + soc { + aips@50000000 { /* AIPS1 */ + spba@50000000 { + esdhc@50004000 { /* ESDHC1 */ + cd-gpios = <&gpio0 1 0>; /* GPIO1_1 */ + wp-gpios = <&gpio0 9 0>; /* GPIO1_9 */ + status = "okay"; + }; + }; + + wdog@53f98000 { /* WDOG1 */ + status = "okay"; + }; + + iomuxc@53fa8000 { + compatible = "fsl,imx53-iomuxc-ard"; + reg = <0x53fa8000 0x4000>; + }; + + uart0: uart@53fbc000 { /* UART1 */ + status = "okay"; + }; + }; + + aips@60000000 { /* AIPS2 */ + sdma@63fb0000 { + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx53.bin"; + }; + }; + }; + + eim-cs1@f4000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eim-bus", "simple-bus"; + reg = <0xf4000000 0x3ff0000>; + ranges; + + lan9220@f4000000 { + compatible = "smsc,lan9220", "smsc,lan9115"; + reg = <0xf4000000 0x2000000>; + phy-mode = "mii"; + interrupt-parent = <&gpio1>; + interrupts = <31>; + reg-io-width = <4>; + smsc,irq-push-pull; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + home { + label = "Home"; + gpios = <&gpio4 10 0>; /* GPIO5_10 */ + linux,code = <102>; /* KEY_HOME */ + gpio-key,wakeup; + }; + + back { + label = "Back"; + gpios = <&gpio4 11 0>; /* GPIO5_11 */ + linux,code = <158>; /* KEY_BACK */ + gpio-key,wakeup; + }; + + program { + label = "Program"; + gpios = <&gpio4 12 0>; /* GPIO5_12 */ + linux,code = <362>; /* KEY_PROGRAM */ + gpio-key,wakeup; + }; + + volume-up { + label = "Volume Up"; + gpios = <&gpio4 13 0>; /* GPIO5_13 */ + linux,code = <115>; /* KEY_VOLUMEUP */ + }; + + volume-down { + label = "Volume Down"; + gpios = <&gpio3 0 0>; /* GPIO4_0 */ + linux,code = <114>; /* KEY_VOLUMEDOWN */ + }; + }; +}; diff --git a/arch/arm/boot/dts/imx53-evk.dts b/arch/arm/boot/dts/imx53-evk.dts new file mode 100644 index 000000000000..3f3a88185ff8 --- /dev/null +++ b/arch/arm/boot/dts/imx53-evk.dts @@ -0,0 +1,120 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "imx53.dtsi" + +/ { + model = "Freescale i.MX53 Evaluation Kit"; + compatible = "fsl,imx53-evk", "fsl,imx53"; + + chosen { + bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; + }; + + memory { + reg = <0x70000000 0x80000000>; + }; + + soc { + aips@50000000 { /* AIPS1 */ + spba@50000000 { + esdhc@50004000 { /* ESDHC1 */ + cd-gpios = <&gpio2 13 0>; /* GPIO3_13 */ + wp-gpios = <&gpio2 14 0>; /* GPIO3_14 */ + status = "okay"; + }; + + ecspi@50010000 { /* ECSPI1 */ + fsl,spi-num-chipselects = <2>; + cs-gpios = <&gpio1 30 0>, /* GPIO2_30 */ + <&gpio2 19 0>; /* GPIO3_19 */ + status = "okay"; + + flash: at45db321d@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "atmel,at45db321d", "atmel,at45", "atmel,dataflash"; + spi-max-frequency = <25000000>; + reg = <1>; + + partition@0 { + label = "U-Boot"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "Kernel"; + reg = <0x40000 0x3c0000>; + }; + }; + }; + + esdhc@50020000 { /* ESDHC3 */ + cd-gpios = <&gpio2 11 0>; /* GPIO3_11 */ + wp-gpios = <&gpio2 12 0>; /* GPIO3_12 */ + status = "okay"; + }; + }; + + wdog@53f98000 { /* WDOG1 */ + status = "okay"; + }; + + iomuxc@53fa8000 { + compatible = "fsl,imx53-iomuxc-evk"; + reg = <0x53fa8000 0x4000>; + }; + + uart0: uart@53fbc000 { /* UART1 */ + status = "okay"; + }; + }; + + aips@60000000 { /* AIPS2 */ + sdma@63fb0000 { + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx53.bin"; + }; + + i2c@63fc4000 { /* I2C2 */ + status = "okay"; + + pmic: mc13892@08 { + compatible = "fsl,mc13892", "fsl,mc13xxx"; + reg = <0x08>; + }; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + }; + }; + + fec@63fec000 { + phy-mode = "rmii"; + phy-reset-gpios = <&gpio6 6 0>; /* GPIO7_6 */ + status = "okay"; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + green { + label = "Heartbeat"; + gpios = <&gpio6 7 0>; /* GPIO7_7 */ + linux,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts new file mode 100644 index 000000000000..ae6de6d0c3f1 --- /dev/null +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -0,0 +1,125 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "imx53.dtsi" + +/ { + model = "Freescale i.MX53 Quick Start Board"; + compatible = "fsl,imx53-qsb", "fsl,imx53"; + + chosen { + bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; + }; + + memory { + reg = <0x70000000 0x40000000>; + }; + + soc { + aips@50000000 { /* AIPS1 */ + spba@50000000 { + esdhc@50004000 { /* ESDHC1 */ + cd-gpios = <&gpio2 13 0>; /* GPIO3_13 */ + status = "okay"; + }; + + esdhc@50020000 { /* ESDHC3 */ + cd-gpios = <&gpio2 11 0>; /* GPIO3_11 */ + wp-gpios = <&gpio2 12 0>; /* GPIO3_12 */ + status = "okay"; + }; + }; + + wdog@53f98000 { /* WDOG1 */ + status = "okay"; + }; + + iomuxc@53fa8000 { + compatible = "fsl,imx53-iomuxc-qsb"; + reg = <0x53fa8000 0x4000>; + }; + + uart0: uart@53fbc000 { /* UART1 */ + status = "okay"; + }; + }; + + aips@60000000 { /* AIPS2 */ + sdma@63fb0000 { + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx53.bin"; + }; + + i2c@63fc4000 { /* I2C2 */ + status = "okay"; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + }; + }; + + i2c@63fc8000 { /* I2C1 */ + status = "okay"; + + accelerometer: mma8450@1c { + compatible = "fsl,mma8450"; + reg = <0x1c>; + }; + + pmic: dialog@48 { + compatible = "dialog,da9053", "dialog,da9052"; + reg = <0x48>; + }; + }; + + fec@63fec000 { + phy-mode = "rmii"; + phy-reset-gpios = <&gpio6 6 0>; /* GPIO7_6 */ + status = "okay"; + }; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + power { + label = "Power Button"; + gpios = <&gpio0 8 0>; /* GPIO1_8 */ + linux,code = <116>; /* KEY_POWER */ + gpio-key,wakeup; + }; + + volume-up { + label = "Volume Up"; + gpios = <&gpio1 14 0>; /* GPIO2_14 */ + linux,code = <115>; /* KEY_VOLUMEUP */ + }; + + volume-down { + label = "Volume Down"; + gpios = <&gpio1 15 0>; /* GPIO2_15 */ + linux,code = <114>; /* KEY_VOLUMEDOWN */ + }; + }; + + leds { + compatible = "gpio-leds"; + + user { + label = "Heartbeat"; + gpios = <&gpio6 7 0>; /* GPIO7_7 */ + linux,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx53-smd.dts b/arch/arm/boot/dts/imx53-smd.dts new file mode 100644 index 000000000000..b1c062eea715 --- /dev/null +++ b/arch/arm/boot/dts/imx53-smd.dts @@ -0,0 +1,169 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "imx53.dtsi" + +/ { + model = "Freescale i.MX53 Smart Mobile Reference Design Board"; + compatible = "fsl,imx53-smd", "fsl,imx53"; + + chosen { + bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; + }; + + memory { + reg = <0x70000000 0x40000000>; + }; + + soc { + aips@50000000 { /* AIPS1 */ + spba@50000000 { + esdhc@50004000 { /* ESDHC1 */ + cd-gpios = <&gpio2 13 0>; /* GPIO3_13 */ + wp-gpios = <&gpio3 11 0>; /* GPIO4_11 */ + status = "okay"; + }; + + esdhc@50008000 { /* ESDHC2 */ + fsl,card-wired; + status = "okay"; + }; + + uart2: uart@5000c000 { /* UART3 */ + fsl,uart-has-rtscts; + status = "okay"; + }; + + ecspi@50010000 { /* ECSPI1 */ + fsl,spi-num-chipselects = <2>; + cs-gpios = <&gpio1 30 0>, /* GPIO2_30 */ + <&gpio2 19 0>; /* GPIO3_19 */ + status = "okay"; + + zigbee: mc1323@0 { + compatible = "fsl,mc1323"; + spi-max-frequency = <8000000>; + reg = <0>; + }; + + flash: m25p32@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p32", "st,m25p"; + spi-max-frequency = <20000000>; + reg = <1>; + + partition@0 { + label = "U-Boot"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "Kernel"; + reg = <0x40000 0x3c0000>; + }; + }; + }; + + esdhc@50020000 { /* ESDHC3 */ + fsl,card-wired; + status = "okay"; + }; + }; + + wdog@53f98000 { /* WDOG1 */ + status = "okay"; + }; + + iomuxc@53fa8000 { + compatible = "fsl,imx53-iomuxc-smd"; + reg = <0x53fa8000 0x4000>; + }; + + uart0: uart@53fbc000 { /* UART1 */ + status = "okay"; + }; + + uart1: uart@53fc0000 { /* UART2 */ + status = "okay"; + }; + }; + + aips@60000000 { /* AIPS2 */ + sdma@63fb0000 { + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx53.bin"; + }; + + i2c@63fc4000 { /* I2C2 */ + status = "okay"; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + }; + + magnetometer: mag3110@0e { + compatible = "fsl,mag3110"; + reg = <0x0e>; + }; + + touchkey: mpr121@5a { + compatible = "fsl,mpr121"; + reg = <0x5a>; + }; + }; + + i2c@63fc8000 { /* I2C1 */ + status = "okay"; + + accelerometer: mma8450@1c { + compatible = "fsl,mma8450"; + reg = <0x1c>; + }; + + camera: ov5642@3c { + compatible = "ovti,ov5642"; + reg = <0x3c>; + }; + + pmic: dialog@48 { + compatible = "dialog,da9053", "dialog,da9052"; + reg = <0x48>; + }; + }; + + fec@63fec000 { + phy-mode = "rmii"; + phy-reset-gpios = <&gpio6 6 0>; /* GPIO7_6 */ + status = "okay"; + }; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + volume-up { + label = "Volume Up"; + gpios = <&gpio1 14 0>; /* GPIO2_14 */ + linux,code = <115>; /* KEY_VOLUMEUP */ + }; + + volume-down { + label = "Volume Down"; + gpios = <&gpio1 15 0>; /* GPIO2_15 */ + linux,code = <114>; /* KEY_VOLUMEDOWN */ + }; + }; +}; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi new file mode 100644 index 000000000000..099cd84ee372 --- /dev/null +++ b/arch/arm/boot/dts/imx53.dtsi @@ -0,0 +1,301 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/include/ "skeleton.dtsi" + +/ { + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + }; + + tzic: tz-interrupt-controller@0fffc000 { + compatible = "fsl,imx53-tzic", "fsl,tzic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x0fffc000 0x4000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + ckil { + compatible = "fsl,imx-ckil", "fixed-clock"; + clock-frequency = <32768>; + }; + + ckih1 { + compatible = "fsl,imx-ckih1", "fixed-clock"; + clock-frequency = <22579200>; + }; + + ckih2 { + compatible = "fsl,imx-ckih2", "fixed-clock"; + clock-frequency = <0>; + }; + + osc { + compatible = "fsl,imx-osc", "fixed-clock"; + clock-frequency = <24000000>; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&tzic>; + ranges; + + aips@50000000 { /* AIPS1 */ + compatible = "fsl,aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x50000000 0x10000000>; + ranges; + + spba@50000000 { + compatible = "fsl,spba-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x50000000 0x40000>; + ranges; + + esdhc@50004000 { /* ESDHC1 */ + compatible = "fsl,imx53-esdhc"; + reg = <0x50004000 0x4000>; + interrupts = <1>; + status = "disabled"; + }; + + esdhc@50008000 { /* ESDHC2 */ + compatible = "fsl,imx53-esdhc"; + reg = <0x50008000 0x4000>; + interrupts = <2>; + status = "disabled"; + }; + + uart2: uart@5000c000 { /* UART3 */ + compatible = "fsl,imx53-uart", "fsl,imx21-uart"; + reg = <0x5000c000 0x4000>; + interrupts = <33>; + status = "disabled"; + }; + + ecspi@50010000 { /* ECSPI1 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx53-ecspi", "fsl,imx51-ecspi"; + reg = <0x50010000 0x4000>; + interrupts = <36>; + status = "disabled"; + }; + + esdhc@50020000 { /* ESDHC3 */ + compatible = "fsl,imx53-esdhc"; + reg = <0x50020000 0x4000>; + interrupts = <3>; + status = "disabled"; + }; + + esdhc@50024000 { /* ESDHC4 */ + compatible = "fsl,imx53-esdhc"; + reg = <0x50024000 0x4000>; + interrupts = <4>; + status = "disabled"; + }; + }; + + gpio0: gpio@53f84000 { /* GPIO1 */ + compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + reg = <0x53f84000 0x4000>; + interrupts = <50 51>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio1: gpio@53f88000 { /* GPIO2 */ + compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + reg = <0x53f88000 0x4000>; + interrupts = <52 53>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio2: gpio@53f8c000 { /* GPIO3 */ + compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + reg = <0x53f8c000 0x4000>; + interrupts = <54 55>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio3: gpio@53f90000 { /* GPIO4 */ + compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + reg = <0x53f90000 0x4000>; + interrupts = <56 57>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + wdog@53f98000 { /* WDOG1 */ + compatible = "fsl,imx53-wdt", "fsl,imx21-wdt"; + reg = <0x53f98000 0x4000>; + interrupts = <58>; + status = "disabled"; + }; + + wdog@53f9c000 { /* WDOG2 */ + compatible = "fsl,imx53-wdt", "fsl,imx21-wdt"; + reg = <0x53f9c000 0x4000>; + interrupts = <59>; + status = "disabled"; + }; + + uart0: uart@53fbc000 { /* UART1 */ + compatible = "fsl,imx53-uart", "fsl,imx21-uart"; + reg = <0x53fbc000 0x4000>; + interrupts = <31>; + status = "disabled"; + }; + + uart1: uart@53fc0000 { /* UART2 */ + compatible = "fsl,imx53-uart", "fsl,imx21-uart"; + reg = <0x53fc0000 0x4000>; + interrupts = <32>; + status = "disabled"; + }; + + gpio4: gpio@53fdc000 { /* GPIO5 */ + compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + reg = <0x53fdc000 0x4000>; + interrupts = <103 104>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio5: gpio@53fe0000 { /* GPIO6 */ + compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + reg = <0x53fe0000 0x4000>; + interrupts = <105 106>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio6: gpio@53fe4000 { /* GPIO7 */ + compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + reg = <0x53fe4000 0x4000>; + interrupts = <107 108>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + i2c@53fec000 { /* I2C3 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx53-i2c", "fsl,imx1-i2c"; + reg = <0x53fec000 0x4000>; + interrupts = <64>; + status = "disabled"; + }; + + uart3: uart@53ff0000 { /* UART4 */ + compatible = "fsl,imx53-uart", "fsl,imx21-uart"; + reg = <0x53ff0000 0x4000>; + interrupts = <13>; + status = "disabled"; + }; + }; + + aips@60000000 { /* AIPS2 */ + compatible = "fsl,aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x60000000 0x10000000>; + ranges; + + uart4: uart@63f90000 { /* UART5 */ + compatible = "fsl,imx53-uart", "fsl,imx21-uart"; + reg = <0x63f90000 0x4000>; + interrupts = <86>; + status = "disabled"; + }; + + ecspi@63fac000 { /* ECSPI2 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx53-ecspi", "fsl,imx51-ecspi"; + reg = <0x63fac000 0x4000>; + interrupts = <37>; + status = "disabled"; + }; + + sdma@63fb0000 { + compatible = "fsl,imx53-sdma", "fsl,imx35-sdma"; + reg = <0x63fb0000 0x4000>; + interrupts = <6>; + }; + + cspi@63fc0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx53-cspi", "fsl,imx35-cspi"; + reg = <0x63fc0000 0x4000>; + interrupts = <38>; + status = "disabled"; + }; + + i2c@63fc4000 { /* I2C2 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx53-i2c", "fsl,imx1-i2c"; + reg = <0x63fc4000 0x4000>; + interrupts = <63>; + status = "disabled"; + }; + + i2c@63fc8000 { /* I2C1 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx53-i2c", "fsl,imx1-i2c"; + reg = <0x63fc8000 0x4000>; + interrupts = <62>; + status = "disabled"; + }; + + fec@63fec000 { + compatible = "fsl,imx53-fec", "fsl,imx25-fec"; + reg = <0x63fec000 0x4000>; + interrupts = <87>; + status = "disabled"; + }; + }; + }; +}; diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index b4e7c58bbb38..0ac676c5256d 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig @@ -172,6 +172,18 @@ endif # ARCH_MX51 if ARCH_MX53_SUPPORTED comment "i.MX53 machines:" +config MACH_IMX53_DT + bool "Support i.MX53 platforms from device tree" + select SOC_IMX53 + select USE_OF + select MACH_MX53_ARD + select MACH_MX53_EVK + select MACH_MX53_LOCO + select MACH_MX53_SMD + help + Include support for Freescale i.MX53 based platforms + using the device tree for discovery + config MACH_MX53_EVK bool "Support MX53 EVK platforms" select SOC_IMX53 diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile index 383e7cd3fbcb..3dbe5e26a51b 100644 --- a/arch/arm/mach-mx5/Makefile +++ b/arch/arm/mach-mx5/Makefile @@ -22,3 +22,5 @@ obj-$(CONFIG_MX51_EFIKA_COMMON) += mx51_efika.o obj-$(CONFIG_MACH_MX51_EFIKAMX) += board-mx51_efikamx.o obj-$(CONFIG_MACH_MX51_EFIKASB) += board-mx51_efikasb.o obj-$(CONFIG_MACH_MX50_RDP) += board-mx50_rdp.o + +obj-$(CONFIG_MACH_IMX53_DT) += imx53-dt.o diff --git a/arch/arm/mach-mx5/board-mx53_ard.c b/arch/arm/mach-mx5/board-mx53_ard.c index 76a67c4a2a0b..9b4395d7a07c 100644 --- a/arch/arm/mach-mx5/board-mx53_ard.c +++ b/arch/arm/mach-mx5/board-mx53_ard.c @@ -171,9 +171,6 @@ static struct imxi2c_platform_data mx53_ard_i2c3_data = { static void __init mx53_ard_io_init(void) { - mxc_iomux_v3_setup_multiple_pads(mx53_ard_pads, - ARRAY_SIZE(mx53_ard_pads)); - gpio_request(ARD_ETHERNET_INT_B, "eth-int-b"); gpio_direction_input(ARD_ETHERNET_INT_B); @@ -216,6 +213,13 @@ static int weim_cs_config(void) return 0; } +void __init imx53_ard_common_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53_ard_pads, + ARRAY_SIZE(mx53_ard_pads)); + weim_cs_config(); +} + static struct platform_device *devices[] __initdata = { &ard_smsc_lan9220_device, }; @@ -225,8 +229,8 @@ static void __init mx53_ard_board_init(void) imx53_soc_init(); imx53_add_imx_uart(0, NULL); + imx53_ard_common_init(); mx53_ard_io_init(); - weim_cs_config(); platform_add_devices(devices, ARRAY_SIZE(devices)); imx53_add_sdhci_esdhc_imx(0, &mx53_ard_sd1_data); diff --git a/arch/arm/mach-mx5/board-mx53_evk.c b/arch/arm/mach-mx5/board-mx53_evk.c index 1b417b06b736..7663905d5c6d 100644 --- a/arch/arm/mach-mx5/board-mx53_evk.c +++ b/arch/arm/mach-mx5/board-mx53_evk.c @@ -131,12 +131,17 @@ static const struct spi_imx_master mx53_evk_spi_data __initconst = { .num_chipselect = ARRAY_SIZE(mx53_evk_spi_cs), }; +void __init imx53_evk_common_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53_evk_pads, + ARRAY_SIZE(mx53_evk_pads)); +} + static void __init mx53_evk_board_init(void) { imx53_soc_init(); + imx53_evk_common_init(); - mxc_iomux_v3_setup_multiple_pads(mx53_evk_pads, - ARRAY_SIZE(mx53_evk_pads)); mx53_evk_init_uart(); mx53_evk_fec_reset(); imx53_add_fec(&mx53_evk_fec_pdata); diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c index 4e1d51d252dc..3922cd5ea854 100644 --- a/arch/arm/mach-mx5/board-mx53_loco.c +++ b/arch/arm/mach-mx5/board-mx53_loco.c @@ -257,12 +257,17 @@ static const struct gpio_led_platform_data mx53loco_leds_data __initconst = { .num_leds = ARRAY_SIZE(mx53loco_leds), }; +void __init imx53_qsb_common_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53_loco_pads, + ARRAY_SIZE(mx53_loco_pads)); +} + static void __init mx53_loco_board_init(void) { imx53_soc_init(); + imx53_qsb_common_init(); - mxc_iomux_v3_setup_multiple_pads(mx53_loco_pads, - ARRAY_SIZE(mx53_loco_pads)); imx53_add_imx_uart(0, NULL); mx53_loco_fec_reset(); imx53_add_fec(&mx53_loco_fec_data); diff --git a/arch/arm/mach-mx5/board-mx53_smd.c b/arch/arm/mach-mx5/board-mx53_smd.c index bc02894eafef..b10c89982fbc 100644 --- a/arch/arm/mach-mx5/board-mx53_smd.c +++ b/arch/arm/mach-mx5/board-mx53_smd.c @@ -111,12 +111,17 @@ static const struct imxi2c_platform_data mx53_smd_i2c_data __initconst = { .bitrate = 100000, }; +void __init imx53_smd_common_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53_smd_pads, + ARRAY_SIZE(mx53_smd_pads)); +} + static void __init mx53_smd_board_init(void) { imx53_soc_init(); + imx53_smd_common_init(); - mxc_iomux_v3_setup_multiple_pads(mx53_smd_pads, - ARRAY_SIZE(mx53_smd_pads)); mx53_smd_init_uart(); mx53_smd_fec_reset(); imx53_add_fec(&mx53_smd_fec_data); diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c index f7bf996f463b..d9b03d4dba6d 100644 --- a/arch/arm/mach-mx5/clock-mx51-mx53.c +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -1609,3 +1610,33 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, MX53_INT_GPT); return 0; } + +static void __init clk_get_freq_dt(unsigned long *ckil, unsigned long *osc, + unsigned long *ckih1, unsigned long *ckih2) +{ + struct device_node *np; + + /* retrieve the freqency of fixed clocks from device tree */ + for_each_compatible_node(np, NULL, "fixed-clock") { + u32 rate; + if (of_property_read_u32(np, "clock-frequency", &rate)) + continue; + + if (of_device_is_compatible(np, "fsl,imx-ckil")) + *ckil = rate; + else if (of_device_is_compatible(np, "fsl,imx-osc")) + *osc = rate; + else if (of_device_is_compatible(np, "fsl,imx-ckih1")) + *ckih1 = rate; + else if (of_device_is_compatible(np, "fsl,imx-ckih2")) + *ckih2 = rate; + } +} + +int __init mx53_clocks_init_dt(void) +{ + unsigned long ckil, osc, ckih1, ckih2; + + clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); + return mx53_clocks_init(ckil, osc, ckih1, ckih2); +} diff --git a/arch/arm/mach-mx5/imx53-dt.c b/arch/arm/mach-mx5/imx53-dt.c new file mode 100644 index 000000000000..ccaa0b81b768 --- /dev/null +++ b/arch/arm/mach-mx5/imx53-dt.c @@ -0,0 +1,126 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Lookup table for attaching a specific name and platform_data pointer to + * devices as they get created by of_platform_populate(). Ideally this table + * would not exist, but the current clock implementation depends on some devices + * having a specific name. + */ +static const struct of_dev_auxdata imx53_auxdata_lookup[] __initconst = { + OF_DEV_AUXDATA("fsl,imx53-uart", MX53_UART1_BASE_ADDR, "imx21-uart.0", NULL), + OF_DEV_AUXDATA("fsl,imx53-uart", MX53_UART2_BASE_ADDR, "imx21-uart.1", NULL), + OF_DEV_AUXDATA("fsl,imx53-uart", MX53_UART3_BASE_ADDR, "imx21-uart.2", NULL), + OF_DEV_AUXDATA("fsl,imx53-uart", MX53_UART4_BASE_ADDR, "imx21-uart.3", NULL), + OF_DEV_AUXDATA("fsl,imx53-uart", MX53_UART5_BASE_ADDR, "imx21-uart.4", NULL), + OF_DEV_AUXDATA("fsl,imx53-fec", MX53_FEC_BASE_ADDR, "imx25-fec.0", NULL), + OF_DEV_AUXDATA("fsl,imx53-esdhc", MX53_ESDHC1_BASE_ADDR, "sdhci-esdhc-imx53.0", NULL), + OF_DEV_AUXDATA("fsl,imx53-esdhc", MX53_ESDHC2_BASE_ADDR, "sdhci-esdhc-imx53.1", NULL), + OF_DEV_AUXDATA("fsl,imx53-esdhc", MX53_ESDHC3_BASE_ADDR, "sdhci-esdhc-imx53.2", NULL), + OF_DEV_AUXDATA("fsl,imx53-esdhc", MX53_ESDHC4_BASE_ADDR, "sdhci-esdhc-imx53.3", NULL), + OF_DEV_AUXDATA("fsl,imx53-ecspi", MX53_ECSPI1_BASE_ADDR, "imx51-ecspi.0", NULL), + OF_DEV_AUXDATA("fsl,imx53-ecspi", MX53_ECSPI2_BASE_ADDR, "imx51-ecspi.1", NULL), + OF_DEV_AUXDATA("fsl,imx53-cspi", MX53_CSPI_BASE_ADDR, "imx35-cspi.0", NULL), + OF_DEV_AUXDATA("fsl,imx53-i2c", MX53_I2C1_BASE_ADDR, "imx-i2c.0", NULL), + OF_DEV_AUXDATA("fsl,imx53-i2c", MX53_I2C2_BASE_ADDR, "imx-i2c.1", NULL), + OF_DEV_AUXDATA("fsl,imx53-i2c", MX53_I2C3_BASE_ADDR, "imx-i2c.2", NULL), + OF_DEV_AUXDATA("fsl,imx53-sdma", MX53_SDMA_BASE_ADDR, "imx35-sdma", NULL), + OF_DEV_AUXDATA("fsl,imx53-wdt", MX53_WDOG1_BASE_ADDR, "imx2-wdt.0", NULL), + { /* sentinel */ } +}; + +static void __init imx53_tzic_add_irq_domain(struct device_node *np, + struct device_node *interrupt_parent) +{ + irq_domain_add_simple(np, 0); +} + +static void __init imx53_gpio_add_irq_domain(struct device_node *np, + struct device_node *interrupt_parent) +{ + static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS - + 32 * 7; /* imx53 gets 7 gpio ports */ + + irq_domain_add_simple(np, gpio_irq_base); + gpio_irq_base += 32; +} + +static const struct of_device_id imx53_irq_match[] __initconst = { + { .compatible = "fsl,imx53-tzic", .data = imx53_tzic_add_irq_domain, }, + { .compatible = "fsl,imx53-gpio", .data = imx53_gpio_add_irq_domain, }, + { /* sentinel */ } +}; + +static const struct of_device_id imx53_iomuxc_of_match[] __initconst = { + { .compatible = "fsl,imx53-iomuxc-ard", .data = imx53_ard_common_init, }, + { .compatible = "fsl,imx53-iomuxc-evk", .data = imx53_evk_common_init, }, + { .compatible = "fsl,imx53-iomuxc-qsb", .data = imx53_qsb_common_init, }, + { .compatible = "fsl,imx53-iomuxc-smd", .data = imx53_smd_common_init, }, + { /* sentinel */ } +}; + +static void __init imx53_dt_init(void) +{ + struct device_node *node; + const struct of_device_id *of_id; + void (*func)(void); + + of_irq_init(imx53_irq_match); + + node = of_find_matching_node(NULL, imx53_iomuxc_of_match); + if (node) { + of_id = of_match_node(imx53_iomuxc_of_match, node); + func = of_id->data; + func(); + of_node_put(node); + } + + of_platform_populate(NULL, of_default_bus_match_table, + imx53_auxdata_lookup, NULL); +} + +static void __init imx53_timer_init(void) +{ + mx53_clocks_init_dt(); +} + +static struct sys_timer imx53_timer = { + .init = imx53_timer_init, +}; + +static const char *imx53_dt_board_compat[] __initdata = { + "fsl,imx53-ard", + "fsl,imx53-evk", + "fsl,imx53-qsb", + "fsl,imx53-smd", + NULL +}; + +DT_MACHINE_START(IMX53_DT, "Freescale i.MX53 (Device Tree Support)") + .map_io = mx53_map_io, + .init_early = imx53_init_early, + .init_irq = mx53_init_irq, + .handle_irq = imx53_handle_irq, + .timer = &imx53_timer, + .init_machine = imx53_dt_init, + .dt_compat = imx53_dt_board_compat, +MACHINE_END diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 4e3d97890d69..eb3e7c4e2f1a 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -64,6 +64,7 @@ extern int mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); extern int mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); +extern int mx53_clocks_init_dt(void); extern struct platform_device *mxc_register_gpio(char *name, int id, resource_size_t iobase, resource_size_t iosize, int irq, int irq_high); extern int mxc_register_device(struct platform_device *pdev, void *data); @@ -72,4 +73,9 @@ extern void mxc_arch_reset_init(void __iomem *); extern void mx51_efikamx_reset(void); extern int mx53_revision(void); extern int mx53_display_revision(void); + +extern void imx53_ard_common_init(void); +extern void imx53_evk_common_init(void); +extern void imx53_qsb_common_init(void); +extern void imx53_smd_common_init(void); #endif From 9daaf31a8cc9c98751b7b71198307e47d5bf6a4d Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 17 Oct 2011 08:42:17 +0800 Subject: [PATCH 05/13] arm/mx5: add device tree support for imx51 babbage It adds device tree support for imx51 babbage board. Signed-off-by: Shawn Guo Acked-by: Grant Likely Acked-by: Sascha Hauer Signed-off-by: Sascha Hauer --- Documentation/devicetree/bindings/arm/fsl.txt | 4 + arch/arm/boot/dts/imx51-babbage.dts | 135 ++++++++++ arch/arm/boot/dts/imx51.dtsi | 246 ++++++++++++++++++ arch/arm/mach-mx5/Kconfig | 9 + arch/arm/mach-mx5/Makefile | 1 + arch/arm/mach-mx5/board-mx51_babbage.c | 9 +- arch/arm/mach-mx5/clock-mx51-mx53.c | 8 + arch/arm/mach-mx5/imx51-dt.c | 116 +++++++++ arch/arm/plat-mxc/include/mach/common.h | 2 + 9 files changed, 528 insertions(+), 2 deletions(-) create mode 100644 arch/arm/boot/dts/imx51-babbage.dts create mode 100644 arch/arm/boot/dts/imx51.dtsi create mode 100644 arch/arm/mach-mx5/imx51-dt.c diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt index d1e8d6f797ef..e2401cd632ab 100644 --- a/Documentation/devicetree/bindings/arm/fsl.txt +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -1,3 +1,7 @@ +i.MX51 Babbage Board +Required root node properties: + - compatible = "fsl,imx51-babbage", "fsl,imx51"; + i.MX53 Automotive Reference Design Board Required root node properties: - compatible = "fsl,imx53-ard", "fsl,imx53"; diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts new file mode 100644 index 000000000000..f8766af11215 --- /dev/null +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -0,0 +1,135 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "imx51.dtsi" + +/ { + model = "Freescale i.MX51 Babbage Board"; + compatible = "fsl,imx51-babbage", "fsl,imx51"; + + chosen { + bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; + }; + + memory { + reg = <0x90000000 0x20000000>; + }; + + soc { + aips@70000000 { /* aips-1 */ + spba@70000000 { + esdhc@70004000 { /* ESDHC1 */ + fsl,cd-internal; + fsl,wp-internal; + status = "okay"; + }; + + esdhc@70008000 { /* ESDHC2 */ + cd-gpios = <&gpio0 6 0>; /* GPIO1_6 */ + wp-gpios = <&gpio0 5 0>; /* GPIO1_5 */ + status = "okay"; + }; + + uart2: uart@7000c000 { /* UART3 */ + fsl,uart-has-rtscts; + status = "okay"; + }; + + ecspi@70010000 { /* ECSPI1 */ + fsl,spi-num-chipselects = <2>; + cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */ + <&gpio3 25 0>; /* GPIO4_25 */ + status = "okay"; + + pmic: mc13892@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mc13892"; + spi-max-frequency = <6000000>; + reg = <0>; + mc13xxx-irq-gpios = <&gpio0 8 0>; /* GPIO1_8 */ + fsl,mc13xxx-uses-regulator; + }; + + flash: at45db321d@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "atmel,at45db321d", "atmel,at45", "atmel,dataflash"; + spi-max-frequency = <25000000>; + reg = <1>; + + partition@0 { + label = "U-Boot"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "Kernel"; + reg = <0x40000 0x3c0000>; + }; + }; + }; + }; + + wdog@73f98000 { /* WDOG1 */ + status = "okay"; + }; + + iomuxc@73fa8000 { + compatible = "fsl,imx51-iomuxc-babbage"; + reg = <0x73fa8000 0x4000>; + }; + + uart0: uart@73fbc000 { + fsl,uart-has-rtscts; + status = "okay"; + }; + + uart1: uart@73fc0000 { + status = "okay"; + }; + }; + + aips@80000000 { /* aips-2 */ + sdma@83fb0000 { + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx51.bin"; + }; + + i2c@83fc4000 { /* I2C2 */ + status = "okay"; + + codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + }; + }; + + fec@83fec000 { + phy-mode = "mii"; + status = "okay"; + }; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + power { + label = "Power Button"; + gpios = <&gpio1 21 0>; + linux,code = <116>; /* KEY_POWER */ + gpio-key,wakeup; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi new file mode 100644 index 000000000000..327ab8e3a4c8 --- /dev/null +++ b/arch/arm/boot/dts/imx51.dtsi @@ -0,0 +1,246 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/include/ "skeleton.dtsi" + +/ { + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + }; + + tzic: tz-interrupt-controller@e0000000 { + compatible = "fsl,imx51-tzic", "fsl,tzic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xe0000000 0x4000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + ckil { + compatible = "fsl,imx-ckil", "fixed-clock"; + clock-frequency = <32768>; + }; + + ckih1 { + compatible = "fsl,imx-ckih1", "fixed-clock"; + clock-frequency = <22579200>; + }; + + ckih2 { + compatible = "fsl,imx-ckih2", "fixed-clock"; + clock-frequency = <0>; + }; + + osc { + compatible = "fsl,imx-osc", "fixed-clock"; + clock-frequency = <24000000>; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&tzic>; + ranges; + + aips@70000000 { /* AIPS1 */ + compatible = "fsl,aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x70000000 0x10000000>; + ranges; + + spba@70000000 { + compatible = "fsl,spba-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x70000000 0x40000>; + ranges; + + esdhc@70004000 { /* ESDHC1 */ + compatible = "fsl,imx51-esdhc"; + reg = <0x70004000 0x4000>; + interrupts = <1>; + status = "disabled"; + }; + + esdhc@70008000 { /* ESDHC2 */ + compatible = "fsl,imx51-esdhc"; + reg = <0x70008000 0x4000>; + interrupts = <2>; + status = "disabled"; + }; + + uart2: uart@7000c000 { /* UART3 */ + compatible = "fsl,imx51-uart", "fsl,imx21-uart"; + reg = <0x7000c000 0x4000>; + interrupts = <33>; + status = "disabled"; + }; + + ecspi@70010000 { /* ECSPI1 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx51-ecspi"; + reg = <0x70010000 0x4000>; + interrupts = <36>; + status = "disabled"; + }; + + esdhc@70020000 { /* ESDHC3 */ + compatible = "fsl,imx51-esdhc"; + reg = <0x70020000 0x4000>; + interrupts = <3>; + status = "disabled"; + }; + + esdhc@70024000 { /* ESDHC4 */ + compatible = "fsl,imx51-esdhc"; + reg = <0x70024000 0x4000>; + interrupts = <4>; + status = "disabled"; + }; + }; + + gpio0: gpio@73f84000 { /* GPIO1 */ + compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + reg = <0x73f84000 0x4000>; + interrupts = <50 51>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio1: gpio@73f88000 { /* GPIO2 */ + compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + reg = <0x73f88000 0x4000>; + interrupts = <52 53>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio2: gpio@73f8c000 { /* GPIO3 */ + compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + reg = <0x73f8c000 0x4000>; + interrupts = <54 55>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio3: gpio@73f90000 { /* GPIO4 */ + compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + reg = <0x73f90000 0x4000>; + interrupts = <56 57>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + wdog@73f98000 { /* WDOG1 */ + compatible = "fsl,imx51-wdt", "fsl,imx21-wdt"; + reg = <0x73f98000 0x4000>; + interrupts = <58>; + status = "disabled"; + }; + + wdog@73f9c000 { /* WDOG2 */ + compatible = "fsl,imx51-wdt", "fsl,imx21-wdt"; + reg = <0x73f9c000 0x4000>; + interrupts = <59>; + status = "disabled"; + }; + + uart0: uart@73fbc000 { + compatible = "fsl,imx51-uart", "fsl,imx21-uart"; + reg = <0x73fbc000 0x4000>; + interrupts = <31>; + status = "disabled"; + }; + + uart1: uart@73fc0000 { + compatible = "fsl,imx51-uart", "fsl,imx21-uart"; + reg = <0x73fc0000 0x4000>; + interrupts = <32>; + status = "disabled"; + }; + }; + + aips@80000000 { /* AIPS2 */ + compatible = "fsl,aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80000000 0x10000000>; + ranges; + + ecspi@83fac000 { /* ECSPI2 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx51-ecspi"; + reg = <0x83fac000 0x4000>; + interrupts = <37>; + status = "disabled"; + }; + + sdma@83fb0000 { + compatible = "fsl,imx51-sdma", "fsl,imx35-sdma"; + reg = <0x83fb0000 0x4000>; + interrupts = <6>; + }; + + cspi@83fc0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx51-cspi", "fsl,imx35-cspi"; + reg = <0x83fc0000 0x4000>; + interrupts = <38>; + status = "disabled"; + }; + + i2c@83fc4000 { /* I2C2 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx51-i2c", "fsl,imx1-i2c"; + reg = <0x83fc4000 0x4000>; + interrupts = <63>; + status = "disabled"; + }; + + i2c@83fc8000 { /* I2C1 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx51-i2c", "fsl,imx1-i2c"; + reg = <0x83fc8000 0x4000>; + interrupts = <62>; + status = "disabled"; + }; + + fec@83fec000 { + compatible = "fsl,imx51-fec", "fsl,imx27-fec"; + reg = <0x83fec000 0x4000>; + interrupts = <87>; + status = "disabled"; + }; + }; + }; +}; diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index 0ac676c5256d..bda12e84429a 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig @@ -62,6 +62,15 @@ endif # ARCH_MX50_SUPPORTED if ARCH_MX51 comment "i.MX51 machines:" +config MACH_IMX51_DT + bool "Support i.MX51 platforms from device tree" + select SOC_IMX51 + select USE_OF + select MACH_MX51_BABBAGE + help + Include support for Freescale i.MX51 based platforms + using the device tree for discovery + config MACH_MX51_BABBAGE bool "Support MX51 BABBAGE platforms" select SOC_IMX51 diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile index 3dbe5e26a51b..a3c75f368f4b 100644 --- a/arch/arm/mach-mx5/Makefile +++ b/arch/arm/mach-mx5/Makefile @@ -23,4 +23,5 @@ obj-$(CONFIG_MACH_MX51_EFIKAMX) += board-mx51_efikamx.o obj-$(CONFIG_MACH_MX51_EFIKASB) += board-mx51_efikasb.o obj-$(CONFIG_MACH_MX50_RDP) += board-mx50_rdp.o +obj-$(CONFIG_MACH_IMX51_DT) += imx51-dt.o obj-$(CONFIG_MACH_IMX53_DT) += imx53-dt.o diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index 11b0ff67f89d..5cc28e0ce3e5 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -351,6 +351,12 @@ static const struct esdhc_platform_data mx51_babbage_sd2_data __initconst = { .wp_type = ESDHC_WP_GPIO, }; +void __init imx51_babbage_common_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads, + ARRAY_SIZE(mx51babbage_pads)); +} + /* * Board specific initialization. */ @@ -365,8 +371,7 @@ static void __init mx51_babbage_init(void) #if defined(CONFIG_CPU_FREQ_IMX) get_cpu_op = mx51_get_cpu_op; #endif - mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads, - ARRAY_SIZE(mx51babbage_pads)); + imx51_babbage_common_init(); imx51_add_imx_uart(0, &uart_pdata); imx51_add_imx_uart(1, NULL); diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c index d9b03d4dba6d..cc3547c88261 100644 --- a/arch/arm/mach-mx5/clock-mx51-mx53.c +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c @@ -1633,6 +1633,14 @@ static void __init clk_get_freq_dt(unsigned long *ckil, unsigned long *osc, } } +int __init mx51_clocks_init_dt(void) +{ + unsigned long ckil, osc, ckih1, ckih2; + + clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); + return mx51_clocks_init(ckil, osc, ckih1, ckih2); +} + int __init mx53_clocks_init_dt(void) { unsigned long ckil, osc, ckih1, ckih2; diff --git a/arch/arm/mach-mx5/imx51-dt.c b/arch/arm/mach-mx5/imx51-dt.c new file mode 100644 index 000000000000..ccc61585659b --- /dev/null +++ b/arch/arm/mach-mx5/imx51-dt.c @@ -0,0 +1,116 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Lookup table for attaching a specific name and platform_data pointer to + * devices as they get created by of_platform_populate(). Ideally this table + * would not exist, but the current clock implementation depends on some devices + * having a specific name. + */ +static const struct of_dev_auxdata imx51_auxdata_lookup[] __initconst = { + OF_DEV_AUXDATA("fsl,imx51-uart", MX51_UART1_BASE_ADDR, "imx21-uart.0", NULL), + OF_DEV_AUXDATA("fsl,imx51-uart", MX51_UART2_BASE_ADDR, "imx21-uart.1", NULL), + OF_DEV_AUXDATA("fsl,imx51-uart", MX51_UART3_BASE_ADDR, "imx21-uart.2", NULL), + OF_DEV_AUXDATA("fsl,imx51-fec", MX51_FEC_BASE_ADDR, "imx27-fec.0", NULL), + OF_DEV_AUXDATA("fsl,imx51-esdhc", MX51_ESDHC1_BASE_ADDR, "sdhci-esdhc-imx51.0", NULL), + OF_DEV_AUXDATA("fsl,imx51-esdhc", MX51_ESDHC2_BASE_ADDR, "sdhci-esdhc-imx51.1", NULL), + OF_DEV_AUXDATA("fsl,imx51-esdhc", MX51_ESDHC3_BASE_ADDR, "sdhci-esdhc-imx51.2", NULL), + OF_DEV_AUXDATA("fsl,imx51-esdhc", MX51_ESDHC4_BASE_ADDR, "sdhci-esdhc-imx51.3", NULL), + OF_DEV_AUXDATA("fsl,imx51-ecspi", MX51_ECSPI1_BASE_ADDR, "imx51-ecspi.0", NULL), + OF_DEV_AUXDATA("fsl,imx51-ecspi", MX51_ECSPI2_BASE_ADDR, "imx51-ecspi.1", NULL), + OF_DEV_AUXDATA("fsl,imx51-cspi", MX51_CSPI_BASE_ADDR, "imx35-cspi.0", NULL), + OF_DEV_AUXDATA("fsl,imx51-i2c", MX51_I2C1_BASE_ADDR, "imx-i2c.0", NULL), + OF_DEV_AUXDATA("fsl,imx51-i2c", MX51_I2C2_BASE_ADDR, "imx-i2c.1", NULL), + OF_DEV_AUXDATA("fsl,imx51-sdma", MX51_SDMA_BASE_ADDR, "imx35-sdma", NULL), + OF_DEV_AUXDATA("fsl,imx51-wdt", MX51_WDOG1_BASE_ADDR, "imx2-wdt.0", NULL), + { /* sentinel */ } +}; + +static void __init imx51_tzic_add_irq_domain(struct device_node *np, + struct device_node *interrupt_parent) +{ + irq_domain_add_simple(np, 0); +} + +static void __init imx51_gpio_add_irq_domain(struct device_node *np, + struct device_node *interrupt_parent) +{ + static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS - + 32 * 4; /* imx51 gets 4 gpio ports */ + + irq_domain_add_simple(np, gpio_irq_base); + gpio_irq_base += 32; +} + +static const struct of_device_id imx51_irq_match[] __initconst = { + { .compatible = "fsl,imx51-tzic", .data = imx51_tzic_add_irq_domain, }, + { .compatible = "fsl,imx51-gpio", .data = imx51_gpio_add_irq_domain, }, + { /* sentinel */ } +}; + +static const struct of_device_id imx51_iomuxc_of_match[] __initconst = { + { .compatible = "fsl,imx51-iomuxc-babbage", .data = imx51_babbage_common_init, }, + { /* sentinel */ } +}; + +static void __init imx51_dt_init(void) +{ + struct device_node *node; + const struct of_device_id *of_id; + void (*func)(void); + + of_irq_init(imx51_irq_match); + + node = of_find_matching_node(NULL, imx51_iomuxc_of_match); + if (node) { + of_id = of_match_node(imx51_iomuxc_of_match, node); + func = of_id->data; + func(); + of_node_put(node); + } + + of_platform_populate(NULL, of_default_bus_match_table, + imx51_auxdata_lookup, NULL); +} + +static void __init imx51_timer_init(void) +{ + mx51_clocks_init_dt(); +} + +static struct sys_timer imx51_timer = { + .init = imx51_timer_init, +}; + +static const char *imx51_dt_board_compat[] __initdata = { + "fsl,imx51-babbage", + NULL +}; + +DT_MACHINE_START(IMX51_DT, "Freescale i.MX51 (Device Tree Support)") + .map_io = mx51_map_io, + .init_early = imx51_init_early, + .init_irq = mx51_init_irq, + .handle_irq = imx51_handle_irq, + .timer = &imx51_timer, + .init_machine = imx51_dt_init, + .dt_compat = imx51_dt_board_compat, +MACHINE_END diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index eb3e7c4e2f1a..d19703930ef6 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -64,6 +64,7 @@ extern int mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); extern int mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); +extern int mx51_clocks_init_dt(void); extern int mx53_clocks_init_dt(void); extern struct platform_device *mxc_register_gpio(char *name, int id, resource_size_t iobase, resource_size_t iosize, int irq, int irq_high); @@ -74,6 +75,7 @@ extern void mx51_efikamx_reset(void); extern int mx53_revision(void); extern int mx53_display_revision(void); +extern void imx51_babbage_common_init(void); extern void imx53_ard_common_init(void); extern void imx53_evk_common_init(void); extern void imx53_qsb_common_init(void); From 49fe2ba3138ca60422fd90ed76c1918be1c30fc0 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 10 Oct 2011 18:29:24 +0200 Subject: [PATCH 06/13] ARM: at91: dt: at91sam9g45 family and board device tree files Create a new device tree source file for Atmel at91sam9g45 SoC family. The Evaluation Kit at91sam9m10g45ek includes it. This first basic support will be populated as drivers and boards will be converted to device tree. Contains serial, dma and interrupt controllers. The generic board file still takes advantage of platform data for early serial init. As we need a storage media and the NAND flash driver is not converted to DT yet, we keep old initialization for it. Signed-off-by: Nicolas Ferre Reviewed-by: Rob Herring --- arch/arm/boot/dts/at91sam9g45.dtsi | 106 +++++++++++++++++++++ arch/arm/boot/dts/at91sam9m10g45ek.dts | 35 +++++++ arch/arm/mach-at91/Kconfig | 11 +++ arch/arm/mach-at91/Makefile | 3 + arch/arm/mach-at91/Makefile.boot | 2 + arch/arm/mach-at91/at91sam9g45.c | 6 ++ arch/arm/mach-at91/board-dt.c | 122 +++++++++++++++++++++++++ 7 files changed, 285 insertions(+) create mode 100644 arch/arm/boot/dts/at91sam9g45.dtsi create mode 100644 arch/arm/boot/dts/at91sam9m10g45ek.dts create mode 100644 arch/arm/mach-at91/board-dt.c diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi new file mode 100644 index 000000000000..db6a45202f26 --- /dev/null +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -0,0 +1,106 @@ +/* + * at91sam9g45.dtsi - Device Tree Include file for AT91SAM9G45 family SoC + * applies to AT91SAM9G45, AT91SAM9M10, + * AT91SAM9G46, AT91SAM9M11 SoC + * + * Copyright (C) 2011 Atmel, + * 2011 Nicolas Ferre + * + * Licensed under GPLv2 or later. + */ + +/include/ "skeleton.dtsi" + +/ { + model = "Atmel AT91SAM9G45 family SoC"; + compatible = "atmel,at91sam9g45"; + interrupt-parent = <&aic>; + + aliases { + serial0 = &dbgu; + serial1 = &usart0; + serial2 = &usart1; + serial3 = &usart2; + serial4 = &usart3; + }; + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + memory@70000000 { + reg = <0x70000000 0x10000000>; + }; + + ahb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + aic: interrupt-controller@fffff000 { + #interrupt-cells = <1>; + compatible = "atmel,at91rm9200-aic"; + interrupt-controller; + interrupt-parent; + reg = <0xfffff000 0x200>; + }; + + dma: dma-controller@ffffec00 { + compatible = "atmel,at91sam9g45-dma"; + reg = <0xffffec00 0x200>; + interrupts = <21>; + }; + + dbgu: serial@ffffee00 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xffffee00 0x200>; + interrupts = <1>; + status = "disabled"; + }; + + usart0: serial@fff8c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff8c000 0x200>; + interrupts = <7>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart1: serial@fff90000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff90000 0x200>; + interrupts = <8>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart2: serial@fff94000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff94000 0x200>; + interrupts = <9>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart3: serial@fff98000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff98000 0x200>; + interrupts = <10>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts new file mode 100644 index 000000000000..85b34f59cd82 --- /dev/null +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -0,0 +1,35 @@ +/* + * at91sam9m10g45ek.dts - Device Tree file for AT91SAM9M10G45-EK board + * + * Copyright (C) 2011 Atmel, + * 2011 Nicolas Ferre + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +/include/ "at91sam9g45.dtsi" + +/ { + model = "Atmel AT91SAM9M10G45-EK"; + compatible = "atmel,at91sam9m10g45ek", "atmel,at91sam9g45", "atmel,at91sam9"; + + chosen { + bootargs = "mem=64M console=ttyS0,115200 mtdparts=atmel_nand:4M(bootstrap/uboot/kernel)ro,60M(rootfs),-(data) root=/dev/mtdblock1 rw rootfstype=jffs2"; + }; + + memory@70000000 { + reg = <0x70000000 0x4000000>; + }; + + ahb { + apb { + dbgu: serial@ffffee00 { + status = "okay"; + }; + + usart1: serial@fff90000 { + status = "okay"; + }; + }; + }; +}; diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 22484670e7ba..4b59d96e1cd8 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -442,6 +442,17 @@ endif # ---------------------------------------------------------- +comment "Generic Board Type" + +config MACH_AT91SAM_DT + bool "Atmel AT91SAM Evaluation Kits with device-tree support" + select USE_OF + help + Select this if you want to experiment device-tree with + an Atmel Evaluation Kit. + +# ---------------------------------------------------------- + comment "AT91 Board Options" config MTD_AT91_DATAFLASH_CARD diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index bf57e8b1c9d0..3ff245ebcad1 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -74,6 +74,9 @@ obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o # AT91SAM9G45 board-specific support obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o +# AT91SAM board with device-tree +obj-$(CONFIG_MACH_AT91SAM_DT) += board-dt.o + # AT91CAP9 board-specific support obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot index 3462b815054a..d2788636805c 100644 --- a/arch/arm/mach-at91/Makefile.boot +++ b/arch/arm/mach-at91/Makefile.boot @@ -16,3 +16,5 @@ else params_phys-y := 0x20000100 initrd_phys-y := 0x20410000 endif + +dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index e04c5fb6f1ee..8baf5a1ed167 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -215,6 +215,12 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), + /* more usart lookup table for DT entries */ + CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck), + CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk), + CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk), + CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk), + CLKDEV_CON_DEV_ID("usart", "fff98000.serial", &usart3_clk), }; static struct clk_lookup usart_clocks_lookups[] = { diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c new file mode 100644 index 000000000000..33a0d8b549b4 --- /dev/null +++ b/arch/arm/mach-at91/board-dt.c @@ -0,0 +1,122 @@ +/* + * Setup code for AT91SAM Evaluation Kits with Device Tree support + * + * Covers: * AT91SAM9G45-EKES board + * * AT91SAM9M10-EKES board + * * AT91SAM9M10G45-EK board + * + * Copyright (C) 2011 Atmel, + * 2011 Nicolas Ferre + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sam9_smc.h" +#include "generic.h" + + +static void __init ek_init_early(void) +{ + /* Initialize processor: 12.000 MHz crystal */ + at91_initialize(12000000); + + /* DGBU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); + + /* set serial console to ttyS0 (ie, DBGU) */ + at91_set_serial_console(0); +} + +/* det_pin is not connected */ +static struct atmel_nand_data __initdata ek_nand_data = { + .ale = 21, + .cle = 22, + .rdy_pin = AT91_PIN_PC8, + .enable_pin = AT91_PIN_PC14, +}; + +static struct sam9_smc_config __initdata ek_nand_smc_config = { + .ncs_read_setup = 0, + .nrd_setup = 2, + .ncs_write_setup = 0, + .nwe_setup = 2, + + .ncs_read_pulse = 4, + .nrd_pulse = 4, + .ncs_write_pulse = 4, + .nwe_pulse = 4, + + .read_cycle = 7, + .write_cycle = 7, + + .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, + .tdf_cycles = 3, +}; + +static void __init ek_add_device_nand(void) +{ + ek_nand_data.bus_width_16 = board_have_nand_16bit(); + /* setup bus-width (8 or 16) */ + if (ek_nand_data.bus_width_16) + ek_nand_smc_config.mode |= AT91_SMC_DBW_16; + else + ek_nand_smc_config.mode |= AT91_SMC_DBW_8; + + /* configure chip-select 3 (NAND) */ + sam9_smc_configure(3, &ek_nand_smc_config); + + at91_add_device_nand(&ek_nand_data); +} + +static const struct of_device_id aic_of_match[] __initconst = { + { .compatible = "atmel,at91rm9200-aic", }, + {}, +}; + +static void __init at91_dt_init_irq(void) +{ + irq_domain_generate_simple(aic_of_match, 0xfffff000, 0); + at91_init_irq_default(); +} + +static void __init at91_dt_device_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + + /* NAND */ + ek_add_device_nand(); +} + +static const char *at91_dt_board_compat[] __initdata = { + "atmel,at91sam9m10g45ek", + NULL +}; + +DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)") + /* Maintainer: Atmel */ + .timer = &at91sam926x_timer, + .map_io = at91_map_io, + .init_early = ek_init_early, + .init_irq = at91_dt_init_irq, + .init_machine = at91_dt_device_init, + .dt_compat = at91_dt_board_compat, +MACHINE_END From fea3158c5508f3a96b0cfec6d37a239aa7f3ed4b Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 14 Oct 2011 09:40:52 +0800 Subject: [PATCH 07/13] ARM: at91: add at91sam9g20 and Calao USB A9G20 DT support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Nicolas Ferre Reviewed-by: Rob Herring --- arch/arm/boot/dts/at91sam9g20.dtsi | 119 +++++++++++++++++++++++++++++ arch/arm/boot/dts/usb_a9g20.dts | 30 ++++++++ arch/arm/mach-at91/Makefile.boot | 2 +- arch/arm/mach-at91/at91sam9260.c | 8 ++ arch/arm/mach-at91/board-dt.c | 1 + 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/at91sam9g20.dtsi create mode 100644 arch/arm/boot/dts/usb_a9g20.dts diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi new file mode 100644 index 000000000000..aeef04269cf8 --- /dev/null +++ b/arch/arm/boot/dts/at91sam9g20.dtsi @@ -0,0 +1,119 @@ +/* + * at91sam9g20.dtsi - Device Tree Include file for AT91SAM9G20 family SoC + * + * Copyright (C) 2011 Atmel, + * 2011 Nicolas Ferre , + * 2011 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2 or later. + */ + +/include/ "skeleton.dtsi" + +/ { + model = "Atmel AT91SAM9G20 family SoC"; + compatible = "atmel,at91sam9g20"; + interrupt-parent = <&aic>; + + aliases { + serial0 = &dbgu; + serial1 = &usart0; + serial2 = &usart1; + serial3 = &usart2; + serial4 = &usart3; + serial5 = &usart4; + serial6 = &usart5; + }; + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + memory@20000000 { + reg = <0x20000000 0x08000000>; + }; + + ahb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + aic: interrupt-controller@fffff000 { + #interrupt-cells = <1>; + compatible = "atmel,at91rm9200-aic"; + interrupt-controller; + interrupt-parent; + reg = <0xfffff000 0x200>; + }; + + dbgu: serial@fffff200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <1>; + status = "disabled"; + }; + + usart0: serial@fffb0000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb0000 0x200>; + interrupts = <6>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart1: serial@fffb4000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb4000 0x200>; + interrupts = <7>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart2: serial@fffb8000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb8000 0x200>; + interrupts = <8>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart3: serial@fffd0000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffd0000 0x200>; + interrupts = <23>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart4: serial@fffd4000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffd4000 0x200>; + interrupts = <24>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart5: serial@fffd8000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffd8000 0x200>; + interrupts = <25>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/usb_a9g20.dts b/arch/arm/boot/dts/usb_a9g20.dts new file mode 100644 index 000000000000..d66e2c00ac35 --- /dev/null +++ b/arch/arm/boot/dts/usb_a9g20.dts @@ -0,0 +1,30 @@ +/* + * usb_a9g20.dts - Device Tree file for Caloa USB A9G20 board + * + * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +/include/ "at91sam9g20.dtsi" + +/ { + model = "Calao USB A9G20"; + compatible = "calao,usb-a9g20", "atmel,at91sam9g20", "atmel,at91sam9"; + + chosen { + bootargs = "mem=64M console=ttyS0,115200 mtdparts=atmel_nand:128k(at91bootstrap),256k(barebox)ro,128k(bareboxenv),128k(bareboxenv2),4M(kernel),120M(rootfs),-(data) root=/dev/mtdblock5 rw rootfstype=ubifs"; + }; + + memory@20000000 { + reg = <0x20000000 0x4000000>; + }; + + ahb { + apb { + dbgu: serial@fffff200 { + status = "okay"; + }; + }; + }; +}; diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot index d2788636805c..08c665affde4 100644 --- a/arch/arm/mach-at91/Makefile.boot +++ b/arch/arm/mach-at91/Makefile.boot @@ -17,4 +17,4 @@ params_phys-y := 0x20000100 initrd_phys-y := 0x20410000 endif -dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb +dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb usb_a9g20.dtb diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index cb397be14448..f4518b49cb82 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -199,6 +199,14 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t4_clk", "atmel_tcb.1", &tc4_clk), CLKDEV_CON_DEV_ID("t5_clk", "atmel_tcb.1", &tc5_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk), + /* more usart lookup table for DT entries */ + CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck), + CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk), + CLKDEV_CON_DEV_ID("usart", "fffb4000.serial", &usart1_clk), + CLKDEV_CON_DEV_ID("usart", "fffb8000.serial", &usart2_clk), + CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk), + CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk), + CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk), }; static struct clk_lookup usart_clocks_lookups[] = { diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c index 33a0d8b549b4..0b7d32778210 100644 --- a/arch/arm/mach-at91/board-dt.c +++ b/arch/arm/mach-at91/board-dt.c @@ -108,6 +108,7 @@ static void __init at91_dt_device_init(void) static const char *at91_dt_board_compat[] __initdata = { "atmel,at91sam9m10g45ek", + "calao,usb-a9g20", NULL }; From c71a54b0820179e53483d5220cdef1a0df8d5bd1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 20 Sep 2011 15:13:50 -0500 Subject: [PATCH 08/13] of/irq: introduce of_irq_init of_irq_init will scan the devicetree for matching interrupt controller nodes. Then it calls an initialization function for each found controller in the proper order with parent nodes initialized before child nodes. Based on initial pseudo code from Grant Likely. Changes in v4: - Drop unnecessary empty list check - Be more verbose on errors - Simplify "if (!desc) WARN_ON(1)" to "if (WARN_ON(!desc))" Changes in v3: - add missing kfree's found by Jamie - Implement Grant's comments to simplify the init loop - fix function comments Changes in v2: - Complete re-write of list searching code from Grant Likely Signed-off-by: Rob Herring Reviewed-by: Jamie Iles Tested-by: Thomas Abraham Acked-by: Grant Likely --- drivers/of/irq.c | 107 +++++++++++++++++++++++++++++++++++++++++ include/linux/of_irq.h | 3 ++ 2 files changed, 110 insertions(+) diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 9f689f1da0fc..791270b8bd1c 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -19,10 +19,12 @@ */ #include +#include #include #include #include #include +#include /* For archs that don't support NO_IRQ (such as x86), provide a dummy value */ #ifndef NO_IRQ @@ -386,3 +388,108 @@ int of_irq_to_resource_table(struct device_node *dev, struct resource *res, return i; } + +struct intc_desc { + struct list_head list; + struct device_node *dev; + struct device_node *interrupt_parent; +}; + +/** + * of_irq_init - Scan and init matching interrupt controllers in DT + * @matches: 0 terminated array of nodes to match and init function to call + * + * This function scans the device tree for matching interrupt controller nodes, + * and calls their initialization functions in order with parents first. + */ +void __init of_irq_init(const struct of_device_id *matches) +{ + struct device_node *np, *parent = NULL; + struct intc_desc *desc, *temp_desc; + struct list_head intc_desc_list, intc_parent_list; + + INIT_LIST_HEAD(&intc_desc_list); + INIT_LIST_HEAD(&intc_parent_list); + + for_each_matching_node(np, matches) { + if (!of_find_property(np, "interrupt-controller", NULL)) + continue; + /* + * Here, we allocate and populate an intc_desc with the node + * pointer, interrupt-parent device_node etc. + */ + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (WARN_ON(!desc)) + goto err; + + desc->dev = np; + desc->interrupt_parent = of_irq_find_parent(np); + list_add_tail(&desc->list, &intc_desc_list); + } + + /* + * The root irq controller is the one without an interrupt-parent. + * That one goes first, followed by the controllers that reference it, + * followed by the ones that reference the 2nd level controllers, etc. + */ + while (!list_empty(&intc_desc_list)) { + /* + * Process all controllers with the current 'parent'. + * First pass will be looking for NULL as the parent. + * The assumption is that NULL parent means a root controller. + */ + list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) { + const struct of_device_id *match; + int ret; + of_irq_init_cb_t irq_init_cb; + + if (desc->interrupt_parent != parent) + continue; + + list_del(&desc->list); + match = of_match_node(matches, desc->dev); + if (WARN(!match->data, + "of_irq_init: no init function for %s\n", + match->compatible)) { + kfree(desc); + continue; + } + + pr_debug("of_irq_init: init %s @ %p, parent %p\n", + match->compatible, + desc->dev, desc->interrupt_parent); + irq_init_cb = match->data; + ret = irq_init_cb(desc->dev, desc->interrupt_parent); + if (ret) { + kfree(desc); + continue; + } + + /* + * This one is now set up; add it to the parent list so + * its children can get processed in a subsequent pass. + */ + list_add_tail(&desc->list, &intc_parent_list); + } + + /* Get the next pending parent that might have children */ + desc = list_first_entry(&intc_parent_list, typeof(*desc), list); + if (list_empty(&intc_parent_list) || !desc) { + pr_err("of_irq_init: children remain, but no parents\n"); + break; + } + list_del(&desc->list); + parent = desc->dev; + kfree(desc); + } + + list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) { + list_del(&desc->list); + kfree(desc); + } +err: + list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) { + list_del(&desc->list); + kfree(desc); + } +} diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index cd2e61ce4e83..d0307eed20c9 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -33,6 +33,8 @@ struct of_irq { u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */ }; +typedef int (*of_irq_init_cb_t)(struct device_node *, struct device_node *); + /* * Workarounds only applied to 32bit powermac machines */ @@ -73,6 +75,7 @@ extern int of_irq_to_resource_table(struct device_node *dev, struct resource *res, int nr_irqs); extern struct device_node *of_irq_find_parent(struct device_node *child); +extern void of_irq_init(const struct of_device_id *matches); #endif /* CONFIG_OF_IRQ */ #endif /* CONFIG_OF */ From 6d274309d0e64bdbdb6c50945ca2964596e8fa5a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 30 Sep 2011 10:48:38 -0500 Subject: [PATCH 09/13] irq: support domains with non-zero hwirq base Interrupt controllers can have non-zero starting value for h/w irq numbers. Adding support in irq_domain allows the domain hwirq numbering to match the interrupt controllers' numbering. As this makes looping over irqs for a domain more complicated, add loop iterators to iterate over all hwirqs and irqs for a domain. Signed-off-by: Rob Herring Reviewed-by: Jamie Iles Tested-by: Thomas Abraham Acked-by: Grant Likely Acked-by: Thomas Gleixner --- include/linux/irqdomain.h | 16 +++++++++++++++- kernel/irq/irqdomain.c | 12 ++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 3ad553e8eae2..99834e581b9e 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -47,6 +47,7 @@ struct irq_domain_ops { * of the irq_domain is responsible for allocating the array of * irq_desc structures. * @nr_irq: Number of irqs managed by the irq domain + * @hwirq_base: Starting number for hwirqs managed by the irq domain * @ops: pointer to irq_domain methods * @priv: private data pointer for use by owner. Not touched by irq_domain * core code. @@ -57,6 +58,7 @@ struct irq_domain { struct list_head list; unsigned int irq_base; unsigned int nr_irq; + unsigned int hwirq_base; const struct irq_domain_ops *ops; void *priv; struct device_node *of_node; @@ -72,9 +74,21 @@ struct irq_domain { static inline unsigned int irq_domain_to_irq(struct irq_domain *d, unsigned long hwirq) { - return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq; + if (d->ops->to_irq) + return d->ops->to_irq(d, hwirq); + if (WARN_ON(hwirq < d->hwirq_base)) + return 0; + return d->irq_base + hwirq - d->hwirq_base; } +#define irq_domain_for_each_hwirq(d, hw) \ + for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++) + +#define irq_domain_for_each_irq(d, hw, irq) \ + for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \ + hw < d->hwirq_base + d->nr_irq; \ + hw++, irq = irq_domain_to_irq(d, hw)) + extern void irq_domain_add(struct irq_domain *domain); extern void irq_domain_del(struct irq_domain *domain); #endif /* CONFIG_IRQ_DOMAIN */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index b57a3776de44..200ce832c585 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -20,15 +20,15 @@ static DEFINE_MUTEX(irq_domain_mutex); void irq_domain_add(struct irq_domain *domain) { struct irq_data *d; - int hwirq; + int hwirq, irq; /* * This assumes that the irq_domain owner has already allocated * the irq_descs. This block will be removed when support for dynamic * allocation of irq_descs is added to irq_domain. */ - for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) { - d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq)); + irq_domain_for_each_irq(domain, hwirq, irq) { + d = irq_get_irq_data(irq); if (!d) { WARN(1, "error: assigning domain to non existant irq_desc"); return; @@ -54,15 +54,15 @@ void irq_domain_add(struct irq_domain *domain) void irq_domain_del(struct irq_domain *domain) { struct irq_data *d; - int hwirq; + int hwirq, irq; mutex_lock(&irq_domain_mutex); list_del(&domain->list); mutex_unlock(&irq_domain_mutex); /* Clear the irq_domain assignments */ - for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) { - d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq)); + irq_domain_for_each_irq(domain, hwirq, irq) { + d = irq_get_irq_data(irq); d->domain = NULL; } } From 4294f8baaf174c9aa57886e7ed27caf4b02578f6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 28 Sep 2011 21:25:31 -0500 Subject: [PATCH 10/13] ARM: gic: add irq_domain support Convert the gic interrupt controller to use irq domains in preparation for device-tree binding and MULTI_IRQ. This allows for translation between GIC interrupt IDs and Linux irq numbers. The meaning of irq_offset has changed. It now is just the number of skipped GIC interrupt IDs for the controller. It will be 16 for primary GIC and 32 for secondary GICs. Signed-off-by: Rob Herring Cc: Marc Zyngier Reviewed-by: Jamie Iles Tested-by: Thomas Abraham Acked-by: Grant Likely --- arch/arm/common/Kconfig | 1 + arch/arm/common/gic.c | 118 +++++++++++++--------------- arch/arm/include/asm/hardware/gic.h | 7 +- 3 files changed, 63 insertions(+), 63 deletions(-) diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 4b71766fb21d..74df9ca2be31 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -1,4 +1,5 @@ config ARM_GIC + select IRQ_DOMAIN bool config ARM_VIC diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 016c1aeb847c..ccaa1ab18de7 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -24,11 +24,13 @@ */ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -75,8 +77,7 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d) static inline unsigned int gic_irq(struct irq_data *d) { - struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); - return d->irq - gic_data->irq_offset; + return d->hwirq; } /* @@ -84,7 +85,7 @@ static inline unsigned int gic_irq(struct irq_data *d) */ static void gic_mask_irq(struct irq_data *d) { - u32 mask = 1 << (d->irq % 32); + u32 mask = 1 << (gic_irq(d) % 32); spin_lock(&irq_controller_lock); writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); @@ -95,7 +96,7 @@ static void gic_mask_irq(struct irq_data *d) static void gic_unmask_irq(struct irq_data *d) { - u32 mask = 1 << (d->irq % 32); + u32 mask = 1 << (gic_irq(d) % 32); spin_lock(&irq_controller_lock); if (gic_arch_extn.irq_unmask) @@ -176,7 +177,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); - unsigned int shift = (d->irq % 4) * 8; + unsigned int shift = (gic_irq(d) % 4) * 8; unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); u32 val, mask, bit; @@ -227,7 +228,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) if (gic_irq == 1023) goto out; - cascade_irq = gic_irq + chip_data->irq_offset; + cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq); if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS)) do_bad_IRQ(cascade_irq, desc); else @@ -259,14 +260,14 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) irq_set_chained_handler(irq, gic_handle_cascade_irq); } -static void __init gic_dist_init(struct gic_chip_data *gic, - unsigned int irq_start) +static void __init gic_dist_init(struct gic_chip_data *gic) { - unsigned int gic_irqs, irq_limit, i; + unsigned int i, irq; u32 cpumask; + unsigned int gic_irqs = gic->gic_irqs; + struct irq_domain *domain = &gic->domain; void __iomem *base = gic->dist_base; u32 cpu = 0; - u32 nrppis = 0, ppi_base = 0; #ifdef CONFIG_SMP cpu = cpu_logical_map(smp_processor_id()); @@ -278,34 +279,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic, writel_relaxed(0, base + GIC_DIST_CTRL); - /* - * Find out how many interrupts are supported. - * The GIC only supports up to 1020 interrupt sources. - */ - gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f; - gic_irqs = (gic_irqs + 1) * 32; - if (gic_irqs > 1020) - gic_irqs = 1020; - - gic->gic_irqs = gic_irqs; - - /* - * Nobody would be insane enough to use PPIs on a secondary - * GIC, right? - */ - if (gic == &gic_data[0]) { - nrppis = (32 - irq_start) & 31; - - /* The GIC only supports up to 16 PPIs. */ - if (nrppis > 16) - BUG(); - - ppi_base = gic->irq_offset + 32 - nrppis; - } - - pr_info("Configuring GIC with %d sources (%d PPIs)\n", - gic_irqs, (gic == &gic_data[0]) ? nrppis : 0); - /* * Set all global interrupts to be level triggered, active low. */ @@ -331,30 +304,21 @@ static void __init gic_dist_init(struct gic_chip_data *gic, for (i = 32; i < gic_irqs; i += 32) writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); - /* - * Limit number of interrupts registered to the platform maximum - */ - irq_limit = gic->irq_offset + gic_irqs; - if (WARN_ON(irq_limit > NR_IRQS)) - irq_limit = NR_IRQS; - /* * Setup the Linux IRQ subsystem. */ - for (i = 0; i < nrppis; i++) { - int ppi = i + ppi_base; - - irq_set_percpu_devid(ppi); - irq_set_chip_and_handler(ppi, &gic_chip, - handle_percpu_devid_irq); - irq_set_chip_data(ppi, gic); - set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN); - } - - for (i = irq_start + nrppis; i < irq_limit; i++) { - irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq); - irq_set_chip_data(i, gic); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + irq_domain_for_each_irq(domain, i, irq) { + if (i < 32) { + irq_set_percpu_devid(irq); + irq_set_chip_and_handler(irq, &gic_chip, + handle_percpu_devid_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); + } else { + irq_set_chip_and_handler(irq, &gic_chip, + handle_fasteoi_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + irq_set_chip_data(irq, gic); } writel_relaxed(1, base + GIC_DIST_CTRL); @@ -566,23 +530,53 @@ static void __init gic_pm_init(struct gic_chip_data *gic) } #endif +const struct irq_domain_ops gic_irq_domain_ops = { +}; + void __init gic_init(unsigned int gic_nr, unsigned int irq_start, void __iomem *dist_base, void __iomem *cpu_base) { struct gic_chip_data *gic; + struct irq_domain *domain; + int gic_irqs; BUG_ON(gic_nr >= MAX_GIC_NR); gic = &gic_data[gic_nr]; + domain = &gic->domain; gic->dist_base = dist_base; gic->cpu_base = cpu_base; - gic->irq_offset = (irq_start - 1) & ~31; - if (gic_nr == 0) + /* + * For primary GICs, skip over SGIs. + * For secondary GICs, skip over PPIs, too. + */ + if (gic_nr == 0) { gic_cpu_base_addr = cpu_base; + domain->hwirq_base = 16; + irq_start = (irq_start & ~31) + 16; + } else + domain->hwirq_base = 32; + + /* + * Find out how many interrupts are supported. + * The GIC only supports up to 1020 interrupt sources. + */ + gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f; + gic_irqs = (gic_irqs + 1) * 32; + if (gic_irqs > 1020) + gic_irqs = 1020; + gic->gic_irqs = gic_irqs; + + domain->nr_irq = gic_irqs - domain->hwirq_base; + domain->irq_base = irq_alloc_descs(-1, irq_start, domain->nr_irq, + numa_node_id()); + domain->priv = gic; + domain->ops = &gic_irq_domain_ops; + irq_domain_add(domain); gic_chip.flags |= gic_arch_extn.flags; - gic_dist_init(gic, irq_start); + gic_dist_init(gic); gic_cpu_init(gic); gic_pm_init(gic); } diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 14867e12f205..43a05d90e43b 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -33,6 +33,9 @@ #define GIC_DIST_SOFTINT 0xf00 #ifndef __ASSEMBLY__ +#include +struct device_node; + extern void __iomem *gic_cpu_base_addr; extern struct irq_chip gic_arch_extn; @@ -42,7 +45,6 @@ void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); struct gic_chip_data { - unsigned int irq_offset; void __iomem *dist_base; void __iomem *cpu_base; #ifdef CONFIG_CPU_PM @@ -51,6 +53,9 @@ struct gic_chip_data { u32 saved_spi_target[DIV_ROUND_UP(1020, 4)]; u32 __percpu *saved_ppi_enable; u32 __percpu *saved_ppi_conf; +#endif +#ifdef CONFIG_IRQ_DOMAIN + struct irq_domain domain; #endif unsigned int gic_irqs; }; From b3f7ed0324091e2cb23fe1b3c10570700f614014 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 28 Sep 2011 21:27:52 -0500 Subject: [PATCH 11/13] ARM: gic: add OF based initialization This adds ARM gic interrupt controller initialization using device tree data. The initialization function is intended to be called by of_irq_init function like this: const static struct of_device_id irq_match[] = { { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, {} }; static void __init init_irqs(void) { of_irq_init(irq_match); } Signed-off-by: Rob Herring Reviewed-by: Jamie Iles Tested-by: Thomas Abraham Acked-by: Grant Likely --- Documentation/devicetree/bindings/arm/gic.txt | 55 +++++++++++++++++ arch/arm/common/gic.c | 61 +++++++++++++++++++ arch/arm/include/asm/hardware/gic.h | 1 + 3 files changed, 117 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/gic.txt diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt new file mode 100644 index 000000000000..52916b4aa1fe --- /dev/null +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -0,0 +1,55 @@ +* ARM Generic Interrupt Controller + +ARM SMP cores are often associated with a GIC, providing per processor +interrupts (PPI), shared processor interrupts (SPI) and software +generated interrupts (SGI). + +Primary GIC is attached directly to the CPU and typically has PPIs and SGIs. +Secondary GICs are cascaded into the upward interrupt controller and do not +have PPIs or SGIs. + +Main node required properties: + +- compatible : should be one of: + "arm,cortex-a9-gic" + "arm,arm11mp-gic" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 3. + + The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI + interrupts. + + The 2nd cell contains the interrupt number for the interrupt type. + SPI interrupts are in the range [0-987]. PPI interrupts are in the + range [0-15]. + + The 3rd cell is the flags, encoded as follows: + bits[3:0] trigger type and level flags. + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of + the 8 possible cpus attached to the GIC. A bit set to '1' indicated + the interrupt is wired to that CPU. Only valid for PPI interrupts. + +- reg : Specifies base physical address(s) and size of the GIC registers. The + first region is the GIC distributor register base and size. The 2nd region is + the GIC cpu interface register base and size. + +Optional +- interrupts : Interrupt source of the parent interrupt controller. Only + present on secondary GICs. + +Example: + + intc: interrupt-controller@fff11000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <1>; + interrupt-controller; + reg = <0xfff11000 0x1000>, + <0xfff10100 0x100>; + }; + diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index ccaa1ab18de7..1333e68b1f96 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -530,7 +533,33 @@ static void __init gic_pm_init(struct gic_chip_data *gic) } #endif +#ifdef CONFIG_OF +static int gic_irq_domain_dt_translate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, unsigned int *out_type) +{ + if (d->of_node != controller) + return -EINVAL; + if (intsize < 3) + return -EINVAL; + + /* Get the interrupt number and add 16 to skip over SGIs */ + *out_hwirq = intspec[1] + 16; + + /* For SPIs, we need to add 16 more to get the GIC irq ID number */ + if (!intspec[0]) + *out_hwirq += 16; + + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + return 0; +} +#endif + const struct irq_domain_ops gic_irq_domain_ops = { +#ifdef CONFIG_OF + .dt_translate = gic_irq_domain_dt_translate, +#endif }; void __init gic_init(unsigned int gic_nr, unsigned int irq_start, @@ -608,3 +637,35 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); } #endif + +#ifdef CONFIG_OF +static int gic_cnt __initdata = 0; + +int __init gic_of_init(struct device_node *node, struct device_node *parent) +{ + void __iomem *cpu_base; + void __iomem *dist_base; + int irq; + struct irq_domain *domain = &gic_data[gic_cnt].domain; + + if (WARN_ON(!node)) + return -ENODEV; + + dist_base = of_iomap(node, 0); + WARN(!dist_base, "unable to map gic dist registers\n"); + + cpu_base = of_iomap(node, 1); + WARN(!cpu_base, "unable to map gic cpu registers\n"); + + domain->of_node = of_node_get(node); + + gic_init(gic_cnt, 16, dist_base, cpu_base); + + if (parent) { + irq = irq_of_parse_and_map(node, 0); + gic_cascade_irq(gic_cnt, irq); + } + gic_cnt++; + return 0; +} +#endif diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 43a05d90e43b..0a026b9290f2 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -40,6 +40,7 @@ extern void __iomem *gic_cpu_base_addr; extern struct irq_chip gic_arch_extn; void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *); +int gic_of_init(struct device_node *node, struct device_node *parent); void gic_secondary_init(unsigned int); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); From f37a53cc5d8a8fb199e41386d125d8c2ed9e54ef Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 21 Oct 2011 17:14:27 -0500 Subject: [PATCH 12/13] ARM: gic: fix irq_alloc_descs handling for sparse irq Commit "ARM: gic: add irq_domain support" (b49b6ff) breaks SPARSE_IRQ on platforms with GIC. When SPARSE_IRQ is enabled, all NR_IRQS or mach_desc->nr_irqs will be allocated by arch_probe_nr_irqs(). This caused irq_alloc_descs to allocate irq_descs after the pre-allocated space. Make irq_alloc_descs search for an exact irq range and assume it has been pre-allocated on failure. For DT probing dynamic allocation is used. DT enabled platforms should set their nr_irqs to NR_IRQ_LEGACY and have all irq_chips allocate their irq_descs with irq_alloc_descs if SPARSE_IRQ is enabled. gic_init irq_start param is changed to be signed with negative meaning do dynamic Linux irq assigment. Signed-off-by: Rob Herring --- arch/arm/common/gic.c | 15 +++++++++++---- arch/arm/include/asm/hardware/gic.h | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 1333e68b1f96..9d77777076f0 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -24,6 +24,7 @@ */ #include #include +#include #include #include #include @@ -562,7 +563,7 @@ const struct irq_domain_ops gic_irq_domain_ops = { #endif }; -void __init gic_init(unsigned int gic_nr, unsigned int irq_start, +void __init gic_init(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base) { struct gic_chip_data *gic; @@ -583,7 +584,8 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start, if (gic_nr == 0) { gic_cpu_base_addr = cpu_base; domain->hwirq_base = 16; - irq_start = (irq_start & ~31) + 16; + if (irq_start > 0) + irq_start = (irq_start & ~31) + 16; } else domain->hwirq_base = 32; @@ -598,8 +600,13 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start, gic->gic_irqs = gic_irqs; domain->nr_irq = gic_irqs - domain->hwirq_base; - domain->irq_base = irq_alloc_descs(-1, irq_start, domain->nr_irq, + domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq, numa_node_id()); + if (IS_ERR_VALUE(domain->irq_base)) { + WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", + irq_start); + domain->irq_base = irq_start; + } domain->priv = gic; domain->ops = &gic_irq_domain_ops; irq_domain_add(domain); @@ -659,7 +666,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) domain->of_node = of_node_get(node); - gic_init(gic_cnt, 16, dist_base, cpu_base); + gic_init(gic_cnt, -1, dist_base, cpu_base); if (parent) { irq = irq_of_parse_and_map(node, 0); diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 0a026b9290f2..3e91f22046f5 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -39,7 +39,7 @@ struct device_node; extern void __iomem *gic_cpu_base_addr; extern struct irq_chip gic_arch_extn; -void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *); +void gic_init(unsigned int, int, void __iomem *, void __iomem *); int gic_of_init(struct device_node *node, struct device_node *parent); void gic_secondary_init(unsigned int); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); From 7e1efcf5d2039fb7a91e21df32f4175dbca4d61c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 1 Nov 2011 00:28:37 +0100 Subject: [PATCH 13/13] ARM: gic: use module.h instead of export.h The module.h cleanup series is not merged at this point, so use the older header file for now, to make it build either way. Signed-off-by: Arnd Bergmann --- arch/arm/common/gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 9d77777076f0..bf0e134e5206 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include