diff options
author | Paul Burton <paul.burton@imgtec.com> | 2016-08-26 16:17:34 +0200 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2016-10-05 01:31:20 +0200 |
commit | b6d5e47e67292542a41c3fe367bacb364eb4e601 (patch) | |
tree | 009d252825c827993b2b6fb67b21827cb1fc20a4 /arch | |
parent | MIPS: SEAD3: Split obj-y entries across lines (diff) | |
download | linux-b6d5e47e67292542a41c3fe367bacb364eb4e601.tar.xz linux-b6d5e47e67292542a41c3fe367bacb364eb4e601.zip |
MIPS: SEAD3: Probe interrupt controllers using DT
Probe the CPU interrupt controller & optional Global Interrupt
Controller (GIC) using devicetree rather than platform code. Because the
bootloader on SEAD3 does not provide a device tree to the kernel & the
device tree is always built in, we patch out the GIC node during boot if
we detect that a GIC is not present in the system.
The appropriate IRQ domain is discovered by platform code setting up
device IRQ numbers temporarily. It will be removed by further patches
which move the devices towards being probed via device tree.
No behavioural change is intended by this patch.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: Matt Redfearn <matt.redfearn@imgtec.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Jacek Anaszewski <j.anaszewski@samsung.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/14047/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/boot/dts/mti/sead3.dts | 31 | ||||
-rw-r--r-- | arch/mips/include/asm/mach-sead3/sead3-dtshim.h | 29 | ||||
-rw-r--r-- | arch/mips/include/asm/mips-boards/sead3int.h | 5 | ||||
-rw-r--r-- | arch/mips/mti-sead3/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/mti-sead3/sead3-dtshim.c | 92 | ||||
-rw-r--r-- | arch/mips/mti-sead3/sead3-int.c | 27 | ||||
-rw-r--r-- | arch/mips/mti-sead3/sead3-platform.c | 43 | ||||
-rw-r--r-- | arch/mips/mti-sead3/sead3-setup.c | 13 |
8 files changed, 197 insertions, 44 deletions
diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index e4b317d414f1..051b3a9e5a9e 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -4,10 +4,13 @@ /memreserve/ 0x00001000 0x000ef000; // ROM data /memreserve/ 0x000f0000 0x004cc000; // reserved +#include <dt-bindings/interrupt-controller/mips-gic.h> + / { #address-cells = <1>; #size-cells = <1>; compatible = "mti,sead-3"; + interrupt-parent = <&gic>; cpus { cpu@0 { @@ -19,4 +22,32 @@ device_type = "memory"; reg = <0x0 0x08000000>; }; + + cpu_intc: interrupt-controller { + compatible = "mti,cpu-interrupt-controller"; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + gic: interrupt-controller@1b1c0000 { + compatible = "mti,gic"; + reg = <0x1b1c0000 0x20000>; + + interrupt-controller; + #interrupt-cells = <3>; + + /* + * Declare the interrupt-parent even though the mti,gic + * binding doesn't require it, such that the kernel can + * figure out that cpu_intc is the root interrupt + * controller & should be probed first. + */ + interrupt-parent = <&cpu_intc>; + + timer { + compatible = "mti,gic-timer"; + interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>; + }; + }; }; diff --git a/arch/mips/include/asm/mach-sead3/sead3-dtshim.h b/arch/mips/include/asm/mach-sead3/sead3-dtshim.h new file mode 100644 index 000000000000..f5d7d9c9dd17 --- /dev/null +++ b/arch/mips/include/asm/mach-sead3/sead3-dtshim.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton <paul.burton@imgtec.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __MIPS_SEAD3_DTSHIM_H__ +#define __MIPS_SEAD3_DTSHIM_H__ + +#include <linux/init.h> + +#ifdef CONFIG_MIPS_SEAD3 + +extern void __init *sead3_dt_shim(void *fdt); + +#else /* !CONFIG_MIPS_SEAD3 */ + +static inline void *sead3_dt_shim(void *fdt) +{ + return fdt; +} + +#endif /* !CONFIG_MIPS_SEAD3 */ + +#endif /* __MIPS_SEAD3_DTSHIM_H__ */ diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h index 8932c7de0419..bd85da3d6770 100644 --- a/arch/mips/include/asm/mips-boards/sead3int.h +++ b/arch/mips/include/asm/mips-boards/sead3int.h @@ -12,12 +12,7 @@ #include <linux/irqchip/mips-gic.h> -/* SEAD-3 GIC address space definitions. */ -#define GIC_BASE_ADDR 0x1b1c0000 -#define GIC_ADDRSPACE_SZ (128 * 1024) - /* CPU interrupt offsets */ -#define CPU_INT_GIC 2 #define CPU_INT_EHCI 2 #define CPU_INT_UART0 4 #define CPU_INT_UART1 4 diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile index 8b03cfb12759..aad67aac3dba 100644 --- a/arch/mips/mti-sead3/Makefile +++ b/arch/mips/mti-sead3/Makefile @@ -10,6 +10,7 @@ # obj-y := sead3-lcd.o obj-y += sead3-display.o +obj-y += sead3-dtshim.o obj-y += sead3-init.o obj-y += sead3-int.o obj-y += sead3-platform.o diff --git a/arch/mips/mti-sead3/sead3-dtshim.c b/arch/mips/mti-sead3/sead3-dtshim.c new file mode 100644 index 000000000000..3283a7e19a88 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-dtshim.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton <paul.burton@imgtec.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#define pr_fmt(fmt) "sead3-dtshim: " fmt + +#include <linux/errno.h> +#include <linux/libfdt.h> +#include <linux/printk.h> + +#include <asm/io.h> + +#define SEAD_CONFIG CKSEG1ADDR(0x1b100110) +#define SEAD_CONFIG_GIC_PRESENT BIT(1) + +static unsigned char fdt_buf[16 << 10] __initdata; + +static int remove_gic(void *fdt) +{ + int gic_off, cpu_off, err; + uint32_t cfg, cpu_phandle; + + /* leave the GIC node intact if a GIC is present */ + cfg = __raw_readl((uint32_t *)SEAD_CONFIG); + if (cfg & SEAD_CONFIG_GIC_PRESENT) + return 0; + + gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic"); + if (gic_off < 0) { + pr_err("unable to find DT GIC node: %d\n", gic_off); + return gic_off; + } + + err = fdt_nop_node(fdt, gic_off); + if (err) { + pr_err("unable to nop GIC node\n"); + return err; + } + + cpu_off = fdt_node_offset_by_compatible(fdt, -1, + "mti,cpu-interrupt-controller"); + if (cpu_off < 0) { + pr_err("unable to find CPU intc node: %d\n", cpu_off); + return cpu_off; + } + + cpu_phandle = fdt_get_phandle(fdt, cpu_off); + if (!cpu_phandle) { + pr_err("unable to get CPU intc phandle\n"); + return -EINVAL; + } + + err = fdt_setprop_u32(fdt, 0, "interrupt-parent", cpu_phandle); + if (err) { + pr_err("unable to set root interrupt-parent: %d\n", err); + return err; + } + + return 0; +} + +void __init *sead3_dt_shim(void *fdt) +{ + int err; + + if (fdt_check_header(fdt)) + panic("Corrupt DT"); + + /* if this isn't SEAD3, leave the DT alone */ + if (fdt_node_check_compatible(fdt, 0, "mti,sead-3")) + return fdt; + + err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf)); + if (err) + panic("Unable to open FDT: %d", err); + + err = remove_gic(fdt_buf); + if (err) + panic("Unable to patch FDT: %d", err); + + err = fdt_pack(fdt_buf); + if (err) + panic("Unable to pack FDT: %d\n", err); + + return fdt_buf; +} diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c index e31e17f81eef..2e6b73244ecd 100644 --- a/arch/mips/mti-sead3/sead3-int.c +++ b/arch/mips/mti-sead3/sead3-int.c @@ -6,37 +6,18 @@ * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. */ #include <linux/init.h> -#include <linux/irq.h> +#include <linux/irqchip.h> #include <linux/irqchip/mips-gic.h> -#include <linux/io.h> -#include <asm/irq_cpu.h> -#include <asm/setup.h> - -#include <asm/mips-boards/sead3int.h> - -#define SEAD_CONFIG_GIC_PRESENT_SHF 1 -#define SEAD_CONFIG_GIC_PRESENT_MSK (1 << SEAD_CONFIG_GIC_PRESENT_SHF) -#define SEAD_CONFIG_BASE 0x1b100110 -#define SEAD_CONFIG_SIZE 4 - -static void __iomem *sead3_config_reg; +#include <asm/cpu-info.h> +#include <asm/irq.h> void __init arch_init_irq(void) { - if (!cpu_has_veic) - mips_cpu_irq_init(); + irqchip_init(); - sead3_config_reg = ioremap_nocache(SEAD_CONFIG_BASE, SEAD_CONFIG_SIZE); - gic_present = (__raw_readl(sead3_config_reg) & - SEAD_CONFIG_GIC_PRESENT_MSK) >> - SEAD_CONFIG_GIC_PRESENT_SHF; pr_info("GIC: %spresent\n", (gic_present) ? "" : "not "); pr_info("EIC: %s\n", (current_cpu_data.options & MIPS_CPU_VEIC) ? "on" : "off"); - - if (gic_present) - gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, CPU_INT_GIC, - MIPS_GIC_IRQ_BASE); } diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c index 73b73efbfb05..d6be0298056a 100644 --- a/arch/mips/mti-sead3/sead3-platform.c +++ b/arch/mips/mti-sead3/sead3-platform.c @@ -9,8 +9,10 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/irqchip/mips-gic.h> +#include <linux/irqdomain.h> #include <linux/leds.h> #include <linux/mtd/physmap.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/serial_8250.h> #include <linux/smsc911x.h> @@ -204,16 +206,41 @@ static struct platform_device *sead3_platform_devices[] __initdata = { static int __init sead3_platforms_device_init(void) { + const char *intc_compat; + struct device_node *node; + struct irq_domain *irqd; + + if (gic_present) + intc_compat = "mti,gic"; + else + intc_compat = "mti,cpu-interrupt-controller"; + + node = of_find_compatible_node(NULL, NULL, intc_compat); + if (!node) { + pr_err("unable to find interrupt controller DT node\n"); + return -ENODEV; + } + + irqd = irq_find_host(node); + if (!irqd) { + pr_err("unable to find interrupt controller IRQ domain\n"); + return -ENODEV; + } + if (gic_present) { - uart8250_data[0].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART0; - uart8250_data[1].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART1; - ehci_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_EHCI; - sead3_net_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_NET; + uart8250_data[0].irq = irq_create_mapping(irqd, GIC_INT_UART0); + uart8250_data[1].irq = irq_create_mapping(irqd, GIC_INT_UART1); + ehci_resources[1].start = + irq_create_mapping(irqd, GIC_INT_EHCI); + sead3_net_resources[1].start = + irq_create_mapping(irqd, GIC_INT_NET); } else { - uart8250_data[0].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART0; - uart8250_data[1].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART1; - ehci_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_EHCI; - sead3_net_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_NET; + uart8250_data[0].irq = irq_create_mapping(irqd, CPU_INT_UART0); + uart8250_data[1].irq = irq_create_mapping(irqd, CPU_INT_UART1); + ehci_resources[1].start = + irq_create_mapping(irqd, CPU_INT_EHCI); + sead3_net_resources[1].start = + irq_create_mapping(irqd, CPU_INT_NET); } return platform_add_devices(sead3_platform_devices, diff --git a/arch/mips/mti-sead3/sead3-setup.c b/arch/mips/mti-sead3/sead3-setup.c index edfcaf06680d..c4fc0c6d2654 100644 --- a/arch/mips/mti-sead3/sead3-setup.c +++ b/arch/mips/mti-sead3/sead3-setup.c @@ -13,6 +13,7 @@ #include <asm/prom.h> #include <asm/fw/fw.h> +#include <asm/mach-sead3/sead3-dtshim.h> #include <asm/mips-boards/generic.h> const char *get_system_type(void) @@ -89,20 +90,16 @@ void __init *plat_get_fdt(void) void __init plat_mem_setup(void) { + void *fdt = plat_get_fdt(); + /* allow command line/bootloader env to override memory size in DT */ parse_memsize_param(); - /* - * Load the builtin devicetree. This causes the chosen node to be - * parsed resulting in our memory appearing - */ - __dt_setup_arch(__dtb_start); + fdt = sead3_dt_shim(fdt); + __dt_setup_arch(fdt); } void __init device_tree_init(void) { - if (!initial_boot_params) - return; - unflatten_and_copy_device_tree(); } |