diff options
author | Kevin Cernekee <cernekee@gmail.com> | 2014-12-25 12:49:14 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2015-04-01 11:21:40 -0400 |
commit | 4b049a6b275db68c2c028937b89abd732dcdf536 (patch) | |
tree | c258057e0d8a7649c81f00170aa3a2978b0b9194 | |
parent | c4b257091745170183e73d476906cabaf7edd540 (diff) |
MIPS: BMIPS: Add quirks for several Broadcom platforms
A couple of chips require special handling in order to make SMP secondary
boot and/or exception vectors work correctly. Take care of these in
setup.c.
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Cc: f.fainelli@gmail.com
Cc: jaedon.shin@gmail.com
Cc: abrestic@chromium.org
Cc: tglx@linutronix.de
Cc: jason@lakedaemon.net
Cc: jogo@openwrt.org
Cc: arnd@arndb.de
Cc: computersforpeace@gmail.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/8852/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/bmips/setup.c | 101 |
1 files changed, 99 insertions, 2 deletions
diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index ac402ed8443b..fae800e8b1e1 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c | |||
@@ -8,9 +8,12 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/bitops.h> | ||
11 | #include <linux/bootmem.h> | 12 | #include <linux/bootmem.h> |
12 | #include <linux/clk-provider.h> | 13 | #include <linux/clk-provider.h> |
13 | #include <linux/ioport.h> | 14 | #include <linux/ioport.h> |
15 | #include <linux/kernel.h> | ||
16 | #include <linux/io.h> | ||
14 | #include <linux/of.h> | 17 | #include <linux/of.h> |
15 | #include <linux/of_fdt.h> | 18 | #include <linux/of_fdt.h> |
16 | #include <linux/of_platform.h> | 19 | #include <linux/of_platform.h> |
@@ -18,9 +21,92 @@ | |||
18 | #include <asm/addrspace.h> | 21 | #include <asm/addrspace.h> |
19 | #include <asm/bmips.h> | 22 | #include <asm/bmips.h> |
20 | #include <asm/bootinfo.h> | 23 | #include <asm/bootinfo.h> |
24 | #include <asm/cpu-type.h> | ||
25 | #include <asm/mipsregs.h> | ||
21 | #include <asm/prom.h> | 26 | #include <asm/prom.h> |
22 | #include <asm/smp-ops.h> | 27 | #include <asm/smp-ops.h> |
23 | #include <asm/time.h> | 28 | #include <asm/time.h> |
29 | #include <asm/traps.h> | ||
30 | |||
31 | #define RELO_NORMAL_VEC BIT(18) | ||
32 | |||
33 | #define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c)) | ||
34 | #define BCM6328_TP1_DISABLED BIT(9) | ||
35 | |||
36 | static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000; | ||
37 | |||
38 | struct bmips_quirk { | ||
39 | const char *compatible; | ||
40 | void (*quirk_fn)(void); | ||
41 | }; | ||
42 | |||
43 | static void kbase_setup(void) | ||
44 | { | ||
45 | __raw_writel(kbase | RELO_NORMAL_VEC, | ||
46 | BMIPS_GET_CBR() + BMIPS_RELO_VECTOR_CONTROL_1); | ||
47 | ebase = kbase; | ||
48 | } | ||
49 | |||
50 | static void bcm3384_viper_quirks(void) | ||
51 | { | ||
52 | /* | ||
53 | * Some experimental CM boxes are set up to let CM own the Viper TP0 | ||
54 | * and let Linux own TP1. This requires moving the kernel | ||
55 | * load address to a non-conflicting region (e.g. via | ||
56 | * CONFIG_PHYSICAL_START) and supplying an alternate DTB. | ||
57 | * If we detect this condition, we need to move the MIPS exception | ||
58 | * vectors up to an area that we own. | ||
59 | * | ||
60 | * This is distinct from the OTHER special case mentioned in | ||
61 | * smp-bmips.c (boot on TP1, but enable SMP, then TP0 becomes our | ||
62 | * logical CPU#1). For the Viper TP1 case, SMP is off limits. | ||
63 | * | ||
64 | * Also note that many BMIPS435x CPUs do not have a | ||
65 | * BMIPS_RELO_VECTOR_CONTROL_1 register, so it isn't safe to just | ||
66 | * write VMLINUX_LOAD_ADDRESS into that register on every SoC. | ||
67 | */ | ||
68 | board_ebase_setup = &kbase_setup; | ||
69 | bmips_smp_enabled = 0; | ||
70 | } | ||
71 | |||
72 | static void bcm63xx_fixup_cpu1(void) | ||
73 | { | ||
74 | /* | ||
75 | * The bootloader has set up the CPU1 reset vector at | ||
76 | * 0xa000_0200. | ||
77 | * This conflicts with the special interrupt vector (IV). | ||
78 | * The bootloader has also set up CPU1 to respond to the wrong | ||
79 | * IPI interrupt. | ||
80 | * Here we will start up CPU1 in the background and ask it to | ||
81 | * reconfigure itself then go back to sleep. | ||
82 | */ | ||
83 | memcpy((void *)0xa0000200, &bmips_smp_movevec, 0x20); | ||
84 | __sync(); | ||
85 | set_c0_cause(C_SW0); | ||
86 | cpumask_set_cpu(1, &bmips_booted_mask); | ||
87 | } | ||
88 | |||
89 | static void bcm6328_quirks(void) | ||
90 | { | ||
91 | /* Check CPU1 status in OTP (it is usually disabled) */ | ||
92 | if (__raw_readl(REG_BCM6328_OTP) & BCM6328_TP1_DISABLED) | ||
93 | bmips_smp_enabled = 0; | ||
94 | else | ||
95 | bcm63xx_fixup_cpu1(); | ||
96 | } | ||
97 | |||
98 | static void bcm6368_quirks(void) | ||
99 | { | ||
100 | bcm63xx_fixup_cpu1(); | ||
101 | } | ||
102 | |||
103 | static const struct bmips_quirk bmips_quirk_list[] = { | ||
104 | { "brcm,bcm3384-viper", &bcm3384_viper_quirks }, | ||
105 | { "brcm,bcm33843-viper", &bcm3384_viper_quirks }, | ||
106 | { "brcm,bcm6328", &bcm6328_quirks }, | ||
107 | { "brcm,bcm6368", &bcm6368_quirks }, | ||
108 | { }, | ||
109 | }; | ||
24 | 110 | ||
25 | void __init prom_init(void) | 111 | void __init prom_init(void) |
26 | { | 112 | { |
@@ -53,7 +139,8 @@ void __init plat_time_init(void) | |||
53 | 139 | ||
54 | void __init plat_mem_setup(void) | 140 | void __init plat_mem_setup(void) |
55 | { | 141 | { |
56 | void *dtb = __dtb_start; | 142 | void *dtb; |
143 | const struct bmips_quirk *q; | ||
57 | 144 | ||
58 | set_io_port_base(0); | 145 | set_io_port_base(0); |
59 | ioport_resource.start = 0; | 146 | ioport_resource.start = 0; |
@@ -62,10 +149,20 @@ void __init plat_mem_setup(void) | |||
62 | /* intended to somewhat resemble ARM; see Documentation/arm/Booting */ | 149 | /* intended to somewhat resemble ARM; see Documentation/arm/Booting */ |
63 | if (fw_arg0 == 0 && fw_arg1 == 0xffffffff) | 150 | if (fw_arg0 == 0 && fw_arg1 == 0xffffffff) |
64 | dtb = phys_to_virt(fw_arg2); | 151 | dtb = phys_to_virt(fw_arg2); |
152 | else if (__dtb_start != __dtb_end) | ||
153 | dtb = (void *)__dtb_start; | ||
154 | else | ||
155 | panic("no dtb found"); | ||
65 | 156 | ||
66 | __dt_setup_arch(dtb); | 157 | __dt_setup_arch(dtb); |
67 | |||
68 | strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); | 158 | strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); |
159 | |||
160 | for (q = bmips_quirk_list; q->quirk_fn; q++) { | ||
161 | if (of_flat_dt_is_compatible(of_get_flat_dt_root(), | ||
162 | q->compatible)) { | ||
163 | q->quirk_fn(); | ||
164 | } | ||
165 | } | ||
69 | } | 166 | } |
70 | 167 | ||
71 | void __init device_tree_init(void) | 168 | void __init device_tree_init(void) |