summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS4
-rw-r--r--arch/Kconfig1
-rw-r--r--arch/sandbox/cpu/os.c9
-rw-r--r--arch/sandbox/dts/sandbox.dts24
-rw-r--r--arch/sandbox/dts/sandbox.dtsi2
-rw-r--r--arch/sandbox/dts/sandbox64.dts25
-rw-r--r--arch/sandbox/dts/test.dts11
-rw-r--r--board/sandbox/sandbox.c6
-rw-r--r--cmd/fdt.c2
-rw-r--r--common/Kconfig9
-rw-r--r--common/Makefile1
-rw-r--r--common/log_syslog.c117
-rw-r--r--configs/sandbox64_defconfig3
-rw-r--r--configs/sandbox_defconfig2
-rw-r--r--configs/sandbox_flattree_defconfig3
-rw-r--r--configs/sandbox_spl_defconfig2
-rw-r--r--doc/README.log3
-rw-r--r--doc/driver-model/design.rst96
-rw-r--r--doc/driver-model/pci-info.rst10
-rw-r--r--drivers/clk/altera/clk-arria10.c2
-rw-r--r--drivers/clk/at91/pmc.c2
-rw-r--r--drivers/core/device-remove.c23
-rw-r--r--drivers/core/device.c22
-rw-r--r--drivers/core/lists.c2
-rw-r--r--drivers/core/of_access.c40
-rw-r--r--drivers/core/ofnode.c49
-rw-r--r--drivers/core/read.c13
-rw-r--r--drivers/core/root.c52
-rw-r--r--drivers/core/uclass.c6
-rw-r--r--drivers/core/util.c28
-rw-r--r--drivers/misc/p2sb_emul.c2
-rw-r--r--drivers/serial/serial-uclass.c1
-rw-r--r--include/dm/device.h11
-rw-r--r--include/dm/of_access.h19
-rw-r--r--include/dm/ofnode.h25
-rw-r--r--include/dm/read.h40
-rw-r--r--include/dm/util.h27
-rw-r--r--include/log.h10
-rw-r--r--include/test/log.h16
-rw-r--r--include/test/suites.h1
-rw-r--r--include/test/ut.h16
-rw-r--r--lib/fdtdec.c36
-rw-r--r--test/Kconfig9
-rw-r--r--test/Makefile2
-rw-r--r--test/cmd_ut.c6
-rw-r--r--test/dm/Makefile1
-rw-r--r--test/dm/fdtdec.c59
-rw-r--r--test/dm/test-fdt.c66
-rw-r--r--test/log/Makefile14
-rw-r--r--test/log/nolog_test.c135
-rw-r--r--test/log/syslog_test.c280
-rw-r--r--test/log/test-main.c20
-rw-r--r--tools/patman/series.py6
53 files changed, 1166 insertions, 205 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index d8d420f84f..7ac7e21ba1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -654,9 +654,9 @@ LOGGING
M: Simon Glass <sjg@chromium.org>
S: Maintained
T: git https://gitlab.denx.de/u-boot/u-boot.git
-F: common/log.c
+F: common/log*
F: cmd/log.c
-F: test/log/log_test.c
+F: test/log/
F: test/py/tests/test_log.py
MALI DISPLAY PROCESSORS
diff --git a/arch/Kconfig b/arch/Kconfig
index ae9c93ed7b..91e049b322 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -96,6 +96,7 @@ config SANDBOX
select DM_SPI_FLASH
select HAVE_BLOCK_DEVICE
select LZO
+ select OF_BOARD_SETUP
select PCI_ENDPOINT
select SPI
select SUPPORT_OF_CONTROL
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index f7c73e3a0b..e7ec892bdf 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -8,6 +8,7 @@
#include <fcntl.h>
#include <getopt.h>
#include <setjmp.h>
+#include <signal.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -175,6 +176,13 @@ void os_fd_restore(void)
}
}
+static void os_sigint_handler(int sig)
+{
+ os_fd_restore();
+ signal(SIGINT, SIG_DFL);
+ raise(SIGINT);
+}
+
/* Put tty into raw mode so <tab> and <ctrl+c> work */
void os_tty_raw(int fd, bool allow_sigs)
{
@@ -205,6 +213,7 @@ void os_tty_raw(int fd, bool allow_sigs)
term_setup = true;
atexit(os_fd_restore);
+ signal(SIGINT, os_sigint_handler);
}
void *os_malloc(size_t length)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 4dd82f6a32..20f6893829 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -10,7 +10,7 @@
aliases {
i2c0 = &i2c_0;
- pci0 = &pci;
+ pci0 = &pcic;
rtc0 = &rtc_0;
axi0 = &axi;
spi0 = &spi;
@@ -20,6 +20,25 @@
reg = <0 CONFIG_SYS_SDRAM_SIZE>;
};
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ reservation_test0 {
+ size = <0x4000>;
+ alignment = <0x2000>;
+ };
+
+ reservation_test1: restest@a000 {
+ reg = <0x00d0a000 0x2000>;
+ };
+
+ reservation_test2: restest@7000 {
+ reg = <0x00d07000 0x1000>;
+ };
+ };
+
cros_ec: cros-ec {
reg = <0 0>;
u-boot,dm-pre-reloc;
@@ -52,9 +71,10 @@
pinctrl-0 = <&pinctrl_i2c0>;
};
- pci: pci-controller {
+ pcic: pci@0 {
compatible = "sandbox,pci";
device_type = "pci";
+ bus-range = <0x00 0xff>;
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x02000000 0 0x10000000 0x10000000 0 0x2000
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index 7cd56c14f2..e1f68cd552 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -100,7 +100,7 @@
};
};
- pci-controller {
+ pci@0 {
pci@1e,0 {
compatible = "sandbox,pmc";
reg = <0xf000 0 0 0 0>;
diff --git a/arch/sandbox/dts/sandbox64.dts b/arch/sandbox/dts/sandbox64.dts
index 5c95cee9d7..a39f94feec 100644
--- a/arch/sandbox/dts/sandbox64.dts
+++ b/arch/sandbox/dts/sandbox64.dts
@@ -10,7 +10,7 @@
aliases {
i2c0 = &i2c_0;
- pci0 = &pci;
+ pci0 = &pcic;
rtc0 = &rtc_0;
axi0 = &axi;
spi0 = &spi;
@@ -20,6 +20,26 @@
reg = /bits/ 64 <0 CONFIG_SYS_SDRAM_SIZE>;
};
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ reservation_test_size {
+ size = <0 0x4000>;
+ alignment = <0 0x2000>;
+ };
+
+ reservation_test@a000 {
+ reg = <0 0x00d0a000 0 0x2000>;
+ };
+
+ reservation_test@7000 {
+ reg = <0 0x00d07000 0 0x1000>;
+ };
+ };
+
+ /* ... */
cros_ec: cros-ec {
reg = <0 0 0 0>;
u-boot,dm-pre-reloc;
@@ -47,9 +67,10 @@
pinctrl-0 = <&pinctrl_i2c0>;
};
- pci: pci-controller {
+ pcic: pci@0 {
compatible = "sandbox,pci";
device_type = "pci";
+ bus-range = <0x00 0xff>;
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x02000000 0 0x10000000 0 0x10000000 0 0x2000
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 5fa951ad4b..6803c00f90 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -93,6 +93,8 @@
<&gpio_b 9 0xc 3 2 1>;
int-value = <1234>;
uint-value = <(-1234)>;
+ int64-value = /bits/ 64 <0x1111222233334444>;
+ int-array = <5678 9123 4567>;
interrupts-extended = <&irq 3 0>;
};
@@ -467,9 +469,10 @@
compatible = "sandbox,pch";
};
- pci0: pci-controller0 {
+ pci0: pci@0 {
compatible = "sandbox,pci";
device_type = "pci";
+ bus-range = <0x00 0xff>;
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x02000000 0 0x10000000 0x10000000 0 0x2000000
@@ -535,9 +538,10 @@
};
};
- pci1: pci-controller1 {
+ pci1: pci@1 {
compatible = "sandbox,pci";
device_type = "pci";
+ bus-range = <0x00 0xff>;
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x02000000 0 0x30000000 0x30000000 0 0x2000
@@ -550,9 +554,10 @@
};
};
- pci2: pci-controller2 {
+ pci2: pci@2 {
compatible = "sandbox,pci";
device_type = "pci";
+ bus-range = <0x00 0xff>;
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x02000000 0 0x50000000 0x50000000 0 0x2000
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
index 0c3d245dff..1372003018 100644
--- a/board/sandbox/sandbox.c
+++ b/board/sandbox/sandbox.c
@@ -58,6 +58,12 @@ int board_init(void)
return 0;
}
+int ft_board_setup(void *fdt, bd_t *bd)
+{
+ /* Create an arbitrary reservation to allow testing OF_BOARD_SETUP.*/
+ return fdt_add_mem_rsv(fdt, 0x00d02000, 0x4000);
+}
+
#ifdef CONFIG_BOARD_LATE_INIT
int board_late_init(void)
{
diff --git a/cmd/fdt.c b/cmd/fdt.c
index 25a6ed40d2..36cc726540 100644
--- a/cmd/fdt.c
+++ b/cmd/fdt.c
@@ -286,7 +286,7 @@ static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/*
* Set the value of a property in the working_fdt.
*/
- } else if (argv[1][0] == 's') {
+ } else if (strncmp(argv[1], "se", 2) == 0) {
char *pathp; /* path */
char *prop; /* property */
int nodeoffset; /* node offset from libfdt */
diff --git a/common/Kconfig b/common/Kconfig
index 3072651082..ee4f748c32 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -775,9 +775,16 @@ config TPL_LOG_CONSOLE
log message is shown - other details like level, category, file and
line number are omitted.
+config LOG_SYSLOG
+ bool "Log output to syslog server"
+ depends on LOG && NET
+ help
+ Enables a log driver which broadcasts log records via UDP port 514
+ to syslog servers.
+
config LOG_TEST
bool "Provide a test for logging"
- depends on LOG
+ depends on LOG && UNIT_TEST
default y if SANDBOX
help
This enables a 'log test' command to test logging. It is normally
diff --git a/common/Makefile b/common/Makefile
index 702f2396cf..d84e10ba99 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -132,6 +132,7 @@ obj-$(CONFIG_DFU_OVER_USB) += dfu.o
obj-y += command.o
obj-$(CONFIG_$(SPL_TPL_)LOG) += log.o
obj-$(CONFIG_$(SPL_TPL_)LOG_CONSOLE) += log_console.o
+obj-$(CONFIG_$(SPL_TPL_)LOG_SYSLOG) += log_syslog.o
obj-y += s_record.o
obj-$(CONFIG_CMD_LOADB) += xyzModem.o
obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o
diff --git a/common/log_syslog.c b/common/log_syslog.c
new file mode 100644
index 0000000000..5e3e20e8a4
--- /dev/null
+++ b/common/log_syslog.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Log to syslog.
+ *
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+
+#include <common.h>
+#include <log.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define BUFFER_SIZE 480
+
+static void append(char **buf, char *buf_end, const char *fmt, ...)
+{
+ va_list args;
+ size_t size = buf_end - *buf;
+
+ va_start(args, fmt);
+ vsnprintf(*buf, size, fmt, args);
+ va_end(args);
+ *buf += strlen(*buf);
+}
+
+static int log_syslog_emit(struct log_device *ldev, struct log_rec *rec)
+{
+ int ret;
+ int fmt = gd->log_fmt;
+ char msg[BUFFER_SIZE];
+ char *msg_end = msg + BUFFER_SIZE;
+ char *ptr = msg;
+ char *iphdr;
+ char *log_msg;
+ int eth_hdr_size;
+ struct in_addr bcast_ip;
+ static int processing_msg;
+ unsigned int log_level;
+ char *log_hostname;
+
+ /* Fend off messages from the network stack while writing a message */
+ if (processing_msg)
+ return 0;
+
+ processing_msg = 1;
+
+ /* Setup packet buffers */
+ net_init();
+ /* Disable hardware and put it into the reset state */
+ eth_halt();
+ /* Set current device according to environment variables */
+ eth_set_current();
+ /* Get hardware ready for send and receive operations */
+ ret = eth_init();
+ if (ret < 0) {
+ eth_halt();
+ goto out;
+ }
+
+ memset(msg, 0, BUFFER_SIZE);
+
+ /* Set ethernet header */
+ eth_hdr_size = net_set_ether((uchar *)ptr, net_bcast_ethaddr, PROT_IP);
+ ptr += eth_hdr_size;
+ iphdr = ptr;
+ ptr += IP_UDP_HDR_SIZE;
+ log_msg = ptr;
+
+ /*
+ * The syslog log levels defined in RFC 5424 match the U-Boot ones up to
+ * level 7 (debug).
+ */
+ log_level = rec->level;
+ if (log_level > 7)
+ log_level = 7;
+ /* Leave high bits as 0 to write a 'kernel message' */
+
+ /* Write log message to buffer */
+ append(&ptr, msg_end, "<%u>", log_level);
+ log_hostname = env_get("log_hostname");
+ if (log_hostname)
+ append(&ptr, msg_end, "%s ", log_hostname);
+ append(&ptr, msg_end, "uboot: ");
+ if (fmt & (1 << LOGF_LEVEL))
+ append(&ptr, msg_end, "%s.",
+ log_get_level_name(rec->level));
+ if (fmt & (1 << LOGF_CAT))
+ append(&ptr, msg_end, "%s,",
+ log_get_cat_name(rec->cat));
+ if (fmt & (1 << LOGF_FILE))
+ append(&ptr, msg_end, "%s:", rec->file);
+ if (fmt & (1 << LOGF_LINE))
+ append(&ptr, msg_end, "%d-", rec->line);
+ if (fmt & (1 << LOGF_FUNC))
+ append(&ptr, msg_end, "%s()", rec->func);
+ if (fmt & (1 << LOGF_MSG))
+ append(&ptr, msg_end, "%s%s",
+ fmt != (1 << LOGF_MSG) ? " " : "", rec->msg);
+ /* Consider trailing 0x00 */
+ ptr++;
+
+ debug("log message: '%s'\n", log_msg);
+
+ /* Broadcast message */
+ bcast_ip.s_addr = 0xFFFFFFFFL;
+ net_set_udp_header((uchar *)iphdr, bcast_ip, 514, 514, ptr - log_msg);
+ net_send_packet((uchar *)msg, ptr - msg);
+
+out:
+ processing_msg = 0;
+ return ret;
+}
+
+LOG_DRIVER(syslog) = {
+ .name = "syslog",
+ .emit = log_syslog_emit,
+};
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index 8ca17d621b..a6183d9814 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -18,10 +18,12 @@ CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000
CONFIG_SILENT_CONSOLE=y
CONFIG_PRE_CONSOLE_BUFFER=y
CONFIG_LOG_MAX_LEVEL=6
+CONFIG_LOG_SYSLOG=y
CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_CMD_CPU=y
CONFIG_CMD_LICENSE=y
CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_BOOTEFI_HELLO=y
# CONFIG_CMD_ELF is not set
CONFIG_CMD_ASKENV=y
CONFIG_CMD_GREPENV=y
@@ -53,6 +55,7 @@ CONFIG_CMD_DNS=y
CONFIG_CMD_LINK_LOCAL=y
CONFIG_CMD_ETHSW=y
CONFIG_CMD_BMP=y
+CONFIG_CMD_EFIDEBUG=y
CONFIG_CMD_TIME=y
CONFIG_CMD_TIMER=y
CONFIG_CMD_SOUND=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index cc90f0006e..fa72c666c6 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -19,12 +19,14 @@ CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000
CONFIG_SILENT_CONSOLE=y
CONFIG_PRE_CONSOLE_BUFFER=y
CONFIG_LOG_MAX_LEVEL=6
+CONFIG_LOG_SYSLOG=y
CONFIG_LOG_ERROR_RETURN=y
CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_ANDROID_AB=y
CONFIG_CMD_CPU=y
CONFIG_CMD_LICENSE=y
CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_BOOTEFI_HELLO=y
CONFIG_CMD_ABOOTIMG=y
# CONFIG_CMD_ELF is not set
CONFIG_CMD_ASKENV=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 59d34cb5e0..00d9359f19 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -15,10 +15,12 @@ CONFIG_CONSOLE_RECORD=y
CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000
CONFIG_SILENT_CONSOLE=y
CONFIG_LOG_MAX_LEVEL=6
+CONFIG_LOG_SYSLOG=y
CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_CMD_CPU=y
CONFIG_CMD_LICENSE=y
CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_BOOTEFI_HELLO=y
# CONFIG_CMD_ELF is not set
CONFIG_CMD_ASKENV=y
CONFIG_CMD_GREPENV=y
@@ -43,6 +45,7 @@ CONFIG_CMD_CDP=y
CONFIG_CMD_SNTP=y
CONFIG_CMD_DNS=y
CONFIG_CMD_LINK_LOCAL=y
+CONFIG_CMD_EFIDEBUG=y
CONFIG_CMD_TIME=y
CONFIG_CMD_TIMER=y
CONFIG_CMD_SOUND=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index 53c5bd8a4e..18c6a47602 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -28,6 +28,7 @@ CONFIG_SPL_ENV_SUPPORT=y
CONFIG_CMD_CPU=y
CONFIG_CMD_LICENSE=y
CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_BOOTEFI_HELLO=y
# CONFIG_CMD_ELF is not set
CONFIG_CMD_ASKENV=y
CONFIG_CMD_GREPENV=y
@@ -56,6 +57,7 @@ CONFIG_CMD_SNTP=y
CONFIG_CMD_DNS=y
CONFIG_CMD_LINK_LOCAL=y
CONFIG_CMD_BMP=y
+CONFIG_CMD_EFIDEBUG=y
CONFIG_CMD_TIME=y
CONFIG_CMD_TIMER=y
CONFIG_CMD_SOUND=y
diff --git a/doc/README.log b/doc/README.log
index 19856d43da..1057981f45 100644
--- a/doc/README.log
+++ b/doc/README.log
@@ -147,7 +147,10 @@ several possible determinations for logging information, all of which can be
enabled or disabled independently:
console - goes to stdout
+ syslog - broadcast RFC 3164 messages to syslog servers on UDP port 514
+The syslog driver sends the value of environmental variable 'log_hostname' as
+HOSTNAME if available.
Log format
----------
diff --git a/doc/driver-model/design.rst b/doc/driver-model/design.rst
index 5247ecc276..635effcef6 100644
--- a/doc/driver-model/design.rst
+++ b/doc/driver-model/design.rst
@@ -579,7 +579,7 @@ a USB bus with several devices attached to it, each from a different (made
up) uclass::
xhci_usb (UCLASS_USB)
- eth (UCLASS_ETHERNET)
+ eth (UCLASS_ETH)
camera (UCLASS_CAMERA)
flash (UCLASS_FLASH_STORAGE)
@@ -683,11 +683,17 @@ probe/remove which is independent of bind/unbind. This is partly because in
U-Boot it may be expensive to probe devices and we don't want to do it until
they are needed, or perhaps until after relocation.
-Activation/probe
-^^^^^^^^^^^^^^^^
+Reading ofdata
+^^^^^^^^^^^^^^
+
+Most devices have data in the device tree which they can read to find out the
+base address of hardware registers and parameters relating to driver
+operation. This is called 'ofdata' (Open-Firmware data).
-When a device needs to be used, U-Boot activates it, by following these
-steps (see device_probe()):
+The device's_ofdata_to_platdata() implemnents allocation and reading of
+platdata. A parent's ofdata is always read before a child.
+
+The steps are:
1. If priv_auto_alloc_size is non-zero, then the device-private space
is allocated for the device and zeroed. It will be accessible as
@@ -713,32 +719,72 @@ steps (see device_probe()):
space. The controller can hold information about the USB state of each
of its children.
- 5. All parent devices are probed. It is not possible to activate a device
+ 5. If the driver provides an ofdata_to_platdata() method, then this is
+ called to convert the device tree data into platform data. This should
+ do various calls like dev_read_u32(dev, ...) to access the node and store
+ the resulting information into dev->platdata. After this point, the device
+ works the same way whether it was bound using a device tree node or
+ U_BOOT_DEVICE() structure. In either case, the platform data is now stored
+ in the platdata structure. Typically you will use the
+ platdata_auto_alloc_size feature to specify the size of the platform data
+ structure, and U-Boot will automatically allocate and zero it for you before
+ entry to ofdata_to_platdata(). But if not, you can allocate it yourself in
+ ofdata_to_platdata(). Note that it is preferable to do all the device tree
+ decoding in ofdata_to_platdata() rather than in probe(). (Apart from the
+ ugliness of mixing configuration and run-time data, one day it is possible
+ that U-Boot will cache platform data for devices which are regularly
+ de/activated).
+
+ 5. The device is marked 'platdata valid'.
+
+Note that ofdata reading is always done (for a child and all its parents)
+before probing starts. Thus devices go through two distinct states when
+probing: reading platform data and actually touching the hardware to bring
+the device up.
+
+Having probing separate from ofdata-reading helps deal with of-platdata, where
+the probe() method is common to both DT/of-platdata operation, but the
+ofdata_to_platdata() method is implemented differently.
+
+Another case has come up where this separate is useful. Generation of ACPI
+tables uses the of-platdata but does not want to probe the device. Probing
+would cause U-Boot to violate one of its design principles, viz that it
+should only probe devices that are used. For ACPI we want to generate a
+table for each device, even if U-Boot does not use it. In fact it may not
+even be possible to probe the device - e.g. an SD card which is not
+present will cause an error on probe, yet we still must tell Linux about
+the SD card connector in case it is used while Linux is running.
+
+It is important that the ofdata_to_platdata() method does not actually probe
+the device itself. However there are cases where other devices must be probed
+in the ofdata_to_platdata() method. An example is where a device requires a
+GPIO for it to operate. To select a GPIO obviously requires that the GPIO
+device is probed. This is OK when used by common, core devices such as GPIO,
+clock, interrupts, reset and the like.
+
+If your device relies on its parent setting up a suitable address space, so
+that dev_read_addr() works correctly, then make sure that the parent device
+has its setup code in ofdata_to_platdata(). If it has it in the probe method,
+then you cannot call dev_read_addr() from the child device's
+ofdata_to_platdata() method. Move it to probe() instead. Buses like PCI can
+fall afoul of this rule.
+
+Activation/probe
+^^^^^^^^^^^^^^^^
+
+When a device needs to be used, U-Boot activates it, by first reading ofdata
+as above and then following these steps (see device_probe()):
+
+ 1. All parent devices are probed. It is not possible to activate a device
unless its predecessors (all the way up to the root device) are activated.
This means (for example) that an I2C driver will require that its bus
be activated.
- 6. The device's sequence number is assigned, either the requested one
+ 2. The device's sequence number is assigned, either the requested one
(assuming no conflicts) or the next available one if there is a conflict
or nothing particular is requested.
- 7. If the driver provides an ofdata_to_platdata() method, then this is
- called to convert the device tree data into platform data. This should
- do various calls like fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), ...)
- to access the node and store the resulting information into dev->platdata.
- After this point, the device works the same way whether it was bound
- using a device tree node or U_BOOT_DEVICE() structure. In either case,
- the platform data is now stored in the platdata structure. Typically you
- will use the platdata_auto_alloc_size feature to specify the size of the
- platform data structure, and U-Boot will automatically allocate and zero
- it for you before entry to ofdata_to_platdata(). But if not, you can
- allocate it yourself in ofdata_to_platdata(). Note that it is preferable
- to do all the device tree decoding in ofdata_to_platdata() rather than
- in probe(). (Apart from the ugliness of mixing configuration and run-time
- data, one day it is possible that U-Boot will cache platform data for
- devices which are regularly de/activated).
-
- 8. The device's probe() method is called. This should do anything that
+ 4. The device's probe() method is called. This should do anything that
is required by the device to get it going. This could include checking
that the hardware is actually present, setting up clocks for the
hardware and setting up hardware registers to initial values. The code
@@ -753,7 +799,7 @@ steps (see device_probe()):
allocate the priv space here yourself. The same applies also to
platdata_auto_alloc_size. Remember to free them in the remove() method.
- 9. The device is marked 'activated'
+ 5. The device is marked 'activated'
10. The uclass's post_probe() method is called, if one exists. This may
cause the uclass to do some housekeeping to record the device as
diff --git a/doc/driver-model/pci-info.rst b/doc/driver-model/pci-info.rst
index 3c1b1adf07..8b9faa1066 100644
--- a/doc/driver-model/pci-info.rst
+++ b/doc/driver-model/pci-info.rst
@@ -12,10 +12,10 @@ Bus number 0 will need to be requested first, and the alias in the device
tree file will point to the correct device::
aliases {
- pci0 = &pci;
+ pci0 = &pcic;
};
- pci: pci-controller {
+ pcic: pci@0 {
compatible = "sandbox,pci";
...
};
@@ -138,7 +138,7 @@ be scanned as a PCI device, causing confusion.
When this bus is scanned we will end up with something like this::
- `- * pci-controller @ 05c660c8, 0
+ `- * pci@0 @ 05c660c8, 0
`- pci@1f,0 @ 05c661c8, 63488
`- emul@1f,0 @ 05c662c8
@@ -152,7 +152,7 @@ host controller node for this functionality to work.
.. code-block:: none
- pci1: pci-controller1 {
+ pci1: pci@1 {
compatible = "sandbox,pci";
...
sandbox,dev-info = <0x08 0x00 0x1234 0x5678
@@ -166,6 +166,6 @@ fourth cells are PCI vendor ID and device ID respectively.
When this bus is scanned we will end up with something like this::
- pci [ + ] pci_sandbo |-- pci-controller1
+ pci [ + ] pci_sandbo |-- pci1
pci_emul [ ] sandbox_sw | |-- sandbox_swap_case_emul
pci_emul [ ] sandbox_sw | `-- sandbox_swap_case_emul
diff --git a/drivers/clk/altera/clk-arria10.c b/drivers/clk/altera/clk-arria10.c
index b7eed948a5..694a9427e1 100644
--- a/drivers/clk/altera/clk-arria10.c
+++ b/drivers/clk/altera/clk-arria10.c
@@ -258,7 +258,7 @@ static int socfpga_a10_clk_bind(struct udevice *dev)
continue;
if (pre_reloc_only &&
- !dm_ofnode_pre_reloc(offset_to_ofnode(offset)))
+ !ofnode_pre_reloc(offset_to_ofnode(offset)))
continue;
ret = device_bind_driver_to_node(dev, "clk-a10", name,
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 6b55ec59d6..f5808449a6 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -61,7 +61,7 @@ int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
offset > 0;
offset = fdt_next_subnode(fdt, offset)) {
if (pre_reloc_only &&
- !dm_ofnode_pre_reloc(offset_to_ofnode(offset)))
+ !ofnode_pre_reloc(offset_to_ofnode(offset)))
continue;
/*
* If this node has "compatible" property, this is not
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index ff5b28cb6a..efdb0f2905 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <errno.h>
+#include <log.h>
#include <malloc.h>
#include <dm/device.h>
#include <dm/device-internal.h>
@@ -30,11 +31,14 @@ int device_chld_unbind(struct udevice *dev, struct driver *drv)
continue;
ret = device_unbind(pos);
- if (ret && !saved_ret)
+ if (ret && !saved_ret) {
+ log_warning("device '%s' failed to unbind\n",
+ pos->name);
saved_ret = ret;
+ }
}
- return saved_ret;
+ return log_ret(saved_ret);
}
int device_chld_remove(struct udevice *dev, struct driver *drv,
@@ -63,13 +67,13 @@ int device_unbind(struct udevice *dev)
int ret;
if (!dev)
- return -EINVAL;
+ return log_msg_ret("dev", -EINVAL);
if (dev->flags & DM_FLAG_ACTIVATED)
- return -EINVAL;
+ return log_msg_ret("active", -EINVAL);
if (!(dev->flags & DM_FLAG_BOUND))
- return -EINVAL;
+ return log_msg_ret("not-bound", -EINVAL);
drv = dev->driver;
assert(drv);
@@ -77,12 +81,12 @@ int device_unbind(struct udevice *dev)
if (drv->unbind) {
ret = drv->unbind(dev);
if (ret)
- return ret;
+ return log_msg_ret("unbind", ret);
}
ret = device_chld_unbind(dev, NULL);
if (ret)
- return ret;
+ return log_msg_ret("child unbind", ret);
if (dev->flags & DM_FLAG_ALLOC_PDATA) {
free(dev->platdata);
@@ -98,7 +102,7 @@ int device_unbind(struct udevice *dev)
}
ret = uclass_unbind_device(dev);
if (ret)
- return ret;
+ return log_msg_ret("uc", ret);
if (dev->parent)
list_del(&dev->sibling_node);
@@ -194,7 +198,8 @@ int device_remove(struct udevice *dev, uint flags)
}
}
- if (!(drv->flags &
+ if (!(flags & DM_REMOVE_NO_PD) &&
+ !(drv->flags &
(DM_FLAG_DEFAULT_PD_CTRL_OFF | DM_FLAG_REMOVE_WITH_PD_ON)) &&
dev != gd->cur_serial_dev)
dev_power_domain_off(dev);
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 89ea820d48..0157bb1fe0 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -143,11 +143,9 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
goto fail_alloc3;
}
}
- }
-
- /* put dev into parent's successor list */
- if (parent)
+ /* put dev into parent's successor list */
list_add_tail(&dev->sibling_node, &parent->child_head);
+ }
ret = uclass_bind_device(dev);
if (ret)
@@ -323,6 +321,22 @@ int device_ofdata_to_platdata(struct udevice *dev)
if (dev->flags & DM_FLAG_PLATDATA_VALID)
return 0;
+ /* Ensure all parents have ofdata */
+ if (dev->parent) {
+ ret = device_ofdata_to_platdata(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->flags & DM_FLAG_PLATDATA_VALID)
+ return 0;
+ }
+
drv = dev->driver;
assert(drv);
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 68204c303f..c7db14ed56 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -175,7 +175,7 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
continue;
if (pre_reloc_only) {
- if (!dm_ofnode_pre_reloc(node) &&
+ if (!ofnode_pre_reloc(node) &&
!(entry->flags & DM_FLAG_PRE_RELOC)) {
log_debug("Skipping device pre-relocation\n");
return 0;
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index acd745c121..c54baa140a 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -449,21 +449,7 @@ static void *of_find_property_value_of_size(const struct device_node *np,
int of_read_u32(const struct device_node *np, const char *propname, 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));
- if (IS_ERR(val)) {
- debug("(not found)\n");
- return PTR_ERR(val);
- }
-
- *outp = be32_to_cpup(val);
- debug("%#x (%d)\n", *outp, *outp);
-
- return 0;
+ return of_read_u32_index(np, propname, 0, outp);
}
int of_read_u32_array(const struct device_node *np, const char *propname,
@@ -485,6 +471,28 @@ int of_read_u32_array(const struct device_node *np, const char *propname,
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;
@@ -577,7 +585,7 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
{
const __be32 *list, *list_end;
int rc = 0, cur_index = 0;
- uint32_t count = 0;
+ uint32_t count;
struct device_node *node = NULL;
phandle phandle;
int size;
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 96a5dd20bd..b0be7cbe19 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -18,32 +18,53 @@
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(ofnode_to_np(node), propname, outp);
- } else {
- const fdt32_t *cell;
- int len;
+ 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 || len < sizeof(int)) {
- debug("(not found)\n");
- return -EINVAL;
- }
- *outp = fdt32_to_cpu(cell[0]);
+ 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_default(ofnode node, const char *propname, u32 def)
+u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
+ u32 def)
{
assert(ofnode_valid(node));
- ofnode_read_u32(node, propname, &def);
+ ofnode_read_u32_index(node, propname, index, &def);
return def;
}
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 1f999b1b31..ce78f09d28 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -22,6 +22,19 @@ int dev_read_u32_default(const struct udevice *dev, const char *propname,
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);
diff --git a/drivers/core/root.c b/drivers/core/root.c
index e85643819e..14df16c280 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -203,15 +203,6 @@ static int dm_scan_fdt_live(struct udevice *parent,
int ret = 0, err;
for (np = node_parent->child; np; np = np->sibling) {
- /* "chosen" node isn't a device itself but may contain some: */
- if (!strcmp(np->name, "chosen")) {
- pr_debug("parsing subnodes of \"chosen\"\n");
-
- err = dm_scan_fdt_live(parent, np, pre_reloc_only);
- if (err && !ret)
- ret = err;
- continue;
- }
if (!of_device_is_available(np)) {
pr_debug(" - ignoring disabled device\n");
@@ -256,21 +247,6 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
offset = fdt_next_subnode(blob, offset)) {
const char *node_name = fdt_get_name(blob, offset, NULL);
- /*
- * The "chosen" and "firmware" nodes aren't devices
- * themselves but may contain some:
- */
- if (!strcmp(node_name, "chosen") ||
- !strcmp(node_name, "firmware")) {
- pr_debug("parsing subnodes of \"%s\"\n", node_name);
-
- err = dm_scan_fdt_node(parent, blob, offset,
- pre_reloc_only);
- if (err && !ret)
- ret = err;
- continue;
- }
-
if (!fdtdec_get_is_enabled(blob, offset)) {
pr_debug(" - ignoring disabled device\n");
continue;
@@ -315,7 +291,8 @@ int dm_scan_fdt(const void *blob, bool pre_reloc_only)
return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
}
-static int dm_scan_fdt_ofnode_path(const char *path, bool pre_reloc_only)
+static int dm_scan_fdt_ofnode_path(const void *blob, const char *path,
+ bool pre_reloc_only)
{
ofnode node;
@@ -327,13 +304,18 @@ static int dm_scan_fdt_ofnode_path(const char *path, bool pre_reloc_only)
if (of_live_active())
return dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only);
#endif
- return dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, node.of_offset,
+ return dm_scan_fdt_node(gd->dm_root, blob, node.of_offset,
pre_reloc_only);
}
int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
{
- int ret;
+ int ret, i;
+ const char * const nodes[] = {
+ "/chosen",
+ "/clocks",
+ "/firmware"
+ };
ret = dm_scan_fdt(blob, pre_reloc_only);
if (ret) {
@@ -341,16 +323,16 @@ int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
return ret;
}
- ret = dm_scan_fdt_ofnode_path("/clocks", pre_reloc_only);
- if (ret) {
- debug("scan for /clocks 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(blob, nodes[i], pre_reloc_only);
+ if (ret) {
+ debug("dm_scan_fdt() scan for %s failed: %d\n",
+ nodes[i], ret);
+ return ret;
+ }
}
- ret = dm_scan_fdt_ofnode_path("/firmware", pre_reloc_only);
- if (ret)
- debug("scan for /firmware failed: %d\n", ret);
-
return ret;
}
#endif
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 58b19a4210..6849302936 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -118,12 +118,12 @@ int uclass_destroy(struct uclass *uc)
while (!list_empty(&uc->dev_head)) {
dev = list_first_entry(&uc->dev_head, struct udevice,
uclass_node);
- ret = device_remove(dev, DM_REMOVE_NORMAL);
+ ret = device_remove(dev, DM_REMOVE_NORMAL | DM_REMOVE_NO_PD);
if (ret)
- return ret;
+ return log_msg_ret("remove", ret);
ret = device_unbind(dev);
if (ret)
- return ret;
+ return log_msg_ret("unbind", ret);
}
uc_drv = uc->uc_drv;
diff --git a/drivers/core/util.c b/drivers/core/util.c
index 69f83755f0..25b0d76f43 100644
--- a/drivers/core/util.c
+++ b/drivers/core/util.c
@@ -33,34 +33,6 @@ int list_count_items(struct list_head *head)
return count;
}
-#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
-bool dm_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
-}
-#endif
-
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
int pci_get_devfn(struct udevice *dev)
{
diff --git a/drivers/misc/p2sb_emul.c b/drivers/misc/p2sb_emul.c
index a6ee9a235e..02f7a7ea67 100644
--- a/drivers/misc/p2sb_emul.c
+++ b/drivers/misc/p2sb_emul.c
@@ -215,7 +215,7 @@ static int sandbox_p2sb_emul_map_physmem(struct udevice *dev,
void **ptrp)
{
struct p2sb_emul_priv *priv = dev_get_priv(dev);
- struct udevice *child;
+ struct udevice *child = NULL; /* Silence compiler warning */
unsigned int offset;
int barnum;
int ret;
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 30f9b8c939..7703c67492 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -162,6 +162,7 @@ int serial_init(void)
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
serial_find_console_or_panic();
gd->flags |= GD_FLG_SERIAL_READY;
+ serial_setbrg();
#endif
return 0;
diff --git a/include/dm/device.h b/include/dm/device.h
index 35e19d8700..975eec5d0e 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -80,18 +80,21 @@ struct driver_info;
*/
enum {
/* Normal remove, remove all devices */
- DM_REMOVE_NORMAL = 1 << 0,
+ DM_REMOVE_NORMAL = 1 << 0,
/* Remove devices with active DMA */
- DM_REMOVE_ACTIVE_DMA = DM_FLAG_ACTIVE_DMA,
+ DM_REMOVE_ACTIVE_DMA = DM_FLAG_ACTIVE_DMA,
/* Remove devices which need some final OS preparation steps */
- DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE,
+ DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE,
/* Add more use cases here */
/* Remove devices with any active flag */
- DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA | DM_REMOVE_OS_PREPARE,
+ DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA | DM_REMOVE_OS_PREPARE,
+
+ /* Don't power down any attached power domains */
+ DM_REMOVE_NO_PD = 1 << 1,
};
/**
diff --git a/include/dm/of_access.h b/include/dm/of_access.h
index 13fedb7cf5..92876b3ecb 100644
--- a/include/dm/of_access.h
+++ b/include/dm/of_access.h
@@ -235,6 +235,25 @@ struct device_node *of_find_node_by_phandle(phandle handle);
int of_read_u32(const struct device_node *np, const char *propname, u32 *outp);
/**
+ * of_read_u32_index() - Find and read a 32-bit value from a multi-value
+ * property
+ *
+ * Search for a property in a device node and read a 32-bit value from
+ * it.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @index: index of the u32 in the list of values
+ * @outp: pointer to return value, modified only if return value is 0.
+ *
+ * @return 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ */
+int of_read_u32_index(const struct device_node *np, const char *propname,
+ int index, u32 *outp);
+
+/**
* of_read_u64() - Find and read a 64-bit integer from a property
*
* Search for a property in a device node and read a 64-bit value from
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index b5a50e8849..ce5e366c06 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -203,6 +203,18 @@ static inline ofnode ofnode_null(void)
int ofnode_read_u32(ofnode node, const char *propname, u32 *outp);
/**
+ * ofnode_read_u32_index() - Read a 32-bit integer from a multi-value property
+ *
+ * @ref: valid node reference to read property from
+ * @propname: name of the property to read from
+ * @index: index of the integer to return
+ * @outp: place to put value (if found)
+ * @return 0 if OK, -ve on error
+ */
+int ofnode_read_u32_index(ofnode node, const char *propname, int index,
+ u32 *outp);
+
+/**
* ofnode_read_s32() - Read a 32-bit integer from a property
*
* @ref: valid node reference to read property from
@@ -227,6 +239,19 @@ static inline int ofnode_read_s32(ofnode node, const char *propname,
u32 ofnode_read_u32_default(ofnode ref, const char *propname, u32 def);
/**
+ * ofnode_read_u32_index_default() - Read a 32-bit integer from a multi-value
+ * property
+ *
+ * @ref: valid node reference to read property from
+ * @propname: name of the property to read from
+ * @index: index of the integer to return
+ * @def: default value to return if the property has no value
+ * @return property value, or @def if not found
+ */
+u32 ofnode_read_u32_index_default(ofnode ref, const char *propname, int index,
+ u32 def);
+
+/**
* ofnode_read_s32_default() - Read a 32-bit integer from a property
*
* @ref: valid node reference to read property from
diff --git a/include/dm/read.h b/include/dm/read.h
index da8c7f25e7..77d3bc8db5 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -67,6 +67,32 @@ int dev_read_u32_default(const struct udevice *dev, const char *propname,
int def);
/**
+ * dev_read_u32_index() - read an indexed 32-bit integer from a device's DT
+ * property
+ *
+ * @dev: device to read DT property from
+ * @propname: name of the property to read from
+ * @index: index of the integer to return
+ * @outp: place to put value (if found)
+ * @return 0 if OK, -ve on error
+ */
+int dev_read_u32_index(struct udevice *dev, const char *propname, int index,
+ u32 *outp);
+
+/**
+ * dev_read_u32_index_default() - read an indexed 32-bit integer from a device's
+ * DT property
+ *
+ * @dev: device to read DT property from
+ * @propname: name of the property to read from
+ * @index: index of the integer to return
+ * @def: default value to return if the property has no value
+ * @return property value, or @def if not found
+ */
+u32 dev_read_u32_index_default(struct udevice *dev, const char *propname,
+ int index, u32 def);
+
+/**
* dev_read_s32() - read a signed 32-bit integer from a device's DT property
*
* @dev: device to read DT property from
@@ -621,6 +647,20 @@ static inline int dev_read_u32_default(const struct udevice *dev,
return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
}
+static inline 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);
+}
+
+static inline 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);
+}
+
static inline int dev_read_s32(const struct udevice *dev,
const char *propname, s32 *outp)
{
diff --git a/include/dm/util.h b/include/dm/util.h
index 0ccb3fbadf..23f8deb14e 100644
--- a/include/dm/util.h
+++ b/include/dm/util.h
@@ -42,31 +42,4 @@ static inline void dm_dump_devres(void)
/* Dump out a list of drivers */
void dm_dump_drivers(void);
-/**
- * Check if an of node should be or was bound before relocation.
- *
- * Devicetree nodes can be marked as needed to be bound
- * in the loader stages via special devicetree properties.
- *
- * Before relocation this function can be used to check if nodes
- * are required in either SPL or TPL stages.
- *
- * After relocation and jumping into the real U-Boot binary
- * it is possible to determine if a node was bound in one of
- * SPL/TPL stages.
- *
- * There are 4 settings currently in use
- * - u-boot,dm-pre-proper: U-Boot proper pre-relocation only
- * - u-boot,dm-pre-reloc: legacy and indicates any of TPL or SPL
- * Existing platforms only use it to indicate nodes needed in
- * SPL. Should probably be replaced by u-boot,dm-spl for
- * existing platforms.
- * - u-boot,dm-spl: SPL and U-Boot pre-relocation
- * - u-boot,dm-tpl: TPL and U-Boot pre-relocation
- * @node: of node
- *
- * Returns true if node is needed in SPL/TL, false otherwise.
- */
-bool dm_ofnode_pre_reloc(ofnode node);
-
#endif
diff --git a/include/log.h b/include/log.h
index fbcbd42fb4..cf32351134 100644
--- a/include/log.h
+++ b/include/log.h
@@ -117,11 +117,11 @@ static inline int _log_nop(enum log_category_t cat, enum log_level_t level,
#define log_io(_fmt...) log(LOG_CATEGORY, LOGL_DEBUG_IO, ##_fmt)
#else
#define _LOG_MAX_LEVEL LOGL_INFO
-#define log_err(_fmt...) log_nop(LOG_CATEGORY, LOGL_ERR, ##_fmt)
-#define log_warning(_fmt...) log_nop(LOG_CATEGORY, LOGL_WARNING, ##_fmt)
-#define log_notice(_fmt...) log_nop(LOG_CATEGORY, LOGL_NOTICE, ##_fmt)
-#define log_info(_fmt...) log_nop(LOG_CATEGORY, LOGL_INFO, ##_fmt)
-#define log_debug(_fmt...) log_nop(LOG_CATEGORY, LOGL_DEBUG, ##_fmt)
+#define log_err(_fmt, ...) printf(_fmt, ##__VA_ARGS__)
+#define log_warning(_fmt, ...) printf(_fmt, ##__VA_ARGS__)
+#define log_notice(_fmt, ...) printf(_fmt, ##__VA_ARGS__)
+#define log_info(_fmt, ...) printf(_fmt, ##__VA_ARGS__)
+#define log_debug(_fmt, ...) debug(_fmt, ##__VA_ARGS__)
#define log_content(_fmt...) log_nop(LOG_CATEGORY, \
LOGL_DEBUG_CONTENT, ##_fmt)
#define log_io(_fmt...) log_nop(LOG_CATEGORY, LOGL_DEBUG_IO, ##_fmt)
diff --git a/include/test/log.h b/include/test/log.h
new file mode 100644
index 0000000000..c661cde75a
--- /dev/null
+++ b/include/test/log.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Tests for logging functions
+ */
+
+#ifndef __TEST_LOG_H__
+#define __TEST_LOG_H__
+
+#include <test/test.h>
+
+/* Declare a new logging test */
+#define LOG_TEST(_name) UNIT_TEST(_name, 0, log_test)
+
+#endif /* __TEST_LOG_H__ */
diff --git a/include/test/suites.h b/include/test/suites.h
index 0748185eaf..39ad81a90f 100644
--- a/include/test/suites.h
+++ b/include/test/suites.h
@@ -30,6 +30,7 @@ int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
int do_ut_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
int do_ut_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
int do_ut_lib(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_ut_log(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
int do_ut_optee(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
diff --git a/include/test/ut.h b/include/test/ut.h
index 39d15953ed..b05d719ed0 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -105,6 +105,22 @@ int ut_check_console_dump(struct unit_test_state *uts, int total_bytes);
} \
}
+/* Assert that two 64 int expressions are equal */
+#define ut_asserteq_64(expr1, expr2) { \
+ u64 _val1 = (expr1), _val2 = (expr2); \
+ \
+ if (_val1 != _val2) { \
+ ut_failf(uts, __FILE__, __LINE__, __func__, \
+ #expr1 " == " #expr2, \
+ "Expected %#llx (%lld), got %#llx (%lld)", \
+ (unsigned long long)_val1, \
+ (unsigned long long)_val1, \
+ (unsigned long long)_val2, \
+ (unsigned long long)_val2); \
+ return CMD_RET_FAILURE; \
+ } \
+}
+
/* Assert that two string expressions are equal */
#define ut_asserteq_str(expr1, expr2) { \
const char *_val1 = (expr1), *_val2 = (expr2); \
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index eb11fc898e..9ecfa2a2d7 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -1433,14 +1433,9 @@ int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name,
const struct fdt_memory *carveout)
{
uint32_t phandle;
- int err, offset;
+ int err, offset, len;
fdt32_t value;
-
- /* XXX implement support for multiple phandles */
- if (index > 0) {
- debug("invalid index %u\n", index);
- return -FDT_ERR_BADOFFSET;
- }
+ void *prop;
err = fdtdec_add_reserved_memory(blob, name, carveout, &phandle);
if (err < 0) {
@@ -1456,10 +1451,31 @@ int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name,
value = cpu_to_fdt32(phandle);
- err = fdt_setprop(blob, offset, prop_name, &value, sizeof(value));
+ if (!fdt_getprop(blob, offset, prop_name, &len)) {
+ if (len == -FDT_ERR_NOTFOUND)
+ len = 0;
+ else
+ return len;
+ }
+
+ if ((index + 1) * sizeof(value) > len) {
+ err = fdt_setprop_placeholder(blob, offset, prop_name,
+ (index + 1) * sizeof(value),
+ &prop);
+ if (err < 0) {
+ debug("failed to resize reserved memory property: %s\n",
+ fdt_strerror(err));
+ return err;
+ }
+ }
+
+ err = fdt_setprop_inplace_namelen_partial(blob, offset, prop_name,
+ strlen(prop_name),
+ index * sizeof(value),
+ &value, sizeof(value));
if (err < 0) {
- debug("failed to set %s property for node %s: %d\n", prop_name,
- node, err);
+ debug("failed to update %s property for node %s: %s\n",
+ prop_name, node, fdt_strerror(err));
return err;
}
diff --git a/test/Kconfig b/test/Kconfig
index 0157e0b060..28704a25b6 100644
--- a/test/Kconfig
+++ b/test/Kconfig
@@ -40,6 +40,15 @@ config UT_LIB_RSA
endif
+config UT_LOG
+ bool "Unit tests for logging functions"
+ depends on UNIT_TEST
+ default y
+ help
+ Enables the 'ut log' command which tests logging functions like
+ log_err().
+ See also CONFIG_LOG_TEST which provides the 'log test' command.
+
config UT_TIME
bool "Unit tests for time functions"
depends on UNIT_TEST
diff --git a/test/Makefile b/test/Makefile
index 2fe41f489c..2971d0d87f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -10,5 +10,5 @@ obj-$(CONFIG_SANDBOX) += compression.o
obj-$(CONFIG_SANDBOX) += print_ut.o
obj-$(CONFIG_UT_TIME) += time_ut.o
obj-$(CONFIG_UT_UNICODE) += unicode_ut.o
-obj-$(CONFIG_$(SPL_)LOG) += log/
+obj-y += log/
obj-$(CONFIG_UNIT_TEST) += lib/
diff --git a/test/cmd_ut.c b/test/cmd_ut.c
index a3a9d49f7e..7fdcdbb1a6 100644
--- a/test/cmd_ut.c
+++ b/test/cmd_ut.c
@@ -60,6 +60,9 @@ static cmd_tbl_t cmd_ut_sub[] = {
#ifdef CONFIG_UT_LIB
U_BOOT_CMD_MKENT(lib, CONFIG_SYS_MAXARGS, 1, do_ut_lib, "", ""),
#endif
+#ifdef CONFIG_UT_LOG
+ U_BOOT_CMD_MKENT(log, CONFIG_SYS_MAXARGS, 1, do_ut_log, "", ""),
+#endif
#ifdef CONFIG_UT_TIME
U_BOOT_CMD_MKENT(time, CONFIG_SYS_MAXARGS, 1, do_ut_time, "", ""),
#endif
@@ -125,6 +128,9 @@ static char ut_help_text[] =
#ifdef CONFIG_UT_LIB
"ut lib [test-name] - test library functions\n"
#endif
+#ifdef CONFIG_UT_LOG
+ "ut log [test-name] - test logging functions\n"
+#endif
#ifdef CONFIG_UT_OPTEE
"ut optee [test-name]\n"
#endif
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 3daf8a544e..f55874c0f2 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_LED) += led.o
obj-$(CONFIG_DM_MAILBOX) += mailbox.o
obj-$(CONFIG_DM_MMC) += mmc.o
obj-y += ofnode.o
+obj-y += fdtdec.o
obj-$(CONFIG_OSD) += osd.o
obj-$(CONFIG_DM_VIDEO) += panel.o
obj-$(CONFIG_DM_PCI) += pci.o
diff --git a/test/dm/fdtdec.c b/test/dm/fdtdec.c
new file mode 100644
index 0000000000..b2f75b5843
--- /dev/null
+++ b/test/dm/fdtdec.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/of_extra.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+static int dm_test_fdtdec_set_carveout(struct unit_test_state *uts)
+{
+ struct fdt_memory resv;
+ void *blob;
+ const fdt32_t *prop;
+ int blob_sz, len, offset;
+
+ blob_sz = fdt_totalsize(gd->fdt_blob) + 4096;
+ blob = malloc(blob_sz);
+ ut_assertnonnull(blob);
+
+ /* Make a writtable copy of the fdt blob */
+ ut_assertok(fdt_open_into(gd->fdt_blob, blob, blob_sz));
+
+ resv.start = 0x1000;
+ resv.end = 0x2000;
+ ut_assertok(fdtdec_set_carveout(blob, "/a-test",
+ "memory-region", 2, "test_resv1",
+ &resv));
+
+ resv.start = 0x10000;
+ resv.end = 0x20000;
+ ut_assertok(fdtdec_set_carveout(blob, "/a-test",
+ "memory-region", 1, "test_resv2",
+ &resv));
+
+ resv.start = 0x100000;
+ resv.end = 0x200000;
+ ut_assertok(fdtdec_set_carveout(blob, "/a-test",
+ "memory-region", 0, "test_resv3",
+ &resv));
+
+ offset = fdt_path_offset(blob, "/a-test");
+ ut_assert(offset > 0);
+ prop = fdt_getprop(blob, offset, "memory-region", &len);
+ ut_assertnonnull(prop);
+
+ ut_asserteq(len, 12);
+ ut_assert(fdt_node_offset_by_phandle(blob, fdt32_to_cpu(prop[0])) > 0);
+ ut_assert(fdt_node_offset_by_phandle(blob, fdt32_to_cpu(prop[1])) > 0);
+ ut_assert(fdt_node_offset_by_phandle(blob, fdt32_to_cpu(prop[2])) > 0);
+
+ free(blob);
+
+ return 0;
+}
+DM_TEST(dm_test_fdtdec_set_carveout,
+ DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | DM_TESTF_FLAT_TREE);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 75ae08081c..a56275aef9 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -255,7 +255,7 @@ static int dm_test_fdt(struct unit_test_state *uts)
int ret;
int i;
- ret = dm_scan_fdt(gd->fdt_blob, false);
+ ret = dm_extended_scan_fdt(gd->fdt_blob, false);
ut_assert(!ret);
ret = uclass_get(UCLASS_TEST_FDT, &uc);
@@ -867,6 +867,7 @@ static int dm_test_read_int(struct unit_test_state *uts)
u32 val32;
s32 sval;
uint val;
+ u64 val64;
ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
ut_asserteq_str("a-test", dev->name);
@@ -891,10 +892,48 @@ static int dm_test_read_int(struct unit_test_state *uts)
ut_assertok(dev_read_u32u(dev, "uint-value", &val));
ut_asserteq(-1234, val);
+ ut_assertok(dev_read_u64(dev, "int64-value", &val64));
+ ut_asserteq_64(0x1111222233334444, val64);
+
+ ut_asserteq_64(-EINVAL, dev_read_u64(dev, "missing", &val64));
+ ut_asserteq_64(6, dev_read_u64_default(dev, "missing", 6));
+
+ ut_asserteq_64(0x1111222233334444,
+ dev_read_u64_default(dev, "int64-value", 6));
+
return 0;
}
DM_TEST(dm_test_read_int, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+static int dm_test_read_int_index(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ u32 val32;
+
+ ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
+ ut_asserteq_str("a-test", dev->name);
+
+ ut_asserteq(-EINVAL, dev_read_u32_index(dev, "missing", 0, &val32));
+ ut_asserteq(19, dev_read_u32_index_default(dev, "missing", 0, 19));
+
+ ut_assertok(dev_read_u32_index(dev, "int-array", 0, &val32));
+ ut_asserteq(5678, val32);
+ ut_assertok(dev_read_u32_index(dev, "int-array", 1, &val32));
+ ut_asserteq(9123, val32);
+ ut_assertok(dev_read_u32_index(dev, "int-array", 2, &val32));
+ ut_asserteq(4567, val32);
+ ut_asserteq(-EOVERFLOW, dev_read_u32_index(dev, "int-array", 3,
+ &val32));
+
+ ut_asserteq(5678, dev_read_u32_index_default(dev, "int-array", 0, 2));
+ ut_asserteq(9123, dev_read_u32_index_default(dev, "int-array", 1, 2));
+ ut_asserteq(4567, dev_read_u32_index_default(dev, "int-array", 2, 2));
+ ut_asserteq(2, dev_read_u32_index_default(dev, "int-array", 3, 2));
+
+ return 0;
+}
+DM_TEST(dm_test_read_int_index, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
/* Test iteration through devices by drvdata */
static int dm_test_uclass_drvdata(struct unit_test_state *uts)
{
@@ -953,3 +992,28 @@ static int dm_test_first_child_probe(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_first_child_probe, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that ofdata is read for parents before children */
+static int dm_test_ofdata_order(struct unit_test_state *uts)
+{
+ struct udevice *bus, *dev;
+
+ ut_assertok(uclass_find_first_device(UCLASS_I2C, &bus));
+ ut_assertnonnull(bus);
+ ut_assert(!(bus->flags & DM_FLAG_PLATDATA_VALID));
+
+ ut_assertok(device_find_first_child(bus, &dev));
+ ut_assertnonnull(dev);
+ ut_assert(!(dev->flags & DM_FLAG_PLATDATA_VALID));
+
+ /* read the child's ofdata which should cause the parent's to be read */
+ ut_assertok(device_ofdata_to_platdata(dev));
+ ut_assert(dev->flags & DM_FLAG_PLATDATA_VALID);
+ ut_assert(bus->flags & DM_FLAG_PLATDATA_VALID);
+
+ ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
+ ut_assert(!(bus->flags & DM_FLAG_ACTIVATED));
+
+ return 0;
+}
+DM_TEST(dm_test_ofdata_order, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/log/Makefile b/test/log/Makefile
index e0d0a4745f..4c92550f6e 100644
--- a/test/log/Makefile
+++ b/test/log/Makefile
@@ -3,3 +3,17 @@
# Copyright (c) 2017 Google, Inc
obj-$(CONFIG_LOG_TEST) += log_test.o
+
+ifdef CONFIG_UT_LOG
+
+obj-y += test-main.o
+
+ifdef CONFIG_SANDBOX
+obj-$(CONFIG_LOG_SYSLOG) += syslog_test.o
+endif
+
+ifndef CONFIG_LOG
+obj-$(CONFIG_CONSOLE_RECORD) += nolog_test.o
+endif
+
+endif # CONFIG_UT_LOG
diff --git a/test/log/nolog_test.c b/test/log/nolog_test.c
new file mode 100644
index 0000000000..84619521c9
--- /dev/null
+++ b/test/log/nolog_test.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Logging function tests for CONFIG_LOG=n.
+ */
+
+/* Needed for testing log_debug() */
+#define DEBUG 1
+
+#include <common.h>
+#include <console.h>
+#include <test/log.h>
+#include <test/test.h>
+#include <test/suites.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define BUFFSIZE 32
+
+static int nolog_test_log_err(struct unit_test_state *uts)
+{
+ char buf[BUFFSIZE];
+
+ memset(buf, 0, BUFFSIZE);
+ console_record_reset_enable();
+ log_err("testing %s\n", "log_err");
+ gd->flags &= ~GD_FLG_RECORD;
+ ut_assertok(ut_check_console_line(uts, "testing log_err"));
+ ut_assertok(ut_check_console_end(uts));
+ return 0;
+}
+LOG_TEST(nolog_test_log_err);
+
+static int nolog_test_log_warning(struct unit_test_state *uts)
+{
+ char buf[BUFFSIZE];
+
+ memset(buf, 0, BUFFSIZE);
+ console_record_reset_enable();
+ log_warning("testing %s\n", "log_warning");
+ gd->flags &= ~GD_FLG_RECORD;
+ ut_assertok(ut_check_console_line(uts, "testing log_warning"));
+ ut_assertok(ut_check_console_end(uts));
+ return 0;
+}
+LOG_TEST(nolog_test_log_warning);
+
+static int nolog_test_log_notice(struct unit_test_state *uts)
+{
+ char buf[BUFFSIZE];
+
+ memset(buf, 0, BUFFSIZE);
+ console_record_reset_enable();
+ log_notice("testing %s\n", "log_notice");
+ gd->flags &= ~GD_FLG_RECORD;
+ ut_assertok(ut_check_console_line(uts, "testing log_notice"));
+ ut_assertok(ut_check_console_end(uts));
+ return 0;
+}
+LOG_TEST(nolog_test_log_notice);
+
+static int nolog_test_log_info(struct unit_test_state *uts)
+{
+ char buf[BUFFSIZE];
+
+ memset(buf, 0, BUFFSIZE);
+ console_record_reset_enable();
+ log_err("testing %s\n", "log_info");
+ gd->flags &= ~GD_FLG_RECORD;
+ ut_assertok(ut_check_console_line(uts, "testing log_info"));
+ ut_assertok(ut_check_console_end(uts));
+ return 0;
+}
+LOG_TEST(nolog_test_log_info);
+
+#undef _DEBUG
+#define _DEBUG 0
+static int nolog_test_nodebug(struct unit_test_state *uts)
+{
+ char buf[BUFFSIZE];
+
+ memset(buf, 0, BUFFSIZE);
+ console_record_reset_enable();
+ debug("testing %s\n", "debug");
+ gd->flags &= ~GD_FLG_RECORD;
+ ut_assertok(ut_check_console_end(uts));
+ return 0;
+}
+LOG_TEST(nolog_test_nodebug);
+
+static int nolog_test_log_nodebug(struct unit_test_state *uts)
+{
+ char buf[BUFFSIZE];
+
+ memset(buf, 0, BUFFSIZE);
+ console_record_reset_enable();
+ log_debug("testing %s\n", "log_debug");
+ gd->flags &= ~GD_FLG_RECORD;
+ ut_assert(!strcmp(buf, ""));
+ ut_assertok(ut_check_console_end(uts));
+ return 0;
+}
+LOG_TEST(nolog_test_log_nodebug);
+
+#undef _DEBUG
+#define _DEBUG 1
+static int nolog_test_debug(struct unit_test_state *uts)
+{
+ char buf[BUFFSIZE];
+
+ memset(buf, 0, BUFFSIZE);
+ console_record_reset_enable();
+ debug("testing %s\n", "debug");
+ gd->flags &= ~GD_FLG_RECORD;
+ ut_assertok(ut_check_console_line(uts, "testing debug"));
+ ut_assertok(ut_check_console_end(uts));
+ return 0;
+}
+LOG_TEST(nolog_test_debug);
+
+static int nolog_test_log_debug(struct unit_test_state *uts)
+{
+ char buf[BUFFSIZE];
+
+ memset(buf, 0, BUFFSIZE);
+ console_record_reset_enable();
+ log_debug("testing %s\n", "log_debug");
+ gd->flags &= ~GD_FLG_RECORD;
+ ut_assertok(ut_check_console_line(uts, "testing log_debug"));
+ ut_assertok(ut_check_console_end(uts));
+ return 0;
+}
+LOG_TEST(nolog_test_log_debug);
diff --git a/test/log/syslog_test.c b/test/log/syslog_test.c
new file mode 100644
index 0000000000..6ca5760eac
--- /dev/null
+++ b/test/log/syslog_test.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Logging function tests for CONFIG_LOG_SYSLOG=y.
+ *
+ * Invoke the test with: ./u-boot -d arch/sandbox/dts/test.dtb
+ */
+
+/* Override CONFIG_LOG_MAX_LEVEL */
+#define LOG_DEBUG
+
+#include <common.h>
+#include <dm/device.h>
+#include <hexdump.h>
+#include <test/log.h>
+#include <test/test.h>
+#include <test/suites.h>
+#include <test/ut.h>
+#include <asm/eth.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct sb_log_env - private data for sandbox ethernet driver
+ *
+ * This structure is used for the private data of the sandbox ethernet
+ * driver.
+ *
+ * @expected: string expected to be written by the syslog driver
+ * @uts: unit test state
+ */
+struct sb_log_env {
+ const char *expected;
+ struct unit_test_state *uts;
+};
+
+/**
+ * sb_log_tx_handler() - transmit callback function
+ *
+ * This callback function is invoked when a network package is sent using the
+ * sandbox Ethernet driver. The private data of the driver holds a sb_log_env
+ * structure with the unit test state and the expected UDP payload.
+ *
+ * The following checks are executed:
+ *
+ * * the Ethernet packet indicates a IP broadcast message
+ * * the IP header is for a local UDP broadcast message to port 514
+ * * the UDP payload matches the expected string
+ *
+ * After testing the pointer to the expected string is set to NULL to signal
+ * that the callback function has been called.
+ *
+ * @dev: sandbox ethernet device
+ * @packet: Ethernet packet
+ * @len: length of Ethernet packet
+ * Return: 0 = success
+ */
+static int sb_log_tx_handler(struct udevice *dev, void *packet,
+ unsigned int len)
+{
+ struct eth_sandbox_priv *priv = dev_get_priv(dev);
+ struct sb_log_env *env = priv->priv;
+ /* uts is updated by the ut_assert* macros */
+ struct unit_test_state *uts = env->uts;
+ char *buf = packet;
+ struct ethernet_hdr *eth_hdr = packet;
+ struct ip_udp_hdr *ip_udp_hdr;
+
+ /* Check Ethernet header */
+ ut_asserteq_mem(&eth_hdr->et_dest, net_bcast_ethaddr, ARP_HLEN);
+ ut_asserteq(ntohs(eth_hdr->et_protlen), PROT_IP);
+
+ /* Check IP header */
+ buf += sizeof(struct ethernet_hdr);
+ ip_udp_hdr = (struct ip_udp_hdr *)buf;
+ ut_asserteq(ip_udp_hdr->ip_p, IPPROTO_UDP);
+ ut_asserteq(ip_udp_hdr->ip_dst.s_addr, 0xffffffff);
+ ut_asserteq(ntohs(ip_udp_hdr->udp_dst), 514);
+ ut_asserteq(UDP_HDR_SIZE + strlen(env->expected) + 1,
+ ntohs(ip_udp_hdr->udp_len));
+
+ /* Check payload */
+ buf += sizeof(struct ip_udp_hdr);
+ ut_asserteq_mem(env->expected, buf,
+ ntohs(ip_udp_hdr->udp_len) - UDP_HDR_SIZE);
+
+ /* Signal that the callback function has been executed */
+ env->expected = NULL;
+
+ return 0;
+}
+
+/**
+ * syslog_test_log_err() - test log_err() function
+ *
+ * @uts: unit test state
+ * Return: 0 = success
+ */
+static int syslog_test_log_err(struct unit_test_state *uts)
+{
+ int old_log_level = gd->default_log_level;
+ struct sb_log_env env;
+
+ gd->log_fmt = LOGF_DEFAULT;
+ gd->default_log_level = LOGL_INFO;
+ env_set("ethact", "eth@10002000");
+ env_set("log_hostname", "sandbox");
+ env.expected = "<3>sandbox uboot: syslog_test_log_err() "
+ "testing log_err\n";
+ env.uts = uts;
+ sandbox_eth_set_tx_handler(0, sb_log_tx_handler);
+ /* Used by ut_assert macros in the tx_handler */
+ sandbox_eth_set_priv(0, &env);
+ log_err("testing %s\n", "log_err");
+ /* Check that the callback function was called */
+ sandbox_eth_set_tx_handler(0, NULL);
+ gd->default_log_level = old_log_level;
+
+ return 0;
+}
+LOG_TEST(syslog_test_log_err);
+
+/**
+ * syslog_test_log_warning() - test log_warning() function
+ *
+ * @uts: unit test state
+ * Return: 0 = success
+ */
+static int syslog_test_log_warning(struct unit_test_state *uts)
+{
+ int old_log_level = gd->default_log_level;
+ struct sb_log_env env;
+
+ gd->log_fmt = LOGF_DEFAULT;
+ gd->default_log_level = LOGL_INFO;
+ env_set("ethact", "eth@10002000");
+ env_set("log_hostname", "sandbox");
+ env.expected = "<4>sandbox uboot: syslog_test_log_warning() "
+ "testing log_warning\n";
+ env.uts = uts;
+ sandbox_eth_set_tx_handler(0, sb_log_tx_handler);
+ /* Used by ut_assert macros in the tx_handler */
+ sandbox_eth_set_priv(0, &env);
+ log_warning("testing %s\n", "log_warning");
+ sandbox_eth_set_tx_handler(0, NULL);
+ /* Check that the callback function was called */
+ ut_assertnull(env.expected);
+ gd->default_log_level = old_log_level;
+
+ return 0;
+}
+LOG_TEST(syslog_test_log_warning);
+
+/**
+ * syslog_test_log_notice() - test log_notice() function
+ *
+ * @uts: unit test state
+ * Return: 0 = success
+ */
+static int syslog_test_log_notice(struct unit_test_state *uts)
+{
+ int old_log_level = gd->default_log_level;
+ struct sb_log_env env;
+
+ gd->log_fmt = LOGF_DEFAULT;
+ gd->default_log_level = LOGL_INFO;
+ env_set("ethact", "eth@10002000");
+ env_set("log_hostname", "sandbox");
+ env.expected = "<5>sandbox uboot: syslog_test_log_notice() "
+ "testing log_notice\n";
+ env.uts = uts;
+ sandbox_eth_set_tx_handler(0, sb_log_tx_handler);
+ /* Used by ut_assert macros in the tx_handler */
+ sandbox_eth_set_priv(0, &env);
+ log_notice("testing %s\n", "log_notice");
+ sandbox_eth_set_tx_handler(0, NULL);
+ /* Check that the callback function was called */
+ ut_assertnull(env.expected);
+ gd->default_log_level = old_log_level;
+
+ return 0;
+}
+LOG_TEST(syslog_test_log_notice);
+
+/**
+ * syslog_test_log_info() - test log_info() function
+ *
+ * @uts: unit test state
+ * Return: 0 = success
+ */
+static int syslog_test_log_info(struct unit_test_state *uts)
+{
+ int old_log_level = gd->default_log_level;
+ struct sb_log_env env;
+
+ gd->log_fmt = LOGF_DEFAULT;
+ gd->default_log_level = LOGL_INFO;
+ env_set("ethact", "eth@10002000");
+ env_set("log_hostname", "sandbox");
+ env.expected = "<6>sandbox uboot: syslog_test_log_info() "
+ "testing log_info\n";
+ env.uts = uts;
+ sandbox_eth_set_tx_handler(0, sb_log_tx_handler);
+ /* Used by ut_assert macros in the tx_handler */
+ sandbox_eth_set_priv(0, &env);
+ log_info("testing %s\n", "log_info");
+ sandbox_eth_set_tx_handler(0, NULL);
+ /* Check that the callback function was called */
+ ut_assertnull(env.expected);
+ gd->default_log_level = old_log_level;
+
+ return 0;
+}
+LOG_TEST(syslog_test_log_info);
+
+/**
+ * syslog_test_log_debug() - test log_debug() function
+ *
+ * @uts: unit test state
+ * Return: 0 = success
+ */
+static int syslog_test_log_debug(struct unit_test_state *uts)
+{
+ int old_log_level = gd->default_log_level;
+ struct sb_log_env env;
+
+ gd->log_fmt = LOGF_DEFAULT;
+ gd->default_log_level = LOGL_DEBUG;
+ env_set("ethact", "eth@10002000");
+ env_set("log_hostname", "sandbox");
+ env.expected = "<7>sandbox uboot: syslog_test_log_debug() "
+ "testing log_debug\n";
+ env.uts = uts;
+ sandbox_eth_set_tx_handler(0, sb_log_tx_handler);
+ /* Used by ut_assert macros in the tx_handler */
+ sandbox_eth_set_priv(0, &env);
+ log_debug("testing %s\n", "log_debug");
+ sandbox_eth_set_tx_handler(0, NULL);
+ /* Check that the callback function was called */
+ ut_assertnull(env.expected);
+ gd->default_log_level = old_log_level;
+
+ return 0;
+}
+LOG_TEST(syslog_test_log_debug);
+
+/**
+ * syslog_test_log_nodebug() - test logging level filter
+ *
+ * Verify that log_debug() does not lead to a log message if the logging level
+ * is set to LOGL_INFO.
+ *
+ * @uts: unit test state
+ * Return: 0 = success
+ */
+static int syslog_test_log_nodebug(struct unit_test_state *uts)
+{
+ int old_log_level = gd->default_log_level;
+ struct sb_log_env env;
+
+ gd->log_fmt = LOGF_DEFAULT;
+ gd->default_log_level = LOGL_INFO;
+ env_set("ethact", "eth@10002000");
+ env_set("log_hostname", "sandbox");
+ env.expected = "<7>sandbox uboot: syslog_test_log_nodebug() "
+ "testing log_debug\n";
+ env.uts = uts;
+ sandbox_eth_set_tx_handler(0, sb_log_tx_handler);
+ /* Used by ut_assert macros in the tx_handler */
+ sandbox_eth_set_priv(0, &env);
+ log_debug("testing %s\n", "log_debug");
+ sandbox_eth_set_tx_handler(0, NULL);
+ /* Check that the callback function was not called */
+ ut_assertnonnull(env.expected);
+ gd->default_log_level = old_log_level;
+
+ return 0;
+}
+LOG_TEST(syslog_test_log_nodebug);
diff --git a/test/log/test-main.c b/test/log/test-main.c
new file mode 100644
index 0000000000..855de47f33
--- /dev/null
+++ b/test/log/test-main.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Logging function tests.
+ */
+
+#include <common.h>
+#include <console.h>
+#include <test/log.h>
+#include <test/suites.h>
+
+int do_ut_log(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct unit_test *tests = ll_entry_start(struct unit_test, log_test);
+ const int n_ents = ll_entry_count(struct unit_test, log_test);
+
+ return cmd_ut_category("log", "log_test_",
+ tests, n_ents, argc, argv);
+}
diff --git a/tools/patman/series.py b/tools/patman/series.py
index a15f7625ed..6d9d48b123 100644
--- a/tools/patman/series.py
+++ b/tools/patman/series.py
@@ -249,8 +249,10 @@ class Series(dict):
if cover_fname:
cover_cc = gitutil.BuildEmailList(self.get('cover_cc', ''))
cover_cc = [tools.FromUnicode(m) for m in cover_cc]
- cc_list = '\0'.join([tools.ToUnicode(x)
- for x in sorted(set(cover_cc + all_ccs))])
+ cover_cc = list(set(cover_cc + all_ccs))
+ if limit is not None:
+ cover_cc = cover_cc[:limit]
+ cc_list = '\0'.join([tools.ToUnicode(x) for x in sorted(cover_cc)])
print(cover_fname, cc_list, file=fd)
fd.close()