From 179157f4e198ded6ca92841226b7b4317a180b9a Mon Sep 17 00:00:00 2001 From: wusongjie Date: Tue, 4 Jul 2023 13:41:03 +0800 Subject: Components/drivers: support DM device id management We add the device name and id set api in DM, now driver could set name like sprintf without know how many devices it is. The misc.h and byteorder.h add some macros to developers that they always use in drivers. Signed-off-by: GuEe-GUI --- components/drivers/core/SConscript | 2 +- components/drivers/core/dm.c | 160 +++++++++++++++++++++++++ components/drivers/include/drivers/byteorder.h | 58 +++++++++ components/drivers/include/drivers/core/rtdm.h | 50 ++++++++ components/drivers/include/drivers/misc.h | 86 +++++++++++++ components/drivers/include/rtdevice.h | 4 + 6 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 components/drivers/core/dm.c create mode 100644 components/drivers/include/drivers/byteorder.h create mode 100755 components/drivers/include/drivers/core/rtdm.h create mode 100644 components/drivers/include/drivers/misc.h diff --git a/components/drivers/core/SConscript b/components/drivers/core/SConscript index 4aac2b7166..717af9ae78 100644 --- a/components/drivers/core/SConscript +++ b/components/drivers/core/SConscript @@ -8,7 +8,7 @@ if GetDepend(['RT_USING_DEV_BUS']): src = src + ['bus.c'] if GetDepend(['RT_USING_DM']): - src = src + ['driver.c'] + src = src + ['dm.c', 'driver.c'] group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DEVICE'], CPPPATH = CPPPATH) diff --git a/components/drivers/core/dm.c b/components/drivers/core/dm.c new file mode 100644 index 0000000000..dfba2a0b24 --- /dev/null +++ b/components/drivers/core/dm.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-04-20 ErikChan the first version + */ + +#include + +#include + +#ifdef RT_USING_SMP +static int rti_secondary_cpu_start(void) +{ + return 0; +} +INIT_EXPORT(rti_secondary_cpu_start, "6.end"); + +static int rti_secondary_cpu_end(void) +{ + return 0; +} +INIT_EXPORT(rti_secondary_cpu_end, "7.end"); + +void rt_dm_secondary_cpu_init(void) +{ +#if RT_DEBUG_INIT + int result; + const struct rt_init_desc *desc; + + rt_kprintf("do secondary cpu initialization.\n"); + for (desc = &__rt_init_desc_rti_secondary_cpu_start; desc < &__rt_init_desc_rti_secondary_cpu_end; ++desc) + { + rt_kprintf("initialize %s", desc->fn_name); + result = desc->fn(); + rt_kprintf(":%d done\n", result); + } +#else + volatile const init_fn_t *fn_ptr; + + for (fn_ptr = &__rt_init_rti_secondary_cpu_start; fn_ptr < &__rt_init_rti_secondary_cpu_end; ++fn_ptr) + { + (*fn_ptr)(); + } +#endif /* RT_DEBUG_INIT */ +} +#endif /* RT_USING_SMP */ + +struct prefix_track +{ + rt_list_t list; + + int uid; + const char *prefix; +}; +static struct rt_spinlock _prefix_nodes_lock; +static rt_list_t _prefix_nodes = RT_LIST_OBJECT_INIT(_prefix_nodes); + +int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix) +{ + int uid = -1; + struct prefix_track *pt = RT_NULL; + + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(prefix != RT_NULL); + + RT_DEBUG_NOT_IN_INTERRUPT; + + rt_spin_lock(&_prefix_nodes_lock); + + rt_list_for_each_entry(pt, &_prefix_nodes, list) + { + /* caller always input constants string, check ptr is faster */ + if (pt->prefix == prefix || !rt_strcmp(pt->prefix, prefix)) + { + uid = ++pt->uid; + break; + } + } + + rt_spin_unlock(&_prefix_nodes_lock); + + if (uid < 0) + { + pt = rt_malloc(sizeof(*pt)); + + if (!pt) + { + return -RT_ENOMEM; + } + + rt_list_init(&pt->list); + + pt->uid = uid = 0; + pt->prefix = prefix; + + rt_spin_lock(&_prefix_nodes_lock); + + rt_list_insert_before(&_prefix_nodes, &pt->list); + + rt_spin_unlock(&_prefix_nodes_lock); + } + + return rt_dm_set_dev_name(dev, "%s%u", prefix, uid); +} + +int rt_dm_get_dev_name_id(rt_device_t dev) +{ + int id = 0, len; + const char *name; + + RT_ASSERT(dev != RT_NULL); + + name = rt_dm_get_dev_name(dev); + len = rt_strlen(name) - 1; + name += len; + + while (len --> 0) + { + if (*name < '0' || *name > '9') + { + while (*(++name)) + { + id *= 10; + id += *name - '0'; + } + + break; + } + + --name; + } + + return id; +} + +int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...) +{ + int n; + va_list arg_ptr; + + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(format != RT_NULL); + + va_start(arg_ptr, format); + n = rt_vsnprintf(dev->parent.name, RT_NAME_MAX, format, arg_ptr); + va_end(arg_ptr); + + return n; +} + +const char *rt_dm_get_dev_name(rt_device_t dev) +{ + RT_ASSERT(dev != RT_NULL); + + return dev->parent.name; +} diff --git a/components/drivers/include/drivers/byteorder.h b/components/drivers/include/drivers/byteorder.h new file mode 100644 index 0000000000..30decb5440 --- /dev/null +++ b/components/drivers/include/drivers/byteorder.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __BYTEORDER__ +#define __BYTEORDER__ + +#ifdef __CHECKER__ +#define __bitwise __attribute__((bitwise)) +#else +#define __bitwise +#endif + +typedef rt_uint16_t __bitwise rt_le16_t; +typedef rt_uint32_t __bitwise rt_le32_t; +typedef rt_uint64_t __bitwise rt_le64_t; +typedef rt_uint16_t __bitwise rt_be16_t; +typedef rt_uint32_t __bitwise rt_be32_t; +typedef rt_uint64_t __bitwise rt_be64_t; + +/* gcc defines __BIG_ENDIAN__ on big endian targets */ +#if defined(__BIG_ENDIAN__) || defined(ARCH_CPU_BIG_ENDIAN) +#define rt_cpu_to_be16(x) (x) +#define rt_cpu_to_be32(x) (x) +#define rt_cpu_to_be64(x) (x) +#define rt_be16_to_cpu(x) (x) +#define rt_be32_to_cpu(x) (x) +#define rt_be64_to_cpu(x) (x) +#define rt_le16_to_cpu(x) __builtin_bswap16(x) +#define rt_le32_to_cpu(x) __builtin_bswap32(x) +#define rt_le64_to_cpu(x) __builtin_bswap64(x) +#define rt_cpu_to_le16(x) __builtin_bswap16(x) +#define rt_cpu_to_le32(x) __builtin_bswap32(x) +#define rt_cpu_to_le64(x) __builtin_bswap64(x) +#else +#define rt_cpu_to_be16(x) __builtin_bswap16(x) +#define rt_cpu_to_be32(x) __builtin_bswap32(x) +#define rt_cpu_to_be64(x) __builtin_bswap64(x) +#define rt_be16_to_cpu(x) __builtin_bswap16(x) +#define rt_be32_to_cpu(x) __builtin_bswap32(x) +#define rt_be64_to_cpu(x) __builtin_bswap64(x) +#define rt_le16_to_cpu(x) (x) +#define rt_le32_to_cpu(x) (x) +#define rt_le64_to_cpu(x) (x) +#define rt_cpu_to_le16(x) (x) +#define rt_cpu_to_le32(x) (x) +#define rt_cpu_to_le64(x) (x) +#endif /* __BIG_ENDIAN__ || ARCH_CPU_BIG_ENDIAN */ + +#undef __bitwise + +#endif /* __BYTEORDER__ */ diff --git a/components/drivers/include/drivers/core/rtdm.h b/components/drivers/include/drivers/core/rtdm.h new file mode 100755 index 0000000000..95d3c259b8 --- /dev/null +++ b/components/drivers/include/drivers/core/rtdm.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-04-20 ErikChan the first version + */ + +#ifndef __RT_DM_H__ +#define __RT_DM_H__ + +#include +#include +#include +#include + +#ifndef RT_CPUS_NR +#define RT_CPUS_NR 1 +#endif + +#ifndef RT_USING_SMP +extern int rt_hw_cpu_id(void); +#endif + +void rt_dm_secondary_cpu_init(void); + +int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix); +int rt_dm_get_dev_name_id(rt_device_t dev); + +int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...); +const char *rt_dm_get_dev_name(rt_device_t dev); + +/* init cpu, memory, interrupt-controller, bus... */ +#define INIT_CORE_EXPORT(fn) INIT_EXPORT(fn, "1.0") +/* init pci/pcie, usb platform driver... */ +#define INIT_FRAMEWORK_EXPORT(fn) INIT_EXPORT(fn, "1.1") +/* init platform, user code... */ +#define INIT_PLATFORM_EXPORT(fn) INIT_EXPORT(fn, "1.2") +/* init sys-timer, clk, pinctrl... */ +#define INIT_SUBSYS_EXPORT(fn) INIT_EXPORT(fn, "1.3") +/* init early drivers */ +#define INIT_DRIVER_EARLY_EXPORT(fn) INIT_EXPORT(fn, "1.4") +/* init in secondary_cpu_c_start */ +#define INIT_SECONDARY_CPU_EXPORT(fn) INIT_EXPORT(fn, "7") +/* init after mount fs */ +#define INIT_FS_EXPORT(fn) INIT_EXPORT(fn, "6.0") + +#endif /* __RT_DM_H__ */ diff --git a/components/drivers/include/drivers/misc.h b/components/drivers/include/drivers/misc.h new file mode 100644 index 0000000000..aa2b715512 --- /dev/null +++ b/components/drivers/include/drivers/misc.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __MISC_H__ +#define __MISC_H__ + +#include + +#ifdef ARCH_CPU_64BIT +#define RT_BITS_PER_LONG 64 +#else +#define RT_BITS_PER_LONG 32 +#endif +#define RT_BITS_PER_LONG_LONG 64 + +#define RT_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +#define RT_DIV_ROUND_CLOSEST(x, divisor) \ +({ \ + typeof(x) __x = x; \ + typeof(divisor) __d = divisor; \ + (((typeof(x))-1) > 0 || \ + ((typeof(divisor))-1) > 0 || \ + (((__x) > 0) == ((__d) > 0))) ? \ + (((__x) + ((__d) / 2)) / (__d)) : \ + (((__x) - ((__d) / 2)) / (__d)); \ +}) + +#define RT_BIT(n) (1UL << (n)) +#define RT_BIT_ULL(n) (1ULL << (n)) +#define RT_BIT_MASK(nr) (1UL << ((nr) % RT_BITS_PER_LONG)) +#define RT_BIT_WORD(nr) ((nr) / RT_BITS_PER_LONG) + +#define RT_BITS_PER_BYTE 8 +#define RT_BITS_PER_TYPE(type) (sizeof(type) * RT_BITS_PER_BYTE) +#define RT_BITS_TO_BYTES(nr) RT_DIV_ROUND_UP(nr, RT_BITS_PER_TYPE(char)) +#define RT_BITS_TO_LONGS(nr) RT_DIV_ROUND_UP(nr, RT_BITS_PER_TYPE(long)) + +#define RT_GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (RT_BITS_PER_LONG - 1 - (h)))) +#define RT_GENMASK_ULL(h, l) (((~0ULL) << (l)) & (~0ULL >> (RT_BITS_PER_LONG_LONG - 1 - (h)))) + +#define RT_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +#define rt_min(x, y) \ +({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; \ +}) + +#define rt_max(x, y) \ +({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; \ +}) + +#define rt_min_t(type, x, y) \ +({ \ + type _x = (x); \ + type _y = (y); \ + _x < _y ? _x: _y; \ +}) + +#define rt_clamp(val, lo, hi) rt_min((typeof(val))rt_max(val, lo), hi) + +#define rt_do_div(n, base) \ +({ \ + rt_uint32_t _base = (base), _rem; \ + _rem = ((rt_uint64_t)(n)) % _base; \ + (n) = ((rt_uint64_t)(n)) / _base; \ + if (_rem > _base / 2) \ + ++(n); \ + _rem; \ +}) + +#endif /* __MISC_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index afce028b0e..60da08f8b1 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -169,6 +169,10 @@ extern "C" { #include "drivers/lcd.h" #endif +#ifdef RT_USING_DM +#include "drivers/core/rtdm.h" +#endif /* RT_USING_DM */ + #ifdef __cplusplus } #endif -- cgit v1.3.1 From 3b7e46de7eae5ed96e24cdfca0d5866a71cb6dd6 Mon Sep 17 00:00:00 2001 From: wusongjie Date: Wed, 5 Jul 2023 13:38:29 +0800 Subject: AArch64: support hardware atomic Support aarch64 rt_hw_atomic_* api. Add atomic implemente by rt_atomic api: rt_atomic_dec_and_test rt_atomic_fetch_add_unless rt_atomic_add_unless rt_atomic_inc_not_zero Signed-off-by: GuEe-GUI --- include/rtatomic.h | 31 ++++++++++ libcpu/aarch64/common/atomic_aarch64.c | 108 +++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 libcpu/aarch64/common/atomic_aarch64.c diff --git a/include/rtatomic.h b/include/rtatomic.h index d711a64a05..9f361fd925 100644 --- a/include/rtatomic.h +++ b/include/rtatomic.h @@ -11,6 +11,8 @@ #ifndef __RT_ATOMIC_H__ #define __RT_ATOMIC_H__ +#include + #if !defined(__cplusplus) rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr); @@ -206,6 +208,35 @@ rt_inline rt_atomic_t rt_soft_atomic_compare_exchange_strong(volatile rt_atomic_ } #endif /* RT_USING_STDC_ATOMIC */ +rt_inline rt_bool_t rt_atomic_dec_and_test(volatile rt_atomic_t *ptr) +{ + return rt_atomic_sub(ptr, 1) == 0; +} + +rt_inline rt_atomic_t rt_atomic_fetch_add_unless(volatile rt_atomic_t *ptr, rt_atomic_t a, rt_atomic_t u) +{ + rt_atomic_t c = rt_atomic_load(ptr); + + do { + if (c == u) + { + break; + } + } while (!rt_atomic_compare_exchange_strong(ptr, &c, c + a)); + + return c; +} + +rt_inline rt_bool_t rt_atomic_add_unless(volatile rt_atomic_t *ptr, rt_atomic_t a, rt_atomic_t u) +{ + return rt_atomic_fetch_add_unless(ptr, a, u) != u; +} + +rt_inline rt_bool_t rt_atomic_inc_not_zero(volatile rt_atomic_t *ptr) +{ + return rt_atomic_add_unless(ptr, 1, 0); +} + #endif /* __cplusplus */ #endif /* __RT_ATOMIC_H__ */ diff --git a/libcpu/aarch64/common/atomic_aarch64.c b/libcpu/aarch64/common/atomic_aarch64.c new file mode 100644 index 0000000000..c55cd8a84f --- /dev/null +++ b/libcpu/aarch64/common/atomic_aarch64.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-05-18 GuEe-GUI first version + */ + +#include + +rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr) +{ + rt_atomic_t ret; + + __asm__ volatile ( + " ldr %w0, %1\n" + " dmb ish" + : "=r" (ret) + : "Q" (*ptr) + : "memory"); + + return ret; +} + +void rt_hw_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val) +{ + __asm__ volatile ( + " stlr %w1, %0\n" + " dmb ish" + : "=Q" (*ptr) + : "r" (val) + : "memory"); +} + +#define AARCH64_ATOMIC_OP_RETURN(op, ins, constraint) \ +rt_atomic_t rt_hw_atomic_##op(volatile rt_atomic_t *ptr, rt_atomic_t in_val) \ +{ \ + rt_atomic_t tmp, val, result; \ + \ + __asm__ volatile ( \ + " prfm pstl1strm, %3\n" \ + "1: ldxr %w0, %3\n" \ + " "#ins " %w1, %w0, %w4\n" \ + " stlxr %w2, %w1, %3\n" \ + " cbnz %w2, 1b\n" \ + " dmb ish" \ + : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (*ptr) \ + : __RT_STRINGIFY(constraint) "r" (in_val) \ + : "memory"); \ + \ + return result; \ +} + +AARCH64_ATOMIC_OP_RETURN(add, add, I) +AARCH64_ATOMIC_OP_RETURN(sub, sub, J) +AARCH64_ATOMIC_OP_RETURN(and, and, K) +AARCH64_ATOMIC_OP_RETURN(or, orr, K) +AARCH64_ATOMIC_OP_RETURN(xor, eor, K) + +rt_atomic_t rt_hw_atomic_exchange(volatile rt_atomic_t *ptr, rt_atomic_t val) +{ + rt_atomic_t ret, tmp; + + __asm__ volatile ( + " prfm pstl1strm, %2\n" + "1: ldxr %w0, %2\n" + " stlxr %w1, %w3, %2\n" + " cbnz %w1, 1b\n" + " dmb ish" + : "=&r" (ret), "=&r" (tmp), "+Q" (*ptr) + : "r" (val) + : "memory"); + + return ret; +} + +void rt_hw_atomic_flag_clear(volatile rt_atomic_t *ptr) +{ + rt_hw_atomic_and(ptr, 0); +} + +rt_atomic_t rt_hw_atomic_flag_test_and_set(volatile rt_atomic_t *ptr) +{ + return rt_hw_atomic_or(ptr, 1); +} + +rt_atomic_t rt_hw_atomic_compare_exchange_strong(volatile rt_atomic_t *ptr, rt_atomic_t *old, rt_atomic_t new) +{ + rt_atomic_t tmp, oldval; + + __asm__ volatile ( + " prfm pstl1strm, %2\n" + "1: ldxr %w0, %2\n" + " eor %w1, %w0, %w3\n" + " cbnz %w1, 2f\n" + " stlxr %w1, %w4, %2\n" + " cbnz %w1, 1b\n" + " dmb ish\n" + "2:" + : "=&r" (oldval), "=&r" (tmp), "+Q" (*ptr) + : "Kr" (*old), "r" (new) + : "memory"); + + return oldval; +} + -- cgit v1.3.1 From 950d71e1accaee3e4aa76438601715395015943f Mon Sep 17 00:00:00 2001 From: wusongjie Date: Wed, 5 Jul 2023 13:39:51 +0800 Subject: Utilities/libadt: support adt API for DM Add reference with rt_atomic in resources' put/get management. Add bitmap operator base on rt_ubase_t. Add hashmap for key->data map management. Signed-off-by: GuEe-GUI --- components/utilities/libadt/Kconfig | 24 +++ components/utilities/libadt/SConscript | 15 +- components/utilities/libadt/avl.c | 242 ------------------------- components/utilities/libadt/avl.h | 116 ------------ components/utilities/libadt/avl/SConscript | 9 + components/utilities/libadt/avl/avl.c | 242 +++++++++++++++++++++++++ components/utilities/libadt/avl/avl.h | 116 ++++++++++++ components/utilities/libadt/bitmap/SConscript | 9 + components/utilities/libadt/bitmap/bitmap.h | 77 ++++++++ components/utilities/libadt/hashmap/SConscript | 9 + components/utilities/libadt/hashmap/hashmap.h | 41 +++++ components/utilities/libadt/ref/SConscript | 9 + components/utilities/libadt/ref/ref.h | 75 ++++++++ 13 files changed, 622 insertions(+), 362 deletions(-) create mode 100644 components/utilities/libadt/Kconfig delete mode 100644 components/utilities/libadt/avl.c delete mode 100644 components/utilities/libadt/avl.h create mode 100755 components/utilities/libadt/avl/SConscript create mode 100644 components/utilities/libadt/avl/avl.c create mode 100644 components/utilities/libadt/avl/avl.h create mode 100755 components/utilities/libadt/bitmap/SConscript create mode 100755 components/utilities/libadt/bitmap/bitmap.h create mode 100755 components/utilities/libadt/hashmap/SConscript create mode 100755 components/utilities/libadt/hashmap/hashmap.h create mode 100755 components/utilities/libadt/ref/SConscript create mode 100644 components/utilities/libadt/ref/ref.h diff --git a/components/utilities/libadt/Kconfig b/components/utilities/libadt/Kconfig new file mode 100644 index 0000000000..bb421cf8b0 --- /dev/null +++ b/components/utilities/libadt/Kconfig @@ -0,0 +1,24 @@ +menuconfig RT_USING_ADT + bool "Enable ADT(abstract data type)" + default y if ARCH_MM_MMU + default n + +config RT_USING_ADT_AVL + bool "AVL tree" + depends on RT_USING_ADT + default y + +config RT_USING_ADT_BITMAP + bool "Bitmap" + depends on RT_USING_ADT + default y + +config RT_USING_ADT_HASHMAP + bool "HashMap" + depends on RT_USING_ADT + default y + +config RT_USING_ADT_REF + bool "Reference API" + depends on RT_USING_ADT + default y diff --git a/components/utilities/libadt/SConscript b/components/utilities/libadt/SConscript index 86055d8ba2..22ea93cadf 100644 --- a/components/utilities/libadt/SConscript +++ b/components/utilities/libadt/SConscript @@ -1,8 +1,15 @@ from building import * cwd = GetCurrentDir() -src = Glob('*.c') -CPPPATH = [cwd] -group = DefineGroup('Utilities', src, depend = ['RT_USING_ADT'], CPPPATH = CPPPATH) +list = os.listdir(cwd) +objs = [] -Return('group') +if not GetDepend(['RT_USING_ADT']): + Return('objs') + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/components/utilities/libadt/avl.c b/components/utilities/libadt/avl.c deleted file mode 100644 index 0b474b1f9e..0000000000 --- a/components/utilities/libadt/avl.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2006-2022, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-10-12 Jesven first version - * 2022-11-14 WangXiaoyao Optimize footprint and performance - * Export as ADT for generic use case - */ -#include -#include - -#include "avl.h" - -#define HEIGHT_OF(node) ((node) ? (node)->height : 0) -#define IS_RCHILD(node) (!((node) - ((node)->parent->avl_right))) -#define IS_LCHILD(node) (!((node) - ((node)->parent->avl_left))) -#define NODE_PLACE(node) \ - IS_LCHILD(node) ? &(node)->parent->avl_left : &(node)->parent->avl_right - -static inline void rotate_right(struct util_avl_struct *axis, - struct util_avl_struct *lchild, - struct util_avl_struct *lrchild, - struct util_avl_struct **nodeplace, - size_t lrheight) -{ - axis->avl_left = lrchild; - lchild->avl_right = axis; - - axis->height = lrheight + 1; - lchild->height = axis->height + 1; - - lchild->parent = axis->parent; - axis->parent = lchild; - - *nodeplace = lchild; - if (lrchild != NULL) - lrchild->parent = axis; -} - -static inline void midmount_right(struct util_avl_struct *axis, - struct util_avl_struct *lchild, - struct util_avl_struct *lrchild, - struct util_avl_struct **nodeplace, - size_t lrheight) -{ - lchild->avl_right = lrchild->avl_left; - axis->avl_left = lrchild->avl_right; - lrchild->avl_left = lchild; - lrchild->avl_right = axis; - - lrchild->height = lchild->height; - lchild->height = lrheight; - axis->height = lrheight; - - lrchild->parent = axis->parent; - lchild->parent = lrchild; - axis->parent = lrchild; - if (lchild->avl_right != NULL) - lchild->avl_right->parent = lchild; - if (axis->avl_left != NULL) - axis->avl_left->parent = axis; - *nodeplace = lrchild; -} - -static inline void rotate_left(struct util_avl_struct *axis, - struct util_avl_struct *rchild, - struct util_avl_struct *rlchild, - struct util_avl_struct **nodeplace, - size_t rlheight) -{ - axis->avl_right = rlchild; - rchild->avl_left = axis; - - axis->height = rlheight + 1; - rchild->height = axis->height + 1; - - rchild->parent = axis->parent; - axis->parent = rchild; - - *nodeplace = rchild; - if (rlchild != NULL) - rlchild->parent = axis; -} - -static inline void midmount_left(struct util_avl_struct *axis, - struct util_avl_struct *rchild, - struct util_avl_struct *rlchild, - struct util_avl_struct **nodeplace, - size_t rlheight) -{ - rchild->avl_left = rlchild->avl_right; - axis->avl_right = rlchild->avl_left; - rlchild->avl_right = rchild; - rlchild->avl_left = axis; - - rlchild->height = rchild->height; - rchild->height = rlheight; - axis->height = rlheight; - - rlchild->parent = axis->parent; - rchild->parent = rlchild; - axis->parent = rlchild; - if (rchild->avl_left != NULL) - rchild->avl_left->parent = rchild; - if (axis->avl_right != NULL) - axis->avl_right->parent = axis; - - *nodeplace = rlchild; -} - -/** - * @brief avl insertion & delete conceptually contain 2 stage - * 1. insertion/delete of reference - * 2. rebalance - */ - -void util_avl_rebalance(struct util_avl_struct *node, - struct util_avl_root *root) -{ - if (!node) - return; - - struct util_avl_struct *axis = node; - struct util_avl_struct **nodeplace; - do - { - struct util_avl_struct *lchild = axis->avl_left; - struct util_avl_struct *rchild = axis->avl_right; - nodeplace = axis->parent ? NODE_PLACE(axis) : &root->root_node; - int lheight = HEIGHT_OF(lchild); - int rheight = HEIGHT_OF(rchild); - if (rheight + 1 < lheight) - { - struct util_avl_struct *lrchild = lchild->avl_right; - size_t lrheight = HEIGHT_OF(lrchild); - if (HEIGHT_OF(lchild->avl_left) >= lrheight) - { - rotate_right(axis, lchild, lrchild, nodeplace, lrheight); - axis = lchild->parent; - } - else - { - midmount_right(axis, lchild, lrchild, nodeplace, lrheight); - axis = lrchild->parent; - } - } - else if (lheight + 1 < rheight) - { - struct util_avl_struct *rlchild = rchild->avl_left; - size_t rlheight = HEIGHT_OF(rlchild); - if (HEIGHT_OF(rchild->avl_right) >= rlheight) - { - rotate_left(axis, rchild, rlchild, nodeplace, rlheight); - axis = rchild->parent; - } - else - { - midmount_left(axis, rchild, rlchild, nodeplace, rlheight); - axis = rlchild->parent; - } - } - else - { - int height = (lheight < rheight ? rheight : lheight) + 1; - if (height == axis->height) - break; - axis->height = height; - axis = axis->parent; - } - } while (axis); -} - -void util_avl_remove(struct util_avl_struct *node, struct util_avl_root *root) -{ - struct util_avl_struct **nodeplace; - - if (root->root_node == NULL) - return; - - if (node->parent != NULL) - { - nodeplace = NODE_PLACE(node); - } - else - { - nodeplace = &root->root_node; - } - - /* deletion */ - if (node->avl_right == NULL) - { - *nodeplace = node->avl_left; - if (node->avl_left != NULL) - node->avl_left->parent = node->parent; - node = node->parent; - } - else - { - struct util_avl_struct *rchild = node->avl_right; - if (rchild->avl_left == NULL) - { - *nodeplace = rchild; - rchild->avl_left = node->avl_left; - if (rchild->avl_left != NULL) - rchild->avl_left->parent = rchild; - rchild->parent = node->parent; - util_avl_rebalance(rchild, root); - node = rchild->parent; - } - else - { - struct util_avl_struct *successor = rchild->avl_left; - struct util_avl_struct *sparent = rchild; - while (successor->avl_left != NULL) - { - sparent = successor; - successor = successor->avl_left; - } - *nodeplace = successor; - sparent->avl_left = successor->avl_right; - successor->avl_left = node->avl_left; - successor->avl_right = node->avl_right; - - if (successor->avl_left != NULL) - successor->avl_left->parent = successor; - successor->avl_right->parent = successor; - - if (sparent->avl_left != NULL) - sparent->avl_left->parent = sparent; - successor->parent = node->parent; - util_avl_rebalance(sparent, root); - node = successor; - } - } - - /* rebalance */ - util_avl_rebalance(node, root); - return; -} diff --git a/components/utilities/libadt/avl.h b/components/utilities/libadt/avl.h deleted file mode 100644 index e0d4811dfd..0000000000 --- a/components/utilities/libadt/avl.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-10-12 Jesven first version - * 2022-11-14 WangXiaoyao Optimize for generic use case - * and performance - */ -#ifndef __UTIL_TREE_AVL_H__ -#define __UTIL_TREE_AVL_H__ - -#include -#include - -struct util_avl_struct -{ - struct util_avl_struct *avl_left; - struct util_avl_struct *avl_right; - struct util_avl_struct *parent; - size_t height; -}; - -#define AVL_ROOT ((struct util_avl_struct *)0) - -struct util_avl_root -{ - struct util_avl_struct *root_node; -}; - -void util_avl_rebalance(struct util_avl_struct *node, - struct util_avl_root *root); - -void util_avl_remove(struct util_avl_struct *node, struct util_avl_root *root); - -static inline void util_avl_link(struct util_avl_struct *new_node, - struct util_avl_struct *parent, - struct util_avl_struct **nodeplace) -{ - new_node->avl_left = AVL_ROOT; - new_node->avl_right = AVL_ROOT; - new_node->parent = parent; - new_node->height = 1; - *nodeplace = new_node; -} - -static inline struct util_avl_struct *util_avl_next( - struct util_avl_struct *node) -{ - struct util_avl_struct *successor = 0; - if (node) - { - if (node->avl_right) - { - node = node->avl_right; - while (node->avl_left) - node = node->avl_left; - successor = node; - } - else - { - while ((successor = node->parent) && (node == successor->avl_right)) - node = successor; - } - } - return successor; -} - -static inline struct util_avl_struct *util_avl_prev( - struct util_avl_struct *node) -{ - struct util_avl_struct *predecessor = 0; - if (node) - { - if (node->avl_left) - { - node = node->avl_left; - while (node->avl_right) - node = node->avl_right; - predecessor = node; - } - else - { - while ((predecessor = node->parent) && - (node == predecessor->avl_left)) - node = predecessor; - } - } - return predecessor; -} - -static inline struct util_avl_struct *util_avl_first(struct util_avl_root *root) -{ - struct util_avl_struct *first = root->root_node; - if (first) - { - while (first->avl_left) - first = first->avl_left; - } - return first; -} - -static inline struct util_avl_struct *util_avl_last(struct util_avl_root *root) -{ - struct util_avl_struct *last = root->root_node; - if (last) - { - while (last->avl_right) - last = last->avl_right; - } - return last; -} - -#endif /* __UTIL_TREE_AVL_H__ */ diff --git a/components/utilities/libadt/avl/SConscript b/components/utilities/libadt/avl/SConscript new file mode 100755 index 0000000000..8fabef3de3 --- /dev/null +++ b/components/utilities/libadt/avl/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] +group = [] + +group = DefineGroup('LIBADT', src, depend = ['RT_USING_ADT_AVL'], CPPPATH = CPPPATH) +Return('group') diff --git a/components/utilities/libadt/avl/avl.c b/components/utilities/libadt/avl/avl.c new file mode 100644 index 0000000000..0b474b1f9e --- /dev/null +++ b/components/utilities/libadt/avl/avl.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-10-12 Jesven first version + * 2022-11-14 WangXiaoyao Optimize footprint and performance + * Export as ADT for generic use case + */ +#include +#include + +#include "avl.h" + +#define HEIGHT_OF(node) ((node) ? (node)->height : 0) +#define IS_RCHILD(node) (!((node) - ((node)->parent->avl_right))) +#define IS_LCHILD(node) (!((node) - ((node)->parent->avl_left))) +#define NODE_PLACE(node) \ + IS_LCHILD(node) ? &(node)->parent->avl_left : &(node)->parent->avl_right + +static inline void rotate_right(struct util_avl_struct *axis, + struct util_avl_struct *lchild, + struct util_avl_struct *lrchild, + struct util_avl_struct **nodeplace, + size_t lrheight) +{ + axis->avl_left = lrchild; + lchild->avl_right = axis; + + axis->height = lrheight + 1; + lchild->height = axis->height + 1; + + lchild->parent = axis->parent; + axis->parent = lchild; + + *nodeplace = lchild; + if (lrchild != NULL) + lrchild->parent = axis; +} + +static inline void midmount_right(struct util_avl_struct *axis, + struct util_avl_struct *lchild, + struct util_avl_struct *lrchild, + struct util_avl_struct **nodeplace, + size_t lrheight) +{ + lchild->avl_right = lrchild->avl_left; + axis->avl_left = lrchild->avl_right; + lrchild->avl_left = lchild; + lrchild->avl_right = axis; + + lrchild->height = lchild->height; + lchild->height = lrheight; + axis->height = lrheight; + + lrchild->parent = axis->parent; + lchild->parent = lrchild; + axis->parent = lrchild; + if (lchild->avl_right != NULL) + lchild->avl_right->parent = lchild; + if (axis->avl_left != NULL) + axis->avl_left->parent = axis; + *nodeplace = lrchild; +} + +static inline void rotate_left(struct util_avl_struct *axis, + struct util_avl_struct *rchild, + struct util_avl_struct *rlchild, + struct util_avl_struct **nodeplace, + size_t rlheight) +{ + axis->avl_right = rlchild; + rchild->avl_left = axis; + + axis->height = rlheight + 1; + rchild->height = axis->height + 1; + + rchild->parent = axis->parent; + axis->parent = rchild; + + *nodeplace = rchild; + if (rlchild != NULL) + rlchild->parent = axis; +} + +static inline void midmount_left(struct util_avl_struct *axis, + struct util_avl_struct *rchild, + struct util_avl_struct *rlchild, + struct util_avl_struct **nodeplace, + size_t rlheight) +{ + rchild->avl_left = rlchild->avl_right; + axis->avl_right = rlchild->avl_left; + rlchild->avl_right = rchild; + rlchild->avl_left = axis; + + rlchild->height = rchild->height; + rchild->height = rlheight; + axis->height = rlheight; + + rlchild->parent = axis->parent; + rchild->parent = rlchild; + axis->parent = rlchild; + if (rchild->avl_left != NULL) + rchild->avl_left->parent = rchild; + if (axis->avl_right != NULL) + axis->avl_right->parent = axis; + + *nodeplace = rlchild; +} + +/** + * @brief avl insertion & delete conceptually contain 2 stage + * 1. insertion/delete of reference + * 2. rebalance + */ + +void util_avl_rebalance(struct util_avl_struct *node, + struct util_avl_root *root) +{ + if (!node) + return; + + struct util_avl_struct *axis = node; + struct util_avl_struct **nodeplace; + do + { + struct util_avl_struct *lchild = axis->avl_left; + struct util_avl_struct *rchild = axis->avl_right; + nodeplace = axis->parent ? NODE_PLACE(axis) : &root->root_node; + int lheight = HEIGHT_OF(lchild); + int rheight = HEIGHT_OF(rchild); + if (rheight + 1 < lheight) + { + struct util_avl_struct *lrchild = lchild->avl_right; + size_t lrheight = HEIGHT_OF(lrchild); + if (HEIGHT_OF(lchild->avl_left) >= lrheight) + { + rotate_right(axis, lchild, lrchild, nodeplace, lrheight); + axis = lchild->parent; + } + else + { + midmount_right(axis, lchild, lrchild, nodeplace, lrheight); + axis = lrchild->parent; + } + } + else if (lheight + 1 < rheight) + { + struct util_avl_struct *rlchild = rchild->avl_left; + size_t rlheight = HEIGHT_OF(rlchild); + if (HEIGHT_OF(rchild->avl_right) >= rlheight) + { + rotate_left(axis, rchild, rlchild, nodeplace, rlheight); + axis = rchild->parent; + } + else + { + midmount_left(axis, rchild, rlchild, nodeplace, rlheight); + axis = rlchild->parent; + } + } + else + { + int height = (lheight < rheight ? rheight : lheight) + 1; + if (height == axis->height) + break; + axis->height = height; + axis = axis->parent; + } + } while (axis); +} + +void util_avl_remove(struct util_avl_struct *node, struct util_avl_root *root) +{ + struct util_avl_struct **nodeplace; + + if (root->root_node == NULL) + return; + + if (node->parent != NULL) + { + nodeplace = NODE_PLACE(node); + } + else + { + nodeplace = &root->root_node; + } + + /* deletion */ + if (node->avl_right == NULL) + { + *nodeplace = node->avl_left; + if (node->avl_left != NULL) + node->avl_left->parent = node->parent; + node = node->parent; + } + else + { + struct util_avl_struct *rchild = node->avl_right; + if (rchild->avl_left == NULL) + { + *nodeplace = rchild; + rchild->avl_left = node->avl_left; + if (rchild->avl_left != NULL) + rchild->avl_left->parent = rchild; + rchild->parent = node->parent; + util_avl_rebalance(rchild, root); + node = rchild->parent; + } + else + { + struct util_avl_struct *successor = rchild->avl_left; + struct util_avl_struct *sparent = rchild; + while (successor->avl_left != NULL) + { + sparent = successor; + successor = successor->avl_left; + } + *nodeplace = successor; + sparent->avl_left = successor->avl_right; + successor->avl_left = node->avl_left; + successor->avl_right = node->avl_right; + + if (successor->avl_left != NULL) + successor->avl_left->parent = successor; + successor->avl_right->parent = successor; + + if (sparent->avl_left != NULL) + sparent->avl_left->parent = sparent; + successor->parent = node->parent; + util_avl_rebalance(sparent, root); + node = successor; + } + } + + /* rebalance */ + util_avl_rebalance(node, root); + return; +} diff --git a/components/utilities/libadt/avl/avl.h b/components/utilities/libadt/avl/avl.h new file mode 100644 index 0000000000..e0d4811dfd --- /dev/null +++ b/components/utilities/libadt/avl/avl.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-10-12 Jesven first version + * 2022-11-14 WangXiaoyao Optimize for generic use case + * and performance + */ +#ifndef __UTIL_TREE_AVL_H__ +#define __UTIL_TREE_AVL_H__ + +#include +#include + +struct util_avl_struct +{ + struct util_avl_struct *avl_left; + struct util_avl_struct *avl_right; + struct util_avl_struct *parent; + size_t height; +}; + +#define AVL_ROOT ((struct util_avl_struct *)0) + +struct util_avl_root +{ + struct util_avl_struct *root_node; +}; + +void util_avl_rebalance(struct util_avl_struct *node, + struct util_avl_root *root); + +void util_avl_remove(struct util_avl_struct *node, struct util_avl_root *root); + +static inline void util_avl_link(struct util_avl_struct *new_node, + struct util_avl_struct *parent, + struct util_avl_struct **nodeplace) +{ + new_node->avl_left = AVL_ROOT; + new_node->avl_right = AVL_ROOT; + new_node->parent = parent; + new_node->height = 1; + *nodeplace = new_node; +} + +static inline struct util_avl_struct *util_avl_next( + struct util_avl_struct *node) +{ + struct util_avl_struct *successor = 0; + if (node) + { + if (node->avl_right) + { + node = node->avl_right; + while (node->avl_left) + node = node->avl_left; + successor = node; + } + else + { + while ((successor = node->parent) && (node == successor->avl_right)) + node = successor; + } + } + return successor; +} + +static inline struct util_avl_struct *util_avl_prev( + struct util_avl_struct *node) +{ + struct util_avl_struct *predecessor = 0; + if (node) + { + if (node->avl_left) + { + node = node->avl_left; + while (node->avl_right) + node = node->avl_right; + predecessor = node; + } + else + { + while ((predecessor = node->parent) && + (node == predecessor->avl_left)) + node = predecessor; + } + } + return predecessor; +} + +static inline struct util_avl_struct *util_avl_first(struct util_avl_root *root) +{ + struct util_avl_struct *first = root->root_node; + if (first) + { + while (first->avl_left) + first = first->avl_left; + } + return first; +} + +static inline struct util_avl_struct *util_avl_last(struct util_avl_root *root) +{ + struct util_avl_struct *last = root->root_node; + if (last) + { + while (last->avl_right) + last = last->avl_right; + } + return last; +} + +#endif /* __UTIL_TREE_AVL_H__ */ diff --git a/components/utilities/libadt/bitmap/SConscript b/components/utilities/libadt/bitmap/SConscript new file mode 100755 index 0000000000..739ff3b090 --- /dev/null +++ b/components/utilities/libadt/bitmap/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = list() +CPPPATH = [cwd] +group = [] + +group = DefineGroup('LIBADT', src, depend = ['RT_USING_ADT_BITMAP'], CPPPATH = CPPPATH) +Return('group') diff --git a/components/utilities/libadt/bitmap/bitmap.h b/components/utilities/libadt/bitmap/bitmap.h new file mode 100755 index 0000000000..72fe54333a --- /dev/null +++ b/components/utilities/libadt/bitmap/bitmap.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-6-27 GuEe-GUI first version + */ + +#ifndef __UTIL_BITMAP_H__ +#define __UTIL_BITMAP_H__ + +#include + +typedef rt_ubase_t rt_bitmap_t; + +#define RT_BITMAP_BITS_MIN (sizeof(rt_bitmap_t) * 8) +#define RT_BITMAP_LEN(bits) (((bits) + (RT_BITMAP_BITS_MIN) - 1) / (RT_BITMAP_BITS_MIN)) +#define RT_BITMAP_BIT_LEN(nr) (nr * RT_BITMAP_BITS_MIN) +#define RT_DECLARE_BITMAP(name, bits) rt_bitmap_t name[RT_BITMAP_LEN(bits)] + +rt_inline void rt_bitmap_set_bit(rt_bitmap_t *bitmap, rt_uint32_t bit) +{ + bitmap[bit / RT_BITMAP_BITS_MIN] |= (1UL << (bit & (RT_BITMAP_BITS_MIN - 1))); +} + +rt_inline rt_bool_t rt_bitmap_test_bit(rt_bitmap_t *bitmap, rt_uint32_t bit) +{ + return !!(bitmap[bit / RT_BITMAP_BITS_MIN] & (1UL << (bit & (RT_BITMAP_BITS_MIN - 1)))); +} + +rt_inline void rt_bitmap_clear_bit(rt_bitmap_t *bitmap, rt_uint32_t bit) +{ + bitmap[bit / RT_BITMAP_BITS_MIN] &= ~(1UL << (bit & (RT_BITMAP_BITS_MIN - 1))); +} + +rt_inline rt_size_t rt_bitmap_next_set_bit(rt_bitmap_t *bitmap, rt_size_t start, rt_size_t limit) +{ + rt_size_t bit; + + for (bit = start; bit < limit && !rt_bitmap_test_bit(bitmap, bit); ++bit) + { + } + + return bit; +} + +rt_inline rt_size_t rt_bitmap_next_clear_bit(rt_bitmap_t *bitmap, rt_size_t start, rt_size_t limit) +{ + rt_size_t bit; + + for (bit = start; bit < limit && rt_bitmap_test_bit(bitmap, bit); ++bit) + { + } + + return bit; +} + +#define rt_bitmap_for_each_bit_from(state, bitmap, from, bit, limit) \ + for ((bit) = rt_bitmap_next_##state##_bit((bitmap), (from), (limit)); \ + (bit) < (limit); \ + (bit) = rt_bitmap_next_##state##_bit((bitmap), (bit + 1), (limit))) + +#define rt_bitmap_for_each_set_bit_from(bitmap, from, bit, limit) \ + rt_bitmap_for_each_bit_from(set, bitmap, from, bit, limit) + +#define rt_bitmap_for_each_set_bit(bitmap, bit, limit) \ + rt_bitmap_for_each_set_bit_from(bitmap, 0, bit, limit) + +#define rt_bitmap_for_each_clear_bit_from(bitmap, from, bit, limit) \ + rt_bitmap_for_each_bit_from(clear, bitmap, from, bit, limit) + +#define rt_bitmap_for_each_clear_bit(bitmap, bit, limit) \ + rt_bitmap_for_each_clear_bit_from(bitmap, 0, bit, limit) + +#endif /* __UTIL_BITMAP_H__ */ diff --git a/components/utilities/libadt/hashmap/SConscript b/components/utilities/libadt/hashmap/SConscript new file mode 100755 index 0000000000..21e4764945 --- /dev/null +++ b/components/utilities/libadt/hashmap/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = list() +CPPPATH = [cwd] +group = [] + +group = DefineGroup('LIBADT', src, depend = ['RT_USING_ADT_HASHMAP'], CPPPATH = CPPPATH) +Return('group') diff --git a/components/utilities/libadt/hashmap/hashmap.h b/components/utilities/libadt/hashmap/hashmap.h new file mode 100755 index 0000000000..03e41b2345 --- /dev/null +++ b/components/utilities/libadt/hashmap/hashmap.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-01 GuEe-GUI first version + */ + +#ifndef __UTIL_HASHMAP_H__ +#define __UTIL_HASHMAP_H__ + +#include + +/* + * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf + * + * GoldenRatio = ~(Math.pow(2, 32) / ((Math.sqrt(5) - 1) / 2)) + 1 + */ +#define RT_HASHMAP_GOLDEN_RATIO_32 0x61C88647 +#define RT_HASHMAP_GOLDEN_RATIO_64 0X61C8864680B583EBULL + +rt_inline rt_uint32_t rt_hashmap_32(rt_uint32_t val, rt_uint32_t bits) +{ + /* High bits are more random, so use them. */ + return (val * RT_HASHMAP_GOLDEN_RATIO_32) >> (32 - bits); +} + +rt_inline rt_uint32_t rt_hashmap_64(rt_uint64_t val, rt_uint32_t bits) +{ +#ifdef ARCH_CPU_64BIT + /* 64x64-bit multiply is efficient on all 64-bit processors */ + return val * RT_HASHMAP_GOLDEN_RATIO_64 >> (64 - bits); +#else + /* Hash 64 bits using only 32x32-bit multiply. */ + return rt_hashmap_32((rt_uint32_t)val ^ ((val >> 32) * RT_HASHMAP_GOLDEN_RATIO_32), bits); +#endif +} + +#endif /* __UTIL_HASHMAP_H__ */ diff --git a/components/utilities/libadt/ref/SConscript b/components/utilities/libadt/ref/SConscript new file mode 100755 index 0000000000..faec462207 --- /dev/null +++ b/components/utilities/libadt/ref/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = list() +CPPPATH = [cwd] +group = [] + +group = DefineGroup('LIBADT', src, depend = ['RT_USING_ADT_REF'], CPPPATH = CPPPATH) +Return('group') diff --git a/components/utilities/libadt/ref/ref.h b/components/utilities/libadt/ref/ref.h new file mode 100644 index 0000000000..da700e4a1c --- /dev/null +++ b/components/utilities/libadt/ref/ref.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-1 zhouxiaohu first version + * 2023-5-18 GuEe-GUI implemented by rtatomic + */ + +#ifndef __UTIL_REF_H__ +#define __UTIL_REF_H__ + +#include + +/** + * struct ref must be embedded in an object. + * it acts as a reference counter for the object. + */ +struct rt_ref +{ + rt_atomic_t refcount; +}; + +#define RT_REF_INIT(n) { .refcount = n, } + +rt_inline void rt_ref_init(struct rt_ref *r) +{ + rt_atomic_store(&r->refcount, 1); +} + +rt_inline unsigned int rt_ref_read(struct rt_ref *r) +{ + return rt_atomic_load(&r->refcount); +} + +/** + * ref_get + * increment reference counter for object. + */ +rt_inline void rt_ref_get(struct rt_ref *r) +{ + rt_atomic_add(&r->refcount, 1); +} + +/** + * ref_put + * decrement reference counter for object. + * If the reference counter is zero, call release(). + * + * Return 1 means the object's reference counter is zero and release() is called. + */ +rt_inline int rt_ref_put(struct rt_ref *r, void (*release)(struct rt_ref *r)) +{ + if (rt_atomic_dec_and_test(&r->refcount)) + { + release(r); + + return 1; + } + + return 0; +} + +/** + * ref_get_unless_zero - Increment refcount for object unless it is zero. + * Return non-zero if the increment succeeded. Otherwise return 0. + */ +rt_inline int rt_ref_get_unless_zero(struct rt_ref *r) +{ + return (int)rt_atomic_inc_not_zero(&r->refcount); +} + +#endif /* __UTIL_REF_H__ */ -- cgit v1.3.1 From 8aa4366cb2910c2c61729608d9f2a90868d16deb Mon Sep 17 00:00:00 2001 From: wusongjie Date: Wed, 5 Jul 2023 13:50:18 +0800 Subject: Drivers: Support Open Firmware API and model of PIC We support OFW API to replace fdt old API, and add IRQ, IO, Platform-Bus, CPUs ... OFW node contorl. To support work with Device Tree or ACPI in drivers that use IRQ, we make a programmable interrupt controller driver's model. Signed-off-by: GuEe-GUI --- bsp/allwinner/d1/.config | 1 + bsp/allwinner/d1/rtconfig.h | 1 + bsp/allwinner/d1s/.config | 1 + bsp/allwinner/d1s/rtconfig.h | 1 + bsp/bouffalo_lab/bl808/d0/.config | 1 + bsp/bouffalo_lab/bl808/d0/rtconfig.h | 1 + bsp/cv1800b/.config | 1 + bsp/cv1800b/rtconfig.h | 1 + bsp/ft2004/.config | 1 + bsp/ft2004/rtconfig.h | 1 + bsp/imx/imx6ull-smart/.config | 1 + bsp/imx/imx6ull-smart/rtconfig.h | 1 + bsp/imx6ul/.config | 1 + bsp/imx6ul/rtconfig.h | 1 + bsp/nuvoton/nk-980iot/.config | 1 + bsp/nuvoton/nk-n9h30/.config | 1 + bsp/nuvoton/nk-rtu980/.config | 1 + bsp/nuvoton/numaker-hmi-ma35d1/.config | 1 + bsp/nuvoton/numaker-iot-ma35d1/.config | 1 + bsp/phytium/aarch32/.config | 1 + bsp/phytium/aarch32/rtconfig.h | 1 + bsp/phytium/aarch64/.config | 1 + bsp/phytium/aarch64/rtconfig.h | 1 + bsp/qemu-vexpress-a9/.config | 1 + bsp/qemu-vexpress-a9/rtconfig.h | 1 + bsp/qemu-virt64-aarch64/.config | 1 + bsp/qemu-virt64-aarch64/rtconfig.h | 1 + bsp/qemu-virt64-riscv/.config | 1 + bsp/qemu-virt64-riscv/rtconfig.h | 1 + bsp/raspberry-pi/raspi2/.config | 1 + bsp/raspberry-pi/raspi2/rtconfig.h | 1 + bsp/raspberry-pi/raspi3-32/.config | 1 + bsp/raspberry-pi/raspi3-32/rtconfig.h | 1 + bsp/raspberry-pi/raspi3-64/.config | 1 + bsp/raspberry-pi/raspi3-64/rtconfig.h | 1 + bsp/raspberry-pi/raspi4-32/.config | 1 + bsp/raspberry-pi/raspi4-32/rtconfig.h | 1 + bsp/raspberry-pi/raspi4-64/.config | 1 + bsp/raspberry-pi/raspi4-64/rtconfig.h | 1 + bsp/rockchip/rk3568/.config | 1 + bsp/rockchip/rk3568/rtconfig.h | 1 + components/drivers/Kconfig | 3 + components/drivers/include/drivers/ofw.h | 433 +++++ components/drivers/include/drivers/ofw_fdt.h | 78 + components/drivers/include/drivers/ofw_io.h | 32 + components/drivers/include/drivers/ofw_irq.h | 28 + components/drivers/include/drivers/ofw_raw.h | 66 + components/drivers/include/drivers/pic.h | 167 ++ components/drivers/include/rtdevice.h | 12 + components/drivers/ofw/Kconfig | 22 + components/drivers/ofw/SConscript | 22 + components/drivers/ofw/base.c | 1511 ++++++++++++++++ components/drivers/ofw/fdt.c | 1108 ++++++++++++ components/drivers/ofw/io.c | 421 +++++ components/drivers/ofw/irq.c | 648 +++++++ components/drivers/ofw/libfdt/SConscript | 10 + components/drivers/ofw/libfdt/fdt.c | 339 ++++ components/drivers/ofw/libfdt/fdt.h | 66 + components/drivers/ofw/libfdt/fdt_addresses.c | 101 ++ components/drivers/ofw/libfdt/fdt_empty_tree.c | 38 + components/drivers/ofw/libfdt/fdt_overlay.c | 867 +++++++++ components/drivers/ofw/libfdt/fdt_ro.c | 859 +++++++++ components/drivers/ofw/libfdt/fdt_rw.c | 500 ++++++ components/drivers/ofw/libfdt/fdt_strerror.c | 60 + components/drivers/ofw/libfdt/fdt_sw.c | 384 ++++ components/drivers/ofw/libfdt/fdt_wip.c | 94 + components/drivers/ofw/libfdt/libfdt.h | 2154 +++++++++++++++++++++++ components/drivers/ofw/libfdt/libfdt_env.h | 100 ++ components/drivers/ofw/libfdt/libfdt_internal.h | 192 ++ components/drivers/ofw/ofw.c | 573 ++++++ components/drivers/ofw/ofw_internal.h | 74 + components/drivers/ofw/raw.c | 197 +++ components/drivers/pic/Kconfig | 11 + components/drivers/pic/SConscript | 15 + components/drivers/pic/pic.c | 977 ++++++++++ components/utilities/Kconfig | 6 +- 76 files changed, 12204 insertions(+), 5 deletions(-) create mode 100644 components/drivers/include/drivers/ofw.h create mode 100755 components/drivers/include/drivers/ofw_fdt.h create mode 100755 components/drivers/include/drivers/ofw_io.h create mode 100755 components/drivers/include/drivers/ofw_irq.h create mode 100755 components/drivers/include/drivers/ofw_raw.h create mode 100755 components/drivers/include/drivers/pic.h create mode 100755 components/drivers/ofw/Kconfig create mode 100644 components/drivers/ofw/SConscript create mode 100644 components/drivers/ofw/base.c create mode 100755 components/drivers/ofw/fdt.c create mode 100755 components/drivers/ofw/io.c create mode 100755 components/drivers/ofw/irq.c create mode 100644 components/drivers/ofw/libfdt/SConscript create mode 100644 components/drivers/ofw/libfdt/fdt.c create mode 100644 components/drivers/ofw/libfdt/fdt.h create mode 100644 components/drivers/ofw/libfdt/fdt_addresses.c create mode 100644 components/drivers/ofw/libfdt/fdt_empty_tree.c create mode 100644 components/drivers/ofw/libfdt/fdt_overlay.c create mode 100644 components/drivers/ofw/libfdt/fdt_ro.c create mode 100644 components/drivers/ofw/libfdt/fdt_rw.c create mode 100644 components/drivers/ofw/libfdt/fdt_strerror.c create mode 100644 components/drivers/ofw/libfdt/fdt_sw.c create mode 100644 components/drivers/ofw/libfdt/fdt_wip.c create mode 100644 components/drivers/ofw/libfdt/libfdt.h create mode 100644 components/drivers/ofw/libfdt/libfdt_env.h create mode 100644 components/drivers/ofw/libfdt/libfdt_internal.h create mode 100755 components/drivers/ofw/ofw.c create mode 100755 components/drivers/ofw/ofw_internal.h create mode 100755 components/drivers/ofw/raw.c create mode 100755 components/drivers/pic/Kconfig create mode 100644 components/drivers/pic/SConscript create mode 100644 components/drivers/pic/pic.c diff --git a/bsp/allwinner/d1/.config b/bsp/allwinner/d1/.config index 33f0866023..dbfd4b53f7 100644 --- a/bsp/allwinner/d1/.config +++ b/bsp/allwinner/d1/.config @@ -347,6 +347,7 @@ CONFIG_RT_LWIP_USING_PING=y # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/allwinner/d1/rtconfig.h b/bsp/allwinner/d1/rtconfig.h index 04fd734a30..87feff4485 100644 --- a/bsp/allwinner/d1/rtconfig.h +++ b/bsp/allwinner/d1/rtconfig.h @@ -219,6 +219,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/allwinner/d1s/.config b/bsp/allwinner/d1s/.config index 28a1c0d0a5..a815cee74f 100644 --- a/bsp/allwinner/d1s/.config +++ b/bsp/allwinner/d1s/.config @@ -275,6 +275,7 @@ CONFIG_RT_USING_POSIX_PIPE_SIZE=512 # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/allwinner/d1s/rtconfig.h b/bsp/allwinner/d1s/rtconfig.h index e6e40aa64f..ccedd34d46 100644 --- a/bsp/allwinner/d1s/rtconfig.h +++ b/bsp/allwinner/d1s/rtconfig.h @@ -162,6 +162,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/bouffalo_lab/bl808/d0/.config b/bsp/bouffalo_lab/bl808/d0/.config index 45c2827572..8a9e19e6b4 100644 --- a/bsp/bouffalo_lab/bl808/d0/.config +++ b/bsp/bouffalo_lab/bl808/d0/.config @@ -266,6 +266,7 @@ CONFIG_RT_USING_POSIX_PIPE_SIZE=512 # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y CONFIG_RT_USING_RESOURCE_ID=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/bouffalo_lab/bl808/d0/rtconfig.h b/bsp/bouffalo_lab/bl808/d0/rtconfig.h index ddaaf939df..9872da0e14 100755 --- a/bsp/bouffalo_lab/bl808/d0/rtconfig.h +++ b/bsp/bouffalo_lab/bl808/d0/rtconfig.h @@ -149,6 +149,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL #define RT_USING_RESOURCE_ID /* RT-Thread Utestcases */ diff --git a/bsp/cv1800b/.config b/bsp/cv1800b/.config index f7d25e22cf..78d9240df5 100644 --- a/bsp/cv1800b/.config +++ b/bsp/cv1800b/.config @@ -256,6 +256,7 @@ CONFIG_RT_USING_POSIX_TIMER=y # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y CONFIG_RT_USING_RESOURCE_ID=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/cv1800b/rtconfig.h b/bsp/cv1800b/rtconfig.h index ecac19cac5..43c20696a5 100644 --- a/bsp/cv1800b/rtconfig.h +++ b/bsp/cv1800b/rtconfig.h @@ -140,6 +140,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL #define RT_USING_RESOURCE_ID /* RT-Thread Utestcases */ diff --git a/bsp/ft2004/.config b/bsp/ft2004/.config index 942eab8345..ca770db11a 100644 --- a/bsp/ft2004/.config +++ b/bsp/ft2004/.config @@ -364,6 +364,7 @@ CONFIG_ULOG_BACKEND_USING_CONSOLE=y # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/ft2004/rtconfig.h b/bsp/ft2004/rtconfig.h index c03b9a7ddc..a4da55de52 100644 --- a/bsp/ft2004/rtconfig.h +++ b/bsp/ft2004/rtconfig.h @@ -209,6 +209,7 @@ #define ULOG_OUTPUT_TAG #define ULOG_BACKEND_USING_CONSOLE #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/imx/imx6ull-smart/.config b/bsp/imx/imx6ull-smart/.config index c32a0179ab..f4cd26432c 100644 --- a/bsp/imx/imx6ull-smart/.config +++ b/bsp/imx/imx6ull-smart/.config @@ -414,6 +414,7 @@ CONFIG_ULOG_BACKEND_USING_CONSOLE=y # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/imx/imx6ull-smart/rtconfig.h b/bsp/imx/imx6ull-smart/rtconfig.h index d5418d96f0..b2208b9d79 100644 --- a/bsp/imx/imx6ull-smart/rtconfig.h +++ b/bsp/imx/imx6ull-smart/rtconfig.h @@ -267,6 +267,7 @@ #define ULOG_OUTPUT_TAG #define ULOG_BACKEND_USING_CONSOLE #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/imx6ul/.config b/bsp/imx6ul/.config index fee3faa71e..7c1b500cf4 100644 --- a/bsp/imx6ul/.config +++ b/bsp/imx6ul/.config @@ -228,6 +228,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/imx6ul/rtconfig.h b/bsp/imx6ul/rtconfig.h index 833168b1d3..3310b75945 100644 --- a/bsp/imx6ul/rtconfig.h +++ b/bsp/imx6ul/rtconfig.h @@ -113,6 +113,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/nuvoton/nk-980iot/.config b/bsp/nuvoton/nk-980iot/.config index 5dddc30467..184978b323 100644 --- a/bsp/nuvoton/nk-980iot/.config +++ b/bsp/nuvoton/nk-980iot/.config @@ -398,6 +398,7 @@ CONFIG_UTEST_THR_STACK_SIZE=4096 CONFIG_UTEST_THR_PRIORITY=20 # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/nuvoton/nk-n9h30/.config b/bsp/nuvoton/nk-n9h30/.config index cc86ef62ae..89ffdfe1c0 100644 --- a/bsp/nuvoton/nk-n9h30/.config +++ b/bsp/nuvoton/nk-n9h30/.config @@ -386,6 +386,7 @@ CONFIG_UTEST_THR_STACK_SIZE=4096 CONFIG_UTEST_THR_PRIORITY=20 # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/nuvoton/nk-rtu980/.config b/bsp/nuvoton/nk-rtu980/.config index 74f9055cca..13df539149 100644 --- a/bsp/nuvoton/nk-rtu980/.config +++ b/bsp/nuvoton/nk-rtu980/.config @@ -404,6 +404,7 @@ CONFIG_UTEST_THR_STACK_SIZE=4096 CONFIG_UTEST_THR_PRIORITY=20 # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/nuvoton/numaker-hmi-ma35d1/.config b/bsp/nuvoton/numaker-hmi-ma35d1/.config index d063bd93a0..6df82b3414 100644 --- a/bsp/nuvoton/numaker-hmi-ma35d1/.config +++ b/bsp/nuvoton/numaker-hmi-ma35d1/.config @@ -398,6 +398,7 @@ CONFIG_UTEST_THR_STACK_SIZE=4096 CONFIG_UTEST_THR_PRIORITY=20 # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/nuvoton/numaker-iot-ma35d1/.config b/bsp/nuvoton/numaker-iot-ma35d1/.config index d7eeccde32..e630741b8e 100644 --- a/bsp/nuvoton/numaker-iot-ma35d1/.config +++ b/bsp/nuvoton/numaker-iot-ma35d1/.config @@ -399,6 +399,7 @@ CONFIG_UTEST_THR_STACK_SIZE=4096 CONFIG_UTEST_THR_PRIORITY=20 # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/phytium/aarch32/.config b/bsp/phytium/aarch32/.config index e78d576898..62d8bff4b0 100644 --- a/bsp/phytium/aarch32/.config +++ b/bsp/phytium/aarch32/.config @@ -272,6 +272,7 @@ CONFIG_UTEST_THR_STACK_SIZE=4096 CONFIG_UTEST_THR_PRIORITY=20 # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/phytium/aarch32/rtconfig.h b/bsp/phytium/aarch32/rtconfig.h index 913e053bd7..4146488599 100644 --- a/bsp/phytium/aarch32/rtconfig.h +++ b/bsp/phytium/aarch32/rtconfig.h @@ -164,6 +164,7 @@ #define UTEST_THR_STACK_SIZE 4096 #define UTEST_THR_PRIORITY 20 #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/phytium/aarch64/.config b/bsp/phytium/aarch64/.config index c63a196b1f..24e339bf7c 100644 --- a/bsp/phytium/aarch64/.config +++ b/bsp/phytium/aarch64/.config @@ -252,6 +252,7 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/phytium/aarch64/rtconfig.h b/bsp/phytium/aarch64/rtconfig.h index 76b14cfc28..29e11f836e 100644 --- a/bsp/phytium/aarch64/rtconfig.h +++ b/bsp/phytium/aarch64/rtconfig.h @@ -143,6 +143,7 @@ #define RT_USING_RYM #define YMODEM_USING_FILE_TRANSFER #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/qemu-vexpress-a9/.config b/bsp/qemu-vexpress-a9/.config index a90d2217e6..d0b510d289 100644 --- a/bsp/qemu-vexpress-a9/.config +++ b/bsp/qemu-vexpress-a9/.config @@ -289,6 +289,7 @@ CONFIG_RT_USING_POSIX_MESSAGE_SEMAPHORE=y # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/qemu-vexpress-a9/rtconfig.h b/bsp/qemu-vexpress-a9/rtconfig.h index 99c4fa425a..42af02ceb6 100644 --- a/bsp/qemu-vexpress-a9/rtconfig.h +++ b/bsp/qemu-vexpress-a9/rtconfig.h @@ -181,6 +181,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/qemu-virt64-aarch64/.config b/bsp/qemu-virt64-aarch64/.config index 57c2735f2e..86d73fe1c0 100644 --- a/bsp/qemu-virt64-aarch64/.config +++ b/bsp/qemu-virt64-aarch64/.config @@ -277,6 +277,7 @@ CONFIG_RT_USING_POSIX_PIPE_SIZE=512 # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/qemu-virt64-aarch64/rtconfig.h b/bsp/qemu-virt64-aarch64/rtconfig.h index 4e9dd72e7a..3bdf25b998 100644 --- a/bsp/qemu-virt64-aarch64/rtconfig.h +++ b/bsp/qemu-virt64-aarch64/rtconfig.h @@ -171,6 +171,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/qemu-virt64-riscv/.config b/bsp/qemu-virt64-riscv/.config index c7da62a3dd..571d1fdfe0 100644 --- a/bsp/qemu-virt64-riscv/.config +++ b/bsp/qemu-virt64-riscv/.config @@ -349,6 +349,7 @@ CONFIG_UTEST_THR_STACK_SIZE=4096 CONFIG_UTEST_THR_PRIORITY=20 # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/qemu-virt64-riscv/rtconfig.h b/bsp/qemu-virt64-riscv/rtconfig.h index 1741274ead..2d174cf9d7 100644 --- a/bsp/qemu-virt64-riscv/rtconfig.h +++ b/bsp/qemu-virt64-riscv/rtconfig.h @@ -223,6 +223,7 @@ #define UTEST_THR_STACK_SIZE 4096 #define UTEST_THR_PRIORITY 20 #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/raspberry-pi/raspi2/.config b/bsp/raspberry-pi/raspi2/.config index ac188aedbf..6f25dab649 100644 --- a/bsp/raspberry-pi/raspi2/.config +++ b/bsp/raspberry-pi/raspi2/.config @@ -218,6 +218,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/raspberry-pi/raspi2/rtconfig.h b/bsp/raspberry-pi/raspi2/rtconfig.h index 2ebdb977e4..48deaf9aef 100644 --- a/bsp/raspberry-pi/raspi2/rtconfig.h +++ b/bsp/raspberry-pi/raspi2/rtconfig.h @@ -107,6 +107,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/raspberry-pi/raspi3-32/.config b/bsp/raspberry-pi/raspi3-32/.config index 8779d3bfd9..2b02db83db 100644 --- a/bsp/raspberry-pi/raspi3-32/.config +++ b/bsp/raspberry-pi/raspi3-32/.config @@ -260,6 +260,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/raspberry-pi/raspi3-32/rtconfig.h b/bsp/raspberry-pi/raspi3-32/rtconfig.h index 2ab676eec4..b3567095ae 100644 --- a/bsp/raspberry-pi/raspi3-32/rtconfig.h +++ b/bsp/raspberry-pi/raspi3-32/rtconfig.h @@ -138,6 +138,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/raspberry-pi/raspi3-64/.config b/bsp/raspberry-pi/raspi3-64/.config index e26421abfa..01eb5c7dfe 100644 --- a/bsp/raspberry-pi/raspi3-64/.config +++ b/bsp/raspberry-pi/raspi3-64/.config @@ -265,6 +265,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/raspberry-pi/raspi3-64/rtconfig.h b/bsp/raspberry-pi/raspi3-64/rtconfig.h index b9aedc17b5..ab319ae256 100644 --- a/bsp/raspberry-pi/raspi3-64/rtconfig.h +++ b/bsp/raspberry-pi/raspi3-64/rtconfig.h @@ -148,6 +148,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/raspberry-pi/raspi4-32/.config b/bsp/raspberry-pi/raspi4-32/.config index 0cf47e124a..26dfa85e75 100644 --- a/bsp/raspberry-pi/raspi4-32/.config +++ b/bsp/raspberry-pi/raspi4-32/.config @@ -350,6 +350,7 @@ CONFIG_RT_LWIP_USING_PING=y # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/raspberry-pi/raspi4-32/rtconfig.h b/bsp/raspberry-pi/raspi4-32/rtconfig.h index fd394f3d69..f946b29294 100644 --- a/bsp/raspberry-pi/raspi4-32/rtconfig.h +++ b/bsp/raspberry-pi/raspi4-32/rtconfig.h @@ -204,6 +204,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/raspberry-pi/raspi4-64/.config b/bsp/raspberry-pi/raspi4-64/.config index 7228a42d85..e8668e9f36 100644 --- a/bsp/raspberry-pi/raspi4-64/.config +++ b/bsp/raspberry-pi/raspi4-64/.config @@ -357,6 +357,7 @@ CONFIG_UTEST_THR_STACK_SIZE=8192 CONFIG_UTEST_THR_PRIORITY=20 # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/raspberry-pi/raspi4-64/rtconfig.h b/bsp/raspberry-pi/raspi4-64/rtconfig.h index ff4b54bd7e..d84361cb25 100644 --- a/bsp/raspberry-pi/raspi4-64/rtconfig.h +++ b/bsp/raspberry-pi/raspi4-64/rtconfig.h @@ -227,6 +227,7 @@ #define UTEST_THR_STACK_SIZE 8192 #define UTEST_THR_PRIORITY 20 #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/bsp/rockchip/rk3568/.config b/bsp/rockchip/rk3568/.config index 772d3c6469..5e0e0893da 100644 --- a/bsp/rockchip/rk3568/.config +++ b/bsp/rockchip/rk3568/.config @@ -216,6 +216,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set diff --git a/bsp/rockchip/rk3568/rtconfig.h b/bsp/rockchip/rk3568/rtconfig.h index 38fd8b3407..54931231c2 100644 --- a/bsp/rockchip/rk3568/rtconfig.h +++ b/bsp/rockchip/rk3568/rtconfig.h @@ -113,6 +113,7 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL /* RT-Thread Utestcases */ diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 92a7dbf6ff..4a3d7f7fff 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -773,6 +773,9 @@ menuconfig RT_USING_VIRTIO default y endif +source "$RTT_DIR/components/drivers/ofw/Kconfig" +source "$RTT_DIR/components/drivers/pic/Kconfig" + menu "Using USB" config RT_USING_USB bool diff --git a/components/drivers/include/drivers/ofw.h b/components/drivers/include/drivers/ofw.h new file mode 100644 index 0000000000..c760cf7e83 --- /dev/null +++ b/components/drivers/include/drivers/ofw.h @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#ifndef __OFW_H__ +#define __OFW_H__ + +#include + +#include +#include + +#include + +typedef rt_uint32_t rt_phandle; + +struct rt_ofw_prop +{ + const char *name; + int length; + void *value; + + struct rt_ofw_prop *next; +}; + +struct rt_ofw_node +{ + const char *name; + /* full_name is 'path/tag' or 'path/tag@reg' */ + const char *full_name; + /* phandles range from 1 to 2^32-2 (0xfffffffe) */ + rt_phandle phandle; + + struct rt_ofw_prop *props; + struct rt_ofw_node *parent; + struct rt_ofw_node *child; + struct rt_ofw_node *sibling; + + struct rt_ref ref; + +#define RT_OFW_F_SYSTEM 0 /* node is system node */ +#define RT_OFW_F_READLY 1 /* node has driver */ +#define RT_OFW_F_PLATFORM 2 /* node is platform device */ +#define RT_OFW_F_OVERLAY 3 /* node is from overlay */ + rt_bitmap_t flags; + + /* RT-Thread object prototype */ + void *rt_data; +}; + +#define RT_OFW_MAX_CELL_ARGS 16 + +struct rt_ofw_cell_args +{ + void *data; + + int args_count; + rt_uint32_t args[RT_OFW_MAX_CELL_ARGS]; +}; + +struct rt_ofw_node_id +{ + /* The name string should consist name property (deprecated) */ + char name[32]; + + /* + * The type string should consist device_type property, such as pci, memory + * serial. Because it's deprecated in , we can use other + * name (like "ttyS" or "ttyAMA" ...) to config with /chosen. + */ + char type[32]; + + /* + * The compatible string should consist only of lowercase letters, digits + * and dashes, and should start with a letter. A single comma is typically + * only used following a vendor prefix. Underscores should not be used. + */ + char compatible[128]; + + const void *data; +}; + +struct rt_ofw_stub +{ + const struct rt_ofw_node_id *ids; + rt_err_t (*handler)(struct rt_ofw_node *np, const struct rt_ofw_node_id *id); +}; + +#define RT_OFW_SYMBOL(_class, _level) \ + rt_section(".rt_ofw_data." #_class "." #_level) + +#define RT_OFW_SYMBOL_TYPE_RANGE(_class, _type, _start, _end) \ +static const rt_used RT_OFW_SYMBOL(_class, 0) _type _start; \ +static const rt_used RT_OFW_SYMBOL(_class, end) _type _end; \ + +#define RT_OFW_STUB_EXPORT(_name, _ids, _class, _handler, ...) \ +static const struct rt_ofw_stub __rt_ofw_##_name \ +rt_used RT_OFW_SYMBOL(_class, __VA_ARGS__ _) = \ +{ \ + .ids = _ids, \ + .handler = _handler, \ +} + +#define RT_OFW_STUB_RANGE_EXPORT(_class, _start, _end) \ + RT_OFW_SYMBOL_TYPE_RANGE(_class, struct rt_ofw_stub, _start = {}, _end = {}) + +#define rt_ofw_data(np) ((struct rt_ofw_node *)np)->rt_data + +rt_inline rt_bool_t rt_ofw_node_test_flag(const struct rt_ofw_node *np, int flag) +{ + return rt_bitmap_test_bit((rt_bitmap_t *)&np->flags, flag); +} + +rt_inline void rt_ofw_node_set_flag(struct rt_ofw_node *np, int flag) +{ + rt_bitmap_set_bit(&np->flags, flag); +} + +rt_inline rt_bool_t rt_ofw_node_test_and_set_flag(struct rt_ofw_node *np, int flag) +{ + rt_bool_t res = rt_ofw_node_test_flag(np, flag); + + rt_ofw_node_set_flag(np, flag); + + return res; +} + +rt_inline void rt_ofw_node_clear_flag(struct rt_ofw_node *np, int flag) +{ + rt_bitmap_clear_bit(&np->flags, flag); +} + +rt_err_t rt_ofw_node_destroy(struct rt_ofw_node *np); + +struct rt_ofw_node *rt_ofw_node_get(struct rt_ofw_node *np); +void rt_ofw_node_put(struct rt_ofw_node *np); + +rt_bool_t rt_ofw_node_tag_equ(const struct rt_ofw_node *np, const char *tag); +rt_bool_t rt_ofw_node_tag_prefix(const struct rt_ofw_node *np, const char *prefix); + +rt_inline const char *rt_ofw_node_name(const struct rt_ofw_node *np) +{ + return np ? np->name : ""; +} + +rt_inline const char *rt_ofw_node_full_name(const struct rt_ofw_node *np) +{ + return np ? np->full_name : ""; +} + +rt_bool_t rt_ofw_machine_is_compatible(const char *compatible); +rt_bool_t rt_ofw_node_is_available(const struct rt_ofw_node *np); +rt_bool_t rt_ofw_node_is_compatible(const struct rt_ofw_node *np, const char *compatible); + +struct rt_ofw_node_id *rt_ofw_prop_match(struct rt_ofw_prop *prop, const struct rt_ofw_node_id *ids); +struct rt_ofw_node_id *rt_ofw_node_match(struct rt_ofw_node *np, const struct rt_ofw_node_id *ids); + +struct rt_ofw_node *rt_ofw_find_node_by_tag(struct rt_ofw_node *from, const char *tag); +struct rt_ofw_node *rt_ofw_find_node_by_prop_r(struct rt_ofw_node *from, const char *propname, + const struct rt_ofw_prop **out_prop); + +rt_inline struct rt_ofw_node *rt_ofw_find_node_by_prop(struct rt_ofw_node *from, const char *propname) +{ + return rt_ofw_find_node_by_prop_r(from, propname, RT_NULL); +} + +struct rt_ofw_node *rt_ofw_find_node_by_name(struct rt_ofw_node *from, const char *name); +struct rt_ofw_node *rt_ofw_find_node_by_type(struct rt_ofw_node *from, const char *type); +struct rt_ofw_node *rt_ofw_find_node_by_compatible(struct rt_ofw_node *from, const char *compatible); +struct rt_ofw_node *rt_ofw_find_node_by_ids_r(struct rt_ofw_node *from, const struct rt_ofw_node_id *ids, + const struct rt_ofw_node_id **out_id); +struct rt_ofw_node *rt_ofw_find_node_by_path(const char *path); +struct rt_ofw_node *rt_ofw_find_node_by_phandle(rt_phandle phandle); + +rt_inline struct rt_ofw_node *rt_ofw_find_node_by_ids(struct rt_ofw_node *from, const struct rt_ofw_node_id *ids) +{ + return rt_ofw_find_node_by_ids_r(from, ids, RT_NULL); +} + +struct rt_ofw_node *rt_ofw_get_parent(const struct rt_ofw_node *np); +struct rt_ofw_node *rt_ofw_get_child_by_tag(const struct rt_ofw_node *parent, const char *tag); +struct rt_ofw_node *rt_ofw_get_child_by_compatible(const struct rt_ofw_node *parent, const char *compatible); + +int rt_ofw_get_child_count(const struct rt_ofw_node *np); +int rt_ofw_get_available_child_count(const struct rt_ofw_node *np); + +struct rt_ofw_node *rt_ofw_get_next_node(struct rt_ofw_node *prev); +struct rt_ofw_node *rt_ofw_get_next_parent(struct rt_ofw_node *prev); +struct rt_ofw_node *rt_ofw_get_next_child(const struct rt_ofw_node *parent, struct rt_ofw_node *prev); +struct rt_ofw_node *rt_ofw_get_next_available_child(const struct rt_ofw_node *parent, struct rt_ofw_node *prev); + +struct rt_ofw_node *rt_ofw_get_cpu_node(int cpu, int *thread, rt_bool_t (*match_cpu_hwid)(int cpu, rt_uint64_t hwid)); +struct rt_ofw_node *rt_ofw_get_next_cpu_node(struct rt_ofw_node *prev); +struct rt_ofw_node *rt_ofw_get_cpu_state_node(struct rt_ofw_node *cpu_np, int index); +rt_uint64_t rt_ofw_get_cpu_id(struct rt_ofw_node *cpu_np); +rt_uint64_t rt_ofw_get_cpu_hwid(struct rt_ofw_node *cpu_np, unsigned int thread); + +struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id); +int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag); +int rt_ofw_get_alias_last_id(const char *tag); + +struct rt_ofw_node *rt_ofw_parse_phandle(const struct rt_ofw_node *np, const char *phandle_name, int index); +rt_err_t rt_ofw_parse_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name, + int index, struct rt_ofw_cell_args *out_args); +int rt_ofw_count_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name); + +struct rt_ofw_prop *rt_ofw_get_prop(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length); + +rt_inline const void *rt_ofw_prop_read_raw(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length) +{ + struct rt_ofw_prop *prop = rt_ofw_get_prop(np, name, out_length); + + return prop ? prop->value : RT_NULL; +} + +int rt_ofw_prop_read_u8_array_index(const struct rt_ofw_node *np, const char *propname, + int index, int nr, rt_uint8_t *out_values); +int rt_ofw_prop_read_u16_array_index(const struct rt_ofw_node *np, const char *propname, + int index, int nr, rt_uint16_t *out_values); +int rt_ofw_prop_read_u32_array_index(const struct rt_ofw_node *np, const char *propname, + int index, int nr, rt_uint32_t *out_values); +int rt_ofw_prop_read_u64_array_index(const struct rt_ofw_node *np, const char *propname, + int index, int nr, rt_uint64_t *out_values); +int rt_ofw_prop_read_string_array_index(const struct rt_ofw_node *np, const char *propname, + int index, int nr, const char **out_strings); + +int rt_ofw_prop_count_of_size(const struct rt_ofw_node *np, const char *propname, int size); +int rt_ofw_prop_index_of_string(const struct rt_ofw_node *np, const char *propname, const char *string); + +const fdt32_t *rt_ofw_prop_next_u32(struct rt_ofw_prop *prop, const fdt32_t *cur, rt_uint32_t *out_value); +const char *rt_ofw_prop_next_string(struct rt_ofw_prop *prop, const char *cur); + +rt_inline rt_err_t rt_ofw_prop_read_u8_index(const struct rt_ofw_node *np, const char *propname, + int index, rt_uint8_t *out_value) +{ + int nr = rt_ofw_prop_read_u8_array_index(np, propname, index, 1, out_value); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_ofw_prop_read_u16_index(const struct rt_ofw_node *np, const char *propname, + int index, rt_uint16_t *out_value) +{ + int nr = rt_ofw_prop_read_u16_array_index(np, propname, index, 1, out_value); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_ofw_prop_read_u32_index(const struct rt_ofw_node *np, const char *propname, + int index, rt_uint32_t *out_value) +{ + int nr = rt_ofw_prop_read_u32_array_index(np, propname, index, 1, out_value); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_ofw_prop_read_u64_index(const struct rt_ofw_node *np, const char *propname, + int index, rt_uint64_t *out_value) +{ + int nr = rt_ofw_prop_read_u64_array_index(np, propname, index, 1, out_value); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_ofw_prop_read_string_index(const struct rt_ofw_node *np, const char *propname, + int index, const char **out_string) +{ + int nr = rt_ofw_prop_read_string_array_index(np, propname, index, 1, out_string); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_ofw_prop_read_u8(const struct rt_ofw_node *np, const char *propname, + rt_uint8_t *out_value) +{ + return rt_ofw_prop_read_u8_index(np, propname, 0, out_value); +} + +rt_inline rt_err_t rt_ofw_prop_read_u16(const struct rt_ofw_node *np, const char *propname, + rt_uint16_t *out_value) +{ + return rt_ofw_prop_read_u16_index(np, propname, 0, out_value); +} + +rt_inline rt_err_t rt_ofw_prop_read_u32(const struct rt_ofw_node *np, const char *propname, + rt_uint32_t *out_value) +{ + return rt_ofw_prop_read_u32_index(np, propname, 0, out_value); +} + +rt_inline rt_err_t rt_ofw_prop_read_s32(const struct rt_ofw_node *np, const char *propname, + rt_int32_t *out_value) +{ + return rt_ofw_prop_read_u32_index(np, propname, 0, (rt_uint32_t *)out_value); +} + +rt_inline rt_err_t rt_ofw_prop_read_u64(const struct rt_ofw_node *np, const char *propname, + rt_uint64_t *out_value) +{ + return rt_ofw_prop_read_u64_index(np, propname, 0, out_value); +} + +rt_inline rt_err_t rt_ofw_prop_read_string(const struct rt_ofw_node *np, const char *propname, + const char **out_string) +{ + return rt_ofw_prop_read_string_index(np, propname, 0, out_string); +} + +rt_inline rt_bool_t rt_ofw_prop_read_bool(const struct rt_ofw_node *np, const char *propname) +{ + return rt_ofw_get_prop(np, propname, RT_NULL) ? RT_TRUE : RT_FALSE; +} + +rt_inline int rt_ofw_prop_count_of_u8(const struct rt_ofw_node *np, const char *propname) +{ + return rt_ofw_prop_count_of_size(np, propname, sizeof(rt_uint8_t)); +} + +rt_inline int rt_ofw_prop_count_of_u16(const struct rt_ofw_node *np, const char *propname) +{ + return rt_ofw_prop_count_of_size(np, propname, sizeof(rt_uint16_t)); +} + +rt_inline int rt_ofw_prop_count_of_u32(const struct rt_ofw_node *np, const char *propname) +{ + return rt_ofw_prop_count_of_size(np, propname, sizeof(rt_uint32_t)); +} + +rt_inline int rt_ofw_prop_count_of_u64(const struct rt_ofw_node *np, const char *propname) +{ + return rt_ofw_prop_count_of_size(np, propname, sizeof(rt_uint64_t)); +} + +rt_inline const char *rt_ofw_node_type(const struct rt_ofw_node *np) +{ + return rt_ofw_prop_read_raw(np, "device_type", RT_NULL); +} + +rt_inline rt_bool_t rt_ofw_node_is_type(const struct rt_ofw_node *np, const char *type) +{ + const char *get_type = rt_ofw_node_type(np); + + return np && get_type && type && !rt_strcmp(get_type, type); +} + +#define rt_ofw_foreach_node_by_tag(np, name) \ + for (np = rt_ofw_find_node_by_tag(RT_NULL, name); np; \ + np = rt_ofw_find_node_by_tag(np, name)) + +#define rt_ofw_foreach_node_by_prop(np, prop_name) \ + for (np = rt_ofw_find_node_by_prop(RT_NULL, prop_name); \ + np; np = rt_ofw_find_node_by_prop(np, prop_name)) + +#define rt_ofw_foreach_node_by_prop_r(np, prop_name, prop) \ + for (np = rt_ofw_find_node_by_prop_r(RT_NULL, prop_name, prop); \ + np; np = rt_ofw_find_node_by_prop_r(np, prop_name, prop)) + +#define rt_ofw_foreach_node_by_name(np, name) \ + for (np = rt_ofw_find_node_by_name(RT_NULL, name); np; \ + np = rt_ofw_find_node_by_name(np, name)) + +#define rt_ofw_foreach_node_by_type(np, type) \ + for (np = rt_ofw_find_node_by_type(RT_NULL, type); np; \ + np = rt_ofw_find_node_by_type(np, type)) + +#define rt_ofw_foreach_node_by_compatible(np, type, compatible) \ + for (np = rt_ofw_find_node_by_compatible(RT_NULL, type, compatible); np; \ + np = rt_ofw_find_node_by_compatible(np, type, compatible)) + +#define rt_ofw_foreach_node_by_ids_r(np, id, ids) \ + for (np = rt_ofw_find_node_by_ids_r(RT_NULL, ids, id); \ + np; np = rt_ofw_find_node_by_ids_r(np, ids, id)) + +#define rt_ofw_foreach_node_by_ids(np, ids) \ + for (np = rt_ofw_find_node_by_ids(RT_NULL, ids); np; \ + np = rt_ofw_find_node_by_ids(np, ids)) + +#define rt_ofw_foreach_nodes(from, np) \ + for (np = rt_ofw_get_next_node(from); \ + np; np = rt_ofw_get_next_node(np)) + +#define rt_ofw_foreach_allnodes(np) \ + rt_ofw_foreach_nodes(RT_NULL, np) + +#define rt_ofw_foreach_parent_node(np) \ + for (np = rt_ofw_get_next_parent(rt_ofw_node_get(np)); \ + np; np = rt_ofw_get_next_parent(np)) + +#define rt_ofw_foreach_child_node(parent, child) \ + for (child = rt_ofw_get_next_child(parent, RT_NULL); \ + child; child = rt_ofw_get_next_child(parent, child)) + +#define rt_ofw_foreach_available_child_node(parent, child) \ + for (child = rt_ofw_get_next_available_child(parent, RT_NULL); child; \ + child = rt_ofw_get_next_available_child(parent, child)) + +#define rt_ofw_foreach_cpu_node(cpu_np) \ + for (cpu_np = rt_ofw_get_next_cpu_node(RT_NULL); \ + cpu_np; cpu_np = rt_ofw_get_next_cpu_node(cpu_np)) + +#define rt_ofw_foreach_prop(np, prop) \ + for (prop = np->props; prop; prop = prop->next) + +#define rt_ofw_foreach_prop_u32(np, propname, prop, p, u) \ + for (prop = rt_ofw_get_prop(np, propname, RT_NULL), \ + p = rt_ofw_prop_next_u32(prop, RT_NULL, &u); p; \ + p = rt_ofw_prop_next_u32(prop, p, &u)) + +#define rt_ofw_foreach_prop_string(np, propname, prop, s) \ + for (prop = rt_ofw_get_prop(np, propname, RT_NULL), \ + s = rt_ofw_prop_next_string(prop, RT_NULL); s; \ + s = rt_ofw_prop_next_string(prop, s)) + +#define rt_ofw_foreach_stub(stub, stub_start, stub_end) \ + for (stub = stub_start; stub <= stub_end; ++stub) + +struct rt_ofw_stub *rt_ofw_stub_probe_range(struct rt_ofw_node *np, + const struct rt_ofw_stub *stub_start, const struct rt_ofw_stub *stub_end); + +rt_err_t rt_ofw_console_setup(void); +const char *rt_ofw_bootargs_select(const char *key, int index); + +#ifdef RT_USING_CONSOLE +void rt_ofw_node_dump_dts(struct rt_ofw_node *np, rt_bool_t sibling_too); +#endif + +#endif /* __OFW_H__ */ diff --git a/components/drivers/include/drivers/ofw_fdt.h b/components/drivers/include/drivers/ofw_fdt.h new file mode 100755 index 0000000000..a9c951ca40 --- /dev/null +++ b/components/drivers/include/drivers/ofw_fdt.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#ifndef __OFW_FDT_H__ +#define __OFW_FDT_H__ + +#include +#include + +struct rt_fdt_earlycon +{ + union { rt_ubase_t mmio, port; }; + union { rt_ubase_t size, width; }; + + void *fdt; + long nodeoffset; + + void *data; + void (*console_putc)(void *data, char c); + +#define FDT_EARLYCON_KICK_UPDATE 0 +#define FDT_EARLYCON_KICK_COMPLETED 1 + void (*console_kick)(struct rt_fdt_earlycon *earlycon, int why); + + long msg_idx; + char msg[RT_FDT_EARLYCON_MSG_SIZE * 1024]; +}; + +struct rt_fdt_earlycon_id +{ + char *name; + char *type; + char *compatible; + rt_err_t (*setup)(struct rt_fdt_earlycon *earlycon, const char *options); +}; + +#define RT_FDT_EARLYCON_OPTION_SIGNATURE '\n' + +#define RT_FDT_EARLYCON_EXPORT(_name, _type, _compatible, _setup) \ +static const struct rt_fdt_earlycon_id __rt_fdt_##_name##_earlycon \ +rt_used RT_OFW_SYMBOL(earlycon, _) = \ +{ \ + .name = #_name, \ + .type = _type, \ + .compatible = _compatible, \ + .setup = _setup, \ +} + +const char *rt_fdt_node_name(const char *full_name); +rt_uint64_t rt_fdt_read_number(const fdt32_t *cell, int size); +rt_uint64_t rt_fdt_next_cell(const fdt32_t **cellptr, int size); +rt_uint64_t rt_fdt_translate_address(void *fdt, int nodeoffset, rt_uint64_t address); +rt_bool_t rt_fdt_device_is_available(void *fdt, int nodeoffset); + +rt_err_t rt_fdt_commit_memregion_early(rt_region_t *region, rt_bool_t is_reserved); +rt_err_t rt_fdt_commit_memregion_request(rt_region_t **out_region, rt_size_t *out_nr, rt_bool_t is_reserved); + +rt_err_t rt_fdt_prefetch(void *fdt); +rt_err_t rt_fdt_scan_root(void); +rt_err_t rt_fdt_scan_memory(void); +rt_err_t rt_fdt_scan_initrd(rt_uint64_t *ranges); +rt_err_t rt_fdt_model_dump(void); +rt_err_t rt_fdt_boot_dump(void); +void rt_fdt_earlycon_output(const char *str); +void rt_fdt_earlycon_kick(int why); +rt_err_t rt_fdt_scan_chosen_stdout(void); +rt_err_t rt_fdt_unflatten(void); + +struct rt_ofw_node *rt_fdt_unflatten_single(void *fdt); + +#endif /* __OFW_FDT_H__ */ diff --git a/components/drivers/include/drivers/ofw_io.h b/components/drivers/include/drivers/ofw_io.h new file mode 100755 index 0000000000..5fdfe8f5e6 --- /dev/null +++ b/components/drivers/include/drivers/ofw_io.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#ifndef __OFW_IO_H__ +#define __OFW_IO_H__ + +#include + +int rt_ofw_bus_addr_cells(struct rt_ofw_node *np); +int rt_ofw_bus_size_cells(struct rt_ofw_node *np); +int rt_ofw_io_addr_cells(struct rt_ofw_node *np); +int rt_ofw_io_size_cells(struct rt_ofw_node *np); + +int rt_ofw_get_address_count(struct rt_ofw_node *np); +rt_err_t rt_ofw_get_address(struct rt_ofw_node *np, int index, rt_uint64_t *out_address, rt_uint64_t *out_size); +rt_err_t rt_ofw_get_address_by_name(struct rt_ofw_node *np, const char *name, + rt_uint64_t *out_address, rt_uint64_t *out_size); +int rt_ofw_get_address_array(struct rt_ofw_node *np, int nr, rt_uint64_t *out_regs); + +rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address); + +void *rt_ofw_iomap(struct rt_ofw_node *np, int index); +void *rt_ofw_iomap_by_name(struct rt_ofw_node *np, const char *name); + +#endif /* __OFW_IO_H__ */ diff --git a/components/drivers/include/drivers/ofw_irq.h b/components/drivers/include/drivers/ofw_irq.h new file mode 100755 index 0000000000..e9b8482eac --- /dev/null +++ b/components/drivers/include/drivers/ofw_irq.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#ifndef __OFW_IRQ_H__ +#define __OFW_IRQ_H__ + +#include + +int rt_ofw_irq_cells(struct rt_ofw_node *np); + +rt_err_t rt_ofw_parse_irq_map(struct rt_ofw_node *np, struct rt_ofw_cell_args *irq_args); +rt_err_t rt_ofw_parse_irq_cells(struct rt_ofw_node *np, int index, struct rt_ofw_cell_args *out_irq_args); + +struct rt_ofw_node *rt_ofw_find_irq_parent(struct rt_ofw_node *np, int *out_interrupt_cells); +int rt_ofw_map_irq(struct rt_ofw_cell_args *irq_args); + +int rt_ofw_get_irq_count(struct rt_ofw_node *np); +int rt_ofw_get_irq(struct rt_ofw_node *np, int index); +int rt_ofw_get_irq_by_name(struct rt_ofw_node *np, const char *name); + +#endif /* __OFW_IRQ_H__ */ diff --git a/components/drivers/include/drivers/ofw_raw.h b/components/drivers/include/drivers/ofw_raw.h new file mode 100755 index 0000000000..13736c3010 --- /dev/null +++ b/components/drivers/include/drivers/ofw_raw.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#ifndef __OFW_RAW_H__ +#define __OFW_RAW_H__ + +#include + +#define FDT_SIZE_KB 1024 +#define FDT_SIZE_MB (1024 * FDT_SIZE_KB) + +#define FDT_SIZE_MAX (2 * FDT_SIZE_MB) +#define FDT_PADDING_SIZE (1 * FDT_SIZE_KB) + +typedef uint8_t fdt8_t; + +static inline uint8_t fdt8_to_cpu(fdt8_t x) +{ + return (uint8_t)x; +} + +int fdt_add_subnode_possible(void *fdt, int parentoffset, const char *name); +int fdt_add_mem_rsv_possible(void *fdt, size_t addr, size_t size); + +#define fdt_setprop_cstring(fdt, nodeoffset, name, str) \ + fdt_setprop((fdt), (nodeoffset), (name), (str), sizeof(str)) + +#define fdt_prop_cells_ops(ops, fdt, nodeoffset, prop, ...) \ +({ \ + int ret = 0; \ + uint32_t tmp[] = { __VA_ARGS__ }; \ + for (int i = 0; i < sizeof(tmp) / sizeof(tmp[0]); ++i) \ + { \ + tmp[i] = cpu_to_fdt32(tmp[i]); \ + } \ + ret += ops(fdt, nodeoffset, prop, tmp, sizeof(tmp)); \ + ret; \ +}) + +#define fdt_setprop_cells(fdt, nodeoffset, prop, ...) \ + fdt_prop_cells_ops(fdt_setprop, fdt, nodeoffset, prop, __VA_ARGS__) + +#define fdt_appendprop_cells(fdt, nodeoffset, prop, ...) \ + fdt_prop_cells_ops(fdt_appendprop, fdt, nodeoffset, prop, __VA_ARGS__) + +int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name, uint64_t val, bool is_u64); +int fdt_getprop_u8(void *fdt, int nodeoffset, const char *name, uint8_t *out_value, int *lenp); +int fdt_getprop_s8(void *fdt, int nodeoffset, const char *name, int8_t *out_value, int *lenp); +int fdt_getprop_u16(void *fdt, int nodeoffset, const char *name, uint16_t *out_value, int *lenp); +int fdt_getprop_s16(void *fdt, int nodeoffset, const char *name, int16_t *out_value, int *lenp); +int fdt_getprop_u32(void *fdt, int nodeoffset, const char *name, uint32_t *out_value, int *lenp); +int fdt_getprop_s32(void *fdt, int nodeoffset, const char *name, int32_t *out_value, int *lenp); + +int fdt_io_addr_cells(void *fdt, int nodeoffset); +int fdt_io_size_cells(void *fdt, int nodeoffset); + +int fdt_install_initrd(void *fdt, char *os_name, size_t initrd_addr, size_t initrd_size); + +#endif /* __OFW_RAW_H__ */ diff --git a/components/drivers/include/drivers/pic.h b/components/drivers/include/drivers/pic.h new file mode 100755 index 0000000000..5c6ac24c50 --- /dev/null +++ b/components/drivers/include/drivers/pic.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-24 GuEe-GUI first version + */ + +#ifndef __PIC_H__ +#define __PIC_H__ + +#include + +#include +#include +#include + +struct rt_pci_msi_desc; +struct rt_pci_msi_msg; + +struct rt_pic_ops; +struct rt_pic_irq; + +struct rt_pic +{ + rt_list_t list; + + struct rt_pic_ops *ops; + + void *priv_data; + void *user_data; + + struct rt_pic *parent; + + int irq_start; + rt_size_t irq_nr; + struct rt_pic_irq *pirqs; +}; + +struct rt_pic_ops +{ + const char *name; + + rt_err_t (*irq_init)(struct rt_pic *pic); + rt_err_t (*irq_finit)(struct rt_pic *pic); + + void (*irq_enable)(struct rt_pic_irq *pirq); + void (*irq_disable)(struct rt_pic_irq *pirq); + void (*irq_ack)(struct rt_pic_irq *pirq); + void (*irq_mask)(struct rt_pic_irq *pirq); + void (*irq_unmask)(struct rt_pic_irq *pirq); + void (*irq_eoi)(struct rt_pic_irq *pirq); + + rt_err_t (*irq_set_priority)(struct rt_pic_irq *pirq, rt_uint32_t priority); + rt_err_t (*irq_set_affinity)(struct rt_pic_irq *pirq, rt_bitmap_t *affinity); + rt_err_t (*irq_set_triger_mode)(struct rt_pic_irq *pirq, rt_uint32_t mode); + + void (*irq_send_ipi)(struct rt_pic_irq *pirq, rt_bitmap_t *cpumask); + + void (*irq_compose_msi_msg)(struct rt_pic_irq *pirq, struct rt_pci_msi_msg *msg); + void (*irq_write_msi_msg)(struct rt_pic_irq *pirq, struct rt_pci_msi_msg *msg); + int (*irq_alloc_msi)(struct rt_pic *pic, struct rt_pci_msi_desc *msi_desc); + void (*irq_free_msi)(struct rt_pic *pic, int irq); + + int (*irq_map)(struct rt_pic *pic, int hwirq, rt_uint32_t mode); + rt_err_t (*irq_parse)(struct rt_pic *pic, struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq); +}; + +struct rt_pic_isr +{ + rt_list_t list; + +#define RT_IRQ_F_NONE 0 + int flags; + struct rt_irq_desc action; +}; + +struct rt_pic_irq +{ + int irq; + int hwirq; + +#define RT_IRQ_MODE_NONE 0 +#define RT_IRQ_MODE_EDGE_RISING 1 +#define RT_IRQ_MODE_EDGE_FALLING 2 +#define RT_IRQ_MODE_EDGE_BOTH (RT_IRQ_MODE_EDGE_FALLING | RT_IRQ_MODE_EDGE_RISING) +#define RT_IRQ_MODE_LEVEL_HIGH 4 +#define RT_IRQ_MODE_LEVEL_LOW 8 +#define RT_IRQ_MODE_LEVEL_MASK (RT_IRQ_MODE_LEVEL_LOW | RT_IRQ_MODE_LEVEL_HIGH) +#define RT_IRQ_MODE_MASK 0xf + rt_uint32_t mode; + + rt_uint32_t priority; + RT_DECLARE_BITMAP(affinity, RT_CPUS_NR); + + struct rt_pci_msi_desc *msi_desc; + + struct rt_pic_isr isr; + + struct rt_spinlock rw_lock; + + struct rt_pic *pic; +}; + +rt_err_t rt_pic_linear_irq(struct rt_pic *pic, rt_size_t irq_nr); + +int rt_pic_config_ipi(struct rt_pic *pic, int ipi_index, int hwirq); +int rt_pic_config_irq(struct rt_pic *pic, int irq_index, int hwirq); + +rt_inline struct rt_pic_irq *rt_pic_find_irq(struct rt_pic *pic, int irq_index) +{ + /* This is a quickly interface */ + RT_ASSERT(pic != RT_NULL); + RT_ASSERT(pic->pirqs != RT_NULL); + RT_ASSERT(irq_index < pic->irq_nr); + + return &pic->pirqs[irq_index]; +} + +struct rt_pic_irq *rt_pic_find_ipi(struct rt_pic *pic, int ipi_index); + +int rt_pic_cascade(struct rt_pic *pic, struct rt_pic *parent_pic, int hwirq, rt_uint32_t mode); +void rt_pic_uncascade(struct rt_pic *pic, int irq); + +rt_err_t rt_pic_attach_irq(int irq, rt_isr_handler_t handler, void *uid, const char *name, int flags); +rt_err_t rt_pic_detach_irq(int irq, void *uid); + +rt_err_t rt_pic_add_traps(rt_bool_t (*handler)(void *), void *data); +rt_err_t rt_pic_do_traps(void); +rt_err_t rt_pic_handle_isr(struct rt_pic_irq *pirq); + +/* User-implemented extensions */ +rt_err_t rt_pic_user_extends(struct rt_pic *pic); + +rt_err_t rt_pic_irq_init(void); +rt_err_t rt_pic_irq_finit(void); +void rt_pic_irq_enable(int irq); +void rt_pic_irq_disable(int irq); +void rt_pic_irq_ack(int irq); +void rt_pic_irq_mask(int irq); +void rt_pic_irq_unmask(int irq); +void rt_pic_irq_eoi(int irq); +rt_err_t rt_pic_irq_set_priority(int irq, rt_uint32_t priority); +rt_uint32_t rt_pic_irq_get_priority(int irq); +rt_err_t rt_pic_irq_set_affinity(int irq, rt_bitmap_t *affinity); +rt_err_t rt_pic_irq_get_affinity(int irq, rt_bitmap_t *out_affinity); +rt_err_t rt_pic_irq_set_triger_mode(int irq, rt_uint32_t mode); +rt_uint32_t rt_pic_irq_get_triger_mode(int irq); +void rt_pic_irq_send_ipi(int irq, rt_bitmap_t *cpumask); + +void rt_pic_irq_parent_enable(struct rt_pic *ppic, struct rt_pic_irq *pirq); +void rt_pic_irq_parent_disable(struct rt_pic *ppic, struct rt_pic_irq *pirq); +void rt_pic_irq_parent_ack(struct rt_pic *ppic, struct rt_pic_irq *pirq); +void rt_pic_irq_parent_mask(struct rt_pic *ppic, struct rt_pic_irq *pirq); +void rt_pic_irq_parent_unmask(struct rt_pic *ppic, struct rt_pic_irq *pirq); +void rt_pic_irq_parent_eoi(struct rt_pic *ppic, struct rt_pic_irq *pirq); +rt_err_t rt_pic_irq_parent_set_priority(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_uint32_t priority); +rt_err_t rt_pic_irq_parent_set_affinity(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_bitmap_t *affinity); +rt_err_t rt_pic_irq_parent_set_triger_mode(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_uint32_t mode); + +#define RT_PIC_OFW_DECLARE(name, ids, handler) RT_OFW_STUB_EXPORT(name, ids, pic, handler) + +rt_err_t rt_pic_init(void); + +#endif /* __PIC_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 60da08f8b1..06e5c7158a 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -171,6 +171,18 @@ extern "C" { #ifdef RT_USING_DM #include "drivers/core/rtdm.h" + +#ifdef RT_USING_OFW +#include "drivers/ofw.h" +#include "drivers/ofw_fdt.h" +#include "drivers/ofw_io.h" +#include "drivers/ofw_irq.h" +#include "drivers/ofw_raw.h" +#endif /* RT_USING_OFW */ + +#ifdef RT_USING_PIC +#include "drivers/pic.h" +#endif #endif /* RT_USING_DM */ #ifdef __cplusplus diff --git a/components/drivers/ofw/Kconfig b/components/drivers/ofw/Kconfig new file mode 100755 index 0000000000..bebb5b4384 --- /dev/null +++ b/components/drivers/ofw/Kconfig @@ -0,0 +1,22 @@ +menuconfig RT_USING_OFW + bool "Using Open Firmware (OFW)" + select RT_USING_ADT + select RT_USING_ADT_REF + select RT_USING_ADT_BITMAP + depends on RT_USING_DM + default n + +config RT_USING_BUILTIN_FDT + bool "Using builtin fdt in kernel" + depends on RT_USING_OFW + default n + +config RT_BUILTIN_FDT_PATH + string "Builtin fdt path, will rebuild if have dts" + depends on RT_USING_BUILTIN_FDT + default "rtthread.dtb" + +config RT_FDT_EARLYCON_MSG_SIZE + int "Earlycon message buffer size (KB)" + depends on RT_USING_OFW + default 128 diff --git a/components/drivers/ofw/SConscript b/components/drivers/ofw/SConscript new file mode 100644 index 0000000000..d878c0c64a --- /dev/null +++ b/components/drivers/ofw/SConscript @@ -0,0 +1,22 @@ +from building import * + +objs = [] + +if not GetDepend(['RT_USING_OFW']): + Return('objs') + +cwd = GetCurrentDir() +list = os.listdir(cwd) +CPPPATH = [cwd, cwd + '/../include'] + +src = Glob('*.c') + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) +objs = objs + group + +Return('objs') diff --git a/components/drivers/ofw/base.c b/components/drivers/ofw/base.c new file mode 100644 index 0000000000..63f6d2702e --- /dev/null +++ b/components/drivers/ofw/base.c @@ -0,0 +1,1511 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#include + +#include +#include +#include +#include + +#define DBG_TAG "rtdm.ofw" +#define DBG_LVL DBG_INFO +#include + +#include "ofw_internal.h" + +struct rt_ofw_node *ofw_node_root = RT_NULL; +struct rt_ofw_node *ofw_node_cpus = RT_NULL; +struct rt_ofw_node *ofw_node_chosen = RT_NULL; +struct rt_ofw_node *ofw_node_aliases = RT_NULL; +struct rt_ofw_node *ofw_node_reserved_memory = RT_NULL; + +static rt_phandle _phandle_range[2] = { 1, 1 }; +static struct rt_ofw_node **_phandle_hash = RT_NULL; + +static rt_list_t _aliases_nodes = RT_LIST_OBJECT_INIT(_aliases_nodes); + +rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max) +{ + rt_err_t err = RT_EOK; + struct rt_ofw_node **hash_ptr = RT_NULL; + + max = RT_ALIGN(max, OFW_NODE_MIN_HASH); + + if (max > _phandle_range[1]) + { + rt_size_t size = sizeof(*_phandle_hash) * (max - min); + + if (!_phandle_hash) + { + hash_ptr = rt_calloc(1, size); + } + else + { + hash_ptr = rt_realloc(_phandle_hash, size); + + if (hash_ptr) + { + rt_size_t old_max = _phandle_range[1]; + + rt_memset(&hash_ptr[old_max], 0, sizeof(_phandle_hash) * (max - old_max)); + } + } + } + + if (hash_ptr) + { + /* We always reset min value only once */ + if (min) + { + _phandle_range[0] = min; + } + _phandle_range[1] = max; + + _phandle_hash = hash_ptr; + } + else + { + err = -RT_ENOMEM; + } + + return err; +} + +static void ofw_prop_destroy(struct rt_ofw_prop *prop) +{ + struct rt_ofw_prop *next; + + while (prop) + { + next = prop->next; + + rt_free(prop); + + prop = next; + } +} + +static struct rt_ofw_node *ofw_get_next_node(struct rt_ofw_node *prev) +{ + struct rt_ofw_node *np; + + /* + * Walk: + * + * / { ------------------------ [0] (START) has child, goto child. + * + * node0 { ---------------- [1] has child, goto child. + * + * node0_0 { ---------- [2] no child, has sibling, goto sibling. + * }; + * + * node0_1 { ---------- [3] no sibling now. + * upward while the parent has sibling. + * }; + * }; + * + * node1 { ---------------- [4] come from node0 who find the sibling: + * node1, node1 has child, goto child. + * + * node1_0 { ---------- [5] has child, goto child. + * + * node1_0_0 { ---- [6] no sibling now. + * upward while the parent has sibling. + * (END) in the root. + * }; + * }; + * }; + * }; + */ + + if (!prev) + { + np = ofw_node_root; + } + else if (prev->child) + { + np = prev->child; + } + else + { + np = prev; + + while (np->parent && !np->sibling) + { + np = np->parent; + } + + np = np->sibling; + } + + return np; +} + +static void ofw_node_destroy(struct rt_ofw_node *np) +{ + struct rt_ofw_node *prev; + + if (np->parent) + { + /* Ask parent and prev sibling we are destroy. */ + prev = np->parent->child; + + if (prev == np) + { + np->parent->child = RT_NULL; + } + else + { + while (prev->sibling != np) + { + prev = prev->sibling; + } + + prev->sibling = np->sibling; + } + } + + while (np) + { + if (rt_ofw_node_test_flag(np, RT_OFW_F_SYSTEM) == RT_FALSE) + { + LOG_E("%s is system node", np->full_name); + RT_ASSERT(0); + } + + prev = np; + + np = ofw_get_next_node(np); + + ofw_prop_destroy(prev->props); + rt_free(prev); + } +} + +rt_err_t rt_ofw_node_destroy(struct rt_ofw_node *np) +{ + rt_err_t err = RT_EOK; + + if (np) + { + if (rt_ref_read(&np->ref) <= 1) + { + ofw_node_destroy(np); + } + else + { + err = -RT_EBUSY; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +struct rt_ofw_node *rt_ofw_node_get(struct rt_ofw_node *np) +{ + if (np) + { + LOG_D("%s get ref = %d", np->full_name, rt_ref_read(&np->ref)); + rt_ref_get(&np->ref); + } + + return np; +} + +static void ofw_node_release(struct rt_ref *r) +{ + struct rt_ofw_node *np = rt_container_of(r, struct rt_ofw_node, ref); + + LOG_E("%s is release", np->full_name); + + RT_ASSERT(0); +} + +void rt_ofw_node_put(struct rt_ofw_node *np) +{ + if (np) + { + LOG_D("%s put ref = %d", np->full_name, rt_ref_read(&np->ref)); + rt_ref_put(&np->ref, &ofw_node_release); + } +} + +rt_bool_t rt_ofw_node_tag_equ(const struct rt_ofw_node *np, const char *tag) +{ + rt_bool_t ret = RT_FALSE; + + if (np && tag) + { + const char *node_name = rt_fdt_node_name(np->full_name); + rt_size_t tag_len = rt_strchrnul(node_name, '@') - node_name; + + ret = (rt_strlen(tag) == tag_len && !rt_strncmp(node_name, tag, tag_len)); + } + + return ret; +} + +rt_bool_t rt_ofw_node_tag_prefix(const struct rt_ofw_node *np, const char *prefix) +{ + rt_bool_t ret = RT_FALSE; + + if (np && prefix) + { + ret = !rt_strncmp(rt_fdt_node_name(np->full_name), prefix, rt_strlen(prefix)); + } + + return ret; +} + +static int ofw_prop_index_of_string(struct rt_ofw_prop *prop, const char *string, + rt_int32_t (*cmp)(const char *cs, const char *ct)) +{ + int index = -1; + rt_size_t len = prop->length, slen = 0; + const char *value = prop->value; + + for (int idx = 0; len > 0; ++idx) + { + /* Add '\0' */ + slen = rt_strlen(value) + 1; + + if (!cmp(value, string)) + { + index = idx; + + break; + } + + len -= slen; + value += slen; + } + + return index; +} + +static rt_int32_t ofw_strcasecmp(const char *cs, const char *ct) +{ + extern rt_int32_t strcasecmp(const char *cs, const char *ct); + + return rt_strcasecmp(cs, ct); +} + +static int ofw_prop_index_of_compatible(struct rt_ofw_prop *prop, const char *compatible) +{ + return ofw_prop_index_of_string(prop, compatible, ofw_strcasecmp); +} + +static int ofw_node_index_of_compatible(const struct rt_ofw_node *np, const char *compatible) +{ + int idx = -1; + struct rt_ofw_prop *prop = rt_ofw_get_prop(np, "compatible", RT_NULL); + + if (prop) + { + idx = ofw_prop_index_of_compatible(prop, compatible); + } + + return idx; +} + +rt_bool_t rt_ofw_machine_is_compatible(const char *compatible) +{ + return ofw_node_index_of_compatible(ofw_node_root, compatible) >= 0; +} + +/* + * Property status: + * + * "okay" or "ok": + * Indicates the device is operational. + * + * "disabled": + * Indicates that the device is not presently operational, but it might + * become operational in the future (for example, something is not + * plugged in, or switched off). + * Refer to the device binding for details on what disabled means for a + * given device. + * + * "reserved": + * Indicates that the device is operational, but should not be used. + * Typically this is used for devices that are controlled by another + * software component, such as platform firmware. + * + * "fail": + * Indicates that the device is not operational. A serious error was + * detected in the device, and it is unlikely to become operational + * without repair. + * + * "fail-sss": + * Indicates that the device is not operational. A serious error was + * detected in the device and it is unlikely to become operational + * without repair. The sss portion of the value is specific to the + * device and indicates the error condition detected. + */ + +static rt_bool_t ofw_node_is_fail(const struct rt_ofw_node *np) +{ + rt_bool_t res = RT_FALSE; + const char *status = rt_ofw_prop_read_raw(np, "status", RT_NULL); + + if (status) + { + res = !rt_strcmp(status, "fail") || !rt_strncmp(status, "fail-", 5); + } + + return res; +} + +static rt_bool_t ofw_node_is_available(const struct rt_ofw_node *np) +{ + rt_bool_t res = RT_TRUE; + const char *status = rt_ofw_prop_read_raw(np, "status", RT_NULL); + + if (status) + { + res = !rt_strcmp(status, "okay") || !rt_strcmp(status, "ok"); + } + + return res; +} + +rt_bool_t rt_ofw_node_is_available(const struct rt_ofw_node *np) +{ + return np ? ofw_node_is_available(np) : RT_FALSE; +} + +rt_bool_t rt_ofw_node_is_compatible(const struct rt_ofw_node *np, const char *compatible) +{ + rt_bool_t res = RT_FALSE; + + if (np) + { + res = ofw_node_index_of_compatible(np, compatible) >= 0; + } + + return res; +} + +static struct rt_ofw_node_id *ofw_prop_match(struct rt_ofw_prop *prop, const struct rt_ofw_node_id *ids) +{ + int best_index = RT_UINT32_MAX >> 1, index; + struct rt_ofw_node_id *found_id = RT_NULL, *id; + + for (id = (struct rt_ofw_node_id *)ids; id->compatible[0]; ++id) + { + index = ofw_prop_index_of_compatible(prop, id->compatible); + + if (index >= 0 && index < best_index) + { + found_id = id; + best_index = index; + } + } + + return found_id; +} + +struct rt_ofw_node_id *rt_ofw_prop_match(struct rt_ofw_prop *prop, const struct rt_ofw_node_id *ids) +{ + struct rt_ofw_node_id *id = RT_NULL; + + if (prop && ids && !rt_strcmp(prop->name, "compatible")) + { + id = ofw_prop_match(prop, ids); + } + + return id; +} + +struct rt_ofw_node_id *rt_ofw_node_match(struct rt_ofw_node *np, const struct rt_ofw_node_id *ids) +{ + struct rt_ofw_prop *prop; + struct rt_ofw_node_id *id = RT_NULL; + + if (np && ids && (prop = rt_ofw_get_prop(np, "compatible", RT_NULL))) + { + id = ofw_prop_match(prop, ids); + } + + return id; +} + +struct rt_ofw_node *rt_ofw_find_node_by_tag(struct rt_ofw_node *from, const char *tag) +{ + struct rt_ofw_node *np = RT_NULL; + + if (tag) + { + rt_ofw_foreach_nodes(from, np) + { + if (rt_ofw_node_tag_equ(np, tag)) + { + break; + } + } + } + + return np; +} + +struct rt_ofw_node *rt_ofw_find_node_by_prop_r(struct rt_ofw_node *from, const char *propname, + const struct rt_ofw_prop **out_prop) +{ + struct rt_ofw_node *np = RT_NULL; + + if (propname) + { + rt_ofw_foreach_nodes(from, np) + { + struct rt_ofw_prop *prop = rt_ofw_get_prop(np, propname, RT_NULL); + + if (prop) + { + if (out_prop) + { + *out_prop = prop; + } + + break; + } + } + } + + return np; +} + +struct rt_ofw_node *rt_ofw_find_node_by_name(struct rt_ofw_node *from, const char *name) +{ + struct rt_ofw_node *np = RT_NULL; + + if (name) + { + rt_ofw_foreach_nodes(from, np) + { + if (np->name && !rt_strcmp(np->name, name)) + { + np = rt_ofw_node_get(np); + break; + } + } + } + + return np; +} + +struct rt_ofw_node *rt_ofw_find_node_by_type(struct rt_ofw_node *from, const char *type) +{ + struct rt_ofw_node *np = RT_NULL; + + if (type) + { + rt_ofw_foreach_nodes(from, np) + { + if (rt_ofw_node_is_type(np, type)) + { + break; + } + } + } + + return np; +} + +struct rt_ofw_node *rt_ofw_find_node_by_compatible(struct rt_ofw_node *from, const char *compatible) +{ + struct rt_ofw_node *np = RT_NULL; + + if (compatible) + { + rt_ofw_foreach_nodes(from, np) + { + if (ofw_node_index_of_compatible(np, compatible) >= 0) + { + break; + } + } + } + + return np; +} + +struct rt_ofw_node *rt_ofw_find_node_by_ids_r(struct rt_ofw_node *from, const struct rt_ofw_node_id *ids, + const struct rt_ofw_node_id **out_id) +{ + struct rt_ofw_node *np = RT_NULL; + + if (ids) + { + rt_ofw_foreach_nodes(from, np) + { + struct rt_ofw_node_id *id = rt_ofw_node_match(np, ids); + + if (id) + { + if (out_id) + { + *out_id = id; + } + + break; + } + } + } + + return np; +} + +struct rt_ofw_node *rt_ofw_find_node_by_path(const char *path) +{ + struct rt_ofw_node *np, *parent, *tmp; + + if (path) + { + if (!rt_strcmp(path, "/")) + { + np = ofw_node_root; + } + else + { + ++path; + parent = rt_ofw_node_get(ofw_node_root); + + while (*path) + { + const char *next = rt_strchrnul(path, '/'); + rt_size_t len = next - path; + + tmp = RT_NULL; + + rt_ofw_foreach_child_node(parent, np) + { + if (!rt_strncmp(np->full_name, path, len)) + { + rt_ofw_node_put(parent); + + parent = np; + tmp = np; + + break; + } + } + + if (!tmp) + { + rt_ofw_node_put(parent); + + break; + } + + path += len; + } + + np = tmp; + } + + rt_ofw_node_get(np); + } + + return np; +} + +struct rt_ofw_node *rt_ofw_find_node_by_phandle(rt_phandle phandle) +{ + struct rt_ofw_node *np = RT_NULL; + + if (phandle >= OFW_PHANDLE_MIN && phandle <= OFW_PHANDLE_MAX) + { + /* rebase from zero */ + rt_phandle poff = phandle - _phandle_range[0]; + + np = _phandle_hash[poff]; + + if (!np) + { + rt_ofw_foreach_allnodes(np) + { + if (np->phandle == phandle) + { + _phandle_hash[poff] = np; + + break; + } + } + } + else + { + rt_ofw_node_get(np); + } + } + + return np; +} + +struct rt_ofw_node *rt_ofw_get_parent(const struct rt_ofw_node *np) +{ + if (np) + { + np = rt_ofw_node_get(np->parent); + } + + return (struct rt_ofw_node *)np; +} + +struct rt_ofw_node *rt_ofw_get_child_by_tag(const struct rt_ofw_node *parent, const char *tag) +{ + struct rt_ofw_node *child = RT_NULL; + + if (parent && tag) + { + rt_ofw_foreach_child_node(parent, child) + { + if (rt_ofw_node_tag_equ(child, tag)) + { + break; + } + } + } + + return child; +} + +struct rt_ofw_node *rt_ofw_get_child_by_compatible(const struct rt_ofw_node *parent, const char *compatible) +{ + struct rt_ofw_node *child = RT_NULL; + + if (parent && compatible) + { + rt_ofw_foreach_child_node(parent, child) + { + if (ofw_node_index_of_compatible(child, compatible) >= 0) + { + break; + } + } + } + + return child; +} + +int rt_ofw_get_child_count(const struct rt_ofw_node *np) +{ + int nr; + + if (np) + { + struct rt_ofw_node *child; + + nr = 0; + + rt_ofw_foreach_child_node(np, child) + { + ++nr; + } + } + else + { + nr = -RT_EINVAL; + } + + return nr; +} + +int rt_ofw_get_available_child_count(const struct rt_ofw_node *np) +{ + int nr; + + if (np) + { + struct rt_ofw_node *child; + + nr = 0; + + rt_ofw_foreach_available_child_node(np, child) + { + ++nr; + } + } + else + { + nr = -RT_EINVAL; + } + + return nr; +} + +struct rt_ofw_node *rt_ofw_get_next_node(struct rt_ofw_node *prev) +{ + struct rt_ofw_node *np; + + np = rt_ofw_node_get(ofw_get_next_node(prev)); + rt_ofw_node_put(prev); + + return np; +} + +struct rt_ofw_node *rt_ofw_get_next_parent(struct rt_ofw_node *prev) +{ + struct rt_ofw_node *next = RT_NULL; + + if (prev) + { + next = rt_ofw_node_get(prev->parent); + rt_ofw_node_put(prev); + } + + return next; +} + +struct rt_ofw_node *rt_ofw_get_next_child(const struct rt_ofw_node *parent, struct rt_ofw_node *prev) +{ + struct rt_ofw_node *next = RT_NULL; + + if (parent) + { + next = prev ? prev->sibling : parent->child; + rt_ofw_node_put(prev); + rt_ofw_node_get(next); + } + + return next; +} + +struct rt_ofw_node *rt_ofw_get_next_available_child(const struct rt_ofw_node *parent, struct rt_ofw_node *prev) +{ + struct rt_ofw_node *next = RT_NULL; + + if (parent) + { + next = prev; + + do { + next = rt_ofw_get_next_child(parent, next); + + } while (next && !ofw_node_is_available(next)); + } + + return next; +} + +struct rt_ofw_node *rt_ofw_get_cpu_node(int cpu, int *thread, rt_bool_t (*match_cpu_hwid)(int cpu, rt_uint64_t hwid)) +{ + const char *propname = "reg"; + struct rt_ofw_node *cpu_np = RT_NULL; + + /* + * "reg" (some of the obsolete arch may be other names): + * The value of reg is a that defines a unique + * CPU/thread id for the CPU/threads represented by the CPU node. + * + * If a CPU supports more than one thread (i.e. multiple streams of + * execution) the reg property is an array with 1 element per thread. The + * #address-cells on the /cpus node specifies how many cells each element + * of the array takes. Software can determine the number of threads by + * dividing the size of reg by the parent node’s #address-cells: + * + * thread-number = reg-cells / address-cells + * + * If a CPU/thread can be the target of an external interrupt the reg + * property value must be a unique CPU/thread id that is addressable by the + * interrupt controller. + * + * If a CPU/thread cannot be the target of an external interrupt, then reg + * must be unique and out of bounds of the range addressed by the interrupt + * controller + * + * If a CPU/thread’s PIR (pending interrupt register) is modifiable, a + * client program should modify PIR to match the reg property value. If PIR + * cannot be modified and the PIR value is distinct from the interrupt + * controller number space, the CPUs binding may define a binding-specific + * representation of PIR values if desired. + */ + + rt_ofw_foreach_cpu_node(cpu_np) + { + rt_ssize_t prop_len; + rt_bool_t is_end = RT_FALSE; + int tid, addr_cells = rt_ofw_io_addr_cells(cpu_np); + const fdt32_t *cell = rt_ofw_prop_read_raw(cpu_np, propname, &prop_len); + + if (!cell && !addr_cells) + { + if (match_cpu_hwid && match_cpu_hwid(cpu, 0)) + { + break; + } + + continue; + } + + if (!match_cpu_hwid) + { + continue; + } + + prop_len /= sizeof(*cell) * addr_cells; + + for (tid = 0; tid < prop_len; ++tid) + { + rt_uint64_t hwid = rt_fdt_read_number(cell, addr_cells); + + if (match_cpu_hwid(cpu, hwid)) + { + if (thread) + { + *thread = tid; + } + + is_end = RT_TRUE; + + break; + } + + cell += addr_cells; + } + + if (is_end) + { + break; + } + } + + return cpu_np; +} + +struct rt_ofw_node *rt_ofw_get_next_cpu_node(struct rt_ofw_node *prev) +{ + struct rt_ofw_node *cpu_np; + + if (prev) + { + cpu_np = prev->sibling; + rt_ofw_node_put(prev); + } + else + { + cpu_np = ofw_node_cpus->child; + } + + for (; cpu_np; cpu_np = cpu_np->sibling) + { + if (ofw_node_is_fail(cpu_np)) + { + continue; + } + + if (!(rt_ofw_node_tag_equ(cpu_np, "cpu") || rt_ofw_node_is_type(cpu_np, "cpu"))) + { + continue; + } + + if (rt_ofw_node_get(cpu_np)) + { + break; + } + } + + return cpu_np; +} + +struct rt_ofw_node *rt_ofw_get_cpu_state_node(struct rt_ofw_node *cpu_np, int index) +{ + struct rt_ofw_cell_args args; + struct rt_ofw_node *np = RT_NULL, *state_np; + rt_err_t err = rt_ofw_parse_phandle_cells(cpu_np, "power-domains", "#power-domain-cells", 0, &args); + + if (!err) + { + state_np = rt_ofw_parse_phandle(args.data, "domain-idle-states", index); + + rt_ofw_node_put(args.data); + + if (state_np) + { + np = state_np; + } + } + + if (!np) + { + int count = 0; + rt_uint32_t phandle; + const fdt32_t *cell; + struct rt_ofw_prop *prop; + + rt_ofw_foreach_prop_u32(cpu_np, "cpu-idle-states", prop, cell, phandle) + { + if (count == index) + { + np = rt_ofw_find_node_by_phandle((rt_phandle)phandle); + + break; + } + + ++count; + } + } + + return np; +} + +rt_uint64_t rt_ofw_get_cpu_id(struct rt_ofw_node *cpu_np) +{ + rt_uint64_t cpuid = ~0ULL; + + if (cpu_np) + { + rt_uint64_t idx = 0; + struct rt_ofw_node *np = ofw_node_cpus->child; + + for (; np; np = np->sibling) + { + if (!(rt_ofw_node_tag_equ(cpu_np, "cpu") || rt_ofw_node_is_type(cpu_np, "cpu"))) + { + continue; + } + + if (cpu_np == np) + { + cpuid = idx; + + break; + } + + ++idx; + } + + if ((rt_int64_t)cpuid < 0 && !rt_ofw_prop_read_u64(cpu_np, "rt-thread,cpuid", &idx)) + { + cpuid = idx; + } + } + + return cpuid; +} + +rt_uint64_t rt_ofw_get_cpu_hwid(struct rt_ofw_node *cpu_np, unsigned int thread) +{ + rt_uint64_t thread_id, hwid = ~0ULL; + + if (cpu_np && thread >= 0 && !rt_ofw_get_address(cpu_np, thread, &thread_id, RT_NULL)) + { + hwid = thread_id; + } + + return hwid; +} + +rt_err_t ofw_alias_scan(void) +{ + rt_err_t err = RT_EOK; + struct rt_ofw_prop *prop; + struct rt_ofw_node *np = ofw_node_aliases, *tmp; + + rt_ofw_foreach_prop(np, prop) + { + int id = 0, rate = 1; + struct alias_info *info; + const char *name = prop->name, *end; + + /* Maybe the bootloader will set the name, or other nodes reference the aliases */ + if (!rt_strcmp(name, "name") || !rt_strcmp(name, "phandle")) + { + continue; + } + + if (!(tmp = rt_ofw_find_node_by_path(prop->value))) + { + continue; + } + + end = name + rt_strlen(name); + + while (*end && !(*end >= '0' && *end <= '9')) + { + --end; + } + + while (*end && (*end >= '0' && *end <= '9')) + { + id += (*end - '0') * rate; + rate *= 10; + + --end; + } + + info = rt_malloc(sizeof(*info)); + + if (!info) + { + err = -RT_ENOMEM; + break; + } + + rt_list_init(&info->list); + + info->id = id; + info->tag = name; + info->tag_len = end - name; + info->np = tmp; + + rt_list_insert_after(&_aliases_nodes, &info->list); + } + + return err; +} + +struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id) +{ + struct alias_info *info; + struct rt_ofw_node *np = RT_NULL; + + if (tag && id >= 0) + { + rt_list_for_each_entry(info, &_aliases_nodes, list) + { + if (rt_strncmp(info->tag, tag, info->tag_len)) + { + continue; + } + + if (info->id == id) + { + np = info->np; + break; + } + } + } + + return np; +} + +int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag) +{ + int id; + struct alias_info *info; + + if (np && tag) + { + id = -1; + + rt_list_for_each_entry(info, &_aliases_nodes, list) + { + if (rt_strncmp(info->tag, tag, info->tag_len)) + { + continue; + } + + if (info->np == np) + { + id = info->id; + break; + } + } + } + else + { + id = -RT_EINVAL; + } + + return id; +} + +int rt_ofw_get_alias_last_id(const char *tag) +{ + int id; + struct alias_info *info; + + if (tag) + { + id = -1; + + rt_list_for_each_entry(info, &_aliases_nodes, list) + { + if (rt_strncmp(info->tag, tag, info->tag_len)) + { + continue; + } + + if (info->id > id) + { + id = info->id; + } + } + } + else + { + id = -RT_EINVAL; + } + + return id; +} + +struct rt_ofw_node *rt_ofw_parse_phandle(const struct rt_ofw_node *np, const char *phandle_name, int index) +{ + struct rt_ofw_cell_args args; + struct rt_ofw_node *ref_np = RT_NULL; + + if (!rt_ofw_parse_phandle_cells(np, phandle_name, RT_NULL, index, &args)) + { + ref_np = args.data; + } + + return ref_np; +} + +static rt_err_t ofw_parse_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name, + int index, struct rt_ofw_cell_args *out_args) +{ + rt_err_t err = -RT_EEMPTY; + rt_uint32_t value; + rt_size_t count = 0; + const fdt32_t *cell; + struct rt_ofw_prop *prop; + + /* + * List: + * + * phandle1: node1 { + * #list-cells = <2>; + * }; + * + * phandle2: node2 { + * #list-cells = <1>; + * }; + * + * node3 { + * list = <&phandle1 0xaa 0xbb>, <&phandle2 0xcc>; + * }; + * + * if call: + * rt_ofw_parse_phandle_cells(node3, "list", "#list-cells", 0, &args): + * + * args.data = node1; + * args.args_count = 2; + * args.args[0] = 0xaa; + * args.args[1] = 0xbb; + * + * rt_ofw_parse_phandle_cells(node3, "list", "#list-cells", 1, &args): + * + * args.data = node2; + * args.args_count = 1; + * args.args[0] = 0xcc; + */ + + rt_ofw_foreach_prop_u32(np, list_name, prop, cell, value) + { + rt_uint32_t cells_count = 0; + struct rt_ofw_node *phandle_np = rt_ofw_find_node_by_phandle((rt_phandle)value); + + /* if phandle node is undefined, we assume that the cels_count is 0 */ + if (cells_name && phandle_np) + { + rt_ofw_prop_read_u32(phandle_np, cells_name, &cells_count); + } + + if (count++ == index) + { + for (int idx = 0; idx < cells_count; ++idx) + { + cell = rt_ofw_prop_next_u32(prop, cell, &value); + + out_args->args[idx] = value; + } + + out_args->args_count = cells_count; + out_args->data = phandle_np; + + if (out_args->data) + { + err = RT_EOK; + } + + break; + } + + cell += cells_count; + } + + return err; +} + +rt_err_t rt_ofw_parse_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name, + int index, struct rt_ofw_cell_args *out_args) +{ + rt_err_t err; + + if (np && list_name && index >= 0 && out_args) + { + err = ofw_parse_phandle_cells(np, list_name, cells_name, index, out_args); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +int rt_ofw_count_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name) +{ + int count; + + if (np && list_name) + { + count = -1; + + if (!cells_name) + { + rt_ssize_t length; + + if (rt_ofw_get_prop(np, list_name, &length)) + { + count = length / sizeof(fdt32_t); + } + } + else + { + int index = count = 0; + struct rt_ofw_cell_args args; + + while (!ofw_parse_phandle_cells(np, list_name, cells_name, index, &args)) + { + ++index; + ++count; + } + } + } + else + { + count = -RT_EINVAL; + } + + return count; +} + +struct rt_ofw_prop *rt_ofw_get_prop(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length) +{ + struct rt_ofw_prop *prop = RT_NULL; + + if (np && name) + { + rt_ofw_foreach_prop(np, prop) + { + if (!rt_strcmp(prop->name, name)) + { + if (out_length) + { + *out_length = prop->length; + } + + break; + } + } + } + + return prop; +} + +#define OFW_PROP_READ_UXX_ARRAY_INDEX(bit) \ +int rt_ofw_prop_read_u##bit##_array_index( \ + const struct rt_ofw_node *np, const char *propname, \ + int index, int nr, rt_uint##bit##_t *out_values) \ +{ \ + int res, max_nr; \ + if (np && propname && index >= 0 && nr >= 0 && out_values) \ + { \ + rt_ssize_t len; \ + const fdt##bit##_t *elm; \ + elm = rt_ofw_prop_read_raw(np, propname, &len); \ + max_nr = len / sizeof(*elm); \ + if (elm && index < max_nr) \ + { \ + elm += index; \ + max_nr -= index; \ + res = nr > max_nr ? max_nr : nr; \ + for (nr = 0; nr < res; ++nr) \ + { \ + *out_values++ = fdt##bit##_to_cpu(*elm++); \ + } \ + } \ + else \ + { \ + res = -RT_EEMPTY; \ + } \ + } \ + else \ + { \ + res = -RT_EINVAL; \ + } \ + return res; \ +} + +OFW_PROP_READ_UXX_ARRAY_INDEX(8) +OFW_PROP_READ_UXX_ARRAY_INDEX(16) +OFW_PROP_READ_UXX_ARRAY_INDEX(32) +OFW_PROP_READ_UXX_ARRAY_INDEX(64) + +#undef OFW_PROP_READ_UXX_ARRAY_INDEX + +int rt_ofw_prop_read_string_array_index(const struct rt_ofw_node *np, const char *propname, + int index, int nr, const char **out_strings) +{ + int res = 0; + + if (np && propname && index >= 0 && nr >= 0 && out_strings) + { + rt_ssize_t len, slen = 0; + const char *value = rt_ofw_prop_read_raw(np, propname, &len); + + if (value) + { + nr += index; + + for (int idx = 0; idx < nr && len > 0; ++idx) + { + /* Add '\0' */ + slen = rt_strlen(value) + 1; + + if (idx >= index) + { + *out_strings++ = value; + + ++res; + } + + len -= slen; + value += slen; + } + } + else + { + res = -RT_EEMPTY; + } + } + else + { + res = -RT_EINVAL; + } + + return res; +} + +int rt_ofw_prop_count_of_size(const struct rt_ofw_node *np, const char *propname, int size) +{ + int count; + + if (np && propname && size > 0) + { + rt_ssize_t len; + + count = -RT_EEMPTY; + + if (rt_ofw_get_prop(np, propname, &len)) + { + count = len / size; + } + } + else + { + count = -RT_EINVAL; + } + + return count; +} + +static rt_int32_t ofw_strcmp(const char *cs, const char *ct) +{ + return rt_strcmp(cs, ct); +} + +int rt_ofw_prop_index_of_string(const struct rt_ofw_node *np, const char *propname, const char *string) +{ + int idx; + + if (np && propname && string) + { + struct rt_ofw_prop *prop = rt_ofw_get_prop(np, propname, RT_NULL); + + idx = -1; + + if (prop) + { + idx = ofw_prop_index_of_string(prop, string, ofw_strcmp); + } + } + else + { + idx = -RT_EINVAL; + } + + return idx; +} + +const fdt32_t *rt_ofw_prop_next_u32(struct rt_ofw_prop *prop, const fdt32_t *cur, rt_uint32_t *out_value) +{ + if (prop && out_value) + { + if (cur) + { + ++cur; + + if ((void *)cur >= prop->value + prop->length) + { + cur = RT_NULL; + } + } + else + { + cur = prop->value; + } + + if (cur) + { + *out_value = fdt32_to_cpu(*cur); + } + } + else + { + cur = RT_NULL; + } + + return cur; +} + +const char *rt_ofw_prop_next_string(struct rt_ofw_prop *prop, const char *cur) +{ + if (prop) + { + if (cur) + { + cur += rt_strlen(cur) + 1; + + if ((void *)cur >= prop->value + prop->length) + { + cur = RT_NULL; + } + } + else + { + cur = prop->value; + } + } + else + { + cur = RT_NULL; + } + + return cur; +} diff --git a/components/drivers/ofw/fdt.c b/components/drivers/ofw/fdt.c new file mode 100755 index 0000000000..69eb332bee --- /dev/null +++ b/components/drivers/ofw/fdt.c @@ -0,0 +1,1108 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#include +#include + +#include +#include +#include + +#define DBG_TAG "rtdm.ofw" +#define DBG_LVL DBG_INFO +#include + +#include "ofw_internal.h" + +struct rt_fdt_earlycon fdt_earlycon rt_section(".bss.noclean.earlycon"); + +RT_OFW_SYMBOL_TYPE_RANGE(earlycon, struct rt_fdt_earlycon_id, _earlycon_start = {}, _earlycon_end = {}); + +#ifndef ARCH_INIT_MEMREGION_NR +#define ARCH_INIT_MEMREGION_NR 128 +#endif + +static rt_region_t _memregion[ARCH_INIT_MEMREGION_NR] rt_section(".bss.noclean.memregion"); +static int _memregion_front_idx = 0, _memregion_last_idx = RT_ARRAY_SIZE(_memregion) - 1; + +static void *_fdt = RT_NULL; +static rt_phandle _phandle_min; +static rt_phandle _phandle_max; +static rt_size_t _root_size_cells; +static rt_size_t _root_addr_cells; + +const char *rt_fdt_node_name(const char *full_name) +{ + const char *node_name = rt_strrchr(full_name, '/'); + + return node_name ? node_name + 1 : full_name; +} + +rt_uint64_t rt_fdt_read_number(const fdt32_t *cell, int size) +{ + rt_uint64_t val = 0; + + for (; size--; ++cell) + { + val = (val << 32) | fdt32_to_cpu(*cell); + } + + return val; +} + +rt_uint64_t rt_fdt_next_cell(const fdt32_t **cellptr, int size) +{ + const fdt32_t *ptr = *cellptr; + + *cellptr = ptr + size; + + return rt_fdt_read_number(ptr, size); +} + +rt_uint64_t rt_fdt_translate_address(void *fdt, int nodeoffset, rt_uint64_t address) +{ + rt_uint64_t ret = address; + + if (fdt && nodeoffset >= 0) + { + struct + { + rt_uint64_t addr; + rt_size_t size; + int addr_cells; + int size_cells; + } local, cpu; + int parent, length, group_len; + const fdt32_t *ranges = RT_NULL; + + parent = fdt_parent_offset(fdt, nodeoffset); + + if (parent >= 0) + { + length = 0; + ranges = fdt_getprop(fdt, nodeoffset, "ranges", &length); + } + + if (ranges && length > 0) + { + local.addr_cells = fdt_address_cells(fdt, nodeoffset); + local.size_cells = fdt_size_cells(fdt, nodeoffset); + cpu.addr_cells = fdt_io_addr_cells(fdt, nodeoffset); + cpu.size_cells = fdt_io_size_cells(fdt, nodeoffset); + + group_len = local.addr_cells + cpu.addr_cells + local.size_cells; + + while (length > 0) + { + local.addr = rt_fdt_next_cell(&ranges, local.addr_cells); + cpu.addr = rt_fdt_next_cell(&ranges, cpu.addr_cells); + local.size = rt_fdt_next_cell(&ranges, local.size_cells); + + if (local.addr <= address && local.addr + local.size > address) + { + ret += address - cpu.addr; + break; + } + + length -= group_len; + } + } + } + + return ret; +} + +rt_bool_t rt_fdt_device_is_available(void *fdt, int nodeoffset) +{ + rt_bool_t ret; + + const char *status = fdt_getprop(fdt, nodeoffset, "status", RT_NULL); + + if (!status) + { + ret = RT_TRUE; + } + else if (!rt_strcmp(status, "ok") || !rt_strcmp(status, "okay")) + { + ret = RT_TRUE; + } + else + { + ret = RT_FALSE; + } + + return ret; +} + +rt_err_t rt_fdt_commit_memregion_early(rt_region_t *region, rt_bool_t is_reserved) +{ + rt_err_t err = RT_EOK; + + if (region && region->name) + { + if (_memregion_front_idx < _memregion_last_idx) + { + int idx; + + if (!_memregion_front_idx && _memregion_last_idx == RT_ARRAY_SIZE(_memregion) - 1) + { + for (int i = 0; i < RT_ARRAY_SIZE(_memregion); ++i) + { + _memregion[i].name = RT_NULL; + } + } + + idx = is_reserved ? _memregion_last_idx-- : _memregion_front_idx++; + + rt_memcpy(&_memregion[idx], region, sizeof(*region)); + } + else + { + err = -RT_EEMPTY; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_fdt_commit_memregion_request(rt_region_t **out_region, rt_size_t *out_nr, rt_bool_t is_reserved) +{ + rt_err_t err = RT_EOK; + + if (out_region && out_nr) + { + if (is_reserved) + { + *out_region = &_memregion[_memregion_last_idx + 1]; + *out_nr = RT_ARRAY_SIZE(_memregion) - 1 - _memregion_last_idx; + } + else + { + *out_region = &_memregion[0]; + *out_nr = _memregion_front_idx; + } + + if (*out_nr == 0) + { + err = -RT_EEMPTY; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_fdt_prefetch(void *fdt) +{ + rt_err_t err = -RT_ERROR; + + if (fdt) + { + _fdt = fdt; + + if (!fdt_check_header(_fdt)) + { + err = rt_fdt_scan_root(); + } + else + { + err = -RT_EINVAL; + } + } + + return err; +} + +rt_err_t rt_fdt_scan_root(void) +{ + rt_err_t err = RT_EOK; + int root = fdt_path_offset(_fdt, "/"); + + if (root >= 0) + { + const fdt32_t *prop; + + _root_addr_cells = OFW_ROOT_NODE_ADDR_CELLS_DEFAULT; + _root_size_cells = OFW_ROOT_NODE_SIZE_CELLS_DEFAULT; + + if ((prop = fdt_getprop(_fdt, root, "#address-cells", RT_NULL))) + { + _root_addr_cells = fdt32_to_cpu(*prop); + } + + if ((prop = fdt_getprop(_fdt, root, "#size-cells", RT_NULL))) + { + _root_size_cells = fdt32_to_cpu(*prop); + } + } + else + { + err = -RT_EEMPTY; + } + + return err; +} + +rt_inline rt_err_t commit_memregion(const char *name, rt_uint64_t base, rt_uint64_t size, rt_bool_t is_reserved) +{ + return rt_fdt_commit_memregion_early(&(rt_region_t) + { + .name = name, + .start = (rt_size_t)base, + .end = (rt_size_t)(base + size), + }, is_reserved); +} + +static rt_err_t reserve_memregion(const char *name, rt_uint64_t base, rt_uint64_t size) +{ + if (commit_memregion(name, base, size, RT_TRUE) == -RT_EEMPTY) + { + LOG_W("Reserved memory: %p - %p%s", base, base + size, " unable to record"); + } + + return RT_EOK; +} + +static rt_err_t fdt_reserved_mem_check_root(int nodeoffset) +{ + rt_err_t err = RT_EOK; + const fdt32_t *prop = fdt_getprop(_fdt, nodeoffset, "#size-cells", RT_NULL); + + if (!prop || fdt32_to_cpu(*prop) != _root_size_cells) + { + err = -RT_EINVAL; + } + + if (!err) + { + prop = fdt_getprop(_fdt, nodeoffset, "#address-cells", RT_NULL); + + if (!prop || fdt32_to_cpu(*prop) != _root_addr_cells) + { + err = -RT_EINVAL; + } + } + + if (!err && !(prop = fdt_getprop(_fdt, nodeoffset, "ranges", RT_NULL))) + { + err = -RT_EINVAL; + } + + return err; +} + +static rt_err_t fdt_reserved_memory_reg(int nodeoffset, const char *uname) +{ + rt_err_t err = RT_EOK; + + rt_ubase_t base, size; + const fdt32_t *prop; + int len, t_len = (_root_addr_cells + _root_size_cells) * sizeof(fdt32_t); + + if ((prop = fdt_getprop(_fdt, nodeoffset, "reg", &len))) + { + if (len && len % t_len != 0) + { + LOG_E("Reserved memory: invalid reg property in '%s', skipping node", uname); + err = -RT_EINVAL; + } + else + { + while (len >= t_len) + { + base = rt_fdt_next_cell(&prop, _root_addr_cells); + size = rt_fdt_next_cell(&prop, _root_size_cells); + + if (!size) + { + continue; + } + + base = rt_fdt_translate_address(_fdt, nodeoffset, base); + reserve_memregion(fdt_get_name(_fdt, nodeoffset, RT_NULL), base, size); + + len -= t_len; + } + } + } + else + { + err = -RT_EEMPTY; + } + + return err; +} + +static void fdt_scan_reserved_memory(void) +{ + int nodeoffset, child; + + nodeoffset = fdt_path_offset(_fdt, "/reserved-memory"); + + if (nodeoffset >= 0) + { + if (!fdt_reserved_mem_check_root(nodeoffset)) + { + fdt_for_each_subnode(child, _fdt, nodeoffset) + { + rt_err_t err; + const char *uname; + + if (!rt_fdt_device_is_available(_fdt, child)) + { + continue; + } + + uname = fdt_get_name(_fdt, child, RT_NULL); + err = fdt_reserved_memory_reg(child, uname); + + if (err == -RT_EEMPTY && fdt_getprop(_fdt, child, "size", RT_NULL)) + { + reserve_memregion(fdt_get_name(_fdt, child, RT_NULL), 0, 0); + } + } + } + else + { + LOG_E("Reserved memory: unsupported node format, ignoring"); + } + } +} + +static rt_err_t fdt_scan_memory(void) +{ + int nodeoffset, no; + rt_region_t *region; + rt_uint64_t base, size; + rt_err_t err = -RT_EEMPTY; + + /* Process header /memreserve/ fields */ + for (no = 0; ; ++no) + { + fdt_get_mem_rsv(_fdt, no, &base, &size); + + if (!size) + { + break; + } + + reserve_memregion("memreserve", base, size); + } + + no = 0; + + fdt_for_each_subnode(nodeoffset, _fdt, 0) + { + int len; + const fdt32_t *reg, *endptr; + const char *name = fdt_get_name(_fdt, nodeoffset, RT_NULL); + const char *type = fdt_getprop(_fdt, nodeoffset, "device_type", RT_NULL); + + if (!type || rt_strcmp(type, "memory")) + { + continue; + } + + if (!rt_fdt_device_is_available(_fdt, nodeoffset)) + { + continue; + } + + reg = fdt_getprop(_fdt, nodeoffset, "reg", &len); + + if (!reg) + { + continue; + } + + endptr = reg + (len / sizeof(fdt32_t)); + name = name ? name : "memory"; + + while ((endptr - reg) >= (_root_addr_cells + _root_size_cells)) + { + base = rt_fdt_next_cell(®, _root_addr_cells); + size = rt_fdt_next_cell(®, _root_size_cells); + + if (!size) + { + continue; + } + + err = commit_memregion(name, base, size, RT_FALSE); + + if (!err) + { + LOG_I("Memory node(%d) ranges: %p - %p%s", no, base, base + size, ""); + } + else + { + LOG_W("Memory node(%d) ranges: %p - %p%s", no, base, base + size, " unable to record"); + } + + ++no; + } + } + + if (!err) + { + fdt_scan_reserved_memory(); + } + + region = &_memregion[0]; + + for (no = 0; region->name; ++region) + { + /* We need check the memory region now. */ + for (int i = RT_ARRAY_SIZE(_memregion) - 1; i > no; --i) + { + rt_region_t *res_region = &_memregion[i]; + + if (!res_region->name) + { + break; + } + + /* + * case 0: case 1: + * +------------------+ +----------+ + * | memory | | memory | + * +---+----------+---+ +---+----------+---+ + * | reserved | | reserved | + * +----------+ +---+----------+---+ + * + * case 2: case 3: + * +------------------+ +------------------+ + * | memory | | memory | + * +--------------+---+------+ +------+---+--------------+ + * | reserved | | reserved | + * +----------+ +----------+ + */ + + /* case 0 */ + if (res_region->start >= region->start && res_region->end <= region->end) + { + rt_size_t new_size = region->end - res_region->end; + + region->end = res_region->start; + + /* Commit part next block */ + if (new_size) + { + err = commit_memregion(region->name, res_region->end, new_size, RT_FALSE); + } + + if (!err) + { + ++no; + + /* Scan again */ + region = &_memregion[0]; + --region; + + break; + } + + continue; + } + + /* case 1 */ + if (res_region->start <= region->start && res_region->end >= region->end) + { + region->name = RT_NULL; + + break; + } + + /* case 2 */ + if (res_region->start <= region->end && res_region->end >= region->end) + { + region->end = res_region->start; + + continue; + } + + /* case 3 */ + if (res_region->start <= region->start && res_region->end >= region->start) + { + region->start = res_region->end; + + continue; + } + } + } + + return err; +} + +rt_err_t rt_fdt_scan_memory(void) +{ + rt_err_t err = -RT_EEMPTY; + + if (_fdt) + { + err = fdt_scan_memory(); + } + + return err; +} + +rt_err_t rt_fdt_scan_initrd(rt_uint64_t *ranges) +{ + rt_err_t err = -RT_EEMPTY; + + if (_fdt && ranges) + { + int s_len, e_len; + const fdt32_t *start = RT_NULL, *end = RT_NULL; + int offset = fdt_path_offset(_fdt, "/chosen"); + + if (offset >= 0) + { + start = fdt_getprop(_fdt, offset, "linux,initrd-start", &s_len); + end = fdt_getprop(_fdt, offset, "linux,initrd-end", &e_len); + } + + if (start && end) + { + s_len /= sizeof(*start); + e_len /= sizeof(*end); + + ranges[0] = rt_fdt_read_number(start, s_len); + ranges[1] = rt_fdt_read_number(end, e_len); + + commit_memregion("initrd", ranges[0], ranges[1] - ranges[0], RT_TRUE); + + err = RT_EOK; + } + } + else if (!ranges) + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_fdt_model_dump(void) +{ + rt_err_t err = RT_EOK; + int root = fdt_path_offset(_fdt, "/"); + + if (root >= 0) + { + const char *mach_model = fdt_getprop(_fdt, root, "model", RT_NULL); + + if (!mach_model) + { + mach_model = fdt_getprop(_fdt, root, "compatible", RT_NULL); + } + + LOG_I("Machine model: %s", mach_model ? mach_model : ""); + } + else + { + err = -RT_EEMPTY; + } + + return err; +} + +rt_weak rt_err_t rt_fdt_boot_dump(void) +{ + LOG_I("Booting RT-Thread on physical CPU 0x%x", rt_hw_cpu_id()); + + return RT_EOK; +} + +void rt_fdt_earlycon_output(const char *str) +{ + if (fdt_earlycon.console_putc) + { + while (*str) + { + fdt_earlycon.console_putc(fdt_earlycon.data, *str); + + if (*str == '\n') + { + /* Make sure return */ + fdt_earlycon.console_putc(fdt_earlycon.data, '\r'); + } + + ++str; + } + } + else + { + /* We need a byte to save '\0' */ + while (*str && fdt_earlycon.msg_idx < sizeof(fdt_earlycon.msg) - 1) + { + fdt_earlycon.msg[fdt_earlycon.msg_idx++] = *str; + + ++str; + } + fdt_earlycon.msg[fdt_earlycon.msg_idx] = '\0'; + } +} + +void rt_fdt_earlycon_kick(int why) +{ + if (fdt_earlycon.console_kick) + { + fdt_earlycon.console_kick(&fdt_earlycon, why); + } + + if (why == FDT_EARLYCON_KICK_COMPLETED && fdt_earlycon.msg_idx) + { + fdt_earlycon.msg_idx = 0; + + /* Dump old messages */ + rt_kputs(fdt_earlycon.msg); + } +} + +rt_err_t rt_fdt_scan_chosen_stdout(void) +{ + rt_err_t err = RT_EOK; + + int offset; + int len, options_len = 0; + const char *options = RT_NULL, *con_type = RT_NULL; + + rt_memset(&fdt_earlycon, 0, sizeof(fdt_earlycon) - sizeof(fdt_earlycon.msg)); + fdt_earlycon.nodeoffset = -1; + + offset = fdt_path_offset(_fdt, "/chosen"); + + if (offset >= 0) + { + const char *stdout_path = RT_NULL; + const char *bootargs = fdt_getprop(_fdt, offset, "bootargs", &len); + + if (bootargs && (options = rt_strstr(bootargs, "earlycon"))) + { + options += sizeof("earlycon") - 1; + + if (*options == '\0' || *options == ' ') + { + stdout_path = fdt_getprop(_fdt, offset, "stdout-path", &len); + + if (stdout_path && len) + { + const char *path_split = rt_strchrnul(stdout_path, ':'); + + if (*path_split != '\0') + { + options = path_split + 1; + } + + len = path_split - stdout_path; + + /* + * Will try 2 styles: + * 1: stdout-path = "serialN:bbbbpnf"; + * 2: stdout-path = "/serial-path"; + */ + offset = fdt_path_offset_namelen(_fdt, stdout_path, len); + + if (offset < 0) + { + stdout_path = RT_NULL; + } + } + else if (*options == '=') + { + ++options; + } + else + { + /* Maybe is error in bootargs or it is a new arg */ + options = RT_NULL; + } + + if (!stdout_path) + { + /* We couldn't know how to setup the earlycon */ + options = RT_NULL; + } + } + else + { + offset = -1; + } + + if (options) + { + int type_len = 0; + struct rt_fdt_earlycon_id *earlycon_id, *earlycon_id_end, *best_earlycon_id = RT_NULL; + + earlycon_id = (struct rt_fdt_earlycon_id *)&_earlycon_start; + earlycon_id_end = (struct rt_fdt_earlycon_id *)&_earlycon_end; + + err = -RT_ENOSYS; + + /* Only "earlycon" in bootargs */ + if (stdout_path) + { + const fdt32_t *reg; + options = RT_NULL; + + if ((reg = fdt_getprop(_fdt, offset, "reg", RT_NULL))) + { + rt_uint64_t address; + int addr_cells = fdt_io_addr_cells(_fdt, offset); + int size_cells = fdt_io_size_cells(_fdt, offset); + + address = rt_fdt_read_number(reg, addr_cells); + fdt_earlycon.mmio = rt_fdt_translate_address(_fdt, offset, address); + fdt_earlycon.size = rt_fdt_read_number(reg + addr_cells, size_cells); + } + } + else + { + /* Pass split */ + while (*options && (*options == '=' || *options == ' ')) + { + ++options; + } + + if (*options) + { + type_len = rt_strchrnul(options, ',') - options; + } + } + + if (options && *options && *options != ' ') + { + options_len = rt_strchrnul(options, ' ') - options; + } + + /* console > stdout-path */ + for (int max_score = 0; earlycon_id < earlycon_id_end; ++earlycon_id) + { + int score = 0; + + if (type_len && earlycon_id->type) + { + if (!rt_strncmp(earlycon_id->type, options, type_len)) + { + score += 1; + } + } + + if (stdout_path && earlycon_id->compatible) + { + if (!fdt_node_check_compatible(_fdt, offset, earlycon_id->compatible)) + { + score += 2; + } + } + + if (score > max_score) + { + max_score = score; + best_earlycon_id = earlycon_id; + + if (score == 3) + { + break; + } + } + } + + if (best_earlycon_id && best_earlycon_id->setup) + { + rt_bool_t used_options = RT_FALSE; + + if (!con_type) + { + con_type = best_earlycon_id->type; + } + fdt_earlycon.fdt = _fdt; + fdt_earlycon.nodeoffset = offset; + + err = best_earlycon_id->setup(&fdt_earlycon, options); + + for (int i = 0; i < options_len; ++i) + { + if (options[i] == RT_FDT_EARLYCON_OPTION_SIGNATURE) + { + /* Restore ',' */ + ((char *)options)[i++] = ','; + options = &options[i]; + options_len -= i; + used_options = RT_TRUE; + break; + } + } + if (!used_options) + { + options = RT_NULL; + options_len = 0; + } + } + } + } + else + { + err = -RT_EEMPTY; + } + } + else + { + err = -RT_EEMPTY; + } + + if (fdt_earlycon.msg_idx) + { + fdt_earlycon.msg_idx = 0; + + rt_kputs(fdt_earlycon.msg); + } + + rt_fdt_boot_dump(); + rt_fdt_model_dump(); + + if (fdt_earlycon.mmio) + { + LOG_I("Earlycon: %s at MMIO/PIO %p (options '%.*s')", + con_type, fdt_earlycon.mmio, options_len, options ? options : ""); + } + + return err; +} + +static void system_node_init_flag(struct rt_ofw_node *np) +{ + if (np) + { + rt_ofw_node_set_flag(np, RT_OFW_F_READLY); + rt_ofw_node_set_flag(np, RT_OFW_F_SYSTEM); + } +} + +rt_err_t rt_fdt_unflatten(void) +{ + rt_err_t err = RT_EOK; + + if (_fdt) + { + _phandle_min = OFW_PHANDLE_MAX; + _phandle_max = OFW_PHANDLE_MIN; + + ofw_node_root = rt_fdt_unflatten_single(_fdt); + + if (ofw_node_root) + { + ofw_node_cpus = rt_ofw_find_node_by_path("/cpus"); + ofw_node_chosen = rt_ofw_find_node_by_path("/chosen"); + ofw_node_aliases = rt_ofw_find_node_by_path("/aliases"); + ofw_node_reserved_memory = rt_ofw_find_node_by_path("/reserved-memory"); + + RT_ASSERT(ofw_node_cpus != RT_NULL); + + system_node_init_flag(ofw_node_root); + system_node_init_flag(ofw_node_cpus); + system_node_init_flag(ofw_node_chosen); + system_node_init_flag(ofw_node_aliases); + system_node_init_flag(ofw_node_reserved_memory); + + if (ofw_node_aliases) + { + err = ofw_alias_scan(); + } + + err = err ? : ofw_phandle_hash_reset(_phandle_min, _phandle_max); + } + } + else + { + err = -RT_ERROR; + } + + return err; +} + +static rt_err_t fdt_unflatten_props(struct rt_ofw_node *np, int node_off) +{ + rt_err_t err = RT_EOK; + struct rt_ofw_prop *prop; + int prop_off = fdt_first_property_offset(_fdt, node_off); + + if (prop_off >= 0) + { + np->props = rt_malloc(sizeof(struct rt_ofw_prop)); + } + + prop = np->props; + + while (prop_off >= 0) + { + if (!prop) + { + err = -RT_ENOMEM; + break; + } + + prop->value = (void *)fdt_getprop_by_offset(_fdt, prop_off, &prop->name, &prop->length); + + if (prop->name && !rt_strcmp(prop->name, "name")) + { + np->name = prop->value; + } + + prop_off = fdt_next_property_offset(_fdt, prop_off); + + if (prop_off < 0) + { + prop->next = RT_NULL; + break; + } + + prop->next = rt_malloc(sizeof(struct rt_ofw_prop)); + prop = prop->next; + } + + return err; +} + +static rt_err_t fdt_unflatten_single(struct rt_ofw_node *np, int node_off) +{ + int depth = 0; + rt_err_t err = RT_EOK; + struct rt_ofw_node *np_stack[OFW_NODE_MAX_DEPTH], *parent = RT_NULL; + + do { + if (!np) + { + err = -RT_ENOMEM; + break; + } + + np->name = ""; + np->full_name = fdt_get_name(_fdt, node_off, RT_NULL); + np->phandle = fdt_get_phandle(_fdt, node_off); + + if (np->phandle >= OFW_PHANDLE_MIN) + { + if (np->phandle < _phandle_min) + { + _phandle_min = np->phandle; + } + + if (np->phandle > _phandle_max) + { + _phandle_max = np->phandle; + } + } + + if ((err = fdt_unflatten_props(np, node_off))) + { + break; + } + + np->parent = parent; + + rt_ref_init(&np->ref); + np->flags = 0; + + if (!np->child) + { + /* Save node offset temp */ + rt_ofw_data(np) = (void *)(rt_ubase_t)node_off; + + /* Check children */ + node_off = fdt_first_subnode(_fdt, node_off); + + if (node_off >= 0) + { + parent = np; + + np_stack[depth++] = np; + + np->child = rt_calloc(1, sizeof(struct rt_ofw_node)); + np = np->child; + + continue; + } + } + + while (depth >= 0) + { + /* Restore node offset temp */ + node_off = (long)rt_ofw_data(np); + rt_ofw_data(np) = RT_NULL; + + /* Next step */ + node_off = fdt_next_subnode(_fdt, node_off); + + if (node_off < 0) + { + np->sibling = RT_NULL; + + np = np_stack[--depth]; + } + else + { + parent = np->parent; + + np->sibling = rt_calloc(1, sizeof(struct rt_ofw_node)); + np = np->sibling; + + break; + } + } + } while (depth >= 0); + + return err; +} + +struct rt_ofw_node *rt_fdt_unflatten_single(void *fdt) +{ + int root_off; + struct fdt_info *header; + struct rt_ofw_node *root = RT_NULL; + + if (fdt && (root_off = fdt_path_offset(fdt, "/")) >= 0) + { + root = rt_calloc(1, sizeof(struct fdt_info) + sizeof(struct rt_ofw_node)); + } + + if (root) + { + header = (void *)root + sizeof(struct rt_ofw_node); + + rt_strncpy(header->name, "/", sizeof("/")); + + header->fdt = fdt; + + header->rsvmap = (struct fdt_reserve_entry *)((void *)fdt + fdt_off_mem_rsvmap(fdt)); + header->rsvmap_nr = fdt_num_mem_rsv(fdt); + + if (!fdt_unflatten_single(root, root_off)) + { + root->name = (const char *)header; + } + else + { + rt_ofw_node_destroy(root); + + root = RT_NULL; + } + } + + return root; +} diff --git a/components/drivers/ofw/io.c b/components/drivers/ofw/io.c new file mode 100755 index 0000000000..b5d6b58425 --- /dev/null +++ b/components/drivers/ofw/io.c @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#include + +#include +#include +#include +#include + +#define DBG_TAG "rtdm.ofw" +#define DBG_LVL DBG_INFO +#include + +#include "ofw_internal.h" + +static int ofw_bus_addr_cells(struct rt_ofw_node *np) +{ + int res = OFW_ROOT_NODE_ADDR_CELLS_DEFAULT; + + for (rt_uint32_t cells; np; np = np->parent) + { + if (!rt_ofw_prop_read_u32(np, "#address-cells", &cells)) + { + res = cells; + break; + } + } + + return res; +} + +static int ofw_bus_size_cells(struct rt_ofw_node *np) +{ + int res = OFW_ROOT_NODE_SIZE_CELLS_DEFAULT; + + for (rt_uint32_t cells; np; np = np->parent) + { + if (!rt_ofw_prop_read_u32(np, "#size-cells", &cells)) + { + res = cells; + break; + } + } + + return res; +} + +int rt_ofw_bus_addr_cells(struct rt_ofw_node *np) +{ + return np ? ofw_bus_addr_cells(np) : -RT_EINVAL; +} + +int rt_ofw_bus_size_cells(struct rt_ofw_node *np) +{ + return np ? ofw_bus_size_cells(np) : -RT_EINVAL; +} + +int rt_ofw_io_addr_cells(struct rt_ofw_node *np) +{ + return np ? ofw_bus_addr_cells(np->parent ? np->parent : np) : -RT_EINVAL; +} + +int rt_ofw_io_size_cells(struct rt_ofw_node *np) +{ + return np ? ofw_bus_size_cells(np->parent ? np->parent : np) : -RT_EINVAL; +} + +int rt_ofw_get_address_count(struct rt_ofw_node *np) +{ + int count; + + if (np) + { + rt_ssize_t len; + + count = 0; + + if (rt_ofw_get_prop(np, "reg", &len)) + { + count = len / (sizeof(fdt32_t) * (rt_ofw_io_addr_cells(np) + rt_ofw_io_size_cells(np))); + } + } + else + { + count = -RT_EINVAL; + } + + return count; +} + +static rt_err_t ofw_get_address(struct rt_ofw_node *np, int index, rt_uint64_t *out_address, rt_uint64_t *out_size) +{ + rt_ssize_t len; + rt_err_t err = RT_EOK; + int addr_cells = rt_ofw_io_addr_cells(np); + int size_cells = rt_ofw_io_size_cells(np); + int skip_cells = (addr_cells + size_cells) * index; + const fdt32_t *cell = rt_ofw_prop_read_raw(np, "reg", &len); + + if (cell && skip_cells < (len / sizeof(*cell))) + { + cell += skip_cells; + *out_address = rt_fdt_next_cell(&cell, addr_cells); + *out_address = rt_ofw_translate_address(np, RT_NULL, *out_address); + *out_size = rt_fdt_read_number(cell, size_cells); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_ofw_get_address(struct rt_ofw_node *np, int index, rt_uint64_t *out_address, rt_uint64_t *out_size) +{ + rt_err_t err; + + if (np && index >= 0 && (out_address || out_size)) + { + rt_uint64_t address, size; + + err = ofw_get_address(np, index, &address, &size); + + if (!err) + { + if (out_address) + { + *out_address = address; + } + if (out_size) + { + *out_size = size; + } + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +static rt_err_t ofw_get_address_by_name(struct rt_ofw_node *np, const char *name, + rt_uint64_t *out_address, rt_uint64_t *out_size) + +{ + int index = 0; + rt_err_t err = RT_EOK; + const char *reg_name; + struct rt_ofw_prop *prop; + + rt_ofw_foreach_prop_string(np, "reg-names", prop, reg_name) + { + if (!rt_strcmp(name, reg_name)) + { + err = rt_ofw_get_address(np, index, out_address, out_size); + + break; + } + + ++index; + } + + return err; +} + +rt_err_t rt_ofw_get_address_by_name(struct rt_ofw_node *np, const char *name, + rt_uint64_t *out_address, rt_uint64_t *out_size) +{ + rt_err_t err; + + if (np && name && (out_address || out_size)) + { + rt_uint64_t address, size; + + err = ofw_get_address_by_name(np, name, &address, &size); + + if (!err) + { + if (out_address) + { + *out_address = address; + } + if (out_size) + { + *out_size = size; + } + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +int rt_ofw_get_address_array(struct rt_ofw_node *np, int nr, rt_uint64_t *out_regs) +{ + int count; + + if (np && nr > 0 && out_regs) + { + rt_ssize_t len; + int max_nr; + int addr_cells = rt_ofw_io_addr_cells(np); + int size_cells = rt_ofw_io_size_cells(np); + const fdt32_t *cell = rt_ofw_prop_read_raw(np, "reg", &len); + + max_nr = len / (sizeof(*cell) * (addr_cells + size_cells)); + + if (nr > max_nr) + { + nr = max_nr; + } + + count = nr; + + while (nr --> 0) + { + *out_regs = rt_fdt_next_cell(&cell, addr_cells); + *out_regs = rt_ofw_translate_address(np, RT_NULL, *out_regs); + ++out_regs; + + *out_regs = rt_fdt_next_cell(&cell, size_cells); + ++out_regs; + } + } + else + { + count = -RT_EINVAL; + } + + return count; +} + +static struct bus_ranges *ofw_bus_ranges(struct rt_ofw_node *np, struct rt_ofw_prop *prop) +{ + const fdt32_t *cell; + struct bus_ranges *ranges = RT_NULL; + int child_address_cells, child_size_cells, parent_address_cells, groups; + rt_uint64_t *child_addr, *parent_addr, *child_size; + + /* + * Address Translation Example: + * + * / { + * #address-cells = <1>; + * #size-cells = <1>; + * + * soc { + * compatible = "simple-bus"; + * #address-cells = <1>; + * #size-cells = <1>; + * ranges = <0x0 0xe0000000 0x00100000>; + * + * serial@4600 { + * device_type = "serial"; + * reg = <0x4600 0x100>; + * clock-frequency = <0>; + * }; + * }; + * } + * + * The soc node specifies a ranges property of <0x0 0xe0000000 0x00100000>; + * This property value specifies that for a 1024 KB range of address space, a + * child node addressed at physical 0x0 maps to a parent address of physical + * 0xe0000000. With this mapping, the serial device node can be addressed by a + * load or store at address 0xe0004600, an offset of 0x4600 (specified in reg) + * plus the 0xe0000000 mapping specified in ranges: + * + * bus-address = parent-bus-address + (reg-address - child-bus-address) + */ + + do { + child_address_cells = rt_ofw_bus_addr_cells(np); + child_size_cells = rt_ofw_bus_size_cells(np); + parent_address_cells = rt_ofw_io_addr_cells(np); + + if (child_address_cells < 0 || child_size_cells < 0 || parent_address_cells < 0) + { + LOG_D("%s read address/size cells fail: child[%d, %d] parent[%d]", + np->full_name, child_address_cells, child_size_cells, parent_address_cells); + + break; + } + + groups = prop->length / sizeof(*cell); + groups /= child_address_cells + child_size_cells + parent_address_cells; + + ranges = rt_malloc(sizeof(*ranges) + sizeof(rt_uint64_t) * 3 * groups); + + if (!ranges) + { + break; + } + + ranges->nr = groups; + ranges->child_addr = (void *)ranges + sizeof(*ranges); + ranges->parent_addr = &ranges->child_addr[groups]; + ranges->child_size = &ranges->parent_addr[groups]; + + cell = prop->value; + + child_addr = ranges->child_addr; + parent_addr = ranges->parent_addr; + child_size = ranges->child_size; + + while (groups --> 0) + { + *child_addr++ = rt_fdt_next_cell(&cell, child_address_cells); + *parent_addr++ = rt_fdt_next_cell(&cell, parent_address_cells); + *child_size++ = rt_fdt_next_cell(&cell, child_size_cells); + } + + rt_ofw_data(np) = ranges; + } while (0); + + return ranges; +} + +rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address) +{ + rt_uint64_t cpu_addr = address; + + if (!range_type) + { + range_type = "ranges"; + } + + rt_ofw_foreach_parent_node(np) + { + rt_ssize_t len; + struct rt_ofw_prop *prop; + struct bus_ranges *ranges; + + prop = rt_ofw_get_prop(np, range_type, &len); + + if (!prop || !len) + { + continue; + } + + ranges = rt_ofw_data(np); + + if (!ranges) + { + ranges = ofw_bus_ranges(np, prop); + } + + if (ranges) + { + for (int i = 0; i < ranges->nr; ++i) + { + rt_uint64_t child_addr = ranges->child_addr[i]; + rt_uint64_t child_size = ranges->child_size[i]; + + if (address >= child_addr && address < child_addr + child_size) + { + cpu_addr = address + (ranges->parent_addr[i] - child_addr); + + break; + } + } + } + else + { + cpu_addr = ~0ULL; + } + + rt_ofw_node_put(np); + + break; + } + + return cpu_addr; +} + +void *rt_ofw_iomap(struct rt_ofw_node *np, int index) +{ + void *iomem = RT_NULL; + + if (np) + { + rt_uint64_t regs[2]; + + if (!ofw_get_address(np, index, ®s[0], ®s[1])) + { + iomem = rt_ioremap((void *)regs[0], (size_t)regs[1]); + } + } + + return iomem; +} + +void *rt_ofw_iomap_by_name(struct rt_ofw_node *np, const char *name) +{ + void *iomem = RT_NULL; + + if (np) + { + rt_uint64_t regs[2]; + + if (!ofw_get_address_by_name(np, name, ®s[0], ®s[1])) + { + iomem = rt_ioremap((void *)regs[0], (size_t)regs[1]); + } + } + + return iomem; +} diff --git a/components/drivers/ofw/irq.c b/components/drivers/ofw/irq.c new file mode 100755 index 0000000000..f5457453b4 --- /dev/null +++ b/components/drivers/ofw/irq.c @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#include + +#include +#include +#include +#include + +#define DBG_TAG "rtdm.ofw" +#define DBG_LVL DBG_INFO +#include + +#include "ofw_internal.h" + +static int ofw_interrupt_cells(struct rt_ofw_node *np) +{ + int interrupt_cells = -RT_EEMPTY; + + rt_ofw_prop_read_u32(np, "#interrupt-cells", (rt_uint32_t *)&interrupt_cells); + + return interrupt_cells; +} + +int rt_ofw_irq_cells(struct rt_ofw_node *np) +{ + return np ? ofw_interrupt_cells(np) : -RT_EINVAL; +} + +static rt_err_t ofw_parse_irq_map(struct rt_ofw_node *np, struct rt_ofw_cell_args *irq_args) +{ + rt_err_t err = RT_EOK; + rt_phandle ic_phandle = 0; + rt_ssize_t map_len, map_mask_len; + struct rt_ofw_node *ic_np = RT_NULL; + const fdt32_t *addr, *map, *map_mask; + int child_address_cells, child_interrupt_cells; + int parent_address_cells, parent_interrupt_cells; + int addr_cells, pin_cells, icaddr_cells, idx1, idx2, limit; + + /* + * interrupt-map: + * An interrupt-map is a property on a nexus node that bridges one + * interrupt domain with a set of parent interrupt domains and specifies + * how interrupt specifiers in the child domain are mapped to + * their respective parent domains. + * + * The interrupt map is a table where each row is a mapping entry + * consisting of five components: child unit address, child interrupt + * specifier, interrupt-parent, parent unit address, parent interrupt + * specifier. + * + * child unit address + * The unit address of the child node being mapped. The number of + * 32-bit cells required to specify this is described by the + * #address-cells property of the bus node on which the child is + * located. + * + * child interrupt specifier + * The interrupt specifier of the child node being mapped. The number + * of 32-bit cells required to specify this component is described by + * the #interrupt-cells property of this node—the nexus node containing + * the interrupt-map property. + * + * interrupt-parent + * A single value that points to the interrupt parent to + * which the child domain is being mapped. + * + * parent unit address + * The unit address in the domain of the interrupt parent. The number + * of 32-bit cells required to specify this address is described by the + * #address-cells property of the node pointed to by the + * interrupt-parent field. + * + * parent interrupt specifier + * The interrupt specifier in the parent domain. The number of 32-bit + * cells required to specify this component is described by the + * #interrupt-cells property of the node pointed to by the + * interrupt-parent field. + * + * Lookups are performed on the interrupt mapping table by matching a + * unit-address/interrupt specifier pair against the child components in + * the interrupt-map. Because some fields in the unit interrupt specifier + * may not be relevant, a mask is applied before the lookup is done. + * Example: + * + * pic: interrupt-controller@0 { + * interrupt-controller; + * #address-cells = <0>; // icaddr (parent unit address) + * #interrupt-cells = <1>; // icintr (parent interrupt specifier) + * }; + * + * gic: interrupt-controller@1 { + * interrupt-controller; + * #address-cells = <2>; // icaddr (parent unit address) + * #interrupt-cells = <3>; // icintr (parent interrupt specifier) + * }; + * + * pcie { + * #address-cells = <3>; // addr (child unit address) + * #interrupt-cells = <1>; // pin (child interrupt specifier) + * interrupt-parent = <&gic>; + * interrupt-map-mask = <0x1800 0 0 7>; + * interrupt-map = + * // addr pin ic icintr + * <0x0000 0 0 1 &pic 1>, // INTA SOLT 0 + * <0x0000 0 0 2 &pic 2>, // INTB + * <0x0000 0 0 3 &pic 3>, // INTC + * <0x0000 0 0 4 &pic 4>, // INTD + * <0x0800 0 0 1 &pic 2>, // INTA SOLT 1 + * <0x0800 0 0 2 &pic 3>, // INTB + * <0x0800 0 0 3 &pic 4>, // INTC + * <0x0800 0 0 4 &pic 1>, // INTD + * // addr pin ic icaddr icintr + * <0x1000 0 0 1 &gic 0 0 GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, // INTA SOLT 2 + * <0x1000 0 0 2 &gic 0 0 GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, // INTB + * <0x1000 0 0 3 &gic 0 0 GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>, // INTC + * <0x1000 0 0 4 &gic 0 0 GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, // INTD + * <0x1800 0 0 1 &gic 0 0 GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, // INTA SOLT 3 + * <0x1800 0 0 2 &gic 0 0 GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>, // INTB + * <0x1800 0 0 3 &gic 0 0 GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, // INTC + * <0x1800 0 0 4 &gic 0 0 GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; // INTD + * }; + * + * In fact, basically no SoC will be use multi ic to implemented INTx. + * before call ofw_parse_irq_map(np, &args): + * + * args.data = addr; + * args.args_count = 2 or 3; + * args.args[0] = (addr cells); + * args.args[1] = (pin cells); + * args.args[2] = (icaddr cells); + * + * if call with `pcie` in ofw_parse_irq_map(np, &args): + * + * np = &pcie; + * args.data = addr = fdt32_t({ (bus << 16) | (device << 11) | (function << 8), 0, 0, pin }); + * args.args_count = 2; + * args.args[0] = 3; + * args.args[1] = 1; + * + * To perform a lookup of the gic interrupt source number for INTB for IDSEL + * 0x12 (slot 2), function 0x3, the following steps would be performed: + * + * 1.The user addr is value <0x9300 0 0 2>. + * + * 2.The encoding of the address includes the bus number (0x0 << 16), + * device number (0x12 << 11), and function number (0x3 << 8). + * + * 3.The interrupt specifier is 2, which is the encoding for INTB as per + * the PCI binding. + * + * 4.The interrupt-map-mask value <0x1800 0 0 7> is applied, giving a + * result of <0x1000 0 0 2>. + * + * 5.That result is looked up in the interrupt-map table, which maps to the + * parent interrupt specifier . + */ + + do { + err = -RT_EEMPTY; + + if ((child_address_cells = rt_ofw_bus_addr_cells(np)) < 0) + { + LOG_D("%s property %s is undefined", np->full_name, "#address-cells"); + + break; + } + + if ((child_interrupt_cells = ofw_interrupt_cells(np)) < 0) + { + LOG_D("%s property %s is undefined", np->full_name, "#interrupt-cells"); + + break; + } + + if (!(map = rt_ofw_prop_read_raw(np, "interrupt-map", &map_len))) + { + LOG_D("%s property %s is undefined", np->full_name, "interrupt-map"); + + break; + } + + if (!(map_mask = rt_ofw_prop_read_raw(np, "interrupt-map-mask", &map_mask_len))) + { + LOG_D("%s property %s is undefined", np->full_name, "interrupt-map-mask"); + + break; + } + + err = -RT_EINVAL; + + addr = irq_args->data; + addr_cells = irq_args->args[0]; + pin_cells = irq_args->args[1]; + icaddr_cells = irq_args->args_count == 3 ? irq_args->args[2] : 0; + + if (addr_cells > child_address_cells) + { + LOG_D("%s(%d) > %s(%d)", "addr_cells", addr_cells, "child_address_cells", child_address_cells); + + break; + } + + if (pin_cells > child_interrupt_cells) + { + LOG_D("%s(%d) > %s(%d)", "pin_cells", pin_cells, "child_interrupt_cells", child_interrupt_cells); + + break; + } + + err = -RT_ENOENT; + +#define _map_walk_range(_idx, _idx2, _count, ...) \ + for (idx1 = _idx, idx2 = _idx2, limit = idx1 + _count; idx1 < limit __VA_ARGS__; ++idx1, ++idx2) + + _map_walk_range(0, 0, addr_cells) + { + /* Applied addr mask */ + ((fdt32_t *)addr)[idx1] &= map_mask[idx2]; + } + + _map_walk_range(addr_cells, child_address_cells, pin_cells) + { + /* Applied pin mask */ + ((fdt32_t *)addr)[idx1] &= map_mask[idx2]; + } + + while (map_len > 0) + { + rt_bool_t match = RT_TRUE; + + _map_walk_range(0, 0, addr_cells) + { + /* Applied mask */ + if (addr[idx1] != map[idx2]) + { + match = RT_FALSE; + break; + } + } + + _map_walk_range(addr_cells, child_address_cells, pin_cells, && match) + { + /* Applied mask */ + if (addr[idx1] != map[idx2]) + { + match = RT_FALSE; + break; + } + } + + /* Skip addr, pin */ + map += map_mask_len; + + /* IC is different? */ + if (ic_phandle != fdt32_to_cpu(*map)) + { + rt_ofw_node_put(ic_np); + + ic_phandle = fdt32_to_cpu(*map); + ic_np = rt_ofw_find_node_by_phandle(ic_phandle); + + if (!ic_np) + { + LOG_D("%s irq parent phandle = %d is not found", np->full_name, ic_phandle); + + break; + } + + if ((parent_address_cells = rt_ofw_bus_addr_cells(ic_np)) < 0) + { + LOG_D("%s property %s is undefined", ic_np->full_name, "#address-cells"); + + break; + } + + if (icaddr_cells > parent_address_cells) + { + LOG_D("%s(%d) > %s(%d)", "icaddr_cells", icaddr_cells, "parent_address_cells", parent_address_cells); + + break; + } + + if ((parent_interrupt_cells = ofw_interrupt_cells(ic_np)) < 0) + { + LOG_D("%s property %s is undefined", ic_np->full_name, "#interrupt-cells"); + + break; + } + + RT_ASSERT(parent_interrupt_cells <= RT_OFW_MAX_CELL_ARGS); + } + + /* Skip ic phandle */ + ++map; + + _map_walk_range(addr_cells + pin_cells, 0, icaddr_cells, && match) + { + /* Applied ic_addr mask */ + if (addr[idx1] != map[idx2]) + { + match = RT_FALSE; + break; + } + } + + /* Skip icaddr */ + map += parent_address_cells; + + if (match) + { + irq_args->data = ic_np; + irq_args->args_count = parent_interrupt_cells; + + for (int i = 0; i < irq_args->args_count; ++i) + { + irq_args->args[i] = fdt32_to_cpu(*map++); + } + + err = RT_EOK; + + break; + } + + /* Skip icintr */ + map += parent_interrupt_cells; + + map_len -= map_mask_len + 1 + parent_address_cells + parent_interrupt_cells; + } + +#undef _map_walk_range + } while (0); + + return err; +} + +rt_err_t rt_ofw_parse_irq_map(struct rt_ofw_node *np, struct rt_ofw_cell_args *irq_args) +{ + rt_err_t err; + + if (np && irq_args && irq_args->data) + { + err = ofw_parse_irq_map(np, irq_args); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +static rt_err_t ofw_parse_irq_cells(struct rt_ofw_node *np, int index, struct rt_ofw_cell_args *out_irq_args) +{ + rt_err_t err; + + /* + * interrupts-extended: + * + * The interrupts-extended property lists the interrupt(s) generated by a + * device. interrupts-extended should be used instead of interrupts when a + * device is connected to multiple interrupt controllers as it encodes a + * parent phandle with each interrupt specifier. Example: + * + * pic: interrupt-controller@0 { + * interrupt-controller; + * #interrupt-cells = <1>; + * }; + * + * gic: interrupt-controller@1 { + * interrupt-controller; + * #interrupt-cells = <3>; + * }; + * + * node: node { + * interrupts-extended = <&pic 9>, <&gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; + * }; + * + * call `rt_ofw_parse_phandle_cells` to get irq info; + */ + + err = rt_ofw_parse_phandle_cells(np, "interrupts-extended", "#interrupt-cells", index, out_irq_args); + + do { + int interrupt_cells; + const fdt32_t *cell; + rt_ssize_t interrupt_len; + struct rt_ofw_node *ic_np; + + if (!err) + { + break; + } + + /* + * interrupts (old style): + * + * The interrupts property of a device node defines the interrupt or + * interrupts that are generated by the device. The value of the + * interrupts property consists of an arbitrary number of interrupt + * specifiers. The format of an interrupt specifier is defined by the + * binding of the interrupt domain root. + * interrupts is overridden by the interrupts-extended property and + * normally only one or the other should be used. Example: + * + * pic: interrupt-controller@0 { + * interrupt-controller; + * #interrupt-cells = <1>; + * }; + * + * gic: interrupt-controller@1 { + * interrupt-controller; + * #interrupt-cells = <3>; + * }; + * + * node0: node0 { + * interrupt-parent = <&pic>; + * interrupts = <9>; + * }; + * + * node1: node1 { + * interrupt-parent = <&gic>; + * interrupts = ; + * }; + */ + + cell = rt_ofw_prop_read_raw(np, "interrupts", &interrupt_len); + + if (!cell) + { + err = -RT_ERROR; + break; + } + + ic_np = rt_ofw_find_irq_parent(np, &interrupt_cells); + + if (!ic_np) + { + err = -RT_ERROR; + break; + } + + RT_ASSERT(interrupt_cells <= RT_OFW_MAX_CELL_ARGS); + + if (index >= interrupt_len / (interrupt_cells * sizeof(*cell))) + { + err = -RT_EINVAL; + break; + } + + cell += index * interrupt_cells; + + out_irq_args->data = ic_np; + out_irq_args->args_count = interrupt_cells; + + for (int idx = 0; idx < interrupt_cells; ++idx, ++cell) + { + out_irq_args->args[idx] = fdt32_to_cpu(*cell); + } + + err = RT_EOK; + } while (0); + + return err; +} + +rt_err_t rt_ofw_parse_irq_cells(struct rt_ofw_node *np, int index, struct rt_ofw_cell_args *out_irq_args) +{ + rt_err_t err; + + if (np && index >= 0 && out_irq_args) + { + err = ofw_parse_irq_cells(np, index, out_irq_args); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +struct rt_ofw_node *rt_ofw_find_irq_parent(struct rt_ofw_node *np, int *out_interrupt_cells) +{ + rt_ofw_foreach_parent_node(np) + { + rt_phandle ic_phandle; + + if (!rt_ofw_prop_read_u32(np, "interrupt-parent", (rt_uint32_t *)&ic_phandle)) + { + int interrupt_cells; + struct rt_ofw_node *ic_np = rt_ofw_find_node_by_phandle(ic_phandle); + + if (ic_np && (interrupt_cells = ofw_interrupt_cells(ic_np)) >= 0) + { + np = ic_np; + + if (out_interrupt_cells) + { + *out_interrupt_cells = interrupt_cells; + } + + break; + } + + rt_ofw_node_put(ic_np); + } + } + + return np; +} + +static int ofw_map_irq(struct rt_ofw_cell_args *irq_args) +{ + int irq; + struct rt_ofw_node *ic_np = irq_args->data; + struct rt_pic *pic = rt_ofw_data(ic_np); + + /* args.data is "interrupt-controller" */ + if (pic) + { + struct rt_pic_irq pirq; + + if (!pic->ops->irq_parse) + { + LOG_E("Master pic MUST implemented irq_parse"); + RT_ASSERT(0); + } + + if (!pic->ops->irq_map) + { + LOG_E("Master pic MUST implemented irq_map"); + RT_ASSERT(0); + } + + irq = pic->ops->irq_parse(pic, irq_args, &pirq); + + if (!irq) + { + irq = pic->ops->irq_map(pic, pirq.hwirq, pirq.mode); + } + } + else + { + LOG_E("Master pic %s not support", ic_np->full_name); + irq = -RT_EIO; + } + + rt_ofw_node_put(ic_np); + + return irq; +} + +int rt_ofw_map_irq(struct rt_ofw_cell_args *irq_args) +{ + int irq; + + if (irq_args && irq_args->data && irq_args->args_count > 0) + { + irq = ofw_map_irq(irq_args); + } + else + { + irq = -RT_EINVAL; + } + + return irq; +} + +int rt_ofw_get_irq_count(struct rt_ofw_node *np) +{ + int count; + + if (np) + { + struct rt_ofw_cell_args irq_args; + + count = 0; + + while (!ofw_parse_irq_cells(np, count, &irq_args)) + { + ++count; + } + } + else + { + count = -RT_EINVAL; + } + + return count; +} + +int rt_ofw_get_irq(struct rt_ofw_node *np, int index) +{ + int irq; + + if (np && index >= 0) + { + struct rt_ofw_cell_args irq_args; + + irq = ofw_parse_irq_cells(np, index, &irq_args); + + if (irq >= 0) + { + irq = ofw_map_irq(&irq_args); + } + } + else + { + irq = -RT_EINVAL; + } + + return irq; +} + +int rt_ofw_get_irq_by_name(struct rt_ofw_node *np, const char *name) +{ + int irq; + + if (np && name) + { + int index = rt_ofw_prop_index_of_string(np, "interrupt-names", name); + + if (index >= 0) + { + irq = rt_ofw_get_irq(np, index); + } + else + { + irq = -1; + } + } + else + { + irq = -RT_EINVAL; + } + + return irq; +} diff --git a/components/drivers/ofw/libfdt/SConscript b/components/drivers/ofw/libfdt/SConscript new file mode 100644 index 0000000000..fb1fe97f3b --- /dev/null +++ b/components/drivers/ofw/libfdt/SConscript @@ -0,0 +1,10 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + +CPPPATH = [cwd] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/ofw/libfdt/fdt.c b/components/drivers/ofw/libfdt/fdt.c new file mode 100644 index 0000000000..20c6415b9c --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +/* + * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks + * that the given buffer contains what appears to be a flattened + * device tree with sane information in its header. + */ +int32_t fdt_ro_probe_(const void *fdt) +{ + uint32_t totalsize = fdt_totalsize(fdt); + + if (can_assume(VALID_DTB)) + return totalsize; + + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + + if (fdt_magic(fdt) == FDT_MAGIC) { + /* Complete tree */ + if (!can_assume(LATEST)) { + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + if (fdt_last_comp_version(fdt) > + FDT_LAST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + } + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + /* Unfinished sequential-write blob */ + if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0) + return -FDT_ERR_BADSTATE; + } else { + return -FDT_ERR_BADMAGIC; + } + + if (totalsize < INT32_MAX) + return totalsize; + else + return -FDT_ERR_TRUNCATED; +} + +static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off) +{ + return (off >= hdrsize) && (off <= totalsize); +} + +static int check_block_(uint32_t hdrsize, uint32_t totalsize, + uint32_t base, uint32_t size) +{ + if (!check_off_(hdrsize, totalsize, base)) + return 0; /* block start out of bounds */ + if ((base + size) < base) + return 0; /* overflow */ + if (!check_off_(hdrsize, totalsize, base + size)) + return 0; /* block end out of bounds */ + return 1; +} + +size_t fdt_header_size_(uint32_t version) +{ + if (version <= 1) + return FDT_V1_SIZE; + else if (version <= 2) + return FDT_V2_SIZE; + else if (version <= 3) + return FDT_V3_SIZE; + else if (version <= 16) + return FDT_V16_SIZE; + else + return FDT_V17_SIZE; +} + +size_t fdt_header_size(const void *fdt) +{ + return can_assume(LATEST) ? FDT_V17_SIZE : + fdt_header_size_(fdt_version(fdt)); +} + +int fdt_check_header(const void *fdt) +{ + size_t hdrsize; + + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + + if (fdt_magic(fdt) != FDT_MAGIC) + return -FDT_ERR_BADMAGIC; + if (!can_assume(LATEST)) { + if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + || (fdt_last_comp_version(fdt) > + FDT_LAST_SUPPORTED_VERSION)) + return -FDT_ERR_BADVERSION; + if (fdt_version(fdt) < fdt_last_comp_version(fdt)) + return -FDT_ERR_BADVERSION; + } + hdrsize = fdt_header_size(fdt); + if (!can_assume(VALID_DTB)) { + if ((fdt_totalsize(fdt) < hdrsize) + || (fdt_totalsize(fdt) > INT_MAX)) + return -FDT_ERR_TRUNCATED; + + /* Bounds check memrsv block */ + if (!check_off_(hdrsize, fdt_totalsize(fdt), + fdt_off_mem_rsvmap(fdt))) + return -FDT_ERR_TRUNCATED; + + /* Bounds check structure block */ + if (!can_assume(LATEST) && fdt_version(fdt) < 17) { + if (!check_off_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } else { + if (!check_block_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } + + /* Bounds check strings block */ + if (!check_block_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_strings(fdt), + fdt_size_dt_strings(fdt))) + return -FDT_ERR_TRUNCATED; + } + + return 0; +} + +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) +{ + unsigned int uoffset = offset; + unsigned int absoffset = offset + fdt_off_dt_struct(fdt); + + if (offset < 0) + return NULL; + + if (!can_assume(VALID_INPUT)) + if ((absoffset < uoffset) + || ((absoffset + len) < absoffset) + || (absoffset + len) > fdt_totalsize(fdt)) + return NULL; + + if (can_assume(LATEST) || fdt_version(fdt) >= 0x11) + if (((uoffset + len) < uoffset) + || ((offset + len) > fdt_size_dt_struct(fdt))) + return NULL; + + return fdt_offset_ptr_(fdt, offset); +} + +uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) +{ + const fdt32_t *tagp, *lenp; + uint32_t tag, len, sum; + int offset = startoffset; + const char *p; + + *nextoffset = -FDT_ERR_TRUNCATED; + tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); + if (!can_assume(VALID_DTB) && !tagp) + return FDT_END; /* premature end */ + tag = fdt32_to_cpu(*tagp); + offset += FDT_TAGSIZE; + + *nextoffset = -FDT_ERR_BADSTRUCTURE; + switch (tag) { + case FDT_BEGIN_NODE: + /* skip name */ + do { + p = fdt_offset_ptr(fdt, offset++, 1); + } while (p && (*p != '\0')); + if (!can_assume(VALID_DTB) && !p) + return FDT_END; /* premature end */ + break; + + case FDT_PROP: + lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); + if (!can_assume(VALID_DTB) && !lenp) + return FDT_END; /* premature end */ + + len = fdt32_to_cpu(*lenp); + sum = len + offset; + if (!can_assume(VALID_DTB) && + (INT_MAX <= sum || sum < (uint32_t) offset)) + return FDT_END; /* premature end */ + + /* skip-name offset, length and value */ + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len; + + if (!can_assume(LATEST) && + fdt_version(fdt) < 0x10 && len >= 8 && + ((offset - len) % 8) != 0) + offset += 4; + break; + + case FDT_END: + case FDT_END_NODE: + case FDT_NOP: + break; + + default: + return FDT_END; + } + + if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) + return FDT_END; /* premature end */ + + *nextoffset = FDT_TAGALIGN(offset); + return tag; +} + +int fdt_check_node_offset_(const void *fdt, int offset) +{ + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; + + if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int fdt_check_prop_offset_(const void *fdt, int offset) +{ + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; + + if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int fdt_next_node(const void *fdt, int offset, int *depth) +{ + int nextoffset = 0; + uint32_t tag; + + if (offset >= 0) + if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0) + return nextoffset; + + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_PROP: + case FDT_NOP: + break; + + case FDT_BEGIN_NODE: + if (depth) + (*depth)++; + break; + + case FDT_END_NODE: + if (depth && ((--(*depth)) < 0)) + return nextoffset; + break; + + case FDT_END: + if ((nextoffset >= 0) + || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) + return -FDT_ERR_NOTFOUND; + else + return nextoffset; + } + } while (tag != FDT_BEGIN_NODE); + + return offset; +} + +int fdt_first_subnode(const void *fdt, int offset) +{ + int depth = 0; + + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth != 1) + return -FDT_ERR_NOTFOUND; + + return offset; +} + +int fdt_next_subnode(const void *fdt, int offset) +{ + int depth = 1; + + /* + * With respect to the parent, the depth of the next subnode will be + * the same as the last. + */ + do { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth < 1) + return -FDT_ERR_NOTFOUND; + } while (depth > 1); + + return offset; +} + +const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) +{ + int len = strlen(s) + 1; + const char *last = strtab + tabsize - len; + const char *p; + + for (p = strtab; p <= last; p++) + if (memcmp(p, s, len) == 0) + return p; + return NULL; +} + +int fdt_move(const void *fdt, void *buf, int bufsize) +{ + if (!can_assume(VALID_INPUT) && bufsize < 0) + return -FDT_ERR_NOSPACE; + + FDT_RO_PROBE(fdt); + + if (fdt_totalsize(fdt) > (unsigned int)bufsize) + return -FDT_ERR_NOSPACE; + + memmove(buf, fdt, fdt_totalsize(fdt)); + return 0; +} diff --git a/components/drivers/ofw/libfdt/fdt.h b/components/drivers/ofw/libfdt/fdt.h new file mode 100644 index 0000000000..0c91aa7f67 --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +#ifndef FDT_H +#define FDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2012 Kim Phillips, Freescale Semiconductor. + */ + +#ifndef __ASSEMBLY__ + +struct fdt_header { + fdt32_t magic; /* magic word FDT_MAGIC */ + fdt32_t totalsize; /* total size of DT block */ + fdt32_t off_dt_struct; /* offset to structure */ + fdt32_t off_dt_strings; /* offset to strings */ + fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ + fdt32_t version; /* format version */ + fdt32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + fdt32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + fdt32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + fdt32_t size_dt_struct; /* size of the structure block */ +}; + +struct fdt_reserve_entry { + fdt64_t address; + fdt64_t size; +}; + +struct fdt_node_header { + fdt32_t tag; + char name[]; +}; + +struct fdt_property { + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; + char data[]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ +#define FDT_TAGSIZE sizeof(fdt32_t) + +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, + size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 + +#define FDT_V1_SIZE (7*sizeof(fdt32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) +#define FDT_V16_SIZE FDT_V3_SIZE +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) + +#endif /* FDT_H */ diff --git a/components/drivers/ofw/libfdt/fdt_addresses.c b/components/drivers/ofw/libfdt/fdt_addresses.c new file mode 100644 index 0000000000..c40ba094f1 --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt_addresses.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2014 David Gibson + * Copyright (C) 2018 embedded brains GmbH + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int fdt_cells(const void *fdt, int nodeoffset, const char *name) +{ + const fdt32_t *c; + uint32_t val; + int len; + + c = fdt_getprop(fdt, nodeoffset, name, &len); + if (!c) + return len; + + if (len != sizeof(*c)) + return -FDT_ERR_BADNCELLS; + + val = fdt32_to_cpu(*c); + if (val > FDT_MAX_NCELLS) + return -FDT_ERR_BADNCELLS; + + return (int)val; +} + +int fdt_address_cells(const void *fdt, int nodeoffset) +{ + int val; + + val = fdt_cells(fdt, nodeoffset, "#address-cells"); + if (val == 0) + return -FDT_ERR_BADNCELLS; + if (val == -FDT_ERR_NOTFOUND) + return 2; + return val; +} + +int fdt_size_cells(const void *fdt, int nodeoffset) +{ + int val; + + val = fdt_cells(fdt, nodeoffset, "#size-cells"); + if (val == -FDT_ERR_NOTFOUND) + return 1; + return val; +} + +/* This function assumes that [address|size]_cells is 1 or 2 */ +int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, + const char *name, uint64_t addr, uint64_t size) +{ + int addr_cells, size_cells, ret; + uint8_t data[sizeof(fdt64_t) * 2], *prop; + + ret = fdt_address_cells(fdt, parent); + if (ret < 0) + return ret; + addr_cells = ret; + + ret = fdt_size_cells(fdt, parent); + if (ret < 0) + return ret; + size_cells = ret; + + /* check validity of address */ + prop = data; + if (addr_cells == 1) { + if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) + return -FDT_ERR_BADVALUE; + + fdt32_st(prop, (uint32_t)addr); + } else if (addr_cells == 2) { + fdt64_st(prop, addr); + } else { + return -FDT_ERR_BADNCELLS; + } + + /* check validity of size */ + prop += addr_cells * sizeof(fdt32_t); + if (size_cells == 1) { + if (size > UINT32_MAX) + return -FDT_ERR_BADVALUE; + + fdt32_st(prop, (uint32_t)size); + } else if (size_cells == 2) { + fdt64_st(prop, size); + } else { + return -FDT_ERR_BADNCELLS; + } + + return fdt_appendprop(fdt, nodeoffset, name, data, + (addr_cells + size_cells) * sizeof(fdt32_t)); +} diff --git a/components/drivers/ofw/libfdt/fdt_empty_tree.c b/components/drivers/ofw/libfdt/fdt_empty_tree.c new file mode 100644 index 0000000000..49d54d44b8 --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt_empty_tree.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2012 David Gibson, IBM Corporation. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_create_empty_tree(void *buf, int bufsize) +{ + int err; + + err = fdt_create(buf, bufsize); + if (err) + return err; + + err = fdt_finish_reservemap(buf); + if (err) + return err; + + err = fdt_begin_node(buf, ""); + if (err) + return err; + + err = fdt_end_node(buf); + if (err) + return err; + + err = fdt_finish(buf); + if (err) + return err; + + return fdt_open_into(buf, buf, bufsize); +} diff --git a/components/drivers/ofw/libfdt/fdt_overlay.c b/components/drivers/ofw/libfdt/fdt_overlay.c new file mode 100644 index 0000000000..5c0c3981b8 --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt_overlay.c @@ -0,0 +1,867 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2016 Free Electrons + * Copyright (C) 2016 NextThing Co. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +/** + * overlay_get_target_phandle - retrieves the target phandle of a fragment + * @fdto: pointer to the device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * + * overlay_get_target_phandle() retrieves the target phandle of an + * overlay fragment when that fragment uses a phandle (target + * property) instead of a path (target-path property). + * + * returns: + * the phandle pointed by the target property + * 0, if the phandle was not found + * -1, if the phandle was malformed + */ +static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) +{ + const fdt32_t *val; + int len; + + val = fdt_getprop(fdto, fragment, "target", &len); + if (!val) + return 0; + + if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) + return (uint32_t)-1; + + return fdt32_to_cpu(*val); +} + +int fdt_overlay_target_offset(const void *fdt, const void *fdto, + int fragment_offset, char const **pathp) +{ + uint32_t phandle; + const char *path = NULL; + int path_len = 0, ret; + + /* Try first to do a phandle based lookup */ + phandle = overlay_get_target_phandle(fdto, fragment_offset); + if (phandle == (uint32_t)-1) + return -FDT_ERR_BADPHANDLE; + + /* no phandle, try path */ + if (!phandle) { + /* And then a path based lookup */ + path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len); + if (path) + ret = fdt_path_offset(fdt, path); + else + ret = path_len; + } else + ret = fdt_node_offset_by_phandle(fdt, phandle); + + /* + * If we haven't found either a target or a + * target-path property in a node that contains a + * __overlay__ subnode (we wouldn't be called + * otherwise), consider it a improperly written + * overlay + */ + if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) + ret = -FDT_ERR_BADOVERLAY; + + /* return on error */ + if (ret < 0) + return ret; + + /* return pointer to path (if available) */ + if (pathp) + *pathp = path ? path : NULL; + + return ret; +} + +/** + * overlay_phandle_add_offset - Increases a phandle by an offset + * @fdt: Base device tree blob + * @node: Device tree overlay blob + * @name: Name of the property to modify (phandle or linux,phandle) + * @delta: offset to apply + * + * overlay_phandle_add_offset() increments a node phandle by a given + * offset. + * + * returns: + * 0 on success. + * Negative error code on error + */ +static int overlay_phandle_add_offset(void *fdt, int node, + const char *name, uint32_t delta) +{ + const fdt32_t *val; + uint32_t adj_val; + int len; + + val = fdt_getprop(fdt, node, name, &len); + if (!val) + return len; + + if (len != sizeof(*val)) + return -FDT_ERR_BADPHANDLE; + + adj_val = fdt32_to_cpu(*val); + if ((adj_val + delta) < adj_val) + return -FDT_ERR_NOPHANDLES; + + adj_val += delta; + if (adj_val == (uint32_t)-1) + return -FDT_ERR_NOPHANDLES; + + return fdt_setprop_inplace_u32(fdt, node, name, adj_val); +} + +/** + * overlay_adjust_node_phandles - Offsets the phandles of a node + * @fdto: Device tree overlay blob + * @node: Offset of the node we want to adjust + * @delta: Offset to shift the phandles of + * + * overlay_adjust_node_phandles() adds a constant to all the phandles + * of a given node. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_node_phandles(void *fdto, int node, + uint32_t delta) +{ + int child; + int ret; + + ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + fdt_for_each_subnode(child, fdto, node) { + ret = overlay_adjust_node_phandles(fdto, child, delta); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_adjust_local_phandles() adds a constant to all the + * phandles of an overlay. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) +{ + /* + * Start adjusting the phandles from the overlay root + */ + return overlay_adjust_node_phandles(fdto, 0, delta); +} + +/** + * overlay_update_local_node_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @tree_node: Node offset of the node to operate on + * @fixup_node: Node offset of the matching local fixups node + * @delta: Offset to shift the phandles of + * + * overlay_update_local_nodes_references() update the phandles + * pointing to a node within the device tree overlay by adding a + * constant delta. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_node_references(void *fdto, + int tree_node, + int fixup_node, + uint32_t delta) +{ + int fixup_prop; + int fixup_child; + int ret; + + fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { + const fdt32_t *fixup_val; + const char *tree_val; + const char *name; + int fixup_len; + int tree_len; + int i; + + fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, + &name, &fixup_len); + if (!fixup_val) + return fixup_len; + + if (fixup_len % sizeof(uint32_t)) + return -FDT_ERR_BADOVERLAY; + fixup_len /= sizeof(uint32_t); + + tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); + if (!tree_val) { + if (tree_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + + return tree_len; + } + + for (i = 0; i < fixup_len; i++) { + fdt32_t adj_val; + uint32_t poffset; + + poffset = fdt32_to_cpu(fixup_val[i]); + + /* + * phandles to fixup can be unaligned. + * + * Use a memcpy for the architectures that do + * not support unaligned accesses. + */ + memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); + + adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); + + ret = fdt_setprop_inplace_namelen_partial(fdto, + tree_node, + name, + strlen(name), + poffset, + &adj_val, + sizeof(adj_val)); + if (ret == -FDT_ERR_NOSPACE) + return -FDT_ERR_BADOVERLAY; + + if (ret) + return ret; + } + } + + fdt_for_each_subnode(fixup_child, fdto, fixup_node) { + const char *fixup_child_name = fdt_get_name(fdto, fixup_child, + NULL); + int tree_child; + + tree_child = fdt_subnode_offset(fdto, tree_node, + fixup_child_name); + if (tree_child == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (tree_child < 0) + return tree_child; + + ret = overlay_update_local_node_references(fdto, + tree_child, + fixup_child, + delta); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_update_local_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_update_local_references() update all the phandles pointing + * to a node within the device tree overlay by adding a constant + * delta to not conflict with the base overlay. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_references(void *fdto, uint32_t delta) +{ + int fixups; + + fixups = fdt_path_offset(fdto, "/__local_fixups__"); + if (fixups < 0) { + /* There's no local phandles to adjust, bail out */ + if (fixups == -FDT_ERR_NOTFOUND) + return 0; + + return fixups; + } + + /* + * Update our local references from the root of the tree + */ + return overlay_update_local_node_references(fdto, 0, fixups, + delta); +} + +/** + * overlay_fixup_one_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @path: Path to a node holding a phandle in the overlay + * @path_len: number of path characters to consider + * @name: Name of the property holding the phandle reference in the overlay + * @name_len: number of name characters to consider + * @poffset: Offset within the overlay property where the phandle is stored + * @label: Label of the node referenced by the phandle + * + * overlay_fixup_one_phandle() resolves an overlay phandle pointing to + * a node in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_one_phandle(void *fdt, void *fdto, + int symbols_off, + const char *path, uint32_t path_len, + const char *name, uint32_t name_len, + int poffset, const char *label) +{ + const char *symbol_path; + uint32_t phandle; + fdt32_t phandle_prop; + int symbol_off, fixup_off; + int prop_len; + + if (symbols_off < 0) + return symbols_off; + + symbol_path = fdt_getprop(fdt, symbols_off, label, + &prop_len); + if (!symbol_path) + return prop_len; + + symbol_off = fdt_path_offset(fdt, symbol_path); + if (symbol_off < 0) + return symbol_off; + + phandle = fdt_get_phandle(fdt, symbol_off); + if (!phandle) + return -FDT_ERR_NOTFOUND; + + fixup_off = fdt_path_offset_namelen(fdto, path, path_len); + if (fixup_off == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (fixup_off < 0) + return fixup_off; + + phandle_prop = cpu_to_fdt32(phandle); + return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, + name, name_len, poffset, + &phandle_prop, + sizeof(phandle_prop)); +}; + +/** + * overlay_fixup_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @property: Property offset in the overlay holding the list of fixups + * + * overlay_fixup_phandle() resolves all the overlay phandles pointed + * to in a __fixups__ property, and updates them to match the phandles + * in use in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, + int property) +{ + const char *value; + const char *label; + int len; + + value = fdt_getprop_by_offset(fdto, property, + &label, &len); + if (!value) { + if (len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + + return len; + } + + do { + const char *path, *name, *fixup_end; + const char *fixup_str = value; + uint32_t path_len, name_len; + uint32_t fixup_len; + char *sep, *endptr; + int poffset, ret; + + fixup_end = memchr(value, '\0', len); + if (!fixup_end) + return -FDT_ERR_BADOVERLAY; + fixup_len = fixup_end - fixup_str; + + len -= fixup_len + 1; + value += fixup_len + 1; + + path = fixup_str; + sep = memchr(fixup_str, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + path_len = sep - path; + if (path_len == (fixup_len - 1)) + return -FDT_ERR_BADOVERLAY; + + fixup_len -= path_len + 1; + name = sep + 1; + sep = memchr(name, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + name_len = sep - name; + if (!name_len) + return -FDT_ERR_BADOVERLAY; + + poffset = strtoul(sep + 1, &endptr, 10); + if ((*endptr != '\0') || (endptr <= (sep + 1))) + return -FDT_ERR_BADOVERLAY; + + ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, + path, path_len, name, name_len, + poffset, label); + if (ret) + return ret; + } while (len > 0); + + return 0; +} + +/** + * overlay_fixup_phandles - Resolve the overlay phandles to the base + * device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_fixup_phandles() resolves all the overlay phandles pointing + * to nodes in the base device tree. + * + * This is one of the steps of the device tree overlay application + * process, when you want all the phandles in the overlay to point to + * the actual base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandles(void *fdt, void *fdto) +{ + int fixups_off, symbols_off; + int property; + + /* We can have overlays without any fixups */ + fixups_off = fdt_path_offset(fdto, "/__fixups__"); + if (fixups_off == -FDT_ERR_NOTFOUND) + return 0; /* nothing to do */ + if (fixups_off < 0) + return fixups_off; + + /* And base DTs without symbols */ + symbols_off = fdt_path_offset(fdt, "/__symbols__"); + if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) + return symbols_off; + + fdt_for_each_property_offset(property, fdto, fixups_off) { + int ret; + + ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_apply_node - Merges a node into the base device tree + * @fdt: Base Device Tree blob + * @target: Node offset in the base device tree to apply the fragment to + * @fdto: Device tree overlay blob + * @node: Node offset in the overlay holding the changes to merge + * + * overlay_apply_node() merges a node into a target base device tree + * node pointed. + * + * This is part of the final step in the device tree overlay + * application process, when all the phandles have been adjusted and + * resolved and you just have to merge overlay into the base device + * tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_apply_node(void *fdt, int target, + void *fdto, int node) +{ + int property; + int subnode; + + fdt_for_each_property_offset(property, fdto, node) { + const char *name; + const void *prop; + int prop_len; + int ret; + + prop = fdt_getprop_by_offset(fdto, property, &name, + &prop_len); + if (prop_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + if (prop_len < 0) + return prop_len; + + ret = fdt_setprop(fdt, target, name, prop, prop_len); + if (ret) + return ret; + } + + fdt_for_each_subnode(subnode, fdto, node) { + const char *name = fdt_get_name(fdto, subnode, NULL); + int nnode; + int ret; + + nnode = fdt_add_subnode(fdt, target, name); + if (nnode == -FDT_ERR_EXISTS) { + nnode = fdt_subnode_offset(fdt, target, name); + if (nnode == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + } + + if (nnode < 0) + return nnode; + + ret = overlay_apply_node(fdt, nnode, fdto, subnode); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_merge - Merge an overlay into its base device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_merge() merges an overlay into its base device tree. + * + * This is the next to last step in the device tree overlay application + * process, when all the phandles have been adjusted and resolved and + * you just have to merge overlay into the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_merge(void *fdt, void *fdto) +{ + int fragment; + + fdt_for_each_subnode(fragment, fdto, 0) { + int overlay; + int target; + int ret; + + /* + * Each fragments will have an __overlay__ node. If + * they don't, it's not supposed to be merged + */ + overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (overlay == -FDT_ERR_NOTFOUND) + continue; + + if (overlay < 0) + return overlay; + + target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); + if (target < 0) + return target; + + ret = overlay_apply_node(fdt, target, fdto, overlay); + if (ret) + return ret; + } + + return 0; +} + +static int get_path_len(const void *fdt, int nodeoffset) +{ + int len = 0, namelen; + const char *name; + + FDT_RO_PROBE(fdt); + + for (;;) { + name = fdt_get_name(fdt, nodeoffset, &namelen); + if (!name) + return namelen; + + /* root? we're done */ + if (namelen == 0) + break; + + nodeoffset = fdt_parent_offset(fdt, nodeoffset); + if (nodeoffset < 0) + return nodeoffset; + len += namelen + 1; + } + + /* in case of root pretend it's "/" */ + if (len == 0) + len++; + return len; +} + +/** + * overlay_symbol_update - Update the symbols of base tree after a merge + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_symbol_update() updates the symbols of the base tree with the + * symbols of the applied overlay + * + * This is the last step in the device tree overlay application + * process, allowing the reference of overlay symbols by subsequent + * overlay operations. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_symbol_update(void *fdt, void *fdto) +{ + int root_sym, ov_sym, prop, path_len, fragment, target; + int len, frag_name_len, ret, rel_path_len; + const char *s, *e; + const char *path; + const char *name; + const char *frag_name; + const char *rel_path; + const char *target_path; + char *buf; + void *p; + + ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); + + /* if no overlay symbols exist no problem */ + if (ov_sym < 0) + return 0; + + root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); + + /* it no root symbols exist we should create them */ + if (root_sym == -FDT_ERR_NOTFOUND) + root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); + + /* any error is fatal now */ + if (root_sym < 0) + return root_sym; + + /* iterate over each overlay symbol */ + fdt_for_each_property_offset(prop, fdto, ov_sym) { + path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); + if (!path) + return path_len; + + /* verify it's a string property (terminated by a single \0) */ + if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) + return -FDT_ERR_BADVALUE; + + /* keep end marker to avoid strlen() */ + e = path + path_len; + + if (*path != '/') + return -FDT_ERR_BADVALUE; + + /* get fragment name first */ + s = strchr(path + 1, '/'); + if (!s) { + /* Symbol refers to something that won't end + * up in the target tree */ + continue; + } + + frag_name = path + 1; + frag_name_len = s - path - 1; + + /* verify format; safe since "s" lies in \0 terminated prop */ + len = sizeof("/__overlay__/") - 1; + if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { + /* //__overlay__/ */ + rel_path = s + len; + rel_path_len = e - rel_path - 1; + } else if ((e - s) == len + && (memcmp(s, "/__overlay__", len - 1) == 0)) { + /* //__overlay__ */ + rel_path = ""; + rel_path_len = 0; + } else { + /* Symbol refers to something that won't end + * up in the target tree */ + continue; + } + + /* find the fragment index in which the symbol lies */ + ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, + frag_name_len); + /* not found? */ + if (ret < 0) + return -FDT_ERR_BADOVERLAY; + fragment = ret; + + /* an __overlay__ subnode must exist */ + ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (ret < 0) + return -FDT_ERR_BADOVERLAY; + + /* get the target of the fragment */ + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); + if (ret < 0) + return ret; + target = ret; + + /* if we have a target path use */ + if (!target_path) { + ret = get_path_len(fdt, target); + if (ret < 0) + return ret; + len = ret; + } else { + len = strlen(target_path); + } + + ret = fdt_setprop_placeholder(fdt, root_sym, name, + len + (len > 1) + rel_path_len + 1, &p); + if (ret < 0) + return ret; + + if (!target_path) { + /* again in case setprop_placeholder changed it */ + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); + if (ret < 0) + return ret; + target = ret; + } + + buf = p; + if (len > 1) { /* target is not root */ + if (!target_path) { + ret = fdt_get_path(fdt, target, buf, len + 1); + if (ret < 0) + return ret; + } else + memcpy(buf, target_path, len + 1); + + } else + len--; + + buf[len] = '/'; + memcpy(buf + len + 1, rel_path, rel_path_len); + buf[len + 1 + rel_path_len] = '\0'; + } + + return 0; +} + +int fdt_overlay_apply(void *fdt, void *fdto) +{ + uint32_t delta; + int ret; + + FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdto); + + ret = fdt_find_max_phandle(fdt, &delta); + if (ret) + goto err; + + ret = overlay_adjust_local_phandles(fdto, delta); + if (ret) + goto err; + + ret = overlay_update_local_references(fdto, delta); + if (ret) + goto err; + + ret = overlay_fixup_phandles(fdt, fdto); + if (ret) + goto err; + + ret = overlay_merge(fdt, fdto); + if (ret) + goto err; + + ret = overlay_symbol_update(fdt, fdto); + if (ret) + goto err; + + /* + * The overlay has been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + return 0; + +err: + /* + * The overlay might have been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + /* + * The base device tree might have been damaged, erase its + * magic. + */ + fdt_set_magic(fdt, ~0); + + return ret; +} diff --git a/components/drivers/ofw/libfdt/fdt_ro.c b/components/drivers/ofw/libfdt/fdt_ro.c new file mode 100644 index 0000000000..9f6c551a22 --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt_ro.c @@ -0,0 +1,859 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int fdt_nodename_eq_(const void *fdt, int offset, + const char *s, int len) +{ + int olen; + const char *p = fdt_get_name(fdt, offset, &olen); + + if (!p || olen < len) + /* short match */ + return 0; + + if (memcmp(p, s, len) != 0) + return 0; + + if (p[len] == '\0') + return 1; + else if (!memchr(s, '@', len) && (p[len] == '@')) + return 1; + else + return 0; +} + +const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) +{ + int32_t totalsize; + uint32_t absoffset; + size_t len; + int err; + const char *s, *n; + + if (can_assume(VALID_INPUT)) { + s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; + + if (lenp) + *lenp = strlen(s); + return s; + } + totalsize = fdt_ro_probe_(fdt); + err = totalsize; + if (totalsize < 0) + goto fail; + + err = -FDT_ERR_BADOFFSET; + absoffset = stroffset + fdt_off_dt_strings(fdt); + if (absoffset >= (unsigned)totalsize) + goto fail; + len = totalsize - absoffset; + + if (fdt_magic(fdt) == FDT_MAGIC) { + if (stroffset < 0) + goto fail; + if (can_assume(LATEST) || fdt_version(fdt) >= 17) { + if ((unsigned)stroffset >= fdt_size_dt_strings(fdt)) + goto fail; + if ((fdt_size_dt_strings(fdt) - stroffset) < len) + len = fdt_size_dt_strings(fdt) - stroffset; + } + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + unsigned int sw_stroffset = -stroffset; + + if ((stroffset >= 0) || + (sw_stroffset > fdt_size_dt_strings(fdt))) + goto fail; + if (sw_stroffset < len) + len = sw_stroffset; + } else { + err = -FDT_ERR_INTERNAL; + goto fail; + } + + s = (const char *)fdt + absoffset; + n = memchr(s, '\0', len); + if (!n) { + /* missing terminating NULL */ + err = -FDT_ERR_TRUNCATED; + goto fail; + } + + if (lenp) + *lenp = n - s; + return s; + +fail: + if (lenp) + *lenp = err; + return NULL; +} + +const char *fdt_string(const void *fdt, int stroffset) +{ + return fdt_get_string(fdt, stroffset, NULL); +} + +static int fdt_string_eq_(const void *fdt, int stroffset, + const char *s, int len) +{ + int slen; + const char *p = fdt_get_string(fdt, stroffset, &slen); + + return p && (slen == len) && (memcmp(p, s, len) == 0); +} + +int fdt_find_max_phandle(const void *fdt, uint32_t *phandle) +{ + uint32_t max = 0; + int offset = -1; + + while (true) { + uint32_t value; + + offset = fdt_next_node(fdt, offset, NULL); + if (offset < 0) { + if (offset == -FDT_ERR_NOTFOUND) + break; + + return offset; + } + + value = fdt_get_phandle(fdt, offset); + + if (value > max) + max = value; + } + + if (phandle) + *phandle = max; + + return 0; +} + +int fdt_generate_phandle(const void *fdt, uint32_t *phandle) +{ + uint32_t max; + int err; + + err = fdt_find_max_phandle(fdt, &max); + if (err < 0) + return err; + + if (max == FDT_MAX_PHANDLE) + return -FDT_ERR_NOPHANDLES; + + if (phandle) + *phandle = max + 1; + + return 0; +} + +static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) +{ + unsigned int offset = n * sizeof(struct fdt_reserve_entry); + unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset; + + if (!can_assume(VALID_INPUT)) { + if (absoffset < fdt_off_mem_rsvmap(fdt)) + return NULL; + if (absoffset > fdt_totalsize(fdt) - + sizeof(struct fdt_reserve_entry)) + return NULL; + } + return fdt_mem_rsv_(fdt, n); +} + +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) +{ + const struct fdt_reserve_entry *re; + + FDT_RO_PROBE(fdt); + re = fdt_mem_rsv(fdt, n); + if (!can_assume(VALID_INPUT) && !re) + return -FDT_ERR_BADOFFSET; + + *address = fdt64_ld_(&re->address); + *size = fdt64_ld_(&re->size); + return 0; +} + +int fdt_num_mem_rsv(const void *fdt) +{ + int i; + const struct fdt_reserve_entry *re; + + for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { + if (fdt64_ld_(&re->size) == 0) + return i; + } + return -FDT_ERR_TRUNCATED; +} + +static int nextprop_(const void *fdt, int offset) +{ + uint32_t tag; + int nextoffset; + + do { + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_END: + if (nextoffset >= 0) + return -FDT_ERR_BADSTRUCTURE; + else + return nextoffset; + + case FDT_PROP: + return offset; + } + offset = nextoffset; + } while (tag == FDT_NOP); + + return -FDT_ERR_NOTFOUND; +} + +int fdt_subnode_offset_namelen(const void *fdt, int offset, + const char *name, int namelen) +{ + int depth; + + FDT_RO_PROBE(fdt); + + for (depth = 0; + (offset >= 0) && (depth >= 0); + offset = fdt_next_node(fdt, offset, &depth)) + if ((depth == 1) + && fdt_nodename_eq_(fdt, offset, name, namelen)) + return offset; + + if (depth < 0) + return -FDT_ERR_NOTFOUND; + return offset; /* error */ +} + +int fdt_subnode_offset(const void *fdt, int parentoffset, + const char *name) +{ + return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) +{ + const char *end = path + namelen; + const char *p = path; + int offset = 0; + + FDT_RO_PROBE(fdt); + + /* see if we have an alias */ + if (*path != '/') { + const char *q = memchr(path, '/', end - p); + + if (!q) + q = end; + + p = fdt_get_alias_namelen(fdt, p, q - p); + if (!p) + return -FDT_ERR_BADPATH; + offset = fdt_path_offset(fdt, p); + + p = q; + } + + while (p < end) { + const char *q; + + while (*p == '/') { + p++; + if (p == end) + return offset; + } + q = memchr(p, '/', end - p); + if (! q) + q = end; + + offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); + if (offset < 0) + return offset; + + p = q; + } + + return offset; +} + +int fdt_path_offset(const void *fdt, const char *path) +{ + return fdt_path_offset_namelen(fdt, path, strlen(path)); +} + +const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) +{ + const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset); + const char *nameptr; + int err; + + if (((err = fdt_ro_probe_(fdt)) < 0) + || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) + goto fail; + + nameptr = nh->name; + + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { + /* + * For old FDT versions, match the naming conventions of V16: + * give only the leaf name (after all /). The actual tree + * contents are loosely checked. + */ + const char *leaf; + leaf = strrchr(nameptr, '/'); + if (leaf == NULL) { + err = -FDT_ERR_BADSTRUCTURE; + goto fail; + } + nameptr = leaf+1; + } + + if (len) + *len = strlen(nameptr); + + return nameptr; + + fail: + if (len) + *len = err; + return NULL; +} + +int fdt_first_property_offset(const void *fdt, int nodeoffset) +{ + int offset; + + if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) + return offset; + + return nextprop_(fdt, offset); +} + +int fdt_next_property_offset(const void *fdt, int offset) +{ + if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) + return offset; + + return nextprop_(fdt, offset); +} + +static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, + int offset, + int *lenp) +{ + int err; + const struct fdt_property *prop; + + if (!can_assume(VALID_INPUT) && + (err = fdt_check_prop_offset_(fdt, offset)) < 0) { + if (lenp) + *lenp = err; + return NULL; + } + + prop = fdt_offset_ptr_(fdt, offset); + + if (lenp) + *lenp = fdt32_ld_(&prop->len); + + return prop; +} + +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp) +{ + /* Prior to version 16, properties may need realignment + * and this API does not work. fdt_getprop_*() will, however. */ + + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { + if (lenp) + *lenp = -FDT_ERR_BADVERSION; + return NULL; + } + + return fdt_get_property_by_offset_(fdt, offset, lenp); +} + +static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, + int offset, + const char *name, + int namelen, + int *lenp, + int *poffset) +{ + for (offset = fdt_first_property_offset(fdt, offset); + (offset >= 0); + (offset = fdt_next_property_offset(fdt, offset))) { + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset_(fdt, offset, lenp); + if (!can_assume(LIBFDT_FLAWLESS) && !prop) { + offset = -FDT_ERR_INTERNAL; + break; + } + if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff), + name, namelen)) { + if (poffset) + *poffset = offset; + return prop; + } + } + + if (lenp) + *lenp = offset; + return NULL; +} + + +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int offset, + const char *name, + int namelen, int *lenp) +{ + /* Prior to version 16, properties may need realignment + * and this API does not work. fdt_getprop_*() will, however. */ + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { + if (lenp) + *lenp = -FDT_ERR_BADVERSION; + return NULL; + } + + return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp, + NULL); +} + + +const struct fdt_property *fdt_get_property(const void *fdt, + int nodeoffset, + const char *name, int *lenp) +{ + return fdt_get_property_namelen(fdt, nodeoffset, name, + strlen(name), lenp); +} + +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp) +{ + int poffset; + const struct fdt_property *prop; + + prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, + &poffset); + if (!prop) + return NULL; + + /* Handle realignment */ + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && + (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) + return prop->data + 4; + return prop->data; +} + +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset_(fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) { + const char *name; + int namelen; + + if (!can_assume(VALID_INPUT)) { + name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff), + &namelen); + *namep = name; + if (!name) { + if (lenp) + *lenp = namelen; + return NULL; + } + } else { + *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff)); + } + } + + /* Handle realignment */ + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && + (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) + return prop->data + 4; + return prop->data; +} + +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); +} + +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) +{ + const fdt32_t *php; + int len; + + /* FIXME: This is a bit sub-optimal, since we potentially scan + * over all the properties twice. */ + php = fdt_getprop(fdt, nodeoffset, "phandle", &len); + if (!php || (len != sizeof(*php))) { + php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); + if (!php || (len != sizeof(*php))) + return 0; + } + + return fdt32_ld_(php); +} + +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen) +{ + int aliasoffset; + + aliasoffset = fdt_path_offset(fdt, "/aliases"); + if (aliasoffset < 0) + return NULL; + + return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); +} + +const char *fdt_get_alias(const void *fdt, const char *name) +{ + return fdt_get_alias_namelen(fdt, name, strlen(name)); +} + +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) +{ + int pdepth = 0, p = 0; + int offset, depth, namelen; + const char *name; + + FDT_RO_PROBE(fdt); + + if (buflen < 2) + return -FDT_ERR_NOSPACE; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + while (pdepth > depth) { + do { + p--; + } while (buf[p-1] != '/'); + pdepth--; + } + + if (pdepth >= depth) { + name = fdt_get_name(fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) { + memcpy(buf + p, name, namelen); + p += namelen; + buf[p++] = '/'; + pdepth++; + } + } + + if (offset == nodeoffset) { + if (pdepth < (depth + 1)) + return -FDT_ERR_NOSPACE; + + if (p > 1) /* special case so that root path is "/", not "" */ + p--; + buf[p] = '\0'; + return 0; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth) +{ + int offset, depth; + int supernodeoffset = -FDT_ERR_INTERNAL; + + FDT_RO_PROBE(fdt); + + if (supernodedepth < 0) + return -FDT_ERR_NOTFOUND; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + if (depth == supernodedepth) + supernodeoffset = offset; + + if (offset == nodeoffset) { + if (nodedepth) + *nodedepth = depth; + + if (supernodedepth > depth) + return -FDT_ERR_NOTFOUND; + else + return supernodeoffset; + } + } + + if (!can_assume(VALID_INPUT)) { + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_depth(const void *fdt, int nodeoffset) +{ + int nodedepth; + int err; + + err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); + if (err) + return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err : + -FDT_ERR_INTERNAL; + return nodedepth; +} + +int fdt_parent_offset(const void *fdt, int nodeoffset) +{ + int nodedepth = fdt_node_depth(fdt, nodeoffset); + + if (nodedepth < 0) + return nodedepth; + return fdt_supernode_atdepth_offset(fdt, nodeoffset, + nodedepth - 1, NULL); +} + +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen) +{ + int offset; + const void *val; + int len; + + FDT_RO_PROBE(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_getprop(), then if that didn't + * find what we want, we scan over them again making our way + * to the next node. Still it's the easiest to implement + * approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + val = fdt_getprop(fdt, offset, propname, &len); + if (val && (len == proplen) + && (memcmp(val, propval, len) == 0)) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) +{ + int offset; + + if ((phandle == 0) || (phandle == ~0U)) + return -FDT_ERR_BADPHANDLE; + + FDT_RO_PROBE(fdt); + + /* FIXME: The algorithm here is pretty horrible: we + * potentially scan each property of a node in + * fdt_get_phandle(), then if that didn't find what + * we want, we scan over them again making our way to the next + * node. Still it's the easiest to implement approach; + * performance can come later. */ + for (offset = fdt_next_node(fdt, -1, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (fdt_get_phandle(fdt, offset) == phandle) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) +{ + int len = strlen(str); + const char *p; + + while (listlen >= len) { + if (memcmp(str, strlist, len+1) == 0) + return 1; + p = memchr(strlist, '\0', listlen); + if (!p) + return 0; /* malformed strlist.. */ + listlen -= (p-strlist) + 1; + strlist = p + 1; + } + return 0; +} + +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) +{ + const char *list, *end; + int length, count = 0; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return length; + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + list += length; + count++; + } + + return count; +} + +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string) +{ + int length, len, idx = 0; + const char *list, *end; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return length; + + len = strlen(string) + 1; + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + if (length == len && memcmp(list, string, length) == 0) + return idx; + + list += length; + idx++; + } + + return -FDT_ERR_NOTFOUND; +} + +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int idx, + int *lenp) +{ + const char *list, *end; + int length; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) { + if (lenp) + *lenp = length; + + return NULL; + } + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) { + if (lenp) + *lenp = -FDT_ERR_BADVALUE; + + return NULL; + } + + if (idx == 0) { + if (lenp) + *lenp = length - 1; + + return list; + } + + list += length; + idx--; + } + + if (lenp) + *lenp = -FDT_ERR_NOTFOUND; + + return NULL; +} + +int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible) +{ + const void *prop; + int len; + + prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); + if (!prop) + return len; + + return !fdt_stringlist_contains(prop, len, compatible); +} + +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + const char *compatible) +{ + int offset, err; + + FDT_RO_PROBE(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_node_check_compatible(), then if + * that didn't find what we want, we scan over them again + * making our way to the next node. Still it's the easiest to + * implement approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + err = fdt_node_check_compatible(fdt, offset, compatible); + if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) + return err; + else if (err == 0) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} diff --git a/components/drivers/ofw/libfdt/fdt_rw.c b/components/drivers/ofw/libfdt/fdt_rw.c new file mode 100644 index 0000000000..3621d3651d --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt_rw.c @@ -0,0 +1,500 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int fdt_blocks_misordered_(const void *fdt, + int mem_rsv_size, int struct_size) +{ + return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) + || (fdt_off_dt_struct(fdt) < + (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) + || (fdt_off_dt_strings(fdt) < + (fdt_off_dt_struct(fdt) + struct_size)) + || (fdt_totalsize(fdt) < + (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); +} + +static int fdt_rw_probe_(void *fdt) +{ + if (can_assume(VALID_DTB)) + return 0; + FDT_RO_PROBE(fdt); + + if (!can_assume(LATEST) && fdt_version(fdt) < 17) + return -FDT_ERR_BADVERSION; + if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_BADLAYOUT; + if (!can_assume(LATEST) && fdt_version(fdt) > 17) + fdt_set_version(fdt, 17); + + return 0; +} + +#define FDT_RW_PROBE(fdt) \ + { \ + int err_; \ + if ((err_ = fdt_rw_probe_(fdt)) != 0) \ + return err_; \ + } + +static inline unsigned int fdt_data_size_(void *fdt) +{ + return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); +} + +static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) +{ + char *p = splicepoint; + unsigned int dsize = fdt_data_size_(fdt); + size_t soff = p - (char *)fdt; + + if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize)) + return -FDT_ERR_BADOFFSET; + if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen)) + return -FDT_ERR_BADOFFSET; + if (dsize - oldlen + newlen > fdt_totalsize(fdt)) + return -FDT_ERR_NOSPACE; + memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen)); + return 0; +} + +static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p, + int oldn, int newn) +{ + int delta = (newn - oldn) * sizeof(*p); + int err; + err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); + if (err) + return err; + fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +static int fdt_splice_struct_(void *fdt, void *p, + int oldlen, int newlen) +{ + int delta = newlen - oldlen; + int err; + + if ((err = fdt_splice_(fdt, p, oldlen, newlen))) + return err; + + fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +/* Must only be used to roll back in case of error */ +static void fdt_del_last_string_(void *fdt, const char *s) +{ + int newlen = strlen(s) + 1; + + fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen); +} + +static int fdt_splice_string_(void *fdt, int newlen) +{ + void *p = (char *)fdt + + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + int err; + + if ((err = fdt_splice_(fdt, p, 0, newlen))) + return err; + + fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); + return 0; +} + +/** + * fdt_find_add_string_() - Find or allocate a string + * + * @fdt: pointer to the device tree to check/adjust + * @s: string to find/add + * @allocated: Set to 0 if the string was found, 1 if not found and so + * allocated. Ignored if can_assume(NO_ROLLBACK) + * @return offset of string in the string table (whether found or added) + */ +static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) +{ + char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); + const char *p; + char *new; + int len = strlen(s) + 1; + int err; + + if (!can_assume(NO_ROLLBACK)) + *allocated = 0; + + p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); + if (p) + /* found it */ + return (p - strtab); + + new = strtab + fdt_size_dt_strings(fdt); + err = fdt_splice_string_(fdt, len); + if (err) + return err; + + if (!can_assume(NO_ROLLBACK)) + *allocated = 1; + + memcpy(new, s, len); + return (new - strtab); +} + +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) +{ + struct fdt_reserve_entry *re; + int err; + + FDT_RW_PROBE(fdt); + + re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); + err = fdt_splice_mem_rsv_(fdt, re, 0, 1); + if (err) + return err; + + re->address = cpu_to_fdt64(address); + re->size = cpu_to_fdt64(size); + return 0; +} + +int fdt_del_mem_rsv(void *fdt, int n) +{ + struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); + + FDT_RW_PROBE(fdt); + + if (n >= fdt_num_mem_rsv(fdt)) + return -FDT_ERR_NOTFOUND; + + return fdt_splice_mem_rsv_(fdt, re, 1, 0); +} + +static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int oldlen; + int err; + + *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (!*prop) + return oldlen; + + if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(len)))) + return err; + + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int proplen; + int nextoffset; + int namestroff; + int err; + int allocated; + + if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) + return nextoffset; + + namestroff = fdt_find_add_string_(fdt, name, &allocated); + if (namestroff < 0) + return namestroff; + + *prop = fdt_offset_ptr_w_(fdt, nextoffset); + proplen = sizeof(**prop) + FDT_TAGALIGN(len); + + err = fdt_splice_struct_(fdt, *prop, 0, proplen); + if (err) { + /* Delete the string if we failed to add it */ + if (!can_assume(NO_ROLLBACK) && allocated) + fdt_del_last_string_(fdt, name); + return err; + } + + (*prop)->tag = cpu_to_fdt32(FDT_PROP); + (*prop)->nameoff = cpu_to_fdt32(namestroff); + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +int fdt_set_name(void *fdt, int nodeoffset, const char *name) +{ + char *namep; + int oldlen, newlen; + int err; + + FDT_RW_PROBE(fdt); + + namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); + if (!namep) + return oldlen; + + newlen = strlen(name); + + err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1), + FDT_TAGALIGN(newlen+1)); + if (err) + return err; + + memcpy(namep, name, newlen+1); + return 0; +} + +int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, + int len, void **prop_data) +{ + struct fdt_property *prop; + int err; + + FDT_RW_PROBE(fdt); + + err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); + if (err == -FDT_ERR_NOTFOUND) + err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + + *prop_data = prop->data; + return 0; +} + +int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + void *prop_data; + int err; + + err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); + if (err) + return err; + + if (len) + memcpy(prop_data, val, len); + return 0; +} + +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err, oldlen, newlen; + + FDT_RW_PROBE(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; + err = fdt_splice_struct_(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) + return err; + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { + err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); + } + return 0; +} + +int fdt_delprop(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len, proplen; + + FDT_RW_PROBE(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (!prop) + return len; + + proplen = sizeof(*prop) + FDT_TAGALIGN(len); + return fdt_splice_struct_(fdt, prop, proplen, 0); +} + +int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen) +{ + struct fdt_node_header *nh; + int offset, nextoffset; + int nodelen; + int err; + uint32_t tag; + fdt32_t *endtag; + + FDT_RW_PROBE(fdt); + + offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); + if (offset >= 0) + return -FDT_ERR_EXISTS; + else if (offset != -FDT_ERR_NOTFOUND) + return offset; + + /* Try to place the new node after the parent's properties */ + tag = fdt_next_tag(fdt, parentoffset, &nextoffset); + /* the fdt_subnode_offset_namelen() should ensure this never hits */ + if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) + return -FDT_ERR_INTERNAL; + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + } while ((tag == FDT_PROP) || (tag == FDT_NOP)); + + nh = fdt_offset_ptr_w_(fdt, offset); + nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; + + err = fdt_splice_struct_(fdt, nh, 0, nodelen); + if (err) + return err; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); + memcpy(nh->name, name, namelen); + endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); + *endtag = cpu_to_fdt32(FDT_END_NODE); + + return offset; +} + +int fdt_add_subnode(void *fdt, int parentoffset, const char *name) +{ + return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_del_node(void *fdt, int nodeoffset) +{ + int endoffset; + + FDT_RW_PROBE(fdt); + + endoffset = fdt_node_end_offset_(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset), + endoffset - nodeoffset, 0); +} + +static void fdt_packblocks_(const char *old, char *new, + int mem_rsv_size, + int struct_size, + int strings_size) +{ + int mem_rsv_off, struct_off, strings_off; + + mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); + struct_off = mem_rsv_off + mem_rsv_size; + strings_off = struct_off + struct_size; + + memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); + fdt_set_off_mem_rsvmap(new, mem_rsv_off); + + memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); + fdt_set_off_dt_struct(new, struct_off); + fdt_set_size_dt_struct(new, struct_size); + + memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); + fdt_set_off_dt_strings(new, strings_off); + fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); +} + +int fdt_open_into(const void *fdt, void *buf, int bufsize) +{ + int err; + int mem_rsv_size, struct_size; + int newsize; + const char *fdtstart = fdt; + const char *fdtend = fdtstart + fdt_totalsize(fdt); + char *tmp; + + FDT_RO_PROBE(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + + if (can_assume(LATEST) || fdt_version(fdt) >= 17) { + struct_size = fdt_size_dt_struct(fdt); + } else if (fdt_version(fdt) == 16) { + struct_size = 0; + while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) + ; + if (struct_size < 0) + return struct_size; + } else { + return -FDT_ERR_BADVERSION; + } + + if (can_assume(LIBFDT_ORDER) || + !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { + /* no further work necessary */ + err = fdt_move(fdt, buf, bufsize); + if (err) + return err; + fdt_set_version(buf, 17); + fdt_set_size_dt_struct(buf, struct_size); + fdt_set_totalsize(buf, bufsize); + return 0; + } + + /* Need to reorder */ + newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + + struct_size + fdt_size_dt_strings(fdt); + + if (bufsize < newsize) + return -FDT_ERR_NOSPACE; + + /* First attempt to build converted tree at beginning of buffer */ + tmp = buf; + /* But if that overlaps with the old tree... */ + if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { + /* Try right after the old tree instead */ + tmp = (char *)(uintptr_t)fdtend; + if ((tmp + newsize) > ((char *)buf + bufsize)) + return -FDT_ERR_NOSPACE; + } + + fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, + fdt_size_dt_strings(fdt)); + memmove(buf, tmp, newsize); + + fdt_set_magic(buf, FDT_MAGIC); + fdt_set_totalsize(buf, bufsize); + fdt_set_version(buf, 17); + fdt_set_last_comp_version(buf, 16); + fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); + + return 0; +} + +int fdt_pack(void *fdt) +{ + int mem_rsv_size; + + FDT_RW_PROBE(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), + fdt_size_dt_strings(fdt)); + fdt_set_totalsize(fdt, fdt_data_size_(fdt)); + + return 0; +} diff --git a/components/drivers/ofw/libfdt/fdt_strerror.c b/components/drivers/ofw/libfdt/fdt_strerror.c new file mode 100644 index 0000000000..d852b77e81 --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt_strerror.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +struct fdt_errtabent { + const char *str; +}; + +#define FDT_ERRTABENT(val) \ + [(val)] = { .str = #val, } + +static struct fdt_errtabent fdt_errtable[] = { + FDT_ERRTABENT(FDT_ERR_NOTFOUND), + FDT_ERRTABENT(FDT_ERR_EXISTS), + FDT_ERRTABENT(FDT_ERR_NOSPACE), + + FDT_ERRTABENT(FDT_ERR_BADOFFSET), + FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADPHANDLE), + FDT_ERRTABENT(FDT_ERR_BADSTATE), + + FDT_ERRTABENT(FDT_ERR_TRUNCATED), + FDT_ERRTABENT(FDT_ERR_BADMAGIC), + FDT_ERRTABENT(FDT_ERR_BADVERSION), + FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), + FDT_ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_INTERNAL), + FDT_ERRTABENT(FDT_ERR_BADNCELLS), + FDT_ERRTABENT(FDT_ERR_BADVALUE), + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_NOPHANDLES), + FDT_ERRTABENT(FDT_ERR_BADFLAGS), + FDT_ERRTABENT(FDT_ERR_ALIGNMENT), +}; +#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) + +const char *fdt_strerror(int errval) +{ + if (errval > 0) + return ""; + else if (errval == 0) + return ""; + else if (-errval < FDT_ERRTABSIZE) { + const char *s = fdt_errtable[-errval].str; + + if (s) + return s; + } + + return ""; +} diff --git a/components/drivers/ofw/libfdt/fdt_sw.c b/components/drivers/ofw/libfdt/fdt_sw.c new file mode 100644 index 0000000000..4c569ee7eb --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt_sw.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int fdt_sw_probe_(void *fdt) +{ + if (!can_assume(VALID_INPUT)) { + if (fdt_magic(fdt) == FDT_MAGIC) + return -FDT_ERR_BADSTATE; + else if (fdt_magic(fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; + } + + return 0; +} + +#define FDT_SW_PROBE(fdt) \ + { \ + int err; \ + if ((err = fdt_sw_probe_(fdt)) != 0) \ + return err; \ + } + +/* 'memrsv' state: Initial state after fdt_create() + * + * Allowed functions: + * fdt_add_reservemap_entry() + * fdt_finish_reservemap() [moves to 'struct' state] + */ +static int fdt_sw_probe_memrsv_(void *fdt) +{ + int err = fdt_sw_probe_(fdt); + if (err) + return err; + + if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0) + return -FDT_ERR_BADSTATE; + return 0; +} + +#define FDT_SW_PROBE_MEMRSV(fdt) \ + { \ + int err; \ + if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ + return err; \ + } + +/* 'struct' state: Enter this state after fdt_finish_reservemap() + * + * Allowed functions: + * fdt_begin_node() + * fdt_end_node() + * fdt_property*() + * fdt_finish() [moves to 'complete' state] + */ +static int fdt_sw_probe_struct_(void *fdt) +{ + int err = fdt_sw_probe_(fdt); + if (err) + return err; + + if (!can_assume(VALID_INPUT) && + fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) + return -FDT_ERR_BADSTATE; + return 0; +} + +#define FDT_SW_PROBE_STRUCT(fdt) \ + { \ + int err; \ + if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ + return err; \ + } + +static inline uint32_t sw_flags(void *fdt) +{ + /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */ + return fdt_last_comp_version(fdt); +} + +/* 'complete' state: Enter this state after fdt_finish() + * + * Allowed functions: none + */ + +static void *fdt_grab_space_(void *fdt, size_t len) +{ + unsigned int offset = fdt_size_dt_struct(fdt); + unsigned int spaceleft; + + spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) + - fdt_size_dt_strings(fdt); + + if ((offset + len < offset) || (offset + len > spaceleft)) + return NULL; + + fdt_set_size_dt_struct(fdt, offset + len); + return fdt_offset_ptr_w_(fdt, offset); +} + +int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) +{ + const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry)); + void *fdt = buf; + + if (bufsize < hdrsize) + return -FDT_ERR_NOSPACE; + + if (flags & ~FDT_CREATE_FLAGS_ALL) + return -FDT_ERR_BADFLAGS; + + memset(buf, 0, bufsize); + + /* + * magic and last_comp_version keep intermediate state during the fdt + * creation process, which is replaced with the proper FDT format by + * fdt_finish(). + * + * flags should be accessed with sw_flags(). + */ + fdt_set_magic(fdt, FDT_SW_MAGIC); + fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, flags); + + fdt_set_totalsize(fdt, bufsize); + + fdt_set_off_mem_rsvmap(fdt, hdrsize); + fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); + fdt_set_off_dt_strings(fdt, 0); + + return 0; +} + +int fdt_create(void *buf, int bufsize) +{ + return fdt_create_with_flags(buf, bufsize, 0); +} + +int fdt_resize(void *fdt, void *buf, int bufsize) +{ + size_t headsize, tailsize; + char *oldtail, *newtail; + + FDT_SW_PROBE(fdt); + + if (bufsize < 0) + return -FDT_ERR_NOSPACE; + + headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + tailsize = fdt_size_dt_strings(fdt); + + if (!can_assume(VALID_DTB) && + headsize + tailsize > fdt_totalsize(fdt)) + return -FDT_ERR_INTERNAL; + + if ((headsize + tailsize) > (unsigned)bufsize) + return -FDT_ERR_NOSPACE; + + oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; + newtail = (char *)buf + bufsize - tailsize; + + /* Two cases to avoid clobbering data if the old and new + * buffers partially overlap */ + if (buf <= fdt) { + memmove(buf, fdt, headsize); + memmove(newtail, oldtail, tailsize); + } else { + memmove(newtail, oldtail, tailsize); + memmove(buf, fdt, headsize); + } + + fdt_set_totalsize(buf, bufsize); + if (fdt_off_dt_strings(buf)) + fdt_set_off_dt_strings(buf, bufsize); + + return 0; +} + +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) +{ + struct fdt_reserve_entry *re; + int offset; + + FDT_SW_PROBE_MEMRSV(fdt); + + offset = fdt_off_dt_struct(fdt); + if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) + return -FDT_ERR_NOSPACE; + + re = (struct fdt_reserve_entry *)((char *)fdt + offset); + re->address = cpu_to_fdt64(addr); + re->size = cpu_to_fdt64(size); + + fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); + + return 0; +} + +int fdt_finish_reservemap(void *fdt) +{ + int err = fdt_add_reservemap_entry(fdt, 0, 0); + + if (err) + return err; + + fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); + return 0; +} + +int fdt_begin_node(void *fdt, const char *name) +{ + struct fdt_node_header *nh; + int namelen; + + FDT_SW_PROBE_STRUCT(fdt); + + namelen = strlen(name) + 1; + nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); + if (! nh) + return -FDT_ERR_NOSPACE; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memcpy(nh->name, name, namelen); + return 0; +} + +int fdt_end_node(void *fdt) +{ + fdt32_t *en; + + FDT_SW_PROBE_STRUCT(fdt); + + en = fdt_grab_space_(fdt, FDT_TAGSIZE); + if (! en) + return -FDT_ERR_NOSPACE; + + *en = cpu_to_fdt32(FDT_END_NODE); + return 0; +} + +static int fdt_add_string_(void *fdt, const char *s) +{ + char *strtab = (char *)fdt + fdt_totalsize(fdt); + unsigned int strtabsize = fdt_size_dt_strings(fdt); + unsigned int len = strlen(s) + 1; + unsigned int struct_top, offset; + + offset = strtabsize + len; + struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + if (fdt_totalsize(fdt) - offset < struct_top) + return 0; /* no more room :( */ + + memcpy(strtab - offset, s, len); + fdt_set_size_dt_strings(fdt, strtabsize + len); + return -offset; +} + +/* Must only be used to roll back in case of error */ +static void fdt_del_last_string_(void *fdt, const char *s) +{ + int strtabsize = fdt_size_dt_strings(fdt); + int len = strlen(s) + 1; + + fdt_set_size_dt_strings(fdt, strtabsize - len); +} + +static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) +{ + char *strtab = (char *)fdt + fdt_totalsize(fdt); + int strtabsize = fdt_size_dt_strings(fdt); + const char *p; + + *allocated = 0; + + p = fdt_find_string_(strtab - strtabsize, strtabsize, s); + if (p) + return p - strtab; + + *allocated = 1; + + return fdt_add_string_(fdt, s); +} + +int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) +{ + struct fdt_property *prop; + int nameoff; + int allocated; + + FDT_SW_PROBE_STRUCT(fdt); + + /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */ + if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) { + allocated = 1; + nameoff = fdt_add_string_(fdt, name); + } else { + nameoff = fdt_find_add_string_(fdt, name, &allocated); + } + if (nameoff == 0) + return -FDT_ERR_NOSPACE; + + prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); + if (! prop) { + if (allocated) + fdt_del_last_string_(fdt, name); + return -FDT_ERR_NOSPACE; + } + + prop->tag = cpu_to_fdt32(FDT_PROP); + prop->nameoff = cpu_to_fdt32(nameoff); + prop->len = cpu_to_fdt32(len); + *valp = prop->data; + return 0; +} + +int fdt_property(void *fdt, const char *name, const void *val, int len) +{ + void *ptr; + int ret; + + ret = fdt_property_placeholder(fdt, name, len, &ptr); + if (ret) + return ret; + memcpy(ptr, val, len); + return 0; +} + +int fdt_finish(void *fdt) +{ + char *p = (char *)fdt; + fdt32_t *end; + int oldstroffset, newstroffset; + uint32_t tag; + int offset, nextoffset; + + FDT_SW_PROBE_STRUCT(fdt); + + /* Add terminator */ + end = fdt_grab_space_(fdt, sizeof(*end)); + if (! end) + return -FDT_ERR_NOSPACE; + *end = cpu_to_fdt32(FDT_END); + + /* Relocate the string table */ + oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); + newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); + fdt_set_off_dt_strings(fdt, newstroffset); + + /* Walk the structure, correcting string offsets */ + offset = 0; + while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { + if (tag == FDT_PROP) { + struct fdt_property *prop = + fdt_offset_ptr_w_(fdt, offset); + int nameoff; + + nameoff = fdt32_to_cpu(prop->nameoff); + nameoff += fdt_size_dt_strings(fdt); + prop->nameoff = cpu_to_fdt32(nameoff); + } + offset = nextoffset; + } + if (nextoffset < 0) + return nextoffset; + + /* Finally, adjust the header */ + fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); + + /* And fix up fields that were keeping intermediate state. */ + fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION); + fdt_set_magic(fdt, FDT_MAGIC); + + return 0; +} diff --git a/components/drivers/ofw/libfdt/fdt_wip.c b/components/drivers/ofw/libfdt/fdt_wip.c new file mode 100644 index 0000000000..c2d7566a67 --- /dev/null +++ b/components/drivers/ofw/libfdt/fdt_wip.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len) +{ + void *propval; + int proplen; + + propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, + &proplen); + if (!propval) + return proplen; + + if ((unsigned)proplen < (len + idx)) + return -FDT_ERR_NOSPACE; + + memcpy((char *)propval + idx, val, len); + return 0; +} + +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + const void *propval; + int proplen; + + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); + if (!propval) + return proplen; + + if (proplen != len) + return -FDT_ERR_NOSPACE; + + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), 0, + val, len); +} + +static void fdt_nop_region_(void *start, int len) +{ + fdt32_t *p; + + for (p = start; (char *)p < ((char *)start + len); p++) + *p = cpu_to_fdt32(FDT_NOP); +} + +int fdt_nop_property(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len; + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (!prop) + return len; + + fdt_nop_region_(prop, len + sizeof(*prop)); + + return 0; +} + +int fdt_node_end_offset_(void *fdt, int offset) +{ + int depth = 0; + + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node(fdt, offset, &depth); + + return offset; +} + +int fdt_nop_node(void *fdt, int nodeoffset) +{ + int endoffset; + + endoffset = fdt_node_end_offset_(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0), + endoffset - nodeoffset); + return 0; +} diff --git a/components/drivers/ofw/libfdt/libfdt.h b/components/drivers/ofw/libfdt/libfdt.h new file mode 100644 index 0000000000..77ccff1991 --- /dev/null +++ b/components/drivers/ofw/libfdt/libfdt.h @@ -0,0 +1,2154 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +#ifndef LIBFDT_H +#define LIBFDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ + +#include "libfdt_env.h" +#include "fdt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FDT_FIRST_SUPPORTED_VERSION 0x02 +#define FDT_LAST_COMPATIBLE_VERSION 0x10 +#define FDT_LAST_SUPPORTED_VERSION 0x11 + +/* Error codes: informative error codes */ +#define FDT_ERR_NOTFOUND 1 + /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ +#define FDT_ERR_EXISTS 2 + /* FDT_ERR_EXISTS: Attempted to create a node or property which + * already exists */ +#define FDT_ERR_NOSPACE 3 + /* FDT_ERR_NOSPACE: Operation needed to expand the device + * tree, but its buffer did not have sufficient space to + * contain the expanded tree. Use fdt_open_into() to move the + * device tree to a buffer with more space. */ + +/* Error codes: codes for bad parameters */ +#define FDT_ERR_BADOFFSET 4 + /* FDT_ERR_BADOFFSET: Function was passed a structure block + * offset which is out-of-bounds, or which points to an + * unsuitable part of the structure for the operation. */ +#define FDT_ERR_BADPATH 5 + /* FDT_ERR_BADPATH: Function was passed a badly formatted path + * (e.g. missing a leading / for a function which requires an + * absolute path) */ +#define FDT_ERR_BADPHANDLE 6 + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. + * This can be caused either by an invalid phandle property + * length, or the phandle value was either 0 or -1, which are + * not permitted. */ +#define FDT_ERR_BADSTATE 7 + /* FDT_ERR_BADSTATE: Function was passed an incomplete device + * tree created by the sequential-write functions, which is + * not sufficiently complete for the requested operation. */ + +/* Error codes: codes for bad device tree blobs */ +#define FDT_ERR_TRUNCATED 8 + /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly + * terminated (overflows, goes outside allowed bounds, or + * isn't properly terminated). */ +#define FDT_ERR_BADMAGIC 9 + /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a + * device tree at all - it is missing the flattened device + * tree magic number. */ +#define FDT_ERR_BADVERSION 10 + /* FDT_ERR_BADVERSION: Given device tree has a version which + * can't be handled by the requested operation. For + * read-write functions, this may mean that fdt_open_into() is + * required to convert the tree to the expected version. */ +#define FDT_ERR_BADSTRUCTURE 11 + /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt + * structure block or other serious error (e.g. misnested + * nodes, or subnodes preceding properties). */ +#define FDT_ERR_BADLAYOUT 12 + /* FDT_ERR_BADLAYOUT: For read-write functions, the given + * device tree has it's sub-blocks in an order that the + * function can't handle (memory reserve map, then structure, + * then strings). Use fdt_open_into() to reorganize the tree + * into a form suitable for the read-write operations. */ + +/* "Can't happen" error indicating a bug in libfdt */ +#define FDT_ERR_INTERNAL 13 + /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. + * Should never be returned, if it is, it indicates a bug in + * libfdt itself. */ + +/* Errors in device tree content */ +#define FDT_ERR_BADNCELLS 14 + /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells + * or similar property with a bad format or value */ + +#define FDT_ERR_BADVALUE 15 + /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected + * value. For example: a property expected to contain a string list + * is not NUL-terminated within the length of its value. */ + +#define FDT_ERR_BADOVERLAY 16 + /* FDT_ERR_BADOVERLAY: The device tree overlay, while + * correctly structured, cannot be applied due to some + * unexpected or missing value, property or node. */ + +#define FDT_ERR_NOPHANDLES 17 + /* FDT_ERR_NOPHANDLES: The device tree doesn't have any + * phandle available anymore without causing an overflow */ + +#define FDT_ERR_BADFLAGS 18 + /* FDT_ERR_BADFLAGS: The function was passed a flags field that + * contains invalid flags or an invalid combination of flags. */ + +#define FDT_ERR_ALIGNMENT 19 + /* FDT_ERR_ALIGNMENT: The device tree base address is not 8-byte + * aligned. */ + +#define FDT_ERR_MAX 19 + +/* constants */ +#define FDT_MAX_PHANDLE 0xfffffffe + /* Valid values for phandles range from 1 to 2^32-2. */ + +/**********************************************************************/ +/* Low-level functions (you probably don't need these) */ +/**********************************************************************/ + +#ifndef SWIG /* This function is not useful in Python */ +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); +#endif +static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) +{ + return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); +} + +uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); + +/* + * External helpers to access words from a device tree blob. They're built + * to work even with unaligned pointers on platforms (such as ARMv5) that don't + * like unaligned loads and stores. + */ +static inline uint16_t fdt16_ld(const fdt16_t *p) +{ + const uint8_t *bp = (const uint8_t *)p; + + return ((uint16_t)bp[0] << 8) | bp[1]; +} + +static inline uint32_t fdt32_ld(const fdt32_t *p) +{ + const uint8_t *bp = (const uint8_t *)p; + + return ((uint32_t)bp[0] << 24) + | ((uint32_t)bp[1] << 16) + | ((uint32_t)bp[2] << 8) + | bp[3]; +} + +static inline void fdt32_st(void *property, uint32_t value) +{ + uint8_t *bp = (uint8_t *)property; + + bp[0] = value >> 24; + bp[1] = (value >> 16) & 0xff; + bp[2] = (value >> 8) & 0xff; + bp[3] = value & 0xff; +} + +static inline uint64_t fdt64_ld(const fdt64_t *p) +{ + const uint8_t *bp = (const uint8_t *)p; + + return ((uint64_t)bp[0] << 56) + | ((uint64_t)bp[1] << 48) + | ((uint64_t)bp[2] << 40) + | ((uint64_t)bp[3] << 32) + | ((uint64_t)bp[4] << 24) + | ((uint64_t)bp[5] << 16) + | ((uint64_t)bp[6] << 8) + | bp[7]; +} + +static inline void fdt64_st(void *property, uint64_t value) +{ + uint8_t *bp = (uint8_t *)property; + + bp[0] = value >> 56; + bp[1] = (value >> 48) & 0xff; + bp[2] = (value >> 40) & 0xff; + bp[3] = (value >> 32) & 0xff; + bp[4] = (value >> 24) & 0xff; + bp[5] = (value >> 16) & 0xff; + bp[6] = (value >> 8) & 0xff; + bp[7] = value & 0xff; +} + +/**********************************************************************/ +/* Traversal functions */ +/**********************************************************************/ + +int fdt_next_node(const void *fdt, int offset, int *depth); + +/** + * fdt_first_subnode() - get offset of first direct subnode + * @fdt: FDT blob + * @offset: Offset of node to check + * + * Return: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none + */ +int fdt_first_subnode(const void *fdt, int offset); + +/** + * fdt_next_subnode() - get offset of next direct subnode + * @fdt: FDT blob + * @offset: Offset of previous subnode + * + * After first calling fdt_first_subnode(), call this function repeatedly to + * get direct subnodes of a parent node. + * + * Return: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more + * subnodes + */ +int fdt_next_subnode(const void *fdt, int offset); + +/** + * fdt_for_each_subnode - iterate over all subnodes of a parent + * + * @node: child node (int, lvalue) + * @fdt: FDT blob (const void *) + * @parent: parent node (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_subnode(node, fdt, parent) { + * Use node + * ... + * } + * + * if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and @node is used as + * iterator in the loop. The parent variable be constant or even a + * literal. + */ +#define fdt_for_each_subnode(node, fdt, parent) \ + for (node = fdt_first_subnode(fdt, parent); \ + node >= 0; \ + node = fdt_next_subnode(fdt, node)) + +/**********************************************************************/ +/* General functions */ +/**********************************************************************/ +#define fdt_get_header(fdt, field) \ + (fdt32_ld(&((const struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) +#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) +#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) +#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) +#define fdt_version(fdt) (fdt_get_header(fdt, version)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) + +#define fdt_set_hdr_(name) \ + static inline void fdt_set_##name(void *fdt, uint32_t val) \ + { \ + struct fdt_header *fdth = (struct fdt_header *)fdt; \ + fdth->name = cpu_to_fdt32(val); \ + } +fdt_set_hdr_(magic); +fdt_set_hdr_(totalsize); +fdt_set_hdr_(off_dt_struct); +fdt_set_hdr_(off_dt_strings); +fdt_set_hdr_(off_mem_rsvmap); +fdt_set_hdr_(version); +fdt_set_hdr_(last_comp_version); +fdt_set_hdr_(boot_cpuid_phys); +fdt_set_hdr_(size_dt_strings); +fdt_set_hdr_(size_dt_struct); +#undef fdt_set_hdr_ + +/** + * fdt_header_size - return the size of the tree's header + * @fdt: pointer to a flattened device tree + * + * Return: size of DTB header in bytes + */ +size_t fdt_header_size(const void *fdt); + +/** + * fdt_header_size_ - internal function to get header size from a version number + * @version: devicetree version number + * + * Return: size of DTB header in bytes + */ +size_t fdt_header_size_(uint32_t version); + +/** + * fdt_check_header - sanity check a device tree header + * @fdt: pointer to data which might be a flattened device tree + * + * fdt_check_header() checks that the given buffer contains what + * appears to be a flattened device tree, and that the header contains + * valid information (to the extent that can be determined from the + * header alone). + * + * returns: + * 0, if the buffer appears to contain a valid device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_TRUNCATED, standard meanings, as above + */ +int fdt_check_header(const void *fdt); + +/** + * fdt_move - move a device tree around in memory + * @fdt: pointer to the device tree to move + * @buf: pointer to memory where the device is to be moved + * @bufsize: size of the memory space at buf + * + * fdt_move() relocates, if possible, the device tree blob located at + * fdt to the buffer at buf of size bufsize. The buffer may overlap + * with the existing device tree blob at fdt. Therefore, + * fdt_move(fdt, fdt, fdt_totalsize(fdt)) + * should always succeed. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_move(const void *fdt, void *buf, int bufsize); + +/**********************************************************************/ +/* Read-only functions */ +/**********************************************************************/ + +int fdt_check_full(const void *fdt, size_t bufsize); + +/** + * fdt_get_string - retrieve a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * @lenp: optional pointer to return the string's length + * + * fdt_get_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt, and optionally also + * returns the string's length in *lenp. + * + * returns: + * a pointer to the string, on success + * NULL, if stroffset is out of bounds, or doesn't point to a valid string + */ +const char *fdt_get_string(const void *fdt, int stroffset, int *lenp); + +/** + * fdt_string - retrieve a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * + * fdt_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt. + * + * returns: + * a pointer to the string, on success + * NULL, if stroffset is out of bounds, or doesn't point to a valid string + */ +const char *fdt_string(const void *fdt, int stroffset); + +/** + * fdt_find_max_phandle - find and return the highest phandle in a tree + * @fdt: pointer to the device tree blob + * @phandle: return location for the highest phandle value found in the tree + * + * fdt_find_max_phandle() finds the highest phandle value in the given device + * tree. The value returned in @phandle is only valid if the function returns + * success. + * + * returns: + * 0 on success or a negative error code on failure + */ +int fdt_find_max_phandle(const void *fdt, uint32_t *phandle); + +/** + * fdt_get_max_phandle - retrieves the highest phandle in a tree + * @fdt: pointer to the device tree blob + * + * fdt_get_max_phandle retrieves the highest phandle in the given + * device tree. This will ignore badly formatted phandles, or phandles + * with a value of 0 or -1. + * + * This function is deprecated in favour of fdt_find_max_phandle(). + * + * returns: + * the highest phandle on success + * 0, if no phandle was found in the device tree + * -1, if an error occurred + */ +static inline uint32_t fdt_get_max_phandle(const void *fdt) +{ + uint32_t phandle; + int err; + + err = fdt_find_max_phandle(fdt, &phandle); + if (err < 0) + return (uint32_t)-1; + + return phandle; +} + +/** + * fdt_generate_phandle - return a new, unused phandle for a device tree blob + * @fdt: pointer to the device tree blob + * @phandle: return location for the new phandle + * + * Walks the device tree blob and looks for the highest phandle value. On + * success, the new, unused phandle value (one higher than the previously + * highest phandle value in the device tree blob) will be returned in the + * @phandle parameter. + * + * Return: 0 on success or a negative error-code on failure + */ +int fdt_generate_phandle(const void *fdt, uint32_t *phandle); + +/** + * fdt_num_mem_rsv - retrieve the number of memory reserve map entries + * @fdt: pointer to the device tree blob + * + * Returns the number of entries in the device tree blob's memory + * reservation map. This does not include the terminating 0,0 entry + * or any other (0,0) entries reserved for expansion. + * + * returns: + * the number of entries + */ +int fdt_num_mem_rsv(const void *fdt); + +/** + * fdt_get_mem_rsv - retrieve one memory reserve map entry + * @fdt: pointer to the device tree blob + * @n: index of reserve map entry + * @address: pointer to 64-bit variable to hold the start address + * @size: pointer to 64-bit variable to hold the size of the entry + * + * On success, @address and @size will contain the address and size of + * the n-th reserve map entry from the device tree blob, in + * native-endian format. + * + * returns: + * 0, on success + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); + +/** + * fdt_subnode_offset_namelen - find a subnode based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_subnode_offset(), but only examine the first + * namelen characters of name for matching the subnode name. This is + * useful for finding subnodes based on a portion of a larger string, + * such as a full path. + * + * Return: offset of the subnode or -FDT_ERR_NOTFOUND if name not found. + */ +#ifndef SWIG /* Not available in Python */ +int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + const char *name, int namelen); +#endif +/** + * fdt_subnode_offset - find a subnode of a given node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_subnode_offset() finds a subnode of the node at structure block + * offset parentoffset with the given name. name may include a unit + * address, in which case fdt_subnode_offset() will find the subnode + * with that unit address, or the unit address may be omitted, in + * which case fdt_subnode_offset() will find an arbitrary subnode + * whose name excluding unit address matches the given name. + * + * returns: + * structure block offset of the requested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + +/** + * fdt_path_offset_namelen - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * @namelen: number of characters of path to consider + * + * Identical to fdt_path_offset(), but only consider the first namelen + * characters of path as the path name. + * + * Return: offset of the node or negative libfdt error value otherwise + */ +#ifndef SWIG /* Not available in Python */ +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); +#endif + +/** + * fdt_path_offset - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * + * fdt_path_offset() finds a node of a given path in the device tree. + * Each path component may omit the unit address portion, but the + * results of this are undefined if any such path component is + * ambiguous (that is if there are multiple nodes at the relevant + * level matching the given component, differentiated only by unit + * address). + * + * returns: + * structure block offset of the node with the requested path (>=0), on + * success + * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + * -FDT_ERR_NOTFOUND, if the requested node does not exist + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_path_offset(const void *fdt, const char *path); + +/** + * fdt_get_name - retrieve the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the starting node + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_name() retrieves the name (including unit address) of the + * device tree node at structure block offset nodeoffset. If lenp is + * non-NULL, the length of this name is also returned, in the integer + * pointed to by lenp. + * + * returns: + * pointer to the node's name, on success + * If lenp is non-NULL, *lenp contains the length of that name + * (>=0) + * NULL, on error + * if lenp is non-NULL *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); + +/** + * fdt_first_property_offset - find the offset of a node's first property + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * + * fdt_first_property_offset() finds the first property of the node at + * the given structure block offset. + * + * returns: + * structure block offset of the property (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested node has no properties + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_first_property_offset(const void *fdt, int nodeoffset); + +/** + * fdt_next_property_offset - step through a node's properties + * @fdt: pointer to the device tree blob + * @offset: structure block offset of a property + * + * fdt_next_property_offset() finds the property immediately after the + * one at the given structure block offset. This will be a property + * of the same node as the given property. + * + * returns: + * structure block offset of the next property (>=0), on success + * -FDT_ERR_NOTFOUND, if the given property is the last in its node + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_next_property_offset(const void *fdt, int offset); + +/** + * fdt_for_each_property_offset - iterate over all properties of a node + * + * @property: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_property_offset(property, fdt, node) { + * Use property + * ... + * } + * + * if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and property is used as + * iterator in the loop. The node variable can be constant or even a + * literal. + */ +#define fdt_for_each_property_offset(property, fdt, node) \ + for (property = fdt_first_property_offset(fdt, node); \ + property >= 0; \ + property = fdt_next_property_offset(fdt, property)) + +/** + * fdt_get_property_by_offset - retrieve the property at a given offset + * @fdt: pointer to the device tree blob + * @offset: offset of the property to retrieve + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property_by_offset() retrieves a pointer to the + * fdt_property structure within the device tree blob at the given + * offset. If lenp is non-NULL, the length of the property value is + * also returned, in the integer pointed to by lenp. + * + * Note that this code only works on device tree versions >= 16. fdt_getprop() + * works on all versions. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp); +static inline struct fdt_property *fdt_get_property_by_offset_w(void *fdt, + int offset, + int *lenp) +{ + return (struct fdt_property *)(uintptr_t) + fdt_get_property_by_offset(fdt, offset, lenp); +} + +/** + * fdt_get_property_namelen - find a property based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_get_property(), but only examine the first namelen + * characters of name for matching the property name. + * + * Return: pointer to the structure representing the property, or NULL + * if not found + */ +#ifndef SWIG /* Not available in Python */ +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int nodeoffset, + const char *name, + int namelen, int *lenp); +#endif + +/** + * fdt_get_property - find a given property in a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property() retrieves a pointer to the fdt_property + * structure within the device tree blob corresponding to the property + * named 'name' of the node at offset nodeoffset. If lenp is + * non-NULL, the length of the property value is also returned, in the + * integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, + const char *name, + int *lenp) +{ + return (struct fdt_property *)(uintptr_t) + fdt_get_property(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_getprop_by_offset - retrieve the value of a property at a given offset + * @fdt: pointer to the device tree blob + * @offset: offset of the property to read + * @namep: pointer to a string variable (will be overwritten) or NULL + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop_by_offset() retrieves a pointer to the value of the + * property at structure block offset 'offset' (this will be a pointer + * to within the device blob itself, not a copy of the value). If + * lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. If namep is non-NULL, + * the property's namne will also be returned in the char * pointed to + * by namep (this will be a pointer to within the device tree's string + * block, not a new copy of the name). + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * if namep is non-NULL *namep contiains a pointer to the property + * name. + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#ifndef SWIG /* This function is not useful in Python */ +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp); +#endif + +/** + * fdt_getprop_namelen - get property value based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_getprop(), but only examine the first namelen + * characters of name for matching the property name. + * + * Return: pointer to the property's value or NULL on error + */ +#ifndef SWIG /* Not available in Python */ +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); +static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, + const char *name, int namelen, + int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, + namelen, lenp); +} +#endif + +/** + * fdt_getprop - retrieve the value of a given property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop() retrieves a pointer to the value of the property + * named @name of the node at offset @nodeoffset (this will be a + * pointer to within the device blob itself, not a copy of the value). + * If @lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by @lenp. + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline void *fdt_getprop_w(void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_get_phandle - retrieve the phandle of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the node + * + * fdt_get_phandle() retrieves the phandle of the device tree node at + * structure block offset nodeoffset. + * + * returns: + * the phandle of the node at nodeoffset, on success (!= 0, != -1) + * 0, if the node has no phandle, or another error occurs + */ +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); + +/** + * fdt_get_alias_namelen - get alias based on substring + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * @namelen: number of characters of name to consider + * + * Identical to fdt_get_alias(), but only examine the first @namelen + * characters of @name for matching the alias name. + * + * Return: a pointer to the expansion of the alias named @name, if it exists, + * NULL otherwise + */ +#ifndef SWIG /* Not available in Python */ +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen); +#endif + +/** + * fdt_get_alias - retrieve the path referenced by a given alias + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * + * fdt_get_alias() retrieves the value of a given alias. That is, the + * value of the property named @name in the node /aliases. + * + * returns: + * a pointer to the expansion of the alias named 'name', if it exists + * NULL, if the given alias or the /aliases node does not exist + */ +const char *fdt_get_alias(const void *fdt, const char *name); + +/** + * fdt_get_path - determine the full path of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose path to find + * @buf: character buffer to contain the returned path (will be overwritten) + * @buflen: size of the character buffer at buf + * + * fdt_get_path() computes the full path of the node at offset + * nodeoffset, and records that path in the buffer at buf. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * 0, on success + * buf contains the absolute path of the node at + * nodeoffset, as a NUL-terminated string. + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + * characters and will not fit in the given buffer. + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); + +/** + * fdt_supernode_atdepth_offset - find a specific ancestor of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * @supernodedepth: depth of the ancestor to find + * @nodedepth: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_supernode_atdepth_offset() finds an ancestor of the given node + * at a specific depth from the root (where the root itself has depth + * 0, its immediate subnodes depth 1 and so forth). So + * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); + * will always return 0, the offset of the root node. If the node at + * nodeoffset has depth D, then: + * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); + * will return nodeoffset itself. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * structure block offset of the node at node offset's ancestor + * of depth supernodedepth (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of + * nodeoffset + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth); + +/** + * fdt_node_depth - find the depth of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_node_depth() finds the depth of a given node. The root node + * has depth 0, its immediate subnodes depth 1 and so forth. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * depth of the node at nodeoffset (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_depth(const void *fdt, int nodeoffset); + +/** + * fdt_parent_offset - find the parent of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_parent_offset() locates the parent node of a given node (that + * is, it finds the offset of the node which contains the node at + * nodeoffset as a subnode). + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset, *twice*. + * + * returns: + * structure block offset of the parent of the node at nodeoffset + * (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_parent_offset(const void *fdt, int nodeoffset); + +/** + * fdt_node_offset_by_prop_value - find nodes with a given property value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @propname: property name to check + * @propval: property value to search for + * @proplen: length of the value in propval + * + * fdt_node_offset_by_prop_value() returns the offset of the first + * node after startoffset, which has a property named propname whose + * value is of length proplen and has value equal to propval; or if + * startoffset is -1, the very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, + * propval, proplen); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, + * propval, proplen); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen); + +/** + * fdt_node_offset_by_phandle - find the node with a given phandle + * @fdt: pointer to the device tree blob + * @phandle: phandle value + * + * fdt_node_offset_by_phandle() returns the offset of the node + * which has the given phandle value. If there is more than one node + * in the tree with the given phandle (an invalid tree), results are + * undefined. + * + * returns: + * structure block offset of the located node (>= 0), on success + * -FDT_ERR_NOTFOUND, no node with that phandle exists + * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); + +/** + * fdt_node_check_compatible - check a node's compatible property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @compatible: string to match against + * + * fdt_node_check_compatible() returns 0 if the given node contains a + * @compatible property with the given string as one of its elements, + * it returns non-zero otherwise, or on error. + * + * returns: + * 0, if the node has a 'compatible' property listing the given string + * 1, if the node has a 'compatible' property, but it does not list + * the given string + * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible); + +/** + * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @compatible: 'compatible' string to match against + * + * fdt_node_offset_by_compatible() returns the offset of the first + * node after startoffset, which has a 'compatible' property which + * lists the given compatible string; or if startoffset is -1, the + * very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + const char *compatible); + +/** + * fdt_stringlist_contains - check a string list property for a string + * @strlist: Property containing a list of strings to check + * @listlen: Length of property + * @str: String to search for + * + * This is a utility function provided for convenience. The list contains + * one or more strings, each terminated by \0, as is found in a device tree + * "compatible" property. + * + * Return: 1 if the string is found in the list, 0 not found, or invalid list + */ +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); + +/** + * fdt_stringlist_count - count the number of strings in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * + * Return: + * the number of strings in the given property + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); + +/** + * fdt_stringlist_search - find a string in a string list and return its index + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @string: string to look up in the string list + * + * Note that it is possible for this function to succeed on property values + * that are not NUL-terminated. That's because the function will stop after + * finding the first occurrence of @string. This can for example happen with + * small-valued cell properties, such as #address-cells, when searching for + * the empty string. + * + * return: + * the index of the string in the list of strings + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist or does not contain + * the given string + */ +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string); + +/** + * fdt_stringlist_get() - obtain the string at a given index in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @index: index of the string to return + * @lenp: return location for the string length or an error code on failure + * + * Note that this will successfully extract strings from properties with + * non-NUL-terminated values. For example on small-valued cell properties + * this function will return the empty string. + * + * If non-NULL, the length of the string (on success) or a negative error-code + * (on failure) will be stored in the integer pointer to by lenp. + * + * Return: + * A pointer to the string at the given index in the string list or NULL on + * failure. On success the length of the string will be stored in the memory + * location pointed to by the lenp parameter, if non-NULL. On failure one of + * the following negative error codes will be returned in the lenp parameter + * (if non-NULL): + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int index, + int *lenp); + +/**********************************************************************/ +/* Read-only functions (addressing related) */ +/**********************************************************************/ + +/** + * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells + * + * This is the maximum value for #address-cells, #size-cells and + * similar properties that will be processed by libfdt. IEE1275 + * requires that OF implementations handle values up to 4. + * Implementations may support larger values, but in practice higher + * values aren't used. + */ +#define FDT_MAX_NCELLS 4 + +/** + * fdt_address_cells - retrieve address size for a bus represented in the tree + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to find the address size for + * + * When the node has a valid #address-cells property, returns its value. + * + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 2, if the node has no #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #address-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_address_cells(const void *fdt, int nodeoffset); + +/** + * fdt_size_cells - retrieve address range size for a bus represented in the + * tree + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to find the address range size for + * + * When the node has a valid #size-cells property, returns its value. + * + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 1, if the node has no #size-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #size-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_size_cells(const void *fdt, int nodeoffset); + + +/**********************************************************************/ +/* Write-in-place functions */ +/**********************************************************************/ + +/** + * fdt_setprop_inplace_namelen_partial - change a property's value, + * but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: number of characters of name to consider + * @idx: index of the property to change in the array + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * Identical to fdt_setprop_inplace(), but modifies the given property + * starting from the given index, and using only the first characters + * of the name. It is useful when you want to manipulate only one value of + * an array and you have a string that doesn't end with \0. + * + * Return: 0 on success, negative libfdt error value otherwise + */ +#ifndef SWIG /* Not available in Python */ +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len); +#endif + +/** + * fdt_setprop_inplace - change a property's value, but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * fdt_setprop_inplace() replaces the value of a given property with + * the data in val, of length len. This function cannot change the + * size of a property, and so will only work if len is equal to the + * current length of the property. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if len is not equal to the property's current length + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#ifndef SWIG /* Not available in Python */ +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len); +#endif + +/** + * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to replace the property with + * + * fdt_setprop_inplace_u32() replaces the value of a given property + * with the 32-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 4. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to replace the property with + * + * fdt_setprop_inplace_u64() replaces the value of a given property + * with the 64-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 8. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node containing the property + * @name: name of the property to change the value of + * @val: new value of the 32-bit cell + * + * This is an alternative name for fdt_setprop_inplace_u32() + * Return: 0 on success, negative libfdt error number otherwise. + */ +static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_nop_property - replace a property with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_nop_property() will replace a given property's representation + * in the blob with FDT_NOP tags, effectively removing it from the + * tree. + * + * This function will alter only the bytes in the blob which contain + * the property, and will not alter or move any other part of the + * tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_property(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_nop_node - replace a node (subtree) with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_nop_node() will replace a given node's representation in the + * blob, including all its subnodes, if any, with FDT_NOP tags, + * effectively removing it from the tree. + * + * This function will alter only the bytes in the blob which contain + * the node and its properties and subnodes, and will not alter or + * move any other part of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_node(void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Sequential write functions */ +/**********************************************************************/ + +/* fdt_create_with_flags flags */ +#define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1 + /* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property + * names in the fdt. This can result in faster creation times, but + * a larger fdt. */ + +#define FDT_CREATE_FLAGS_ALL (FDT_CREATE_FLAG_NO_NAME_DEDUP) + +/** + * fdt_create_with_flags - begin creation of a new fdt + * @buf: pointer to memory allocated where fdt will be created + * @bufsize: size of the memory space at fdt + * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0. + * + * fdt_create_with_flags() begins the process of creating a new fdt with + * the sequential write interface. + * + * fdt creation process must end with fdt_finished() to produce a valid fdt. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt + * -FDT_ERR_BADFLAGS, flags is not valid + */ +int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags); + +/** + * fdt_create - begin creation of a new fdt + * @buf: pointer to memory allocated where fdt will be created + * @bufsize: size of the memory space at fdt + * + * fdt_create() is equivalent to fdt_create_with_flags() with flags=0. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt + */ +int fdt_create(void *buf, int bufsize); + +int fdt_resize(void *fdt, void *buf, int bufsize); +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); +int fdt_finish_reservemap(void *fdt); +int fdt_begin_node(void *fdt, const char *name); +int fdt_property(void *fdt, const char *name, const void *val, int len); +static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); +} +static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); +} + +#ifndef SWIG /* Not available in Python */ +static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +{ + return fdt_property_u32(fdt, name, val); +} +#endif + +/** + * fdt_property_placeholder - add a new property and return a ptr to its value + * + * @fdt: pointer to the device tree blob + * @name: name of property to add + * @len: length of property value in bytes + * @valp: returns a pointer to where where the value should be placed + * + * returns: + * 0, on success + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_NOSPACE, standard meanings + */ +int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp); + +#define fdt_property_string(fdt, name, str) \ + fdt_property(fdt, name, str, strlen(str)+1) +int fdt_end_node(void *fdt); +int fdt_finish(void *fdt); + +/**********************************************************************/ +/* Read-write functions */ +/**********************************************************************/ + +int fdt_create_empty_tree(void *buf, int bufsize); +int fdt_open_into(const void *fdt, void *buf, int bufsize); +int fdt_pack(void *fdt); + +/** + * fdt_add_mem_rsv - add one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address: 64-bit start address of the reserve map entry + * @size: 64-bit size of the reserved region + * + * Adds a reserve map entry to the given blob reserving a region at + * address address of length size. + * + * This function will insert data into the reserve map and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new reservation entry + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); + +/** + * fdt_del_mem_rsv - remove a memory reserve map entry + * @fdt: pointer to the device tree blob + * @n: entry to remove + * + * fdt_del_mem_rsv() removes the n-th memory reserve map entry from + * the blob. + * + * This function will delete data from the reservation table and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there + * are less than n+1 reserve map entries) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_mem_rsv(void *fdt, int n); + +/** + * fdt_set_name - change the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * @name: name to give the node + * + * fdt_set_name() replaces the name (including unit address, if any) + * of the given node with the given string. NOTE: this function can't + * efficiently check if the new name is unique amongst the given + * node's siblings; results are undefined if this function is invoked + * with a name equal to one of the given node's siblings. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob + * to contain the new name + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_set_name(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_setprop - create or change a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to set the property value to + * @len: length of the property value + * + * fdt_setprop() sets the value of the named property in the given + * node to the given value and length, creating the property if it + * does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_setprop_placeholder - allocate space for a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @len: length of the property value + * @prop_data: return pointer to property data + * + * fdt_setprop_placeholer() allocates the named property in the given node. + * If the property exists it is resized. In either case a pointer to the + * property data is returned. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, + int len, void **prop_data); + +/** + * fdt_setprop_u32 - set a property to a 32-bit integer + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) + * + * fdt_setprop_u32() sets the value of the named property in the given + * node to the given 32-bit integer value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_u64 - set a property to a 64-bit integer + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value for the property (native endian) + * + * fdt_setprop_u64() sets the value of the named property in the given + * node to the given 64-bit integer value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, + uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_cell - set a property to a single cell value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) + * + * This is an alternative name for fdt_setprop_u32() + * + * Return: 0 on success, negative libfdt error value otherwise. + */ +static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + return fdt_setprop_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_setprop_string - set a property to a string value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value for the property + * + * fdt_setprop_string() sets the value of the named property in the + * given node to the given string value (using the length of the + * string to determine the new length of the property), or creates a + * new property with that value if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_string(fdt, nodeoffset, name, str) \ + fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + + +/** + * fdt_setprop_empty - set a property to an empty value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * + * fdt_setprop_empty() sets the value of the named property in the + * given node to an empty (zero length) value, or creates a new empty + * property if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_empty(fdt, nodeoffset, name) \ + fdt_setprop((fdt), (nodeoffset), (name), NULL, 0) + +/** + * fdt_appendprop - append to or create a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to append to + * @val: pointer to data to append to the property value + * @len: length of the data to append to the property value + * + * fdt_appendprop() appends the value to the named property in the + * given node, creating the property if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_appendprop_u32 - append a 32-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u32() appends the given 32-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_appendprop_u64 - append a 64-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u64() appends the given 64-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_appendprop_cell - append a single cell value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) + * + * This is an alternative name for fdt_appendprop_u32() + * + * Return: 0 on success, negative libfdt error value otherwise. + */ +static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_appendprop_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_appendprop_string - append a string to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value to append to the property + * + * fdt_appendprop_string() appends the given string to the value of + * the named property in the given node, or creates a new property + * with that value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_appendprop_string(fdt, nodeoffset, name, str) \ + fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** + * fdt_appendprop_addrrange - append a address range property + * @fdt: pointer to the device tree blob + * @parent: offset of the parent node + * @nodeoffset: offset of the node to add a property at + * @name: name of property + * @addr: start address of a given range + * @size: size of a given range + * + * fdt_appendprop_addrrange() appends an address range value (start + * address and size) to the value of the named property in the given + * node, or creates a new property with that value if it does not + * already exist. + * If "name" is not specified, a default "reg" is used. + * Cell sizes are determined by parent's #address-cells and #size-cells. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #address-cells property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain a new property + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, + const char *name, uint64_t addr, uint64_t size); + +/** + * fdt_delprop - delete a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_del_property() will delete the given property. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_delprop(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_add_subnode_namelen - creates a new node based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to create + * @namelen: number of characters of name to consider + * + * Identical to fdt_add_subnode(), but use only the first @namelen + * characters of @name as the name of the new node. This is useful for + * creating subnodes based on a portion of a larger string, such as a + * full path. + * + * Return: structure block offset of the created subnode (>=0), + * negative libfdt error value otherwise + */ +#ifndef SWIG /* Not available in Python */ +int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen); +#endif + +/** + * fdt_add_subnode - creates a new node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_add_subnode() creates a new node as a subnode of the node at + * structure block offset parentoffset, with the given name (which + * should include the unit address, if any). + * + * This function will insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * structure block offset of the created nodeequested subnode (>=0), on + * success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + * the given name + * -FDT_ERR_NOSPACE, if there is insufficient free space in the + * blob to contain the new node + * -FDT_ERR_NOSPACE + * -FDT_ERR_BADLAYOUT + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_add_subnode(void *fdt, int parentoffset, const char *name); + +/** + * fdt_del_node - delete a node (subtree) + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_del_node() will remove the given node, including all its + * subnodes if any, from the blob. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_node(void *fdt, int nodeoffset); + +/** + * fdt_overlay_apply - Applies a DT overlay on a base DT + * @fdt: pointer to the base device tree blob + * @fdto: pointer to the device tree overlay blob + * + * fdt_overlay_apply() will apply the given device tree overlay on the + * given base device tree. + * + * Expect the base device tree to be modified, even if the function + * returns an error. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there's not enough space in the base device tree + * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or + * properties in the base DT + * -FDT_ERR_BADPHANDLE, + * -FDT_ERR_BADOVERLAY, + * -FDT_ERR_NOPHANDLES, + * -FDT_ERR_INTERNAL, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, + * -FDT_ERR_BADPATH, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_overlay_apply(void *fdt, void *fdto); + +/** + * fdt_overlay_target_offset - retrieves the offset of a fragment's target + * @fdt: Base device tree blob + * @fdto: Device tree overlay blob + * @fragment_offset: node offset of the fragment in the overlay + * @pathp: pointer which receives the path of the target (or NULL) + * + * fdt_overlay_target_offset() retrieves the target offset in the base + * device tree of a fragment, no matter how the actual targeting is + * done (through a phandle or a path) + * + * returns: + * the targeted node offset in the base device tree + * Negative error code on error + */ +int fdt_overlay_target_offset(const void *fdt, const void *fdto, + int fragment_offset, char const **pathp); + +/**********************************************************************/ +/* Debugging / informational functions */ +/**********************************************************************/ + +const char *fdt_strerror(int errval); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBFDT_H */ diff --git a/components/drivers/ofw/libfdt/libfdt_env.h b/components/drivers/ofw/libfdt/libfdt_env.h new file mode 100644 index 0000000000..07d9b0a97a --- /dev/null +++ b/components/drivers/ofw/libfdt/libfdt_env.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +#ifndef LIBFDT_ENV_H +#define LIBFDT_ENV_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2012 Kim Phillips, Freescale Semiconductor. + */ + +#include +#include +#include +#include +#include +#include + +#ifdef __CHECKER__ +#define FDT_FORCE __attribute__((force)) +#define FDT_BITWISE __attribute__((bitwise)) +#else +#define FDT_FORCE +#define FDT_BITWISE +#endif + +#include + +#define strnlen rt_strnlen + +typedef uint16_t FDT_BITWISE fdt16_t; +typedef uint32_t FDT_BITWISE fdt32_t; +typedef uint64_t FDT_BITWISE fdt64_t; + +#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) +#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) +#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ + (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) +#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ + (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ + (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ + (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) + +static inline uint16_t fdt16_to_cpu(fdt16_t x) +{ + return (FDT_FORCE uint16_t)CPU_TO_FDT16(x); +} +static inline fdt16_t cpu_to_fdt16(uint16_t x) +{ + return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x); +} + +static inline uint32_t fdt32_to_cpu(fdt32_t x) +{ + return (FDT_FORCE uint32_t)CPU_TO_FDT32(x); +} +static inline fdt32_t cpu_to_fdt32(uint32_t x) +{ + return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x); +} + +static inline uint64_t fdt64_to_cpu(fdt64_t x) +{ + return (FDT_FORCE uint64_t)CPU_TO_FDT64(x); +} +static inline fdt64_t cpu_to_fdt64(uint64_t x) +{ + return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x); +} +#undef CPU_TO_FDT64 +#undef CPU_TO_FDT32 +#undef CPU_TO_FDT16 +#undef EXTRACT_BYTE + +#ifdef __APPLE__ +#include + +/* strnlen() is not available on Mac OS < 10.7 */ +# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \ + MAC_OS_X_VERSION_10_7) + +#define strnlen fdt_strnlen + +/* + * fdt_strnlen: returns the length of a string or max_count - which ever is + * smallest. + * Input 1 string: the string whose size is to be determined + * Input 2 max_count: the maximum value returned by this function + * Output: length of the string or max_count (the smallest of the two) + */ +static inline size_t fdt_strnlen(const char *string, size_t max_count) +{ + const char *p = memchr(string, 0, max_count); + return p ? p - string : max_count; +} + +#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < + MAC_OS_X_VERSION_10_7) */ + +#endif /* __APPLE__ */ + +#endif /* LIBFDT_ENV_H */ diff --git a/components/drivers/ofw/libfdt/libfdt_internal.h b/components/drivers/ofw/libfdt/libfdt_internal.h new file mode 100644 index 0000000000..16bda1906a --- /dev/null +++ b/components/drivers/ofw/libfdt/libfdt_internal.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +#ifndef LIBFDT_INTERNAL_H +#define LIBFDT_INTERNAL_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + */ +#include + +#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) + +int32_t fdt_ro_probe_(const void *fdt); +#define FDT_RO_PROBE(fdt) \ + { \ + int32_t totalsize_; \ + if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \ + return totalsize_; \ + } + +int fdt_check_node_offset_(const void *fdt, int offset); +int fdt_check_prop_offset_(const void *fdt, int offset); +const char *fdt_find_string_(const char *strtab, int tabsize, const char *s); +int fdt_node_end_offset_(void *fdt, int nodeoffset); + +static inline const void *fdt_offset_ptr_(const void *fdt, int offset) +{ + return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; +} + +static inline void *fdt_offset_ptr_w_(void *fdt, int offset) +{ + return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset); +} + +static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n) +{ + const struct fdt_reserve_entry *rsv_table = + (const struct fdt_reserve_entry *) + ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); + + return rsv_table + n; +} +static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) +{ + return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n); +} + +/* + * Internal helpers to access tructural elements of the device tree + * blob (rather than for exaple reading integers from within property + * values). We assume that we are either given a naturally aligned + * address for the platform or if we are not, we are on a platform + * where unaligned memory reads will be handled in a graceful manner. + * If not the external helpers fdtXX_ld() from libfdt.h can be used + * instead. + */ +static inline uint32_t fdt32_ld_(const fdt32_t *p) +{ + return fdt32_to_cpu(*p); +} + +static inline uint64_t fdt64_ld_(const fdt64_t *p) +{ + return fdt64_to_cpu(*p); +} + +#define FDT_SW_MAGIC (~FDT_MAGIC) + +/**********************************************************************/ +/* Checking controls */ +/**********************************************************************/ + +#ifndef FDT_ASSUME_MASK +#define FDT_ASSUME_MASK 0 +#endif + +/* + * Defines assumptions which can be enabled. Each of these can be enabled + * individually. For maximum safety, don't enable any assumptions! + * + * For minimal code size and no safety, use ASSUME_PERFECT at your own risk. + * You should have another method of validating the device tree, such as a + * signature or hash check before using libfdt. + * + * For situations where security is not a concern it may be safe to enable + * ASSUME_SANE. + */ +enum { + /* + * This does essentially no checks. Only the latest device-tree + * version is correctly handled. Inconsistencies or errors in the device + * tree may cause undefined behaviour or crashes. Invalid parameters + * passed to libfdt may do the same. + * + * If an error occurs when modifying the tree it may leave the tree in + * an intermediate (but valid) state. As an example, adding a property + * where there is insufficient space may result in the property name + * being added to the string table even though the property itself is + * not added to the struct section. + * + * Only use this if you have a fully validated device tree with + * the latest supported version and wish to minimise code size. + */ + ASSUME_PERFECT = 0xff, + + /* + * This assumes that the device tree is sane. i.e. header metadata + * and basic hierarchy are correct. + * + * With this assumption enabled, normal device trees produced by libfdt + * and the compiler should be handled safely. Malicious device trees and + * complete garbage may cause libfdt to behave badly or crash. Truncated + * device trees (e.g. those only partially loaded) can also cause + * problems. + * + * Note: Only checks that relate exclusively to the device tree itself + * (not the parameters passed to libfdt) are disabled by this + * assumption. This includes checking headers, tags and the like. + */ + ASSUME_VALID_DTB = 1 << 0, + + /* + * This builds on ASSUME_VALID_DTB and further assumes that libfdt + * functions are called with valid parameters, i.e. not trigger + * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any + * extensive checking of parameters and the device tree, making various + * assumptions about correctness. + * + * It doesn't make sense to enable this assumption unless + * ASSUME_VALID_DTB is also enabled. + */ + ASSUME_VALID_INPUT = 1 << 1, + + /* + * This disables checks for device-tree version and removes all code + * which handles older versions. + * + * Only enable this if you know you have a device tree with the latest + * version. + */ + ASSUME_LATEST = 1 << 2, + + /* + * This assumes that it is OK for a failed addition to the device tree, + * due to lack of space or some other problem, to skip any rollback + * steps (such as dropping the property name from the string table). + * This is safe to enable in most circumstances, even though it may + * leave the tree in a sub-optimal state. + */ + ASSUME_NO_ROLLBACK = 1 << 3, + + /* + * This assumes that the device tree components appear in a 'convenient' + * order, i.e. the memory reservation block first, then the structure + * block and finally the string block. + * + * This order is not specified by the device-tree specification, + * but is expected by libfdt. The device-tree compiler always created + * device trees with this order. + * + * This assumption disables a check in fdt_open_into() and removes the + * ability to fix the problem there. This is safe if you know that the + * device tree is correctly ordered. See fdt_blocks_misordered_(). + */ + ASSUME_LIBFDT_ORDER = 1 << 4, + + /* + * This assumes that libfdt itself does not have any internal bugs. It + * drops certain checks that should never be needed unless libfdt has an + * undiscovered bug. + * + * This can generally be considered safe to enable. + */ + ASSUME_LIBFDT_FLAWLESS = 1 << 5, +}; + +/** + * can_assume_() - check if a particular assumption is enabled + * + * @mask: Mask to check (ASSUME_...) + * @return true if that assumption is enabled, else false + */ +static inline bool can_assume_(int mask) +{ + return FDT_ASSUME_MASK & mask; +} + +/** helper macros for checking assumptions */ +#define can_assume(_assume) can_assume_(ASSUME_ ## _assume) + +#endif /* LIBFDT_INTERNAL_H */ diff --git a/components/drivers/ofw/ofw.c b/components/drivers/ofw/ofw.c new file mode 100755 index 0000000000..88a5fe963d --- /dev/null +++ b/components/drivers/ofw/ofw.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "rtdm.ofw" +#define DBG_LVL DBG_INFO +#include + +#include "ofw_internal.h" + +struct rt_ofw_stub *rt_ofw_stub_probe_range(struct rt_ofw_node *np, + const struct rt_ofw_stub *stub_start, const struct rt_ofw_stub *stub_end) +{ + const struct rt_ofw_stub *stub = RT_NULL; + + if (np && stub_start && stub_end && + !rt_ofw_node_test_flag(np, RT_OFW_F_READLY) && + !rt_ofw_node_test_flag(np, RT_OFW_F_SYSTEM)) + { + struct rt_ofw_prop *compat_prop = rt_ofw_get_prop(np, "compatible", RT_NULL); + + if (compat_prop) + { + rt_ofw_foreach_stub(stub, stub_start, stub_end) + { + struct rt_ofw_node_id *id; + + if (!stub->ids) + { + continue; + } + + id = rt_ofw_prop_match(compat_prop, stub->ids); + + if (id) + { + if (!stub->handler(np, id)) + { + rt_ofw_node_set_flag(np, RT_OFW_F_READLY); + } + + break; + } + } + } + } + + return (struct rt_ofw_stub *)stub; +} + +static const char *ofw_console_serial_find(char *dst_con, struct rt_ofw_node *np) +{ + rt_object_t rt_obj; + const char *ofw_name = RT_NULL; + struct rt_serial_device *rt_serial = rt_ofw_data(np); + + if (rt_serial) + { + rt_obj = &rt_serial->parent.parent; + } + + /* + * This is a dangerous behavior because rt_data can be modified by other + * user. But fortunately, we can check if the rt_data is a rt_device or + * rt_serial_device. + */ + if (rt_obj && rt_object_get_type(rt_obj) == RT_Object_Class_Device && + rt_serial->parent.type == RT_Device_Class_Char) + { + ofw_name = np->full_name; + rt_strncpy(dst_con, rt_obj->name, RT_NAME_MAX); + } + + return ofw_name; +} + +static const char *ofw_console_tty_find(char *dst_con, const char *con) +{ + const char *ofw_name = RT_NULL; + static rt_bus_t platform_bus = RT_NULL; + + if (!platform_bus) + { + platform_bus = rt_bus_find_by_name("platform"); + } + + if (platform_bus) + { + rt_device_t dev; + rt_ubase_t level; + const char *console = con; + int tty_idx = 0, tty_id = 0, tty_name_len; + + con += sizeof("tty") - 1; + + while (*con && !(*con >= '0' && *con <= '9')) + { + ++con; + } + + tty_name_len = con - console; + + while (*con && *con >= '0' && *con <= '9') + { + tty_id *= 10; + tty_id += *con - '0'; + + ++con; + } + + level = rt_spin_lock_irqsave(&platform_bus->spinlock); + + rt_list_for_each_entry(dev, &platform_bus->dev_list, node) + { + struct rt_platform_device *pdev = rt_container_of(dev, struct rt_platform_device, parent); + const struct rt_ofw_node_id *id = pdev->id; + + if (id && id->type[0] && !rt_strncmp(id->type, console, tty_name_len)) + { + if (tty_idx == tty_id) + { + ofw_name = ofw_console_serial_find(dst_con, pdev->parent.ofw_node); + + break; + } + + ++tty_idx; + } + } + + rt_spin_unlock_irqrestore(&platform_bus->spinlock, level); + } + + return ofw_name; +} + +rt_err_t rt_ofw_console_setup(void) +{ + rt_err_t err = -RT_ENOSYS; + char con_name[RT_NAME_MAX]; + const char *ofw_name = RT_NULL, *stdout_path, *con; + + /* chosen.console > chosen.stdout-path > RT_CONSOLE_DEVICE_NAME */ + + con = rt_ofw_bootargs_select("console=", 0); + + for (int i = 1; con; ++i) + { + if (!rt_strncmp(con, "uart", sizeof("uart") - 1)) + { + rt_strncpy(con_name, con, RT_NAME_MAX); + + err = RT_EOK; + break; + } + else if (!rt_strncmp(con, "tty", sizeof("tty") - 1)) + { + ofw_name = ofw_console_tty_find(con_name, con); + + if (ofw_name) + { + err = RT_EOK; + break; + } + } + + con = rt_ofw_bootargs_select("console=", i); + } + + if (err == -RT_ENOSYS && !rt_ofw_prop_read_string(ofw_node_chosen, "stdout-path", &stdout_path)) + { + struct rt_ofw_node *stdout_np = rt_ofw_find_node_by_path(stdout_path); + + if (stdout_np && (ofw_name = ofw_console_serial_find(con_name, stdout_np))) + { + err = RT_EOK; + } + } + + if (err == -RT_ENOSYS) + { + rt_device_t serial = rt_device_find(RT_CONSOLE_DEVICE_NAME); + + if (serial) + { + ofw_name = rt_ofw_node_full_name(serial->ofw_node); + + con = RT_CONSOLE_DEVICE_NAME; + } + else + { + LOG_W("Console will probably fail to setup"); + } + } + else + { + con = con_name; + } + + rt_console_set_device(con); + + rt_fdt_earlycon_kick(FDT_EARLYCON_KICK_COMPLETED); + + LOG_I("Console: %s (%s)", con, ofw_name ? ofw_name : ""); + + return err; +} + +const char *rt_ofw_bootargs_select(const char *key, int index) +{ + const char *value = RT_NULL; + + if (key && index >= 0) + { + static char **values = RT_NULL; + static rt_size_t bootargs_nr = 1; + const char *bootargs = RT_NULL, *ch; + + if (bootargs_nr && !values && + (bootargs_nr = 0, !rt_ofw_prop_read_string(ofw_node_chosen, "bootargs", &bootargs)) && + bootargs && (bootargs = rt_strdup(bootargs))) + { + rt_bool_t quotes = RT_TRUE; + rt_size_t length = rt_strlen(bootargs); + const char *bootargs_end = bootargs + length; + + for (ch = bootargs; ch < bootargs_end; ++ch) + { + if (*ch == '"') + { + quotes = !quotes; + continue; + } + + if (*ch != ' ' || !quotes) + { + continue; + } + + ++bootargs_nr; + + while (*ch == ' ' && ch < bootargs_end) + { + *(char *)ch++ = '\0'; + } + --ch; + } + + if (bootargs_nr) + { + /* last arg */ + ++bootargs_nr; + values = rt_malloc(sizeof(char *) * bootargs_nr); + } + + if (values) + { + int idx = 0; + + for (int i = 0; i < length; ++i) + { + for (; i < length && !bootargs[i]; ++i) + { + } + + if (i < length) + { + values[idx++] = (char *)&bootargs[i]; + } + + for (; i < length && bootargs[i]; ++i) + { + } + } + } + else + { + rt_free((char *)bootargs); + } + } + + if (values) + { + int keylen = rt_strlen(key); + + for (int idx = 0, count = 0; idx < bootargs_nr; ++idx) + { + if (!rt_strncmp(values[idx], key, keylen)) + { + if (count == index) + { + value = values[idx] + keylen; + + break; + } + + ++count; + } + } + } + } + + return value; +} + +#ifdef RT_USING_CONSOLE +static void dts_put_depth(int depth) +{ + while (depth --> 0) + { + rt_kputs(" "); + } +} + +static rt_bool_t dts_test_string_list(const void *value, int size) +{ + const char *str, *str_start, *str_end; + + if (!size) + { + return RT_FALSE; + } + + str = value; + + /* String end with '\0' */ + if (str[size - 1] != '\0') + { + return RT_FALSE; + } + + /* Get string list end */ + str_end = str + size; + + while (str < str_end) + { + str_start = str; + /* Before string list end, not '\0' and a printable characters */ + while (str < str_end && *str && ((unsigned char)*str >= ' ' && (unsigned char)*str <= '~')) + { + ++str; + } + + /* Not zero, or not increased */ + if (*str != '\0' || str == str_start) + { + return RT_FALSE; + } + + /* Next string */ + ++str; + } + + return RT_TRUE; +} + +static void ofw_node_dump_dts(struct rt_ofw_node *np, rt_bool_t sibling_too) +{ + int depth = 0; + struct rt_ofw_prop *prop; + struct rt_ofw_node *org_np = np; + + while (np) + { + dts_put_depth(depth); + rt_kputs(np->full_name); + rt_kputs(" {\n"); + + prop = np->props; + + /* Print prop start */ + ++depth; + + while (prop) + { + dts_put_depth(depth); + + rt_kputs(prop->name); + + /* Have value? */ + if (prop->length > 0) + { + int length = prop->length; + void *value = prop->value; + + rt_kputs(" = "); + + if (dts_test_string_list(value, length)) + { + /* String list */ + char *str = value; + + do { + rt_kputs("\""); + rt_kputs(str); + rt_kputs("\", "); + + str += rt_strlen(str) + 1; + + } while (str < (char *)value + length); + + rt_kputs("\b\b"); + } + else if ((length % 4) == 0) + { + /* u32 data in */ + fdt32_t *cell = value; + + rt_kputs("<"); + + length /= 4; + + for (int i = 0; i < length; ++i) + { + rt_kprintf("0x%02x ", fdt32_to_cpu(cell[i])); + } + + rt_kputs("\b>"); + } + else + { + /* Byte data in [?] */ + rt_uint8_t *byte = value; + + rt_kputs("["); + + for (int i = 0; i < length; ++i) + { + rt_kprintf("%02x ", *byte++); + } + + rt_kputs("\b]"); + } + } + + rt_kputs(";\n"); + + prop = prop->next; + } + + --depth; + /* Print prop end */ + + if (np->child) + { + rt_kputs("\n"); + np = np->child; + ++depth; + } + else + { + dts_put_depth(depth); + rt_kputs("};\n"); + + while (np->parent && !np->sibling) + { + np = np->parent; + --depth; + + if (depth >= 0) + { + dts_put_depth(depth); + rt_kputs("};\n"); + } + } + + if (!sibling_too && org_np == np) + { + break; + } + + np = np->sibling; + + if (np) + { + rt_kputs("\n"); + } + } + } +} + +void rt_ofw_node_dump_dts(struct rt_ofw_node *np, rt_bool_t sibling_too) +{ + if (np) + { + if (!rt_strcmp(np->name, "/")) + { + struct fdt_info *header = (struct fdt_info *)np->name; + struct fdt_reserve_entry *rsvmap = header->rsvmap; + + rt_kprintf("/dts-v%x/;\n\n", fdt_version(header->fdt)); + + for (int i = header->rsvmap_nr - 1; i >= 0; --i) + { + rt_kprintf("/memreserve/\t%p %p;\n", + ofw_static_cast(rt_size_t, fdt64_to_cpu(rsvmap->address)), + ofw_static_cast(rt_size_t, fdt64_to_cpu(rsvmap->size))); + + ++rsvmap; + } + + rt_kputs(np->name); + } + + ofw_node_dump_dts(np, sibling_too); + } +} + +#ifdef RT_USING_MSH +static void ofw_dts(int argc, char**argv) +{ + if (ofw_node_root) + { + if (argc == 1) + { + rt_ofw_node_dump_dts(ofw_node_root, RT_TRUE); + } + else if (argv[1][0] == '/') + { + struct rt_ofw_node *np = rt_ofw_find_node_by_path(argv[1]); + + if (np) + { + rt_ofw_node_dump_dts(np, RT_FALSE); + } + else + { + rt_kprintf("%s not found.\n", argv[1]); + } + } + else if (argc >= 2 && !rt_strcmp(argv[1], "list") && argv[2][0] == '/') + { + struct rt_ofw_node *np = rt_ofw_find_node_by_path(argv[2]); + + if (np) + { + const char *split = np == ofw_node_root ? "" : "/"; + + np = np->child; + + while (np) + { + rt_kprintf("%s%s%s\n", argv[2], split, np->full_name); + np = np->sibling; + } + } + else + { + rt_kprintf("%s not found.\n", argv[2]); + } + } + else + { + rt_kprintf("Usage: %s {list} {path}\n", __func__); + } + } + else + { + rt_kprintf("\"/\" path not found."); + } +} +MSH_CMD_EXPORT(ofw_dts, dump the dts or node for this platform); +#endif /* RT_USING_MSH */ +#endif /* RT_USING_CONSOLE */ diff --git a/components/drivers/ofw/ofw_internal.h b/components/drivers/ofw/ofw_internal.h new file mode 100755 index 0000000000..619cf4a922 --- /dev/null +++ b/components/drivers/ofw/ofw_internal.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#ifndef __OFW_INTERNAL_H__ +#define __OFW_INTERNAL_H__ + +#include + +#include + +#define OFW_PHANDLE_MIN 1 +#define OFW_PHANDLE_MAX FDT_MAX_PHANDLE + +#define OFW_NODE_MAX_DEPTH 64 +#define OFW_NODE_MIN_HASH 128 + +#define OFW_ROOT_NODE_ADDR_CELLS_DEFAULT 1 +#define OFW_ROOT_NODE_SIZE_CELLS_DEFAULT 1 + +struct fdt_info +{ + /* Always "/", because we save "ofw" information in root node. */ + char name[sizeof("/")]; + + /* Information start */ + void *fdt; + + /* Only root can use */ + struct fdt_reserve_entry *rsvmap; + rt_size_t rsvmap_nr; +}; + +struct alias_info +{ + rt_list_t list; + + int id; + const char *tag; + rt_size_t tag_len; + + struct rt_ofw_node *np; +}; + +struct bus_ranges +{ + rt_size_t nr; + + rt_uint64_t *child_addr; + rt_uint64_t *parent_addr; + rt_uint64_t *child_size; +}; + +extern struct rt_ofw_node *ofw_node_root; +extern struct rt_ofw_node *ofw_node_cpus; +extern struct rt_ofw_node *ofw_node_chosen; +extern struct rt_ofw_node *ofw_node_aliases; +extern struct rt_ofw_node *ofw_node_reserved_memory; + +extern struct rt_fdt_earlycon fdt_earlycon; + +#define ofw_static_cast(to_type, value) \ + (to_type)(((value) >> ((sizeof(value) - sizeof(to_type)) * 8))) + +rt_err_t ofw_alias_scan(void); +rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max); + +#endif /* __OFW_INTERNAL_H__ */ diff --git a/components/drivers/ofw/raw.c b/components/drivers/ofw/raw.c new file mode 100755 index 0000000000..35e7aaa343 --- /dev/null +++ b/components/drivers/ofw/raw.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-19 GuEe-GUI first version + */ + +#include + +int fdt_add_subnode_possible(void *fdt, int parentoffset, const char *name) +{ + int nodeoffset; + + if ((nodeoffset = fdt_add_subnode(fdt, parentoffset, name)) < 0) + { + fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_PADDING_SIZE); + nodeoffset = fdt_add_subnode(fdt, parentoffset, name); + } + + return nodeoffset; +} + +int fdt_add_mem_rsv_possible(void *fdt, size_t addr, size_t size) +{ + int err = 0; + + if (fdt_add_mem_rsv(fdt, addr, size) < 0) + { + fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_PADDING_SIZE); + err = fdt_add_mem_rsv(fdt, addr, size); + } + + return err; +} + +int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name, uint64_t val, bool is_u64) +{ + int err; + + if (is_u64) + { + err = fdt_setprop_u64(fdt, nodeoffset, name, val); + } + else + { + err = fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val); + } + + return err; +} + +#define FDT_RAW_GET_VAL_FLAG(std_type, s, sz) \ +int fdt_getprop_##std_type##sz(void *fdt, int nodeoffset, \ + const char *name, s##int##sz##_t *out_value, int *lenp) \ +{ \ + int err = -FDT_ERR_NOTFOUND; \ + if (fdt && nodeoffset >= 0 && name && out_value) \ + { \ + const fdt##sz##_t *ptr; \ + if ((ptr = fdt_getprop(fdt, nodeoffset, name, lenp))) \ + { \ + *out_value = fdt##sz##_to_cpu(*ptr); \ + err = 0; \ + } \ + } \ + return err; \ +} + +#define FDT_RAW_GET_VAL(size) \ + FDT_RAW_GET_VAL_FLAG(u, u, size) \ + FDT_RAW_GET_VAL_FLAG(s, , size) + +FDT_RAW_GET_VAL(64) +FDT_RAW_GET_VAL(32) +FDT_RAW_GET_VAL(16) +FDT_RAW_GET_VAL(8) + +#undef FDT_RAW_GET_VAL +#undef FDT_RAW_GET_VAL_FLAG + +int fdt_io_addr_cells(void *fdt, int nodeoffset) +{ + int cells = -1; + int parentoffset = fdt_parent_offset(fdt, nodeoffset); + + for (; parentoffset >= 0 ; parentoffset = fdt_parent_offset(fdt, parentoffset)) + { + const fdt32_t *cells_tmp = fdt_getprop(fdt, parentoffset, "#address-cells", NULL); + + if (cells_tmp) + { + cells = fdt32_to_cpu(*cells_tmp); + } + } + + if (cells < 0) + { + cells = fdt_address_cells(fdt, nodeoffset); + } + + return cells; +} + +int fdt_io_size_cells(void *fdt, int nodeoffset) +{ + int cells = -1; + int parentoffset = fdt_parent_offset(fdt, nodeoffset); + + for (; parentoffset >= 0 ; parentoffset = fdt_parent_offset(fdt, parentoffset)) + { + const fdt32_t *cells_tmp = fdt_getprop(fdt, parentoffset, "#size-cells", NULL); + + if (cells_tmp) + { + cells = fdt32_to_cpu(*cells_tmp); + } + } + + if (cells < 0) + { + cells = fdt_size_cells(fdt, nodeoffset); + } + + return cells; +} + +int fdt_install_initrd(void *fdt, char *os_name, size_t initrd_addr, size_t initrd_size) +{ + int err = -FDT_ERR_NOTFOUND; + int chosen_offset = -1, root_off = fdt_path_offset(fdt, "/"); + + if (root_off >= 0) + { + chosen_offset = fdt_subnode_offset(fdt, root_off, "chosen"); + + if (chosen_offset == -FDT_ERR_NOTFOUND) + { + chosen_offset = fdt_add_subnode_possible(fdt, root_off, "chosen"); + } + } + + if (chosen_offset >= 0) + { + uint64_t addr, size; + + err = 0; + + /* Update the entry */ + for (int i = fdt_num_mem_rsv(fdt) - 1; i >= 0; --i) + { + fdt_get_mem_rsv(fdt, i, &addr, &size); + + if (addr == initrd_addr) + { + fdt_del_mem_rsv(fdt, i); + break; + } + } + + /* Add the memory */ + if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0) + { + /* Move the memory */ + fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_PADDING_SIZE); + + if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0) + { + err = -FDT_ERR_NOSPACE; + } + } + + if (!err) + { + size_t name_len; + char initrd_name[64]; + bool is_u64 = (fdt_io_addr_cells(fdt, root_off) == 2); + + if (!os_name) + { + os_name = "rt-thread"; + } + + name_len = strlen(initrd_name); + + strncpy(&initrd_name[name_len], ",initrd-start", sizeof(initrd_name) - name_len); + fdt_setprop_uxx(fdt, chosen_offset, initrd_name, initrd_addr, is_u64); + + strncpy(&initrd_name[name_len], ",initrd-end", sizeof(initrd_name) - name_len); + fdt_setprop_uxx(fdt, chosen_offset, initrd_name, initrd_addr + initrd_size, is_u64); + } + } + + return err; +} diff --git a/components/drivers/pic/Kconfig b/components/drivers/pic/Kconfig new file mode 100755 index 0000000000..cadb52b669 --- /dev/null +++ b/components/drivers/pic/Kconfig @@ -0,0 +1,11 @@ +menuconfig RT_USING_PIC + bool "Using Programmable Interrupt Controller (PIC)" + select RT_USING_BITMAP + depends on RT_USING_DM + default n + +config MAX_HANDLERS + int "IRQ max handlers" + depends on RT_USING_PIC + range 1 4294967294 + default 256 diff --git a/components/drivers/pic/SConscript b/components/drivers/pic/SConscript new file mode 100644 index 0000000000..ade23fc309 --- /dev/null +++ b/components/drivers/pic/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_PIC']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['pic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/pic/pic.c b/components/drivers/pic/pic.c new file mode 100644 index 0000000000..e5bc0fed7c --- /dev/null +++ b/components/drivers/pic/pic.c @@ -0,0 +1,977 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-24 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "rtdm.pic" +#define DBG_LVL DBG_INFO +#include + +#include + +struct irq_traps +{ + rt_list_t list; + + void *data; + rt_bool_t (*handler)(void *); +}; + +static int _ipi_hash[] = +{ +#ifdef RT_USING_SMP + [RT_SCHEDULE_IPI] = RT_SCHEDULE_IPI, + [RT_STOP_IPI] = RT_STOP_IPI, +#endif +}; + +/* reserved ipi */ +static int _pirq_hash_idx = RT_ARRAY_SIZE(_ipi_hash); +static struct rt_pic_irq _pirq_hash[MAX_HANDLERS] = +{ + [0 ... MAX_HANDLERS - 1] = + { + .irq = -1, + .hwirq = -1, + .mode = RT_IRQ_MODE_NONE, + .priority = RT_UINT32_MAX, + .rw_lock = { }, + } +}; + +static struct rt_spinlock _pic_lock = { }; +static rt_size_t _pic_name_max = sizeof("PIC"); +static rt_list_t _pic_nodes = RT_LIST_OBJECT_INIT(_pic_nodes); +static rt_list_t _traps_nodes = RT_LIST_OBJECT_INIT(_traps_nodes); + +static struct rt_pic_irq *irq2pirq(int irq) +{ + struct rt_pic_irq *pirq; + + if (irq >= 0 && irq < MAX_HANDLERS) + { + pirq = &_pirq_hash[irq]; + + if (pirq->irq < 0) + { + pirq = RT_NULL; + } + } + + if (!pirq) + { + LOG_E("irq = %d is invalid", irq); + } + + return pirq; +} + +static void append_pic(struct rt_pic *pic) +{ + int pic_name_len = rt_strlen(pic->ops->name); + + rt_list_insert_before(&_pic_nodes, &pic->list); + + if (pic_name_len > _pic_name_max) + { + _pic_name_max = pic_name_len; + } +} + +rt_err_t rt_pic_linear_irq(struct rt_pic *pic, rt_size_t irq_nr) +{ + rt_err_t err = RT_EOK; + + if (pic && pic->ops && pic->ops->name) + { + rt_ubase_t level = rt_spin_lock_irqsave(&_pic_lock); + + if (_pirq_hash_idx + irq_nr <= RT_ARRAY_SIZE(_pirq_hash)) + { + rt_list_init(&pic->list); + + pic->irq_start = _pirq_hash_idx; + pic->irq_nr = irq_nr; + pic->pirqs = &_pirq_hash[_pirq_hash_idx]; + + _pirq_hash_idx += irq_nr; + + append_pic(pic); + + LOG_D("%s alloc irqs ranges [%d, %d]", pic->ops->name, + pic->irq_start, pic->irq_start + pic->irq_nr); + } + else + { + LOG_E("%s alloc %d irqs is overflow", pic->ops->name, irq_nr); + + err = -RT_EEMPTY; + } + + rt_spin_unlock_irqrestore(&_pic_lock, level); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +static void config_pirq(struct rt_pic *pic, struct rt_pic_irq *pirq, int irq, int hwirq) +{ + rt_ubase_t level = rt_spin_lock_irqsave(&pirq->rw_lock); + + pirq->irq = irq; + pirq->hwirq = hwirq; + + pirq->pic = pic; + + rt_list_init(&pirq->isr.list); + + rt_spin_unlock_irqrestore(&pirq->rw_lock, level); +} + +int rt_pic_config_ipi(struct rt_pic *pic, int ipi_index, int hwirq) +{ + int ipi = ipi_index; + + if (pic && ipi < RT_ARRAY_SIZE(_ipi_hash) && hwirq >= 0 && pic->ops->irq_send_ipi) + { + config_pirq(pic, &_pirq_hash[ipi], ipi, hwirq); + + LOG_D("%s config %s %d to hwirq %d", pic->ops->name, "ipi", ipi, hwirq); + } + else + { + ipi = -RT_EINVAL; + } + + return ipi; +} + +int rt_pic_config_irq(struct rt_pic *pic, int irq_index, int hwirq) +{ + int irq; + + if (pic && hwirq >= 0) + { + irq = pic->irq_start + irq_index; + + if (irq >= 0 && irq < MAX_HANDLERS) + { + config_pirq(pic, &_pirq_hash[irq], irq, hwirq); + + LOG_D("%s config %s %d to hwirq %d", pic->ops->name, "irq", irq, hwirq); + } + else + { + irq = -RT_ERROR; + } + } + else + { + irq = -RT_EINVAL; + } + + return irq; +} + +struct rt_pic_irq *rt_pic_find_ipi(struct rt_pic *pic, int ipi_index) +{ + struct rt_pic_irq *pirq = &_pirq_hash[ipi_index]; + + RT_ASSERT(ipi_index < RT_ARRAY_SIZE(_ipi_hash)); + RT_ASSERT(pirq->pic == pic); + + return pirq; +} + +int rt_pic_cascade(struct rt_pic *pic, struct rt_pic *parent_pic, int hwirq, rt_uint32_t mode) +{ + int irq = -RT_EINVAL; + + if (pic && parent_pic && hwirq >= 0) + { + struct rt_pic *ppic = parent_pic; + rt_ubase_t level = rt_spin_lock_irqsave(&_pic_lock); + + while (!ppic->ops->irq_map && ppic->parent) + { + ppic = ppic->parent; + } + + rt_spin_unlock_irqrestore(&_pic_lock, level); + + if (ppic->ops->irq_map) + { + struct rt_pic_irq *pirq; + + irq = ppic->ops->irq_map(ppic, hwirq, mode); + + if (irq >= 0 && (pirq = irq2pirq(irq))) + { + rt_spin_lock(&pirq->rw_lock); + + pirq->pic = pic; + pic->parent = parent_pic; + + rt_spin_unlock(&pirq->rw_lock); + + if (rt_list_isempty(&pic->list)) + { + rt_ubase_t level = rt_spin_lock_irqsave(&_pic_lock); + + append_pic(pic); + + rt_spin_unlock_irqrestore(&_pic_lock, level); + } + } + } + else + { + irq = -RT_ENOSYS; + } + } + + return irq; +} + +void rt_pic_uncascade(struct rt_pic *pic, int irq) +{ + struct rt_pic_irq *pirq; + + if (pic && pic->parent && irq >= 0 && (pirq = irq2pirq(irq))) + { + struct rt_pic *ppic, *prev = RT_NULL; + + rt_spin_lock(&pirq->rw_lock); + + ppic = pirq->pic; + + while (ppic && pic->parent != ppic->parent) + { + prev = ppic; + ppic = ppic->parent; + } + + if (ppic) + { + if (prev) + { + pirq->pic = prev; + prev->parent = pic->parent; + } + else + { + pirq->pic = pic->parent; + } + + pic->parent = RT_NULL; + } + + rt_spin_unlock(&pirq->rw_lock); + } +} + +rt_err_t rt_pic_attach_irq(int irq, rt_isr_handler_t handler, void *uid, const char *name, int flags) +{ + rt_err_t err = -RT_EINVAL; + struct rt_pic_irq *pirq; + + if (handler && name && (pirq = irq2pirq(irq))) + { + struct rt_pic_isr *isr = RT_NULL; + rt_ubase_t level = rt_spin_lock_irqsave(&pirq->rw_lock); + + err = RT_EOK; + + if (!pirq->isr.action.handler) + { + /* first attach */ + isr = &pirq->isr; + rt_list_init(&isr->list); + } + else + { + rt_spin_unlock_irqrestore(&pirq->rw_lock, level); + + if ((isr = rt_malloc(sizeof(*isr)))) + { + rt_list_init(&isr->list); + + level = rt_spin_lock_irqsave(&pirq->rw_lock); + + rt_list_insert_after(&pirq->isr.list, &isr->list); + } + else + { + LOG_E("No memory to save '%s' isr", name); + err = -RT_ERROR; + } + } + + if (!err) + { + isr->flags = flags; + isr->action.handler = handler; + isr->action.param = uid; + #ifdef RT_USING_INTERRUPT_INFO + isr->action.counter = 0; + rt_strncpy(isr->action.name, name, RT_NAME_MAX); + #endif + + rt_spin_unlock_irqrestore(&pirq->rw_lock, level); + } + } + + return err; +} + +rt_err_t rt_pic_detach_irq(int irq, void *uid) +{ + rt_err_t err = -RT_EINVAL; + struct rt_pic_irq *pirq = irq2pirq(irq); + + if (pirq) + { + rt_bool_t will_free = RT_FALSE; + struct rt_pic_isr *isr = RT_NULL; + rt_ubase_t level = rt_spin_lock_irqsave(&pirq->rw_lock); + + isr = &pirq->isr; + + if (isr->action.param == uid) + { + if (rt_list_isempty(&isr->list)) + { + isr->action.handler = RT_NULL; + isr->action.param = RT_NULL; + } + else + { + struct rt_pic_isr *next_isr = rt_list_entry(isr->list.next, struct rt_pic_isr, list); + + rt_list_remove(&next_isr->list); + + isr->action.handler = next_isr->action.handler; + isr->action.param = next_isr->action.param; + #ifdef RT_USING_INTERRUPT_INFO + isr->action.counter = next_isr->action.counter; + rt_strncpy(isr->action.name, next_isr->action.name, RT_NAME_MAX); + #endif + + isr = next_isr; + will_free = RT_TRUE; + } + + err = RT_EOK; + } + else + { + rt_list_for_each_entry(isr, &pirq->isr.list, list) + { + if (isr->action.param == uid) + { + err = RT_EOK; + + will_free = RT_TRUE; + rt_list_remove(&isr->list); + break; + } + } + } + + rt_spin_unlock_irqrestore(&pirq->rw_lock, level); + + if (will_free) + { + rt_free(isr); + } + } + + return err; +} + +rt_err_t rt_pic_add_traps(rt_bool_t (*handler)(void *), void *data) +{ + rt_err_t err = -RT_EINVAL; + + if (handler) + { + struct irq_traps *traps = rt_malloc(sizeof(*traps)); + + if (traps) + { + rt_ubase_t level = rt_hw_interrupt_disable(); + + rt_list_init(&traps->list); + + traps->data = data; + traps->handler = handler; + + rt_list_insert_before(&_traps_nodes, &traps->list); + err = RT_EOK; + + rt_hw_interrupt_enable(level); + } + else + { + LOG_E("No memory to save '%p' handler", handler); + err = -RT_ENOMEM; + } + } + + return err; +} + +rt_err_t rt_pic_do_traps(void) +{ + rt_err_t err = -RT_ERROR; + struct irq_traps *traps; + + rt_list_for_each_entry(traps, &_traps_nodes, list) + { + if (traps->handler(traps->data)) + { + err = RT_EOK; + + break; + } + } + + return err; +} + +rt_err_t rt_pic_handle_isr(struct rt_pic_irq *pirq) +{ + rt_err_t err; + rt_list_t *handler_nodes; + struct rt_irq_desc *action; + + RT_ASSERT(pirq != RT_NULL); + RT_ASSERT(pirq->pic != RT_NULL); + + /* Corrected irq affinity */ + rt_bitmap_set_bit(pirq->affinity, rt_hw_cpu_id()); + + handler_nodes = &pirq->isr.list; + action = &pirq->isr.action; + + if (action->handler) + { + action->handler(pirq->irq, action->param); + #ifdef RT_USING_INTERRUPT_INFO + action->counter++; + #endif + + if (!rt_list_isempty(handler_nodes)) + { + struct rt_pic_isr *isr; + + rt_list_for_each_entry(isr, handler_nodes, list) + { + action = &isr->action; + + RT_ASSERT(action->handler != RT_NULL); + + action->handler(pirq->irq, action->param); + #ifdef RT_USING_INTERRUPT_INFO + action->counter++; + #endif + } + } + } + else + { + err = -RT_EEMPTY; + } + + return err; +} + +rt_weak rt_err_t rt_pic_user_extends(struct rt_pic *pic) +{ + return -RT_ENOSYS; +} + +rt_err_t rt_pic_irq_init(void) +{ + rt_err_t err = RT_EOK; + struct rt_pic *pic; + + rt_list_for_each_entry(pic, &_pic_nodes, list) + { + if (pic->ops->irq_init) + { + err = pic->ops->irq_init(pic); + + if (err) + { + LOG_E("PIC = %s init fail", pic->ops->name); + break; + } + } + } + + return err; +} + +rt_err_t rt_pic_irq_finit(void) +{ + rt_err_t err = RT_EOK; + struct rt_pic *pic; + + rt_list_for_each_entry(pic, &_pic_nodes, list) + { + if (pic->ops->irq_finit) + { + err = pic->ops->irq_finit(pic); + + if (err) + { + LOG_E("PIC = %s finit fail", pic->ops->name); + break; + } + } + } + + return err; +} + +#define _irq_call_helper(irq, fn) \ +({ \ + struct rt_pic_irq *pirq; \ + if ((pirq = irq2pirq(irq))) \ + { \ + rt_spin_lock(&pirq->rw_lock); \ + if (pirq->pic->ops->fn) \ + pirq->pic->ops->fn(pirq); \ + rt_spin_unlock(&pirq->rw_lock); \ + } \ +}) + +void rt_pic_irq_enable(int irq) +{ + _irq_call_helper(irq, irq_enable); +} + +void rt_pic_irq_disable(int irq) +{ + _irq_call_helper(irq, irq_disable); +} + +void rt_pic_irq_ack(int irq) +{ + _irq_call_helper(irq, irq_ack); +} + +void rt_pic_irq_mask(int irq) +{ + _irq_call_helper(irq, irq_mask); +} + +void rt_pic_irq_unmask(int irq) +{ + _irq_call_helper(irq, irq_unmask); +} + +void rt_pic_irq_eoi(int irq) +{ + _irq_call_helper(irq, irq_eoi); +} + +#undef _irq_call_helper + +rt_err_t rt_pic_irq_set_priority(int irq, rt_uint32_t priority) +{ + rt_err_t err = -RT_EINVAL; + struct rt_pic_irq *pirq = irq2pirq(irq); + + if (pirq) + { + rt_spin_lock(&pirq->rw_lock); + + if (pirq->pic->ops->irq_set_priority) + { + err = pirq->pic->ops->irq_set_priority(pirq, priority); + + if (!err) + { + pirq->priority = priority; + } + } + else + { + err = -RT_ENOSYS; + } + + rt_spin_unlock(&pirq->rw_lock); + } + + return err; +} + +rt_uint32_t rt_pic_irq_get_priority(int irq) +{ + rt_uint32_t priority = RT_UINT32_MAX; + struct rt_pic_irq *pirq = irq2pirq(irq); + + if (pirq) + { + rt_spin_lock(&pirq->rw_lock); + + priority = pirq->priority; + + rt_spin_unlock(&pirq->rw_lock); + } + + return priority; +} + +rt_err_t rt_pic_irq_set_affinity(int irq, rt_bitmap_t *affinity) +{ + rt_err_t err = -RT_EINVAL; + struct rt_pic_irq *pirq; + + if (affinity && (pirq = irq2pirq(irq))) + { + rt_spin_lock(&pirq->rw_lock); + + if (pirq->pic->ops->irq_set_affinity) + { + err = pirq->pic->ops->irq_set_affinity(pirq, affinity); + + if (!err) + { + rt_memcpy(pirq->affinity, affinity, sizeof(pirq->affinity)); + } + } + else + { + err = -RT_ENOSYS; + } + + rt_spin_unlock(&pirq->rw_lock); + } + + return err; +} + +rt_err_t rt_pic_irq_get_affinity(int irq, rt_bitmap_t *out_affinity) +{ + rt_err_t err = -RT_EINVAL; + struct rt_pic_irq *pirq; + + if (out_affinity && (pirq = irq2pirq(irq))) + { + rt_spin_lock(&pirq->rw_lock); + + rt_memcpy(out_affinity, pirq->affinity, sizeof(pirq->affinity)); + err = RT_EOK; + + rt_spin_unlock(&pirq->rw_lock); + } + + return err; +} + +rt_err_t rt_pic_irq_set_triger_mode(int irq, rt_uint32_t mode) +{ + rt_err_t err = -RT_EINVAL; + struct rt_pic_irq *pirq; + + if ((~mode & RT_IRQ_MODE_MASK) && (pirq = irq2pirq(irq))) + { + rt_spin_lock(&pirq->rw_lock); + + if (pirq->pic->ops->irq_set_triger_mode) + { + err = pirq->pic->ops->irq_set_triger_mode(pirq, mode); + + if (!err) + { + pirq->mode = mode; + } + } + else + { + err = -RT_ENOSYS; + } + + rt_spin_unlock(&pirq->rw_lock); + } + + return err; +} + +rt_uint32_t rt_pic_irq_get_triger_mode(int irq) +{ + rt_uint32_t mode = RT_UINT32_MAX; + struct rt_pic_irq *pirq = irq2pirq(irq); + + if (pirq) + { + rt_spin_lock(&pirq->rw_lock); + + mode = pirq->mode; + + rt_spin_unlock(&pirq->rw_lock); + } + + return mode; +} + +void rt_pic_irq_send_ipi(int irq, rt_bitmap_t *cpumask) +{ + struct rt_pic_irq *pirq; + + if (cpumask && (pirq = irq2pirq(irq))) + { + rt_hw_spin_lock(&pirq->rw_lock.lock); + + if (pirq->pic->ops->irq_send_ipi) + { + pirq->pic->ops->irq_send_ipi(pirq, cpumask); + } + + rt_hw_spin_unlock(&pirq->rw_lock.lock); + } +} + +#define _pirq_parent_call_helper(ppic, pirq, fn, ret,...) \ +({ \ + if (ppic && pirq) \ + { \ + rt_spin_lock(&pirq->rw_lock); \ + if (ppic->ops->fn) \ + { \ + struct rt_pic *cpic; \ + cpic = pirq->pic; /* push old pic */ \ + pirq->pic = ppic; \ + ret ppic->ops->fn(pirq __VA_ARGS__); \ + pirq->pic = cpic; /* pop old pic */ \ + } \ + rt_spin_unlock(&pirq->rw_lock); \ + } \ +}) + +void rt_pic_irq_parent_enable(struct rt_pic *ppic, struct rt_pic_irq *pirq) +{ + _pirq_parent_call_helper(ppic, pirq, irq_enable,,); +} + +void rt_pic_irq_parent_disable(struct rt_pic *ppic, struct rt_pic_irq *pirq) +{ + _pirq_parent_call_helper(ppic, pirq, irq_disable,,); +} + +void rt_pic_irq_parent_ack(struct rt_pic *ppic, struct rt_pic_irq *pirq) +{ + _pirq_parent_call_helper(ppic, pirq, irq_ack,,); +} + +void rt_pic_irq_parent_mask(struct rt_pic *ppic, struct rt_pic_irq *pirq) +{ + _pirq_parent_call_helper(ppic, pirq, irq_mask,,); +} + +void rt_pic_irq_parent_unmask(struct rt_pic *ppic, struct rt_pic_irq *pirq) +{ + _pirq_parent_call_helper(ppic, pirq, irq_unmask,,); +} + +void rt_pic_irq_parent_eoi(struct rt_pic *ppic, struct rt_pic_irq *pirq) +{ + _pirq_parent_call_helper(ppic, pirq, irq_eoi,,); +} + +rt_err_t rt_pic_irq_parent_set_priority(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_uint32_t priority) +{ + rt_err_t err = -RT_ENOSYS; + + _pirq_parent_call_helper(ppic, pirq, irq_set_priority, err = , ,priority); + + return err; +} + +rt_err_t rt_pic_irq_parent_set_affinity(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_bitmap_t *affinity) +{ + rt_err_t err = -RT_ENOSYS; + + _pirq_parent_call_helper(ppic, pirq, irq_set_affinity, err = , ,affinity); + + return err; +} + +rt_err_t rt_pic_irq_parent_set_triger_mode(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_uint32_t mode) +{ + rt_err_t err = -RT_ENOSYS; + + _pirq_parent_call_helper(ppic, pirq, irq_set_triger_mode, err = , ,mode); + + return err; +} + +#undef _pirq_parent_call_helper + +#ifdef RT_USING_OFW +RT_OFW_STUB_RANGE_EXPORT(pic, _pic_ofw_start, _pic_ofw_end); + +static rt_err_t ofw_pic_init(void) +{ + struct rt_ofw_node *ic_np; + + rt_ofw_foreach_node_by_prop(ic_np, "interrupt-controller") + { + rt_ofw_stub_probe_range(ic_np, &_pic_ofw_start, &_pic_ofw_end); + } + + return RT_EOK; +} +#else +static rt_err_t ofw_pic_init(void) +{ + return RT_EOK; +} +#endif /* !RT_USING_OFW */ + +rt_err_t rt_pic_init(void) +{ + rt_err_t err; + + LOG_D("init start"); + + err = ofw_pic_init(); + + LOG_D("init end"); + + return err; +} + +#if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH) +static int list_irq(int argc, char**argv) +{ + rt_ubase_t level; + rt_size_t irq_nr = 0; + rt_bool_t dump_all = RT_FALSE; + const char *const irq_modes[] = + { + [RT_IRQ_MODE_NONE] = "None", + [RT_IRQ_MODE_EDGE_RISING] = "Edge-Rising", + [RT_IRQ_MODE_EDGE_FALLING] = "Edge-Falling", + [RT_IRQ_MODE_EDGE_BOTH] = "Edge-Both", + [RT_IRQ_MODE_LEVEL_HIGH] = "Level-High", + [RT_IRQ_MODE_LEVEL_LOW] = "Level-Low", + }; + static char info[RT_CONSOLEBUF_SIZE]; +#ifdef RT_USING_SMP + static char cpumask[RT_CPUS_NR + 1] = { [RT_CPUS_NR] = '\0' }; +#endif + + if (argc > 1) + { + if (!rt_strcmp(argv[1], "all")) + { + dump_all = RT_TRUE; + } + } + + level = rt_hw_interrupt_disable(); + + rt_kprintf("%-*.s %-*.s %s %-*.s %-*.s %-*.s %-*.sUsers%s\n", + 10, "IRQ", + 10, "HW-IRQ", + "MSI", + _pic_name_max, "PIC", + 12, "Mode", + #ifdef RT_USING_SMP + RT_CPUS_NR, "CPUs", + #else + 0, 0, + #endif + #ifdef RT_USING_INTERRUPT_INFO + 11, "Count", + "" + #else + 0, 0, + "-Number" + #endif + ); + + for (int i = 0; i < RT_ARRAY_SIZE(_pirq_hash); ++i) + { + struct rt_pic_irq *pirq = &_pirq_hash[i]; + + if (!pirq->pic || !(dump_all || pirq->isr.action.handler)) + { + continue; + } + + rt_snprintf(info, sizeof(info), "%-10d %-10d %c %-*.s %-*.s ", + pirq->irq, + pirq->hwirq, + pirq->msi_desc ? 'Y' : 'N', + _pic_name_max, pirq->pic->ops->name, + 12, irq_modes[pirq->mode]); + + #ifdef RT_USING_SMP + for (int group = 0, id = 0; group < RT_ARRAY_SIZE(pirq->affinity); ++group) + { + rt_bitmap_t mask = pirq->affinity[group]; + + for (int idx = 0; id < RT_CPUS_NR && idx < BITMAP_BIT_LEN(1); ++idx, ++id) + { + cpumask[RT_ARRAY_SIZE(cpumask) - id - 2] = '0' + ((mask >> idx) & 1); + } + } + #endif /* RT_USING_SMP */ + + rt_kputs(info); + #ifdef RT_USING_SMP + rt_kputs(cpumask); + #endif + + #ifdef RT_USING_INTERRUPT_INFO + rt_kprintf(" %-10d ", pirq->isr.action.counter); + rt_kputs(pirq->isr.action.name); + rt_kputs("\n"); + + if (!rt_list_isempty(&pirq->isr.list)) + { + struct rt_pic_isr *repeat_isr; + + rt_list_for_each_entry(repeat_isr, &pirq->isr.list, list) + { + rt_kputs(info); + #ifdef RT_USING_SMP + rt_kputs(cpumask); + #endif + rt_kprintf("%-10d ", repeat_isr->action.counter); + rt_kputs(repeat_isr->action.name); + rt_kputs("\n"); + } + } + #else + rt_kprintf(" %d\n", rt_list_len(&pirq->isr.list)); + #endif + + ++irq_nr; + } + + rt_hw_interrupt_enable(level); + + rt_kprintf("%d IRQs found\n", irq_nr); + + return 0; +} +MSH_CMD_EXPORT(list_irq, dump using or args = all of irq information); +#endif /* RT_USING_CONSOLE && RT_USING_MSH */ diff --git a/components/utilities/Kconfig b/components/utilities/Kconfig index 93afcc01b0..a1597db9b5 100644 --- a/components/utilities/Kconfig +++ b/components/utilities/Kconfig @@ -216,15 +216,11 @@ config RT_USING_VAR_EXPORT bool "Enable Var Export" default n -config RT_USING_ADT - bool "Enable ADT(abstract data type), such as AVL tree" - default y if ARCH_MM_MMU - default n - config RT_USING_RESOURCE_ID bool "Enable resource id" default n +source "$RTT_DIR/components/utilities/libadt/Kconfig" source "$RTT_DIR/components/utilities/rt-link/Kconfig" endmenu -- cgit v1.3.1 From cc8781930c234c50b899d296b3d38316f4836d3b Mon Sep 17 00:00:00 2001 From: erikchan <1043490933@qq.com> Date: Thu, 6 Jul 2023 11:02:13 +0800 Subject: 【libfdt】replace tab with space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/drivers/ofw/libfdt/fdt.c | 500 ++++----- components/drivers/ofw/libfdt/fdt.h | 70 +- components/drivers/ofw/libfdt/fdt_addresses.c | 134 +-- components/drivers/ofw/libfdt/fdt_empty_tree.c | 34 +- components/drivers/ofw/libfdt/fdt_overlay.c | 1142 +++++++++---------- components/drivers/ofw/libfdt/fdt_ro.c | 1170 +++++++++---------- components/drivers/ofw/libfdt/fdt_rw.c | 690 ++++++------ components/drivers/ofw/libfdt/fdt_strerror.c | 72 +- components/drivers/ofw/libfdt/fdt_sw.c | 492 ++++---- components/drivers/ofw/libfdt/fdt_wip.c | 90 +- components/drivers/ofw/libfdt/libfdt.h | 1366 +++++++++++------------ components/drivers/ofw/libfdt/libfdt_env.h | 22 +- components/drivers/ofw/libfdt/libfdt_internal.h | 212 ++-- 13 files changed, 2997 insertions(+), 2997 deletions(-) diff --git a/components/drivers/ofw/libfdt/fdt.c b/components/drivers/ofw/libfdt/fdt.c index 20c6415b9c..b400a18a39 100644 --- a/components/drivers/ofw/libfdt/fdt.c +++ b/components/drivers/ofw/libfdt/fdt.c @@ -17,323 +17,323 @@ */ int32_t fdt_ro_probe_(const void *fdt) { - uint32_t totalsize = fdt_totalsize(fdt); - - if (can_assume(VALID_DTB)) - return totalsize; - - /* The device tree must be at an 8-byte aligned address */ - if ((uintptr_t)fdt & 7) - return -FDT_ERR_ALIGNMENT; - - if (fdt_magic(fdt) == FDT_MAGIC) { - /* Complete tree */ - if (!can_assume(LATEST)) { - if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - if (fdt_last_comp_version(fdt) > - FDT_LAST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - } - } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { - /* Unfinished sequential-write blob */ - if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0) - return -FDT_ERR_BADSTATE; - } else { - return -FDT_ERR_BADMAGIC; - } - - if (totalsize < INT32_MAX) - return totalsize; - else - return -FDT_ERR_TRUNCATED; + uint32_t totalsize = fdt_totalsize(fdt); + + if (can_assume(VALID_DTB)) + return totalsize; + + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + + if (fdt_magic(fdt) == FDT_MAGIC) { + /* Complete tree */ + if (!can_assume(LATEST)) { + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + if (fdt_last_comp_version(fdt) > + FDT_LAST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + } + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + /* Unfinished sequential-write blob */ + if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0) + return -FDT_ERR_BADSTATE; + } else { + return -FDT_ERR_BADMAGIC; + } + + if (totalsize < INT32_MAX) + return totalsize; + else + return -FDT_ERR_TRUNCATED; } static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off) { - return (off >= hdrsize) && (off <= totalsize); + return (off >= hdrsize) && (off <= totalsize); } static int check_block_(uint32_t hdrsize, uint32_t totalsize, - uint32_t base, uint32_t size) + uint32_t base, uint32_t size) { - if (!check_off_(hdrsize, totalsize, base)) - return 0; /* block start out of bounds */ - if ((base + size) < base) - return 0; /* overflow */ - if (!check_off_(hdrsize, totalsize, base + size)) - return 0; /* block end out of bounds */ - return 1; + if (!check_off_(hdrsize, totalsize, base)) + return 0; /* block start out of bounds */ + if ((base + size) < base) + return 0; /* overflow */ + if (!check_off_(hdrsize, totalsize, base + size)) + return 0; /* block end out of bounds */ + return 1; } size_t fdt_header_size_(uint32_t version) { - if (version <= 1) - return FDT_V1_SIZE; - else if (version <= 2) - return FDT_V2_SIZE; - else if (version <= 3) - return FDT_V3_SIZE; - else if (version <= 16) - return FDT_V16_SIZE; - else - return FDT_V17_SIZE; + if (version <= 1) + return FDT_V1_SIZE; + else if (version <= 2) + return FDT_V2_SIZE; + else if (version <= 3) + return FDT_V3_SIZE; + else if (version <= 16) + return FDT_V16_SIZE; + else + return FDT_V17_SIZE; } size_t fdt_header_size(const void *fdt) { - return can_assume(LATEST) ? FDT_V17_SIZE : - fdt_header_size_(fdt_version(fdt)); + return can_assume(LATEST) ? FDT_V17_SIZE : + fdt_header_size_(fdt_version(fdt)); } int fdt_check_header(const void *fdt) { - size_t hdrsize; - - /* The device tree must be at an 8-byte aligned address */ - if ((uintptr_t)fdt & 7) - return -FDT_ERR_ALIGNMENT; - - if (fdt_magic(fdt) != FDT_MAGIC) - return -FDT_ERR_BADMAGIC; - if (!can_assume(LATEST)) { - if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) - || (fdt_last_comp_version(fdt) > - FDT_LAST_SUPPORTED_VERSION)) - return -FDT_ERR_BADVERSION; - if (fdt_version(fdt) < fdt_last_comp_version(fdt)) - return -FDT_ERR_BADVERSION; - } - hdrsize = fdt_header_size(fdt); - if (!can_assume(VALID_DTB)) { - if ((fdt_totalsize(fdt) < hdrsize) - || (fdt_totalsize(fdt) > INT_MAX)) - return -FDT_ERR_TRUNCATED; - - /* Bounds check memrsv block */ - if (!check_off_(hdrsize, fdt_totalsize(fdt), - fdt_off_mem_rsvmap(fdt))) - return -FDT_ERR_TRUNCATED; - - /* Bounds check structure block */ - if (!can_assume(LATEST) && fdt_version(fdt) < 17) { - if (!check_off_(hdrsize, fdt_totalsize(fdt), - fdt_off_dt_struct(fdt))) - return -FDT_ERR_TRUNCATED; - } else { - if (!check_block_(hdrsize, fdt_totalsize(fdt), - fdt_off_dt_struct(fdt), - fdt_size_dt_struct(fdt))) - return -FDT_ERR_TRUNCATED; - } - - /* Bounds check strings block */ - if (!check_block_(hdrsize, fdt_totalsize(fdt), - fdt_off_dt_strings(fdt), - fdt_size_dt_strings(fdt))) - return -FDT_ERR_TRUNCATED; - } - - return 0; + size_t hdrsize; + + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + + if (fdt_magic(fdt) != FDT_MAGIC) + return -FDT_ERR_BADMAGIC; + if (!can_assume(LATEST)) { + if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + || (fdt_last_comp_version(fdt) > + FDT_LAST_SUPPORTED_VERSION)) + return -FDT_ERR_BADVERSION; + if (fdt_version(fdt) < fdt_last_comp_version(fdt)) + return -FDT_ERR_BADVERSION; + } + hdrsize = fdt_header_size(fdt); + if (!can_assume(VALID_DTB)) { + if ((fdt_totalsize(fdt) < hdrsize) + || (fdt_totalsize(fdt) > INT_MAX)) + return -FDT_ERR_TRUNCATED; + + /* Bounds check memrsv block */ + if (!check_off_(hdrsize, fdt_totalsize(fdt), + fdt_off_mem_rsvmap(fdt))) + return -FDT_ERR_TRUNCATED; + + /* Bounds check structure block */ + if (!can_assume(LATEST) && fdt_version(fdt) < 17) { + if (!check_off_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } else { + if (!check_block_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } + + /* Bounds check strings block */ + if (!check_block_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_strings(fdt), + fdt_size_dt_strings(fdt))) + return -FDT_ERR_TRUNCATED; + } + + return 0; } const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { - unsigned int uoffset = offset; - unsigned int absoffset = offset + fdt_off_dt_struct(fdt); + unsigned int uoffset = offset; + unsigned int absoffset = offset + fdt_off_dt_struct(fdt); - if (offset < 0) - return NULL; + if (offset < 0) + return NULL; - if (!can_assume(VALID_INPUT)) - if ((absoffset < uoffset) - || ((absoffset + len) < absoffset) - || (absoffset + len) > fdt_totalsize(fdt)) - return NULL; + if (!can_assume(VALID_INPUT)) + if ((absoffset < uoffset) + || ((absoffset + len) < absoffset) + || (absoffset + len) > fdt_totalsize(fdt)) + return NULL; - if (can_assume(LATEST) || fdt_version(fdt) >= 0x11) - if (((uoffset + len) < uoffset) - || ((offset + len) > fdt_size_dt_struct(fdt))) - return NULL; + if (can_assume(LATEST) || fdt_version(fdt) >= 0x11) + if (((uoffset + len) < uoffset) + || ((offset + len) > fdt_size_dt_struct(fdt))) + return NULL; - return fdt_offset_ptr_(fdt, offset); + return fdt_offset_ptr_(fdt, offset); } uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { - const fdt32_t *tagp, *lenp; - uint32_t tag, len, sum; - int offset = startoffset; - const char *p; - - *nextoffset = -FDT_ERR_TRUNCATED; - tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); - if (!can_assume(VALID_DTB) && !tagp) - return FDT_END; /* premature end */ - tag = fdt32_to_cpu(*tagp); - offset += FDT_TAGSIZE; - - *nextoffset = -FDT_ERR_BADSTRUCTURE; - switch (tag) { - case FDT_BEGIN_NODE: - /* skip name */ - do { - p = fdt_offset_ptr(fdt, offset++, 1); - } while (p && (*p != '\0')); - if (!can_assume(VALID_DTB) && !p) - return FDT_END; /* premature end */ - break; - - case FDT_PROP: - lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); - if (!can_assume(VALID_DTB) && !lenp) - return FDT_END; /* premature end */ - - len = fdt32_to_cpu(*lenp); - sum = len + offset; - if (!can_assume(VALID_DTB) && - (INT_MAX <= sum || sum < (uint32_t) offset)) - return FDT_END; /* premature end */ - - /* skip-name offset, length and value */ - offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len; - - if (!can_assume(LATEST) && - fdt_version(fdt) < 0x10 && len >= 8 && - ((offset - len) % 8) != 0) - offset += 4; - break; - - case FDT_END: - case FDT_END_NODE: - case FDT_NOP: - break; - - default: - return FDT_END; - } - - if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) - return FDT_END; /* premature end */ - - *nextoffset = FDT_TAGALIGN(offset); - return tag; + const fdt32_t *tagp, *lenp; + uint32_t tag, len, sum; + int offset = startoffset; + const char *p; + + *nextoffset = -FDT_ERR_TRUNCATED; + tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); + if (!can_assume(VALID_DTB) && !tagp) + return FDT_END; /* premature end */ + tag = fdt32_to_cpu(*tagp); + offset += FDT_TAGSIZE; + + *nextoffset = -FDT_ERR_BADSTRUCTURE; + switch (tag) { + case FDT_BEGIN_NODE: + /* skip name */ + do { + p = fdt_offset_ptr(fdt, offset++, 1); + } while (p && (*p != '\0')); + if (!can_assume(VALID_DTB) && !p) + return FDT_END; /* premature end */ + break; + + case FDT_PROP: + lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); + if (!can_assume(VALID_DTB) && !lenp) + return FDT_END; /* premature end */ + + len = fdt32_to_cpu(*lenp); + sum = len + offset; + if (!can_assume(VALID_DTB) && + (INT_MAX <= sum || sum < (uint32_t) offset)) + return FDT_END; /* premature end */ + + /* skip-name offset, length and value */ + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len; + + if (!can_assume(LATEST) && + fdt_version(fdt) < 0x10 && len >= 8 && + ((offset - len) % 8) != 0) + offset += 4; + break; + + case FDT_END: + case FDT_END_NODE: + case FDT_NOP: + break; + + default: + return FDT_END; + } + + if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) + return FDT_END; /* premature end */ + + *nextoffset = FDT_TAGALIGN(offset); + return tag; } int fdt_check_node_offset_(const void *fdt, int offset) { - if (!can_assume(VALID_INPUT) - && ((offset < 0) || (offset % FDT_TAGSIZE))) - return -FDT_ERR_BADOFFSET; + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; - if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE) - return -FDT_ERR_BADOFFSET; + if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE) + return -FDT_ERR_BADOFFSET; - return offset; + return offset; } int fdt_check_prop_offset_(const void *fdt, int offset) { - if (!can_assume(VALID_INPUT) - && ((offset < 0) || (offset % FDT_TAGSIZE))) - return -FDT_ERR_BADOFFSET; + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; - if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP) - return -FDT_ERR_BADOFFSET; + if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP) + return -FDT_ERR_BADOFFSET; - return offset; + return offset; } int fdt_next_node(const void *fdt, int offset, int *depth) { - int nextoffset = 0; - uint32_t tag; - - if (offset >= 0) - if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0) - return nextoffset; - - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_PROP: - case FDT_NOP: - break; - - case FDT_BEGIN_NODE: - if (depth) - (*depth)++; - break; - - case FDT_END_NODE: - if (depth && ((--(*depth)) < 0)) - return nextoffset; - break; - - case FDT_END: - if ((nextoffset >= 0) - || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) - return -FDT_ERR_NOTFOUND; - else - return nextoffset; - } - } while (tag != FDT_BEGIN_NODE); - - return offset; + int nextoffset = 0; + uint32_t tag; + + if (offset >= 0) + if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0) + return nextoffset; + + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_PROP: + case FDT_NOP: + break; + + case FDT_BEGIN_NODE: + if (depth) + (*depth)++; + break; + + case FDT_END_NODE: + if (depth && ((--(*depth)) < 0)) + return nextoffset; + break; + + case FDT_END: + if ((nextoffset >= 0) + || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) + return -FDT_ERR_NOTFOUND; + else + return nextoffset; + } + } while (tag != FDT_BEGIN_NODE); + + return offset; } int fdt_first_subnode(const void *fdt, int offset) { - int depth = 0; + int depth = 0; - offset = fdt_next_node(fdt, offset, &depth); - if (offset < 0 || depth != 1) - return -FDT_ERR_NOTFOUND; + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth != 1) + return -FDT_ERR_NOTFOUND; - return offset; + return offset; } int fdt_next_subnode(const void *fdt, int offset) { - int depth = 1; - - /* - * With respect to the parent, the depth of the next subnode will be - * the same as the last. - */ - do { - offset = fdt_next_node(fdt, offset, &depth); - if (offset < 0 || depth < 1) - return -FDT_ERR_NOTFOUND; - } while (depth > 1); - - return offset; + int depth = 1; + + /* + * With respect to the parent, the depth of the next subnode will be + * the same as the last. + */ + do { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth < 1) + return -FDT_ERR_NOTFOUND; + } while (depth > 1); + + return offset; } const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) { - int len = strlen(s) + 1; - const char *last = strtab + tabsize - len; - const char *p; - - for (p = strtab; p <= last; p++) - if (memcmp(p, s, len) == 0) - return p; - return NULL; + int len = strlen(s) + 1; + const char *last = strtab + tabsize - len; + const char *p; + + for (p = strtab; p <= last; p++) + if (memcmp(p, s, len) == 0) + return p; + return NULL; } int fdt_move(const void *fdt, void *buf, int bufsize) { - if (!can_assume(VALID_INPUT) && bufsize < 0) - return -FDT_ERR_NOSPACE; + if (!can_assume(VALID_INPUT) && bufsize < 0) + return -FDT_ERR_NOSPACE; - FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdt); - if (fdt_totalsize(fdt) > (unsigned int)bufsize) - return -FDT_ERR_NOSPACE; + if (fdt_totalsize(fdt) > (unsigned int)bufsize) + return -FDT_ERR_NOSPACE; - memmove(buf, fdt, fdt_totalsize(fdt)); - return 0; + memmove(buf, fdt, fdt_totalsize(fdt)); + return 0; } diff --git a/components/drivers/ofw/libfdt/fdt.h b/components/drivers/ofw/libfdt/fdt.h index 0c91aa7f67..0b5523b973 100644 --- a/components/drivers/ofw/libfdt/fdt.h +++ b/components/drivers/ofw/libfdt/fdt.h @@ -10,57 +10,57 @@ #ifndef __ASSEMBLY__ struct fdt_header { - fdt32_t magic; /* magic word FDT_MAGIC */ - fdt32_t totalsize; /* total size of DT block */ - fdt32_t off_dt_struct; /* offset to structure */ - fdt32_t off_dt_strings; /* offset to strings */ - fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ - fdt32_t version; /* format version */ - fdt32_t last_comp_version; /* last compatible version */ + fdt32_t magic; /* magic word FDT_MAGIC */ + fdt32_t totalsize; /* total size of DT block */ + fdt32_t off_dt_struct; /* offset to structure */ + fdt32_t off_dt_strings; /* offset to strings */ + fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ + fdt32_t version; /* format version */ + fdt32_t last_comp_version; /* last compatible version */ - /* version 2 fields below */ - fdt32_t boot_cpuid_phys; /* Which physical CPU id we're - booting on */ - /* version 3 fields below */ - fdt32_t size_dt_strings; /* size of the strings block */ + /* version 2 fields below */ + fdt32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + fdt32_t size_dt_strings; /* size of the strings block */ - /* version 17 fields below */ - fdt32_t size_dt_struct; /* size of the structure block */ + /* version 17 fields below */ + fdt32_t size_dt_struct; /* size of the structure block */ }; struct fdt_reserve_entry { - fdt64_t address; - fdt64_t size; + fdt64_t address; + fdt64_t size; }; struct fdt_node_header { - fdt32_t tag; - char name[]; + fdt32_t tag; + char name[]; }; struct fdt_property { - fdt32_t tag; - fdt32_t len; - fdt32_t nameoff; - char data[]; + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; + char data[]; }; #endif /* !__ASSEMBLY */ -#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ -#define FDT_TAGSIZE sizeof(fdt32_t) +#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ +#define FDT_TAGSIZE sizeof(fdt32_t) -#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ -#define FDT_END_NODE 0x2 /* End node */ -#define FDT_PROP 0x3 /* Property: name off, - size, content */ -#define FDT_NOP 0x4 /* nop */ -#define FDT_END 0x9 +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, + size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 -#define FDT_V1_SIZE (7*sizeof(fdt32_t)) -#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) -#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) -#define FDT_V16_SIZE FDT_V3_SIZE -#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) +#define FDT_V1_SIZE (7*sizeof(fdt32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) +#define FDT_V16_SIZE FDT_V3_SIZE +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) #endif /* FDT_H */ diff --git a/components/drivers/ofw/libfdt/fdt_addresses.c b/components/drivers/ofw/libfdt/fdt_addresses.c index c40ba094f1..b69420d49e 100644 --- a/components/drivers/ofw/libfdt/fdt_addresses.c +++ b/components/drivers/ofw/libfdt/fdt_addresses.c @@ -13,89 +13,89 @@ static int fdt_cells(const void *fdt, int nodeoffset, const char *name) { - const fdt32_t *c; - uint32_t val; - int len; + const fdt32_t *c; + uint32_t val; + int len; - c = fdt_getprop(fdt, nodeoffset, name, &len); - if (!c) - return len; + c = fdt_getprop(fdt, nodeoffset, name, &len); + if (!c) + return len; - if (len != sizeof(*c)) - return -FDT_ERR_BADNCELLS; + if (len != sizeof(*c)) + return -FDT_ERR_BADNCELLS; - val = fdt32_to_cpu(*c); - if (val > FDT_MAX_NCELLS) - return -FDT_ERR_BADNCELLS; + val = fdt32_to_cpu(*c); + if (val > FDT_MAX_NCELLS) + return -FDT_ERR_BADNCELLS; - return (int)val; + return (int)val; } int fdt_address_cells(const void *fdt, int nodeoffset) { - int val; - - val = fdt_cells(fdt, nodeoffset, "#address-cells"); - if (val == 0) - return -FDT_ERR_BADNCELLS; - if (val == -FDT_ERR_NOTFOUND) - return 2; - return val; + int val; + + val = fdt_cells(fdt, nodeoffset, "#address-cells"); + if (val == 0) + return -FDT_ERR_BADNCELLS; + if (val == -FDT_ERR_NOTFOUND) + return 2; + return val; } int fdt_size_cells(const void *fdt, int nodeoffset) { - int val; + int val; - val = fdt_cells(fdt, nodeoffset, "#size-cells"); - if (val == -FDT_ERR_NOTFOUND) - return 1; - return val; + val = fdt_cells(fdt, nodeoffset, "#size-cells"); + if (val == -FDT_ERR_NOTFOUND) + return 1; + return val; } /* This function assumes that [address|size]_cells is 1 or 2 */ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, - const char *name, uint64_t addr, uint64_t size) + const char *name, uint64_t addr, uint64_t size) { - int addr_cells, size_cells, ret; - uint8_t data[sizeof(fdt64_t) * 2], *prop; - - ret = fdt_address_cells(fdt, parent); - if (ret < 0) - return ret; - addr_cells = ret; - - ret = fdt_size_cells(fdt, parent); - if (ret < 0) - return ret; - size_cells = ret; - - /* check validity of address */ - prop = data; - if (addr_cells == 1) { - if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) - return -FDT_ERR_BADVALUE; - - fdt32_st(prop, (uint32_t)addr); - } else if (addr_cells == 2) { - fdt64_st(prop, addr); - } else { - return -FDT_ERR_BADNCELLS; - } - - /* check validity of size */ - prop += addr_cells * sizeof(fdt32_t); - if (size_cells == 1) { - if (size > UINT32_MAX) - return -FDT_ERR_BADVALUE; - - fdt32_st(prop, (uint32_t)size); - } else if (size_cells == 2) { - fdt64_st(prop, size); - } else { - return -FDT_ERR_BADNCELLS; - } - - return fdt_appendprop(fdt, nodeoffset, name, data, - (addr_cells + size_cells) * sizeof(fdt32_t)); + int addr_cells, size_cells, ret; + uint8_t data[sizeof(fdt64_t) * 2], *prop; + + ret = fdt_address_cells(fdt, parent); + if (ret < 0) + return ret; + addr_cells = ret; + + ret = fdt_size_cells(fdt, parent); + if (ret < 0) + return ret; + size_cells = ret; + + /* check validity of address */ + prop = data; + if (addr_cells == 1) { + if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) + return -FDT_ERR_BADVALUE; + + fdt32_st(prop, (uint32_t)addr); + } else if (addr_cells == 2) { + fdt64_st(prop, addr); + } else { + return -FDT_ERR_BADNCELLS; + } + + /* check validity of size */ + prop += addr_cells * sizeof(fdt32_t); + if (size_cells == 1) { + if (size > UINT32_MAX) + return -FDT_ERR_BADVALUE; + + fdt32_st(prop, (uint32_t)size); + } else if (size_cells == 2) { + fdt64_st(prop, size); + } else { + return -FDT_ERR_BADNCELLS; + } + + return fdt_appendprop(fdt, nodeoffset, name, data, + (addr_cells + size_cells) * sizeof(fdt32_t)); } diff --git a/components/drivers/ofw/libfdt/fdt_empty_tree.c b/components/drivers/ofw/libfdt/fdt_empty_tree.c index 49d54d44b8..3bf4fea2a7 100644 --- a/components/drivers/ofw/libfdt/fdt_empty_tree.c +++ b/components/drivers/ofw/libfdt/fdt_empty_tree.c @@ -12,27 +12,27 @@ int fdt_create_empty_tree(void *buf, int bufsize) { - int err; + int err; - err = fdt_create(buf, bufsize); - if (err) - return err; + err = fdt_create(buf, bufsize); + if (err) + return err; - err = fdt_finish_reservemap(buf); - if (err) - return err; + err = fdt_finish_reservemap(buf); + if (err) + return err; - err = fdt_begin_node(buf, ""); - if (err) - return err; + err = fdt_begin_node(buf, ""); + if (err) + return err; - err = fdt_end_node(buf); - if (err) - return err; + err = fdt_end_node(buf); + if (err) + return err; - err = fdt_finish(buf); - if (err) - return err; + err = fdt_finish(buf); + if (err) + return err; - return fdt_open_into(buf, buf, bufsize); + return fdt_open_into(buf, buf, bufsize); } diff --git a/components/drivers/ofw/libfdt/fdt_overlay.c b/components/drivers/ofw/libfdt/fdt_overlay.c index 5c0c3981b8..1251c40327 100644 --- a/components/drivers/ofw/libfdt/fdt_overlay.c +++ b/components/drivers/ofw/libfdt/fdt_overlay.c @@ -23,65 +23,65 @@ * returns: * the phandle pointed by the target property * 0, if the phandle was not found - * -1, if the phandle was malformed + * -1, if the phandle was malformed */ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) { - const fdt32_t *val; - int len; + const fdt32_t *val; + int len; - val = fdt_getprop(fdto, fragment, "target", &len); - if (!val) - return 0; + val = fdt_getprop(fdto, fragment, "target", &len); + if (!val) + return 0; - if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) - return (uint32_t)-1; + if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) + return (uint32_t)-1; - return fdt32_to_cpu(*val); + return fdt32_to_cpu(*val); } int fdt_overlay_target_offset(const void *fdt, const void *fdto, - int fragment_offset, char const **pathp) + int fragment_offset, char const **pathp) { - uint32_t phandle; - const char *path = NULL; - int path_len = 0, ret; - - /* Try first to do a phandle based lookup */ - phandle = overlay_get_target_phandle(fdto, fragment_offset); - if (phandle == (uint32_t)-1) - return -FDT_ERR_BADPHANDLE; - - /* no phandle, try path */ - if (!phandle) { - /* And then a path based lookup */ - path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len); - if (path) - ret = fdt_path_offset(fdt, path); - else - ret = path_len; - } else - ret = fdt_node_offset_by_phandle(fdt, phandle); - - /* - * If we haven't found either a target or a - * target-path property in a node that contains a - * __overlay__ subnode (we wouldn't be called - * otherwise), consider it a improperly written - * overlay - */ - if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) - ret = -FDT_ERR_BADOVERLAY; - - /* return on error */ - if (ret < 0) - return ret; - - /* return pointer to path (if available) */ - if (pathp) - *pathp = path ? path : NULL; - - return ret; + uint32_t phandle; + const char *path = NULL; + int path_len = 0, ret; + + /* Try first to do a phandle based lookup */ + phandle = overlay_get_target_phandle(fdto, fragment_offset); + if (phandle == (uint32_t)-1) + return -FDT_ERR_BADPHANDLE; + + /* no phandle, try path */ + if (!phandle) { + /* And then a path based lookup */ + path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len); + if (path) + ret = fdt_path_offset(fdt, path); + else + ret = path_len; + } else + ret = fdt_node_offset_by_phandle(fdt, phandle); + + /* + * If we haven't found either a target or a + * target-path property in a node that contains a + * __overlay__ subnode (we wouldn't be called + * otherwise), consider it a improperly written + * overlay + */ + if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) + ret = -FDT_ERR_BADOVERLAY; + + /* return on error */ + if (ret < 0) + return ret; + + /* return pointer to path (if available) */ + if (pathp) + *pathp = path ? path : NULL; + + return ret; } /** @@ -99,28 +99,28 @@ int fdt_overlay_target_offset(const void *fdt, const void *fdto, * Negative error code on error */ static int overlay_phandle_add_offset(void *fdt, int node, - const char *name, uint32_t delta) + const char *name, uint32_t delta) { - const fdt32_t *val; - uint32_t adj_val; - int len; + const fdt32_t *val; + uint32_t adj_val; + int len; - val = fdt_getprop(fdt, node, name, &len); - if (!val) - return len; + val = fdt_getprop(fdt, node, name, &len); + if (!val) + return len; - if (len != sizeof(*val)) - return -FDT_ERR_BADPHANDLE; + if (len != sizeof(*val)) + return -FDT_ERR_BADPHANDLE; - adj_val = fdt32_to_cpu(*val); - if ((adj_val + delta) < adj_val) - return -FDT_ERR_NOPHANDLES; + adj_val = fdt32_to_cpu(*val); + if ((adj_val + delta) < adj_val) + return -FDT_ERR_NOPHANDLES; - adj_val += delta; - if (adj_val == (uint32_t)-1) - return -FDT_ERR_NOPHANDLES; + adj_val += delta; + if (adj_val == (uint32_t)-1) + return -FDT_ERR_NOPHANDLES; - return fdt_setprop_inplace_u32(fdt, node, name, adj_val); + return fdt_setprop_inplace_u32(fdt, node, name, adj_val); } /** @@ -139,26 +139,26 @@ static int overlay_phandle_add_offset(void *fdt, int node, * Negative error code on failure */ static int overlay_adjust_node_phandles(void *fdto, int node, - uint32_t delta) + uint32_t delta) { - int child; - int ret; + int child; + int ret; - ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); - if (ret && ret != -FDT_ERR_NOTFOUND) - return ret; + ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; - ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); - if (ret && ret != -FDT_ERR_NOTFOUND) - return ret; + ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; - fdt_for_each_subnode(child, fdto, node) { - ret = overlay_adjust_node_phandles(fdto, child, delta); - if (ret) - return ret; - } + fdt_for_each_subnode(child, fdto, node) { + ret = overlay_adjust_node_phandles(fdto, child, delta); + if (ret) + return ret; + } - return 0; + return 0; } /** @@ -177,10 +177,10 @@ static int overlay_adjust_node_phandles(void *fdto, int node, */ static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) { - /* - * Start adjusting the phandles from the overlay root - */ - return overlay_adjust_node_phandles(fdto, 0, delta); + /* + * Start adjusting the phandles from the overlay root + */ + return overlay_adjust_node_phandles(fdto, 0, delta); } /** @@ -203,91 +203,91 @@ static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) * Negative error code on failure */ static int overlay_update_local_node_references(void *fdto, - int tree_node, - int fixup_node, - uint32_t delta) + int tree_node, + int fixup_node, + uint32_t delta) { - int fixup_prop; - int fixup_child; - int ret; - - fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { - const fdt32_t *fixup_val; - const char *tree_val; - const char *name; - int fixup_len; - int tree_len; - int i; - - fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, - &name, &fixup_len); - if (!fixup_val) - return fixup_len; - - if (fixup_len % sizeof(uint32_t)) - return -FDT_ERR_BADOVERLAY; - fixup_len /= sizeof(uint32_t); - - tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); - if (!tree_val) { - if (tree_len == -FDT_ERR_NOTFOUND) - return -FDT_ERR_BADOVERLAY; - - return tree_len; - } - - for (i = 0; i < fixup_len; i++) { - fdt32_t adj_val; - uint32_t poffset; - - poffset = fdt32_to_cpu(fixup_val[i]); - - /* - * phandles to fixup can be unaligned. - * - * Use a memcpy for the architectures that do - * not support unaligned accesses. - */ - memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); - - adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); - - ret = fdt_setprop_inplace_namelen_partial(fdto, - tree_node, - name, - strlen(name), - poffset, - &adj_val, - sizeof(adj_val)); - if (ret == -FDT_ERR_NOSPACE) - return -FDT_ERR_BADOVERLAY; - - if (ret) - return ret; - } - } - - fdt_for_each_subnode(fixup_child, fdto, fixup_node) { - const char *fixup_child_name = fdt_get_name(fdto, fixup_child, - NULL); - int tree_child; - - tree_child = fdt_subnode_offset(fdto, tree_node, - fixup_child_name); - if (tree_child == -FDT_ERR_NOTFOUND) - return -FDT_ERR_BADOVERLAY; - if (tree_child < 0) - return tree_child; - - ret = overlay_update_local_node_references(fdto, - tree_child, - fixup_child, - delta); - if (ret) - return ret; - } - - return 0; + int fixup_prop; + int fixup_child; + int ret; + + fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { + const fdt32_t *fixup_val; + const char *tree_val; + const char *name; + int fixup_len; + int tree_len; + int i; + + fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, + &name, &fixup_len); + if (!fixup_val) + return fixup_len; + + if (fixup_len % sizeof(uint32_t)) + return -FDT_ERR_BADOVERLAY; + fixup_len /= sizeof(uint32_t); + + tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); + if (!tree_val) { + if (tree_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + + return tree_len; + } + + for (i = 0; i < fixup_len; i++) { + fdt32_t adj_val; + uint32_t poffset; + + poffset = fdt32_to_cpu(fixup_val[i]); + + /* + * phandles to fixup can be unaligned. + * + * Use a memcpy for the architectures that do + * not support unaligned accesses. + */ + memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); + + adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); + + ret = fdt_setprop_inplace_namelen_partial(fdto, + tree_node, + name, + strlen(name), + poffset, + &adj_val, + sizeof(adj_val)); + if (ret == -FDT_ERR_NOSPACE) + return -FDT_ERR_BADOVERLAY; + + if (ret) + return ret; + } + } + + fdt_for_each_subnode(fixup_child, fdto, fixup_node) { + const char *fixup_child_name = fdt_get_name(fdto, fixup_child, + NULL); + int tree_child; + + tree_child = fdt_subnode_offset(fdto, tree_node, + fixup_child_name); + if (tree_child == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (tree_child < 0) + return tree_child; + + ret = overlay_update_local_node_references(fdto, + tree_child, + fixup_child, + delta); + if (ret) + return ret; + } + + return 0; } /** @@ -309,22 +309,22 @@ static int overlay_update_local_node_references(void *fdto, */ static int overlay_update_local_references(void *fdto, uint32_t delta) { - int fixups; - - fixups = fdt_path_offset(fdto, "/__local_fixups__"); - if (fixups < 0) { - /* There's no local phandles to adjust, bail out */ - if (fixups == -FDT_ERR_NOTFOUND) - return 0; - - return fixups; - } - - /* - * Update our local references from the root of the tree - */ - return overlay_update_local_node_references(fdto, 0, fixups, - delta); + int fixups; + + fixups = fdt_path_offset(fdto, "/__local_fixups__"); + if (fixups < 0) { + /* There's no local phandles to adjust, bail out */ + if (fixups == -FDT_ERR_NOTFOUND) + return 0; + + return fixups; + } + + /* + * Update our local references from the root of the tree + */ + return overlay_update_local_node_references(fdto, 0, fixups, + delta); } /** @@ -351,44 +351,44 @@ static int overlay_update_local_references(void *fdto, uint32_t delta) * Negative error code on failure */ static int overlay_fixup_one_phandle(void *fdt, void *fdto, - int symbols_off, - const char *path, uint32_t path_len, - const char *name, uint32_t name_len, - int poffset, const char *label) + int symbols_off, + const char *path, uint32_t path_len, + const char *name, uint32_t name_len, + int poffset, const char *label) { - const char *symbol_path; - uint32_t phandle; - fdt32_t phandle_prop; - int symbol_off, fixup_off; - int prop_len; - - if (symbols_off < 0) - return symbols_off; - - symbol_path = fdt_getprop(fdt, symbols_off, label, - &prop_len); - if (!symbol_path) - return prop_len; - - symbol_off = fdt_path_offset(fdt, symbol_path); - if (symbol_off < 0) - return symbol_off; - - phandle = fdt_get_phandle(fdt, symbol_off); - if (!phandle) - return -FDT_ERR_NOTFOUND; - - fixup_off = fdt_path_offset_namelen(fdto, path, path_len); - if (fixup_off == -FDT_ERR_NOTFOUND) - return -FDT_ERR_BADOVERLAY; - if (fixup_off < 0) - return fixup_off; - - phandle_prop = cpu_to_fdt32(phandle); - return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, - name, name_len, poffset, - &phandle_prop, - sizeof(phandle_prop)); + const char *symbol_path; + uint32_t phandle; + fdt32_t phandle_prop; + int symbol_off, fixup_off; + int prop_len; + + if (symbols_off < 0) + return symbols_off; + + symbol_path = fdt_getprop(fdt, symbols_off, label, + &prop_len); + if (!symbol_path) + return prop_len; + + symbol_off = fdt_path_offset(fdt, symbol_path); + if (symbol_off < 0) + return symbol_off; + + phandle = fdt_get_phandle(fdt, symbol_off); + if (!phandle) + return -FDT_ERR_NOTFOUND; + + fixup_off = fdt_path_offset_namelen(fdto, path, path_len); + if (fixup_off == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (fixup_off < 0) + return fixup_off; + + phandle_prop = cpu_to_fdt32(phandle); + return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, + name, name_len, poffset, + &phandle_prop, + sizeof(phandle_prop)); }; /** @@ -411,68 +411,68 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto, * Negative error code on failure */ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, - int property) + int property) { - const char *value; - const char *label; - int len; - - value = fdt_getprop_by_offset(fdto, property, - &label, &len); - if (!value) { - if (len == -FDT_ERR_NOTFOUND) - return -FDT_ERR_INTERNAL; - - return len; - } - - do { - const char *path, *name, *fixup_end; - const char *fixup_str = value; - uint32_t path_len, name_len; - uint32_t fixup_len; - char *sep, *endptr; - int poffset, ret; - - fixup_end = memchr(value, '\0', len); - if (!fixup_end) - return -FDT_ERR_BADOVERLAY; - fixup_len = fixup_end - fixup_str; - - len -= fixup_len + 1; - value += fixup_len + 1; - - path = fixup_str; - sep = memchr(fixup_str, ':', fixup_len); - if (!sep || *sep != ':') - return -FDT_ERR_BADOVERLAY; - - path_len = sep - path; - if (path_len == (fixup_len - 1)) - return -FDT_ERR_BADOVERLAY; - - fixup_len -= path_len + 1; - name = sep + 1; - sep = memchr(name, ':', fixup_len); - if (!sep || *sep != ':') - return -FDT_ERR_BADOVERLAY; - - name_len = sep - name; - if (!name_len) - return -FDT_ERR_BADOVERLAY; - - poffset = strtoul(sep + 1, &endptr, 10); - if ((*endptr != '\0') || (endptr <= (sep + 1))) - return -FDT_ERR_BADOVERLAY; - - ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, - path, path_len, name, name_len, - poffset, label); - if (ret) - return ret; - } while (len > 0); - - return 0; + const char *value; + const char *label; + int len; + + value = fdt_getprop_by_offset(fdto, property, + &label, &len); + if (!value) { + if (len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + + return len; + } + + do { + const char *path, *name, *fixup_end; + const char *fixup_str = value; + uint32_t path_len, name_len; + uint32_t fixup_len; + char *sep, *endptr; + int poffset, ret; + + fixup_end = memchr(value, '\0', len); + if (!fixup_end) + return -FDT_ERR_BADOVERLAY; + fixup_len = fixup_end - fixup_str; + + len -= fixup_len + 1; + value += fixup_len + 1; + + path = fixup_str; + sep = memchr(fixup_str, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + path_len = sep - path; + if (path_len == (fixup_len - 1)) + return -FDT_ERR_BADOVERLAY; + + fixup_len -= path_len + 1; + name = sep + 1; + sep = memchr(name, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + name_len = sep - name; + if (!name_len) + return -FDT_ERR_BADOVERLAY; + + poffset = strtoul(sep + 1, &endptr, 10); + if ((*endptr != '\0') || (endptr <= (sep + 1))) + return -FDT_ERR_BADOVERLAY; + + ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, + path, path_len, name, name_len, + poffset, label); + if (ret) + return ret; + } while (len > 0); + + return 0; } /** @@ -494,30 +494,30 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, */ static int overlay_fixup_phandles(void *fdt, void *fdto) { - int fixups_off, symbols_off; - int property; - - /* We can have overlays without any fixups */ - fixups_off = fdt_path_offset(fdto, "/__fixups__"); - if (fixups_off == -FDT_ERR_NOTFOUND) - return 0; /* nothing to do */ - if (fixups_off < 0) - return fixups_off; - - /* And base DTs without symbols */ - symbols_off = fdt_path_offset(fdt, "/__symbols__"); - if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) - return symbols_off; - - fdt_for_each_property_offset(property, fdto, fixups_off) { - int ret; - - ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); - if (ret) - return ret; - } - - return 0; + int fixups_off, symbols_off; + int property; + + /* We can have overlays without any fixups */ + fixups_off = fdt_path_offset(fdto, "/__fixups__"); + if (fixups_off == -FDT_ERR_NOTFOUND) + return 0; /* nothing to do */ + if (fixups_off < 0) + return fixups_off; + + /* And base DTs without symbols */ + symbols_off = fdt_path_offset(fdt, "/__symbols__"); + if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) + return symbols_off; + + fdt_for_each_property_offset(property, fdto, fixups_off) { + int ret; + + ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); + if (ret) + return ret; + } + + return 0; } /** @@ -540,50 +540,50 @@ static int overlay_fixup_phandles(void *fdt, void *fdto) * Negative error code on failure */ static int overlay_apply_node(void *fdt, int target, - void *fdto, int node) + void *fdto, int node) { - int property; - int subnode; - - fdt_for_each_property_offset(property, fdto, node) { - const char *name; - const void *prop; - int prop_len; - int ret; - - prop = fdt_getprop_by_offset(fdto, property, &name, - &prop_len); - if (prop_len == -FDT_ERR_NOTFOUND) - return -FDT_ERR_INTERNAL; - if (prop_len < 0) - return prop_len; - - ret = fdt_setprop(fdt, target, name, prop, prop_len); - if (ret) - return ret; - } - - fdt_for_each_subnode(subnode, fdto, node) { - const char *name = fdt_get_name(fdto, subnode, NULL); - int nnode; - int ret; - - nnode = fdt_add_subnode(fdt, target, name); - if (nnode == -FDT_ERR_EXISTS) { - nnode = fdt_subnode_offset(fdt, target, name); - if (nnode == -FDT_ERR_NOTFOUND) - return -FDT_ERR_INTERNAL; - } - - if (nnode < 0) - return nnode; - - ret = overlay_apply_node(fdt, nnode, fdto, subnode); - if (ret) - return ret; - } - - return 0; + int property; + int subnode; + + fdt_for_each_property_offset(property, fdto, node) { + const char *name; + const void *prop; + int prop_len; + int ret; + + prop = fdt_getprop_by_offset(fdto, property, &name, + &prop_len); + if (prop_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + if (prop_len < 0) + return prop_len; + + ret = fdt_setprop(fdt, target, name, prop, prop_len); + if (ret) + return ret; + } + + fdt_for_each_subnode(subnode, fdto, node) { + const char *name = fdt_get_name(fdto, subnode, NULL); + int nnode; + int ret; + + nnode = fdt_add_subnode(fdt, target, name); + if (nnode == -FDT_ERR_EXISTS) { + nnode = fdt_subnode_offset(fdt, target, name); + if (nnode == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + } + + if (nnode < 0) + return nnode; + + ret = overlay_apply_node(fdt, nnode, fdto, subnode); + if (ret) + return ret; + } + + return 0; } /** @@ -603,62 +603,62 @@ static int overlay_apply_node(void *fdt, int target, */ static int overlay_merge(void *fdt, void *fdto) { - int fragment; - - fdt_for_each_subnode(fragment, fdto, 0) { - int overlay; - int target; - int ret; - - /* - * Each fragments will have an __overlay__ node. If - * they don't, it's not supposed to be merged - */ - overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); - if (overlay == -FDT_ERR_NOTFOUND) - continue; - - if (overlay < 0) - return overlay; - - target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); - if (target < 0) - return target; - - ret = overlay_apply_node(fdt, target, fdto, overlay); - if (ret) - return ret; - } - - return 0; + int fragment; + + fdt_for_each_subnode(fragment, fdto, 0) { + int overlay; + int target; + int ret; + + /* + * Each fragments will have an __overlay__ node. If + * they don't, it's not supposed to be merged + */ + overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (overlay == -FDT_ERR_NOTFOUND) + continue; + + if (overlay < 0) + return overlay; + + target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); + if (target < 0) + return target; + + ret = overlay_apply_node(fdt, target, fdto, overlay); + if (ret) + return ret; + } + + return 0; } static int get_path_len(const void *fdt, int nodeoffset) { - int len = 0, namelen; - const char *name; - - FDT_RO_PROBE(fdt); - - for (;;) { - name = fdt_get_name(fdt, nodeoffset, &namelen); - if (!name) - return namelen; - - /* root? we're done */ - if (namelen == 0) - break; - - nodeoffset = fdt_parent_offset(fdt, nodeoffset); - if (nodeoffset < 0) - return nodeoffset; - len += namelen + 1; - } - - /* in case of root pretend it's "/" */ - if (len == 0) - len++; - return len; + int len = 0, namelen; + const char *name; + + FDT_RO_PROBE(fdt); + + for (;;) { + name = fdt_get_name(fdt, nodeoffset, &namelen); + if (!name) + return namelen; + + /* root? we're done */ + if (namelen == 0) + break; + + nodeoffset = fdt_parent_offset(fdt, nodeoffset); + if (nodeoffset < 0) + return nodeoffset; + len += namelen + 1; + } + + /* in case of root pretend it's "/" */ + if (len == 0) + len++; + return len; } /** @@ -679,189 +679,189 @@ static int get_path_len(const void *fdt, int nodeoffset) */ static int overlay_symbol_update(void *fdt, void *fdto) { - int root_sym, ov_sym, prop, path_len, fragment, target; - int len, frag_name_len, ret, rel_path_len; - const char *s, *e; - const char *path; - const char *name; - const char *frag_name; - const char *rel_path; - const char *target_path; - char *buf; - void *p; - - ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); - - /* if no overlay symbols exist no problem */ - if (ov_sym < 0) - return 0; - - root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); - - /* it no root symbols exist we should create them */ - if (root_sym == -FDT_ERR_NOTFOUND) - root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); - - /* any error is fatal now */ - if (root_sym < 0) - return root_sym; - - /* iterate over each overlay symbol */ - fdt_for_each_property_offset(prop, fdto, ov_sym) { - path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); - if (!path) - return path_len; - - /* verify it's a string property (terminated by a single \0) */ - if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) - return -FDT_ERR_BADVALUE; - - /* keep end marker to avoid strlen() */ - e = path + path_len; - - if (*path != '/') - return -FDT_ERR_BADVALUE; - - /* get fragment name first */ - s = strchr(path + 1, '/'); - if (!s) { - /* Symbol refers to something that won't end - * up in the target tree */ - continue; - } - - frag_name = path + 1; - frag_name_len = s - path - 1; - - /* verify format; safe since "s" lies in \0 terminated prop */ - len = sizeof("/__overlay__/") - 1; - if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { - /* //__overlay__/ */ - rel_path = s + len; - rel_path_len = e - rel_path - 1; - } else if ((e - s) == len - && (memcmp(s, "/__overlay__", len - 1) == 0)) { - /* //__overlay__ */ - rel_path = ""; - rel_path_len = 0; - } else { - /* Symbol refers to something that won't end - * up in the target tree */ - continue; - } - - /* find the fragment index in which the symbol lies */ - ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, - frag_name_len); - /* not found? */ - if (ret < 0) - return -FDT_ERR_BADOVERLAY; - fragment = ret; - - /* an __overlay__ subnode must exist */ - ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); - if (ret < 0) - return -FDT_ERR_BADOVERLAY; - - /* get the target of the fragment */ - ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); - if (ret < 0) - return ret; - target = ret; - - /* if we have a target path use */ - if (!target_path) { - ret = get_path_len(fdt, target); - if (ret < 0) - return ret; - len = ret; - } else { - len = strlen(target_path); - } - - ret = fdt_setprop_placeholder(fdt, root_sym, name, - len + (len > 1) + rel_path_len + 1, &p); - if (ret < 0) - return ret; - - if (!target_path) { - /* again in case setprop_placeholder changed it */ - ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); - if (ret < 0) - return ret; - target = ret; - } - - buf = p; - if (len > 1) { /* target is not root */ - if (!target_path) { - ret = fdt_get_path(fdt, target, buf, len + 1); - if (ret < 0) - return ret; - } else - memcpy(buf, target_path, len + 1); - - } else - len--; - - buf[len] = '/'; - memcpy(buf + len + 1, rel_path, rel_path_len); - buf[len + 1 + rel_path_len] = '\0'; - } - - return 0; + int root_sym, ov_sym, prop, path_len, fragment, target; + int len, frag_name_len, ret, rel_path_len; + const char *s, *e; + const char *path; + const char *name; + const char *frag_name; + const char *rel_path; + const char *target_path; + char *buf; + void *p; + + ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); + + /* if no overlay symbols exist no problem */ + if (ov_sym < 0) + return 0; + + root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); + + /* it no root symbols exist we should create them */ + if (root_sym == -FDT_ERR_NOTFOUND) + root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); + + /* any error is fatal now */ + if (root_sym < 0) + return root_sym; + + /* iterate over each overlay symbol */ + fdt_for_each_property_offset(prop, fdto, ov_sym) { + path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); + if (!path) + return path_len; + + /* verify it's a string property (terminated by a single \0) */ + if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) + return -FDT_ERR_BADVALUE; + + /* keep end marker to avoid strlen() */ + e = path + path_len; + + if (*path != '/') + return -FDT_ERR_BADVALUE; + + /* get fragment name first */ + s = strchr(path + 1, '/'); + if (!s) { + /* Symbol refers to something that won't end + * up in the target tree */ + continue; + } + + frag_name = path + 1; + frag_name_len = s - path - 1; + + /* verify format; safe since "s" lies in \0 terminated prop */ + len = sizeof("/__overlay__/") - 1; + if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { + /* //__overlay__/ */ + rel_path = s + len; + rel_path_len = e - rel_path - 1; + } else if ((e - s) == len + && (memcmp(s, "/__overlay__", len - 1) == 0)) { + /* //__overlay__ */ + rel_path = ""; + rel_path_len = 0; + } else { + /* Symbol refers to something that won't end + * up in the target tree */ + continue; + } + + /* find the fragment index in which the symbol lies */ + ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, + frag_name_len); + /* not found? */ + if (ret < 0) + return -FDT_ERR_BADOVERLAY; + fragment = ret; + + /* an __overlay__ subnode must exist */ + ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (ret < 0) + return -FDT_ERR_BADOVERLAY; + + /* get the target of the fragment */ + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); + if (ret < 0) + return ret; + target = ret; + + /* if we have a target path use */ + if (!target_path) { + ret = get_path_len(fdt, target); + if (ret < 0) + return ret; + len = ret; + } else { + len = strlen(target_path); + } + + ret = fdt_setprop_placeholder(fdt, root_sym, name, + len + (len > 1) + rel_path_len + 1, &p); + if (ret < 0) + return ret; + + if (!target_path) { + /* again in case setprop_placeholder changed it */ + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); + if (ret < 0) + return ret; + target = ret; + } + + buf = p; + if (len > 1) { /* target is not root */ + if (!target_path) { + ret = fdt_get_path(fdt, target, buf, len + 1); + if (ret < 0) + return ret; + } else + memcpy(buf, target_path, len + 1); + + } else + len--; + + buf[len] = '/'; + memcpy(buf + len + 1, rel_path, rel_path_len); + buf[len + 1 + rel_path_len] = '\0'; + } + + return 0; } int fdt_overlay_apply(void *fdt, void *fdto) { - uint32_t delta; - int ret; + uint32_t delta; + int ret; - FDT_RO_PROBE(fdt); - FDT_RO_PROBE(fdto); + FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdto); - ret = fdt_find_max_phandle(fdt, &delta); - if (ret) - goto err; + ret = fdt_find_max_phandle(fdt, &delta); + if (ret) + goto err; - ret = overlay_adjust_local_phandles(fdto, delta); - if (ret) - goto err; + ret = overlay_adjust_local_phandles(fdto, delta); + if (ret) + goto err; - ret = overlay_update_local_references(fdto, delta); - if (ret) - goto err; + ret = overlay_update_local_references(fdto, delta); + if (ret) + goto err; - ret = overlay_fixup_phandles(fdt, fdto); - if (ret) - goto err; + ret = overlay_fixup_phandles(fdt, fdto); + if (ret) + goto err; - ret = overlay_merge(fdt, fdto); - if (ret) - goto err; + ret = overlay_merge(fdt, fdto); + if (ret) + goto err; - ret = overlay_symbol_update(fdt, fdto); - if (ret) - goto err; + ret = overlay_symbol_update(fdt, fdto); + if (ret) + goto err; - /* - * The overlay has been damaged, erase its magic. - */ - fdt_set_magic(fdto, ~0); + /* + * The overlay has been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); - return 0; + return 0; err: - /* - * The overlay might have been damaged, erase its magic. - */ - fdt_set_magic(fdto, ~0); - - /* - * The base device tree might have been damaged, erase its - * magic. - */ - fdt_set_magic(fdt, ~0); - - return ret; + /* + * The overlay might have been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + /* + * The base device tree might have been damaged, erase its + * magic. + */ + fdt_set_magic(fdt, ~0); + + return ret; } diff --git a/components/drivers/ofw/libfdt/fdt_ro.c b/components/drivers/ofw/libfdt/fdt_ro.c index 9f6c551a22..4543181147 100644 --- a/components/drivers/ofw/libfdt/fdt_ro.c +++ b/components/drivers/ofw/libfdt/fdt_ro.c @@ -11,849 +11,849 @@ #include "libfdt_internal.h" static int fdt_nodename_eq_(const void *fdt, int offset, - const char *s, int len) + const char *s, int len) { - int olen; - const char *p = fdt_get_name(fdt, offset, &olen); + int olen; + const char *p = fdt_get_name(fdt, offset, &olen); - if (!p || olen < len) - /* short match */ - return 0; + if (!p || olen < len) + /* short match */ + return 0; - if (memcmp(p, s, len) != 0) - return 0; + if (memcmp(p, s, len) != 0) + return 0; - if (p[len] == '\0') - return 1; - else if (!memchr(s, '@', len) && (p[len] == '@')) - return 1; - else - return 0; + if (p[len] == '\0') + return 1; + else if (!memchr(s, '@', len) && (p[len] == '@')) + return 1; + else + return 0; } const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) { - int32_t totalsize; - uint32_t absoffset; - size_t len; - int err; - const char *s, *n; - - if (can_assume(VALID_INPUT)) { - s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; - - if (lenp) - *lenp = strlen(s); - return s; - } - totalsize = fdt_ro_probe_(fdt); - err = totalsize; - if (totalsize < 0) - goto fail; - - err = -FDT_ERR_BADOFFSET; - absoffset = stroffset + fdt_off_dt_strings(fdt); - if (absoffset >= (unsigned)totalsize) - goto fail; - len = totalsize - absoffset; - - if (fdt_magic(fdt) == FDT_MAGIC) { - if (stroffset < 0) - goto fail; - if (can_assume(LATEST) || fdt_version(fdt) >= 17) { - if ((unsigned)stroffset >= fdt_size_dt_strings(fdt)) - goto fail; - if ((fdt_size_dt_strings(fdt) - stroffset) < len) - len = fdt_size_dt_strings(fdt) - stroffset; - } - } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { - unsigned int sw_stroffset = -stroffset; - - if ((stroffset >= 0) || - (sw_stroffset > fdt_size_dt_strings(fdt))) - goto fail; - if (sw_stroffset < len) - len = sw_stroffset; - } else { - err = -FDT_ERR_INTERNAL; - goto fail; - } - - s = (const char *)fdt + absoffset; - n = memchr(s, '\0', len); - if (!n) { - /* missing terminating NULL */ - err = -FDT_ERR_TRUNCATED; - goto fail; - } - - if (lenp) - *lenp = n - s; - return s; + int32_t totalsize; + uint32_t absoffset; + size_t len; + int err; + const char *s, *n; + + if (can_assume(VALID_INPUT)) { + s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; + + if (lenp) + *lenp = strlen(s); + return s; + } + totalsize = fdt_ro_probe_(fdt); + err = totalsize; + if (totalsize < 0) + goto fail; + + err = -FDT_ERR_BADOFFSET; + absoffset = stroffset + fdt_off_dt_strings(fdt); + if (absoffset >= (unsigned)totalsize) + goto fail; + len = totalsize - absoffset; + + if (fdt_magic(fdt) == FDT_MAGIC) { + if (stroffset < 0) + goto fail; + if (can_assume(LATEST) || fdt_version(fdt) >= 17) { + if ((unsigned)stroffset >= fdt_size_dt_strings(fdt)) + goto fail; + if ((fdt_size_dt_strings(fdt) - stroffset) < len) + len = fdt_size_dt_strings(fdt) - stroffset; + } + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + unsigned int sw_stroffset = -stroffset; + + if ((stroffset >= 0) || + (sw_stroffset > fdt_size_dt_strings(fdt))) + goto fail; + if (sw_stroffset < len) + len = sw_stroffset; + } else { + err = -FDT_ERR_INTERNAL; + goto fail; + } + + s = (const char *)fdt + absoffset; + n = memchr(s, '\0', len); + if (!n) { + /* missing terminating NULL */ + err = -FDT_ERR_TRUNCATED; + goto fail; + } + + if (lenp) + *lenp = n - s; + return s; fail: - if (lenp) - *lenp = err; - return NULL; + if (lenp) + *lenp = err; + return NULL; } const char *fdt_string(const void *fdt, int stroffset) { - return fdt_get_string(fdt, stroffset, NULL); + return fdt_get_string(fdt, stroffset, NULL); } static int fdt_string_eq_(const void *fdt, int stroffset, - const char *s, int len) + const char *s, int len) { - int slen; - const char *p = fdt_get_string(fdt, stroffset, &slen); + int slen; + const char *p = fdt_get_string(fdt, stroffset, &slen); - return p && (slen == len) && (memcmp(p, s, len) == 0); + return p && (slen == len) && (memcmp(p, s, len) == 0); } int fdt_find_max_phandle(const void *fdt, uint32_t *phandle) { - uint32_t max = 0; - int offset = -1; + uint32_t max = 0; + int offset = -1; - while (true) { - uint32_t value; + while (true) { + uint32_t value; - offset = fdt_next_node(fdt, offset, NULL); - if (offset < 0) { - if (offset == -FDT_ERR_NOTFOUND) - break; + offset = fdt_next_node(fdt, offset, NULL); + if (offset < 0) { + if (offset == -FDT_ERR_NOTFOUND) + break; - return offset; - } + return offset; + } - value = fdt_get_phandle(fdt, offset); + value = fdt_get_phandle(fdt, offset); - if (value > max) - max = value; - } + if (value > max) + max = value; + } - if (phandle) - *phandle = max; + if (phandle) + *phandle = max; - return 0; + return 0; } int fdt_generate_phandle(const void *fdt, uint32_t *phandle) { - uint32_t max; - int err; + uint32_t max; + int err; - err = fdt_find_max_phandle(fdt, &max); - if (err < 0) - return err; + err = fdt_find_max_phandle(fdt, &max); + if (err < 0) + return err; - if (max == FDT_MAX_PHANDLE) - return -FDT_ERR_NOPHANDLES; + if (max == FDT_MAX_PHANDLE) + return -FDT_ERR_NOPHANDLES; - if (phandle) - *phandle = max + 1; + if (phandle) + *phandle = max + 1; - return 0; + return 0; } static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) { - unsigned int offset = n * sizeof(struct fdt_reserve_entry); - unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset; + unsigned int offset = n * sizeof(struct fdt_reserve_entry); + unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset; - if (!can_assume(VALID_INPUT)) { - if (absoffset < fdt_off_mem_rsvmap(fdt)) - return NULL; - if (absoffset > fdt_totalsize(fdt) - - sizeof(struct fdt_reserve_entry)) - return NULL; - } - return fdt_mem_rsv_(fdt, n); + if (!can_assume(VALID_INPUT)) { + if (absoffset < fdt_off_mem_rsvmap(fdt)) + return NULL; + if (absoffset > fdt_totalsize(fdt) - + sizeof(struct fdt_reserve_entry)) + return NULL; + } + return fdt_mem_rsv_(fdt, n); } int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { - const struct fdt_reserve_entry *re; + const struct fdt_reserve_entry *re; - FDT_RO_PROBE(fdt); - re = fdt_mem_rsv(fdt, n); - if (!can_assume(VALID_INPUT) && !re) - return -FDT_ERR_BADOFFSET; + FDT_RO_PROBE(fdt); + re = fdt_mem_rsv(fdt, n); + if (!can_assume(VALID_INPUT) && !re) + return -FDT_ERR_BADOFFSET; - *address = fdt64_ld_(&re->address); - *size = fdt64_ld_(&re->size); - return 0; + *address = fdt64_ld_(&re->address); + *size = fdt64_ld_(&re->size); + return 0; } int fdt_num_mem_rsv(const void *fdt) { - int i; - const struct fdt_reserve_entry *re; + int i; + const struct fdt_reserve_entry *re; - for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { - if (fdt64_ld_(&re->size) == 0) - return i; - } - return -FDT_ERR_TRUNCATED; + for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { + if (fdt64_ld_(&re->size) == 0) + return i; + } + return -FDT_ERR_TRUNCATED; } static int nextprop_(const void *fdt, int offset) { - uint32_t tag; - int nextoffset; + uint32_t tag; + int nextoffset; - do { - tag = fdt_next_tag(fdt, offset, &nextoffset); + do { + tag = fdt_next_tag(fdt, offset, &nextoffset); - switch (tag) { - case FDT_END: - if (nextoffset >= 0) - return -FDT_ERR_BADSTRUCTURE; - else - return nextoffset; + switch (tag) { + case FDT_END: + if (nextoffset >= 0) + return -FDT_ERR_BADSTRUCTURE; + else + return nextoffset; - case FDT_PROP: - return offset; - } - offset = nextoffset; - } while (tag == FDT_NOP); + case FDT_PROP: + return offset; + } + offset = nextoffset; + } while (tag == FDT_NOP); - return -FDT_ERR_NOTFOUND; + return -FDT_ERR_NOTFOUND; } int fdt_subnode_offset_namelen(const void *fdt, int offset, - const char *name, int namelen) + const char *name, int namelen) { - int depth; + int depth; - FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdt); - for (depth = 0; - (offset >= 0) && (depth >= 0); - offset = fdt_next_node(fdt, offset, &depth)) - if ((depth == 1) - && fdt_nodename_eq_(fdt, offset, name, namelen)) - return offset; + for (depth = 0; + (offset >= 0) && (depth >= 0); + offset = fdt_next_node(fdt, offset, &depth)) + if ((depth == 1) + && fdt_nodename_eq_(fdt, offset, name, namelen)) + return offset; - if (depth < 0) - return -FDT_ERR_NOTFOUND; - return offset; /* error */ + if (depth < 0) + return -FDT_ERR_NOTFOUND; + return offset; /* error */ } int fdt_subnode_offset(const void *fdt, int parentoffset, - const char *name) + const char *name) { - return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); + return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); } int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) { - const char *end = path + namelen; - const char *p = path; - int offset = 0; + const char *end = path + namelen; + const char *p = path; + int offset = 0; - FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdt); - /* see if we have an alias */ - if (*path != '/') { - const char *q = memchr(path, '/', end - p); + /* see if we have an alias */ + if (*path != '/') { + const char *q = memchr(path, '/', end - p); - if (!q) - q = end; + if (!q) + q = end; - p = fdt_get_alias_namelen(fdt, p, q - p); - if (!p) - return -FDT_ERR_BADPATH; - offset = fdt_path_offset(fdt, p); + p = fdt_get_alias_namelen(fdt, p, q - p); + if (!p) + return -FDT_ERR_BADPATH; + offset = fdt_path_offset(fdt, p); - p = q; - } + p = q; + } - while (p < end) { - const char *q; + while (p < end) { + const char *q; - while (*p == '/') { - p++; - if (p == end) - return offset; - } - q = memchr(p, '/', end - p); - if (! q) - q = end; + while (*p == '/') { + p++; + if (p == end) + return offset; + } + q = memchr(p, '/', end - p); + if (! q) + q = end; - offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); - if (offset < 0) - return offset; + offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); + if (offset < 0) + return offset; - p = q; - } + p = q; + } - return offset; + return offset; } int fdt_path_offset(const void *fdt, const char *path) { - return fdt_path_offset_namelen(fdt, path, strlen(path)); + return fdt_path_offset_namelen(fdt, path, strlen(path)); } const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) { - const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset); - const char *nameptr; - int err; + const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset); + const char *nameptr; + int err; - if (((err = fdt_ro_probe_(fdt)) < 0) - || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) - goto fail; + if (((err = fdt_ro_probe_(fdt)) < 0) + || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) + goto fail; - nameptr = nh->name; + nameptr = nh->name; - if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { - /* - * For old FDT versions, match the naming conventions of V16: - * give only the leaf name (after all /). The actual tree - * contents are loosely checked. - */ - const char *leaf; - leaf = strrchr(nameptr, '/'); - if (leaf == NULL) { - err = -FDT_ERR_BADSTRUCTURE; - goto fail; - } - nameptr = leaf+1; - } + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { + /* + * For old FDT versions, match the naming conventions of V16: + * give only the leaf name (after all /). The actual tree + * contents are loosely checked. + */ + const char *leaf; + leaf = strrchr(nameptr, '/'); + if (leaf == NULL) { + err = -FDT_ERR_BADSTRUCTURE; + goto fail; + } + nameptr = leaf+1; + } - if (len) - *len = strlen(nameptr); + if (len) + *len = strlen(nameptr); - return nameptr; + return nameptr; fail: - if (len) - *len = err; - return NULL; + if (len) + *len = err; + return NULL; } int fdt_first_property_offset(const void *fdt, int nodeoffset) { - int offset; + int offset; - if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) - return offset; + if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) + return offset; - return nextprop_(fdt, offset); + return nextprop_(fdt, offset); } int fdt_next_property_offset(const void *fdt, int offset) { - if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) - return offset; + if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) + return offset; - return nextprop_(fdt, offset); + return nextprop_(fdt, offset); } static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, - int offset, - int *lenp) + int offset, + int *lenp) { - int err; - const struct fdt_property *prop; + int err; + const struct fdt_property *prop; - if (!can_assume(VALID_INPUT) && - (err = fdt_check_prop_offset_(fdt, offset)) < 0) { - if (lenp) - *lenp = err; - return NULL; - } + if (!can_assume(VALID_INPUT) && + (err = fdt_check_prop_offset_(fdt, offset)) < 0) { + if (lenp) + *lenp = err; + return NULL; + } - prop = fdt_offset_ptr_(fdt, offset); + prop = fdt_offset_ptr_(fdt, offset); - if (lenp) - *lenp = fdt32_ld_(&prop->len); + if (lenp) + *lenp = fdt32_ld_(&prop->len); - return prop; + return prop; } const struct fdt_property *fdt_get_property_by_offset(const void *fdt, - int offset, - int *lenp) + int offset, + int *lenp) { - /* Prior to version 16, properties may need realignment - * and this API does not work. fdt_getprop_*() will, however. */ + /* Prior to version 16, properties may need realignment + * and this API does not work. fdt_getprop_*() will, however. */ - if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { - if (lenp) - *lenp = -FDT_ERR_BADVERSION; - return NULL; - } + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { + if (lenp) + *lenp = -FDT_ERR_BADVERSION; + return NULL; + } - return fdt_get_property_by_offset_(fdt, offset, lenp); + return fdt_get_property_by_offset_(fdt, offset, lenp); } static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, - int offset, - const char *name, - int namelen, - int *lenp, - int *poffset) -{ - for (offset = fdt_first_property_offset(fdt, offset); - (offset >= 0); - (offset = fdt_next_property_offset(fdt, offset))) { - const struct fdt_property *prop; - - prop = fdt_get_property_by_offset_(fdt, offset, lenp); - if (!can_assume(LIBFDT_FLAWLESS) && !prop) { - offset = -FDT_ERR_INTERNAL; - break; - } - if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff), - name, namelen)) { - if (poffset) - *poffset = offset; - return prop; - } - } - - if (lenp) - *lenp = offset; - return NULL; + int offset, + const char *name, + int namelen, + int *lenp, + int *poffset) +{ + for (offset = fdt_first_property_offset(fdt, offset); + (offset >= 0); + (offset = fdt_next_property_offset(fdt, offset))) { + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset_(fdt, offset, lenp); + if (!can_assume(LIBFDT_FLAWLESS) && !prop) { + offset = -FDT_ERR_INTERNAL; + break; + } + if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff), + name, namelen)) { + if (poffset) + *poffset = offset; + return prop; + } + } + + if (lenp) + *lenp = offset; + return NULL; } const struct fdt_property *fdt_get_property_namelen(const void *fdt, - int offset, - const char *name, - int namelen, int *lenp) + int offset, + const char *name, + int namelen, int *lenp) { - /* Prior to version 16, properties may need realignment - * and this API does not work. fdt_getprop_*() will, however. */ - if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { - if (lenp) - *lenp = -FDT_ERR_BADVERSION; - return NULL; - } + /* Prior to version 16, properties may need realignment + * and this API does not work. fdt_getprop_*() will, however. */ + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { + if (lenp) + *lenp = -FDT_ERR_BADVERSION; + return NULL; + } - return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp, - NULL); + return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp, + NULL); } const struct fdt_property *fdt_get_property(const void *fdt, - int nodeoffset, - const char *name, int *lenp) + int nodeoffset, + const char *name, int *lenp) { - return fdt_get_property_namelen(fdt, nodeoffset, name, - strlen(name), lenp); + return fdt_get_property_namelen(fdt, nodeoffset, name, + strlen(name), lenp); } const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp) + const char *name, int namelen, int *lenp) { - int poffset; - const struct fdt_property *prop; + int poffset; + const struct fdt_property *prop; - prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, - &poffset); - if (!prop) - return NULL; + prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, + &poffset); + if (!prop) + return NULL; - /* Handle realignment */ - if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && - (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) - return prop->data + 4; - return prop->data; + /* Handle realignment */ + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && + (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) + return prop->data + 4; + return prop->data; } const void *fdt_getprop_by_offset(const void *fdt, int offset, - const char **namep, int *lenp) -{ - const struct fdt_property *prop; - - prop = fdt_get_property_by_offset_(fdt, offset, lenp); - if (!prop) - return NULL; - if (namep) { - const char *name; - int namelen; - - if (!can_assume(VALID_INPUT)) { - name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff), - &namelen); - *namep = name; - if (!name) { - if (lenp) - *lenp = namelen; - return NULL; - } - } else { - *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff)); - } - } - - /* Handle realignment */ - if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && - (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) - return prop->data + 4; - return prop->data; + const char **namep, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset_(fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) { + const char *name; + int namelen; + + if (!can_assume(VALID_INPUT)) { + name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff), + &namelen); + *namep = name; + if (!name) { + if (lenp) + *lenp = namelen; + return NULL; + } + } else { + *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff)); + } + } + + /* Handle realignment */ + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && + (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) + return prop->data + 4; + return prop->data; } const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp) + const char *name, int *lenp) { - return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); + return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); } uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) { - const fdt32_t *php; - int len; + const fdt32_t *php; + int len; - /* FIXME: This is a bit sub-optimal, since we potentially scan - * over all the properties twice. */ - php = fdt_getprop(fdt, nodeoffset, "phandle", &len); - if (!php || (len != sizeof(*php))) { - php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); - if (!php || (len != sizeof(*php))) - return 0; - } + /* FIXME: This is a bit sub-optimal, since we potentially scan + * over all the properties twice. */ + php = fdt_getprop(fdt, nodeoffset, "phandle", &len); + if (!php || (len != sizeof(*php))) { + php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); + if (!php || (len != sizeof(*php))) + return 0; + } - return fdt32_ld_(php); + return fdt32_ld_(php); } const char *fdt_get_alias_namelen(const void *fdt, - const char *name, int namelen) + const char *name, int namelen) { - int aliasoffset; + int aliasoffset; - aliasoffset = fdt_path_offset(fdt, "/aliases"); - if (aliasoffset < 0) - return NULL; + aliasoffset = fdt_path_offset(fdt, "/aliases"); + if (aliasoffset < 0) + return NULL; - return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); + return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); } const char *fdt_get_alias(const void *fdt, const char *name) { - return fdt_get_alias_namelen(fdt, name, strlen(name)); + return fdt_get_alias_namelen(fdt, name, strlen(name)); } int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { - int pdepth = 0, p = 0; - int offset, depth, namelen; - const char *name; - - FDT_RO_PROBE(fdt); - - if (buflen < 2) - return -FDT_ERR_NOSPACE; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - while (pdepth > depth) { - do { - p--; - } while (buf[p-1] != '/'); - pdepth--; - } - - if (pdepth >= depth) { - name = fdt_get_name(fdt, offset, &namelen); - if (!name) - return namelen; - if ((p + namelen + 1) <= buflen) { - memcpy(buf + p, name, namelen); - p += namelen; - buf[p++] = '/'; - pdepth++; - } - } - - if (offset == nodeoffset) { - if (pdepth < (depth + 1)) - return -FDT_ERR_NOSPACE; - - if (p > 1) /* special case so that root path is "/", not "" */ - p--; - buf[p] = '\0'; - return 0; - } - } - - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - - return offset; /* error from fdt_next_node() */ + int pdepth = 0, p = 0; + int offset, depth, namelen; + const char *name; + + FDT_RO_PROBE(fdt); + + if (buflen < 2) + return -FDT_ERR_NOSPACE; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + while (pdepth > depth) { + do { + p--; + } while (buf[p-1] != '/'); + pdepth--; + } + + if (pdepth >= depth) { + name = fdt_get_name(fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) { + memcpy(buf + p, name, namelen); + p += namelen; + buf[p++] = '/'; + pdepth++; + } + } + + if (offset == nodeoffset) { + if (pdepth < (depth + 1)) + return -FDT_ERR_NOSPACE; + + if (p > 1) /* special case so that root path is "/", not "" */ + p--; + buf[p] = '\0'; + return 0; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ } int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth) + int supernodedepth, int *nodedepth) { - int offset, depth; - int supernodeoffset = -FDT_ERR_INTERNAL; + int offset, depth; + int supernodeoffset = -FDT_ERR_INTERNAL; - FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdt); - if (supernodedepth < 0) - return -FDT_ERR_NOTFOUND; + if (supernodedepth < 0) + return -FDT_ERR_NOTFOUND; - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - if (depth == supernodedepth) - supernodeoffset = offset; + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + if (depth == supernodedepth) + supernodeoffset = offset; - if (offset == nodeoffset) { - if (nodedepth) - *nodedepth = depth; + if (offset == nodeoffset) { + if (nodedepth) + *nodedepth = depth; - if (supernodedepth > depth) - return -FDT_ERR_NOTFOUND; - else - return supernodeoffset; - } - } + if (supernodedepth > depth) + return -FDT_ERR_NOTFOUND; + else + return supernodeoffset; + } + } - if (!can_assume(VALID_INPUT)) { - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - } + if (!can_assume(VALID_INPUT)) { + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + } - return offset; /* error from fdt_next_node() */ + return offset; /* error from fdt_next_node() */ } int fdt_node_depth(const void *fdt, int nodeoffset) { - int nodedepth; - int err; + int nodedepth; + int err; - err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); - if (err) - return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err : - -FDT_ERR_INTERNAL; - return nodedepth; + err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); + if (err) + return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err : + -FDT_ERR_INTERNAL; + return nodedepth; } int fdt_parent_offset(const void *fdt, int nodeoffset) { - int nodedepth = fdt_node_depth(fdt, nodeoffset); + int nodedepth = fdt_node_depth(fdt, nodeoffset); - if (nodedepth < 0) - return nodedepth; - return fdt_supernode_atdepth_offset(fdt, nodeoffset, - nodedepth - 1, NULL); + if (nodedepth < 0) + return nodedepth; + return fdt_supernode_atdepth_offset(fdt, nodeoffset, + nodedepth - 1, NULL); } int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen) + const char *propname, + const void *propval, int proplen) { - int offset; - const void *val; - int len; + int offset; + const void *val; + int len; - FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdt); - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_getprop(), then if that didn't - * find what we want, we scan over them again making our way - * to the next node. Still it's the easiest to implement - * approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - val = fdt_getprop(fdt, offset, propname, &len); - if (val && (len == proplen) - && (memcmp(val, propval, len) == 0)) - return offset; - } + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_getprop(), then if that didn't + * find what we want, we scan over them again making our way + * to the next node. Still it's the easiest to implement + * approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + val = fdt_getprop(fdt, offset, propname, &len); + if (val && (len == proplen) + && (memcmp(val, propval, len) == 0)) + return offset; + } - return offset; /* error from fdt_next_node() */ + return offset; /* error from fdt_next_node() */ } int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { - int offset; + int offset; - if ((phandle == 0) || (phandle == ~0U)) - return -FDT_ERR_BADPHANDLE; + if ((phandle == 0) || (phandle == ~0U)) + return -FDT_ERR_BADPHANDLE; - FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdt); - /* FIXME: The algorithm here is pretty horrible: we - * potentially scan each property of a node in - * fdt_get_phandle(), then if that didn't find what - * we want, we scan over them again making our way to the next - * node. Still it's the easiest to implement approach; - * performance can come later. */ - for (offset = fdt_next_node(fdt, -1, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - if (fdt_get_phandle(fdt, offset) == phandle) - return offset; - } + /* FIXME: The algorithm here is pretty horrible: we + * potentially scan each property of a node in + * fdt_get_phandle(), then if that didn't find what + * we want, we scan over them again making our way to the next + * node. Still it's the easiest to implement approach; + * performance can come later. */ + for (offset = fdt_next_node(fdt, -1, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (fdt_get_phandle(fdt, offset) == phandle) + return offset; + } - return offset; /* error from fdt_next_node() */ + return offset; /* error from fdt_next_node() */ } int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) { - int len = strlen(str); - const char *p; + int len = strlen(str); + const char *p; - while (listlen >= len) { - if (memcmp(str, strlist, len+1) == 0) - return 1; - p = memchr(strlist, '\0', listlen); - if (!p) - return 0; /* malformed strlist.. */ - listlen -= (p-strlist) + 1; - strlist = p + 1; - } - return 0; + while (listlen >= len) { + if (memcmp(str, strlist, len+1) == 0) + return 1; + p = memchr(strlist, '\0', listlen); + if (!p) + return 0; /* malformed strlist.. */ + listlen -= (p-strlist) + 1; + strlist = p + 1; + } + return 0; } int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) { - const char *list, *end; - int length, count = 0; + const char *list, *end; + int length, count = 0; - list = fdt_getprop(fdt, nodeoffset, property, &length); - if (!list) - return length; + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return length; - end = list + length; + end = list + length; - while (list < end) { - length = strnlen(list, end - list) + 1; + while (list < end) { + length = strnlen(list, end - list) + 1; - /* Abort if the last string isn't properly NUL-terminated. */ - if (list + length > end) - return -FDT_ERR_BADVALUE; + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; - list += length; - count++; - } + list += length; + count++; + } - return count; + return count; } int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, - const char *string) + const char *string) { - int length, len, idx = 0; - const char *list, *end; + int length, len, idx = 0; + const char *list, *end; - list = fdt_getprop(fdt, nodeoffset, property, &length); - if (!list) - return length; + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return length; - len = strlen(string) + 1; - end = list + length; + len = strlen(string) + 1; + end = list + length; - while (list < end) { - length = strnlen(list, end - list) + 1; + while (list < end) { + length = strnlen(list, end - list) + 1; - /* Abort if the last string isn't properly NUL-terminated. */ - if (list + length > end) - return -FDT_ERR_BADVALUE; + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; - if (length == len && memcmp(list, string, length) == 0) - return idx; + if (length == len && memcmp(list, string, length) == 0) + return idx; - list += length; - idx++; - } + list += length; + idx++; + } - return -FDT_ERR_NOTFOUND; + return -FDT_ERR_NOTFOUND; } const char *fdt_stringlist_get(const void *fdt, int nodeoffset, - const char *property, int idx, - int *lenp) + const char *property, int idx, + int *lenp) { - const char *list, *end; - int length; + const char *list, *end; + int length; - list = fdt_getprop(fdt, nodeoffset, property, &length); - if (!list) { - if (lenp) - *lenp = length; + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) { + if (lenp) + *lenp = length; - return NULL; - } + return NULL; + } - end = list + length; + end = list + length; - while (list < end) { - length = strnlen(list, end - list) + 1; + while (list < end) { + length = strnlen(list, end - list) + 1; - /* Abort if the last string isn't properly NUL-terminated. */ - if (list + length > end) { - if (lenp) - *lenp = -FDT_ERR_BADVALUE; + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) { + if (lenp) + *lenp = -FDT_ERR_BADVALUE; - return NULL; - } + return NULL; + } - if (idx == 0) { - if (lenp) - *lenp = length - 1; + if (idx == 0) { + if (lenp) + *lenp = length - 1; - return list; - } + return list; + } - list += length; - idx--; - } + list += length; + idx--; + } - if (lenp) - *lenp = -FDT_ERR_NOTFOUND; + if (lenp) + *lenp = -FDT_ERR_NOTFOUND; - return NULL; + return NULL; } int fdt_node_check_compatible(const void *fdt, int nodeoffset, - const char *compatible) + const char *compatible) { - const void *prop; - int len; + const void *prop; + int len; - prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); - if (!prop) - return len; + prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); + if (!prop) + return len; - return !fdt_stringlist_contains(prop, len, compatible); + return !fdt_stringlist_contains(prop, len, compatible); } int fdt_node_offset_by_compatible(const void *fdt, int startoffset, - const char *compatible) -{ - int offset, err; - - FDT_RO_PROBE(fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_node_check_compatible(), then if - * that didn't find what we want, we scan over them again - * making our way to the next node. Still it's the easiest to - * implement approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - err = fdt_node_check_compatible(fdt, offset, compatible); - if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) - return err; - else if (err == 0) - return offset; - } - - return offset; /* error from fdt_next_node() */ + const char *compatible) +{ + int offset, err; + + FDT_RO_PROBE(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_node_check_compatible(), then if + * that didn't find what we want, we scan over them again + * making our way to the next node. Still it's the easiest to + * implement approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + err = fdt_node_check_compatible(fdt, offset, compatible); + if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) + return err; + else if (err == 0) + return offset; + } + + return offset; /* error from fdt_next_node() */ } diff --git a/components/drivers/ofw/libfdt/fdt_rw.c b/components/drivers/ofw/libfdt/fdt_rw.c index 3621d3651d..07509a261f 100644 --- a/components/drivers/ofw/libfdt/fdt_rw.c +++ b/components/drivers/ofw/libfdt/fdt_rw.c @@ -11,108 +11,108 @@ #include "libfdt_internal.h" static int fdt_blocks_misordered_(const void *fdt, - int mem_rsv_size, int struct_size) + int mem_rsv_size, int struct_size) { - return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) - || (fdt_off_dt_struct(fdt) < - (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) - || (fdt_off_dt_strings(fdt) < - (fdt_off_dt_struct(fdt) + struct_size)) - || (fdt_totalsize(fdt) < - (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); + return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) + || (fdt_off_dt_struct(fdt) < + (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) + || (fdt_off_dt_strings(fdt) < + (fdt_off_dt_struct(fdt) + struct_size)) + || (fdt_totalsize(fdt) < + (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); } static int fdt_rw_probe_(void *fdt) { - if (can_assume(VALID_DTB)) - return 0; - FDT_RO_PROBE(fdt); - - if (!can_assume(LATEST) && fdt_version(fdt) < 17) - return -FDT_ERR_BADVERSION; - if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), - fdt_size_dt_struct(fdt))) - return -FDT_ERR_BADLAYOUT; - if (!can_assume(LATEST) && fdt_version(fdt) > 17) - fdt_set_version(fdt, 17); - - return 0; + if (can_assume(VALID_DTB)) + return 0; + FDT_RO_PROBE(fdt); + + if (!can_assume(LATEST) && fdt_version(fdt) < 17) + return -FDT_ERR_BADVERSION; + if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_BADLAYOUT; + if (!can_assume(LATEST) && fdt_version(fdt) > 17) + fdt_set_version(fdt, 17); + + return 0; } #define FDT_RW_PROBE(fdt) \ - { \ - int err_; \ - if ((err_ = fdt_rw_probe_(fdt)) != 0) \ - return err_; \ - } + { \ + int err_; \ + if ((err_ = fdt_rw_probe_(fdt)) != 0) \ + return err_; \ + } static inline unsigned int fdt_data_size_(void *fdt) { - return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); } static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) { - char *p = splicepoint; - unsigned int dsize = fdt_data_size_(fdt); - size_t soff = p - (char *)fdt; - - if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize)) - return -FDT_ERR_BADOFFSET; - if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen)) - return -FDT_ERR_BADOFFSET; - if (dsize - oldlen + newlen > fdt_totalsize(fdt)) - return -FDT_ERR_NOSPACE; - memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen)); - return 0; + char *p = splicepoint; + unsigned int dsize = fdt_data_size_(fdt); + size_t soff = p - (char *)fdt; + + if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize)) + return -FDT_ERR_BADOFFSET; + if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen)) + return -FDT_ERR_BADOFFSET; + if (dsize - oldlen + newlen > fdt_totalsize(fdt)) + return -FDT_ERR_NOSPACE; + memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen)); + return 0; } static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p, - int oldn, int newn) + int oldn, int newn) { - int delta = (newn - oldn) * sizeof(*p); - int err; - err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); - if (err) - return err; - fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); - fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); - return 0; + int delta = (newn - oldn) * sizeof(*p); + int err; + err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); + if (err) + return err; + fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; } static int fdt_splice_struct_(void *fdt, void *p, - int oldlen, int newlen) + int oldlen, int newlen) { - int delta = newlen - oldlen; - int err; + int delta = newlen - oldlen; + int err; - if ((err = fdt_splice_(fdt, p, oldlen, newlen))) - return err; + if ((err = fdt_splice_(fdt, p, oldlen, newlen))) + return err; - fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); - fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); - return 0; + fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; } /* Must only be used to roll back in case of error */ static void fdt_del_last_string_(void *fdt, const char *s) { - int newlen = strlen(s) + 1; + int newlen = strlen(s) + 1; - fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen); + fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen); } static int fdt_splice_string_(void *fdt, int newlen) { - void *p = (char *)fdt - + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); - int err; + void *p = (char *)fdt + + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + int err; - if ((err = fdt_splice_(fdt, p, 0, newlen))) - return err; + if ((err = fdt_splice_(fdt, p, 0, newlen))) + return err; - fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); - return 0; + fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); + return 0; } /** @@ -121,380 +121,380 @@ static int fdt_splice_string_(void *fdt, int newlen) * @fdt: pointer to the device tree to check/adjust * @s: string to find/add * @allocated: Set to 0 if the string was found, 1 if not found and so - * allocated. Ignored if can_assume(NO_ROLLBACK) + * allocated. Ignored if can_assume(NO_ROLLBACK) * @return offset of string in the string table (whether found or added) */ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) { - char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); - const char *p; - char *new; - int len = strlen(s) + 1; - int err; - - if (!can_assume(NO_ROLLBACK)) - *allocated = 0; - - p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); - if (p) - /* found it */ - return (p - strtab); - - new = strtab + fdt_size_dt_strings(fdt); - err = fdt_splice_string_(fdt, len); - if (err) - return err; - - if (!can_assume(NO_ROLLBACK)) - *allocated = 1; - - memcpy(new, s, len); - return (new - strtab); + char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); + const char *p; + char *new; + int len = strlen(s) + 1; + int err; + + if (!can_assume(NO_ROLLBACK)) + *allocated = 0; + + p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); + if (p) + /* found it */ + return (p - strtab); + + new = strtab + fdt_size_dt_strings(fdt); + err = fdt_splice_string_(fdt, len); + if (err) + return err; + + if (!can_assume(NO_ROLLBACK)) + *allocated = 1; + + memcpy(new, s, len); + return (new - strtab); } int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) { - struct fdt_reserve_entry *re; - int err; + struct fdt_reserve_entry *re; + int err; - FDT_RW_PROBE(fdt); + FDT_RW_PROBE(fdt); - re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); - err = fdt_splice_mem_rsv_(fdt, re, 0, 1); - if (err) - return err; + re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); + err = fdt_splice_mem_rsv_(fdt, re, 0, 1); + if (err) + return err; - re->address = cpu_to_fdt64(address); - re->size = cpu_to_fdt64(size); - return 0; + re->address = cpu_to_fdt64(address); + re->size = cpu_to_fdt64(size); + return 0; } int fdt_del_mem_rsv(void *fdt, int n) { - struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); + struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); - FDT_RW_PROBE(fdt); + FDT_RW_PROBE(fdt); - if (n >= fdt_num_mem_rsv(fdt)) - return -FDT_ERR_NOTFOUND; + if (n >= fdt_num_mem_rsv(fdt)) + return -FDT_ERR_NOTFOUND; - return fdt_splice_mem_rsv_(fdt, re, 1, 0); + return fdt_splice_mem_rsv_(fdt, re, 1, 0); } static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) + int len, struct fdt_property **prop) { - int oldlen; - int err; + int oldlen; + int err; - *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); - if (!*prop) - return oldlen; + *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (!*prop) + return oldlen; - if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), - FDT_TAGALIGN(len)))) - return err; + if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(len)))) + return err; - (*prop)->len = cpu_to_fdt32(len); - return 0; + (*prop)->len = cpu_to_fdt32(len); + return 0; } static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) + int len, struct fdt_property **prop) { - int proplen; - int nextoffset; - int namestroff; - int err; - int allocated; - - if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) - return nextoffset; - - namestroff = fdt_find_add_string_(fdt, name, &allocated); - if (namestroff < 0) - return namestroff; - - *prop = fdt_offset_ptr_w_(fdt, nextoffset); - proplen = sizeof(**prop) + FDT_TAGALIGN(len); - - err = fdt_splice_struct_(fdt, *prop, 0, proplen); - if (err) { - /* Delete the string if we failed to add it */ - if (!can_assume(NO_ROLLBACK) && allocated) - fdt_del_last_string_(fdt, name); - return err; - } - - (*prop)->tag = cpu_to_fdt32(FDT_PROP); - (*prop)->nameoff = cpu_to_fdt32(namestroff); - (*prop)->len = cpu_to_fdt32(len); - return 0; + int proplen; + int nextoffset; + int namestroff; + int err; + int allocated; + + if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) + return nextoffset; + + namestroff = fdt_find_add_string_(fdt, name, &allocated); + if (namestroff < 0) + return namestroff; + + *prop = fdt_offset_ptr_w_(fdt, nextoffset); + proplen = sizeof(**prop) + FDT_TAGALIGN(len); + + err = fdt_splice_struct_(fdt, *prop, 0, proplen); + if (err) { + /* Delete the string if we failed to add it */ + if (!can_assume(NO_ROLLBACK) && allocated) + fdt_del_last_string_(fdt, name); + return err; + } + + (*prop)->tag = cpu_to_fdt32(FDT_PROP); + (*prop)->nameoff = cpu_to_fdt32(namestroff); + (*prop)->len = cpu_to_fdt32(len); + return 0; } int fdt_set_name(void *fdt, int nodeoffset, const char *name) { - char *namep; - int oldlen, newlen; - int err; + char *namep; + int oldlen, newlen; + int err; - FDT_RW_PROBE(fdt); + FDT_RW_PROBE(fdt); - namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); - if (!namep) - return oldlen; + namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); + if (!namep) + return oldlen; - newlen = strlen(name); + newlen = strlen(name); - err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1), - FDT_TAGALIGN(newlen+1)); - if (err) - return err; + err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1), + FDT_TAGALIGN(newlen+1)); + if (err) + return err; - memcpy(namep, name, newlen+1); - return 0; + memcpy(namep, name, newlen+1); + return 0; } int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, - int len, void **prop_data) + int len, void **prop_data) { - struct fdt_property *prop; - int err; + struct fdt_property *prop; + int err; - FDT_RW_PROBE(fdt); + FDT_RW_PROBE(fdt); - err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); - if (err == -FDT_ERR_NOTFOUND) - err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); - if (err) - return err; + err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); + if (err == -FDT_ERR_NOTFOUND) + err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); + if (err) + return err; - *prop_data = prop->data; - return 0; + *prop_data = prop->data; + return 0; } int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len) + const void *val, int len) { - void *prop_data; - int err; + void *prop_data; + int err; - err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); - if (err) - return err; + err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); + if (err) + return err; - if (len) - memcpy(prop_data, val, len); - return 0; + if (len) + memcpy(prop_data, val, len); + return 0; } int fdt_appendprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len) + const void *val, int len) { - struct fdt_property *prop; - int err, oldlen, newlen; - - FDT_RW_PROBE(fdt); - - prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); - if (prop) { - newlen = len + oldlen; - err = fdt_splice_struct_(fdt, prop->data, - FDT_TAGALIGN(oldlen), - FDT_TAGALIGN(newlen)); - if (err) - return err; - prop->len = cpu_to_fdt32(newlen); - memcpy(prop->data + oldlen, val, len); - } else { - err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); - if (err) - return err; - memcpy(prop->data, val, len); - } - return 0; + struct fdt_property *prop; + int err, oldlen, newlen; + + FDT_RW_PROBE(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; + err = fdt_splice_struct_(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) + return err; + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { + err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); + } + return 0; } int fdt_delprop(void *fdt, int nodeoffset, const char *name) { - struct fdt_property *prop; - int len, proplen; + struct fdt_property *prop; + int len, proplen; - FDT_RW_PROBE(fdt); + FDT_RW_PROBE(fdt); - prop = fdt_get_property_w(fdt, nodeoffset, name, &len); - if (!prop) - return len; + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (!prop) + return len; - proplen = sizeof(*prop) + FDT_TAGALIGN(len); - return fdt_splice_struct_(fdt, prop, proplen, 0); + proplen = sizeof(*prop) + FDT_TAGALIGN(len); + return fdt_splice_struct_(fdt, prop, proplen, 0); } int fdt_add_subnode_namelen(void *fdt, int parentoffset, - const char *name, int namelen) + const char *name, int namelen) { - struct fdt_node_header *nh; - int offset, nextoffset; - int nodelen; - int err; - uint32_t tag; - fdt32_t *endtag; - - FDT_RW_PROBE(fdt); - - offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); - if (offset >= 0) - return -FDT_ERR_EXISTS; - else if (offset != -FDT_ERR_NOTFOUND) - return offset; - - /* Try to place the new node after the parent's properties */ - tag = fdt_next_tag(fdt, parentoffset, &nextoffset); - /* the fdt_subnode_offset_namelen() should ensure this never hits */ - if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) - return -FDT_ERR_INTERNAL; - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - } while ((tag == FDT_PROP) || (tag == FDT_NOP)); - - nh = fdt_offset_ptr_w_(fdt, offset); - nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; - - err = fdt_splice_struct_(fdt, nh, 0, nodelen); - if (err) - return err; - - nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); - memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); - memcpy(nh->name, name, namelen); - endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); - *endtag = cpu_to_fdt32(FDT_END_NODE); - - return offset; + struct fdt_node_header *nh; + int offset, nextoffset; + int nodelen; + int err; + uint32_t tag; + fdt32_t *endtag; + + FDT_RW_PROBE(fdt); + + offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); + if (offset >= 0) + return -FDT_ERR_EXISTS; + else if (offset != -FDT_ERR_NOTFOUND) + return offset; + + /* Try to place the new node after the parent's properties */ + tag = fdt_next_tag(fdt, parentoffset, &nextoffset); + /* the fdt_subnode_offset_namelen() should ensure this never hits */ + if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) + return -FDT_ERR_INTERNAL; + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + } while ((tag == FDT_PROP) || (tag == FDT_NOP)); + + nh = fdt_offset_ptr_w_(fdt, offset); + nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; + + err = fdt_splice_struct_(fdt, nh, 0, nodelen); + if (err) + return err; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); + memcpy(nh->name, name, namelen); + endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); + *endtag = cpu_to_fdt32(FDT_END_NODE); + + return offset; } int fdt_add_subnode(void *fdt, int parentoffset, const char *name) { - return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); + return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); } int fdt_del_node(void *fdt, int nodeoffset) { - int endoffset; + int endoffset; - FDT_RW_PROBE(fdt); + FDT_RW_PROBE(fdt); - endoffset = fdt_node_end_offset_(fdt, nodeoffset); - if (endoffset < 0) - return endoffset; + endoffset = fdt_node_end_offset_(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; - return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset), - endoffset - nodeoffset, 0); + return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset), + endoffset - nodeoffset, 0); } static void fdt_packblocks_(const char *old, char *new, - int mem_rsv_size, - int struct_size, - int strings_size) + int mem_rsv_size, + int struct_size, + int strings_size) { - int mem_rsv_off, struct_off, strings_off; + int mem_rsv_off, struct_off, strings_off; - mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); - struct_off = mem_rsv_off + mem_rsv_size; - strings_off = struct_off + struct_size; + mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); + struct_off = mem_rsv_off + mem_rsv_size; + strings_off = struct_off + struct_size; - memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); - fdt_set_off_mem_rsvmap(new, mem_rsv_off); + memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); + fdt_set_off_mem_rsvmap(new, mem_rsv_off); - memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); - fdt_set_off_dt_struct(new, struct_off); - fdt_set_size_dt_struct(new, struct_size); + memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); + fdt_set_off_dt_struct(new, struct_off); + fdt_set_size_dt_struct(new, struct_size); - memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); - fdt_set_off_dt_strings(new, strings_off); - fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); + memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); + fdt_set_off_dt_strings(new, strings_off); + fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); } int fdt_open_into(const void *fdt, void *buf, int bufsize) { - int err; - int mem_rsv_size, struct_size; - int newsize; - const char *fdtstart = fdt; - const char *fdtend = fdtstart + fdt_totalsize(fdt); - char *tmp; - - FDT_RO_PROBE(fdt); - - mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) - * sizeof(struct fdt_reserve_entry); - - if (can_assume(LATEST) || fdt_version(fdt) >= 17) { - struct_size = fdt_size_dt_struct(fdt); - } else if (fdt_version(fdt) == 16) { - struct_size = 0; - while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) - ; - if (struct_size < 0) - return struct_size; - } else { - return -FDT_ERR_BADVERSION; - } - - if (can_assume(LIBFDT_ORDER) || - !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { - /* no further work necessary */ - err = fdt_move(fdt, buf, bufsize); - if (err) - return err; - fdt_set_version(buf, 17); - fdt_set_size_dt_struct(buf, struct_size); - fdt_set_totalsize(buf, bufsize); - return 0; - } - - /* Need to reorder */ - newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size - + struct_size + fdt_size_dt_strings(fdt); - - if (bufsize < newsize) - return -FDT_ERR_NOSPACE; - - /* First attempt to build converted tree at beginning of buffer */ - tmp = buf; - /* But if that overlaps with the old tree... */ - if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { - /* Try right after the old tree instead */ - tmp = (char *)(uintptr_t)fdtend; - if ((tmp + newsize) > ((char *)buf + bufsize)) - return -FDT_ERR_NOSPACE; - } - - fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, - fdt_size_dt_strings(fdt)); - memmove(buf, tmp, newsize); - - fdt_set_magic(buf, FDT_MAGIC); - fdt_set_totalsize(buf, bufsize); - fdt_set_version(buf, 17); - fdt_set_last_comp_version(buf, 16); - fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); - - return 0; + int err; + int mem_rsv_size, struct_size; + int newsize; + const char *fdtstart = fdt; + const char *fdtend = fdtstart + fdt_totalsize(fdt); + char *tmp; + + FDT_RO_PROBE(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + + if (can_assume(LATEST) || fdt_version(fdt) >= 17) { + struct_size = fdt_size_dt_struct(fdt); + } else if (fdt_version(fdt) == 16) { + struct_size = 0; + while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) + ; + if (struct_size < 0) + return struct_size; + } else { + return -FDT_ERR_BADVERSION; + } + + if (can_assume(LIBFDT_ORDER) || + !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { + /* no further work necessary */ + err = fdt_move(fdt, buf, bufsize); + if (err) + return err; + fdt_set_version(buf, 17); + fdt_set_size_dt_struct(buf, struct_size); + fdt_set_totalsize(buf, bufsize); + return 0; + } + + /* Need to reorder */ + newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + + struct_size + fdt_size_dt_strings(fdt); + + if (bufsize < newsize) + return -FDT_ERR_NOSPACE; + + /* First attempt to build converted tree at beginning of buffer */ + tmp = buf; + /* But if that overlaps with the old tree... */ + if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { + /* Try right after the old tree instead */ + tmp = (char *)(uintptr_t)fdtend; + if ((tmp + newsize) > ((char *)buf + bufsize)) + return -FDT_ERR_NOSPACE; + } + + fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, + fdt_size_dt_strings(fdt)); + memmove(buf, tmp, newsize); + + fdt_set_magic(buf, FDT_MAGIC); + fdt_set_totalsize(buf, bufsize); + fdt_set_version(buf, 17); + fdt_set_last_comp_version(buf, 16); + fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); + + return 0; } int fdt_pack(void *fdt) { - int mem_rsv_size; + int mem_rsv_size; - FDT_RW_PROBE(fdt); + FDT_RW_PROBE(fdt); - mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) - * sizeof(struct fdt_reserve_entry); - fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), - fdt_size_dt_strings(fdt)); - fdt_set_totalsize(fdt, fdt_data_size_(fdt)); + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), + fdt_size_dt_strings(fdt)); + fdt_set_totalsize(fdt, fdt_data_size_(fdt)); - return 0; + return 0; } diff --git a/components/drivers/ofw/libfdt/fdt_strerror.c b/components/drivers/ofw/libfdt/fdt_strerror.c index d852b77e81..4d0774f18e 100644 --- a/components/drivers/ofw/libfdt/fdt_strerror.c +++ b/components/drivers/ofw/libfdt/fdt_strerror.c @@ -12,49 +12,49 @@ #include "libfdt_internal.h" struct fdt_errtabent { - const char *str; + const char *str; }; #define FDT_ERRTABENT(val) \ - [(val)] = { .str = #val, } + [(val)] = { .str = #val, } static struct fdt_errtabent fdt_errtable[] = { - FDT_ERRTABENT(FDT_ERR_NOTFOUND), - FDT_ERRTABENT(FDT_ERR_EXISTS), - FDT_ERRTABENT(FDT_ERR_NOSPACE), - - FDT_ERRTABENT(FDT_ERR_BADOFFSET), - FDT_ERRTABENT(FDT_ERR_BADPATH), - FDT_ERRTABENT(FDT_ERR_BADPHANDLE), - FDT_ERRTABENT(FDT_ERR_BADSTATE), - - FDT_ERRTABENT(FDT_ERR_TRUNCATED), - FDT_ERRTABENT(FDT_ERR_BADMAGIC), - FDT_ERRTABENT(FDT_ERR_BADVERSION), - FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), - FDT_ERRTABENT(FDT_ERR_BADLAYOUT), - FDT_ERRTABENT(FDT_ERR_INTERNAL), - FDT_ERRTABENT(FDT_ERR_BADNCELLS), - FDT_ERRTABENT(FDT_ERR_BADVALUE), - FDT_ERRTABENT(FDT_ERR_BADOVERLAY), - FDT_ERRTABENT(FDT_ERR_NOPHANDLES), - FDT_ERRTABENT(FDT_ERR_BADFLAGS), - FDT_ERRTABENT(FDT_ERR_ALIGNMENT), + FDT_ERRTABENT(FDT_ERR_NOTFOUND), + FDT_ERRTABENT(FDT_ERR_EXISTS), + FDT_ERRTABENT(FDT_ERR_NOSPACE), + + FDT_ERRTABENT(FDT_ERR_BADOFFSET), + FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADPHANDLE), + FDT_ERRTABENT(FDT_ERR_BADSTATE), + + FDT_ERRTABENT(FDT_ERR_TRUNCATED), + FDT_ERRTABENT(FDT_ERR_BADMAGIC), + FDT_ERRTABENT(FDT_ERR_BADVERSION), + FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), + FDT_ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_INTERNAL), + FDT_ERRTABENT(FDT_ERR_BADNCELLS), + FDT_ERRTABENT(FDT_ERR_BADVALUE), + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_NOPHANDLES), + FDT_ERRTABENT(FDT_ERR_BADFLAGS), + FDT_ERRTABENT(FDT_ERR_ALIGNMENT), }; -#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) +#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) const char *fdt_strerror(int errval) { - if (errval > 0) - return ""; - else if (errval == 0) - return ""; - else if (-errval < FDT_ERRTABSIZE) { - const char *s = fdt_errtable[-errval].str; - - if (s) - return s; - } - - return ""; + if (errval > 0) + return ""; + else if (errval == 0) + return ""; + else if (-errval < FDT_ERRTABSIZE) { + const char *s = fdt_errtable[-errval].str; + + if (s) + return s; + } + + return ""; } diff --git a/components/drivers/ofw/libfdt/fdt_sw.c b/components/drivers/ofw/libfdt/fdt_sw.c index 4c569ee7eb..62dcb7d170 100644 --- a/components/drivers/ofw/libfdt/fdt_sw.c +++ b/components/drivers/ofw/libfdt/fdt_sw.c @@ -12,373 +12,373 @@ static int fdt_sw_probe_(void *fdt) { - if (!can_assume(VALID_INPUT)) { - if (fdt_magic(fdt) == FDT_MAGIC) - return -FDT_ERR_BADSTATE; - else if (fdt_magic(fdt) != FDT_SW_MAGIC) - return -FDT_ERR_BADMAGIC; - } - - return 0; + if (!can_assume(VALID_INPUT)) { + if (fdt_magic(fdt) == FDT_MAGIC) + return -FDT_ERR_BADSTATE; + else if (fdt_magic(fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; + } + + return 0; } #define FDT_SW_PROBE(fdt) \ - { \ - int err; \ - if ((err = fdt_sw_probe_(fdt)) != 0) \ - return err; \ - } + { \ + int err; \ + if ((err = fdt_sw_probe_(fdt)) != 0) \ + return err; \ + } -/* 'memrsv' state: Initial state after fdt_create() +/* 'memrsv' state: Initial state after fdt_create() * * Allowed functions: - * fdt_add_reservemap_entry() - * fdt_finish_reservemap() [moves to 'struct' state] + * fdt_add_reservemap_entry() + * fdt_finish_reservemap() [moves to 'struct' state] */ static int fdt_sw_probe_memrsv_(void *fdt) { - int err = fdt_sw_probe_(fdt); - if (err) - return err; + int err = fdt_sw_probe_(fdt); + if (err) + return err; - if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0) - return -FDT_ERR_BADSTATE; - return 0; + if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0) + return -FDT_ERR_BADSTATE; + return 0; } #define FDT_SW_PROBE_MEMRSV(fdt) \ - { \ - int err; \ - if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ - return err; \ - } + { \ + int err; \ + if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ + return err; \ + } -/* 'struct' state: Enter this state after fdt_finish_reservemap() +/* 'struct' state: Enter this state after fdt_finish_reservemap() * * Allowed functions: - * fdt_begin_node() - * fdt_end_node() - * fdt_property*() - * fdt_finish() [moves to 'complete' state] + * fdt_begin_node() + * fdt_end_node() + * fdt_property*() + * fdt_finish() [moves to 'complete' state] */ static int fdt_sw_probe_struct_(void *fdt) { - int err = fdt_sw_probe_(fdt); - if (err) - return err; - - if (!can_assume(VALID_INPUT) && - fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) - return -FDT_ERR_BADSTATE; - return 0; + int err = fdt_sw_probe_(fdt); + if (err) + return err; + + if (!can_assume(VALID_INPUT) && + fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) + return -FDT_ERR_BADSTATE; + return 0; } #define FDT_SW_PROBE_STRUCT(fdt) \ - { \ - int err; \ - if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ - return err; \ - } + { \ + int err; \ + if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ + return err; \ + } static inline uint32_t sw_flags(void *fdt) { - /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */ - return fdt_last_comp_version(fdt); + /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */ + return fdt_last_comp_version(fdt); } -/* 'complete' state: Enter this state after fdt_finish() +/* 'complete' state: Enter this state after fdt_finish() * * Allowed functions: none */ static void *fdt_grab_space_(void *fdt, size_t len) { - unsigned int offset = fdt_size_dt_struct(fdt); - unsigned int spaceleft; + unsigned int offset = fdt_size_dt_struct(fdt); + unsigned int spaceleft; - spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - - fdt_size_dt_strings(fdt); + spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) + - fdt_size_dt_strings(fdt); - if ((offset + len < offset) || (offset + len > spaceleft)) - return NULL; + if ((offset + len < offset) || (offset + len > spaceleft)) + return NULL; - fdt_set_size_dt_struct(fdt, offset + len); - return fdt_offset_ptr_w_(fdt, offset); + fdt_set_size_dt_struct(fdt, offset + len); + return fdt_offset_ptr_w_(fdt, offset); } int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) { - const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry)); - void *fdt = buf; + const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry)); + void *fdt = buf; - if (bufsize < hdrsize) - return -FDT_ERR_NOSPACE; + if (bufsize < hdrsize) + return -FDT_ERR_NOSPACE; - if (flags & ~FDT_CREATE_FLAGS_ALL) - return -FDT_ERR_BADFLAGS; + if (flags & ~FDT_CREATE_FLAGS_ALL) + return -FDT_ERR_BADFLAGS; - memset(buf, 0, bufsize); + memset(buf, 0, bufsize); - /* - * magic and last_comp_version keep intermediate state during the fdt - * creation process, which is replaced with the proper FDT format by - * fdt_finish(). - * - * flags should be accessed with sw_flags(). - */ - fdt_set_magic(fdt, FDT_SW_MAGIC); - fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); - fdt_set_last_comp_version(fdt, flags); + /* + * magic and last_comp_version keep intermediate state during the fdt + * creation process, which is replaced with the proper FDT format by + * fdt_finish(). + * + * flags should be accessed with sw_flags(). + */ + fdt_set_magic(fdt, FDT_SW_MAGIC); + fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, flags); - fdt_set_totalsize(fdt, bufsize); + fdt_set_totalsize(fdt, bufsize); - fdt_set_off_mem_rsvmap(fdt, hdrsize); - fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); - fdt_set_off_dt_strings(fdt, 0); + fdt_set_off_mem_rsvmap(fdt, hdrsize); + fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); + fdt_set_off_dt_strings(fdt, 0); - return 0; + return 0; } int fdt_create(void *buf, int bufsize) { - return fdt_create_with_flags(buf, bufsize, 0); + return fdt_create_with_flags(buf, bufsize, 0); } int fdt_resize(void *fdt, void *buf, int bufsize) { - size_t headsize, tailsize; - char *oldtail, *newtail; + size_t headsize, tailsize; + char *oldtail, *newtail; - FDT_SW_PROBE(fdt); + FDT_SW_PROBE(fdt); - if (bufsize < 0) - return -FDT_ERR_NOSPACE; + if (bufsize < 0) + return -FDT_ERR_NOSPACE; - headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - tailsize = fdt_size_dt_strings(fdt); + headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + tailsize = fdt_size_dt_strings(fdt); - if (!can_assume(VALID_DTB) && - headsize + tailsize > fdt_totalsize(fdt)) - return -FDT_ERR_INTERNAL; + if (!can_assume(VALID_DTB) && + headsize + tailsize > fdt_totalsize(fdt)) + return -FDT_ERR_INTERNAL; - if ((headsize + tailsize) > (unsigned)bufsize) - return -FDT_ERR_NOSPACE; + if ((headsize + tailsize) > (unsigned)bufsize) + return -FDT_ERR_NOSPACE; - oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; - newtail = (char *)buf + bufsize - tailsize; + oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; + newtail = (char *)buf + bufsize - tailsize; - /* Two cases to avoid clobbering data if the old and new - * buffers partially overlap */ - if (buf <= fdt) { - memmove(buf, fdt, headsize); - memmove(newtail, oldtail, tailsize); - } else { - memmove(newtail, oldtail, tailsize); - memmove(buf, fdt, headsize); - } + /* Two cases to avoid clobbering data if the old and new + * buffers partially overlap */ + if (buf <= fdt) { + memmove(buf, fdt, headsize); + memmove(newtail, oldtail, tailsize); + } else { + memmove(newtail, oldtail, tailsize); + memmove(buf, fdt, headsize); + } - fdt_set_totalsize(buf, bufsize); - if (fdt_off_dt_strings(buf)) - fdt_set_off_dt_strings(buf, bufsize); + fdt_set_totalsize(buf, bufsize); + if (fdt_off_dt_strings(buf)) + fdt_set_off_dt_strings(buf, bufsize); - return 0; + return 0; } int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) { - struct fdt_reserve_entry *re; - int offset; + struct fdt_reserve_entry *re; + int offset; - FDT_SW_PROBE_MEMRSV(fdt); + FDT_SW_PROBE_MEMRSV(fdt); - offset = fdt_off_dt_struct(fdt); - if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) - return -FDT_ERR_NOSPACE; + offset = fdt_off_dt_struct(fdt); + if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) + return -FDT_ERR_NOSPACE; - re = (struct fdt_reserve_entry *)((char *)fdt + offset); - re->address = cpu_to_fdt64(addr); - re->size = cpu_to_fdt64(size); + re = (struct fdt_reserve_entry *)((char *)fdt + offset); + re->address = cpu_to_fdt64(addr); + re->size = cpu_to_fdt64(size); - fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); + fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); - return 0; + return 0; } int fdt_finish_reservemap(void *fdt) { - int err = fdt_add_reservemap_entry(fdt, 0, 0); + int err = fdt_add_reservemap_entry(fdt, 0, 0); - if (err) - return err; + if (err) + return err; - fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); - return 0; + fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); + return 0; } int fdt_begin_node(void *fdt, const char *name) { - struct fdt_node_header *nh; - int namelen; + struct fdt_node_header *nh; + int namelen; - FDT_SW_PROBE_STRUCT(fdt); + FDT_SW_PROBE_STRUCT(fdt); - namelen = strlen(name) + 1; - nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); - if (! nh) - return -FDT_ERR_NOSPACE; + namelen = strlen(name) + 1; + nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); + if (! nh) + return -FDT_ERR_NOSPACE; - nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); - memcpy(nh->name, name, namelen); - return 0; + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memcpy(nh->name, name, namelen); + return 0; } int fdt_end_node(void *fdt) { - fdt32_t *en; + fdt32_t *en; - FDT_SW_PROBE_STRUCT(fdt); + FDT_SW_PROBE_STRUCT(fdt); - en = fdt_grab_space_(fdt, FDT_TAGSIZE); - if (! en) - return -FDT_ERR_NOSPACE; + en = fdt_grab_space_(fdt, FDT_TAGSIZE); + if (! en) + return -FDT_ERR_NOSPACE; - *en = cpu_to_fdt32(FDT_END_NODE); - return 0; + *en = cpu_to_fdt32(FDT_END_NODE); + return 0; } static int fdt_add_string_(void *fdt, const char *s) { - char *strtab = (char *)fdt + fdt_totalsize(fdt); - unsigned int strtabsize = fdt_size_dt_strings(fdt); - unsigned int len = strlen(s) + 1; - unsigned int struct_top, offset; - - offset = strtabsize + len; - struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - if (fdt_totalsize(fdt) - offset < struct_top) - return 0; /* no more room :( */ - - memcpy(strtab - offset, s, len); - fdt_set_size_dt_strings(fdt, strtabsize + len); - return -offset; + char *strtab = (char *)fdt + fdt_totalsize(fdt); + unsigned int strtabsize = fdt_size_dt_strings(fdt); + unsigned int len = strlen(s) + 1; + unsigned int struct_top, offset; + + offset = strtabsize + len; + struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + if (fdt_totalsize(fdt) - offset < struct_top) + return 0; /* no more room :( */ + + memcpy(strtab - offset, s, len); + fdt_set_size_dt_strings(fdt, strtabsize + len); + return -offset; } /* Must only be used to roll back in case of error */ static void fdt_del_last_string_(void *fdt, const char *s) { - int strtabsize = fdt_size_dt_strings(fdt); - int len = strlen(s) + 1; + int strtabsize = fdt_size_dt_strings(fdt); + int len = strlen(s) + 1; - fdt_set_size_dt_strings(fdt, strtabsize - len); + fdt_set_size_dt_strings(fdt, strtabsize - len); } static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) { - char *strtab = (char *)fdt + fdt_totalsize(fdt); - int strtabsize = fdt_size_dt_strings(fdt); - const char *p; + char *strtab = (char *)fdt + fdt_totalsize(fdt); + int strtabsize = fdt_size_dt_strings(fdt); + const char *p; - *allocated = 0; + *allocated = 0; - p = fdt_find_string_(strtab - strtabsize, strtabsize, s); - if (p) - return p - strtab; + p = fdt_find_string_(strtab - strtabsize, strtabsize, s); + if (p) + return p - strtab; - *allocated = 1; + *allocated = 1; - return fdt_add_string_(fdt, s); + return fdt_add_string_(fdt, s); } int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) { - struct fdt_property *prop; - int nameoff; - int allocated; - - FDT_SW_PROBE_STRUCT(fdt); - - /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */ - if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) { - allocated = 1; - nameoff = fdt_add_string_(fdt, name); - } else { - nameoff = fdt_find_add_string_(fdt, name, &allocated); - } - if (nameoff == 0) - return -FDT_ERR_NOSPACE; - - prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); - if (! prop) { - if (allocated) - fdt_del_last_string_(fdt, name); - return -FDT_ERR_NOSPACE; - } - - prop->tag = cpu_to_fdt32(FDT_PROP); - prop->nameoff = cpu_to_fdt32(nameoff); - prop->len = cpu_to_fdt32(len); - *valp = prop->data; - return 0; + struct fdt_property *prop; + int nameoff; + int allocated; + + FDT_SW_PROBE_STRUCT(fdt); + + /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */ + if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) { + allocated = 1; + nameoff = fdt_add_string_(fdt, name); + } else { + nameoff = fdt_find_add_string_(fdt, name, &allocated); + } + if (nameoff == 0) + return -FDT_ERR_NOSPACE; + + prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); + if (! prop) { + if (allocated) + fdt_del_last_string_(fdt, name); + return -FDT_ERR_NOSPACE; + } + + prop->tag = cpu_to_fdt32(FDT_PROP); + prop->nameoff = cpu_to_fdt32(nameoff); + prop->len = cpu_to_fdt32(len); + *valp = prop->data; + return 0; } int fdt_property(void *fdt, const char *name, const void *val, int len) { - void *ptr; - int ret; - - ret = fdt_property_placeholder(fdt, name, len, &ptr); - if (ret) - return ret; - memcpy(ptr, val, len); - return 0; + void *ptr; + int ret; + + ret = fdt_property_placeholder(fdt, name, len, &ptr); + if (ret) + return ret; + memcpy(ptr, val, len); + return 0; } int fdt_finish(void *fdt) { - char *p = (char *)fdt; - fdt32_t *end; - int oldstroffset, newstroffset; - uint32_t tag; - int offset, nextoffset; - - FDT_SW_PROBE_STRUCT(fdt); - - /* Add terminator */ - end = fdt_grab_space_(fdt, sizeof(*end)); - if (! end) - return -FDT_ERR_NOSPACE; - *end = cpu_to_fdt32(FDT_END); - - /* Relocate the string table */ - oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); - newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); - fdt_set_off_dt_strings(fdt, newstroffset); - - /* Walk the structure, correcting string offsets */ - offset = 0; - while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { - if (tag == FDT_PROP) { - struct fdt_property *prop = - fdt_offset_ptr_w_(fdt, offset); - int nameoff; - - nameoff = fdt32_to_cpu(prop->nameoff); - nameoff += fdt_size_dt_strings(fdt); - prop->nameoff = cpu_to_fdt32(nameoff); - } - offset = nextoffset; - } - if (nextoffset < 0) - return nextoffset; - - /* Finally, adjust the header */ - fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); - - /* And fix up fields that were keeping intermediate state. */ - fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION); - fdt_set_magic(fdt, FDT_MAGIC); - - return 0; + char *p = (char *)fdt; + fdt32_t *end; + int oldstroffset, newstroffset; + uint32_t tag; + int offset, nextoffset; + + FDT_SW_PROBE_STRUCT(fdt); + + /* Add terminator */ + end = fdt_grab_space_(fdt, sizeof(*end)); + if (! end) + return -FDT_ERR_NOSPACE; + *end = cpu_to_fdt32(FDT_END); + + /* Relocate the string table */ + oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); + newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); + fdt_set_off_dt_strings(fdt, newstroffset); + + /* Walk the structure, correcting string offsets */ + offset = 0; + while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { + if (tag == FDT_PROP) { + struct fdt_property *prop = + fdt_offset_ptr_w_(fdt, offset); + int nameoff; + + nameoff = fdt32_to_cpu(prop->nameoff); + nameoff += fdt_size_dt_strings(fdt); + prop->nameoff = cpu_to_fdt32(nameoff); + } + offset = nextoffset; + } + if (nextoffset < 0) + return nextoffset; + + /* Finally, adjust the header */ + fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); + + /* And fix up fields that were keeping intermediate state. */ + fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION); + fdt_set_magic(fdt, FDT_MAGIC); + + return 0; } diff --git a/components/drivers/ofw/libfdt/fdt_wip.c b/components/drivers/ofw/libfdt/fdt_wip.c index c2d7566a67..f8710250da 100644 --- a/components/drivers/ofw/libfdt/fdt_wip.c +++ b/components/drivers/ofw/libfdt/fdt_wip.c @@ -11,84 +11,84 @@ #include "libfdt_internal.h" int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, - const char *name, int namelen, - uint32_t idx, const void *val, - int len) + const char *name, int namelen, + uint32_t idx, const void *val, + int len) { - void *propval; - int proplen; + void *propval; + int proplen; - propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, - &proplen); - if (!propval) - return proplen; + propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, + &proplen); + if (!propval) + return proplen; - if ((unsigned)proplen < (len + idx)) - return -FDT_ERR_NOSPACE; + if ((unsigned)proplen < (len + idx)) + return -FDT_ERR_NOSPACE; - memcpy((char *)propval + idx, val, len); - return 0; + memcpy((char *)propval + idx, val, len); + return 0; } int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, - const void *val, int len) + const void *val, int len) { - const void *propval; - int proplen; + const void *propval; + int proplen; - propval = fdt_getprop(fdt, nodeoffset, name, &proplen); - if (!propval) - return proplen; + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); + if (!propval) + return proplen; - if (proplen != len) - return -FDT_ERR_NOSPACE; + if (proplen != len) + return -FDT_ERR_NOSPACE; - return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, - strlen(name), 0, - val, len); + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), 0, + val, len); } static void fdt_nop_region_(void *start, int len) { - fdt32_t *p; + fdt32_t *p; - for (p = start; (char *)p < ((char *)start + len); p++) - *p = cpu_to_fdt32(FDT_NOP); + for (p = start; (char *)p < ((char *)start + len); p++) + *p = cpu_to_fdt32(FDT_NOP); } int fdt_nop_property(void *fdt, int nodeoffset, const char *name) { - struct fdt_property *prop; - int len; + struct fdt_property *prop; + int len; - prop = fdt_get_property_w(fdt, nodeoffset, name, &len); - if (!prop) - return len; + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (!prop) + return len; - fdt_nop_region_(prop, len + sizeof(*prop)); + fdt_nop_region_(prop, len + sizeof(*prop)); - return 0; + return 0; } int fdt_node_end_offset_(void *fdt, int offset) { - int depth = 0; + int depth = 0; - while ((offset >= 0) && (depth >= 0)) - offset = fdt_next_node(fdt, offset, &depth); + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node(fdt, offset, &depth); - return offset; + return offset; } int fdt_nop_node(void *fdt, int nodeoffset) { - int endoffset; + int endoffset; - endoffset = fdt_node_end_offset_(fdt, nodeoffset); - if (endoffset < 0) - return endoffset; + endoffset = fdt_node_end_offset_(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; - fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0), - endoffset - nodeoffset); - return 0; + fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0), + endoffset - nodeoffset); + return 0; } diff --git a/components/drivers/ofw/libfdt/libfdt.h b/components/drivers/ofw/libfdt/libfdt.h index 77ccff1991..2bde408815 100644 --- a/components/drivers/ofw/libfdt/libfdt.h +++ b/components/drivers/ofw/libfdt/libfdt.h @@ -13,104 +13,104 @@ extern "C" { #endif -#define FDT_FIRST_SUPPORTED_VERSION 0x02 +#define FDT_FIRST_SUPPORTED_VERSION 0x02 #define FDT_LAST_COMPATIBLE_VERSION 0x10 -#define FDT_LAST_SUPPORTED_VERSION 0x11 +#define FDT_LAST_SUPPORTED_VERSION 0x11 /* Error codes: informative error codes */ -#define FDT_ERR_NOTFOUND 1 - /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ -#define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attempted to create a node or property which - * already exists */ -#define FDT_ERR_NOSPACE 3 - /* FDT_ERR_NOSPACE: Operation needed to expand the device - * tree, but its buffer did not have sufficient space to - * contain the expanded tree. Use fdt_open_into() to move the - * device tree to a buffer with more space. */ +#define FDT_ERR_NOTFOUND 1 + /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ +#define FDT_ERR_EXISTS 2 + /* FDT_ERR_EXISTS: Attempted to create a node or property which + * already exists */ +#define FDT_ERR_NOSPACE 3 + /* FDT_ERR_NOSPACE: Operation needed to expand the device + * tree, but its buffer did not have sufficient space to + * contain the expanded tree. Use fdt_open_into() to move the + * device tree to a buffer with more space. */ /* Error codes: codes for bad parameters */ -#define FDT_ERR_BADOFFSET 4 - /* FDT_ERR_BADOFFSET: Function was passed a structure block - * offset which is out-of-bounds, or which points to an - * unsuitable part of the structure for the operation. */ -#define FDT_ERR_BADPATH 5 - /* FDT_ERR_BADPATH: Function was passed a badly formatted path - * (e.g. missing a leading / for a function which requires an - * absolute path) */ -#define FDT_ERR_BADPHANDLE 6 - /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. - * This can be caused either by an invalid phandle property - * length, or the phandle value was either 0 or -1, which are - * not permitted. */ -#define FDT_ERR_BADSTATE 7 - /* FDT_ERR_BADSTATE: Function was passed an incomplete device - * tree created by the sequential-write functions, which is - * not sufficiently complete for the requested operation. */ +#define FDT_ERR_BADOFFSET 4 + /* FDT_ERR_BADOFFSET: Function was passed a structure block + * offset which is out-of-bounds, or which points to an + * unsuitable part of the structure for the operation. */ +#define FDT_ERR_BADPATH 5 + /* FDT_ERR_BADPATH: Function was passed a badly formatted path + * (e.g. missing a leading / for a function which requires an + * absolute path) */ +#define FDT_ERR_BADPHANDLE 6 + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. + * This can be caused either by an invalid phandle property + * length, or the phandle value was either 0 or -1, which are + * not permitted. */ +#define FDT_ERR_BADSTATE 7 + /* FDT_ERR_BADSTATE: Function was passed an incomplete device + * tree created by the sequential-write functions, which is + * not sufficiently complete for the requested operation. */ /* Error codes: codes for bad device tree blobs */ -#define FDT_ERR_TRUNCATED 8 - /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly - * terminated (overflows, goes outside allowed bounds, or - * isn't properly terminated). */ -#define FDT_ERR_BADMAGIC 9 - /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a - * device tree at all - it is missing the flattened device - * tree magic number. */ -#define FDT_ERR_BADVERSION 10 - /* FDT_ERR_BADVERSION: Given device tree has a version which - * can't be handled by the requested operation. For - * read-write functions, this may mean that fdt_open_into() is - * required to convert the tree to the expected version. */ -#define FDT_ERR_BADSTRUCTURE 11 - /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt - * structure block or other serious error (e.g. misnested - * nodes, or subnodes preceding properties). */ -#define FDT_ERR_BADLAYOUT 12 - /* FDT_ERR_BADLAYOUT: For read-write functions, the given - * device tree has it's sub-blocks in an order that the - * function can't handle (memory reserve map, then structure, - * then strings). Use fdt_open_into() to reorganize the tree - * into a form suitable for the read-write operations. */ +#define FDT_ERR_TRUNCATED 8 + /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly + * terminated (overflows, goes outside allowed bounds, or + * isn't properly terminated). */ +#define FDT_ERR_BADMAGIC 9 + /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a + * device tree at all - it is missing the flattened device + * tree magic number. */ +#define FDT_ERR_BADVERSION 10 + /* FDT_ERR_BADVERSION: Given device tree has a version which + * can't be handled by the requested operation. For + * read-write functions, this may mean that fdt_open_into() is + * required to convert the tree to the expected version. */ +#define FDT_ERR_BADSTRUCTURE 11 + /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt + * structure block or other serious error (e.g. misnested + * nodes, or subnodes preceding properties). */ +#define FDT_ERR_BADLAYOUT 12 + /* FDT_ERR_BADLAYOUT: For read-write functions, the given + * device tree has it's sub-blocks in an order that the + * function can't handle (memory reserve map, then structure, + * then strings). Use fdt_open_into() to reorganize the tree + * into a form suitable for the read-write operations. */ /* "Can't happen" error indicating a bug in libfdt */ -#define FDT_ERR_INTERNAL 13 - /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. - * Should never be returned, if it is, it indicates a bug in - * libfdt itself. */ +#define FDT_ERR_INTERNAL 13 + /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. + * Should never be returned, if it is, it indicates a bug in + * libfdt itself. */ /* Errors in device tree content */ -#define FDT_ERR_BADNCELLS 14 - /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells - * or similar property with a bad format or value */ +#define FDT_ERR_BADNCELLS 14 + /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells + * or similar property with a bad format or value */ -#define FDT_ERR_BADVALUE 15 - /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected - * value. For example: a property expected to contain a string list - * is not NUL-terminated within the length of its value. */ +#define FDT_ERR_BADVALUE 15 + /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected + * value. For example: a property expected to contain a string list + * is not NUL-terminated within the length of its value. */ -#define FDT_ERR_BADOVERLAY 16 - /* FDT_ERR_BADOVERLAY: The device tree overlay, while - * correctly structured, cannot be applied due to some - * unexpected or missing value, property or node. */ +#define FDT_ERR_BADOVERLAY 16 + /* FDT_ERR_BADOVERLAY: The device tree overlay, while + * correctly structured, cannot be applied due to some + * unexpected or missing value, property or node. */ -#define FDT_ERR_NOPHANDLES 17 - /* FDT_ERR_NOPHANDLES: The device tree doesn't have any - * phandle available anymore without causing an overflow */ +#define FDT_ERR_NOPHANDLES 17 + /* FDT_ERR_NOPHANDLES: The device tree doesn't have any + * phandle available anymore without causing an overflow */ -#define FDT_ERR_BADFLAGS 18 - /* FDT_ERR_BADFLAGS: The function was passed a flags field that - * contains invalid flags or an invalid combination of flags. */ +#define FDT_ERR_BADFLAGS 18 + /* FDT_ERR_BADFLAGS: The function was passed a flags field that + * contains invalid flags or an invalid combination of flags. */ -#define FDT_ERR_ALIGNMENT 19 - /* FDT_ERR_ALIGNMENT: The device tree base address is not 8-byte - * aligned. */ +#define FDT_ERR_ALIGNMENT 19 + /* FDT_ERR_ALIGNMENT: The device tree base address is not 8-byte + * aligned. */ -#define FDT_ERR_MAX 19 +#define FDT_ERR_MAX 19 /* constants */ #define FDT_MAX_PHANDLE 0xfffffffe - /* Valid values for phandles range from 1 to 2^32-2. */ + /* Valid values for phandles range from 1 to 2^32-2. */ /**********************************************************************/ /* Low-level functions (you probably don't need these) */ @@ -121,7 +121,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); #endif static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) { - return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); + return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); } uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); @@ -133,57 +133,57 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); */ static inline uint16_t fdt16_ld(const fdt16_t *p) { - const uint8_t *bp = (const uint8_t *)p; + const uint8_t *bp = (const uint8_t *)p; - return ((uint16_t)bp[0] << 8) | bp[1]; + return ((uint16_t)bp[0] << 8) | bp[1]; } static inline uint32_t fdt32_ld(const fdt32_t *p) { - const uint8_t *bp = (const uint8_t *)p; + const uint8_t *bp = (const uint8_t *)p; - return ((uint32_t)bp[0] << 24) - | ((uint32_t)bp[1] << 16) - | ((uint32_t)bp[2] << 8) - | bp[3]; + return ((uint32_t)bp[0] << 24) + | ((uint32_t)bp[1] << 16) + | ((uint32_t)bp[2] << 8) + | bp[3]; } static inline void fdt32_st(void *property, uint32_t value) { - uint8_t *bp = (uint8_t *)property; + uint8_t *bp = (uint8_t *)property; - bp[0] = value >> 24; - bp[1] = (value >> 16) & 0xff; - bp[2] = (value >> 8) & 0xff; - bp[3] = value & 0xff; + bp[0] = value >> 24; + bp[1] = (value >> 16) & 0xff; + bp[2] = (value >> 8) & 0xff; + bp[3] = value & 0xff; } static inline uint64_t fdt64_ld(const fdt64_t *p) { - const uint8_t *bp = (const uint8_t *)p; - - return ((uint64_t)bp[0] << 56) - | ((uint64_t)bp[1] << 48) - | ((uint64_t)bp[2] << 40) - | ((uint64_t)bp[3] << 32) - | ((uint64_t)bp[4] << 24) - | ((uint64_t)bp[5] << 16) - | ((uint64_t)bp[6] << 8) - | bp[7]; + const uint8_t *bp = (const uint8_t *)p; + + return ((uint64_t)bp[0] << 56) + | ((uint64_t)bp[1] << 48) + | ((uint64_t)bp[2] << 40) + | ((uint64_t)bp[3] << 32) + | ((uint64_t)bp[4] << 24) + | ((uint64_t)bp[5] << 16) + | ((uint64_t)bp[6] << 8) + | bp[7]; } static inline void fdt64_st(void *property, uint64_t value) { - uint8_t *bp = (uint8_t *)property; - - bp[0] = value >> 56; - bp[1] = (value >> 48) & 0xff; - bp[2] = (value >> 40) & 0xff; - bp[3] = (value >> 32) & 0xff; - bp[4] = (value >> 24) & 0xff; - bp[5] = (value >> 16) & 0xff; - bp[6] = (value >> 8) & 0xff; - bp[7] = value & 0xff; + uint8_t *bp = (uint8_t *)property; + + bp[0] = value >> 56; + bp[1] = (value >> 48) & 0xff; + bp[2] = (value >> 40) & 0xff; + bp[3] = (value >> 32) & 0xff; + bp[4] = (value >> 24) & 0xff; + bp[5] = (value >> 16) & 0xff; + bp[6] = (value >> 8) & 0xff; + bp[7] = value & 0xff; } /**********************************************************************/ @@ -194,8 +194,8 @@ int fdt_next_node(const void *fdt, int offset, int *depth); /** * fdt_first_subnode() - get offset of first direct subnode - * @fdt: FDT blob - * @offset: Offset of node to check + * @fdt: FDT blob + * @offset: Offset of node to check * * Return: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none */ @@ -203,8 +203,8 @@ int fdt_first_subnode(const void *fdt, int offset); /** * fdt_next_subnode() - get offset of next direct subnode - * @fdt: FDT blob - * @offset: Offset of previous subnode + * @fdt: FDT blob + * @offset: Offset of previous subnode * * After first calling fdt_first_subnode(), call this function repeatedly to * get direct subnodes of a parent node. @@ -217,52 +217,52 @@ int fdt_next_subnode(const void *fdt, int offset); /** * fdt_for_each_subnode - iterate over all subnodes of a parent * - * @node: child node (int, lvalue) - * @fdt: FDT blob (const void *) - * @parent: parent node (int) + * @node: child node (int, lvalue) + * @fdt: FDT blob (const void *) + * @parent: parent node (int) * * This is actually a wrapper around a for loop and would be used like so: * - * fdt_for_each_subnode(node, fdt, parent) { - * Use node - * ... - * } + * fdt_for_each_subnode(node, fdt, parent) { + * Use node + * ... + * } * - * if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) { - * Error handling - * } + * if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) { + * Error handling + * } * * Note that this is implemented as a macro and @node is used as * iterator in the loop. The parent variable be constant or even a * literal. */ -#define fdt_for_each_subnode(node, fdt, parent) \ - for (node = fdt_first_subnode(fdt, parent); \ - node >= 0; \ - node = fdt_next_subnode(fdt, node)) +#define fdt_for_each_subnode(node, fdt, parent) \ + for (node = fdt_first_subnode(fdt, parent); \ + node >= 0; \ + node = fdt_next_subnode(fdt, node)) /**********************************************************************/ /* General functions */ /**********************************************************************/ #define fdt_get_header(fdt, field) \ - (fdt32_ld(&((const struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) -#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) -#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) -#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) -#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) -#define fdt_version(fdt) (fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) -#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) + (fdt32_ld(&((const struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) +#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) +#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) +#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) +#define fdt_version(fdt) (fdt_get_header(fdt, version)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) #define fdt_set_hdr_(name) \ - static inline void fdt_set_##name(void *fdt, uint32_t val) \ - { \ - struct fdt_header *fdth = (struct fdt_header *)fdt; \ - fdth->name = cpu_to_fdt32(val); \ - } + static inline void fdt_set_##name(void *fdt, uint32_t val) \ + { \ + struct fdt_header *fdth = (struct fdt_header *)fdt; \ + fdth->name = cpu_to_fdt32(val); \ + } fdt_set_hdr_(magic); fdt_set_hdr_(totalsize); fdt_set_hdr_(off_dt_struct); @@ -397,14 +397,14 @@ int fdt_find_max_phandle(const void *fdt, uint32_t *phandle); */ static inline uint32_t fdt_get_max_phandle(const void *fdt) { - uint32_t phandle; - int err; + uint32_t phandle; + int err; - err = fdt_find_max_phandle(fdt, &phandle); - if (err < 0) - return (uint32_t)-1; + err = fdt_find_max_phandle(fdt, &phandle); + if (err < 0) + return (uint32_t)-1; - return phandle; + return phandle; } /** @@ -469,7 +469,7 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); */ #ifndef SWIG /* Not available in Python */ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, - const char *name, int namelen); + const char *name, int namelen); #endif /** * fdt_subnode_offset - find a subnode of a given node @@ -485,15 +485,15 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, * whose name excluding unit address matches the given name. * * returns: - * structure block offset of the requested subnode (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE - * tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. + * structure block offset of the requested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); @@ -525,15 +525,15 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); * address). * * returns: - * structure block offset of the node with the requested path (>=0), on - * success - * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid - * -FDT_ERR_NOTFOUND, if the requested node does not exist + * structure block offset of the node with the requested path (>=0), on + * success + * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + * -FDT_ERR_NOTFOUND, if the requested node does not exist * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_path_offset(const void *fdt, const char *path); @@ -549,16 +549,16 @@ int fdt_path_offset(const void *fdt, const char *path); * pointed to by lenp. * * returns: - * pointer to the node's name, on success - * If lenp is non-NULL, *lenp contains the length of that name - * (>=0) - * NULL, on error - * if lenp is non-NULL *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE - * tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings + * pointer to the node's name, on success + * If lenp is non-NULL, *lenp contains the length of that name + * (>=0) + * NULL, on error + * if lenp is non-NULL *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings */ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); @@ -571,14 +571,14 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); * the given structure block offset. * * returns: - * structure block offset of the property (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested node has no properties - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag + * structure block offset of the property (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested node has no properties + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_first_property_offset(const void *fdt, int nodeoffset); @@ -592,43 +592,43 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset); * of the same node as the given property. * * returns: - * structure block offset of the next property (>=0), on success - * -FDT_ERR_NOTFOUND, if the given property is the last in its node - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag + * structure block offset of the next property (>=0), on success + * -FDT_ERR_NOTFOUND, if the given property is the last in its node + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_next_property_offset(const void *fdt, int offset); /** * fdt_for_each_property_offset - iterate over all properties of a node * - * @property: property offset (int, lvalue) - * @fdt: FDT blob (const void *) - * @node: node offset (int) + * @property: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) * * This is actually a wrapper around a for loop and would be used like so: * - * fdt_for_each_property_offset(property, fdt, node) { - * Use property - * ... - * } + * fdt_for_each_property_offset(property, fdt, node) { + * Use property + * ... + * } * - * if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) { - * Error handling - * } + * if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) { + * Error handling + * } * * Note that this is implemented as a macro and property is used as * iterator in the loop. The node variable can be constant or even a * literal. */ -#define fdt_for_each_property_offset(property, fdt, node) \ - for (property = fdt_first_property_offset(fdt, node); \ - property >= 0; \ - property = fdt_next_property_offset(fdt, property)) +#define fdt_for_each_property_offset(property, fdt, node) \ + for (property = fdt_first_property_offset(fdt, node); \ + property >= 0; \ + property = fdt_next_property_offset(fdt, property)) /** * fdt_get_property_by_offset - retrieve the property at a given offset @@ -645,27 +645,27 @@ int fdt_next_property_offset(const void *fdt, int offset); * works on all versions. * * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, - int offset, - int *lenp); + int offset, + int *lenp); static inline struct fdt_property *fdt_get_property_by_offset_w(void *fdt, - int offset, - int *lenp) + int offset, + int *lenp) { - return (struct fdt_property *)(uintptr_t) - fdt_get_property_by_offset(fdt, offset, lenp); + return (struct fdt_property *)(uintptr_t) + fdt_get_property_by_offset(fdt, offset, lenp); } /** @@ -684,9 +684,9 @@ static inline struct fdt_property *fdt_get_property_by_offset_w(void *fdt, */ #ifndef SWIG /* Not available in Python */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, - int nodeoffset, - const char *name, - int namelen, int *lenp); + int nodeoffset, + const char *name, + int namelen, int *lenp); #endif /** @@ -703,28 +703,28 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, * integer pointed to by lenp. * * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE - * tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, - const char *name, int *lenp); + const char *name, int *lenp); static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, - const char *name, - int *lenp) + const char *name, + int *lenp) { - return (struct fdt_property *)(uintptr_t) - fdt_get_property(fdt, nodeoffset, name, lenp); + return (struct fdt_property *)(uintptr_t) + fdt_get_property(fdt, nodeoffset, name, lenp); } /** @@ -744,23 +744,23 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, * block, not a new copy of the name). * * returns: - * pointer to the property's value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * if namep is non-NULL *namep contiains a pointer to the property - * name. - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * if namep is non-NULL *namep contiains a pointer to the property + * name. + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ #ifndef SWIG /* This function is not useful in Python */ const void *fdt_getprop_by_offset(const void *fdt, int offset, - const char **namep, int *lenp); + const char **namep, int *lenp); #endif /** @@ -778,13 +778,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, */ #ifndef SWIG /* Not available in Python */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp); + const char *name, int namelen, int *lenp); static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, - const char *name, int namelen, - int *lenp) + const char *name, int namelen, + int *lenp) { - return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, - namelen, lenp); + return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, + namelen, lenp); } #endif @@ -802,26 +802,26 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, * returned, in the integer pointed to by @lenp. * * returns: - * pointer to the property's value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE - * tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp); + const char *name, int *lenp); static inline void *fdt_getprop_w(void *fdt, int nodeoffset, - const char *name, int *lenp) + const char *name, int *lenp) { - return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); + return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); } /** @@ -833,8 +833,8 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset, * structure block offset nodeoffset. * * returns: - * the phandle of the node at nodeoffset, on success (!= 0, != -1) - * 0, if the node has no phandle, or another error occurs + * the phandle of the node at nodeoffset, on success (!= 0, != -1) + * 0, if the node has no phandle, or another error occurs */ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); @@ -848,11 +848,11 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); * characters of @name for matching the alias name. * * Return: a pointer to the expansion of the alias named @name, if it exists, - * NULL otherwise + * NULL otherwise */ #ifndef SWIG /* Not available in Python */ const char *fdt_get_alias_namelen(const void *fdt, - const char *name, int namelen); + const char *name, int namelen); #endif /** @@ -864,8 +864,8 @@ const char *fdt_get_alias_namelen(const void *fdt, * value of the property named @name in the node /aliases. * * returns: - * a pointer to the expansion of the alias named 'name', if it exists - * NULL, if the given alias or the /aliases node does not exist + * a pointer to the expansion of the alias named 'name', if it exists + * NULL, if the given alias or the /aliases node does not exist */ const char *fdt_get_alias(const void *fdt, const char *name); @@ -883,16 +883,16 @@ const char *fdt_get_alias(const void *fdt, const char *name); * structure from the start to nodeoffset. * * returns: - * 0, on success - * buf contains the absolute path of the node at - * nodeoffset, as a NUL-terminated string. - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) - * characters and will not fit in the given buffer. - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings + * 0, on success + * buf contains the absolute path of the node at + * nodeoffset, as a NUL-terminated string. + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + * characters and will not fit in the given buffer. + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); @@ -906,28 +906,28 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); * fdt_supernode_atdepth_offset() finds an ancestor of the given node * at a specific depth from the root (where the root itself has depth * 0, its immediate subnodes depth 1 and so forth). So - * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); + * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); * will always return 0, the offset of the root node. If the node at * nodeoffset has depth D, then: - * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); + * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); * will return nodeoffset itself. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: - * structure block offset of the node at node offset's ancestor - * of depth supernodedepth (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of - * nodeoffset - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings + * structure block offset of the node at node offset's ancestor + * of depth supernodedepth (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of + * nodeoffset + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth); + int supernodedepth, int *nodedepth); /** * fdt_node_depth - find the depth of a given node @@ -941,12 +941,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, * structure from the start to nodeoffset. * * returns: - * depth of the node at nodeoffset (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings + * depth of the node at nodeoffset (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_depth(const void *fdt, int nodeoffset); @@ -963,13 +963,13 @@ int fdt_node_depth(const void *fdt, int nodeoffset); * structure from the start to nodeoffset, *twice*. * * returns: - * structure block offset of the parent of the node at nodeoffset - * (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings + * structure block offset of the parent of the node at nodeoffset + * (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_parent_offset(const void *fdt, int nodeoffset); @@ -988,32 +988,32 @@ int fdt_parent_offset(const void *fdt, int nodeoffset); * * To iterate through all nodes matching the criterion, the following * idiom can be used: - * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, - * propval, proplen); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, - * propval, proplen); - * } + * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, + * propval, proplen); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, + * propval, proplen); + * } * * Note the -1 in the first call to the function, if 0 is used here * instead, the function will never locate the root node, even if it * matches the criterion. * * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen); + const char *propname, + const void *propval, int proplen); /** * fdt_node_offset_by_phandle - find the node with a given phandle @@ -1026,13 +1026,13 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, * undefined. * * returns: - * structure block offset of the located node (>= 0), on success - * -FDT_ERR_NOTFOUND, no node with that phandle exists - * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings + * structure block offset of the located node (>= 0), on success + * -FDT_ERR_NOTFOUND, no node with that phandle exists + * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); @@ -1047,18 +1047,18 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); * it returns non-zero otherwise, or on error. * * returns: - * 0, if the node has a 'compatible' property listing the given string - * 1, if the node has a 'compatible' property, but it does not list - * the given string - * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property - * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings + * 0, if the node has a 'compatible' property listing the given string + * 1, if the node has a 'compatible' property, but it does not list + * the given string + * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_check_compatible(const void *fdt, int nodeoffset, - const char *compatible); + const char *compatible); /** * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value @@ -1073,29 +1073,29 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, * * To iterate through all nodes matching the criterion, the following * idiom can be used: - * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); - * } + * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); + * } * * Note the -1 in the first call to the function, if 0 is used here * instead, the function will never locate the root node, even if it * matches the criterion. * * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, - const char *compatible); + const char *compatible); /** * fdt_stringlist_contains - check a string list property for a string @@ -1144,7 +1144,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); * the given string */ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, - const char *string); + const char *string); /** * fdt_stringlist_get() - obtain the string at a given index in a string list @@ -1171,8 +1171,8 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, * -FDT_ERR_NOTFOUND if the property does not exist */ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, - const char *property, int index, - int *lenp); + const char *property, int index, + int *lenp); /**********************************************************************/ /* Read-only functions (addressing related) */ @@ -1187,7 +1187,7 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, * Implementations may support larger values, but in practice higher * values aren't used. */ -#define FDT_MAX_NCELLS 4 +#define FDT_MAX_NCELLS 4 /** * fdt_address_cells - retrieve address size for a bus represented in the tree @@ -1197,15 +1197,15 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, * When the node has a valid #address-cells property, returns its value. * * returns: - * 0 <= n < FDT_MAX_NCELLS, on success + * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid - * #address-cells property - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * #address-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_address_cells(const void *fdt, int nodeoffset); @@ -1218,15 +1218,15 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * When the node has a valid #size-cells property, returns its value. * * returns: - * 0 <= n < FDT_MAX_NCELLS, on success + * 0 <= n < FDT_MAX_NCELLS, on success * 1, if the node has no #size-cells property * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid - * #size-cells property - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * #size-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_size_cells(const void *fdt, int nodeoffset); @@ -1255,9 +1255,9 @@ int fdt_size_cells(const void *fdt, int nodeoffset); */ #ifndef SWIG /* Not available in Python */ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, - const char *name, int namelen, - uint32_t idx, const void *val, - int len); + const char *name, int namelen, + uint32_t idx, const void *val, + int len); #endif /** @@ -1278,19 +1278,19 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, * of the tree. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if len is not equal to the property's current length - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, if len is not equal to the property's current length + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ #ifndef SWIG /* Not available in Python */ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, - const void *val, int len); + const void *val, int len); #endif /** @@ -1311,21 +1311,21 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, * of the tree. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, - const char *name, uint32_t val) + const char *name, uint32_t val) { - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -1346,21 +1346,21 @@ static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, * of the tree. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, - const char *name, uint64_t val) + const char *name, uint64_t val) { - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -1374,9 +1374,9 @@ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, * Return: 0 on success, negative libfdt error number otherwise. */ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, - const char *name, uint32_t val) + const char *name, uint32_t val) { - return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); + return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); } /** @@ -1394,14 +1394,14 @@ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, * tree. * * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_nop_property(void *fdt, int nodeoffset, const char *name); @@ -1419,13 +1419,13 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name); * move any other part of the tree. * * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_nop_node(void *fdt, int nodeoffset); @@ -1435,11 +1435,11 @@ int fdt_nop_node(void *fdt, int nodeoffset); /* fdt_create_with_flags flags */ #define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1 - /* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property - * names in the fdt. This can result in faster creation times, but - * a larger fdt. */ + /* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property + * names in the fdt. This can result in faster creation times, but + * a larger fdt. */ -#define FDT_CREATE_FLAGS_ALL (FDT_CREATE_FLAG_NO_NAME_DEDUP) +#define FDT_CREATE_FLAGS_ALL (FDT_CREATE_FLAG_NO_NAME_DEDUP) /** * fdt_create_with_flags - begin creation of a new fdt @@ -1453,9 +1453,9 @@ int fdt_nop_node(void *fdt, int nodeoffset); * fdt creation process must end with fdt_finished() to produce a valid fdt. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt - * -FDT_ERR_BADFLAGS, flags is not valid + * 0, on success + * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt + * -FDT_ERR_BADFLAGS, flags is not valid */ int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags); @@ -1467,8 +1467,8 @@ int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags); * fdt_create() is equivalent to fdt_create_with_flags() with flags=0. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt + * 0, on success + * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt */ int fdt_create(void *buf, int bufsize); @@ -1479,19 +1479,19 @@ int fdt_begin_node(void *fdt, const char *name); int fdt_property(void *fdt, const char *name, const void *val, int len); static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) { - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_property(fdt, name, &tmp, sizeof(tmp)); + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); } static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) { - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_property(fdt, name, &tmp, sizeof(tmp)); + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); } #ifndef SWIG /* Not available in Python */ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) { - return fdt_property_u32(fdt, name, val); + return fdt_property_u32(fdt, name, val); } #endif @@ -1504,14 +1504,14 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) * @valp: returns a pointer to where where the value should be placed * * returns: - * 0, on success - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_NOSPACE, standard meanings + * 0, on success + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_NOSPACE, standard meanings */ int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp); #define fdt_property_string(fdt, name, str) \ - fdt_property(fdt, name, str, strlen(str)+1) + fdt_property(fdt, name, str, strlen(str)+1) int fdt_end_node(void *fdt); int fdt_finish(void *fdt); @@ -1536,15 +1536,15 @@ int fdt_pack(void *fdt); * therefore change the indexes of some entries in the table. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new reservation entry - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new reservation entry + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); @@ -1560,15 +1560,15 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); * therefore change the indexes of some entries in the table. * * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there - * are less than n+1 reserve map entries) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there + * are less than n+1 reserve map entries) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_del_mem_rsv(void *fdt, int n); @@ -1588,13 +1588,13 @@ int fdt_del_mem_rsv(void *fdt, int n); * therefore change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob - * to contain the new name - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob + * to contain the new name + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings */ int fdt_set_name(void *fdt, int nodeoffset, const char *name); @@ -1614,20 +1614,20 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name); * therefore change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); + const void *val, int len); /** * fdt_setprop_placeholder - allocate space for a property @@ -1645,20 +1645,20 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, * therefore change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, - int len, void **prop_data); + int len, void **prop_data); /** * fdt_setprop_u32 - set a property to a 32-bit integer @@ -1676,23 +1676,23 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, * therefore change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, - uint32_t val) + uint32_t val) { - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -1711,23 +1711,23 @@ static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, * therefore change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, - uint64_t val) + uint64_t val) { - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -1742,9 +1742,9 @@ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, - uint32_t val) + uint32_t val) { - return fdt_setprop_u32(fdt, nodeoffset, name, val); + return fdt_setprop_u32(fdt, nodeoffset, name, val); } /** @@ -1763,20 +1763,20 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, * therefore change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ #define fdt_setprop_string(fdt, nodeoffset, name, str) \ - fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** @@ -1793,20 +1793,20 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, * therefore change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ #define fdt_setprop_empty(fdt, nodeoffset, name) \ - fdt_setprop((fdt), (nodeoffset), (name), NULL, 0) + fdt_setprop((fdt), (nodeoffset), (name), NULL, 0) /** * fdt_appendprop - append to or create a property @@ -1823,20 +1823,20 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, * change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); + const void *val, int len); /** * fdt_appendprop_u32 - append a 32-bit integer value to a property @@ -1854,23 +1854,23 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, * change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, - const char *name, uint32_t val) + const char *name, uint32_t val) { - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -1889,23 +1889,23 @@ static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, * change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, - const char *name, uint64_t val) + const char *name, uint64_t val) { - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -1920,9 +1920,9 @@ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, - const char *name, uint32_t val) + const char *name, uint32_t val) { - return fdt_appendprop_u32(fdt, nodeoffset, name, val); + return fdt_appendprop_u32(fdt, nodeoffset, name, val); } /** @@ -1940,20 +1940,20 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, * change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings */ #define fdt_appendprop_string(fdt, nodeoffset, name, str) \ - fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** * fdt_appendprop_addrrange - append a address range property @@ -1975,22 +1975,22 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, * change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid - * #address-cells property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain a new property - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #address-cells property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain a new property + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, - const char *name, uint64_t addr, uint64_t size); + const char *name, uint64_t addr, uint64_t size); /** * fdt_delprop - delete a property @@ -2004,15 +2004,15 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, * change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_delprop(void *fdt, int nodeoffset, const char *name); @@ -2029,11 +2029,11 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name); * full path. * * Return: structure block offset of the created subnode (>=0), - * negative libfdt error value otherwise + * negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_add_subnode_namelen(void *fdt, int parentoffset, - const char *name, int namelen); + const char *name, int namelen); #endif /** @@ -2050,22 +2050,22 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * change the offsets of some existing nodes. * * returns: - * structure block offset of the created nodeequested subnode (>=0), on - * success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE - * tag - * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of - * the given name - * -FDT_ERR_NOSPACE, if there is insufficient free space in the - * blob to contain the new node - * -FDT_ERR_NOSPACE - * -FDT_ERR_BADLAYOUT + * structure block offset of the created nodeequested subnode (>=0), on + * success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + * the given name + * -FDT_ERR_NOSPACE, if there is insufficient free space in the + * blob to contain the new node + * -FDT_ERR_NOSPACE + * -FDT_ERR_BADLAYOUT * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); @@ -2081,14 +2081,14 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); * change the offsets of some existing nodes. * * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_del_node(void *fdt, int nodeoffset); @@ -2104,22 +2104,22 @@ int fdt_del_node(void *fdt, int nodeoffset); * returns an error. * * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there's not enough space in the base device tree - * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or - * properties in the base DT - * -FDT_ERR_BADPHANDLE, - * -FDT_ERR_BADOVERLAY, - * -FDT_ERR_NOPHANDLES, - * -FDT_ERR_INTERNAL, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADOFFSET, - * -FDT_ERR_BADPATH, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_TRUNCATED, standard meanings + * 0, on success + * -FDT_ERR_NOSPACE, there's not enough space in the base device tree + * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or + * properties in the base DT + * -FDT_ERR_BADPHANDLE, + * -FDT_ERR_BADOVERLAY, + * -FDT_ERR_NOPHANDLES, + * -FDT_ERR_INTERNAL, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, + * -FDT_ERR_BADPATH, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_overlay_apply(void *fdt, void *fdto); @@ -2139,7 +2139,7 @@ int fdt_overlay_apply(void *fdt, void *fdto); * Negative error code on error */ int fdt_overlay_target_offset(const void *fdt, const void *fdto, - int fragment_offset, char const **pathp); + int fragment_offset, char const **pathp); /**********************************************************************/ /* Debugging / informational functions */ diff --git a/components/drivers/ofw/libfdt/libfdt_env.h b/components/drivers/ofw/libfdt/libfdt_env.h index 07d9b0a97a..25e4746bbc 100644 --- a/components/drivers/ofw/libfdt/libfdt_env.h +++ b/components/drivers/ofw/libfdt/libfdt_env.h @@ -30,40 +30,40 @@ typedef uint16_t FDT_BITWISE fdt16_t; typedef uint32_t FDT_BITWISE fdt32_t; typedef uint64_t FDT_BITWISE fdt64_t; -#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) +#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) #define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) #define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ - (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) + (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) #define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ - (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ - (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ - (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) + (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ + (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ + (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) static inline uint16_t fdt16_to_cpu(fdt16_t x) { - return (FDT_FORCE uint16_t)CPU_TO_FDT16(x); + return (FDT_FORCE uint16_t)CPU_TO_FDT16(x); } static inline fdt16_t cpu_to_fdt16(uint16_t x) { - return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x); + return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x); } static inline uint32_t fdt32_to_cpu(fdt32_t x) { - return (FDT_FORCE uint32_t)CPU_TO_FDT32(x); + return (FDT_FORCE uint32_t)CPU_TO_FDT32(x); } static inline fdt32_t cpu_to_fdt32(uint32_t x) { - return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x); + return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x); } static inline uint64_t fdt64_to_cpu(fdt64_t x) { - return (FDT_FORCE uint64_t)CPU_TO_FDT64(x); + return (FDT_FORCE uint64_t)CPU_TO_FDT64(x); } static inline fdt64_t cpu_to_fdt64(uint64_t x) { - return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x); + return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x); } #undef CPU_TO_FDT64 #undef CPU_TO_FDT32 diff --git a/components/drivers/ofw/libfdt/libfdt_internal.h b/components/drivers/ofw/libfdt/libfdt_internal.h index 16bda1906a..33ae33536c 100644 --- a/components/drivers/ofw/libfdt/libfdt_internal.h +++ b/components/drivers/ofw/libfdt/libfdt_internal.h @@ -7,16 +7,16 @@ */ #include -#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) +#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) int32_t fdt_ro_probe_(const void *fdt); -#define FDT_RO_PROBE(fdt) \ - { \ - int32_t totalsize_; \ - if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \ - return totalsize_; \ - } +#define FDT_RO_PROBE(fdt) \ + { \ + int32_t totalsize_; \ + if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \ + return totalsize_; \ + } int fdt_check_node_offset_(const void *fdt, int offset); int fdt_check_prop_offset_(const void *fdt, int offset); @@ -25,25 +25,25 @@ int fdt_node_end_offset_(void *fdt, int nodeoffset); static inline const void *fdt_offset_ptr_(const void *fdt, int offset) { - return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; + return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; } static inline void *fdt_offset_ptr_w_(void *fdt, int offset) { - return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset); + return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset); } static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n) { - const struct fdt_reserve_entry *rsv_table = - (const struct fdt_reserve_entry *) - ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); + const struct fdt_reserve_entry *rsv_table = + (const struct fdt_reserve_entry *) + ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); - return rsv_table + n; + return rsv_table + n; } static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) { - return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n); + return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n); } /* @@ -57,15 +57,15 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) */ static inline uint32_t fdt32_ld_(const fdt32_t *p) { - return fdt32_to_cpu(*p); + return fdt32_to_cpu(*p); } static inline uint64_t fdt64_ld_(const fdt64_t *p) { - return fdt64_to_cpu(*p); + return fdt64_to_cpu(*p); } -#define FDT_SW_MAGIC (~FDT_MAGIC) +#define FDT_SW_MAGIC (~FDT_MAGIC) /**********************************************************************/ /* Checking controls */ @@ -87,92 +87,92 @@ static inline uint64_t fdt64_ld_(const fdt64_t *p) * ASSUME_SANE. */ enum { - /* - * This does essentially no checks. Only the latest device-tree - * version is correctly handled. Inconsistencies or errors in the device - * tree may cause undefined behaviour or crashes. Invalid parameters - * passed to libfdt may do the same. - * - * If an error occurs when modifying the tree it may leave the tree in - * an intermediate (but valid) state. As an example, adding a property - * where there is insufficient space may result in the property name - * being added to the string table even though the property itself is - * not added to the struct section. - * - * Only use this if you have a fully validated device tree with - * the latest supported version and wish to minimise code size. - */ - ASSUME_PERFECT = 0xff, - - /* - * This assumes that the device tree is sane. i.e. header metadata - * and basic hierarchy are correct. - * - * With this assumption enabled, normal device trees produced by libfdt - * and the compiler should be handled safely. Malicious device trees and - * complete garbage may cause libfdt to behave badly or crash. Truncated - * device trees (e.g. those only partially loaded) can also cause - * problems. - * - * Note: Only checks that relate exclusively to the device tree itself - * (not the parameters passed to libfdt) are disabled by this - * assumption. This includes checking headers, tags and the like. - */ - ASSUME_VALID_DTB = 1 << 0, - - /* - * This builds on ASSUME_VALID_DTB and further assumes that libfdt - * functions are called with valid parameters, i.e. not trigger - * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any - * extensive checking of parameters and the device tree, making various - * assumptions about correctness. - * - * It doesn't make sense to enable this assumption unless - * ASSUME_VALID_DTB is also enabled. - */ - ASSUME_VALID_INPUT = 1 << 1, - - /* - * This disables checks for device-tree version and removes all code - * which handles older versions. - * - * Only enable this if you know you have a device tree with the latest - * version. - */ - ASSUME_LATEST = 1 << 2, - - /* - * This assumes that it is OK for a failed addition to the device tree, - * due to lack of space or some other problem, to skip any rollback - * steps (such as dropping the property name from the string table). - * This is safe to enable in most circumstances, even though it may - * leave the tree in a sub-optimal state. - */ - ASSUME_NO_ROLLBACK = 1 << 3, - - /* - * This assumes that the device tree components appear in a 'convenient' - * order, i.e. the memory reservation block first, then the structure - * block and finally the string block. - * - * This order is not specified by the device-tree specification, - * but is expected by libfdt. The device-tree compiler always created - * device trees with this order. - * - * This assumption disables a check in fdt_open_into() and removes the - * ability to fix the problem there. This is safe if you know that the - * device tree is correctly ordered. See fdt_blocks_misordered_(). - */ - ASSUME_LIBFDT_ORDER = 1 << 4, - - /* - * This assumes that libfdt itself does not have any internal bugs. It - * drops certain checks that should never be needed unless libfdt has an - * undiscovered bug. - * - * This can generally be considered safe to enable. - */ - ASSUME_LIBFDT_FLAWLESS = 1 << 5, + /* + * This does essentially no checks. Only the latest device-tree + * version is correctly handled. Inconsistencies or errors in the device + * tree may cause undefined behaviour or crashes. Invalid parameters + * passed to libfdt may do the same. + * + * If an error occurs when modifying the tree it may leave the tree in + * an intermediate (but valid) state. As an example, adding a property + * where there is insufficient space may result in the property name + * being added to the string table even though the property itself is + * not added to the struct section. + * + * Only use this if you have a fully validated device tree with + * the latest supported version and wish to minimise code size. + */ + ASSUME_PERFECT = 0xff, + + /* + * This assumes that the device tree is sane. i.e. header metadata + * and basic hierarchy are correct. + * + * With this assumption enabled, normal device trees produced by libfdt + * and the compiler should be handled safely. Malicious device trees and + * complete garbage may cause libfdt to behave badly or crash. Truncated + * device trees (e.g. those only partially loaded) can also cause + * problems. + * + * Note: Only checks that relate exclusively to the device tree itself + * (not the parameters passed to libfdt) are disabled by this + * assumption. This includes checking headers, tags and the like. + */ + ASSUME_VALID_DTB = 1 << 0, + + /* + * This builds on ASSUME_VALID_DTB and further assumes that libfdt + * functions are called with valid parameters, i.e. not trigger + * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any + * extensive checking of parameters and the device tree, making various + * assumptions about correctness. + * + * It doesn't make sense to enable this assumption unless + * ASSUME_VALID_DTB is also enabled. + */ + ASSUME_VALID_INPUT = 1 << 1, + + /* + * This disables checks for device-tree version and removes all code + * which handles older versions. + * + * Only enable this if you know you have a device tree with the latest + * version. + */ + ASSUME_LATEST = 1 << 2, + + /* + * This assumes that it is OK for a failed addition to the device tree, + * due to lack of space or some other problem, to skip any rollback + * steps (such as dropping the property name from the string table). + * This is safe to enable in most circumstances, even though it may + * leave the tree in a sub-optimal state. + */ + ASSUME_NO_ROLLBACK = 1 << 3, + + /* + * This assumes that the device tree components appear in a 'convenient' + * order, i.e. the memory reservation block first, then the structure + * block and finally the string block. + * + * This order is not specified by the device-tree specification, + * but is expected by libfdt. The device-tree compiler always created + * device trees with this order. + * + * This assumption disables a check in fdt_open_into() and removes the + * ability to fix the problem there. This is safe if you know that the + * device tree is correctly ordered. See fdt_blocks_misordered_(). + */ + ASSUME_LIBFDT_ORDER = 1 << 4, + + /* + * This assumes that libfdt itself does not have any internal bugs. It + * drops certain checks that should never be needed unless libfdt has an + * undiscovered bug. + * + * This can generally be considered safe to enable. + */ + ASSUME_LIBFDT_FLAWLESS = 1 << 5, }; /** @@ -183,10 +183,10 @@ enum { */ static inline bool can_assume_(int mask) { - return FDT_ASSUME_MASK & mask; + return FDT_ASSUME_MASK & mask; } /** helper macros for checking assumptions */ -#define can_assume(_assume) can_assume_(ASSUME_ ## _assume) +#define can_assume(_assume) can_assume_(ASSUME_ ## _assume) #endif /* LIBFDT_INTERNAL_H */ -- cgit v1.3.1 From fa10a99c3ccecd6113d30842a05e1b853cf7d1cb Mon Sep 17 00:00:00 2001 From: erikchan <1043490933@qq.com> Date: Thu, 6 Jul 2023 11:24:19 +0800 Subject: 【ofw】 format encoding of irq.c to utf-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/drivers/ofw/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/drivers/ofw/irq.c b/components/drivers/ofw/irq.c index f5457453b4..69ac3b3d5e 100755 --- a/components/drivers/ofw/irq.c +++ b/components/drivers/ofw/irq.c @@ -67,7 +67,7 @@ static rt_err_t ofw_parse_irq_map(struct rt_ofw_node *np, struct rt_ofw_cell_arg * child interrupt specifier * The interrupt specifier of the child node being mapped. The number * of 32-bit cells required to specify this component is described by - * the #interrupt-cells property of this node—the nexus node containing + * the #interrupt-cells property of this node-the nexus node containing * the interrupt-map property. * * interrupt-parent -- cgit v1.3.1