ARM: integrator: hook the AP into the SoC bus

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>
This commit is contained in:
Linus Walleij 2012-11-02 01:31:10 +01:00
parent 6f0c0580b7
commit e67ae6be73
5 changed files with 153 additions and 2 deletions

View file

@ -18,6 +18,11 @@
bootargs = "root=/dev/ram0 console=ttyAM0,38400n8 earlyprintk";
};
syscon {
/* AP system controller registers */
reg = <0x11000000 0x100>;
};
timer0: timer@13000000 {
compatible = "arm,integrator-timer";
};

View 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.

View 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);

View 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);
}

View 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++) {