1*553125dfSNikos Nikoleris // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2*553125dfSNikos Nikoleris /* 3*553125dfSNikos Nikoleris * libfdt - Flat Device Tree manipulation 4*553125dfSNikos Nikoleris * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> 5*553125dfSNikos Nikoleris * Copyright (C) 2018 embedded brains GmbH 6*553125dfSNikos Nikoleris */ 7*553125dfSNikos Nikoleris #include "libfdt_env.h" 8*553125dfSNikos Nikoleris 9*553125dfSNikos Nikoleris #include <fdt.h> 10*553125dfSNikos Nikoleris #include <libfdt.h> 11*553125dfSNikos Nikoleris 12*553125dfSNikos Nikoleris #include "libfdt_internal.h" 13*553125dfSNikos Nikoleris 14*553125dfSNikos Nikoleris static int fdt_cells(const void *fdt, int nodeoffset, const char *name) 15*553125dfSNikos Nikoleris { 16*553125dfSNikos Nikoleris const fdt32_t *c; 17*553125dfSNikos Nikoleris uint32_t val; 18*553125dfSNikos Nikoleris int len; 19*553125dfSNikos Nikoleris 20*553125dfSNikos Nikoleris c = fdt_getprop(fdt, nodeoffset, name, &len); 21*553125dfSNikos Nikoleris if (!c) 22*553125dfSNikos Nikoleris return len; 23*553125dfSNikos Nikoleris 24*553125dfSNikos Nikoleris if (len != sizeof(*c)) 25*553125dfSNikos Nikoleris return -FDT_ERR_BADNCELLS; 26*553125dfSNikos Nikoleris 27*553125dfSNikos Nikoleris val = fdt32_to_cpu(*c); 28*553125dfSNikos Nikoleris if (val > FDT_MAX_NCELLS) 29*553125dfSNikos Nikoleris return -FDT_ERR_BADNCELLS; 30*553125dfSNikos Nikoleris 31*553125dfSNikos Nikoleris return (int)val; 32*553125dfSNikos Nikoleris } 33*553125dfSNikos Nikoleris 34*553125dfSNikos Nikoleris int fdt_address_cells(const void *fdt, int nodeoffset) 35*553125dfSNikos Nikoleris { 36*553125dfSNikos Nikoleris int val; 37*553125dfSNikos Nikoleris 38*553125dfSNikos Nikoleris val = fdt_cells(fdt, nodeoffset, "#address-cells"); 39*553125dfSNikos Nikoleris if (val == 0) 40*553125dfSNikos Nikoleris return -FDT_ERR_BADNCELLS; 41*553125dfSNikos Nikoleris if (val == -FDT_ERR_NOTFOUND) 42*553125dfSNikos Nikoleris return 2; 43*553125dfSNikos Nikoleris return val; 44*553125dfSNikos Nikoleris } 45*553125dfSNikos Nikoleris 46*553125dfSNikos Nikoleris int fdt_size_cells(const void *fdt, int nodeoffset) 47*553125dfSNikos Nikoleris { 48*553125dfSNikos Nikoleris int val; 49*553125dfSNikos Nikoleris 50*553125dfSNikos Nikoleris val = fdt_cells(fdt, nodeoffset, "#size-cells"); 51*553125dfSNikos Nikoleris if (val == -FDT_ERR_NOTFOUND) 52*553125dfSNikos Nikoleris return 1; 53*553125dfSNikos Nikoleris return val; 54*553125dfSNikos Nikoleris } 55*553125dfSNikos Nikoleris 56*553125dfSNikos Nikoleris /* This function assumes that [address|size]_cells is 1 or 2 */ 57*553125dfSNikos Nikoleris int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, 58*553125dfSNikos Nikoleris const char *name, uint64_t addr, uint64_t size) 59*553125dfSNikos Nikoleris { 60*553125dfSNikos Nikoleris int addr_cells, size_cells, ret; 61*553125dfSNikos Nikoleris uint8_t data[sizeof(fdt64_t) * 2], *prop; 62*553125dfSNikos Nikoleris 63*553125dfSNikos Nikoleris ret = fdt_address_cells(fdt, parent); 64*553125dfSNikos Nikoleris if (ret < 0) 65*553125dfSNikos Nikoleris return ret; 66*553125dfSNikos Nikoleris addr_cells = ret; 67*553125dfSNikos Nikoleris 68*553125dfSNikos Nikoleris ret = fdt_size_cells(fdt, parent); 69*553125dfSNikos Nikoleris if (ret < 0) 70*553125dfSNikos Nikoleris return ret; 71*553125dfSNikos Nikoleris size_cells = ret; 72*553125dfSNikos Nikoleris 73*553125dfSNikos Nikoleris /* check validity of address */ 74*553125dfSNikos Nikoleris prop = data; 75*553125dfSNikos Nikoleris if (addr_cells == 1) { 76*553125dfSNikos Nikoleris if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size)) 77*553125dfSNikos Nikoleris return -FDT_ERR_BADVALUE; 78*553125dfSNikos Nikoleris 79*553125dfSNikos Nikoleris fdt32_st(prop, (uint32_t)addr); 80*553125dfSNikos Nikoleris } else if (addr_cells == 2) { 81*553125dfSNikos Nikoleris fdt64_st(prop, addr); 82*553125dfSNikos Nikoleris } else { 83*553125dfSNikos Nikoleris return -FDT_ERR_BADNCELLS; 84*553125dfSNikos Nikoleris } 85*553125dfSNikos Nikoleris 86*553125dfSNikos Nikoleris /* check validity of size */ 87*553125dfSNikos Nikoleris prop += addr_cells * sizeof(fdt32_t); 88*553125dfSNikos Nikoleris if (size_cells == 1) { 89*553125dfSNikos Nikoleris if (size > UINT32_MAX) 90*553125dfSNikos Nikoleris return -FDT_ERR_BADVALUE; 91*553125dfSNikos Nikoleris 92*553125dfSNikos Nikoleris fdt32_st(prop, (uint32_t)size); 93*553125dfSNikos Nikoleris } else if (size_cells == 2) { 94*553125dfSNikos Nikoleris fdt64_st(prop, size); 95*553125dfSNikos Nikoleris } else { 96*553125dfSNikos Nikoleris return -FDT_ERR_BADNCELLS; 97*553125dfSNikos Nikoleris } 98*553125dfSNikos Nikoleris 99*553125dfSNikos Nikoleris return fdt_appendprop(fdt, nodeoffset, name, data, 100*553125dfSNikos Nikoleris (addr_cells + size_cells) * sizeof(fdt32_t)); 101*553125dfSNikos Nikoleris } 102