ARM: integrator: hook the CP into the SoC bus
authorLinus Walleij <linus.walleij@linaro.org>
Fri, 2 Nov 2012 00:20:43 +0000 (01:20 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Fri, 16 Nov 2012 21:26:07 +0000 (22:26 +0100)
This hooks the Integrator/CP into the SoC bus when booting from
device tree, by mapping the CP controller registers first,
then registering the SoC device, and then populating the device
tree with the SoC device as parent.

Cc: Lee Jones <lee.jones@linaro.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Documentation/devicetree/bindings/arm/arm-boards
arch/arm/boot/dts/integratorcp.dts
arch/arm/mach-integrator/Kconfig
arch/arm/mach-integrator/integrator_cp.c

index fc81a7d6b0f1424169f8e710770ea685d2e3c0c6..db5858e32d3f86f88c9776e80b98eddb27435131 100644 (file)
@@ -9,6 +9,10 @@ Required properties (in root node):
 
 FPGA type interrupt controllers, see the versatile-fpga-irq binding doc.
 
+In the root node the Integrator/CP must have a /cpcon node pointing
+to the CP control registers, and the Integrator/AP must have a
+/syscon node pointing to the Integrator/AP system controller.
+
 
 ARM Versatile Application and Platform Baseboards
 -------------------------------------------------
index 2dd5e4e48481bf386ee42691bce1ebe4d679aff4..8b119399025a16067330562ea9136abc0363d134 100644 (file)
                bootargs = "root=/dev/ram0 console=ttyAMA0,38400n8 earlyprintk";
        };
 
+       cpcon {
+               /* CP controller registers */
+               reg = <0xcb000000 0x100>;
+       };
+
        timer0: timer@13000000 {
                compatible = "arm,sp804", "arm,primecell";
        };
index 3961942c9e11ae548691a25957f9fed735991540..abeff25532abce23869a8f5f268cf47545283160 100644 (file)
@@ -20,6 +20,7 @@ config ARCH_INTEGRATOR_CP
        select PLAT_VERSATILE_CLCD
        select SERIAL_AMBA_PL011
        select SERIAL_AMBA_PL011_CONSOLE
+       select SOC_BUS
        help
          Include support for the ARM(R) Integrator CP platform.
 
index 5b08e8e4cc838a4221e28313c80a535d41c8e506..9194a4f3339c9153ad9231f87bbe182510567cb9 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/sys_soc.h>
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
@@ -336,10 +337,62 @@ static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = {
        { /* sentinel */ },
 };
 
+/* Base address to the CP controller */
+static void __iomem *intcp_con_base;
+
 static void __init intcp_init_of(void)
 {
-       of_platform_populate(NULL, of_default_bus_match_table,
-                       intcp_auxdata_lookup, NULL);
+       struct device_node *root;
+       struct device_node *cpcon;
+       struct device *parent;
+       struct soc_device *soc_dev;
+       struct soc_device_attribute *soc_dev_attr;
+       u32 intcp_sc_id;
+       int err;
+
+       /* Here we create an SoC device for the root node */
+       root = of_find_node_by_path("/");
+       if (!root)
+               return;
+       cpcon = of_find_node_by_path("/cpcon");
+       if (!cpcon)
+               return;
+
+       intcp_con_base = of_iomap(cpcon, 0);
+       if (!intcp_con_base)
+               return;
+
+       intcp_sc_id = readl(intcp_con_base);
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return;
+
+       err = of_property_read_string(root, "compatible",
+                                     &soc_dev_attr->soc_id);
+       if (err)
+               return;
+       err = of_property_read_string(root, "model", &soc_dev_attr->machine);
+       if (err)
+               return;
+       soc_dev_attr->family = "Integrator";
+       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
+                                          'A' + (intcp_sc_id & 0x0f));
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR_OR_NULL(soc_dev)) {
+               kfree(soc_dev_attr->revision);
+               kfree(soc_dev_attr);
+               return;
+       }
+
+       parent = soc_device_to_device(soc_dev);
+
+       if (!IS_ERR_OR_NULL(parent))
+               integrator_init_sysfs(parent, intcp_sc_id);
+
+       of_platform_populate(root, of_default_bus_match_table,
+                       intcp_auxdata_lookup, parent);
 }
 
 static const char * intcp_dt_board_compat[] = {