2
* PROM interface support
3
* Copyright 1996 The Australian National University.
4
* Copyright 1996 Fujitsu Laboratories Limited
5
* Copyright 1999 Pete A. Zaitcev
6
* This software may be distributed under the terms of the Gnu
7
* Public License version 2 or later
14
#include "libopenbios/bindings.h"
15
#include "drivers/drivers.h"
16
#include "libopenbios/sys_info.h"
20
#ifdef CONFIG_DEBUG_OBP
21
#define DPRINTF(fmt, args...) \
22
do { printk(fmt , ##args); } while (0)
24
#define DPRINTF(fmt, args...)
27
char obp_stdin, obp_stdout;
28
const char *obp_stdin_path, *obp_stdout_path;
30
struct linux_arguments_v0 obp_arg;
32
static const struct linux_arguments_v0 * const obp_argp = &obp_arg;
34
static void (*sync_hook)(void);
36
static struct linux_romvec romvec0;
38
static void doublewalk(__attribute__((unused)) unsigned int ptab1,
39
__attribute__((unused)) unsigned int va)
43
int obp_nextnode(int node)
50
DPRINTF("obp_nextnode(0x%x) = 0x%x\n", node, peer);
55
int obp_child(int node)
62
DPRINTF("obp_child(0x%x) = 0x%x\n", node, child);
67
int obp_proplen(int node, const char *name)
72
DPRINTF("obp_proplen(0x0, %s) = -1\n", name);
78
fword("get-package-property");
82
DPRINTF("obp_proplen(0x%x, %s) (not found)\n", node, name);
90
DPRINTF("obp_proplen(0x%x, %s) = %d\n", node, name, len);
96
#ifdef CONFIG_DEBUG_OBP
97
static int looks_like_string(const char *str, int len)
100
int ret = (str[len-1] == '\0');
101
for (i = 0; i < len-1 && ret; i++)
103
int ch = str[i] & 0xFF;
104
if (ch < 0x20 || ch > 0x7F)
111
int obp_getprop(int node, const char *name, char *value)
118
DPRINTF("obp_getprop(0x0, %s) = -1\n", name);
123
// NULL name means get first property
126
fword("next-property");
130
str = (char *) POP();
131
DPRINTF("obp_getprop(0x%x, NULL) = %s\n", node, str);
135
DPRINTF("obp_getprop(0x%x, NULL) (not found)\n", node);
141
fword("get-package-property");
145
DPRINTF("obp_getprop(0x%x, %s) (not found)\n", node, name);
150
str = (char *) POP();
152
memcpy(value, str, len);
156
#ifdef CONFIG_DEBUG_OBP
157
if (looks_like_string(str, len)) {
158
DPRINTF("obp_getprop(0x%x, %s) = %s\n", node, name, str);
161
DPRINTF("obp_getprop(0x%x, %s) = ", node, name);
162
for (i = 0; i < len; i++) {
163
DPRINTF("%02x%s", str[i] & 0xFF,
164
(len == 4 || i == len-1) ? "" : " ");
174
const char *obp_nextprop(int node, const char *name)
178
if (!name || *name == '\0') {
179
// NULL name means get first property
186
fword("next-property");
189
DPRINTF("obp_nextprop(0x%x, %s) (not found)\n", node, name);
196
str = (char *) POP();
198
DPRINTF("obp_nextprop(0x%x, %s) = %s\n", node, name, str);
204
int obp_setprop(__attribute__((unused)) int node,
205
__attribute__((unused)) const char *name,
206
__attribute__((unused)) char *value,
207
__attribute__((unused)) int len)
209
DPRINTF("obp_setprop(0x%x, %s) = %s (%d)\n", node, name, value, len);
214
static const struct linux_nodeops nodeops0 = {
215
obp_nextnode_handler, /* int (*no_nextnode)(int node); */
216
obp_child_handler, /* int (*no_child)(int node); */
217
obp_proplen_handler, /* int (*no_proplen)(int node, char *name); */
218
obp_getprop_handler, /* int (*no_getprop)(int node,char *name,char *val); */
219
obp_setprop_handler, /* int (*no_setprop)(int node, char *name,
220
char *val, int len); */
221
obp_nextprop_handler /* char * (*no_nextprop)(int node, char *name); */
224
int obp_nbgetchar(void)
229
int obp_nbputchar(int ch)
236
void obp_putstr(char *str, int len)
238
PUSH(pointer2cell(str));
243
void obp_printf(const char *fmt, ...)
252
void obp_reboot(char *str)
254
printk("rebooting (%s)\n", str);
256
printk("reboot failed\n");
262
printk("abort, power off\n");
264
printk("power off failed\n");
270
printk("halt, power off\n");
272
printk("power off failed\n");
276
int obp_devopen(char *str)
283
DPRINTF("obp_devopen(%s) = 0x%x\n", str, ret);
288
int obp_devclose(int dev_desc)
295
DPRINTF("obp_devclose(0x%x) = %d\n", dev_desc, ret);
300
int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf)
305
hi = ((uint64_t)offset * bs) >> 32;
306
lo = ((uint64_t)offset * bs) & 0xffffffff;
308
ret = obp_devseek(dev_desc, hi, lo);
310
ret = obp_devread(dev_desc, buf, num_blks * bs) / bs;
312
DPRINTF("obp_rdblkdev(fd 0x%x, num_blks %d, offset %d (hi %d lo %d), buf 0x%x) = %d\n", dev_desc, num_blks, offset, hi, lo, (int)buf, ret);
317
int obp_devread(int dev_desc, char *buf, int nbytes)
325
fword("$call-method");
328
DPRINTF("obp_devread(fd 0x%x, buf 0x%x, nbytes %d) = %d\n", dev_desc, (int)buf, nbytes, ret);
333
int obp_devwrite(int dev_desc, char *buf, int nbytes)
335
#ifdef CONFIG_DEBUG_OBP_DEVWRITE /* disabled, makes too much noise */
343
fword("$call-method");
344
#ifdef CONFIG_DEBUG_OBP_DEVWRITE
346
DPRINTF("obp_devwrite(fd 0x%x, buf %s, nbytes %d) = %d\n", dev_desc, buf, nbytes, ret);
354
int obp_devseek(int dev_desc, int hi, int lo)
362
fword("$call-method");
365
DPRINTF("obp_devseek(fd 0x%x, hi %d, lo %d) = %d\n", dev_desc, hi, lo, ret);
370
int obp_inst2pkg(int dev_desc)
375
fword("ihandle>non-interposed-phandle");
378
DPRINTF("obp_inst2pkg(fd 0x%x) = 0x%x\n", dev_desc, ret);
383
int obp_cpustart(__attribute__((unused))unsigned int whichcpu,
384
__attribute__((unused))int ctxtbl_ptr,
385
__attribute__((unused))int thiscontext,
386
__attribute__((unused))char *prog_counter)
389
struct linux_prom_registers *smp_ctable = (void *)ctxtbl_ptr;
391
DPRINTF("obp_cpustart: cpu %d, ctxptr 0x%x, ctx %d, pc 0x%x\n", whichcpu,
392
smp_ctable->phys_addr, thiscontext, (unsigned int)prog_counter);
394
found = obp_getprop(whichcpu, "mid", (char *)&cpu);
397
DPRINTF("cpu found, id %d -> cpu %d\n", whichcpu, cpu);
399
return start_cpu((unsigned int)prog_counter, ((unsigned int)smp_ctable->phys_addr) >> 4,
403
int obp_cpustop(__attribute__((unused)) unsigned int whichcpu)
405
DPRINTF("obp_cpustop: cpu %d\n", whichcpu);
410
int obp_cpuidle(__attribute__((unused)) unsigned int whichcpu)
412
DPRINTF("obp_cpuidle: cpu %d\n", whichcpu);
417
int obp_cpuresume(__attribute__((unused)) unsigned int whichcpu)
419
DPRINTF("obp_cpuresume: cpu %d\n", whichcpu);
424
void obp_fortheval_v2(char *str, int arg0, int arg1, int arg2, int arg3, int arg4)
428
// It seems Solaris passes up to 5 arguments which should be pushed onto the Forth
429
// stack for execution. However the API doesn't provide for a way to specify the number
430
// of arguments actually being passed. Hence we preserve the state of the Forth stack
431
// before, push all the arguments, execute the Forth, then restore the stack to its
432
// previous state. This enables us to have a variable number of arguments and still
433
// preserve stack state between subsequent calls.
435
// Preserve stack state
436
dstacktmp = dstackcnt;
444
DPRINTF("obp_fortheval_v2(%x %x %x %x %x %s)\n", arg4, arg3, arg2, arg1, arg0, str);
448
// Restore stack state
449
dstackcnt = dstacktmp;
452
volatile uint32_t *obp_ticks;
457
/* Setup the openprom vector. Note that all functions should be invoked
458
via their handler (see call-romvec.S) which acts as a proxy to save
459
the globals and setup the stack correctly */
461
// Linux wants a R/W romvec table
462
romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC;
463
romvec0.pv_romvers = 3;
464
romvec0.pv_plugin_revision = 2;
465
romvec0.pv_printrev = 0x20019;
466
romvec0.pv_v0mem.v0_totphys = NULL;
467
romvec0.pv_v0mem.v0_prommap = NULL;
468
romvec0.pv_v0mem.v0_available = NULL;
469
romvec0.pv_nodeops = &nodeops0;
470
romvec0.pv_bootstr = (void *)doublewalk;
471
romvec0.pv_v0devops.v0_devopen = &obp_devopen_handler;
472
romvec0.pv_v0devops.v0_devclose = &obp_devclose_handler;
473
romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev_handler;
474
romvec0.pv_stdin = &obp_stdin;
475
romvec0.pv_stdout = &obp_stdout;
476
romvec0.pv_getchar = obp_nbgetchar_handler;
477
romvec0.pv_putchar = (void (*)(int))obp_nbputchar_handler;
478
romvec0.pv_nbgetchar = obp_nbgetchar_handler;
479
romvec0.pv_nbputchar = obp_nbputchar_handler;
480
romvec0.pv_putstr = obp_putstr_handler;
481
romvec0.pv_reboot = obp_reboot_handler;
482
romvec0.pv_printf = obp_printf_handler;
483
romvec0.pv_abort = obp_abort_handler;
485
/* Point to the Forth obp-ticks variable and reset */
487
obp_ticks = cell2pointer(POP());
489
romvec0.pv_ticks = obp_ticks;
491
romvec0.pv_halt = obp_halt_handler;
492
romvec0.pv_synchook = &sync_hook;
493
romvec0.pv_v0bootargs = &obp_argp;
494
romvec0.pv_fortheval.v2_eval = obp_fortheval_v2_handler;
495
romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg_handler;
496
romvec0.pv_v2devops.v2_dumb_mem_alloc = obp_dumb_memalloc_handler;
497
romvec0.pv_v2devops.v2_dumb_mem_free = obp_dumb_memfree_handler;
498
romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap_handler;
499
romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap_handler;
500
romvec0.pv_v2devops.v2_dev_open = obp_devopen_handler;
501
romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose_handler;
502
romvec0.pv_v2devops.v2_dev_read = obp_devread_handler;
503
romvec0.pv_v2devops.v2_dev_write = obp_devwrite_handler;
504
romvec0.pv_v2devops.v2_dev_seek = obp_devseek_handler;
506
romvec0.pv_v2bootargs.bootpath = &bootpath;
508
romvec0.pv_v2bootargs.bootargs = &obp_arg.argv[1];
510
/* Point fd_stdin/fd_stdout to the Forth stdin/stdout variables */
512
romvec0.pv_v2bootargs.fd_stdin = cell2pointer(POP());
514
romvec0.pv_v2bootargs.fd_stdout = cell2pointer(POP());
516
romvec0.v3_memalloc = obp_memalloc_handler;
518
romvec0.v3_cpustart = obp_cpustart_handler;
519
romvec0.v3_cpustop = obp_cpustop_handler;
520
romvec0.v3_cpuidle = obp_cpuidle_handler;
521
romvec0.v3_cpuresume = obp_cpuresume_handler;