1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
17 #include <libbootmsg.h>
20 extern void call_client_interface(of_arg_t *);
22 static int claim_rc = 0;
23 static void* client_start;
24 static size_t client_size;
27 of_0_1(const char *serv)
35 call_client_interface(&arg);
41 of_1_0(const char *serv, int arg0)
49 call_client_interface(&arg);
52 static inline unsigned int
53 of_1_1(const char *serv, int arg0)
61 call_client_interface(&arg);
65 static inline unsigned int
66 of_1_2(const char *serv, int arg0, int *ret0)
74 call_client_interface(&arg);
80 of_2_0(const char *serv, int arg0, int arg1)
88 call_client_interface(&arg);
91 static inline unsigned int
92 of_2_1(const char *serv, int arg0, int arg1)
100 call_client_interface(&arg);
104 static inline unsigned int
105 of_2_2(const char *serv, int arg0, int arg1, int *ret0)
113 call_client_interface(&arg);
118 static inline unsigned int
119 of_2_3(const char *serv, int arg0, int arg1, int *ret0, int *ret1)
124 {arg0, arg1, 0, 0, 0}
127 call_client_interface(&arg);
134 of_3_0(const char *serv, int arg0, int arg1, int arg2)
139 {arg0, arg1, arg2, 0}
142 call_client_interface(&arg);
146 static inline unsigned int
147 of_3_1(const char *serv, int arg0, int arg1, int arg2)
152 {arg0, arg1, arg2, 0}
155 call_client_interface(&arg);
159 static inline unsigned int
160 of_3_2(const char *serv, int arg0, int arg1, int arg2, int *ret0)
165 {arg0, arg1, arg2, 0, 0}
168 call_client_interface(&arg);
173 static inline unsigned int
174 of_3_3(const char *serv, int arg0, int arg1, int arg2, int *ret0, int *ret1)
179 {arg0, arg1, arg2, 0, 0, 0}
182 call_client_interface(&arg);
188 static inline unsigned int
189 of_4_1(const char *serv, int arg0, int arg1, int arg2, int arg3)
194 {arg0, arg1, arg2, arg3, 0}
197 call_client_interface(&arg);
202 of_test(const char *name)
204 return (int) of_1_1("test", p32cast name);
208 of_interpret_1(void *s, void *ret)
210 return of_1_2("interpret", p32cast s, ret);
214 of_close(ihandle_t ihandle)
216 of_1_0("close", ihandle);
220 of_write(ihandle_t ihandle, void *s, int len)
222 return of_3_1("write", ihandle, p32cast s, len);
226 of_read(ihandle_t ihandle, void *s, int len)
228 return of_3_1("read", ihandle, p32cast s, len);
232 of_seek(ihandle_t ihandle, int poshi, int poslo)
234 return of_3_1("seek", ihandle, poshi, poslo);
238 of_getprop(phandle_t phandle, const char *name, void *buf, int len)
240 return of_4_1("getprop", phandle, p32cast name, p32cast buf, len);
244 of_peer(phandle_t phandle)
246 return (phandle_t) of_1_1("peer", phandle);
250 of_child(phandle_t phandle)
252 return (phandle_t) of_1_1("child", phandle);
256 of_parent(phandle_t phandle)
258 return (phandle_t) of_1_1("parent", phandle);
262 of_instance_to_package(ihandle_t ihandle)
264 return (phandle_t) of_1_1("instance-to-package", ihandle);
269 of_finddevice(const char *name)
271 return (phandle_t) of_1_1("finddevice", p32cast name);
275 of_open(const char *name)
277 return (ihandle_t) of_1_1("open", p32cast name);
281 of_claim(void *start, unsigned int size, unsigned int align)
283 return(void *)(long)(size_t)of_3_1("claim", p32cast start, size, align);
287 of_release(void *start, unsigned int size)
289 (void) of_2_0("release", p32cast start, size);
293 of_call_method_3(const char *name, ihandle_t ihandle, int arg0)
296 rc = of_3_2("call-method", p32cast name, ihandle, arg0, &entry);
297 return rc != 0 ? 0 : (void *) (long) entry;
301 vpd_read(unsigned int offset, unsigned int length, char *data)
304 long tmp = (long) data;
305 result = of_3_1("rtas-read-vpd", offset, length, (int) tmp);
310 vpd_write(unsigned int offset, unsigned int length, char *data)
313 long tmp = (long) data;
314 result = of_3_1("rtas-write-vpd", offset, length, (int) tmp);
319 ipmi_oem_led_set(int type, int instance, int state)
321 return of_3_0("set-led", type, instance, state);
325 write_mm_log(char *data, unsigned int length, unsigned short type)
327 long tmp = (long) data;
329 ipmi_oem_led_set(2, 0, 1);
330 return of_3_1("write-mm-log", (int) tmp, length, type);
336 return of_0_1("yield");
340 of_set_callback(void *addr)
342 return (void *) (long) (size_t) of_1_1("set-callback", p32cast addr);
346 bootmsg_warning(short id, const char *str, short lvl)
348 (void) of_3_0("bootmsg-warning", id, lvl, p32cast str);
352 bootmsg_error(short id, const char *str)
354 (void) of_2_0("bootmsg-error", id, p32cast str);
359 bootmsg_debugcp(short id, const char *str, short lvl)
361 (void) of_3_0("bootmsg-debugcp", id, lvl, p32cast str);
367 (void) of_1_0("bootmsg-cp", id);
371 #define CONFIG_SPACE 0
375 #define ASSIGNED_ADDRESS_PROPERTY 0
376 #define REG_PROPERTY 1
378 #define DEBUG_TRANSLATE_ADDRESS 0
379 #if DEBUG_TRANSLATE_ADDRESS != 0
380 #define DEBUG_TR(str...) printf(str)
382 #define DEBUG_TR(str...)
386 * pci_address_type tries to find the type for which a
387 * mapping should be done. This is PCI specific and is done by
388 * looking at the first 32bit of the phys-addr in
391 * @param node the node of the device which requests
393 * @param address the address which needs to be translated
394 * @param prop_type the type of the property to search in (either REG_PROPERTY or ASSIGNED_ADDRESS_PROPERTY)
395 * @return the corresponding type (config, i/o, mem)
398 pci_address_type(phandle_t node, uint64_t address, uint8_t prop_type)
400 char *prop_name = "assigned-addresses";
401 if (prop_type == REG_PROPERTY)
404 const unsigned int nac = 3; //PCI
406 const unsigned int nsc = 2; //PCI
407 /* up to 11 pairs of (phys-addr(3) size(2)) */
408 unsigned char buf[11 * (nac + nsc) * sizeof(int)];
409 unsigned int *assigned_ptr;
412 len = of_getprop(node, prop_name, buf, 11 * (nac + nsc) * sizeof(int));
413 assigned_ptr = (unsigned int *) &buf[0];
415 if ((prop_type == REG_PROPERTY)
416 && ((assigned_ptr[0] & 0xFF) != 0)) {
417 //BARs and Expansion ROM must be in assigned-addresses... so in reg
418 // we only look for those without config space offset set...
419 assigned_ptr += (nac + nsc);
420 len -= (nac + nsc) * sizeof(int);
423 DEBUG_TR("%s %x size %x\n", prop_name, assigned_ptr[2],
425 if (address >= assigned_ptr[2]
426 && address <= assigned_ptr[2] + assigned_ptr[4]) {
427 DEBUG_TR("found a match\n");
428 result = (assigned_ptr[0] & 0x03000000) >> 24;
431 assigned_ptr += (nac + nsc);
432 len -= (nac + nsc) * sizeof(int);
434 /* this can only handle 32bit memory space and should be
435 * removed as soon as translations for 64bit are available */
436 return (result == 3) ? MEM_SPACE : result;
440 * this is a hack which returns the lower 64 bit of any number of cells
441 * all the higher bits will silently discarded
442 * right now this works pretty good as long 64 bit addresses is all we want
444 * @param addr a pointer to the first address cell
445 * @param nc number of cells addr points to
446 * @return the lower 64 bit to which addr points
449 get_dt_address(uint32_t *addr, uint32_t nc)
453 result = (result << 32) | *(addr++);
458 * this functions tries to find a mapping for the given address
459 * it assumes that if we have #address-cells == 3 that we are trying
460 * to do a PCI translation
462 * @param addr a pointer to the address that should be translated
463 * if a translation has been found the address will
465 * @param type this is required for PCI devices to find the
466 * correct translation
467 * @param ranges this is one "range" containing the translation
468 * information (one range = nac + pnac + nsc)
469 * @param nac the OF property #address-cells
470 * @param nsc the OF property #size-cells
471 * @param pnac the OF property #address-cells from the parent node
472 * @return -1 if no translation was possible; else 0
475 map_one_range(uint64_t *addr, int type, uint32_t *ranges, uint32_t nac,
476 uint32_t nsc, uint32_t pnac)
479 /* cm - child mapping */
480 /* pm - parent mapping */
481 uint64_t cm, size, pm;
482 /* only check for the type if nac == 3 (PCI) */
483 DEBUG_TR("type %x, nac %x\n", ranges[0], nac);
484 if (((ranges[0] & 0x03000000) >> 24) != type && nac == 3)
486 /* okay, it is the same type let's see if we find a mapping */
487 size = get_dt_address(ranges + nac + pnac, nsc);
488 if (nac == 3) /* skip type if PCI */
489 cm = get_dt_address(ranges + 1, nac - 1);
491 cm = get_dt_address(ranges, nac);
493 DEBUG_TR("\t\tchild_mapping %lx\n", cm);
494 DEBUG_TR("\t\tsize %lx\n", size);
495 DEBUG_TR("\t\t*address %lx\n", (uint64_t) * addr);
496 if (cm + size <= (uint64_t) * addr || cm > (uint64_t) * addr)
497 /* it is not inside the mapping range */
501 /* and add the offset on the parent mapping */
502 if (pnac == 3) /* skip type if PCI */
503 pm = get_dt_address(ranges + nac + 1, pnac - 1);
505 pm = get_dt_address(ranges + nac, pnac);
506 DEBUG_TR("\t\tparent_mapping %lx\n", pm);
508 DEBUG_TR("\t\t*address %lx\n", *addr);
513 * translate_address_dev tries to translate the device specific address
514 * to a host specific address by walking up in the device tree
516 * @param address a pointer to a 64 bit value which will be
518 * @param current_node phandle of the device from which the
519 * translation will be started
522 translate_address_dev(uint64_t *addr, phandle_t current_node)
524 unsigned char buf[1024];
531 unsigned int *ranges;
532 unsigned int one_range;
533 DEBUG_TR("translate address %lx, node: %lx\n", *addr, current_node);
534 of_getprop(current_node, "name", buf, 400);
535 DEBUG_TR("current node: %s\n", buf);
537 pci_address_type(current_node, *addr, ASSIGNED_ADDRESS_PROPERTY);
538 if (addr_type == -1) {
539 // check in "reg" property if not found in "assigned-addresses"
540 addr_type = pci_address_type(current_node, *addr, REG_PROPERTY);
542 DEBUG_TR("address_type %x\n", addr_type);
543 current_node = of_parent(current_node);
545 parent = of_parent(current_node);
547 DEBUG_TR("reached root node...\n");
550 of_getprop(current_node, "#address-cells", &nac, 4);
551 of_getprop(current_node, "#size-cells", &nsc, 4);
552 of_getprop(parent, "#address-cells", &pnac, 4);
553 one_range = nac + pnac + nsc;
554 len = of_getprop(current_node, "ranges", buf, 400);
556 DEBUG_TR("no 'ranges' property; not translatable\n");
559 ranges = (unsigned int *) &buf[0];
562 ((uint64_t *) addr, addr_type, ranges, nac, nsc,
564 /* after a successful mapping we stop
565 * going through the ranges */
568 len -= one_range * sizeof(int);
570 DEBUG_TR("address %lx\n", *addr);
571 of_getprop(current_node, "name", buf, 400);
572 DEBUG_TR("current node: %s\n", buf);
573 DEBUG_TR("\t#address-cells: %x\n", nac);
574 DEBUG_TR("\t#size-cells: %x\n", nsc);
575 of_getprop(parent, "name", buf, 400);
576 DEBUG_TR("parent node: %s\n", buf);
577 DEBUG_TR("\t#address-cells: %x\n", pnac);
578 current_node = parent;
583 get_boot_device(void)
586 phandle_t dev = of_finddevice("/chosen");
589 dev = of_finddevice("/aliases");
592 of_getprop(dev, "net", buf, 1024);
594 of_getprop(dev, "bootpath", buf, 1024);
596 return of_finddevice(buf);
600 * translate_address tries to translate the device specific address
601 * of the boot device to a host specific address
603 * @param address a pointer to a 64 bit value which will be
607 translate_address(unsigned long *addr)
609 translate_address_dev((uint64_t*) addr, get_boot_device());
613 * get_puid walks up in the device tree until it finds a parent
614 * node without a reg property. get_puid is assuming that if the
615 * parent node has no reg property it has found the pci host bridge
617 * this is not the correct way to find PHBs but it seems to work
618 * for all our systems
620 * @param node the device for which to find the puid
622 * @return the puid or 0
625 get_puid(phandle_t node)
629 phandle_t curr_node, last_node;
631 curr_node = last_node = of_parent(node);
635 if (of_getprop(curr_node, "reg", &tmp, 8) < 8) {
636 /* if the found PHB is not directly under
637 * root we need to translate the found address */
638 translate_address_dev(&puid, last_node);
641 last_node = curr_node;
642 curr_node = of_parent(curr_node);
648 int of_get_mac(phandle_t device, char *mac)
653 len = of_getprop(device, "local-mac-address", localmac, 8);
658 /* Some bad FDT nodes like veth use a 8-byte wide
659 * property instead of 6-byte wide MACs... :-( */
660 memcpy(mac, &localmac[2], 6);
663 memcpy(mac, localmac, 6);
669 get_timebase(unsigned int *timebase)
672 phandle_t cpus = of_finddevice("/cpus");
677 cpu = of_child(cpus);
682 of_getprop(cpu, "timebase-frequency", timebase, 4);
685 int of_glue_init(unsigned int * timebase,
686 size_t _client_start, size_t _client_size)
688 phandle_t chosen = of_finddevice("/chosen");
689 ihandle_t stdin_ih, stdout_ih;
691 client_start = (void *) (long) _client_start;
692 client_size = _client_size;
697 of_getprop(chosen, "stdin", &stdin_ih, sizeof(ihandle_t));
698 of_getprop(chosen, "stdout", &stdout_ih, sizeof(ihandle_t));
699 pre_open_ih(0, stdin_ih);
700 pre_open_ih(1, stdout_ih);
701 pre_open_ih(2, stdout_ih);
702 get_timebase(timebase);
705 claim_rc=(int)(long)of_claim(client_start, client_size, 0);
710 void of_glue_release(void)
713 of_release(client_start, client_size);