From 968164b6863e3a75fb0f5842f4f1cab9ac7c8c36 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:17 +0200 Subject: [PATCH 01/11] vsprintf: add %pOF This prints a full ofnode path. Signed-off-by: Casey Connolly --- lib/vsprintf.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index c7340a047b2..49dc9c38c65 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -26,6 +26,11 @@ #include #include +/* For %pOF */ +#if CONFIG_IS_ENABLED(OF_CONTROL) +#include +#endif + /* we use this so that we can do without the ctype library */ #define is_digit(c) ((c) >= '0' && (c) <= '9') @@ -438,6 +443,30 @@ static char *uuid_string(char *buf, char *end, u8 *addr, int field_width, } #endif +#if CONFIG_IS_ENABLED(OF_CONTROL) && !defined(API_BUILD) +static char *ofnode_string(char *buf, char *end, ofnode *dp, int field_width, + int precision, int flags) +{ +#define NP_PATH_MAX 64 + char str[NP_PATH_MAX] = { 0 }; + const char *err = "..."; + + /* If dp == NULL output the string '' */ + if (!dp || !ofnode_valid(*dp)) + return string(buf, end, NULL, field_width, precision, flags); + + /* Get the path and indicate if it got cut off */ + if (ofnode_get_path(*dp, str, NP_PATH_MAX)) { + str[NP_PATH_MAX - 1] = '\0'; + char *p = str + min((NP_PATH_MAX - 2) - strlen(err), strlen(str)); + memcpy(p, err, strlen(err) + 1); + } + + return string(buf, end, str, field_width, precision, flags); +#undef NP_PATH_MAX +} +#endif + /* * Show a '%p' thing. A kernel extension is that the '%p' is followed * by an extra set of alphanumeric characters that are extended format @@ -473,6 +502,14 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, case 'D': return device_path_string(buf, end, ptr, field_width, precision, flags); +#endif +/* Device paths only exist in the EFI context. */ +#if CONFIG_IS_ENABLED(OF_CONTROL) && !defined(API_BUILD) + case 'O': + if (fmt[1] == 'F') + return ofnode_string(buf, end, ptr, field_width, + precision, flags); + break; #endif case 'a': flags |= SPECIAL | ZEROPAD; From f5e96fdffc024552944776848bd5570e1b2caa9b Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:18 +0200 Subject: [PATCH 02/11] common: add an option to skip DM pre-relocation For some platforms like Qualcomm, it isn't necessary to perform a full DM init and scan prior to relocation, it's also particularly slow since it runs with dcache disabled and prior to building the livetree. The only device which needs to be probed pre-reloc is the serial port (otherwise U-Boot will panic), however this can be found through /chosen/stdout-path. Therefore we can avoid scanning the entire FDT and binding devices, instead just binding the serial port and clock driver on-demand. This decreases the total time from power on to reaching the interactive U-Boot shell be about 50% (from ~2.8s to 1.8s). Signed-off-by: Casey Connolly --- Kconfig | 12 ++++++++++++ common/board_f.c | 11 ++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Kconfig b/Kconfig index ce25ea24a60..2f7677f47f1 100644 --- a/Kconfig +++ b/Kconfig @@ -474,6 +474,18 @@ config SKIP_RELOCATE Skips relocation of U-Boot allowing for systems that have extremely limited RAM to run U-Boot. +config SKIP_EARLY_DM + bool "Skips initialising device model pre-relocation" + help + Enable this option to skip scanning and probing devices prior to + U-Boot relocation (during board_f). Unless console support is disabled + a serial port is still required, however this can be found through + /chosen/stdout-path in FDT. If the serial port relies on other devices + like clocks these will also be bound and probed on demand. + + This can speed up time to interactive console by about 50%, particularly + when combined with OF_LIVE. + endif # EXPERT config PHYS_64BIT diff --git a/common/board_f.c b/common/board_f.c index df2b0dc899b..2713438cc18 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -814,7 +814,16 @@ static int initf_dm(void) return 0; bootstage_start(BOOTSTAGE_ID_ACCUM_DM_F, "dm_f"); - ret = dm_init_and_scan(true); + + /* + * If SKIP_EARLY_DM is set then we just create an empty device + * model, the serial port will still be bound later through + * serial_find_console_or_panic() via /chosen/stdout-path + */ + if (!CONFIG_IS_ENABLED(SKIP_EARLY_DM)) + ret = dm_init_and_scan(true); + else + ret = dm_init(false); if (ret) return ret; From 139f5292e7985d0326a1d18eee88720255e423dc Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:19 +0200 Subject: [PATCH 03/11] string: add strdup_const and kstrdup_const Extend Linux compat by adding kstrdup_const(), backed by lib/string.c. This leverages U-Boots .rodata section on ARM64 to avoid pointlessly duplicating const strings. This is used by the Linux CCF_FULL port and may be useful elsewhere in U-Boot. Signed-off-by: Casey Connolly --- include/asm-generic/sections.h | 19 +++++++++++++++++++ include/linux/compat.h | 13 +++++++++++++ include/linux/string.h | 2 ++ lib/string.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index d59787948fd..48bd4fa8604 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -9,6 +9,7 @@ #define _ASM_GENERIC_SECTIONS_H_ #include +#include /* References to section boundaries */ @@ -62,6 +63,24 @@ static inline int arch_is_kernel_data(unsigned long addr) } #endif +/** + * is_kernel_rodata - checks if the pointer address is located in the + * .rodata section + * + * @addr: address to check + * + * Returns: true if the address is located in .rodata, false otherwise. + */ +static inline bool is_kernel_rodata(unsigned long addr) +{ +#ifdef CONFIG_ARM64 + return addr >= (unsigned long)__start_rodata && + addr < (unsigned long)__end_rodata; +#else + return false; +#endif +} + /* U-Boot-specific things begin here */ /* Start of U-Boot text region */ diff --git a/include/linux/compat.h b/include/linux/compat.h index 62381451617..d4ba4d0088a 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -67,6 +67,19 @@ static inline void vfree(const void *addr) free((void *)addr); } +/** + * kstrdup_const - conditionally duplicate an existing const string + * @s: the string to duplicate + * @gfp: the GFP mask used in the kmalloc() call when allocating memory + * + * Note: Strings allocated by kstrdup_const should be freed by kfree_const and + * must not be passed to krealloc(). + * + * Return: source string if it is in .rodata section otherwise + * fallback to kstrdup. + */ +#define kstrdup_const(s, gfp) strdup_const(s) + struct kmem_cache { int sz; }; struct kmem_cache *get_mem(int element_sz); diff --git a/include/linux/string.h b/include/linux/string.h index d943fcce690..a8a6cf4af50 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -104,6 +104,8 @@ size_t strcspn(const char *s, const char *reject); #ifndef __HAVE_ARCH_STRDUP extern char * strdup(const char *); extern char * strndup(const char *, size_t); +extern const char *strdup_const(const char *s); +extern void kfree_const(const void *x); #endif #ifndef __HAVE_ARCH_STRSWAB extern char * strswab(const char *); diff --git a/lib/string.c b/lib/string.c index d56f88d4a84..302efe048b0 100644 --- a/lib/string.c +++ b/lib/string.c @@ -379,6 +379,37 @@ char * strndup(const char *s, size_t n) return new; } + +/** + * strdup_const - conditionally duplicate an existing const string + * @s: the string to duplicate + * + * Note: Strings allocated by kstrdup_const should be freed by kfree_const and + * must not be passed to krealloc(). + * + * Return: source string if it is in .rodata section otherwise + * fallback to kstrdup. + */ +const char *strdup_const(const char *s) +{ + if (is_kernel_rodata((unsigned long)s)) + return s; + + return strdup(s); +} + +/** + * kfree_const - conditionally free memory + * @x: pointer to the memory + * + * Function calls kfree only if @x is not in .rodata section. + */ +void kfree_const(const void *x) +{ + if (!is_kernel_rodata((unsigned long)x)) + free((void *)x); +} + #endif #ifndef __HAVE_ARCH_STRSPN From 45c610d718bd605a1b3bdf99ec0386620b54b559 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:20 +0200 Subject: [PATCH 04/11] ofnode: add read_u64_array and count_elems_of_size These are similar to their Linux counterparts, adding helpers for reading arrays of 64-bit values with of_access and fdtdec implementations. Signed-off-by: Casey Connolly --- drivers/core/of_access.c | 52 ++++++++++++++++++++++++++++++++++++++++ drivers/core/ofnode.c | 48 +++++++++++++++++++++++++++++++++++++ include/dm/of_access.h | 20 ++++++++++++++++ include/dm/ofnode.h | 50 ++++++++++++++++++++++++++++++++++++++ include/fdtdec.h | 16 +++++++++++++ lib/fdtdec.c | 18 ++++++++++++++ 6 files changed, 204 insertions(+) diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index b11e36202c1..969492aae37 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -598,6 +598,25 @@ int of_read_u64(const struct device_node *np, const char *propname, u64 *outp) return of_read_u64_index(np, propname, 0, outp); } +int of_read_u64_array(const struct device_node *np, const char *propname, + u64 *out_values, size_t sz) +{ + const __be64 *val; + + log_debug("%s: %s: ", __func__, propname); + val = of_find_property_value_of_size(np, propname, + sz * sizeof(*out_values)); + + if (IS_ERR(val)) + return PTR_ERR(val); + + log_debug("size %zd\n", sz); + while (sz--) + *out_values++ = be64_to_cpup(val++); + + return 0; +} + int of_property_match_string(const struct device_node *np, const char *propname, const char *string) { @@ -845,6 +864,39 @@ int of_count_phandle_with_args(const struct device_node *np, cell_count); } +/** + * of_property_count_elems_of_size - Count the number of elements in a property + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @elem_size: size of the individual element + * + * Search for a property in a device node and count the number of elements of + * size elem_size in it. + * + * Return: The number of elements on sucess, -EINVAL if the property does not + * exist or its length does not match a multiple of elem_size and -ENODATA if + * the property does not have a value. + */ +int of_property_count_elems_of_size(const struct device_node *np, + const char *propname, int elem_size) +{ + const struct property *prop = of_find_property(np, propname, NULL); + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + if (prop->length % elem_size != 0) { + pr_err("size of %s in node %pOF is not a multiple of %d\n", + propname, np, elem_size); + return -EINVAL; + } + + return prop->length / elem_size; +} + static void of_alias_add(struct alias_prop *ap, struct device_node *np, int id, const char *stem, int stem_len) { diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 3a36b6fdd03..d605c0f7b7c 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -664,6 +664,54 @@ int ofnode_read_u32_array(ofnode node, const char *propname, } } +int ofnode_read_u64_array(ofnode node, const char *propname, + u64 *out_values, size_t sz) +{ + assert(ofnode_valid(node)); + log_debug("%s: %s: ", __func__, propname); + + if (ofnode_is_np(node)) { + return of_read_u64_array(ofnode_to_np(node), propname, + out_values, sz); + } else { + int ret; + + ret = fdtdec_get_long_array(ofnode_to_fdt(node), + ofnode_to_offset(node), propname, + out_values, sz); + + /* get the error right, but space is more important in SPL */ + if (!IS_ENABLED(CONFIG_XPL_BUILD)) { + if (ret == -FDT_ERR_NOTFOUND) + return -EINVAL; + else if (ret == -FDT_ERR_BADLAYOUT) + return -EOVERFLOW; + } + return ret; + } +} + +int ofnode_count_elems_of_size(ofnode node, const char *propname, int elem_size) +{ + const char *prop; + int len; + assert(ofnode_valid(node)); + + if (ofnode_is_np(node)) { + return of_property_count_elems_of_size(node.np, propname, elem_size); + } else { + prop = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node), propname, &len); + if (!prop) + return -ENOENT; + if (len % elem_size != 0) { + log_debug("size of %s in node %pOF is not a multiple of %d\n", + propname, &node, elem_size); + return -EINVAL; + } + return len / elem_size; + } +} + #if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE) bool ofnode_is_enabled(ofnode node) { diff --git a/include/dm/of_access.h b/include/dm/of_access.h index 44143a5a391..fe0de73d7e2 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -385,6 +385,23 @@ int of_read_u64(const struct device_node *np, const char *propname, u64 *outp); int of_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz); +/** + * of_read_u64_array() - Find and read an array of 64 bit integers + * + * Search for a property in a device node and read 64-bit value(s) from + * it. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_values: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * Return: + * 0 on success, -EINVAL if the property does not exist, or -EOVERFLOW if + * longer than sz. + */ +int of_read_u64_array(const struct device_node *np, const char *propname, + u64 *out_values, size_t sz); + /** * of_property_match_string() - Find string in a list and return index * @@ -616,6 +633,9 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name, int cells_count); +int of_property_count_elems_of_size(const struct device_node *np, + const char *propname, int elem_size); + /** * of_alias_scan() - Scan all properties of the 'aliases' node * diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 120393426db..c905e86b283 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -375,6 +375,13 @@ static inline oftree oftree_from_np(struct device_node *root) return tree; } +/* Dummy put for Linux compat */ +static inline void ofnode_put(ofnode node) +{ + if (ofnode_is_np(node)) + of_node_put(node.np); +} + /** * oftree_dispose() - Dispose of an oftree * @@ -588,6 +595,25 @@ const char *ofnode_read_string(ofnode node, const char *propname); int ofnode_read_u32_array(ofnode node, const char *propname, u32 *out_values, size_t sz); +/** + * ofnode_read_u64_array() - Find and read an array of 64 bit integers + * + * @node: valid node reference to read property from + * @propname: name of the property to read + * @out_values: pointer to return value, modified only if return value is 0 + * @sz: number of array elements to read + * Return: 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough + * + * Search for a property in a device node and read 64-bit value(s) from + * it. + * + * The out_values is modified only if a valid u64 value can be decoded. + */ +int ofnode_read_u64_array(ofnode node, const char *propname, + u64 *out_values, size_t sz); + /** * ofnode_read_bool() - read a boolean value from a property * @@ -652,6 +678,30 @@ static inline ofnode ofnode_next_subnode(ofnode node) fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node))); } #else + +/** + * ofnode_count_elems_of_size() - count the number of elements of size @elem_size + * in the property @propname. + * + * @node: ofnode to check + * @propname: the name of the property to count + * @elem_size: the size of each element + * + * Returns: the number of elements or -EINVAL if the property size is not a + * multiple of elem_size. + */ +int ofnode_count_elems_of_size(ofnode node, const char *propname, int elem_size); + +static inline int ofnode_count_u32_elems(ofnode node, const char *propname) +{ + return ofnode_count_elems_of_size(node, propname, 4); +} + +static inline int ofnode_count_u64_elems(ofnode node, const char *propname) +{ + return ofnode_count_elems_of_size(node, propname, 8); +} + /** * ofnode_is_enabled() - Checks whether a node is enabled. * This looks for a 'status' property. If this exists, then returns true if diff --git a/include/fdtdec.h b/include/fdtdec.h index d9fcd037ed2..3d199e56b03 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -700,6 +700,22 @@ int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name); int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, u32 *array, int count); +/** + * Look up a property in a node and return its contents in a u64 + * array of given length. The property must have at least enough data for + * the array (8*count bytes). It may have more, but this will be ignored. + * + * @param blob FDT blob + * @param node node to examine + * @param prop_name name of property to find + * @param array array to fill with data + * @param count number of array elements + * Return: 0 if ok, or -FDT_ERR_NOTFOUND if the property is not found, + * or -FDT_ERR_BADLAYOUT if not enough data + */ +int fdtdec_get_long_array(const void *blob, int node, const char *prop_name, + u64 *array, int count); + /** * Look up a property in a node and return its contents in an integer * array of given length. The property must exist but may have less data that diff --git a/lib/fdtdec.c b/lib/fdtdec.c index c38738b48c7..e23e53f58f2 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -714,6 +714,24 @@ int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, return err; } +int fdtdec_get_long_array(const void *blob, int node, const char *prop_name, + u64 *array, int count) +{ + const u64 *cell; + int err = 0; + + debug("%s: %s\n", __func__, prop_name); + cell = get_prop_check_min_len(blob, node, prop_name, + sizeof(u64) * count, &err); + if (!err) { + int i; + + for (i = 0; i < count; i++) + array[i] = fdt64_to_cpu(cell[i]); + } + return err; +} + int fdtdec_get_int_array_count(const void *blob, int node, const char *prop_name, u32 *array, int count) { From 3f6f674b4a5653eb7223645be00ddb82368ddb33 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:21 +0200 Subject: [PATCH 05/11] compat: add PTR_ERR_OR_ZERO Imported from Linux, this is nice to have along with the other ERR_PTR helper macros. Signed-off-by: Casey Connolly --- include/linux/err.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/linux/err.h b/include/linux/err.h index 7a0b212c813..2463c4611b2 100644 --- a/include/linux/err.h +++ b/include/linux/err.h @@ -53,6 +53,31 @@ static inline void * __must_check ERR_CAST(__force const void *ptr) return (void *) ptr; } +/** + * PTR_ERR_OR_ZERO - Extract the error code from a pointer if it has one. + * @ptr: A potential error pointer. + * + * Convenience function that can be used inside a function that returns + * an error code to propagate errors received as error pointers. + * For example, ``return PTR_ERR_OR_ZERO(ptr);`` replaces: + * + * .. code-block:: c + * + * if (IS_ERR(ptr)) + * return PTR_ERR(ptr); + * else + * return 0; + * + * Return: The error code within @ptr if it is an error pointer; 0 otherwise. + */ +static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr) +{ + if (IS_ERR(ptr)) + return PTR_ERR(ptr); + else + return 0; +} + #endif #endif /* _LINUX_ERR_H */ From 70b55377553403932cb37cc530433aaee6ee41e0 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:22 +0200 Subject: [PATCH 06/11] compat: add kref implementation This is a very basic port of Linux' kref, we don't actually need atomics so we just use a simple counter. This is used by CCF to free unused clocks. Signed-off-by: Casey Connolly --- include/linux/kref.h | 124 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 include/linux/kref.h diff --git a/include/linux/kref.h b/include/linux/kref.h new file mode 100644 index 00000000000..30927047d54 --- /dev/null +++ b/include/linux/kref.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * kref.h - library routines for handling generic reference counted objects + * + * Copyright (C) 2004 Greg Kroah-Hartman + * Copyright (C) 2004 IBM Corp. + * + * based on kobject.h which was: + * Copyright (C) 2002-2003 Patrick Mochel + * Copyright (C) 2002-2003 Open Source Development Labs + */ + +#ifndef _KREF_H_ +#define _KREF_H_ + +#include + +struct kref { + long refcount; +}; + +#define KREF_INIT(n) { .refcount = REFCOUNT_INIT(n), } + +/** + * kref_init - initialize object. + * @kref: object in question. + */ +static inline void kref_init(struct kref *kref) +{ + kref->refcount = 1; +} + +static inline unsigned int kref_read(const struct kref *kref) +{ + return kref->refcount; +} + +/** + * kref_get - increment refcount for object. + * @kref: object. + */ +static inline void kref_get(struct kref *kref) +{ + kref->refcount++; +} + +/** + * kref_put - Decrement refcount for object + * @kref: Object + * @release: Pointer to the function that will clean up the object when the + * last reference to the object is released. + * + * Decrement the refcount, and if 0, call @release. The caller may not + * pass NULL or kfree() as the release function. + * + * Return: 1 if this call removed the object, otherwise return 0. Beware, + * if this function returns 0, another caller may have removed the object + * by the time this function returns. The return value is only certain + * if you want to see if the object is definitely released. + */ +static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref)) +{ + if (--kref->refcount == 0) { + release(kref); + return 1; + } + return 0; +} + +/** + * kref_put_mutex - Decrement refcount for object + * @kref: Object + * @release: Pointer to the function that will clean up the object when the + * last reference to the object is released. + * @mutex: Mutex which protects the release function. + * + * This variant of kref_lock() calls the @release function with the @mutex + * held. The @release function will release the mutex. + */ +static inline int kref_put_mutex(struct kref *kref, + void (*release)(struct kref *kref), + struct mutex *mutex) +{ + return kref_put(kref, release); +} + +/** + * kref_put_lock - Decrement refcount for object + * @kref: Object + * @release: Pointer to the function that will clean up the object when the + * last reference to the object is released. + * @lock: Spinlock which protects the release function. + * + * This variant of kref_lock() calls the @release function with the @lock + * held. The @release function will release the lock. + */ +static inline int kref_put_lock(struct kref *kref, + void (*release)(struct kref *kref), + spinlock_t *lock) +{ + return kref_put(kref, release); +} + +/** + * kref_get_unless_zero - Increment refcount for object unless it is zero. + * @kref: object. + * + * This function is intended to simplify locking around refcounting for + * objects that can be looked up from a lookup structure, and which are + * removed from that lookup structure in the object destructor. + * Operations on such objects require at least a read lock around + * lookup + kref_get, and a write lock around kref_put + remove from lookup + * structure. Furthermore, RCU implementations become extremely tricky. + * With a lookup followed by a kref_get_unless_zero *with return value check* + * locking in the kref_put path can be deferred to the actual removal from + * the lookup structure and RCU lookups become trivial. + * + * Return: non-zero if the increment succeeded. Otherwise return 0. + */ +static inline int kref_get_unless_zero(struct kref *kref) +{ + return kref->refcount ? kref->refcount++ : 0; +} +#endif /* _KREF_H_ */ From 8e0ed228d8b062690365e439fbd40f1edd34780a Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:23 +0200 Subject: [PATCH 07/11] compat: add dev_name() This function just wraps udevice->name. Signed-off-by: Casey Connolly --- include/linux/device.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 include/linux/device.h diff --git a/include/linux/device.h b/include/linux/device.h new file mode 100644 index 00000000000..e76635cfde9 --- /dev/null +++ b/include/linux/device.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * device.h - generic, centralized driver model + * + * U-Boot: compat header derived from Linux + * + * Copyright (c) 2001-2003 Patrick Mochel + * Copyright (c) 2004-2009 Greg Kroah-Hartman + * Copyright (c) 2008-2009 Novell Inc. + * + * See Documentation/driver-api/driver-model/ for more information. + */ + +#ifndef _DEVICE_H_ +#define _DEVICE_H_ + +#include + +/** + * dev_name - Return a device's name. + * @dev: Device with name to get. + * Return: The kobject name of the device, or its initial name if unavailable. + */ +static inline const char *dev_name(const struct udevice *dev) +{ + return dev->name; +} + +#endif /* _DEVICE_H_ */ From fae701400dd040165d713993b06239f3b4dcd9b9 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:24 +0200 Subject: [PATCH 08/11] compat: add linux/regmap.h symlink Add a symlink to the Linux regmap.h path so that drivers ported from Linux don't all need additional changes to include the U-Boot specific path. Signed-off-by: Casey Connolly --- include/linux/regmap.h | 1 + 1 file changed, 1 insertion(+) create mode 120000 include/linux/regmap.h diff --git a/include/linux/regmap.h b/include/linux/regmap.h new file mode 120000 index 00000000000..8a3780b5ceb --- /dev/null +++ b/include/linux/regmap.h @@ -0,0 +1 @@ +../regmap.h \ No newline at end of file From 6c11994b7e7b324ea41e6d62e9a73dc430ea0df8 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:25 +0200 Subject: [PATCH 09/11] regmap: add regmap_assign_bits This is a simple wrapper around set/clear bits used by drivers in Linux. Add it here so it can be used by Qualcomm CCF clk drivers. Signed-off-by: Casey Connolly --- include/regmap.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/regmap.h b/include/regmap.h index 8c6f7c1c9b1..eeae843bfb7 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -389,6 +389,15 @@ static inline int regmap_clear_bits(struct regmap *map, uint offset, uint bits) return regmap_update_bits(map, offset, bits, 0); } +static inline int regmap_assign_bits(struct regmap *map, unsigned int reg, + unsigned int bits, bool value) +{ + if (value) + return regmap_set_bits(map, reg, bits); + else + return regmap_clear_bits(map, reg, bits); +} + /** * regmap_init_mem() - Set up a new register map that uses memory access * From 076265b75e61f56490003639b3d0a6483a9f507f Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:26 +0200 Subject: [PATCH 10/11] compat: regulator: add enable/disable macros These just wrap regulator_set_enable() and provide a closer analogue to the Linux API. Signed-off-by: Casey Connolly --- include/power/regulator.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/power/regulator.h b/include/power/regulator.h index 8a914dfc74f..4011fb1d254 100644 --- a/include/power/regulator.h +++ b/include/power/regulator.h @@ -359,6 +359,9 @@ int regulator_get_enable(struct udevice *dev); */ int regulator_set_enable(struct udevice *dev, bool enable); +#define regulator_enable(dev) regulator_set_enable(dev, true) +#define regulator_disable(dev) regulator_set_enable(dev, false) + /** * regulator_set_enable_if_allowed: set regulator enable state if allowed by * regulator From f1f4a1d1d8355b0fc6bfc82d9ca6741a8e92623b Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Wed, 1 Apr 2026 16:15:27 +0200 Subject: [PATCH 11/11] compat: math64: add abs_diff() Add the abs_diff() macro, copied directly from Linux 6.18. Signed-off-by: Casey Connolly --- include/linux/math64.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/linux/math64.h b/include/linux/math64.h index eaa9fd5b968..70a7ee3ff1d 100644 --- a/include/linux/math64.h +++ b/include/linux/math64.h @@ -257,4 +257,23 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor) } #endif /* mul_u64_u32_div */ +/** + * abs_diff - return absolute value of the difference between the arguments + * @a: the first argument + * @b: the second argument + * + * @a and @b have to be of the same type. With this restriction we compare + * signed to signed and unsigned to unsigned. The result is the subtraction + * the smaller of the two from the bigger, hence result is always a positive + * value. + * + * Return: an absolute value of the difference between the @a and @b. + */ +#define abs_diff(a, b) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + (void)(&__a == &__b); \ + __a > __b ? (__a - __b) : (__b - __a); \ +}) + #endif /* _LINUX_MATH64_H */