aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sibyte/common/cfe.c
diff options
context:
space:
mode:
authorImre Kaloz <kaloz@openwrt.org>2009-06-02 08:22:06 -0400
committerRalf Baechle <ralf@linux-mips.org>2009-06-17 06:06:27 -0400
commit05f94eebd55ef69a354d3ea70179e40ea4c34de6 (patch)
treee97c73c3b3eeabcc888f8b5f21d97a2976eabc5c /arch/mips/sibyte/common/cfe.c
parent435f81f4a24206f82ce10d430fa6f312cee80669 (diff)
MIPS: Sibyte: Remove standalone kernel support
CFE is the only supported and used bootloader on the SiByte boards, the standalone kernel support has been never used outside Broadcom. Remove it and make the kernel use CFE by default. Signed-off-by: Imre Kaloz <kaloz@openwrt.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/sibyte/common/cfe.c')
-rw-r--r--arch/mips/sibyte/common/cfe.c344
1 files changed, 344 insertions, 0 deletions
diff --git a/arch/mips/sibyte/common/cfe.c b/arch/mips/sibyte/common/cfe.c
new file mode 100644
index 000000000000..eb5396cf81bb
--- /dev/null
+++ b/arch/mips/sibyte/common/cfe.c
@@ -0,0 +1,344 @@
1/*
2 * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/linkage.h>
22#include <linux/mm.h>
23#include <linux/blkdev.h>
24#include <linux/bootmem.h>
25#include <linux/pm.h>
26#include <linux/smp.h>
27
28#include <asm/bootinfo.h>
29#include <asm/reboot.h>
30#include <asm/sibyte/board.h>
31#include <asm/smp-ops.h>
32
33#include <asm/fw/cfe/cfe_api.h>
34#include <asm/fw/cfe/cfe_error.h>
35
36/* Max ram addressable in 32-bit segments */
37#ifdef CONFIG_64BIT
38#define MAX_RAM_SIZE (~0ULL)
39#else
40#ifdef CONFIG_HIGHMEM
41#ifdef CONFIG_64BIT_PHYS_ADDR
42#define MAX_RAM_SIZE (~0ULL)
43#else
44#define MAX_RAM_SIZE (0xffffffffULL)
45#endif
46#else
47#define MAX_RAM_SIZE (0x1fffffffULL)
48#endif
49#endif
50
51#define SIBYTE_MAX_MEM_REGIONS 8
52phys_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS];
53phys_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS];
54unsigned int board_mem_region_count;
55
56int cfe_cons_handle;
57
58#ifdef CONFIG_BLK_DEV_INITRD
59extern unsigned long initrd_start, initrd_end;
60#endif
61
62static void __noreturn cfe_linux_exit(void *arg)
63{
64 int warm = *(int *)arg;
65
66 if (smp_processor_id()) {
67 static int reboot_smp;
68
69 /* Don't repeat the process from another CPU */
70 if (!reboot_smp) {
71 /* Get CPU 0 to do the cfe_exit */
72 reboot_smp = 1;
73 smp_call_function(cfe_linux_exit, arg, 0);
74 }
75 } else {
76 printk("Passing control back to CFE...\n");
77 cfe_exit(warm, 0);
78 printk("cfe_exit returned??\n");
79 }
80 while (1);
81}
82
83static void __noreturn cfe_linux_restart(char *command)
84{
85 static const int zero;
86
87 cfe_linux_exit((void *)&zero);
88}
89
90static void __noreturn cfe_linux_halt(void)
91{
92 static const int one = 1;
93
94 cfe_linux_exit((void *)&one);
95}
96
97static __init void prom_meminit(void)
98{
99 u64 addr, size, type; /* regardless of 64BIT_PHYS_ADDR */
100 int mem_flags = 0;
101 unsigned int idx;
102 int rd_flag;
103#ifdef CONFIG_BLK_DEV_INITRD
104 unsigned long initrd_pstart;
105 unsigned long initrd_pend;
106
107 initrd_pstart = CPHYSADDR(initrd_start);
108 initrd_pend = CPHYSADDR(initrd_end);
109 if (initrd_start &&
110 ((initrd_pstart > MAX_RAM_SIZE)
111 || (initrd_pend > MAX_RAM_SIZE))) {
112 panic("initrd out of addressable memory");
113 }
114
115#endif /* INITRD */
116
117 for (idx = 0; cfe_enummem(idx, mem_flags, &addr, &size, &type) != CFE_ERR_NOMORE;
118 idx++) {
119 rd_flag = 0;
120 if (type == CFE_MI_AVAILABLE) {
121 /*
122 * See if this block contains (any portion of) the
123 * ramdisk
124 */
125#ifdef CONFIG_BLK_DEV_INITRD
126 if (initrd_start) {
127 if ((initrd_pstart > addr) &&
128 (initrd_pstart < (addr + size))) {
129 add_memory_region(addr,
130 initrd_pstart - addr,
131 BOOT_MEM_RAM);
132 rd_flag = 1;
133 }
134 if ((initrd_pend > addr) &&
135 (initrd_pend < (addr + size))) {
136 add_memory_region(initrd_pend,
137 (addr + size) - initrd_pend,
138 BOOT_MEM_RAM);
139 rd_flag = 1;
140 }
141 }
142#endif
143 if (!rd_flag) {
144 if (addr > MAX_RAM_SIZE)
145 continue;
146 if (addr+size > MAX_RAM_SIZE)
147 size = MAX_RAM_SIZE - (addr+size) + 1;
148 /*
149 * memcpy/__copy_user prefetch, which
150 * will cause a bus error for
151 * KSEG/KUSEG addrs not backed by RAM.
152 * Hence, reserve some padding for the
153 * prefetch distance.
154 */
155 if (size > 512)
156 size -= 512;
157 add_memory_region(addr, size, BOOT_MEM_RAM);
158 }
159 board_mem_region_addrs[board_mem_region_count] = addr;
160 board_mem_region_sizes[board_mem_region_count] = size;
161 board_mem_region_count++;
162 if (board_mem_region_count ==
163 SIBYTE_MAX_MEM_REGIONS) {
164 /*
165 * Too many regions. Need to configure more
166 */
167 while(1);
168 }
169 }
170 }
171#ifdef CONFIG_BLK_DEV_INITRD
172 if (initrd_start) {
173 add_memory_region(initrd_pstart, initrd_pend - initrd_pstart,
174 BOOT_MEM_RESERVED);
175 }
176#endif
177}
178
179#ifdef CONFIG_BLK_DEV_INITRD
180static int __init initrd_setup(char *str)
181{
182 char rdarg[64];
183 int idx;
184 char *tmp, *endptr;
185 unsigned long initrd_size;
186
187 /* Make a copy of the initrd argument so we can smash it up here */
188 for (idx = 0; idx < sizeof(rdarg)-1; idx++) {
189 if (!str[idx] || (str[idx] == ' ')) break;
190 rdarg[idx] = str[idx];
191 }
192
193 rdarg[idx] = 0;
194 str = rdarg;
195
196 /*
197 *Initrd location comes in the form "<hex size of ramdisk in bytes>@<location in memory>"
198 * e.g. initrd=3abfd@80010000. This is set up by the loader.
199 */
200 for (tmp = str; *tmp != '@'; tmp++) {
201 if (!*tmp) {
202 goto fail;
203 }
204 }
205 *tmp = 0;
206 tmp++;
207 if (!*tmp) {
208 goto fail;
209 }
210 initrd_size = simple_strtoul(str, &endptr, 16);
211 if (*endptr) {
212 *(tmp-1) = '@';
213 goto fail;
214 }
215 *(tmp-1) = '@';
216 initrd_start = simple_strtoul(tmp, &endptr, 16);
217 if (*endptr) {
218 goto fail;
219 }
220 initrd_end = initrd_start + initrd_size;
221 printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start);
222 return 1;
223 fail:
224 printk("Bad initrd argument. Disabling initrd\n");
225 initrd_start = 0;
226 initrd_end = 0;
227 return 1;
228}
229
230#endif
231
232extern struct plat_smp_ops sb_smp_ops;
233extern struct plat_smp_ops bcm1480_smp_ops;
234
235/*
236 * prom_init is called just after the cpu type is determined, from setup_arch()
237 */
238void __init prom_init(void)
239{
240 uint64_t cfe_ept, cfe_handle;
241 unsigned int cfe_eptseal;
242 int argc = fw_arg0;
243 char **envp = (char **) fw_arg2;
244 int *prom_vec = (int *) fw_arg3;
245
246 _machine_restart = cfe_linux_restart;
247 _machine_halt = cfe_linux_halt;
248 pm_power_off = cfe_linux_halt;
249
250 /*
251 * Check if a loader was used; if NOT, the 4 arguments are
252 * what CFE gives us (handle, 0, EPT and EPTSEAL)
253 */
254 if (argc < 0) {
255 cfe_handle = (uint64_t)(long)argc;
256 cfe_ept = (long)envp;
257 cfe_eptseal = (uint32_t)(unsigned long)prom_vec;
258 } else {
259 if ((int32_t)(long)prom_vec < 0) {
260 /*
261 * Old loader; all it gives us is the handle,
262 * so use the "known" entrypoint and assume
263 * the seal.
264 */
265 cfe_handle = (uint64_t)(long)prom_vec;
266 cfe_ept = (uint64_t)((int32_t)0x9fc00500);
267 cfe_eptseal = CFE_EPTSEAL;
268 } else {
269 /*
270 * Newer loaders bundle the handle/ept/eptseal
271 * Note: prom_vec is in the loader's useg
272 * which is still alive in the TLB.
273 */
274 cfe_handle = (uint64_t)((int32_t *)prom_vec)[0];
275 cfe_ept = (uint64_t)((int32_t *)prom_vec)[2];
276 cfe_eptseal = (unsigned int)((uint32_t *)prom_vec)[3];
277 }
278 }
279 if (cfe_eptseal != CFE_EPTSEAL) {
280 /* too early for panic to do any good */
281 printk("CFE's entrypoint seal doesn't match. Spinning.");
282 while (1) ;
283 }
284 cfe_init(cfe_handle, cfe_ept);
285 /*
286 * Get the handle for (at least) prom_putchar, possibly for
287 * boot console
288 */
289 cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
290 if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, CL_SIZE) < 0) {
291 if (argc >= 0) {
292 /* The loader should have set the command line */
293 /* too early for panic to do any good */
294 printk("LINUX_CMDLINE not defined in cfe.");
295 while (1) ;
296 }
297 }
298
299#ifdef CONFIG_BLK_DEV_INITRD
300 {
301 char *ptr;
302 /* Need to find out early whether we've got an initrd. So scan
303 the list looking now */
304 for (ptr = arcs_cmdline; *ptr; ptr++) {
305 while (*ptr == ' ') {
306 ptr++;
307 }
308 if (!strncmp(ptr, "initrd=", 7)) {
309 initrd_setup(ptr+7);
310 break;
311 } else {
312 while (*ptr && (*ptr != ' ')) {
313 ptr++;
314 }
315 }
316 }
317 }
318#endif /* CONFIG_BLK_DEV_INITRD */
319
320 /* Not sure this is needed, but it's the safe way. */
321 arcs_cmdline[CL_SIZE-1] = 0;
322
323 prom_meminit();
324
325#if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
326 register_smp_ops(&sb_smp_ops);
327#endif
328#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
329 register_smp_ops(&bcm1480_smp_ops);
330#endif
331}
332
333void __init prom_free_prom_memory(void)
334{
335 /* Not sure what I'm supposed to do here. Nothing, I think */
336}
337
338void prom_putchar(char c)
339{
340 int ret;
341
342 while ((ret = cfe_write(cfe_cons_handle, &c, 1)) == 0)
343 ;
344}