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

Introduce some helpers in the core to provide sysfs files
detailing the use of the SoC ID which will later be reused by
the Integrator/CP patch for the same bus grouping.

Cc: Lee Jones <lee.jones@linaro.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
arch/arm/boot/dts/integratorap.dts
arch/arm/mach-integrator/Kconfig
arch/arm/mach-integrator/common.h
arch/arm/mach-integrator/core.c
arch/arm/mach-integrator/integrator_ap.c

index 61767757b50a6fa60c399901a4fc7e1c0f0ebf2a..c9c3fa344647de9f012d1a14f44c36910bdf8dd0 100644 (file)
                bootargs = "root=/dev/ram0 console=ttyAM0,38400n8 earlyprintk";
        };
 
+       syscon {
+               /* AP system controller registers */
+               reg = <0x11000000 0x100>;
+       };
+
        timer0: timer@13000000 {
                compatible = "arm,integrator-timer";
        };
index 350e26636a06c8b0c21a3552377ef268f788aca2..3961942c9e11ae548691a25957f9fed735991540 100644 (file)
@@ -8,6 +8,7 @@ config ARCH_INTEGRATOR_AP
        select MIGHT_HAVE_PCI
        select SERIAL_AMBA_PL010
        select SERIAL_AMBA_PL010_CONSOLE
+       select SOC_BUS
        help
          Include support for the ARM(R) Integrator/AP and
          Integrator/PP2 platforms.
index c3ff21b5ea24ececc1d2bb8a5f94b152464034e2..fc9f47d289f4bbc51d2822286963d54559bcbb93 100644 (file)
@@ -4,3 +4,4 @@ void integrator_init_early(void);
 int integrator_init(bool is_cp);
 void integrator_reserve(void);
 void integrator_restart(char, const char *);
+void integrator_init_sysfs(struct device *parent, u32 id);
index ea22a17246d702722958ed0dbb96b63d8e45ae1a..161fbf8596bd96f1a82cd6450b014f8fd2c01e24 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/serial.h>
 #include <linux/io.h>
+#include <linux/stat.h>
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
@@ -169,3 +170,93 @@ void integrator_restart(char mode, const char *cmd)
 {
        cm_control(CM_CTRL_RESET, CM_CTRL_RESET);
 }
+
+static u32 integrator_id;
+
+static ssize_t intcp_get_manf(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return sprintf(buf, "%02x\n", integrator_id >> 24);
+}
+
+static struct device_attribute intcp_manf_attr =
+       __ATTR(manufacturer,  S_IRUGO, intcp_get_manf,  NULL);
+
+static ssize_t intcp_get_arch(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       const char *arch;
+
+       switch ((integrator_id >> 16) & 0xff) {
+       case 0x00:
+               arch = "ASB little-endian";
+               break;
+       case 0x01:
+               arch = "AHB little-endian";
+               break;
+       case 0x03:
+               arch = "AHB-Lite system bus, bi-endian";
+               break;
+       case 0x04:
+               arch = "AHB";
+               break;
+       default:
+               arch = "Unknown";
+               break;
+       }
+
+       return sprintf(buf, "%s\n", arch);
+}
+
+static struct device_attribute intcp_arch_attr =
+       __ATTR(architecture,  S_IRUGO, intcp_get_arch,  NULL);
+
+static ssize_t intcp_get_fpga(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       const char *fpga;
+
+       switch ((integrator_id >> 12) & 0xf) {
+       case 0x01:
+               fpga = "XC4062";
+               break;
+       case 0x02:
+               fpga = "XC4085";
+               break;
+       case 0x04:
+               fpga = "EPM7256AE (Altera PLD)";
+               break;
+       default:
+               fpga = "Unknown";
+               break;
+       }
+
+       return sprintf(buf, "%s\n", fpga);
+}
+
+static struct device_attribute intcp_fpga_attr =
+       __ATTR(fpga,  S_IRUGO, intcp_get_fpga,  NULL);
+
+static ssize_t intcp_get_build(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF);
+}
+
+static struct device_attribute intcp_build_attr =
+       __ATTR(build,  S_IRUGO, intcp_get_build,  NULL);
+
+
+
+void integrator_init_sysfs(struct device *parent, u32 id)
+{
+       integrator_id = id;
+       device_create_file(parent, &intcp_manf_attr);
+       device_create_file(parent, &intcp_arch_attr);
+       device_create_file(parent, &intcp_fpga_attr);
+       device_create_file(parent, &intcp_build_attr);
+}
index e6617c134fafe27542ef140be83e7783db0a9bf3..7d84080f9aa3de13460e5b01c32cedb8ec2634be 100644 (file)
@@ -37,6 +37,8 @@
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/stat.h>
+#include <linux/sys_soc.h>
 #include <video/vga.h>
 
 #include <mach/hardware.h>
@@ -462,13 +464,64 @@ static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = {
        { /* sentinel */ },
 };
 
+/* Base address to the AP system controller */
+static void __iomem *ap_syscon_base;
+
 static void __init ap_init_of(void)
 {
        unsigned long sc_dec;
+       struct device_node *root;
+       struct device_node *syscon;
+       struct device *parent;
+       struct soc_device *soc_dev;
+       struct soc_device_attribute *soc_dev_attr;
+       u32 ap_sc_id;
+       int err;
        int i;
 
-       of_platform_populate(NULL, of_default_bus_match_table,
-                       ap_auxdata_lookup, NULL);
+       /* Here we create an SoC device for the root node */
+       root = of_find_node_by_path("/");
+       if (!root)
+               return;
+       syscon = of_find_node_by_path("/syscon");
+       if (!syscon)
+               return;
+
+       ap_syscon_base = of_iomap(syscon, 0);
+       if (!ap_syscon_base)
+               return;
+
+       ap_sc_id = readl(ap_syscon_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' + (ap_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, ap_sc_id);
+
+       of_platform_populate(root, of_default_bus_match_table,
+                       ap_auxdata_lookup, parent);
 
        sc_dec = readl(VA_SC_BASE + INTEGRATOR_SC_DEC_OFFSET);
        for (i = 0; i < 4; i++) {