summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/dts/exynos4210-pinctrl-uboot.dtsi2
-rw-r--r--arch/arm/dts/exynos4x12-pinctrl-uboot.dtsi2
-rw-r--r--arch/arm/dts/exynos5250-pinctrl-uboot.dtsi2
-rw-r--r--arch/arm/dts/exynos54xx-pinctrl-uboot.dtsi2
-rw-r--r--arch/arm/dts/s5pc100-pinctrl.dtsi2
-rw-r--r--arch/arm/dts/s5pc110-pinctrl.dtsi2
-rw-r--r--arch/sandbox/cpu/cpu.c41
-rw-r--r--arch/sandbox/include/asm/bitops.h2
-rw-r--r--arch/sandbox/include/asm/u-boot-sandbox.h8
-rw-r--r--common/board_f.c84
-rw-r--r--common/dlmalloc.c11
-rw-r--r--common/spl/spl.c22
-rw-r--r--doc/driver-model/README.txt58
-rw-r--r--drivers/core/Kconfig9
-rw-r--r--drivers/core/device-remove.c4
-rw-r--r--drivers/core/device.c103
-rw-r--r--drivers/core/root.c14
-rw-r--r--drivers/core/uclass.c122
-rw-r--r--drivers/serial/Kconfig10
-rw-r--r--drivers/serial/ns16550.c36
-rw-r--r--drivers/serial/serial-uclass.c2
-rw-r--r--drivers/usb/emul/sandbox_hub.c1
-rw-r--r--dts/Kconfig11
-rw-r--r--include/config_uncmd_spl.h1
-rw-r--r--include/dm/device.h38
-rw-r--r--include/dm/test.h20
-rw-r--r--include/dm/uclass-internal.h108
-rw-r--r--include/dm/uclass.h19
-rw-r--r--include/fdtdec.h16
-rw-r--r--include/malloc.h3
-rw-r--r--include/vsprintf.h23
-rw-r--r--lib/Makefile6
-rw-r--r--lib/fdtdec.c39
-rw-r--r--lib/vsprintf.c23
-rw-r--r--test/dm/core.c175
-rw-r--r--test/dm/test-uclass.c11
36 files changed, 815 insertions, 217 deletions
diff --git a/arch/arm/dts/exynos4210-pinctrl-uboot.dtsi b/arch/arm/dts/exynos4210-pinctrl-uboot.dtsi
index f9b61ba8e8..0ff41d0028 100644
--- a/arch/arm/dts/exynos4210-pinctrl-uboot.dtsi
+++ b/arch/arm/dts/exynos4210-pinctrl-uboot.dtsi
@@ -2,6 +2,8 @@
* U-Boot additions to enable a generic Exynos GPIO driver
*
* Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
*/
/{
diff --git a/arch/arm/dts/exynos4x12-pinctrl-uboot.dtsi b/arch/arm/dts/exynos4x12-pinctrl-uboot.dtsi
index c41d07b65f..8e5a6c6118 100644
--- a/arch/arm/dts/exynos4x12-pinctrl-uboot.dtsi
+++ b/arch/arm/dts/exynos4x12-pinctrl-uboot.dtsi
@@ -2,6 +2,8 @@
* U-Boot additions to enable a generic Exynos GPIO driver
*
* Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
*/
/{
diff --git a/arch/arm/dts/exynos5250-pinctrl-uboot.dtsi b/arch/arm/dts/exynos5250-pinctrl-uboot.dtsi
index 7edb0ca290..068c5f696f 100644
--- a/arch/arm/dts/exynos5250-pinctrl-uboot.dtsi
+++ b/arch/arm/dts/exynos5250-pinctrl-uboot.dtsi
@@ -2,6 +2,8 @@
* U-Boot additions to enable a generic Exynos GPIO driver
*
* Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
*/
/{
diff --git a/arch/arm/dts/exynos54xx-pinctrl-uboot.dtsi b/arch/arm/dts/exynos54xx-pinctrl-uboot.dtsi
index 5a86211d4a..635a1b0d3a 100644
--- a/arch/arm/dts/exynos54xx-pinctrl-uboot.dtsi
+++ b/arch/arm/dts/exynos54xx-pinctrl-uboot.dtsi
@@ -2,6 +2,8 @@
* U-Boot additions to enable a generic Exynos GPIO driver
*
* Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
*/
/{
diff --git a/arch/arm/dts/s5pc100-pinctrl.dtsi b/arch/arm/dts/s5pc100-pinctrl.dtsi
index bd9f97c97b..975386969e 100644
--- a/arch/arm/dts/s5pc100-pinctrl.dtsi
+++ b/arch/arm/dts/s5pc100-pinctrl.dtsi
@@ -2,6 +2,8 @@
* U-Boot additions to enable a generic Exynos GPIO driver
*
* Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
*/
/ {
diff --git a/arch/arm/dts/s5pc110-pinctrl.dtsi b/arch/arm/dts/s5pc110-pinctrl.dtsi
index d21b6ab756..2e9d552daa 100644
--- a/arch/arm/dts/s5pc110-pinctrl.dtsi
+++ b/arch/arm/dts/s5pc110-pinctrl.dtsi
@@ -2,6 +2,8 @@
* U-Boot additions to enable a generic Exynos GPIO driver
*
* Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
*/
/ {
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index f0dafedc25..168f2efa33 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <dm/root.h>
#include <os.h>
+#include <asm/io.h>
#include <asm/state.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -97,3 +98,43 @@ phys_addr_t map_to_sysmem(const void *ptr)
void flush_dcache_range(unsigned long start, unsigned long stop)
{
}
+
+int sandbox_read_fdt_from_file(void)
+{
+ struct sandbox_state *state = state_get_current();
+ const char *fname = state->fdt_fname;
+ void *blob;
+ loff_t size;
+ int err;
+ int fd;
+
+ blob = map_sysmem(CONFIG_SYS_FDT_LOAD_ADDR, 0);
+ if (!state->fdt_fname) {
+ err = fdt_create_empty_tree(blob, 256);
+ if (!err)
+ goto done;
+ printf("Unable to create empty FDT: %s\n", fdt_strerror(err));
+ return -EINVAL;
+ }
+
+ err = os_get_filesize(fname, &size);
+ if (err < 0) {
+ printf("Failed to file FDT file '%s'\n", fname);
+ return err;
+ }
+ fd = os_open(fname, OS_O_RDONLY);
+ if (fd < 0) {
+ printf("Failed to open FDT file '%s'\n", fname);
+ return -EACCES;
+ }
+ if (os_read(fd, blob, size) != size) {
+ os_close(fd);
+ return -EIO;
+ }
+ os_close(fd);
+
+done:
+ gd->fdt_blob = blob;
+
+ return 0;
+}
diff --git a/arch/sandbox/include/asm/bitops.h b/arch/sandbox/include/asm/bitops.h
index e807c4ef34..f1a7aeee93 100644
--- a/arch/sandbox/include/asm/bitops.h
+++ b/arch/sandbox/include/asm/bitops.h
@@ -1,6 +1,8 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
*
+ * Modified from Linux arch/arm/include/asm/bitops.h
+ *
* Copyright 1995, Russell King.
* Various bits and pieces copyrights include:
* Linus Torvalds (test_bit).
diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h
index d5b9361683..da87cc3040 100644
--- a/arch/sandbox/include/asm/u-boot-sandbox.h
+++ b/arch/sandbox/include/asm/u-boot-sandbox.h
@@ -75,4 +75,12 @@ int pci_unmap_physmem(const void *addr, unsigned long len,
*/
void sandbox_set_enable_pci_map(int enable);
+/**
+ * sandbox_read_fdt_from_file() - Read a device tree from a file
+ *
+ * Read a device tree file from a host file and set it up for use as the
+ * control FDT.
+ */
+int sandbox_read_fdt_from_file(void);
+
#endif /* _U_BOOT_SANDBOX_H_ */
diff --git a/common/board_f.c b/common/board_f.c
index 775df1419e..322e0700d7 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -23,6 +23,7 @@
#include <i2c.h>
#include <initcall.h>
#include <logbuff.h>
+#include <malloc.h>
#include <mapmem.h>
/* TODO: Can we move these into arch/ headers? */
@@ -282,49 +283,6 @@ __weak int arch_cpu_init(void)
return 0;
}
-#ifdef CONFIG_OF_HOSTFILE
-
-static int read_fdt_from_file(void)
-{
- struct sandbox_state *state = state_get_current();
- const char *fname = state->fdt_fname;
- void *blob;
- loff_t size;
- int err;
- int fd;
-
- blob = map_sysmem(CONFIG_SYS_FDT_LOAD_ADDR, 0);
- if (!state->fdt_fname) {
- err = fdt_create_empty_tree(blob, 256);
- if (!err)
- goto done;
- printf("Unable to create empty FDT: %s\n", fdt_strerror(err));
- return -EINVAL;
- }
-
- err = os_get_filesize(fname, &size);
- if (err < 0) {
- printf("Failed to file FDT file '%s'\n", fname);
- return err;
- }
- fd = os_open(fname, OS_O_RDONLY);
- if (fd < 0) {
- printf("Failed to open FDT file '%s'\n", fname);
- return -EACCES;
- }
- if (os_read(fd, blob, size) != size) {
- os_close(fd);
- return -EIO;
- }
- os_close(fd);
-
-done:
- gd->fdt_blob = blob;
-
- return 0;
-}
-#endif
-
#ifdef CONFIG_SANDBOX
static int setup_ram_buf(void)
{
@@ -337,28 +295,6 @@ static int setup_ram_buf(void)
}
#endif
-static int setup_fdt(void)
-{
-#ifdef CONFIG_OF_CONTROL
-# ifdef CONFIG_OF_EMBED
- /* Get a pointer to the FDT */
- gd->fdt_blob = __dtb_dt_begin;
-# elif defined CONFIG_OF_SEPARATE
- /* FDT is at end of image */
- gd->fdt_blob = (ulong *)&_end;
-# elif defined(CONFIG_OF_HOSTFILE)
- if (read_fdt_from_file()) {
- puts("Failed to read control FDT\n");
- return -1;
- }
-# endif
- /* Allow the early environment to override the fdt address */
- gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
- (uintptr_t)gd->fdt_blob);
-#endif
- return 0;
-}
-
/* Get the top of usable RAM */
__weak ulong board_get_usable_ram_top(ulong total_size)
{
@@ -786,17 +722,6 @@ static int mark_bootstage(void)
return 0;
}
-static int initf_malloc(void)
-{
-#ifdef CONFIG_SYS_MALLOC_F_LEN
- assert(gd->malloc_base); /* Set up by crt0.S */
- gd->malloc_limit = gd->malloc_base + CONFIG_SYS_MALLOC_F_LEN;
- gd->malloc_ptr = 0;
-#endif
-
- return 0;
-}
-
static int initf_dm(void)
{
#if defined(CONFIG_DM) && defined(CONFIG_SYS_MALLOC_F_LEN)
@@ -826,7 +751,9 @@ static init_fnc_t init_sequence_f[] = {
setup_ram_buf,
#endif
setup_mon_len,
- setup_fdt,
+#ifdef CONFIG_OF_CONTROL
+ fdtdec_setup,
+#endif
#ifdef CONFIG_TRACE
trace_early_init,
#endif
@@ -837,9 +764,6 @@ static init_fnc_t init_sequence_f[] = {
#endif
arch_cpu_init, /* basic arch cpu dependent setup */
mark_bootstage,
-#ifdef CONFIG_OF_CONTROL
- fdtdec_check_fdt,
-#endif
initf_dm,
arch_cpu_init_dm,
#if defined(CONFIG_BOARD_EARLY_INIT_F)
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index b2ce063c5f..b5bb05191c 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -3261,6 +3261,17 @@ int mALLOPt(param_number, value) int param_number; int value;
}
}
+int initf_malloc(void)
+{
+#ifdef CONFIG_SYS_MALLOC_F_LEN
+ assert(gd->malloc_base); /* Set up by crt0.S */
+ gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;
+ gd->malloc_ptr = 0;
+#endif
+
+ return 0;
+}
+
/*
History:
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 8e1fb40c47..6a02c9ed96 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -151,6 +151,8 @@ static void spl_ram_load_image(void)
void board_init_r(gd_t *dummy1, ulong dummy2)
{
u32 boot_device;
+ int ret;
+
debug(">>spl:board_init_r()\n");
#if defined(CONFIG_SYS_SPL_MALLOC_START)
@@ -158,12 +160,24 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
CONFIG_SYS_SPL_MALLOC_SIZE);
gd->flags |= GD_FLG_FULL_MALLOC_INIT;
#elif defined(CONFIG_SYS_MALLOC_F_LEN)
- gd->malloc_limit = gd->malloc_base + CONFIG_SYS_MALLOC_F_LEN;
+ gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;
gd->malloc_ptr = 0;
#endif
-#ifdef CONFIG_SPL_DM
- dm_init_and_scan(true);
-#endif
+ if (IS_ENABLED(CONFIG_OF_CONTROL) &&
+ !IS_ENABLED(CONFIG_SPL_DISABLE_OF_CONTROL)) {
+ ret = fdtdec_setup();
+ if (ret) {
+ debug("fdtdec_setup() returned error %d\n", ret);
+ hang();
+ }
+ }
+ if (IS_ENABLED(CONFIG_SPL_DM)) {
+ ret = dm_init_and_scan(true);
+ if (ret) {
+ debug("dm_init_and_scan() returned error %d\n", ret);
+ hang();
+ }
+ }
#ifndef CONFIG_PPC
/*
diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index f83264d615..f0276b1b46 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,43 +95,82 @@ are provided in test/dm. To run them, try:
You should see something like this:
<...U-Boot banner...>
- Running 29 driver model tests
+ Running 53 driver model tests
Test: dm_test_autobind
Test: dm_test_autoprobe
+ Test: dm_test_bus_child_post_bind
+ Test: dm_test_bus_child_post_bind_uclass
+ Test: dm_test_bus_child_pre_probe_uclass
Test: dm_test_bus_children
- Device 'd-test': seq 3 is in use by 'b-test'
- Device 'c-test@0': seq 0 is in use by 'a-test'
- Device 'c-test@1': seq 1 is in use by 'd-test'
+ Device 'c-test@0': seq 0 is in use by 'd-test'
+ Device 'c-test@1': seq 1 is in use by 'f-test'
Test: dm_test_bus_children_funcs
Test: dm_test_bus_children_iterators
Test: dm_test_bus_parent_data
+ Test: dm_test_bus_parent_data_uclass
Test: dm_test_bus_parent_ops
+ Test: dm_test_bus_parent_platdata
+ Test: dm_test_bus_parent_platdata_uclass
Test: dm_test_children
+ Test: dm_test_device_get_uclass_id
+ Test: dm_test_eth
+ Using eth@10002000 device
+ Using eth@10003000 device
+ Using eth@10004000 device
+ Test: dm_test_eth_alias
+ Using eth@10002000 device
+ Using eth@10004000 device
+ Using eth@10002000 device
+ Using eth@10003000 device
+ Test: dm_test_eth_prime
+ Using eth@10003000 device
+ Using eth@10002000 device
+ Test: dm_test_eth_rotate
+
+ Error: eth@10004000 address not set.
+
+ Error: eth@10004000 address not set.
+ Using eth@10002000 device
+
+ Error: eth@10004000 address not set.
+
+ Error: eth@10004000 address not set.
+ Using eth@10004000 device
Test: dm_test_fdt
- Device 'd-test': seq 3 is in use by 'b-test'
Test: dm_test_fdt_offset
Test: dm_test_fdt_pre_reloc
Test: dm_test_fdt_uclass_seq
- Device 'd-test': seq 3 is in use by 'b-test'
- Device 'a-test': seq 0 is in use by 'd-test'
Test: dm_test_gpio
extra-gpios: get_value: error: gpio b5 not reserved
Test: dm_test_gpio_anon
Test: dm_test_gpio_copy
Test: dm_test_gpio_leak
extra-gpios: get_value: error: gpio b5 not reserved
+ Test: dm_test_gpio_phandles
Test: dm_test_gpio_requestf
+ Test: dm_test_i2c_bytewise
+ Test: dm_test_i2c_find
+ Test: dm_test_i2c_offset
+ Test: dm_test_i2c_offset_len
+ Test: dm_test_i2c_probe_empty
+ Test: dm_test_i2c_read_write
+ Test: dm_test_i2c_speed
Test: dm_test_leak
Test: dm_test_lifecycle
+ Test: dm_test_net_retry
+ Using eth@10004000 device
+ Using eth@10002000 device
+ Using eth@10004000 device
Test: dm_test_operations
Test: dm_test_ordering
+ Test: dm_test_pci_base
+ Test: dm_test_pci_swapcase
Test: dm_test_platdata
Test: dm_test_pre_reloc
Test: dm_test_remove
Test: dm_test_spi_find
Invalid chip select 0:0 (err=-19)
SF: Failed to get idcodes
- Device 'name-emul': seq 0 is in use by 'name-emul'
SF: Detected M25P16 with page size 256 Bytes, erase size 64 KiB, total 2 MiB
Test: dm_test_spi_flash
2097152 bytes written in 0 ms
@@ -150,6 +189,9 @@ You should see something like this:
SF: Detected M25P16 with page size 256 Bytes, erase size 64 KiB, total 2 MiB
Test: dm_test_uclass
Test: dm_test_uclass_before_ready
+ Test: dm_test_usb_base
+ Test: dm_test_usb_flash
+ USB-1: scanning bus 1 for devices... 2 USB Device(s) found
Failures: 0
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 75d182d27f..2861b43079 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -46,3 +46,12 @@ config DM_STDIO
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, to save code space in SPL.
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 7fee1c001e..6a16b4f690 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -92,6 +92,10 @@ int device_unbind(struct udevice *dev)
free(dev->platdata);
dev->platdata = NULL;
}
+ if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
+ free(dev->uclass_platdata);
+ dev->uclass_platdata = NULL;
+ }
if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
free(dev->parent_platdata);
dev->parent_platdata = NULL;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index ccaa99ca63..3b77d231d3 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -30,7 +30,7 @@ int device_bind(struct udevice *parent, const struct driver *drv,
{
struct udevice *dev;
struct uclass *uc;
- int ret = 0;
+ int size, ret = 0;
*devp = NULL;
if (!name)
@@ -56,21 +56,23 @@ int device_bind(struct udevice *parent, const struct driver *drv,
dev->seq = -1;
dev->req_seq = -1;
-#ifdef CONFIG_OF_CONTROL
- /*
- * Some devices, such as a SPI bus, I2C bus and serial ports are
- * numbered using aliases.
- *
- * This is just a 'requested' sequence, and will be
- * resolved (and ->seq updated) when the device is probed.
- */
- if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) {
- if (uc->uc_drv->name && of_offset != -1) {
- fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name,
- of_offset, &dev->req_seq);
+ if (IS_ENABLED(CONFIG_OF_CONTROL) && IS_ENABLED(CONFIG_DM_SEQ_ALIAS)) {
+ /*
+ * Some devices, such as a SPI bus, I2C bus and serial ports
+ * are numbered using aliases.
+ *
+ * This is just a 'requested' sequence, and will be
+ * resolved (and ->seq updated) when the device is probed.
+ */
+ if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) {
+ if (uc->uc_drv->name && of_offset != -1) {
+ fdtdec_get_alias_seq(gd->fdt_blob,
+ uc->uc_drv->name, of_offset,
+ &dev->req_seq);
+ }
}
}
-#endif
+
if (!dev->platdata && drv->platdata_auto_alloc_size) {
dev->flags |= DM_FLAG_ALLOC_PDATA;
dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
@@ -79,9 +81,19 @@ int device_bind(struct udevice *parent, const struct driver *drv,
goto fail_alloc1;
}
}
- if (parent) {
- int size = parent->driver->per_child_platdata_auto_alloc_size;
+ size = uc->uc_drv->per_device_platdata_auto_alloc_size;
+ if (size) {
+ dev->flags |= DM_FLAG_ALLOC_UCLASS_PDATA;
+ dev->uclass_platdata = calloc(1, size);
+ if (!dev->uclass_platdata) {
+ ret = -ENOMEM;
+ goto fail_alloc2;
+ }
+ }
+
+ if (parent) {
+ size = parent->driver->per_child_platdata_auto_alloc_size;
if (!size) {
size = parent->uclass->uc_drv->
per_child_platdata_auto_alloc_size;
@@ -91,7 +103,7 @@ int device_bind(struct udevice *parent, const struct driver *drv,
dev->parent_platdata = calloc(1, size);
if (!dev->parent_platdata) {
ret = -ENOMEM;
- goto fail_alloc2;
+ goto fail_alloc3;
}
}
}
@@ -123,21 +135,32 @@ int device_bind(struct udevice *parent, const struct driver *drv,
return 0;
fail_child_post_bind:
- if (drv->unbind && drv->unbind(dev)) {
- dm_warn("unbind() method failed on dev '%s' on error path\n",
- dev->name);
+ if (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 (uclass_unbind_device(dev)) {
- dm_warn("Failed to unbind dev '%s' on error path\n",
- dev->name);
+ if (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:
- list_del(&dev->sibling_node);
- if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
- free(dev->parent_platdata);
- dev->parent_platdata = NULL;
+ if (IS_ENABLED(DM_DEVICE_REMOVE)) {
+ list_del(&dev->sibling_node);
+ if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
+ free(dev->parent_platdata);
+ dev->parent_platdata = NULL;
+ }
+ }
+fail_alloc3:
+ if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
+ free(dev->uclass_platdata);
+ dev->uclass_platdata = NULL;
}
fail_alloc2:
if (dev->flags & DM_FLAG_ALLOC_PDATA) {
@@ -314,6 +337,16 @@ void *dev_get_parent_platdata(struct udevice *dev)
return dev->parent_platdata;
}
+void *dev_get_uclass_platdata(struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device", __func__);
+ return NULL;
+ }
+
+ return dev->uclass_platdata;
+}
+
void *dev_get_priv(struct udevice *dev)
{
if (!dev) {
@@ -474,11 +507,27 @@ ulong dev_get_driver_data(struct udevice *dev)
return dev->driver_data;
}
+const void *dev_get_driver_ops(struct udevice *dev)
+{
+ if (!dev || !dev->driver->ops)
+ return NULL;
+
+ return dev->driver->ops;
+}
+
enum uclass_id device_get_uclass_id(struct udevice *dev)
{
return dev->uclass->uc_drv->id;
}
+const char *dev_get_uclass_name(struct udevice *dev)
+{
+ if (!dev)
+ return NULL;
+
+ return dev->uclass->uc_drv->name;
+}
+
#ifdef CONFIG_OF_CONTROL
fdt_addr_t dev_get_addr(struct udevice *dev)
{
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 9b5c6bb10c..12d046051f 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -197,13 +197,15 @@ int dm_init_and_scan(bool pre_reloc_only)
debug("dm_scan_platdata() failed: %d\n", ret);
return ret;
}
-#ifdef CONFIG_OF_CONTROL
- ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
- if (ret) {
- debug("dm_scan_fdt() failed: %d\n", ret);
- return ret;
+
+ if (OF_CONTROL) {
+ ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
+ if (ret) {
+ debug("dm_scan_fdt() failed: %d\n", ret);
+ return ret;
+ }
}
-#endif
+
ret = dm_scan_other(pre_reloc_only);
if (ret)
return ret;
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 98c15e585d..04e939d6c1 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -99,10 +99,18 @@ fail_mem:
int uclass_destroy(struct uclass *uc)
{
struct uclass_driver *uc_drv;
- struct udevice *dev, *tmp;
+ struct udevice *dev;
int ret;
- list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) {
+ /*
+ * 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);
if (ret)
return ret;
@@ -156,6 +164,60 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
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;
+
+ list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+ if (!strncmp(dev->name, name, strlen(name))) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
bool find_req_seq, struct udevice **devp)
{
@@ -209,17 +271,7 @@ static int uclass_find_device_by_of_offset(enum uclass_id id, int node,
return -ENODEV;
}
-/**
- * uclass_get_device_tail() - handle the end of a get_device call
- *
- * This handles returning an error or probing a device as needed.
- *
- * @dev: Device that needs to be probed
- * @ret: Error to return. If non-zero then the device is not probed
- * @devp: Returns the value of 'dev' if there is no error
- * @return ret, if non-zero, else the result of the device_probe() call
- */
-static int uclass_get_device_tail(struct udevice *dev, int ret,
+int uclass_get_device_tail(struct udevice *dev, int ret,
struct udevice **devp)
{
if (ret)
@@ -244,6 +296,17 @@ int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
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;
@@ -274,24 +337,12 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node,
int uclass_first_device(enum uclass_id id, 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 0;
-
- dev = list_first_entry(&uc->dev_head, struct udevice, uclass_node);
- ret = device_probe(dev);
- if (ret)
- return ret;
- *devp = dev;
-
- return 0;
+ ret = uclass_find_first_device(id, &dev);
+ return uclass_get_device_tail(dev, ret, devp);
}
int uclass_next_device(struct udevice **devp)
@@ -300,17 +351,8 @@ int uclass_next_device(struct udevice **devp)
int ret;
*devp = NULL;
- if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head))
- return 0;
-
- dev = list_entry(dev->uclass_node.next, struct udevice,
- uclass_node);
- ret = device_probe(dev);
- if (ret)
- return ret;
- *devp = dev;
-
- return 0;
+ ret = uclass_find_next_device(&dev);
+ return uclass_get_device_tail(dev, ret, devp);
}
int uclass_bind_device(struct udevice *dev)
@@ -344,6 +386,7 @@ err:
return ret;
}
+#ifdef CONFIG_DM_DEVICE_REMOVE
int uclass_unbind_device(struct udevice *dev)
{
struct uclass *uc;
@@ -359,6 +402,7 @@ int uclass_unbind_device(struct udevice *dev)
list_del(&dev->uclass_node);
return 0;
}
+#endif
int uclass_resolve_seq(struct udevice *dev)
{
@@ -422,6 +466,7 @@ int uclass_post_probe_device(struct udevice *dev)
return 0;
}
+#ifdef CONFIG_DM_DEVICE_REMOVE
int uclass_pre_remove_device(struct udevice *dev)
{
struct uclass_driver *uc_drv;
@@ -443,3 +488,4 @@ int uclass_pre_remove_device(struct udevice *dev)
return 0;
}
+#endif
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 1686a1f951..54e6f26d38 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -66,6 +66,16 @@ config DEBUG_UART_CLOCK
A default should be provided by your board, but if not you will need
to use the correct value here.
+config DEBUG_UART_SHIFT
+ int "UART register shift"
+ depends on DEBUG_UART
+ default 0 if DEBUG_UART
+ help
+ Some UARTs (notably ns16550) support different register layouts
+ where the registers are spaced either as bytes, words or some other
+ value. Use this value to specify the shift to use, where 0=byte
+ registers, 2=32-bit word registers, etc.
+
config UNIPHIER_SERIAL
bool "UniPhier on-chip UART support"
depends on ARCH_UNIPHIER && DM_SERIAL
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 67b1d60171..fd110b3ddc 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -57,7 +57,7 @@ DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_DM_SERIAL
-static inline void serial_out_shift(unsigned char *addr, int shift, int value)
+static inline void serial_out_shift(void *addr, int shift, int value)
{
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
outb(value, (ulong)addr);
@@ -72,7 +72,7 @@ static inline void serial_out_shift(unsigned char *addr, int shift, int value)
#endif
}
-static inline int serial_in_shift(unsigned char *addr, int shift)
+static inline int serial_in_shift(void *addr, int shift)
{
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
return inb((ulong)addr);
@@ -114,9 +114,11 @@ static int ns16550_readb(NS16550_t port, int offset)
/* We can clean these up once everything is moved to driver model */
#define serial_out(value, addr) \
- ns16550_writeb(com_port, addr - (unsigned char *)com_port, value)
+ ns16550_writeb(com_port, \
+ (unsigned char *)addr - (unsigned char *)com_port, value)
#define serial_in(addr) \
- ns16550_readb(com_port, addr - (unsigned char *)com_port)
+ ns16550_readb(com_port, \
+ (unsigned char *)addr - (unsigned char *)com_port)
#endif
static inline int calc_divisor(NS16550_t port, int clock, int baudrate)
@@ -173,7 +175,6 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
defined(CONFIG_TI81XX) || defined(CONFIG_AM43XX)
serial_out(0x7, &com_port->mdr1); /* mode select reset TL16C750*/
#endif
- NS16550_setbrg(com_port, 0);
serial_out(UART_MCRVAL, &com_port->mcr);
serial_out(UART_FCRVAL, &com_port->fcr);
if (baud_divisor != -1)
@@ -254,15 +255,20 @@ void debug_uart_init(void)
*/
baud_divisor = calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
CONFIG_BAUDRATE);
-
- serial_out_shift(&com_port->ier, 0, CONFIG_SYS_NS16550_IER);
- serial_out_shift(&com_port->mcr, 0, UART_MCRVAL);
- serial_out_shift(&com_port->fcr, 0, UART_FCRVAL);
-
- serial_out_shift(&com_port->lcr, 0, UART_LCR_BKSE | UART_LCRVAL);
- serial_out_shift(&com_port->dll, 0, baud_divisor & 0xff);
- serial_out_shift(&com_port->dlm, 0, (baud_divisor >> 8) & 0xff);
- serial_out_shift(&com_port->lcr, 0, UART_LCRVAL);
+ baud_divisor = 13;
+ serial_out_shift(&com_port->ier, CONFIG_DEBUG_UART_SHIFT,
+ CONFIG_SYS_NS16550_IER);
+ serial_out_shift(&com_port->mcr, CONFIG_DEBUG_UART_SHIFT, UART_MCRVAL);
+ serial_out_shift(&com_port->fcr, CONFIG_DEBUG_UART_SHIFT, UART_FCRVAL);
+
+ serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT,
+ UART_LCR_BKSE | UART_LCRVAL);
+ serial_out_shift(&com_port->dll, CONFIG_DEBUG_UART_SHIFT,
+ baud_divisor & 0xff);
+ serial_out_shift(&com_port->dlm, CONFIG_DEBUG_UART_SHIFT,
+ (baud_divisor >> 8) & 0xff);
+ serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT,
+ UART_LCRVAL);
}
static inline void _debug_uart_putc(int ch)
@@ -271,7 +277,7 @@ static inline void _debug_uart_putc(int ch)
while (!(serial_in_shift(&com_port->lsr, 0) & UART_LSR_THRE))
;
- serial_out_shift(&com_port->thr, 0, ch);
+ serial_out_shift(&com_port->thr, CONFIG_DEBUG_UART_SHIFT, ch);
}
DEBUG_UART_FUNCS
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index b239691efe..b8c2f48228 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -70,7 +70,7 @@ static void serial_find_console_or_panic(void)
if (uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) &&
uclass_get_device(UCLASS_SERIAL, INDEX, &dev) &&
(uclass_first_device(UCLASS_SERIAL, &dev) || !dev))
- panic("No serial driver found");
+ panic_str("No serial driver found");
#undef INDEX
gd->cur_serial_dev = dev;
}
diff --git a/drivers/usb/emul/sandbox_hub.c b/drivers/usb/emul/sandbox_hub.c
index 280c7080f2..baf8bdc857 100644
--- a/drivers/usb/emul/sandbox_hub.c
+++ b/drivers/usb/emul/sandbox_hub.c
@@ -32,6 +32,7 @@ static struct usb_string hub_strings[] = {
{STRING_MANUFACTURER, "sandbox"},
{STRING_PRODUCT, "hub"},
{STRING_SERIAL, "2345"},
+ {},
};
static struct usb_device_descriptor hub_device_desc = {
diff --git a/dts/Kconfig b/dts/Kconfig
index ca5bd6fb46..957f5c7ffa 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -1,9 +1,6 @@
#
# Device Tree Control
#
-# TODO:
-# This feature is not currently supported for SPL,
-# but this restriction should be removed in the future.
config SUPPORT_OF_CONTROL
bool
@@ -17,6 +14,14 @@ config OF_CONTROL
This feature provides for run-time configuration of U-Boot
via a flattened device tree.
+config SPL_DISABLE_OF_CONTROL
+ bool "Disable run-time configuration via Device Tree in SPL"
+ depends on OF_CONTROL
+ help
+ Some boards use device tree in U-Boot but only have 4KB of SRAM
+ which is not enough to support device tree. Enable this option to
+ allow such boards to be supported by U-Boot SPL.
+
choice
prompt "Provider of DTB for DT control"
depends on OF_CONTROL
diff --git a/include/config_uncmd_spl.h b/include/config_uncmd_spl.h
index a9106f4f3b..38cb0e8aba 100644
--- a/include/config_uncmd_spl.h
+++ b/include/config_uncmd_spl.h
@@ -31,6 +31,7 @@
#undef CONFIG_DM_WARN
#undef CONFIG_DM_DEVICE_REMOVE
+#undef CONFIG_DM_SEQ_ALIAS
#undef CONFIG_DM_STDIO
#endif /* CONFIG_SPL_BUILD */
diff --git a/include/dm/device.h b/include/dm/device.h
index c11342c33b..18296bb686 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -30,8 +30,11 @@ struct driver_info;
/* DM is responsible for allocating and freeing parent_platdata */
#define DM_FLAG_ALLOC_PARENT_PDATA (1 << 3)
+/* DM is responsible for allocating and freeing uclass_platdata */
+#define DM_FLAG_ALLOC_UCLASS_PDATA (1 << 4)
+
/* Allocate driver private data on a DMA boundary */
-#define DM_FLAG_ALLOC_PRIV_DMA (1 << 4)
+#define DM_FLAG_ALLOC_PRIV_DMA (1 << 5)
/**
* struct udevice - An instance of a driver
@@ -54,6 +57,7 @@ struct driver_info;
* @name: Name of device, typically the FDT node name
* @platdata: Configuration data for this device
* @parent_platdata: The parent bus's configuration data for this device
+ * @uclass_platdata: The uclass's configuration data for this device
* @of_offset: Device tree node offset for this device (- for none)
* @driver_data: Driver data word for the entry that matched this device with
* its driver
@@ -75,6 +79,7 @@ struct udevice {
const char *name;
void *platdata;
void *parent_platdata;
+ void *uclass_platdata;
int of_offset;
ulong driver_data;
struct udevice *parent;
@@ -210,6 +215,16 @@ void *dev_get_platdata(struct udevice *dev);
void *dev_get_parent_platdata(struct udevice *dev);
/**
+ * dev_get_uclass_platdata() - Get the uclass platform data for a device
+ *
+ * This checks that dev is not NULL, but no other checks for now
+ *
+ * @dev Device to check
+ * @return uclass's platform data, or NULL if none
+ */
+void *dev_get_uclass_platdata(struct udevice *dev);
+
+/**
* dev_get_parentdata() - Get the parent data for a device
*
* The parent data is data stored in the device but owned by the parent.
@@ -265,6 +280,17 @@ void *dev_get_uclass_priv(struct udevice *dev);
*/
ulong dev_get_driver_data(struct udevice *dev);
+/**
+ * dev_get_driver_ops() - get the device's driver's operations
+ *
+ * This checks that dev is not NULL, and returns the pointer to device's
+ * driver's operations.
+ *
+ * @dev: Device to check
+ * @return void pointer to driver's operations or NULL for NULL-dev or NULL-ops
+ */
+const void *dev_get_driver_ops(struct udevice *dev);
+
/*
* device_get_uclass_id() - return the uclass ID of a device
*
@@ -273,6 +299,16 @@ ulong dev_get_driver_data(struct udevice *dev);
*/
enum uclass_id device_get_uclass_id(struct udevice *dev);
+/*
+ * dev_get_uclass_name() - return the uclass name of a device
+ *
+ * This checks that dev is not NULL.
+ *
+ * @dev: Device to check
+ * @return pointer to the uclass name for the device
+ */
+const char *dev_get_uclass_name(struct udevice *dev);
+
/**
* device_get_child() - Get the child of a device by index
*
diff --git a/include/dm/test.h b/include/dm/test.h
index 9c4b8d3e57..f03fbcb1cd 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -98,6 +98,26 @@ struct dm_test_parent_data {
int flag;
};
+/* Test values for test device's uclass platform data */
+enum {
+ TEST_UC_PDATA_INTVAL1 = 2,
+ TEST_UC_PDATA_INTVAL2 = 334,
+ TEST_UC_PDATA_INTVAL3 = 789452,
+};
+
+/**
+ * struct dm_test_uclass_platda - uclass's information on each device
+ *
+ * @intval1: set to TEST_UC_PDATA_INTVAL1 in .post_bind method of test uclass
+ * @intval2: set to TEST_UC_PDATA_INTVAL2 in .post_bind method of test uclass
+ * @intval3: set to TEST_UC_PDATA_INTVAL3 in .post_bind method of test uclass
+ */
+struct dm_test_perdev_uc_pdata {
+ int intval1;
+ int intval2;
+ int intval3;
+};
+
/*
* Operation counts for the test driver, used to check that each method is
* called correctly
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
index ae2a93d7d4..9b68508667 100644
--- a/include/dm/uclass-internal.h
+++ b/include/dm/uclass-internal.h
@@ -11,12 +11,25 @@
#define _DM_UCLASS_INTERNAL_H
/**
+ * uclass_get_device_tail() - handle the end of a get_device call
+ *
+ * This handles returning an error or probing a device as needed.
+ *
+ * @dev: Device that needs to be probed
+ * @ret: Error to return. If non-zero then the device is not probed
+ * @devp: Returns the value of 'dev' if there is no error
+ * @return ret, if non-zero, else the result of the device_probe() call
+ */
+int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp);
+
+/**
* uclass_find_device() - Return n-th child of uclass
* @id: Id number of the uclass
* @index: Position of the child in uclass's list
* #devp: Returns pointer to device, or NULL on error
*
- * The device is not prepared for use - this is an internal function
+ * The device is not prepared for use - this is an internal function.
+ * The function uclass_get_device_tail() can be used to probe the device.
*
* @return the uclass pointer of a child at the given index or
* return NULL on error.
@@ -24,6 +37,68 @@
int uclass_find_device(enum uclass_id id, int index, struct udevice **devp);
/**
+ * uclass_find_first_device() - Return the first device in a uclass
+ * @id: Id number of the uclass
+ * #devp: Returns pointer to device, or NULL on error
+ *
+ * The device is not prepared for use - this is an internal function.
+ * The function uclass_get_device_tail() can be used to probe the device.
+ *
+ * @return 0 if OK (found or not found), -1 on error
+ */
+int uclass_find_first_device(enum uclass_id id, struct udevice **devp);
+
+/**
+ * uclass_find_next_device() - Return the next device in a uclass
+ * @devp: On entry, pointer to device to lookup. On exit, returns pointer
+ * to the next device in the same uclass, or NULL if none
+ *
+ * The device is not prepared for use - this is an internal function.
+ * The function uclass_get_device_tail() can be used to probe the device.
+ *
+ * @return 0 if OK (found or not found), -1 on error
+ */
+int uclass_find_next_device(struct udevice **devp);
+
+/**
+ * uclass_find_device_by_name() - Find uclass device based on ID and name
+ *
+ * This searches for a device with the exactly given name.
+ *
+ * The device is NOT probed, it is merely returned.
+ *
+ * @id: ID to look up
+ * @name: name of a device to find
+ * @devp: Returns pointer to device (the first one with the name)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_find_device_by_name(enum uclass_id id, const char *name,
+ struct udevice **devp);
+
+/**
+ * uclass_find_device_by_seq() - Find uclass device based on ID and sequence
+ *
+ * This searches for a device with the given seq or req_seq.
+ *
+ * For seq, if an active device has this sequence it will be returned.
+ * If there is no such device then this will return -ENODEV.
+ *
+ * For req_seq, if a device (whether activated or not) has this req_seq
+ * value, that device will be returned. This is a strong indication that
+ * the device will receive that sequence when activated.
+ *
+ * The device is NOT probed, it is merely returned.
+ *
+ * @id: ID to look up
+ * @seq_or_req_seq: Sequence number to find (0=first)
+ * @find_req_seq: true to find req_seq, false to find seq
+ * @devp: Returns pointer to device (there is only one per for each seq)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
+ bool find_req_seq, struct udevice **devp);
+
+/**
* uclass_bind_device() - Associate device with a uclass
*
* Connect the device into uclass's list of devices.
@@ -41,7 +116,11 @@ int uclass_bind_device(struct udevice *dev);
* @dev: Pointer to the device
* #return 0 on success, -ve on error
*/
+#ifdef CONFIG_DM_DEVICE_REMOVE
int uclass_unbind_device(struct udevice *dev);
+#else
+static inline int uclass_unbind_device(struct udevice *dev) { return 0; }
+#endif
/**
* uclass_pre_probe_device() - Deal with a device that is about to be probed
@@ -74,7 +153,11 @@ int uclass_post_probe_device(struct udevice *dev);
* @dev: Pointer to the device
* #return 0 on success, -ve on error
*/
+#ifdef CONFIG_DM_DEVICE_REMOVE
int uclass_pre_remove_device(struct udevice *dev);
+#else
+static inline int uclass_pre_remove_device(struct udevice *dev) { return 0; }
+#endif
/**
* uclass_find() - Find uclass by its id
@@ -94,27 +177,4 @@ struct uclass *uclass_find(enum uclass_id key);
*/
int uclass_destroy(struct uclass *uc);
-/**
- * uclass_find_device_by_seq() - Find uclass device based on ID and sequence
- *
- * This searches for a device with the given seq or req_seq.
- *
- * For seq, if an active device has this sequence it will be returned.
- * If there is no such device then this will return -ENODEV.
- *
- * For req_seq, if a device (whether activated or not) has this req_seq
- * value, that device will be returned. This is a strong indication that
- * the device will receive that sequence when activated.
- *
- * The device is NOT probed, it is merely returned.
- *
- * @id: ID to look up
- * @seq_or_req_seq: Sequence number to find (0=first)
- * @find_req_seq: true to find req_seq, false to find seq
- * @devp: Returns pointer to device (there is only one per for each seq)
- * @return 0 if OK, -ve on error
- */
-int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
- bool find_req_seq, struct udevice **devp);
-
#endif
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index d57d804259..4cfc0df84c 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -65,6 +65,9 @@ struct udevice;
* @per_device_auto_alloc_size: Each device can hold private data owned
* by the uclass. If required this will be automatically allocated if this
* value is non-zero.
+ * @per_device_platdata_auto_alloc_size: Each device can hold platform data
+ * owned by the uclass as 'dev->uclass_platdata'. If the value is non-zero,
+ * then this will be automatically allocated.
* @per_child_auto_alloc_size: Each child device (of a parent in this
* uclass) can hold parent data for the device/uclass. This value is only
* used as a falback if this member is 0 in the driver.
@@ -90,6 +93,7 @@ struct uclass_driver {
int (*destroy)(struct uclass *class);
int priv_auto_alloc_size;
int per_device_auto_alloc_size;
+ int per_device_platdata_auto_alloc_size;
int per_child_auto_alloc_size;
int per_child_platdata_auto_alloc_size;
const void *ops;
@@ -126,6 +130,21 @@ int uclass_get(enum uclass_id key, struct uclass **ucp);
int uclass_get_device(enum uclass_id id, int index, struct udevice **devp);
/**
+ * uclass_get_device_by_name() - Get a uclass device by it's name
+ *
+ * This searches the devices in the uclass for one with the exactly given name.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @id: ID to look up
+ * @name: name of a device to get
+ * @devp: Returns pointer to device (the first one with the name)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_get_device_by_name(enum uclass_id id, const char *name,
+ struct udevice **devp);
+
+/**
* uclass_get_device_by_seq() - Get a uclass device based on an ID and sequence
*
* If an active device has this sequence it will be returned. If there is no
diff --git a/include/fdtdec.h b/include/fdtdec.h
index d14e06abab..659047097a 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -41,6 +41,16 @@ struct fdt_memory {
fdt_addr_t end;
};
+#ifdef CONFIG_OF_CONTROL
+# if defined(CONFIG_SPL_BUILD) && defined(SPL_DISABLE_OF_CONTROL)
+# define OF_CONTROL 0
+# else
+# define OF_CONTROL 1
+# endif
+#else
+# define OF_CONTROL 0
+#endif
+
/*
* Information about a resource. start is the first address of the resource
* and end is the last address (inclusive). The length of the resource will
@@ -793,4 +803,10 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property,
int fdtdec_decode_memory_region(const void *blob, int node,
const char *mem_type, const char *suffix,
fdt_addr_t *basep, fdt_size_t *sizep);
+
+/**
+ * Set up the device tree ready for use
+ */
+int fdtdec_setup(void);
+
#endif
diff --git a/include/malloc.h b/include/malloc.h
index 5df634873f..f4da9e6ddd 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -906,6 +906,9 @@ void *realloc_simple(void *ptr, size_t size);
#endif
+/* Set up pre-relocation malloc() ready for use */
+int initf_malloc(void);
+
/* Public routines */
/* Simple versions which can be used when space is tight */
diff --git a/include/vsprintf.h b/include/vsprintf.h
index 5624482d57..09c8abd951 100644
--- a/include/vsprintf.h
+++ b/include/vsprintf.h
@@ -39,10 +39,33 @@ int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
unsigned long long simple_strtoull(const char *cp, char **endp,
unsigned int base);
long simple_strtol(const char *cp, char **endp, unsigned int base);
+
+/**
+ * panic() - Print a message and reset/hang
+ *
+ * Prints a message on the console(s) and then resets. If CONFIG_PANIC_HANG is
+ * defined, then it will hang instead of reseting.
+ *
+ * @param fmt: printf() format string for message, which should not include
+ * \n, followed by arguments
+ */
void panic(const char *fmt, ...)
__attribute__ ((format (__printf__, 1, 2), noreturn));
/**
+ * panic_str() - Print a message and reset/hang
+ *
+ * Prints a message on the console(s) and then resets. If CONFIG_PANIC_HANG is
+ * defined, then it will hang instead of reseting.
+ *
+ * This function can be used instead of panic() when your board does not
+ * already use printf(), * to keep code size small.
+ *
+ * @param fmt: string to display, which should not include \n
+ */
+void panic_str(const char *str) __attribute__ ((noreturn));
+
+/**
* Format a string and place it in a buffer
*
* @param buf The buffer to place the result into
diff --git a/lib/Makefile b/lib/Makefile
index 07d175f45e..97ed398ade 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -44,6 +44,12 @@ obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-y += list_sort.o
endif
+ifndef CONFIG_SPL_DISABLE_OF_CONTROL
+obj-$(CONFIG_OF_LIBFDT) += libfdt/
+obj-$(CONFIG_OF_CONTROL) += fdtdec_common.o
+obj-$(CONFIG_OF_CONTROL) += fdtdec.o
+endif
+
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o
obj-$(CONFIG_SPL_NET_SUPPORT) += net_utils.o
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 331eae2ce1..80b897a21c 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -9,6 +9,7 @@
#include <serial.h>
#include <libfdt.h>
#include <fdtdec.h>
+#include <asm/sections.h>
#include <linux/ctype.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -565,9 +566,11 @@ int fdtdec_prepare_fdt(void)
{
if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
fdt_check_header(gd->fdt_blob)) {
- printf("No valid FDT found - please append one to U-Boot "
- "binary, use u-boot-dtb.bin or define "
- "CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
+#ifdef CONFIG_SPL_BUILD
+ puts("Missing DTB\n");
+#else
+ puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
+#endif
return -1;
}
return 0;
@@ -1035,4 +1038,34 @@ int fdtdec_decode_memory_region(const void *blob, int config_node,
return 0;
}
+
+int fdtdec_setup(void)
+{
+#ifdef CONFIG_OF_CONTROL
+# ifdef CONFIG_OF_EMBED
+ /* Get a pointer to the FDT */
+ gd->fdt_blob = __dtb_dt_begin;
+# elif defined CONFIG_OF_SEPARATE
+# ifdef CONFIG_SPL_BUILD
+ /* FDT is at end of BSS */
+ gd->fdt_blob = (ulong *)&__bss_end;
+# else
+ /* FDT is at end of image */
+ gd->fdt_blob = (ulong *)&_end;
+#endif
+# elif defined(CONFIG_OF_HOSTFILE)
+ if (sandbox_read_fdt_from_file()) {
+ puts("Failed to read control FDT\n");
+ return -1;
+ }
+# endif
+# ifndef CONFIG_SPL_BUILD
+ /* Allow the early environment to override the fdt address */
+ gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
+ (uintptr_t)gd->fdt_blob);
+# endif
#endif
+ return fdtdec_prepare_fdt();
+}
+
+#endif /* !USE_HOSTCC */
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index e0f264850f..bedc865240 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -842,13 +842,11 @@ int sprintf(char *buf, const char *fmt, ...)
return i;
}
-void panic(const char *fmt, ...)
+static void panic_finish(void) __attribute__ ((noreturn));
+
+static void panic_finish(void)
{
- va_list args;
- va_start(args, fmt);
- vprintf(fmt, args);
putc('\n');
- va_end(args);
#if defined(CONFIG_PANIC_HANG)
hang();
#else
@@ -859,6 +857,21 @@ void panic(const char *fmt, ...)
;
}
+void panic_str(const char *str)
+{
+ puts(str);
+ panic_finish();
+}
+
+void panic(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ panic_finish();
+}
+
void __assert_fail(const char *assertion, const char *file, unsigned line,
const char *function)
{
diff --git a/test/dm/core.c b/test/dm/core.c
index 990d390d01..91be1e5d43 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -129,6 +129,61 @@ static int dm_test_autobind(struct dm_test_state *dms)
}
DM_TEST(dm_test_autobind, 0);
+/* Test that binding with uclass platdata allocation occurs correctly */
+static int dm_test_autobind_uclass_pdata_alloc(struct dm_test_state *dms)
+{
+ struct dm_test_perdev_uc_pdata *uc_pdata;
+ struct udevice *dev;
+ struct uclass *uc;
+
+ ut_assertok(uclass_get(UCLASS_TEST, &uc));
+ ut_assert(uc);
+
+ /**
+ * Test if test uclass driver requires allocation for the uclass
+ * platform data and then check the dev->uclass_platdata pointer.
+ */
+ ut_assert(uc->uc_drv->per_device_platdata_auto_alloc_size);
+
+ for (uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ ut_assert(dev);
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+ ut_assert(uc_pdata);
+ }
+
+ return 0;
+}
+DM_TEST(dm_test_autobind_uclass_pdata_alloc, DM_TESTF_SCAN_PDATA);
+
+/* Test that binding with uclass platdata setting occurs correctly */
+static int dm_test_autobind_uclass_pdata_valid(struct dm_test_state *dms)
+{
+ struct dm_test_perdev_uc_pdata *uc_pdata;
+ struct udevice *dev;
+
+ /**
+ * In the test_postbind() method of test uclass driver, the uclass
+ * platform data should be set to three test int values - test it.
+ */
+ for (uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ ut_assert(dev);
+
+ uc_pdata = dev_get_uclass_platdata(dev);
+ ut_assert(uc_pdata);
+ ut_assert(uc_pdata->intval1 == TEST_UC_PDATA_INTVAL1);
+ ut_assert(uc_pdata->intval2 == TEST_UC_PDATA_INTVAL2);
+ ut_assert(uc_pdata->intval3 == TEST_UC_PDATA_INTVAL3);
+ }
+
+ return 0;
+}
+DM_TEST(dm_test_autobind_uclass_pdata_valid, DM_TESTF_SCAN_PDATA);
+
/* Test that autoprobe finds all the expected devices */
static int dm_test_autoprobe(struct dm_test_state *dms)
{
@@ -596,14 +651,130 @@ static int dm_test_uclass_before_ready(struct dm_test_state *dms)
ut_assertok(uclass_get(UCLASS_TEST, &uc));
- memset(gd, '\0', sizeof(*gd));
+ gd->dm_root = NULL;
+ gd->dm_root_f = NULL;
+ memset(&gd->uclass_root, '\0', sizeof(gd->uclass_root));
+
ut_asserteq_ptr(NULL, uclass_find(UCLASS_TEST));
return 0;
}
-
DM_TEST(dm_test_uclass_before_ready, 0);
+static int dm_test_uclass_devices_find(struct dm_test_state *dms)
+{
+ struct udevice *dev;
+ int ret;
+
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assert(dev);
+ }
+
+ return 0;
+}
+DM_TEST(dm_test_uclass_devices_find, DM_TESTF_SCAN_PDATA);
+
+static int dm_test_uclass_devices_find_by_name(struct dm_test_state *dms)
+{
+ struct udevice *finddev;
+ struct udevice *testdev;
+ int findret, ret;
+
+ /*
+ * For each test device found in fdt like: "a-test", "b-test", etc.,
+ * use its name and try to find it by uclass_find_device_by_name().
+ * Then, on success check if:
+ * - current 'testdev' name is equal to the returned 'finddev' name
+ * - current 'testdev' pointer is equal to the returned 'finddev'
+ *
+ * We assume that, each uclass's device name is unique, so if not, then
+ * this will fail on checking condition: testdev == finddev, since the
+ * uclass_find_device_by_name(), returns the first device by given name.
+ */
+ for (ret = uclass_find_first_device(UCLASS_TEST_FDT, &testdev);
+ testdev;
+ ret = uclass_find_next_device(&testdev)) {
+ ut_assertok(ret);
+ ut_assert(testdev);
+
+ findret = uclass_find_device_by_name(UCLASS_TEST_FDT,
+ testdev->name,
+ &finddev);
+
+ ut_assertok(findret);
+ ut_assert(testdev);
+ ut_asserteq_str(testdev->name, finddev->name);
+ ut_asserteq_ptr(testdev, finddev);
+ }
+
+ return 0;
+}
+DM_TEST(dm_test_uclass_devices_find_by_name, DM_TESTF_SCAN_FDT);
+
+static int dm_test_uclass_devices_get(struct dm_test_state *dms)
+{
+ struct udevice *dev;
+ int ret;
+
+ for (ret = uclass_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assert(dev);
+ ut_assert(device_active(dev));
+ }
+
+ return 0;
+}
+DM_TEST(dm_test_uclass_devices_get, DM_TESTF_SCAN_PDATA);
+
+static int dm_test_uclass_devices_get_by_name(struct dm_test_state *dms)
+{
+ struct udevice *finddev;
+ struct udevice *testdev;
+ int ret, findret;
+
+ /*
+ * For each test device found in fdt like: "a-test", "b-test", etc.,
+ * use its name and try to get it by uclass_get_device_by_name().
+ * On success check if:
+ * - returned finddev' is active
+ * - current 'testdev' name is equal to the returned 'finddev' name
+ * - current 'testdev' pointer is equal to the returned 'finddev'
+ *
+ * We asserts that the 'testdev' is active on each loop entry, so we
+ * could be sure that the 'finddev' is activated too, but for sure
+ * we check it again.
+ *
+ * We assume that, each uclass's device name is unique, so if not, then
+ * this will fail on checking condition: testdev == finddev, since the
+ * uclass_get_device_by_name(), returns the first device by given name.
+ */
+ for (ret = uclass_first_device(UCLASS_TEST_FDT, &testdev);
+ testdev;
+ ret = uclass_next_device(&testdev)) {
+ ut_assertok(ret);
+ ut_assert(testdev);
+ ut_assert(device_active(testdev));
+
+ findret = uclass_get_device_by_name(UCLASS_TEST_FDT,
+ testdev->name,
+ &finddev);
+
+ ut_assertok(findret);
+ ut_assert(finddev);
+ ut_assert(device_active(finddev));
+ ut_asserteq_str(testdev->name, finddev->name);
+ ut_asserteq_ptr(testdev, finddev);
+ }
+
+ return 0;
+}
+DM_TEST(dm_test_uclass_devices_get_by_name, DM_TESTF_SCAN_FDT);
+
static int dm_test_device_get_uclass_id(struct dm_test_state *dms)
{
struct udevice *dev;
diff --git a/test/dm/test-uclass.c b/test/dm/test-uclass.c
index 7cb37f70c7..4ae75ef764 100644
--- a/test/dm/test-uclass.c
+++ b/test/dm/test-uclass.c
@@ -30,9 +30,18 @@ int test_ping(struct udevice *dev, int pingval, int *pingret)
static int test_post_bind(struct udevice *dev)
{
+ struct dm_test_perdev_uc_pdata *uc_pdata;
+
dm_testdrv_op_count[DM_TEST_OP_POST_BIND]++;
ut_assert(!device_active(dev));
+ uc_pdata = dev_get_uclass_platdata(dev);
+ ut_assert(uc_pdata);
+
+ uc_pdata->intval1 = TEST_UC_PDATA_INTVAL1;
+ uc_pdata->intval2 = TEST_UC_PDATA_INTVAL2;
+ uc_pdata->intval3 = TEST_UC_PDATA_INTVAL3;
+
return 0;
}
@@ -115,4 +124,6 @@ UCLASS_DRIVER(test) = {
.destroy = test_destroy,
.priv_auto_alloc_size = sizeof(struct dm_test_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct dm_test_uclass_perdev_priv),
+ .per_device_platdata_auto_alloc_size =
+ sizeof(struct dm_test_perdev_uc_pdata),
};