[U-Boot] [PATCH v3 00/72] dm: Add support for a 'live' device tree

(this is series 2 of 3 for live tree support - the final series will fully convert a real board and provide size comparisons)
So far U-Boot uses a 'flat' device tree, which means that it is decoded on the fly as needed. This uses the libfdt library and avoids needing extra memory for additional tables.
For some time there has been discussion about moving U-Boot to use a 'live' tree, where the device tree is decoded at start-up into a set of hierarchical structures with pointers.
The advantages are:
- It is somewhat faster to access (in particular scanning and looking for a parent) - It permits the device tree to be changed at run-time (this is not recommended with the flat device tree since devices store the offset of their device tree node and updating the tree may invalidate that). Enabling this feature could be useful for overlays, for example. - It allows nodes to be referenced by a single pointer, instead of the current device tree pointer plus offset
The disadvantages are:
- It requires more memory - It takes (a little) time to build the live tree - It adds more complexity under the hood, including an additional abstraction layer
This series is an attempt to introduce a useful live tree feature into U-Boot. There are many options and trade-offs. This series is the culmination of quite a bit of thought and experimentation.
The approach used in this series is:
- Before relocation the flat tree is used, to avoid extra memory usage and time. In general, there is not much access before relocation since most drivers are not started up. So there is little benefit in having a live tree
- After relocation the live tree is built. At this point the CPU should be running quickly and there is plenty of memory. All available devices will be bound so the overhead of building the live tree may be outweighed by its greater efficiency.
As a simplification, this series supports only one tree or the other. When the live tree is active, the flat tree cannot be used. That makes it easy to know the current state and avoids confusion over mixing offset and node pointers.
Some drivers will need to be used both before and after relocation. This means that they must support both the flat and the live tree. To support this, the concept of a node 'reference' is defined. A reference can hold either a node offset (for the flat tree) or a node pointer (for the live tree). This allows drivers to access values from the tree regardless of which tree is in use.
In addition, since most device tree access happens in the context of a device (struct udevice), a new 'dev_read' layer is provided to read device tree configuration associated with a device. This encapsulates the details of exactly how this information is read.
I have taken the view that code compatibility with Linux is desirable. So the of_access.c file brings in code from Linux with very little modification. As new access methods are needed we should be able to bring in more code and avoid writing it ourselves in U-Boot.
Conversion of drivers and subsystems to support the live tree (as well as flat tree) is fairly easy. Patch are included to add support to subsystems for which tests exist, to ensure that 'make tests' still passes.
Future work will enable the live device tree on a real board and include code size comparisons.
For now here is a code size comparison for firefly (within inlining of ofnode which I intend to implement):
arm: (for 1/1 boards) all +268.0 bss -24.0 data -4.0 spl/u-boot-spl:all +240.0 spl/u-boot-spl:text +240.0 text +296.0 firefly-rk3288 : all +268 bss -24 data -4 spl/u-boot-spl:all +240 spl/u-boot-spl:text +240 text +296 u-boot: add: 18/-4, grow: 2/-22 bytes: 764/-490 (274) function old new delta gpio_request_tail - 132 +132 ofnode_parse_phandle_with_args - 66 +66 uclass_find_device_by_ofnode - 64 +64 ofnode_pre_reloc - 64 +64 ofnode_read_string - 52 +52 fdt_support_default_count_cells - 52 +52 ofnode_read_u32 - 48 +48 gpio_request_by_name 32 72 +40 ofnode_read_size - 34 +34 uclass_get_device_by_ofnode - 28 +28 ofnode_read_u32_array - 28 +28 ofnode_read_bool - 26 +26 ofnode_read_prop - 24 +24 ofnode_get_addr_size - 24 +24 ofnode_read_u32_default - 22 +22 ofnode_find_subnode - 18 +18 ofnode_next_subnode - 14 +14 ofnode_first_subnode - 14 +14 ofnode_get_name - 12 +12 dm_init_and_scan 42 44 +2 uclass_get_device_by_phandle 106 104 -2 spi_child_post_bind 32 30 -2 i2c_child_post_bind 32 30 -2 spi_post_probe 36 32 -4 spi_flash_scan 520 516 -4 serial_init 212 208 -4 i2c_post_probe 48 44 -4 clk_fixed_rate_ofdata_to_platdata 36 32 -4 act8846_bind 48 44 -4 simple_bus_post_bind 60 52 -8 lists_bind_fdt 240 232 -8 i2c_chip_ofdata_to_platdata 64 56 -8 clk_get_by_index 108 100 -8 usb_child_post_bind 92 80 -12 regmap_init_mem 228 216 -12 fixed_regulator_ofdata_to_platdata 108 96 -12 pmic_bind_children 158 144 -14 spi_slave_ofdata_to_platdata 256 240 -16 pinconfig_post_bind 136 116 -20 led_gpio_bind 108 88 -20 regulator_post_bind 148 124 -24 gpio_request_by_name_nodev 28 - -28 fdtdec_get_uint 30 - -30 regulator_pre_probe 220 184 -36 of_bus_default_count_cells 52 - -52 _gpio_request_by_name_nodev 152 - -152 spl-u-boot-spl: add: 8/-1, grow: 1/-5 bytes: 300/-56 (244) function old new delta ofnode_parse_phandle_with_args - 66 +66 uclass_find_device_by_ofnode - 64 +64 ofnode_read_u32 - 48 +48 ofnode_read_size - 34 +34 uclass_get_device_by_ofnode - 28 +28 ofnode_read_prop - 24 +24 ofnode_read_u32_default - 22 +22 ofnode_get_name - 12 +12 dm_init_and_scan 42 44 +2 dm_scan_fdt_node 96 94 -2 clk_fixed_rate_ofdata_to_platdata 36 32 -4 lists_bind_fdt 224 216 -8 clk_get_by_index 108 100 -8 regmap_init_mem 220 208 -12 device_bind 22 - -22 (no errors to report)
Changes in v3: - Adjust header includes in ofnode.h to make it stand alone - Fix up the fdtaddr.h header guard to avoid conflicts - Clear the watchdog state also - Add new patch to move pmic header out of config file
Changes in v2: - Rewrite based on testing and refining the v1 series - Convert various subsystems to enable sandbox tests to pass
Simon Glass (72): dm: core: Set return value first in lists_bind_fdt() Update WARN_ON() to return a value dm: core: Add livetree definitions dm: core: Add livetree access functions dm: Add a function to create a 'live' device tree dm: Build a live tree after relocation dm: core: Rename of_device_is_compatible() dm: core: Add operations on device tree references dm: core: Add livetree address functions fdt: Update fdt_get_base_address() to use const dm: core: Add address operations on device tree references dm: core: Add a place to put extra device-tree reading functions dm: core: Add device-based 'read' functions to access DT dm: core: Implement live tree 'read' functions dm: core: Allow binding a device from a live tree dm: core: Update lists_bind_fdt() to use ofnode dm: core: Update device_bind_driver_to_node() to use ofnode dm: core: Scan the live tree when setting up driver model dm: core: Add a way to find a device by ofnode dm: regmap: Add support for livetree dm: simple-bus: Add support for livetree dm: core: Update uclass_find_device_by_phandle() for livetree sandbox: Add a way to reset sandbox state for tests dm: test: Move test running code into a separate function dm: test: Show the test filename when running dm: test: Add support for running tests with livetree dm: core: Run tests with both livetree and flat tree dm: gpio: Refactor to prepare for live tree support dm: gpio: Drop blank line in gpio_xlate_offs_flags() comment dm: gpio: sandbox: Use dev_read...() functions to access DT dm: gpio: Add live tree support cros_ec: Fix debug() statement in ec_command_inptr() cros_ec: Convert to support live tree sandbox: Add a new sandbox_flattree board test: Update 'make test' to run more tests fdt: Rename a few functions in fdt_support dm: Add more livetree helpers and definitions string: Add strchrnul() string: Add strcspn() dm: i2c: Convert uclass to livetree samsung: Move pmic header out of config file dm: pmic: Convert uclass to livetree sandbox: pmic: Convert pmic emulator to support livetree dm: regulator: Convert regulator uclass to support livetree dm: regulator: Update fixed regulator to support livetree. dm: mmc: Convert uclass to livetree dm: adc: Convert uclass to livetree dm: usb: Convert uclass to livetree sandbox: usb: Convert emulators to livetree clk: Modify xlate() method for livetree dm: clk: Update uclass to support livetree dm: clk: fixed: Update to support livetree dm: test: Separate out the bus DT offset test dm: test: Disable the fdt_offset test with livetree dm: phy: Update tests to use ut_asserteq() dm: mailbox: Update uclass to support livetree dm: phy: Update uclass to support livetree sandbox: phy: Update driver for livetree dm: power-domain: Update uclass to support livetree dm: reset: Update uclass to support livetree dm: pci: Update uclass to support livetree dm: Update the I2C eeprom driver for livetree cros_ec: Update the cros_ec keyboard driver to livetree dm: spi: Convert uclass to livetree dm: sandbox: i2c: Drop fdtdec.h header dm: sandbox: i2c_rtc: Drop fdtdec.h header dm: spi-flash: Convert uclass to livetree dm: sandbox: spi: Convert driver to support livetree dm: sandbox: sysreset: Convert driver to livetree dm: test: Fix nit with position of backslash dm: gpio: power: Convert pm8916 drivers to livetree sandbox: Move to use live tree
arch/arm/cpu/armv8/fsl-layerscape/fdt.c | 4 +- arch/arm/mach-tegra/tegra186/nvtboot_mem.c | 4 +- arch/sandbox/cpu/state.c | 15 +- arch/sandbox/include/asm/state.h | 7 + board/qualcomm/dragonboard410c/dragonboard410c.c | 12 +- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt.c | 2 +- board/samsung/common/misc.c | 1 + board/sandbox/MAINTAINERS | 7 + common/board_r.c | 12 + common/fdt_support.c | 28 +- configs/sandbox_defconfig | 1 + configs/sandbox_flattree_defconfig | 179 ++++++ drivers/adc/adc-uclass.c | 14 +- drivers/clk/at91/pmc.c | 4 +- drivers/clk/at91/pmc.h | 2 +- drivers/clk/clk-uclass.c | 14 +- drivers/clk/clk_fixed_rate.c | 5 +- drivers/clk/clk_stm32f7.c | 3 +- drivers/core/Kconfig | 4 + drivers/core/Makefile | 5 + drivers/core/device.c | 20 +- drivers/core/lists.c | 29 +- drivers/core/of_access.c | 735 +++++++++++++++++++++++ drivers/core/of_addr.c | 359 +++++++++++ drivers/core/of_extra.c | 37 ++ drivers/core/ofnode.c | 579 ++++++++++++++++++ drivers/core/read.c | 140 +++++ drivers/core/regmap.c | 37 +- drivers/core/root.c | 60 +- drivers/core/simple-bus.c | 3 +- drivers/core/uclass.c | 42 +- drivers/cpu/cpu-uclass.c | 6 +- drivers/firmware/psci.c | 4 +- drivers/gpio/74x164_gpio.c | 2 +- drivers/gpio/gpio-uclass.c | 82 +-- drivers/gpio/pca953x_gpio.c | 2 +- drivers/gpio/pm8916_gpio.c | 8 +- drivers/gpio/sandbox.c | 12 +- drivers/gpio/sunxi_gpio.c | 2 +- drivers/gpio/tegra186_gpio.c | 2 +- drivers/gpio/tegra_gpio.c | 2 +- drivers/i2c/i2c-uclass.c | 28 +- drivers/i2c/muxes/i2c-mux-uclass.c | 11 +- drivers/i2c/mxc_i2c.c | 12 +- drivers/i2c/sandbox_i2c.c | 1 - drivers/input/cros_ec_keyb.c | 24 +- drivers/input/key_matrix.c | 19 +- drivers/input/tegra-kbc.c | 3 +- drivers/led/led_bcm6328.c | 2 +- drivers/led/led_bcm6358.c | 2 +- drivers/led/led_gpio.c | 13 +- drivers/mailbox/mailbox-uclass.c | 20 +- drivers/mailbox/tegra-hsp.c | 2 +- drivers/misc/cros_ec.c | 36 +- drivers/misc/cros_ec_sandbox.c | 23 +- drivers/misc/i2c_eeprom_emul.c | 7 +- drivers/misc/tegra186_bpmp.c | 6 +- drivers/misc/tegra_car.c | 4 +- drivers/mmc/fsl_esdhc.c | 6 +- drivers/mmc/mmc-uclass.c | 3 +- drivers/mmc/s5p_sdhci.c | 8 +- drivers/mmc/xenon_sdhci.c | 2 +- drivers/mtd/altera_qspi.c | 2 +- drivers/mtd/cfi_flash.c | 2 +- drivers/mtd/nand/sunxi_nand.c | 2 +- drivers/mtd/nand/tegra_nand.c | 4 +- drivers/mtd/pic32_flash.c | 2 +- drivers/mtd/spi/sandbox.c | 6 +- drivers/mtd/spi/spi_flash.c | 7 +- drivers/net/altera_tse.c | 2 +- drivers/net/cpsw-common.c | 4 +- drivers/net/keystone_net.c | 6 +- drivers/net/mvneta.c | 2 +- drivers/net/pic32_eth.c | 3 +- drivers/pci/pci-uclass.c | 26 +- drivers/phy/marvell/comphy_core.c | 4 +- drivers/phy/phy-uclass.c | 21 +- drivers/phy/sandbox-phy.c | 3 +- drivers/pinctrl/pinctrl-uclass.c | 15 +- drivers/power/domain/power-domain-uclass.c | 19 +- drivers/power/pmic/act8846.c | 8 +- drivers/power/pmic/i2c_pmic_emul.c | 6 +- drivers/power/pmic/lp873x.c | 12 +- drivers/power/pmic/max77686.c | 8 +- drivers/power/pmic/palmas.c | 16 +- drivers/power/pmic/pfuze100.c | 8 +- drivers/power/pmic/pm8916.c | 2 +- drivers/power/pmic/pmic-uclass.c | 22 +- drivers/power/pmic/rk8xx.c | 8 +- drivers/power/pmic/s5m8767.c | 7 +- drivers/power/pmic/sandbox.c | 2 +- drivers/power/pmic/tps65090.c | 8 +- drivers/power/regulator/fixed.c | 17 +- drivers/power/regulator/regulator-uclass.c | 39 +- drivers/reset/reset-uclass.c | 21 +- drivers/rtc/i2c_rtc_emul.c | 1 - drivers/serial/serial-uclass.c | 3 +- drivers/sound/max98095.c | 2 + drivers/sound/wm8994.c | 2 +- drivers/spi/pic32_spi.c | 2 +- drivers/spi/spi-uclass.c | 31 +- drivers/sysreset/sysreset_sandbox.c | 2 +- drivers/timer/timer-uclass.c | 3 +- drivers/usb/emul/sandbox_flash.c | 4 +- drivers/usb/emul/sandbox_hub.c | 3 +- drivers/usb/host/ehci-marvell.c | 2 +- drivers/usb/host/ehci-tegra.c | 7 +- drivers/usb/host/ehci-vf.c | 5 +- drivers/usb/host/usb-uclass.c | 8 +- drivers/usb/host/xhci-rockchip.c | 2 +- drivers/usb/musb-new/ti-musb.c | 2 +- dts/Kconfig | 11 + include/asm-generic/global_data.h | 3 + include/asm-generic/gpio.h | 17 +- include/clk-uclass.h | 5 +- include/configs/trats2.h | 1 - include/cros_ec.h | 8 +- include/dm.h | 2 + include/dm/device-internal.h | 10 +- include/dm/device.h | 4 +- include/dm/fdtaddr.h | 4 +- include/dm/lists.h | 9 +- include/dm/of.h | 142 +++++ include/dm/of_access.h | 347 +++++++++++ include/dm/of_addr.h | 64 ++ include/dm/of_extra.h | 46 ++ include/dm/ofnode.h | 488 ++++++++++++++- include/dm/read.h | 439 ++++++++++++++ include/dm/root.h | 3 +- include/dm/test.h | 2 + include/dm/uclass-internal.h | 18 + include/dm/uclass.h | 17 + include/fdt_support.h | 6 +- include/fdtdec.h | 34 -- include/generic-phy.h | 3 +- include/i2c.h | 3 +- include/key_matrix.h | 3 +- include/linux/compat.h | 8 +- include/linux/string.h | 28 + include/mailbox-uclass.h | 2 +- include/of_live.h | 24 + include/power-domain-uclass.h | 2 +- include/power/pmic.h | 2 +- include/reset-uclass.h | 4 +- include/spi.h | 2 +- include/test/test.h | 4 + include/test/ut.h | 2 +- lib/Makefile | 1 + lib/fdtdec.c | 33 +- lib/of_live.c | 333 ++++++++++ lib/string.c | 32 + test/dm/bus.c | 16 +- test/dm/phy.c | 15 +- test/dm/test-fdt.c | 3 +- test/dm/test-main.c | 105 +++- test/run | 8 +- 157 files changed, 4761 insertions(+), 667 deletions(-) create mode 100644 configs/sandbox_flattree_defconfig create mode 100644 drivers/core/of_access.c create mode 100644 drivers/core/of_addr.c create mode 100644 drivers/core/of_extra.c create mode 100644 drivers/core/ofnode.c create mode 100644 drivers/core/read.c create mode 100644 include/dm/of.h create mode 100644 include/dm/of_access.h create mode 100644 include/dm/of_addr.h create mode 100644 include/dm/of_extra.h create mode 100644 include/dm/read.h create mode 100644 include/of_live.h create mode 100644 lib/of_live.c

Adjust the order to make it clear that *devp is set to NULL by default.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/lists.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 23b6ba78d3..72c55e205f 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -140,10 +140,10 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, int result = 0; int ret = 0;
- name = fdt_get_name(blob, offset, NULL); - dm_dbg("bind node %s\n", name); if (devp) *devp = NULL; + name = fdt_get_name(blob, offset, NULL); + dm_dbg("bind node %s\n", name);
compat_list = fdt_getprop(blob, offset, "compatible", &compat_length); if (!compat_list) {

Adjust the order to make it clear that *devp is set to NULL by default.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/lists.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Applied to u-boot-dm

In linux v4.9 this returns a value. This saves checking the warning condition twice in some code.
Update the U-Boot version to do this also.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/linux/compat.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/linux/compat.h b/include/linux/compat.h index a43e4d6698..03f9bef0da 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -106,8 +106,12 @@ static inline void kmem_cache_destroy(struct kmem_cache *cachep) #define BUG_ON(condition) do { if (condition) BUG(); } while(0) #endif /* BUG */
-#define WARN_ON(x) if (x) {printf("WARNING in %s line %d\n" \ - , __FILE__, __LINE__); } +#define WARN_ON(condition) ({ \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) \ + printf("WARNING in %s line %d\n", __FILE__, __LINE__);; \ + unlikely(__ret_warn_on); \ +})
#define PAGE_SIZE 4096

In linux v4.9 this returns a value. This saves checking the warning condition twice in some code.
Update the U-Boot version to do this also.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/linux/compat.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
Applied to u-boot-dm

Add a Kconfig option to enable a live device tree, built at run time from the flat tree. Also add structure definitions and a root node.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
dts/Kconfig | 11 ++++ include/asm-generic/global_data.h | 3 ++ include/dm/of.h | 106 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 include/dm/of.h
diff --git a/dts/Kconfig b/dts/Kconfig index 9a0622154a..b3009af03f 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -32,6 +32,17 @@ config SPL_OF_CONTROL which is not enough to support device tree. Enable this option to allow such boards to be supported by U-Boot SPL.
+config OF_LIVE + bool "Enable use of a live tree" + depends on OF_CONTROL + help + Normally U-Boot uses a flat device tree which saves space and + avoids the need to unpack the tree before use. However a flat + tree does not support modifcation from within U-Boot since it + can invalidate driver-model device tree offsets. This option + enables a live tree which is available after relocation, + and can be adjusted as needed. + choice prompt "Provider of DTB for DT control" depends on OF_CONTROL diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 51838b5ead..e6f905110e 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -72,6 +72,9 @@ typedef struct global_data { const void *fdt_blob; /* Our device tree, NULL if none */ void *new_fdt; /* Relocated FDT */ unsigned long fdt_size; /* Space reserved for relocated FDT */ +#ifdef CONFIG_OF_LIVE + struct device_node *of_root; +#endif struct jt_funcs *jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ #ifdef CONFIG_TRACE diff --git a/include/dm/of.h b/include/dm/of.h new file mode 100644 index 0000000000..6b5afab1c1 --- /dev/null +++ b/include/dm/of.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DM_OF_H +#define _DM_OF_H + +#include <asm/u-boot.h> +#include <asm/global_data.h> + +/* integer value within a device tree property which references another node */ +typedef u32 phandle; + +/** + * struct property: Device tree property + * + * @name: Property name + * @length: Length of property in bytes + * @value: Pointer to property value + * @next: Pointer to next property, or NULL if none + */ +struct property { + char *name; + int length; + void *value; + struct property *next; +}; + +/** + * struct device_node: Device tree node + * + * @name: Node name + * @type: Node type (value of device_type property) or "<NULL>" if none + * @phandle: Phandle value of this none, or 0 if none + * @full_name: Full path to node, e.g. "/bus@1/spi@1100" + * @properties: Pointer to head of list of properties, or NULL if none + * @parent: Pointer to parent node, or NULL if this is the root node + * @child: Pointer to head of child node list, or NULL if no children + * @sibling: Pointer to the next sibling node, or NULL if this is the last + */ +struct device_node { + const char *name; + const char *type; + phandle phandle; + const char *full_name; + + struct property *properties; + struct device_node *parent; + struct device_node *child; + struct device_node *sibling; +}; + +#define OF_MAX_PHANDLE_ARGS 16 + +/** + * struct of_phandle_args - structure to hold phandle and arguments + * + * This is used when decoding a phandle in a device tree property. Typically + * these look like this: + * + * wibble { + * phandle = <5>; + * }; + * + * ... + * some-prop = <&wibble 1 2 3> + * + * Here &node is the phandle of the node 'wibble', i.e. 5. There are three + * arguments: 1, 2, 3. + * + * So when decoding the phandle in some-prop, np will point to wibble, + * args_count will be 3 and the three arguments will be in args. + * + * @np: Node that the phandle refers to + * @args_count: Number of arguments + * @args: Argument values + */ +struct of_phandle_args { + struct device_node *np; + int args_count; + uint32_t args[OF_MAX_PHANDLE_ARGS]; +}; + +DECLARE_GLOBAL_DATA_PTR; + +/** + * of_live_active() - check if livetree is active + * + * @returns true if livetree is active, false it not + */ +#ifdef CONFIG_OF_LIVE +static inline bool of_live_active(void) +{ + return gd->of_root != NULL; +} +#else +static inline bool of_live_active(void) +{ + return false; +} +#endif + +#endif

Add a Kconfig option to enable a live device tree, built at run time from the flat tree. Also add structure definitions and a root node.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
dts/Kconfig | 11 ++++ include/asm-generic/global_data.h | 3 ++ include/dm/of.h | 106 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 include/dm/of.h
Applied to u-boot-dm

Add a basic assortment of functions to access the live device tree. These come from Linux v4.9 and are modified for U-Boot to the minimum extent possible. While these functions are now very stable in Linux, it will be possible to merge in fixes if needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/Makefile | 1 + drivers/core/of_access.c | 735 +++++++++++++++++++++++++++++++++++++++++++++++ include/dm/of_access.h | 347 ++++++++++++++++++++++ 3 files changed, 1083 insertions(+) create mode 100644 drivers/core/of_access.c create mode 100644 include/dm/of_access.h
diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 8261f14f45..4211fd1e22 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_$(SPL_)SIMPLE_BUS) += simple-bus.o obj-$(CONFIG_DM) += dump.o obj-$(CONFIG_$(SPL_)REGMAP) += regmap.o obj-$(CONFIG_$(SPL_)SYSCON) += syscon-uclass.o +obj-$(CONFIG_OF_LIVE) += of_access.o diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c new file mode 100644 index 0000000000..94ef3cc251 --- /dev/null +++ b/drivers/core/of_access.c @@ -0,0 +1,735 @@ +/* + * Originally from Linux v4.9 + * Paul Mackerras August 1996. + * Copyright (C) 1996-2005 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. + * {engebret|bergner}@us.ibm.com + * + * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net + * + * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and + * Grant Likely. + * + * Modified for U-Boot + * Copyright (c) 2017 Google, Inc + * + * This file follows drivers/of/base.c with functions in the same order as the + * Linux version. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <libfdt.h> +#include <dm/of_access.h> +#include <linux/ctype.h> +#include <linux/err.h> +#include <linux/ioport.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* list of struct alias_prop aliases */ +LIST_HEAD(aliases_lookup); + +/* "/aliaes" node */ +static struct device_node *of_aliases; + +/* "/chosen" node */ +static struct device_node *of_chosen; + +/* node pointed to by the stdout-path alias */ +static struct device_node *of_stdout; + +/* pointer to options given after the alias (separated by :) or NULL if none */ +static const char *of_stdout_options; + +/** + * struct alias_prop - Alias property in 'aliases' node + * + * The structure represents one alias property of 'aliases' node as + * an entry in aliases_lookup list. + * + * @link: List node to link the structure in aliases_lookup list + * @alias: Alias property name + * @np: Pointer to device_node that the alias stands for + * @id: Index value from end of alias name + * @stem: Alias string without the index + */ +struct alias_prop { + struct list_head link; + const char *alias; + struct device_node *np; + int id; + char stem[0]; +}; + +int of_n_addr_cells(const struct device_node *np) +{ + const __be32 *ip; + + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#address-cells", NULL); + if (ip) + return be32_to_cpup(ip); + } while (np->parent); + + /* No #address-cells property for the root node */ + return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; +} + +int of_n_size_cells(const struct device_node *np) +{ + const __be32 *ip; + + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#size-cells", NULL); + if (ip) + return be32_to_cpup(ip); + } while (np->parent); + + /* No #size-cells property for the root node */ + return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; +} + +struct property *of_find_property(const struct device_node *np, + const char *name, int *lenp) +{ + struct property *pp; + + if (!np) + return NULL; + + for (pp = np->properties; pp; pp = pp->next) { + if (strcmp(pp->name, name) == 0) { + if (lenp) + *lenp = pp->length; + break; + } + } + if (!pp && lenp) + *lenp = -FDT_ERR_NOTFOUND; + + return pp; +} + +struct device_node *of_find_all_nodes(struct device_node *prev) +{ + struct device_node *np; + + if (!prev) { + np = gd->of_root; + } else if (prev->child) { + np = prev->child; + } else { + /* + * Walk back up looking for a sibling, or the end of the + * structure + */ + np = prev; + while (np->parent && !np->sibling) + np = np->parent; + np = np->sibling; /* Might be null at the end of the tree */ + } + + return np; +} + +const void *of_get_property(const struct device_node *np, const char *name, + int *lenp) +{ + struct property *pp = of_find_property(np, name, lenp); + + return pp ? pp->value : NULL; +} + +static const char *of_prop_next_string(struct property *prop, const char *cur) +{ + const void *curv = cur; + + if (!prop) + return NULL; + + if (!cur) + return prop->value; + + curv += strlen(cur) + 1; + if (curv >= prop->value + prop->length) + return NULL; + + return curv; +} + +int of_device_is_compatible(const struct device_node *device, + const char *compat, const char *type, + const char *name) +{ + struct property *prop; + const char *cp; + int index = 0, score = 0; + + /* Compatible match has highest priority */ + if (compat && compat[0]) { + prop = of_find_property(device, "compatible", NULL); + for (cp = of_prop_next_string(prop, NULL); cp; + cp = of_prop_next_string(prop, cp), index++) { + if (of_compat_cmp(cp, compat, strlen(compat)) == 0) { + score = INT_MAX/2 - (index << 2); + break; + } + } + if (!score) + return 0; + } + + /* Matching type is better than matching name */ + if (type && type[0]) { + if (!device->type || of_node_cmp(type, device->type)) + return 0; + score += 2; + } + + /* Matching name is a bit better than not */ + if (name && name[0]) { + if (!device->name || of_node_cmp(name, device->name)) + return 0; + score++; + } + + return score; +} + +bool of_device_is_available(const struct device_node *device) +{ + const char *status; + int statlen; + + if (!device) + return false; + + status = of_get_property(device, "status", &statlen); + if (status == NULL) + return true; + + if (statlen > 0) { + if (!strcmp(status, "okay")) + return true; + } + + return false; +} + +struct device_node *of_get_parent(const struct device_node *node) +{ + const struct device_node *np; + + if (!node) + return NULL; + + np = of_node_get(node->parent); + + return (struct device_node *)np; +} + +static struct device_node *__of_get_next_child(const struct device_node *node, + struct device_node *prev) +{ + struct device_node *next; + + if (!node) + return NULL; + + next = prev ? prev->sibling : node->child; + for (; next; next = next->sibling) + if (of_node_get(next)) + break; + of_node_put(prev); + return next; +} + +#define __for_each_child_of_node(parent, child) \ + for (child = __of_get_next_child(parent, NULL); child != NULL; \ + child = __of_get_next_child(parent, child)) + +static struct device_node *__of_find_node_by_path(struct device_node *parent, + const char *path) +{ + struct device_node *child; + int len; + + len = strcspn(path, "/:"); + if (!len) + return NULL; + + __for_each_child_of_node(parent, child) { + const char *name = strrchr(child->full_name, '/'); + + name++; + if (strncmp(path, name, len) == 0 && (strlen(name) == len)) + return child; + } + return NULL; +} + +#define for_each_property_of_node(dn, pp) \ + for (pp = dn->properties; pp != NULL; pp = pp->next) + +struct device_node *of_find_node_opts_by_path(const char *path, + const char **opts) +{ + struct device_node *np = NULL; + struct property *pp; + const char *separator = strchr(path, ':'); + + if (opts) + *opts = separator ? separator + 1 : NULL; + + if (strcmp(path, "/") == 0) + return of_node_get(gd->of_root); + + /* The path could begin with an alias */ + if (*path != '/') { + int len; + const char *p = separator; + + if (!p) + p = strchrnul(path, '/'); + len = p - path; + + /* of_aliases must not be NULL */ + if (!of_aliases) + return NULL; + + for_each_property_of_node(of_aliases, pp) { + if (strlen(pp->name) == len && !strncmp(pp->name, path, + len)) { + np = of_find_node_by_path(pp->value); + break; + } + } + if (!np) + return NULL; + path = p; + } + + /* Step down the tree matching path components */ + if (!np) + np = of_node_get(gd->of_root); + while (np && *path == '/') { + struct device_node *tmp = np; + + path++; /* Increment past '/' delimiter */ + np = __of_find_node_by_path(np, path); + of_node_put(tmp); + path = strchrnul(path, '/'); + if (separator && separator < path) + break; + } + + return np; +} + +struct device_node *of_find_compatible_node(struct device_node *from, + const char *type, const char *compatible) +{ + struct device_node *np; + + for_each_of_allnodes_from(from, np) + if (of_device_is_compatible(np, compatible, type, NULL) && + of_node_get(np)) + break; + of_node_put(from); + + return np; +} + +struct device_node *of_find_node_by_phandle(phandle handle) +{ + struct device_node *np; + + if (!handle) + return NULL; + + for_each_of_allnodes(np) + if (np->phandle == handle) + break; + (void)of_node_get(np); + + return np; +} + +/** + * of_find_property_value_of_size() - find property of given size + * + * Search for a property in a device node and validate the requested size. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @len: requested length of property value + * + * @return the property value on success, -EINVAL if the property does not + * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + */ +static void *of_find_property_value_of_size(const struct device_node *np, + const char *propname, u32 len) +{ + struct property *prop = of_find_property(np, propname, NULL); + + if (!prop) + return ERR_PTR(-EINVAL); + if (!prop->value) + return ERR_PTR(-ENODATA); + if (len > prop->length) + return ERR_PTR(-EOVERFLOW); + + return prop->value; +} + +int of_read_u32(const struct device_node *np, const char *propname, u32 *outp) +{ + 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; +} + +int of_read_u32_array(const struct device_node *np, const char *propname, + u32 *out_values, size_t sz) +{ + const __be32 *val; + + debug("%s: %s: ", __func__, propname); + val = of_find_property_value_of_size(np, propname, + sz * sizeof(*out_values)); + + if (IS_ERR(val)) + return PTR_ERR(val); + + debug("size %zd\n", sz); + while (sz--) + *out_values++ = be32_to_cpup(val++); + + return 0; +} + +int of_property_match_string(const struct device_node *np, const char *propname, + const char *string) +{ + const struct property *prop = of_find_property(np, propname, NULL); + size_t l; + int i; + const char *p, *end; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + p = prop->value; + end = p + prop->length; + + for (i = 0; p < end; i++, p += l) { + l = strnlen(p, end - p) + 1; + if (p + l > end) + return -EILSEQ; + debug("comparing %s with %s\n", string, p); + if (strcmp(string, p) == 0) + return i; /* Found it; return index */ + } + return -ENODATA; +} + +/** + * of_property_read_string_helper() - Utility helper for parsing string properties + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_strs: output array of string pointers. + * @sz: number of array elements to read. + * @skip: Number of strings to skip over at beginning of list. + * + * Don't call this function directly. It is a utility helper for the + * of_property_read_string*() family of functions. + */ +int of_property_read_string_helper(const struct device_node *np, + const char *propname, const char **out_strs, + size_t sz, int skip) +{ + const struct property *prop = of_find_property(np, propname, NULL); + int l = 0, i = 0; + const char *p, *end; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + p = prop->value; + end = p + prop->length; + + for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) { + l = strnlen(p, end - p) + 1; + if (p + l > end) + return -EILSEQ; + if (out_strs && i >= skip) + *out_strs++ = p; + } + i -= skip; + return i <= 0 ? -ENODATA : i; +} + +static int __of_parse_phandle_with_args(const struct device_node *np, + const char *list_name, + const char *cells_name, + int cell_count, int index, + struct of_phandle_args *out_args) +{ + const __be32 *list, *list_end; + int rc = 0, cur_index = 0; + uint32_t count = 0; + struct device_node *node = NULL; + phandle phandle; + int size; + + /* Retrieve the phandle list property */ + list = of_get_property(np, list_name, &size); + if (!list) + return -ENOENT; + list_end = list + size / sizeof(*list); + + /* Loop over the phandles until all the requested entry is found */ + while (list < list_end) { + rc = -EINVAL; + count = 0; + + /* + * If phandle is 0, then it is an empty entry with no + * arguments. Skip forward to the next entry. + */ + phandle = be32_to_cpup(list++); + if (phandle) { + /* + * Find the provider node and parse the #*-cells + * property to determine the argument length. + * + * This is not needed if the cell count is hard-coded + * (i.e. cells_name not set, but cell_count is set), + * except when we're going to return the found node + * below. + */ + if (cells_name || cur_index == index) { + node = of_find_node_by_phandle(phandle); + if (!node) { + debug("%s: could not find phandle\n", + np->full_name); + goto err; + } + } + + if (cells_name) { + if (of_read_u32(node, cells_name, &count)) { + debug("%s: could not get %s for %s\n", + np->full_name, cells_name, + node->full_name); + goto err; + } + } else { + count = cell_count; + } + + /* + * Make sure that the arguments actually fit in the + * remaining property data length + */ + if (list + count > list_end) { + debug("%s: arguments longer than property\n", + np->full_name); + goto err; + } + } + + /* + * All of the error cases above bail out of the loop, so at + * this point, the parsing is successful. If the requested + * index matches, then fill the out_args structure and return, + * or return -ENOENT for an empty entry. + */ + rc = -ENOENT; + if (cur_index == index) { + if (!phandle) + goto err; + + if (out_args) { + int i; + if (WARN_ON(count > OF_MAX_PHANDLE_ARGS)) + count = OF_MAX_PHANDLE_ARGS; + out_args->np = node; + out_args->args_count = count; + for (i = 0; i < count; i++) + out_args->args[i] = + be32_to_cpup(list++); + } else { + of_node_put(node); + } + + /* Found it! return success */ + return 0; + } + + of_node_put(node); + node = NULL; + list += count; + cur_index++; + } + + /* + * Unlock node before returning result; will be one of: + * -ENOENT : index is for empty phandle + * -EINVAL : parsing error on data + * [1..n] : Number of phandle (count mode; when index = -1) + */ + rc = index < 0 ? cur_index : -ENOENT; + err: + if (node) + of_node_put(node); + return rc; +} + +struct device_node *of_parse_phandle(const struct device_node *np, + const char *phandle_name, int index) +{ + struct of_phandle_args args; + + if (index < 0) + return NULL; + + if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0, index, + &args)) + return NULL; + + return args.np; +} + +int of_parse_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name, + int index, struct of_phandle_args *out_args) +{ + if (index < 0) + return -EINVAL; + + return __of_parse_phandle_with_args(np, list_name, cells_name, 0, + index, out_args); +} + +static void of_alias_add(struct alias_prop *ap, struct device_node *np, + int id, const char *stem, int stem_len) +{ + ap->np = np; + ap->id = id; + strncpy(ap->stem, stem, stem_len); + ap->stem[stem_len] = 0; + list_add_tail(&ap->link, &aliases_lookup); + debug("adding DT alias:%s: stem=%s id=%i node=%s\n", + ap->alias, ap->stem, ap->id, of_node_full_name(np)); +} + +int of_alias_scan(void) +{ + struct property *pp; + + of_aliases = of_find_node_by_path("/aliases"); + of_chosen = of_find_node_by_path("/chosen"); + if (of_chosen == NULL) + of_chosen = of_find_node_by_path("/chosen@0"); + + if (of_chosen) { + const char *name; + + name = of_get_property(of_chosen, "stdout-path", NULL); + if (name) + of_stdout = of_find_node_opts_by_path(name, + &of_stdout_options); + } + + if (!of_aliases) + return 0; + + for_each_property_of_node(of_aliases, pp) { + const char *start = pp->name; + const char *end = start + strlen(start); + struct device_node *np; + struct alias_prop *ap; + ulong id; + int len; + + /* Skip those we do not want to proceed */ + if (!strcmp(pp->name, "name") || + !strcmp(pp->name, "phandle") || + !strcmp(pp->name, "linux,phandle")) + continue; + + np = of_find_node_by_path(pp->value); + if (!np) + continue; + + /* + * walk the alias backwards to extract the id and work out + * the 'stem' string + */ + while (isdigit(*(end-1)) && end > start) + end--; + len = end - start; + + if (strict_strtoul(end, 10, &id) < 0) + continue; + + /* Allocate an alias_prop with enough space for the stem */ + ap = malloc(sizeof(*ap) + len + 1); + if (!ap) + return -ENOMEM; + memset(ap, 0, sizeof(*ap) + len + 1); + ap->alias = start; + of_alias_add(ap, np, id, start, len); + } + + return 0; +} + +int of_alias_get_id(const struct device_node *np, const char *stem) +{ + struct alias_prop *app; + int id = -ENODEV; + + mutex_lock(&of_mutex); + list_for_each_entry(app, &aliases_lookup, link) { + if (strcmp(app->stem, stem) != 0) + continue; + + if (np == app->np) { + id = app->id; + break; + } + } + mutex_unlock(&of_mutex); + + return id; +} + +struct device_node *of_get_stdout(void) +{ + return of_stdout; +} diff --git a/include/dm/of_access.h b/include/dm/of_access.h new file mode 100644 index 0000000000..142f0f43c9 --- /dev/null +++ b/include/dm/of_access.h @@ -0,0 +1,347 @@ +/* + * Originally from Linux v4.9 + * Copyright (C) 1996-2005 Paul Mackerras. + * + * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp. + * Updates for SPARC64 by David S. Miller + * Derived from PowerPC and Sparc prom.h files by Stephen Rothwell, IBM Corp. + * + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * Modified for U-Boot + * Copyright (c) 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DM_OF_ACCESS_H +#define _DM_OF_ACCESS_H + +#include <dm/of.h> + +/** + * of_find_all_nodes - Get next node in global list + * @prev: Previous node or NULL to start iteration + * of_node_put() will be called on it + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_all_nodes(struct device_node *prev); + +#define for_each_of_allnodes_from(from, dn) \ + for (dn = of_find_all_nodes(from); dn; dn = of_find_all_nodes(dn)) +#define for_each_of_allnodes(dn) for_each_of_allnodes_from(NULL, dn) + +/* Dummy functions to mirror Linux. These are not used in U-Boot */ +#define of_node_get(x) (x) +static inline void of_node_put(const struct device_node *np) { } + +/** + * of_n_addr_cells() - Get the number of address cells for a node + * + * This walks back up the tree to find the closest #address-cells property + * which controls the given node. + * + * @np: Node pointer to check + * @return number of address cells this node uses + */ +int of_n_addr_cells(const struct device_node *np); + +/** + * of_n_size_cells() - Get the number of size cells for a node + * + * This walks back up the tree to find the closest #size-cells property + * which controls the given node. + * + * @np: Node pointer to check + * @return number of size cells this node uses + */ +int of_n_size_cells(const struct device_node *np); + +/** + * of_find_property() - find a property in a node + * + * @np: Pointer to device node holding property + * @name: Name of property + * @lenp: If non-NULL, returns length of property + * @return pointer to property, or NULL if not found + */ +struct property *of_find_property(const struct device_node *np, + const char *name, int *lenp); + +/** + * of_get_property() - get a property value + * + * Find a property with a given name for a given node and return the value. + * + * @np: Pointer to device node holding property + * @name: Name of property + * @lenp: If non-NULL, returns length of property + * @return pointer to property value, or NULL if not found + */ +const void *of_get_property(const struct device_node *np, const char *name, + int *lenp); + +/** + * of_device_is_compatible() - Check if the node matches given constraints + * @device: pointer to node + * @compat: required compatible string, NULL or "" for any match + * @type: required device_type value, NULL or "" for any match + * @name: required node name, NULL or "" for any match + * + * Checks if the given @compat, @type and @name strings match the + * properties of the given @device. A constraints can be skipped by + * passing NULL or an empty string as the constraint. + * + * @return 0 for no match, and a positive integer on match. The return + * value is a relative score with larger values indicating better + * matches. The score is weighted for the most specific compatible value + * to get the highest score. Matching type is next, followed by matching + * name. Practically speaking, this results in the following priority + * order for matches: + * + * 1. specific compatible && type && name + * 2. specific compatible && type + * 3. specific compatible && name + * 4. specific compatible + * 5. general compatible && type && name + * 6. general compatible && type + * 7. general compatible && name + * 8. general compatible + * 9. type && name + * 10. type + * 11. name + */ +int of_device_is_compatible(const struct device_node *np, const char *compat, + const char *type, const char *name); + +/** + * of_device_is_available() - check if a device is available for use + * + * @device: Node to check for availability + * + * @return true if the status property is absent or set to "okay", false + * otherwise + */ +bool of_device_is_available(const struct device_node *np); + +/** + * of_get_parent() - Get a node's parent, if any + * + * @node: Node to check + * @eturns a node pointer, or NULL if none + */ +struct device_node *of_get_parent(const struct device_node *np); + +/** + * of_find_node_opts_by_path() - Find a node matching a full OF path + * + * @path: Either the full path to match, or if the path does not start with + * '/', the name of a property of the /aliases node (an alias). In the + * case of an alias, the node matching the alias' value will be returned. + * @opts: Address of a pointer into which to store the start of an options + * string appended to the end of the path with a ':' separator. Can be NULL + * + * Valid paths: + * /foo/bar Full path + * foo Valid alias + * foo/bar Valid alias + relative path + * + * @return a node pointer or NULL if not found + */ +struct device_node *of_find_node_opts_by_path(const char *path, + const char **opts); + +static inline struct device_node *of_find_node_by_path(const char *path) +{ + return of_find_node_opts_by_path(path, NULL); +} + +/** + * of_find_compatible_node() - find a node based on its compatible string + * + * Find a node based on type and one of the tokens in its "compatible" property + * @from: Node to start searching from or NULL. the node you pass will not be + * searched, only the next one will; typically, you pass what the previous + * call returned. + * @type: The type string to match "device_type" or NULL to ignore + * @compatible: The string to match to one of the tokens in the device + * "compatible" list. + * @return node pointer or NULL if not found + */ +struct device_node *of_find_compatible_node(struct device_node *from, + const char *type, const char *compatible); + +/** + * of_find_node_by_phandle() - Find a node given a phandle + * + * @handle: phandle of the node to find + * + * @return node pointer, or NULL if not found + */ +struct device_node *of_find_node_by_phandle(phandle handle); + +/** + * of_read_u32() - Find and read a 32-bit integer from a 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. + * @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(const struct device_node *np, const char *propname, u32 *outp); + +/** + * of_read_u32_array() - Find and read an array of 32 bit integers + * + * Search for a property in a device node and read 32-bit value(s) from + * it. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_values: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * @return 0 on success, -EINVAL if the property does not exist, -ENODATA + * if property does not have a value, and -EOVERFLOW is longer than sz. + */ +int of_read_u32_array(const struct device_node *np, const char *propname, + u32 *out_values, size_t sz); + +/** + * of_property_match_string() - Find string in a list and return index + * + * This function searches a string list property and returns the index + * of a specific string value. + * + * @np: pointer to node containing string list property + * @propname: string list property name + * @string: pointer to string to search for in string list + * @return 0 on success, -EINVAL if the property does not exist, -ENODATA + * if property does not have a value, and -EOVERFLOW is longer than sz. + */ +int of_property_match_string(const struct device_node *np, const char *propname, + const char *string); + +int of_property_read_string_helper(const struct device_node *np, + const char *propname, const char **out_strs, + size_t sz, int index); + +/** + * of_property_read_string_index() - Find and read a string from a multiple + * strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @index: index of the string in the list of strings + * @out_string: pointer to null terminated return string, modified only if + * return value is 0. + * + * Search for a property in a device tree node and retrieve a null + * terminated string value (pointer to data, not a copy) in the list of strings + * contained in that property. + * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if + * property does not have a value, and -EILSEQ if the string is not + * null-terminated within the length of the property data. + * + * The out_string pointer is modified only if a valid string can be decoded. + */ +static inline int of_property_read_string_index(const struct device_node *np, + const char *propname, + int index, const char **output) +{ + int rc = of_property_read_string_helper(np, propname, output, 1, index); + return rc < 0 ? rc : 0; +} + +/** + * of_parse_phandle - Resolve a phandle property to a device_node pointer + * @np: Pointer to device node holding phandle property + * @phandle_name: Name of property holding a phandle value + * @index: For properties holding a table of phandles, this is the index into + * the table + * + * Returns the device_node pointer with refcount incremented. Use + * of_node_put() on it when done. + */ +struct device_node *of_parse_phandle(const struct device_node *np, + const char *phandle_name, int index); + +/** + * of_parse_phandle_with_args() - Find a node pointed by phandle in a list + * + * @np: pointer to a device tree node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * @index: index of a phandle to parse out + * @out_args: optional pointer to output arguments structure (will be filled) + * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if + * @list_name does not exist, -EINVAL if a phandle was not found, + * @cells_name could not be found, the arguments were truncated or there + * were too many arguments. + * + * This function is useful to parse lists of phandles and their arguments. + * Returns 0 on success and fills out_args, on error returns appropriate + * errno value. + * + * Caller is responsible to call of_node_put() on the returned out_args->np + * pointer. + * + * Example: + * + * phandle1: node1 { + * #list-cells = <2>; + * } + * + * phandle2: node2 { + * #list-cells = <1>; + * } + * + * node3 { + * list = <&phandle1 1 2 &phandle2 3>; + * } + * + * To get a device_node of the `node2' node you may call this: + * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); + */ +int of_parse_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name, + int index, struct of_phandle_args *out_args); + +/** + * of_alias_scan() - Scan all properties of the 'aliases' node + * + * The function scans all the properties of the 'aliases' node and populates + * the lookup table with the properties. It returns the number of alias + * properties found, or an error code in case of failure. + * + * @return 9 if OK, -ENOMEM if not enough memory + */ +int of_alias_scan(void); + +/** + * of_alias_get_id - Get alias id for the given device_node + * + * Travels the lookup table to get the alias id for the given device_node and + * alias stem. + * + * @np: Pointer to the given device_node + * @stem: Alias stem of the given device_node + * @return alias ID, if found, else -ENODEV + */ +int of_alias_get_id(const struct device_node *np, const char *stem); + +/** + * of_get_stdout() - Get node to use for stdout + * + * @return node referred to by stdout-path alias, or NULL if none + */ +struct device_node *of_get_stdout(void); + +#endif

Add a basic assortment of functions to access the live device tree. These come from Linux v4.9 and are modified for U-Boot to the minimum extent possible. While these functions are now very stable in Linux, it will be possible to merge in fixes if needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/Makefile | 1 + drivers/core/of_access.c | 735 +++++++++++++++++++++++++++++++++++++++++++++++ include/dm/of_access.h | 347 ++++++++++++++++++++++ 3 files changed, 1083 insertions(+) create mode 100644 drivers/core/of_access.c create mode 100644 include/dm/of_access.h
Applied to u-boot-dm

This function converts the flat device tree into a hierarchical one with C structures and pointers. This is easier to access.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/of_live.h | 24 ++++ lib/Makefile | 1 + lib/of_live.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 include/of_live.h create mode 100644 lib/of_live.c
diff --git a/include/of_live.h b/include/of_live.h new file mode 100644 index 0000000000..f5303bb018 --- /dev/null +++ b/include/of_live.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Support for a 'live' (as opposed to flat) device tree + */ + +#ifndef _OF_LIVE_H +#define _OF_LIVE_H + +struct device_node; + +/** + * of_live_build() - build a live (hierarchical) tree from a flat DT + * + * @fdt_blob: Input tree to convert + * @rootp: Returns live tree that was created + * @return 0 if OK, -ve on error + */ +int of_live_build(const void *fdt_blob, struct device_node **rootp); + +#endif diff --git a/lib/Makefile b/lib/Makefile index 23e9f1ef11..bc2fb0a361 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_ZLIB) += zlib/ obj-$(CONFIG_BZIP2) += bzip2/ obj-$(CONFIG_TIZEN) += tizen/ obj-$(CONFIG_FIT) += libfdt/ +obj-$(CONFIG_OF_LIVE) += of_live.o obj-$(CONFIG_CMD_DHRYSTONE) += dhry/
obj-$(CONFIG_AES) += aes.o diff --git a/lib/of_live.c b/lib/of_live.c new file mode 100644 index 0000000000..51927f9e91 --- /dev/null +++ b/lib/of_live.c @@ -0,0 +1,333 @@ +/* + * Copyright 2009 Benjamin Herrenschmidt, IBM Corp + * benh@kernel.crashing.org + * + * Based on parts of drivers/of/fdt.c from Linux v4.9 + * Modifications for U-Boot + * Copyright (c) 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <libfdt.h> +#include <of_live.h> +#include <malloc.h> +#include <dm/of_access.h> +#include <linux/err.h> + +DECLARE_GLOBAL_DATA_PTR; + +static void *unflatten_dt_alloc(void **mem, unsigned long size, + unsigned long align) +{ + void *res; + + *mem = PTR_ALIGN(*mem, align); + res = *mem; + *mem += size; + + return res; +} + +/** + * unflatten_dt_node() - Alloc and populate a device_node from the flat tree + * @blob: The parent device tree blob + * @mem: Memory chunk to use for allocating device nodes and properties + * @poffset: pointer to node in flat tree + * @dad: Parent struct device_node + * @nodepp: The device_node tree created by the call + * @fpsize: Size of the node path up at t05he current depth. + * @dryrun: If true, do not allocate device nodes but still calculate needed + * memory size + */ +static void *unflatten_dt_node(const void *blob, void *mem, int *poffset, + struct device_node *dad, + struct device_node **nodepp, + unsigned long fpsize, bool dryrun) +{ + const __be32 *p; + struct device_node *np; + struct property *pp, **prev_pp = NULL; + const char *pathp; + int l; + unsigned int allocl; + static int depth; + int old_depth; + int offset; + int has_name = 0; + int new_format = 0; + + pathp = fdt_get_name(blob, *poffset, &l); + if (!pathp) + return mem; + + allocl = ++l; + + /* + * version 0x10 has a more compact unit name here instead of the full + * path. we accumulate the full path size using "fpsize", we'll rebuild + * it later. We detect this because the first character of the name is + * not '/'. + */ + if ((*pathp) != '/') { + new_format = 1; + if (fpsize == 0) { + /* + * root node: special case. fpsize accounts for path + * plus terminating zero. root node only has '/', so + * fpsize should be 2, but we want to avoid the first + * level nodes to have two '/' so we use fpsize 1 here + */ + fpsize = 1; + allocl = 2; + l = 1; + pathp = ""; + } else { + /* + * account for '/' and path size minus terminal 0 + * already in 'l' + */ + fpsize += l; + allocl = fpsize; + } + } + + np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, + __alignof__(struct device_node)); + if (!dryrun) { + char *fn; + + fn = (char *)np + sizeof(*np); + np->full_name = fn; + if (new_format) { + /* rebuild full path for new format */ + if (dad && dad->parent) { + strcpy(fn, dad->full_name); +#ifdef DEBUG + if ((strlen(fn) + l + 1) != allocl) { + debug("%s: p: %d, l: %d, a: %d\n", + pathp, (int)strlen(fn), l, + allocl); + } +#endif + fn += strlen(fn); + } + *(fn++) = '/'; + } + memcpy(fn, pathp, l); + + prev_pp = &np->properties; + if (dad != NULL) { + np->parent = dad; + np->sibling = dad->child; + dad->child = np; + } + } + /* process properties */ + for (offset = fdt_first_property_offset(blob, *poffset); + (offset >= 0); + (offset = fdt_next_property_offset(blob, offset))) { + const char *pname; + int sz; + + p = fdt_getprop_by_offset(blob, offset, &pname, &sz); + if (!p) { + offset = -FDT_ERR_INTERNAL; + break; + } + + if (pname == NULL) { + debug("Can't find property name in list !\n"); + break; + } + if (strcmp(pname, "name") == 0) + has_name = 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property), + __alignof__(struct property)); + if (!dryrun) { + /* + * We accept flattened tree phandles either in + * ePAPR-style "phandle" properties, or the + * legacy "linux,phandle" properties. If both + * appear and have different values, things + * will get weird. Don't do that. */ + if ((strcmp(pname, "phandle") == 0) || + (strcmp(pname, "linux,phandle") == 0)) { + if (np->phandle == 0) + np->phandle = be32_to_cpup(p); + } + /* + * And we process the "ibm,phandle" property + * used in pSeries dynamic device tree + * stuff */ + if (strcmp(pname, "ibm,phandle") == 0) + np->phandle = be32_to_cpup(p); + pp->name = (char *)pname; + pp->length = sz; + pp->value = (__be32 *)p; + *prev_pp = pp; + prev_pp = &pp->next; + } + } + /* + * with version 0x10 we may not have the name property, recreate + * it here from the unit name if absent + */ + if (!has_name) { + const char *p1 = pathp, *ps = pathp, *pa = NULL; + int sz; + + while (*p1) { + if ((*p1) == '@') + pa = p1; + if ((*p1) == '/') + ps = p1 + 1; + p1++; + } + if (pa < ps) + pa = p1; + sz = (pa - ps) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, + __alignof__(struct property)); + if (!dryrun) { + pp->name = "name"; + pp->length = sz; + pp->value = pp + 1; + *prev_pp = pp; + prev_pp = &pp->next; + memcpy(pp->value, ps, sz - 1); + ((char *)pp->value)[sz - 1] = 0; + debug("fixed up name for %s -> %s\n", pathp, + (char *)pp->value); + } + } + if (!dryrun) { + *prev_pp = NULL; + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + + if (!np->name) + np->name = "<NULL>"; + if (!np->type) + np->type = "<NULL>"; } + + old_depth = depth; + *poffset = fdt_next_node(blob, *poffset, &depth); + if (depth < 0) + depth = 0; + while (*poffset > 0 && depth > old_depth) + mem = unflatten_dt_node(blob, mem, poffset, np, NULL, + fpsize, dryrun); + + if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) { + debug("unflatten: error %d processing FDT\n", *poffset); + return NULL; + } + + /* + * Reverse the child list. Some drivers assumes node order matches .dts + * node order + */ + if (!dryrun && np->child) { + struct device_node *child = np->child; + np->child = NULL; + while (child) { + struct device_node *next = child->sibling; + + child->sibling = np->child; + np->child = child; + child = next; + } + } + + if (nodepp) + *nodepp = np; + + return mem; +} + +/** + * unflatten_device_tree() - create tree of device_nodes from flat blob + * + * unflattens a device-tree, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. + * @blob: The blob to expand + * @mynodes: The device_node tree created by the call + * @return 0 if OK, -ve on error + */ +static int unflatten_device_tree(const void *blob, + struct device_node **mynodes) +{ + unsigned long size; + int start; + void *mem; + + debug(" -> unflatten_device_tree()\n"); + + if (!blob) { + debug("No device tree pointer\n"); + return -EINVAL; + } + + debug("Unflattening device tree:\n"); + debug("magic: %08x\n", fdt_magic(blob)); + debug("size: %08x\n", fdt_totalsize(blob)); + debug("version: %08x\n", fdt_version(blob)); + + if (fdt_check_header(blob)) { + debug("Invalid device tree blob header\n"); + return -EINVAL; + } + + /* First pass, scan for size */ + start = 0; + size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, + 0, true); + size = ALIGN(size, 4); + + debug(" size is %lx, allocating...\n", size); + + /* Allocate memory for the expanded device tree */ + mem = malloc(size + 4); + memset(mem, '\0', size); + + *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef); + + debug(" unflattening %p...\n", mem); + + /* Second pass, do actual unflattening */ + start = 0; + unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false); + if (be32_to_cpup(mem + size) != 0xdeadbeef) { + debug("End of tree marker overwritten: %08x\n", + be32_to_cpup(mem + size)); + return -ENOSPC; + } + + debug(" <- unflatten_device_tree()\n"); + + return 0; +} + +int of_live_build(const void *fdt_blob, struct device_node **rootp) +{ + int ret; + + debug("%s: start\n", __func__); + ret = unflatten_device_tree(fdt_blob, rootp); + if (ret) { + debug("Failed to create live tree: err=%d\n", ret); + return ret; + } + ret = of_alias_scan(); + if (ret) { + debug("Failed to scan live tree aliases: err=%d\n", ret); + return ret; + } + debug("%s: stop\n", __func__); + + return ret; +}

This function converts the flat device tree into a hierarchical one with C structures and pointers. This is easier to access.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/of_live.h | 24 ++++ lib/Makefile | 1 + lib/of_live.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 include/of_live.h create mode 100644 lib/of_live.c
Applied to u-boot-dm

If enabled, build a live device tree after relocation. This can then be used by driver model.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
common/board_r.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/common/board_r.c b/common/board_r.c index 28f32c3885..a9c6a84ce4 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -42,6 +42,7 @@ #endif #include <mmc.h> #include <nand.h> +#include <of_live.h> #include <onenand_uboot.h> #include <scsi.h> #include <serial.h> @@ -294,6 +295,14 @@ static int initr_noncached(void) } #endif
+#ifdef CONFIG_OF_LIVE +static int initr_of_live(void) +{ + return of_live_build(gd->fdt_blob, + (struct device_node **)&gd->of_root); +} +#endif + #ifdef CONFIG_DM static int initr_dm(void) { @@ -724,6 +733,9 @@ static init_fnc_t init_sequence_r[] = { initr_noncached, #endif bootstage_relocate, +#ifdef CONFIG_OF_LIVE + initr_of_live, +#endif #ifdef CONFIG_DM initr_dm, #endif

If enabled, build a live device tree after relocation. This can then be used by driver model.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
common/board_r.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
Applied to u-boot-dm

The of_ prefix conflicts with the livetree version of this function. Rename it to avoid problems when we add livetree support.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/device.c | 2 +- drivers/firmware/psci.c | 4 ++-- drivers/mmc/xenon_sdhci.c | 2 +- drivers/net/cpsw-common.c | 4 ++-- drivers/net/mvneta.c | 2 +- drivers/phy/marvell/comphy_core.c | 4 ++-- drivers/usb/host/ehci-marvell.c | 2 +- drivers/usb/host/xhci-rockchip.c | 2 +- include/dm/device.h | 4 ++-- 9 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 363c1833e9..f5e85413f7 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -701,7 +701,7 @@ int device_set_name(struct udevice *dev, const char *name) return 0; }
-bool of_device_is_compatible(struct udevice *dev, const char *compat) +bool device_is_compatible(struct udevice *dev, const char *compat) { const void *fdt = gd->fdt_blob;
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 7652cc27aa..451fbdebba 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -40,8 +40,8 @@ static unsigned long __invoke_psci_fn_smc(unsigned long function_id, static int psci_bind(struct udevice *dev) { /* No SYSTEM_RESET support for PSCI 0.1 */ - if (of_device_is_compatible(dev, "arm,psci-0.2") || - of_device_is_compatible(dev, "arm,psci-1.0")) { + if (device_is_compatible(dev, "arm,psci-0.2") || + device_is_compatible(dev, "arm,psci-1.0")) { int ret;
/* bind psci-sysreset optionally */ diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c index 6cd176f9f8..2b7cb7f6b6 100644 --- a/drivers/mmc/xenon_sdhci.c +++ b/drivers/mmc/xenon_sdhci.c @@ -454,7 +454,7 @@ static int xenon_sdhci_ofdata_to_platdata(struct udevice *dev) host->name = dev->name; host->ioaddr = (void *)devfdt_get_addr(dev);
- if (of_device_is_compatible(dev, "marvell,armada-3700-sdhci")) + if (device_is_compatible(dev, "marvell,armada-3700-sdhci")) priv->pad_ctrl_reg = (void *)devfdt_get_addr_index(dev, 1);
name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "marvell,pad-type", diff --git a/drivers/net/cpsw-common.c b/drivers/net/cpsw-common.c index 55f56d9555..8970ee00af 100644 --- a/drivers/net/cpsw-common.c +++ b/drivers/net/cpsw-common.c @@ -104,10 +104,10 @@ int ti_cm_get_macid(struct udevice *dev, int slave, u8 *mac_addr) if (of_machine_is_compatible("ti,am33xx")) return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr);
- if (of_device_is_compatible(dev, "ti,am3517-emac")) + if (device_is_compatible(dev, "ti,am3517-emac")) return davinci_emac_3517_get_macid(dev, 0x110, slave, mac_addr);
- if (of_device_is_compatible(dev, "ti,dm816-emac")) + if (device_is_compatible(dev, "ti,dm816-emac")) return cpsw_am33xx_cm_get_macid(dev, 0x30, slave, mac_addr);
if (of_machine_is_compatible("ti,am43")) diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index af07b281e8..50577d7f07 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -1695,7 +1695,7 @@ static int mvneta_probe(struct udevice *dev) pp->base = (void __iomem *)pdata->iobase;
/* Configure MBUS address windows */ - if (of_device_is_compatible(dev, "marvell,armada-3700-neta")) + if (device_is_compatible(dev, "marvell,armada-3700-neta")) mvneta_bypass_mbus_windows(pp); else mvneta_conf_mbus_windows(pp); diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c index ccf024b792..426db30f73 100644 --- a/drivers/phy/marvell/comphy_core.c +++ b/drivers/phy/marvell/comphy_core.c @@ -135,10 +135,10 @@ static int comphy_probe(struct udevice *dev) return -EINVAL; }
- if (of_device_is_compatible(dev, "marvell,comphy-armada-3700")) + if (device_is_compatible(dev, "marvell,comphy-armada-3700")) chip_cfg->ptr_comphy_chip_init = comphy_a3700_init;
- if (of_device_is_compatible(dev, "marvell,comphy-cp110")) + if (device_is_compatible(dev, "marvell,comphy-cp110")) chip_cfg->ptr_comphy_chip_init = comphy_cp110_init;
/* diff --git a/drivers/usb/host/ehci-marvell.c b/drivers/usb/host/ehci-marvell.c index 56409df26e..7a0f2083ad 100644 --- a/drivers/usb/host/ehci-marvell.c +++ b/drivers/usb/host/ehci-marvell.c @@ -121,7 +121,7 @@ static int ehci_mvebu_probe(struct udevice *dev) * Also, the address decoder doesn't need to get setup with this * SoC, so don't call usb_brg_adrdec_setup(). */ - if (of_device_is_compatible(dev, "marvell,armada3700-ehci")) + if (device_is_compatible(dev, "marvell,armada3700-ehci")) marvell_ehci_ops.powerup_fixup = marvell_ehci_powerup_fixup; else usb_brg_adrdec_setup((void *)priv->hcd_base); diff --git a/drivers/usb/host/xhci-rockchip.c b/drivers/usb/host/xhci-rockchip.c index 5e7130f0e1..38e1c68db7 100644 --- a/drivers/usb/host/xhci-rockchip.c +++ b/drivers/usb/host/xhci-rockchip.c @@ -55,7 +55,7 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) /* Get the base address for usbphy from the device node */ for (device_find_first_child(dev, &child); child; device_find_next_child(&child)) { - if (!of_device_is_compatible(child, "rockchip,rk3399-usb3-phy")) + if (!device_is_compatible(child, "rockchip,rk3399-usb3-phy")) continue; plat->phy_base = devfdt_get_addr(child); break; diff --git a/include/dm/device.h b/include/dm/device.h index 489cf33987..4866f7c002 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -563,7 +563,7 @@ int device_set_name(struct udevice *dev, const char *name); void device_set_name_alloced(struct udevice *dev);
/** - * of_device_is_compatible() - check if the device is compatible with the compat + * device_is_compatible() - check if the device is compatible with the compat * * This allows to check whether the device is comaptible with the compat. * @@ -572,7 +572,7 @@ void device_set_name_alloced(struct udevice *dev); * device * @return true if OK, false if the compatible is not found */ -bool of_device_is_compatible(struct udevice *dev, const char *compat); +bool device_is_compatible(struct udevice *dev, const char *compat);
/** * of_machine_is_compatible() - check if the machine is compatible with

The of_ prefix conflicts with the livetree version of this function. Rename it to avoid problems when we add livetree support.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/device.c | 2 +- drivers/firmware/psci.c | 4 ++-- drivers/mmc/xenon_sdhci.c | 2 +- drivers/net/cpsw-common.c | 4 ++-- drivers/net/mvneta.c | 2 +- drivers/phy/marvell/comphy_core.c | 4 ++-- drivers/usb/host/ehci-marvell.c | 2 +- drivers/usb/host/xhci-rockchip.c | 2 +- include/dm/device.h | 4 ++-- 9 files changed, 13 insertions(+), 13 deletions(-)
Applied to u-boot-dm

Since U-Boot supports both a live tree and a flat tree, we need an easy way to access the tree without worrying about which is currently active. To support this, U-Boot has the concept of an ofnode, which can refer either to a live tree node or a flat tree node.
For the live tree, the reference contains a pointer to the node (struct device_node *) or NULL if the node is invalid. For the flat tree, the reference contains the node offset or -1 if the node is invalid.
Add a basic set of operations using ofnodes. These are implemented by using either libfdt functions (in the case of a flat DT reference) or the live-tree of_...() functions.
Note that it is not possible to have both live and flat references active at the same time. As soon as the live tree is available, everything in U-Boot should switch to using that. This avoids confusion and allows us to assume that the type of a reference is simply based on whether we have a live tree yet, or not.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: - Adjust header includes in ofnode.h to make it stand alone
Changes in v2: None
drivers/core/Makefile | 1 + drivers/core/ofnode.c | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/dm/ofnode.h | 467 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 1017 insertions(+), 3 deletions(-) create mode 100644 drivers/core/ofnode.c
diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 4211fd1e22..c25288e464 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_DM) += dump.o obj-$(CONFIG_$(SPL_)REGMAP) += regmap.o obj-$(CONFIG_$(SPL_)SYSCON) += syscon-uclass.o obj-$(CONFIG_OF_LIVE) += of_access.o +obj-$(CONFIG_OF_CONTROL) += ofnode.o diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c new file mode 100644 index 0000000000..e6c9a28bae --- /dev/null +++ b/drivers/core/ofnode.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <fdt_support.h> +#include <libfdt.h> +#include <dm/of_access.h> +#include <dm/ofnode.h> +#include <linux/err.h> + +int ofnode_read_u32(ofnode node, const char *propname, u32 *outp) +{ + 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 int *cell; + int len; + + 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]); + } + debug("%#x (%d)\n", *outp, *outp); + + return 0; +} + +int ofnode_read_u32_default(ofnode node, const char *propname, u32 def) +{ + assert(ofnode_valid(node)); + ofnode_read_u32(node, propname, &def); + + return def; +} + +int ofnode_read_s32_default(ofnode node, const char *propname, s32 def) +{ + assert(ofnode_valid(node)); + ofnode_read_u32(node, propname, (u32 *)&def); + + return def; +} + +bool ofnode_read_bool(ofnode node, const char *propname) +{ + bool val; + + assert(ofnode_valid(node)); + debug("%s: %s: ", __func__, propname); + + if (ofnode_is_np(node)) { + val = !!of_find_property(ofnode_to_np(node), propname, NULL); + } else { + val = !!fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), + propname, NULL); + } + debug("%s\n", val ? "true" : "false"); + + return val; +} + +const char *ofnode_read_string(ofnode node, const char *propname) +{ + const char *str = NULL; + int len = -1; + + assert(ofnode_valid(node)); + debug("%s: %s: ", __func__, propname); + + if (ofnode_is_np(node)) { + struct property *prop = of_find_property( + ofnode_to_np(node), propname, NULL); + + if (prop) { + str = prop->value; + len = prop->length; + } + } else { + str = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), + propname, &len); + } + if (!str) { + debug("<not found>\n"); + return NULL; + } + if (strnlen(str, len) >= len) { + debug("<invalid>\n"); + return NULL; + } + debug("%s\n", str); + + return str; +} + +ofnode ofnode_find_subnode(ofnode node, const char *subnode_name) +{ + ofnode subnode; + + assert(ofnode_valid(node)); + debug("%s: %s: ", __func__, subnode_name); + + if (ofnode_is_np(node)) { + const struct device_node *np = ofnode_to_np(node); + + for (np = np->child; np; np = np->sibling) { + if (!strcmp(subnode_name, np->name)) + break; + } + subnode = np_to_ofnode(np); + } else { + int ooffset = fdt_subnode_offset(gd->fdt_blob, + ofnode_to_offset(node), subnode_name); + subnode = offset_to_ofnode(ooffset); + } + debug("%s\n", ofnode_valid(subnode) ? + ofnode_get_name(subnode) : "<none>"); + + return subnode; +} + +int ofnode_read_u32_array(ofnode node, const char *propname, + u32 *out_values, size_t sz) +{ + assert(ofnode_valid(node)); + debug("%s: %s: ", __func__, propname); + + if (ofnode_is_np(node)) { + return of_read_u32_array(ofnode_to_np(node), propname, + out_values, sz); + } else { + return fdtdec_get_int_array(gd->fdt_blob, + ofnode_to_offset(node), propname, + out_values, sz); + } +} + +ofnode ofnode_first_subnode(ofnode node) +{ + assert(ofnode_valid(node)); + if (ofnode_is_np(node)) + return np_to_ofnode(node.np->child); + + return offset_to_ofnode( + fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node))); +} + +ofnode ofnode_next_subnode(ofnode node) +{ + assert(ofnode_valid(node)); + if (ofnode_is_np(node)) + return np_to_ofnode(node.np->sibling); + + return offset_to_ofnode( + fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node))); +} + +const char *ofnode_get_name(ofnode node) +{ + assert(ofnode_valid(node)); + if (ofnode_is_np(node)) + return strrchr(node.np->full_name, '/') + 1; + + return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL); +} + +int ofnode_read_size(ofnode node, const char *propname) +{ + int len; + + if (ofnode_is_np(node)) { + struct property *prop = of_find_property( + ofnode_to_np(node), propname, NULL); + + if (prop) + return prop->length; + } else { + if (fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname, + &len)) + return len; + } + + return -EINVAL; +} + +int ofnode_stringlist_search(ofnode node, const char *property, + const char *string) +{ + if (ofnode_is_np(node)) { + return of_property_match_string(ofnode_to_np(node), + property, string); + } else { + int ret; + + ret = fdt_stringlist_search(gd->fdt_blob, + ofnode_to_offset(node), property, + string); + if (ret == -FDT_ERR_NOTFOUND) + return -ENODATA; + else if (ret < 0) + return -EINVAL; + + return ret; + } +} + +int ofnode_read_string_index(ofnode node, const char *property, int index, + const char **outp) +{ + if (ofnode_is_np(node)) { + return of_property_read_string_index(ofnode_to_np(node), + property, index, outp); + } else { + int len; + + *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node), + property, index, &len); + if (len < 0) + return -EINVAL; + return 0; + } +} + +static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in, + struct ofnode_phandle_args *out) +{ + assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS); + out->node = offset_to_ofnode(in->node); + out->args_count = in->args_count; + memcpy(out->args, in->args, sizeof(out->args)); +} + +static void ofnode_from_of_phandle_args(struct of_phandle_args *in, + struct ofnode_phandle_args *out) +{ + assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS); + out->node = np_to_ofnode(in->np); + out->args_count = in->args_count; + memcpy(out->args, in->args, sizeof(out->args)); +} + +int ofnode_parse_phandle_with_args(ofnode node, const char *list_name, + const char *cells_name, int cell_count, + int index, + struct ofnode_phandle_args *out_args) +{ + if (ofnode_is_np(node)) { + struct of_phandle_args args; + int ret; + + ret = of_parse_phandle_with_args(ofnode_to_np(node), + list_name, cells_name, index, &args); + if (ret) + return ret; + ofnode_from_of_phandle_args(&args, out_args); + } else { + struct fdtdec_phandle_args args; + int ret; + + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, + ofnode_to_offset(node), list_name, cells_name, + cell_count, index, &args); + if (ret) + return ret; + ofnode_from_fdtdec_phandle_args(&args, out_args); + } + + return 0; +} + +ofnode ofnode_path(const char *path) +{ + if (of_live_active()) + return np_to_ofnode(of_find_node_by_path(path)); + else + return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path)); +} + +const char *ofnode_get_chosen_prop(const char *name) +{ + ofnode chosen_node; + + chosen_node = ofnode_path("/chosen"); + + return ofnode_read_string(chosen_node, name); +} + +ofnode ofnode_get_chosen_node(const char *name) +{ + const char *prop; + + prop = ofnode_get_chosen_prop(name); + if (!prop) + return ofnode_null(); + + return ofnode_path(prop); +} + +static int decode_timing_property(ofnode node, const char *name, + struct timing_entry *result) +{ + int length, ret = 0; + + length = ofnode_read_size(node, name); + if (length < 0) { + debug("%s: could not find property %s\n", + ofnode_get_name(node), name); + return length; + } + + if (length == sizeof(u32)) { + result->typ = ofnode_read_u32_default(node, name, 0); + result->min = result->typ; + result->max = result->typ; + } else { + ret = ofnode_read_u32_array(node, name, &result->min, 3); + } + + return ret; +} + +int ofnode_decode_display_timing(ofnode parent, int index, + struct display_timing *dt) +{ + int i; + ofnode timings, node; + u32 val = 0; + int ret = 0; + + timings = ofnode_find_subnode(parent, "display-timings"); + if (!ofnode_valid(timings)) + return -EINVAL; + + for (i = 0, node = ofnode_first_subnode(timings); + ofnode_valid(node) && i != index; + node = ofnode_first_subnode(node)) + i++; + + if (!ofnode_valid(node)) + return -EINVAL; + + memset(dt, 0, sizeof(*dt)); + + ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch); + ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch); + ret |= decode_timing_property(node, "hactive", &dt->hactive); + ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len); + ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch); + ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch); + ret |= decode_timing_property(node, "vactive", &dt->vactive); + ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len); + ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock); + + dt->flags = 0; + val = ofnode_read_u32_default(node, "vsync-active", -1); + if (val != -1) { + dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH : + DISPLAY_FLAGS_VSYNC_LOW; + } + val = ofnode_read_u32_default(node, "hsync-active", -1); + if (val != -1) { + dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH : + DISPLAY_FLAGS_HSYNC_LOW; + } + val = ofnode_read_u32_default(node, "de-active", -1); + if (val != -1) { + dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH : + DISPLAY_FLAGS_DE_LOW; + } + val = ofnode_read_u32_default(node, "pixelclk-active", -1); + if (val != -1) { + dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE : + DISPLAY_FLAGS_PIXDATA_NEGEDGE; + } + + if (ofnode_read_bool(node, "interlaced")) + dt->flags |= DISPLAY_FLAGS_INTERLACED; + if (ofnode_read_bool(node, "doublescan")) + dt->flags |= DISPLAY_FLAGS_DOUBLESCAN; + if (ofnode_read_bool(node, "doubleclk")) + dt->flags |= DISPLAY_FLAGS_DOUBLECLK; + + return ret; +} + +const u32 *ofnode_read_prop(ofnode node, const char *propname, int *lenp) +{ + if (ofnode_is_np(node)) { + struct property *prop; + + prop = of_find_property(ofnode_to_np(node), propname, lenp); + if (!prop) + return NULL; + return prop->value; + } else { + return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), + propname, lenp); + } +} + +bool ofnode_is_available(ofnode node) +{ + if (ofnode_is_np(node)) + return of_device_is_available(ofnode_to_np(node)); + else + return fdtdec_get_is_enabled(gd->fdt_blob, + ofnode_to_offset(node)); +} + +fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property, + fdt_size_t *sizep) +{ + if (ofnode_is_np(node)) { + int na, ns; + int psize; + const struct device_node *np = ofnode_to_np(node); + const __be32 *prop = of_get_property(np, "reg", &psize); + + na = of_n_addr_cells(np); + ns = of_n_addr_cells(np); + *sizep = of_read_number(prop + na, ns); + return of_read_number(prop, na); + } else { + return fdtdec_get_addr_size(gd->fdt_blob, + ofnode_to_offset(node), property, + sizep); + } +} + +const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname, + size_t sz) +{ + if (ofnode_is_np(node)) { + const struct device_node *np = ofnode_to_np(node); + int psize; + const __be32 *prop = of_get_property(np, propname, &psize); + + if (!prop || sz != psize) + return NULL; + return (uint8_t *)prop; + + } else { + return fdtdec_locate_byte_array(gd->fdt_blob, + ofnode_to_offset(node), propname, sz); + } +} + +int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, + const char *propname, struct fdt_pci_addr *addr) +{ + const u32 *cell; + int len; + int ret = -ENOENT; + + debug("%s: %s: ", __func__, propname); + + /* + * If we follow the pci bus bindings strictly, we should check + * the value of the node's parent node's #address-cells and + * #size-cells. They need to be 3 and 2 accordingly. However, + * for simplicity we skip the check here. + */ + cell = ofnode_read_prop(node, propname, &len); + if (!cell) + goto fail; + + if ((len % FDT_PCI_REG_SIZE) == 0) { + int num = len / FDT_PCI_REG_SIZE; + int i; + + for (i = 0; i < num; i++) { + debug("pci address #%d: %08lx %08lx %08lx\n", i, + (ulong)fdt32_to_cpu(cell[0]), + (ulong)fdt32_to_cpu(cell[1]), + (ulong)fdt32_to_cpu(cell[2])); + if ((fdt32_to_cpu(*cell) & type) == type) { + addr->phys_hi = fdt32_to_cpu(cell[0]); + addr->phys_mid = fdt32_to_cpu(cell[1]); + addr->phys_lo = fdt32_to_cpu(cell[1]); + break; + } else { + cell += (FDT_PCI_ADDR_CELLS + + FDT_PCI_SIZE_CELLS); + } + } + + if (i == num) { + ret = -ENXIO; + goto fail; + } + + return 0; + } else { + ret = -EINVAL; + } + +fail: + debug("(not found)\n"); + return ret; +} + +int ofnode_read_addr_cells(ofnode node) +{ + if (ofnode_is_np(node)) + return of_n_addr_cells(ofnode_to_np(node)); + else + return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node)); +} + +int ofnode_read_size_cells(ofnode node) +{ + if (ofnode_is_np(node)) + return of_n_size_cells(ofnode_to_np(node)); + else + return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node)); +} + +bool ofnode_pre_reloc(ofnode node) +{ + if (ofnode_read_prop(node, "u-boot,dm-pre-reloc", NULL)) + return true; + +#ifdef CONFIG_TPL_BUILD + if (ofnode_read_prop(node, "u-boot,dm-tpl", NULL)) + return true; +#elif defined(CONFIG_SPL_BUILD) + if (ofnode_read_prop(node, "u-boot,dm-spl", NULL)) + return true; +#else + /* + * In regular builds individual spl and tpl handling both + * count as handled pre-relocation for later second init. + */ + if (ofnode_read_prop(node, "u-boot,dm-spl", NULL) || + ofnode_read_prop(node, "u-boot,dm-tpl", NULL)) + return true; +#endif + + return false; +} diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index ed362e134e..e8b33c158d 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -8,6 +8,13 @@ #ifndef _DM_OFNODE_H #define _DM_OFNODE_H
+/* TODO(sjg@chromium.org): Drop fdtdec.h include */ +#include <fdtdec.h> +#include <dm/of.h> + +/* Enable checks to protect against invalid calls */ +#undef OF_CHECKS + /** * ofnode - reference to a device tree node * @@ -20,7 +27,7 @@ * ofnode and either an offset or a struct device_node *. * * The reference can also hold a null offset, in which case the pointer value - * here is (void *)-1. This corresponds to a struct device_node * value of + * here is NULL. This corresponds to a struct device_node * value of * NULL, or an offset of -1. * * There is no ambiguity as to whether ofnode holds an offset or a node @@ -44,6 +51,29 @@ typedef union ofnode_union { long of_offset; } ofnode;
+struct ofnode_phandle_args { + ofnode node; + int args_count; + uint32_t args[OF_MAX_PHANDLE_ARGS]; +}; + +/** + * _ofnode_to_np() - convert an ofnode to a live DT node pointer + * + * This cannot be called if the reference contains an offset. + * + * @node: Reference containing struct device_node * (possibly invalid) + * @return pointer to device node (can be NULL) + */ +static inline const struct device_node *ofnode_to_np(ofnode node) +{ +#ifdef OF_CHECKS + if (!of_live_active()) + return NULL; +#endif + return node.np; +} + /** * ofnode_to_offset() - convert an ofnode to a flat DT offset * @@ -54,6 +84,10 @@ typedef union ofnode_union { */ static inline int ofnode_to_offset(ofnode node) { +#ifdef OF_CHECKS + if (of_live_active()) + return -1; +#endif return node.of_offset; }
@@ -64,7 +98,10 @@ static inline int ofnode_to_offset(ofnode node) */ static inline bool ofnode_valid(ofnode node) { - return node.of_offset != -1; + if (of_live_active()) + return node.np != NULL; + else + return node.of_offset != -1; }
/** @@ -77,12 +114,55 @@ static inline ofnode offset_to_ofnode(int of_offset) { ofnode node;
- node.of_offset = of_offset; + if (of_live_active()) + node.np = NULL; + else + node.of_offset = of_offset; + + return node; +} + +/** + * np_to_ofnode() - convert a node pointer to an ofnode + * + * @np: Live node pointer (can be NULL) + * @return reference to the associated node pointer + */ +static inline ofnode np_to_ofnode(const struct device_node *np) +{ + ofnode node; + + node.np = np;
return node; }
/** + * ofnode_is_np() - check if a reference is a node pointer + * + * This function associated that if there is a valid live tree then all + * references will use it. This is because using the flat DT when the live tree + * is valid is not permitted. + * + * @node: reference to check (possibly invalid) + * @return true if the reference is a live node pointer, false if it is a DT + * offset + */ +static inline bool ofnode_is_np(ofnode node) +{ +#ifdef OF_CHECKS + /* + * Check our assumption that flat tree offsets are not used when a + * live tree is in use. + */ + assert(!ofnode_valid(node) || + (of_live_active() ? _ofnode_to_np(node) + : _ofnode_to_np(node))); +#endif + return of_live_active() && ofnode_valid(node); +} + +/** * ofnode_equal() - check if two references are equal * * @return true if equal, else false @@ -93,4 +173,385 @@ static inline bool ofnode_equal(ofnode ref1, ofnode ref2) return ref1.of_offset == ref2.of_offset; }
+/** + * ofnode_null() - Obtain a null ofnode + * + * This returns an ofnode which points to no node. It works both with the flat + * tree and livetree. + */ +static inline ofnode ofnode_null(void) +{ + ofnode node; + + if (of_live_active()) + node.np = NULL; + else + node.of_offset = -1; + + return node; +} + +/** + * ofnode_read_u32() - Read a 32-bit integer from a property + * + * @ref: valid node reference to read property from + * @propname: name of the property to read from + * @outp: place to put value (if found) + * @return 0 if OK, -ve on error + */ +int ofnode_read_u32(ofnode node, const char *propname, u32 *outp); + +/** + * ofnode_read_s32() - Read a 32-bit integer from a property + * + * @ref: valid node reference to read property from + * @propname: name of the property to read from + * @outp: place to put value (if found) + * @return 0 if OK, -ve on error + */ +static inline int ofnode_read_s32(ofnode node, const char *propname, + s32 *out_value) +{ + return ofnode_read_u32(node, propname, (u32 *)out_value); +} + +/** + * ofnode_read_u32_default() - Read a 32-bit integer from a property + * + * @ref: valid node reference to read property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * @return property value, or @def if not found + */ +int ofnode_read_u32_default(ofnode ref, const char *propname, u32 def); + +/** + * ofnode_read_s32_default() - Read a 32-bit integer from a property + * + * @ref: valid node reference to read property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * @return property value, or @def if not found + */ +int ofnode_read_s32_default(ofnode node, const char *propname, s32 def); + +/** + * ofnode_read_string() - Read a string from a property + * + * @ref: valid node reference to read property from + * @propname: name of the property to read + * @return string from property value, or NULL if there is no such property + */ +const char *ofnode_read_string(ofnode node, const char *propname); + +/** + * ofnode_read_u32_array - Find and read an array of 32 bit integers + * + * @node: valid node reference to read property from + * @propname: name of the property to read + * @out_values: pointer to return value, modified only if return value is 0 + * @sz: number of array elements to read + * + * Search for a property in a device node and read 32-bit value(s) from + * it. Returns 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. + * + * The out_values is modified only if a valid u32 value can be decoded. + */ +int ofnode_read_u32_array(ofnode node, const char *propname, + u32 *out_values, size_t sz); + +/** + * ofnode_read_bool() - read a boolean value from a property + * + * @node: valid node reference to read property from + * @propname: name of property to read + * @return true if property is present (meaning true), false if not present + */ +bool ofnode_read_bool(ofnode node, const char *propname); + +/** + * ofnode_find_subnode() - find a named subnode of a parent node + * + * @node: valid reference to parent node + * @subnode_name: name of subnode to find + * @return reference to subnode (which can be invalid if there is no such + * subnode) + */ +ofnode ofnode_find_subnode(ofnode node, const char *subnode_name); + +/** + * ofnode_first_subnode() - find the first subnode of a parent node + * + * @node: valid reference to a valid parent node + * @return reference to the first subnode (which can be invalid if the parent + * node has no subnodes) + */ +ofnode ofnode_first_subnode(ofnode node); + +/** + * ofnode_next_subnode() - find the next sibling of a subnode + * + * @node: valid reference to previous node (sibling) + * @return reference to the next subnode (which can be invalid if the node + * has no more siblings) + */ +ofnode ofnode_next_subnode(ofnode node); + +/** + * ofnode_get_name() - get the name of a node + * + * @node: valid node to look up + * @return name or node + */ +const char *ofnode_get_name(ofnode node); + +/** + * ofnode_read_size() - read the size of a property + * + * @node: node to check + * @propname: property to check + * @return size of property if present, or -EINVAL if not + */ +int ofnode_read_size(ofnode node, const char *propname); + +/** + * ofnode_stringlist_search() - find a string in a string list and return index + * + * Note that it is possible for this function to succeed on property values + * that are not NUL-terminated. That's because the function will stop after + * finding the first occurrence of @string. This can for example happen with + * small-valued cell properties, such as #address-cells, when searching for + * the empty string. + * + * @node: node to check + * @propname: name of the property containing the string list + * @string: string to look up in the string list + * + * @return: + * the index of the string in the list of strings + * -ENODATA if the property is not found + * -EINVAL on some other error + */ +int ofnode_stringlist_search(ofnode node, const char *propname, + const char *string); + +/** + * fdt_stringlist_get() - obtain the string at a given index in a string list + * + * Note that this will successfully extract strings from properties with + * non-NUL-terminated values. For example on small-valued cell properties + * this function will return the empty string. + * + * If non-NULL, the length of the string (on success) or a negative error-code + * (on failure) will be stored in the integer pointer to by lenp. + * + * @node: node to check + * @propname: name of the property containing the string list + * @index: index of the string to return + * @lenp: return location for the string length or an error code on failure + * + * @return: + * length of string, if found or -ve error value if not found + */ +int ofnode_read_string_index(ofnode node, const char *propname, int index, + const char **outp); + +/** + * ofnode_parse_phandle_with_args() - Find a node pointed by phandle in a list + * + * This function is useful to parse lists of phandles and their arguments. + * Returns 0 on success and fills out_args, on error returns appropriate + * errno value. + * + * Caller is responsible to call of_node_put() on the returned out_args->np + * pointer. + * + * Example: + * + * phandle1: node1 { + * #list-cells = <2>; + * } + * + * phandle2: node2 { + * #list-cells = <1>; + * } + * + * node3 { + * list = <&phandle1 1 2 &phandle2 3>; + * } + * + * To get a device_node of the `node2' node you may call this: + * ofnode_parse_phandle_with_args(node3, "list", "#list-cells", 0, 1, &args); + * + * @node: device tree node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * @cells_count: Cell count to use if @cells_name is NULL + * @index: index of a phandle to parse out + * @out_args: optional pointer to output arguments structure (will be filled) + * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if + * @list_name does not exist, -EINVAL if a phandle was not found, + * @cells_name could not be found, the arguments were truncated or there + * were too many arguments. + */ +int ofnode_parse_phandle_with_args(ofnode node, const char *list_name, + const char *cells_name, int cell_count, + int index, + struct ofnode_phandle_args *out_args); + +/** + * ofnode_path() - find a node by full path + * + * @path: Full path to node, e.g. "/bus/spi@1" + * @return reference to the node found. Use ofnode_valid() to check if it exists + */ +ofnode ofnode_path(const char *path); + +/** + * ofnode_get_chosen_prop() - get the value of a chosen property + * + * This looks for a property within the /chosen node and returns its value + * + * @propname: Property name to look for + */ +const char *ofnode_get_chosen_prop(const char *propname); + +/** + * ofnode_get_chosen_node() - get the chosen node + * + * @return the chosen node if present, else ofnode_null() + */ +ofnode ofnode_get_chosen_node(const char *name); + +struct display_timing; +/** + * ofnode_decode_display_timing() - decode display timings + * + * Decode display timings from the supplied 'display-timings' node. + * See doc/device-tree-bindings/video/display-timing.txt for binding + * information. + * + * @node 'display-timing' node containing the timing subnodes + * @index Index number to read (0=first timing subnode) + * @config Place to put timings + * @return 0 if OK, -FDT_ERR_NOTFOUND if not found + */ +int ofnode_decode_display_timing(ofnode node, int index, + struct display_timing *config); + +/** + * ofnode_read_prop()- - read a node property + * + * @node: node to read + * @propname: property to read + * @lenp: place to put length on success + * @return pointer to property, or NULL if not found + */ +const u32 *ofnode_read_prop(ofnode node, const char *propname, int *lenp); + +/** + * ofnode_is_available() - check if a node is marked available + * + * @node: node to check + * @return true if node's 'status' property is "okay" (or is missing) + */ +bool ofnode_is_available(ofnode node); + +/** + * ofnode_get_addr_size() - get address and size from a property + * + * This does no address translation. It simply reads an property that contains + * an address and a size value, one after the other. + * + * @node: node to read from + * @propname: property to read + * @sizep: place to put size value (on success) + * @return address value, or FDT_ADDR_T_NONE on error + */ +phys_addr_t ofnode_get_addr_size(ofnode node, const char *propname, + phys_size_t *sizep); + +/** + * ofnode_read_u8_array_ptr() - find an 8-bit array + * + * Look up a property in a node and return a pointer to its contents as a + * byte array of given length. The property must have at least enough data + * for the array (count bytes). It may have more, but this will be ignored. + * The data is not copied. + * + * @node node to examine + * @propname name of property to find + * @sz number of array elements + * @return pointer to byte array if found, or NULL if the property is not + * found or there is not enough data + */ +const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname, + size_t sz); + +/** + * ofnode_read_pci_addr() - look up a PCI address + * + * Look at an address property in a node and return the PCI address which + * corresponds to the given type in the form of fdt_pci_addr. + * The property must hold one fdt_pci_addr with a lengh. + * + * @node node to examine + * @type pci address type (FDT_PCI_SPACE_xxx) + * @propname name of property to find + * @addr returns pci address in the form of fdt_pci_addr + * @return 0 if ok, -ENOENT if the property did not exist, -EINVAL if the + * format of the property was invalid, -ENXIO if the requested + * address type was not found + */ +int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, + const char *propname, struct fdt_pci_addr *addr); + +/** + * ofnode_read_addr_cells() - Get the number of address cells for a node + * + * This walks back up the tree to find the closest #address-cells property + * which controls the given node. + * + * @node: Node to check + * @return number of address cells this node uses + */ +int ofnode_read_addr_cells(ofnode node); + +/** + * ofnode_read_size_cells() - Get the number of size cells for a node + * + * This walks back up the tree to find the closest #size-cells property + * which controls the given node. + * + * @node: Node to check + * @return number of size cells this node uses + */ +int ofnode_read_size_cells(ofnode node); + +/** + * ofnode_pre_reloc() - check if a node should be bound before relocation + * + * Device tree nodes can be marked as needing-to-be-bound in the loader stages + * via special device tree 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 3 settings currently in use + * - + * - 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 + * new platforms. + * + * @node: node to check + * @eturns true if node is needed in SPL/TL, false otherwise + */ +bool ofnode_pre_reloc(ofnode node); + #endif

Since U-Boot supports both a live tree and a flat tree, we need an easy way to access the tree without worrying about which is currently active. To support this, U-Boot has the concept of an ofnode, which can refer either to a live tree node or a flat tree node.
For the live tree, the reference contains a pointer to the node (struct device_node *) or NULL if the node is invalid. For the flat tree, the reference contains the node offset or -1 if the node is invalid.
Add a basic set of operations using ofnodes. These are implemented by using either libfdt functions (in the case of a flat DT reference) or the live-tree of_...() functions.
Note that it is not possible to have both live and flat references active at the same time. As soon as the live tree is available, everything in U-Boot should switch to using that. This avoids confusion and allows us to assume that the type of a reference is simply based on whether we have a live tree yet, or not.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: - Adjust header includes in ofnode.h to make it stand alone
Changes in v2: None
drivers/core/Makefile | 1 + drivers/core/ofnode.c | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/dm/ofnode.h | 467 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 1017 insertions(+), 3 deletions(-) create mode 100644 drivers/core/ofnode.c
Applied to u-boot-dm

Add functions to access addresses in the device tree. These are brought in from Linux 4.10.
Also fix up the header guard for fdtaddr.h to avoid confusion.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: - Fix up the fdtaddr.h header guard to avoid conflicts
Changes in v2: None
drivers/core/Makefile | 2 +- drivers/core/of_addr.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++++ include/dm/fdtaddr.h | 4 +- include/dm/of_addr.h | 64 +++++++++ 4 files changed, 426 insertions(+), 3 deletions(-) create mode 100644 drivers/core/of_addr.c create mode 100644 include/dm/of_addr.h
diff --git a/drivers/core/Makefile b/drivers/core/Makefile index c25288e464..1c6795af13 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -11,5 +11,5 @@ obj-$(CONFIG_$(SPL_)SIMPLE_BUS) += simple-bus.o obj-$(CONFIG_DM) += dump.o obj-$(CONFIG_$(SPL_)REGMAP) += regmap.o obj-$(CONFIG_$(SPL_)SYSCON) += syscon-uclass.o -obj-$(CONFIG_OF_LIVE) += of_access.o +obj-$(CONFIG_OF_LIVE) += of_access.o of_addr.o obj-$(CONFIG_OF_CONTROL) += ofnode.o diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c new file mode 100644 index 0000000000..4757066967 --- /dev/null +++ b/drivers/core/of_addr.c @@ -0,0 +1,359 @@ +/* + * Taken from Linux v4.9 drivers/of/address.c + * + * Modified for U-Boot + * Copyright (c) 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <libfdt.h> +#include <dm/of_access.h> +#include <dm/of_addr.h> +#include <linux/err.h> +#include <linux/ioport.h> + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 +#define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) +#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0) + +static struct of_bus *of_match_bus(struct device_node *np); + +/* Debug utility */ +#ifdef DEBUG +static void of_dump_addr(const char *s, const __be32 *addr, int na) +{ + debug("%s", s); + while (na--) + pr_cont(" %08x", be32_to_cpu(*(addr++))); + pr_cont("\n"); +} +#else +static void of_dump_addr(const char *s, const __be32 *addr, int na) { } +#endif + +/* Callbacks for bus specific translators */ +struct of_bus { + const char *name; + const char *addresses; + int (*match)(struct device_node *parent); + void (*count_cells)(const struct device_node *child, int *addrc, + int *sizec); + u64 (*map)(__be32 *addr, const __be32 *range, int na, int ns, int pna); + int (*translate)(__be32 *addr, u64 offset, int na); + unsigned int (*get_flags)(const __be32 *addr); +}; + +static void of_bus_default_count_cells(const struct device_node *np, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = of_n_addr_cells(np); + if (sizec) + *sizec = of_n_size_cells(np); +} + +static u64 of_bus_default_map(__be32 *addr, const __be32 *range, + int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = of_read_number(range, na); + s = of_read_number(range + na + pna, ns); + da = of_read_number(addr, na); + + debug("default map, cp=%llx, s=%llx, da=%llx\n", + (unsigned long long)cp, (unsigned long long)s, + (unsigned long long)da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_default_translate(__be32 *addr, u64 offset, int na) +{ + u64 a = of_read_number(addr, na); + memset(addr, 0, na * 4); + a += offset; + if (na > 1) + addr[na - 2] = cpu_to_be32(a >> 32); + addr[na - 1] = cpu_to_be32(a & 0xffffffffu); + + return 0; +} + +static unsigned int of_bus_default_get_flags(const __be32 *addr) +{ + return IORESOURCE_MEM; +} + +/* + * Array of bus-specific translators + */ +static struct of_bus of_busses[] = { + /* Default */ + { + .name = "default", + .addresses = "reg", + .match = NULL, + .count_cells = of_bus_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + .get_flags = of_bus_default_get_flags, + }, +}; + +static struct of_bus *of_match_bus(struct device_node *np) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(of_busses); i++) + if (!of_busses[i].match || of_busses[i].match(np)) + return &of_busses[i]; + BUG(); + return NULL; +} + +static void dev_count_cells(const struct device_node *np, int *nap, int *nsp) +{ + of_bus_default_count_cells(np, nap, nsp); +} + +const __be32 *of_get_address(const struct device_node *dev, int index, + u64 *size, unsigned int *flags) +{ + const __be32 *prop; + int psize; + struct device_node *parent; + struct of_bus *bus; + int onesize, i, na, ns; + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + return NULL; + dev_count_cells(dev, &na, &ns); + bus = of_match_bus(parent); + bus->count_cells(dev, &na, &ns); + of_node_put(parent); + if (!OF_CHECK_ADDR_COUNT(na)) + return NULL; + + /* Get "reg" or "assigned-addresses" property */ + prop = of_get_property(dev, "reg", &psize); + if (prop == NULL) + return NULL; + psize /= 4; + + onesize = na + ns; + for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) + if (i == index) { + if (size) + *size = of_read_number(prop + na, ns); + if (flags) + *flags = bus->get_flags(prop); + return prop; + } + return NULL; +} +EXPORT_SYMBOL(of_get_address); + +static int of_empty_ranges_quirk(const struct device_node *np) +{ + return false; +} + +static int of_translate_one(const struct device_node *parent, + struct of_bus *bus, struct of_bus *pbus, + __be32 *addr, int na, int ns, int pna, + const char *rprop) +{ + const __be32 *ranges; + int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + /* + * Normally, an absence of a "ranges" property means we are + * crossing a non-translatable boundary, and thus the addresses + * below the current cannot be converted to CPU physical ones. + * Unfortunately, while this is very clear in the spec, it's not + * what Apple understood, and they do have things like /uni-n or + * /ht nodes with no "ranges" property and a lot of perfectly + * useable mapped devices below them. Thus we treat the absence of + * "ranges" as equivalent to an empty "ranges" property which means + * a 1:1 translation at that level. It's up to the caller not to try + * to translate addresses that aren't supposed to be translated in + * the first place. --BenH. + * + * As far as we know, this damage only exists on Apple machines, so + * This code is only enabled on powerpc. --gcl + */ + ranges = of_get_property(parent, rprop, &rlen); + if (ranges == NULL && !of_empty_ranges_quirk(parent)) { + debug("no ranges; cannot translate\n"); + return 1; + } + if (ranges == NULL || rlen == 0) { + offset = of_read_number(addr, na); + memset(addr, 0, pna * 4); + debug("empty ranges; 1:1 translation\n"); + goto finish; + } + + debug("walking ranges...\n"); + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map(addr, ranges, na, ns, pna); + if (offset != OF_BAD_ADDR) + break; + } + if (offset == OF_BAD_ADDR) { + debug("not found !\n"); + return 1; + } + memcpy(addr, ranges + na, 4 * pna); + + finish: + of_dump_addr("parent translation for:", addr, pna); + debug("with offset: %llx\n", (unsigned long long)offset); + + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +/* + * Translate an address from the device-tree into a CPU physical address, + * this walks up the tree and applies the various bus mappings on the + * way. + * + * Note: We consider that crossing any level with #size-cells == 0 to mean + * that translation is impossible (that is we are not dealing with a value + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + */ +static u64 __of_translate_address(const struct device_node *dev, + const __be32 *in_addr, const char *rprop) +{ + struct device_node *parent = NULL; + struct of_bus *bus, *pbus; + __be32 addr[OF_MAX_ADDR_CELLS]; + int na, ns, pna, pns; + u64 result = OF_BAD_ADDR; + + debug("** translation for device %s **\n", of_node_full_name(dev)); + + /* Increase refcount at current level */ + (void)of_node_get(dev); + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + goto bail; + bus = of_match_bus(parent); + + /* Count address cells & copy address locally */ + bus->count_cells(dev, &na, &ns); + if (!OF_CHECK_COUNTS(na, ns)) { + debug("Bad cell count for %s\n", of_node_full_name(dev)); + goto bail; + } + memcpy(addr, in_addr, na * 4); + + debug("bus is %s (na=%d, ns=%d) on %s\n", bus->name, na, ns, + of_node_full_name(parent)); + of_dump_addr("translating address:", addr, na); + + /* Translate */ + for (;;) { + /* Switch to parent bus */ + of_node_put(dev); + dev = parent; + parent = of_get_parent(dev); + + /* If root, we have finished */ + if (parent == NULL) { + debug("reached root node\n"); + result = of_read_number(addr, na); + break; + } + + /* Get new parent bus and counts */ + pbus = of_match_bus(parent); + pbus->count_cells(dev, &pna, &pns); + if (!OF_CHECK_COUNTS(pna, pns)) { + debug("Bad cell count for %s\n", + of_node_full_name(dev)); + break; + } + + debug("parent bus is %s (na=%d, ns=%d) on %s\n", pbus->name, + pna, pns, of_node_full_name(parent)); + + /* Apply bus translation */ + if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)) + break; + + /* Complete the move up one level */ + na = pna; + ns = pns; + bus = pbus; + + of_dump_addr("one level translation:", addr, na); + } + bail: + of_node_put(parent); + of_node_put(dev); + + return result; +} + +u64 of_translate_address(const struct device_node *dev, const __be32 *in_addr) +{ + return __of_translate_address(dev, in_addr, "ranges"); +} + + +static int __of_address_to_resource(const struct device_node *dev, + const __be32 *addrp, u64 size, unsigned int flags, + const char *name, struct resource *r) +{ + u64 taddr; + + if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) + return -EINVAL; + taddr = of_translate_address(dev, addrp); + if (taddr == OF_BAD_ADDR) + return -EINVAL; + memset(r, 0, sizeof(struct resource)); + r->start = taddr; + r->end = taddr + size - 1; + r->flags = flags; + r->name = name ? name : dev->full_name; + + return 0; +} + +int of_address_to_resource(const struct device_node *dev, int index, + struct resource *r) +{ + const __be32 *addrp; + u64 size; + unsigned int flags; + const char *name = NULL; + + addrp = of_get_address(dev, index, &size, &flags); + if (addrp == NULL) + return -EINVAL; + + /* Get optional "reg-names" property to add a name to a resource */ + of_property_read_string_index(dev, "reg-names", index, &name); + + return __of_address_to_resource(dev, addrp, size, flags, name, r); +} diff --git a/include/dm/fdtaddr.h b/include/dm/fdtaddr.h index ef6e86379f..c46f0e91d0 100644 --- a/include/dm/fdtaddr.h +++ b/include/dm/fdtaddr.h @@ -8,8 +8,8 @@ * SPDX-License-Identifier: GPL-2.0+ */
-#ifndef _DM_ADDR_H -#define _DM_ADDR_H +#ifndef _DM_FDTADDR_H +#define _DM_FDTADDR_H
#include <fdtdec.h>
diff --git a/include/dm/of_addr.h b/include/dm/of_addr.h new file mode 100644 index 0000000000..25ca05b315 --- /dev/null +++ b/include/dm/of_addr.h @@ -0,0 +1,64 @@ +/* + * Taken from Linux v4.9 drivers/of/address.c + * + * Modified for U-Boot + * Copyright (c) 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DM_OF_ADDR_H +#define _DM_OF_ADDR_H + +/** + * of_translate_address() - translate a device-tree address to a CPU address + * + * Translate an address from the device-tree into a CPU physical address, + * this walks up the tree and applies the various bus mappings on the way. + * + * Note: We consider that crossing any level with #size-cells == 0 to mean + * that translation is impossible (that is we are not dealing with a value + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + * + * @np: node to check + * @in_addr: pointer to input address + * @return translated address or OF_BAD_ADDR on error + */ +u64 of_translate_address(const struct device_node *no, const __be32 *in_addr); + +/** + * of_get_address() - obtain an address from a node + * + * Extract an address from a node, returns the region size and the address + * space flags too. The PCI version uses a BAR number instead of an absolute + * index. + * + * @np: Node to check + * @index: Index of address to read (0 = first) + * @size: place to put size on success + * @flags: place to put flags on success + * @return pointer to address which can be read + */ +const __be32 *of_get_address(const struct device_node *no, int index, + u64 *size, unsigned int *flags); + +struct resource; + +/** + * of_address_to_resource() - translate device tree address to resource + * + * Note that if your address is a PIO address, the conversion will fail if + * the physical address can't be internally converted to an IO token with + * pci_address_to_pio(), that is because it's either called to early or it + * can't be matched to any host bridge IO space + * + * @np: node to check + * @index: index of address to read (0 = first) + * @r: place to put resource information + * @return 0 if OK, -ve on error + */ +int of_address_to_resource(const struct device_node *no, int index, + struct resource *r); + +#endif

Add functions to access addresses in the device tree. These are brought in from Linux 4.10.
Also fix up the header guard for fdtaddr.h to avoid confusion.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: - Fix up the fdtaddr.h header guard to avoid conflicts
Changes in v2: None
drivers/core/Makefile | 2 +- drivers/core/of_addr.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++++ include/dm/fdtaddr.h | 4 +- include/dm/of_addr.h | 64 +++++++++ 4 files changed, 426 insertions(+), 3 deletions(-) create mode 100644 drivers/core/of_addr.c create mode 100644 include/dm/of_addr.h
Applied to u-boot-dm

This function does not change the device tree so adjust it to use const for this parameter.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
common/fdt_support.c | 2 +- include/fdt_support.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/common/fdt_support.c b/common/fdt_support.c index c6a76b7ad2..c63b27bbb6 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -1539,7 +1539,7 @@ int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr) /* * Returns the base address of an SOC or PCI node */ -u64 fdt_get_base_address(void *fdt, int node) +u64 fdt_get_base_address(const void *fdt, int node) { int size; u32 naddr; diff --git a/include/fdt_support.h b/include/fdt_support.h index 955c121713..6fea5c7da0 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -207,7 +207,7 @@ int fdt_add_edid(void *blob, const char *compat, unsigned char *buf);
int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr); -u64 fdt_get_base_address(void *fdt, int node); +u64 fdt_get_base_address(const void *fdt, int node); int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr, uint64_t *addr, uint64_t *len);

This function does not change the device tree so adjust it to use const for this parameter.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
common/fdt_support.c | 2 +- include/fdt_support.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Applied to u-boot-dm

Add functions to add addresses in the device tree using ofnode references.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/ofnode.c | 27 +++++++++++++++++++++++++++ include/dm/ofnode.h | 23 ++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index e6c9a28bae..ac312d6546 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -11,6 +11,7 @@ #include <fdt_support.h> #include <libfdt.h> #include <dm/of_access.h> +#include <dm/of_addr.h> #include <dm/ofnode.h> #include <linux/err.h>
@@ -195,6 +196,32 @@ int ofnode_read_size(ofnode node, const char *propname) return -EINVAL; }
+fdt_addr_t ofnode_get_addr_index(ofnode node, int index) +{ + if (ofnode_is_np(node)) { + const __be32 *prop_val; + uint flags; + u64 size; + + prop_val = of_get_address( + (struct device_node *)ofnode_to_np(node), index, + &size, &flags); + if (!prop_val) + return FDT_ADDR_T_NONE; + return be32_to_cpup(prop_val); + } else { + return fdt_get_base_address(gd->fdt_blob, + ofnode_to_offset(node)); + } + + return FDT_ADDR_T_NONE; +} + +fdt_addr_t ofnode_get_addr(ofnode node) +{ + return ofnode_get_addr_index(node, 0); +} + int ofnode_stringlist_search(ofnode node, const char *property, const char *string) { diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index e8b33c158d..149622a0b2 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -245,7 +245,7 @@ int ofnode_read_s32_default(ofnode node, const char *propname, s32 def); const char *ofnode_read_string(ofnode node, const char *propname);
/** - * ofnode_read_u32_array - Find and read an array of 32 bit integers + * ofnode_read_u32_array() - Find and read an array of 32 bit integers * * @node: valid node reference to read property from * @propname: name of the property to read @@ -317,6 +317,27 @@ const char *ofnode_get_name(ofnode node); int ofnode_read_size(ofnode node, const char *propname);
/** + * ofnode_get_addr_index() - get an address from a node + * + * This reads the register address from a node + * + * @node: node to read from + * @index: Index of address to read (0 for first) + * @return address, or FDT_ADDR_T_NONE if not present or invalid + */ +phys_addr_t ofnode_get_addr_index(ofnode node, int index); + +/** + * ofnode_get_addr() - get an address from a node + * + * This reads the register address from a node + * + * @node: node to read from + * @return address, or FDT_ADDR_T_NONE if not present or invalid + */ +phys_addr_t ofnode_get_addr(ofnode node); + +/** * ofnode_stringlist_search() - find a string in a string list and return index * * Note that it is possible for this function to succeed on property values

Add functions to add addresses in the device tree using ofnode references.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/ofnode.c | 27 +++++++++++++++++++++++++++ include/dm/ofnode.h | 23 ++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-)
Applied to u-boot-dm

Some functions deal with structured data rather than simple data types. It makes sense to have these in their own file. For now this just has a function to read a flashmap entry. Move the data types also.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/Makefile | 2 +- drivers/core/of_extra.c | 37 +++++++++++++++++++++++++++++++++++++ include/cros_ec.h | 1 + include/dm/of_extra.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/fdtdec.h | 23 +---------------------- lib/fdtdec.c | 1 + 6 files changed, 87 insertions(+), 23 deletions(-) create mode 100644 drivers/core/of_extra.c create mode 100644 include/dm/of_extra.h
diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 1c6795af13..d74b065a07 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -12,4 +12,4 @@ obj-$(CONFIG_DM) += dump.o obj-$(CONFIG_$(SPL_)REGMAP) += regmap.o obj-$(CONFIG_$(SPL_)SYSCON) += syscon-uclass.o obj-$(CONFIG_OF_LIVE) += of_access.o of_addr.o -obj-$(CONFIG_OF_CONTROL) += ofnode.o +obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c new file mode 100644 index 0000000000..0381909848 --- /dev/null +++ b/drivers/core/of_extra.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <libfdt.h> +#include <dm/of_access.h> +#include <dm/of_extra.h> +#include <dm/ofnode.h> + +int of_read_fmap_entry(ofnode node, const char *name, + struct fmap_entry *entry) +{ + const char *prop; + u32 reg[2]; + + if (ofnode_read_u32_array(node, "reg", reg, 2)) { + debug("Node '%s' has bad/missing 'reg' property\n", name); + return -FDT_ERR_NOTFOUND; + } + entry->offset = reg[0]; + entry->length = reg[1]; + entry->used = ofnode_read_s32_default(node, "used", entry->length); + prop = ofnode_read_string(node, "compress"); + entry->compress_algo = prop && !strcmp(prop, "lzo") ? + FMAP_COMPRESS_LZO : FMAP_COMPRESS_NONE; + prop = ofnode_read_string(node, "hash"); + if (prop) + entry->hash_size = strlen(prop); + entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE; + entry->hash = (uint8_t *)prop; + + return 0; +} diff --git a/include/cros_ec.h b/include/cros_ec.h index 0271f2b827..2bd9f2251f 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -14,6 +14,7 @@ #include <fdtdec.h> #include <cros_ec_message.h> #include <asm/gpio.h> +#include <dm/of_extra.h>
/* Our configuration information */ struct cros_ec_dev { diff --git a/include/dm/of_extra.h b/include/dm/of_extra.h new file mode 100644 index 0000000000..01b6ebedff --- /dev/null +++ b/include/dm/of_extra.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DM_OF_EXTRA_H +#define _DM_OF_EXTRA_H + +#include <dm/ofnode.h> + +enum fmap_compress_t { + FMAP_COMPRESS_NONE, + FMAP_COMPRESS_LZO, +}; + +enum fmap_hash_t { + FMAP_HASH_NONE, + FMAP_HASH_SHA1, + FMAP_HASH_SHA256, +}; + +/* A flash map entry, containing an offset and length */ +struct fmap_entry { + uint32_t offset; + uint32_t length; + uint32_t used; /* Number of bytes used in region */ + enum fmap_compress_t compress_algo; /* Compression type */ + enum fmap_hash_t hash_algo; /* Hash algorithm */ + const uint8_t *hash; /* Hash value */ + int hash_size; /* Hash size */ +}; + +/** + * Read a flash entry from the fdt + * + * @param node Reference to node to read + * @param name Name of node being read + * @param entry Place to put offset and size of this node + * @return 0 if ok, -ve on error + */ +int of_read_fmap_entry(ofnode node, const char *name, + struct fmap_entry *entry); + +#endif diff --git a/include/fdtdec.h b/include/fdtdec.h index 3000ecbb58..f27fb368ad 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -815,28 +815,7 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, int fdtdec_decode_region(const void *blob, int node, const char *prop_name, fdt_addr_t *basep, fdt_size_t *sizep);
-enum fmap_compress_t { - FMAP_COMPRESS_NONE, - FMAP_COMPRESS_LZO, -}; - -enum fmap_hash_t { - FMAP_HASH_NONE, - FMAP_HASH_SHA1, - FMAP_HASH_SHA256, -}; - -/* A flash map entry, containing an offset and length */ -struct fmap_entry { - uint32_t offset; - uint32_t length; - uint32_t used; /* Number of bytes used in region */ - enum fmap_compress_t compress_algo; /* Compression type */ - enum fmap_hash_t hash_algo; /* Hash algorithm */ - const uint8_t *hash; /* Hash value */ - int hash_size; /* Hash size */ -}; - +struct fmap_entry; /** * Read a flash entry from the fdt * diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 942244f9a3..e23bd7a382 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -12,6 +12,7 @@ #include <fdt_support.h> #include <fdtdec.h> #include <asm/sections.h> +#include <dm/of_extra.h> #include <linux/ctype.h>
DECLARE_GLOBAL_DATA_PTR;

Some functions deal with structured data rather than simple data types. It makes sense to have these in their own file. For now this just has a function to read a flashmap entry. Move the data types also.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/Makefile | 2 +- drivers/core/of_extra.c | 37 +++++++++++++++++++++++++++++++++++++ include/cros_ec.h | 1 + include/dm/of_extra.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/fdtdec.h | 23 +---------------------- lib/fdtdec.c | 1 + 6 files changed, 87 insertions(+), 23 deletions(-) create mode 100644 drivers/core/of_extra.c create mode 100644 include/dm/of_extra.h
Applied to u-boot-dm

It is common to read a device-tree property from the node associated with a device. Add convenience functions to do this so that drivers do not need to deal with accessing the ofnode from the device.
These functions all start with 'dev_read_' to provide consistent naming for all functions which read information from a device's device tree node.
These are inlined when using the flat DT to save code size. The live tree implementation is added in a later commit.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/Kconfig | 4 + include/dm/read.h | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 387 insertions(+) create mode 100644 include/dm/read.h
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 405e9ad8ef..fb5c4e834d 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -215,4 +215,8 @@ config OF_ISA_BUS mistranslation of device addresses, so ensure that this is enabled if your board does include an ISA bus.
+config DM_DEV_READ_INLINE + bool + default y if !OF_LIVE + endmenu diff --git a/include/dm/read.h b/include/dm/read.h new file mode 100644 index 0000000000..4ce2bc2d6e --- /dev/null +++ b/include/dm/read.h @@ -0,0 +1,383 @@ +/* + * Function to read values from the device tree node attached to a udevice. + * + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DM_READ_H +#define _DM_READ_H + +#include <dm/fdtaddr.h> +#include <dm/ofnode.h> +#include <dm/uclass.h> + +#if CONFIG_IS_ENABLED(OF_LIVE) +static inline const struct device_node *dev_np(struct udevice *dev) +{ + return ofnode_to_np(dev->node); +} +#else +static inline const struct device_node *dev_np(struct udevice *dev) +{ + return NULL; +} +#endif + +/** + * dev_ofnode() - get the DT node reference associated with a udevice + * + * @dev: device to check + * @return reference of the the device's DT node + */ +static inline ofnode dev_ofnode(struct udevice *dev) +{ + return dev->node; +} + +static inline bool dev_of_valid(struct udevice *dev) +{ + return ofnode_valid(dev_ofnode(dev)); +} + +#ifdef CONFIG_DM_DEV_READ_INLINE + +static inline int dev_read_u32_default(struct udevice *dev, + const char *propname, int def) +{ + return ofnode_read_u32_default(dev_ofnode(dev), propname, def); +} + +/** + * dev_read_string() - Read a string from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read + * @return string from property value, or NULL if there is no such property + */ +static inline const char *dev_read_string(struct udevice *dev, + const char *propname) +{ + return ofnode_read_string(dev_ofnode(dev), propname); +} + +/** + * dev_read_bool() - read a boolean value from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of property to read + * @return true if property is present (meaning true), false if not present + */ +static inline bool dev_read_bool(struct udevice *dev, const char *propname) +{ + return ofnode_read_bool(dev_ofnode(dev), propname); +} + +/** + * dev_read_subnode() - find a named subnode of a device + * + * @dev: device whose DT node contains the subnode + * @subnode_name: name of subnode to find + * @return reference to subnode (which can be invalid if there is no such + * subnode) + */ +static inline ofnode dev_read_subnode(struct udevice *dev, + const char *subbnode_name) +{ + return ofnode_find_subnode(dev_ofnode(dev), subbnode_name); +} + +/** + * dev_read_size() - read the size of a property + * + * @dev: device to check + * @propname: property to check + * @return size of property if present, or -EINVAL if not + */ +static inline int dev_read_size(struct udevice *dev, const char *propname) +{ + return ofnode_read_size(dev_ofnode(dev), propname); +} + +/** + * dev_read_addr_index() - Get the indexed reg property of a device + * + * @dev: Device to read from + * @index: the 'reg' property can hold a list of <addr, size> pairs + * and @index is used to select which one is required + * + * @return address or FDT_ADDR_T_NONE if not found + */ +static inline fdt_addr_t dev_read_addr_index(struct udevice *dev, int index) +{ + return devfdt_get_addr_index(dev, index); +} + +/** + * dev_read_addr() - Get the reg property of a device + * + * @dev: Device to read from + * + * @return address or FDT_ADDR_T_NONE if not found + */ +static inline fdt_addr_t dev_read_addr(struct udevice *dev) +{ + return devfdt_get_addr(dev); +} + +/** + * dev_read_addr_size() - get address and size from a device property + * + * This does no address translation. It simply reads an property that contains + * an address and a size value, one after the other. + * + * @dev: Device to read from + * @propname: property to read + * @sizep: place to put size value (on success) + * @return address value, or FDT_ADDR_T_NONE on error + */ +static inline fdt_addr_t dev_read_addr_size(struct udevice *dev, + const char *propname, + fdt_size_t *sizep) +{ + return ofnode_get_addr_size(dev_ofnode(dev), propname, sizep); +} + +/** + * dev_read_name() - get the name of a device's node + * + * @node: valid node to look up + * @return name of node + */ +static inline const char *dev_read_name(struct udevice *dev) +{ + return ofnode_get_name(dev_ofnode(dev)); +} + +/** + * dev_read_stringlist_search() - find string in a string list and return index + * + * Note that it is possible for this function to succeed on property values + * that are not NUL-terminated. That's because the function will stop after + * finding the first occurrence of @string. This can for example happen with + * small-valued cell properties, such as #address-cells, when searching for + * the empty string. + * + * @dev: device to check + * @propname: name of the property containing the string list + * @string: string to look up in the string list + * + * @return: + * the index of the string in the list of strings + * -ENODATA if the property is not found + * -EINVAL on some other error + */ +static inline int dev_read_stringlist_search(struct udevice *dev, + const char *propname, + const char *string) +{ + return ofnode_stringlist_search(dev_ofnode(dev), propname, string); +} + +/** + * dev_read_phandle_with_args() - Find a node pointed by phandle in a list + * + * This function is useful to parse lists of phandles and their arguments. + * Returns 0 on success and fills out_args, on error returns appropriate + * errno value. + * + * Caller is responsible to call of_node_put() on the returned out_args->np + * pointer. + * + * Example: + * + * phandle1: node1 { + * #list-cells = <2>; + * } + * + * phandle2: node2 { + * #list-cells = <1>; + * } + * + * node3 { + * list = <&phandle1 1 2 &phandle2 3>; + * } + * + * To get a device_node of the `node2' node you may call this: + * dev_read_phandle_with_args(dev, "list", "#list-cells", 0, 1, &args); + * + * @dev: device whose node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * @cells_count: Cell count to use if @cells_name is NULL + * @index: index of a phandle to parse out + * @out_args: optional pointer to output arguments structure (will be filled) + * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if + * @list_name does not exist, -EINVAL if a phandle was not found, + * @cells_name could not be found, the arguments were truncated or there + * were too many arguments. + */ +static inline int dev_read_phandle_with_args(struct udevice *dev, + const char *list_name, const char *cells_name, int cell_count, + int index, struct ofnode_phandle_args *out_args) +{ + return ofnode_parse_phandle_with_args(dev_ofnode(dev), list_name, + cells_name, cell_count, index, + out_args); +} + +/** + * dev_read_addr_cells() - Get the number of address cells for a device's node + * + * This walks back up the tree to find the closest #address-cells property + * which controls the given node. + * + * @dev: devioe to check + * @return number of address cells this node uses + */ +static inline int dev_read_addr_cells(struct udevice *dev) +{ + return fdt_address_cells(gd->fdt_blob, dev_of_offset(dev)); +} + +/** + * dev_read_size_cells() - Get the number of size cells for a device's node + * + * This walks back up the tree to find the closest #size-cells property + * which controls the given node. + * + * @dev: devioe to check + * @return number of size cells this node uses + */ +static inline int dev_read_size_cells(struct udevice *dev) +{ + return fdt_size_cells(gd->fdt_blob, dev_of_offset(dev)); +} + +/** + * dev_read_phandle() - Get the phandle from a device + * + * @dev: device to check + * @return phandle (1 or greater), or 0 if no phandle or other error + */ +static inline int dev_read_phandle(struct udevice *dev) +{ + return fdt_get_phandle(gd->fdt_blob, dev_of_offset(dev)); +} + +/** + * dev_read_prop()- - read a property from a device's node + * + * @dev: device to check + * @propname: property to read + * @lenp: place to put length on success + * @return pointer to property, or NULL if not found + */ +static inline const u32 *dev_read_prop(struct udevice *dev, + const char *propname, int *lenp) +{ + return ofnode_read_prop(dev_ofnode(dev), propname, lenp); +} + +/** + * dev_read_alias_seq() - Get the alias sequence number of a node + * + * This works out whether a node is pointed to by an alias, and if so, the + * sequence number of that alias. Aliases are of the form <base><num> where + * <num> is the sequence number. For example spi2 would be sequence number 2. + * + * @dev: device to look up + * @devnump: set to the sequence number if one is found + * @return 0 if a sequence was found, -ve if not + */ +static inline int dev_read_alias_seq(struct udevice *dev, int *devnump) +{ + return fdtdec_get_alias_seq(gd->fdt_blob, dev->uclass->uc_drv->name, + dev_of_offset(dev), devnump); +} + +/** + * dev_read_u32_array() - Find and read an array of 32 bit integers + * + * Search for a property in a device node and read 32-bit value(s) from + * it. + * + * The out_values is modified only if a valid u32 value can be decoded. + * + * @dev: device to look up + * @propname: name of the property to read + * @out_values: pointer to return value, modified only if return value is 0 + * @sz: number of array elements to read + * @return 0 on success, -EINVAL if the property does not exist, -ENODATA if + * property does not have a value, and -EOVERFLOW if the property data isn't + * large enough. + */ +static inline int dev_read_u32_array(struct udevice *dev, const char *propname, + u32 *out_values, size_t sz) +{ + return ofnode_read_u32_array(dev_ofnode(dev), propname, out_values, sz); +} + +/** + * dev_read_first_subnode() - find the first subnode of a device's node + * + * @dev: device to look up + * @return reference to the first subnode (which can be invalid if the device's + * node has no subnodes) + */ +static inline ofnode dev_read_first_subnode(struct udevice *dev) +{ + return ofnode_first_subnode(dev_ofnode(dev)); +} + +/** + * ofnode_next_subnode() - find the next sibling of a subnode + * + * @node: valid reference to previous node (sibling) + * @return reference to the next subnode (which can be invalid if the node + * has no more siblings) + */ +static inline ofnode dev_read_next_subnode(ofnode node) +{ + return ofnode_next_subnode(node); +} + +/** + * dev_read_u8_array_ptr() - find an 8-bit array + * + * Look up a device's node property and return a pointer to its contents as a + * byte array of given length. The property must have at least enough data + * for the array (count bytes). It may have more, but this will be ignored. + * The data is not copied. + * + * @dev: device to look up + * @propname: name of property to find + * @sz: number of array elements + * @return pointer to byte array if found, or NULL if the property is not + * found or there is not enough data + */ +static inline const uint8_t *dev_read_u8_array_ptr(struct udevice *dev, + const char *propname, size_t sz) +{ + return ofnode_read_u8_array_ptr(dev_ofnode(dev), propname, sz); +} + +#endif /* CONFIG_DM_DEV_READ_INLINE */ + +/** + * dev_for_each_subnode() - Helper function to iterate through subnodes + * + * This creates a for() loop which works through the subnodes in a device's + * device-tree node. + * + * @subnode: ofnode holding the current subnode + * @dev: device to use for interation (struct udevice *) + */ +#define dev_for_each_subnode(subnode, dev) \ + for (subnode = dev_read_first_subnode(dev); \ + ofnode_valid(subnode); \ + subnode = ofnode_next_subnode(subnode)) + +#endif

It is common to read a device-tree property from the node associated with a device. Add convenience functions to do this so that drivers do not need to deal with accessing the ofnode from the device.
These functions all start with 'dev_read_' to provide consistent naming for all functions which read information from a device's device tree node.
These are inlined when using the flat DT to save code size. The live tree implementation is added in a later commit.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/Kconfig | 4 + include/dm/read.h | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 387 insertions(+) create mode 100644 include/dm/read.h
Applied to u-boot-dm

When the live tree is supported some functions need to change a little. Add an implementation which is used when not inlining these functions.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/Makefile | 3 + drivers/core/read.c | 140 +++++++++++++++++++++++++++++ include/dm/read.h | 240 +++++++++++++++++++++++++++++++------------------- 3 files changed, 291 insertions(+), 92 deletions(-) create mode 100644 drivers/core/read.c
diff --git a/drivers/core/Makefile b/drivers/core/Makefile index d74b065a07..435cf98ae1 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -12,4 +12,7 @@ obj-$(CONFIG_DM) += dump.o obj-$(CONFIG_$(SPL_)REGMAP) += regmap.o obj-$(CONFIG_$(SPL_)SYSCON) += syscon-uclass.o obj-$(CONFIG_OF_LIVE) += of_access.o of_addr.o +ifndef CONFIG_DM_DEV_READ_INLINE +obj-$(CONFIG_OF_CONTROL) += read.o +endif obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o diff --git a/drivers/core/read.c b/drivers/core/read.c new file mode 100644 index 0000000000..3131e5379c --- /dev/null +++ b/drivers/core/read.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <dm/of_access.h> + +int dev_read_u32_default(struct udevice *dev, const char *propname, int def) +{ + return ofnode_read_u32_default(dev_ofnode(dev), propname, def); +} + +const char *dev_read_string(struct udevice *dev, const char *propname) +{ + return ofnode_read_string(dev_ofnode(dev), propname); +} + +bool dev_read_bool(struct udevice *dev, const char *propname) +{ + return ofnode_read_bool(dev_ofnode(dev), propname); +} + +ofnode dev_read_subnode(struct udevice *dev, const char *subnode_name) +{ + return ofnode_find_subnode(dev_ofnode(dev), subnode_name); +} + +ofnode dev_read_first_subnode(struct udevice *dev) +{ + return ofnode_first_subnode(dev_ofnode(dev)); +} + +ofnode dev_read_next_subnode(ofnode node) +{ + return ofnode_next_subnode(node); +} + +int dev_read_size(struct udevice *dev, const char *propname) +{ + return ofnode_read_size(dev_ofnode(dev), propname); +} + +fdt_addr_t dev_read_addr_index(struct udevice *dev, int index) +{ + if (ofnode_is_np(dev_ofnode(dev))) + return ofnode_get_addr_index(dev_ofnode(dev), index); + else + return devfdt_get_addr_index(dev, index); +} + +fdt_addr_t dev_read_addr(struct udevice *dev) +{ + return dev_read_addr_index(dev, 0); +} + +fdt_addr_t dev_read_addr_size(struct udevice *dev, const char *property, + fdt_size_t *sizep) +{ + return ofnode_get_addr_size(dev_ofnode(dev), property, sizep); +} + +const char *dev_read_name(struct udevice *dev) +{ + return ofnode_get_name(dev_ofnode(dev)); +} + +int dev_read_stringlist_search(struct udevice *dev, const char *property, + const char *string) +{ + return ofnode_stringlist_search(dev_ofnode(dev), property, string); +} + +int dev_read_phandle_with_args(struct udevice *dev, const char *list_name, + const char *cells_name, int cell_count, + int index, + struct ofnode_phandle_args *out_args) +{ + return ofnode_parse_phandle_with_args(dev_ofnode(dev), list_name, + cells_name, cell_count, index, + out_args); +} + +int dev_read_addr_cells(struct udevice *dev) +{ + return ofnode_read_addr_cells(dev_ofnode(dev)); +} + +int dev_read_size_cells(struct udevice *dev) +{ + return ofnode_read_size_cells(dev_ofnode(dev)); +} + +int dev_read_phandle(struct udevice *dev) +{ + ofnode node = dev_ofnode(dev); + + if (ofnode_is_np(node)) + return ofnode_to_np(node)->phandle; + else + return fdt_get_phandle(gd->fdt_blob, ofnode_to_offset(node)); +} + +const u32 *dev_read_prop(struct udevice *dev, const char *propname, int *lenp) +{ + return ofnode_read_prop(dev_ofnode(dev), propname, lenp); +} + +int dev_read_alias_seq(struct udevice *dev, int *devnump) +{ + ofnode node = dev_ofnode(dev); + const char *uc_name = dev->uclass->uc_drv->name; + int ret; + + if (ofnode_is_np(node)) { + ret = of_alias_get_id(ofnode_to_np(node), uc_name); + if (ret >= 0) + *devnump = ret; + } else { + ret = fdtdec_get_alias_seq(gd->fdt_blob, uc_name, + ofnode_to_offset(node), devnump); + } + + return ret; +} + +int dev_read_u32_array(struct udevice *dev, const char *propname, + u32 *out_values, size_t sz) +{ + return ofnode_read_u32_array(dev_ofnode(dev), propname, out_values, sz); +} + +const uint8_t *dev_read_u8_array_ptr(struct udevice *dev, const char *propname, + size_t sz) +{ + return ofnode_read_u8_array_ptr(dev_ofnode(dev), propname, sz); +} diff --git a/include/dm/read.h b/include/dm/read.h index 4ce2bc2d6e..8c9846eaf2 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -42,13 +42,16 @@ static inline bool dev_of_valid(struct udevice *dev) return ofnode_valid(dev_ofnode(dev)); }
-#ifdef CONFIG_DM_DEV_READ_INLINE - -static inline int dev_read_u32_default(struct udevice *dev, - const char *propname, int def) -{ - return ofnode_read_u32_default(dev_ofnode(dev), propname, def); -} +#ifndef CONFIG_DM_DEV_READ_INLINE +/** + * dev_read_u32_default() - read a 32-bit integer from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * @return property value, or @def if not found + */ +int dev_read_u32_default(struct udevice *dev, const char *propname, int def);
/** * dev_read_string() - Read a string from a device's DT property @@ -57,11 +60,7 @@ static inline int dev_read_u32_default(struct udevice *dev, * @propname: name of the property to read * @return string from property value, or NULL if there is no such property */ -static inline const char *dev_read_string(struct udevice *dev, - const char *propname) -{ - return ofnode_read_string(dev_ofnode(dev), propname); -} +const char *dev_read_string(struct udevice *dev, const char *propname);
/** * dev_read_bool() - read a boolean value from a device's DT property @@ -70,10 +69,7 @@ static inline const char *dev_read_string(struct udevice *dev, * @propname: name of property to read * @return true if property is present (meaning true), false if not present */ -static inline bool dev_read_bool(struct udevice *dev, const char *propname) -{ - return ofnode_read_bool(dev_ofnode(dev), propname); -} +bool dev_read_bool(struct udevice *dev, const char *propname);
/** * dev_read_subnode() - find a named subnode of a device @@ -83,11 +79,7 @@ static inline bool dev_read_bool(struct udevice *dev, const char *propname) * @return reference to subnode (which can be invalid if there is no such * subnode) */ -static inline ofnode dev_read_subnode(struct udevice *dev, - const char *subbnode_name) -{ - return ofnode_find_subnode(dev_ofnode(dev), subbnode_name); -} +ofnode dev_read_subnode(struct udevice *dev, const char *subbnode_name);
/** * dev_read_size() - read the size of a property @@ -96,10 +88,7 @@ static inline ofnode dev_read_subnode(struct udevice *dev, * @propname: property to check * @return size of property if present, or -EINVAL if not */ -static inline int dev_read_size(struct udevice *dev, const char *propname) -{ - return ofnode_read_size(dev_ofnode(dev), propname); -} +int dev_read_size(struct udevice *dev, const char *propname);
/** * dev_read_addr_index() - Get the indexed reg property of a device @@ -110,10 +99,7 @@ static inline int dev_read_size(struct udevice *dev, const char *propname) * * @return address or FDT_ADDR_T_NONE if not found */ -static inline fdt_addr_t dev_read_addr_index(struct udevice *dev, int index) -{ - return devfdt_get_addr_index(dev, index); -} +fdt_addr_t dev_read_addr_index(struct udevice *dev, int index);
/** * dev_read_addr() - Get the reg property of a device @@ -122,10 +108,7 @@ static inline fdt_addr_t dev_read_addr_index(struct udevice *dev, int index) * * @return address or FDT_ADDR_T_NONE if not found */ -static inline fdt_addr_t dev_read_addr(struct udevice *dev) -{ - return devfdt_get_addr(dev); -} +fdt_addr_t dev_read_addr(struct udevice *dev);
/** * dev_read_addr_size() - get address and size from a device property @@ -138,12 +121,8 @@ static inline fdt_addr_t dev_read_addr(struct udevice *dev) * @sizep: place to put size value (on success) * @return address value, or FDT_ADDR_T_NONE on error */ -static inline fdt_addr_t dev_read_addr_size(struct udevice *dev, - const char *propname, - fdt_size_t *sizep) -{ - return ofnode_get_addr_size(dev_ofnode(dev), propname, sizep); -} +fdt_addr_t dev_read_addr_size(struct udevice *dev, const char *propname, + fdt_size_t *sizep);
/** * dev_read_name() - get the name of a device's node @@ -151,10 +130,7 @@ static inline fdt_addr_t dev_read_addr_size(struct udevice *dev, * @node: valid node to look up * @return name of node */ -static inline const char *dev_read_name(struct udevice *dev) -{ - return ofnode_get_name(dev_ofnode(dev)); -} +const char *dev_read_name(struct udevice *dev);
/** * dev_read_stringlist_search() - find string in a string list and return index @@ -174,12 +150,8 @@ static inline const char *dev_read_name(struct udevice *dev) * -ENODATA if the property is not found * -EINVAL on some other error */ -static inline int dev_read_stringlist_search(struct udevice *dev, - const char *propname, - const char *string) -{ - return ofnode_stringlist_search(dev_ofnode(dev), propname, string); -} +int dev_read_stringlist_search(struct udevice *dev, const char *property, + const char *string);
/** * dev_read_phandle_with_args() - Find a node pointed by phandle in a list @@ -219,14 +191,10 @@ static inline int dev_read_stringlist_search(struct udevice *dev, * @cells_name could not be found, the arguments were truncated or there * were too many arguments. */ -static inline int dev_read_phandle_with_args(struct udevice *dev, - const char *list_name, const char *cells_name, int cell_count, - int index, struct ofnode_phandle_args *out_args) -{ - return ofnode_parse_phandle_with_args(dev_ofnode(dev), list_name, - cells_name, cell_count, index, - out_args); -} +int dev_read_phandle_with_args(struct udevice *dev, const char *list_name, + const char *cells_name, int cell_count, + int index, + struct ofnode_phandle_args *out_args);
/** * dev_read_addr_cells() - Get the number of address cells for a device's node @@ -237,10 +205,7 @@ static inline int dev_read_phandle_with_args(struct udevice *dev, * @dev: devioe to check * @return number of address cells this node uses */ -static inline int dev_read_addr_cells(struct udevice *dev) -{ - return fdt_address_cells(gd->fdt_blob, dev_of_offset(dev)); -} +int dev_read_addr_cells(struct udevice *dev);
/** * dev_read_size_cells() - Get the number of size cells for a device's node @@ -251,10 +216,7 @@ static inline int dev_read_addr_cells(struct udevice *dev) * @dev: devioe to check * @return number of size cells this node uses */ -static inline int dev_read_size_cells(struct udevice *dev) -{ - return fdt_size_cells(gd->fdt_blob, dev_of_offset(dev)); -} +int dev_read_size_cells(struct udevice *dev);
/** * dev_read_phandle() - Get the phandle from a device @@ -262,10 +224,7 @@ static inline int dev_read_size_cells(struct udevice *dev) * @dev: device to check * @return phandle (1 or greater), or 0 if no phandle or other error */ -static inline int dev_read_phandle(struct udevice *dev) -{ - return fdt_get_phandle(gd->fdt_blob, dev_of_offset(dev)); -} +int dev_read_phandle(struct udevice *dev);
/** * dev_read_prop()- - read a property from a device's node @@ -275,11 +234,7 @@ static inline int dev_read_phandle(struct udevice *dev) * @lenp: place to put length on success * @return pointer to property, or NULL if not found */ -static inline const u32 *dev_read_prop(struct udevice *dev, - const char *propname, int *lenp) -{ - return ofnode_read_prop(dev_ofnode(dev), propname, lenp); -} +const u32 *dev_read_prop(struct udevice *dev, const char *propname, int *lenp);
/** * dev_read_alias_seq() - Get the alias sequence number of a node @@ -292,11 +247,7 @@ static inline const u32 *dev_read_prop(struct udevice *dev, * @devnump: set to the sequence number if one is found * @return 0 if a sequence was found, -ve if not */ -static inline int dev_read_alias_seq(struct udevice *dev, int *devnump) -{ - return fdtdec_get_alias_seq(gd->fdt_blob, dev->uclass->uc_drv->name, - dev_of_offset(dev), devnump); -} +int dev_read_alias_seq(struct udevice *dev, int *devnump);
/** * dev_read_u32_array() - Find and read an array of 32 bit integers @@ -314,11 +265,8 @@ static inline int dev_read_alias_seq(struct udevice *dev, int *devnump) * property does not have a value, and -EOVERFLOW if the property data isn't * large enough. */ -static inline int dev_read_u32_array(struct udevice *dev, const char *propname, - u32 *out_values, size_t sz) -{ - return ofnode_read_u32_array(dev_ofnode(dev), propname, out_values, sz); -} +int dev_read_u32_array(struct udevice *dev, const char *propname, + u32 *out_values, size_t sz);
/** * dev_read_first_subnode() - find the first subnode of a device's node @@ -327,10 +275,7 @@ static inline int dev_read_u32_array(struct udevice *dev, const char *propname, * @return reference to the first subnode (which can be invalid if the device's * node has no subnodes) */ -static inline ofnode dev_read_first_subnode(struct udevice *dev) -{ - return ofnode_first_subnode(dev_ofnode(dev)); -} +ofnode dev_read_first_subnode(struct udevice *dev);
/** * ofnode_next_subnode() - find the next sibling of a subnode @@ -339,10 +284,7 @@ static inline ofnode dev_read_first_subnode(struct udevice *dev) * @return reference to the next subnode (which can be invalid if the node * has no more siblings) */ -static inline ofnode dev_read_next_subnode(ofnode node) -{ - return ofnode_next_subnode(node); -} +ofnode dev_read_next_subnode(ofnode node);
/** * dev_read_u8_array_ptr() - find an 8-bit array @@ -358,6 +300,120 @@ static inline ofnode dev_read_next_subnode(ofnode node) * @return pointer to byte array if found, or NULL if the property is not * found or there is not enough data */ +const uint8_t *dev_read_u8_array_ptr(struct udevice *dev, const char *propname, + size_t sz); + +#else /* CONFIG_DM_DEV_READ_INLINE is enabled */ + +static inline int dev_read_u32_default(struct udevice *dev, + const char *propname, int def) +{ + return ofnode_read_u32_default(dev_ofnode(dev), propname, def); +} + +static inline const char *dev_read_string(struct udevice *dev, + const char *propname) +{ + return ofnode_read_string(dev_ofnode(dev), propname); +} + +static inline bool dev_read_bool(struct udevice *dev, const char *propname) +{ + return ofnode_read_bool(dev_ofnode(dev), propname); +} + +static inline ofnode dev_read_subnode(struct udevice *dev, + const char *subbnode_name) +{ + return ofnode_find_subnode(dev_ofnode(dev), subbnode_name); +} + +static inline int dev_read_size(struct udevice *dev, const char *propname) +{ + return ofnode_read_size(dev_ofnode(dev), propname); +} + +static inline fdt_addr_t dev_read_addr_index(struct udevice *dev, int index) +{ + return devfdt_get_addr_index(dev, index); +} + +static inline fdt_addr_t dev_read_addr(struct udevice *dev) +{ + return devfdt_get_addr(dev); +} + +static inline fdt_addr_t dev_read_addr_size(struct udevice *dev, + const char *propname, + fdt_size_t *sizep) +{ + return ofnode_get_addr_size(dev_ofnode(dev), propname, sizep); +} + +static inline const char *dev_read_name(struct udevice *dev) +{ + return ofnode_get_name(dev_ofnode(dev)); +} + +static inline int dev_read_stringlist_search(struct udevice *dev, + const char *propname, + const char *string) +{ + return ofnode_stringlist_search(dev_ofnode(dev), propname, string); +} + +static inline int dev_read_phandle_with_args(struct udevice *dev, + const char *list_name, const char *cells_name, int cell_count, + int index, struct ofnode_phandle_args *out_args) +{ + return ofnode_parse_phandle_with_args(dev_ofnode(dev), list_name, + cells_name, cell_count, index, + out_args); +} + +static inline int dev_read_addr_cells(struct udevice *dev) +{ + return fdt_address_cells(gd->fdt_blob, dev_of_offset(dev)); +} + +static inline int dev_read_size_cells(struct udevice *dev) +{ + return fdt_size_cells(gd->fdt_blob, dev_of_offset(dev)); +} + +static inline int dev_read_phandle(struct udevice *dev) +{ + return fdt_get_phandle(gd->fdt_blob, dev_of_offset(dev)); +} + +static inline const u32 *dev_read_prop(struct udevice *dev, + const char *propname, int *lenp) +{ + return ofnode_read_prop(dev_ofnode(dev), propname, lenp); +} + +static inline int dev_read_alias_seq(struct udevice *dev, int *devnump) +{ + return fdtdec_get_alias_seq(gd->fdt_blob, dev->uclass->uc_drv->name, + dev_of_offset(dev), devnump); +} + +static inline int dev_read_u32_array(struct udevice *dev, const char *propname, + u32 *out_values, size_t sz) +{ + return ofnode_read_u32_array(dev_ofnode(dev), propname, out_values, sz); +} + +static inline ofnode dev_read_first_subnode(struct udevice *dev) +{ + return ofnode_first_subnode(dev_ofnode(dev)); +} + +static inline ofnode dev_read_next_subnode(ofnode node) +{ + return ofnode_next_subnode(node); +} + static inline const uint8_t *dev_read_u8_array_ptr(struct udevice *dev, const char *propname, size_t sz) {

When the live tree is supported some functions need to change a little. Add an implementation which is used when not inlining these functions.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/Makefile | 3 + drivers/core/read.c | 140 +++++++++++++++++++++++++++++ include/dm/read.h | 240 +++++++++++++++++++++++++++++++------------------- 3 files changed, 291 insertions(+), 92 deletions(-) create mode 100644 drivers/core/read.c
Applied to u-boot-dm

When a live tree is being used we need to record the node that was used to create the device. Update device_bind_with_driver_data() to support this.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/device.c | 18 ++++++++---------- drivers/core/lists.c | 2 +- include/dm/device-internal.h | 10 ++++++---- 3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index f5e85413f7..5463d1ffa5 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -19,6 +19,7 @@ #include <dm/lists.h> #include <dm/pinctrl.h> #include <dm/platdata.h> +#include <dm/read.h> #include <dm/uclass.h> #include <dm/uclass-internal.h> #include <dm/util.h> @@ -77,10 +78,7 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, */ if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) { if (uc->uc_drv->name && ofnode_valid(node)) { - fdtdec_get_alias_seq(gd->fdt_blob, - uc->uc_drv->name, - ofnode_to_offset(node), - &dev->req_seq); + dev_read_alias_seq(dev, &dev->req_seq); } } } @@ -216,11 +214,11 @@ fail_alloc1:
int device_bind_with_driver_data(struct udevice *parent, const struct driver *drv, const char *name, - ulong driver_data, int of_offset, + ulong driver_data, ofnode node, struct udevice **devp) { - return device_bind_common(parent, drv, name, NULL, driver_data, - offset_to_ofnode(of_offset), 0, devp); + return device_bind_common(parent, drv, name, NULL, driver_data, node, + 0, devp); }
int device_bind(struct udevice *parent, const struct driver *drv, @@ -247,8 +245,8 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, platdata_size = info->platdata_size; #endif return device_bind_common(parent, drv, info->name, - (void *)info->platdata, 0, offset_to_ofnode(-1), - platdata_size, devp); + (void *)info->platdata, 0, ofnode_null(), platdata_size, + devp); }
static void *alloc_priv(int size, uint flags) @@ -385,7 +383,7 @@ int device_probe(struct udevice *dev) goto fail; }
- if (drv->ofdata_to_platdata && dev_of_offset(dev) >= 0) { + if (drv->ofdata_to_platdata && dev_has_of_node(dev)) { ret = drv->ofdata_to_platdata(dev); if (ret) goto fail; diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 72c55e205f..9adfa758bc 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -177,7 +177,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
dm_dbg(" - found match at '%s'\n", entry->name); ret = device_bind_with_driver_data(parent, entry, name, - id->data, offset, &dev); + id->data, offset_to_ofnode(offset), &dev); if (ret == -ENODEV) { dm_dbg("Driver '%s' refuses to bind\n", entry->name); continue; diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 2cabc87338..81ab893b60 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -11,6 +11,9 @@ #ifndef _DM_DEVICE_INTERNAL_H #define _DM_DEVICE_INTERNAL_H
+#include <dm/ofnode.h> + +struct device_node; struct udevice;
/** @@ -52,16 +55,15 @@ int device_bind(struct udevice *parent, const struct driver *drv, * @drv: Device's driver * @name: Name of device (e.g. device tree node name) * @driver_data: The driver_data field from the driver's match table. - * @of_offset: Offset of device tree node for this device. This is -1 for - * devices which don't use device tree. + * @node: Device tree node for this device. This is invalid for devices which + * don't use device tree. * @devp: if non-NULL, returns a pointer to the bound device * @return 0 if OK, -ve on error */ int device_bind_with_driver_data(struct udevice *parent, const struct driver *drv, const char *name, - ulong driver_data, int of_offset, + ulong driver_data, ofnode node, struct udevice **devp); - /** * device_bind_by_name: Create a device and bind it to a driver *

When a live tree is being used we need to record the node that was used to create the device. Update device_bind_with_driver_data() to support this.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/device.c | 18 ++++++++---------- drivers/core/lists.c | 2 +- include/dm/device-internal.h | 10 ++++++---- 3 files changed, 15 insertions(+), 15 deletions(-)
Applied to u-boot-dm

Adjust this function to use an ofnode instead of an offset, so it can be used with livetree. This involves updating all callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/lists.c | 12 ++++++------ drivers/core/root.c | 2 +- drivers/serial/serial-uclass.c | 3 ++- drivers/timer/timer-uclass.c | 3 ++- include/dm/lists.h | 7 +++---- 5 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 9adfa758bc..facf276474 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -126,8 +126,7 @@ static int driver_check_compatible(const struct udevice_id *of_match, return -ENOENT; }
-int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, - struct udevice **devp) +int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp) { struct driver *driver = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver); @@ -142,17 +141,18 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
if (devp) *devp = NULL; - name = fdt_get_name(blob, offset, NULL); + name = ofnode_get_name(node); dm_dbg("bind node %s\n", name);
- compat_list = fdt_getprop(blob, offset, "compatible", &compat_length); + compat_list = (const char *)ofnode_read_prop(node, "compatible", + &compat_length); if (!compat_list) { if (compat_length == -FDT_ERR_NOTFOUND) { dm_dbg("Device '%s' has no compatible string\n", name); return 0; }
- dm_warn("Device tree error at offset %d\n", offset); + dm_warn("Device tree error at node '%s'\n", name); return compat_length; }
@@ -177,7 +177,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
dm_dbg(" - found match at '%s'\n", entry->name); ret = device_bind_with_driver_data(parent, entry, name, - id->data, offset_to_ofnode(offset), &dev); + id->data, node, &dev); if (ret == -ENODEV) { dm_dbg("Driver '%s' refuses to bind\n", entry->name); continue; diff --git a/drivers/core/root.c b/drivers/core/root.c index 570b4d855f..0c00a4e051 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -235,7 +235,7 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob, dm_dbg(" - ignoring disabled device\n"); continue; } - err = lists_bind_fdt(parent, blob, offset, NULL); + err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL); if (err && !ret) { ret = err; debug("%s: ret=%d\n", fdt_get_name(blob, offset, NULL), diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index c2b9c5f12f..a9c4f89e1a 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -74,7 +74,8 @@ static void serial_find_console_or_panic(void) * bind it anyway. */ if (node > 0 && - !lists_bind_fdt(gd->dm_root, blob, node, &dev)) { + !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node), + &dev)) { if (!device_probe(dev)) { gd->cur_serial_dev = dev; return; diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c index 1caf3cd288..ec10b28288 100644 --- a/drivers/timer/timer-uclass.c +++ b/drivers/timer/timer-uclass.c @@ -103,7 +103,8 @@ int notrace dm_timer_init(void) * relocation, bind it anyway. */ if (node > 0 && - !lists_bind_fdt(gd->dm_root, blob, node, &dev)) { + !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node), + &dev)) { ret = device_probe(dev); if (ret) return ret; diff --git a/include/dm/lists.h b/include/dm/lists.h index 4513d6a311..f55c41991b 100644 --- a/include/dm/lists.h +++ b/include/dm/lists.h @@ -10,6 +10,7 @@ #ifndef _DM_LISTS_H_ #define _DM_LISTS_H_
+#include <dm/ofnode.h> #include <dm/uclass-id.h>
/** @@ -51,14 +52,12 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only); * @parent as its parent. * * @parent: parent device (root) - * @blob: device tree blob - * @offset: offset of this device tree node + * @node: device tree node to bind * @devp: if non-NULL, returns a pointer to the bound device * @return 0 if device was bound, -EINVAL if the device tree is invalid, * other -ve value on error */ -int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, - struct udevice **devp); +int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp);
/** * device_bind_driver() - bind a device to a driver

Adjust this function to use an ofnode instead of an offset, so it can be used with livetree. This involves updating all callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/lists.c | 12 ++++++------ drivers/core/root.c | 2 +- drivers/serial/serial-uclass.c | 3 ++- drivers/timer/timer-uclass.c | 3 ++- include/dm/lists.h | 7 +++---- 5 files changed, 14 insertions(+), 13 deletions(-)
Applied to u-boot-dm

Adjust this function to us an ofnode instead of an offset, so it can be used with livetree. This involves updating all callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/clk/at91/pmc.c | 2 +- drivers/core/lists.c | 15 ++++++--------- drivers/cpu/cpu-uclass.c | 6 +++--- drivers/i2c/muxes/i2c-mux-uclass.c | 11 ++++------- drivers/led/led_bcm6328.c | 2 +- drivers/led/led_bcm6358.c | 2 +- drivers/led/led_gpio.c | 13 +++++-------- drivers/misc/tegra186_bpmp.c | 6 +++--- drivers/misc/tegra_car.c | 4 ++-- drivers/net/keystone_net.c | 6 +++--- drivers/pinctrl/pinctrl-uclass.c | 15 ++++++--------- drivers/usb/musb-new/ti-musb.c | 2 +- include/dm.h | 2 ++ include/dm/lists.h | 2 +- 14 files changed, 39 insertions(+), 49 deletions(-)
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index c552c75562..f4ec5fcb5e 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -79,7 +79,7 @@ int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name) if (!name) return -EINVAL; ret = device_bind_driver_to_node(dev, drv_name, name, - offset, NULL); + offset_to_ofnode(offset), NULL); if (ret) return ret; } diff --git a/drivers/core/lists.c b/drivers/core/lists.c index facf276474..b79f26dbe6 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -74,11 +74,12 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) int device_bind_driver(struct udevice *parent, const char *drv_name, const char *dev_name, struct udevice **devp) { - return device_bind_driver_to_node(parent, drv_name, dev_name, -1, devp); + return device_bind_driver_to_node(parent, drv_name, dev_name, + ofnode_null(), devp); }
int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, - const char *dev_name, int node, + const char *dev_name, ofnode node, struct udevice **devp) { struct driver *drv; @@ -89,14 +90,10 @@ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, debug("Cannot find driver '%s'\n", drv_name); return -ENOENT; } - ret = device_bind(parent, drv, dev_name, NULL, node, devp); - if (ret) { - debug("Cannot create device named '%s' (err=%d)\n", - dev_name, ret); - return ret; - } + ret = device_bind_with_driver_data(parent, drv, dev_name, 0 /* data */, + node, devp);
- return 0; + return ret; }
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c index c57ac16b3a..73e4853939 100644 --- a/drivers/cpu/cpu-uclass.c +++ b/drivers/cpu/cpu-uclass.c @@ -63,11 +63,11 @@ U_BOOT_DRIVER(cpu_bus) = { static int uclass_cpu_init(struct uclass *uc) { struct udevice *dev; - int node; + ofnode node; int ret;
- node = fdt_path_offset(gd->fdt_blob, "/cpus"); - if (node < 0) + node = ofnode_path("/cpus"); + if (!ofnode_valid(node)) return 0;
ret = device_bind_driver_to_node(dm_root(), "cpu_bus", "cpus", node, diff --git a/drivers/i2c/muxes/i2c-mux-uclass.c b/drivers/i2c/muxes/i2c-mux-uclass.c index d243b8e32d..187e8a7c91 100644 --- a/drivers/i2c/muxes/i2c-mux-uclass.c +++ b/drivers/i2c/muxes/i2c-mux-uclass.c @@ -51,24 +51,21 @@ static int i2c_mux_child_post_bind(struct udevice *dev) /* Find the I2C buses selected by this mux */ static int i2c_mux_post_bind(struct udevice *mux) { - const void *blob = gd->fdt_blob; + ofnode node; int ret; - int offset;
debug("%s: %s\n", __func__, mux->name); /* * There is no compatible string in the sub-nodes, so we must manually * bind these */ - for (offset = fdt_first_subnode(blob, dev_of_offset(mux)); - offset > 0; - offset = fdt_next_subnode(blob, offset)) { + dev_for_each_subnode(node, mux) { struct udevice *dev; const char *name;
- name = fdt_get_name(blob, offset, NULL); + name = ofnode_get_name(node); ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv", name, - offset, &dev); + node, &dev); debug(" - bind ret=%d, %s\n", ret, dev ? dev->name : NULL); if (ret) return ret; diff --git a/drivers/led/led_bcm6328.c b/drivers/led/led_bcm6328.c index fa7c6d16d5..5d545c5096 100644 --- a/drivers/led/led_bcm6328.c +++ b/drivers/led/led_bcm6328.c @@ -236,7 +236,7 @@ static int bcm6328_led_bind(struct udevice *parent)
ret = device_bind_driver_to_node(parent, "bcm6328-led", fdt_get_name(blob, node, NULL), - node, &dev); + offset_to_ofnode(node), &dev); if (ret) return ret;
diff --git a/drivers/led/led_bcm6358.c b/drivers/led/led_bcm6358.c index a9a194b0e1..e8a3b64e68 100644 --- a/drivers/led/led_bcm6358.c +++ b/drivers/led/led_bcm6358.c @@ -201,7 +201,7 @@ static int bcm6358_led_bind(struct udevice *parent)
ret = device_bind_driver_to_node(parent, "bcm6358-led", fdt_get_name(blob, node, NULL), - node, &dev); + offset_to_ofnode(node), &dev); if (ret) return ret;
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index 4106ecb679..9976635887 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -85,25 +85,22 @@ static int led_gpio_remove(struct udevice *dev)
static int led_gpio_bind(struct udevice *parent) { - const void *blob = gd->fdt_blob; struct udevice *dev; - int node; + ofnode node; int ret;
- for (node = fdt_first_subnode(blob, dev_of_offset(parent)); - node > 0; - node = fdt_next_subnode(blob, node)) { + dev_for_each_subnode(node, parent) { struct led_uc_plat *uc_plat; const char *label;
- label = fdt_getprop(blob, node, "label", NULL); + label = ofnode_read_string(node, "label"); if (!label) { debug("%s: node %s has no label\n", __func__, - fdt_get_name(blob, node, NULL)); + ofnode_get_name(node)); return -EINVAL; } ret = device_bind_driver_to_node(parent, "gpio_led", - fdt_get_name(blob, node, NULL), + ofnode_get_name(node), node, &dev); if (ret) return ret; diff --git a/drivers/misc/tegra186_bpmp.c b/drivers/misc/tegra186_bpmp.c index bd8b9602e0..d61bacfc44 100644 --- a/drivers/misc/tegra186_bpmp.c +++ b/drivers/misc/tegra186_bpmp.c @@ -112,19 +112,19 @@ static int tegra186_bpmp_bind(struct udevice *dev) debug("%s(dev=%p)\n", __func__, dev);
ret = device_bind_driver_to_node(dev, "tegra186_clk", "tegra186_clk", - dev_of_offset(dev), &child); + dev_ofnode(dev), &child); if (ret) return ret;
ret = device_bind_driver_to_node(dev, "tegra186_reset", - "tegra186_reset", dev_of_offset(dev), + "tegra186_reset", dev_ofnode(dev), &child); if (ret) return ret;
ret = device_bind_driver_to_node(dev, "tegra186_power_domain", "tegra186_power_domain", - dev_of_offset(dev), &child); + dev_ofnode(dev), &child); if (ret) return ret;
diff --git a/drivers/misc/tegra_car.c b/drivers/misc/tegra_car.c index 5db3c374ce..93639e1989 100644 --- a/drivers/misc/tegra_car.c +++ b/drivers/misc/tegra_car.c @@ -22,12 +22,12 @@ static int tegra_car_bpmp_bind(struct udevice *dev) debug("%s(dev=%p)\n", __func__, dev);
ret = device_bind_driver_to_node(dev, "tegra_car_clk", "tegra_car_clk", - dev_of_offset(dev), &child); + dev_ofnode(dev), &child); if (ret) return ret;
ret = device_bind_driver_to_node(dev, "tegra_car_reset", - "tegra_car_reset", dev_of_offset(dev), + "tegra_car_reset", dev_ofnode(dev), &child); if (ret) return ret; diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c index f9ffd6d725..72ef42cca8 100644 --- a/drivers/net/keystone_net.c +++ b/drivers/net/keystone_net.c @@ -1008,8 +1008,8 @@ static int ks2_eth_bind_slaves(struct udevice *dev, int gbe, int *gbe_0) slave_name = malloc(20); snprintf(slave_name, 20, "netcp@slave-%d", slave_no); ret = device_bind_driver_to_node(dev, "eth_ks2_sl", - slave_name, slave, - &sl_dev); + slave_name, offset_to_ofnode(slave), + &sl_dev); if (ret) { error("ks2_net - not able to bind slave interfaces\n"); return ret; @@ -1029,7 +1029,7 @@ static int ks2_eth_bind_slaves(struct udevice *dev, int gbe, int *gbe_0) slave_name = malloc(20); snprintf(slave_name, 20, "netcp@slave-%d", slave_no); ret = device_bind_driver_to_node(dev, "eth_ks2_sl", slave_name, - slave, &sl_dev); + offset_to_ofnode(slave), &sl_dev); if (ret) { error("ks2_net - not able to bind slave interfaces\n"); return ret; diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index 0633b69bbe..02e269020d 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -121,34 +121,31 @@ static int pinctrl_select_state_full(struct udevice *dev, const char *statename) */ static int pinconfig_post_bind(struct udevice *dev) { - const void *fdt = gd->fdt_blob; - int offset = dev_of_offset(dev); bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC); const char *name; + ofnode node; int ret;
- for (offset = fdt_first_subnode(fdt, offset); - offset > 0; - offset = fdt_next_subnode(fdt, offset)) { + dev_for_each_subnode(node, dev) { if (pre_reloc_only && - !dm_fdt_pre_reloc(fdt, offset)) + !ofnode_pre_reloc(node)) continue; /* * If this node has "compatible" property, this is not * a pin configuration node, but a normal device. skip. */ - fdt_get_property(fdt, offset, "compatible", &ret); + ofnode_read_prop(node, "compatible", &ret); if (ret >= 0) continue;
if (ret != -FDT_ERR_NOTFOUND) return ret;
- name = fdt_get_name(fdt, offset, NULL); + name = ofnode_get_name(node); if (!name) return -EINVAL; ret = device_bind_driver_to_node(dev, "pinconfig", name, - offset, NULL); + node, NULL); if (ret) return ret; } diff --git a/drivers/usb/musb-new/ti-musb.c b/drivers/usb/musb-new/ti-musb.c index 27018c73b6..de101319cd 100644 --- a/drivers/usb/musb-new/ti-musb.c +++ b/drivers/usb/musb-new/ti-musb.c @@ -227,7 +227,7 @@ static int ti_musb_wrapper_bind(struct udevice *parent) case USB_DR_MODE_HOST: /* Bind MUSB host */ ret = device_bind_driver_to_node(parent, "ti-musb-host", - name, node, &dev); + name, offset_to_ofnode(node), &dev); if (ret) { error("musb - not able to bind usb host node\n"); return ret; diff --git a/include/dm.h b/include/dm.h index e634814d74..f752792c92 100644 --- a/include/dm.h +++ b/include/dm.h @@ -10,6 +10,8 @@ #include <dm/ofnode.h> #include <dm/device.h> #include <dm/fdtaddr.h> +#include <dm/ofnode.h> +#include <dm/read.h> #include <dm/platdata.h> #include <dm/uclass.h>
diff --git a/include/dm/lists.h b/include/dm/lists.h index f55c41991b..d4d82d2fc4 100644 --- a/include/dm/lists.h +++ b/include/dm/lists.h @@ -85,7 +85,7 @@ int device_bind_driver(struct udevice *parent, const char *drv_name, * @devp: If non-NULL, returns the newly bound device */ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, - const char *dev_name, int node, + const char *dev_name, ofnode node, struct udevice **devp);
#endif

Adjust this function to us an ofnode instead of an offset, so it can be used with livetree. This involves updating all callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/clk/at91/pmc.c | 2 +- drivers/core/lists.c | 15 ++++++--------- drivers/cpu/cpu-uclass.c | 6 +++--- drivers/i2c/muxes/i2c-mux-uclass.c | 11 ++++------- drivers/led/led_bcm6328.c | 2 +- drivers/led/led_bcm6358.c | 2 +- drivers/led/led_gpio.c | 13 +++++-------- drivers/misc/tegra186_bpmp.c | 6 +++--- drivers/misc/tegra_car.c | 4 ++-- drivers/net/keystone_net.c | 6 +++--- drivers/pinctrl/pinctrl-uclass.c | 15 ++++++--------- drivers/usb/musb-new/ti-musb.c | 2 +- include/dm.h | 2 ++ include/dm/lists.h | 2 +- 14 files changed, 39 insertions(+), 49 deletions(-)
Applied to u-boot-dm

When starting up driver model with a live tree we need to scan the tree for devices. Add code to handle this.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/root.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++---- include/dm/root.h | 3 ++- test/dm/test-main.c | 4 ++-- 3 files changed, 58 insertions(+), 7 deletions(-)
diff --git a/drivers/core/root.c b/drivers/core/root.c index 0c00a4e051..d691d6ff94 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -15,7 +15,10 @@ #include <dm/device.h> #include <dm/device-internal.h> #include <dm/lists.h> +#include <dm/of.h> +#include <dm/of_access.h> #include <dm/platdata.h> +#include <dm/read.h> #include <dm/root.h> #include <dm/uclass.h> #include <dm/util.h> @@ -147,7 +150,7 @@ void fix_devices(void)
#endif
-int dm_init(void) +int dm_init(bool of_live) { int ret;
@@ -167,7 +170,12 @@ int dm_init(void) if (ret) return ret; #if CONFIG_IS_ENABLED(OF_CONTROL) - DM_ROOT_NON_CONST->node = offset_to_ofnode(0); +# if CONFIG_IS_ENABLED(OF_LIVE) + if (of_live) + DM_ROOT_NON_CONST->node = np_to_ofnode(gd->of_root); + else +#endif + DM_ROOT_NON_CONST->node = offset_to_ofnode(0); #endif ret = device_probe(DM_ROOT_NON_CONST); if (ret) @@ -206,6 +214,36 @@ int dm_scan_platdata(bool pre_reloc_only) return ret; }
+#if CONFIG_IS_ENABLED(OF_LIVE) +static int dm_scan_fdt_live(struct udevice *parent, + const struct device_node *node_parent, + bool pre_reloc_only) +{ + struct device_node *np; + int ret = 0, err; + + for (np = node_parent->child; np; np = np->sibling) { + if (pre_reloc_only && + !of_find_property(np, "u-boot,dm-pre-reloc", NULL)) + continue; + if (!of_device_is_available(np)) { + dm_dbg(" - ignoring disabled device\n"); + continue; + } + err = lists_bind_fdt(parent, np_to_ofnode(np), NULL); + if (err && !ret) { + ret = err; + debug("%s: ret=%d\n", np->name, ret); + } + } + + if (ret) + dm_warn("Some drivers failed to bind\n"); + + return ret; +} +#endif /* CONFIG_IS_ENABLED(OF_LIVE) */ + #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) /** * dm_scan_fdt_node() - Scan the device tree and bind drivers for a node @@ -251,15 +289,27 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
int dm_scan_fdt_dev(struct udevice *dev) { - if (dev_of_offset(dev) == -1) + if (!dev_of_valid(dev)) return 0;
+#if CONFIG_IS_ENABLED(OF_LIVE) + if (of_live_active()) + return dm_scan_fdt_live(dev, dev_np(dev), + gd->flags & GD_FLG_RELOC ? false : true); + else +#endif return dm_scan_fdt_node(dev, gd->fdt_blob, dev_of_offset(dev), gd->flags & GD_FLG_RELOC ? false : true); }
int dm_scan_fdt(const void *blob, bool pre_reloc_only) { +#if CONFIG_IS_ENABLED(OF_LIVE) + if (of_live_active()) + return dm_scan_fdt_live(gd->dm_root, gd->of_root, + pre_reloc_only); + else +#endif return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); } #endif @@ -273,7 +323,7 @@ int dm_init_and_scan(bool pre_reloc_only) { int ret;
- ret = dm_init(); + ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE)); if (ret) { debug("dm_init() failed: %d\n", ret); return ret; diff --git a/include/dm/root.h b/include/dm/root.h index 186cf8ba1c..50a6011644 100644 --- a/include/dm/root.h +++ b/include/dm/root.h @@ -87,9 +87,10 @@ int dm_init_and_scan(bool pre_reloc_only); * This function will initialize roots of driver tree and class tree. * This needs to be called before anything uses the DM * + * @of_live: Enable live device tree * @return 0 if OK, -ve on error */ -int dm_init(void); +int dm_init(bool of_live);
/** * dm_uninit - Uninitialise Driver Model structures diff --git a/test/dm/test-main.c b/test/dm/test-main.c index f2e0048143..67c0082fb8 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -30,7 +30,7 @@ static int dm_test_init(struct unit_test_state *uts) gd->dm_root = NULL; memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count));
- ut_assertok(dm_init()); + ut_assertok(dm_init(false)); dms->root = dm_root();
return 0; @@ -137,7 +137,7 @@ static int dm_test_main(const char *test_name) printf("Failures: %d\n", uts->fail_count);
gd->dm_root = NULL; - ut_assertok(dm_init()); + ut_assertok(dm_init(false)); dm_scan_platdata(false); dm_scan_fdt(gd->fdt_blob, false);

When starting up driver model with a live tree we need to scan the tree for devices. Add code to handle this.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/root.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++---- include/dm/root.h | 3 ++- test/dm/test-main.c | 4 ++-- 3 files changed, 58 insertions(+), 7 deletions(-)
Applied to u-boot-dm

Add a function which looks up a device by its node (either in live tree or flat tree).
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/uclass.c | 37 +++++++++++++++++++++++++++++++++++++ include/dm/uclass-internal.h | 18 ++++++++++++++++++ include/dm/uclass.h | 17 +++++++++++++++++ 3 files changed, 72 insertions(+)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 04fb45b01a..630b2e7336 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -8,6 +8,7 @@ */
#include <common.h> +#include <dm.h> #include <errno.h> #include <malloc.h> #include <dm/device.h> @@ -287,6 +288,30 @@ int uclass_find_device_by_of_offset(enum uclass_id id, int node, return -ENODEV; }
+int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node, + struct udevice **devp) +{ + struct uclass *uc; + struct udevice *dev; + int ret; + + *devp = NULL; + if (!ofnode_valid(node)) + return -ENODEV; + ret = uclass_get(id, &uc); + if (ret) + return ret; + + list_for_each_entry(dev, &uc->dev_head, uclass_node) { + if (ofnode_equal(dev_ofnode(dev), node)) { + *devp = dev; + return 0; + } + } + + return -ENODEV; +} + #if CONFIG_IS_ENABLED(OF_CONTROL) static int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent, @@ -407,6 +432,18 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node, return uclass_get_device_tail(dev, ret, devp); }
+int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node, + struct udevice **devp) +{ + struct udevice *dev; + int ret; + + *devp = NULL; + ret = uclass_find_device_by_ofnode(id, node, &dev); + + return uclass_get_device_tail(dev, ret, devp); +} + #if CONFIG_IS_ENABLED(OF_CONTROL) int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent, const char *name, struct udevice **devp) diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index ad284b8445..c086004318 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -10,6 +10,8 @@ #ifndef _DM_UCLASS_INTERNAL_H #define _DM_UCLASS_INTERNAL_H
+#include <dm/ofnode.h> + /** * uclass_get_device_tail() - handle the end of a get_device call * @@ -115,6 +117,22 @@ int uclass_find_device_by_of_offset(enum uclass_id id, int node, struct udevice **devp);
/** + * uclass_find_device_by_of_node() - Find a uclass device by device tree node + * + * This searches the devices in the uclass for one attached to the given + * device tree node. + * + * The device is NOT probed, it is merely returned. + * + * @id: ID to look up + * @node: Device tree offset to search for (if NULL then -ENODEV is returned) + * @devp: Returns pointer to device (there is only one for each node) + * @return 0 if OK, -ve on error + */ +int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node, + struct udevice **devp); + +/** * uclass_bind_device() - Associate device with a uclass * * Connect the device into uclass's list of devices. diff --git a/include/dm/uclass.h b/include/dm/uclass.h index b583aa869b..7f5a1304b5 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -10,6 +10,7 @@ #ifndef _DM_UCLASS_H #define _DM_UCLASS_H
+#include <dm/ofnode.h> #include <dm/uclass-id.h> #include <linker_lists.h> #include <linux/list.h> @@ -186,6 +187,22 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node, struct udevice **devp);
/** + * uclass_get_device_by_ofnode() - Get a uclass device by device tree node + * + * This searches the devices in the uclass for one attached to the given + * device tree node. + * + * The device is probed to activate it ready for use. + * + * @id: ID to look up + * @np: Device tree node to search for (if NULL then -ENODEV is returned) + * @devp: Returns pointer to device (there is only one for each node) + * @return 0 if OK, -ve on error + */ +int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node, + struct udevice **devp); + +/** * uclass_get_device_by_phandle() - Get a uclass device by phandle * * This searches the devices in the uclass for one with the given phandle.

Add a function which looks up a device by its node (either in live tree or flat tree).
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/uclass.c | 37 +++++++++++++++++++++++++++++++++++++ include/dm/uclass-internal.h | 18 ++++++++++++++++++ include/dm/uclass.h | 17 +++++++++++++++++ 3 files changed, 72 insertions(+)
Applied to u-boot-dm

Modify regmap to support livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/regmap.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-)
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 7f21dee7e4..749d913372 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -12,8 +12,9 @@ #include <malloc.h> #include <mapmem.h> #include <regmap.h> - #include <asm/io.h> +#include <dm/of_addr.h> +#include <linux/ioport.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -62,25 +63,25 @@ int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count, #else int regmap_init_mem(struct udevice *dev, struct regmap **mapp) { - const void *blob = gd->fdt_blob; struct regmap_range *range; - const fdt32_t *cell; struct regmap *map; int count; int addr_len, size_len, both_len; - int parent; int len; int index; + ofnode node = dev_ofnode(dev); + struct resource r;
- parent = dev_of_offset(dev->parent); - addr_len = fdt_address_cells(blob, parent); - size_len = fdt_size_cells(blob, parent); + addr_len = dev_read_addr_cells(dev->parent); + size_len = dev_read_size_cells(dev->parent); both_len = addr_len + size_len;
- cell = fdt_getprop(blob, dev_of_offset(dev), "reg", &len); - len /= sizeof(*cell); + len = dev_read_size(dev, "reg"); + if (len < 0) + return len; + len /= sizeof(fdt32_t); count = len / both_len; - if (!cell || !count) + if (!count) return -EINVAL;
map = regmap_alloc_count(count); @@ -88,12 +89,18 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp) return -ENOMEM;
for (range = map->range, index = 0; count > 0; - count--, cell += both_len, range++, index++) { + count--, range++, index++) { fdt_size_t sz; - range->start = fdtdec_get_addr_size_fixed(blob, - dev_of_offset(dev), "reg", index, addr_len, - size_len, &sz, true); - range->size = sz; + if (of_live_active()) { + of_address_to_resource(ofnode_to_np(node), index, &r); + range->start = r.start; + range->size = r.end - r.start + 1; + } else { + range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob, + dev_of_offset(dev), "reg", index, + addr_len, size_len, &sz, true); + range->size = sz; + } } map->base = map->range[0].start;

Modify regmap to support livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/regmap.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-)
Applied to u-boot-dm

Modify simple-bus to support livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/simple-bus.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/core/simple-bus.c b/drivers/core/simple-bus.c index a300217d39..14803e32b1 100644 --- a/drivers/core/simple-bus.c +++ b/drivers/core/simple-bus.c @@ -33,8 +33,7 @@ static int simple_bus_post_bind(struct udevice *dev) u32 cell[3]; int ret;
- ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), "ranges", - cell, ARRAY_SIZE(cell)); + ret = dev_read_u32_array(dev, "ranges", cell, ARRAY_SIZE(cell)); if (!ret) { struct simple_bus_plat *plat = dev_get_uclass_platdata(dev);

Modify simple-bus to support livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/simple-bus.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
Applied to u-boot-dm

Adjust this function to work with livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/uclass.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 630b2e7336..21dc696da3 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -324,8 +324,7 @@ static int uclass_find_device_by_phandle(enum uclass_id id, int ret;
*devp = NULL; - find_phandle = fdtdec_get_int(gd->fdt_blob, dev_of_offset(parent), name, - -1); + find_phandle = dev_read_u32_default(parent, name, -1); if (find_phandle <= 0) return -ENOENT; ret = uclass_get(id, &uc); @@ -335,7 +334,7 @@ static int uclass_find_device_by_phandle(enum uclass_id id, list_for_each_entry(dev, &uc->dev_head, uclass_node) { uint phandle;
- phandle = fdt_get_phandle(gd->fdt_blob, dev_of_offset(dev)); + phandle = dev_read_phandle(dev);
if (phandle == find_phandle) { *devp = dev;

Adjust this function to work with livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/uclass.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
Applied to u-boot-dm

Running a new test should reset the sandbox state to avoid tests interferring with each other. Move the existing state-reset code into a function so it can be used from tests.
Also update the code to reset the SPI devices and adjust the test code to call it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: - Clear the watchdog state also
Changes in v2: None
arch/sandbox/cpu/state.c | 15 +++++++++++---- arch/sandbox/include/asm/state.h | 7 +++++++ test/dm/test-main.c | 1 + 3 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c index 2b4dbd341f..07584486db 100644 --- a/arch/sandbox/cpu/state.c +++ b/arch/sandbox/cpu/state.c @@ -351,6 +351,16 @@ bool state_get_skip_delays(void) return state->skip_delays; }
+void state_reset_for_test(struct sandbox_state *state) +{ + /* No reset yet, so mark it as such. Always allow power reset */ + state->last_sysreset = SYSRESET_COUNT; + state->sysreset_allowed[SYSRESET_POWER] = true; + + memset(&state->wdt, '\0', sizeof(state->wdt)); + memset(state->spi, '\0', sizeof(state->spi)); +} + int state_init(void) { state = &main_state; @@ -359,10 +369,7 @@ int state_init(void) state->ram_buf = os_malloc(state->ram_size); assert(state->ram_buf);
- /* No reset yet, so mark it as such. Always allow power reset */ - state->last_sysreset = SYSRESET_COUNT; - state->sysreset_allowed[SYSRESET_POWER] = true; - + state_reset_for_test(state); /* * Example of how to use GPIOs: * diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 987cc7b49d..617f95291a 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -214,6 +214,13 @@ void state_set_skip_delays(bool skip_delays); bool state_get_skip_delays(void);
/** + * state_reset_for_test() - Reset ready to re-run tests + * + * This clears out any test state ready for another test run. + */ +void state_reset_for_test(struct sandbox_state *state); + +/** * Initialize the test system state */ int state_init(void); diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 67c0082fb8..9aa9d3a953 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -29,6 +29,7 @@ static int dm_test_init(struct unit_test_state *uts) memset(dms, '\0', sizeof(*dms)); gd->dm_root = NULL; memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); + state_reset_for_test(state_get_current());
ut_assertok(dm_init(false)); dms->root = dm_root();

Running a new test should reset the sandbox state to avoid tests interferring with each other. Move the existing state-reset code into a function so it can be used from tests.
Also update the code to reset the SPI devices and adjust the test code to call it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: - Clear the watchdog state also
Changes in v2: None
arch/sandbox/cpu/state.c | 15 +++++++++++---- arch/sandbox/include/asm/state.h | 7 +++++++ test/dm/test-main.c | 1 + 3 files changed, 19 insertions(+), 4 deletions(-)
Applied to u-boot-dm

We want to run the same test on flat and live trees. In preparation for this, create a new function which handles running a test.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/test-main.c | 56 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 24 deletions(-)
diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 9aa9d3a953..2848673e06 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -72,12 +72,42 @@ static int dm_test_destroy(struct unit_test_state *uts) return 0; }
+static int dm_do_test(struct unit_test_state *uts, struct unit_test *test) +{ + struct sandbox_state *state = state_get_current(); + + printf("Test: %s\n", test->name); + ut_assertok(dm_test_init(uts)); + + uts->start = mallinfo(); + if (test->flags & DM_TESTF_SCAN_PDATA) + ut_assertok(dm_scan_platdata(false)); + if (test->flags & DM_TESTF_PROBE_TEST) + ut_assertok(do_autoprobe(uts)); + if (test->flags & DM_TESTF_SCAN_FDT) + ut_assertok(dm_scan_fdt(gd->fdt_blob, false)); + + /* + * Silence the console and rely on console reocrding to get + * our output. + */ + console_record_reset(); + if (!state->show_test_output) + gd->flags |= GD_FLG_SILENT; + test->func(uts); + gd->flags &= ~GD_FLG_SILENT; + state_set_skip_delays(false); + + ut_assertok(dm_test_destroy(uts)); + + return 0; +} + static int dm_test_main(const char *test_name) { struct unit_test *tests = ll_entry_start(struct unit_test, dm_test); const int n_ents = ll_entry_count(struct unit_test, dm_test); struct unit_test_state *uts = &global_dm_test_state; - struct sandbox_state *state = state_get_current(); uts->priv = &_global_priv_dm_test_state; struct unit_test *test; int run_count; @@ -106,30 +136,8 @@ static int dm_test_main(const char *test_name) name += 8; if (test_name && strcmp(test_name, name)) continue; - printf("Test: %s\n", test->name); + ut_assertok(dm_do_test(uts, test)); run_count++; - ut_assertok(dm_test_init(uts)); - - uts->start = mallinfo(); - if (test->flags & DM_TESTF_SCAN_PDATA) - ut_assertok(dm_scan_platdata(false)); - if (test->flags & DM_TESTF_PROBE_TEST) - ut_assertok(do_autoprobe(uts)); - if (test->flags & DM_TESTF_SCAN_FDT) - ut_assertok(dm_scan_fdt(gd->fdt_blob, false)); - - /* - * Silence the console and rely on console reocrding to get - * our output. - */ - console_record_reset(); - if (!state->show_test_output) - gd->flags |= GD_FLG_SILENT; - test->func(uts); - gd->flags &= ~GD_FLG_SILENT; - state_set_skip_delays(false); - - ut_assertok(dm_test_destroy(uts)); }
if (test_name && !run_count)

We want to run the same test on flat and live trees. In preparation for this, create a new function which handles running a test.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/test-main.c | 56 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 24 deletions(-)
Applied to u-boot-dm

Show the filename of the test being run. Skip the path and show just the base name.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/test/test.h | 2 ++ test/dm/test-main.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/include/test/test.h b/include/test/test.h index b7e1ae2dec..e3e821c6ea 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -30,6 +30,7 @@ struct unit_test_state { * @flags: Flags indicated pre-conditions for test */ struct unit_test { + const char *file; const char *name; int (*func)(struct unit_test_state *state); int flags; @@ -38,6 +39,7 @@ struct unit_test { /* Declare a new unit test */ #define UNIT_TEST(_name, _flags, _suite) \ ll_entry_declare(struct unit_test, _name, _suite) = { \ + .file = __FILE__, \ .name = #_name, \ .flags = _flags, \ .func = _name, \ diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 2848673e06..10d2706377 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -75,8 +75,9 @@ static int dm_test_destroy(struct unit_test_state *uts) static int dm_do_test(struct unit_test_state *uts, struct unit_test *test) { struct sandbox_state *state = state_get_current(); + const char *fname = strrchr(test->file, '/') + 1;
- printf("Test: %s\n", test->name); + printf("Test: %s: %s\n", test->name, fname); ut_assertok(dm_test_init(uts));
uts->start = mallinfo();

Show the filename of the test being run. Skip the path and show just the base name.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/test/test.h | 2 ++ test/dm/test-main.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-)
Applied to u-boot-dm

It is useful to run the driver model tests with both livetree and flat tree in case something is different between the two. Add this feature to the test runner.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/test-main.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 10d2706377..88ef267458 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -22,7 +22,7 @@ struct unit_test_state global_dm_test_state; static struct dm_test_state _global_priv_dm_test_state;
/* Get ready for testing */ -static int dm_test_init(struct unit_test_state *uts) +static int dm_test_init(struct unit_test_state *uts, bool of_live) { struct dm_test_state *dms = uts->priv;
@@ -31,7 +31,11 @@ static int dm_test_init(struct unit_test_state *uts) memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); state_reset_for_test(state_get_current());
- ut_assertok(dm_init(false)); +#ifdef CONFIG_OF_LIVE + /* Determine whether to make the live tree available */ + gd->of_root = of_live ? uts->of_root : NULL; +#endif + ut_assertok(dm_init(of_live)); dms->root = dm_root();
return 0; @@ -72,13 +76,15 @@ static int dm_test_destroy(struct unit_test_state *uts) return 0; }
-static int dm_do_test(struct unit_test_state *uts, struct unit_test *test) +static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, + bool of_live) { struct sandbox_state *state = state_get_current(); const char *fname = strrchr(test->file, '/') + 1;
- printf("Test: %s: %s\n", test->name, fname); - ut_assertok(dm_test_init(uts)); + printf("Test: %s: %s%s\n", test->name, fname, + !of_live ? " (flat tree)" : ""); + ut_assertok(dm_test_init(uts, of_live));
uts->start = mallinfo(); if (test->flags & DM_TESTF_SCAN_PDATA) @@ -109,10 +115,10 @@ static int dm_test_main(const char *test_name) struct unit_test *tests = ll_entry_start(struct unit_test, dm_test); const int n_ents = ll_entry_count(struct unit_test, dm_test); struct unit_test_state *uts = &global_dm_test_state; - uts->priv = &_global_priv_dm_test_state; struct unit_test *test; int run_count;
+ uts->priv = &_global_priv_dm_test_state; uts->fail_count = 0;
/* @@ -129,6 +135,9 @@ static int dm_test_main(const char *test_name) printf("Running %d driver model tests\n", n_ents);
run_count = 0; +#ifdef CONFIG_OF_LIVE + uts->of_root = gd->of_root; +#endif for (test = tests; test < tests + n_ents; test++) { const char *name = test->name;
@@ -137,7 +146,7 @@ static int dm_test_main(const char *test_name) name += 8; if (test_name && strcmp(test_name, name)) continue; - ut_assertok(dm_do_test(uts, test)); + ut_assertok(dm_do_test(uts, test, false)); run_count++; }

It is useful to run the driver model tests with both livetree and flat tree in case something is different between the two. Add this feature to the test runner.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/test-main.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-)
Applied to u-boot-dm

Some tests require either livetree or flat tree. Add flags to allow the tests to specify this. Adjust the test runner to run with livetree (if supported) and then flat tree.
Some video tests are quite slow and running on flat tree adds little extra test value, so run these on livetree only.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/dm/test.h | 2 ++ include/test/test.h | 2 ++ test/dm/test-main.c | 38 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/include/dm/test.h b/include/dm/test.h index cba504909a..cecee26f33 100644 --- a/include/dm/test.h +++ b/include/dm/test.h @@ -150,6 +150,8 @@ enum { DM_TESTF_SCAN_PDATA = 1 << 0, /* test needs platform data */ DM_TESTF_PROBE_TEST = 1 << 1, /* probe test uclass */ DM_TESTF_SCAN_FDT = 1 << 2, /* scan device tree */ + DM_TESTF_FLAT_TREE = 1 << 3, /* test needs flat DT */ + DM_TESTF_LIVE_TREE = 1 << 4, /* needs live device tree */ };
/* Declare a new driver model test */ diff --git a/include/test/test.h b/include/test/test.h index e3e821c6ea..646dbfd486 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -15,11 +15,13 @@ * @fail_count: Number of tests that failed * @start: Store the starting mallinfo when doing leak test * @priv: A pointer to some other info some suites want to track + * @of_root: Record of the livetree root node (used for setting up tests) */ struct unit_test_state { int fail_count; struct mallinfo start; void *priv; + struct device_node *of_root; };
/** diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 88ef267458..9d88d31467 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -110,6 +110,21 @@ static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, return 0; }
+/** + * dm_test_run_on_flattree() - Check if we should run a test with flat DT + * + * This skips long/slow tests where there is not much value in running a flat + * DT test in addition to a live DT test. + * + * @return true to run the given test on the flat device tree + */ +static bool dm_test_run_on_flattree(struct unit_test *test) +{ + const char *fname = strrchr(test->file, '/') + 1; + + return !strstr(fname, "video") || strstr(test->name, "video_base"); +} + static int dm_test_main(const char *test_name) { struct unit_test *tests = ll_entry_start(struct unit_test, dm_test); @@ -140,14 +155,33 @@ static int dm_test_main(const char *test_name) #endif for (test = tests; test < tests + n_ents; test++) { const char *name = test->name; + int runs;
/* All tests have this prefix */ if (!strncmp(name, "dm_test_", 8)) name += 8; if (test_name && strcmp(test_name, name)) continue; - ut_assertok(dm_do_test(uts, test, false)); - run_count++; + + /* Run with the live tree if possible */ + runs = 0; + if (IS_ENABLED(CONFIG_OF_LIVE)) { + if (!(test->flags & DM_TESTF_FLAT_TREE)) { + ut_assertok(dm_do_test(uts, test, true)); + runs++; + } + } + + /* + * Run with the flat tree if we couldn't run it with live tree, + * or it is a core test. + */ + if (!(test->flags & DM_TESTF_LIVE_TREE) && + (!runs || dm_test_run_on_flattree(test))) { + ut_assertok(dm_do_test(uts, test, false)); + runs++; + } + run_count += runs; }
if (test_name && !run_count)

Some tests require either livetree or flat tree. Add flags to allow the tests to specify this. Adjust the test runner to run with livetree (if supported) and then flat tree.
Some video tests are quite slow and running on flat tree adds little extra test value, so run these on livetree only.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/dm/test.h | 2 ++ include/test/test.h | 2 ++ test/dm/test-main.c | 38 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-)
Applied to u-boot-dm

Move the main part of the GPIO request function into a separate function so that it can be used by the live tree function when added. Update the xlate method to use a node reference.
Update all GPIO drivers to handle the modified xlate() method.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/gpio/74x164_gpio.c | 2 +- drivers/gpio/gpio-uclass.c | 51 ++++++++++++++++++++++++++------------------ drivers/gpio/pca953x_gpio.c | 2 +- drivers/gpio/sandbox.c | 3 ++- drivers/gpio/sunxi_gpio.c | 2 +- drivers/gpio/tegra186_gpio.c | 2 +- drivers/gpio/tegra_gpio.c | 2 +- include/asm-generic/gpio.h | 6 ++++-- 8 files changed, 41 insertions(+), 29 deletions(-)
diff --git a/drivers/gpio/74x164_gpio.c b/drivers/gpio/74x164_gpio.c index 750eedfffd..ad69cb5a65 100644 --- a/drivers/gpio/74x164_gpio.c +++ b/drivers/gpio/74x164_gpio.c @@ -106,7 +106,7 @@ static int gen_74x164_get_function(struct udevice *dev, unsigned offset) }
static int gen_74x164_xlate(struct udevice *dev, struct gpio_desc *desc, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { desc->offset = args->args[0]; desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index ba4804083d..92a1346aa2 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -114,9 +114,8 @@ int gpio_lookup_name(const char *name, struct udevice **devp, return 0; }
-int gpio_xlate_offs_flags(struct udevice *dev, - struct gpio_desc *desc, - struct fdtdec_phandle_args *args) +int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc, + struct ofnode_phandle_args *args) { if (args->args_count < 1) return -EINVAL; @@ -133,7 +132,7 @@ int gpio_xlate_offs_flags(struct udevice *dev, }
static int gpio_find_and_xlate(struct gpio_desc *desc, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
@@ -642,37 +641,30 @@ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count) return vector; }
-static int _gpio_request_by_name_nodev(const void *blob, int node, - const char *list_name, int index, - struct gpio_desc *desc, int flags, - bool add_index) +static int gpio_request_tail(int ret, ofnode node, + struct ofnode_phandle_args *args, + const char *list_name, int index, + struct gpio_desc *desc, int flags, bool add_index) { - struct fdtdec_phandle_args args; - int ret; - desc->dev = NULL; desc->offset = 0; desc->flags = 0; - ret = fdtdec_parse_phandle_with_args(blob, node, list_name, - "#gpio-cells", 0, index, &args); - if (ret) { - debug("%s: fdtdec_parse_phandle_with_args failed\n", __func__); + if (ret) goto err; - }
- ret = uclass_get_device_by_of_offset(UCLASS_GPIO, args.node, - &desc->dev); + ret = uclass_get_device_by_ofnode(UCLASS_GPIO, args->node, + &desc->dev); if (ret) { debug("%s: uclass_get_device_by_of_offset failed\n", __func__); goto err; } - ret = gpio_find_and_xlate(desc, &args); + ret = gpio_find_and_xlate(desc, args); if (ret) { debug("%s: gpio_find_and_xlate failed\n", __func__); goto err; } ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s", - fdt_get_name(blob, node, NULL), + ofnode_get_name(node), list_name, index); if (ret) { debug("%s: dm_gpio_requestf failed\n", __func__); @@ -687,10 +679,27 @@ static int _gpio_request_by_name_nodev(const void *blob, int node, return 0; err: debug("%s: Node '%s', property '%s', failed to request GPIO index %d: %d\n", - __func__, fdt_get_name(blob, node, NULL), list_name, index, ret); + __func__, ofnode_get_name(node), list_name, index, ret); return ret; }
+static int _gpio_request_by_name_nodev(const void *blob, int node, + const char *list_name, int index, + struct gpio_desc *desc, int flags, + bool add_index) +{ + struct ofnode_phandle_args args; + int ret; + + ret = ofnode_parse_phandle_with_args(offset_to_ofnode(node), list_name, + "#gpio-cells", 0, index, &args); + if (ret) + debug("%s: fdtdec_parse_phandle_with_args failed\n", __func__); + + return gpio_request_tail(ret, offset_to_ofnode(node), &args, list_name, + index, desc, flags, add_index); +} + int gpio_request_by_name_nodev(const void *blob, int node, const char *list_name, int index, struct gpio_desc *desc, int flags) diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c index b81f0fa90c..4962f25230 100644 --- a/drivers/gpio/pca953x_gpio.c +++ b/drivers/gpio/pca953x_gpio.c @@ -228,7 +228,7 @@ static int pca953x_get_function(struct udevice *dev, unsigned offset) }
static int pca953x_xlate(struct udevice *dev, struct gpio_desc *desc, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { desc->offset = args->args[0]; desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index ae6d93013f..0f22acb0e6 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -8,6 +8,7 @@ #include <fdtdec.h> #include <malloc.h> #include <asm/gpio.h> +#include <dm/of.h> #include <dt-bindings/gpio/gpio.h>
DECLARE_GLOBAL_DATA_PTR; @@ -165,7 +166,7 @@ static int sb_gpio_get_function(struct udevice *dev, unsigned offset) }
static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { desc->offset = args->args[0]; if (args->args_count < 2) diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index f0c9ea0794..b47cc66c58 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -217,7 +217,7 @@ static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset) }
static int sunxi_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { int ret;
diff --git a/drivers/gpio/tegra186_gpio.c b/drivers/gpio/tegra186_gpio.c index cb2524e9bf..c5a7e13cce 100644 --- a/drivers/gpio/tegra186_gpio.c +++ b/drivers/gpio/tegra186_gpio.c @@ -139,7 +139,7 @@ static int tegra186_gpio_get_function(struct udevice *dev, unsigned offset) }
static int tegra186_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { int gpio, port, ret;
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index fb79f7fa58..687cd74fee 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -236,7 +236,7 @@ static int tegra_gpio_get_function(struct udevice *dev, unsigned offset) }
static int tegra_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { int gpio, port, ret;
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 4aa0004fab..b073b39138 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -7,6 +7,8 @@ #ifndef _ASM_GENERIC_GPIO_H_ #define _ASM_GENERIC_GPIO_H_
+struct ofnode_phandle_args; + /* * Generic GPIO API for U-Boot * @@ -214,7 +216,7 @@ struct fdtdec_phandle_args; * */ int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc, - struct fdtdec_phandle_args *args); + struct ofnode_phandle_args *args);
/** * struct struct dm_gpio_ops - Driver model GPIO operations @@ -286,7 +288,7 @@ struct dm_gpio_ops { * @return 0 if OK, -ve on error */ int (*xlate)(struct udevice *dev, struct gpio_desc *desc, - struct fdtdec_phandle_args *args); + struct ofnode_phandle_args *args); };
/**

Move the main part of the GPIO request function into a separate function so that it can be used by the live tree function when added. Update the xlate method to use a node reference.
Update all GPIO drivers to handle the modified xlate() method.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/gpio/74x164_gpio.c | 2 +- drivers/gpio/gpio-uclass.c | 51 ++++++++++++++++++++++++++------------------ drivers/gpio/pca953x_gpio.c | 2 +- drivers/gpio/sandbox.c | 3 ++- drivers/gpio/sunxi_gpio.c | 2 +- drivers/gpio/tegra186_gpio.c | 2 +- drivers/gpio/tegra_gpio.c | 2 +- include/asm-generic/gpio.h | 6 ++++-- 8 files changed, 41 insertions(+), 29 deletions(-)
Applied to u-boot-dm

This is not needed. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/asm-generic/gpio.h | 1 - 1 file changed, 1 deletion(-)
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index b073b39138..d78491dfc2 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -213,7 +213,6 @@ struct fdtdec_phandle_args; * * This routine sets the offset field to args[0] and the flags field to * GPIOD_ACTIVE_LOW if the GPIO_ACTIVE_LOW flag is present in args[1]. - * */ int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc, struct ofnode_phandle_args *args);

This is not needed. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/asm-generic/gpio.h | 1 - 1 file changed, 1 deletion(-)
Applied to u-boot-dm

Use the new dev_read...() functions to access the device tree, so that a live tree can be used.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/gpio/sandbox.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index 0f22acb0e6..4f7b62eba0 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -198,10 +198,8 @@ static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "num-gpios", 0); - uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), - "gpio-bank-name", NULL); + uc_priv->gpio_count = dev_read_u32_default(dev, "num-gpios", 0); + uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
return 0; } @@ -210,10 +208,9 @@ static int gpio_sandbox_probe(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- if (dev_of_offset(dev) == -1) { + if (!dev_of_valid(dev)) /* Tell the uclass how many GPIOs we have */ uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT; - }
dev->priv = calloc(sizeof(struct gpio_state), uc_priv->gpio_count);

Use the new dev_read...() functions to access the device tree, so that a live tree can be used.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/gpio/sandbox.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
Applied to u-boot-dm

Add support for requesting GPIOs with a live device tree.
This involves adjusting the function signature for the legacy function gpio_request_by_name_nodev(), so fix up all callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
board/qualcomm/dragonboard410c/dragonboard410c.c | 12 +++--- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt.c | 2 +- drivers/gpio/gpio-uclass.c | 51 +++++++++++------------- drivers/i2c/mxc_i2c.c | 12 +++--- drivers/mmc/fsl_esdhc.c | 6 +-- drivers/mmc/s5p_sdhci.c | 8 ++-- drivers/mtd/nand/sunxi_nand.c | 2 +- drivers/mtd/nand/tegra_nand.c | 4 +- drivers/net/pic32_eth.c | 3 +- drivers/sound/max98095.c | 2 + drivers/sound/wm8994.c | 2 +- drivers/spi/pic32_spi.c | 2 +- drivers/usb/host/ehci-tegra.c | 7 ++-- drivers/usb/host/ehci-vf.c | 5 ++- include/asm-generic/gpio.h | 10 ++--- 16 files changed, 65 insertions(+), 67 deletions(-)
diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.c b/board/qualcomm/dragonboard410c/dragonboard410c.c index e923ddc2e2..37d0b85e0e 100644 --- a/board/qualcomm/dragonboard410c/dragonboard410c.c +++ b/board/qualcomm/dragonboard410c/dragonboard410c.c @@ -53,8 +53,8 @@ int board_prepare_usb(enum usb_init_type type) printf("Failed to find usb_hub_reset_pm dt node.\n"); return node; } - ret = gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0, - &hub_reset, 0); + ret = gpio_request_by_name_nodev(offset_to_ofnode(node), + "gpios", 0, &hub_reset, 0); if (ret < 0) { printf("Failed to request usb_hub_reset_pm gpio.\n"); return ret; @@ -69,8 +69,8 @@ int board_prepare_usb(enum usb_init_type type) printf("Failed to find usb_sw_sel_pm dt node.\n"); return 0; } - ret = gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0, - &usb_sel, 0); + ret = gpio_request_by_name_nodev(offset_to_ofnode(node), + "gpios", 0, &usb_sel, 0); if (ret < 0) { printf("Failed to request usb_sw_sel_pm gpio.\n"); return ret; @@ -121,8 +121,8 @@ int misc_init_r(void) return 0; }
- if (gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0, &resin, - 0)) { + if (gpio_request_by_name_nodev(offset_to_ofnode(node), "gpios", 0, + &resin, 0)) { printf("Failed to request key_vol_down button.\n"); return 0; } diff --git a/board/samsung/common/board.c b/board/samsung/common/board.c index 17626966aa..88299f17e3 100644 --- a/board/samsung/common/board.c +++ b/board/samsung/common/board.c @@ -351,8 +351,8 @@ void reset_misc(void) if (node < 0) return;
- gpio_request_by_name_nodev(gd->fdt_blob, node, "reset-gpio", 0, &gpio, - GPIOD_IS_OUT); + gpio_request_by_name_nodev(offset_to_ofnode(node), "reset-gpio", 0, + &gpio, GPIOD_IS_OUT);
if (dm_gpio_is_valid(&gpio)) { /* diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index aec1f396b0..44f412db5d 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -45,7 +45,7 @@ static void board_enable_audio_codec(void) if (node <= 0) return;
- ret = gpio_request_by_name_nodev(gd->fdt_blob, node, + ret = gpio_request_by_name_nodev(offset_to_ofnode(node), "codec-enable-gpio", 0, &en_gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); if (ret == -FDT_ERR_NOTFOUND) diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 92a1346aa2..f611996f17 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -683,45 +683,41 @@ err: return ret; }
-static int _gpio_request_by_name_nodev(const void *blob, int node, - const char *list_name, int index, - struct gpio_desc *desc, int flags, - bool add_index) +static int _gpio_request_by_name_nodev(ofnode node, const char *list_name, + int index, struct gpio_desc *desc, + int flags, bool add_index) { struct ofnode_phandle_args args; int ret;
- ret = ofnode_parse_phandle_with_args(offset_to_ofnode(node), list_name, - "#gpio-cells", 0, index, &args); - if (ret) - debug("%s: fdtdec_parse_phandle_with_args failed\n", __func__); + ret = ofnode_parse_phandle_with_args(node, list_name, "#gpio-cells", 0, + index, &args);
- return gpio_request_tail(ret, offset_to_ofnode(node), &args, list_name, - index, desc, flags, add_index); + return gpio_request_tail(ret, node, &args, list_name, index, desc, + flags, add_index); }
-int gpio_request_by_name_nodev(const void *blob, int node, - const char *list_name, int index, +int gpio_request_by_name_nodev(ofnode node, const char *list_name, int index, struct gpio_desc *desc, int flags) { - return _gpio_request_by_name_nodev(blob, node, list_name, index, desc, - flags, index > 0); + return _gpio_request_by_name_nodev(node, list_name, index, desc, flags, + index > 0); }
-int gpio_request_by_name(struct udevice *dev, const char *list_name, int index, +int gpio_request_by_name(struct udevice *dev, const char *list_name, int index, struct gpio_desc *desc, int flags) { - /* - * This isn't ideal since we don't use dev->name in the debug() - * calls in gpio_request_by_name(), but we can do this until - * gpio_request_by_name_nodev() can be dropped. - */ - return gpio_request_by_name_nodev(gd->fdt_blob, dev_of_offset(dev), - list_name, index, desc, flags); + struct ofnode_phandle_args args; + int ret; + + ret = dev_read_phandle_with_args(dev, list_name, "#gpio-cells", 0, + index, &args); + + return gpio_request_tail(ret, dev_ofnode(dev), &args, list_name, + index, desc, flags, index > 0); }
-int gpio_request_list_by_name_nodev(const void *blob, int node, - const char *list_name, +int gpio_request_list_by_name_nodev(ofnode node, const char *list_name, struct gpio_desc *desc, int max_count, int flags) { @@ -729,7 +725,7 @@ int gpio_request_list_by_name_nodev(const void *blob, int node, int ret;
for (count = 0; count < max_count; count++) { - ret = _gpio_request_by_name_nodev(blob, node, list_name, count, + ret = _gpio_request_by_name_nodev(node, list_name, count, &desc[count], flags, true); if (ret == -ENOENT) break; @@ -755,9 +751,8 @@ int gpio_request_list_by_name(struct udevice *dev, const char *list_name, * calls in gpio_request_by_name(), but we can do this until * gpio_request_list_by_name_nodev() can be dropped. */ - return gpio_request_list_by_name_nodev(gd->fdt_blob, dev_of_offset(dev), - list_name, desc, max_count, - flags); + return gpio_request_list_by_name_nodev(dev_ofnode(dev), list_name, desc, + max_count, flags); }
int gpio_get_list_count(struct udevice *dev, const char *list_name) diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 3258ae7ced..110b9d6119 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -773,12 +773,12 @@ static int mxc_i2c_probe(struct udevice *bus) if (ret < 0) { debug("i2c bus %d at 0x%2lx, no gpio pinctrl state.\n", bus->seq, i2c_bus->base); } else { - ret = gpio_request_by_name_nodev(fdt, node, "scl-gpios", - 0, &i2c_bus->scl_gpio, - GPIOD_IS_OUT); - ret2 = gpio_request_by_name_nodev(fdt, node, "sda-gpios", - 0, &i2c_bus->sda_gpio, - GPIOD_IS_OUT); + ret = gpio_request_by_name_nodev(offset_to_ofnode(node), + "scl-gpios", 0, &i2c_bus->scl_gpio, + GPIOD_IS_OUT); + ret2 = gpio_request_by_name_nodev(offset_to_ofnode(node), + "sda-gpios", 0, &i2c_bus->sda_gpio, + GPIOD_IS_OUT); if (!dm_gpio_is_valid(&i2c_bus->sda_gpio) | !dm_gpio_is_valid(&i2c_bus->scl_gpio) | ret | ret2) { diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 3b3110f58b..5ee712f09b 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -983,15 +983,15 @@ static int fsl_esdhc_probe(struct udevice *dev) } else { priv->non_removable = 0; #ifdef CONFIG_DM_GPIO - gpio_request_by_name_nodev(fdt, node, "cd-gpios", 0, - &priv->cd_gpio, GPIOD_IS_IN); + gpio_request_by_name_nodev(offset_to_ofnode(node), "cd-gpios", + 0, &priv->cd_gpio, GPIOD_IS_IN); #endif }
priv->wp_enable = 1;
#ifdef CONFIG_DM_GPIO - ret = gpio_request_by_name_nodev(fdt, node, "wp-gpios", 0, + ret = gpio_request_by_name_nodev(offset_to_ofnode(node), "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN); if (ret) priv->wp_enable = 0; diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index 640ea0261e..62817a0d07 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -184,10 +184,10 @@ static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) } host->ioaddr = (void *)base;
- gpio_request_by_name_nodev(blob, node, "pwr-gpios", 0, &host->pwr_gpio, - GPIOD_IS_OUT); - gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio, - GPIOD_IS_IN); + gpio_request_by_name_nodev(offset_to_ofnode(node), "pwr-gpios", 0, + &host->pwr_gpio, GPIOD_IS_OUT); + gpio_request_by_name_nodev(offset_to_ofnode(node), "cd-gpios", 0, + &host->cd_gpio, GPIOD_IS_IN);
return 0; } diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index c4e2cd7f55..8bc3828854 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -1663,7 +1663,7 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum) chip->sels[i].rb.type = RB_NATIVE; chip->sels[i].rb.info.nativeid = tmp; } else { - ret = gpio_request_by_name_nodev(blob, node, + ret = gpio_request_by_name_nodev(offset_to_ofnode(node), "rb-gpios", i, &chip->sels[i].rb.info.gpio, GPIOD_IS_IN); diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c index 5c9b485b08..c03c9cb178 100644 --- a/drivers/mtd/nand/tegra_nand.c +++ b/drivers/mtd/nand/tegra_nand.c @@ -894,8 +894,8 @@ static int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config) config->reg = (struct nand_ctlr *)fdtdec_get_addr(blob, node, "reg"); config->enabled = fdtdec_get_is_enabled(blob, node); config->width = fdtdec_get_int(blob, node, "nvidia,nand-width", 8); - err = gpio_request_by_name_nodev(blob, node, "nvidia,wp-gpios", 0, - &config->wp_gpio, GPIOD_IS_OUT); + err = gpio_request_by_name_nodev(offset_to_ofnode(node), + "nvidia,wp-gpios", 0, &config->wp_gpio, GPIOD_IS_OUT); if (err) return err; err = fdtdec_get_int_array(blob, node, "nvidia,timing", diff --git a/drivers/net/pic32_eth.c b/drivers/net/pic32_eth.c index 385aad5b7e..0b89911f04 100644 --- a/drivers/net/pic32_eth.c +++ b/drivers/net/pic32_eth.c @@ -561,8 +561,7 @@ static int pic32_eth_probe(struct udevice *dev) phy_addr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1);
/* phy reset gpio */ - gpio_request_by_name_nodev(gd->fdt_blob, dev_of_offset(dev), - "reset-gpios", 0, + gpio_request_by_name_nodev(dev_ofnode(dev), "reset-gpios", 0, &priv->rst_gpio, GPIOD_IS_OUT);
priv->phyif = pdata->phy_interface; diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c index 35829f88c9..7c37bd0701 100644 --- a/drivers/sound/max98095.c +++ b/drivers/sound/max98095.c @@ -9,6 +9,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#include <common.h> #include <asm/arch/clk.h> #include <asm/arch/cpu.h> #include <asm/arch/power.h> diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c index d378442c50..b8208cdc87 100644 --- a/drivers/sound/wm8994.c +++ b/drivers/sound/wm8994.c @@ -4,11 +4,11 @@ * * SPDX-License-Identifier: GPL-2.0+ */ +#include <common.h> #include <asm/arch/clk.h> #include <asm/arch/cpu.h> #include <asm/gpio.h> #include <asm/io.h> -#include <common.h> #include <div64.h> #include <fdtdec.h> #include <i2c.h> diff --git a/drivers/spi/pic32_spi.c b/drivers/spi/pic32_spi.c index 78d78bc54b..15266b048c 100644 --- a/drivers/spi/pic32_spi.c +++ b/drivers/spi/pic32_spi.c @@ -414,7 +414,7 @@ static int pic32_spi_probe(struct udevice *bus) * of the ongoing transfer. To avoid this sort of error we will drive * /CS manually by toggling cs-gpio pins. */ - ret = gpio_request_by_name_nodev(gd->fdt_blob, node, "cs-gpios", 0, + ret = gpio_request_by_name_nodev(offset_to_ofnode(node), "cs-gpios", 0, &priv->cs_gpio, GPIOD_IS_OUT); if (ret) { printf("pic32-spi: error, cs-gpios not found\n"); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index da9e9440b7..7dc37f045d 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -728,9 +728,10 @@ static int fdt_decode_usb(struct udevice *dev, struct fdt_usb *config) debug("%s: Missing/invalid peripheral ID\n", __func__); return -EINVAL; } - gpio_request_by_name_nodev(blob, node, "nvidia,vbus-gpio", 0, - &config->vbus_gpio, GPIOD_IS_OUT); - gpio_request_by_name_nodev(blob, node, "nvidia,phy-reset-gpio", 0, + gpio_request_by_name_nodev(offset_to_ofnode(node), "nvidia,vbus-gpio", + 0, &config->vbus_gpio, GPIOD_IS_OUT); + gpio_request_by_name_nodev(offset_to_ofnode(node), + "nvidia,phy-reset-gpio", 0, &config->phy_reset_gpio, GPIOD_IS_OUT); debug("enabled=%d, legacy_mode=%d, utmi=%d, ulpi=%d, periph_id=%d, " "vbus=%d, phy_reset=%d, dr_mode=%d\n", diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c index e52cd6ad32..a7f6f21fa2 100644 --- a/drivers/usb/host/ehci-vf.c +++ b/drivers/usb/host/ehci-vf.c @@ -252,8 +252,9 @@ static int vf_usb_ofdata_to_platdata(struct udevice *dev) }
if (priv->dr_mode == DR_MODE_OTG) { - gpio_request_by_name_nodev(dt_blob, node, "fsl,cdet-gpio", 0, - &priv->cdet_gpio, GPIOD_IS_IN); + gpio_request_by_name_nodev(offset_to_ofnode(node), + "fsl,cdet-gpio", 0, &priv->cdet_gpio, + GPIOD_IS_IN); if (dm_gpio_is_valid(&priv->cdet_gpio)) { if (dm_gpio_get_value(&priv->cdet_gpio)) priv->init_type = USB_INIT_DEVICE; diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index d78491dfc2..bf230c15ba 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -7,6 +7,8 @@ #ifndef _ASM_GENERIC_GPIO_H_ #define _ASM_GENERIC_GPIO_H_
+#include <dm/ofnode.h> + struct ofnode_phandle_args;
/* @@ -488,9 +490,8 @@ int gpio_get_list_count(struct udevice *dev, const char *list_name); * This is a version of gpio_request_list_by_name() that does not use a * device. Avoid it unless the caller is not yet using driver model */ -int gpio_request_by_name_nodev(const void *blob, int node, - const char *list_name, - int index, struct gpio_desc *desc, int flags); +int gpio_request_by_name_nodev(ofnode node, const char *list_name, int index, + struct gpio_desc *desc, int flags);
/** * gpio_request_list_by_name_nodev() - request GPIOs without a device @@ -498,8 +499,7 @@ int gpio_request_by_name_nodev(const void *blob, int node, * This is a version of gpio_request_list_by_name() that does not use a * device. Avoid it unless the caller is not yet using driver model */ -int gpio_request_list_by_name_nodev(const void *blob, int node, - const char *list_name, +int gpio_request_list_by_name_nodev(ofnode node, const char *list_name, struct gpio_desc *desc_list, int max_count, int flags);

Add support for requesting GPIOs with a live device tree.
This involves adjusting the function signature for the legacy function gpio_request_by_name_nodev(), so fix up all callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
board/qualcomm/dragonboard410c/dragonboard410c.c | 12 +++--- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt.c | 2 +- drivers/gpio/gpio-uclass.c | 51 +++++++++++------------- drivers/i2c/mxc_i2c.c | 12 +++--- drivers/mmc/fsl_esdhc.c | 6 +-- drivers/mmc/s5p_sdhci.c | 8 ++-- drivers/mtd/nand/sunxi_nand.c | 2 +- drivers/mtd/nand/tegra_nand.c | 4 +- drivers/net/pic32_eth.c | 3 +- drivers/sound/max98095.c | 2 + drivers/sound/wm8994.c | 2 +- drivers/spi/pic32_spi.c | 2 +- drivers/usb/host/ehci-tegra.c | 7 ++-- drivers/usb/host/ehci-vf.c | 5 ++- include/asm-generic/gpio.h | 10 ++--- 16 files changed, 65 insertions(+), 67 deletions(-)
Applied to u-boot-dm

This prints out the wrong pointers. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/misc/cros_ec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 3d449b2a55..e2027ea5d2 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -304,8 +304,7 @@ static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd, NULL, 0, &din, din_len); }
- debug("%s: len=%d, dinp=%p, *dinp=%p\n", __func__, len, dinp, - dinp ? *dinp : NULL); + debug("%s: len=%d, din=%p\n", __func__, len, din); if (dinp) { /* If we have any data to return, it must be 64bit-aligned */ assert(len <= 0 || !((uintptr_t)din & 7));

This prints out the wrong pointers. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/misc/cros_ec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
Applied to u-boot-dm

Convert this driver to support the live device tree and remove the old fdtdec support.
The keyboard is not yet converted.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/misc/cros_ec.c | 33 ++++++++++++++------------------- drivers/misc/cros_ec_sandbox.c | 23 +++++++++++------------ include/cros_ec.h | 7 ++----- include/fdtdec.h | 13 ------------- lib/fdtdec.c | 32 -------------------------------- 5 files changed, 27 insertions(+), 81 deletions(-)
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index e2027ea5d2..feaa5d8567 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -26,6 +26,7 @@ #include <asm/io.h> #include <asm-generic/gpio.h> #include <dm/device-internal.h> +#include <dm/of_extra.h> #include <dm/uclass-internal.h>
#ifdef DEBUG_TRACE @@ -996,15 +997,12 @@ int cros_ec_get_ldo(struct udevice *dev, uint8_t index, uint8_t *state) int cros_ec_register(struct udevice *dev) { struct cros_ec_dev *cdev = dev_get_uclass_priv(dev); - const void *blob = gd->fdt_blob; - int node = dev_of_offset(dev); char id[MSG_BYTES];
cdev->dev = dev; gpio_request_by_name(dev, "ec-interrupt", 0, &cdev->ec_int, GPIOD_IS_IN); - cdev->optimise_flash_write = fdtdec_get_bool(blob, node, - "optimise-flash-write"); + cdev->optimise_flash_write = dev_read_bool(dev, "optimise-flash-write");
if (cros_ec_check_version(cdev)) { debug("%s: Could not detect CROS-EC version\n", __func__); @@ -1023,28 +1021,26 @@ int cros_ec_register(struct udevice *dev) return 0; }
-int cros_ec_decode_ec_flash(const void *blob, int node, - struct fdt_cros_ec *config) +int cros_ec_decode_ec_flash(struct udevice *dev, struct fdt_cros_ec *config) { - int flash_node; + ofnode flash_node, node;
- flash_node = fdt_subnode_offset(blob, node, "flash"); - if (flash_node < 0) { + flash_node = dev_read_subnode(dev, "flash"); + if (!ofnode_valid(flash_node)) { debug("Failed to find flash node\n"); return -1; }
- if (fdtdec_read_fmap_entry(blob, flash_node, "flash", - &config->flash)) { - debug("Failed to decode flash node in chrome-ec'\n"); + if (of_read_fmap_entry(flash_node, "flash", &config->flash)) { + debug("Failed to decode flash node in chrome-ec\n"); return -1; }
- config->flash_erase_value = fdtdec_get_int(blob, flash_node, - "erase-value", -1); - for (node = fdt_first_subnode(blob, flash_node); node >= 0; - node = fdt_next_subnode(blob, node)) { - const char *name = fdt_get_name(blob, node, NULL); + config->flash_erase_value = ofnode_read_s32_default(flash_node, + "erase-value", -1); + for (node = ofnode_first_subnode(flash_node); ofnode_valid(node); + node = ofnode_next_subnode(node)) { + const char *name = ofnode_get_name(node); enum ec_flash_region region;
if (0 == strcmp(name, "ro")) { @@ -1058,8 +1054,7 @@ int cros_ec_decode_ec_flash(const void *blob, int node, return -1; }
- if (fdtdec_read_fmap_entry(blob, node, "reg", - &config->region[region])) { + if (of_read_fmap_entry(node, "reg", &config->region[region])) { debug("Failed to decode flash region in chrome-ec'\n"); return -1; } diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 848c67bc23..c96e26e6b7 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -188,18 +188,16 @@ static int get_image_used(struct ec_state *ec, struct fmap_entry *entry) * RR=Row CC=Column KKKK=Key Code * * @param ec Current emulated EC state - * @param blob Device tree blob containing keyscan information * @param node Keyboard node of device tree containing keyscan information * @return 0 if ok, -1 on error */ -static int keyscan_read_fdt_matrix(struct ec_state *ec, const void *blob, - int node) +static int keyscan_read_fdt_matrix(struct ec_state *ec, ofnode node) { const u32 *cell; int upto; int len;
- cell = fdt_getprop(blob, node, "linux,keymap", &len); + cell = ofnode_read_prop(node, "linux,keymap", &len); ec->matrix_count = len / 4; ec->matrix = calloc(ec->matrix_count, sizeof(*ec->matrix)); if (!ec->matrix) { @@ -516,28 +514,29 @@ int cros_ec_probe(struct udevice *dev) { struct ec_state *ec = dev->priv; struct cros_ec_dev *cdev = dev->uclass_priv; - const void *blob = gd->fdt_blob; struct udevice *keyb_dev; - int node; + ofnode node; int err;
memcpy(ec, &s_state, sizeof(*ec)); - err = cros_ec_decode_ec_flash(blob, dev_of_offset(dev), &ec->ec_config); - if (err) + err = cros_ec_decode_ec_flash(dev, &ec->ec_config); + if (err) { + debug("%s: Cannot device EC flash\n", __func__); return err; + }
- node = -1; + node = ofnode_null(); for (device_find_first_child(dev, &keyb_dev); keyb_dev; device_find_next_child(&keyb_dev)) { if (device_get_uclass_id(keyb_dev) == UCLASS_KEYBOARD) { - node = dev_of_offset(keyb_dev); + node = dev_ofnode(keyb_dev); break; } } - if (node < 0) { + if (!ofnode_valid(node)) { debug("%s: No cros_ec keyboard found\n", __func__); - } else if (keyscan_read_fdt_matrix(ec, blob, node)) { + } else if (keyscan_read_fdt_matrix(ec, node)) { debug("%s: Could not read key matrix\n", __func__); return -1; } diff --git a/include/cros_ec.h b/include/cros_ec.h index 2bd9f2251f..771a176eea 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -11,7 +11,6 @@
#include <linux/compiler.h> #include <ec_commands.h> -#include <fdtdec.h> #include <cros_ec_message.h> #include <asm/gpio.h> #include <dm/of_extra.h> @@ -378,12 +377,10 @@ int cros_ec_get_error(void); /** * Returns information from the FDT about the Chrome EC flash * - * @param blob FDT blob to use - * @param node Node offset to read from + * @param dev Device to read from * @param config Structure to use to return information */ -int cros_ec_decode_ec_flash(const void *blob, int node, - struct fdt_cros_ec *config); +int cros_ec_decode_ec_flash(struct udevice *dev, struct fdt_cros_ec *config);
/** * Check the current keyboard state, in case recovery mode is requested. diff --git a/include/fdtdec.h b/include/fdtdec.h index f27fb368ad..eda2ffaf66 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -815,19 +815,6 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, int fdtdec_decode_region(const void *blob, int node, const char *prop_name, fdt_addr_t *basep, fdt_size_t *sizep);
-struct fmap_entry; -/** - * Read a flash entry from the fdt - * - * @param blob FDT blob - * @param node Offset of node to read - * @param name Name of node being read - * @param entry Place to put offset and size of this node - * @return 0 if ok, -ve on error - */ -int fdtdec_read_fmap_entry(const void *blob, int node, const char *name, - struct fmap_entry *entry); - /** * Obtain an indexed resource from a device property. * diff --git a/lib/fdtdec.c b/lib/fdtdec.c index e23bd7a382..91503b8cb9 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -941,38 +941,6 @@ int fdtdec_decode_region(const void *blob, int node, const char *prop_name, return 0; }
-/** - * Read a flash entry from the fdt - * - * @param blob FDT blob - * @param node Offset of node to read - * @param name Name of node being read - * @param entry Place to put offset and size of this node - * @return 0 if ok, -ve on error - */ -int fdtdec_read_fmap_entry(const void *blob, int node, const char *name, - struct fmap_entry *entry) -{ - const char *prop; - u32 reg[2]; - - if (fdtdec_get_int_array(blob, node, "reg", reg, 2)) { - debug("Node '%s' has bad/missing 'reg' property\n", name); - return -FDT_ERR_NOTFOUND; - } - entry->offset = reg[0]; - entry->length = reg[1]; - entry->used = fdtdec_get_int(blob, node, "used", entry->length); - prop = fdt_getprop(blob, node, "compress", NULL); - entry->compress_algo = prop && !strcmp(prop, "lzo") ? - FMAP_COMPRESS_LZO : FMAP_COMPRESS_NONE; - prop = fdt_getprop(blob, node, "hash", &entry->hash_size); - entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE; - entry->hash = (uint8_t *)prop; - - return 0; -} - u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells) { u64 number = 0;

Convert this driver to support the live device tree and remove the old fdtdec support.
The keyboard is not yet converted.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/misc/cros_ec.c | 33 ++++++++++++++------------------- drivers/misc/cros_ec_sandbox.c | 23 +++++++++++------------ include/cros_ec.h | 7 ++----- include/fdtdec.h | 13 ------------- lib/fdtdec.c | 32 -------------------------------- 5 files changed, 27 insertions(+), 81 deletions(-)
Applied to u-boot-dm

Add a sandbox board to test the non-livetree build (i.e. with CONFIG_OF_FLAT disabled). This increases our build and test coverage.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
board/sandbox/MAINTAINERS | 7 ++ configs/sandbox_flattree_defconfig | 179 +++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 configs/sandbox_flattree_defconfig
diff --git a/board/sandbox/MAINTAINERS b/board/sandbox/MAINTAINERS index 4dcbf4ba03..6d0790ccd1 100644 --- a/board/sandbox/MAINTAINERS +++ b/board/sandbox/MAINTAINERS @@ -18,3 +18,10 @@ S: Maintained F: board/sandbox/ F: include/configs/sandbox_spl.h F: configs/sandbox_spl_defconfig + +SANDBOX FLAT TREE BOARD +M: Simon Glass sjg@chromium.org +S: Maintained +F: board/sandbox/ +F: include/configs/sandbox.h +F: configs/sandbox_flattree_defconfig diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig new file mode 100644 index 0000000000..83efb23dbc --- /dev/null +++ b/configs/sandbox_flattree_defconfig @@ -0,0 +1,179 @@ +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_DEFAULT_DEVICE_TREE="sandbox" +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_FIT_VERBOSE=y +CONFIG_SPL_LOAD_FIT=y +CONFIG_BOOTSTAGE=y +CONFIG_BOOTSTAGE_REPORT=y +CONFIG_BOOTSTAGE_USER_COUNT=0x20 +CONFIG_BOOTSTAGE_FDT=y +CONFIG_BOOTSTAGE_STASH=y +CONFIG_BOOTSTAGE_STASH_ADDR=0x0 +CONFIG_BOOTSTAGE_STASH_SIZE=0x4096 +CONFIG_CONSOLE_RECORD=y +CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 +CONFIG_SILENT_CONSOLE=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_BOOTZ=y +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_ASKENV=y +CONFIG_CMD_GREPENV=y +CONFIG_CMD_MD5SUM=y +CONFIG_LOOPW=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_MX_CYCLIC=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_DEMO=y +CONFIG_CMD_GPT=y +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +CONFIG_CMD_I2C=y +CONFIG_CMD_USB=y +CONFIG_CMD_REMOTEPROC=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_TFTPPUT=y +CONFIG_CMD_TFTPSRV=y +CONFIG_CMD_RARP=y +CONFIG_CMD_CDP=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y +CONFIG_CMD_SOUND=y +CONFIG_CMD_QFW=y +CONFIG_CMD_BOOTSTAGE=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_TPM=y +CONFIG_CMD_TPM_TEST=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_MAC_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_OF_CONTROL=y +CONFIG_OF_HOSTFILE=y +CONFIG_NETCONSOLE=y +CONFIG_REGMAP=y +CONFIG_SPL_REGMAP=y +CONFIG_SYSCON=y +CONFIG_SPL_SYSCON=y +CONFIG_DEVRES=y +CONFIG_DEBUG_DEVRES=y +CONFIG_ADC=y +CONFIG_ADC_SANDBOX=y +CONFIG_CLK=y +CONFIG_CPU=y +CONFIG_DM_DEMO=y +CONFIG_DM_DEMO_SIMPLE=y +CONFIG_DM_DEMO_SHAPE=y +CONFIG_PM8916_GPIO=y +CONFIG_SANDBOX_GPIO=y +CONFIG_DM_I2C_COMPAT=y +CONFIG_I2C_CROS_EC_TUNNEL=y +CONFIG_I2C_CROS_EC_LDO=y +CONFIG_DM_I2C_GPIO=y +CONFIG_SYS_I2C_SANDBOX=y +CONFIG_I2C_MUX=y +CONFIG_SPL_I2C_MUX=y +CONFIG_I2C_ARB_GPIO_CHALLENGE=y +CONFIG_CROS_EC_KEYB=y +CONFIG_I8042_KEYB=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_SANDBOX_MBOX=y +CONFIG_MISC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_I2C=y +CONFIG_CROS_EC_LPC=y +CONFIG_CROS_EC_SANDBOX=y +CONFIG_CROS_EC_SPI=y +CONFIG_PWRSEQ=y +CONFIG_SPL_PWRSEQ=y +CONFIG_I2C_EEPROM=y +CONFIG_MMC_SANDBOX=y +CONFIG_SPI_FLASH_SANDBOX=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_SPI_FLASH_EON=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_SST=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_DM_ETH=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_DM_PCI_COMPAT=y +CONFIG_PCI_SANDBOX=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_ROCKCHIP_RK3036=y +CONFIG_PINCTRL_ROCKCHIP_RK3288=y +CONFIG_PINCTRL_SANDBOX=y +CONFIG_POWER_DOMAIN=y +CONFIG_SANDBOX_POWER_DOMAIN=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_ACT8846=y +CONFIG_DM_PMIC_PFUZE100=y +CONFIG_DM_PMIC_MAX77686=y +CONFIG_PMIC_PM8916=y +CONFIG_PMIC_RK808=y +CONFIG_PMIC_S2MPS11=y +CONFIG_DM_PMIC_SANDBOX=y +CONFIG_PMIC_S5M8767=y +CONFIG_PMIC_TPS65090=y +CONFIG_DM_REGULATOR=y +CONFIG_REGULATOR_ACT8846=y +CONFIG_DM_REGULATOR_PFUZE100=y +CONFIG_DM_REGULATOR_MAX77686=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_REGULATOR_RK808=y +CONFIG_REGULATOR_S5M8767=y +CONFIG_DM_REGULATOR_SANDBOX=y +CONFIG_REGULATOR_TPS65090=y +CONFIG_RAM=y +CONFIG_REMOTEPROC_SANDBOX=y +CONFIG_DM_RESET=y +CONFIG_SANDBOX_RESET=y +CONFIG_DM_RTC=y +CONFIG_SANDBOX_SERIAL=y +CONFIG_SOUND=y +CONFIG_SOUND_SANDBOX=y +CONFIG_SANDBOX_SPI=y +CONFIG_SPMI=y +CONFIG_SPMI_SANDBOX=y +CONFIG_SYSRESET=y +CONFIG_TIMER=y +CONFIG_TIMER_EARLY=y +CONFIG_SANDBOX_TIMER=y +CONFIG_TPM_TIS_SANDBOX=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EMUL=y +CONFIG_USB_STORAGE=y +CONFIG_USB_KEYBOARD=y +CONFIG_SYS_USB_EVENT_POLL=y +CONFIG_DM_VIDEO=y +CONFIG_CONSOLE_ROTATION=y +CONFIG_CONSOLE_TRUETYPE=y +CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y +CONFIG_VIDEO_SANDBOX_SDL=y +CONFIG_PHY=y +CONFIG_PHY_SANDBOX=y +CONFIG_CMD_DHRYSTONE=y +CONFIG_TPM=y +CONFIG_LZ4=y +CONFIG_ERRNO_STR=y +CONFIG_UNIT_TEST=y +CONFIG_UT_TIME=y +CONFIG_UT_DM=y +CONFIG_UT_ENV=y +CONFIG_DM_PWM=y +CONFIG_PWM_SANDBOX=y

Add a sandbox board to test the non-livetree build (i.e. with CONFIG_OF_FLAT disabled). This increases our build and test coverage.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
board/sandbox/MAINTAINERS | 7 ++ configs/sandbox_flattree_defconfig | 179 +++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 configs/sandbox_flattree_defconfig
Applied to u-boot-dm

The standard sandbox board cannot run the of-platdata test since it needs SPL. Also, we should test the flat tree version of sandbox.
Add these tests to the default test script.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/run | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/test/run b/test/run index a6dcf8f44f..b1649ee101 100755 --- a/test/run +++ b/test/run @@ -1,4 +1,10 @@ #!/bin/sh
-# Run all tests +# Run all tests that the standard sandbox build can support ./test/py/test.py --bd sandbox --build + +# Run tests which require sandbox_spl +./test/py/test.py --bd sandbox_spl --build -k test/py/tests/test_ofplatdata.py + +# Run tests for the flat DT version of sandbox +./test/py/test.py --bd sandbox_flattree --build

The standard sandbox board cannot run the of-platdata test since it needs SPL. Also, we should test the flat tree version of sandbox.
Add these tests to the default test script.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/run | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
Applied to u-boot-dm

These two functions have an of_ prefix which conflicts with naming used in of_addr. Rename them:
fdt_read_number fdt_support_bus_default_count_cells
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
arch/arm/cpu/armv8/fsl-layerscape/fdt.c | 4 ++-- arch/arm/mach-tegra/tegra186/nvtboot_mem.c | 4 ++-- common/fdt_support.c | 26 +++++++++++++------------- drivers/core/ofnode.c | 4 ++-- drivers/mtd/altera_qspi.c | 2 +- drivers/mtd/cfi_flash.c | 2 +- drivers/mtd/pic32_flash.c | 2 +- drivers/net/altera_tse.c | 2 +- include/fdt_support.h | 4 ++-- 9 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c index 05c4577753..f5f4840f19 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c @@ -79,13 +79,13 @@ remove_psci_node: puts("couldn't find /cpus node\n"); return; } - of_bus_default_count_cells(blob, off, &addr_cells, NULL); + fdt_support_default_count_cells(blob, off, &addr_cells, NULL);
off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); while (off != -FDT_ERR_NOTFOUND) { reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); if (reg) { - core_id = of_read_number(reg, addr_cells); + core_id = fdt_read_number(reg, addr_cells); if (core_id == 0 || (is_core_online(core_id))) { val = spin_tbl_addr; val += id_to_core(core_id) * diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c index bf1616628b..966cf9f1c4 100644 --- a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c +++ b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c @@ -60,9 +60,9 @@ int dram_init(void)
gd->ram_size = 0; for (i = 0; i < len; i++) { - ram_banks[i].start = of_read_number(prop, na); + ram_banks[i].start = fdt_read_number(prop, na); prop += na; - ram_banks[i].size = of_read_number(prop, ns); + ram_banks[i].size = fdt_read_number(prop, ns); prop += ns; gd->ram_size += ram_banks[i].size; } diff --git a/common/fdt_support.c b/common/fdt_support.c index c63b27bbb6..dfdc04dfba 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -1008,7 +1008,7 @@ struct of_bus { };
/* Default translator (generic bus) */ -void of_bus_default_count_cells(const void *blob, int parentoffset, +void fdt_support_default_count_cells(const void *blob, int parentoffset, int *addrc, int *sizec) { const fdt32_t *prop; @@ -1030,9 +1030,9 @@ static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range, { u64 cp, s, da;
- cp = of_read_number(range, na); - s = of_read_number(range + na + pna, ns); - da = of_read_number(addr, na); + cp = fdt_read_number(range, na); + s = fdt_read_number(range + na + pna, ns); + da = fdt_read_number(addr, na);
debug("OF: default map, cp=%" PRIu64 ", s=%" PRIu64 ", da=%" PRIu64 "\n", cp, s, da); @@ -1044,7 +1044,7 @@ static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range,
static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na) { - u64 a = of_read_number(addr, na); + u64 a = fdt_read_number(addr, na); memset(addr, 0, na * 4); a += offset; if (na > 1) @@ -1086,9 +1086,9 @@ static u64 of_bus_isa_map(fdt32_t *addr, const fdt32_t *range, if ((addr[0] ^ range[0]) & cpu_to_be32(1)) return OF_BAD_ADDR;
- cp = of_read_number(range + 1, na - 1); - s = of_read_number(range + na + pna, ns); - da = of_read_number(addr + 1, na - 1); + cp = fdt_read_number(range + 1, na - 1); + s = fdt_read_number(range + na + pna, ns); + da = fdt_read_number(addr + 1, na - 1);
debug("OF: ISA map, cp=%" PRIu64 ", s=%" PRIu64 ", da=%" PRIu64 "\n", cp, s, da); @@ -1122,7 +1122,7 @@ static struct of_bus of_busses[] = { { .name = "default", .addresses = "reg", - .count_cells = of_bus_default_count_cells, + .count_cells = fdt_support_default_count_cells, .map = of_bus_default_map, .translate = of_bus_default_translate, }, @@ -1173,7 +1173,7 @@ static int of_translate_one(const void *blob, int parent, struct of_bus *bus, */ ranges = fdt_getprop(blob, parent, rprop, &rlen); if (ranges == NULL || rlen == 0) { - offset = of_read_number(addr, na); + offset = fdt_read_number(addr, na); memset(addr, 0, pna * 4); debug("OF: no ranges, 1:1 translation\n"); goto finish; @@ -1253,7 +1253,7 @@ static u64 __of_translate_address(const void *blob, int node_offset, /* If root, we have finished */ if (parent < 0) { debug("OF: reached root node\n"); - result = of_read_number(addr, na); + result = fdt_read_number(addr, na); break; }
@@ -1666,8 +1666,8 @@ int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width, fdt32_t cells[4]; int i, addrc, sizec, ret;
- of_bus_default_count_cells(fdt, fdt_parent_offset(fdt, node), - &addrc, &sizec); + fdt_support_default_count_cells(fdt, fdt_parent_offset(fdt, node), + &addrc, &sizec); i = 0; if (addrc == 2) cells[i++] = cpu_to_fdt32(base_address >> 32); diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index ac312d6546..6805fe2424 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -457,8 +457,8 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
na = of_n_addr_cells(np); ns = of_n_addr_cells(np); - *sizep = of_read_number(prop + na, ns); - return of_read_number(prop, na); + *sizep = fdt_read_number(prop + na, ns); + return fdt_read_number(prop, na); } else { return fdtdec_get_addr_size(gd->fdt_blob, ofnode_to_offset(node), property, diff --git a/drivers/mtd/altera_qspi.c b/drivers/mtd/altera_qspi.c index e04964b558..fb33cef13f 100644 --- a/drivers/mtd/altera_qspi.c +++ b/drivers/mtd/altera_qspi.c @@ -362,7 +362,7 @@ static int altera_qspi_ofdata_to_platdata(struct udevice *dev) * match with reg-names. */ parent = fdt_parent_offset(blob, node); - of_bus_default_count_cells(blob, parent, &addrc, &sizec); + fdt_support_default_count_cells(blob, parent, &addrc, &sizec); list = fdt_getprop(blob, node, "reg-names", &len); if (!list) return -ENOENT; diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index d440f5ccd9..048a51785e 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -2448,7 +2448,7 @@ static int cfi_flash_probe(struct udevice *dev) int len, idx;
parent = fdt_parent_offset(blob, node); - of_bus_default_count_cells(blob, parent, &addrc, &sizec); + fdt_support_default_count_cells(blob, parent, &addrc, &sizec); /* decode regs, there may be multiple reg tuples. */ cell = fdt_getprop(blob, node, "reg", &len); if (!cell) diff --git a/drivers/mtd/pic32_flash.c b/drivers/mtd/pic32_flash.c index 8ed7874cc9..e1a8d3bc4b 100644 --- a/drivers/mtd/pic32_flash.c +++ b/drivers/mtd/pic32_flash.c @@ -384,7 +384,7 @@ static int pic32_flash_probe(struct udevice *dev) * match with reg-names. */ parent = fdt_parent_offset(blob, node); - of_bus_default_count_cells(blob, parent, &addrc, &sizec); + fdt_support_default_count_cells(blob, parent, &addrc, &sizec); list = fdt_getprop(blob, node, "reg-names", &len); if (!list) return -ENOENT; diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c index d4d17dd222..fb878d4e63 100644 --- a/drivers/net/altera_tse.c +++ b/drivers/net/altera_tse.c @@ -595,7 +595,7 @@ static int altera_tse_probe(struct udevice *dev) * match with reg-names. */ parent = fdt_parent_offset(blob, node); - of_bus_default_count_cells(blob, parent, &addrc, &sizec); + fdt_support_default_count_cells(blob, parent, &addrc, &sizec); list = fdt_getprop(blob, node, "reg-names", &len); if (!list) return -ENOENT; diff --git a/include/fdt_support.h b/include/fdt_support.h index 6fea5c7da0..5ef78cce6e 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -248,7 +248,7 @@ static inline int fdt_status_fail_by_alias(void *fdt, const char *alias) }
/* Helper to read a big number; size is in cells (not bytes) */ -static inline u64 of_read_number(const fdt32_t *cell, int size) +static inline u64 fdt_read_number(const fdt32_t *cell, int size) { u64 r = 0; while (size--) @@ -256,7 +256,7 @@ static inline u64 of_read_number(const fdt32_t *cell, int size) return r; }
-void of_bus_default_count_cells(const void *blob, int parentoffset, +void fdt_support_default_count_cells(const void *blob, int parentoffset, int *addrc, int *sizec); int ft_verify_fdt(void *fdt); int arch_fixup_memory_node(void *blob);

These two functions have an of_ prefix which conflicts with naming used in of_addr. Rename them:
fdt_read_number fdt_support_bus_default_count_cells
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
arch/arm/cpu/armv8/fsl-layerscape/fdt.c | 4 ++-- arch/arm/mach-tegra/tegra186/nvtboot_mem.c | 4 ++-- common/fdt_support.c | 26 +++++++++++++------------- drivers/core/ofnode.c | 4 ++-- drivers/mtd/altera_qspi.c | 2 +- drivers/mtd/cfi_flash.c | 2 +- drivers/mtd/pic32_flash.c | 2 +- drivers/net/altera_tse.c | 2 +- include/fdt_support.h | 4 ++-- 9 files changed, 25 insertions(+), 25 deletions(-)
Applied to u-boot-dm

Add some definitions and helpers for livetree in the main of.h header file. These include:
- reading multi-cell integers - default number of address/size cells - functions for comparing names
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/ofnode.c | 4 ++-- include/dm/of.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 6805fe2424..ac312d6546 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -457,8 +457,8 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
na = of_n_addr_cells(np); ns = of_n_addr_cells(np); - *sizep = fdt_read_number(prop + na, ns); - return fdt_read_number(prop, na); + *sizep = of_read_number(prop + na, ns); + return of_read_number(prop, na); } else { return fdtdec_get_addr_size(gd->fdt_blob, ofnode_to_offset(node), property, diff --git a/include/dm/of.h b/include/dm/of.h index 6b5afab1c1..d4d941e75c 100644 --- a/include/dm/of.h +++ b/include/dm/of.h @@ -103,4 +103,40 @@ static inline bool of_live_active(void) } #endif
+#define OF_BAD_ADDR ((u64)-1) + +static inline const char *of_node_full_name(const struct device_node *np) +{ + return np ? np->full_name : "<no-node>"; +} + +/* Default #address and #size cells */ +#if !defined(OF_ROOT_NODE_ADDR_CELLS_DEFAULT) +#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 +#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 +#endif + +/* Default string compare functions */ +#if !defined(of_compat_cmp) +#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) +#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) +#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) +#endif + +/* Helper to read a big number; size is in cells (not bytes) */ +static inline u64 of_read_number(const __be32 *cell, int size) +{ + u64 r = 0; + while (size--) + r = (r << 32) | be32_to_cpu(*(cell++)); + return r; +} + +/* Like of_read_number, but we want an unsigned long result */ +static inline unsigned long of_read_ulong(const __be32 *cell, int size) +{ + /* toss away upper bits if unsigned long is smaller than u64 */ + return of_read_number(cell, size); +} + #endif

Add some definitions and helpers for livetree in the main of.h header file. These include:
- reading multi-cell integers - default number of address/size cells - functions for comparing names
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/core/ofnode.c | 4 ++-- include/dm/of.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-)
Applied to u-boot-dm

This functions works like strchr() but returns the end of the string if the character is not found. Add an implementation of this.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/linux/string.h | 13 +++++++++++++ lib/string.c | 8 ++++++++ 2 files changed, 21 insertions(+)
diff --git a/include/linux/string.h b/include/linux/string.h index 091ccab395..718c3720a1 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -50,6 +50,19 @@ extern int strncasecmp(const char *s1, const char *s2, __kernel_size_t len); #ifndef __HAVE_ARCH_STRCHR extern char * strchr(const char *,int); #endif + +/** + * strchrnul() - return position of a character in the string, or end of string + * + * The strchrnul() function is like strchr() except that if c is not found + * in s, then it returns a pointer to the nul byte at the end of s, rather than + * NULL + * @s: string to search + * @c: character to search for + * @return position of @c in @s, or end of @s if not found + */ +const char *strchrnul(const char *s, int c); + #ifndef __HAVE_ARCH_STRRCHR extern char * strrchr(const char *,int); #endif diff --git a/lib/string.c b/lib/string.c index e94021c468..e6e749b80b 100644 --- a/lib/string.c +++ b/lib/string.c @@ -230,6 +230,14 @@ char * strchr(const char * s, int c) } #endif
+const char *strchrnul(const char *s, int c) +{ + for (; *s != (char)c; ++s) + if (*s == '\0') + break; + return s; +} + #ifndef __HAVE_ARCH_STRRCHR /** * strrchr - Find the last occurrence of a character in a string

This functions works like strchr() but returns the end of the string if the character is not found. Add an implementation of this.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/linux/string.h | 13 +++++++++++++ lib/string.c | 8 ++++++++ 2 files changed, 21 insertions(+)
Applied to u-boot-dm

Add an implementation of strcspn() which returns the number of initial characters that do not match any in a rejection list.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/linux/string.h | 15 +++++++++++++++ lib/string.c | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+)
diff --git a/include/linux/string.h b/include/linux/string.h index 718c3720a1..3606620739 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -76,6 +76,21 @@ extern __kernel_size_t strlen(const char *); #ifndef __HAVE_ARCH_STRNLEN extern __kernel_size_t strnlen(const char *,__kernel_size_t); #endif + +#ifndef __HAVE_ARCH_STRCSPN +/** + * strcspn() - find span of string without given characters + * + * Calculates the length of the initial segment of @s which consists entirely + * of bsytes not in reject. + * + * @s: string to search + * @reject: strings which cause the search to halt + * @return number of characters at the start of @s which are not in @reject + */ +size_t strcspn(const char *s, const char *reject); +#endif + #ifndef __HAVE_ARCH_STRDUP extern char * strdup(const char *); #endif diff --git a/lib/string.c b/lib/string.c index e6e749b80b..c4ca944bb4 100644 --- a/lib/string.c +++ b/lib/string.c @@ -286,6 +286,30 @@ size_t strnlen(const char * s, size_t count) } #endif
+#ifndef __HAVE_ARCH_STRCSPN +/** + * strcspn - Calculate the length of the initial substring of @s which does + * not contain letters in @reject + * @s: The string to be searched + * @reject: The string to avoid + */ +size_t strcspn(const char *s, const char *reject) +{ + const char *p; + const char *r; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) { + for (r = reject; *r != '\0'; ++r) { + if (*p == *r) + return count; + } + ++count; + } + return count; +} +#endif + #ifndef __HAVE_ARCH_STRDUP char * strdup(const char *s) {

Add an implementation of strcspn() which returns the number of initial characters that do not match any in a rejection list.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/linux/string.h | 15 +++++++++++++++ lib/string.c | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+)
Applied to u-boot-dm

Update the i2c uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/i2c/i2c-uclass.c | 28 +++++++++++++--------------- include/i2c.h | 3 +-- 2 files changed, 14 insertions(+), 17 deletions(-)
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index f3184c71d9..1397f34dda 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -7,7 +7,6 @@ #include <common.h> #include <dm.h> #include <errno.h> -#include <fdtdec.h> #include <i2c.h> #include <malloc.h> #include <dm/device-internal.h> @@ -467,18 +466,20 @@ int i2c_deblock(struct udevice *bus) }
#if CONFIG_IS_ENABLED(OF_CONTROL) -int i2c_chip_ofdata_to_platdata(const void *blob, int node, - struct dm_i2c_chip *chip) +int i2c_chip_ofdata_to_platdata(struct udevice *dev, struct dm_i2c_chip *chip) { - chip->offset_len = fdtdec_get_int(gd->fdt_blob, node, - "u-boot,i2c-offset-len", 1); + int addr; + + chip->offset_len = dev_read_u32_default(dev, "u-boot,i2c-offset-len", + 1); chip->flags = 0; - chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1); - if (chip->chip_addr == -1) { - debug("%s: I2C Node '%s' has no 'reg' property\n", __func__, - fdt_get_name(blob, node, NULL)); + addr = dev_read_u32_default(dev, "reg", -1); + if (addr == -1) { + debug("%s: I2C Node '%s' has no 'reg' property %s\n", __func__, + dev_read_name(dev), dev->name); return -EINVAL; } + chip->chip_addr = addr;
return 0; } @@ -489,8 +490,7 @@ static int i2c_post_probe(struct udevice *dev) #if CONFIG_IS_ENABLED(OF_CONTROL) struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
- i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "clock-frequency", 100000); + i2c->speed_hz = dev_read_u32_default(dev, "clock-frequency", 100000);
return dm_i2c_set_bus_speed(dev, i2c->speed_hz); #else @@ -503,11 +503,9 @@ static int i2c_child_post_bind(struct udevice *dev) #if CONFIG_IS_ENABLED(OF_CONTROL) struct dm_i2c_chip *plat = dev_get_parent_platdata(dev);
- if (dev_of_offset(dev) == -1) + if (!dev_of_valid(dev)) return 0; - - return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev_of_offset(dev), - plat); + return i2c_chip_ofdata_to_platdata(dev, plat); #else return 0; #endif diff --git a/include/i2c.h b/include/i2c.h index a88cc7cddf..d0950b5d01 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -525,8 +525,7 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len, * @node: Node offset to read from * @spi: Place to put the decoded information */ -int i2c_chip_ofdata_to_platdata(const void *blob, int node, - struct dm_i2c_chip *chip); +int i2c_chip_ofdata_to_platdata(struct udevice *dev, struct dm_i2c_chip *chip);
/** * i2c_dump_msgs() - Dump a list of I2C messages

Update the i2c uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/i2c/i2c-uclass.c | 28 +++++++++++++--------------- include/i2c.h | 3 +-- 2 files changed, 14 insertions(+), 17 deletions(-)
Applied to u-boot-dm

We should not be including a PMIC header file in the board config. Move it to a C file.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: - Add new patch to move pmic header out of config file
Changes in v2: None
board/samsung/common/misc.c | 1 + include/configs/trats2.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/board/samsung/common/misc.c b/board/samsung/common/misc.c index dc4dead20b..3a8e807736 100644 --- a/board/samsung/common/misc.c +++ b/board/samsung/common/misc.c @@ -18,6 +18,7 @@ #include <asm/gpio.h> #include <linux/input.h> #include <dm.h> +#include <power/max77686_pmic.h> #include <power/pmic.h> #include <mmc.h>
diff --git a/include/configs/trats2.h b/include/configs/trats2.h index 6a4604ce93..927d48255c 100644 --- a/include/configs/trats2.h +++ b/include/configs/trats2.h @@ -169,7 +169,6 @@
/* Download menu - definitions for check keys */ #ifndef __ASSEMBLY__ -#include <power/max77686_pmic.h>
#define KEY_PWR_PMIC_NAME "MAX77686_PMIC" #define KEY_PWR_STATUS_REG MAX77686_REG_PMIC_STATUS1

We should not be including a PMIC header file in the board config. Move it to a C file.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: - Add new patch to move pmic header out of config file
Changes in v2: None
board/samsung/common/misc.c | 1 + include/configs/trats2.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-)
Applied to u-boot-dm

Update the pmic uclass and all pmics to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/pmic/act8846.c | 8 +++----- drivers/power/pmic/lp873x.c | 12 +++++------- drivers/power/pmic/max77686.c | 8 +++----- drivers/power/pmic/palmas.c | 16 +++++++--------- drivers/power/pmic/pfuze100.c | 8 +++----- drivers/power/pmic/pmic-uclass.c | 22 ++++++++++------------ drivers/power/pmic/rk8xx.c | 8 +++----- drivers/power/pmic/s5m8767.c | 7 +++---- drivers/power/pmic/sandbox.c | 2 +- drivers/power/pmic/tps65090.c | 8 +++----- include/power/pmic.h | 2 +- 11 files changed, 42 insertions(+), 59 deletions(-)
diff --git a/drivers/power/pmic/act8846.c b/drivers/power/pmic/act8846.c index 15da12edea..a6b0940956 100644 --- a/drivers/power/pmic/act8846.c +++ b/drivers/power/pmic/act8846.c @@ -48,13 +48,11 @@ static int act8846_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
static int act8846_bind(struct udevice *dev) { - const void *blob = gd->fdt_blob; - int regulators_node; + ofnode regulators_node; int children;
- regulators_node = fdt_subnode_offset(blob, dev_of_offset(dev), - "regulators"); - if (regulators_node <= 0) { + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { debug("%s: %s regulators subnode not found!", __func__, dev->name); return -ENXIO; diff --git a/drivers/power/pmic/lp873x.c b/drivers/power/pmic/lp873x.c index d8f30df371..f505468313 100644 --- a/drivers/power/pmic/lp873x.c +++ b/drivers/power/pmic/lp873x.c @@ -46,15 +46,13 @@ static int lp873x_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
static int lp873x_bind(struct udevice *dev) { - int regulators_node; - const void *blob = gd->fdt_blob; + ofnode regulators_node; int children; - int node = dev_of_offset(dev);
- regulators_node = fdt_subnode_offset(blob, node, "regulators"); - - if (regulators_node <= 0) { - printf("%s: %s reg subnode not found!", __func__, dev->name); + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!", __func__, + dev->name); return -ENXIO; }
diff --git a/drivers/power/pmic/max77686.c b/drivers/power/pmic/max77686.c index 8295fab3f0..ceca9f96a7 100644 --- a/drivers/power/pmic/max77686.c +++ b/drivers/power/pmic/max77686.c @@ -50,13 +50,11 @@ static int max77686_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
static int max77686_bind(struct udevice *dev) { - int regulators_node; - const void *blob = gd->fdt_blob; + ofnode regulators_node; int children;
- regulators_node = fdt_subnode_offset(blob, dev_of_offset(dev), - "voltage-regulators"); - if (regulators_node <= 0) { + regulators_node = dev_read_subnode(dev, "voltage-regulators"); + if (!ofnode_valid(regulators_node)) { debug("%s: %s regulators subnode not found!", __func__, dev->name); return -ENXIO; diff --git a/drivers/power/pmic/palmas.c b/drivers/power/pmic/palmas.c index f5a23073c4..804c0d13a0 100644 --- a/drivers/power/pmic/palmas.c +++ b/drivers/power/pmic/palmas.c @@ -46,17 +46,15 @@ static int palmas_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
static int palmas_bind(struct udevice *dev) { - int pmic_node = -1, regulators_node; - const void *blob = gd->fdt_blob; + ofnode pmic_node = ofnode_null(), regulators_node; + ofnode subnode; int children; - int node = dev_of_offset(dev); - int subnode, len;
- fdt_for_each_subnode(subnode, blob, node) { + dev_for_each_subnode(subnode, dev) { const char *name; char *temp;
- name = fdt_get_name(blob, subnode, &len); + name = ofnode_get_name(subnode); temp = strstr(name, "pmic"); if (temp) { pmic_node = subnode; @@ -64,14 +62,14 @@ static int palmas_bind(struct udevice *dev) } }
- if (pmic_node <= 0) { + if (!ofnode_valid(pmic_node)) { debug("%s: %s pmic subnode not found!", __func__, dev->name); return -ENXIO; }
- regulators_node = fdt_subnode_offset(blob, pmic_node, "regulators"); + regulators_node = ofnode_find_subnode(pmic_node, "regulators");
- if (regulators_node <= 0) { + if (!ofnode_valid(regulators_node)) { debug("%s: %s reg subnode not found!", __func__, dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/pfuze100.c b/drivers/power/pmic/pfuze100.c index 90a43f2fe5..5f361c7696 100644 --- a/drivers/power/pmic/pfuze100.c +++ b/drivers/power/pmic/pfuze100.c @@ -52,13 +52,11 @@ static int pfuze100_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
static int pfuze100_bind(struct udevice *dev) { + ofnode regulators_node; int children; - int regulators_node; - const void *blob = gd->fdt_blob;
- regulators_node = fdt_subnode_offset(blob, dev_of_offset(dev), - "regulators"); - if (regulators_node <= 0) { + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { debug("%s: %s regulators subnode not found!", __func__, dev->name); return -ENXIO; diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c index 0f7fa517f9..953bbe5026 100644 --- a/drivers/power/pmic/pmic-uclass.c +++ b/drivers/power/pmic/pmic-uclass.c @@ -19,29 +19,27 @@ DECLARE_GLOBAL_DATA_PTR;
#if CONFIG_IS_ENABLED(PMIC_CHILDREN) -int pmic_bind_children(struct udevice *pmic, int offset, +int pmic_bind_children(struct udevice *pmic, ofnode parent, const struct pmic_child_info *child_info) { const struct pmic_child_info *info; - const void *blob = gd->fdt_blob; struct driver *drv; struct udevice *child; const char *node_name; int bind_count = 0; - int node; + ofnode node; int prefix_len; int ret;
debug("%s for '%s' at node offset: %d\n", __func__, pmic->name, dev_of_offset(pmic));
- for (node = fdt_first_subnode(blob, offset); - node > 0; - node = fdt_next_subnode(blob, node)) { - node_name = fdt_get_name(blob, node, NULL); + for (node = ofnode_first_subnode(parent); + ofnode_valid(node); + node = ofnode_next_subnode(node)) { + node_name = ofnode_get_name(node);
- debug("* Found child node: '%s' at offset:%d\n", node_name, - node); + debug("* Found child node: '%s'\n", node_name);
child = NULL; for (info = child_info; info->prefix && info->driver; info++) { @@ -60,8 +58,8 @@ int pmic_bind_children(struct udevice *pmic, int offset,
debug(" - found child driver: '%s'\n", drv->name);
- ret = device_bind(pmic, drv, node_name, NULL, - node, &child); + ret = device_bind_with_driver_data(pmic, drv, node_name, + 0, node, &child); if (ret) { debug(" - child binding error: %d\n", ret); continue; @@ -82,7 +80,7 @@ int pmic_bind_children(struct udevice *pmic, int offset, debug(" - compatible prefix not found\n"); }
- debug("Bound: %d childs for PMIC: '%s'\n", bind_count, pmic->name); + debug("Bound: %d children for PMIC: '%s'\n", bind_count, pmic->name); return bind_count; } #endif diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c index 394e2ff9db..09b9b54c62 100644 --- a/drivers/power/pmic/rk8xx.c +++ b/drivers/power/pmic/rk8xx.c @@ -57,13 +57,11 @@ static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len) #if CONFIG_IS_ENABLED(PMIC_CHILDREN) static int rk8xx_bind(struct udevice *dev) { - const void *blob = gd->fdt_blob; - int regulators_node; + ofnode regulators_node; int children;
- regulators_node = fdt_subnode_offset(blob, dev_of_offset(dev), - "regulators"); - if (regulators_node <= 0) { + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { debug("%s: %s regulators subnode not found!", __func__, dev->name); return -ENXIO; diff --git a/drivers/power/pmic/s5m8767.c b/drivers/power/pmic/s5m8767.c index 25d673b998..f8ae5ea2db 100644 --- a/drivers/power/pmic/s5m8767.c +++ b/drivers/power/pmic/s5m8767.c @@ -54,12 +54,11 @@ int s5m8767_enable_32khz_cp(struct udevice *dev)
static int s5m8767_bind(struct udevice *dev) { - int node; - const void *blob = gd->fdt_blob; int children; + ofnode node;
- node = fdt_subnode_offset(blob, dev_of_offset(dev), "regulators"); - if (node <= 0) { + node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(node)) { debug("%s: %s regulators subnode not found!", __func__, dev->name); return -ENXIO; diff --git a/drivers/power/pmic/sandbox.c b/drivers/power/pmic/sandbox.c index b4e412eb3e..6763303c66 100644 --- a/drivers/power/pmic/sandbox.c +++ b/drivers/power/pmic/sandbox.c @@ -51,7 +51,7 @@ static int sandbox_pmic_read(struct udevice *dev, uint reg,
static int sandbox_pmic_bind(struct udevice *dev) { - if (!pmic_bind_children(dev, dev_of_offset(dev), pmic_children_info)) + if (!pmic_bind_children(dev, dev_ofnode(dev), pmic_children_info)) error("%s:%d PMIC: %s - no child found!", __func__, __LINE__, dev->name);
diff --git a/drivers/power/pmic/tps65090.c b/drivers/power/pmic/tps65090.c index b30a7f08e9..4565e3b54c 100644 --- a/drivers/power/pmic/tps65090.c +++ b/drivers/power/pmic/tps65090.c @@ -52,13 +52,11 @@ static int tps65090_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
static int tps65090_bind(struct udevice *dev) { - int regulators_node; - const void *blob = gd->fdt_blob; + ofnode regulators_node; int children;
- regulators_node = fdt_subnode_offset(blob, dev_of_offset(dev), - "regulators"); - if (regulators_node <= 0) { + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { debug("%s: %s regulators subnode not found!", __func__, dev->name); return -ENXIO; diff --git a/include/power/pmic.h b/include/power/pmic.h index e0b2e129dd..4b34316427 100644 --- a/include/power/pmic.h +++ b/include/power/pmic.h @@ -226,7 +226,7 @@ struct pmic_child_info { * buck2 { ... }; * }; */ -int pmic_bind_children(struct udevice *pmic, int offset, +int pmic_bind_children(struct udevice *pmic, ofnode parent, const struct pmic_child_info *child_info);
/**

Update the pmic uclass and all pmics to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/pmic/act8846.c | 8 +++----- drivers/power/pmic/lp873x.c | 12 +++++------- drivers/power/pmic/max77686.c | 8 +++----- drivers/power/pmic/palmas.c | 16 +++++++--------- drivers/power/pmic/pfuze100.c | 8 +++----- drivers/power/pmic/pmic-uclass.c | 22 ++++++++++------------ drivers/power/pmic/rk8xx.c | 8 +++----- drivers/power/pmic/s5m8767.c | 7 +++---- drivers/power/pmic/sandbox.c | 2 +- drivers/power/pmic/tps65090.c | 8 +++----- include/power/pmic.h | 2 +- 11 files changed, 42 insertions(+), 59 deletions(-)
Applied to u-boot-dm

Update this driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/pmic/i2c_pmic_emul.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/power/pmic/i2c_pmic_emul.c b/drivers/power/pmic/i2c_pmic_emul.c index 4f92e3dad8..2d35d09d45 100644 --- a/drivers/power/pmic/i2c_pmic_emul.c +++ b/drivers/power/pmic/i2c_pmic_emul.c @@ -6,7 +6,6 @@ */
#include <common.h> -#include <fdtdec.h> #include <errno.h> #include <dm.h> #include <i2c.h> @@ -108,9 +107,8 @@ static int sandbox_i2c_pmic_ofdata_to_platdata(struct udevice *emul)
debug("%s:%d Setting PMIC default registers\n", __func__, __LINE__);
- reg_defaults = fdtdec_locate_byte_array(gd->fdt_blob, - dev_of_offset(emul), "reg-defaults", - SANDBOX_PMIC_REG_COUNT); + reg_defaults = dev_read_u8_array_ptr(emul, "reg-defaults", + SANDBOX_PMIC_REG_COUNT);
if (!reg_defaults) { error("Property "reg-defaults" not found for device: %s!",

Update this driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/pmic/i2c_pmic_emul.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
Applied to u-boot-dm

Update the regulator uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/regulator/regulator-uclass.c | 39 ++++++++++++------------------ 1 file changed, 16 insertions(+), 23 deletions(-)
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 2e0b5ed307..a42f80bb2b 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -4,8 +4,8 @@ * * SPDX-License-Identifier: GPL-2.0+ */ + #include <common.h> -#include <fdtdec.h> #include <errno.h> #include <dm.h> #include <dm/uclass-internal.h> @@ -278,20 +278,16 @@ static bool regulator_name_is_unique(struct udevice *check_dev, static int regulator_post_bind(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; - int offset = dev_of_offset(dev); - const void *blob = gd->fdt_blob; const char *property = "regulator-name";
uc_pdata = dev_get_uclass_platdata(dev); - if (!uc_pdata) - return -ENXIO;
/* Regulator's mandatory constraint */ - uc_pdata->name = fdt_getprop(blob, offset, property, NULL); + uc_pdata->name = dev_read_string(dev, property); if (!uc_pdata->name) { - debug("%s: dev: %s has no property 'regulator-name'\n", - __func__, dev->name); - uc_pdata->name = fdt_get_name(blob, offset, NULL); + debug("%s: dev '%s' has no property '%s'\n", + __func__, dev->name, property); + uc_pdata->name = dev_read_name(dev); if (!uc_pdata->name) return -EINVAL; } @@ -299,7 +295,7 @@ static int regulator_post_bind(struct udevice *dev) if (regulator_name_is_unique(dev, uc_pdata->name)) return 0;
- debug(""%s" of dev: "%s", has nonunique value: "%s"", + debug("'%s' of dev: '%s', has nonunique value: '%s\n", property, dev->name, uc_pdata->name);
return -EINVAL; @@ -308,25 +304,22 @@ static int regulator_post_bind(struct udevice *dev) static int regulator_pre_probe(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; - int offset = dev_of_offset(dev);
uc_pdata = dev_get_uclass_platdata(dev); if (!uc_pdata) return -ENXIO;
/* Regulator's optional constraints */ - uc_pdata->min_uV = fdtdec_get_int(gd->fdt_blob, offset, - "regulator-min-microvolt", -ENODATA); - uc_pdata->max_uV = fdtdec_get_int(gd->fdt_blob, offset, - "regulator-max-microvolt", -ENODATA); - uc_pdata->min_uA = fdtdec_get_int(gd->fdt_blob, offset, - "regulator-min-microamp", -ENODATA); - uc_pdata->max_uA = fdtdec_get_int(gd->fdt_blob, offset, - "regulator-max-microamp", -ENODATA); - uc_pdata->always_on = fdtdec_get_bool(gd->fdt_blob, offset, - "regulator-always-on"); - uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset, - "regulator-boot-on"); + uc_pdata->min_uV = dev_read_u32_default(dev, "regulator-min-microvolt", + -ENODATA); + uc_pdata->max_uV = dev_read_u32_default(dev, "regulator-max-microvolt", + -ENODATA); + uc_pdata->min_uA = dev_read_u32_default(dev, "regulator-min-microamp", + -ENODATA); + uc_pdata->max_uA = dev_read_u32_default(dev, "regulator-max-microamp", + -ENODATA); + uc_pdata->always_on = dev_read_bool(dev, "regulator-always-on"); + uc_pdata->boot_on = dev_read_bool(dev, "regulator-boot-on");
/* Those values are optional (-ENODATA if unset) */ if ((uc_pdata->min_uV != -ENODATA) &&

Update the regulator uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/regulator/regulator-uclass.c | 39 ++++++++++++------------------ 1 file changed, 16 insertions(+), 23 deletions(-)
Applied to u-boot-dm

Update this driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/regulator/fixed.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index cd5213766d..656371b235 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -7,7 +7,6 @@ */
#include <common.h> -#include <fdtdec.h> #include <errno.h> #include <dm.h> #include <i2c.h> @@ -27,8 +26,7 @@ static int fixed_regulator_ofdata_to_platdata(struct udevice *dev) struct dm_regulator_uclass_platdata *uc_pdata; struct fixed_regulator_platdata *dev_pdata; struct gpio_desc *gpio; - const void *blob = gd->fdt_blob; - int node = dev_of_offset(dev), flags = GPIOD_IS_OUT; + int flags = GPIOD_IS_OUT; int ret;
dev_pdata = dev_get_platdata(dev); @@ -39,7 +37,7 @@ static int fixed_regulator_ofdata_to_platdata(struct udevice *dev) /* Set type to fixed */ uc_pdata->type = REGULATOR_TYPE_FIXED;
- if (fdtdec_get_bool(blob, node, "enable-active-high")) + if (dev_read_bool(dev, "enable-active-high")) flags |= GPIOD_IS_OUT_ACTIVE;
/* Get fixed regulator optional enable GPIO desc */ @@ -53,9 +51,8 @@ static int fixed_regulator_ofdata_to_platdata(struct udevice *dev) }
/* Get optional ramp up delay */ - dev_pdata->startup_delay_us = fdtdec_get_uint(gd->fdt_blob, - dev_of_offset(dev), - "startup-delay-us", 0); + dev_pdata->startup_delay_us = dev_read_u32_default(dev, + "startup-delay-us", 0);
return 0; } @@ -108,8 +105,11 @@ static int fixed_regulator_set_enable(struct udevice *dev, bool enable) struct fixed_regulator_platdata *dev_pdata = dev_get_platdata(dev); int ret;
+ debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__, + dev->name, enable, dev_pdata->startup_delay_us, + dm_gpio_is_valid(&dev_pdata->gpio)); /* Enable GPIO is optional */ - if (!dev_pdata->gpio.dev) { + if (!dm_gpio_is_valid(&dev_pdata->gpio)) { if (!enable) return -ENOSYS; return 0; @@ -124,6 +124,7 @@ static int fixed_regulator_set_enable(struct udevice *dev, bool enable)
if (enable && dev_pdata->startup_delay_us) udelay(dev_pdata->startup_delay_us); + debug("%s: done\n", __func__);
return 0; }

Update this driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/regulator/fixed.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
Applied to u-boot-dm

Update the mmc uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/mmc/mmc-uclass.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 91f6fc5753..994d2686f4 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -204,7 +204,8 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) #endif #ifndef CONFIG_SPL_BUILD /* Use the fixed index with aliase node's index */ - fdtdec_get_alias_seq(gd->fdt_blob, "mmc", dev_of_offset(dev), &devnum); + ret = dev_read_alias_seq(dev, &devnum); + debug("%s: alias ret=%d, devnum=%d\n", __func__, ret, devnum); #endif
ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC,

Update the mmc uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/mmc/mmc-uclass.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
Applied to u-boot-dm

Update the adc uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/adc/adc-uclass.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c index 3e28a5600b..a5ef722d21 100644 --- a/drivers/adc/adc-uclass.c +++ b/drivers/adc/adc-uclass.c @@ -345,12 +345,11 @@ nodev: static int adc_vdd_platdata_set(struct udevice *dev) { struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); - int ret, offset = dev_of_offset(dev); - const void *fdt = gd->fdt_blob; + int ret; char *prop;
prop = "vdd-polarity-negative"; - uc_pdata->vdd_polarity_negative = fdtdec_get_bool(fdt, offset, prop); + uc_pdata->vdd_polarity_negative = dev_read_bool(dev, prop);
ret = adc_vdd_platdata_update(dev); if (ret != -ENOENT) @@ -358,7 +357,7 @@ static int adc_vdd_platdata_set(struct udevice *dev)
/* No vdd-supply phandle. */ prop = "vdd-microvolts"; - uc_pdata->vdd_microvolts = fdtdec_get_int(fdt, offset, prop, -ENODATA); + uc_pdata->vdd_microvolts = dev_read_u32_default(dev, prop, -ENODATA);
return 0; } @@ -366,12 +365,11 @@ static int adc_vdd_platdata_set(struct udevice *dev) static int adc_vss_platdata_set(struct udevice *dev) { struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); - int ret, offset = dev_of_offset(dev); - const void *fdt = gd->fdt_blob; + int ret; char *prop;
prop = "vss-polarity-negative"; - uc_pdata->vss_polarity_negative = fdtdec_get_bool(fdt, offset, prop); + uc_pdata->vss_polarity_negative = dev_read_bool(dev, prop);
ret = adc_vss_platdata_update(dev); if (ret != -ENOENT) @@ -379,7 +377,7 @@ static int adc_vss_platdata_set(struct udevice *dev)
/* No vss-supply phandle. */ prop = "vss-microvolts"; - uc_pdata->vss_microvolts = fdtdec_get_int(fdt, offset, prop, -ENODATA); + uc_pdata->vss_microvolts = dev_read_u32_default(dev, prop, -ENODATA);
return 0; }

Update the adc uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/adc/adc-uclass.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
Applied to u-boot-dm

Update the usb uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/usb/host/usb-uclass.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 6eded4abad..110ddc92fa 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -683,20 +683,18 @@ int usb_detect_change(void) int usb_child_post_bind(struct udevice *dev) { struct usb_dev_platdata *plat = dev_get_parent_platdata(dev); - const void *blob = gd->fdt_blob; int val;
- if (dev_of_offset(dev) == -1) + if (!dev_of_valid(dev)) return 0;
/* We only support matching a few things */ - val = fdtdec_get_int(blob, dev_of_offset(dev), "usb,device-class", -1); + val = dev_read_u32_default(dev, "usb,device-class", -1); if (val != -1) { plat->id.match_flags |= USB_DEVICE_ID_MATCH_DEV_CLASS; plat->id.bDeviceClass = val; } - val = fdtdec_get_int(blob, dev_of_offset(dev), "usb,interface-class", - -1); + val = dev_read_u32_default(dev, "usb,interface-class", -1); if (val != -1) { plat->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS; plat->id.bInterfaceClass = val;

Update the usb uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/usb/host/usb-uclass.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
Applied to u-boot-dm

Update the sandbox flash and hub USB emulators to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/usb/emul/sandbox_flash.c | 4 +--- drivers/usb/emul/sandbox_hub.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/emul/sandbox_flash.c b/drivers/usb/emul/sandbox_flash.c index 9abb323745..73fa82b8e6 100644 --- a/drivers/usb/emul/sandbox_flash.c +++ b/drivers/usb/emul/sandbox_flash.c @@ -371,10 +371,8 @@ err: static int sandbox_flash_ofdata_to_platdata(struct udevice *dev) { struct sandbox_flash_plat *plat = dev_get_platdata(dev); - const void *blob = gd->fdt_blob;
- plat->pathname = fdt_getprop(blob, dev_of_offset(dev), - "sandbox,filepath", NULL); + plat->pathname = dev_read_string(dev, "sandbox,filepath");
return 0; } diff --git a/drivers/usb/emul/sandbox_hub.c b/drivers/usb/emul/sandbox_hub.c index f0939b19f4..9ffda9cc74 100644 --- a/drivers/usb/emul/sandbox_hub.c +++ b/drivers/usb/emul/sandbox_hub.c @@ -277,8 +277,7 @@ static int sandbox_child_post_bind(struct udevice *dev) { struct sandbox_hub_platdata *plat = dev_get_parent_platdata(dev);
- plat->port = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", - -1); + plat->port = dev_read_u32_default(dev, "reg", -1);
return 0; }

Update the sandbox flash and hub USB emulators to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/usb/emul/sandbox_flash.c | 4 +--- drivers/usb/emul/sandbox_hub.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-)
Applied to u-boot-dm

Update the xlate() method to use ofnode_phandle_args instead of the fdtdec variant. This will allow drivers to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/clk/at91/pmc.c | 2 +- drivers/clk/at91/pmc.h | 2 +- drivers/clk/clk-uclass.c | 7 ++++--- drivers/clk/clk_stm32f7.c | 3 +-- include/clk-uclass.h | 5 +++-- 5 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index f4ec5fcb5e..be1d11ed4e 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -87,7 +87,7 @@ int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name) return 0; }
-int at91_clk_of_xlate(struct clk *clk, struct fdtdec_phandle_args *args) +int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) { int periph;
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index f222fce11f..bd3caba48d 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -15,7 +15,7 @@ struct pmc_platdata { int at91_pmc_core_probe(struct udevice *dev); int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name);
-int at91_clk_of_xlate(struct clk *clk, struct fdtdec_phandle_args *args); +int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args); int at91_clk_probe(struct udevice *dev);
#endif diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 6fcfd6997c..f6194b60f9 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -38,7 +38,7 @@ int clk_get_by_index_platdata(struct udevice *dev, int index, } # else static int clk_of_xlate_default(struct clk *clk, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { debug("%s(clk=%p)\n", __func__, clk);
@@ -86,9 +86,10 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) ops = clk_dev_ops(dev_clk);
if (ops->of_xlate) - ret = ops->of_xlate(clk, &args); + ret = ops->of_xlate(clk, (struct ofnode_phandle_args *)&args); else - ret = clk_of_xlate_default(clk, &args); + ret = clk_of_xlate_default(clk, + (struct ofnode_phandle_args *)&args); if (ret) { debug("of_xlate() failed: %d\n", ret); return ret; diff --git a/drivers/clk/clk_stm32f7.c b/drivers/clk/clk_stm32f7.c index da3c204ff5..fcdc3c052b 100644 --- a/drivers/clk/clk_stm32f7.c +++ b/drivers/clk/clk_stm32f7.c @@ -252,8 +252,7 @@ static int stm32_clk_probe(struct udevice *dev) return 0; }
-static int stm32_clk_of_xlate(struct clk *clk, - struct fdtdec_phandle_args *args) +static int stm32_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) { debug("%s(clk=%p)\n", __func__, clk);
diff --git a/include/clk-uclass.h b/include/clk-uclass.h index 07c1065495..e7ea334c60 100644 --- a/include/clk-uclass.h +++ b/include/clk-uclass.h @@ -12,7 +12,8 @@ /* See clk.h for background documentation. */
#include <clk.h> -#include <fdtdec.h> + +struct ofnode_phandle_args;
/** * struct clk_ops - The functions that a clock driver must implement. @@ -37,7 +38,7 @@ struct clk_ops { * @return 0 if OK, or a negative error code. */ int (*of_xlate)(struct clk *clock, - struct fdtdec_phandle_args *args); + struct ofnode_phandle_args *args); /** * request - Request a translated clock. *

Update the xlate() method to use ofnode_phandle_args instead of the fdtdec variant. This will allow drivers to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/clk/at91/pmc.c | 2 +- drivers/clk/at91/pmc.h | 2 +- drivers/clk/clk-uclass.c | 7 ++++--- drivers/clk/clk_stm32f7.c | 3 +-- include/clk-uclass.h | 5 +++-- 5 files changed, 10 insertions(+), 9 deletions(-)
Applied to u-boot-dm

Update the clk uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/clk/clk-uclass.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index f6194b60f9..83b63288fb 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -58,23 +58,22 @@ static int clk_of_xlate_default(struct clk *clk, int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) { int ret; - struct fdtdec_phandle_args args; + struct ofnode_phandle_args args; struct udevice *dev_clk; struct clk_ops *ops;
debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk);
assert(clk); - ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), - "clocks", "#clock-cells", 0, index, - &args); + ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0, + index, &args); if (ret) { debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n", __func__, ret); return ret; }
- ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev_clk); + ret = uclass_get_device_by_ofnode(UCLASS_CLK, args.node, &dev_clk); if (ret) { debug("%s: uclass_get_device_by_of_offset failed: err=%d\n", __func__, ret); @@ -86,10 +85,9 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) ops = clk_dev_ops(dev_clk);
if (ops->of_xlate) - ret = ops->of_xlate(clk, (struct ofnode_phandle_args *)&args); + ret = ops->of_xlate(clk, &args); else - ret = clk_of_xlate_default(clk, - (struct ofnode_phandle_args *)&args); + ret = clk_of_xlate_default(clk, &args); if (ret) { debug("of_xlate() failed: %d\n", ret); return ret; @@ -105,8 +103,7 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
debug("%s(dev=%p, name=%s, clk=%p)\n", __func__, dev, name, clk);
- index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), - "clock-names", name); + index = dev_read_stringlist_search(dev, "clock-names", name); if (index < 0) { debug("fdt_stringlist_search() failed: %d\n", index); return index;

Update the clk uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/clk/clk-uclass.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
Applied to u-boot-dm

Update the fixed-rate clock driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/clk/clk_fixed_rate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index 1cac4bbb85..63565b6ed8 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -31,9 +31,8 @@ const struct clk_ops clk_fixed_rate_ops = { static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev) { #if !CONFIG_IS_ENABLED(OF_PLATDATA) - to_clk_fixed_rate(dev)->fixed_rate = - fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "clock-frequency", 0); + to_clk_fixed_rate(dev)->fixed_rate = dev_read_u32_default(dev, + "clock-frequency", 0); #endif
return 0;

Update the fixed-rate clock driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/clk/clk_fixed_rate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
Applied to u-boot-dm

We cannot access the device tree via an offset when running in livetree mode. Separate out that part of the bus' children tests and mark it as for the flat tree only.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/bus.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/test/dm/bus.c b/test/dm/bus.c index 6a2773565e..8ba75d4b7d 100644 --- a/test/dm/bus.c +++ b/test/dm/bus.c @@ -160,8 +160,21 @@ static int dm_test_bus_children_funcs(struct unit_test_state *uts) node = fdt_path_offset(blob, "/d-test"); ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
+ return 0; +} +DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_bus_children_of_offset(struct unit_test_state *uts) +{ + const void *blob = gd->fdt_blob; + struct udevice *bus, *dev; + int node; + + ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); + /* Find a valid child */ node = fdt_path_offset(blob, "/some-bus/c-test@1"); + ut_assert(node > 0); ut_assertok(device_find_child_by_of_offset(bus, node, &dev)); ut_assert(!(dev->flags & DM_FLAG_ACTIVATED)); ut_assertok(device_get_child_by_of_offset(bus, node, &dev)); @@ -169,7 +182,8 @@ static int dm_test_bus_children_funcs(struct unit_test_state *uts)
return 0; } -DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +DM_TEST(dm_test_bus_children_of_offset, + DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | DM_TESTF_FLAT_TREE);
/* Test that we can iterate through children */ static int dm_test_bus_children_iterators(struct unit_test_state *uts)

We cannot access the device tree via an offset when running in livetree mode. Separate out that part of the bus' children tests and mark it as for the flat tree only.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/bus.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
Applied to u-boot-dm

We cannot run this test with livetree since it uses device tree offsets. Mark it as flat tree only.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/test-fdt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index 3048a7b890..987a265ba9 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -265,4 +265,5 @@ static int dm_test_fdt_offset(struct unit_test_state *uts)
return 0; } -DM_TEST(dm_test_fdt_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +DM_TEST(dm_test_fdt_offset, + DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | DM_TESTF_FLAT_TREE);

We cannot run this test with livetree since it uses device tree offsets. Mark it as flat tree only.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/test-fdt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
Applied to u-boot-dm

Use ut_asserteq() to test equality since this gives a better error message on failure. Also make a few of the tests more specific.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/phy.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/test/dm/phy.c b/test/dm/phy.c index 811045fc0a..65b33fe68d 100644 --- a/test/dm/phy.c +++ b/test/dm/phy.c @@ -49,8 +49,8 @@ static int dm_test_phy_base(struct unit_test_state *uts)
/* Try to get a non-existing phy */ ut_asserteq(-ENODEV, uclass_get_device(UCLASS_PHY, 3, &dev)); - ut_assert(generic_phy_get_by_name(parent, "phy_not_existing", - &phy1_method1) < 0) + ut_asserteq(-ENODATA, generic_phy_get_by_name(parent, + "phy_not_existing", &phy1_method1));
return 0; } @@ -68,8 +68,11 @@ static int dm_test_phy_ops(struct unit_test_state *uts) "gen_phy_user", &parent));
ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1)); + ut_asserteq(0, phy1.id); ut_assertok(generic_phy_get_by_name(parent, "phy2", &phy2)); + ut_asserteq(1, phy2.id); ut_assertok(generic_phy_get_by_name(parent, "phy3", &phy3)); + ut_asserteq(0, phy3.id);
/* test normal operations */ ut_assertok(generic_phy_init(&phy1)); @@ -100,12 +103,12 @@ static int dm_test_phy_ops(struct unit_test_state *uts) /* PHY2 has a known problem with power off */ ut_assertok(generic_phy_init(&phy2)); ut_assertok(generic_phy_power_on(&phy2)); - ut_assert(generic_phy_power_off(&phy2) == -EIO); + ut_asserteq(-EIO, generic_phy_power_off(&phy2));
- /* PHY3 has a known problem with power off and power on*/ + /* PHY3 has a known problem with power off and power on */ ut_assertok(generic_phy_init(&phy3)); - ut_assert(generic_phy_power_off(&phy3) == -EIO); - ut_assert(generic_phy_power_off(&phy3) == -EIO); + ut_asserteq(-EIO, generic_phy_power_off(&phy3)); + ut_asserteq(-EIO, generic_phy_power_off(&phy3));
return 0; }

Use ut_asserteq() to test equality since this gives a better error message on failure. Also make a few of the tests more specific.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
test/dm/phy.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
Applied to u-boot-dm

Update the mailbox uclass to support livetree. Fix the xlate() method in all callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/mailbox/mailbox-uclass.c | 20 ++++++++------------ drivers/mailbox/tegra-hsp.c | 2 +- include/mailbox-uclass.h | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/drivers/mailbox/mailbox-uclass.c b/drivers/mailbox/mailbox-uclass.c index 38448de965..822ae5b45e 100644 --- a/drivers/mailbox/mailbox-uclass.c +++ b/drivers/mailbox/mailbox-uclass.c @@ -6,7 +6,6 @@
#include <common.h> #include <dm.h> -#include <fdtdec.h> #include <mailbox.h> #include <mailbox-uclass.h>
@@ -18,7 +17,7 @@ static inline struct mbox_ops *mbox_dev_ops(struct udevice *dev) }
static int mbox_of_xlate_default(struct mbox_chan *chan, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { debug("%s(chan=%p)\n", __func__, chan);
@@ -34,24 +33,22 @@ static int mbox_of_xlate_default(struct mbox_chan *chan,
int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan) { - struct fdtdec_phandle_args args; + struct ofnode_phandle_args args; int ret; struct udevice *dev_mbox; struct mbox_ops *ops;
debug("%s(dev=%p, index=%d, chan=%p)\n", __func__, dev, index, chan);
- ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), - "mboxes", "#mbox-cells", 0, - index, &args); + ret = dev_read_phandle_with_args(dev, "mboxes", "#mbox-cells", 0, index, + &args); if (ret) { - debug("%s: fdtdec_parse_phandle_with_args failed: %d\n", - __func__, ret); + debug("%s: dev_read_phandle_with_args failed: %d\n", __func__, + ret); return ret; }
- ret = uclass_get_device_by_of_offset(UCLASS_MAILBOX, args.node, - &dev_mbox); + ret = uclass_get_device_by_ofnode(UCLASS_MAILBOX, args.node, &dev_mbox); if (ret) { debug("%s: uclass_get_device_by_of_offset failed: %d\n", __func__, ret); @@ -85,8 +82,7 @@ int mbox_get_by_name(struct udevice *dev, const char *name,
debug("%s(dev=%p, name=%s, chan=%p)\n", __func__, dev, name, chan);
- index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), - "mbox-names", name); + index = dev_read_stringlist_search(dev, "mbox-names", name); if (index < 0) { debug("fdt_stringlist_search() failed: %d\n", index); return index; diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index b546ba2471..bd2ec411c7 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -72,7 +72,7 @@ static int tegra_hsp_db_id(ulong chan_id) }
static int tegra_hsp_of_xlate(struct mbox_chan *chan, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { debug("%s(chan=%p)\n", __func__, chan);
diff --git a/include/mailbox-uclass.h b/include/mailbox-uclass.h index 6ec62e5a0e..8a638b04c5 100644 --- a/include/mailbox-uclass.h +++ b/include/mailbox-uclass.h @@ -36,7 +36,7 @@ struct mbox_ops { * @return 0 if OK, or a negative error code. */ int (*of_xlate)(struct mbox_chan *chan, - struct fdtdec_phandle_args *args); + struct ofnode_phandle_args *args); /** * request - Request a translated channel. *

Update the mailbox uclass to support livetree. Fix the xlate() method in all callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/mailbox/mailbox-uclass.c | 20 ++++++++------------ drivers/mailbox/tegra-hsp.c | 2 +- include/mailbox-uclass.h | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-)
Applied to u-boot-dm

Update the phy uclass to support livetree. Fix the xlate() method which has no callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/phy/phy-uclass.c | 21 +++++++++------------ include/generic-phy.h | 3 +-- 2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 0d8bef76db..d8b8d58e44 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -17,7 +17,7 @@ static inline struct phy_ops *phy_dev_ops(struct udevice *dev) }
static int generic_phy_xlate_offs_flags(struct phy *phy, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { debug("%s(phy=%p)\n", __func__, phy);
@@ -31,14 +31,13 @@ static int generic_phy_xlate_offs_flags(struct phy *phy, else phy->id = 0;
- return 0; }
int generic_phy_get_by_index(struct udevice *dev, int index, struct phy *phy) { - struct fdtdec_phandle_args args; + struct ofnode_phandle_args args; struct phy_ops *ops; int ret; struct udevice *phydev; @@ -46,18 +45,17 @@ int generic_phy_get_by_index(struct udevice *dev, int index, debug("%s(dev=%p, index=%d, phy=%p)\n", __func__, dev, index, phy);
assert(phy); - ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), - "phys", "#phy-cells", 0, index, - &args); + ret = dev_read_phandle_with_args(dev, "phys", "#phy-cells", 0, index, + &args); if (ret) { - debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n", + debug("%s: dev_read_phandle_with_args failed: err=%d\n", __func__, ret); return ret; }
- ret = uclass_get_device_by_of_offset(UCLASS_PHY, args.node, &phydev); + ret = uclass_get_device_by_ofnode(UCLASS_PHY, args.node, &phydev); if (ret) { - debug("%s: uclass_get_device_by_of_offset failed: err=%d\n", + debug("%s: uclass_get_device_by_ofnode failed: err=%d\n", __func__, ret); return ret; } @@ -88,10 +86,9 @@ int generic_phy_get_by_name(struct udevice *dev, const char *phy_name,
debug("%s(dev=%p, name=%s, phy=%p)\n", __func__, dev, phy_name, phy);
- index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), - "phy-names", phy_name); + index = dev_read_stringlist_search(dev, "phy-names", phy_name); if (index < 0) { - debug("fdt_stringlist_search() failed: %d\n", index); + debug("dev_read_stringlist_search() failed: %d\n", index); return index; }
diff --git a/include/generic-phy.h b/include/generic-phy.h index d8cf0c9f6a..762704c208 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -50,8 +50,7 @@ struct phy_ops { * @args: The phy specifier values from device tree. * @return 0 if OK, or a negative error code. */ - int (*of_xlate)(struct phy *phy, - struct fdtdec_phandle_args *args); + int (*of_xlate)(struct phy *phy, struct ofnode_phandle_args *args);
/** * init - initialize the hardware.

Update the phy uclass to support livetree. Fix the xlate() method which has no callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/phy/phy-uclass.c | 21 +++++++++------------ include/generic-phy.h | 3 +-- 2 files changed, 10 insertions(+), 14 deletions(-)
Applied to u-boot-dm

Update the sandbox phy driver to support livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/phy/sandbox-phy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/phy/sandbox-phy.c b/drivers/phy/sandbox-phy.c index 9ad820c24c..867c6fe704 100644 --- a/drivers/phy/sandbox-phy.c +++ b/drivers/phy/sandbox-phy.c @@ -80,8 +80,7 @@ static int sandbox_phy_probe(struct udevice *dev)
priv->initialized = false; priv->on = false; - priv->broken = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), - "broken"); + priv->broken = dev_read_bool(dev, "broken");
return 0; }

Update the sandbox phy driver to support livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/phy/sandbox-phy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
Applied to u-boot-dm

Update the power domain uclass to support livetree. Fix the xlate() method which has no callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/domain/power-domain-uclass.c | 19 ++++++++----------- include/power-domain-uclass.h | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/drivers/power/domain/power-domain-uclass.c b/drivers/power/domain/power-domain-uclass.c index 3dabbe4ac0..1847a492a3 100644 --- a/drivers/power/domain/power-domain-uclass.c +++ b/drivers/power/domain/power-domain-uclass.c @@ -6,7 +6,6 @@
#include <common.h> #include <dm.h> -#include <fdtdec.h> #include <power-domain.h> #include <power-domain-uclass.h>
@@ -18,7 +17,7 @@ static inline struct power_domain_ops *power_domain_dev_ops(struct udevice *dev) }
static int power_domain_of_xlate_default(struct power_domain *power_domain, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { debug("%s(power_domain=%p)\n", __func__, power_domain);
@@ -34,27 +33,25 @@ static int power_domain_of_xlate_default(struct power_domain *power_domain,
int power_domain_get(struct udevice *dev, struct power_domain *power_domain) { - struct fdtdec_phandle_args args; + struct ofnode_phandle_args args; int ret; struct udevice *dev_power_domain; struct power_domain_ops *ops;
debug("%s(dev=%p, power_domain=%p)\n", __func__, dev, power_domain);
- ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), - "power-domains", - "#power-domain-cells", 0, 0, - &args); + ret = dev_read_phandle_with_args(dev, "power-domains", + "#power-domain-cells", 0, 0, &args); if (ret) { - debug("%s: fdtdec_parse_phandle_with_args failed: %d\n", + debug("%s: dev_read_phandle_with_args failed: %d\n", __func__, ret); return ret; }
- ret = uclass_get_device_by_of_offset(UCLASS_POWER_DOMAIN, args.node, - &dev_power_domain); + ret = uclass_get_device_by_ofnode(UCLASS_POWER_DOMAIN, args.node, + &dev_power_domain); if (ret) { - debug("%s: uclass_get_device_by_of_offset failed: %d\n", + debug("%s: uclass_get_device_by_ofnode failed: %d\n", __func__, ret); return ret; } diff --git a/include/power-domain-uclass.h b/include/power-domain-uclass.h index 5878021e32..802233d17f 100644 --- a/include/power-domain-uclass.h +++ b/include/power-domain-uclass.h @@ -40,7 +40,7 @@ struct power_domain_ops { * @return 0 if OK, or a negative error code. */ int (*of_xlate)(struct power_domain *power_domain, - struct fdtdec_phandle_args *args); + struct ofnode_phandle_args *args); /** * request - Request a translated power domain. *

Update the power domain uclass to support livetree. Fix the xlate() method which has no callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/power/domain/power-domain-uclass.c | 19 ++++++++----------- include/power-domain-uclass.h | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-)
Applied to u-boot-dm

Update the reset domain uclass to support livetree. Fix the xlate() method which has no callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/reset/reset-uclass.c | 21 ++++++++++----------- include/reset-uclass.h | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c index e92b24fa34..de3695ffaa 100644 --- a/drivers/reset/reset-uclass.c +++ b/drivers/reset/reset-uclass.c @@ -18,7 +18,7 @@ static inline struct reset_ops *reset_dev_ops(struct udevice *dev) }
static int reset_of_xlate_default(struct reset_ctl *reset_ctl, - struct fdtdec_phandle_args *args) + struct ofnode_phandle_args *args) { debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
@@ -35,7 +35,7 @@ static int reset_of_xlate_default(struct reset_ctl *reset_ctl, int reset_get_by_index(struct udevice *dev, int index, struct reset_ctl *reset_ctl) { - struct fdtdec_phandle_args args; + struct ofnode_phandle_args args; int ret; struct udevice *dev_reset; struct reset_ops *ops; @@ -43,20 +43,20 @@ int reset_get_by_index(struct udevice *dev, int index, debug("%s(dev=%p, index=%d, reset_ctl=%p)\n", __func__, dev, index, reset_ctl);
- ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), - "resets", "#reset-cells", 0, - index, &args); + ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0, + index, &args); if (ret) { - debug("%s: fdtdec_parse_phandle_with_args failed: %d\n", + debug("%s: fdtdec_parse_phandle_with_args() failed: %d\n", __func__, ret); return ret; }
- ret = uclass_get_device_by_of_offset(UCLASS_RESET, args.node, - &dev_reset); + ret = uclass_get_device_by_ofnode(UCLASS_RESET, args.node, + &dev_reset); if (ret) { - debug("%s: uclass_get_device_by_of_offset failed: %d\n", + debug("%s: uclass_get_device_by_ofnode() failed: %d\n", __func__, ret); + debug("%s %d\n", ofnode_get_name(args.node), args.args[0]); return ret; } ops = reset_dev_ops(dev_reset); @@ -88,8 +88,7 @@ int reset_get_by_name(struct udevice *dev, const char *name, debug("%s(dev=%p, name=%s, reset_ctl=%p)\n", __func__, dev, name, reset_ctl);
- index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), - "reset-names", name); + index = dev_read_stringlist_search(dev, "reset-names", name); if (index < 0) { debug("fdt_stringlist_search() failed: %d\n", index); return index; diff --git a/include/reset-uclass.h b/include/reset-uclass.h index 38c716ff89..50fbeb10d6 100644 --- a/include/reset-uclass.h +++ b/include/reset-uclass.h @@ -11,7 +11,7 @@
#include <reset.h>
-struct fdtdec_phandle_args; +struct ofnode_phandle_args; struct udevice;
/** @@ -38,7 +38,7 @@ struct reset_ops { * @return 0 if OK, or a negative error code. */ int (*of_xlate)(struct reset_ctl *reset_ctl, - struct fdtdec_phandle_args *args); + struct ofnode_phandle_args *args); /** * request - Request a translated reset control. *

Update the reset domain uclass to support livetree. Fix the xlate() method which has no callers.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/reset/reset-uclass.c | 21 ++++++++++----------- include/reset-uclass.h | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-)
Applied to u-boot-dm

Update the PCI uclass to support livetree. This mostly involves fixing the address decoding from the device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/pci/pci-uclass.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 504d7e3bb1..b36ef3338c 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -8,12 +8,11 @@ #include <common.h> #include <dm.h> #include <errno.h> -#include <fdtdec.h> #include <inttypes.h> #include <pci.h> #include <asm/io.h> -#include <dm/lists.h> #include <dm/device-internal.h> +#include <dm/lists.h> #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) #include <asm/fsp/fsp_support.h> #endif @@ -754,8 +753,8 @@ error: return ret; }
-static int decode_regions(struct pci_controller *hose, const void *blob, - int parent_node, int node) +static int decode_regions(struct pci_controller *hose, ofnode parent_node, + ofnode node) { int pci_addr_cells, addr_cells, size_cells; phys_addr_t base = 0, size; @@ -764,12 +763,12 @@ static int decode_regions(struct pci_controller *hose, const void *blob, int len; int i;
- prop = fdt_getprop(blob, node, "ranges", &len); + prop = ofnode_read_prop(node, "ranges", &len); if (!prop) return -EINVAL; - pci_addr_cells = fdt_address_cells(blob, node); - addr_cells = fdt_address_cells(blob, parent_node); - size_cells = fdt_size_cells(blob, node); + pci_addr_cells = ofnode_read_addr_cells(node); + addr_cells = ofnode_read_addr_cells(parent_node); + size_cells = ofnode_read_size_cells(node);
/* PCI addresses are always 3-cells */ len /= sizeof(u32); @@ -841,9 +840,8 @@ static int pci_uclass_pre_probe(struct udevice *bus) /* For bridges, use the top-level PCI controller */ if (!device_is_on_pci_bus(bus)) { hose->ctlr = bus; - ret = decode_regions(hose, gd->fdt_blob, - dev_of_offset(bus->parent), - dev_of_offset(bus)); + ret = decode_regions(hose, dev_ofnode(bus->parent), + dev_ofnode(bus)); if (ret) { debug("%s: Cannot decode regions\n", __func__); return ret; @@ -906,7 +904,7 @@ static int pci_uclass_child_post_bind(struct udevice *dev) struct fdt_pci_addr addr; int ret;
- if (dev_of_offset(dev) == -1) + if (!dev_of_valid(dev)) return 0;
/* @@ -914,8 +912,8 @@ static int pci_uclass_child_post_bind(struct udevice *dev) * just check the address. */ pplat = dev_get_parent_platdata(dev); - ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev), - FDT_PCI_SPACE_CONFIG, "reg", &addr); + ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG, "reg", + &addr);
if (ret) { if (ret != -ENOENT)

Update the PCI uclass to support livetree. This mostly involves fixing the address decoding from the device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/pci/pci-uclass.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-)
Applied to u-boot-dm

Update this driver so that it works with livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/misc/i2c_eeprom_emul.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c index 02de8d7df3..52aa7d69e9 100644 --- a/drivers/misc/i2c_eeprom_emul.c +++ b/drivers/misc/i2c_eeprom_emul.c @@ -9,7 +9,6 @@ #include <common.h> #include <dm.h> #include <errno.h> -#include <fdtdec.h> #include <i2c.h> #include <malloc.h> #include <asm/test.h> @@ -115,10 +114,8 @@ static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev) { struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
- plat->size = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "sandbox,size", 32); - plat->filename = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), - "sandbox,filename", NULL); + plat->size = dev_read_u32_default(dev, "sandbox,size", 32); + plat->filename = dev_read_string(dev, "sandbox,filename"); if (!plat->filename) { debug("%s: No filename for device '%s'\n", __func__, dev->name);

Update this driver so that it works with livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/misc/i2c_eeprom_emul.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
Applied to u-boot-dm

Update this driver and key_matrix to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/input/cros_ec_keyb.c | 24 ++++++++++++------------ drivers/input/key_matrix.c | 19 +++++++++---------- drivers/input/tegra-kbc.c | 3 +-- include/key_matrix.h | 3 +-- 4 files changed, 23 insertions(+), 26 deletions(-)
diff --git a/drivers/input/cros_ec_keyb.c b/drivers/input/cros_ec_keyb.c index 00381dcd72..6fa35a63dd 100644 --- a/drivers/input/cros_ec_keyb.c +++ b/drivers/input/cros_ec_keyb.c @@ -10,7 +10,6 @@ #include <cros_ec.h> #include <dm.h> #include <errno.h> -#include <fdtdec.h> #include <input.h> #include <keyboard.h> #include <key_matrix.h> @@ -161,15 +160,15 @@ int cros_ec_kbc_check(struct input_config *input) * @param config Configuration data read from fdt * @return 0 if ok, -1 on error */ -static int cros_ec_keyb_decode_fdt(const void *blob, int node, - struct cros_ec_keyb_priv *config) +static int cros_ec_keyb_decode_fdt(struct udevice *dev, + struct cros_ec_keyb_priv *config) { /* * Get keyboard rows and columns - at present we are limited to * 8 columns by the protocol (one byte per row scan) */ - config->key_rows = fdtdec_get_int(blob, node, "keypad,num-rows", 0); - config->key_cols = fdtdec_get_int(blob, node, "keypad,num-columns", 0); + config->key_rows = dev_read_u32_default(dev, "keypad,num-rows", 0); + config->key_cols = dev_read_u32_default(dev, "keypad,num-columns", 0); if (!config->key_rows || !config->key_cols || config->key_rows * config->key_cols / 8 > CROS_EC_KEYSCAN_COLS) { @@ -177,8 +176,8 @@ static int cros_ec_keyb_decode_fdt(const void *blob, int node, config->key_rows, config->key_cols); return -1; } - config->ghost_filter = fdtdec_get_bool(blob, node, - "google,needs-ghost-filter"); + config->ghost_filter = dev_read_bool(dev, "google,needs-ghost-filter"); + return 0; }
@@ -188,12 +187,13 @@ static int cros_ec_kbd_probe(struct udevice *dev) struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev); struct stdio_dev *sdev = &uc_priv->sdev; struct input_config *input = &uc_priv->input; - const void *blob = gd->fdt_blob; - int node = dev_of_offset(dev); int ret;
- if (cros_ec_keyb_decode_fdt(blob, node, priv)) - return -1; + ret = cros_ec_keyb_decode_fdt(dev, priv); + if (ret) { + debug("%s: Cannot decode node (ret=%d)\n", __func__, ret); + return -EINVAL; + } input_set_delays(input, KBC_REPEAT_DELAY_MS, KBC_REPEAT_RATE_MS); ret = key_matrix_init(&priv->matrix, priv->key_rows, priv->key_cols, priv->ghost_filter); @@ -201,7 +201,7 @@ static int cros_ec_kbd_probe(struct udevice *dev) debug("%s: cannot init key matrix\n", __func__); return ret; } - ret = key_matrix_decode_fdt(&priv->matrix, gd->fdt_blob, node); + ret = key_matrix_decode_fdt(dev, &priv->matrix); if (ret) { debug("%s: Could not decode key matrix from fdt\n", __func__); return ret; diff --git a/drivers/input/key_matrix.c b/drivers/input/key_matrix.c index 8867e4964e..cd5bce3613 100644 --- a/drivers/input/key_matrix.c +++ b/drivers/input/key_matrix.c @@ -8,7 +8,7 @@ */
#include <common.h> -#include <fdtdec.h> +#include <dm.h> #include <key_matrix.h> #include <malloc.h> #include <linux/input.h> @@ -105,7 +105,7 @@ int key_matrix_decode(struct key_matrix *config, struct key_matrix_key keys[], * @param pos Returns position of map_keycode, if found, else -1 * @return map Pointer to allocated map */ -static uchar *create_keymap(struct key_matrix *config, u32 *data, int len, +static uchar *create_keymap(struct key_matrix *config, const u32 *data, int len, int map_keycode, int *pos) { uchar *map; @@ -138,33 +138,32 @@ static uchar *create_keymap(struct key_matrix *config, u32 *data, int len, return map; }
-int key_matrix_decode_fdt(struct key_matrix *config, const void *blob, int node) +int key_matrix_decode_fdt(struct udevice *dev, struct key_matrix *config) { - const struct fdt_property *prop; + const u32 *prop; int proplen; uchar *plain_keycode;
- prop = fdt_get_property(blob, node, "linux,keymap", &proplen); + prop = dev_read_prop(dev, "linux,keymap", &proplen); /* Basic keymap is required */ if (!prop) { debug("%s: cannot find keycode-plain map\n", __func__); return -1; }
- plain_keycode = create_keymap(config, (u32 *)prop->data, - proplen, KEY_FN, &config->fn_pos); + plain_keycode = create_keymap(config, prop, proplen, KEY_FN, + &config->fn_pos); config->plain_keycode = plain_keycode; /* Conversion error -> fail */ if (!config->plain_keycode) return -1;
- prop = fdt_get_property(blob, node, "linux,fn-keymap", &proplen); + prop = dev_read_prop(dev, "linux,fn-keymap", &proplen); /* fn keymap is optional */ if (!prop) goto done;
- config->fn_keycode = create_keymap(config, (u32 *)prop->data, - proplen, -1, NULL); + config->fn_keycode = create_keymap(config, prop, proplen, -1, NULL); /* Conversion error -> fail */ if (!config->fn_keycode) { free(plain_keycode); diff --git a/drivers/input/tegra-kbc.c b/drivers/input/tegra-kbc.c index 836aba1f1b..cb5695784e 100644 --- a/drivers/input/tegra-kbc.c +++ b/drivers/input/tegra-kbc.c @@ -290,7 +290,6 @@ static int tegra_kbd_probe(struct udevice *dev) struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev); struct stdio_dev *sdev = &uc_priv->sdev; struct input_config *input = &uc_priv->input; - int node = dev_of_offset(dev); int ret;
priv->kbc = (struct kbc_tegra *)devfdt_get_addr(dev); @@ -306,7 +305,7 @@ static int tegra_kbd_probe(struct udevice *dev) debug("%s: Could not init key matrix: %d\n", __func__, ret); return ret; } - ret = key_matrix_decode_fdt(&priv->matrix, gd->fdt_blob, node); + ret = key_matrix_decode_fdt(dev, &priv->matrix); if (ret) { debug("%s: Could not decode key matrix from fdt: %d\n", __func__, ret); diff --git a/include/key_matrix.h b/include/key_matrix.h index 8db686040d..8dfa44de13 100644 --- a/include/key_matrix.h +++ b/include/key_matrix.h @@ -69,8 +69,7 @@ int key_matrix_decode(struct key_matrix *config, struct key_matrix_key *keys, * @param node Node containing compatible data * @return 0 if ok, -1 on error */ -int key_matrix_decode_fdt(struct key_matrix *config, const void *blob, - int node); +int key_matrix_decode_fdt(struct udevice *dev, struct key_matrix *config);
/** * Set up a new key matrix.

Update this driver and key_matrix to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/input/cros_ec_keyb.c | 24 ++++++++++++------------ drivers/input/key_matrix.c | 19 +++++++++---------- drivers/input/tegra-kbc.c | 3 +-- include/key_matrix.h | 3 +-- 4 files changed, 23 insertions(+), 26 deletions(-)
Applied to u-boot-dm

Update the SPI uclass to support a live device tree. Also adjust spi_slave_ofdata_to_platdata() to accept a device instead of a blob and offset.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/spi/spi-uclass.c | 31 ++++++++++++++----------------- include/spi.h | 2 +- 2 files changed, 15 insertions(+), 18 deletions(-)
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index c061c05443..e06a603ab1 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -7,7 +7,6 @@ #include <common.h> #include <dm.h> #include <errno.h> -#include <fdtdec.h> #include <malloc.h> #include <spi.h> #include <dm/device-internal.h> @@ -113,11 +112,10 @@ static int spi_child_post_bind(struct udevice *dev) { struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
- if (dev_of_offset(dev) == -1) + if (!dev_of_valid(dev)) return 0;
- return spi_slave_ofdata_to_platdata(gd->fdt_blob, dev_of_offset(dev), - plat); + return spi_slave_ofdata_to_platdata(dev, plat); } #endif
@@ -126,8 +124,7 @@ static int spi_post_probe(struct udevice *bus) #if !CONFIG_IS_ENABLED(OF_PLATDATA) struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
- spi->max_hz = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus), - "spi-max-frequency", 0); + spi->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 0); #endif #if defined(CONFIG_NEEDS_MANUAL_RELOC) struct dm_spi_ops *ops = spi_get_ops(bus); @@ -375,7 +372,7 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs, int ret;
ret = spi_get_bus_and_cs(busnum, cs, speed, mode, NULL, 0, &dev, - &slave); + &slave); if (ret) return NULL;
@@ -388,27 +385,27 @@ void spi_free_slave(struct spi_slave *slave) slave->dev = NULL; }
-int spi_slave_ofdata_to_platdata(const void *blob, int node, +int spi_slave_ofdata_to_platdata(struct udevice *dev, struct dm_spi_slave_platdata *plat) { int mode = 0; int value;
- plat->cs = fdtdec_get_int(blob, node, "reg", -1); - plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0); - if (fdtdec_get_bool(blob, node, "spi-cpol")) + plat->cs = dev_read_u32_default(dev, "reg", -1); + plat->max_hz = dev_read_u32_default(dev, "spi-max-frequency", 0); + if (dev_read_bool(dev, "spi-cpol")) mode |= SPI_CPOL; - if (fdtdec_get_bool(blob, node, "spi-cpha")) + if (dev_read_bool(dev, "spi-cpha")) mode |= SPI_CPHA; - if (fdtdec_get_bool(blob, node, "spi-cs-high")) + if (dev_read_bool(dev, "spi-cs-high")) mode |= SPI_CS_HIGH; - if (fdtdec_get_bool(blob, node, "spi-3wire")) + if (dev_read_bool(dev, "spi-3wire")) mode |= SPI_3WIRE; - if (fdtdec_get_bool(blob, node, "spi-half-duplex")) + if (dev_read_bool(dev, "spi-half-duplex")) mode |= SPI_PREAMBLE;
/* Device DUAL/QUAD mode */ - value = fdtdec_get_uint(blob, node, "spi-tx-bus-width", 1); + value = dev_read_u32_default(dev, "spi-tx-bus-width", 1); switch (value) { case 1: break; @@ -423,7 +420,7 @@ int spi_slave_ofdata_to_platdata(const void *blob, int node, break; }
- value = fdtdec_get_uint(blob, node, "spi-rx-bus-width", 1); + value = dev_read_u32_default(dev, "spi-rx-bus-width", 1); switch (value) { case 1: break; diff --git a/include/spi.h b/include/spi.h index deb65efdfb..8c4b882c54 100644 --- a/include/spi.h +++ b/include/spi.h @@ -562,7 +562,7 @@ int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp); * @node: Node offset to read from * @plat: Place to put the decoded information */ -int spi_slave_ofdata_to_platdata(const void *blob, int node, +int spi_slave_ofdata_to_platdata(struct udevice *dev, struct dm_spi_slave_platdata *plat);
/**

Update the SPI uclass to support a live device tree. Also adjust spi_slave_ofdata_to_platdata() to accept a device instead of a blob and offset.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/spi/spi-uclass.c | 31 ++++++++++++++----------------- include/spi.h | 2 +- 2 files changed, 15 insertions(+), 18 deletions(-)
Applied to u-boot-dm

This is not needed in this driver. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/i2c/sandbox_i2c.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c index 4696a1ae62..f5978fda29 100644 --- a/drivers/i2c/sandbox_i2c.c +++ b/drivers/i2c/sandbox_i2c.c @@ -9,7 +9,6 @@ #include <common.h> #include <dm.h> #include <errno.h> -#include <fdtdec.h> #include <i2c.h> #include <asm/test.h> #include <dm/lists.h>

This is not needed in this driver. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/i2c/sandbox_i2c.c | 1 - 1 file changed, 1 deletion(-)
Applied to u-boot-dm

This is not needed in this driver. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/rtc/i2c_rtc_emul.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c index 20827fdff1..0e06c97367 100644 --- a/drivers/rtc/i2c_rtc_emul.c +++ b/drivers/rtc/i2c_rtc_emul.c @@ -16,7 +16,6 @@
#include <common.h> #include <dm.h> -#include <fdtdec.h> #include <i2c.h> #include <os.h> #include <rtc.h>

This is not needed in this driver. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/rtc/i2c_rtc_emul.c | 1 - 1 file changed, 1 deletion(-)
Applied to u-boot-dm

Update the SPI flash uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/mtd/spi/spi_flash.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index ab7910bc14..0034a28d5f 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -914,14 +914,13 @@ static int set_quad_mode(struct spi_flash *flash, }
#if CONFIG_IS_ENABLED(OF_CONTROL) -int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) +int spi_flash_decode_fdt(struct spi_flash *flash) { #ifdef CONFIG_DM_SPI_FLASH fdt_addr_t addr; fdt_size_t size; - int node = dev_of_offset(flash->dev);
- addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); + addr = dev_read_addr_size(flash->dev, "memory-map", &size); if (addr == FDT_ADDR_T_NONE) { debug("%s: Cannot decode address\n", __func__); return 0; @@ -1081,7 +1080,7 @@ int spi_flash_scan(struct spi_flash *flash) #endif
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) - ret = spi_flash_decode_fdt(gd->fdt_blob, flash); + ret = spi_flash_decode_fdt(flash); if (ret) { debug("SF: FDT decode error\n"); return -EINVAL;

Update the SPI flash uclass to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/mtd/spi/spi_flash.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
Applied to u-boot-dm

Update this driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/mtd/spi/sandbox.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index a53f4ebc68..1ba6815232 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -515,11 +515,9 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, int sandbox_sf_ofdata_to_platdata(struct udevice *dev) { struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev); - const void *blob = gd->fdt_blob; - int node = dev_of_offset(dev);
- pdata->filename = fdt_getprop(blob, node, "sandbox,filename", NULL); - pdata->device_name = fdt_getprop(blob, node, "compatible", NULL); + pdata->filename = dev_read_string(dev, "sandbox,filename"); + pdata->device_name = dev_read_string(dev, "compatible"); if (!pdata->filename || !pdata->device_name) { debug("%s: Missing properties, filename=%s, device_name=%s\n", __func__, pdata->filename, pdata->device_name);

Update this driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/mtd/spi/sandbox.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
Applied to u-boot-dm

Update this driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/sysreset/sysreset_sandbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/sysreset/sysreset_sandbox.c b/drivers/sysreset/sysreset_sandbox.c index 0c4e2e1a93..12b3e5f86e 100644 --- a/drivers/sysreset/sysreset_sandbox.c +++ b/drivers/sysreset/sysreset_sandbox.c @@ -41,7 +41,7 @@ static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_t type) * (see the U_BOOT_DEVICE() declaration below) should not do anything. * If we are that device, return an error. */ - if (state->fdt_fname && dev_of_offset(dev) == -1) + if (state->fdt_fname && !dev_of_valid(dev)) return -ENODEV;
switch (type) {

Update this driver to support a live device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/sysreset/sysreset_sandbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Applied to u-boot-dm

Line up this backslash with all the others.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/test/ut.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/test/ut.h b/include/test/ut.h index 85434d785a..d176df58c7 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -104,7 +104,7 @@ void ut_failf(struct unit_test_state *uts, const char *fname, int line, }
/* Assert that a pointer is not an error pointer */ -#define ut_assertok_ptr(expr) { \ +#define ut_assertok_ptr(expr) { \ const void *val = (expr); \ \ if (IS_ERR(val)) { \

Line up this backslash with all the others.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/test/ut.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Applied to u-boot-dm

This PMIC driver (power and GPIO) is used by the sandbox SPMI tests. Update the drivers to support a live device tree so that the tests pass.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
drivers/gpio/pm8916_gpio.c | 8 +++----- drivers/power/pmic/pm8916.c | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/pm8916_gpio.c b/drivers/gpio/pm8916_gpio.c index 8dea69f281..9ec2a24b3e 100644 --- a/drivers/gpio/pm8916_gpio.c +++ b/drivers/gpio/pm8916_gpio.c @@ -173,7 +173,7 @@ static int pm8916_gpio_probe(struct udevice *dev) struct pm8916_gpio_bank *priv = dev_get_priv(dev); int reg;
- priv->pid = devfdt_get_addr(dev); + priv->pid = dev_read_addr(dev); if (priv->pid == FDT_ADDR_T_NONE) return -EINVAL;
@@ -193,10 +193,8 @@ static int pm8916_gpio_ofdata_to_platdata(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "gpio-count", 0); - uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), - "gpio-bank-name", NULL); + uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0); + uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name"); if (uc_priv->bank_name == NULL) uc_priv->bank_name = "pm8916";
diff --git a/drivers/power/pmic/pm8916.c b/drivers/power/pmic/pm8916.c index 3632ee2d1e..a048bbe7ce 100644 --- a/drivers/power/pmic/pm8916.c +++ b/drivers/power/pmic/pm8916.c @@ -70,7 +70,7 @@ static int pm8916_probe(struct udevice *dev) { struct pm8916_priv *priv = dev_get_priv(dev);
- priv->usid = devfdt_get_addr(dev); + priv->usid = dev_read_addr(dev);
if (priv->usid == FDT_ADDR_T_NONE) return -EINVAL;

This updates sandbox to use a live device tree. This means that after relocation (from board_init_r() onwards) it no-longer uses flat device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: - Rewrite based on testing and refining the v1 series - Convert various subsystems to enable sandbox tests to pass
configs/sandbox_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 5417057664..a7656a3ff1 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -58,6 +58,7 @@ CONFIG_CMD_EXT4_WRITE=y CONFIG_MAC_PARTITION=y CONFIG_AMIGA_PARTITION=y CONFIG_OF_CONTROL=y +CONFIG_OF_LIVE=y CONFIG_OF_HOSTFILE=y CONFIG_NETCONSOLE=y CONFIG_REGMAP=y

This updates sandbox to use a live device tree. This means that after relocation (from board_init_r() onwards) it no-longer uses flat device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: - Rewrite based on testing and refining the v1 series - Convert various subsystems to enable sandbox tests to pass
configs/sandbox_defconfig | 1 + 1 file changed, 1 insertion(+)
Applied to u-boot-dm
participants (2)
-
Simon Glass
-
sjg@google.com