File indexing completed on 2025-05-11 08:24:08
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #ifdef HAVE_CONFIG_H
0035 #include "config.h"
0036 #endif
0037
0038 #include <bsp/fdt.h>
0039 #include <sys/param.h>
0040 #include <ofw/ofw.h>
0041 #include <libfdt.h>
0042 #include <assert.h>
0043 #include <rtems/sysinit.h>
0044 #include <ofw/ofw_test.h>
0045 #include <rtems/score/assert.h>
0046
0047 static void *fdtp = NULL;
0048
0049 static phandle_t rtems_fdt_offset_to_phandle( int offset )
0050 {
0051 if (offset < 0) {
0052 return 0;
0053 }
0054
0055 return (phandle_t)offset + fdt_off_dt_struct(fdtp);
0056 }
0057
0058 static int rtems_fdt_phandle_to_offset( phandle_t handle )
0059 {
0060 int off;
0061 int fdt_off;
0062
0063 off = (int) handle;
0064 fdt_off = fdt_off_dt_struct(fdtp);
0065
0066 if (off < fdt_off) {
0067 return -1;
0068
0069 }
0070
0071 return off - fdt_off;
0072 }
0073
0074 void rtems_ofw_init( void ) {
0075 int rv;
0076 const void *fdt;
0077
0078 fdt = bsp_fdt_get();
0079
0080 rv = fdt_check_header(fdt);
0081
0082
0083
0084
0085 if (rv != 0) {
0086 rtems_fatal_error_occurred(RTEMS_NOT_CONFIGURED);
0087 }
0088
0089 fdtp = (void *)fdt;
0090 }
0091
0092 RTEMS_SYSINIT_ITEM(
0093 rtems_ofw_init,
0094 RTEMS_SYSINIT_BSP_PRE_DRIVERS,
0095 RTEMS_SYSINIT_ORDER_FIRST
0096 );
0097
0098 phandle_t rtems_ofw_peer( phandle_t node )
0099 {
0100 int offset;
0101
0102 if (node == 0) {
0103 int root = fdt_path_offset(fdtp, "/");
0104 return rtems_fdt_offset_to_phandle(root);
0105 }
0106
0107 offset = rtems_fdt_phandle_to_offset(node);
0108 if (offset < 0) {
0109 return 0;
0110 }
0111
0112 offset = fdt_next_subnode(fdtp, offset);
0113 return rtems_fdt_offset_to_phandle(offset);
0114 }
0115
0116 phandle_t rtems_ofw_child( phandle_t node )
0117 {
0118 int offset;
0119
0120 offset = rtems_fdt_phandle_to_offset(node);
0121
0122 if (offset < 0) {
0123 return 0;
0124 }
0125
0126 offset = fdt_first_subnode(fdtp, offset);
0127 return rtems_fdt_offset_to_phandle(offset);
0128 }
0129
0130 phandle_t rtems_ofw_parent( phandle_t node )
0131 {
0132 int offset;
0133
0134 offset = rtems_fdt_phandle_to_offset(node);
0135
0136 if (offset < 0) {
0137 return 0;
0138 }
0139
0140 offset = fdt_parent_offset(fdtp, offset);
0141 return rtems_fdt_offset_to_phandle(offset);
0142 }
0143
0144 ssize_t rtems_ofw_get_prop_len(
0145 phandle_t node,
0146 const char *propname
0147 )
0148 {
0149 int offset;
0150 int len;
0151 const void *prop;
0152
0153 offset = rtems_fdt_phandle_to_offset(node);
0154
0155 if (offset < 0) {
0156 return -1;
0157 }
0158
0159 prop = fdt_getprop(fdtp, offset, propname, &len);
0160
0161 if (prop == NULL && strcmp(propname, "name") == 0) {
0162 fdt_get_name(fdtp, offset, &len);
0163 return len + 1;
0164 }
0165
0166 if (prop == NULL && offset == fdt_path_offset(fdtp, "/chosen")) {
0167 if (strcmp(propname, "fdtbootcpu") == 0)
0168 return sizeof(pcell_t);
0169 if (strcmp(propname, "fdtmemreserv") == 0)
0170 return 2 * sizeof(uint64_t) * fdt_num_mem_rsv(fdtp);
0171 }
0172
0173 if (prop == NULL) {
0174 return -1;
0175 }
0176
0177 return len;
0178 }
0179
0180 ssize_t rtems_ofw_get_prop(
0181 phandle_t node,
0182 const char *propname,
0183 void *buf,
0184 size_t bufsize
0185 )
0186 {
0187 const void *prop;
0188 int offset;
0189 int len;
0190 int copy_len;
0191 uint32_t cpuid;
0192
0193 offset = rtems_fdt_phandle_to_offset(node);
0194
0195 if (offset < 0) {
0196 return -1;
0197 }
0198
0199 prop = fdt_getprop(fdtp, offset, propname, &len);
0200
0201 if (prop == NULL && strcmp(propname, "name") == 0) {
0202 prop = fdt_get_name(fdtp, offset, &len);
0203
0204
0205
0206 strlcpy(buf, prop, bufsize);
0207
0208
0209
0210
0211
0212 return len + 1;
0213 }
0214
0215 if (prop == NULL && offset == fdt_path_offset(fdtp, "/chosen")) {
0216 if (strcmp(propname, "fdtbootcpu") == 0) {
0217 cpuid = cpu_to_fdt32(fdt_boot_cpuid_phys(fdtp));
0218 len = sizeof(cpuid);
0219 prop = &cpuid;
0220 }
0221 if (strcmp(propname, "fdtmemreserv") == 0) {
0222 prop = (char *)fdtp + fdt_off_mem_rsvmap(fdtp);
0223 len = sizeof(uint64_t)*2*fdt_num_mem_rsv(fdtp);
0224 }
0225 }
0226
0227 if (prop == NULL) {
0228 return -1;
0229 }
0230
0231 copy_len = MIN(len, bufsize);
0232 _Assert(copy_len <= bufsize);
0233 memmove(buf, prop, copy_len);
0234
0235 return len;
0236 }
0237
0238 ssize_t rtems_ofw_get_enc_prop(
0239 phandle_t node,
0240 const char *prop,
0241 pcell_t *buf,
0242 size_t len
0243 )
0244 {
0245 ssize_t rv;
0246
0247 assert(len % sizeof(pcell_t) == 0);
0248 rv = rtems_ofw_get_prop(node, prop, buf, len);
0249
0250 if (rv < 0) {
0251 return rv;
0252 }
0253
0254 for (int i = 0; i < (len / 4); i++) {
0255 buf[i] = fdt32_to_cpu(buf[i]);
0256 }
0257
0258 return rv;
0259 }
0260
0261 int rtems_ofw_has_prop(
0262 phandle_t node,
0263 const char *propname
0264 )
0265 {
0266 ssize_t rv;
0267
0268 rv = rtems_ofw_get_prop_len(node, propname);
0269 return rv >= 0 ? 1 : 0;
0270 }
0271
0272 ssize_t rtems_ofw_search_prop(
0273 phandle_t node,
0274 const char *propname,
0275 void *buf,
0276 size_t len
0277 )
0278 {
0279 ssize_t rv;
0280
0281 for (; node != 0; node = rtems_ofw_parent(node)) {
0282 if ((rv = rtems_ofw_get_prop(node, propname, buf, len) != -1)) {
0283 return rv;
0284 }
0285 }
0286
0287 return -1;
0288 }
0289
0290 ssize_t rtems_ofw_search_enc_prop(
0291 phandle_t node,
0292 const char *propname,
0293 pcell_t *buf,
0294 size_t len
0295 )
0296 {
0297 ssize_t rv;
0298
0299 for (; node != 0; node = rtems_ofw_parent(node)) {
0300 if ((rv = rtems_ofw_get_enc_prop(node, propname, buf, len) != -1)) {
0301 return rv;
0302 }
0303 }
0304
0305 return -1;
0306 }
0307
0308 ssize_t rtems_ofw_get_prop_alloc(
0309 phandle_t node,
0310 const char *propname,
0311 void **buf
0312 )
0313 {
0314 ssize_t len;
0315
0316 *buf = NULL;
0317 if ((len = rtems_ofw_get_prop_len(node, propname)) == -1) {
0318 return -1;
0319 }
0320
0321 if (len > 0) {
0322 *buf = malloc(len);
0323 if (*buf == NULL) {
0324 return -1;
0325 }
0326
0327 if (rtems_ofw_get_prop(node, propname, *buf, len) == -1) {
0328 rtems_ofw_free(*buf);
0329 *buf = NULL;
0330 return -1;
0331 }
0332 }
0333
0334 return len;
0335 }
0336
0337 ssize_t rtems_ofw_get_prop_alloc_multi(
0338 phandle_t node,
0339 const char *propname,
0340 int elsz,
0341 void **buf
0342 )
0343 {
0344 ssize_t len;
0345
0346 *buf = NULL;
0347 if ((len = rtems_ofw_get_prop_len(node, propname)) == -1 ||
0348 (len % elsz != 0)) {
0349 return -1;
0350 }
0351
0352 if (len > 0) {
0353 *buf = malloc(len);
0354 if (*buf == NULL) {
0355 return -1;
0356 }
0357
0358 if (rtems_ofw_get_prop(node, propname, *buf, len) == -1) {
0359 rtems_ofw_free(*buf);
0360 *buf = NULL;
0361 return -1;
0362 }
0363 }
0364
0365 return (len / elsz);
0366 }
0367
0368 ssize_t rtems_ofw_get_enc_prop_alloc(
0369 phandle_t node,
0370 const char *propname,
0371 void **buf
0372 )
0373 {
0374 ssize_t len;
0375
0376 *buf = NULL;
0377 if ((len = rtems_ofw_get_prop_len(node, propname)) == -1) {
0378 return -1;
0379 }
0380
0381 if (len > 0) {
0382 *buf = malloc(len);
0383 if (*buf == NULL) {
0384 return -1;
0385 }
0386
0387 if (rtems_ofw_get_enc_prop(node, propname, *buf, len) == -1) {
0388 rtems_ofw_free(*buf);
0389 *buf = NULL;
0390 return -1;
0391 }
0392 }
0393
0394 return len;
0395 }
0396
0397 ssize_t rtems_ofw_get_enc_prop_alloc_multi(
0398 phandle_t node,
0399 const char *propname,
0400 int elsz,
0401 void **buf
0402 )
0403 {
0404 ssize_t len;
0405
0406 *buf = NULL;
0407 if ((len = rtems_ofw_get_prop_len(node, propname)) == -1 ||
0408 (len % elsz != 0)) {
0409 return -1;
0410 }
0411
0412 if (len > 0) {
0413 *buf = malloc(len);
0414 if (*buf == NULL) {
0415 return -1;
0416 }
0417
0418 if (rtems_ofw_get_enc_prop(node, propname, *buf, len) == -1) {
0419 rtems_ofw_free(*buf);
0420 *buf = NULL;
0421 return -1;
0422 }
0423 }
0424
0425 return (len / elsz);
0426 }
0427
0428 void rtems_ofw_free( void *buf )
0429 {
0430 free(buf);
0431 }
0432
0433 int rtems_ofw_next_prop(
0434 phandle_t node,
0435 const char *previous,
0436 char *buf,
0437 size_t len
0438 )
0439 {
0440 const void *name;
0441 const void *prop;
0442 int offset;
0443
0444 offset = rtems_fdt_phandle_to_offset(node);
0445
0446 if (offset < 0) {
0447 return -1;
0448 }
0449
0450 if (previous == NULL) {
0451 offset = fdt_first_property_offset(fdtp, offset);
0452 } else {
0453 fdt_for_each_property_offset(offset, fdtp, offset) {
0454 prop = fdt_getprop_by_offset(fdtp, offset, (const char **)&name, NULL);
0455 if (prop == NULL)
0456 return -1;
0457
0458 if (strcmp(previous, name) != 0)
0459 continue;
0460
0461 offset = fdt_next_property_offset(fdtp, offset);
0462 break;
0463 }
0464 }
0465
0466 if (offset < 0)
0467 return 0;
0468
0469 prop = fdt_getprop_by_offset(fdtp, offset, (const char **)&name, &offset);
0470 if (prop == NULL)
0471 return -1;
0472
0473 strncpy(buf, name, len);
0474
0475 return 1;
0476 }
0477
0478 int rtems_ofw_set_prop(
0479 phandle_t node,
0480 const char *name,
0481 const void *buf,
0482 size_t len
0483 )
0484 {
0485 int offset;
0486
0487 offset = rtems_fdt_phandle_to_offset(node);
0488
0489 if (offset < 0)
0490 return -1;
0491
0492 if (fdt_setprop_inplace(fdtp, offset, name, buf, len) != 0)
0493 return (fdt_setprop(fdtp, offset, name, buf, len));
0494
0495 return 0;
0496 }
0497
0498 phandle_t rtems_ofw_find_device( const char *path )
0499 {
0500 int offset;
0501
0502 offset = fdt_path_offset(fdtp, path);
0503 if (offset < 0)
0504 return -1;
0505
0506 return rtems_fdt_offset_to_phandle(offset);
0507 }
0508
0509 static phandle_t rtems_ofw_get_effective_phandle(
0510 phandle_t node,
0511 phandle_t xref
0512 )
0513 {
0514 phandle_t child;
0515 phandle_t ref;
0516 int node_offset;
0517
0518 node_offset = fdt_path_offset(fdtp, "/");
0519
0520 while ((node_offset = fdt_next_node(fdtp, node_offset, NULL)) > 0) {
0521 child = rtems_fdt_offset_to_phandle(node_offset);
0522
0523 if (rtems_ofw_get_enc_prop(child, "phandle", &ref, sizeof(ref)) == -1 &&
0524 rtems_ofw_get_enc_prop(child, "ibm,phandle", &ref, sizeof(ref)) == -1 &&
0525 rtems_ofw_get_enc_prop(child, "linux,phandle", &ref, sizeof(ref)) == -1
0526 ) {
0527 continue;
0528 }
0529
0530 if (ref == xref)
0531 return child;
0532 }
0533
0534 return -1;
0535 }
0536
0537 phandle_t rtems_ofw_node_from_xref( phandle_t xref )
0538 {
0539 phandle_t node;
0540
0541 if ((node = rtems_ofw_get_effective_phandle(rtems_ofw_peer(0), xref)) == -1)
0542 return xref;
0543
0544 return node;
0545 }
0546
0547 phandle_t rtems_ofw_xref_from_node( phandle_t node )
0548 {
0549 phandle_t ref;
0550
0551 if (rtems_ofw_get_enc_prop(node, "phandle", &ref, sizeof(ref)) == -1 &&
0552 rtems_ofw_get_enc_prop(node, "ibm,phandle", &ref, sizeof(ref)) == -1 &&
0553 rtems_ofw_get_enc_prop(node, "linux,phandle", &ref, sizeof(ref)) == -1)
0554 {
0555 return node;
0556 }
0557
0558 return ref;
0559 }
0560
0561 phandle_t rtems_ofw_instance_to_package( ihandle_t instance )
0562 {
0563 return rtems_ofw_node_from_xref(instance);
0564 }
0565
0566 ssize_t rtems_ofw_package_to_path(
0567 phandle_t node,
0568 char *buf,
0569 size_t len
0570 )
0571 {
0572 int offset;
0573 int rv;
0574
0575 offset = rtems_fdt_phandle_to_offset(node);
0576
0577 rv = fdt_get_path(fdtp, offset, buf, len);
0578 if (rv != 0)
0579 return -1;
0580
0581 return rv;
0582 }
0583
0584 ssize_t rtems_ofw_instance_to_path(
0585 ihandle_t instance,
0586 char *buf,
0587 size_t len
0588 )
0589 {
0590 int offset;
0591 int rv;
0592
0593 offset = rtems_ofw_instance_to_package(instance);
0594 offset = rtems_fdt_phandle_to_offset(offset);
0595
0596 rv = fdt_get_path(fdtp, offset, buf, len);
0597 if (rv != 0)
0598 return -1;
0599
0600 return rv;
0601 }
0602
0603 int rtems_ofw_get_reg(
0604 phandle_t node,
0605 rtems_ofw_memory_area *buf,
0606 size_t size
0607 )
0608 {
0609 int len;
0610 int offset;
0611 int nranges;
0612 int nregs;
0613 phandle_t parent;
0614 rtems_ofw_ranges range;
0615 const rtems_ofw_ranges *ptr;
0616
0617 len = rtems_ofw_get_enc_prop(node, "reg", (pcell_t *)buf, size);
0618 if (len <= 0) {
0619 return len;
0620 }
0621
0622 nregs = MIN(len, size) / sizeof(rtems_ofw_memory_area);
0623
0624 for (parent = rtems_ofw_parent(node); parent > 0;
0625 parent = rtems_ofw_parent(parent)) {
0626
0627 offset = rtems_fdt_phandle_to_offset(parent);
0628 ptr = fdt_getprop(fdtp, offset, "ranges", &len);
0629
0630 if (ptr == NULL) {
0631 break;
0632 }
0633
0634 nranges = len / sizeof(rtems_ofw_ranges);
0635
0636 offset = 0;
0637 for (int i=0; i < nregs; i++) {
0638 for (int j=0; j < nranges; j++) {
0639
0640 range.parent_bus = fdt32_to_cpu(ptr[j].parent_bus);
0641 range.child_bus = fdt32_to_cpu(ptr[j].child_bus);
0642 range.size = fdt32_to_cpu(ptr[j].size);
0643
0644
0645
0646
0647
0648
0649 _Assert(&buf[i] < (buf + size - (sizeof(buf[0]) - 1)));
0650 if (buf[i].start >= range.child_bus &&
0651 buf[i].start < range.child_bus + range.size) {
0652 offset = range.parent_bus - range.child_bus;
0653 break;
0654 }
0655
0656 }
0657 buf[i].start += offset;
0658 }
0659 }
0660
0661 return nregs;
0662 }
0663
0664 int rtems_ofw_get_interrupts(
0665 phandle_t node,
0666 rtems_vector_number *buf,
0667 size_t size
0668 )
0669 {
0670 int rv;
0671
0672 rv = rtems_ofw_get_enc_prop(node, "interrupts", buf, size);
0673
0674 if (rv <= 0) {
0675 return rv;
0676 }
0677
0678 return MIN(size, rv) / sizeof(rtems_vector_number);
0679 }
0680
0681 bool rtems_ofw_node_status( phandle_t node )
0682 {
0683 int len;
0684 const char buf[10];
0685
0686 len = rtems_ofw_get_prop(node, "status", (void *)&buf[0], sizeof(buf));
0687 if ((len == -1) ||
0688 (strncmp(buf, "okay", MIN(5, len)) == 0) ||
0689 (strncmp(buf, "ok", MIN(3, len)) == 0)) {
0690 return true;
0691 }
0692
0693 return false;
0694 }
0695
0696 phandle_t rtems_ofw_find_device_by_compat( const char *compat )
0697 {
0698 int offset;
0699
0700 offset = fdt_node_offset_by_compatible(fdtp, -1, compat);
0701 return rtems_fdt_offset_to_phandle(offset);
0702 }
0703
0704 bool rtems_ofw_is_node_compatible(
0705 phandle_t node,
0706 const char *compat
0707 )
0708 {
0709 int offset;
0710
0711 offset = rtems_fdt_phandle_to_offset(node);
0712
0713 return fdt_node_check_compatible(fdtp, offset, compat) == 0;
0714 }