1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
3*4882a593Smuzhiyun * License. See the file "COPYING" in the main directory of this archive
4*4882a593Smuzhiyun * for more details.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7*4882a593Smuzhiyun * Copyright (C) 2014 Kevin Cernekee <cernekee@gmail.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/bitops.h>
12*4882a593Smuzhiyun #include <linux/memblock.h>
13*4882a593Smuzhiyun #include <linux/ioport.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/io.h>
16*4882a593Smuzhiyun #include <linux/of.h>
17*4882a593Smuzhiyun #include <linux/of_clk.h>
18*4882a593Smuzhiyun #include <linux/of_fdt.h>
19*4882a593Smuzhiyun #include <linux/of_platform.h>
20*4882a593Smuzhiyun #include <linux/libfdt.h>
21*4882a593Smuzhiyun #include <linux/smp.h>
22*4882a593Smuzhiyun #include <asm/addrspace.h>
23*4882a593Smuzhiyun #include <asm/bmips.h>
24*4882a593Smuzhiyun #include <asm/bootinfo.h>
25*4882a593Smuzhiyun #include <asm/cpu-type.h>
26*4882a593Smuzhiyun #include <asm/mipsregs.h>
27*4882a593Smuzhiyun #include <asm/prom.h>
28*4882a593Smuzhiyun #include <asm/smp-ops.h>
29*4882a593Smuzhiyun #include <asm/time.h>
30*4882a593Smuzhiyun #include <asm/traps.h>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define RELO_NORMAL_VEC BIT(18)
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c))
35*4882a593Smuzhiyun #define BCM6328_TP1_DISABLED BIT(9)
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun struct bmips_quirk {
40*4882a593Smuzhiyun const char *compatible;
41*4882a593Smuzhiyun void (*quirk_fn)(void);
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun
kbase_setup(void)44*4882a593Smuzhiyun static void kbase_setup(void)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun __raw_writel(kbase | RELO_NORMAL_VEC,
47*4882a593Smuzhiyun BMIPS_GET_CBR() + BMIPS_RELO_VECTOR_CONTROL_1);
48*4882a593Smuzhiyun ebase = kbase;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
bcm3384_viper_quirks(void)51*4882a593Smuzhiyun static void bcm3384_viper_quirks(void)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun /*
54*4882a593Smuzhiyun * Some experimental CM boxes are set up to let CM own the Viper TP0
55*4882a593Smuzhiyun * and let Linux own TP1. This requires moving the kernel
56*4882a593Smuzhiyun * load address to a non-conflicting region (e.g. via
57*4882a593Smuzhiyun * CONFIG_PHYSICAL_START) and supplying an alternate DTB.
58*4882a593Smuzhiyun * If we detect this condition, we need to move the MIPS exception
59*4882a593Smuzhiyun * vectors up to an area that we own.
60*4882a593Smuzhiyun *
61*4882a593Smuzhiyun * This is distinct from the OTHER special case mentioned in
62*4882a593Smuzhiyun * smp-bmips.c (boot on TP1, but enable SMP, then TP0 becomes our
63*4882a593Smuzhiyun * logical CPU#1). For the Viper TP1 case, SMP is off limits.
64*4882a593Smuzhiyun *
65*4882a593Smuzhiyun * Also note that many BMIPS435x CPUs do not have a
66*4882a593Smuzhiyun * BMIPS_RELO_VECTOR_CONTROL_1 register, so it isn't safe to just
67*4882a593Smuzhiyun * write VMLINUX_LOAD_ADDRESS into that register on every SoC.
68*4882a593Smuzhiyun */
69*4882a593Smuzhiyun board_ebase_setup = &kbase_setup;
70*4882a593Smuzhiyun bmips_smp_enabled = 0;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
bcm63xx_fixup_cpu1(void)73*4882a593Smuzhiyun static void bcm63xx_fixup_cpu1(void)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun /*
76*4882a593Smuzhiyun * The bootloader has set up the CPU1 reset vector at
77*4882a593Smuzhiyun * 0xa000_0200.
78*4882a593Smuzhiyun * This conflicts with the special interrupt vector (IV).
79*4882a593Smuzhiyun * The bootloader has also set up CPU1 to respond to the wrong
80*4882a593Smuzhiyun * IPI interrupt.
81*4882a593Smuzhiyun * Here we will start up CPU1 in the background and ask it to
82*4882a593Smuzhiyun * reconfigure itself then go back to sleep.
83*4882a593Smuzhiyun */
84*4882a593Smuzhiyun memcpy((void *)0xa0000200, &bmips_smp_movevec, 0x20);
85*4882a593Smuzhiyun __sync();
86*4882a593Smuzhiyun set_c0_cause(C_SW0);
87*4882a593Smuzhiyun cpumask_set_cpu(1, &bmips_booted_mask);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
bcm6328_quirks(void)90*4882a593Smuzhiyun static void bcm6328_quirks(void)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun /* Check CPU1 status in OTP (it is usually disabled) */
93*4882a593Smuzhiyun if (__raw_readl(REG_BCM6328_OTP) & BCM6328_TP1_DISABLED)
94*4882a593Smuzhiyun bmips_smp_enabled = 0;
95*4882a593Smuzhiyun else
96*4882a593Smuzhiyun bcm63xx_fixup_cpu1();
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
bcm6358_quirks(void)99*4882a593Smuzhiyun static void bcm6358_quirks(void)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun /*
102*4882a593Smuzhiyun * BCM3368/BCM6358 need special handling for their shared TLB, so
103*4882a593Smuzhiyun * disable SMP for now
104*4882a593Smuzhiyun */
105*4882a593Smuzhiyun bmips_smp_enabled = 0;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
bcm6368_quirks(void)108*4882a593Smuzhiyun static void bcm6368_quirks(void)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun bcm63xx_fixup_cpu1();
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun static const struct bmips_quirk bmips_quirk_list[] = {
114*4882a593Smuzhiyun { "brcm,bcm3368", &bcm6358_quirks },
115*4882a593Smuzhiyun { "brcm,bcm3384-viper", &bcm3384_viper_quirks },
116*4882a593Smuzhiyun { "brcm,bcm33843-viper", &bcm3384_viper_quirks },
117*4882a593Smuzhiyun { "brcm,bcm6328", &bcm6328_quirks },
118*4882a593Smuzhiyun { "brcm,bcm6358", &bcm6358_quirks },
119*4882a593Smuzhiyun { "brcm,bcm6362", &bcm6368_quirks },
120*4882a593Smuzhiyun { "brcm,bcm6368", &bcm6368_quirks },
121*4882a593Smuzhiyun { "brcm,bcm63168", &bcm6368_quirks },
122*4882a593Smuzhiyun { "brcm,bcm63268", &bcm6368_quirks },
123*4882a593Smuzhiyun { },
124*4882a593Smuzhiyun };
125*4882a593Smuzhiyun
prom_init(void)126*4882a593Smuzhiyun void __init prom_init(void)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun bmips_cpu_setup();
129*4882a593Smuzhiyun register_bmips_smp_ops();
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
prom_free_prom_memory(void)132*4882a593Smuzhiyun void __init prom_free_prom_memory(void)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
get_system_type(void)136*4882a593Smuzhiyun const char *get_system_type(void)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun return "Generic BMIPS kernel";
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
plat_time_init(void)141*4882a593Smuzhiyun void __init plat_time_init(void)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun struct device_node *np;
144*4882a593Smuzhiyun u32 freq;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun np = of_find_node_by_name(NULL, "cpus");
147*4882a593Smuzhiyun if (!np)
148*4882a593Smuzhiyun panic("missing 'cpus' DT node");
149*4882a593Smuzhiyun if (of_property_read_u32(np, "mips-hpt-frequency", &freq) < 0)
150*4882a593Smuzhiyun panic("missing 'mips-hpt-frequency' property");
151*4882a593Smuzhiyun of_node_put(np);
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun mips_hpt_frequency = freq;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
plat_mem_setup(void)156*4882a593Smuzhiyun void __init plat_mem_setup(void)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun void *dtb;
159*4882a593Smuzhiyun const struct bmips_quirk *q;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun set_io_port_base(0);
162*4882a593Smuzhiyun ioport_resource.start = 0;
163*4882a593Smuzhiyun ioport_resource.end = ~0;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /* intended to somewhat resemble ARM; see Documentation/arm/booting.rst */
166*4882a593Smuzhiyun if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
167*4882a593Smuzhiyun dtb = phys_to_virt(fw_arg2);
168*4882a593Smuzhiyun else if (fw_passed_dtb) /* UHI interface or appended dtb */
169*4882a593Smuzhiyun dtb = (void *)fw_passed_dtb;
170*4882a593Smuzhiyun else if (&__dtb_start != &__dtb_end)
171*4882a593Smuzhiyun dtb = (void *)__dtb_start;
172*4882a593Smuzhiyun else
173*4882a593Smuzhiyun panic("no dtb found");
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun __dt_setup_arch(dtb);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun for (q = bmips_quirk_list; q->quirk_fn; q++) {
178*4882a593Smuzhiyun if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
179*4882a593Smuzhiyun q->compatible)) {
180*4882a593Smuzhiyun q->quirk_fn();
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
device_tree_init(void)185*4882a593Smuzhiyun void __init device_tree_init(void)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun struct device_node *np;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun unflatten_and_copy_device_tree();
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /* Disable SMP boot unless both CPUs are listed in DT and !disabled */
192*4882a593Smuzhiyun np = of_find_node_by_name(NULL, "cpus");
193*4882a593Smuzhiyun if (np && of_get_available_child_count(np) <= 1)
194*4882a593Smuzhiyun bmips_smp_enabled = 0;
195*4882a593Smuzhiyun of_node_put(np);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
plat_dev_init(void)198*4882a593Smuzhiyun static int __init plat_dev_init(void)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun of_clk_init(NULL);
201*4882a593Smuzhiyun return 0;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun device_initcall(plat_dev_init);
205