diff options
Diffstat (limited to 'arch/arm/mach-zynq/common.c')
| -rw-r--r-- | arch/arm/mach-zynq/common.c | 196 |
1 files changed, 141 insertions, 55 deletions
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index e16d4bed0f7..31a6fa40ba3 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -19,11 +19,18 @@ #include <linux/cpumask.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/clk/zynq.h> +#include <linux/clocksource.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of.h> +#include <linux/memblock.h> +#include <linux/irqchip.h> +#include <linux/irqchip/arm-gic.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -31,95 +38,174 @@ #include <asm/mach-types.h> #include <asm/page.h> #include <asm/pgtable.h> -#include <asm/hardware/gic.h> +#include <asm/smp_scu.h> +#include <asm/system_info.h> #include <asm/hardware/cache-l2x0.h> #include "common.h" -static struct of_device_id zynq_of_bus_ids[] __initdata = { - { .compatible = "simple-bus", }, - {} -}; +#define ZYNQ_DEVCFG_MCTRL 0x80 +#define ZYNQ_DEVCFG_PS_VERSION_SHIFT 28 +#define ZYNQ_DEVCFG_PS_VERSION_MASK 0xF + +void __iomem *zynq_scu_base; /** - * xilinx_init_machine() - System specific initialization, intended to be - * called from board specific initialization. + * zynq_memory_init - Initialize special memory + * + * We need to stop things allocating the low memory as DMA can't work in + * the 1st 512K of memory. */ -static void __init xilinx_init_machine(void) +static void __init zynq_memory_init(void) { - /* - * 64KB way size, 8-way associativity, parity disabled - */ - l2x0_of_init(0x02060000, 0xF0F0FFFF); - - of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL); + if (!__pa(PAGE_OFFSET)) + memblock_reserve(__pa(PAGE_OFFSET), __pa(swapper_pg_dir)); } -static struct of_device_id irq_match[] __initdata = { - { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, - { } +static struct platform_device zynq_cpuidle_device = { + .name = "cpuidle-zynq", }; /** - * xilinx_irq_init() - Interrupt controller initialization for the GIC. + * zynq_get_revision - Get Zynq silicon revision + * + * Return: Silicon version or -1 otherwise */ -static void __init xilinx_irq_init(void) +static int __init zynq_get_revision(void) { - of_irq_init(irq_match); -} + struct device_node *np; + void __iomem *zynq_devcfg_base; + u32 revision; -#define SCU_PERIPH_PHYS 0xF8F00000 -#define SCU_PERIPH_SIZE SZ_8K -#define SCU_PERIPH_VIRT (VMALLOC_END - SCU_PERIPH_SIZE) + np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-devcfg-1.0"); + if (!np) { + pr_err("%s: no devcfg node found\n", __func__); + return -1; + } -static struct map_desc scu_desc __initdata = { - .virtual = SCU_PERIPH_VIRT, - .pfn = __phys_to_pfn(SCU_PERIPH_PHYS), - .length = SCU_PERIPH_SIZE, - .type = MT_DEVICE, -}; + zynq_devcfg_base = of_iomap(np, 0); + if (!zynq_devcfg_base) { + pr_err("%s: Unable to map I/O memory\n", __func__); + return -1; + } + + revision = readl(zynq_devcfg_base + ZYNQ_DEVCFG_MCTRL); + revision >>= ZYNQ_DEVCFG_PS_VERSION_SHIFT; + revision &= ZYNQ_DEVCFG_PS_VERSION_MASK; + + iounmap(zynq_devcfg_base); + + return revision; +} -static void __init xilinx_zynq_timer_init(void) +/** + * zynq_init_machine - System specific initialization, intended to be + * called from board specific initialization. + */ +static void __init zynq_init_machine(void) { - struct device_node *np; - void __iomem *slcr; + struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + struct device *parent = NULL; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + goto out; + + system_rev = zynq_get_revision(); + + soc_dev_attr->family = kasprintf(GFP_KERNEL, "Xilinx Zynq"); + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "0x%x", system_rev); + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", + zynq_slcr_get_device_id()); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->family); + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr->soc_id); + kfree(soc_dev_attr); + goto out; + } + + parent = soc_device_to_device(soc_dev); + +out: + /* + * Finished with the static registrations now; fill in the missing + * devices + */ + of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); - np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-slcr"); - slcr = of_iomap(np, 0); - WARN_ON(!slcr); + platform_device_register(&zynq_cpuidle_device); + platform_device_register_full(&devinfo); + + zynq_slcr_init(); +} - xilinx_zynq_clocks_init(slcr); +static void __init zynq_timer_init(void) +{ + zynq_early_slcr_init(); - xttcpss_timer_init(); + zynq_clock_init(); + of_clk_init(NULL); + clocksource_of_init(); } -/* - * Instantiate and initialize the system timer structure - */ -static struct sys_timer xttcpss_sys_timer = { - .init = xilinx_zynq_timer_init, +static struct map_desc zynq_cortex_a9_scu_map __initdata = { + .length = SZ_256, + .type = MT_DEVICE, }; +static void __init zynq_scu_map_io(void) +{ + unsigned long base; + + base = scu_a9_get_base(); + zynq_cortex_a9_scu_map.pfn = __phys_to_pfn(base); + /* Expected address is in vmalloc area that's why simple assign here */ + zynq_cortex_a9_scu_map.virtual = base; + iotable_init(&zynq_cortex_a9_scu_map, 1); + zynq_scu_base = (void __iomem *)base; + BUG_ON(!zynq_scu_base); +} + /** - * xilinx_map_io() - Create memory mappings needed for early I/O. + * zynq_map_io - Create memory mappings needed for early I/O. */ -static void __init xilinx_map_io(void) +static void __init zynq_map_io(void) { debug_ll_io_init(); - iotable_init(&scu_desc, 1); + zynq_scu_map_io(); +} + +static void __init zynq_irq_init(void) +{ + gic_arch_extn.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; + irqchip_init(); +} + +static void zynq_system_reset(enum reboot_mode mode, const char *cmd) +{ + zynq_slcr_system_reset(); } -static const char *xilinx_dt_match[] = { - "xlnx,zynq-zc702", +static const char * const zynq_dt_match[] = { "xlnx,zynq-7000", NULL }; -MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") - .map_io = xilinx_map_io, - .init_irq = xilinx_irq_init, - .handle_irq = gic_handle_irq, - .init_machine = xilinx_init_machine, - .timer = &xttcpss_sys_timer, - .dt_compat = xilinx_dt_match, +DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") + /* 64KB way size, 8-way associativity, parity disabled */ + .l2c_aux_val = 0x02000000, + .l2c_aux_mask = 0xf0ffffff, + .smp = smp_ops(zynq_smp_ops), + .map_io = zynq_map_io, + .init_irq = zynq_irq_init, + .init_machine = zynq_init_machine, + .init_time = zynq_timer_init, + .dt_compat = zynq_dt_match, + .reserve = zynq_memory_init, + .restart = zynq_system_reset, MACHINE_END |
