1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
6 #include <linux/init.h>
7 #include <linux/kernel.h>
8 #include <linux/linkage.h>
10 #include <linux/blkdev.h>
11 #include <linux/memblock.h>
13 #include <linux/smp.h>
15 #include <asm/bootinfo.h>
16 #include <asm/reboot.h>
17 #include <asm/setup.h>
18 #include <asm/sibyte/board.h>
19 #include <asm/smp-ops.h>
21 #include <asm/fw/cfe/cfe_api.h>
22 #include <asm/fw/cfe/cfe_error.h>
24 /* Max ram addressable in 32-bit segments */
26 #define MAX_RAM_SIZE (~0ULL)
29 #ifdef CONFIG_PHYS_ADDR_T_64BIT
30 #define MAX_RAM_SIZE (~0ULL)
32 #define MAX_RAM_SIZE (0xffffffffULL)
35 #define MAX_RAM_SIZE (0x1fffffffULL)
39 #define SIBYTE_MAX_MEM_REGIONS 8
40 phys_addr_t board_mem_region_addrs
[SIBYTE_MAX_MEM_REGIONS
];
41 phys_addr_t board_mem_region_sizes
[SIBYTE_MAX_MEM_REGIONS
];
42 unsigned int board_mem_region_count
;
46 #ifdef CONFIG_BLK_DEV_INITRD
47 extern unsigned long initrd_start
, initrd_end
;
50 static void __noreturn
cfe_linux_exit(void *arg
)
52 int warm
= *(int *)arg
;
54 if (smp_processor_id()) {
55 static int reboot_smp
;
57 /* Don't repeat the process from another CPU */
59 /* Get CPU 0 to do the cfe_exit */
61 smp_call_function(cfe_linux_exit
, arg
, 0);
64 printk("Passing control back to CFE...\n");
66 printk("cfe_exit returned??\n");
71 static void __noreturn
cfe_linux_restart(char *command
)
73 static const int zero
;
75 cfe_linux_exit((void *)&zero
);
78 static void __noreturn
cfe_linux_halt(void)
80 static const int one
= 1;
82 cfe_linux_exit((void *)&one
);
85 static __init
void prom_meminit(void)
87 u64 addr
, size
, type
; /* regardless of PHYS_ADDR_T_64BIT */
91 #ifdef CONFIG_BLK_DEV_INITRD
92 unsigned long initrd_pstart
;
93 unsigned long initrd_pend
;
95 initrd_pstart
= CPHYSADDR(initrd_start
);
96 initrd_pend
= CPHYSADDR(initrd_end
);
98 ((initrd_pstart
> MAX_RAM_SIZE
)
99 || (initrd_pend
> MAX_RAM_SIZE
))) {
100 panic("initrd out of addressable memory");
105 for (idx
= 0; cfe_enummem(idx
, mem_flags
, &addr
, &size
, &type
) != CFE_ERR_NOMORE
;
108 if (type
== CFE_MI_AVAILABLE
) {
110 * See if this block contains (any portion of) the
113 #ifdef CONFIG_BLK_DEV_INITRD
115 if ((initrd_pstart
> addr
) &&
116 (initrd_pstart
< (addr
+ size
))) {
117 add_memory_region(addr
,
118 initrd_pstart
- addr
,
122 if ((initrd_pend
> addr
) &&
123 (initrd_pend
< (addr
+ size
))) {
124 add_memory_region(initrd_pend
,
125 (addr
+ size
) - initrd_pend
,
132 if (addr
> MAX_RAM_SIZE
)
134 if (addr
+size
> MAX_RAM_SIZE
)
135 size
= MAX_RAM_SIZE
- (addr
+size
) + 1;
137 * memcpy/__copy_user prefetch, which
138 * will cause a bus error for
139 * KSEG/KUSEG addrs not backed by RAM.
140 * Hence, reserve some padding for the
145 add_memory_region(addr
, size
, BOOT_MEM_RAM
);
147 board_mem_region_addrs
[board_mem_region_count
] = addr
;
148 board_mem_region_sizes
[board_mem_region_count
] = size
;
149 board_mem_region_count
++;
150 if (board_mem_region_count
==
151 SIBYTE_MAX_MEM_REGIONS
) {
153 * Too many regions. Need to configure more
159 #ifdef CONFIG_BLK_DEV_INITRD
161 add_memory_region(initrd_pstart
, initrd_pend
- initrd_pstart
,
167 #ifdef CONFIG_BLK_DEV_INITRD
168 static int __init
initrd_setup(char *str
)
173 unsigned long initrd_size
;
175 /* Make a copy of the initrd argument so we can smash it up here */
176 for (idx
= 0; idx
< sizeof(rdarg
)-1; idx
++) {
177 if (!str
[idx
] || (str
[idx
] == ' ')) break;
178 rdarg
[idx
] = str
[idx
];
185 *Initrd location comes in the form "<hex size of ramdisk in bytes>@<location in memory>"
186 * e.g. initrd=3abfd@80010000. This is set up by the loader.
188 for (tmp
= str
; *tmp
!= '@'; tmp
++) {
198 initrd_size
= simple_strtoul(str
, &endptr
, 16);
204 initrd_start
= simple_strtoul(tmp
, &endptr
, 16);
208 initrd_end
= initrd_start
+ initrd_size
;
209 printk("Found initrd of %lx@%lx\n", initrd_size
, initrd_start
);
212 printk("Bad initrd argument. Disabling initrd\n");
220 extern const struct plat_smp_ops sb_smp_ops
;
221 extern const struct plat_smp_ops bcm1480_smp_ops
;
224 * prom_init is called just after the cpu type is determined, from setup_arch()
226 void __init
prom_init(void)
228 uint64_t cfe_ept
, cfe_handle
;
229 unsigned int cfe_eptseal
;
231 char **envp
= (char **) fw_arg2
;
232 int *prom_vec
= (int *) fw_arg3
;
234 _machine_restart
= cfe_linux_restart
;
235 _machine_halt
= cfe_linux_halt
;
236 pm_power_off
= cfe_linux_halt
;
239 * Check if a loader was used; if NOT, the 4 arguments are
240 * what CFE gives us (handle, 0, EPT and EPTSEAL)
243 cfe_handle
= (uint64_t)(long)argc
;
244 cfe_ept
= (long)envp
;
245 cfe_eptseal
= (uint32_t)(unsigned long)prom_vec
;
247 if ((int32_t)(long)prom_vec
< 0) {
249 * Old loader; all it gives us is the handle,
250 * so use the "known" entrypoint and assume
253 cfe_handle
= (uint64_t)(long)prom_vec
;
254 cfe_ept
= (uint64_t)((int32_t)0x9fc00500);
255 cfe_eptseal
= CFE_EPTSEAL
;
258 * Newer loaders bundle the handle/ept/eptseal
259 * Note: prom_vec is in the loader's useg
260 * which is still alive in the TLB.
262 cfe_handle
= (uint64_t)((int32_t *)prom_vec
)[0];
263 cfe_ept
= (uint64_t)((int32_t *)prom_vec
)[2];
264 cfe_eptseal
= (unsigned int)((uint32_t *)prom_vec
)[3];
267 if (cfe_eptseal
!= CFE_EPTSEAL
) {
268 /* too early for panic to do any good */
269 printk("CFE's entrypoint seal doesn't match. Spinning.");
272 cfe_init(cfe_handle
, cfe_ept
);
274 * Get the handle for (at least) prom_putchar, possibly for
277 cfe_cons_handle
= cfe_getstdhandle(CFE_STDHANDLE_CONSOLE
);
278 if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline
, COMMAND_LINE_SIZE
) < 0) {
280 /* The loader should have set the command line */
281 /* too early for panic to do any good */
282 printk("LINUX_CMDLINE not defined in cfe.");
287 #ifdef CONFIG_BLK_DEV_INITRD
290 /* Need to find out early whether we've got an initrd. So scan
291 the list looking now */
292 for (ptr
= arcs_cmdline
; *ptr
; ptr
++) {
293 while (*ptr
== ' ') {
296 if (!strncmp(ptr
, "initrd=", 7)) {
300 while (*ptr
&& (*ptr
!= ' ')) {
306 #endif /* CONFIG_BLK_DEV_INITRD */
308 /* Not sure this is needed, but it's the safe way. */
309 arcs_cmdline
[COMMAND_LINE_SIZE
-1] = 0;
313 #if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
314 register_smp_ops(&sb_smp_ops
);
316 #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
317 register_smp_ops(&bcm1480_smp_ops
);
321 void __init
prom_free_prom_memory(void)
323 /* Not sure what I'm supposed to do here. Nothing, I think */
326 void prom_putchar(char c
)
330 while ((ret
= cfe_write(cfe_cons_handle
, &c
, 1)) == 0)