162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file does the necessary interface mapping between the bootwrapper 462306a36Sopenharmony_ci * device tree operations and the interface provided by shared source 562306a36Sopenharmony_ci * files flatdevicetree.[ch]. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright 2007 David Gibson, IBM Corporation. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <stddef.h> 1162306a36Sopenharmony_ci#include <stdio.h> 1262306a36Sopenharmony_ci#include <page.h> 1362306a36Sopenharmony_ci#include <libfdt.h> 1462306a36Sopenharmony_ci#include "ops.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define DEBUG 0 1762306a36Sopenharmony_ci#define BAD_ERROR(err) (((err) < 0) \ 1862306a36Sopenharmony_ci && ((err) != -FDT_ERR_NOTFOUND) \ 1962306a36Sopenharmony_ci && ((err) != -FDT_ERR_EXISTS)) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define check_err(err) \ 2262306a36Sopenharmony_ci ({ \ 2362306a36Sopenharmony_ci if (BAD_ERROR(err) || ((err < 0) && DEBUG)) \ 2462306a36Sopenharmony_ci printf("%s():%d %s\n\r", __func__, __LINE__, \ 2562306a36Sopenharmony_ci fdt_strerror(err)); \ 2662306a36Sopenharmony_ci if (BAD_ERROR(err)) \ 2762306a36Sopenharmony_ci exit(); \ 2862306a36Sopenharmony_ci (err < 0) ? -1 : 0; \ 2962306a36Sopenharmony_ci }) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define offset_devp(off) \ 3262306a36Sopenharmony_ci ({ \ 3362306a36Sopenharmony_ci unsigned long _offset = (off); \ 3462306a36Sopenharmony_ci check_err(_offset) ? NULL : (void *)(_offset+1); \ 3562306a36Sopenharmony_ci }) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define devp_offset_find(devp) (((unsigned long)(devp))-1) 3862306a36Sopenharmony_ci#define devp_offset(devp) (devp ? ((unsigned long)(devp))-1 : 0) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void *fdt; 4162306a36Sopenharmony_cistatic void *buf; /* = NULL */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define EXPAND_GRANULARITY 1024 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic void expand_buf(int minexpand) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci int size = fdt_totalsize(fdt); 4862306a36Sopenharmony_ci int rc; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci size = _ALIGN(size + minexpand, EXPAND_GRANULARITY); 5162306a36Sopenharmony_ci buf = platform_ops.realloc(buf, size); 5262306a36Sopenharmony_ci if (!buf) 5362306a36Sopenharmony_ci fatal("Couldn't find %d bytes to expand device tree\n\r", size); 5462306a36Sopenharmony_ci rc = fdt_open_into(fdt, buf, size); 5562306a36Sopenharmony_ci if (rc != 0) 5662306a36Sopenharmony_ci fatal("Couldn't expand fdt into new buffer: %s\n\r", 5762306a36Sopenharmony_ci fdt_strerror(rc)); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci fdt = buf; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void *fdt_wrapper_finddevice(const char *path) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci return offset_devp(fdt_path_offset(fdt, path)); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int fdt_wrapper_getprop(const void *devp, const char *name, 6862306a36Sopenharmony_ci void *buf, const int buflen) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci const void *p; 7162306a36Sopenharmony_ci int len; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci p = fdt_getprop(fdt, devp_offset(devp), name, &len); 7462306a36Sopenharmony_ci if (!p) 7562306a36Sopenharmony_ci return check_err(len); 7662306a36Sopenharmony_ci memcpy(buf, p, min(len, buflen)); 7762306a36Sopenharmony_ci return len; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int fdt_wrapper_setprop(const void *devp, const char *name, 8162306a36Sopenharmony_ci const void *buf, const int len) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci int rc; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len); 8662306a36Sopenharmony_ci if (rc == -FDT_ERR_NOSPACE) { 8762306a36Sopenharmony_ci expand_buf(len + 16); 8862306a36Sopenharmony_ci rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return check_err(rc); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int fdt_wrapper_del_node(const void *devp) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci return fdt_del_node(fdt, devp_offset(devp)); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void *fdt_wrapper_get_parent(const void *devp) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return offset_devp(fdt_parent_offset(fdt, devp_offset(devp))); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void *fdt_wrapper_create_node(const void *devp, const char *name) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci int offset; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci offset = fdt_add_subnode(fdt, devp_offset(devp), name); 10962306a36Sopenharmony_ci if (offset == -FDT_ERR_NOSPACE) { 11062306a36Sopenharmony_ci expand_buf(strlen(name) + 16); 11162306a36Sopenharmony_ci offset = fdt_add_subnode(fdt, devp_offset(devp), name); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return offset_devp(offset); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void *fdt_wrapper_find_node_by_prop_value(const void *prev, 11862306a36Sopenharmony_ci const char *name, 11962306a36Sopenharmony_ci const char *val, 12062306a36Sopenharmony_ci int len) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci int offset = fdt_node_offset_by_prop_value(fdt, devp_offset_find(prev), 12362306a36Sopenharmony_ci name, val, len); 12462306a36Sopenharmony_ci return offset_devp(offset); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic void *fdt_wrapper_find_node_by_compatible(const void *prev, 12862306a36Sopenharmony_ci const char *val) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci int offset = fdt_node_offset_by_compatible(fdt, devp_offset_find(prev), 13162306a36Sopenharmony_ci val); 13262306a36Sopenharmony_ci return offset_devp(offset); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic char *fdt_wrapper_get_path(const void *devp, char *buf, int len) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci int rc; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci rc = fdt_get_path(fdt, devp_offset(devp), buf, len); 14062306a36Sopenharmony_ci if (check_err(rc)) 14162306a36Sopenharmony_ci return NULL; 14262306a36Sopenharmony_ci return buf; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic unsigned long fdt_wrapper_finalize(void) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci int rc; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci rc = fdt_pack(fdt); 15062306a36Sopenharmony_ci if (rc != 0) 15162306a36Sopenharmony_ci fatal("Couldn't pack flat tree: %s\n\r", 15262306a36Sopenharmony_ci fdt_strerror(rc)); 15362306a36Sopenharmony_ci return (unsigned long)fdt; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_civoid fdt_init(void *blob) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci int err; 15962306a36Sopenharmony_ci int bufsize; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci dt_ops.finddevice = fdt_wrapper_finddevice; 16262306a36Sopenharmony_ci dt_ops.getprop = fdt_wrapper_getprop; 16362306a36Sopenharmony_ci dt_ops.setprop = fdt_wrapper_setprop; 16462306a36Sopenharmony_ci dt_ops.get_parent = fdt_wrapper_get_parent; 16562306a36Sopenharmony_ci dt_ops.create_node = fdt_wrapper_create_node; 16662306a36Sopenharmony_ci dt_ops.find_node_by_prop_value = fdt_wrapper_find_node_by_prop_value; 16762306a36Sopenharmony_ci dt_ops.find_node_by_compatible = fdt_wrapper_find_node_by_compatible; 16862306a36Sopenharmony_ci dt_ops.del_node = fdt_wrapper_del_node; 16962306a36Sopenharmony_ci dt_ops.get_path = fdt_wrapper_get_path; 17062306a36Sopenharmony_ci dt_ops.finalize = fdt_wrapper_finalize; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Make sure the dt blob is the right version and so forth */ 17362306a36Sopenharmony_ci fdt = blob; 17462306a36Sopenharmony_ci bufsize = fdt_totalsize(fdt) + EXPAND_GRANULARITY; 17562306a36Sopenharmony_ci buf = malloc(bufsize); 17662306a36Sopenharmony_ci if(!buf) 17762306a36Sopenharmony_ci fatal("malloc failed. can't relocate the device tree\n\r"); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci err = fdt_open_into(fdt, buf, bufsize); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (err != 0) 18262306a36Sopenharmony_ci fatal("fdt_init(): %s\n\r", fdt_strerror(err)); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci fdt = buf; 18562306a36Sopenharmony_ci} 186