From: Jon Medhurst tixy@linaro.org
The A15xA7 models simulate a Cache Coherent Interconnect (CCI) and this needs to be initialised correctly for Linux to boot.
To perform this initiation we add the new function configure_from_fdt() which will look in the fdt for devices to initialise. In this first case we look for the CCI node and if found then setup this device.
Signed-off-by: Jon Medhurst tixy@linaro.org --- semi_loader.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
diff --git a/semi_loader.c b/semi_loader.c index c9750be..ca70633 100644 --- a/semi_loader.c +++ b/semi_loader.c @@ -242,6 +242,54 @@ libfdt_error: fatal("libfdt: ", fdt_strerror(e), ", while updating device tree\n"); }
+/* For accessing 32-bit device ports */ +#define io32(p) (*(volatile uint32_t *)(p)) + +static void init_cci(unsigned cci) +{ + info("Initialising CCI\n"); + + /* + * Ideally, the CCI device tree binding would include suitable + * information so we can correctly configure the CCI, but for + * now we'll just hard-code settings for the present A15xA7 + * models. + */ + + /* Turn on CCI snoops and DVM messages */ + io32(cci+0x4000) = 0x3; /* A15 cluster */ + io32(cci+0x5000) = 0x3; /* A7 cluster */ + + /* Wait while change pending bit of status register is set */ + while(io32(cci+0xc) & 0x1) + {} +} + +static void configure_from_fdt(struct loader_info *info) +{ + void *fdt = (void *)info->fdt_start; + uint32_t const *p; + int addrcells, sizecells; + int offset, len; + + if(!fdt) + return; + + _fdt_address_and_size_cells(fdt, &addrcells, &sizecells); + + /* See if there is a CCI device to initialise */ + offset = fdt_node_offset_by_compatible(fdt, 0, "arm,cci"); + if (offset >= 0) { + p = fdt_getprop(fdt, offset, "reg", &len); + if(len != (addrcells + sizecells) * 4) + info("Failed parsing device-tree node for CCI\n"); + else + init_cci(fdt32_to_cpu(p[addrcells - 1])); + } + + return; +} + static int is_space(char c) { return c == ' '; @@ -598,4 +646,6 @@ args_done: atag_append(&atagp, ATAG_NONE, 0, 0);
update_fdt(&phys, info); + + configure_from_fdt(info); }