[U-Boot] [U-Boot, 3/3] dtoc: Add support for 32 or 64-bit addresses

Philipp Tomsich philipp.tomsich at theobroma-systems.com
Mon Aug 14 17:26:38 UTC 2017


On Mon, 19 Jun 2017, Simon Glass wrote:

> When using 32-bit addresses dtoc works correctly. For 64-bit addresses it
> does not since it ignores the #address-cells and #size-cells properties.
>
> Update the tool to use fdt64_t as the element type for reg properties when
> either the address or size is larger than one cell. Use the correct value
> so that C code can obtain the information from the device tree easily.
>
> Add tests for the four combinations of address and size values (32/32,
> 64/64, 32/64, 64/32).
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> Suggested-by: Heiko Stuebner <heiko at sntech.de>
> Reported-by: Kever Yang <kever.yang at rock-chips.com>

Reviewed-by: Philipp Tomsich <philipp.tomsich at theobroma-systems.com>
Tested-by: Philipp Tomsich <philipp.tomsich at theobroma-systems.com>

See below for comments.

> ---
>
> tools/dtoc/dtb_platdata.py         |  59 +++++++++++
> tools/dtoc/dtoc_test_addr32.dts    |  27 +++++
> tools/dtoc/dtoc_test_addr32_64.dts |  33 ++++++
> tools/dtoc/dtoc_test_addr64.dts    |  33 ++++++
> tools/dtoc/dtoc_test_addr64_32.dts |  33 ++++++
> tools/dtoc/test_dtoc.py            | 212 +++++++++++++++++++++++++++++++++++++
> 6 files changed, 397 insertions(+)
> create mode 100644 tools/dtoc/dtoc_test_addr32.dts
> create mode 100644 tools/dtoc/dtoc_test_addr32_64.dts
> create mode 100644 tools/dtoc/dtoc_test_addr64.dts
> create mode 100644 tools/dtoc/dtoc_test_addr64_32.dts
>
> diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
> index f5841cbb88..3de1a20dbd 100644
> --- a/tools/dtoc/dtb_platdata.py
> +++ b/tools/dtoc/dtb_platdata.py
> @@ -242,6 +242,64 @@ class DtbPlatdata(object):
>         self._valid_nodes = []
>         return self.scan_node(self._fdt.GetRoot())
>
> +    @staticmethod
> +    def get_num_cells(node):
> +        """Get the number of cells in addresses and sizes for this node
> +
> +        Args:
> +            node: Node to check
> +
> +        Returns:
> +            Tuple:
> +                Number of address cells for this node
> +                Number of size cells for this node
> +        """
> +        parent = node.parent
> +        na, ns = 2, 2
> +        if parent:
> +            na_prop = parent.props.get('#address-cells')
> +            ns_prop = parent.props.get('#size-cells')
> +            if na_prop:
> +                na = fdt_util.fdt32_to_cpu(na_prop.value)
> +            if ns_prop:
> +                ns = fdt_util.fdt32_to_cpu(ns_prop.value)
> +        return na, ns
> +
> +    def scan_reg_sizes(self):
> +        """Scan for 64-bit 'reg' properties and update the values
> +
> +        This finds 'reg' properties with 64-bit data and converts the value to
> +        an array of 64-values. This allows it to be output in a way that the
> +        C code can read.
> +        """
> +        for node in self._valid_nodes:
> +            reg = node.props.get('reg')
> +            if not reg:
> +                continue
> +            na, ns = self.get_num_cells(node)
> +            total = na + ns
> +
> +            if reg.type != fdt.TYPE_INT:
> +                raise ValueError("Node '%s' reg property is not an int")
> +            if len(reg.value) % total:
> +                raise ValueError("Node '%s' reg property has %d cells "
> +                        'which is not a multiple of na + ns = %d + %d)' %
> +                        (node.name, len(reg.value), na, ns))
> +            reg.na = na
> +            reg.ns = ns
> +            if na != 1 or ns != 1:
> +                reg.type = fdt.TYPE_INT64
> +                i = 0
> +                new_value = []
> +                val = reg.value
> +                while i < len(val):
> +                    addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
> +                    i += na
> +                    size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
> +                    i += ns

If there's just a single element in the reg expression (e.g. reg = <1>), 
as will be the case for I2C or SPI devices, the type of reg.na will be
str instead of list... thus causing a failures in fdt_cells_to_cpu.

> +                    new_value += [addr, size]
> +                reg.value = new_value
> +
>     def scan_structs(self):
>         """Scan the device tree building up the C structures we will use.
>
> @@ -445,6 +503,7 @@ def run_steps(args, dtb_file, include_disabled, output):
>     plat = DtbPlatdata(dtb_file, include_disabled)
>     plat.scan_dtb()
>     plat.scan_tree()
> +    plat.scan_reg_sizes()
>     plat.setup_output(output)
>     structs = plat.scan_structs()
>     plat.scan_phandles()
> diff --git a/tools/dtoc/dtoc_test_addr32.dts b/tools/dtoc/dtoc_test_addr32.dts
> new file mode 100644
> index 0000000000..bcfdcae10b
> --- /dev/null
> +++ b/tools/dtoc/dtoc_test_addr32.dts
> @@ -0,0 +1,27 @@
> +/*
> + * Test device tree file for dtoc
> + *
> + * Copyright 2017 Google, Inc
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> + /dts-v1/;
> +
> +/ {
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +
> +	test1 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test1";
> +		reg = <0x1234 0x5678>;
> +	};
> +
> +	test2 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test2";
> +		reg = <0x12345678 0x98765432 2 3>;
> +	};
> +
> +};
> diff --git a/tools/dtoc/dtoc_test_addr32_64.dts b/tools/dtoc/dtoc_test_addr32_64.dts
> new file mode 100644
> index 0000000000..1c96243310
> --- /dev/null
> +++ b/tools/dtoc/dtoc_test_addr32_64.dts
> @@ -0,0 +1,33 @@
> +/*
> + * Test device tree file for dtoc
> + *
> + * Copyright 2017 Google, Inc
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> + /dts-v1/;
> +
> +/ {
> +	#address-cells = <1>;
> +	#size-cells = <2>;
> +
> +	test1 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test1";
> +		reg = <0x1234 0x5678 0x0>;
> +	};
> +
> +	test2 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test2";
> +		reg = <0x12345678 0x98765432 0x10987654>;
> +	};
> +
> +	test3 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test3";
> +		reg = <0x12345678 0x98765432 0x10987654 2 0 3>;
> +	};
> +
> +};
> diff --git a/tools/dtoc/dtoc_test_addr64.dts b/tools/dtoc/dtoc_test_addr64.dts
> new file mode 100644
> index 0000000000..4c0ad0ec36
> --- /dev/null
> +++ b/tools/dtoc/dtoc_test_addr64.dts
> @@ -0,0 +1,33 @@
> +/*
> + * Test device tree file for dtoc
> + *
> + * Copyright 2017 Google, Inc
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> + /dts-v1/;
> +
> +/ {
> +	#address-cells = <2>;
> +	#size-cells = <2>;
> +
> +	test1 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test1";
> +		reg = /bits/ 64 <0x1234 0x5678>;
> +	};
> +
> +	test2 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test2";
> +		reg = /bits/ 64 <0x1234567890123456 0x9876543210987654>;
> +	};
> +
> +	test3 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test3";
> +		reg = /bits/ 64 <0x1234567890123456 0x9876543210987654 2 3>;
> +	};
> +
> +};
> diff --git a/tools/dtoc/dtoc_test_addr64_32.dts b/tools/dtoc/dtoc_test_addr64_32.dts
> new file mode 100644
> index 0000000000..c36f6b726e
> --- /dev/null
> +++ b/tools/dtoc/dtoc_test_addr64_32.dts
> @@ -0,0 +1,33 @@
> +/*
> + * Test device tree file for dtoc
> + *
> + * Copyright 2017 Google, Inc
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> + /dts-v1/;
> +
> +/ {
> +	#address-cells = <2>;
> +	#size-cells = <1>;
> +
> +	test1 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test1";
> +		reg = <0x1234 0x0 0x5678>;
> +	};
> +
> +	test2 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test2";
> +		reg = <0x12345678 0x90123456 0x98765432>;
> +	};
> +
> +	test3 {
> +		u-boot,dm-pre-reloc;
> +		compatible = "test3";
> +		reg = <0x12345678 0x90123456 0x98765432 0 2 3>;
> +	};
> +
> +};
> diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
> index 35aa4c9817..d91ff88c85 100644
> --- a/tools/dtoc/test_dtoc.py
> +++ b/tools/dtoc/test_dtoc.py
> @@ -268,4 +268,216 @@ U_BOOT_DEVICE(spl_test) = {
> \t.platdata_size\t= sizeof(dtv_spl_test),
> };
>
> +''', data)
> +
> +    def test_addresses64(self):
> +        """Test output from a node with a 'reg' property with na=2, ns=2"""
> +        dtb_file = get_dtb_file('dtoc_test_addr64.dts')
> +        output = tools.GetOutputFilename('output')
> +        dtb_platdata.run_steps(['struct'], dtb_file, False, output)
> +        with open(output) as infile:
> +            data = infile.read()
> +        self.assertEqual('''#include <stdbool.h>
> +#include <libfdt.h>
> +struct dtd_test1 {
> +\tfdt64_t\t\treg[2];
> +};
> +struct dtd_test2 {
> +\tfdt64_t\t\treg[2];
> +};
> +struct dtd_test3 {
> +\tfdt64_t\t\treg[4];
> +};
> +''', data)
> +
> +        dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
> +        with open(output) as infile:
> +            data = infile.read()
> +        self.assertEqual('''#include <common.h>
> +#include <dm.h>
> +#include <dt-structs.h>
> +
> +static struct dtd_test1 dtv_test1 = {
> +\t.reg\t\t\t= {0x1234, 0x5678},
> +};
> +U_BOOT_DEVICE(test1) = {
> +\t.name\t\t= "test1",
> +\t.platdata\t= &dtv_test1,
> +\t.platdata_size\t= sizeof(dtv_test1),
> +};
> +
> +static struct dtd_test2 dtv_test2 = {
> +\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
> +};
> +U_BOOT_DEVICE(test2) = {
> +\t.name\t\t= "test2",
> +\t.platdata\t= &dtv_test2,
> +\t.platdata_size\t= sizeof(dtv_test2),
> +};
> +
> +static struct dtd_test3 dtv_test3 = {
> +\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
> +};
> +U_BOOT_DEVICE(test3) = {
> +\t.name\t\t= "test3",
> +\t.platdata\t= &dtv_test3,
> +\t.platdata_size\t= sizeof(dtv_test3),
> +};
> +
> +''', data)
> +
> +    def test_addresses32(self):
> +        """Test output from a node with a 'reg' property with na=1, ns=1"""
> +        dtb_file = get_dtb_file('dtoc_test_addr32.dts')
> +        output = tools.GetOutputFilename('output')
> +        dtb_platdata.run_steps(['struct'], dtb_file, False, output)
> +        with open(output) as infile:
> +            data = infile.read()
> +        self.assertEqual('''#include <stdbool.h>
> +#include <libfdt.h>
> +struct dtd_test1 {
> +\tfdt32_t\t\treg[2];
> +};
> +struct dtd_test2 {
> +\tfdt32_t\t\treg[4];
> +};
> +''', data)
> +
> +        dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
> +        with open(output) as infile:
> +            data = infile.read()
> +        self.assertEqual('''#include <common.h>
> +#include <dm.h>
> +#include <dt-structs.h>
> +
> +static struct dtd_test1 dtv_test1 = {
> +\t.reg\t\t\t= {0x1234, 0x5678},
> +};
> +U_BOOT_DEVICE(test1) = {
> +\t.name\t\t= "test1",
> +\t.platdata\t= &dtv_test1,
> +\t.platdata_size\t= sizeof(dtv_test1),
> +};
> +
> +static struct dtd_test2 dtv_test2 = {
> +\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
> +};
> +U_BOOT_DEVICE(test2) = {
> +\t.name\t\t= "test2",
> +\t.platdata\t= &dtv_test2,
> +\t.platdata_size\t= sizeof(dtv_test2),
> +};
> +
> +''', data)
> +
> +    def test_addresses64_32(self):
> +        """Test output from a node with a 'reg' property with na=2, ns=1"""
> +        dtb_file = get_dtb_file('dtoc_test_addr64_32.dts')
> +        output = tools.GetOutputFilename('output')
> +        dtb_platdata.run_steps(['struct'], dtb_file, False, output)
> +        with open(output) as infile:
> +            data = infile.read()
> +        self.assertEqual('''#include <stdbool.h>
> +#include <libfdt.h>
> +struct dtd_test1 {
> +\tfdt64_t\t\treg[2];
> +};
> +struct dtd_test2 {
> +\tfdt64_t\t\treg[2];
> +};
> +struct dtd_test3 {
> +\tfdt64_t\t\treg[4];
> +};
> +''', data)
> +
> +        dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
> +        with open(output) as infile:
> +            data = infile.read()
> +        self.assertEqual('''#include <common.h>
> +#include <dm.h>
> +#include <dt-structs.h>
> +
> +static struct dtd_test1 dtv_test1 = {
> +\t.reg\t\t\t= {0x123400000000, 0x5678},
> +};
> +U_BOOT_DEVICE(test1) = {
> +\t.name\t\t= "test1",
> +\t.platdata\t= &dtv_test1,
> +\t.platdata_size\t= sizeof(dtv_test1),
> +};
> +
> +static struct dtd_test2 dtv_test2 = {
> +\t.reg\t\t\t= {0x1234567890123456, 0x98765432},
> +};
> +U_BOOT_DEVICE(test2) = {
> +\t.name\t\t= "test2",
> +\t.platdata\t= &dtv_test2,
> +\t.platdata_size\t= sizeof(dtv_test2),
> +};
> +
> +static struct dtd_test3 dtv_test3 = {
> +\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
> +};
> +U_BOOT_DEVICE(test3) = {
> +\t.name\t\t= "test3",
> +\t.platdata\t= &dtv_test3,
> +\t.platdata_size\t= sizeof(dtv_test3),
> +};
> +
> +''', data)
> +
> +    def test_addresses32_64(self):
> +        """Test output from a node with a 'reg' property with na=1, ns=2"""
> +        dtb_file = get_dtb_file('dtoc_test_addr32_64.dts')
> +        output = tools.GetOutputFilename('output')
> +        dtb_platdata.run_steps(['struct'], dtb_file, False, output)
> +        with open(output) as infile:
> +            data = infile.read()
> +        self.assertEqual('''#include <stdbool.h>
> +#include <libfdt.h>
> +struct dtd_test1 {
> +\tfdt64_t\t\treg[2];
> +};
> +struct dtd_test2 {
> +\tfdt64_t\t\treg[2];
> +};
> +struct dtd_test3 {
> +\tfdt64_t\t\treg[4];
> +};
> +''', data)
> +
> +        dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
> +        with open(output) as infile:
> +            data = infile.read()
> +        self.assertEqual('''#include <common.h>
> +#include <dm.h>
> +#include <dt-structs.h>
> +
> +static struct dtd_test1 dtv_test1 = {
> +\t.reg\t\t\t= {0x1234, 0x567800000000},
> +};
> +U_BOOT_DEVICE(test1) = {
> +\t.name\t\t= "test1",
> +\t.platdata\t= &dtv_test1,
> +\t.platdata_size\t= sizeof(dtv_test1),
> +};
> +
> +static struct dtd_test2 dtv_test2 = {
> +\t.reg\t\t\t= {0x12345678, 0x9876543210987654},
> +};
> +U_BOOT_DEVICE(test2) = {
> +\t.name\t\t= "test2",
> +\t.platdata\t= &dtv_test2,
> +\t.platdata_size\t= sizeof(dtv_test2),
> +};
> +
> +static struct dtd_test3 dtv_test3 = {
> +\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
> +};
> +U_BOOT_DEVICE(test3) = {
> +\t.name\t\t= "test3",
> +\t.platdata\t= &dtv_test3,
> +\t.platdata_size\t= sizeof(dtv_test3),
> +};
> +
> ''', data)
>


More information about the U-Boot mailing list