aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/core
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/core')
-rw-r--r--roms/u-boot/drivers/core/Kconfig345
-rw-r--r--roms/u-boot/drivers/core/Makefile20
-rw-r--r--roms/u-boot/drivers/core/acpi.c353
-rw-r--r--roms/u-boot/drivers/core/device-remove.c266
-rw-r--r--roms/u-boot/drivers/core/device.c1171
-rw-r--r--roms/u-boot/drivers/core/devres.c294
-rw-r--r--roms/u-boot/drivers/core/dump.c177
-rw-r--r--roms/u-boot/drivers/core/fdtaddr.c226
-rw-r--r--roms/u-boot/drivers/core/lists.c268
-rw-r--r--roms/u-boot/drivers/core/of_access.c882
-rw-r--r--roms/u-boot/drivers/core/of_addr.c440
-rw-r--r--roms/u-boot/drivers/core/of_extra.c155
-rw-r--r--roms/u-boot/drivers/core/ofnode.c1054
-rw-r--r--roms/u-boot/drivers/core/read.c394
-rw-r--r--roms/u-boot/drivers/core/read_extra.c13
-rw-r--r--roms/u-boot/drivers/core/regmap.c688
-rw-r--r--roms/u-boot/drivers/core/root.c433
-rw-r--r--roms/u-boot/drivers/core/simple-bus.c79
-rw-r--r--roms/u-boot/drivers/core/simple-pm-bus.c56
-rw-r--r--roms/u-boot/drivers/core/syscon-uclass.c216
-rw-r--r--roms/u-boot/drivers/core/uclass.c786
-rw-r--r--roms/u-boot/drivers/core/util.c52
22 files changed, 8368 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/core/Kconfig b/roms/u-boot/drivers/core/Kconfig
new file mode 100644
index 000000000..d618e1637
--- /dev/null
+++ b/roms/u-boot/drivers/core/Kconfig
@@ -0,0 +1,345 @@
+menu "Generic Driver Options"
+
+config DM
+ bool "Enable Driver Model"
+ help
+ This config option enables Driver Model. This brings in the core
+ support, including scanning of platform data on start-up. If
+ CONFIG_OF_CONTROL is enabled, the device tree will be scanned also
+ when available.
+
+config SPL_DM
+ bool "Enable Driver Model for SPL"
+ depends on DM && SPL
+ help
+ Enable driver model in SPL. You will need to provide a
+ suitable malloc() implementation. If you are not using the
+ full malloc() enabled by CONFIG_SYS_SPL_MALLOC_START,
+ consider using CONFIG_SYS_MALLOC_SIMPLE. In that case you
+ must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size.
+ In most cases driver model will only allocate a few uclasses
+ and devices in SPL, so 1KB should be enable. See
+ CONFIG_SPL_SYS_MALLOC_F_LEN for more details on how to enable it.
+
+config TPL_DM
+ bool "Enable Driver Model for TPL"
+ depends on DM && TPL
+ help
+ Enable driver model in TPL. You will need to provide a
+ suitable malloc() implementation. If you are not using the
+ full malloc() enabled by CONFIG_SYS_SPL_MALLOC_START,
+ consider using CONFIG_SYS_MALLOC_SIMPLE. In that case you
+ must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size.
+ In most cases driver model will only allocate a few uclasses
+ and devices in SPL, so 1KB should be enough. See
+ CONFIG_SPL_SYS_MALLOC_F_LEN for more details on how to enable it.
+ Disable this for very small implementations.
+
+config DM_WARN
+ bool "Enable warnings in driver model"
+ depends on DM
+ default y
+ help
+ Enable this to see warnings related to driver model.
+
+ Warnings may help with debugging, such as when expected devices do
+ not bind correctly. If the option is disabled, dm_warn() is compiled
+ out - it will do nothing when called.
+
+config SPL_DM_WARN
+ bool "Enable warnings in driver model wuth SPL"
+ depends on SPL_DM
+ help
+ Enable this to see warnings related to driver model in SPL
+
+ The dm_warn() function can use up quite a bit of space for its
+ strings. By default this is disabled for SPL builds to save space.
+
+ Warnings may help with debugging, such as when expected devices do
+ not bind correctly. If the option is disabled, dm_warn() is compiled
+ out - it will do nothing when called.
+
+config DM_DEBUG
+ bool "Enable debug messages in driver model core"
+ depends on DM
+ help
+ Say Y here if you want to compile in debug messages in DM core.
+
+config DM_DEVICE_REMOVE
+ bool "Support device removal"
+ depends on DM
+ default y
+ help
+ We can save some code space by dropping support for removing a
+ device.
+
+ Note that this may have undesirable results in the USB subsystem as
+ it causes unplugged devices to linger around in the dm-tree, and it
+ causes USB host controllers to not be stopped when booting the OS.
+
+config SPL_DM_DEVICE_REMOVE
+ bool "Support device removal in SPL"
+ depends on SPL_DM
+ default n
+ help
+ We can save some code space by dropping support for removing a
+ device. This is not normally required in SPL, so by default this
+ option is disabled for SPL.
+
+config DM_STDIO
+ bool "Support stdio registration"
+ depends on DM
+ default y
+ help
+ Normally serial drivers register with stdio so that they can be used
+ as normal output devices. In SPL we don't normally use stdio, so
+ we can omit this feature.
+
+config DM_SEQ_ALIAS
+ bool "Support numbered aliases in device tree"
+ depends on DM
+ default y
+ help
+ Most boards will have a '/aliases' node containing the path to
+ numbered devices (e.g. serial0 = &serial0). This feature can be
+ disabled if it is not required.
+
+config SPL_DM_SEQ_ALIAS
+ bool "Support numbered aliases in device tree in SPL"
+ depends on SPL_DM
+ default n
+ help
+ Most boards will have a '/aliases' node containing the path to
+ numbered devices (e.g. serial0 = &serial0). This feature can be
+ disabled if it is not required, to save code space in SPL.
+
+config SPL_DM_INLINE_OFNODE
+ bool "Inline some ofnode functions which are seldom used in SPL"
+ depends on SPL_DM
+ default y
+ help
+ This applies to several ofnode functions (see ofnode.h) which are
+ seldom used. Inlining them can help reduce code size.
+
+config TPL_DM_INLINE_OFNODE
+ bool "Inline some ofnode functions which are seldom used in TPL"
+ depends on TPL_DM
+ default y
+ help
+ This applies to several ofnode functions (see ofnode.h) which are
+ seldom used. Inlining them can help reduce code size.
+
+config DM_DMA
+ bool "Support per-device DMA constraints"
+ depends on DM
+ default n
+ help
+ Enable this to extract per-device DMA constraints, only supported on
+ device-tree systems for now. This is needed in order translate
+ addresses on systems where different buses have different views of
+ the physical address space.
+
+config REGMAP
+ bool "Support register maps"
+ depends on DM
+ help
+ Hardware peripherals tend to have one or more sets of registers
+ which can be accessed to control the hardware. A register map
+ models this with a simple read/write interface. It can in principle
+ support any bus type (I2C, SPI) but so far this only supports
+ direct memory access.
+
+config SPL_REGMAP
+ bool "Support register maps in SPL"
+ depends on SPL_DM
+ help
+ Hardware peripherals tend to have one or more sets of registers
+ which can be accessed to control the hardware. A register map
+ models this with a simple read/write interface. It can in principle
+ support any bus type (I2C, SPI) but so far this only supports
+ direct memory access.
+
+config TPL_REGMAP
+ bool "Support register maps in TPL"
+ depends on TPL_DM
+ help
+ Hardware peripherals tend to have one or more sets of registers
+ which can be accessed to control the hardware. A register map
+ models this with a simple read/write interface. It can in principle
+ support any bus type (I2C, SPI) but so far this only supports
+ direct memory access.
+
+config SYSCON
+ bool "Support system controllers"
+ depends on REGMAP
+ help
+ Many SoCs have a number of system controllers which are dealt with
+ as a group by a single driver. Some common functionality is provided
+ by this uclass, including accessing registers via regmap and
+ assigning a unique number to each.
+
+config SPL_SYSCON
+ bool "Support system controllers in SPL"
+ depends on SPL_REGMAP
+ help
+ Many SoCs have a number of system controllers which are dealt with
+ as a group by a single driver. Some common functionality is provided
+ by this uclass, including accessing registers via regmap and
+ assigning a unique number to each.
+
+config TPL_SYSCON
+ bool "Support system controllers in TPL"
+ depends on TPL_REGMAP
+ help
+ Many SoCs have a number of system controllers which are dealt with
+ as a group by a single driver. Some common functionality is provided
+ by this uclass, including accessing registers via regmap and
+ assigning a unique number to each.
+
+config DEVRES
+ bool "Managed device resources"
+ depends on DM
+ help
+ This option enables the Managed device resources core support.
+ Device resources managed by the devres framework are automatically
+ released whether initialization fails half-way or the device gets
+ detached.
+
+ If this option is disabled, devres functions fall back to
+ non-managed variants. For example, devres_alloc() to kzalloc(),
+ devm_kmalloc() to kmalloc(), etc.
+
+config DEBUG_DEVRES
+ bool "Managed device resources debugging functions"
+ depends on DEVRES
+ help
+ If this option is enabled, devres debug messages are printed.
+ Also, a function is available to dump a list of device resources.
+ Select this if you are having a problem with devres or want to
+ debug resource management for a managed device.
+
+ If you are unsure about this, Say N here.
+
+config SIMPLE_BUS
+ bool "Support simple-bus driver"
+ depends on DM && OF_CONTROL
+ default y
+ help
+ Supports the 'simple-bus' driver, which is used on some systems.
+
+config SPL_SIMPLE_BUS
+ bool "Support simple-bus driver in SPL"
+ depends on SPL_DM && SPL_OF_CONTROL
+ default y
+ help
+ Supports the 'simple-bus' driver, which is used on some systems
+ in SPL.
+
+config SIMPLE_BUS_CORRECT_RANGE
+ bool "Decode the 'simple-bus' <range> by honoring the #address-cells and #size-cells"
+ depends on SIMPLE_BUS
+ default y if SANDBOX
+ help
+ Decoding the 'simple-bus' <range> by honoring the #address-cells
+ and #size-cells of parent/child bus. If unset, #address-cells of
+ parent bus is assumed to be 1, #address-cells and #size-cells of
+ child bus is also assumed to be 1, to save some spaces of using
+ an advanced API to decode the <range>, which benefits SPL image
+ builds that have size limits.
+
+ If you are unsure about this, Say N here.
+
+config SIMPLE_PM_BUS
+ bool "Support simple-pm-bus driver"
+ depends on DM && OF_CONTROL && CLK && POWER_DOMAIN
+ help
+ Supports the 'simple-pm-bus' driver, which is used for busses that
+ have power domains and/or clocks which need to be enabled before use.
+
+config OF_TRANSLATE
+ bool "Translate addresses using fdt_translate_address"
+ depends on DM && OF_CONTROL
+ default y
+ help
+ If this option is enabled, the reg property will be translated
+ using the fdt_translate_address() function. This is necessary
+ on some platforms (e.g. MVEBU) using complex "ranges"
+ properties in many nodes. As this translation is not handled
+ correctly in the default simple_bus_translate() function.
+
+ If this option is not enabled, simple_bus_translate() will be
+ used for the address translation. This function is faster and
+ smaller in size than fdt_translate_address().
+
+config SPL_OF_TRANSLATE
+ bool "Translate addresses using fdt_translate_address in SPL"
+ depends on SPL_DM && SPL_OF_CONTROL
+ default n
+ help
+ If this option is enabled, the reg property will be translated
+ using the fdt_translate_address() function. This is necessary
+ on some platforms (e.g. MVEBU) using complex "ranges"
+ properties in many nodes. As this translation is not handled
+ correctly in the default simple_bus_translate() function.
+
+ If this option is not enabled, simple_bus_translate() will be
+ used for the address translation. This function is faster and
+ smaller in size than fdt_translate_address().
+
+config TRANSLATION_OFFSET
+ bool "Platforms specific translation offset"
+ depends on DM && OF_CONTROL
+ help
+ Some platforms need a special address translation. Those
+ platforms (e.g. mvebu in SPL) can configure a translation
+ offset by enabling this option and setting the translation_offset
+ variable in the GD in their platform- / board-specific code.
+
+config OF_ISA_BUS
+ bool
+ depends on OF_TRANSLATE
+ help
+ Is this option is enabled then support for the ISA bus will
+ be included for addresses read from DT. This is something that
+ should be known to be required or not based upon the board
+ being targeted, and whether or not it makes use of an ISA bus.
+
+ The bus is matched based upon its node name equalling "isa". The
+ busses #address-cells should equal 2, with the first cell being
+ used to hold flags & flag 0x1 indicating that the address range
+ should be accessed using I/O port in/out accessors. The second
+ cell holds the offset into ISA bus address space. The #size-cells
+ property should equal 1, and of course holds the size of the
+ address range used by a device.
+
+ If this option is not enabled then support for the ISA bus is
+ not included and any such busses used in DT will be treated as
+ typical simple-bus compatible busses. This will lead to
+ mistranslation of device addresses, so ensure that this is
+ enabled if your board does include an ISA bus.
+
+config DM_DEV_READ_INLINE
+ bool
+ default y if !OF_LIVE
+
+config ACPIGEN
+ bool "Support ACPI table generation in driver model"
+ default y if SANDBOX || (GENERATE_ACPI_TABLE && !QEMU)
+ help
+ This option enables generation of ACPI tables using driver-model
+ devices. It adds a new operation struct to each driver, to support
+ things like generating device-specific tables and returning the ACPI
+ name of a device.
+
+config BOUNCE_BUFFER
+ bool "Include bounce buffer API"
+ help
+ Some peripherals support DMA from a subset of physically
+ addressable memory only. To support such peripherals, the
+ bounce buffer API uses a temporary buffer: it copies data
+ to/from DMA regions while managing cache operations.
+
+ A second possible use of bounce buffers is their ability to
+ provide aligned buffers for DMA operations.
+
+endmenu
diff --git a/roms/u-boot/drivers/core/Makefile b/roms/u-boot/drivers/core/Makefile
new file mode 100644
index 000000000..5edd4e413
--- /dev/null
+++ b/roms/u-boot/drivers/core/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2013 Google, Inc
+
+obj-y += device.o fdtaddr.o lists.o root.o uclass.o util.o
+obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi.o
+obj-$(CONFIG_DEVRES) += devres.o
+obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE) += device-remove.o
+obj-$(CONFIG_$(SPL_)SIMPLE_BUS) += simple-bus.o
+obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
+obj-$(CONFIG_DM) += dump.o
+obj-$(CONFIG_$(SPL_TPL_)REGMAP) += regmap.o
+obj-$(CONFIG_$(SPL_TPL_)SYSCON) += syscon-uclass.o
+obj-$(CONFIG_$(SPL_)OF_LIVE) += of_access.o of_addr.o
+ifndef CONFIG_DM_DEV_READ_INLINE
+obj-$(CONFIG_OF_CONTROL) += read.o
+endif
+obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o
+
+ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG
diff --git a/roms/u-boot/drivers/core/acpi.c b/roms/u-boot/drivers/core/acpi.c
new file mode 100644
index 000000000..2176d8b83
--- /dev/null
+++ b/roms/u-boot/drivers/core/acpi.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Core driver model support for ACPI table generation
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEOGRY LOGC_ACPI
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <acpi/acpi_device.h>
+#include <dm/acpi.h>
+#include <dm/device-internal.h>
+#include <dm/root.h>
+
+#define MAX_ACPI_ITEMS 100
+
+/* Type of table that we collected */
+enum gen_type_t {
+ TYPE_NONE,
+ TYPE_SSDT,
+ TYPE_DSDT,
+};
+
+/* Type of method to call */
+enum method_t {
+ METHOD_WRITE_TABLES,
+ METHOD_FILL_SSDT,
+ METHOD_INJECT_DSDT,
+ METHOD_SETUP_NHLT,
+};
+
+/* Prototype for all methods */
+typedef int (*acpi_method)(const struct udevice *dev, struct acpi_ctx *ctx);
+
+/**
+ * struct acpi_item - Holds info about ACPI data generated by a driver method
+ *
+ * @dev: Device that generated this data
+ * @type: Table type it refers to
+ * @buf: Buffer containing the data
+ * @size: Size of the data in bytes
+ */
+struct acpi_item {
+ struct udevice *dev;
+ enum gen_type_t type;
+ char *buf;
+ int size;
+};
+
+/* List of ACPI items collected */
+static struct acpi_item acpi_item[MAX_ACPI_ITEMS];
+static int item_count;
+
+int acpi_copy_name(char *out_name, const char *name)
+{
+ strncpy(out_name, name, ACPI_NAME_LEN);
+ out_name[ACPI_NAME_LEN] = '\0';
+
+ return 0;
+}
+
+int acpi_get_name(const struct udevice *dev, char *out_name)
+{
+ struct acpi_ops *aops;
+ const char *name;
+ int ret;
+
+ aops = device_get_acpi_ops(dev);
+ if (aops && aops->get_name)
+ return aops->get_name(dev, out_name);
+ name = dev_read_string(dev, "acpi,name");
+ if (name)
+ return acpi_copy_name(out_name, name);
+ ret = acpi_device_infer_name(dev, out_name);
+ if (ret)
+ return log_msg_ret("dev", ret);
+
+ return 0;
+}
+
+int acpi_get_path(const struct udevice *dev, char *out_path, int maxlen)
+{
+ const char *path;
+ int ret;
+
+ path = dev_read_string(dev, "acpi,path");
+ if (path) {
+ if (strlen(path) >= maxlen)
+ return -ENOSPC;
+ strcpy(out_path, path);
+ return 0;
+ }
+ ret = acpi_device_path(dev, out_path, maxlen);
+ if (ret)
+ return log_msg_ret("dev", ret);
+
+ return 0;
+}
+
+/**
+ * acpi_add_item() - Add a new item to the list of data collected
+ *
+ * @ctx: ACPI context
+ * @dev: Device that generated the data
+ * @type: Table type it refers to
+ * @start: The start of the data (the end is obtained from ctx->current)
+ * @return 0 if OK, -ENOSPC if too many items, -ENOMEM if out of memory
+ */
+static int acpi_add_item(struct acpi_ctx *ctx, struct udevice *dev,
+ enum gen_type_t type, void *start)
+{
+ struct acpi_item *item;
+ void *end = ctx->current;
+
+ if (item_count == MAX_ACPI_ITEMS) {
+ log_err("Too many items\n");
+ return log_msg_ret("mem", -ENOSPC);
+ }
+
+ item = &acpi_item[item_count];
+ item->dev = dev;
+ item->type = type;
+ item->size = end - start;
+ if (!item->size)
+ return 0;
+ item->buf = malloc(item->size);
+ if (!item->buf)
+ return log_msg_ret("mem", -ENOMEM);
+ memcpy(item->buf, start, item->size);
+ item_count++;
+ log_debug("* %s: Added type %d, %p, size %x\n", dev->name, type, start,
+ item->size);
+
+ return 0;
+}
+
+void acpi_dump_items(enum acpi_dump_option option)
+{
+ int i;
+
+ for (i = 0; i < item_count; i++) {
+ struct acpi_item *item = &acpi_item[i];
+
+ printf("dev '%s', type %d, size %x\n", item->dev->name,
+ item->type, item->size);
+ if (option == ACPI_DUMP_CONTENTS) {
+ print_buffer(0, item->buf, 1, item->size, 0);
+ printf("\n");
+ }
+ }
+}
+
+static struct acpi_item *find_acpi_item(const char *devname)
+{
+ int i;
+
+ for (i = 0; i < item_count; i++) {
+ struct acpi_item *item = &acpi_item[i];
+
+ if (!strcmp(devname, item->dev->name))
+ return item;
+ }
+
+ return NULL;
+}
+
+/**
+ * sort_acpi_item_type - Sort the ACPI items into the desired order
+ *
+ * This looks up the ordering in the device tree and then adds each item one by
+ * one into the supplied buffer
+ *
+ * @ctx: ACPI context
+ * @start: Start position to put the sorted items. The items will follow each
+ * other in sorted order
+ * @type: Type of items to sort
+ * @return 0 if OK, -ve on error
+ */
+static int sort_acpi_item_type(struct acpi_ctx *ctx, void *start,
+ enum gen_type_t type)
+{
+ const u32 *order;
+ int size;
+ int count;
+ void *ptr;
+ void *end = ctx->current;
+
+ ptr = start;
+ order = ofnode_read_chosen_prop(type == TYPE_DSDT ?
+ "u-boot,acpi-dsdt-order" :
+ "u-boot,acpi-ssdt-order", &size);
+ if (!order) {
+ log_debug("Failed to find ordering, leaving as is\n");
+ return 0;
+ }
+
+ /*
+ * This algorithm rewrites the context buffer without changing its
+ * length. So there is no need to update ctx-current
+ */
+ count = size / sizeof(u32);
+ while (count--) {
+ struct acpi_item *item;
+ const char *name;
+ ofnode node;
+
+ node = ofnode_get_by_phandle(fdt32_to_cpu(*order++));
+ name = ofnode_get_name(node);
+ item = find_acpi_item(name);
+ if (!item) {
+ log_err("Failed to find item '%s'\n", name);
+ return log_msg_ret("find", -ENOENT);
+ }
+ if (item->type == type) {
+ log_debug(" - add %s\n", item->dev->name);
+ memcpy(ptr, item->buf, item->size);
+ ptr += item->size;
+ }
+ }
+
+ /*
+ * If the sort order is missing an item then the output will be too
+ * small. Report this error since the item needs to be added to the
+ * ordering for the ACPI tables to be complete.
+ */
+ if (ptr != end) {
+ log_warning("*** Missing bytes: ptr=%p, end=%p\n", ptr, end);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+acpi_method acpi_get_method(struct udevice *dev, enum method_t method)
+{
+ struct acpi_ops *aops;
+
+ aops = device_get_acpi_ops(dev);
+ if (aops) {
+ switch (method) {
+ case METHOD_WRITE_TABLES:
+ return aops->write_tables;
+ case METHOD_FILL_SSDT:
+ return aops->fill_ssdt;
+ case METHOD_INJECT_DSDT:
+ return aops->inject_dsdt;
+ case METHOD_SETUP_NHLT:
+ return aops->setup_nhlt;
+ }
+ }
+
+ return NULL;
+}
+
+int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent,
+ enum method_t method, enum gen_type_t type)
+{
+ struct udevice *dev;
+ acpi_method func;
+ int ret;
+
+ func = acpi_get_method(parent, method);
+ if (func) {
+ void *start = ctx->current;
+
+ log_debug("- method %d, %s %p\n", method, parent->name, func);
+ ret = device_of_to_plat(parent);
+ if (ret)
+ return log_msg_ret("ofdata", ret);
+ ret = func(parent, ctx);
+ if (ret)
+ return log_msg_ret("func", ret);
+
+ /* Add the item to the internal list */
+ if (type != TYPE_NONE) {
+ ret = acpi_add_item(ctx, parent, type, start);
+ if (ret)
+ return log_msg_ret("add", ret);
+ }
+ }
+ device_foreach_child(dev, parent) {
+ ret = acpi_recurse_method(ctx, dev, method, type);
+ if (ret)
+ return log_msg_ret("recurse", ret);
+ }
+
+ return 0;
+}
+
+int acpi_fill_ssdt(struct acpi_ctx *ctx)
+{
+ void *start = ctx->current;
+ int ret;
+
+ log_debug("Writing SSDT tables\n");
+ ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_SSDT, TYPE_SSDT);
+ log_debug("Writing SSDT finished, err=%d\n", ret);
+ ret = sort_acpi_item_type(ctx, start, TYPE_SSDT);
+ if (ret)
+ return log_msg_ret("build", ret);
+
+ return ret;
+}
+
+int acpi_inject_dsdt(struct acpi_ctx *ctx)
+{
+ void *start = ctx->current;
+ int ret;
+
+ log_debug("Writing DSDT tables\n");
+ ret = acpi_recurse_method(ctx, dm_root(), METHOD_INJECT_DSDT,
+ TYPE_DSDT);
+ log_debug("Writing DSDT finished, err=%d\n", ret);
+ ret = sort_acpi_item_type(ctx, start, TYPE_DSDT);
+ if (ret)
+ return log_msg_ret("build", ret);
+
+ return ret;
+}
+
+void acpi_reset_items(void)
+{
+ item_count = 0;
+}
+
+int acpi_write_dev_tables(struct acpi_ctx *ctx)
+{
+ int ret;
+
+ log_debug("Writing device tables\n");
+ ret = acpi_recurse_method(ctx, dm_root(), METHOD_WRITE_TABLES,
+ TYPE_NONE);
+ log_debug("Writing finished, err=%d\n", ret);
+
+ return ret;
+}
+
+int acpi_setup_nhlt(struct acpi_ctx *ctx, struct nhlt *nhlt)
+{
+ int ret;
+
+ log_debug("Setup NHLT\n");
+ ctx->nhlt = nhlt;
+ ret = acpi_recurse_method(ctx, dm_root(), METHOD_SETUP_NHLT, TYPE_NONE);
+ log_debug("Setup finished, err=%d\n", ret);
+
+ return ret;
+}
diff --git a/roms/u-boot/drivers/core/device-remove.c b/roms/u-boot/drivers/core/device-remove.c
new file mode 100644
index 000000000..11d3959d2
--- /dev/null
+++ b/roms/u-boot/drivers/core/device-remove.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Device manager
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ */
+
+#define LOG_CATEGORY LOGC_DM
+
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/uclass.h>
+#include <dm/uclass-internal.h>
+#include <dm/util.h>
+#include <power-domain.h>
+#include <asm/global_data.h>
+
+int device_chld_unbind(struct udevice *dev, struct driver *drv)
+{
+ struct udevice *pos, *n;
+ int ret, saved_ret = 0;
+
+ assert(dev);
+
+ list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+ if (drv && (pos->driver != drv))
+ continue;
+
+ ret = device_unbind(pos);
+ if (ret && !saved_ret) {
+ log_warning("device '%s' failed to unbind\n",
+ pos->name);
+ saved_ret = ret;
+ }
+ }
+
+ return log_ret(saved_ret);
+}
+
+int device_chld_remove(struct udevice *dev, struct driver *drv,
+ uint flags)
+{
+ struct udevice *pos, *n;
+ int result = 0;
+
+ assert(dev);
+
+ list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+ int ret;
+
+ if (drv && (pos->driver != drv))
+ continue;
+
+ ret = device_remove(pos, flags);
+ if (ret == -EPROBE_DEFER)
+ result = ret;
+ else if (ret && ret != -EKEYREJECTED)
+ return ret;
+ }
+
+ return result;
+}
+
+int device_unbind(struct udevice *dev)
+{
+ const struct driver *drv;
+ int ret;
+
+ if (!dev)
+ return log_msg_ret("dev", -EINVAL);
+
+ if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
+ return log_msg_ret("active", -EINVAL);
+
+ if (!(dev_get_flags(dev) & DM_FLAG_BOUND))
+ return log_msg_ret("not-bound", -EINVAL);
+
+ drv = dev->driver;
+ assert(drv);
+
+ if (drv->unbind) {
+ ret = drv->unbind(dev);
+ if (ret)
+ return log_msg_ret("unbind", ret);
+ }
+
+ ret = device_chld_unbind(dev, NULL);
+ if (ret)
+ return log_msg_ret("child unbind", ret);
+
+ if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) {
+ free(dev_get_plat(dev));
+ dev_set_plat(dev, NULL);
+ }
+ if (dev_get_flags(dev) & DM_FLAG_ALLOC_UCLASS_PDATA) {
+ free(dev_get_uclass_plat(dev));
+ dev_set_uclass_plat(dev, NULL);
+ }
+ if (dev_get_flags(dev) & DM_FLAG_ALLOC_PARENT_PDATA) {
+ free(dev_get_parent_plat(dev));
+ dev_set_parent_plat(dev, NULL);
+ }
+ ret = uclass_unbind_device(dev);
+ if (ret)
+ return log_msg_ret("uc", ret);
+
+ if (dev->parent)
+ list_del(&dev->sibling_node);
+
+ devres_release_all(dev);
+
+ if (dev_get_flags(dev) & DM_FLAG_NAME_ALLOCED)
+ free((char *)dev->name);
+ free(dev);
+
+ return 0;
+}
+
+/**
+ * device_free() - Free memory buffers allocated by a device
+ * @dev: Device that is to be started
+ */
+void device_free(struct udevice *dev)
+{
+ int size;
+
+ if (dev->driver->priv_auto) {
+ free(dev_get_priv(dev));
+ dev_set_priv(dev, NULL);
+ }
+ size = dev->uclass->uc_drv->per_device_auto;
+ if (size) {
+ free(dev_get_uclass_priv(dev));
+ dev_set_uclass_priv(dev, NULL);
+ }
+ if (dev->parent) {
+ size = dev->parent->driver->per_child_auto;
+ if (!size) {
+ size = dev->parent->uclass->uc_drv->
+ per_child_auto;
+ }
+ if (size) {
+ free(dev_get_parent_priv(dev));
+ dev_set_parent_priv(dev, NULL);
+ }
+ }
+ dev_bic_flags(dev, DM_FLAG_PLATDATA_VALID);
+
+ devres_release_probe(dev);
+}
+
+/**
+ * flags_remove() - Figure out whether to remove a device
+ *
+ * If this is called with @flags == DM_REMOVE_NON_VITAL | DM_REMOVE_ACTIVE_DMA,
+ * then it returns 0 (=go head and remove) if the device is not matked vital
+ * but is marked DM_REMOVE_ACTIVE_DMA.
+ *
+ * If this is called with @flags == DM_REMOVE_ACTIVE_DMA,
+ * then it returns 0 (=go head and remove) if the device is marked
+ * DM_REMOVE_ACTIVE_DMA, regardless of whether it is marked vital.
+ *
+ * @flags: Flags passed to device_remove()
+ * @drv_flags: Driver flags
+ * @return 0 if the device should be removed,
+ * -EKEYREJECTED if @flags includes a flag in DM_REMOVE_ACTIVE_ALL but
+ * @drv_flags does not (indicates that this device has nothing to do for
+ * DMA shutdown or OS prepare)
+ * -EPROBE_DEFER if @flags is DM_REMOVE_NON_VITAL but @drv_flags contains
+ * DM_FLAG_VITAL (indicates the device is vital and should not be removed)
+ */
+static int flags_remove(uint flags, uint drv_flags)
+{
+ if (!(flags & DM_REMOVE_NORMAL)) {
+ bool vital_match;
+ bool active_match;
+
+ active_match = !(flags & DM_REMOVE_ACTIVE_ALL) ||
+ (drv_flags & flags);
+ vital_match = !(flags & DM_REMOVE_NON_VITAL) ||
+ !(drv_flags & DM_FLAG_VITAL);
+ if (!vital_match)
+ return -EPROBE_DEFER;
+ if (!active_match)
+ return -EKEYREJECTED;
+ }
+
+ return 0;
+}
+
+int device_remove(struct udevice *dev, uint flags)
+{
+ const struct driver *drv;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (!(dev_get_flags(dev) & DM_FLAG_ACTIVATED))
+ return 0;
+
+ /*
+ * If the child returns EKEYREJECTED, continue. It just means that it
+ * didn't match the flags.
+ */
+ ret = device_chld_remove(dev, NULL, flags);
+ if (ret && ret != -EKEYREJECTED)
+ return ret;
+
+ /*
+ * Remove the device if called with the "normal" remove flag set,
+ * or if the remove flag matches any of the drivers remove flags
+ */
+ drv = dev->driver;
+ assert(drv);
+ ret = flags_remove(flags, drv->flags);
+ if (ret) {
+ log_debug("%s: When removing: flags=%x, drv->flags=%x, err=%d\n",
+ dev->name, flags, drv->flags, ret);
+ return ret;
+ }
+
+ ret = uclass_pre_remove_device(dev);
+ if (ret)
+ return ret;
+
+ if (drv->remove) {
+ ret = drv->remove(dev);
+ if (ret)
+ goto err_remove;
+ }
+
+ if (dev->parent && dev->parent->driver->child_post_remove) {
+ ret = dev->parent->driver->child_post_remove(dev);
+ if (ret) {
+ dm_warn("%s: Device '%s' failed child_post_remove()",
+ __func__, dev->name);
+ }
+ }
+
+ if (!(flags & DM_REMOVE_NO_PD) &&
+ !(drv->flags &
+ (DM_FLAG_DEFAULT_PD_CTRL_OFF | DM_FLAG_LEAVE_PD_ON)) &&
+ dev != gd->cur_serial_dev)
+ dev_power_domain_off(dev);
+
+ device_free(dev);
+
+ dev_bic_flags(dev, DM_FLAG_ACTIVATED);
+
+ return 0;
+
+err_remove:
+ /* We can't put the children back */
+ dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
+ __func__, dev->name);
+
+ return ret;
+}
diff --git a/roms/u-boot/drivers/core/device.c b/roms/u-boot/drivers/core/device.c
new file mode 100644
index 000000000..cb960f8ec
--- /dev/null
+++ b/roms/u-boot/drivers/core/device.c
@@ -0,0 +1,1171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Device manager
+ *
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <malloc.h>
+#include <asm/cache.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/of_access.h>
+#include <dm/pinctrl.h>
+#include <dm/platdata.h>
+#include <dm/read.h>
+#include <dm/uclass.h>
+#include <dm/uclass-internal.h>
+#include <dm/util.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <power-domain.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int device_bind_common(struct udevice *parent, const struct driver *drv,
+ const char *name, void *plat,
+ ulong driver_data, ofnode node,
+ uint of_plat_size, struct udevice **devp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int size, ret = 0;
+ bool auto_seq = true;
+ void *ptr;
+
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND))
+ return -ENOSYS;
+
+ if (devp)
+ *devp = NULL;
+ if (!name)
+ return -EINVAL;
+
+ ret = uclass_get(drv->id, &uc);
+ if (ret) {
+ debug("Missing uclass for driver %s\n", drv->name);
+ return ret;
+ }
+
+ dev = calloc(1, sizeof(struct udevice));
+ if (!dev)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&dev->sibling_node);
+ INIT_LIST_HEAD(&dev->child_head);
+ INIT_LIST_HEAD(&dev->uclass_node);
+#ifdef CONFIG_DEVRES
+ INIT_LIST_HEAD(&dev->devres_head);
+#endif
+ dev_set_plat(dev, plat);
+ dev->driver_data = driver_data;
+ dev->name = name;
+ dev_set_ofnode(dev, node);
+ dev->parent = parent;
+ dev->driver = drv;
+ dev->uclass = uc;
+
+ dev->seq_ = -1;
+ if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
+ (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) {
+ /*
+ * Some devices, such as a SPI bus, I2C bus and serial ports
+ * are numbered using aliases.
+ */
+ if (CONFIG_IS_ENABLED(OF_CONTROL) &&
+ !CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ if (uc->uc_drv->name && ofnode_valid(node)) {
+ if (!dev_read_alias_seq(dev, &dev->seq_))
+ auto_seq = false;
+ }
+ }
+ }
+ if (auto_seq && !(uc->uc_drv->flags & DM_UC_FLAG_NO_AUTO_SEQ))
+ dev->seq_ = uclass_find_next_free_seq(uc);
+
+ /* Check if we need to allocate plat */
+ if (drv->plat_auto) {
+ bool alloc = !plat;
+
+ /*
+ * For of-platdata, we try use the existing data, but if
+ * plat_auto is larger, we must allocate a new space
+ */
+ if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ if (of_plat_size)
+ dev_or_flags(dev, DM_FLAG_OF_PLATDATA);
+ if (of_plat_size < drv->plat_auto)
+ alloc = true;
+ }
+ if (alloc) {
+ dev_or_flags(dev, DM_FLAG_ALLOC_PDATA);
+ ptr = calloc(1, drv->plat_auto);
+ if (!ptr) {
+ ret = -ENOMEM;
+ goto fail_alloc1;
+ }
+
+ /*
+ * For of-platdata, copy the old plat into the new
+ * space
+ */
+ if (CONFIG_IS_ENABLED(OF_PLATDATA) && plat)
+ memcpy(ptr, plat, of_plat_size);
+ dev_set_plat(dev, ptr);
+ }
+ }
+
+ size = uc->uc_drv->per_device_plat_auto;
+ if (size) {
+ dev_or_flags(dev, DM_FLAG_ALLOC_UCLASS_PDATA);
+ ptr = calloc(1, size);
+ if (!ptr) {
+ ret = -ENOMEM;
+ goto fail_alloc2;
+ }
+ dev_set_uclass_plat(dev, ptr);
+ }
+
+ if (parent) {
+ size = parent->driver->per_child_plat_auto;
+ if (!size)
+ size = parent->uclass->uc_drv->per_child_plat_auto;
+ if (size) {
+ dev_or_flags(dev, DM_FLAG_ALLOC_PARENT_PDATA);
+ ptr = calloc(1, size);
+ if (!ptr) {
+ ret = -ENOMEM;
+ goto fail_alloc3;
+ }
+ dev_set_parent_plat(dev, ptr);
+ }
+ /* put dev into parent's successor list */
+ list_add_tail(&dev->sibling_node, &parent->child_head);
+ }
+
+ ret = uclass_bind_device(dev);
+ if (ret)
+ goto fail_uclass_bind;
+
+ /* if we fail to bind we remove device from successors and free it */
+ if (drv->bind) {
+ ret = drv->bind(dev);
+ if (ret)
+ goto fail_bind;
+ }
+ if (parent && parent->driver->child_post_bind) {
+ ret = parent->driver->child_post_bind(dev);
+ if (ret)
+ goto fail_child_post_bind;
+ }
+ if (uc->uc_drv->post_bind) {
+ ret = uc->uc_drv->post_bind(dev);
+ if (ret)
+ goto fail_uclass_post_bind;
+ }
+
+ if (parent)
+ pr_debug("Bound device %s to %s\n", dev->name, parent->name);
+ if (devp)
+ *devp = dev;
+
+ dev_or_flags(dev, DM_FLAG_BOUND);
+
+ return 0;
+
+fail_uclass_post_bind:
+ /* There is no child unbind() method, so no clean-up required */
+fail_child_post_bind:
+ if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
+ if (drv->unbind && drv->unbind(dev)) {
+ dm_warn("unbind() method failed on dev '%s' on error path\n",
+ dev->name);
+ }
+ }
+
+fail_bind:
+ if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
+ if (uclass_unbind_device(dev)) {
+ dm_warn("Failed to unbind dev '%s' on error path\n",
+ dev->name);
+ }
+ }
+fail_uclass_bind:
+ if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
+ list_del(&dev->sibling_node);
+ if (dev_get_flags(dev) & DM_FLAG_ALLOC_PARENT_PDATA) {
+ free(dev_get_parent_plat(dev));
+ dev_set_parent_plat(dev, NULL);
+ }
+ }
+fail_alloc3:
+ if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
+ if (dev_get_flags(dev) & DM_FLAG_ALLOC_UCLASS_PDATA) {
+ free(dev_get_uclass_plat(dev));
+ dev_set_uclass_plat(dev, NULL);
+ }
+ }
+fail_alloc2:
+ if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
+ if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) {
+ free(dev_get_plat(dev));
+ dev_set_plat(dev, NULL);
+ }
+ }
+fail_alloc1:
+ devres_release_all(dev);
+
+ free(dev);
+
+ return ret;
+}
+
+int device_bind_with_driver_data(struct udevice *parent,
+ const struct driver *drv, const char *name,
+ ulong driver_data, ofnode node,
+ struct udevice **devp)
+{
+ return device_bind_common(parent, drv, name, NULL, driver_data, node,
+ 0, devp);
+}
+
+int device_bind(struct udevice *parent, const struct driver *drv,
+ const char *name, void *plat, ofnode node,
+ struct udevice **devp)
+{
+ return device_bind_common(parent, drv, name, plat, 0, node, 0,
+ devp);
+}
+
+int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
+ const struct driver_info *info, struct udevice **devp)
+{
+ struct driver *drv;
+ uint plat_size = 0;
+ int ret;
+
+ drv = lists_driver_lookup_name(info->name);
+ if (!drv)
+ return -ENOENT;
+ if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
+ return -EPERM;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ plat_size = info->plat_size;
+#endif
+ ret = device_bind_common(parent, drv, info->name, (void *)info->plat, 0,
+ ofnode_null(), plat_size, devp);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+int device_reparent(struct udevice *dev, struct udevice *new_parent)
+{
+ struct udevice *pos, *n;
+
+ assert(dev);
+ assert(new_parent);
+
+ list_for_each_entry_safe(pos, n, &dev->parent->child_head,
+ sibling_node) {
+ if (pos->driver != dev->driver)
+ continue;
+
+ list_del(&dev->sibling_node);
+ list_add_tail(&dev->sibling_node, &new_parent->child_head);
+ dev->parent = new_parent;
+
+ break;
+ }
+
+ return 0;
+}
+
+static void *alloc_priv(int size, uint flags)
+{
+ void *priv;
+
+ if (flags & DM_FLAG_ALLOC_PRIV_DMA) {
+ size = ROUND(size, ARCH_DMA_MINALIGN);
+ priv = memalign(ARCH_DMA_MINALIGN, size);
+ if (priv) {
+ memset(priv, '\0', size);
+
+ /*
+ * Ensure that the zero bytes are flushed to memory.
+ * This prevents problems if the driver uses this as
+ * both an input and an output buffer:
+ *
+ * 1. Zeroes written to buffer (here) and sit in the
+ * cache
+ * 2. Driver issues a read command to DMA
+ * 3. CPU runs out of cache space and evicts some cache
+ * data in the buffer, writing zeroes to RAM from
+ * the memset() above
+ * 4. DMA completes
+ * 5. Buffer now has some DMA data and some zeroes
+ * 6. Data being read is now incorrect
+ *
+ * To prevent this, ensure that the cache is clean
+ * within this range at the start. The driver can then
+ * use normal flush-after-write, invalidate-before-read
+ * procedures.
+ *
+ * TODO(sjg@chromium.org): Drop this microblaze
+ * exception.
+ */
+#ifndef CONFIG_MICROBLAZE
+ flush_dcache_range((ulong)priv, (ulong)priv + size);
+#endif
+ }
+ } else {
+ priv = calloc(1, size);
+ }
+
+ return priv;
+}
+
+/**
+ * device_alloc_priv() - Allocate priv/plat data required by the device
+ *
+ * @dev: Device to process
+ * @return 0 if OK, -ENOMEM if out of memory
+ */
+static int device_alloc_priv(struct udevice *dev)
+{
+ const struct driver *drv;
+ void *ptr;
+ int size;
+
+ drv = dev->driver;
+ assert(drv);
+
+ /* Allocate private data if requested and not reentered */
+ if (drv->priv_auto && !dev_get_priv(dev)) {
+ ptr = alloc_priv(drv->priv_auto, drv->flags);
+ if (!ptr)
+ return -ENOMEM;
+ dev_set_priv(dev, ptr);
+ }
+
+ /* Allocate private data if requested and not reentered */
+ size = dev->uclass->uc_drv->per_device_auto;
+ if (size && !dev_get_uclass_priv(dev)) {
+ ptr = alloc_priv(size, dev->uclass->uc_drv->flags);
+ if (!ptr)
+ return -ENOMEM;
+ dev_set_uclass_priv(dev, ptr);
+ }
+
+ /* Allocate parent data for this child */
+ if (dev->parent) {
+ size = dev->parent->driver->per_child_auto;
+ if (!size)
+ size = dev->parent->uclass->uc_drv->per_child_auto;
+ if (size && !dev_get_parent_priv(dev)) {
+ ptr = alloc_priv(size, drv->flags);
+ if (!ptr)
+ return -ENOMEM;
+ dev_set_parent_priv(dev, ptr);
+ }
+ }
+
+ return 0;
+}
+
+int device_of_to_plat(struct udevice *dev)
+{
+ const struct driver *drv;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
+ return 0;
+
+ /*
+ * This is not needed if binding is disabled, since data is allocated
+ * at build time.
+ */
+ if (!CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND)) {
+ /* Ensure all parents have ofdata */
+ if (dev->parent) {
+ ret = device_of_to_plat(dev->parent);
+ if (ret)
+ goto fail;
+
+ /*
+ * The device might have already been probed during
+ * the call to device_probe() on its parent device
+ * (e.g. PCI bridge devices). Test the flags again
+ * so that we don't mess up the device.
+ */
+ if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
+ return 0;
+ }
+
+ ret = device_alloc_priv(dev);
+ if (ret)
+ goto fail;
+ }
+ drv = dev->driver;
+ assert(drv);
+
+ if (drv->of_to_plat &&
+ (CONFIG_IS_ENABLED(OF_PLATDATA) || dev_has_ofnode(dev))) {
+ ret = drv->of_to_plat(dev);
+ if (ret)
+ goto fail;
+ }
+
+ dev_or_flags(dev, DM_FLAG_PLATDATA_VALID);
+
+ return 0;
+fail:
+ device_free(dev);
+
+ return ret;
+}
+
+/**
+ * device_get_dma_constraints() - Populate device's DMA constraints
+ *
+ * Gets a device's DMA constraints from firmware. This information is later
+ * used by drivers to translate physcal addresses to the device's bus address
+ * space. For now only device-tree is supported.
+ *
+ * @dev: Pointer to target device
+ * Return: 0 if OK or if no DMA constraints were found, error otherwise
+ */
+static int device_get_dma_constraints(struct udevice *dev)
+{
+ struct udevice *parent = dev->parent;
+ phys_addr_t cpu = 0;
+ dma_addr_t bus = 0;
+ u64 size = 0;
+ int ret;
+
+ if (!CONFIG_IS_ENABLED(DM_DMA) || !parent || !dev_has_ofnode(parent))
+ return 0;
+
+ /*
+ * We start parsing for dma-ranges from the device's bus node. This is
+ * specially important on nested buses.
+ */
+ ret = dev_get_dma_range(parent, &cpu, &bus, &size);
+ /* Don't return an error if no 'dma-ranges' were found */
+ if (ret && ret != -ENOENT) {
+ dm_warn("%s: failed to get DMA range, %d\n", dev->name, ret);
+ return ret;
+ }
+
+ dev_set_dma_offset(dev, cpu - bus);
+
+ return 0;
+}
+
+int device_probe(struct udevice *dev)
+{
+ const struct driver *drv;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
+ return 0;
+
+ drv = dev->driver;
+ assert(drv);
+
+ ret = device_of_to_plat(dev);
+ if (ret)
+ goto fail;
+
+ /* Ensure all parents are probed */
+ if (dev->parent) {
+ ret = device_probe(dev->parent);
+ if (ret)
+ goto fail;
+
+ /*
+ * The device might have already been probed during
+ * the call to device_probe() on its parent device
+ * (e.g. PCI bridge devices). Test the flags again
+ * so that we don't mess up the device.
+ */
+ if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
+ return 0;
+ }
+
+ dev_or_flags(dev, DM_FLAG_ACTIVATED);
+
+ /*
+ * Process pinctrl for everything except the root device, and
+ * continue regardless of the result of pinctrl. Don't process pinctrl
+ * settings for pinctrl devices since the device may not yet be
+ * probed.
+ *
+ * This call can produce some non-intuitive results. For example, on an
+ * x86 device where dev is the main PCI bus, the pinctrl device may be
+ * child or grandchild of that bus, meaning that the child will be
+ * probed here. If the child happens to be the P2SB and the pinctrl
+ * device is a child of that, then both the pinctrl and P2SB will be
+ * probed by this call. This works because the DM_FLAG_ACTIVATED flag
+ * is set just above. However, the PCI bus' probe() method and
+ * associated uclass methods have not yet been called.
+ */
+ if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)
+ pinctrl_select_state(dev, "default");
+
+ if (CONFIG_IS_ENABLED(POWER_DOMAIN) && dev->parent &&
+ (device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) &&
+ !(drv->flags & DM_FLAG_DEFAULT_PD_CTRL_OFF)) {
+ ret = dev_power_domain_on(dev);
+ if (ret)
+ goto fail;
+ }
+
+ ret = device_get_dma_constraints(dev);
+ if (ret)
+ goto fail;
+
+ ret = uclass_pre_probe_device(dev);
+ if (ret)
+ goto fail;
+
+ if (dev->parent && dev->parent->driver->child_pre_probe) {
+ ret = dev->parent->driver->child_pre_probe(dev);
+ if (ret)
+ goto fail;
+ }
+
+ /* Only handle devices that have a valid ofnode */
+ if (dev_has_ofnode(dev)) {
+ /*
+ * Process 'assigned-{clocks/clock-parents/clock-rates}'
+ * properties
+ */
+ ret = clk_set_defaults(dev, 0);
+ if (ret)
+ goto fail;
+ }
+
+ if (drv->probe) {
+ ret = drv->probe(dev);
+ if (ret)
+ goto fail;
+ }
+
+ ret = uclass_post_probe_device(dev);
+ if (ret)
+ goto fail_uclass;
+
+ if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL)
+ pinctrl_select_state(dev, "default");
+
+ return 0;
+fail_uclass:
+ if (device_remove(dev, DM_REMOVE_NORMAL)) {
+ dm_warn("%s: Device '%s' failed to remove on error path\n",
+ __func__, dev->name);
+ }
+fail:
+ dev_bic_flags(dev, DM_FLAG_ACTIVATED);
+
+ device_free(dev);
+
+ return ret;
+}
+
+void *dev_get_plat(const struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device\n", __func__);
+ return NULL;
+ }
+
+ return dm_priv_to_rw(dev->plat_);
+}
+
+void *dev_get_parent_plat(const struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device\n", __func__);
+ return NULL;
+ }
+
+ return dm_priv_to_rw(dev->parent_plat_);
+}
+
+void *dev_get_uclass_plat(const struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device\n", __func__);
+ return NULL;
+ }
+
+ return dm_priv_to_rw(dev->uclass_plat_);
+}
+
+void *dev_get_priv(const struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device\n", __func__);
+ return NULL;
+ }
+
+ return dm_priv_to_rw(dev->priv_);
+}
+
+void *dev_get_uclass_priv(const struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device\n", __func__);
+ return NULL;
+ }
+
+ return dm_priv_to_rw(dev->uclass_priv_);
+}
+
+void *dev_get_parent_priv(const struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device\n", __func__);
+ return NULL;
+ }
+
+ return dm_priv_to_rw(dev->parent_priv_);
+}
+
+static int device_get_device_tail(struct udevice *dev, int ret,
+ struct udevice **devp)
+{
+ if (ret)
+ return ret;
+
+ ret = device_probe(dev);
+ if (ret)
+ return ret;
+
+ *devp = dev;
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+/**
+ * device_find_by_ofnode() - Return device associated with given ofnode
+ *
+ * The returned device is *not* activated.
+ *
+ * @node: The ofnode for which a associated device should be looked up
+ * @devp: Pointer to structure to hold the found device
+ * Return: 0 if OK, -ve on error
+ */
+static int device_find_by_ofnode(ofnode node, struct udevice **devp)
+{
+ struct uclass *uc;
+ struct udevice *dev;
+ int ret;
+
+ list_for_each_entry(uc, gd->uclass_root, sibling_node) {
+ ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node,
+ &dev);
+ if (!ret || dev) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+#endif
+
+int device_get_child(const struct udevice *parent, int index,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ if (!index--)
+ return device_get_device_tail(dev, 0, devp);
+ }
+
+ return -ENODEV;
+}
+
+int device_get_child_count(const struct udevice *parent)
+{
+ struct udevice *dev;
+ int count = 0;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node)
+ count++;
+
+ return count;
+}
+
+int device_find_child_by_seq(const struct udevice *parent, int seq,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ *devp = NULL;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ if (dev->seq_ == seq) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int device_get_child_by_seq(const struct udevice *parent, int seq,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = device_find_child_by_seq(parent, seq, &dev);
+
+ return device_get_device_tail(dev, ret, devp);
+}
+
+int device_find_child_by_of_offset(const struct udevice *parent, int of_offset,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ *devp = NULL;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ if (dev_of_offset(dev) == of_offset) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int device_get_child_by_of_offset(const struct udevice *parent, int node,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = device_find_child_by_of_offset(parent, node, &dev);
+ return device_get_device_tail(dev, ret, devp);
+}
+
+static struct udevice *_device_find_global_by_ofnode(struct udevice *parent,
+ ofnode ofnode)
+{
+ struct udevice *dev, *found;
+
+ if (ofnode_equal(dev_ofnode(parent), ofnode))
+ return parent;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ found = _device_find_global_by_ofnode(dev, ofnode);
+ if (found)
+ return found;
+ }
+
+ return NULL;
+}
+
+int device_find_global_by_ofnode(ofnode ofnode, struct udevice **devp)
+{
+ *devp = _device_find_global_by_ofnode(gd->dm_root, ofnode);
+
+ return *devp ? 0 : -ENOENT;
+}
+
+int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ dev = _device_find_global_by_ofnode(gd->dm_root, ofnode);
+ return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
+}
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+int device_get_by_ofplat_idx(uint idx, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+ struct udevice *base = ll_entry_start(struct udevice, udevice);
+
+ dev = base + idx;
+ } else {
+ struct driver_rt *drt = gd_dm_driver_rt() + idx;
+
+ dev = drt->dev;
+ }
+ *devp = NULL;
+
+ return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
+}
+#endif
+
+int device_find_first_child(const struct udevice *parent, struct udevice **devp)
+{
+ if (list_empty(&parent->child_head)) {
+ *devp = NULL;
+ } else {
+ *devp = list_first_entry(&parent->child_head, struct udevice,
+ sibling_node);
+ }
+
+ return 0;
+}
+
+int device_find_next_child(struct udevice **devp)
+{
+ struct udevice *dev = *devp;
+ struct udevice *parent = dev->parent;
+
+ if (list_is_last(&dev->sibling_node, &parent->child_head)) {
+ *devp = NULL;
+ } else {
+ *devp = list_entry(dev->sibling_node.next, struct udevice,
+ sibling_node);
+ }
+
+ return 0;
+}
+
+int device_find_first_inactive_child(const struct udevice *parent,
+ enum uclass_id uclass_id,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ *devp = NULL;
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ if (!device_active(dev) &&
+ device_get_uclass_id(dev) == uclass_id) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int device_find_first_child_by_uclass(const struct udevice *parent,
+ enum uclass_id uclass_id,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ *devp = NULL;
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ if (device_get_uclass_id(dev) == uclass_id) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int device_find_child_by_name(const struct udevice *parent, const char *name,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ *devp = NULL;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ if (!strcmp(dev->name, name)) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int device_first_child_err(struct udevice *parent, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ device_find_first_child(parent, &dev);
+ if (!dev)
+ return -ENODEV;
+
+ return device_get_device_tail(dev, 0, devp);
+}
+
+int device_next_child_err(struct udevice **devp)
+{
+ struct udevice *dev = *devp;
+
+ device_find_next_child(&dev);
+ if (!dev)
+ return -ENODEV;
+
+ return device_get_device_tail(dev, 0, devp);
+}
+
+int device_first_child_ofdata_err(struct udevice *parent, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ device_find_first_child(parent, &dev);
+ if (!dev)
+ return -ENODEV;
+
+ ret = device_of_to_plat(dev);
+ if (ret)
+ return ret;
+
+ *devp = dev;
+
+ return 0;
+}
+
+int device_next_child_ofdata_err(struct udevice **devp)
+{
+ struct udevice *dev = *devp;
+ int ret;
+
+ device_find_next_child(&dev);
+ if (!dev)
+ return -ENODEV;
+
+ ret = device_of_to_plat(dev);
+ if (ret)
+ return ret;
+
+ *devp = dev;
+
+ return 0;
+}
+
+struct udevice *dev_get_parent(const struct udevice *child)
+{
+ return child->parent;
+}
+
+ulong dev_get_driver_data(const struct udevice *dev)
+{
+ return dev->driver_data;
+}
+
+const void *dev_get_driver_ops(const struct udevice *dev)
+{
+ if (!dev || !dev->driver->ops)
+ return NULL;
+
+ return dev->driver->ops;
+}
+
+enum uclass_id device_get_uclass_id(const struct udevice *dev)
+{
+ return dev->uclass->uc_drv->id;
+}
+
+const char *dev_get_uclass_name(const struct udevice *dev)
+{
+ if (!dev)
+ return NULL;
+
+ return dev->uclass->uc_drv->name;
+}
+
+bool device_has_children(const struct udevice *dev)
+{
+ return !list_empty(&dev->child_head);
+}
+
+bool device_has_active_children(const struct udevice *dev)
+{
+ struct udevice *child;
+
+ for (device_find_first_child(dev, &child);
+ child;
+ device_find_next_child(&child)) {
+ if (device_active(child))
+ return true;
+ }
+
+ return false;
+}
+
+bool device_is_last_sibling(const struct udevice *dev)
+{
+ struct udevice *parent = dev->parent;
+
+ if (!parent)
+ return false;
+ return list_is_last(&dev->sibling_node, &parent->child_head);
+}
+
+void device_set_name_alloced(struct udevice *dev)
+{
+ dev_or_flags(dev, DM_FLAG_NAME_ALLOCED);
+}
+
+int device_set_name(struct udevice *dev, const char *name)
+{
+ name = strdup(name);
+ if (!name)
+ return -ENOMEM;
+ dev->name = name;
+ device_set_name_alloced(dev);
+
+ return 0;
+}
+
+void dev_set_priv(struct udevice *dev, void *priv)
+{
+ dev->priv_ = priv;
+}
+
+void dev_set_parent_priv(struct udevice *dev, void *parent_priv)
+{
+ dev->parent_priv_ = parent_priv;
+}
+
+void dev_set_uclass_priv(struct udevice *dev, void *uclass_priv)
+{
+ dev->uclass_priv_ = uclass_priv;
+}
+
+void dev_set_plat(struct udevice *dev, void *plat)
+{
+ dev->plat_ = plat;
+}
+
+void dev_set_parent_plat(struct udevice *dev, void *parent_plat)
+{
+ dev->parent_plat_ = parent_plat;
+}
+
+void dev_set_uclass_plat(struct udevice *dev, void *uclass_plat)
+{
+ dev->uclass_plat_ = uclass_plat;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+bool device_is_compatible(const struct udevice *dev, const char *compat)
+{
+ return ofnode_device_is_compatible(dev_ofnode(dev), compat);
+}
+
+bool of_machine_is_compatible(const char *compat)
+{
+ const void *fdt = gd->fdt_blob;
+
+ return !fdt_node_check_compatible(fdt, 0, compat);
+}
+
+int dev_disable_by_path(const char *path)
+{
+ struct uclass *uc;
+ ofnode node = ofnode_path(path);
+ struct udevice *dev;
+ int ret = 1;
+
+ if (!of_live_active())
+ return -ENOSYS;
+
+ list_for_each_entry(uc, gd->uclass_root, sibling_node) {
+ ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node, &dev);
+ if (!ret)
+ break;
+ }
+
+ if (ret)
+ return ret;
+
+ ret = device_remove(dev, DM_REMOVE_NORMAL);
+ if (ret)
+ return ret;
+
+ ret = device_unbind(dev);
+ if (ret)
+ return ret;
+
+ return ofnode_set_enabled(node, false);
+}
+
+int dev_enable_by_path(const char *path)
+{
+ ofnode node = ofnode_path(path);
+ ofnode pnode = ofnode_get_parent(node);
+ struct udevice *parent;
+ int ret = 1;
+
+ if (!of_live_active())
+ return -ENOSYS;
+
+ ret = device_find_by_ofnode(pnode, &parent);
+ if (ret)
+ return ret;
+
+ ret = ofnode_set_enabled(node, true);
+ if (ret)
+ return ret;
+
+ return lists_bind_fdt(parent, node, NULL, false);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
+static struct udevice_rt *dev_get_rt(const struct udevice *dev)
+{
+ struct udevice *base = ll_entry_start(struct udevice, udevice);
+ int idx = dev - base;
+
+ struct udevice_rt *urt = gd_dm_udevice_rt() + idx;
+
+ return urt;
+}
+
+u32 dev_get_flags(const struct udevice *dev)
+{
+ const struct udevice_rt *urt = dev_get_rt(dev);
+
+ return urt->flags_;
+}
+
+void dev_or_flags(const struct udevice *dev, u32 or)
+{
+ struct udevice_rt *urt = dev_get_rt(dev);
+
+ urt->flags_ |= or;
+}
+
+void dev_bic_flags(const struct udevice *dev, u32 bic)
+{
+ struct udevice_rt *urt = dev_get_rt(dev);
+
+ urt->flags_ &= ~bic;
+}
+#endif /* OF_PLATDATA_RT */
diff --git a/roms/u-boot/drivers/core/devres.c b/roms/u-boot/drivers/core/devres.c
new file mode 100644
index 000000000..313ddc708
--- /dev/null
+++ b/roms/u-boot/drivers/core/devres.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * Based on the original work in Linux by
+ * Copyright (c) 2006 SUSE Linux Products GmbH
+ * Copyright (c) 2006 Tejun Heo <teheo@suse.de>
+ */
+
+#define LOG_CATEGORY LOGC_DEVRES
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/compat.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <dm/device.h>
+#include <dm/devres.h>
+#include <dm/root.h>
+#include <dm/util.h>
+
+/** enum devres_phase - Shows where resource was allocated
+ *
+ * DEVRES_PHASE_BIND: In the bind() method
+ * DEVRES_PHASE_OFDATA: In the of_to_plat() method
+ * DEVRES_PHASE_PROBE: In the probe() method
+ */
+enum devres_phase {
+ DEVRES_PHASE_BIND,
+ DEVRES_PHASE_OFDATA,
+ DEVRES_PHASE_PROBE,
+};
+
+/**
+ * struct devres - Bookkeeping info for managed device resource
+ * @entry: List to associate this structure with a device
+ * @release: Callback invoked when this resource is released
+ * @probe: Show where this resource was allocated
+ * @name: Name of release function
+ * @size: Size of resource data
+ * @data: Resource data
+ */
+struct devres {
+ struct list_head entry;
+ dr_release_t release;
+ enum devres_phase phase;
+#ifdef CONFIG_DEBUG_DEVRES
+ const char *name;
+ size_t size;
+#endif
+ unsigned long long data[];
+};
+
+#ifdef CONFIG_DEBUG_DEVRES
+static void set_node_dbginfo(struct devres *dr, const char *name, size_t size)
+{
+ dr->name = name;
+ dr->size = size;
+}
+
+static void devres_log(struct udevice *dev, struct devres *dr,
+ const char *op)
+{
+ log_debug("%s: DEVRES %3s %p %s (%lu bytes)\n", dev->name, op, dr,
+ dr->name, (unsigned long)dr->size);
+}
+#else /* CONFIG_DEBUG_DEVRES */
+#define set_node_dbginfo(dr, n, s) do {} while (0)
+#define devres_log(dev, dr, op) do {} while (0)
+#endif
+
+#if CONFIG_DEBUG_DEVRES
+void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
+ const char *name)
+#else
+void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
+#endif
+{
+ size_t tot_size = sizeof(struct devres) + size;
+ struct devres *dr;
+
+ dr = kmalloc(tot_size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+
+ INIT_LIST_HEAD(&dr->entry);
+ dr->release = release;
+ set_node_dbginfo(dr, name, size);
+
+ return dr->data;
+}
+
+void devres_free(void *res)
+{
+ if (res) {
+ struct devres *dr = container_of(res, struct devres, data);
+
+ assert_noisy(list_empty(&dr->entry));
+ kfree(dr);
+ }
+}
+
+void devres_add(struct udevice *dev, void *res)
+{
+ struct devres *dr = container_of(res, struct devres, data);
+
+ devres_log(dev, dr, "ADD");
+ assert_noisy(list_empty(&dr->entry));
+ if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
+ dr->phase = DEVRES_PHASE_PROBE;
+ else if (dev_get_flags(dev) & DM_FLAG_BOUND)
+ dr->phase = DEVRES_PHASE_OFDATA;
+ else
+ dr->phase = DEVRES_PHASE_BIND;
+ list_add_tail(&dr->entry, &dev->devres_head);
+}
+
+void *devres_find(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ struct devres *dr;
+
+ list_for_each_entry_reverse(dr, &dev->devres_head, entry) {
+ if (dr->release != release)
+ continue;
+ if (match && !match(dev, dr->data, match_data))
+ continue;
+ return dr->data;
+ }
+
+ return NULL;
+}
+
+void *devres_get(struct udevice *dev, void *new_res,
+ dr_match_t match, void *match_data)
+{
+ struct devres *new_dr = container_of(new_res, struct devres, data);
+ void *res;
+
+ res = devres_find(dev, new_dr->release, match, match_data);
+ if (!res) {
+ devres_add(dev, new_res);
+ res = new_res;
+ new_res = NULL;
+ }
+ devres_free(new_res);
+
+ return res;
+}
+
+void *devres_remove(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_find(dev, release, match, match_data);
+ if (res) {
+ struct devres *dr = container_of(res, struct devres, data);
+
+ list_del_init(&dr->entry);
+ devres_log(dev, dr, "REM");
+ }
+
+ return res;
+}
+
+int devres_destroy(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_remove(dev, release, match, match_data);
+ if (unlikely(!res))
+ return -ENOENT;
+
+ devres_free(res);
+ return 0;
+}
+
+int devres_release(struct udevice *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_remove(dev, release, match, match_data);
+ if (unlikely(!res))
+ return -ENOENT;
+
+ (*release)(dev, res);
+ devres_free(res);
+ return 0;
+}
+
+static void release_nodes(struct udevice *dev, struct list_head *head,
+ bool probe_and_ofdata_only)
+{
+ struct devres *dr, *tmp;
+
+ list_for_each_entry_safe_reverse(dr, tmp, head, entry) {
+ if (probe_and_ofdata_only && dr->phase == DEVRES_PHASE_BIND)
+ break;
+ devres_log(dev, dr, "REL");
+ dr->release(dev, dr->data);
+ list_del(&dr->entry);
+ kfree(dr);
+ }
+}
+
+void devres_release_probe(struct udevice *dev)
+{
+ release_nodes(dev, &dev->devres_head, true);
+}
+
+void devres_release_all(struct udevice *dev)
+{
+ release_nodes(dev, &dev->devres_head, false);
+}
+
+#ifdef CONFIG_DEBUG_DEVRES
+static char *const devres_phase_name[] = {"BIND", "OFDATA", "PROBE"};
+
+static void dump_resources(struct udevice *dev, int depth)
+{
+ struct devres *dr;
+ struct udevice *child;
+
+ printf("- %s\n", dev->name);
+
+ list_for_each_entry(dr, &dev->devres_head, entry)
+ printf(" %p (%lu byte) %s %s\n", dr,
+ (unsigned long)dr->size, dr->name,
+ devres_phase_name[dr->phase]);
+
+ list_for_each_entry(child, &dev->child_head, sibling_node)
+ dump_resources(child, depth + 1);
+}
+
+void dm_dump_devres(void)
+{
+ struct udevice *root;
+
+ root = dm_root();
+ if (root)
+ dump_resources(root, 0);
+}
+
+void devres_get_stats(const struct udevice *dev, struct devres_stats *stats)
+{
+ struct devres *dr;
+
+ stats->allocs = 0;
+ stats->total_size = 0;
+ list_for_each_entry(dr, &dev->devres_head, entry) {
+ stats->allocs++;
+ stats->total_size += dr->size;
+ }
+}
+
+#endif
+
+/*
+ * Managed kmalloc/kfree
+ */
+static void devm_kmalloc_release(struct udevice *dev, void *res)
+{
+ /* noop */
+}
+
+static int devm_kmalloc_match(struct udevice *dev, void *res, void *data)
+{
+ return res == data;
+}
+
+void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp)
+{
+ void *data;
+
+ data = _devres_alloc(devm_kmalloc_release, size, gfp);
+ if (unlikely(!data))
+ return NULL;
+
+ devres_add(dev, data);
+
+ return data;
+}
+
+void devm_kfree(struct udevice *dev, void *p)
+{
+ int rc;
+
+ rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p);
+ assert_noisy(!rc);
+}
diff --git a/roms/u-boot/drivers/core/dump.c b/roms/u-boot/drivers/core/dump.c
new file mode 100644
index 000000000..f8afea30a
--- /dev/null
+++ b/roms/u-boot/drivers/core/dump.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <dm/root.h>
+#include <dm/util.h>
+#include <dm/uclass-internal.h>
+
+static void show_devices(struct udevice *dev, int depth, int last_flag)
+{
+ int i, is_last;
+ struct udevice *child;
+ u32 flags = dev_get_flags(dev);
+
+ /* print the first 20 characters to not break the tree-format. */
+ printf(IS_ENABLED(CONFIG_SPL_BUILD) ? " %s %d [ %c ] %s " :
+ " %-10.10s %3d [ %c ] %-20.20s ", dev->uclass->uc_drv->name,
+ dev_get_uclass_index(dev, NULL),
+ flags & DM_FLAG_ACTIVATED ? '+' : ' ', dev->driver->name);
+
+ for (i = depth; i >= 0; i--) {
+ is_last = (last_flag >> i) & 1;
+ if (i) {
+ if (is_last)
+ printf(" ");
+ else
+ printf("| ");
+ } else {
+ if (is_last)
+ printf("`-- ");
+ else
+ printf("|-- ");
+ }
+ }
+
+ printf("%s\n", dev->name);
+
+ list_for_each_entry(child, &dev->child_head, sibling_node) {
+ is_last = list_is_last(&child->sibling_node, &dev->child_head);
+ show_devices(child, depth + 1, (last_flag << 1) | is_last);
+ }
+}
+
+void dm_dump_all(void)
+{
+ struct udevice *root;
+
+ root = dm_root();
+ if (root) {
+ printf(" Class Index Probed Driver Name\n");
+ printf("-----------------------------------------------------------\n");
+ show_devices(root, -1, 0);
+ }
+}
+
+/**
+ * dm_display_line() - Display information about a single device
+ *
+ * Displays a single line of information with an option prefix
+ *
+ * @dev: Device to display
+ */
+static void dm_display_line(struct udevice *dev, int index)
+{
+ printf("%-3i %c %s @ %08lx", index,
+ dev_get_flags(dev) & DM_FLAG_ACTIVATED ? '*' : ' ',
+ dev->name, (ulong)map_to_sysmem(dev));
+ if (dev->seq_ != -1)
+ printf(", seq %d", dev_seq(dev));
+ puts("\n");
+}
+
+void dm_dump_uclass(void)
+{
+ struct uclass *uc;
+ int ret;
+ int id;
+
+ for (id = 0; id < UCLASS_COUNT; id++) {
+ struct udevice *dev;
+ int i = 0;
+
+ ret = uclass_get(id, &uc);
+ if (ret)
+ continue;
+
+ printf("uclass %d: %s\n", id, uc->uc_drv->name);
+ if (list_empty(&uc->dev_head))
+ continue;
+ uclass_foreach_dev(dev, uc) {
+ dm_display_line(dev, i);
+ i++;
+ }
+ puts("\n");
+ }
+}
+
+void dm_dump_driver_compat(void)
+{
+ struct driver *d = ll_entry_start(struct driver, driver);
+ const int n_ents = ll_entry_count(struct driver, driver);
+ struct driver *entry;
+ const struct udevice_id *match;
+
+ puts("Driver Compatible\n");
+ puts("--------------------------------\n");
+ for (entry = d; entry < d + n_ents; entry++) {
+ match = entry->of_match;
+
+ printf("%-20.20s", entry->name);
+ if (match) {
+ printf(" %s", match->compatible);
+ match++;
+ }
+ printf("\n");
+
+ for (; match && match->compatible; match++)
+ printf("%-20.20s %s\n", "", match->compatible);
+ }
+}
+
+void dm_dump_drivers(void)
+{
+ struct driver *d = ll_entry_start(struct driver, driver);
+ const int n_ents = ll_entry_count(struct driver, driver);
+ struct driver *entry;
+ struct udevice *udev;
+ struct uclass *uc;
+ int i;
+
+ puts("Driver uid uclass Devices\n");
+ puts("----------------------------------------------------------\n");
+
+ for (entry = d; entry < d + n_ents; entry++) {
+ uclass_get(entry->id, &uc);
+
+ printf("%-25.25s %-3.3d %-20.20s ", entry->name, entry->id,
+ uc ? uc->uc_drv->name : "<no uclass>");
+
+ if (!uc) {
+ puts("\n");
+ continue;
+ }
+
+ i = 0;
+ uclass_foreach_dev(udev, uc) {
+ if (udev->driver != entry)
+ continue;
+ if (i)
+ printf("%-51.51s", "");
+
+ printf("%-25.25s\n", udev->name);
+ i++;
+ }
+ if (!i)
+ puts("<none>\n");
+ }
+}
+
+void dm_dump_static_driver_info(void)
+{
+ struct driver_info *drv = ll_entry_start(struct driver_info,
+ driver_info);
+ const int n_ents = ll_entry_count(struct driver_info, driver_info);
+ struct driver_info *entry;
+
+ puts("Driver Address\n");
+ puts("---------------------------------\n");
+ for (entry = drv; entry != drv + n_ents; entry++) {
+ printf("%-25.25s @%08lx\n", entry->name,
+ (ulong)map_to_sysmem(entry->plat));
+ }
+}
diff --git a/roms/u-boot/drivers/core/fdtaddr.c b/roms/u-boot/drivers/core/fdtaddr.c
new file mode 100644
index 000000000..b9874c743
--- /dev/null
+++ b/roms/u-boot/drivers/core/fdtaddr.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Device addresses
+ *
+ * Copyright (c) 2017 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ fdt_addr_t addr;
+
+ if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
+ const fdt32_t *reg;
+ int len = 0;
+ int na, ns;
+
+ na = fdt_address_cells(gd->fdt_blob,
+ dev_of_offset(dev->parent));
+ if (na < 1) {
+ debug("bad #address-cells\n");
+ return FDT_ADDR_T_NONE;
+ }
+
+ ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
+ if (ns < 0) {
+ debug("bad #size-cells\n");
+ return FDT_ADDR_T_NONE;
+ }
+
+ reg = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "reg",
+ &len);
+ if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) {
+ debug("Req index out of range\n");
+ return FDT_ADDR_T_NONE;
+ }
+
+ reg += index * (na + ns);
+
+ if (ns) {
+ /*
+ * Use the full-fledged translate function for complex
+ * bus setups.
+ */
+ addr = fdt_translate_address((void *)gd->fdt_blob,
+ dev_of_offset(dev), reg);
+ } else {
+ /* Non translatable if #size-cells == 0 */
+ addr = fdt_read_number(reg, na);
+ }
+ } else {
+ /*
+ * Use the "simple" translate function for less complex
+ * bus setups.
+ */
+ addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
+ dev_of_offset(dev->parent), dev_of_offset(dev),
+ "reg", index, NULL, false);
+ if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) {
+ if (device_get_uclass_id(dev->parent) ==
+ UCLASS_SIMPLE_BUS)
+ addr = simple_bus_translate(dev->parent, addr);
+ }
+ }
+
+#if defined(CONFIG_TRANSLATION_OFFSET)
+ /*
+ * Some platforms need a special address translation. Those
+ * platforms (e.g. mvebu in SPL) can configure a translation
+ * offset by setting this value in the GD and enaling this
+ * feature via CONFIG_TRANSLATION_OFFSET. This value will
+ * get added to all addresses returned by devfdt_get_addr().
+ */
+ addr += gd->translation_offset;
+#endif
+
+ return addr;
+#else
+ return FDT_ADDR_T_NONE;
+#endif
+}
+
+fdt_addr_t devfdt_get_addr_size_index(const struct udevice *dev, int index,
+ fdt_size_t *size)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ /*
+ * Only get the size in this first call. We'll get the addr in the
+ * next call to the exisiting dev_get_xxx function which handles
+ * all config options.
+ */
+ fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev),
+ "reg", index, size, false);
+
+ /*
+ * Get the base address via the existing function which handles
+ * all Kconfig cases
+ */
+ return devfdt_get_addr_index(dev, index);
+#else
+ return FDT_ADDR_T_NONE;
+#endif
+}
+
+fdt_addr_t devfdt_get_addr_name(const struct udevice *dev, const char *name)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ int index;
+
+ index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
+ "reg-names", name);
+ if (index < 0)
+ return index;
+
+ return devfdt_get_addr_index(dev, index);
+#else
+ return FDT_ADDR_T_NONE;
+#endif
+}
+
+fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev,
+ const char *name, fdt_size_t *size)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ int index;
+
+ index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
+ "reg-names", name);
+ if (index < 0)
+ return index;
+
+ return devfdt_get_addr_size_index(dev, index, size);
+#else
+ return FDT_ADDR_T_NONE;
+#endif
+}
+
+fdt_addr_t devfdt_get_addr(const struct udevice *dev)
+{
+ return devfdt_get_addr_index(dev, 0);
+}
+
+void *devfdt_get_addr_ptr(const struct udevice *dev)
+{
+ fdt_addr_t addr = devfdt_get_addr_index(dev, 0);
+
+ return (addr == FDT_ADDR_T_NONE) ? NULL : (void *)(uintptr_t)addr;
+}
+
+void *devfdt_remap_addr_index(const struct udevice *dev, int index)
+{
+ fdt_addr_t addr = devfdt_get_addr_index(dev, index);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_physmem(addr, 0, MAP_NOCACHE);
+}
+
+void *devfdt_remap_addr_name(const struct udevice *dev, const char *name)
+{
+ fdt_addr_t addr = devfdt_get_addr_name(dev, name);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_physmem(addr, 0, MAP_NOCACHE);
+}
+
+void *devfdt_remap_addr(const struct udevice *dev)
+{
+ return devfdt_remap_addr_index(dev, 0);
+}
+
+void *devfdt_map_physmem(const struct udevice *dev, unsigned long size)
+{
+ fdt_addr_t addr = devfdt_get_addr(dev);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_physmem(addr, size, MAP_NOCACHE);
+}
+
+fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev)
+{
+ ulong addr;
+
+ addr = devfdt_get_addr(dev);
+ if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) &&
+ addr == FDT_ADDR_T_NONE) {
+ struct fdt_pci_addr pci_addr;
+ u32 bar;
+ int ret;
+
+ ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32,
+ "reg", &pci_addr);
+ if (ret) {
+ /* try if there is any i/o-mapped register */
+ ret = ofnode_read_pci_addr(dev_ofnode(dev),
+ FDT_PCI_SPACE_IO, "reg",
+ &pci_addr);
+ if (ret)
+ return FDT_ADDR_T_NONE;
+ }
+ ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
+ if (ret)
+ return FDT_ADDR_T_NONE;
+ addr = bar;
+ }
+
+ return addr;
+}
diff --git a/roms/u-boot/drivers/core/lists.c b/roms/u-boot/drivers/core/lists.c
new file mode 100644
index 000000000..e214306b9
--- /dev/null
+++ b/roms/u-boot/drivers/core/lists.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Marek Vasut <marex@denx.de>
+ */
+
+#define LOG_CATEGORY LOGC_DM
+
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/platdata.h>
+#include <dm/uclass.h>
+#include <dm/util.h>
+#include <fdtdec.h>
+#include <linux/compiler.h>
+
+struct driver *lists_driver_lookup_name(const char *name)
+{
+ struct driver *drv =
+ ll_entry_start(struct driver, driver);
+ const int n_ents = ll_entry_count(struct driver, driver);
+ struct driver *entry;
+
+ for (entry = drv; entry != drv + n_ents; entry++) {
+ if (!strcmp(name, entry->name))
+ return entry;
+ }
+
+ /* Not found */
+ return NULL;
+}
+
+struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
+{
+ struct uclass_driver *uclass =
+ ll_entry_start(struct uclass_driver, uclass_driver);
+ const int n_ents = ll_entry_count(struct uclass_driver, uclass_driver);
+ struct uclass_driver *entry;
+
+ for (entry = uclass; entry != uclass + n_ents; entry++) {
+ if (entry->id == id)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static int bind_drivers_pass(struct udevice *parent, bool pre_reloc_only)
+{
+ struct driver_info *info =
+ ll_entry_start(struct driver_info, driver_info);
+ const int n_ents = ll_entry_count(struct driver_info, driver_info);
+ bool missing_parent = false;
+ int result = 0;
+ uint idx;
+
+ /*
+ * Do one iteration through the driver_info records. For of-platdata,
+ * bind only devices whose parent is already bound. If we find any
+ * device we can't bind, set missing_parent to true, which will cause
+ * this function to be called again.
+ */
+ for (idx = 0; idx < n_ents; idx++) {
+ struct udevice *par = parent;
+ const struct driver_info *entry = info + idx;
+ struct driver_rt *drt = gd_dm_driver_rt() + idx;
+ struct udevice *dev;
+ int ret;
+
+ if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ int parent_idx = driver_info_parent_id(entry);
+
+ if (drt->dev)
+ continue;
+
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_PARENT) &&
+ parent_idx != -1) {
+ struct driver_rt *parent_drt;
+
+ parent_drt = gd_dm_driver_rt() + parent_idx;
+ if (!parent_drt->dev) {
+ missing_parent = true;
+ continue;
+ }
+
+ par = parent_drt->dev;
+ }
+ }
+ ret = device_bind_by_name(par, pre_reloc_only, entry, &dev);
+ if (!ret) {
+ if (CONFIG_IS_ENABLED(OF_PLATDATA))
+ drt->dev = dev;
+ } else if (ret != -EPERM) {
+ dm_warn("No match for driver '%s'\n", entry->name);
+ if (!result || ret != -ENOENT)
+ result = ret;
+ }
+ }
+
+ return result ? result : missing_parent ? -EAGAIN : 0;
+}
+
+int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
+{
+ int result = 0;
+ int pass;
+
+ /*
+ * 10 passes is 10 levels deep in the devicetree, which is plenty. If
+ * OF_PLATDATA_PARENT is not enabled, then bind_drivers_pass() will
+ * always succeed on the first pass.
+ */
+ for (pass = 0; pass < 10; pass++) {
+ int ret;
+
+ ret = bind_drivers_pass(parent, pre_reloc_only);
+ if (!ret)
+ break;
+ if (ret != -EAGAIN && !result)
+ result = ret;
+ }
+
+ return result;
+}
+
+int device_bind_driver(struct udevice *parent, const char *drv_name,
+ const char *dev_name, struct udevice **devp)
+{
+ return device_bind_driver_to_node(parent, drv_name, dev_name,
+ ofnode_null(), devp);
+}
+
+int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
+ const char *dev_name, ofnode node,
+ struct udevice **devp)
+{
+ struct driver *drv;
+ int ret;
+
+ drv = lists_driver_lookup_name(drv_name);
+ if (!drv) {
+ debug("Cannot find driver '%s'\n", drv_name);
+ return -ENOENT;
+ }
+ ret = device_bind_with_driver_data(parent, drv, dev_name, 0 /* data */,
+ node, devp);
+
+ return ret;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+/**
+ * driver_check_compatible() - Check if a driver matches a compatible string
+ *
+ * @param of_match: List of compatible strings to match
+ * @param of_idp: Returns the match that was found
+ * @param compat: The compatible string to search for
+ * @return 0 if there is a match, -ENOENT if no match
+ */
+static int driver_check_compatible(const struct udevice_id *of_match,
+ const struct udevice_id **of_idp,
+ const char *compat)
+{
+ if (!of_match)
+ return -ENOENT;
+
+ while (of_match->compatible) {
+ if (!strcmp(of_match->compatible, compat)) {
+ *of_idp = of_match;
+ return 0;
+ }
+ of_match++;
+ }
+
+ return -ENOENT;
+}
+
+int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
+ bool pre_reloc_only)
+{
+ struct driver *driver = ll_entry_start(struct driver, driver);
+ const int n_ents = ll_entry_count(struct driver, driver);
+ const struct udevice_id *id;
+ struct driver *entry;
+ struct udevice *dev;
+ bool found = false;
+ const char *name, *compat_list, *compat;
+ int compat_length, i;
+ int result = 0;
+ int ret = 0;
+
+ if (devp)
+ *devp = NULL;
+ name = ofnode_get_name(node);
+ log_debug("bind node %s\n", name);
+
+ compat_list = ofnode_get_property(node, "compatible", &compat_length);
+ if (!compat_list) {
+ if (compat_length == -FDT_ERR_NOTFOUND) {
+ log_debug("Device '%s' has no compatible string\n",
+ name);
+ return 0;
+ }
+
+ dm_warn("Device tree error at node '%s'\n", name);
+ return compat_length;
+ }
+
+ /*
+ * Walk through the compatible string list, attempting to match each
+ * compatible string in order such that we match in order of priority
+ * from the first string to the last.
+ */
+ for (i = 0; i < compat_length; i += strlen(compat) + 1) {
+ compat = compat_list + i;
+ log_debug(" - attempt to match compatible string '%s'\n",
+ compat);
+
+ for (entry = driver; entry != driver + n_ents; entry++) {
+ ret = driver_check_compatible(entry->of_match, &id,
+ compat);
+ if (!ret)
+ break;
+ }
+ if (entry == driver + n_ents)
+ continue;
+
+ if (pre_reloc_only) {
+ if (!ofnode_pre_reloc(node) &&
+ !(entry->flags & DM_FLAG_PRE_RELOC)) {
+ log_debug("Skipping device pre-relocation\n");
+ return 0;
+ }
+ }
+
+ log_debug(" - found match at '%s': '%s' matches '%s'\n",
+ entry->name, entry->of_match->compatible,
+ id->compatible);
+ ret = device_bind_with_driver_data(parent, entry, name,
+ id->data, node, &dev);
+ if (ret == -ENODEV) {
+ log_debug("Driver '%s' refuses to bind\n", entry->name);
+ continue;
+ }
+ if (ret) {
+ dm_warn("Error binding driver '%s': %d\n", entry->name,
+ ret);
+ return log_msg_ret("bind", ret);
+ } else {
+ found = true;
+ if (devp)
+ *devp = dev;
+ }
+ break;
+ }
+
+ if (!found && !result && ret != -ENODEV)
+ log_debug("No match for node '%s'\n", name);
+
+ return result;
+}
+#endif
diff --git a/roms/u-boot/drivers/core/of_access.c b/roms/u-boot/drivers/core/of_access.c
new file mode 100644
index 000000000..9960e6b31
--- /dev/null
+++ b/roms/u-boot/drivers/core/of_access.c
@@ -0,0 +1,882 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Originally from Linux v4.9
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
+ * Grant Likely.
+ *
+ * Modified for U-Boot
+ * Copyright (c) 2017 Google, Inc
+ *
+ * This file follows drivers/of/base.c with functions in the same order as the
+ * Linux version.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <linux/bug.h>
+#include <linux/libfdt.h>
+#include <dm/of_access.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* list of struct alias_prop aliases */
+LIST_HEAD(aliases_lookup);
+
+/* "/aliaes" node */
+static struct device_node *of_aliases;
+
+/* "/chosen" node */
+static struct device_node *of_chosen;
+
+/* node pointed to by the stdout-path alias */
+static struct device_node *of_stdout;
+
+/* pointer to options given after the alias (separated by :) or NULL if none */
+static const char *of_stdout_options;
+
+/**
+ * struct alias_prop - Alias property in 'aliases' node
+ *
+ * The structure represents one alias property of 'aliases' node as
+ * an entry in aliases_lookup list.
+ *
+ * @link: List node to link the structure in aliases_lookup list
+ * @alias: Alias property name
+ * @np: Pointer to device_node that the alias stands for
+ * @id: Index value from end of alias name
+ * @stem: Alias string without the index
+ */
+struct alias_prop {
+ struct list_head link;
+ const char *alias;
+ struct device_node *np;
+ int id;
+ char stem[0];
+};
+
+int of_n_addr_cells(const struct device_node *np)
+{
+ const __be32 *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#address-cells", NULL);
+ if (ip)
+ return be32_to_cpup(ip);
+ } while (np->parent);
+
+ /* No #address-cells property for the root node */
+ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+
+int of_n_size_cells(const struct device_node *np)
+{
+ const __be32 *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#size-cells", NULL);
+ if (ip)
+ return be32_to_cpup(ip);
+ } while (np->parent);
+
+ /* No #size-cells property for the root node */
+ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+
+int of_simple_addr_cells(const struct device_node *np)
+{
+ const __be32 *ip;
+
+ ip = of_get_property(np, "#address-cells", NULL);
+ if (ip)
+ return be32_to_cpup(ip);
+
+ /* Return a default of 2 to match fdt_address_cells()*/
+ return 2;
+}
+
+int of_simple_size_cells(const struct device_node *np)
+{
+ const __be32 *ip;
+
+ ip = of_get_property(np, "#size-cells", NULL);
+ if (ip)
+ return be32_to_cpup(ip);
+
+ /* Return a default of 2 to match fdt_size_cells()*/
+ return 2;
+}
+
+struct property *of_find_property(const struct device_node *np,
+ const char *name, int *lenp)
+{
+ struct property *pp;
+
+ if (!np)
+ return NULL;
+
+ for (pp = np->properties; pp; pp = pp->next) {
+ if (strcmp(pp->name, name) == 0) {
+ if (lenp)
+ *lenp = pp->length;
+ break;
+ }
+ }
+ if (!pp && lenp)
+ *lenp = -FDT_ERR_NOTFOUND;
+
+ return pp;
+}
+
+struct device_node *of_find_all_nodes(struct device_node *prev)
+{
+ struct device_node *np;
+
+ if (!prev) {
+ np = gd->of_root;
+ } else if (prev->child) {
+ np = prev->child;
+ } else {
+ /*
+ * Walk back up looking for a sibling, or the end of the
+ * structure
+ */
+ np = prev;
+ while (np->parent && !np->sibling)
+ np = np->parent;
+ np = np->sibling; /* Might be null at the end of the tree */
+ }
+
+ return np;
+}
+
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
+{
+ struct property *pp = of_find_property(np, name, lenp);
+
+ return pp ? pp->value : NULL;
+}
+
+const struct property *of_get_first_property(const struct device_node *np)
+{
+ if (!np)
+ return NULL;
+
+ return np->properties;
+}
+
+const struct property *of_get_next_property(const struct device_node *np,
+ const struct property *property)
+{
+ if (!np)
+ return NULL;
+
+ return property->next;
+}
+
+const void *of_get_property_by_prop(const struct device_node *np,
+ const struct property *property,
+ const char **name,
+ int *lenp)
+{
+ if (!np || !property)
+ return NULL;
+ if (name)
+ *name = property->name;
+ if (lenp)
+ *lenp = property->length;
+
+ return property->value;
+}
+
+static const char *of_prop_next_string(struct property *prop, const char *cur)
+{
+ const void *curv = cur;
+
+ if (!prop)
+ return NULL;
+
+ if (!cur)
+ return prop->value;
+
+ curv += strlen(cur) + 1;
+ if (curv >= prop->value + prop->length)
+ return NULL;
+
+ return curv;
+}
+
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat, const char *type,
+ const char *name)
+{
+ struct property *prop;
+ const char *cp;
+ int index = 0, score = 0;
+
+ /* Compatible match has highest priority */
+ if (compat && compat[0]) {
+ prop = of_find_property(device, "compatible", NULL);
+ for (cp = of_prop_next_string(prop, NULL); cp;
+ cp = of_prop_next_string(prop, cp), index++) {
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
+ score = INT_MAX/2 - (index << 2);
+ break;
+ }
+ }
+ if (!score)
+ return 0;
+ }
+
+ /* Matching type is better than matching name */
+ if (type && type[0]) {
+ if (!device->type || of_node_cmp(type, device->type))
+ return 0;
+ score += 2;
+ }
+
+ /* Matching name is a bit better than not */
+ if (name && name[0]) {
+ if (!device->name || of_node_cmp(name, device->name))
+ return 0;
+ score++;
+ }
+
+ return score;
+}
+
+bool of_device_is_available(const struct device_node *device)
+{
+ const char *status;
+ int statlen;
+
+ if (!device)
+ return false;
+
+ status = of_get_property(device, "status", &statlen);
+ if (status == NULL)
+ return true;
+
+ if (statlen > 0) {
+ if (!strcmp(status, "okay"))
+ return true;
+ }
+
+ return false;
+}
+
+struct device_node *of_get_parent(const struct device_node *node)
+{
+ const struct device_node *np;
+
+ if (!node)
+ return NULL;
+
+ np = of_node_get(node->parent);
+
+ return (struct device_node *)np;
+}
+
+static struct device_node *__of_get_next_child(const struct device_node *node,
+ struct device_node *prev)
+{
+ struct device_node *next;
+
+ if (!node)
+ return NULL;
+
+ next = prev ? prev->sibling : node->child;
+ /*
+ * coverity[dead_error_line : FALSE]
+ * Dead code here since our current implementation of of_node_get()
+ * always returns NULL (Coverity CID 163245). But we leave it as is
+ * since we may want to implement get/put later.
+ */
+ for (; next; next = next->sibling)
+ if (of_node_get(next))
+ break;
+ of_node_put(prev);
+ return next;
+}
+
+#define __for_each_child_of_node(parent, child) \
+ for (child = __of_get_next_child(parent, NULL); child != NULL; \
+ child = __of_get_next_child(parent, child))
+
+static struct device_node *__of_find_node_by_path(struct device_node *parent,
+ const char *path)
+{
+ struct device_node *child;
+ int len;
+
+ len = strcspn(path, "/:");
+ if (!len)
+ return NULL;
+
+ __for_each_child_of_node(parent, child) {
+ const char *name = strrchr(child->full_name, '/');
+
+ name++;
+ if (strncmp(path, name, len) == 0 && (strlen(name) == len))
+ return child;
+ }
+ return NULL;
+}
+
+#define for_each_property_of_node(dn, pp) \
+ for (pp = dn->properties; pp != NULL; pp = pp->next)
+
+struct device_node *of_find_node_opts_by_path(const char *path,
+ const char **opts)
+{
+ struct device_node *np = NULL;
+ struct property *pp;
+ const char *separator = strchr(path, ':');
+
+ if (opts)
+ *opts = separator ? separator + 1 : NULL;
+
+ if (strcmp(path, "/") == 0)
+ return of_node_get(gd->of_root);
+
+ /* The path could begin with an alias */
+ if (*path != '/') {
+ int len;
+ const char *p = separator;
+
+ if (!p)
+ p = strchrnul(path, '/');
+ len = p - path;
+
+ /* of_aliases must not be NULL */
+ if (!of_aliases)
+ return NULL;
+
+ for_each_property_of_node(of_aliases, pp) {
+ if (strlen(pp->name) == len && !strncmp(pp->name, path,
+ len)) {
+ np = of_find_node_by_path(pp->value);
+ break;
+ }
+ }
+ if (!np)
+ return NULL;
+ path = p;
+ }
+
+ /* Step down the tree matching path components */
+ if (!np)
+ np = of_node_get(gd->of_root);
+ while (np && *path == '/') {
+ struct device_node *tmp = np;
+
+ path++; /* Increment past '/' delimiter */
+ np = __of_find_node_by_path(np, path);
+ of_node_put(tmp);
+ path = strchrnul(path, '/');
+ if (separator && separator < path)
+ break;
+ }
+
+ return np;
+}
+
+struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compatible)
+{
+ struct device_node *np;
+
+ for_each_of_allnodes_from(from, np)
+ if (of_device_is_compatible(np, compatible, type, NULL) &&
+ of_node_get(np))
+ break;
+ of_node_put(from);
+
+ return np;
+}
+
+static int of_device_has_prop_value(const struct device_node *device,
+ const char *propname, const void *propval,
+ int proplen)
+{
+ struct property *prop = of_find_property(device, propname, NULL);
+
+ if (!prop || !prop->value || prop->length != proplen)
+ return 0;
+ return !memcmp(prop->value, propval, proplen);
+}
+
+struct device_node *of_find_node_by_prop_value(struct device_node *from,
+ const char *propname,
+ const void *propval, int proplen)
+{
+ struct device_node *np;
+
+ for_each_of_allnodes_from(from, np) {
+ if (of_device_has_prop_value(np, propname, propval, proplen) &&
+ of_node_get(np))
+ break;
+ }
+ of_node_put(from);
+
+ return np;
+}
+
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+ struct device_node *np;
+
+ if (!handle)
+ return NULL;
+
+ for_each_of_allnodes(np)
+ if (np->phandle == handle)
+ break;
+ (void)of_node_get(np);
+
+ return np;
+}
+
+/**
+ * of_find_property_value_of_size() - find property of given size
+ *
+ * Search for a property in a device node and validate the requested size.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @len: requested length of property value
+ *
+ * @return the property value 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.
+ */
+static void *of_find_property_value_of_size(const struct device_node *np,
+ const char *propname, u32 len)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!prop)
+ return ERR_PTR(-EINVAL);
+ if (!prop->value)
+ return ERR_PTR(-ENODATA);
+ if (len > prop->length)
+ return ERR_PTR(-EOVERFLOW);
+
+ return prop->value;
+}
+
+int of_read_u32(const struct device_node *np, const char *propname, u32 *outp)
+{
+ return of_read_u32_index(np, propname, 0, outp);
+}
+
+int of_read_u32_array(const struct device_node *np, const char *propname,
+ u32 *out_values, size_t sz)
+{
+ const __be32 *val;
+
+ 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);
+
+ debug("size %zd\n", sz);
+ while (sz--)
+ *out_values++ = be32_to_cpup(val++);
+
+ return 0;
+}
+
+int of_read_u32_index(const struct device_node *np, const char *propname,
+ int index, u32 *outp)
+{
+ const __be32 *val;
+
+ debug("%s: %s: ", __func__, propname);
+ if (!np)
+ return -EINVAL;
+
+ val = of_find_property_value_of_size(np, propname,
+ sizeof(*outp) * (index + 1));
+ if (IS_ERR(val)) {
+ debug("(not found)\n");
+ return PTR_ERR(val);
+ }
+
+ *outp = be32_to_cpup(val + index);
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
+int of_read_u64(const struct device_node *np, const char *propname, u64 *outp)
+{
+ const __be64 *val;
+
+ debug("%s: %s: ", __func__, propname);
+ if (!np)
+ return -EINVAL;
+ val = of_find_property_value_of_size(np, propname, sizeof(*outp));
+ if (IS_ERR(val)) {
+ debug("(not found)\n");
+ return PTR_ERR(val);
+ }
+
+ *outp = be64_to_cpup(val);
+ debug("%#llx (%lld)\n", (unsigned long long)*outp,
+ (unsigned long long)*outp);
+
+ return 0;
+}
+
+int of_property_match_string(const struct device_node *np, const char *propname,
+ const char *string)
+{
+ const struct property *prop = of_find_property(np, propname, NULL);
+ size_t l;
+ int i;
+ const char *p, *end;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ p = prop->value;
+ end = p + prop->length;
+
+ for (i = 0; p < end; i++, p += l) {
+ l = strnlen(p, end - p) + 1;
+ if (p + l > end)
+ return -EILSEQ;
+ debug("comparing %s with %s\n", string, p);
+ if (strcmp(string, p) == 0)
+ return i; /* Found it; return index */
+ }
+ return -ENODATA;
+}
+
+/**
+ * of_property_read_string_helper() - Utility helper for parsing string properties
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_strs: output array of string pointers.
+ * @sz: number of array elements to read.
+ * @skip: Number of strings to skip over at beginning of list.
+ *
+ * Don't call this function directly. It is a utility helper for the
+ * of_property_read_string*() family of functions.
+ */
+int of_property_read_string_helper(const struct device_node *np,
+ const char *propname, const char **out_strs,
+ size_t sz, int skip)
+{
+ const struct property *prop = of_find_property(np, propname, NULL);
+ int l = 0, i = 0;
+ const char *p, *end;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ p = prop->value;
+ end = p + prop->length;
+
+ for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
+ l = strnlen(p, end - p) + 1;
+ if (p + l > end)
+ return -EILSEQ;
+ if (out_strs && i >= skip)
+ *out_strs++ = p;
+ }
+ i -= skip;
+ return i <= 0 ? -ENODATA : i;
+}
+
+static int __of_parse_phandle_with_args(const struct device_node *np,
+ const char *list_name,
+ const char *cells_name,
+ int cell_count, int index,
+ struct of_phandle_args *out_args)
+{
+ const __be32 *list, *list_end;
+ int rc = 0, cur_index = 0;
+ uint32_t count;
+ struct device_node *node = NULL;
+ phandle phandle;
+ int size;
+
+ /* Retrieve the phandle list property */
+ list = of_get_property(np, list_name, &size);
+ if (!list)
+ return -ENOENT;
+ list_end = list + size / sizeof(*list);
+
+ /* Loop over the phandles until all the requested entry is found */
+ while (list < list_end) {
+ rc = -EINVAL;
+ count = 0;
+
+ /*
+ * If phandle is 0, then it is an empty entry with no
+ * arguments. Skip forward to the next entry.
+ */
+ phandle = be32_to_cpup(list++);
+ if (phandle) {
+ /*
+ * Find the provider node and parse the #*-cells
+ * property to determine the argument length.
+ *
+ * This is not needed if the cell count is hard-coded
+ * (i.e. cells_name not set, but cell_count is set),
+ * except when we're going to return the found node
+ * below.
+ */
+ if (cells_name || cur_index == index) {
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ debug("%s: could not find phandle\n",
+ np->full_name);
+ goto err;
+ }
+ }
+
+ if (cells_name) {
+ if (of_read_u32(node, cells_name, &count)) {
+ debug("%s: could not get %s for %s\n",
+ np->full_name, cells_name,
+ node->full_name);
+ goto err;
+ }
+ } else {
+ count = cell_count;
+ }
+
+ /*
+ * Make sure that the arguments actually fit in the
+ * remaining property data length
+ */
+ if (list + count > list_end) {
+ debug("%s: arguments longer than property\n",
+ np->full_name);
+ goto err;
+ }
+ }
+
+ /*
+ * All of the error cases above bail out of the loop, so at
+ * this point, the parsing is successful. If the requested
+ * index matches, then fill the out_args structure and return,
+ * or return -ENOENT for an empty entry.
+ */
+ rc = -ENOENT;
+ if (cur_index == index) {
+ if (!phandle)
+ goto err;
+
+ if (out_args) {
+ int i;
+ if (WARN_ON(count > OF_MAX_PHANDLE_ARGS))
+ count = OF_MAX_PHANDLE_ARGS;
+ out_args->np = node;
+ out_args->args_count = count;
+ for (i = 0; i < count; i++)
+ out_args->args[i] =
+ be32_to_cpup(list++);
+ } else {
+ of_node_put(node);
+ }
+
+ /* Found it! return success */
+ return 0;
+ }
+
+ of_node_put(node);
+ node = NULL;
+ list += count;
+ cur_index++;
+ }
+
+ /*
+ * Unlock node before returning result; will be one of:
+ * -ENOENT : index is for empty phandle
+ * -EINVAL : parsing error on data
+ * [1..n] : Number of phandle (count mode; when index = -1)
+ */
+ rc = index < 0 ? cur_index : -ENOENT;
+ err:
+ if (node)
+ of_node_put(node);
+ return rc;
+}
+
+struct device_node *of_parse_phandle(const struct device_node *np,
+ const char *phandle_name, int index)
+{
+ struct of_phandle_args args;
+
+ if (index < 0)
+ return NULL;
+
+ if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0, index,
+ &args))
+ return NULL;
+
+ return args.np;
+}
+
+int of_parse_phandle_with_args(const struct device_node *np,
+ const char *list_name, const char *cells_name,
+ int cell_count, int index,
+ struct of_phandle_args *out_args)
+{
+ if (index < 0)
+ return -EINVAL;
+
+ return __of_parse_phandle_with_args(np, list_name, cells_name,
+ cell_count, index, out_args);
+}
+
+int of_count_phandle_with_args(const struct device_node *np,
+ const char *list_name, const char *cells_name,
+ int cell_count)
+{
+ return __of_parse_phandle_with_args(np, list_name, cells_name,
+ cell_count, -1, NULL);
+}
+
+static void of_alias_add(struct alias_prop *ap, struct device_node *np,
+ int id, const char *stem, int stem_len)
+{
+ ap->np = np;
+ ap->id = id;
+ strncpy(ap->stem, stem, stem_len);
+ ap->stem[stem_len] = 0;
+ list_add_tail(&ap->link, &aliases_lookup);
+ debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
+ ap->alias, ap->stem, ap->id, of_node_full_name(np));
+}
+
+int of_alias_scan(void)
+{
+ struct property *pp;
+
+ of_aliases = of_find_node_by_path("/aliases");
+ of_chosen = of_find_node_by_path("/chosen");
+ if (of_chosen == NULL)
+ of_chosen = of_find_node_by_path("/chosen@0");
+
+ if (of_chosen) {
+ const char *name;
+
+ name = of_get_property(of_chosen, "stdout-path", NULL);
+ if (name)
+ of_stdout = of_find_node_opts_by_path(name,
+ &of_stdout_options);
+ }
+
+ if (!of_aliases)
+ return 0;
+
+ for_each_property_of_node(of_aliases, pp) {
+ const char *start = pp->name;
+ const char *end = start + strlen(start);
+ struct device_node *np;
+ struct alias_prop *ap;
+ ulong id;
+ int len;
+
+ /* Skip those we do not want to proceed */
+ if (!strcmp(pp->name, "name") ||
+ !strcmp(pp->name, "phandle") ||
+ !strcmp(pp->name, "linux,phandle"))
+ continue;
+
+ np = of_find_node_by_path(pp->value);
+ if (!np)
+ continue;
+
+ /*
+ * walk the alias backwards to extract the id and work out
+ * the 'stem' string
+ */
+ while (isdigit(*(end-1)) && end > start)
+ end--;
+ len = end - start;
+
+ if (strict_strtoul(end, 10, &id) < 0)
+ continue;
+
+ /* Allocate an alias_prop with enough space for the stem */
+ ap = malloc(sizeof(*ap) + len + 1);
+ if (!ap)
+ return -ENOMEM;
+ memset(ap, 0, sizeof(*ap) + len + 1);
+ ap->alias = start;
+ of_alias_add(ap, np, id, start, len);
+ }
+
+ return 0;
+}
+
+int of_alias_get_id(const struct device_node *np, const char *stem)
+{
+ struct alias_prop *app;
+ int id = -ENODEV;
+
+ mutex_lock(&of_mutex);
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (strcmp(app->stem, stem) != 0)
+ continue;
+
+ if (np == app->np) {
+ id = app->id;
+ break;
+ }
+ }
+ mutex_unlock(&of_mutex);
+
+ return id;
+}
+
+int of_alias_get_highest_id(const char *stem)
+{
+ struct alias_prop *app;
+ int id = -1;
+
+ mutex_lock(&of_mutex);
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (strcmp(app->stem, stem) != 0)
+ continue;
+
+ if (app->id > id)
+ id = app->id;
+ }
+ mutex_unlock(&of_mutex);
+
+ return id;
+}
+
+struct device_node *of_get_stdout(void)
+{
+ return of_stdout;
+}
diff --git a/roms/u-boot/drivers/core/of_addr.c b/roms/u-boot/drivers/core/of_addr.c
new file mode 100644
index 000000000..3fbc0a7af
--- /dev/null
+++ b/roms/u-boot/drivers/core/of_addr.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Taken from Linux v4.9 drivers/of/address.c
+ *
+ * Modified for U-Boot
+ * Copyright (c) 2017 Google, Inc
+ */
+
+#include <common.h>
+#include <log.h>
+#include <linux/bug.h>
+#include <linux/libfdt.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+#define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
+#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0)
+
+static struct of_bus *of_match_bus(struct device_node *np);
+
+/* Debug utility */
+#ifdef DEBUG
+static void of_dump_addr(const char *s, const __be32 *addr, int na)
+{
+ debug("%s", s);
+ while (na--)
+ pr_cont(" %08x", be32_to_cpu(*(addr++)));
+ pr_cont("\n");
+}
+#else
+static void of_dump_addr(const char *s, const __be32 *addr, int na) { }
+#endif
+
+/* Callbacks for bus specific translators */
+struct of_bus {
+ const char *name;
+ const char *addresses;
+ int (*match)(struct device_node *parent);
+ void (*count_cells)(const struct device_node *child, int *addrc,
+ int *sizec);
+ u64 (*map)(__be32 *addr, const __be32 *range, int na, int ns, int pna);
+ int (*translate)(__be32 *addr, u64 offset, int na);
+ unsigned int (*get_flags)(const __be32 *addr);
+};
+
+static void of_bus_default_count_cells(const struct device_node *np,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = of_n_addr_cells(np);
+ if (sizec)
+ *sizec = of_n_size_cells(np);
+}
+
+static u64 of_bus_default_map(__be32 *addr, const __be32 *range,
+ int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = of_read_number(range, na);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr, na);
+
+ debug("default map, cp=%llx, s=%llx, da=%llx\n",
+ (unsigned long long)cp, (unsigned long long)s,
+ (unsigned long long)da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_default_translate(__be32 *addr, u64 offset, int na)
+{
+ u64 a = of_read_number(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = cpu_to_be32(a >> 32);
+ addr[na - 1] = cpu_to_be32(a & 0xffffffffu);
+
+ return 0;
+}
+
+static unsigned int of_bus_default_get_flags(const __be32 *addr)
+{
+ return IORESOURCE_MEM;
+}
+
+/*
+ * Array of bus-specific translators
+ */
+static struct of_bus of_busses[] = {
+ /* Default */
+ {
+ .name = "default",
+ .addresses = "reg",
+ .match = NULL,
+ .count_cells = of_bus_default_count_cells,
+ .map = of_bus_default_map,
+ .translate = of_bus_default_translate,
+ .get_flags = of_bus_default_get_flags,
+ },
+};
+
+static struct of_bus *of_match_bus(struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(of_busses); i++)
+ if (!of_busses[i].match || of_busses[i].match(np))
+ return &of_busses[i];
+ BUG();
+ return NULL;
+}
+
+const __be32 *of_get_address(const struct device_node *dev, int index,
+ u64 *size, unsigned int *flags)
+{
+ const __be32 *prop;
+ int psize;
+ struct device_node *parent;
+ struct of_bus *bus;
+ int onesize, i, na, ns;
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ return NULL;
+ bus = of_match_bus(parent);
+ bus->count_cells(dev, &na, &ns);
+ of_node_put(parent);
+ if (!OF_CHECK_ADDR_COUNT(na))
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+ prop = of_get_property(dev, "reg", &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+
+ onesize = na + ns;
+ for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+ if (i == index) {
+ if (size)
+ *size = of_read_number(prop + na, ns);
+ if (flags)
+ *flags = bus->get_flags(prop);
+ return prop;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_get_address);
+
+static int of_empty_ranges_quirk(const struct device_node *np)
+{
+ return false;
+}
+
+static int of_translate_one(const struct device_node *parent,
+ struct of_bus *bus, struct of_bus *pbus,
+ __be32 *addr, int na, int ns, int pna,
+ const char *rprop)
+{
+ const __be32 *ranges;
+ int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+
+ /*
+ * Normally, an absence of a "ranges" property means we are
+ * crossing a non-translatable boundary, and thus the addresses
+ * below the current cannot be converted to CPU physical ones.
+ * Unfortunately, while this is very clear in the spec, it's not
+ * what Apple understood, and they do have things like /uni-n or
+ * /ht nodes with no "ranges" property and a lot of perfectly
+ * useable mapped devices below them. Thus we treat the absence of
+ * "ranges" as equivalent to an empty "ranges" property which means
+ * a 1:1 translation at that level. It's up to the caller not to try
+ * to translate addresses that aren't supposed to be translated in
+ * the first place. --BenH.
+ *
+ * As far as we know, this damage only exists on Apple machines, so
+ * This code is only enabled on powerpc. --gcl
+ *
+ * This quirk also applies for 'dma-ranges' which frequently exist in
+ * child nodes without 'dma-ranges' in the parent nodes. --RobH
+ */
+ ranges = of_get_property(parent, rprop, &rlen);
+ if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
+ strcmp(rprop, "dma-ranges")) {
+ debug("no ranges; cannot translate\n");
+ return 1;
+ }
+ if (ranges == NULL || rlen == 0) {
+ offset = of_read_number(addr, na);
+ memset(addr, 0, pna * 4);
+ debug("empty ranges; 1:1 translation\n");
+ goto finish;
+ }
+
+ debug("walking ranges...\n");
+
+ /* Now walk through the ranges */
+ rlen /= 4;
+ rone = na + pna + ns;
+ for (; rlen >= rone; rlen -= rone, ranges += rone) {
+ offset = bus->map(addr, ranges, na, ns, pna);
+ if (offset != OF_BAD_ADDR)
+ break;
+ }
+ if (offset == OF_BAD_ADDR) {
+ debug("not found !\n");
+ return 1;
+ }
+ memcpy(addr, ranges + na, 4 * pna);
+
+ finish:
+ of_dump_addr("parent translation for:", addr, pna);
+ debug("with offset: %llx\n", (unsigned long long)offset);
+
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+static u64 __of_translate_address(const struct device_node *dev,
+ const __be32 *in_addr, const char *rprop)
+{
+ struct device_node *parent = NULL;
+ struct of_bus *bus, *pbus;
+ __be32 addr[OF_MAX_ADDR_CELLS];
+ int na, ns, pna, pns;
+ u64 result = OF_BAD_ADDR;
+
+ debug("** translation for device %s **\n", of_node_full_name(dev));
+
+ /* Increase refcount at current level */
+ (void)of_node_get(dev);
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ goto bail;
+ bus = of_match_bus(parent);
+
+ /* Count address cells & copy address locally */
+ bus->count_cells(dev, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ debug("Bad cell count for %s\n", of_node_full_name(dev));
+ goto bail;
+ }
+ memcpy(addr, in_addr, na * 4);
+
+ debug("bus is %s (na=%d, ns=%d) on %s\n", bus->name, na, ns,
+ of_node_full_name(parent));
+ of_dump_addr("translating address:", addr, na);
+
+ /* Translate */
+ for (;;) {
+ /* Switch to parent bus */
+ of_node_put(dev);
+ dev = parent;
+ parent = of_get_parent(dev);
+
+ /* If root, we have finished */
+ if (parent == NULL) {
+ debug("reached root node\n");
+ result = of_read_number(addr, na);
+ break;
+ }
+
+ /* Get new parent bus and counts */
+ pbus = of_match_bus(parent);
+ pbus->count_cells(dev, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ debug("Bad cell count for %s\n",
+ of_node_full_name(dev));
+ break;
+ }
+
+ debug("parent bus is %s (na=%d, ns=%d) on %s\n", pbus->name,
+ pna, pns, of_node_full_name(parent));
+
+ /* Apply bus translation */
+ if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
+ break;
+
+ /* Complete the move up one level */
+ na = pna;
+ ns = pns;
+ bus = pbus;
+
+ of_dump_addr("one level translation:", addr, na);
+ }
+ bail:
+ of_node_put(parent);
+ of_node_put(dev);
+
+ return result;
+}
+
+u64 of_translate_address(const struct device_node *dev, const __be32 *in_addr)
+{
+ return __of_translate_address(dev, in_addr, "ranges");
+}
+
+u64 of_translate_dma_address(const struct device_node *dev, const __be32 *in_addr)
+{
+ return __of_translate_address(dev, in_addr, "dma-ranges");
+}
+
+int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size)
+{
+ bool found_dma_ranges = false;
+ struct device_node *parent;
+ struct of_bus *bus_node;
+ int na, ns, pna, pns;
+ const __be32 *ranges;
+ int ret = 0;
+ int len;
+
+ /* Find the closest dma-ranges property */
+ dev = of_node_get(dev);
+ while (dev) {
+ ranges = of_get_property(dev, "dma-ranges", &len);
+
+ /* Ignore empty ranges, they imply no translation required */
+ if (ranges && len > 0)
+ break;
+
+ /* Once we find 'dma-ranges', then a missing one is an error */
+ if (found_dma_ranges && !ranges) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ranges)
+ found_dma_ranges = true;
+
+ parent = of_get_parent(dev);
+ of_node_put(dev);
+ dev = parent;
+ }
+
+ if (!dev || !ranges) {
+ debug("no dma-ranges found for node %s\n",
+ of_node_full_name(dev));
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /* switch to that node */
+ parent = of_get_parent(dev);
+ if (!parent) {
+ printf("Found dma-ranges in root node, shoudln't happen\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Get the address sizes both for the bus and its parent */
+ bus_node = of_match_bus((struct device_node*)dev);
+ bus_node->count_cells(dev, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ printf("Bad cell count for %s\n", of_node_full_name(dev));
+ ret = -EINVAL;
+ goto out_parent;
+ }
+
+ bus_node = of_match_bus(parent);
+ bus_node->count_cells(parent, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ printf("Bad cell count for %s\n", of_node_full_name(parent));
+ ret = -EINVAL;
+ goto out_parent;
+ }
+
+ *bus = of_read_number(ranges, na);
+ *cpu = of_translate_dma_address(dev, ranges + na);
+ *size = of_read_number(ranges + na + pna, ns);
+
+out_parent:
+ of_node_put(parent);
+out:
+ of_node_put(dev);
+ return ret;
+}
+
+
+static int __of_address_to_resource(const struct device_node *dev,
+ const __be32 *addrp, u64 size, unsigned int flags,
+ const char *name, struct resource *r)
+{
+ u64 taddr;
+
+ if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
+ return -EINVAL;
+ taddr = of_translate_address(dev, addrp);
+ if (taddr == OF_BAD_ADDR)
+ return -EINVAL;
+ memset(r, 0, sizeof(struct resource));
+ r->start = taddr;
+ r->end = taddr + size - 1;
+ r->flags = flags;
+ r->name = name ? name : dev->full_name;
+
+ return 0;
+}
+
+int of_address_to_resource(const struct device_node *dev, int index,
+ struct resource *r)
+{
+ const __be32 *addrp;
+ u64 size;
+ unsigned int flags;
+ const char *name = NULL;
+
+ addrp = of_get_address(dev, index, &size, &flags);
+ if (addrp == NULL)
+ return -EINVAL;
+
+ /* Get optional "reg-names" property to add a name to a resource */
+ of_property_read_string_index(dev, "reg-names", index, &name);
+
+ return __of_address_to_resource(dev, addrp, size, flags, name, r);
+}
diff --git a/roms/u-boot/drivers/core/of_extra.c b/roms/u-boot/drivers/core/of_extra.c
new file mode 100644
index 000000000..7702beff9
--- /dev/null
+++ b/roms/u-boot/drivers/core/of_extra.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <linux/libfdt.h>
+#include <dm/of_access.h>
+#include <dm/of_extra.h>
+#include <dm/ofnode.h>
+
+int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry)
+{
+ const char *prop;
+ ofnode subnode;
+
+ if (ofnode_read_u32(node, "image-pos", &entry->offset)) {
+ debug("Node '%s' has bad/missing 'image-pos' property\n",
+ ofnode_get_name(node));
+ return log_msg_ret("image-pos", -ENOENT);
+ }
+ if (ofnode_read_u32(node, "size", &entry->length)) {
+ debug("Node '%s' has bad/missing 'size' property\n",
+ ofnode_get_name(node));
+ return log_msg_ret("size", -ENOENT);
+ }
+ entry->used = ofnode_read_s32_default(node, "used", entry->length);
+ prop = ofnode_read_string(node, "compress");
+ if (prop) {
+ if (!strcmp(prop, "lz4"))
+ entry->compress_algo = FMAP_COMPRESS_LZ4;
+ else
+ return log_msg_ret("compression algo", -EINVAL);
+ } else {
+ entry->compress_algo = FMAP_COMPRESS_NONE;
+ }
+ entry->unc_length = ofnode_read_s32_default(node, "uncomp-size",
+ entry->length);
+ subnode = ofnode_find_subnode(node, "hash");
+ if (ofnode_valid(subnode)) {
+ prop = ofnode_read_prop(subnode, "value", &entry->hash_size);
+
+ /* Assume it is sha256 */
+ entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE;
+ entry->hash = (uint8_t *)prop;
+ }
+
+ return 0;
+}
+
+int ofnode_decode_region(ofnode node, const char *prop_name, fdt_addr_t *basep,
+ fdt_size_t *sizep)
+{
+ const fdt_addr_t *cell;
+ int len;
+
+ debug("%s: %s: %s\n", __func__, ofnode_get_name(node), prop_name);
+ cell = ofnode_get_property(node, prop_name, &len);
+ if (!cell || (len < sizeof(fdt_addr_t) * 2)) {
+ debug("cell=%p, len=%d\n", cell, len);
+ return -1;
+ }
+
+ *basep = fdt_addr_to_cpu(*cell);
+ *sizep = fdt_size_to_cpu(cell[1]);
+ debug("%s: base=%08lx, size=%lx\n", __func__, (ulong)*basep,
+ (ulong)*sizep);
+
+ return 0;
+}
+
+int ofnode_decode_memory_region(ofnode config_node, const char *mem_type,
+ const char *suffix, fdt_addr_t *basep,
+ fdt_size_t *sizep)
+{
+ char prop_name[50];
+ const char *mem;
+ fdt_size_t size, offset_size;
+ fdt_addr_t base, offset;
+ ofnode node;
+
+ if (!ofnode_valid(config_node)) {
+ config_node = ofnode_path("/config");
+ if (!ofnode_valid(config_node)) {
+ debug("%s: Cannot find /config node\n", __func__);
+ return -ENOENT;
+ }
+ }
+ if (!suffix)
+ suffix = "";
+
+ snprintf(prop_name, sizeof(prop_name), "%s-memory%s", mem_type,
+ suffix);
+ mem = ofnode_read_string(config_node, prop_name);
+ if (!mem) {
+ debug("%s: No memory type for '%s', using /memory\n", __func__,
+ prop_name);
+ mem = "/memory";
+ }
+
+ node = ofnode_path(mem);
+ if (!ofnode_valid(node)) {
+ debug("%s: Failed to find node '%s'\n", __func__, mem);
+ return -ENOENT;
+ }
+
+ /*
+ * Not strictly correct - the memory may have multiple banks. We just
+ * use the first
+ */
+ if (ofnode_decode_region(node, "reg", &base, &size)) {
+ debug("%s: Failed to decode memory region %s\n", __func__,
+ mem);
+ return -EINVAL;
+ }
+
+ snprintf(prop_name, sizeof(prop_name), "%s-offset%s", mem_type,
+ suffix);
+ if (ofnode_decode_region(config_node, prop_name, &offset,
+ &offset_size)) {
+ debug("%s: Failed to decode memory region '%s'\n", __func__,
+ prop_name);
+ return -EINVAL;
+ }
+
+ *basep = base + offset;
+ *sizep = offset_size;
+
+ return 0;
+}
+
+bool ofnode_phy_is_fixed_link(ofnode eth_node, ofnode *phy_node)
+{
+ ofnode node, subnode;
+ int len;
+
+ subnode = ofnode_find_subnode(eth_node, "fixed-link");
+ if (ofnode_valid(subnode)) {
+ /* new binding */
+ node = subnode;
+ } else if (ofnode_get_property(eth_node, "fixed-link", &len) &&
+ len == (5 * sizeof(__be32))) {
+ /* old binding */
+ node = eth_node;
+ } else {
+ return false;
+ }
+
+ if (phy_node)
+ *phy_node = node;
+
+ return true;
+}
diff --git a/roms/u-boot/drivers/core/ofnode.c b/roms/u-boot/drivers/core/ofnode.c
new file mode 100644
index 000000000..6c771e364
--- /dev/null
+++ b/roms/u-boot/drivers/core/ofnode.c
@@ -0,0 +1,1054 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/libfdt.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <dm/ofnode.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <asm/global_data.h>
+
+int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
+{
+ return ofnode_read_u32_index(node, propname, 0, outp);
+}
+
+u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
+{
+ assert(ofnode_valid(node));
+ ofnode_read_u32_index(node, propname, 0, &def);
+
+ return def;
+}
+
+int ofnode_read_u32_index(ofnode node, const char *propname, int index,
+ u32 *outp)
+{
+ const fdt32_t *cell;
+ int len;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ if (ofnode_is_np(node))
+ return of_read_u32_index(ofnode_to_np(node), propname, index,
+ outp);
+
+ cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
+ &len);
+ if (!cell) {
+ debug("(not found)\n");
+ return -EINVAL;
+ }
+
+ if (len < (sizeof(int) * (index + 1))) {
+ debug("(not large enough)\n");
+ return -EOVERFLOW;
+ }
+
+ *outp = fdt32_to_cpu(cell[index]);
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
+u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
+ u32 def)
+{
+ assert(ofnode_valid(node));
+ ofnode_read_u32_index(node, propname, index, &def);
+
+ return def;
+}
+
+int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
+{
+ assert(ofnode_valid(node));
+ ofnode_read_u32(node, propname, (u32 *)&def);
+
+ return def;
+}
+
+int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
+{
+ const unaligned_fdt64_t *cell;
+ int len;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ if (ofnode_is_np(node))
+ return of_read_u64(ofnode_to_np(node), propname, outp);
+
+ cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
+ &len);
+ if (!cell || len < sizeof(*cell)) {
+ debug("(not found)\n");
+ return -EINVAL;
+ }
+ *outp = fdt64_to_cpu(cell[0]);
+ debug("%#llx (%lld)\n", (unsigned long long)*outp,
+ (unsigned long long)*outp);
+
+ return 0;
+}
+
+u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
+{
+ assert(ofnode_valid(node));
+ ofnode_read_u64(node, propname, &def);
+
+ return def;
+}
+
+bool ofnode_read_bool(ofnode node, const char *propname)
+{
+ const void *prop;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ prop = ofnode_get_property(node, propname, NULL);
+
+ debug("%s\n", prop ? "true" : "false");
+
+ return prop ? true : false;
+}
+
+const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
+{
+ const char *val = NULL;
+ int len;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ if (ofnode_is_np(node)) {
+ struct property *prop = of_find_property(
+ ofnode_to_np(node), propname, &len);
+
+ if (prop) {
+ val = prop->value;
+ len = prop->length;
+ }
+ } else {
+ val = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
+ propname, &len);
+ }
+ if (!val) {
+ debug("<not found>\n");
+ if (sizep)
+ *sizep = -FDT_ERR_NOTFOUND;
+ return NULL;
+ }
+ if (sizep)
+ *sizep = len;
+
+ return val;
+}
+
+const char *ofnode_read_string(ofnode node, const char *propname)
+{
+ const char *str;
+ int len;
+
+ str = ofnode_read_prop(node, propname, &len);
+ if (!str)
+ return NULL;
+
+ if (strnlen(str, len) >= len) {
+ debug("<invalid>\n");
+ return NULL;
+ }
+ debug("%s\n", str);
+
+ return str;
+}
+
+int ofnode_read_size(ofnode node, const char *propname)
+{
+ int len;
+
+ if (!ofnode_read_prop(node, propname, &len))
+ return -EINVAL;
+
+ return len;
+}
+
+ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
+{
+ ofnode subnode;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, subnode_name);
+
+ if (ofnode_is_np(node)) {
+ const struct device_node *np = ofnode_to_np(node);
+
+ for (np = np->child; np; np = np->sibling) {
+ if (!strcmp(subnode_name, np->name))
+ break;
+ }
+ subnode = np_to_ofnode(np);
+ } else {
+ int ooffset = fdt_subnode_offset(gd->fdt_blob,
+ ofnode_to_offset(node), subnode_name);
+ subnode = offset_to_ofnode(ooffset);
+ }
+ debug("%s\n", ofnode_valid(subnode) ?
+ ofnode_get_name(subnode) : "<none>");
+
+ return subnode;
+}
+
+int ofnode_read_u32_array(ofnode node, const char *propname,
+ u32 *out_values, size_t sz)
+{
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ if (ofnode_is_np(node)) {
+ return of_read_u32_array(ofnode_to_np(node), propname,
+ out_values, sz);
+ } else {
+ return fdtdec_get_int_array(gd->fdt_blob,
+ ofnode_to_offset(node), propname,
+ out_values, sz);
+ }
+}
+
+#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
+bool ofnode_is_enabled(ofnode node)
+{
+ if (ofnode_is_np(node)) {
+ return of_device_is_available(ofnode_to_np(node));
+ } else {
+ return fdtdec_get_is_enabled(gd->fdt_blob,
+ ofnode_to_offset(node));
+ }
+}
+
+ofnode ofnode_first_subnode(ofnode node)
+{
+ assert(ofnode_valid(node));
+ if (ofnode_is_np(node))
+ return np_to_ofnode(node.np->child);
+
+ return offset_to_ofnode(
+ fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node)));
+}
+
+ofnode ofnode_next_subnode(ofnode node)
+{
+ assert(ofnode_valid(node));
+ if (ofnode_is_np(node))
+ return np_to_ofnode(node.np->sibling);
+
+ return offset_to_ofnode(
+ fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
+}
+#endif /* !DM_INLINE_OFNODE */
+
+ofnode ofnode_get_parent(ofnode node)
+{
+ ofnode parent;
+
+ assert(ofnode_valid(node));
+ if (ofnode_is_np(node))
+ parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
+ else
+ parent.of_offset = fdt_parent_offset(gd->fdt_blob,
+ ofnode_to_offset(node));
+
+ return parent;
+}
+
+const char *ofnode_get_name(ofnode node)
+{
+ if (!ofnode_valid(node)) {
+ debug("%s node not valid\n", __func__);
+ return NULL;
+ }
+
+ if (ofnode_is_np(node))
+ return strrchr(node.np->full_name, '/') + 1;
+
+ return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
+}
+
+ofnode ofnode_get_by_phandle(uint phandle)
+{
+ ofnode node;
+
+ if (of_live_active())
+ node = np_to_ofnode(of_find_node_by_phandle(phandle));
+ else
+ node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
+ phandle);
+
+ return node;
+}
+
+fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
+{
+ int na, ns;
+
+ *size = FDT_SIZE_T_NONE;
+
+ if (ofnode_is_np(node)) {
+ const __be32 *prop_val;
+ u64 size64;
+ uint flags;
+
+ prop_val = of_get_address(ofnode_to_np(node), index, &size64,
+ &flags);
+ if (!prop_val)
+ return FDT_ADDR_T_NONE;
+ if (size)
+ *size = size64;
+
+ ns = of_n_size_cells(ofnode_to_np(node));
+
+ if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
+ return of_translate_address(ofnode_to_np(node), prop_val);
+ } else {
+ na = of_n_addr_cells(ofnode_to_np(node));
+ return of_read_number(prop_val, na);
+ }
+ } else {
+ na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
+ ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
+ return fdtdec_get_addr_size_fixed(gd->fdt_blob,
+ ofnode_to_offset(node), "reg",
+ index, na, ns, size, true);
+ }
+
+ return FDT_ADDR_T_NONE;
+}
+
+fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
+{
+ fdt_size_t size;
+
+ return ofnode_get_addr_size_index(node, index, &size);
+}
+
+fdt_addr_t ofnode_get_addr(ofnode node)
+{
+ return ofnode_get_addr_index(node, 0);
+}
+
+fdt_size_t ofnode_get_size(ofnode node)
+{
+ fdt_size_t size;
+
+ ofnode_get_addr_size_index(node, 0, &size);
+
+ return size;
+}
+
+int ofnode_stringlist_search(ofnode node, const char *property,
+ const char *string)
+{
+ if (ofnode_is_np(node)) {
+ return of_property_match_string(ofnode_to_np(node),
+ property, string);
+ } else {
+ int ret;
+
+ ret = fdt_stringlist_search(gd->fdt_blob,
+ ofnode_to_offset(node), property,
+ string);
+ if (ret == -FDT_ERR_NOTFOUND)
+ return -ENODATA;
+ else if (ret < 0)
+ return -EINVAL;
+
+ return ret;
+ }
+}
+
+int ofnode_read_string_index(ofnode node, const char *property, int index,
+ const char **outp)
+{
+ if (ofnode_is_np(node)) {
+ return of_property_read_string_index(ofnode_to_np(node),
+ property, index, outp);
+ } else {
+ int len;
+
+ *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node),
+ property, index, &len);
+ if (len < 0)
+ return -EINVAL;
+ return 0;
+ }
+}
+
+int ofnode_read_string_count(ofnode node, const char *property)
+{
+ if (ofnode_is_np(node)) {
+ return of_property_count_strings(ofnode_to_np(node), property);
+ } else {
+ return fdt_stringlist_count(gd->fdt_blob,
+ ofnode_to_offset(node), property);
+ }
+}
+
+static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
+ struct ofnode_phandle_args *out)
+{
+ assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
+ out->node = offset_to_ofnode(in->node);
+ out->args_count = in->args_count;
+ memcpy(out->args, in->args, sizeof(out->args));
+}
+
+static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
+ struct ofnode_phandle_args *out)
+{
+ assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
+ out->node = np_to_ofnode(in->np);
+ out->args_count = in->args_count;
+ memcpy(out->args, in->args, sizeof(out->args));
+}
+
+int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
+ const char *cells_name, int cell_count,
+ int index,
+ struct ofnode_phandle_args *out_args)
+{
+ if (ofnode_is_np(node)) {
+ struct of_phandle_args args;
+ int ret;
+
+ ret = of_parse_phandle_with_args(ofnode_to_np(node),
+ list_name, cells_name,
+ cell_count, index,
+ &args);
+ if (ret)
+ return ret;
+ ofnode_from_of_phandle_args(&args, out_args);
+ } else {
+ struct fdtdec_phandle_args args;
+ int ret;
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
+ ofnode_to_offset(node),
+ list_name, cells_name,
+ cell_count, index, &args);
+ if (ret)
+ return ret;
+ ofnode_from_fdtdec_phandle_args(&args, out_args);
+ }
+
+ return 0;
+}
+
+int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
+ const char *cells_name, int cell_count)
+{
+ if (ofnode_is_np(node))
+ return of_count_phandle_with_args(ofnode_to_np(node),
+ list_name, cells_name, cell_count);
+ else
+ return fdtdec_parse_phandle_with_args(gd->fdt_blob,
+ ofnode_to_offset(node), list_name, cells_name,
+ cell_count, -1, NULL);
+}
+
+ofnode ofnode_path(const char *path)
+{
+ if (of_live_active())
+ return np_to_ofnode(of_find_node_by_path(path));
+ else
+ return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
+}
+
+const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
+{
+ ofnode chosen_node;
+
+ chosen_node = ofnode_path("/chosen");
+
+ return ofnode_read_prop(chosen_node, propname, sizep);
+}
+
+const char *ofnode_read_chosen_string(const char *propname)
+{
+ return ofnode_read_chosen_prop(propname, NULL);
+}
+
+ofnode ofnode_get_chosen_node(const char *name)
+{
+ const char *prop;
+
+ prop = ofnode_read_chosen_prop(name, NULL);
+ if (!prop)
+ return ofnode_null();
+
+ return ofnode_path(prop);
+}
+
+const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
+{
+ ofnode node;
+
+ node = ofnode_path("/aliases");
+
+ return ofnode_read_prop(node, propname, sizep);
+}
+
+ofnode ofnode_get_aliases_node(const char *name)
+{
+ const char *prop;
+
+ prop = ofnode_read_aliases_prop(name, NULL);
+ if (!prop)
+ return ofnode_null();
+
+ debug("%s: node_path: %s\n", __func__, prop);
+
+ return ofnode_path(prop);
+}
+
+int ofnode_get_child_count(ofnode parent)
+{
+ ofnode child;
+ int num = 0;
+
+ ofnode_for_each_subnode(child, parent)
+ num++;
+
+ return num;
+}
+
+static int decode_timing_property(ofnode node, const char *name,
+ struct timing_entry *result)
+{
+ int length, ret = 0;
+
+ length = ofnode_read_size(node, name);
+ if (length < 0) {
+ debug("%s: could not find property %s\n",
+ ofnode_get_name(node), name);
+ return length;
+ }
+
+ if (length == sizeof(u32)) {
+ result->typ = ofnode_read_u32_default(node, name, 0);
+ result->min = result->typ;
+ result->max = result->typ;
+ } else {
+ ret = ofnode_read_u32_array(node, name, &result->min, 3);
+ }
+
+ return ret;
+}
+
+int ofnode_decode_display_timing(ofnode parent, int index,
+ struct display_timing *dt)
+{
+ int i;
+ ofnode timings, node;
+ u32 val = 0;
+ int ret = 0;
+
+ timings = ofnode_find_subnode(parent, "display-timings");
+ if (!ofnode_valid(timings))
+ return -EINVAL;
+
+ i = 0;
+ ofnode_for_each_subnode(node, timings) {
+ if (i++ == index)
+ break;
+ }
+
+ if (!ofnode_valid(node))
+ return -EINVAL;
+
+ memset(dt, 0, sizeof(*dt));
+
+ ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
+ ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
+ ret |= decode_timing_property(node, "hactive", &dt->hactive);
+ ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
+ ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
+ ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
+ ret |= decode_timing_property(node, "vactive", &dt->vactive);
+ ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
+ ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
+
+ dt->flags = 0;
+ val = ofnode_read_u32_default(node, "vsync-active", -1);
+ if (val != -1) {
+ dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
+ DISPLAY_FLAGS_VSYNC_LOW;
+ }
+ val = ofnode_read_u32_default(node, "hsync-active", -1);
+ if (val != -1) {
+ dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
+ DISPLAY_FLAGS_HSYNC_LOW;
+ }
+ val = ofnode_read_u32_default(node, "de-active", -1);
+ if (val != -1) {
+ dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
+ DISPLAY_FLAGS_DE_LOW;
+ }
+ val = ofnode_read_u32_default(node, "pixelclk-active", -1);
+ if (val != -1) {
+ dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
+ DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+ }
+
+ if (ofnode_read_bool(node, "interlaced"))
+ dt->flags |= DISPLAY_FLAGS_INTERLACED;
+ if (ofnode_read_bool(node, "doublescan"))
+ dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
+ if (ofnode_read_bool(node, "doubleclk"))
+ dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
+
+ return ret;
+}
+
+const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
+{
+ if (ofnode_is_np(node))
+ return of_get_property(ofnode_to_np(node), propname, lenp);
+ else
+ return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
+ propname, lenp);
+}
+
+int ofnode_get_first_property(ofnode node, struct ofprop *prop)
+{
+ prop->node = node;
+
+ if (ofnode_is_np(node)) {
+ prop->prop = of_get_first_property(ofnode_to_np(prop->node));
+ if (!prop->prop)
+ return -FDT_ERR_NOTFOUND;
+ } else {
+ prop->offset =
+ fdt_first_property_offset(gd->fdt_blob,
+ ofnode_to_offset(prop->node));
+ if (prop->offset < 0)
+ return prop->offset;
+ }
+
+ return 0;
+}
+
+int ofnode_get_next_property(struct ofprop *prop)
+{
+ if (ofnode_is_np(prop->node)) {
+ prop->prop = of_get_next_property(ofnode_to_np(prop->node),
+ prop->prop);
+ if (!prop->prop)
+ return -FDT_ERR_NOTFOUND;
+ } else {
+ prop->offset = fdt_next_property_offset(gd->fdt_blob,
+ prop->offset);
+ if (prop->offset < 0)
+ return prop->offset;
+ }
+
+ return 0;
+}
+
+const void *ofnode_get_property_by_prop(const struct ofprop *prop,
+ const char **propname, int *lenp)
+{
+ if (ofnode_is_np(prop->node))
+ return of_get_property_by_prop(ofnode_to_np(prop->node),
+ prop->prop, propname, lenp);
+ else
+ return fdt_getprop_by_offset(gd->fdt_blob,
+ prop->offset,
+ propname, lenp);
+}
+
+bool ofnode_is_available(ofnode node)
+{
+ if (ofnode_is_np(node))
+ return of_device_is_available(ofnode_to_np(node));
+ else
+ return fdtdec_get_is_enabled(gd->fdt_blob,
+ ofnode_to_offset(node));
+}
+
+fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
+ fdt_size_t *sizep)
+{
+ if (ofnode_is_np(node)) {
+ int na, ns;
+ int psize;
+ const struct device_node *np = ofnode_to_np(node);
+ const __be32 *prop = of_get_property(np, property, &psize);
+
+ if (!prop)
+ return FDT_ADDR_T_NONE;
+ na = of_n_addr_cells(np);
+ ns = of_n_size_cells(np);
+ *sizep = of_read_number(prop + na, ns);
+
+ if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
+ return of_translate_address(np, prop);
+ else
+ return of_read_number(prop, na);
+ } else {
+ return fdtdec_get_addr_size(gd->fdt_blob,
+ ofnode_to_offset(node), property,
+ sizep);
+ }
+}
+
+const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
+ size_t sz)
+{
+ if (ofnode_is_np(node)) {
+ const struct device_node *np = ofnode_to_np(node);
+ int psize;
+ const __be32 *prop = of_get_property(np, propname, &psize);
+
+ if (!prop || sz != psize)
+ return NULL;
+ return (uint8_t *)prop;
+
+ } else {
+ return fdtdec_locate_byte_array(gd->fdt_blob,
+ ofnode_to_offset(node), propname, sz);
+ }
+}
+
+int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
+ const char *propname, struct fdt_pci_addr *addr)
+{
+ const fdt32_t *cell;
+ int len;
+ int ret = -ENOENT;
+
+ debug("%s: %s: ", __func__, propname);
+
+ /*
+ * If we follow the pci bus bindings strictly, we should check
+ * the value of the node's parent node's #address-cells and
+ * #size-cells. They need to be 3 and 2 accordingly. However,
+ * for simplicity we skip the check here.
+ */
+ cell = ofnode_get_property(node, propname, &len);
+ if (!cell)
+ goto fail;
+
+ if ((len % FDT_PCI_REG_SIZE) == 0) {
+ int num = len / FDT_PCI_REG_SIZE;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ debug("pci address #%d: %08lx %08lx %08lx\n", i,
+ (ulong)fdt32_to_cpu(cell[0]),
+ (ulong)fdt32_to_cpu(cell[1]),
+ (ulong)fdt32_to_cpu(cell[2]));
+ if ((fdt32_to_cpu(*cell) & type) == type) {
+ addr->phys_hi = fdt32_to_cpu(cell[0]);
+ addr->phys_mid = fdt32_to_cpu(cell[1]);
+ addr->phys_lo = fdt32_to_cpu(cell[2]);
+ break;
+ }
+
+ cell += (FDT_PCI_ADDR_CELLS +
+ FDT_PCI_SIZE_CELLS);
+ }
+
+ if (i == num) {
+ ret = -ENXIO;
+ goto fail;
+ }
+
+ return 0;
+ }
+
+ ret = -EINVAL;
+
+fail:
+ debug("(not found)\n");
+ return ret;
+}
+
+int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
+{
+ const char *list, *end;
+ int len;
+
+ list = ofnode_get_property(node, "compatible", &len);
+ if (!list)
+ return -ENOENT;
+
+ end = list + len;
+ while (list < end) {
+ len = strlen(list);
+ if (len >= strlen("pciVVVV,DDDD")) {
+ char *s = strstr(list, "pci");
+
+ /*
+ * check if the string is something like pciVVVV,DDDD.RR
+ * or just pciVVVV,DDDD
+ */
+ if (s && s[7] == ',' &&
+ (s[12] == '.' || s[12] == 0)) {
+ s += 3;
+ *vendor = simple_strtol(s, NULL, 16);
+
+ s += 5;
+ *device = simple_strtol(s, NULL, 16);
+
+ return 0;
+ }
+ }
+ list += (len + 1);
+ }
+
+ return -ENOENT;
+}
+
+int ofnode_read_addr_cells(ofnode node)
+{
+ if (ofnode_is_np(node)) {
+ return of_n_addr_cells(ofnode_to_np(node));
+ } else {
+ int parent = fdt_parent_offset(gd->fdt_blob,
+ ofnode_to_offset(node));
+
+ return fdt_address_cells(gd->fdt_blob, parent);
+ }
+}
+
+int ofnode_read_size_cells(ofnode node)
+{
+ if (ofnode_is_np(node)) {
+ return of_n_size_cells(ofnode_to_np(node));
+ } else {
+ int parent = fdt_parent_offset(gd->fdt_blob,
+ ofnode_to_offset(node));
+
+ return fdt_size_cells(gd->fdt_blob, parent);
+ }
+}
+
+int ofnode_read_simple_addr_cells(ofnode node)
+{
+ if (ofnode_is_np(node))
+ return of_simple_addr_cells(ofnode_to_np(node));
+ else
+ return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
+}
+
+int ofnode_read_simple_size_cells(ofnode node)
+{
+ if (ofnode_is_np(node))
+ return of_simple_size_cells(ofnode_to_np(node));
+ else
+ return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
+}
+
+bool ofnode_pre_reloc(ofnode node)
+{
+#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
+ /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
+ * had property dm-pre-reloc or u-boot,dm-spl/tpl.
+ * They are removed in final dtb (fdtgrep 2nd pass)
+ */
+ return true;
+#else
+ if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
+ return true;
+ if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
+ return true;
+
+ /*
+ * In regular builds individual spl and tpl handling both
+ * count as handled pre-relocation for later second init.
+ */
+ if (ofnode_read_bool(node, "u-boot,dm-spl") ||
+ ofnode_read_bool(node, "u-boot,dm-tpl"))
+ return true;
+
+ return false;
+#endif
+}
+
+int ofnode_read_resource(ofnode node, uint index, struct resource *res)
+{
+ if (ofnode_is_np(node)) {
+ return of_address_to_resource(ofnode_to_np(node), index, res);
+ } else {
+ struct fdt_resource fres;
+ int ret;
+
+ ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node),
+ "reg", index, &fres);
+ if (ret < 0)
+ return -EINVAL;
+ memset(res, '\0', sizeof(*res));
+ res->start = fres.start;
+ res->end = fres.end;
+
+ return 0;
+ }
+}
+
+int ofnode_read_resource_byname(ofnode node, const char *name,
+ struct resource *res)
+{
+ int index;
+
+ index = ofnode_stringlist_search(node, "reg-names", name);
+ if (index < 0)
+ return index;
+
+ return ofnode_read_resource(node, index, res);
+}
+
+u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
+{
+ if (ofnode_is_np(node))
+ return of_translate_address(ofnode_to_np(node), in_addr);
+ else
+ return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
+}
+
+u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
+{
+ if (ofnode_is_np(node))
+ return of_translate_dma_address(ofnode_to_np(node), in_addr);
+ else
+ return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
+}
+
+int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
+{
+ if (ofnode_is_np(node))
+ return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
+ else
+ return fdt_get_dma_range(gd->fdt_blob, ofnode_to_offset(node),
+ cpu, bus, size);
+}
+
+int ofnode_device_is_compatible(ofnode node, const char *compat)
+{
+ if (ofnode_is_np(node))
+ return of_device_is_compatible(ofnode_to_np(node), compat,
+ NULL, NULL);
+ else
+ return !fdt_node_check_compatible(gd->fdt_blob,
+ ofnode_to_offset(node),
+ compat);
+}
+
+ofnode ofnode_by_compatible(ofnode from, const char *compat)
+{
+ if (of_live_active()) {
+ return np_to_ofnode(of_find_compatible_node(
+ (struct device_node *)ofnode_to_np(from), NULL,
+ compat));
+ } else {
+ return offset_to_ofnode(fdt_node_offset_by_compatible(
+ gd->fdt_blob, ofnode_to_offset(from), compat));
+ }
+}
+
+ofnode ofnode_by_prop_value(ofnode from, const char *propname,
+ const void *propval, int proplen)
+{
+ if (of_live_active()) {
+ return np_to_ofnode(of_find_node_by_prop_value(
+ (struct device_node *)ofnode_to_np(from), propname,
+ propval, proplen));
+ } else {
+ return offset_to_ofnode(fdt_node_offset_by_prop_value(
+ gd->fdt_blob, ofnode_to_offset(from),
+ propname, propval, proplen));
+ }
+}
+
+int ofnode_write_prop(ofnode node, const char *propname, int len,
+ const void *value)
+{
+ const struct device_node *np = ofnode_to_np(node);
+ struct property *pp;
+ struct property *pp_last = NULL;
+ struct property *new;
+
+ if (!of_live_active())
+ return -ENOSYS;
+
+ if (!np)
+ return -EINVAL;
+
+ for (pp = np->properties; pp; pp = pp->next) {
+ if (strcmp(pp->name, propname) == 0) {
+ /* Property exists -> change value */
+ pp->value = (void *)value;
+ pp->length = len;
+ return 0;
+ }
+ pp_last = pp;
+ }
+
+ if (!pp_last)
+ return -ENOENT;
+
+ /* Property does not exist -> append new property */
+ new = malloc(sizeof(struct property));
+ if (!new)
+ return -ENOMEM;
+
+ new->name = strdup(propname);
+ if (!new->name) {
+ free(new);
+ return -ENOMEM;
+ }
+
+ new->value = (void *)value;
+ new->length = len;
+ new->next = NULL;
+
+ pp_last->next = new;
+
+ return 0;
+}
+
+int ofnode_write_string(ofnode node, const char *propname, const char *value)
+{
+ if (!of_live_active())
+ return -ENOSYS;
+
+ assert(ofnode_valid(node));
+
+ debug("%s: %s = %s", __func__, propname, value);
+
+ return ofnode_write_prop(node, propname, strlen(value) + 1, value);
+}
+
+int ofnode_set_enabled(ofnode node, bool value)
+{
+ if (!of_live_active())
+ return -ENOSYS;
+
+ assert(ofnode_valid(node));
+
+ if (value)
+ return ofnode_write_string(node, "status", "okay");
+ else
+ return ofnode_write_string(node, "status", "disabled");
+}
diff --git a/roms/u-boot/drivers/core/read.c b/roms/u-boot/drivers/core/read.c
new file mode 100644
index 000000000..4307ca457
--- /dev/null
+++ b/roms/u-boot/drivers/core/read.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/of_access.h>
+#include <mapmem.h>
+#include <asm/global_data.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+
+int dev_read_u32(const struct udevice *dev, const char *propname, u32 *outp)
+{
+ return ofnode_read_u32(dev_ofnode(dev), propname, outp);
+}
+
+int dev_read_u32_default(const struct udevice *dev, const char *propname,
+ int def)
+{
+ return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
+}
+
+int dev_read_u32_index(struct udevice *dev, const char *propname, int index,
+ u32 *outp)
+{
+ return ofnode_read_u32_index(dev_ofnode(dev), propname, index, outp);
+}
+
+u32 dev_read_u32_index_default(struct udevice *dev, const char *propname,
+ int index, u32 def)
+{
+ return ofnode_read_u32_index_default(dev_ofnode(dev), propname, index,
+ def);
+}
+
+int dev_read_s32(const struct udevice *dev, const char *propname, s32 *outp)
+{
+ return ofnode_read_u32(dev_ofnode(dev), propname, (u32 *)outp);
+}
+
+int dev_read_s32_default(const struct udevice *dev, const char *propname,
+ int def)
+{
+ return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
+}
+
+int dev_read_u32u(const struct udevice *dev, const char *propname, uint *outp)
+{
+ u32 val;
+ int ret;
+
+ ret = ofnode_read_u32(dev_ofnode(dev), propname, &val);
+ if (ret)
+ return ret;
+ *outp = val;
+
+ return 0;
+}
+
+int dev_read_u64(const struct udevice *dev, const char *propname, u64 *outp)
+{
+ return ofnode_read_u64(dev_ofnode(dev), propname, outp);
+}
+
+u64 dev_read_u64_default(const struct udevice *dev, const char *propname,
+ u64 def)
+{
+ return ofnode_read_u64_default(dev_ofnode(dev), propname, def);
+}
+
+const char *dev_read_string(const struct udevice *dev, const char *propname)
+{
+ return ofnode_read_string(dev_ofnode(dev), propname);
+}
+
+bool dev_read_bool(const struct udevice *dev, const char *propname)
+{
+ return ofnode_read_bool(dev_ofnode(dev), propname);
+}
+
+ofnode dev_read_subnode(const struct udevice *dev, const char *subnode_name)
+{
+ return ofnode_find_subnode(dev_ofnode(dev), subnode_name);
+}
+
+ofnode dev_read_first_subnode(const struct udevice *dev)
+{
+ return ofnode_first_subnode(dev_ofnode(dev));
+}
+
+ofnode dev_read_next_subnode(ofnode node)
+{
+ return ofnode_next_subnode(node);
+}
+
+int dev_read_size(const struct udevice *dev, const char *propname)
+{
+ return ofnode_read_size(dev_ofnode(dev), propname);
+}
+
+fdt_addr_t dev_read_addr_index(const struct udevice *dev, int index)
+{
+ if (ofnode_is_np(dev_ofnode(dev)))
+ return ofnode_get_addr_index(dev_ofnode(dev), index);
+ else
+ return devfdt_get_addr_index(dev, index);
+}
+
+fdt_addr_t dev_read_addr_size_index(const struct udevice *dev, int index,
+ fdt_size_t *size)
+{
+ if (ofnode_is_np(dev_ofnode(dev)))
+ return ofnode_get_addr_size_index(dev_ofnode(dev), index, size);
+ else
+ return devfdt_get_addr_size_index(dev, index, size);
+}
+
+void *dev_remap_addr_index(const struct udevice *dev, int index)
+{
+ fdt_addr_t addr = dev_read_addr_index(dev, index);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_physmem(addr, 0, MAP_NOCACHE);
+}
+
+fdt_addr_t dev_read_addr_name(const struct udevice *dev, const char *name)
+{
+ int index = dev_read_stringlist_search(dev, "reg-names", name);
+
+ if (index < 0)
+ return FDT_ADDR_T_NONE;
+ else
+ return dev_read_addr_index(dev, index);
+}
+
+fdt_addr_t dev_read_addr_size_name(const struct udevice *dev, const char *name,
+ fdt_size_t *size)
+{
+ int index = dev_read_stringlist_search(dev, "reg-names", name);
+
+ if (index < 0)
+ return FDT_ADDR_T_NONE;
+ else
+ return dev_read_addr_size_index(dev, index, size);
+}
+
+void *dev_remap_addr_name(const struct udevice *dev, const char *name)
+{
+ fdt_addr_t addr = dev_read_addr_name(dev, name);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_physmem(addr, 0, MAP_NOCACHE);
+}
+
+fdt_addr_t dev_read_addr(const struct udevice *dev)
+{
+ return dev_read_addr_index(dev, 0);
+}
+
+void *dev_read_addr_ptr(const struct udevice *dev)
+{
+ fdt_addr_t addr = dev_read_addr(dev);
+
+ return (addr == FDT_ADDR_T_NONE) ? NULL : (void *)(uintptr_t)addr;
+}
+
+void *dev_remap_addr(const struct udevice *dev)
+{
+ return dev_remap_addr_index(dev, 0);
+}
+
+fdt_addr_t dev_read_addr_size(const struct udevice *dev, const char *property,
+ fdt_size_t *sizep)
+{
+ return ofnode_get_addr_size(dev_ofnode(dev), property, sizep);
+}
+
+const char *dev_read_name(const struct udevice *dev)
+{
+ return ofnode_get_name(dev_ofnode(dev));
+}
+
+int dev_read_stringlist_search(const struct udevice *dev, const char *property,
+ const char *string)
+{
+ return ofnode_stringlist_search(dev_ofnode(dev), property, string);
+}
+
+int dev_read_string_index(const struct udevice *dev, const char *propname,
+ int index, const char **outp)
+{
+ return ofnode_read_string_index(dev_ofnode(dev), propname, index, outp);
+}
+
+int dev_read_string_count(const struct udevice *dev, const char *propname)
+{
+ return ofnode_read_string_count(dev_ofnode(dev), propname);
+}
+
+int dev_read_phandle_with_args(const struct udevice *dev, const char *list_name,
+ const char *cells_name, int cell_count,
+ int index, struct ofnode_phandle_args *out_args)
+{
+ return ofnode_parse_phandle_with_args(dev_ofnode(dev), list_name,
+ cells_name, cell_count, index,
+ out_args);
+}
+
+int dev_count_phandle_with_args(const struct udevice *dev,
+ const char *list_name, const char *cells_name,
+ int cell_count)
+{
+ return ofnode_count_phandle_with_args(dev_ofnode(dev), list_name,
+ cells_name, cell_count);
+}
+
+int dev_read_addr_cells(const struct udevice *dev)
+{
+ return ofnode_read_addr_cells(dev_ofnode(dev));
+}
+
+int dev_read_size_cells(const struct udevice *dev)
+{
+ return ofnode_read_size_cells(dev_ofnode(dev));
+}
+
+int dev_read_simple_addr_cells(const struct udevice *dev)
+{
+ return ofnode_read_simple_addr_cells(dev_ofnode(dev));
+}
+
+int dev_read_simple_size_cells(const struct udevice *dev)
+{
+ return ofnode_read_simple_size_cells(dev_ofnode(dev));
+}
+
+int dev_read_phandle(const struct udevice *dev)
+{
+ ofnode node = dev_ofnode(dev);
+
+ if (ofnode_is_np(node))
+ return ofnode_to_np(node)->phandle;
+ else
+ return fdt_get_phandle(gd->fdt_blob, ofnode_to_offset(node));
+}
+
+const void *dev_read_prop(const struct udevice *dev, const char *propname,
+ int *lenp)
+{
+ return ofnode_get_property(dev_ofnode(dev), propname, lenp);
+}
+
+int dev_read_first_prop(const struct udevice *dev, struct ofprop *prop)
+{
+ return ofnode_get_first_property(dev_ofnode(dev), prop);
+}
+
+int dev_read_next_prop(struct ofprop *prop)
+{
+ return ofnode_get_next_property(prop);
+}
+
+const void *dev_read_prop_by_prop(struct ofprop *prop,
+ const char **propname, int *lenp)
+{
+ return ofnode_get_property_by_prop(prop, propname, lenp);
+}
+
+int dev_read_alias_seq(const struct udevice *dev, int *devnump)
+{
+ ofnode node = dev_ofnode(dev);
+ const char *uc_name = dev->uclass->uc_drv->name;
+ int ret = -ENOTSUPP;
+
+ if (ofnode_is_np(node)) {
+ ret = of_alias_get_id(ofnode_to_np(node), uc_name);
+ if (ret >= 0) {
+ *devnump = ret;
+ ret = 0;
+ }
+ } else {
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ ret = fdtdec_get_alias_seq(gd->fdt_blob, uc_name,
+ ofnode_to_offset(node), devnump);
+#endif
+ }
+
+ return ret;
+}
+
+int dev_read_u32_array(const struct udevice *dev, const char *propname,
+ u32 *out_values, size_t sz)
+{
+ return ofnode_read_u32_array(dev_ofnode(dev), propname, out_values, sz);
+}
+
+const uint8_t *dev_read_u8_array_ptr(const struct udevice *dev,
+ const char *propname, size_t sz)
+{
+ return ofnode_read_u8_array_ptr(dev_ofnode(dev), propname, sz);
+}
+
+int dev_read_enabled(const struct udevice *dev)
+{
+ ofnode node = dev_ofnode(dev);
+
+ if (ofnode_is_np(node))
+ return of_device_is_available(ofnode_to_np(node));
+ else
+ return fdtdec_get_is_enabled(gd->fdt_blob,
+ ofnode_to_offset(node));
+}
+
+int dev_read_resource(const struct udevice *dev, uint index,
+ struct resource *res)
+{
+ return ofnode_read_resource(dev_ofnode(dev), index, res);
+}
+
+int dev_read_resource_byname(const struct udevice *dev, const char *name,
+ struct resource *res)
+{
+ return ofnode_read_resource_byname(dev_ofnode(dev), name, res);
+}
+
+u64 dev_translate_address(const struct udevice *dev, const fdt32_t *in_addr)
+{
+ return ofnode_translate_address(dev_ofnode(dev), in_addr);
+}
+
+u64 dev_translate_dma_address(const struct udevice *dev, const fdt32_t *in_addr)
+{
+ return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
+}
+
+int dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size)
+{
+ return ofnode_get_dma_range(dev_ofnode(dev), cpu, bus, size);
+}
+
+int dev_read_alias_highest_id(const char *stem)
+{
+ if (of_live_active())
+ return of_alias_get_highest_id(stem);
+
+ return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
+}
+
+fdt_addr_t dev_read_addr_pci(const struct udevice *dev)
+{
+ ulong addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE && !of_live_active())
+ addr = devfdt_get_addr_pci(dev);
+
+ return addr;
+}
+
+int dev_get_child_count(const struct udevice *dev)
+{
+ return ofnode_get_child_count(dev_ofnode(dev));
+}
+
+int dev_read_pci_bus_range(const struct udevice *dev,
+ struct resource *res)
+{
+ const u32 *values;
+ int len;
+
+ values = dev_read_prop(dev, "bus-range", &len);
+ if (!values || len < sizeof(*values) * 2)
+ return -EINVAL;
+
+ res->start = *values++;
+ res->end = *values;
+
+ return 0;
+}
+
+int dev_decode_display_timing(const struct udevice *dev, int index,
+ struct display_timing *config)
+{
+ return ofnode_decode_display_timing(dev_ofnode(dev), index, config);
+}
diff --git a/roms/u-boot/drivers/core/read_extra.c b/roms/u-boot/drivers/core/read_extra.c
new file mode 100644
index 000000000..513834882
--- /dev/null
+++ b/roms/u-boot/drivers/core/read_extra.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/of_addr.h>
+#include <dm/read.h>
+#include <linux/ioport.h>
+
+/* This file can hold non-inlined dev_read_...() functions */
diff --git a/roms/u-boot/drivers/core/regmap.c b/roms/u-boot/drivers/core/regmap.c
new file mode 100644
index 000000000..3206f3d11
--- /dev/null
+++ b/roms/u-boot/drivers/core/regmap.c
@@ -0,0 +1,688 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/libfdt.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <regmap.h>
+#include <asm/io.h>
+#include <dm/of_addr.h>
+#include <dm/devres.h>
+#include <linux/ioport.h>
+#include <linux/compat.h>
+#include <linux/err.h>
+#include <linux/bitops.h>
+
+/*
+ * Internal representation of a regmap field. Instead of storing the MSB and
+ * LSB, store the shift and mask. This makes the code a bit cleaner and faster
+ * because the shift and mask don't have to be calculated every time.
+ */
+struct regmap_field {
+ struct regmap *regmap;
+ unsigned int mask;
+ /* lsb */
+ unsigned int shift;
+ unsigned int reg;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * regmap_alloc() - Allocate a regmap with a given number of ranges.
+ *
+ * @count: Number of ranges to be allocated for the regmap.
+ *
+ * The default regmap width is set to REGMAP_SIZE_32. Callers can override it
+ * if they need.
+ *
+ * Return: A pointer to the newly allocated regmap, or NULL on error.
+ */
+static struct regmap *regmap_alloc(int count)
+{
+ struct regmap *map;
+ size_t size = sizeof(*map) + sizeof(map->ranges[0]) * count;
+
+ map = calloc(1, size);
+ if (!map)
+ return NULL;
+ map->range_count = count;
+ map->width = REGMAP_SIZE_32;
+
+ return map;
+}
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+int regmap_init_mem_plat(struct udevice *dev, fdt_val_t *reg, int count,
+ struct regmap **mapp)
+{
+ struct regmap_range *range;
+ struct regmap *map;
+
+ map = regmap_alloc(count);
+ if (!map)
+ return -ENOMEM;
+
+ for (range = map->ranges; count > 0; reg += 2, range++, count--) {
+ range->start = *reg;
+ range->size = reg[1];
+ }
+
+ *mapp = map;
+
+ return 0;
+}
+#else
+/**
+ * init_range() - Initialize a single range of a regmap
+ * @node: Device node that will use the map in question
+ * @range: Pointer to a regmap_range structure that will be initialized
+ * @addr_len: The length of the addr parts of the reg property
+ * @size_len: The length of the size parts of the reg property
+ * @index: The index of the range to initialize
+ *
+ * This function will read the necessary 'reg' information from the device tree
+ * (the 'addr' part, and the 'length' part), and initialize the range in
+ * quesion.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+static int init_range(ofnode node, struct regmap_range *range, int addr_len,
+ int size_len, int index)
+{
+ fdt_size_t sz;
+ struct resource r;
+
+ if (of_live_active()) {
+ int ret;
+
+ ret = of_address_to_resource(ofnode_to_np(node),
+ index, &r);
+ if (ret) {
+ debug("%s: Could not read resource of range %d (ret = %d)\n",
+ ofnode_get_name(node), index, ret);
+ return ret;
+ }
+
+ range->start = r.start;
+ range->size = r.end - r.start + 1;
+ } else {
+ int offset = ofnode_to_offset(node);
+
+ range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob, offset,
+ "reg", index,
+ addr_len, size_len,
+ &sz, true);
+ if (range->start == FDT_ADDR_T_NONE) {
+ debug("%s: Could not read start of range %d\n",
+ ofnode_get_name(node), index);
+ return -EINVAL;
+ }
+
+ range->size = sz;
+ }
+
+ return 0;
+}
+
+int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index)
+{
+ struct regmap *map;
+ int addr_len, size_len;
+ int ret;
+
+ addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
+ if (addr_len < 0) {
+ debug("%s: Error while reading the addr length (ret = %d)\n",
+ ofnode_get_name(node), addr_len);
+ return addr_len;
+ }
+
+ size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
+ if (size_len < 0) {
+ debug("%s: Error while reading the size length: (ret = %d)\n",
+ ofnode_get_name(node), size_len);
+ return size_len;
+ }
+
+ map = regmap_alloc(1);
+ if (!map)
+ return -ENOMEM;
+
+ ret = init_range(node, map->ranges, addr_len, size_len, index);
+ if (ret)
+ goto err;
+
+ if (ofnode_read_bool(node, "little-endian"))
+ map->endianness = REGMAP_LITTLE_ENDIAN;
+ else if (ofnode_read_bool(node, "big-endian"))
+ map->endianness = REGMAP_BIG_ENDIAN;
+ else if (ofnode_read_bool(node, "native-endian"))
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+ else /* Default: native endianness */
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+
+ *mapp = map;
+
+ return 0;
+err:
+ regmap_uninit(map);
+
+ return ret;
+}
+
+int regmap_init_mem_range(ofnode node, ulong r_start, ulong r_size,
+ struct regmap **mapp)
+{
+ struct regmap *map;
+ struct regmap_range *range;
+
+ map = regmap_alloc(1);
+ if (!map)
+ return -ENOMEM;
+
+ range = &map->ranges[0];
+ range->start = r_start;
+ range->size = r_size;
+
+ if (ofnode_read_bool(node, "little-endian"))
+ map->endianness = REGMAP_LITTLE_ENDIAN;
+ else if (ofnode_read_bool(node, "big-endian"))
+ map->endianness = REGMAP_BIG_ENDIAN;
+ else if (ofnode_read_bool(node, "native-endian"))
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+ else /* Default: native endianness */
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+
+ *mapp = map;
+ return 0;
+}
+
+int regmap_init_mem(ofnode node, struct regmap **mapp)
+{
+ struct regmap_range *range;
+ struct regmap *map;
+ int count;
+ int addr_len, size_len, both_len;
+ int len;
+ int index;
+ int ret;
+
+ addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
+ if (addr_len < 0) {
+ debug("%s: Error while reading the addr length (ret = %d)\n",
+ ofnode_get_name(node), addr_len);
+ return addr_len;
+ }
+
+ size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
+ if (size_len < 0) {
+ debug("%s: Error while reading the size length: (ret = %d)\n",
+ ofnode_get_name(node), size_len);
+ return size_len;
+ }
+
+ both_len = addr_len + size_len;
+ if (!both_len) {
+ debug("%s: Both addr and size length are zero\n",
+ ofnode_get_name(node));
+ return -EINVAL;
+ }
+
+ len = ofnode_read_size(node, "reg");
+ if (len < 0) {
+ debug("%s: Error while reading reg size (ret = %d)\n",
+ ofnode_get_name(node), len);
+ return len;
+ }
+ len /= sizeof(fdt32_t);
+ count = len / both_len;
+ if (!count) {
+ debug("%s: Not enough data in reg property\n",
+ ofnode_get_name(node));
+ return -EINVAL;
+ }
+
+ map = regmap_alloc(count);
+ if (!map)
+ return -ENOMEM;
+
+ for (range = map->ranges, index = 0; count > 0;
+ count--, range++, index++) {
+ ret = init_range(node, range, addr_len, size_len, index);
+ if (ret)
+ goto err;
+ }
+
+ if (ofnode_read_bool(node, "little-endian"))
+ map->endianness = REGMAP_LITTLE_ENDIAN;
+ else if (ofnode_read_bool(node, "big-endian"))
+ map->endianness = REGMAP_BIG_ENDIAN;
+ else if (ofnode_read_bool(node, "native-endian"))
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+ else /* Default: native endianness */
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+
+ *mapp = map;
+
+ return 0;
+err:
+ regmap_uninit(map);
+
+ return ret;
+}
+
+static void devm_regmap_release(struct udevice *dev, void *res)
+{
+ regmap_uninit(*(struct regmap **)res);
+}
+
+struct regmap *devm_regmap_init(struct udevice *dev,
+ const struct regmap_bus *bus,
+ void *bus_context,
+ const struct regmap_config *config)
+{
+ int rc;
+ struct regmap **mapp, *map;
+
+ mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *),
+ __GFP_ZERO);
+ if (unlikely(!mapp))
+ return ERR_PTR(-ENOMEM);
+
+ if (config && config->r_size != 0)
+ rc = regmap_init_mem_range(dev_ofnode(dev), config->r_start,
+ config->r_size, mapp);
+ else
+ rc = regmap_init_mem(dev_ofnode(dev), mapp);
+ if (rc)
+ return ERR_PTR(rc);
+
+ map = *mapp;
+ if (config) {
+ map->width = config->width;
+ map->reg_offset_shift = config->reg_offset_shift;
+ }
+
+ devres_add(dev, mapp);
+ return *mapp;
+}
+#endif
+
+void *regmap_get_range(struct regmap *map, unsigned int range_num)
+{
+ struct regmap_range *range;
+
+ if (range_num >= map->range_count)
+ return NULL;
+ range = &map->ranges[range_num];
+
+ return map_sysmem(range->start, range->size);
+}
+
+int regmap_uninit(struct regmap *map)
+{
+ free(map);
+
+ return 0;
+}
+
+static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness)
+{
+ return readb(addr);
+}
+
+static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness)
+{
+ switch (endianness) {
+ case REGMAP_LITTLE_ENDIAN:
+ return in_le16(addr);
+ case REGMAP_BIG_ENDIAN:
+ return in_be16(addr);
+ case REGMAP_NATIVE_ENDIAN:
+ return readw(addr);
+ }
+
+ return readw(addr);
+}
+
+static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness)
+{
+ switch (endianness) {
+ case REGMAP_LITTLE_ENDIAN:
+ return in_le32(addr);
+ case REGMAP_BIG_ENDIAN:
+ return in_be32(addr);
+ case REGMAP_NATIVE_ENDIAN:
+ return readl(addr);
+ }
+
+ return readl(addr);
+}
+
+#if defined(in_le64) && defined(in_be64) && defined(readq)
+static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness)
+{
+ switch (endianness) {
+ case REGMAP_LITTLE_ENDIAN:
+ return in_le64(addr);
+ case REGMAP_BIG_ENDIAN:
+ return in_be64(addr);
+ case REGMAP_NATIVE_ENDIAN:
+ return readq(addr);
+ }
+
+ return readq(addr);
+}
+#endif
+
+int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
+ void *valp, size_t val_len)
+{
+ struct regmap_range *range;
+ void *ptr;
+
+ if (range_num >= map->range_count) {
+ debug("%s: range index %d larger than range count\n",
+ __func__, range_num);
+ return -ERANGE;
+ }
+ range = &map->ranges[range_num];
+
+ offset <<= map->reg_offset_shift;
+ if (offset + val_len > range->size) {
+ debug("%s: offset/size combination invalid\n", __func__);
+ return -ERANGE;
+ }
+
+ ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
+
+ switch (val_len) {
+ case REGMAP_SIZE_8:
+ *((u8 *)valp) = __read_8(ptr, map->endianness);
+ break;
+ case REGMAP_SIZE_16:
+ *((u16 *)valp) = __read_16(ptr, map->endianness);
+ break;
+ case REGMAP_SIZE_32:
+ *((u32 *)valp) = __read_32(ptr, map->endianness);
+ break;
+#if defined(in_le64) && defined(in_be64) && defined(readq)
+ case REGMAP_SIZE_64:
+ *((u64 *)valp) = __read_64(ptr, map->endianness);
+ break;
+#endif
+ default:
+ debug("%s: regmap size %zu unknown\n", __func__, val_len);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
+{
+ return regmap_raw_read_range(map, 0, offset, valp, val_len);
+}
+
+int regmap_read(struct regmap *map, uint offset, uint *valp)
+{
+ union {
+ u8 v8;
+ u16 v16;
+ u32 v32;
+ u64 v64;
+ } u;
+ int res;
+
+ res = regmap_raw_read(map, offset, &u, map->width);
+ if (res)
+ return res;
+
+ switch (map->width) {
+ case REGMAP_SIZE_8:
+ *valp = u.v8;
+ break;
+ case REGMAP_SIZE_16:
+ *valp = u.v16;
+ break;
+ case REGMAP_SIZE_32:
+ *valp = u.v32;
+ break;
+ case REGMAP_SIZE_64:
+ *valp = u.v64;
+ break;
+ default:
+ unreachable();
+ }
+
+ return 0;
+}
+
+static inline void __write_8(u8 *addr, const u8 *val,
+ enum regmap_endianness_t endianness)
+{
+ writeb(*val, addr);
+}
+
+static inline void __write_16(u16 *addr, const u16 *val,
+ enum regmap_endianness_t endianness)
+{
+ switch (endianness) {
+ case REGMAP_NATIVE_ENDIAN:
+ writew(*val, addr);
+ break;
+ case REGMAP_LITTLE_ENDIAN:
+ out_le16(addr, *val);
+ break;
+ case REGMAP_BIG_ENDIAN:
+ out_be16(addr, *val);
+ break;
+ }
+}
+
+static inline void __write_32(u32 *addr, const u32 *val,
+ enum regmap_endianness_t endianness)
+{
+ switch (endianness) {
+ case REGMAP_NATIVE_ENDIAN:
+ writel(*val, addr);
+ break;
+ case REGMAP_LITTLE_ENDIAN:
+ out_le32(addr, *val);
+ break;
+ case REGMAP_BIG_ENDIAN:
+ out_be32(addr, *val);
+ break;
+ }
+}
+
+#if defined(out_le64) && defined(out_be64) && defined(writeq)
+static inline void __write_64(u64 *addr, const u64 *val,
+ enum regmap_endianness_t endianness)
+{
+ switch (endianness) {
+ case REGMAP_NATIVE_ENDIAN:
+ writeq(*val, addr);
+ break;
+ case REGMAP_LITTLE_ENDIAN:
+ out_le64(addr, *val);
+ break;
+ case REGMAP_BIG_ENDIAN:
+ out_be64(addr, *val);
+ break;
+ }
+}
+#endif
+
+int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
+ const void *val, size_t val_len)
+{
+ struct regmap_range *range;
+ void *ptr;
+
+ if (range_num >= map->range_count) {
+ debug("%s: range index %d larger than range count\n",
+ __func__, range_num);
+ return -ERANGE;
+ }
+ range = &map->ranges[range_num];
+
+ offset <<= map->reg_offset_shift;
+ if (offset + val_len > range->size) {
+ debug("%s: offset/size combination invalid\n", __func__);
+ return -ERANGE;
+ }
+
+ ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
+
+ switch (val_len) {
+ case REGMAP_SIZE_8:
+ __write_8(ptr, val, map->endianness);
+ break;
+ case REGMAP_SIZE_16:
+ __write_16(ptr, val, map->endianness);
+ break;
+ case REGMAP_SIZE_32:
+ __write_32(ptr, val, map->endianness);
+ break;
+#if defined(out_le64) && defined(out_be64) && defined(writeq)
+ case REGMAP_SIZE_64:
+ __write_64(ptr, val, map->endianness);
+ break;
+#endif
+ default:
+ debug("%s: regmap size %zu unknown\n", __func__, val_len);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int regmap_raw_write(struct regmap *map, uint offset, const void *val,
+ size_t val_len)
+{
+ return regmap_raw_write_range(map, 0, offset, val, val_len);
+}
+
+int regmap_write(struct regmap *map, uint offset, uint val)
+{
+ union {
+ u8 v8;
+ u16 v16;
+ u32 v32;
+ u64 v64;
+ } u;
+
+ switch (map->width) {
+ case REGMAP_SIZE_8:
+ u.v8 = val;
+ break;
+ case REGMAP_SIZE_16:
+ u.v16 = val;
+ break;
+ case REGMAP_SIZE_32:
+ u.v32 = val;
+ break;
+ case REGMAP_SIZE_64:
+ u.v64 = val;
+ break;
+ default:
+ debug("%s: regmap size %zu unknown\n", __func__,
+ (size_t)map->width);
+ return -EINVAL;
+ }
+
+ return regmap_raw_write(map, offset, &u, map->width);
+}
+
+int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
+{
+ uint reg;
+ int ret;
+
+ ret = regmap_read(map, offset, &reg);
+ if (ret)
+ return ret;
+
+ reg &= ~mask;
+
+ return regmap_write(map, offset, reg | (val & mask));
+}
+
+int regmap_field_read(struct regmap_field *field, unsigned int *val)
+{
+ int ret;
+ unsigned int reg_val;
+
+ ret = regmap_read(field->regmap, field->reg, &reg_val);
+ if (ret != 0)
+ return ret;
+
+ reg_val &= field->mask;
+ reg_val >>= field->shift;
+ *val = reg_val;
+
+ return ret;
+}
+
+int regmap_field_write(struct regmap_field *field, unsigned int val)
+{
+ return regmap_update_bits(field->regmap, field->reg, field->mask,
+ val << field->shift);
+}
+
+static void regmap_field_init(struct regmap_field *rm_field,
+ struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ rm_field->regmap = regmap;
+ rm_field->reg = reg_field.reg;
+ rm_field->shift = reg_field.lsb;
+ rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
+}
+
+struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
+ struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field),
+ GFP_KERNEL);
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+
+void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field)
+{
+ devm_kfree(dev, field);
+}
+
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
+
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+
+void regmap_field_free(struct regmap_field *field)
+{
+ kfree(field);
+}
diff --git a/roms/u-boot/drivers/core/root.c b/roms/u-boot/drivers/core/root.c
new file mode 100644
index 000000000..fe0562cd6
--- /dev/null
+++ b/roms/u-boot/drivers/core/root.c
@@ -0,0 +1,433 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm-generic/sections.h>
+#include <asm/global_data.h>
+#include <linux/libfdt.h>
+#include <dm/acpi.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/of.h>
+#include <dm/of_access.h>
+#include <dm/platdata.h>
+#include <dm/read.h>
+#include <dm/root.h>
+#include <dm/uclass.h>
+#include <dm/util.h>
+#include <linux/list.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct driver_info root_info = {
+ .name = "root_driver",
+};
+
+struct udevice *dm_root(void)
+{
+ if (!gd->dm_root) {
+ dm_warn("Virtual root driver does not exist!\n");
+ return NULL;
+ }
+
+ return gd->dm_root;
+}
+
+void dm_fixup_for_gd_move(struct global_data *new_gd)
+{
+ /* The sentinel node has moved, so update things that point to it */
+ if (gd->dm_root) {
+ new_gd->uclass_root->next->prev = new_gd->uclass_root;
+ new_gd->uclass_root->prev->next = new_gd->uclass_root;
+ }
+}
+
+void fix_drivers(void)
+{
+ struct driver *drv =
+ ll_entry_start(struct driver, driver);
+ const int n_ents = ll_entry_count(struct driver, driver);
+ struct driver *entry;
+
+ for (entry = drv; entry != drv + n_ents; entry++) {
+ if (entry->of_match)
+ entry->of_match = (const struct udevice_id *)
+ ((ulong)entry->of_match + gd->reloc_off);
+ if (entry->bind)
+ entry->bind += gd->reloc_off;
+ if (entry->probe)
+ entry->probe += gd->reloc_off;
+ if (entry->remove)
+ entry->remove += gd->reloc_off;
+ if (entry->unbind)
+ entry->unbind += gd->reloc_off;
+ if (entry->of_to_plat)
+ entry->of_to_plat += gd->reloc_off;
+ if (entry->child_post_bind)
+ entry->child_post_bind += gd->reloc_off;
+ if (entry->child_pre_probe)
+ entry->child_pre_probe += gd->reloc_off;
+ if (entry->child_post_remove)
+ entry->child_post_remove += gd->reloc_off;
+ /* OPS are fixed in every uclass post_probe function */
+ if (entry->ops)
+ entry->ops += gd->reloc_off;
+ }
+}
+
+void fix_uclass(void)
+{
+ struct uclass_driver *uclass =
+ ll_entry_start(struct uclass_driver, uclass_driver);
+ const int n_ents = ll_entry_count(struct uclass_driver, uclass_driver);
+ struct uclass_driver *entry;
+
+ for (entry = uclass; entry != uclass + n_ents; entry++) {
+ if (entry->post_bind)
+ entry->post_bind += gd->reloc_off;
+ if (entry->pre_unbind)
+ entry->pre_unbind += gd->reloc_off;
+ if (entry->pre_probe)
+ entry->pre_probe += gd->reloc_off;
+ if (entry->post_probe)
+ entry->post_probe += gd->reloc_off;
+ if (entry->pre_remove)
+ entry->pre_remove += gd->reloc_off;
+ if (entry->child_post_bind)
+ entry->child_post_bind += gd->reloc_off;
+ if (entry->child_pre_probe)
+ entry->child_pre_probe += gd->reloc_off;
+ if (entry->init)
+ entry->init += gd->reloc_off;
+ if (entry->destroy)
+ entry->destroy += gd->reloc_off;
+ /* FIXME maybe also need to fix these ops */
+ if (entry->ops)
+ entry->ops += gd->reloc_off;
+ }
+}
+
+void fix_devices(void)
+{
+ struct driver_info *dev =
+ ll_entry_start(struct driver_info, driver_info);
+ const int n_ents = ll_entry_count(struct driver_info, driver_info);
+ struct driver_info *entry;
+
+ for (entry = dev; entry != dev + n_ents; entry++) {
+ if (entry->plat)
+ entry->plat += gd->reloc_off;
+ }
+}
+
+static int dm_setup_inst(void)
+{
+ DM_ROOT_NON_CONST = DM_DEVICE_GET(root);
+
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) {
+ struct udevice_rt *urt;
+ void *base;
+ int n_ents;
+ uint size;
+
+ /* Allocate the udevice_rt table */
+ n_ents = ll_entry_count(struct udevice, udevice);
+ urt = calloc(n_ents, sizeof(struct udevice_rt));
+ if (!urt)
+ return log_msg_ret("urt", -ENOMEM);
+ gd_set_dm_udevice_rt(urt);
+
+ /* Now allocate space for the priv/plat data, and copy it in */
+ size = __priv_data_end - __priv_data_start;
+
+ base = calloc(1, size);
+ if (!base)
+ return log_msg_ret("priv", -ENOMEM);
+ memcpy(base, __priv_data_start, size);
+ gd_set_dm_priv_base(base);
+ }
+
+ return 0;
+}
+
+int dm_init(bool of_live)
+{
+ int ret;
+
+ if (gd->dm_root) {
+ dm_warn("Virtual root driver already exists!\n");
+ return -EINVAL;
+ }
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+ gd->uclass_root = &uclass_head;
+ } else {
+ gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST;
+ INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST);
+ }
+
+ if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) {
+ fix_drivers();
+ fix_uclass();
+ fix_devices();
+ }
+
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+ ret = dm_setup_inst();
+ if (ret) {
+ log_debug("dm_setup_inst() failed: %d\n", ret);
+ return ret;
+ }
+ } else {
+ ret = device_bind_by_name(NULL, false, &root_info,
+ &DM_ROOT_NON_CONST);
+ if (ret)
+ return ret;
+ if (CONFIG_IS_ENABLED(OF_CONTROL))
+ dev_set_ofnode(DM_ROOT_NON_CONST, ofnode_root());
+ ret = device_probe(DM_ROOT_NON_CONST);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int dm_uninit(void)
+{
+ /* Remove non-vital devices first */
+ device_remove(dm_root(), DM_REMOVE_NON_VITAL);
+ device_remove(dm_root(), DM_REMOVE_NORMAL);
+ device_unbind(dm_root());
+ gd->dm_root = NULL;
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
+int dm_remove_devices_flags(uint flags)
+{
+ device_remove(dm_root(), flags);
+
+ return 0;
+}
+#endif
+
+int dm_scan_plat(bool pre_reloc_only)
+{
+ int ret;
+
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)) {
+ struct driver_rt *dyn;
+ int n_ents;
+
+ n_ents = ll_entry_count(struct driver_info, driver_info);
+ dyn = calloc(n_ents, sizeof(struct driver_rt));
+ if (!dyn)
+ return -ENOMEM;
+ gd_set_dm_driver_rt(dyn);
+ }
+
+ ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only);
+ if (ret == -ENOENT) {
+ dm_warn("Some drivers were not found\n");
+ ret = 0;
+ }
+
+ return ret;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+/**
+ * dm_scan_fdt_node() - Scan the device tree and bind drivers for a node
+ *
+ * This scans the subnodes of a device tree node and and creates a driver
+ * for each one.
+ *
+ * @parent: Parent device for the devices that will be created
+ * @node: Node to scan
+ * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
+ * flag. If false bind all drivers.
+ * @return 0 if OK, -ve on error
+ */
+static int dm_scan_fdt_node(struct udevice *parent, ofnode parent_node,
+ bool pre_reloc_only)
+{
+ int ret = 0, err = 0;
+ ofnode node;
+
+ if (!ofnode_valid(parent_node))
+ return 0;
+
+ for (node = ofnode_first_subnode(parent_node);
+ ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ const char *node_name = ofnode_get_name(node);
+
+ if (!ofnode_is_enabled(node)) {
+ pr_debug(" - ignoring disabled device\n");
+ continue;
+ }
+ err = lists_bind_fdt(parent, node, NULL, pre_reloc_only);
+ if (err && !ret) {
+ ret = err;
+ debug("%s: ret=%d\n", node_name, ret);
+ }
+ }
+
+ if (ret)
+ dm_warn("Some drivers failed to bind\n");
+
+ return ret;
+}
+
+int dm_scan_fdt_dev(struct udevice *dev)
+{
+ return dm_scan_fdt_node(dev, dev_ofnode(dev),
+ gd->flags & GD_FLG_RELOC ? false : true);
+}
+
+int dm_scan_fdt(bool pre_reloc_only)
+{
+ return dm_scan_fdt_node(gd->dm_root, ofnode_root(), pre_reloc_only);
+}
+
+static int dm_scan_fdt_ofnode_path(const char *path, bool pre_reloc_only)
+{
+ ofnode node;
+
+ node = ofnode_path(path);
+
+ return dm_scan_fdt_node(gd->dm_root, node, pre_reloc_only);
+}
+
+int dm_extended_scan(bool pre_reloc_only)
+{
+ int ret, i;
+ const char * const nodes[] = {
+ "/chosen",
+ "/clocks",
+ "/firmware"
+ };
+
+ ret = dm_scan_fdt(pre_reloc_only);
+ if (ret) {
+ debug("dm_scan_fdt() failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Some nodes aren't devices themselves but may contain some */
+ for (i = 0; i < ARRAY_SIZE(nodes); i++) {
+ ret = dm_scan_fdt_ofnode_path(nodes[i], pre_reloc_only);
+ if (ret) {
+ debug("dm_scan_fdt() scan for %s failed: %d\n",
+ nodes[i], ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+#endif
+
+__weak int dm_scan_other(bool pre_reloc_only)
+{
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY)
+void *dm_priv_to_rw(void *priv)
+{
+ long offset = priv - (void *)__priv_data_start;
+
+ return gd_dm_priv_base() + offset;
+}
+#endif
+
+/**
+ * dm_scan() - Scan tables to bind devices
+ *
+ * Runs through the driver_info tables and binds the devices it finds. Then runs
+ * through the devicetree nodes. Finally calls dm_scan_other() to add any
+ * special devices
+ *
+ * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
+ * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
+ */
+static int dm_scan(bool pre_reloc_only)
+{
+ int ret;
+
+ ret = dm_scan_plat(pre_reloc_only);
+ if (ret) {
+ debug("dm_scan_plat() failed: %d\n", ret);
+ return ret;
+ }
+
+ if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ ret = dm_extended_scan(pre_reloc_only);
+ if (ret) {
+ debug("dm_extended_scan() failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = dm_scan_other(pre_reloc_only);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int dm_init_and_scan(bool pre_reloc_only)
+{
+ int ret;
+
+ ret = dm_init(CONFIG_IS_ENABLED(OF_LIVE));
+ if (ret) {
+ debug("dm_init() failed: %d\n", ret);
+ return ret;
+ }
+ if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+ ret = dm_scan(pre_reloc_only);
+ if (ret) {
+ log_debug("dm_scan() failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_ACPIGEN
+static int root_acpi_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "\\_SB");
+}
+
+struct acpi_ops root_acpi_ops = {
+ .get_name = root_acpi_get_name,
+};
+#endif
+
+/* This is the root driver - all drivers are children of this */
+U_BOOT_DRIVER(root_driver) = {
+ .name = "root_driver",
+ .id = UCLASS_ROOT,
+ ACPI_OPS_PTR(&root_acpi_ops)
+};
+
+/* This is the root uclass */
+UCLASS_DRIVER(root) = {
+ .name = "root",
+ .id = UCLASS_ROOT,
+};
diff --git a/roms/u-boot/drivers/core/simple-bus.c b/roms/u-boot/drivers/core/simple-bus.c
new file mode 100644
index 000000000..18f52d26d
--- /dev/null
+++ b/roms/u-boot/drivers/core/simple-bus.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Google, Inc
+ */
+
+#include <common.h>
+#include <asm/global_data.h>
+#include <dm.h>
+#include <dm/simple_bus.h>
+#include <fdt_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr)
+{
+ struct simple_bus_plat *plat = dev_get_uclass_plat(dev);
+
+ if (addr >= plat->base && addr < plat->base + plat->size)
+ addr = (addr - plat->base) + plat->target;
+
+ return addr;
+}
+
+static int simple_bus_post_bind(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ return 0;
+#else
+ struct simple_bus_plat *plat = dev_get_uclass_plat(dev);
+ int ret;
+
+ if (CONFIG_IS_ENABLED(SIMPLE_BUS_CORRECT_RANGE)) {
+ uint64_t caddr, paddr, len;
+
+ /* only read range index 0 */
+ ret = fdt_read_range((void *)gd->fdt_blob, dev_of_offset(dev),
+ 0, &caddr, &paddr, &len);
+ if (!ret) {
+ plat->base = caddr;
+ plat->target = paddr;
+ plat->size = len;
+ }
+ } else {
+ u32 cell[3];
+
+ ret = dev_read_u32_array(dev, "ranges", cell,
+ ARRAY_SIZE(cell));
+ if (!ret) {
+ plat->base = cell[0];
+ plat->target = cell[1];
+ plat->size = cell[2];
+ }
+ }
+
+ return dm_scan_fdt_dev(dev);
+#endif
+}
+
+UCLASS_DRIVER(simple_bus) = {
+ .id = UCLASS_SIMPLE_BUS,
+ .name = "simple_bus",
+ .post_bind = simple_bus_post_bind,
+ .per_device_plat_auto = sizeof(struct simple_bus_plat),
+};
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+static const struct udevice_id generic_simple_bus_ids[] = {
+ { .compatible = "simple-bus" },
+ { .compatible = "simple-mfd" },
+ { }
+};
+#endif
+
+U_BOOT_DRIVER(simple_bus) = {
+ .name = "simple_bus",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = of_match_ptr(generic_simple_bus_ids),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/core/simple-pm-bus.c b/roms/u-boot/drivers/core/simple-pm-bus.c
new file mode 100644
index 000000000..1bb0d86e2
--- /dev/null
+++ b/roms/u-boot/drivers/core/simple-pm-bus.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+
+/*
+ * Power domains are taken care of by driver_probe, so we just have to enable
+ * clocks
+ */
+static int simple_pm_bus_probe(struct udevice *dev)
+{
+ int ret;
+ struct clk_bulk *bulk = dev_get_priv(dev);
+
+ ret = clk_get_bulk(dev, bulk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable_bulk(bulk);
+ if (ret && ret != -ENOSYS) {
+ clk_release_bulk(bulk);
+ return ret;
+ }
+ return 0;
+}
+
+static int simple_pm_bus_remove(struct udevice *dev)
+{
+ int ret;
+ struct clk_bulk *bulk = dev_get_priv(dev);
+
+ ret = clk_release_bulk(bulk);
+ if (ret && ret != -ENOSYS)
+ return ret;
+ else
+ return 0;
+}
+
+static const struct udevice_id simple_pm_bus_ids[] = {
+ { .compatible = "simple-pm-bus" },
+ { }
+};
+
+U_BOOT_DRIVER(simple_pm_bus_drv) = {
+ .name = "simple_pm_bus",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = simple_pm_bus_ids,
+ .probe = simple_pm_bus_probe,
+ .remove = simple_pm_bus_remove,
+ .priv_auto = sizeof(struct clk_bulk),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/core/syscon-uclass.c b/roms/u-boot/drivers/core/syscon-uclass.c
new file mode 100644
index 000000000..cb33facc7
--- /dev/null
+++ b/roms/u-boot/drivers/core/syscon-uclass.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY UCLASS_SYSCON
+
+#include <common.h>
+#include <log.h>
+#include <syscon.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/err.h>
+
+/*
+ * Caution:
+ * This API requires the given device has already been bound to the syscon
+ * driver. For example,
+ *
+ * compatible = "syscon", "simple-mfd";
+ *
+ * works, but
+ *
+ * compatible = "simple-mfd", "syscon";
+ *
+ * does not. The behavior is different from Linux.
+ */
+struct regmap *syscon_get_regmap(struct udevice *dev)
+{
+ struct syscon_uc_info *priv;
+
+ if (device_get_uclass_id(dev) != UCLASS_SYSCON)
+ return ERR_PTR(-ENOEXEC);
+ priv = dev_get_uclass_priv(dev);
+ return priv->regmap;
+}
+
+static int syscon_pre_probe(struct udevice *dev)
+{
+ struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
+
+ /* Special case for PCI devices, which don't have a regmap */
+ if (device_get_uclass_id(dev->parent) == UCLASS_PCI)
+ return 0;
+
+ /*
+ * With OF_PLATDATA we really have no way of knowing the format of
+ * the device-specific platform data. So we assume that it starts with
+ * a 'reg' member, and this holds a single address and size. Drivers
+ * using OF_PLATDATA will need to ensure that this is true.
+ */
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct syscon_base_plat *plat = dev_get_plat(dev);
+
+ return regmap_init_mem_plat(dev, plat->reg, ARRAY_SIZE(plat->reg),
+ &priv->regmap);
+#else
+ return regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+#endif
+}
+
+static int syscon_probe_by_ofnode(ofnode node, struct udevice **devp)
+{
+ struct udevice *dev, *parent;
+ int ret;
+
+ /* found node with "syscon" compatible, not bounded to SYSCON UCLASS */
+ if (!ofnode_device_is_compatible(node, "syscon")) {
+ log_debug("invalid compatible for syscon device\n");
+ return -EINVAL;
+ }
+
+ /* bound to driver with same ofnode or to root if not found */
+ if (device_find_global_by_ofnode(node, &parent))
+ parent = dm_root();
+
+ /* force bound to syscon class */
+ ret = device_bind_driver_to_node(parent, "syscon",
+ ofnode_get_name(node),
+ node, &dev);
+ if (ret) {
+ dev_dbg(dev, "unable to bound syscon device\n");
+ return ret;
+ }
+ ret = device_probe(dev);
+ if (ret) {
+ dev_dbg(dev, "unable to probe syscon device\n");
+ return ret;
+ }
+
+ *devp = dev;
+ return 0;
+}
+
+struct regmap *syscon_regmap_lookup_by_phandle(struct udevice *dev,
+ const char *name)
+{
+ struct udevice *syscon;
+ struct regmap *r;
+ u32 phandle;
+ ofnode node;
+ int err;
+
+ err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ name, &syscon);
+ if (err) {
+ /* found node with "syscon" compatible, not bounded to SYSCON */
+ err = ofnode_read_u32(dev_ofnode(dev), name, &phandle);
+ if (err)
+ return ERR_PTR(err);
+
+ node = ofnode_get_by_phandle(phandle);
+ if (!ofnode_valid(node)) {
+ dev_dbg(dev, "unable to find syscon device\n");
+ return ERR_PTR(-EINVAL);
+ }
+ err = syscon_probe_by_ofnode(node, &syscon);
+ if (err)
+ return ERR_PTR(-ENODEV);
+ }
+
+ r = syscon_get_regmap(syscon);
+ if (!r) {
+ dev_dbg(dev, "unable to find regmap\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ return r;
+}
+
+int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp)
+{
+ int ret;
+
+ *devp = NULL;
+
+ ret = uclass_first_device_drvdata(UCLASS_SYSCON, driver_data, devp);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data)
+{
+ struct syscon_uc_info *priv;
+ struct udevice *dev;
+ int ret;
+
+ ret = syscon_get_by_driver_data(driver_data, &dev);
+ if (ret)
+ return ERR_PTR(ret);
+ priv = dev_get_uclass_priv(dev);
+
+ return priv->regmap;
+}
+
+void *syscon_get_first_range(ulong driver_data)
+{
+ struct regmap *map;
+
+ map = syscon_get_regmap_by_driver_data(driver_data);
+ if (IS_ERR(map))
+ return map;
+ return regmap_get_range(map, 0);
+}
+
+UCLASS_DRIVER(syscon) = {
+ .id = UCLASS_SYSCON,
+ .name = "syscon",
+ .per_device_auto = sizeof(struct syscon_uc_info),
+ .pre_probe = syscon_pre_probe,
+};
+
+static const struct udevice_id generic_syscon_ids[] = {
+ { .compatible = "syscon" },
+ { }
+};
+
+U_BOOT_DRIVER(generic_syscon) = {
+ .name = "syscon",
+ .id = UCLASS_SYSCON,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .bind = dm_scan_fdt_dev,
+#endif
+ .of_match = generic_syscon_ids,
+};
+
+/*
+ * Linux-compatible syscon-to-regmap
+ * The syscon node can be bound to another driver, but still works
+ * as a syscon provider.
+ */
+struct regmap *syscon_node_to_regmap(ofnode node)
+{
+ struct udevice *dev;
+ struct regmap *r;
+
+ if (uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev))
+ if (syscon_probe_by_ofnode(node, &dev))
+ return ERR_PTR(-ENODEV);
+
+ r = syscon_get_regmap(dev);
+ if (!r) {
+ dev_dbg(dev, "unable to find regmap\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ return r;
+}
diff --git a/roms/u-boot/drivers/core/uclass.c b/roms/u-boot/drivers/core/uclass.c
new file mode 100644
index 000000000..117d35ac4
--- /dev/null
+++ b/roms/u-boot/drivers/core/uclass.c
@@ -0,0 +1,786 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ */
+
+#define LOG_CATEGORY LOGC_DM
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass.h>
+#include <dm/uclass-internal.h>
+#include <dm/util.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct uclass *uclass_find(enum uclass_id key)
+{
+ struct uclass *uc;
+
+ if (!gd->dm_root)
+ return NULL;
+ /*
+ * TODO(sjg@chromium.org): Optimise this, perhaps moving the found
+ * node to the start of the list, or creating a linear array mapping
+ * id to node.
+ */
+ list_for_each_entry(uc, gd->uclass_root, sibling_node) {
+ if (uc->uc_drv->id == key)
+ return uc;
+ }
+
+ return NULL;
+}
+
+/**
+ * uclass_add() - Create new uclass in list
+ * @id: Id number to create
+ * @ucp: Returns pointer to uclass, or NULL on error
+ * @return 0 on success, -ve on error
+ *
+ * The new uclass is added to the list. There must be only one uclass for
+ * each id.
+ */
+static int uclass_add(enum uclass_id id, struct uclass **ucp)
+{
+ struct uclass_driver *uc_drv;
+ struct uclass *uc;
+ int ret;
+
+ *ucp = NULL;
+ uc_drv = lists_uclass_lookup(id);
+ if (!uc_drv) {
+ debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
+ id);
+ /*
+ * Use a strange error to make this case easier to find. When
+ * a uclass is not available it can prevent driver model from
+ * starting up and this failure is otherwise hard to debug.
+ */
+ return -EPFNOSUPPORT;
+ }
+ uc = calloc(1, sizeof(*uc));
+ if (!uc)
+ return -ENOMEM;
+ if (uc_drv->priv_auto) {
+ void *ptr;
+
+ ptr = calloc(1, uc_drv->priv_auto);
+ if (!ptr) {
+ ret = -ENOMEM;
+ goto fail_mem;
+ }
+ uclass_set_priv(uc, ptr);
+ }
+ uc->uc_drv = uc_drv;
+ INIT_LIST_HEAD(&uc->sibling_node);
+ INIT_LIST_HEAD(&uc->dev_head);
+ list_add(&uc->sibling_node, DM_UCLASS_ROOT_NON_CONST);
+
+ if (uc_drv->init) {
+ ret = uc_drv->init(uc);
+ if (ret)
+ goto fail;
+ }
+
+ *ucp = uc;
+
+ return 0;
+fail:
+ if (uc_drv->priv_auto) {
+ free(uclass_get_priv(uc));
+ uclass_set_priv(uc, NULL);
+ }
+ list_del(&uc->sibling_node);
+fail_mem:
+ free(uc);
+
+ return ret;
+}
+
+int uclass_destroy(struct uclass *uc)
+{
+ struct uclass_driver *uc_drv;
+ struct udevice *dev;
+ int ret;
+
+ /*
+ * We cannot use list_for_each_entry_safe() here. If a device in this
+ * uclass has a child device also in this uclass, it will be also be
+ * unbound (by the recursion in the call to device_unbind() below).
+ * We can loop until the list is empty.
+ */
+ while (!list_empty(&uc->dev_head)) {
+ dev = list_first_entry(&uc->dev_head, struct udevice,
+ uclass_node);
+ ret = device_remove(dev, DM_REMOVE_NORMAL | DM_REMOVE_NO_PD);
+ if (ret)
+ return log_msg_ret("remove", ret);
+ ret = device_unbind(dev);
+ if (ret)
+ return log_msg_ret("unbind", ret);
+ }
+
+ uc_drv = uc->uc_drv;
+ if (uc_drv->destroy)
+ uc_drv->destroy(uc);
+ list_del(&uc->sibling_node);
+ if (uc_drv->priv_auto)
+ free(uclass_get_priv(uc));
+ free(uc);
+
+ return 0;
+}
+
+int uclass_get(enum uclass_id id, struct uclass **ucp)
+{
+ struct uclass *uc;
+
+ *ucp = NULL;
+ uc = uclass_find(id);
+ if (!uc) {
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_INST))
+ return -ENOENT;
+ return uclass_add(id, ucp);
+ }
+ *ucp = uc;
+
+ return 0;
+}
+
+const char *uclass_get_name(enum uclass_id id)
+{
+ struct uclass *uc;
+
+ if (uclass_get(id, &uc))
+ return NULL;
+ return uc->uc_drv->name;
+}
+
+void *uclass_get_priv(const struct uclass *uc)
+{
+ return uc->priv_;
+}
+
+void uclass_set_priv(struct uclass *uc, void *priv)
+{
+ uc->priv_ = priv;
+}
+
+enum uclass_id uclass_get_by_name(const char *name)
+{
+ int i;
+
+ for (i = 0; i < UCLASS_COUNT; i++) {
+ struct uclass_driver *uc_drv = lists_uclass_lookup(i);
+
+ if (uc_drv && !strcmp(uc_drv->name, name))
+ return i;
+ }
+
+ return UCLASS_INVALID;
+}
+
+int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
+{
+ struct udevice *iter;
+ struct uclass *uc = dev->uclass;
+ int i = 0;
+
+ if (list_empty(&uc->dev_head))
+ return -ENODEV;
+
+ uclass_foreach_dev(iter, uc) {
+ if (iter == dev) {
+ if (ucp)
+ *ucp = uc;
+ return i;
+ }
+ i++;
+ }
+
+ return -ENODEV;
+}
+
+int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
+{
+ struct uclass *uc;
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+ if (list_empty(&uc->dev_head))
+ return -ENODEV;
+
+ uclass_foreach_dev(dev, uc) {
+ if (!index--) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int uclass_find_first_device(enum uclass_id id, struct udevice **devp)
+{
+ struct uclass *uc;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+ if (list_empty(&uc->dev_head))
+ return 0;
+
+ *devp = list_first_entry(&uc->dev_head, struct udevice, uclass_node);
+
+ return 0;
+}
+
+int uclass_find_next_device(struct udevice **devp)
+{
+ struct udevice *dev = *devp;
+
+ *devp = NULL;
+ if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head))
+ return 0;
+
+ *devp = list_entry(dev->uclass_node.next, struct udevice, uclass_node);
+
+ return 0;
+}
+
+int uclass_find_device_by_name(enum uclass_id id, const char *name,
+ struct udevice **devp)
+{
+ struct uclass *uc;
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ if (!name)
+ return -EINVAL;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(dev, uc) {
+ if (!strcmp(dev->name, name)) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int uclass_find_next_free_seq(struct uclass *uc)
+{
+ struct udevice *dev;
+ int max = -1;
+
+ /* If using aliases, start with the highest alias value */
+ if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
+ (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS))
+ max = dev_read_alias_highest_id(uc->uc_drv->name);
+
+ /* Avoid conflict with existing devices */
+ list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+ if (dev->seq_ > max)
+ max = dev->seq_;
+ }
+ /*
+ * At this point, max will be -1 if there are no existing aliases or
+ * devices
+ */
+
+ return max + 1;
+}
+
+int uclass_find_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
+{
+ struct uclass *uc;
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ log_debug("%d\n", seq);
+ if (seq == -1)
+ return -ENODEV;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(dev, uc) {
+ log_debug(" - %d '%s'\n", dev->seq_, dev->name);
+ if (dev->seq_ == seq) {
+ *devp = dev;
+ log_debug(" - found\n");
+ return 0;
+ }
+ }
+ log_debug(" - not found\n");
+
+ return -ENODEV;
+}
+
+int uclass_find_device_by_of_offset(enum uclass_id id, int node,
+ struct udevice **devp)
+{
+ struct uclass *uc;
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ if (node < 0)
+ return -ENODEV;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(dev, uc) {
+ if (dev_of_offset(dev) == node) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node,
+ struct udevice **devp)
+{
+ struct uclass *uc;
+ struct udevice *dev;
+ int ret;
+
+ log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node));
+ *devp = NULL;
+ if (!ofnode_valid(node))
+ return -ENODEV;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(dev, uc) {
+ log(LOGC_DM, LOGL_DEBUG_CONTENT, " - checking %s\n",
+ dev->name);
+ if (ofnode_equal(dev_ofnode(dev), node)) {
+ *devp = dev;
+ goto done;
+ }
+ }
+ ret = -ENODEV;
+
+done:
+ log(LOGC_DM, LOGL_DEBUG, " - result for %s: %s (ret=%d)\n",
+ ofnode_get_name(node), *devp ? (*devp)->name : "(none)", ret);
+ return ret;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
+ const char *name, struct udevice **devp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int find_phandle;
+ int ret;
+
+ *devp = NULL;
+ find_phandle = dev_read_u32_default(parent, name, -1);
+ if (find_phandle <= 0)
+ return -ENOENT;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(dev, uc) {
+ uint phandle;
+
+ phandle = dev_read_phandle(dev);
+
+ if (phandle == find_phandle) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+#endif
+
+int uclass_get_device_by_driver(enum uclass_id id,
+ const struct driver *find_drv,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(dev, uc) {
+ if (dev->driver == find_drv)
+ return uclass_get_device_tail(dev, 0, devp);
+ }
+
+ return -ENODEV;
+}
+
+int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp)
+{
+ if (ret)
+ return ret;
+
+ assert(dev);
+ ret = device_probe(dev);
+ if (ret)
+ return ret;
+
+ *devp = dev;
+
+ return 0;
+}
+
+int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_device(id, index, &dev);
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+int uclass_get_device_by_name(enum uclass_id id, const char *name,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_device_by_name(id, name, &dev);
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_device_by_seq(id, seq, &dev);
+
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+int uclass_get_device_by_of_offset(enum uclass_id id, int node,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_device_by_of_offset(id, node, &dev);
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node));
+ *devp = NULL;
+ ret = uclass_find_device_by_ofnode(id, node, &dev);
+ log(LOGC_DM, LOGL_DEBUG, " - result for %s: %s (ret=%d)\n",
+ ofnode_get_name(node), dev ? dev->name : "(none)", ret);
+
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(dev, uc) {
+ uint phandle;
+
+ phandle = dev_read_phandle(dev);
+
+ if (phandle == phandle_id) {
+ *devp = dev;
+ return uclass_get_device_tail(dev, ret, devp);
+ }
+ }
+
+ return -ENODEV;
+}
+
+int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
+ const char *name, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_device_by_phandle(id, parent, name, &dev);
+ return uclass_get_device_tail(dev, ret, devp);
+}
+#endif
+
+int uclass_first_device(enum uclass_id id, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_first_device(id, &dev);
+ if (!dev)
+ return 0;
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+int uclass_first_device_err(enum uclass_id id, struct udevice **devp)
+{
+ int ret;
+
+ ret = uclass_first_device(id, devp);
+ if (ret)
+ return ret;
+ else if (!*devp)
+ return -ENODEV;
+
+ return 0;
+}
+
+int uclass_next_device(struct udevice **devp)
+{
+ struct udevice *dev = *devp;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_next_device(&dev);
+ if (!dev)
+ return 0;
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+int uclass_next_device_err(struct udevice **devp)
+{
+ int ret;
+
+ ret = uclass_next_device(devp);
+ if (ret)
+ return ret;
+ else if (!*devp)
+ return -ENODEV;
+
+ return 0;
+}
+
+int uclass_first_device_check(enum uclass_id id, struct udevice **devp)
+{
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_first_device(id, devp);
+ if (ret)
+ return ret;
+ if (!*devp)
+ return 0;
+
+ return device_probe(*devp);
+}
+
+int uclass_next_device_check(struct udevice **devp)
+{
+ int ret;
+
+ ret = uclass_find_next_device(devp);
+ if (ret)
+ return ret;
+ if (!*devp)
+ return 0;
+
+ return device_probe(*devp);
+}
+
+int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+
+ uclass_id_foreach_dev(id, dev, uc) {
+ if (dev_get_driver_data(dev) == driver_data) {
+ *devp = dev;
+
+ return device_probe(dev);
+ }
+ }
+
+ return -ENODEV;
+}
+
+int uclass_bind_device(struct udevice *dev)
+{
+ struct uclass *uc;
+ int ret;
+
+ uc = dev->uclass;
+ list_add_tail(&dev->uclass_node, &uc->dev_head);
+
+ if (dev->parent) {
+ struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv;
+
+ if (uc_drv->child_post_bind) {
+ ret = uc_drv->child_post_bind(dev);
+ if (ret)
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ /* There is no need to undo the parent's post_bind call */
+ list_del(&dev->uclass_node);
+
+ return ret;
+}
+
+#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
+int uclass_unbind_device(struct udevice *dev)
+{
+ struct uclass *uc;
+ int ret;
+
+ uc = dev->uclass;
+ if (uc->uc_drv->pre_unbind) {
+ ret = uc->uc_drv->pre_unbind(dev);
+ if (ret)
+ return ret;
+ }
+
+ list_del(&dev->uclass_node);
+ return 0;
+}
+#endif
+
+int uclass_pre_probe_device(struct udevice *dev)
+{
+ struct uclass_driver *uc_drv;
+ int ret;
+
+ uc_drv = dev->uclass->uc_drv;
+ if (uc_drv->pre_probe) {
+ ret = uc_drv->pre_probe(dev);
+ if (ret)
+ return ret;
+ }
+
+ if (!dev->parent)
+ return 0;
+ uc_drv = dev->parent->uclass->uc_drv;
+ if (uc_drv->child_pre_probe) {
+ ret = uc_drv->child_pre_probe(dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int uclass_post_probe_device(struct udevice *dev)
+{
+ struct uclass_driver *uc_drv;
+ int ret;
+
+ if (dev->parent) {
+ uc_drv = dev->parent->uclass->uc_drv;
+ if (uc_drv->child_post_probe) {
+ ret = uc_drv->child_post_probe(dev);
+ if (ret)
+ return ret;
+ }
+ }
+
+ uc_drv = dev->uclass->uc_drv;
+ if (uc_drv->post_probe) {
+ ret = uc_drv->post_probe(dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
+int uclass_pre_remove_device(struct udevice *dev)
+{
+ struct uclass *uc;
+ int ret;
+
+ uc = dev->uclass;
+ if (uc->uc_drv->pre_remove) {
+ ret = uc->uc_drv->pre_remove(dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+int uclass_probe_all(enum uclass_id id)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_first_device(id, &dev);
+ if (ret || !dev)
+ return ret;
+
+ /* Scanning uclass to probe all devices */
+ while (dev) {
+ ret = uclass_next_device(&dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+UCLASS_DRIVER(nop) = {
+ .id = UCLASS_NOP,
+ .name = "nop",
+};
diff --git a/roms/u-boot/drivers/core/util.c b/roms/u-boot/drivers/core/util.c
new file mode 100644
index 000000000..91e93b0cf
--- /dev/null
+++ b/roms/u-boot/drivers/core/util.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013 Google, Inc
+ */
+
+#include <common.h>
+#include <dm/device.h>
+#include <dm/ofnode.h>
+#include <dm/read.h>
+#include <dm/util.h>
+#include <linux/libfdt.h>
+#include <vsprintf.h>
+
+#if CONFIG_IS_ENABLED(DM_WARN)
+void dm_warn(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+}
+#endif
+
+int list_count_items(struct list_head *head)
+{
+ struct list_head *node;
+ int count = 0;
+
+ list_for_each(node, head)
+ count++;
+
+ return count;
+}
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+int pci_get_devfn(struct udevice *dev)
+{
+ struct fdt_pci_addr addr;
+ int ret;
+
+ /* Extract the devfn from fdt_pci_addr */
+ ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
+ "reg", &addr);
+ if (ret) {
+ if (ret != -ENOENT)
+ return -EINVAL;
+ }
+
+ return addr.phys_hi & 0xff00;
+}
+#endif