aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2016-08-26 10:17:34 -0400
committerRalf Baechle <ralf@linux-mips.org>2016-10-04 19:31:20 -0400
commitb6d5e47e67292542a41c3fe367bacb364eb4e601 (patch)
tree009d252825c827993b2b6fb67b21827cb1fc20a4
parent0a15273666aa18a45985e6419afa05ec24ecfeb4 (diff)
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>
-rw-r--r--arch/mips/boot/dts/mti/sead3.dts31
-rw-r--r--arch/mips/include/asm/mach-sead3/sead3-dtshim.h29
-rw-r--r--arch/mips/include/asm/mips-boards/sead3int.h5
-rw-r--r--arch/mips/mti-sead3/Makefile1
-rw-r--r--arch/mips/mti-sead3/sead3-dtshim.c92
-rw-r--r--arch/mips/mti-sead3/sead3-int.c27
-rw-r--r--arch/mips/mti-sead3/sead3-platform.c43
-rw-r--r--arch/mips/mti-sead3/sead3-setup.c13
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 @@
4/memreserve/ 0x00001000 0x000ef000; // ROM data 4/memreserve/ 0x00001000 0x000ef000; // ROM data
5/memreserve/ 0x000f0000 0x004cc000; // reserved 5/memreserve/ 0x000f0000 0x004cc000; // reserved
6 6
7#include <dt-bindings/interrupt-controller/mips-gic.h>
8
7/ { 9/ {
8 #address-cells = <1>; 10 #address-cells = <1>;
9 #size-cells = <1>; 11 #size-cells = <1>;
10 compatible = "mti,sead-3"; 12 compatible = "mti,sead-3";
13 interrupt-parent = <&gic>;
11 14
12 cpus { 15 cpus {
13 cpu@0 { 16 cpu@0 {
@@ -19,4 +22,32 @@
19 device_type = "memory"; 22 device_type = "memory";
20 reg = <0x0 0x08000000>; 23 reg = <0x0 0x08000000>;
21 }; 24 };
25
26 cpu_intc: interrupt-controller {
27 compatible = "mti,cpu-interrupt-controller";
28
29 interrupt-controller;
30 #interrupt-cells = <1>;
31 };
32
33 gic: interrupt-controller@1b1c0000 {
34 compatible = "mti,gic";
35 reg = <0x1b1c0000 0x20000>;
36
37 interrupt-controller;
38 #interrupt-cells = <3>;
39
40 /*
41 * Declare the interrupt-parent even though the mti,gic
42 * binding doesn't require it, such that the kernel can
43 * figure out that cpu_intc is the root interrupt
44 * controller & should be probed first.
45 */
46 interrupt-parent = <&cpu_intc>;
47
48 timer {
49 compatible = "mti,gic-timer";
50 interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
51 };
52 };
22}; 53};
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 @@
1/*
2 * Copyright (C) 2016 Imagination Technologies
3 * Author: Paul Burton <paul.burton@imgtec.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 */
10
11#ifndef __MIPS_SEAD3_DTSHIM_H__
12#define __MIPS_SEAD3_DTSHIM_H__
13
14#include <linux/init.h>
15
16#ifdef CONFIG_MIPS_SEAD3
17
18extern void __init *sead3_dt_shim(void *fdt);
19
20#else /* !CONFIG_MIPS_SEAD3 */
21
22static inline void *sead3_dt_shim(void *fdt)
23{
24 return fdt;
25}
26
27#endif /* !CONFIG_MIPS_SEAD3 */
28
29#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 @@
12 12
13#include <linux/irqchip/mips-gic.h> 13#include <linux/irqchip/mips-gic.h>
14 14
15/* SEAD-3 GIC address space definitions. */
16#define GIC_BASE_ADDR 0x1b1c0000
17#define GIC_ADDRSPACE_SZ (128 * 1024)
18
19/* CPU interrupt offsets */ 15/* CPU interrupt offsets */
20#define CPU_INT_GIC 2
21#define CPU_INT_EHCI 2 16#define CPU_INT_EHCI 2
22#define CPU_INT_UART0 4 17#define CPU_INT_UART0 4
23#define CPU_INT_UART1 4 18#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 @@
10# 10#
11obj-y := sead3-lcd.o 11obj-y := sead3-lcd.o
12obj-y += sead3-display.o 12obj-y += sead3-display.o
13obj-y += sead3-dtshim.o
13obj-y += sead3-init.o 14obj-y += sead3-init.o
14obj-y += sead3-int.o 15obj-y += sead3-int.o
15obj-y += sead3-platform.o 16obj-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 @@
1/*
2 * Copyright (C) 2016 Imagination Technologies
3 * Author: Paul Burton <paul.burton@imgtec.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 */
10
11#define pr_fmt(fmt) "sead3-dtshim: " fmt
12
13#include <linux/errno.h>
14#include <linux/libfdt.h>
15#include <linux/printk.h>
16
17#include <asm/io.h>
18
19#define SEAD_CONFIG CKSEG1ADDR(0x1b100110)
20#define SEAD_CONFIG_GIC_PRESENT BIT(1)
21
22static unsigned char fdt_buf[16 << 10] __initdata;
23
24static int remove_gic(void *fdt)
25{
26 int gic_off, cpu_off, err;
27 uint32_t cfg, cpu_phandle;
28
29 /* leave the GIC node intact if a GIC is present */
30 cfg = __raw_readl((uint32_t *)SEAD_CONFIG);
31 if (cfg & SEAD_CONFIG_GIC_PRESENT)
32 return 0;
33
34 gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic");
35 if (gic_off < 0) {
36 pr_err("unable to find DT GIC node: %d\n", gic_off);
37 return gic_off;
38 }
39
40 err = fdt_nop_node(fdt, gic_off);
41 if (err) {
42 pr_err("unable to nop GIC node\n");
43 return err;
44 }
45
46 cpu_off = fdt_node_offset_by_compatible(fdt, -1,
47 "mti,cpu-interrupt-controller");
48 if (cpu_off < 0) {
49 pr_err("unable to find CPU intc node: %d\n", cpu_off);
50 return cpu_off;
51 }
52
53 cpu_phandle = fdt_get_phandle(fdt, cpu_off);
54 if (!cpu_phandle) {
55 pr_err("unable to get CPU intc phandle\n");
56 return -EINVAL;
57 }
58
59 err = fdt_setprop_u32(fdt, 0, "interrupt-parent", cpu_phandle);
60 if (err) {
61 pr_err("unable to set root interrupt-parent: %d\n", err);
62 return err;
63 }
64
65 return 0;
66}
67
68void __init *sead3_dt_shim(void *fdt)
69{
70 int err;
71
72 if (fdt_check_header(fdt))
73 panic("Corrupt DT");
74
75 /* if this isn't SEAD3, leave the DT alone */
76 if (fdt_node_check_compatible(fdt, 0, "mti,sead-3"))
77 return fdt;
78
79 err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf));
80 if (err)
81 panic("Unable to open FDT: %d", err);
82
83 err = remove_gic(fdt_buf);
84 if (err)
85 panic("Unable to patch FDT: %d", err);
86
87 err = fdt_pack(fdt_buf);
88 if (err)
89 panic("Unable to pack FDT: %d\n", err);
90
91 return fdt_buf;
92}
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 @@
6 * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. 6 * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
7 */ 7 */
8#include <linux/init.h> 8#include <linux/init.h>
9#include <linux/irq.h> 9#include <linux/irqchip.h>
10#include <linux/irqchip/mips-gic.h> 10#include <linux/irqchip/mips-gic.h>
11#include <linux/io.h>
12 11
13#include <asm/irq_cpu.h> 12#include <asm/cpu-info.h>
14#include <asm/setup.h> 13#include <asm/irq.h>
15
16#include <asm/mips-boards/sead3int.h>
17
18#define SEAD_CONFIG_GIC_PRESENT_SHF 1
19#define SEAD_CONFIG_GIC_PRESENT_MSK (1 << SEAD_CONFIG_GIC_PRESENT_SHF)
20#define SEAD_CONFIG_BASE 0x1b100110
21#define SEAD_CONFIG_SIZE 4
22
23static void __iomem *sead3_config_reg;
24 14
25void __init arch_init_irq(void) 15void __init arch_init_irq(void)
26{ 16{
27 if (!cpu_has_veic) 17 irqchip_init();
28 mips_cpu_irq_init();
29 18
30 sead3_config_reg = ioremap_nocache(SEAD_CONFIG_BASE, SEAD_CONFIG_SIZE);
31 gic_present = (__raw_readl(sead3_config_reg) &
32 SEAD_CONFIG_GIC_PRESENT_MSK) >>
33 SEAD_CONFIG_GIC_PRESENT_SHF;
34 pr_info("GIC: %spresent\n", (gic_present) ? "" : "not "); 19 pr_info("GIC: %spresent\n", (gic_present) ? "" : "not ");
35 pr_info("EIC: %s\n", 20 pr_info("EIC: %s\n",
36 (current_cpu_data.options & MIPS_CPU_VEIC) ? "on" : "off"); 21 (current_cpu_data.options & MIPS_CPU_VEIC) ? "on" : "off");
37
38 if (gic_present)
39 gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, CPU_INT_GIC,
40 MIPS_GIC_IRQ_BASE);
41} 22}
42 23
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 @@
9#include <linux/init.h> 9#include <linux/init.h>
10#include <linux/irq.h> 10#include <linux/irq.h>
11#include <linux/irqchip/mips-gic.h> 11#include <linux/irqchip/mips-gic.h>
12#include <linux/irqdomain.h>
12#include <linux/leds.h> 13#include <linux/leds.h>
13#include <linux/mtd/physmap.h> 14#include <linux/mtd/physmap.h>
15#include <linux/of.h>
14#include <linux/platform_device.h> 16#include <linux/platform_device.h>
15#include <linux/serial_8250.h> 17#include <linux/serial_8250.h>
16#include <linux/smsc911x.h> 18#include <linux/smsc911x.h>
@@ -204,16 +206,41 @@ static struct platform_device *sead3_platform_devices[] __initdata = {
204 206
205static int __init sead3_platforms_device_init(void) 207static int __init sead3_platforms_device_init(void)
206{ 208{
209 const char *intc_compat;
210 struct device_node *node;
211 struct irq_domain *irqd;
212
213 if (gic_present)
214 intc_compat = "mti,gic";
215 else
216 intc_compat = "mti,cpu-interrupt-controller";
217
218 node = of_find_compatible_node(NULL, NULL, intc_compat);
219 if (!node) {
220 pr_err("unable to find interrupt controller DT node\n");
221 return -ENODEV;
222 }
223
224 irqd = irq_find_host(node);
225 if (!irqd) {
226 pr_err("unable to find interrupt controller IRQ domain\n");
227 return -ENODEV;
228 }
229
207 if (gic_present) { 230 if (gic_present) {
208 uart8250_data[0].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART0; 231 uart8250_data[0].irq = irq_create_mapping(irqd, GIC_INT_UART0);
209 uart8250_data[1].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART1; 232 uart8250_data[1].irq = irq_create_mapping(irqd, GIC_INT_UART1);
210 ehci_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_EHCI; 233 ehci_resources[1].start =
211 sead3_net_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_NET; 234 irq_create_mapping(irqd, GIC_INT_EHCI);
235 sead3_net_resources[1].start =
236 irq_create_mapping(irqd, GIC_INT_NET);
212 } else { 237 } else {
213 uart8250_data[0].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART0; 238 uart8250_data[0].irq = irq_create_mapping(irqd, CPU_INT_UART0);
214 uart8250_data[1].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART1; 239 uart8250_data[1].irq = irq_create_mapping(irqd, CPU_INT_UART1);
215 ehci_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_EHCI; 240 ehci_resources[1].start =
216 sead3_net_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_NET; 241 irq_create_mapping(irqd, CPU_INT_EHCI);
242 sead3_net_resources[1].start =
243 irq_create_mapping(irqd, CPU_INT_NET);
217 } 244 }
218 245
219 return platform_add_devices(sead3_platform_devices, 246 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 @@
13#include <asm/prom.h> 13#include <asm/prom.h>
14#include <asm/fw/fw.h> 14#include <asm/fw/fw.h>
15 15
16#include <asm/mach-sead3/sead3-dtshim.h>
16#include <asm/mips-boards/generic.h> 17#include <asm/mips-boards/generic.h>
17 18
18const char *get_system_type(void) 19const char *get_system_type(void)
@@ -89,20 +90,16 @@ void __init *plat_get_fdt(void)
89 90
90void __init plat_mem_setup(void) 91void __init plat_mem_setup(void)
91{ 92{
93 void *fdt = plat_get_fdt();
94
92 /* allow command line/bootloader env to override memory size in DT */ 95 /* allow command line/bootloader env to override memory size in DT */
93 parse_memsize_param(); 96 parse_memsize_param();
94 97
95 /* 98 fdt = sead3_dt_shim(fdt);
96 * Load the builtin devicetree. This causes the chosen node to be 99 __dt_setup_arch(fdt);
97 * parsed resulting in our memory appearing
98 */
99 __dt_setup_arch(__dtb_start);
100} 100}
101 101
102void __init device_tree_init(void) 102void __init device_tree_init(void)
103{ 103{
104 if (!initial_boot_params)
105 return;
106
107 unflatten_and_copy_device_tree(); 104 unflatten_and_copy_device_tree();
108} 105}