162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * libfdt - Flat Device Tree manipulation 462306a36Sopenharmony_ci * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> 562306a36Sopenharmony_ci * Copyright (C) 2018 embedded brains GmbH 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include "libfdt_env.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <fdt.h> 1062306a36Sopenharmony_ci#include <libfdt.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "libfdt_internal.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int fdt_cells(const void *fdt, int nodeoffset, const char *name) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci const fdt32_t *c; 1762306a36Sopenharmony_ci uint32_t val; 1862306a36Sopenharmony_ci int len; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci c = fdt_getprop(fdt, nodeoffset, name, &len); 2162306a36Sopenharmony_ci if (!c) 2262306a36Sopenharmony_ci return len; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if (len != sizeof(*c)) 2562306a36Sopenharmony_ci return -FDT_ERR_BADNCELLS; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci val = fdt32_to_cpu(*c); 2862306a36Sopenharmony_ci if (val > FDT_MAX_NCELLS) 2962306a36Sopenharmony_ci return -FDT_ERR_BADNCELLS; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci return (int)val; 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciint fdt_address_cells(const void *fdt, int nodeoffset) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci int val; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci val = fdt_cells(fdt, nodeoffset, "#address-cells"); 3962306a36Sopenharmony_ci if (val == 0) 4062306a36Sopenharmony_ci return -FDT_ERR_BADNCELLS; 4162306a36Sopenharmony_ci if (val == -FDT_ERR_NOTFOUND) 4262306a36Sopenharmony_ci return 2; 4362306a36Sopenharmony_ci return val; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciint fdt_size_cells(const void *fdt, int nodeoffset) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci int val; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci val = fdt_cells(fdt, nodeoffset, "#size-cells"); 5162306a36Sopenharmony_ci if (val == -FDT_ERR_NOTFOUND) 5262306a36Sopenharmony_ci return 1; 5362306a36Sopenharmony_ci return val; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* This function assumes that [address|size]_cells is 1 or 2 */ 5762306a36Sopenharmony_ciint fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, 5862306a36Sopenharmony_ci const char *name, uint64_t addr, uint64_t size) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci int addr_cells, size_cells, ret; 6162306a36Sopenharmony_ci uint8_t data[sizeof(fdt64_t) * 2], *prop; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci ret = fdt_address_cells(fdt, parent); 6462306a36Sopenharmony_ci if (ret < 0) 6562306a36Sopenharmony_ci return ret; 6662306a36Sopenharmony_ci addr_cells = ret; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci ret = fdt_size_cells(fdt, parent); 6962306a36Sopenharmony_ci if (ret < 0) 7062306a36Sopenharmony_ci return ret; 7162306a36Sopenharmony_ci size_cells = ret; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* check validity of address */ 7462306a36Sopenharmony_ci prop = data; 7562306a36Sopenharmony_ci if (addr_cells == 1) { 7662306a36Sopenharmony_ci if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) 7762306a36Sopenharmony_ci return -FDT_ERR_BADVALUE; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci fdt32_st(prop, (uint32_t)addr); 8062306a36Sopenharmony_ci } else if (addr_cells == 2) { 8162306a36Sopenharmony_ci fdt64_st(prop, addr); 8262306a36Sopenharmony_ci } else { 8362306a36Sopenharmony_ci return -FDT_ERR_BADNCELLS; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* check validity of size */ 8762306a36Sopenharmony_ci prop += addr_cells * sizeof(fdt32_t); 8862306a36Sopenharmony_ci if (size_cells == 1) { 8962306a36Sopenharmony_ci if (size > UINT32_MAX) 9062306a36Sopenharmony_ci return -FDT_ERR_BADVALUE; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci fdt32_st(prop, (uint32_t)size); 9362306a36Sopenharmony_ci } else if (size_cells == 2) { 9462306a36Sopenharmony_ci fdt64_st(prop, size); 9562306a36Sopenharmony_ci } else { 9662306a36Sopenharmony_ci return -FDT_ERR_BADNCELLS; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return fdt_appendprop(fdt, nodeoffset, name, data, 10062306a36Sopenharmony_ci (addr_cells + size_cells) * sizeof(fdt32_t)); 10162306a36Sopenharmony_ci} 102