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

classic Classic list List threaded Threaded
144 messages Options
1234 ... 8
Reply | Threaded
Open this post in threaded view
|

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

Simon Glass-3
(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

--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 01/72] dm: core: Set return value first in lists_bind_fdt()

Simon Glass-3
Adjust the order to make it clear that *devp is set to NULL by default.

Signed-off-by: Simon Glass <[hidden email]>
---

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) {
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 02/72] Update WARN_ON() to return a value

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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
 
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 03/72] dm: core: Add livetree definitions

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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 <[hidden email]>
+ *
+ * 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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 04/72] dm: core: Add livetree access functions

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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 [hidden email]
+ *
+ * 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 <[hidden email]>
+ *
+ * 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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 05/72] dm: Add a function to create a 'live' device tree

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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 <[hidden email]>
+ *
+ * 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
+ * [hidden email]
+ *
+ * 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;
+}
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 06/72] dm: Build a live tree after relocation

Simon Glass-3
In reply to this post by Simon Glass-3
If enabled, build a live device tree after relocation. This can then be
used by driver model.

Signed-off-by: Simon Glass <[hidden email]>
---

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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 07/72] dm: core: Rename of_device_is_compatible()

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 08/72] dm: core: Add operations on device tree references

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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 <[hidden email]>
+ *
+ * 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([hidden email]): 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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 09/72] dm: core: Add livetree address functions

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 10/72] fdt: Update fdt_get_base_address() to use const

Simon Glass-3
In reply to this post by Simon Glass-3
This function does not change the device tree so adjust it to use const
for this parameter.

Signed-off-by: Simon Glass <[hidden email]>
---

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);
 
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 11/72] dm: core: Add address operations on device tree references

Simon Glass-3
In reply to this post by Simon Glass-3
Add functions to add addresses in the device tree using ofnode references.

Signed-off-by: Simon Glass <[hidden email]>
---

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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 12/72] dm: core: Add a place to put extra device-tree reading functions

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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 <[hidden email]>
+ *
+ * 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 <[hidden email]>
+ *
+ * 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;
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 13/72] dm: core: Add device-based 'read' functions to access DT

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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 <[hidden email]>
+ *
+ * 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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 14/72] dm: core: Implement live tree 'read' functions

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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 <[hidden email]>
+ *
+ * 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)
 {
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 15/72] dm: core: Allow binding a device from a live tree

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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
  *
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 16/72] dm: core: Update lists_bind_fdt() to use ofnode

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 17/72] dm: core: Update device_bind_driver_to_node() to use ofnode

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 18/72] dm: core: Scan the live tree when setting up driver model

Simon Glass-3
In reply to this post by Simon Glass-3
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 <[hidden email]>
---

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);
 
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 19/72] dm: core: Add a way to find a device by ofnode

Simon Glass-3
In reply to this post by Simon Glass-3
Add a function which looks up a device by its node (either in live tree
or flat tree).

Signed-off-by: Simon Glass <[hidden email]>
---

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.
--
2.13.0.303.g4ebf302169-goog

_______________________________________________
U-Boot mailing list
[hidden email]
https://lists.denx.de/listinfo/u-boot
1234 ... 8