18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file does the necessary interface mapping between the bootwrapper 48c2ecf20Sopenharmony_ci * device tree operations and the interface provided by shared source 58c2ecf20Sopenharmony_ci * files flatdevicetree.[ch]. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright 2007 David Gibson, IBM Corporation. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <stddef.h> 118c2ecf20Sopenharmony_ci#include <stdio.h> 128c2ecf20Sopenharmony_ci#include <page.h> 138c2ecf20Sopenharmony_ci#include <libfdt.h> 148c2ecf20Sopenharmony_ci#include "ops.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define DEBUG 0 178c2ecf20Sopenharmony_ci#define BAD_ERROR(err) (((err) < 0) \ 188c2ecf20Sopenharmony_ci && ((err) != -FDT_ERR_NOTFOUND) \ 198c2ecf20Sopenharmony_ci && ((err) != -FDT_ERR_EXISTS)) 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define check_err(err) \ 228c2ecf20Sopenharmony_ci ({ \ 238c2ecf20Sopenharmony_ci if (BAD_ERROR(err) || ((err < 0) && DEBUG)) \ 248c2ecf20Sopenharmony_ci printf("%s():%d %s\n\r", __func__, __LINE__, \ 258c2ecf20Sopenharmony_ci fdt_strerror(err)); \ 268c2ecf20Sopenharmony_ci if (BAD_ERROR(err)) \ 278c2ecf20Sopenharmony_ci exit(); \ 288c2ecf20Sopenharmony_ci (err < 0) ? -1 : 0; \ 298c2ecf20Sopenharmony_ci }) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define offset_devp(off) \ 328c2ecf20Sopenharmony_ci ({ \ 338c2ecf20Sopenharmony_ci unsigned long _offset = (off); \ 348c2ecf20Sopenharmony_ci check_err(_offset) ? NULL : (void *)(_offset+1); \ 358c2ecf20Sopenharmony_ci }) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define devp_offset_find(devp) (((unsigned long)(devp))-1) 388c2ecf20Sopenharmony_ci#define devp_offset(devp) (devp ? ((unsigned long)(devp))-1 : 0) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void *fdt; 418c2ecf20Sopenharmony_cistatic void *buf; /* = NULL */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define EXPAND_GRANULARITY 1024 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void expand_buf(int minexpand) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int size = fdt_totalsize(fdt); 488c2ecf20Sopenharmony_ci int rc; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci size = _ALIGN(size + minexpand, EXPAND_GRANULARITY); 518c2ecf20Sopenharmony_ci buf = platform_ops.realloc(buf, size); 528c2ecf20Sopenharmony_ci if (!buf) 538c2ecf20Sopenharmony_ci fatal("Couldn't find %d bytes to expand device tree\n\r", size); 548c2ecf20Sopenharmony_ci rc = fdt_open_into(fdt, buf, size); 558c2ecf20Sopenharmony_ci if (rc != 0) 568c2ecf20Sopenharmony_ci fatal("Couldn't expand fdt into new buffer: %s\n\r", 578c2ecf20Sopenharmony_ci fdt_strerror(rc)); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci fdt = buf; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void *fdt_wrapper_finddevice(const char *path) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci return offset_devp(fdt_path_offset(fdt, path)); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int fdt_wrapper_getprop(const void *devp, const char *name, 688c2ecf20Sopenharmony_ci void *buf, const int buflen) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci const void *p; 718c2ecf20Sopenharmony_ci int len; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci p = fdt_getprop(fdt, devp_offset(devp), name, &len); 748c2ecf20Sopenharmony_ci if (!p) 758c2ecf20Sopenharmony_ci return check_err(len); 768c2ecf20Sopenharmony_ci memcpy(buf, p, min(len, buflen)); 778c2ecf20Sopenharmony_ci return len; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int fdt_wrapper_setprop(const void *devp, const char *name, 818c2ecf20Sopenharmony_ci const void *buf, const int len) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci int rc; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len); 868c2ecf20Sopenharmony_ci if (rc == -FDT_ERR_NOSPACE) { 878c2ecf20Sopenharmony_ci expand_buf(len + 16); 888c2ecf20Sopenharmony_ci rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len); 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return check_err(rc); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int fdt_wrapper_del_node(const void *devp) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci return fdt_del_node(fdt, devp_offset(devp)); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void *fdt_wrapper_get_parent(const void *devp) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci return offset_devp(fdt_parent_offset(fdt, devp_offset(devp))); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void *fdt_wrapper_create_node(const void *devp, const char *name) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int offset; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci offset = fdt_add_subnode(fdt, devp_offset(devp), name); 1098c2ecf20Sopenharmony_ci if (offset == -FDT_ERR_NOSPACE) { 1108c2ecf20Sopenharmony_ci expand_buf(strlen(name) + 16); 1118c2ecf20Sopenharmony_ci offset = fdt_add_subnode(fdt, devp_offset(devp), name); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return offset_devp(offset); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void *fdt_wrapper_find_node_by_prop_value(const void *prev, 1188c2ecf20Sopenharmony_ci const char *name, 1198c2ecf20Sopenharmony_ci const char *val, 1208c2ecf20Sopenharmony_ci int len) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci int offset = fdt_node_offset_by_prop_value(fdt, devp_offset_find(prev), 1238c2ecf20Sopenharmony_ci name, val, len); 1248c2ecf20Sopenharmony_ci return offset_devp(offset); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic void *fdt_wrapper_find_node_by_compatible(const void *prev, 1288c2ecf20Sopenharmony_ci const char *val) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci int offset = fdt_node_offset_by_compatible(fdt, devp_offset_find(prev), 1318c2ecf20Sopenharmony_ci val); 1328c2ecf20Sopenharmony_ci return offset_devp(offset); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic char *fdt_wrapper_get_path(const void *devp, char *buf, int len) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci int rc; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci rc = fdt_get_path(fdt, devp_offset(devp), buf, len); 1408c2ecf20Sopenharmony_ci if (check_err(rc)) 1418c2ecf20Sopenharmony_ci return NULL; 1428c2ecf20Sopenharmony_ci return buf; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic unsigned long fdt_wrapper_finalize(void) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int rc; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci rc = fdt_pack(fdt); 1508c2ecf20Sopenharmony_ci if (rc != 0) 1518c2ecf20Sopenharmony_ci fatal("Couldn't pack flat tree: %s\n\r", 1528c2ecf20Sopenharmony_ci fdt_strerror(rc)); 1538c2ecf20Sopenharmony_ci return (unsigned long)fdt; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_civoid fdt_init(void *blob) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci int err; 1598c2ecf20Sopenharmony_ci int bufsize; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci dt_ops.finddevice = fdt_wrapper_finddevice; 1628c2ecf20Sopenharmony_ci dt_ops.getprop = fdt_wrapper_getprop; 1638c2ecf20Sopenharmony_ci dt_ops.setprop = fdt_wrapper_setprop; 1648c2ecf20Sopenharmony_ci dt_ops.get_parent = fdt_wrapper_get_parent; 1658c2ecf20Sopenharmony_ci dt_ops.create_node = fdt_wrapper_create_node; 1668c2ecf20Sopenharmony_ci dt_ops.find_node_by_prop_value = fdt_wrapper_find_node_by_prop_value; 1678c2ecf20Sopenharmony_ci dt_ops.find_node_by_compatible = fdt_wrapper_find_node_by_compatible; 1688c2ecf20Sopenharmony_ci dt_ops.del_node = fdt_wrapper_del_node; 1698c2ecf20Sopenharmony_ci dt_ops.get_path = fdt_wrapper_get_path; 1708c2ecf20Sopenharmony_ci dt_ops.finalize = fdt_wrapper_finalize; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* Make sure the dt blob is the right version and so forth */ 1738c2ecf20Sopenharmony_ci fdt = blob; 1748c2ecf20Sopenharmony_ci bufsize = fdt_totalsize(fdt) + EXPAND_GRANULARITY; 1758c2ecf20Sopenharmony_ci buf = malloc(bufsize); 1768c2ecf20Sopenharmony_ci if(!buf) 1778c2ecf20Sopenharmony_ci fatal("malloc failed. can't relocate the device tree\n\r"); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci err = fdt_open_into(fdt, buf, bufsize); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (err != 0) 1828c2ecf20Sopenharmony_ci fatal("fdt_init(): %s\n\r", fdt_strerror(err)); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci fdt = buf; 1858c2ecf20Sopenharmony_ci} 186