initial commit
[freebsd-arm:freebsd-arm.git] / boot / ofw / libofw / openfirm.c
1 /*      $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $        */
2
3 /*-
4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5  * Copyright (C) 1995, 1996 TooLs GmbH.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 /*-
34  * Copyright (C) 2000 Benno Rice.
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  *
46  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
47  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56  */
57
58 #include <sys/cdefs.h>
59 __FBSDID("$FreeBSD$");
60
61 #include <machine/stdarg.h>
62
63 #include <stand.h>
64
65 #include "openfirm.h"
66
67 int (*openfirmware)(void *);
68
69 phandle_t chosen;
70 ihandle_t mmu;
71 ihandle_t memory;
72
73 /* Initialiser */
74
75 void
76 OF_init(int (*openfirm)(void *))
77 {
78
79         openfirmware = openfirm;
80
81         if ((chosen = OF_finddevice("/chosen")) == -1)
82                 OF_exit();
83         if (OF_getprop(chosen, "memory", &memory, sizeof(memory)) == -1)
84                 OF_exit();
85         if (OF_getprop(chosen, "mmu", &mmu, sizeof(mmu)) == -1)
86                 OF_exit();
87 }
88
89 /*
90  * Generic functions
91  */
92
93 /* Test to see if a service exists. */
94 int
95 OF_test(char *name)
96 {
97         static struct {
98                 cell_t name;
99                 cell_t nargs;
100                 cell_t nreturns;
101                 cell_t service;
102                 cell_t missing;
103         } args = {
104                 (cell_t)"test",
105                 1,
106                 1,
107         };
108
109         args.service = (cell_t)name;
110         if (openfirmware(&args) == -1)
111                 return (-1);
112         return (args.missing);
113 }
114
115 /* Return firmware millisecond count. */
116 int
117 OF_milliseconds()
118 {
119         static struct {
120                 cell_t name;
121                 cell_t nargs;
122                 cell_t nreturns;
123                 cell_t ms;
124         } args = {
125                 (cell_t)"milliseconds",
126                 0,
127                 1,
128         };
129
130         openfirmware(&args);
131         return (args.ms);
132 }
133
134 /*
135  * Device tree functions
136  */
137
138 /* Return the next sibling of this node or 0. */
139 phandle_t
140 OF_peer(phandle_t node)
141 {
142         static struct {
143                 cell_t name;
144                 cell_t nargs;
145                 cell_t nreturns;
146                 cell_t node;
147                 cell_t next;
148         } args = {
149                 (cell_t)"peer",
150                 1,
151                 1,
152         };
153
154         args.node = node;
155         if (openfirmware(&args) == -1)
156                 return (-1);
157         return (args.next);
158 }
159
160 /* Return the first child of this node or 0. */
161 phandle_t
162 OF_child(phandle_t node)
163 {
164         static struct {
165                 cell_t name;
166                 cell_t nargs;
167                 cell_t nreturns;
168                 cell_t node;
169                 cell_t child;
170         } args = {
171                 (cell_t)"child",
172                 1,
173                 1,
174         };
175
176         args.node = node;
177         if (openfirmware(&args) == -1)
178                 return (-1);
179         return (args.child);
180 }
181
182 /* Return the parent of this node or 0. */
183 phandle_t
184 OF_parent(phandle_t node)
185 {
186         static struct {
187                 cell_t name;
188                 cell_t nargs;
189                 cell_t nreturns;
190                 cell_t node;
191                 cell_t parent;
192         } args = {
193                 (cell_t)"parent",
194                 1,
195                 1,
196         };
197
198         args.node = node;
199         if (openfirmware(&args) == -1)
200                 return (-1);
201         return (args.parent);
202 }
203
204 /* Return the package handle that corresponds to an instance handle. */
205 phandle_t
206 OF_instance_to_package(ihandle_t instance)
207 {
208         static struct {
209                 cell_t name;
210                 cell_t nargs;
211                 cell_t nreturns;
212                 cell_t instance;
213                 cell_t package;
214         } args = {
215                 (cell_t)"instance-to-package",
216                 1,
217                 1,
218         };
219
220         args.instance = instance;
221         if (openfirmware(&args) == -1)
222                 return (-1);
223         return (args.package);
224 }
225
226 /* Get the length of a property of a package. */
227 int
228 OF_getproplen(phandle_t package, char *propname)
229 {
230         static struct {
231                 cell_t name;
232                 cell_t nargs;
233                 cell_t nreturns;
234                 cell_t package;
235                 cell_t propname;
236                 cell_t proplen;
237         } args = {
238                 (cell_t)"getproplen",
239                 2,
240                 1,
241         };
242
243         args.package = package;
244         args.propname = (cell_t)propname;
245         if (openfirmware(&args) == -1)
246                 return (-1);
247         return (args.proplen);
248 }
249
250 /* Get the value of a property of a package. */
251 int
252 OF_getprop(phandle_t package, char *propname, void *buf, int buflen)
253 {
254         static struct {
255                 cell_t name;
256                 cell_t nargs;
257                 cell_t nreturns;
258                 cell_t package;
259                 cell_t propname;
260                 cell_t buf;
261                 cell_t buflen;
262                 cell_t size;
263         } args = {
264                 (cell_t)"getprop",
265                 4,
266                 1,
267         };
268
269         args.package = package;
270         args.propname = (cell_t)propname;
271         args.buf = (cell_t)buf;
272         args.buflen = buflen;
273         if (openfirmware(&args) == -1)
274                 return (-1);
275         return (args.size);
276 }
277
278 /* Get the next property of a package. */
279 int
280 OF_nextprop(phandle_t package, char *previous, char *buf)
281 {
282         static struct {
283                 cell_t name;
284                 cell_t nargs;
285                 cell_t nreturns;
286                 cell_t package;
287                 cell_t previous;
288                 cell_t buf;
289                 cell_t flag;
290         } args = {
291                 (cell_t)"nextprop",
292                 3,
293                 1,
294         };
295
296         args.package = package;
297         args.previous = (cell_t)previous;
298         args.buf = (cell_t)buf;
299         if (openfirmware(&args) == -1)
300                 return (-1);
301         return (args.flag);
302 }
303
304 /* Set the value of a property of a package. */
305 /* XXX Has a bug on FirePower */
306 int
307 OF_setprop(phandle_t package, char *propname, void *buf, int len)
308 {
309         static struct {
310                 cell_t name;
311                 cell_t nargs;
312                 cell_t nreturns;
313                 cell_t package;
314                 cell_t propname;
315                 cell_t buf;
316                 cell_t len;
317                 cell_t size;
318         } args = {
319                 (cell_t)"setprop",
320                 4,
321                 1,
322         };
323
324         args.package = package;
325         args.propname = (cell_t)propname;
326         args.buf = (cell_t)buf;
327         args.len = len;
328         if (openfirmware(&args) == -1)
329                 return (-1);
330         return (args.size);
331 }
332
333 /* Convert a device specifier to a fully qualified pathname. */
334 int
335 OF_canon(const char *device, char *buf, int len)
336 {
337         static struct {
338                 cell_t name;
339                 cell_t nargs;
340                 cell_t nreturns;
341                 cell_t device;
342                 cell_t buf;
343                 cell_t len;
344                 cell_t size;
345         } args = {
346                 (cell_t)"canon",
347                 3,
348                 1,
349         };
350
351         args.device = (cell_t)device;
352         args.buf = (cell_t)buf;
353         args.len = len;
354         if (openfirmware(&args) == -1)
355                 return (-1);
356         return (args.size);
357 }
358
359 /* Return a package handle for the specified device. */
360 phandle_t
361 OF_finddevice(const char *device)
362 {
363         static struct {
364                 cell_t name;
365                 cell_t nargs;
366                 cell_t nreturns;
367                 cell_t device;
368                 cell_t package;
369         } args = {
370                 (cell_t)"finddevice",
371                 1,
372                 1,
373         };
374
375         args.device = (cell_t)device;
376         if (openfirmware(&args) == -1)
377                 return (-1);
378         return (args.package);
379 }
380
381 /* Return the fully qualified pathname corresponding to an instance. */
382 int
383 OF_instance_to_path(ihandle_t instance, char *buf, int len)
384 {
385         static struct {
386                 cell_t name;
387                 cell_t nargs;
388                 cell_t nreturns;
389                 cell_t instance;
390                 cell_t buf;
391                 cell_t len;
392                 cell_t size;
393         } args = {
394                 (cell_t)"instance-to-path",
395                 3,
396                 1,
397         };
398
399         args.instance = instance;
400         args.buf = (cell_t)buf;
401         args.len = len;
402         if (openfirmware(&args) == -1)
403                 return (-1);
404         return (args.size);
405 }
406
407 /* Return the fully qualified pathname corresponding to a package. */
408 int
409 OF_package_to_path(phandle_t package, char *buf, int len)
410 {
411         static struct {
412                 cell_t name;
413                 cell_t nargs;
414                 cell_t nreturns;
415                 cell_t package;
416                 cell_t buf;
417                 cell_t len;
418                 cell_t size;
419         } args = {
420                 (cell_t)"package-to-path",
421                 3,
422                 1,
423         };
424
425         args.package = package;
426         args.buf = (cell_t)buf;
427         args.len = len;
428         if (openfirmware(&args) == -1)
429                 return (-1);
430         return (args.size);
431 }
432
433 /*  Call the method in the scope of a given instance. */
434 int
435 OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...)
436 {
437         va_list ap;
438         static struct {
439                 cell_t name;
440                 cell_t nargs;
441                 cell_t nreturns;
442                 cell_t method;
443                 cell_t instance;
444                 cell_t args_n_results[12];
445         } args = {
446                 (cell_t)"call-method",
447                 2,
448                 1,
449         };
450         cell_t *cp;
451         int n;
452
453         if (nargs > 6)
454                 return (-1);
455         args.nargs = nargs + 2;
456         args.nreturns = nreturns + 1;
457         args.method = (cell_t)method;
458         args.instance = instance;
459         va_start(ap, nreturns);
460         for (cp = (cell_t *)(args.args_n_results + (n = nargs)); --n >= 0;)
461                 *--cp = va_arg(ap, cell_t);
462         if (openfirmware(&args) == -1)
463                 return (-1);
464         if (args.args_n_results[nargs])
465                 return (args.args_n_results[nargs]);
466         for (cp = (cell_t *)(args.args_n_results + nargs + (n = args.nreturns));
467             --n > 0;)
468                 *va_arg(ap, cell_t *) = *--cp;
469         va_end(ap);
470         return (0);
471 }
472
473 /*
474  * Device I/O functions
475  */
476
477 /* Open an instance for a device. */
478 ihandle_t
479 OF_open(char *device)
480 {
481         static struct {
482                 cell_t name;
483                 cell_t nargs;
484                 cell_t nreturns;
485                 cell_t device;
486                 cell_t instance;
487         } args = {
488                 (cell_t)"open",
489                 1,
490                 1,
491         };
492
493         args.device = (cell_t)device;
494         if (openfirmware(&args) == -1 || args.instance == 0) {
495                 return (-1);
496         }
497         return (args.instance);
498 }
499
500 /* Close an instance. */
501 void
502 OF_close(ihandle_t instance)
503 {
504         static struct {
505                 cell_t name;
506                 cell_t nargs;
507                 cell_t nreturns;
508                 cell_t instance;
509         } args = {
510                 (cell_t)"close",
511                 1,
512         };
513
514         args.instance = instance;
515         openfirmware(&args);
516 }
517
518 /* Read from an instance. */
519 int
520 OF_read(ihandle_t instance, void *addr, int len)
521 {
522         static struct {
523                 cell_t name;
524                 cell_t nargs;
525                 cell_t nreturns;
526                 cell_t instance;
527                 cell_t addr;
528                 cell_t len;
529                 cell_t actual;
530         } args = {
531                 (cell_t)"read",
532                 3,
533                 1,
534         };
535
536         args.instance = instance;
537         args.addr = (cell_t)addr;
538         args.len = len;
539
540 #if defined(OPENFIRM_DEBUG)
541         printf("OF_read: called with instance=%08x, addr=%p, len=%d\n",
542             args.instance, args.addr, args.len);
543 #endif
544
545         if (openfirmware(&args) == -1)
546                 return (-1);
547
548 #if defined(OPENFIRM_DEBUG)
549         printf("OF_read: returning instance=%d, addr=%p, len=%d, actual=%d\n",
550             args.instance, args.addr, args.len, args.actual);
551 #endif
552
553         return (args.actual);
554 }
555
556 /* Write to an instance. */
557 int
558 OF_write(ihandle_t instance, void *addr, int len)
559 {
560         static struct {
561                 cell_t name;
562                 cell_t nargs;
563                 cell_t nreturns;
564                 cell_t instance;
565                 cell_t addr;
566                 cell_t len;
567                 cell_t actual;
568         } args = {
569                 (cell_t)"write",
570                 3,
571                 1,
572         };
573
574         args.instance = instance;
575         args.addr = (cell_t)addr;
576         args.len = len;
577         if (openfirmware(&args) == -1)
578                 return (-1);
579         return (args.actual);
580 }
581
582 /* Seek to a position. */
583 int
584 OF_seek(ihandle_t instance, u_int64_t pos)
585 {
586         static struct {
587                 cell_t name;
588                 cell_t nargs;
589                 cell_t nreturns;
590                 cell_t instance;
591                 cell_t poshi;
592                 cell_t poslo;
593                 cell_t status;
594         } args = {
595                 (cell_t)"seek",
596                 3,
597                 1,
598         };
599
600         args.instance = instance;
601         args.poshi = pos >> 32;
602         args.poslo = pos;
603         if (openfirmware(&args) == -1)
604                 return (-1);
605         return (args.status);
606 }
607
608 /*
609  * Memory functions
610  */
611
612 /* Claim an area of memory. */
613 void *
614 OF_claim(void *virt, u_int size, u_int align)
615 {
616         static struct {
617                 cell_t name;
618                 cell_t nargs;
619                 cell_t nreturns;
620                 cell_t virt;
621                 cell_t size;
622                 cell_t align;
623                 cell_t baseaddr;
624         } args = {
625                 (cell_t)"claim",
626                 3,
627                 1,
628         };
629
630         args.virt = (cell_t)virt;
631         args.size = size;
632         args.align = align;
633         if (openfirmware(&args) == -1)
634                 return ((void *)-1);
635         return ((void *)args.baseaddr);
636 }
637
638 /* Release an area of memory. */
639 void
640 OF_release(void *virt, u_int size)
641 {
642         static struct {
643                 cell_t name;
644                 cell_t nargs;
645                 cell_t nreturns;
646                 cell_t virt;
647                 cell_t size;
648         } args = {
649                 (cell_t)"release",
650                 2,
651         };
652
653         args.virt = (cell_t)virt;
654         args.size = size;
655         openfirmware(&args);
656 }
657
658 /*
659  * Control transfer functions
660  */
661
662 /* Reset the system and call "boot <bootspec>". */
663 void
664 OF_boot(char *bootspec)
665 {
666         static struct {
667                 cell_t name;
668                 cell_t nargs;
669                 cell_t nreturns;
670                 cell_t bootspec;
671         } args = {
672                 (cell_t)"boot",
673                 1,
674         };
675
676         args.bootspec = (cell_t)bootspec;
677         openfirmware(&args);
678         for (;;)                        /* just in case */
679                 ;
680 }
681
682 /* Suspend and drop back to the Open Firmware interface. */
683 void
684 OF_enter()
685 {
686         static struct {
687                 cell_t name;
688                 cell_t nargs;
689                 cell_t nreturns;
690         } args = {
691                 (cell_t)"enter",
692         };
693
694         openfirmware(&args);
695         /* We may come back. */
696 }
697
698 /* Shut down and drop back to the Open Firmware interface. */
699 void
700 OF_exit()
701 {
702         static struct {
703                 cell_t name;
704                 cell_t nargs;
705                 cell_t nreturns;
706         } args = {
707                 (cell_t)"exit",
708         };
709
710         openfirmware(&args);
711         for (;;)                        /* just in case */
712                 ;
713 }
714
715 /* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */
716 #if 0
717 void
718 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
719 {
720         static struct {
721                 cell_t name;
722                 cell_t nargs;
723                 cell_t nreturns;
724                 cell_t virt;
725                 cell_t size;
726                 cell_t entry;
727                 cell_t arg;
728                 cell_t len;
729         } args = {
730                 (cell_t)"chain",
731                 5,
732         };
733
734         args.virt = (cell_t)virt;
735         args.size = size;
736         args.entry = (cell_t)entry;
737         args.arg = (cell_t)arg;
738         args.len = len;
739         openfirmware(&args);
740 }
741 #else
742 void
743 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
744 {
745         /*
746          * This is a REALLY dirty hack till the firmware gets this going
747          */
748 #if 0
749         if (size > 0)
750                 OF_release(virt, size);
751 #endif
752         entry(0, 0, openfirmware, arg, len);
753 }
754 #endif