1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2000, 2001, 2002 Broadcom Corporation
8 * Broadcom Common Firmware Environment (CFE)
10 * This module contains device function stubs (small routines to
11 * call the standard "iocb" interface entry point to CFE).
12 * There should be one routine here per iocb function call.
14 * Authors: Mitch Lichtenberg, Chris Demetriou
16 #include <linux/init.h>
17 #include <linux/kernel.h>
18 #include <linux/printk.h>
19 #include <asm/mipsregs.h>
20 #include <asm/fw/cfe/cfe_api.h>
21 #include "cfe_api_int.h"
23 unsigned long __initdata cfe_seal
;
25 /* Cast from a native pointer to a cfe_xptr_t and back. */
26 #define XPTR_FROM_NATIVE(n) ((cfe_xptr_t) (intptr_t) (n))
27 #define NATIVE_FROM_XPTR(x) ((void *) (intptr_t) (x))
29 int cfe_iocb_dispatch(struct cfe_xiocb
*xiocb
);
32 * Declare the dispatch function with args of "intptr_t".
33 * This makes sure whatever model we're compiling in
34 * puts the pointers in a single register. For example,
35 * combining -mlong64 and -mips1 or -mips2 would lead to
36 * trouble, since the handle and IOCB pointer will be
37 * passed in two registers each, and CFE expects one.
40 static int (*cfe_dispfunc
) (intptr_t handle
, intptr_t xiocb
);
41 static u64 cfe_handle
;
43 int cfe_init(u64 handle
, u64 ept
)
45 cfe_dispfunc
= NATIVE_FROM_XPTR(ept
);
50 int cfe_iocb_dispatch(struct cfe_xiocb
* xiocb
)
54 return (*cfe_dispfunc
) ((intptr_t) cfe_handle
, (intptr_t) xiocb
);
57 int cfe_close(int handle
)
59 struct cfe_xiocb xiocb
;
61 xiocb
.xiocb_fcode
= CFE_CMD_DEV_CLOSE
;
62 xiocb
.xiocb_status
= 0;
63 xiocb
.xiocb_handle
= handle
;
64 xiocb
.xiocb_flags
= 0;
65 xiocb
.xiocb_psize
= 0;
67 cfe_iocb_dispatch(&xiocb
);
69 return xiocb
.xiocb_status
;
73 int cfe_cpu_start(int cpu
, void (*fn
) (void), long sp
, long gp
, long a1
)
75 struct cfe_xiocb xiocb
;
77 xiocb
.xiocb_fcode
= CFE_CMD_FW_CPUCTL
;
78 xiocb
.xiocb_status
= 0;
79 xiocb
.xiocb_handle
= 0;
80 xiocb
.xiocb_flags
= 0;
81 xiocb
.xiocb_psize
= sizeof(struct xiocb_cpuctl
);
82 xiocb
.plist
.xiocb_cpuctl
.cpu_number
= cpu
;
83 xiocb
.plist
.xiocb_cpuctl
.cpu_command
= CFE_CPU_CMD_START
;
84 xiocb
.plist
.xiocb_cpuctl
.gp_val
= gp
;
85 xiocb
.plist
.xiocb_cpuctl
.sp_val
= sp
;
86 xiocb
.plist
.xiocb_cpuctl
.a1_val
= a1
;
87 xiocb
.plist
.xiocb_cpuctl
.start_addr
= (long) fn
;
89 cfe_iocb_dispatch(&xiocb
);
91 return xiocb
.xiocb_status
;
94 int cfe_cpu_stop(int cpu
)
96 struct cfe_xiocb xiocb
;
98 xiocb
.xiocb_fcode
= CFE_CMD_FW_CPUCTL
;
99 xiocb
.xiocb_status
= 0;
100 xiocb
.xiocb_handle
= 0;
101 xiocb
.xiocb_flags
= 0;
102 xiocb
.xiocb_psize
= sizeof(struct xiocb_cpuctl
);
103 xiocb
.plist
.xiocb_cpuctl
.cpu_number
= cpu
;
104 xiocb
.plist
.xiocb_cpuctl
.cpu_command
= CFE_CPU_CMD_STOP
;
106 cfe_iocb_dispatch(&xiocb
);
108 return xiocb
.xiocb_status
;
111 int cfe_enumenv(int idx
, char *name
, int namelen
, char *val
, int vallen
)
113 struct cfe_xiocb xiocb
;
115 xiocb
.xiocb_fcode
= CFE_CMD_ENV_SET
;
116 xiocb
.xiocb_status
= 0;
117 xiocb
.xiocb_handle
= 0;
118 xiocb
.xiocb_flags
= 0;
119 xiocb
.xiocb_psize
= sizeof(struct xiocb_envbuf
);
120 xiocb
.plist
.xiocb_envbuf
.enum_idx
= idx
;
121 xiocb
.plist
.xiocb_envbuf
.name_ptr
= XPTR_FROM_NATIVE(name
);
122 xiocb
.plist
.xiocb_envbuf
.name_length
= namelen
;
123 xiocb
.plist
.xiocb_envbuf
.val_ptr
= XPTR_FROM_NATIVE(val
);
124 xiocb
.plist
.xiocb_envbuf
.val_length
= vallen
;
126 cfe_iocb_dispatch(&xiocb
);
128 return xiocb
.xiocb_status
;
132 cfe_enummem(int idx
, int flags
, u64
*start
, u64
*length
, u64
*type
)
134 struct cfe_xiocb xiocb
;
136 xiocb
.xiocb_fcode
= CFE_CMD_FW_MEMENUM
;
137 xiocb
.xiocb_status
= 0;
138 xiocb
.xiocb_handle
= 0;
139 xiocb
.xiocb_flags
= flags
;
140 xiocb
.xiocb_psize
= sizeof(struct xiocb_meminfo
);
141 xiocb
.plist
.xiocb_meminfo
.mi_idx
= idx
;
143 cfe_iocb_dispatch(&xiocb
);
145 if (xiocb
.xiocb_status
< 0)
146 return xiocb
.xiocb_status
;
148 *start
= xiocb
.plist
.xiocb_meminfo
.mi_addr
;
149 *length
= xiocb
.plist
.xiocb_meminfo
.mi_size
;
150 *type
= xiocb
.plist
.xiocb_meminfo
.mi_type
;
155 int cfe_exit(int warm
, int status
)
157 struct cfe_xiocb xiocb
;
159 xiocb
.xiocb_fcode
= CFE_CMD_FW_RESTART
;
160 xiocb
.xiocb_status
= 0;
161 xiocb
.xiocb_handle
= 0;
162 xiocb
.xiocb_flags
= warm
? CFE_FLG_WARMSTART
: 0;
163 xiocb
.xiocb_psize
= sizeof(struct xiocb_exitstat
);
164 xiocb
.plist
.xiocb_exitstat
.status
= status
;
166 cfe_iocb_dispatch(&xiocb
);
168 return xiocb
.xiocb_status
;
171 int cfe_flushcache(int flg
)
173 struct cfe_xiocb xiocb
;
175 xiocb
.xiocb_fcode
= CFE_CMD_FW_FLUSHCACHE
;
176 xiocb
.xiocb_status
= 0;
177 xiocb
.xiocb_handle
= 0;
178 xiocb
.xiocb_flags
= flg
;
179 xiocb
.xiocb_psize
= 0;
181 cfe_iocb_dispatch(&xiocb
);
183 return xiocb
.xiocb_status
;
186 int cfe_getdevinfo(char *name
)
188 struct cfe_xiocb xiocb
;
190 xiocb
.xiocb_fcode
= CFE_CMD_DEV_GETINFO
;
191 xiocb
.xiocb_status
= 0;
192 xiocb
.xiocb_handle
= 0;
193 xiocb
.xiocb_flags
= 0;
194 xiocb
.xiocb_psize
= sizeof(struct xiocb_buffer
);
195 xiocb
.plist
.xiocb_buffer
.buf_offset
= 0;
196 xiocb
.plist
.xiocb_buffer
.buf_ptr
= XPTR_FROM_NATIVE(name
);
197 xiocb
.plist
.xiocb_buffer
.buf_length
= strlen(name
);
199 cfe_iocb_dispatch(&xiocb
);
201 if (xiocb
.xiocb_status
< 0)
202 return xiocb
.xiocb_status
;
203 return xiocb
.plist
.xiocb_buffer
.buf_ioctlcmd
;
206 int cfe_getenv(char *name
, char *dest
, int destlen
)
208 struct cfe_xiocb xiocb
;
212 xiocb
.xiocb_fcode
= CFE_CMD_ENV_GET
;
213 xiocb
.xiocb_status
= 0;
214 xiocb
.xiocb_handle
= 0;
215 xiocb
.xiocb_flags
= 0;
216 xiocb
.xiocb_psize
= sizeof(struct xiocb_envbuf
);
217 xiocb
.plist
.xiocb_envbuf
.enum_idx
= 0;
218 xiocb
.plist
.xiocb_envbuf
.name_ptr
= XPTR_FROM_NATIVE(name
);
219 xiocb
.plist
.xiocb_envbuf
.name_length
= strlen(name
);
220 xiocb
.plist
.xiocb_envbuf
.val_ptr
= XPTR_FROM_NATIVE(dest
);
221 xiocb
.plist
.xiocb_envbuf
.val_length
= destlen
;
223 cfe_iocb_dispatch(&xiocb
);
225 return xiocb
.xiocb_status
;
228 int cfe_getfwinfo(cfe_fwinfo_t
* info
)
230 struct cfe_xiocb xiocb
;
232 xiocb
.xiocb_fcode
= CFE_CMD_FW_GETINFO
;
233 xiocb
.xiocb_status
= 0;
234 xiocb
.xiocb_handle
= 0;
235 xiocb
.xiocb_flags
= 0;
236 xiocb
.xiocb_psize
= sizeof(struct xiocb_fwinfo
);
238 cfe_iocb_dispatch(&xiocb
);
240 if (xiocb
.xiocb_status
< 0)
241 return xiocb
.xiocb_status
;
243 info
->fwi_version
= xiocb
.plist
.xiocb_fwinfo
.fwi_version
;
244 info
->fwi_totalmem
= xiocb
.plist
.xiocb_fwinfo
.fwi_totalmem
;
245 info
->fwi_flags
= xiocb
.plist
.xiocb_fwinfo
.fwi_flags
;
246 info
->fwi_boardid
= xiocb
.plist
.xiocb_fwinfo
.fwi_boardid
;
247 info
->fwi_bootarea_va
= xiocb
.plist
.xiocb_fwinfo
.fwi_bootarea_va
;
248 info
->fwi_bootarea_pa
= xiocb
.plist
.xiocb_fwinfo
.fwi_bootarea_pa
;
249 info
->fwi_bootarea_size
=
250 xiocb
.plist
.xiocb_fwinfo
.fwi_bootarea_size
;
255 int cfe_getstdhandle(int flg
)
257 struct cfe_xiocb xiocb
;
259 xiocb
.xiocb_fcode
= CFE_CMD_DEV_GETHANDLE
;
260 xiocb
.xiocb_status
= 0;
261 xiocb
.xiocb_handle
= 0;
262 xiocb
.xiocb_flags
= flg
;
263 xiocb
.xiocb_psize
= 0;
265 cfe_iocb_dispatch(&xiocb
);
267 if (xiocb
.xiocb_status
< 0)
268 return xiocb
.xiocb_status
;
269 return xiocb
.xiocb_handle
;
275 struct cfe_xiocb xiocb
;
277 xiocb
.xiocb_fcode
= CFE_CMD_FW_GETTIME
;
278 xiocb
.xiocb_status
= 0;
279 xiocb
.xiocb_handle
= 0;
280 xiocb
.xiocb_flags
= 0;
281 xiocb
.xiocb_psize
= sizeof(struct xiocb_time
);
282 xiocb
.plist
.xiocb_time
.ticks
= 0;
284 cfe_iocb_dispatch(&xiocb
);
286 return xiocb
.plist
.xiocb_time
.ticks
;
290 int cfe_inpstat(int handle
)
292 struct cfe_xiocb xiocb
;
294 xiocb
.xiocb_fcode
= CFE_CMD_DEV_INPSTAT
;
295 xiocb
.xiocb_status
= 0;
296 xiocb
.xiocb_handle
= handle
;
297 xiocb
.xiocb_flags
= 0;
298 xiocb
.xiocb_psize
= sizeof(struct xiocb_inpstat
);
299 xiocb
.plist
.xiocb_inpstat
.inp_status
= 0;
301 cfe_iocb_dispatch(&xiocb
);
303 if (xiocb
.xiocb_status
< 0)
304 return xiocb
.xiocb_status
;
305 return xiocb
.plist
.xiocb_inpstat
.inp_status
;
309 cfe_ioctl(int handle
, unsigned int ioctlnum
, unsigned char *buffer
,
310 int length
, int *retlen
, u64 offset
)
312 struct cfe_xiocb xiocb
;
314 xiocb
.xiocb_fcode
= CFE_CMD_DEV_IOCTL
;
315 xiocb
.xiocb_status
= 0;
316 xiocb
.xiocb_handle
= handle
;
317 xiocb
.xiocb_flags
= 0;
318 xiocb
.xiocb_psize
= sizeof(struct xiocb_buffer
);
319 xiocb
.plist
.xiocb_buffer
.buf_offset
= offset
;
320 xiocb
.plist
.xiocb_buffer
.buf_ioctlcmd
= ioctlnum
;
321 xiocb
.plist
.xiocb_buffer
.buf_ptr
= XPTR_FROM_NATIVE(buffer
);
322 xiocb
.plist
.xiocb_buffer
.buf_length
= length
;
324 cfe_iocb_dispatch(&xiocb
);
327 *retlen
= xiocb
.plist
.xiocb_buffer
.buf_retlen
;
328 return xiocb
.xiocb_status
;
331 int cfe_open(char *name
)
333 struct cfe_xiocb xiocb
;
335 xiocb
.xiocb_fcode
= CFE_CMD_DEV_OPEN
;
336 xiocb
.xiocb_status
= 0;
337 xiocb
.xiocb_handle
= 0;
338 xiocb
.xiocb_flags
= 0;
339 xiocb
.xiocb_psize
= sizeof(struct xiocb_buffer
);
340 xiocb
.plist
.xiocb_buffer
.buf_offset
= 0;
341 xiocb
.plist
.xiocb_buffer
.buf_ptr
= XPTR_FROM_NATIVE(name
);
342 xiocb
.plist
.xiocb_buffer
.buf_length
= strlen(name
);
344 cfe_iocb_dispatch(&xiocb
);
346 if (xiocb
.xiocb_status
< 0)
347 return xiocb
.xiocb_status
;
348 return xiocb
.xiocb_handle
;
351 int cfe_read(int handle
, unsigned char *buffer
, int length
)
353 return cfe_readblk(handle
, 0, buffer
, length
);
356 int cfe_readblk(int handle
, s64 offset
, unsigned char *buffer
, int length
)
358 struct cfe_xiocb xiocb
;
360 xiocb
.xiocb_fcode
= CFE_CMD_DEV_READ
;
361 xiocb
.xiocb_status
= 0;
362 xiocb
.xiocb_handle
= handle
;
363 xiocb
.xiocb_flags
= 0;
364 xiocb
.xiocb_psize
= sizeof(struct xiocb_buffer
);
365 xiocb
.plist
.xiocb_buffer
.buf_offset
= offset
;
366 xiocb
.plist
.xiocb_buffer
.buf_ptr
= XPTR_FROM_NATIVE(buffer
);
367 xiocb
.plist
.xiocb_buffer
.buf_length
= length
;
369 cfe_iocb_dispatch(&xiocb
);
371 if (xiocb
.xiocb_status
< 0)
372 return xiocb
.xiocb_status
;
373 return xiocb
.plist
.xiocb_buffer
.buf_retlen
;
376 int cfe_setenv(char *name
, char *val
)
378 struct cfe_xiocb xiocb
;
380 xiocb
.xiocb_fcode
= CFE_CMD_ENV_SET
;
381 xiocb
.xiocb_status
= 0;
382 xiocb
.xiocb_handle
= 0;
383 xiocb
.xiocb_flags
= 0;
384 xiocb
.xiocb_psize
= sizeof(struct xiocb_envbuf
);
385 xiocb
.plist
.xiocb_envbuf
.enum_idx
= 0;
386 xiocb
.plist
.xiocb_envbuf
.name_ptr
= XPTR_FROM_NATIVE(name
);
387 xiocb
.plist
.xiocb_envbuf
.name_length
= strlen(name
);
388 xiocb
.plist
.xiocb_envbuf
.val_ptr
= XPTR_FROM_NATIVE(val
);
389 xiocb
.plist
.xiocb_envbuf
.val_length
= strlen(val
);
391 cfe_iocb_dispatch(&xiocb
);
393 return xiocb
.xiocb_status
;
396 int cfe_write(int handle
, const char *buffer
, int length
)
398 return cfe_writeblk(handle
, 0, buffer
, length
);
401 int cfe_writeblk(int handle
, s64 offset
, const char *buffer
, int length
)
403 struct cfe_xiocb xiocb
;
405 xiocb
.xiocb_fcode
= CFE_CMD_DEV_WRITE
;
406 xiocb
.xiocb_status
= 0;
407 xiocb
.xiocb_handle
= handle
;
408 xiocb
.xiocb_flags
= 0;
409 xiocb
.xiocb_psize
= sizeof(struct xiocb_buffer
);
410 xiocb
.plist
.xiocb_buffer
.buf_offset
= offset
;
411 xiocb
.plist
.xiocb_buffer
.buf_ptr
= XPTR_FROM_NATIVE(buffer
);
412 xiocb
.plist
.xiocb_buffer
.buf_length
= length
;
414 cfe_iocb_dispatch(&xiocb
);
416 if (xiocb
.xiocb_status
< 0)
417 return xiocb
.xiocb_status
;
418 return xiocb
.plist
.xiocb_buffer
.buf_retlen
;
421 void __init
cfe_die(char *fmt
, ...)
423 unsigned int prid
, __maybe_unused rev
;
430 vsprintf(msg
, fmt
, ap
);
433 if (cfe_seal
!= CFE_EPTSEAL
)
436 prid
= read_c0_prid();
437 if ((prid
& PRID_COMP_MASK
) != PRID_COMP_BROADCOM
)
440 rev
= prid
& PRID_REV_MASK
;
442 /* disable XKS01 so that CFE can access the registers */
443 switch (prid
& PRID_IMP_MASK
) {
444 #ifdef CONFIG_CPU_BMIPS4380
445 case PRID_IMP_BMIPS43XX
:
446 if (rev
>= PRID_REV_BMIPS4380_LO
&&
447 rev
<= PRID_REV_BMIPS4380_HI
)
448 __write_32bit_c0_register($
22, 3,
449 __read_32bit_c0_register($
22, 3) & ~BIT(12));
452 #ifdef CONFIG_CPU_BMIPS5000
453 case PRID_IMP_BMIPS5000
:
454 case PRID_IMP_BMIPS5200
:
455 __write_32bit_c0_register($
22, 5,
456 __read_32bit_c0_register($
22, 5) & ~BIT(8));
463 handle
= cfe_getstdhandle(CFE_STDHANDLE_CONSOLE
);
467 cfe_write(handle
, msg
, strlen(msg
));
469 for (count
= 0; count
< 0x7fffffff; count
++)
476 /* probably won't print anywhere useful */