All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D)
@ 2021-02-03 13:00 Simon Glass
  2021-02-03 13:00 ` [PATCH v2 01/33] bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT Simon Glass
                   ` (65 more replies)
  0 siblings, 66 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

By way of background, in May[1] and July[2] two 'tiny-dm' series were
sent out, showing a possible way to reduce the overhead of driver model in
SPL. The potential impact of that work was described in the cover
letter[3].

While this was a successful demonstration, all but eliminating the
overhead of driver model, it was not very practical, since it would have
required substantial effort to adapt drivers used in SPL to what was
effectively a parallel driver model.

Instead, after much discussion [4], it was decided to try to use the
tiny-dm methods to adapt the existing of-platdata infrastructure. This is
considerably more work up front but should result in much less effort for
maintainers, along with a single, more consistent driver model.

Of the options mentioned in [3], the following are implemented (in dtoc
only, not driver model) as part of this series (CS=reduces code size,
DS=reduces data size):

   CS - drop driver_bind() and create devices (struct udevice) at
        build-time
   CS - allocate all device- and uclass-private data at build-time

In addition the following was completed in an earlier series:

   CS / DS - Combine req_seq and seq and calculate the new value at
        build-time

So this series updates dtoc to support generating devices and uclasses
that are ready for use when SPL starts and don't need to be bound.

This 'build-time' instantiation helps to reduce the code-size overhead of
driver model in SPL.

As part of this series, a new -i option is added to dtoc. This changes it
to emit build-time-instantiated devices. Separate Kconfig options control
instantiation and whether run-time binding is supported.

Several corner cases have come up in making this work on sandbox_spl and
chromebook_coral. It is possible that others will come up in the future,
but it should be possible to adapt things to address these, based on the
work here.

This is part D of the overall effort. The final series includes the
driver model implementation, as well as updating the documentation.

To find out what the new generated files look like, see the last four
patches of this series.

It is available at u-boot-dm/prepd-working

[1] http://patchwork.ozlabs.org/project/uboot/list/?series=179128&state=*
[2] http://patchwork.ozlabs.org/project/uboot/list/?series=187295&state=*
[3] https://lists.denx.de/pipermail/u-boot/2020-July/418433.html
[4] http://patchwork.ozlabs.org/project/uboot/patch/20200525093539.1.Ibf2d19439cde35e39192a9d4a8dad23539fae2e6 at changeid/

Changes in v2:
- New patch
- New patch
- New patch
- Drop patches previously applied
- Update cover letter
- Fix the naming for uclass_plat_name so it is different from uclass_priv
- Tidy up tabbing to make the code output line up better
- Add a summary to the top of the generated file

Simon Glass (33):
  bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT
  dtoc: Scan drivers for available information
  dtoc: Save scan information across test runs
  dtoc: Ignore unwanted files when scanning for drivers
  dtoc: Collect priv/plat struct info from drivers
  dtoc: Support scanning of uclasses
  dtoc: Support scanning of structs in header files
  dtoc: Move test files into a test/ directory
  dtoc: Rename sandbox_i2c_test and sandbox_pmic_test
  dtoc: Add some extra properties to nodes
  dtoc: Make use of node properties
  dtoc: Process nodes to set up required properties
  dtoc: Track nodes which are actually used
  dtoc: Support tracking the phase of U-Boot
  Makefile: Pass the U-Boot phase to dtoc
  dtoc: Support headers needed for drivers
  dtoc: Process driver aliases along with drivers
  dtoc: Warn of duplicate drivers
  dtoc: Read aliases for uclasses
  dtoc: Detect drivers only at the start of start of line
  dtoc: Assign a sequence number to each node
  dtoc: Set up the uclasses that are used
  dtoc: Support processing the root node
  dtoc: Add an option for device instantiation
  dm: of-platadata: Add option for device instantiation
  dtoc: Add support for decl file
  dtoc: Don't generate platform data with instantiation
  sandbox: Make sandbox,emul more conventional
  sandbox: i2c: Rename driver names to work with of-platdata
  dtoc: Tidy up the list of supported phandle properties
  dtoc: Generate a summary in the dt-plat.c file
  dtoc: Generate uclass devices
  dtoc: Generate device instances

 arch/sandbox/dts/sandbox.dtsi                 |    6 +-
 arch/sandbox/dts/test.dts                     |    4 +-
 common/Kconfig.boot                           |    3 +
 common/bootstage.c                            |    2 +-
 doc/driver-model/of-plat.rst                  |    3 +-
 doc/driver-model/pci-info.rst                 |    1 +
 drivers/i2c/i2c-emul-uclass.c                 |    4 +-
 drivers/misc/test_drv.c                       |   11 +-
 drivers/rtc/i2c_rtc_emul.c                    |    2 +-
 dts/Kconfig                                   |   23 +-
 include/dm/device.h                           |   34 +
 include/dm/test.h                             |    5 +
 scripts/Makefile.spl                          |    6 +-
 test/dm/test-fdt.c                            |    6 +-
 tools/dtoc/dtb_platdata.py                    |  620 +++++++++-
 tools/dtoc/dtoc_test_scan_drivers.cxx         |    1 -
 tools/dtoc/main.py                            |    9 +-
 tools/dtoc/src_scan.py                        |  597 +++++++++-
 tools/dtoc/{ => test}/dtoc_test.dts           |    0
 tools/dtoc/{ => test}/dtoc_test_add_prop.dts  |    0
 tools/dtoc/{ => test}/dtoc_test_addr32.dts    |    0
 tools/dtoc/{ => test}/dtoc_test_addr32_64.dts |    0
 tools/dtoc/{ => test}/dtoc_test_addr64.dts    |    0
 tools/dtoc/{ => test}/dtoc_test_addr64_32.dts |    0
 tools/dtoc/test/dtoc_test_alias_bad.dts       |   58 +
 tools/dtoc/test/dtoc_test_alias_bad_path.dts  |   58 +
 tools/dtoc/test/dtoc_test_alias_bad_uc.dts    |   58 +
 tools/dtoc/{ => test}/dtoc_test_aliases.dts   |    0
 tools/dtoc/{ => test}/dtoc_test_bad_reg.dts   |    0
 tools/dtoc/{ => test}/dtoc_test_bad_reg2.dts  |    0
 .../{ => test}/dtoc_test_driver_alias.dts     |    0
 tools/dtoc/{ => test}/dtoc_test_empty.dts     |    0
 tools/dtoc/test/dtoc_test_inst.dts            |   58 +
 .../{ => test}/dtoc_test_invalid_driver.dts   |    0
 tools/dtoc/{ => test}/dtoc_test_phandle.dts   |    0
 .../dtoc/{ => test}/dtoc_test_phandle_bad.dts |    0
 .../{ => test}/dtoc_test_phandle_bad2.dts     |    0
 .../{ => test}/dtoc_test_phandle_cd_gpios.dts |    0
 .../{ => test}/dtoc_test_phandle_reorder.dts  |    0
 .../{ => test}/dtoc_test_phandle_single.dts   |    0
 tools/dtoc/test/dtoc_test_scan_drivers.cxx    |    5 +
 tools/dtoc/{ => test}/dtoc_test_simple.dts    |    4 +-
 tools/dtoc/test_dtoc.py                       | 1023 ++++++++++++++++-
 tools/dtoc/test_fdt.py                        |   31 +-
 tools/dtoc/test_src_scan.py                   |  397 ++++++-
 45 files changed, 2847 insertions(+), 182 deletions(-)
 delete mode 100644 tools/dtoc/dtoc_test_scan_drivers.cxx
 rename tools/dtoc/{ => test}/dtoc_test.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_add_prop.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr32.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr32_64.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr64.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr64_32.dts (100%)
 create mode 100644 tools/dtoc/test/dtoc_test_alias_bad.dts
 create mode 100644 tools/dtoc/test/dtoc_test_alias_bad_path.dts
 create mode 100644 tools/dtoc/test/dtoc_test_alias_bad_uc.dts
 rename tools/dtoc/{ => test}/dtoc_test_aliases.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_bad_reg.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_bad_reg2.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_driver_alias.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_empty.dts (100%)
 create mode 100644 tools/dtoc/test/dtoc_test_inst.dts
 rename tools/dtoc/{ => test}/dtoc_test_invalid_driver.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_bad.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_bad2.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_cd_gpios.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_reorder.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_single.dts (100%)
 create mode 100644 tools/dtoc/test/dtoc_test_scan_drivers.cxx
 rename tools/dtoc/{ => test}/dtoc_test_simple.dts (93%)

-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 01/33] bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 02/33] dtoc: Scan drivers for available information Simon Glass
                   ` (64 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

At present these three Kconfigs exist even when bootstage is not enabled.
This is not necessary since bootstage.c is only built if BOOTSTAGE is
enabled.

Make them conditional. Also fix up the overflow message to mention TPL.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 common/Kconfig.boot | 3 +++
 common/bootstage.c  | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/common/Kconfig.boot b/common/Kconfig.boot
index 5eaabdfc27f..c3869f9b8a5 100644
--- a/common/Kconfig.boot
+++ b/common/Kconfig.boot
@@ -427,6 +427,7 @@ config BOOTSTAGE_REPORT
 
 config BOOTSTAGE_RECORD_COUNT
 	int "Number of boot stage records to store"
+	depends on BOOTSTAGE
 	default 30
 	help
 	  This is the size of the bootstage record list and is the maximum
@@ -434,6 +435,7 @@ config BOOTSTAGE_RECORD_COUNT
 
 config SPL_BOOTSTAGE_RECORD_COUNT
 	int "Number of boot stage records to store for SPL"
+	depends on SPL_BOOTSTAGE
 	default 5
 	help
 	  This is the size of the bootstage record list and is the maximum
@@ -441,6 +443,7 @@ config SPL_BOOTSTAGE_RECORD_COUNT
 
 config TPL_BOOTSTAGE_RECORD_COUNT
 	int "Number of boot stage records to store for TPL"
+	depends on TPL_BOOTSTAGE
 	default 5
 	help
 	  This is the size of the bootstage record list and is the maximum
diff --git a/common/bootstage.c b/common/bootstage.c
index 5f87358fd85..ad2e4469af5 100644
--- a/common/bootstage.c
+++ b/common/bootstage.c
@@ -348,7 +348,7 @@ void bootstage_report(void)
 	}
 	if (data->rec_count > RECORD_COUNT)
 		printf("Overflowed internal boot id table by %d entries\n"
-		       "Please increase CONFIG_(SPL_)BOOTSTAGE_RECORD_COUNT\n",
+		       "Please increase CONFIG_(SPL_TPL_)BOOTSTAGE_RECORD_COUNT\n",
 		       data->rec_count - RECORD_COUNT);
 
 	puts("\nAccumulated time:\n");
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 02/33] dtoc: Scan drivers for available information
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
  2021-02-03 13:00 ` [PATCH v2 01/33] bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 03/33] dtoc: Save scan information across test runs Simon Glass
                   ` (63 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

At present we simply record the name of a driver parsed from its
implementation file. We also need to get the uclass and a few other
things so we can instantiate devices at build time. Add support for
collecting this information. This requires parsing each driver file.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 194 ++++++++++++++++++++++++++++++++++--
 tools/dtoc/test_src_scan.py | 131 +++++++++++++++++++++++-
 2 files changed, 311 insertions(+), 14 deletions(-)

diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index f63c9fc166e..095fb6d4766 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -54,15 +54,30 @@ class Driver:
 
     Attributes:
         name: Name of driver. For U_BOOT_DRIVER(x) this is 'x'
+        fname: Filename where the driver was found
+        uclass_id: Name of uclass, e.g. 'UCLASS_I2C'
+        compat: Driver data for each compatible string:
+            key: Compatible string, e.g. 'rockchip,rk3288-grf'
+            value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+        fname: Filename where the driver was found
+        priv (str): struct name of the priv_auto member, e.g. 'serial_priv'
     """
-    def __init__(self, name):
+    def __init__(self, name, fname):
         self.name = name
+        self.fname = fname
+        self.uclass_id = None
+        self.compat = None
+        self.priv = ''
 
     def __eq__(self, other):
-        return self.name == other.name
+        return (self.name == other.name and
+                self.uclass_id == other.uclass_id and
+                self.compat == other.compat and
+                self.priv == other.priv)
 
     def __repr__(self):
-        return "Driver(name='%s')" % self.name
+        return ("Driver(name='%s', uclass_id='%s', compat=%s, priv=%s)" %
+                (self.name, self.uclass_id, self.compat, self.priv))
 
 
 class Scanner:
@@ -81,6 +96,12 @@ class Scanner:
         _warning_disabled: true to disable warnings about driver names not found
         _drivers_additional (list or str): List of additional drivers to use
             during scanning
+        _of_match: Dict holding information about compatible strings
+            key: Name of struct udevice_id variable
+            value: Dict of compatible info in that variable:
+               key: Compatible string, e.g. 'rockchip,rk3288-grf'
+               value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+        _compat_to_driver: Maps compatible strings to Driver
     """
     def __init__(self, basedir, warning_disabled, drivers_additional):
         """Set up a new Scanner
@@ -94,6 +115,8 @@ class Scanner:
         self._driver_aliases = {}
         self._drivers_additional = drivers_additional or []
         self._warning_disabled = warning_disabled
+        self._of_match = {}
+        self._compat_to_driver = {}
 
     def get_normalized_compat_name(self, node):
         """Get a node's normalized compat name
@@ -131,10 +154,163 @@ class Scanner:
 
         return compat_list_c[0], compat_list_c[1:]
 
+    @classmethod
+    def _get_re_for_member(cls, member):
+        """_get_re_for_member: Get a compiled regular expression
+
+        Args:
+            member (str): Struct member name, e.g. 'priv_auto'
+
+        Returns:
+            re.Pattern: Compiled regular expression that parses:
+
+               .member = sizeof(struct fred),
+
+            and returns "fred" as group 1
+        """
+        return re.compile(r'^\s*.%s\s*=\s*sizeof\(struct\s+(.*)\),$' % member)
+
+    def _parse_driver(self, fname, buff):
+        """Parse a C file to extract driver information contained within
+
+        This parses U_BOOT_DRIVER() structs to obtain various pieces of useful
+        information.
+
+        It updates the following members:
+            _drivers - updated with new Driver records for each driver found
+                in the file
+            _of_match - updated with each compatible string found in the file
+            _compat_to_driver - Maps compatible string to Driver
+
+        Args:
+            fname (str): Filename being parsed (used for warnings)
+            buff (str): Contents of file
+
+        Raises:
+            ValueError: Compatible variable is mentioned in .of_match in
+                U_BOOT_DRIVER() but not found in the file
+        """
+        # Dict holding information about compatible strings collected in this
+        # function so far
+        #    key: Name of struct udevice_id variable
+        #    value: Dict of compatible info in that variable:
+        #       key: Compatible string, e.g. 'rockchip,rk3288-grf'
+        #       value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+        of_match = {}
+
+        # Dict holding driver information collected in this function so far
+        #    key: Driver name (C name as in U_BOOT_DRIVER(xxx))
+        #    value: Driver
+        drivers = {}
+
+        # Collect the driver info
+        driver = None
+        re_driver = re.compile(r'U_BOOT_DRIVER\((.*)\)')
+
+        # Collect the uclass ID, e.g. 'UCLASS_SPI'
+        re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
+
+        # Collect the compatible string, e.g. 'rockchip,rk3288-grf'
+        compat = None
+        re_compat = re.compile(r'{\s*.compatible\s*=\s*"(.*)"\s*'
+                               r'(,\s*.data\s*=\s*(\S*))?\s*},')
+
+        # This is a dict of compatible strings that were found:
+        #    key: Compatible string, e.g. 'rockchip,rk3288-grf'
+        #    value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+        compat_dict = {}
+
+        # Holds the var nane of the udevice_id list, e.g.
+        # 'rk3288_syscon_ids_noc' in
+        # static const struct udevice_id rk3288_syscon_ids_noc[] = {
+        ids_name = None
+        re_ids = re.compile(r'struct udevice_id (.*)\[\]\s*=')
+
+        # Matches the references to the udevice_id list
+        re_of_match = re.compile(
+            r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,')
+
+        # Matches the struct name for priv
+        re_priv = self._get_re_for_member('priv_auto')
+
+        prefix = ''
+        for line in buff.splitlines():
+            # Handle line continuation
+            if prefix:
+                line = prefix + line
+                prefix = ''
+            if line.endswith('\\'):
+                prefix = line[:-1]
+                continue
+
+            driver_match = re_driver.search(line)
+
+            # If this line contains U_BOOT_DRIVER()...
+            if driver:
+                m_id = re_id.search(line)
+                m_of_match = re_of_match.search(line)
+                m_priv = re_priv.match(line)
+                if m_priv:
+                    driver.priv = m_priv.group(1)
+                elif m_id:
+                    driver.uclass_id = m_id.group(1)
+                elif m_of_match:
+                    compat = m_of_match.group(2)
+                elif '};' in line:
+                    if driver.uclass_id and compat:
+                        if compat not in of_match:
+                            raise ValueError(
+                                "%s: Unknown compatible var '%s' (found: %s)" %
+                                (fname, compat, ','.join(of_match.keys())))
+                        driver.compat = of_match[compat]
+
+                        # This needs to be deterministic, since a driver may
+                        # have multiple compatible strings pointing to it.
+                        # We record the one earliest in the alphabet so it
+                        # will produce the same result on all machines.
+                        for compat_id in of_match[compat]:
+                            old = self._compat_to_driver.get(compat_id)
+                            if not old or driver.name < old.name:
+                                self._compat_to_driver[compat_id] = driver
+                        drivers[driver.name] = driver
+                    else:
+                        # The driver does not have a uclass or compat string.
+                        # The first is required but the second is not, so just
+                        # ignore this.
+                        pass
+                    driver = None
+                    ids_name = None
+                    compat = None
+                    compat_dict = {}
+
+            elif ids_name:
+                compat_m = re_compat.search(line)
+                if compat_m:
+                    compat_dict[compat_m.group(1)] = compat_m.group(3)
+                elif '};' in line:
+                    of_match[ids_name] = compat_dict
+                    ids_name = None
+            elif driver_match:
+                driver_name = driver_match.group(1)
+                driver = Driver(driver_name, fname)
+            else:
+                ids_m = re_ids.search(line)
+                if ids_m:
+                    ids_name = ids_m.group(1)
+
+        # Make the updates based on what we found
+        self._drivers.update(drivers)
+        self._of_match.update(of_match)
+
     def scan_driver(self, fname):
         """Scan a driver file to build a list of driver names and aliases
 
-        This procedure will populate self._drivers and self._driver_aliases
+        It updates the following members:
+            _drivers - updated with new Driver records for each driver found
+                in the file
+            _of_match - updated with each compatible string found in the file
+            _compat_to_driver - Maps compatible string to Driver
+            _driver_aliases - Maps alias names to driver name
 
         Args
             fname: Driver filename to scan
@@ -147,12 +323,10 @@ class Scanner:
                 print("Skipping file '%s' due to unicode error" % fname)
                 return
 
-            # The following re will search for driver names declared as
-            # U_BOOT_DRIVER(driver_name)
-            drivers = re.findall(r'U_BOOT_DRIVER\((.*)\)', buff)
-
-            for driver in drivers:
-                self._drivers[driver] = Driver(driver)
+            # If this file has any U_BOOT_DRIVER() declarations, process it to
+            # obtain driver information
+            if 'U_BOOT_DRIVER' in buff:
+                self._parse_driver(fname, buff)
 
             # The following re will search for driver aliases declared as
             # DM_DRIVER_ALIAS(alias, driver_name)
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 7d686530d68..25e4866f201 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -17,6 +17,20 @@ from dtoc import src_scan
 from patman import test_util
 from patman import tools
 
+OUR_PATH = os.path.dirname(os.path.realpath(__file__))
+
+class FakeNode:
+    """Fake Node object for testing"""
+    def __init__(self):
+        self.name = None
+        self.props = {}
+
+class FakeProp:
+    """Fake Prop object for testing"""
+    def __init__(self):
+        self.name = None
+        self.value = None
+
 # This is a test so is allowed to access private things in the module it is
 # testing
 # pylint: disable=W0212
@@ -69,10 +83,22 @@ class TestSrcScan(unittest.TestCase):
 
     def test_driver(self):
         """Test the Driver class"""
-        drv1 = src_scan.Driver('fred')
-        drv2 = src_scan.Driver('mary')
-        drv3 = src_scan.Driver('fred')
-        self.assertEqual("Driver(name='fred')", str(drv1))
+        i2c = 'I2C_UCLASS'
+        compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
+                  'rockchip,rk3288-srf': None}
+        drv1 = src_scan.Driver('fred', 'fred.c')
+        drv2 = src_scan.Driver('mary', 'mary.c')
+        drv3 = src_scan.Driver('fred', 'fred.c')
+        drv1.uclass_id = i2c
+        drv1.compat = compat
+        drv2.uclass_id = i2c
+        drv2.compat = compat
+        drv3.uclass_id = i2c
+        drv3.compat = compat
+        self.assertEqual(
+            "Driver(name='fred', uclass_id='I2C_UCLASS', "
+            "compat={'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF', "
+            "'rockchip,rk3288-srf': None}, priv=)", str(drv1))
         self.assertEqual(drv1, drv3)
         self.assertNotEqual(drv1, drv2)
         self.assertNotEqual(drv2, drv3)
@@ -105,3 +131,100 @@ class TestSrcScan(unittest.TestCase):
                              mocked.mock_calls[1])
         finally:
             shutil.rmtree(indir)
+
+    def test_scan(self):
+        """Test scanning of a driver"""
+        fname = os.path.join(OUR_PATH, '..', '..', 'drivers/i2c/tegra_i2c.c')
+        buff = tools.ReadFile(fname, False)
+        scan = src_scan.Scanner(None, False, None)
+        scan._parse_driver(fname, buff)
+        self.assertIn('i2c_tegra', scan._drivers)
+        drv = scan._drivers['i2c_tegra']
+        self.assertEqual('i2c_tegra', drv.name)
+        self.assertEqual('UCLASS_I2C', drv.uclass_id)
+        self.assertEqual(
+            {'nvidia,tegra114-i2c': 'TYPE_114',
+             'nvidia,tegra20-i2c': 'TYPE_STD',
+             'nvidia,tegra20-i2c-dvc': 'TYPE_DVC'}, drv.compat)
+        self.assertEqual('i2c_bus', drv.priv)
+        self.assertEqual(1, len(scan._drivers))
+
+    def test_normalized_name(self):
+        """Test operation of get_normalized_compat_name()"""
+        prop = FakeProp()
+        prop.name = 'compatible'
+        prop.value = 'rockchip,rk3288-grf'
+        node = FakeNode()
+        node.props = {'compatible': prop}
+        scan = src_scan.Scanner(None, False, None)
+        with test_util.capture_sys_output() as (stdout, _):
+            name, aliases = scan.get_normalized_compat_name(node)
+        self.assertEqual('rockchip_rk3288_grf', name)
+        self.assertEqual([], aliases)
+        self.assertEqual(
+            'WARNING: the driver rockchip_rk3288_grf was not found in the driver list',
+            stdout.getvalue().strip())
+
+        i2c = 'I2C_UCLASS'
+        compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
+                  'rockchip,rk3288-srf': None}
+        drv = src_scan.Driver('fred', 'fred.c')
+        drv.uclass_id = i2c
+        drv.compat = compat
+        scan._drivers['rockchip_rk3288_grf'] = drv
+
+        scan._driver_aliases['rockchip_rk3288_srf'] = 'rockchip_rk3288_grf'
+
+        with test_util.capture_sys_output() as (stdout, _):
+            name, aliases = scan.get_normalized_compat_name(node)
+        self.assertEqual('', stdout.getvalue().strip())
+        self.assertEqual('rockchip_rk3288_grf', name)
+        self.assertEqual([], aliases)
+
+        prop.value = 'rockchip,rk3288-srf'
+        with test_util.capture_sys_output() as (stdout, _):
+            name, aliases = scan.get_normalized_compat_name(node)
+        self.assertEqual('', stdout.getvalue().strip())
+        self.assertEqual('rockchip_rk3288_grf', name)
+        self.assertEqual(['rockchip_rk3288_srf'], aliases)
+
+    def test_scan_errors(self):
+        """Test detection of scanning errors"""
+        buff = '''
+static const struct udevice_id tegra_i2c_ids2[] = {
+	{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+	.name	= "i2c_tegra",
+	.id	= UCLASS_I2C,
+	.of_match = tegra_i2c_ids,
+};
+'''
+        scan = src_scan.Scanner(None, False, None)
+        with self.assertRaises(ValueError) as exc:
+            scan._parse_driver('file.c', buff)
+        self.assertIn(
+            "file.c: Unknown compatible var 'tegra_i2c_ids' (found: tegra_i2c_ids2)",
+            str(exc.exception))
+
+    def test_of_match(self):
+        """Test detection of of_match_ptr() member"""
+        buff = '''
+static const struct udevice_id tegra_i2c_ids[] = {
+	{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+	.name	= "i2c_tegra",
+	.id	= UCLASS_I2C,
+	.of_match = of_match_ptr(tegra_i2c_ids),
+};
+'''
+        scan = src_scan.Scanner(None, False, None)
+        scan._parse_driver('file.c', buff)
+        self.assertIn('i2c_tegra', scan._drivers)
+        drv = scan._drivers['i2c_tegra']
+        self.assertEqual('i2c_tegra', drv.name)
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 03/33] dtoc: Save scan information across test runs
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
  2021-02-03 13:00 ` [PATCH v2 01/33] bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT Simon Glass
  2021-02-03 13:00 ` [PATCH v2 02/33] dtoc: Scan drivers for available information Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 04/33] dtoc: Ignore unwanted files when scanning for drivers Simon Glass
                   ` (62 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

At present most of the tests scan the U-Boot source tree as part of their
run. This information does not change across tests, so we can save time
by remembering it.

Add a way to set up this information and use it for each test, taking a
copy first, so as not to mess up the original.

This reduces the run time from about 1.6 seconds to 1.5 seconds on my
machine. For code coverage (which cannot run in parallel), it reduces from
33 seconds to 5.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 11 ++++++++---
 tools/dtoc/main.py         |  2 ++
 tools/dtoc/test_dtoc.py    | 40 +++++++++++++++++++++++++++++++-------
 3 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index b7abaed67ac..e9be5985c72 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -670,7 +670,8 @@ OUTPUT_FILES = {
 
 
 def run_steps(args, dtb_file, include_disabled, output, output_dirs,
-              warning_disabled=False, drivers_additional=None, basedir=None):
+              warning_disabled=False, drivers_additional=None, basedir=None,
+              scan=None):
     """Run all the steps of the dtoc tool
 
     Args:
@@ -687,6 +688,9 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
             scanning
         basedir (str): Base directory of U-Boot source code. Defaults to the
             grandparent of this file's directory
+        scan (src_src.Scanner): Scanner from a previous run. This can help speed
+            up tests. Use None for normal operation
+
     Raises:
         ValueError: if args has no command, or an unknown command
     """
@@ -695,9 +699,10 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
     if output and output_dirs and any(output_dirs):
         raise ValueError('Must specify either output or output_dirs, not both')
 
-    scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional)
+    if not scan:
+        scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional)
+        scan.scan_drivers()
     plat = DtbPlatdata(scan, dtb_file, include_disabled)
-    scan.scan_drivers()
     plat.scan_dtb()
     plat.scan_tree()
     plat.scan_reg_sizes()
diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py
index b0ad0f3952a..355b1e62773 100755
--- a/tools/dtoc/main.py
+++ b/tools/dtoc/main.py
@@ -53,6 +53,8 @@ def run_tests(processes, args):
     sys.argv = [sys.argv[0]]
     test_name = args and args[0] or None
 
+    test_dtoc.setup()
+
     test_util.RunTestSuites(
         result, debug=True, verbosity=1, test_preserve_dirs=False,
         processes=processes, test_name=test_name, toolpath=[],
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index d961d67b8fc..6865d949a05 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -10,6 +10,7 @@ tool.
 """
 
 import collections
+import copy
 import glob
 import os
 import struct
@@ -20,6 +21,7 @@ from dtb_platdata import tab_to
 from dtoc import dtb_platdata
 from dtoc import fdt
 from dtoc import fdt_util
+from dtoc import src_scan
 from dtoc.src_scan import conv_name_to_c
 from dtoc.src_scan import get_compat_name
 from patman import test_util
@@ -53,6 +55,9 @@ C_HEADER = '''/*
 #include <dt-structs.h>
 '''
 
+# Scanner saved from a previous run of the tests (to speed things up)
+saved_scan = None
+
 # This is a test so is allowed to access private things in the module it is
 # testing
 # pylint: disable=W0212
@@ -71,6 +76,19 @@ def get_dtb_file(dts_fname, capture_stderr=False):
                                    capture_stderr=capture_stderr)
 
 
+def setup():
+    global saved_scan
+
+    # Disable warnings so that calls to get_normalized_compat_name() will not
+    # output things.
+    saved_scan = src_scan.Scanner(None, True, False)
+    saved_scan.scan_drivers()
+
+def copy_scan():
+    """Get a copy of saved_scan so that each test can start clean"""
+    return copy.deepcopy(saved_scan)
+
+
 class TestDtoc(unittest.TestCase):
     """Tests for dtoc"""
     @classmethod
@@ -120,7 +138,8 @@ class TestDtoc(unittest.TestCase):
             dtb_file (str): Filename of .dtb file
             output (str): Filename of output file
         """
-        dtb_platdata.run_steps(args, dtb_file, False, output, [], True)
+        dtb_platdata.run_steps(args, dtb_file, False, output, [], True,
+                               None, None, scan=copy_scan())
 
     def test_name(self):
         """Test conversion of device tree names to C identifiers"""
@@ -175,7 +194,9 @@ class TestDtoc(unittest.TestCase):
         """Test output from a device tree file with no nodes"""
         dtb_file = get_dtb_file('dtoc_test_empty.dts')
         output = tools.GetOutputFilename('output')
-        self.run_test(['struct'], dtb_file, output)
+
+        # Run this one without saved_scan to complete test coverage
+        dtb_platdata.run_steps(['struct'], dtb_file, False, output, [], True)
         with open(output) as infile:
             lines = infile.read().splitlines()
         self.assertEqual(HEADER.splitlines(), lines)
@@ -343,7 +364,8 @@ U_BOOT_DRVINFO(gpios_at_0) = {
         dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts')
         output = tools.GetOutputFilename('output')
         with test_util.capture_sys_output() as _:
-            dtb_platdata.run_steps(['struct'], dtb_file, False, output, [])
+            dtb_platdata.run_steps(['struct'], dtb_file, False, output, [],
+                                   scan=copy_scan())
         with open(output) as infile:
             data = infile.read()
         self._check_strings(HEADER + '''
@@ -352,7 +374,8 @@ struct dtd_invalid {
 ''', data)
 
         with test_util.capture_sys_output() as _:
-            dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [])
+            dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [],
+                                   scan=copy_scan())
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
@@ -502,7 +525,8 @@ U_BOOT_DRVINFO(phandle_target) = {
         """Test that phandle targets are generated when unsing cd-gpios"""
         dtb_file = get_dtb_file('dtoc_test_phandle_cd_gpios.dts')
         output = tools.GetOutputFilename('output')
-        dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [], True)
+        dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [], True,
+                               scan=copy_scan())
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
@@ -903,7 +927,8 @@ U_BOOT_DRVINFO(spl_test2) = {
     def test_output_conflict(self):
         """Test a conflict between and output dirs and output file"""
         with self.assertRaises(ValueError) as exc:
-            dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], True)
+            dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], True,
+                                   scan=copy_scan())
         self.assertIn("Must specify either output or output_dirs, not both",
                       str(exc.exception))
 
@@ -919,7 +944,8 @@ U_BOOT_DRVINFO(spl_test2) = {
         fnames = glob.glob(outdir + '/*')
         self.assertEqual(2, len(fnames))
 
-        dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], True)
+        dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], True,
+                               scan=copy_scan())
         fnames = glob.glob(outdir + '/*')
         self.assertEqual(4, len(fnames))
 
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 04/33] dtoc: Ignore unwanted files when scanning for drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (2 preceding siblings ...)
  2021-02-03 13:00 ` [PATCH v2 03/33] dtoc: Save scan information across test runs Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 05/33] dtoc: Collect priv/plat struct info from drivers Simon Glass
                   ` (61 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

We should ignore anything in the .git directory or any of the
build-sandbox, etc. directories created by 'make check'. These can confuse
dtoc. Update the code to ignore these.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 5 +++++
 tools/dtoc/test_src_scan.py | 5 ++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index 095fb6d4766..761164a9c9a 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -345,6 +345,11 @@ class Scanner:
         This procedure will populate self._drivers and self._driver_aliases
         """
         for (dirpath, _, filenames) in os.walk(self._basedir):
+            rel_path = dirpath[len(self._basedir):]
+            if rel_path.startswith('/'):
+                rel_path = rel_path[1:]
+            if rel_path.startswith('build') or rel_path.startswith('.git'):
+                continue
             for fname in filenames:
                 if not fname.endswith('.c'):
                     continue
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 25e4866f201..ada49fb7042 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -117,7 +117,9 @@ class TestSrcScan(unittest.TestCase):
 
             fname_list = []
             add_file('fname.c')
+            add_file('.git/ignoreme.c')
             add_file('dir/fname2.c')
+            add_file('build-sandbox/ignoreme2.c')
 
             # Mock out scan_driver and check that it is called with the
             # expected files
@@ -127,7 +129,8 @@ class TestSrcScan(unittest.TestCase):
             self.assertEqual(2, len(mocked.mock_calls))
             self.assertEqual(mock.call(fname_list[0]),
                              mocked.mock_calls[0])
-            self.assertEqual(mock.call(fname_list[1]),
+            # .git file should be ignored
+            self.assertEqual(mock.call(fname_list[2]),
                              mocked.mock_calls[1])
         finally:
             shutil.rmtree(indir)
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 05/33] dtoc: Collect priv/plat struct info from drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (3 preceding siblings ...)
  2021-02-03 13:00 ` [PATCH v2 04/33] dtoc: Ignore unwanted files when scanning for drivers Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 06/33] dtoc: Support scanning of uclasses Simon Glass
                   ` (60 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

In order to output variables to hold the priv/plat information used by
each device, dtoc needs to know the struct for each. With this, it can
declare this at build time:

   u8 xxx_priv [sizeof(struct <name>)];

Collect the various struct names from the drivers.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 25 +++++++++++++++++++++++--
 tools/dtoc/test_src_scan.py | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index 761164a9c9a..ff3ab409e4b 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -61,6 +61,11 @@ class Driver:
             value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
         fname: Filename where the driver was found
         priv (str): struct name of the priv_auto member, e.g. 'serial_priv'
+        plat (str): struct name of the plat_auto member, e.g. 'serial_plat'
+        child_priv (str): struct name of the per_child_auto member,
+            e.g. 'pci_child_priv'
+        child_plat (str): struct name of the per_child_plat_auto member,
+            e.g. 'pci_child_plat'
     """
     def __init__(self, name, fname):
         self.name = name
@@ -68,12 +73,16 @@ class Driver:
         self.uclass_id = None
         self.compat = None
         self.priv = ''
+        self.plat = ''
+        self.child_priv = ''
+        self.child_plat = ''
 
     def __eq__(self, other):
         return (self.name == other.name and
                 self.uclass_id == other.uclass_id and
                 self.compat == other.compat and
-                self.priv == other.priv)
+                self.priv == other.priv and
+                self.plat == other.plat)
 
     def __repr__(self):
         return ("Driver(name='%s', uclass_id='%s', compat=%s, priv=%s)" %
@@ -230,8 +239,11 @@ class Scanner:
         re_of_match = re.compile(
             r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,')
 
-        # Matches the struct name for priv
+        # Matches the struct name for priv, plat
         re_priv = self._get_re_for_member('priv_auto')
+        re_plat = self._get_re_for_member('plat_auto')
+        re_child_priv = self._get_re_for_member('per_child_auto')
+        re_child_plat = self._get_re_for_member('per_child_plat_auto')
 
         prefix = ''
         for line in buff.splitlines():
@@ -250,8 +262,17 @@ class Scanner:
                 m_id = re_id.search(line)
                 m_of_match = re_of_match.search(line)
                 m_priv = re_priv.match(line)
+                m_plat = re_plat.match(line)
+                m_cplat = re_child_plat.match(line)
+                m_cpriv = re_child_priv.match(line)
                 if m_priv:
                     driver.priv = m_priv.group(1)
+                elif m_plat:
+                    driver.plat = m_plat.group(1)
+                elif m_cplat:
+                    driver.child_plat = m_cplat.group(1)
+                elif m_cpriv:
+                    driver.child_priv = m_cpriv.group(1)
                 elif m_id:
                     driver.uclass_id = m_id.group(1)
                 elif m_of_match:
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index ada49fb7042..62dea2a9612 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -231,3 +231,35 @@ U_BOOT_DRIVER(i2c_tegra) = {
         self.assertIn('i2c_tegra', scan._drivers)
         drv = scan._drivers['i2c_tegra']
         self.assertEqual('i2c_tegra', drv.name)
+
+    def test_priv(self):
+        """Test collection of struct info from drivers"""
+        buff = '''
+static const struct udevice_id test_ids[] = {
+	{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+	{ }
+};
+
+U_BOOT_DRIVER(testing) = {
+	.name	= "testing",
+	.id	= UCLASS_I2C,
+	.of_match = test_ids,
+	.priv_auto	= sizeof(struct some_priv),
+	.plat_auto = sizeof(struct some_plat),
+	.per_child_auto	= sizeof(struct some_cpriv),
+	.per_child_plat_auto = sizeof(struct some_cplat),
+};
+'''
+        scan = src_scan.Scanner(None, False, None)
+        scan._parse_driver('file.c', buff)
+        self.assertIn('testing', scan._drivers)
+        drv = scan._drivers['testing']
+        self.assertEqual('testing', drv.name)
+        self.assertEqual('UCLASS_I2C', drv.uclass_id)
+        self.assertEqual(
+            {'nvidia,tegra114-i2c': 'TYPE_114'}, drv.compat)
+        self.assertEqual('some_priv', drv.priv)
+        self.assertEqual('some_plat', drv.plat)
+        self.assertEqual('some_cpriv', drv.child_priv)
+        self.assertEqual('some_cplat', drv.child_plat)
+        self.assertEqual(1, len(scan._drivers))
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 06/33] dtoc: Support scanning of uclasses
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (4 preceding siblings ...)
  2021-02-03 13:00 ` [PATCH v2 05/33] dtoc: Collect priv/plat struct info from drivers Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 07/33] dtoc: Support scanning of structs in header files Simon Glass
                   ` (59 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

Uclasses can have per-device private / platform data so dtoc needs to
scan these drivers. This allows it to find out the size of this data so
it can be allocated a build time.

Add a parser for uclass information, similar to drivers. Keep a dict of
the uclasses that were found.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 122 ++++++++++++++++++++++++++++++++++++
 tools/dtoc/test_src_scan.py |  55 ++++++++++++++++
 2 files changed, 177 insertions(+)

diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index ff3ab409e4b..3245d02e09b 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -89,6 +89,43 @@ class Driver:
                 (self.name, self.uclass_id, self.compat, self.priv))
 
 
+class UclassDriver:
+    """Holds information about a uclass driver
+
+    Attributes:
+        name: Uclass name, e.g. 'i2c' if the driver is for UCLASS_I2C
+        uclass_id: Uclass ID, e.g. 'UCLASS_I2C'
+        priv: struct name of the private data, e.g. 'i2c_priv'
+        per_dev_priv (str): struct name of the priv_auto member, e.g. 'spi_info'
+        per_dev_plat (str): struct name of the plat_auto member, e.g. 'i2c_chip'
+        per_child_priv (str): struct name of the per_child_auto member,
+            e.g. 'pci_child_priv'
+        per_child_plat (str): struct name of the per_child_plat_auto member,
+            e.g. 'pci_child_plat'
+    """
+    def __init__(self, name):
+        self.name = name
+        self.uclass_id = None
+        self.priv = ''
+        self.per_dev_priv = ''
+        self.per_dev_plat = ''
+        self.per_child_priv = ''
+        self.per_child_plat = ''
+
+    def __eq__(self, other):
+        return (self.name == other.name and
+                self.uclass_id == other.uclass_id and
+                self.priv == other.priv)
+
+    def __repr__(self):
+        return ("UclassDriver(name='%s', uclass_id='%s')" %
+                (self.name, self.uclass_id))
+
+    def __hash__(self):
+        # We can use the uclass ID since it is unique among uclasses
+        return hash(self.uclass_id)
+
+
 class Scanner:
     """Scanning of the U-Boot source tree
 
@@ -111,6 +148,9 @@ class Scanner:
                key: Compatible string, e.g. 'rockchip,rk3288-grf'
                value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
         _compat_to_driver: Maps compatible strings to Driver
+        _uclass: Dict of uclass information
+            key: uclass name, e.g. 'UCLASS_I2C'
+            value: UClassDriver
     """
     def __init__(self, basedir, warning_disabled, drivers_additional):
         """Set up a new Scanner
@@ -126,6 +166,7 @@ class Scanner:
         self._warning_disabled = warning_disabled
         self._of_match = {}
         self._compat_to_driver = {}
+        self._uclass = {}
 
     def get_normalized_compat_name(self, node):
         """Get a node's normalized compat name
@@ -179,6 +220,85 @@ class Scanner:
         """
         return re.compile(r'^\s*.%s\s*=\s*sizeof\(struct\s+(.*)\),$' % member)
 
+    def _parse_uclass_driver(self, fname, buff):
+        """Parse a C file to extract uclass driver information contained within
+
+        This parses UCLASS_DRIVER() structs to obtain various pieces of useful
+        information.
+
+        It updates the following member:
+            _uclass: Dict of uclass information
+                key: uclass name, e.g. 'UCLASS_I2C'
+                value: UClassDriver
+
+        Args:
+            fname (str): Filename being parsed (used for warnings)
+            buff (str): Contents of file
+        """
+        uc_drivers = {}
+
+        # Collect the driver name and associated Driver
+        driver = None
+        re_driver = re.compile(r'UCLASS_DRIVER\((.*)\)')
+
+        # Collect the uclass ID, e.g. 'UCLASS_SPI'
+        re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
+
+        # Matches the header/size information for uclass-private data
+        re_priv = self._get_re_for_member('priv_auto')
+
+        # Set up parsing for the auto members
+        re_per_device_priv = self._get_re_for_member('per_device_auto')
+        re_per_device_plat = self._get_re_for_member('per_device_plat_auto')
+        re_per_child_priv = self._get_re_for_member('per_child_auto')
+        re_per_child_plat = self._get_re_for_member('per_child_plat_auto')
+
+        prefix = ''
+        for line in buff.splitlines():
+            # Handle line continuation
+            if prefix:
+                line = prefix + line
+                prefix = ''
+            if line.endswith('\\'):
+                prefix = line[:-1]
+                continue
+
+            driver_match = re_driver.search(line)
+
+            # If we have seen UCLASS_DRIVER()...
+            if driver:
+                m_id = re_id.search(line)
+                m_priv = re_priv.match(line)
+                m_per_dev_priv = re_per_device_priv.match(line)
+                m_per_dev_plat = re_per_device_plat.match(line)
+                m_per_child_priv = re_per_child_priv.match(line)
+                m_per_child_plat = re_per_child_plat.match(line)
+                if m_id:
+                    driver.uclass_id = m_id.group(1)
+                elif m_priv:
+                    driver.priv = m_priv.group(1)
+                elif m_per_dev_priv:
+                    driver.per_dev_priv = m_per_dev_priv.group(1)
+                elif m_per_dev_plat:
+                    driver.per_dev_plat = m_per_dev_plat.group(1)
+                elif m_per_child_priv:
+                    driver.per_child_priv = m_per_child_priv.group(1)
+                elif m_per_child_plat:
+                    driver.per_child_plat = m_per_child_plat.group(1)
+                elif '};' in line:
+                    if not driver.uclass_id:
+                        raise ValueError(
+                            "%s: Cannot parse uclass ID in driver '%s'" %
+                            (fname, driver.name))
+                    uc_drivers[driver.uclass_id] = driver
+                    driver = None
+
+            elif driver_match:
+                driver_name = driver_match.group(1)
+                driver = UclassDriver(driver_name)
+
+        self._uclass.update(uc_drivers)
+
     def _parse_driver(self, fname, buff):
         """Parse a C file to extract driver information contained within
 
@@ -348,6 +468,8 @@ class Scanner:
             # obtain driver information
             if 'U_BOOT_DRIVER' in buff:
                 self._parse_driver(fname, buff)
+            if 'UCLASS_DRIVER' in buff:
+                self._parse_uclass_driver(fname, buff)
 
             # The following re will search for driver aliases declared as
             # DM_DRIVER_ALIAS(alias, driver_name)
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 62dea2a9612..641d6495de3 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -7,6 +7,7 @@
 This includes unit tests for scanning of the source code
 """
 
+import copy
 import os
 import shutil
 import tempfile
@@ -263,3 +264,57 @@ U_BOOT_DRIVER(testing) = {
         self.assertEqual('some_cpriv', drv.child_priv)
         self.assertEqual('some_cplat', drv.child_plat)
         self.assertEqual(1, len(scan._drivers))
+
+    def test_uclass_scan(self):
+        """Test collection of uclass-driver info"""
+        buff = '''
+UCLASS_DRIVER(i2c) = {
+	.id		= UCLASS_I2C,
+	.name		= "i2c",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.priv_auto	= sizeof(struct some_priv),
+	.per_device_auto	= sizeof(struct per_dev_priv),
+	.per_device_plat_auto	= sizeof(struct per_dev_plat),
+	.per_child_auto	= sizeof(struct per_child_priv),
+	.per_child_plat_auto	= sizeof(struct per_child_plat),
+	.child_post_bind = i2c_child_post_bind,
+};
+
+'''
+        scan = src_scan.Scanner(None, False, None)
+        scan._parse_uclass_driver('file.c', buff)
+        self.assertIn('UCLASS_I2C', scan._uclass)
+        drv = scan._uclass['UCLASS_I2C']
+        self.assertEqual('i2c', drv.name)
+        self.assertEqual('UCLASS_I2C', drv.uclass_id)
+        self.assertEqual('some_priv', drv.priv)
+        self.assertEqual('per_dev_priv', drv.per_dev_priv)
+        self.assertEqual('per_dev_plat', drv.per_dev_plat)
+        self.assertEqual('per_child_priv', drv.per_child_priv)
+        self.assertEqual('per_child_plat', drv.per_child_plat)
+        self.assertEqual(1, len(scan._uclass))
+
+        drv2 = copy.deepcopy(drv)
+        self.assertEqual(drv, drv2)
+        drv2.priv = 'other_priv'
+        self.assertNotEqual(drv, drv2)
+
+        # The hashes only depend on the uclass ID, so should be equal
+        self.assertEqual(drv.__hash__(), drv2.__hash__())
+
+        self.assertEqual("UclassDriver(name='i2c', uclass_id='UCLASS_I2C')",
+                         str(drv))
+
+    def test_uclass_scan_errors(self):
+        """Test detection of uclass scanning errors"""
+        buff = '''
+UCLASS_DRIVER(i2c) = {
+	.name		= "i2c",
+};
+
+'''
+        scan = src_scan.Scanner(None, False, None)
+        with self.assertRaises(ValueError) as exc:
+            scan._parse_uclass_driver('file.c', buff)
+        self.assertIn("file.c: Cannot parse uclass ID in driver 'i2c'",
+                      str(exc.exception))
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 07/33] dtoc: Support scanning of structs in header files
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (5 preceding siblings ...)
  2021-02-03 13:00 ` [PATCH v2 06/33] dtoc: Support scanning of uclasses Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 08/33] dtoc: Move test files into a test/ directory Simon Glass
                   ` (58 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

Drivers can have private / platform data contained in structs and these
struct definitions are generally kept in header files. In order to
generate build-time devices, dtoc needs to generate code that declares
the data contained in those structs. This generated code must include the
relevant header file, to avoid a build error.

We need a way for dtoc to scan header files for struct definitions. Then,
when it wants to generate code that uses a struct, it can make sure it
includes the correct header file, first.

Add a parser for struct information, similar to drivers. Keep a dict of
the structs that were found.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 86 +++++++++++++++++++++++++++++++++++--
 tools/dtoc/test_src_scan.py | 45 +++++++++++++++++++
 2 files changed, 128 insertions(+), 3 deletions(-)

diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index 3245d02e09b..bf3e5de9b1e 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -126,6 +126,22 @@ class UclassDriver:
         return hash(self.uclass_id)
 
 
+class Struct:
+    """Holds information about a struct definition
+
+    Attributes:
+        name: Struct name, e.g. 'fred' if the struct is 'struct fred'
+        fname: Filename containing the struct, in a format that C files can
+            include, e.g. 'asm/clk.h'
+    """
+    def __init__(self, name, fname):
+        self.name = name
+        self.fname =fname
+
+    def __repr__(self):
+        return ("Struct(name='%s', fname='%s')" % (self.name, self.fname))
+
+
 class Scanner:
     """Scanning of the U-Boot source tree
 
@@ -151,6 +167,9 @@ class Scanner:
         _uclass: Dict of uclass information
             key: uclass name, e.g. 'UCLASS_I2C'
             value: UClassDriver
+        _structs: Dict of all structs found in U-Boot:
+            key: Name of struct
+            value: Struct object
     """
     def __init__(self, basedir, warning_disabled, drivers_additional):
         """Set up a new Scanner
@@ -167,6 +186,7 @@ class Scanner:
         self._of_match = {}
         self._compat_to_driver = {}
         self._uclass = {}
+        self._structs = {}
 
     def get_normalized_compat_name(self, node):
         """Get a node's normalized compat name
@@ -204,6 +224,41 @@ class Scanner:
 
         return compat_list_c[0], compat_list_c[1:]
 
+    def _parse_structs(self, fname, buff):
+        """Parse a H file to extract struct definitions contained within
+
+        This parses 'struct xx {' definitions to figure out what structs this
+        header defines.
+
+        Args:
+            buff (str): Contents of file
+            fname (str): Filename (to use when printing errors)
+        """
+        structs = {}
+
+        re_struct = re.compile('^struct ([a-z0-9_]+) {$')
+        re_asm = re.compile('../arch/[a-z0-9]+/include/asm/(.*)')
+        prefix = ''
+        for line in buff.splitlines():
+            # Handle line continuation
+            if prefix:
+                line = prefix + line
+                prefix = ''
+            if line.endswith('\\'):
+                prefix = line[:-1]
+                continue
+
+            m_struct = re_struct.match(line)
+            if m_struct:
+                name = m_struct.group(1)
+                include_dir = os.path.join(self._basedir, 'include')
+                rel_fname = os.path.relpath(fname, include_dir)
+                m_asm = re_asm.match(rel_fname)
+                if m_asm:
+                    rel_fname = 'asm/' + m_asm.group(1)
+                structs[name] = Struct(name, rel_fname)
+        self._structs.update(structs)
+
     @classmethod
     def _get_re_for_member(cls, member):
         """_get_re_for_member: Get a compiled regular expression
@@ -482,6 +537,29 @@ class Scanner:
                     continue
                 self._driver_aliases[alias[1]] = alias[0]
 
+    def scan_header(self, fname):
+        """Scan a header file to build a list of struct definitions
+
+        It updates the following members:
+            _structs - updated with new Struct records for each struct found
+                in the file
+
+        Args
+            fname: header filename to scan
+        """
+        with open(fname, encoding='utf-8') as inf:
+            try:
+                buff = inf.read()
+            except UnicodeDecodeError:
+                # This seems to happen on older Python versions
+                print("Skipping file '%s' due to unicode error" % fname)
+                return
+
+            # If this file has any U_BOOT_DRIVER() declarations, process it to
+            # obtain driver information
+            if 'struct' in buff:
+                self._parse_structs(fname, buff)
+
     def scan_drivers(self):
         """Scan the driver folders to build a list of driver names and aliases
 
@@ -494,9 +572,11 @@ class Scanner:
             if rel_path.startswith('build') or rel_path.startswith('.git'):
                 continue
             for fname in filenames:
-                if not fname.endswith('.c'):
-                    continue
-                self.scan_driver(dirpath + '/' + fname)
+                pathname = dirpath + '/' + fname
+                if fname.endswith('.c'):
+                    self.scan_driver(pathname)
+                elif fname.endswith('.h'):
+                    self.scan_header(pathname)
 
         for fname in self._drivers_additional:
             if not isinstance(fname, str) or len(fname) == 0:
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 641d6495de3..a0b0e097eb2 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -318,3 +318,48 @@ UCLASS_DRIVER(i2c) = {
             scan._parse_uclass_driver('file.c', buff)
         self.assertIn("file.c: Cannot parse uclass ID in driver 'i2c'",
                       str(exc.exception))
+
+    def test_struct_scan(self):
+        """Test collection of struct info"""
+        buff = '''
+/* some comment */
+struct some_struct1 {
+	struct i2c_msg *msgs;
+	uint nmsgs;
+};
+'''
+        scan = src_scan.Scanner(None, False, None)
+        scan._basedir = os.path.join(OUR_PATH, '..', '..')
+        scan._parse_structs('arch/arm/include/asm/file.h', buff)
+        self.assertIn('some_struct1', scan._structs)
+        struc = scan._structs['some_struct1']
+        self.assertEqual('some_struct1', struc.name)
+        self.assertEqual('asm/file.h', struc.fname)
+
+        buff = '''
+/* another comment */
+struct another_struct {
+	int speed_hz;
+	int max_transaction_bytes;
+};
+'''
+        scan._parse_structs('include/file2.h', buff)
+        self.assertIn('another_struct', scan._structs)
+        struc = scan._structs['another_struct']
+        self.assertEqual('another_struct', struc.name)
+        self.assertEqual('file2.h', struc.fname)
+
+        self.assertEqual(2, len(scan._structs))
+
+        self.assertEqual("Struct(name='another_struct', fname='file2.h')",
+                         str(struc))
+
+    def test_struct_scan_errors(self):
+        """Test scanning a header file with an invalid unicode file"""
+        output = tools.GetOutputFilename('output.h')
+        tools.WriteFile(output, b'struct this is a test \x81 of bad unicode')
+
+        scan = src_scan.Scanner(None, False, None)
+        with test_util.capture_sys_output() as (stdout, _):
+            scan.scan_header(output)
+        self.assertIn('due to unicode error', stdout.getvalue())
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 08/33] dtoc: Move test files into a test/ directory
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (6 preceding siblings ...)
  2021-02-03 13:00 ` [PATCH v2 07/33] dtoc: Support scanning of structs in header files Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 09/33] dtoc: Rename sandbox_i2c_test and sandbox_pmic_test Simon Glass
                   ` (57 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

It is confusing to have the test files in the same places as the
implementation. Move them into a separate directory.

Add a helper function for test_dtoc, to avoid repeating the same
path.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/{ => test}/dtoc_test.dts           |  0
 tools/dtoc/{ => test}/dtoc_test_add_prop.dts  |  0
 tools/dtoc/{ => test}/dtoc_test_addr32.dts    |  0
 tools/dtoc/{ => test}/dtoc_test_addr32_64.dts |  0
 tools/dtoc/{ => test}/dtoc_test_addr64.dts    |  0
 tools/dtoc/{ => test}/dtoc_test_addr64_32.dts |  0
 tools/dtoc/{ => test}/dtoc_test_aliases.dts   |  0
 tools/dtoc/{ => test}/dtoc_test_bad_reg.dts   |  0
 tools/dtoc/{ => test}/dtoc_test_bad_reg2.dts  |  0
 .../{ => test}/dtoc_test_driver_alias.dts     |  0
 tools/dtoc/{ => test}/dtoc_test_empty.dts     |  0
 .../{ => test}/dtoc_test_invalid_driver.dts   |  0
 tools/dtoc/{ => test}/dtoc_test_phandle.dts   |  0
 .../dtoc/{ => test}/dtoc_test_phandle_bad.dts |  0
 .../{ => test}/dtoc_test_phandle_bad2.dts     |  0
 .../{ => test}/dtoc_test_phandle_cd_gpios.dts |  0
 .../{ => test}/dtoc_test_phandle_reorder.dts  |  0
 .../{ => test}/dtoc_test_phandle_single.dts   |  0
 .../{ => test}/dtoc_test_scan_drivers.cxx     |  0
 tools/dtoc/{ => test}/dtoc_test_simple.dts    |  0
 tools/dtoc/test_dtoc.py                       |  2 +-
 tools/dtoc/test_fdt.py                        | 31 +++++++++++++------
 tools/dtoc/test_src_scan.py                   |  3 +-
 23 files changed, 24 insertions(+), 12 deletions(-)
 rename tools/dtoc/{ => test}/dtoc_test.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_add_prop.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr32.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr32_64.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr64.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr64_32.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_aliases.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_bad_reg.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_bad_reg2.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_driver_alias.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_empty.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_invalid_driver.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_bad.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_bad2.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_cd_gpios.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_reorder.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_single.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_scan_drivers.cxx (100%)
 rename tools/dtoc/{ => test}/dtoc_test_simple.dts (100%)

diff --git a/tools/dtoc/dtoc_test.dts b/tools/dtoc/test/dtoc_test.dts
similarity index 100%
rename from tools/dtoc/dtoc_test.dts
rename to tools/dtoc/test/dtoc_test.dts
diff --git a/tools/dtoc/dtoc_test_add_prop.dts b/tools/dtoc/test/dtoc_test_add_prop.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_add_prop.dts
rename to tools/dtoc/test/dtoc_test_add_prop.dts
diff --git a/tools/dtoc/dtoc_test_addr32.dts b/tools/dtoc/test/dtoc_test_addr32.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_addr32.dts
rename to tools/dtoc/test/dtoc_test_addr32.dts
diff --git a/tools/dtoc/dtoc_test_addr32_64.dts b/tools/dtoc/test/dtoc_test_addr32_64.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_addr32_64.dts
rename to tools/dtoc/test/dtoc_test_addr32_64.dts
diff --git a/tools/dtoc/dtoc_test_addr64.dts b/tools/dtoc/test/dtoc_test_addr64.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_addr64.dts
rename to tools/dtoc/test/dtoc_test_addr64.dts
diff --git a/tools/dtoc/dtoc_test_addr64_32.dts b/tools/dtoc/test/dtoc_test_addr64_32.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_addr64_32.dts
rename to tools/dtoc/test/dtoc_test_addr64_32.dts
diff --git a/tools/dtoc/dtoc_test_aliases.dts b/tools/dtoc/test/dtoc_test_aliases.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_aliases.dts
rename to tools/dtoc/test/dtoc_test_aliases.dts
diff --git a/tools/dtoc/dtoc_test_bad_reg.dts b/tools/dtoc/test/dtoc_test_bad_reg.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_bad_reg.dts
rename to tools/dtoc/test/dtoc_test_bad_reg.dts
diff --git a/tools/dtoc/dtoc_test_bad_reg2.dts b/tools/dtoc/test/dtoc_test_bad_reg2.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_bad_reg2.dts
rename to tools/dtoc/test/dtoc_test_bad_reg2.dts
diff --git a/tools/dtoc/dtoc_test_driver_alias.dts b/tools/dtoc/test/dtoc_test_driver_alias.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_driver_alias.dts
rename to tools/dtoc/test/dtoc_test_driver_alias.dts
diff --git a/tools/dtoc/dtoc_test_empty.dts b/tools/dtoc/test/dtoc_test_empty.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_empty.dts
rename to tools/dtoc/test/dtoc_test_empty.dts
diff --git a/tools/dtoc/dtoc_test_invalid_driver.dts b/tools/dtoc/test/dtoc_test_invalid_driver.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_invalid_driver.dts
rename to tools/dtoc/test/dtoc_test_invalid_driver.dts
diff --git a/tools/dtoc/dtoc_test_phandle.dts b/tools/dtoc/test/dtoc_test_phandle.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_phandle.dts
rename to tools/dtoc/test/dtoc_test_phandle.dts
diff --git a/tools/dtoc/dtoc_test_phandle_bad.dts b/tools/dtoc/test/dtoc_test_phandle_bad.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_phandle_bad.dts
rename to tools/dtoc/test/dtoc_test_phandle_bad.dts
diff --git a/tools/dtoc/dtoc_test_phandle_bad2.dts b/tools/dtoc/test/dtoc_test_phandle_bad2.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_phandle_bad2.dts
rename to tools/dtoc/test/dtoc_test_phandle_bad2.dts
diff --git a/tools/dtoc/dtoc_test_phandle_cd_gpios.dts b/tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_phandle_cd_gpios.dts
rename to tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts
diff --git a/tools/dtoc/dtoc_test_phandle_reorder.dts b/tools/dtoc/test/dtoc_test_phandle_reorder.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_phandle_reorder.dts
rename to tools/dtoc/test/dtoc_test_phandle_reorder.dts
diff --git a/tools/dtoc/dtoc_test_phandle_single.dts b/tools/dtoc/test/dtoc_test_phandle_single.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_phandle_single.dts
rename to tools/dtoc/test/dtoc_test_phandle_single.dts
diff --git a/tools/dtoc/dtoc_test_scan_drivers.cxx b/tools/dtoc/test/dtoc_test_scan_drivers.cxx
similarity index 100%
rename from tools/dtoc/dtoc_test_scan_drivers.cxx
rename to tools/dtoc/test/dtoc_test_scan_drivers.cxx
diff --git a/tools/dtoc/dtoc_test_simple.dts b/tools/dtoc/test/dtoc_test_simple.dts
similarity index 100%
rename from tools/dtoc/dtoc_test_simple.dts
rename to tools/dtoc/test/dtoc_test_simple.dts
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 6865d949a05..523f0a923eb 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -72,7 +72,7 @@ def get_dtb_file(dts_fname, capture_stderr=False):
     Returns:
         str: Filename of compiled file in output directory
     """
-    return fdt_util.EnsureCompiled(os.path.join(OUR_PATH, dts_fname),
+    return fdt_util.EnsureCompiled(os.path.join(OUR_PATH, 'test', dts_fname),
                                    capture_stderr=capture_stderr)
 
 
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index e8fbbd5d10a..1c3a8a2ab1e 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -48,6 +48,17 @@ def _GetPropertyValue(dtb, node, prop_name):
     data = dtb.GetContents()[offset:offset + len(prop.value)]
     return prop, [chr(x) for x in data]
 
+def find_dtb_file(dts_fname):
+    """Locate a test file in the test/ directory
+
+    Args:
+        dts_fname (str): Filename to find, e.g. 'dtoc_test_simple.dts]
+
+    Returns:
+        str: Path to the test filename
+    """
+    return os.path.join('tools/dtoc/test', dts_fname)
+
 
 class TestFdt(unittest.TestCase):
     """Tests for the Fdt module
@@ -64,7 +75,7 @@ class TestFdt(unittest.TestCase):
         tools.FinaliseOutputDir()
 
     def setUp(self):
-        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+        self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
 
     def testFdt(self):
         """Test that we can open an Fdt"""
@@ -141,7 +152,7 @@ class TestNode(unittest.TestCase):
         tools.FinaliseOutputDir()
 
     def setUp(self):
-        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+        self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
         self.node = self.dtb.GetNode('/spl-test')
 
     def testOffset(self):
@@ -203,7 +214,7 @@ class TestNode(unittest.TestCase):
 
     def testLookupPhandle(self):
         """Test looking up a single phandle"""
-        dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+        dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
         node = dtb.GetNode('/phandle-source2')
         prop = node.props['clocks']
         target = dtb.GetNode('/phandle-target')
@@ -222,7 +233,7 @@ class TestProp(unittest.TestCase):
         tools.FinaliseOutputDir()
 
     def setUp(self):
-        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+        self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
         self.node = self.dtb.GetNode('/spl-test')
         self.fdt = self.dtb.GetFdtObj()
 
@@ -230,7 +241,7 @@ class TestProp(unittest.TestCase):
         self.assertEqual(None, self.dtb.GetNode('missing'))
 
     def testPhandle(self):
-        dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+        dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
         node = dtb.GetNode('/phandle-source2')
         prop = node.props['clocks']
         self.assertTrue(fdt32_to_cpu(prop.value) > 0)
@@ -488,7 +499,7 @@ class TestFdtUtil(unittest.TestCase):
         tools.FinaliseOutputDir()
 
     def setUp(self):
-        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+        self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
         self.node = self.dtb.GetNode('/spl-test')
 
     def testGetInt(self):
@@ -531,7 +542,7 @@ class TestFdtUtil(unittest.TestCase):
                       str(e.exception))
 
     def testGetPhandleList(self):
-        dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+        dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
         node = dtb.GetNode('/phandle-source2')
         self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
         node = dtb.GetNode('/phandle-source')
@@ -551,7 +562,7 @@ class TestFdtUtil(unittest.TestCase):
         self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
         self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
 
-        dtb2 = fdt.FdtScan('tools/dtoc/dtoc_test_addr64.dts')
+        dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
         node1 = dtb2.GetNode('/test1')
         val = node1.props['reg'].value
         self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
@@ -565,7 +576,7 @@ class TestFdtUtil(unittest.TestCase):
 
     def testEnsureCompiled(self):
         """Test a degenerate case of this function (file already compiled)"""
-        dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts')
+        dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
         self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
 
     def testEnsureCompiledTmpdir(self):
@@ -574,7 +585,7 @@ class TestFdtUtil(unittest.TestCase):
             old_outdir = tools.outdir
             tools.outdir= None
             tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
-            dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts',
+            dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
                                           tmpdir)
             self.assertEqual(tmpdir, os.path.dirname(dtb))
             shutil.rmtree(tmpdir)
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index a0b0e097eb2..a7eba3005e5 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -59,7 +59,8 @@ class TestSrcScan(unittest.TestCase):
     def test_additional(self):
         """Test with additional drivers to scan"""
         scan = src_scan.Scanner(
-            None, True, [None, '', 'tools/dtoc/dtoc_test_scan_drivers.cxx'])
+            None, True,
+            [None, '', 'tools/dtoc/test/dtoc_test_scan_drivers.cxx'])
         scan.scan_drivers()
         self.assertIn('sandbox_gpio_alias2', scan._driver_aliases)
         self.assertEqual('sandbox_gpio',
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 09/33] dtoc: Rename sandbox_i2c_test and sandbox_pmic_test
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (7 preceding siblings ...)
  2021-02-03 13:00 ` [PATCH v2 08/33] dtoc: Move test files into a test/ directory Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 10/33] dtoc: Add some extra properties to nodes Simon Glass
                   ` (56 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

These have '_test' suffixes which are not present on the drivers in the
source code. Drop the suffixes to avoid a mismatch when scanning.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/test/dtoc_test_simple.dts |  4 ++--
 tools/dtoc/test_dtoc.py              | 12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/tools/dtoc/test/dtoc_test_simple.dts b/tools/dtoc/test/dtoc_test_simple.dts
index 1c87b891929..d8ab8613ee3 100644
--- a/tools/dtoc/test/dtoc_test_simple.dts
+++ b/tools/dtoc/test/dtoc_test_simple.dts
@@ -45,12 +45,12 @@
 	};
 
 	i2c at 0 {
-		compatible = "sandbox,i2c-test";
+		compatible = "sandbox,i2c";
 		u-boot,dm-pre-reloc;
 		#address-cells = <1>;
 		#size-cells = <0>;
 		pmic at 9 {
-			compatible = "sandbox,pmic-test";
+			compatible = "sandbox,pmic";
 			u-boot,dm-pre-reloc;
 			reg = <9>;
 			low-power;
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 523f0a923eb..9049c2895f1 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -207,9 +207,9 @@ class TestDtoc(unittest.TestCase):
         self.assertEqual(C_HEADER.splitlines() + [''], lines)
 
     struct_text = HEADER + '''
-struct dtd_sandbox_i2c_test {
+struct dtd_sandbox_i2c {
 };
-struct dtd_sandbox_pmic_test {
+struct dtd_sandbox_pmic {
 \tbool\t\tlow_power;
 \tfdt64_t\t\treg[2];
 };
@@ -229,22 +229,22 @@ struct dtd_sandbox_spl_test {
 
     platdata_text = C_HEADER + '''
 /* Node /i2c at 0 index 0 */
-static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
+static struct dtd_sandbox_i2c dtv_i2c_at_0 = {
 };
 U_BOOT_DRVINFO(i2c_at_0) = {
-\t.name\t\t= "sandbox_i2c_test",
+\t.name\t\t= "sandbox_i2c",
 \t.plat\t= &dtv_i2c_at_0,
 \t.plat_size\t= sizeof(dtv_i2c_at_0),
 \t.parent_idx\t= -1,
 };
 
 /* Node /i2c at 0/pmic at 9 index 1 */
-static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
+static struct dtd_sandbox_pmic dtv_pmic_at_9 = {
 \t.low_power\t\t= true,
 \t.reg\t\t\t= {0x9, 0x0},
 };
 U_BOOT_DRVINFO(pmic_at_9) = {
-\t.name\t\t= "sandbox_pmic_test",
+\t.name\t\t= "sandbox_pmic",
 \t.plat\t= &dtv_pmic_at_9,
 \t.plat_size\t= sizeof(dtv_pmic_at_9),
 \t.parent_idx\t= 0,
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 10/33] dtoc: Add some extra properties to nodes
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (8 preceding siblings ...)
  2021-02-03 13:00 ` [PATCH v2 09/33] dtoc: Rename sandbox_i2c_test and sandbox_pmic_test Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:00 ` [PATCH v2 11/33] dtoc: Make use of node properties Simon Glass
                   ` (55 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

It is convenient to attach drivers, etc. to nodes so that we can use the
Node object as the main data structure in this module.

Add a function which adds the new properties, along with documentation.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index e9be5985c72..8c36fbc68d2 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -354,8 +354,44 @@ class DtbPlatdata():
         self.scan_node(self._fdt.GetRoot(), valid_nodes)
         self._valid_nodes = sorted(valid_nodes,
                                    key=lambda x: conv_name_to_c(x.name))
+
+    def prepare_nodes(self):
+        """Add extra properties to the nodes we are using
+
+        The following properties are added for use by dtoc:
+            idx: Index number of this node (0=first, etc.)
+            struct_name: Name of the struct dtd used by this node
+            var_name: C name for this node
+            child_devs: List of child devices for this node, each a None
+            child_refs: Dict of references for each child:
+                key: Position in child list (-1=head, 0=first, 1=second, ...
+                                             n-1=last, n=head)
+            seq: Sequence number of the device (unique within its uclass), or
+                -1 not not known yet
+            dev_ref: Reference to this device, e.g. 'DM_DEVICE_REF(serial)'
+            driver: Driver record for this node, or None if not known
+            uclass: Uclass record for this node, or None if not known
+            uclass_seq: Position of this device within the uclass list (0=first,
+                n-1=last)
+            parent_seq: Position of this device within it siblings (0=first,
+                n-1=last)
+            parent_driver: Driver record of the node's parent, or None if none.
+                We don't use node.parent.driver since node.parent may not be in
+                the list of valid nodes
+        """
         for idx, node in enumerate(self._valid_nodes):
             node.idx = idx
+            node.struct_name, _ = self._scan.get_normalized_compat_name(node)
+            node.var_name = conv_name_to_c(node.name)
+            node.child_devs = []
+            node.child_refs = {}
+            node.seq = -1
+            node.dev_ref = None
+            node.driver = None
+            node.uclass = None
+            node.uclass_seq = None
+            node.parent_seq = None
+            node.parent_driver = None
 
     @staticmethod
     def get_num_cells(node):
@@ -705,6 +741,7 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
     plat = DtbPlatdata(scan, dtb_file, include_disabled)
     plat.scan_dtb()
     plat.scan_tree()
+    plat.prepare_nodes()
     plat.scan_reg_sizes()
     plat.setup_output_dirs(output_dirs)
     plat.scan_structs()
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 11/33] dtoc: Make use of node properties
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (9 preceding siblings ...)
  2021-02-03 13:00 ` [PATCH v2 10/33] dtoc: Add some extra properties to nodes Simon Glass
@ 2021-02-03 13:00 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 12/33] dtoc: Process nodes to set up required properties Simon Glass
                   ` (54 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:00 UTC (permalink / raw)
  To: u-boot

Now that we have these available, use them instead of recalculating
things each time.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 45 ++++++++++++++++----------------------
 1 file changed, 19 insertions(+), 26 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 8c36fbc68d2..2ec22edfbf0 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -470,7 +470,6 @@ class DtbPlatdata():
         """
         structs = self._struct_data
         for node in self._valid_nodes:
-            node_name, _ = self._scan.get_normalized_compat_name(node)
             fields = {}
 
             # Get a list of all the valid properties in this node.
@@ -478,9 +477,9 @@ class DtbPlatdata():
                 if name not in PROP_IGNORE_LIST and name[0] != '#':
                     fields[name] = copy.deepcopy(prop)
 
-            # If we've seen this node_name before, update the existing struct.
-            if node_name in structs:
-                struct = structs[node_name]
+            # If we've seen this struct_name before, update the existing struct
+            if node.struct_name in structs:
+                struct = structs[node.struct_name]
                 for name, prop in fields.items():
                     oldprop = struct.get(name)
                     if oldprop:
@@ -490,11 +489,10 @@ class DtbPlatdata():
 
             # Otherwise store this as a new struct.
             else:
-                structs[node_name] = fields
+                structs[node.struct_name] = fields
 
         for node in self._valid_nodes:
-            node_name, _ = self._scan.get_normalized_compat_name(node)
-            struct = structs[node_name]
+            struct = structs[node.struct_name]
             for name, prop in node.props.items():
                 if name not in PROP_IGNORE_LIST and name[0] != '#':
                     prop.Widen(struct[name])
@@ -598,23 +596,22 @@ class DtbPlatdata():
                 self.buf(', '.join(vals[i:i + 8]))
         self.buf('}')
 
-    def _declare_device(self, var_name, struct_name, node_parent):
+    def _declare_device(self, node):
         """Add a device declaration to the output
 
         This declares a U_BOOT_DRVINFO() for the device being processed
 
         Args:
-            var_name (str): C name for the node
-            struct_name (str): Name for the dt struct associated with the node
-            node_parent (Node): Parent of the node (or None if none)
+            node: Node to process
         """
-        self.buf('U_BOOT_DRVINFO(%s) = {\n' % var_name)
-        self.buf('\t.name\t\t= "%s",\n' % struct_name)
-        self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, var_name))
-        self.buf('\t.plat_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
+        self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
+        self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
+        self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
+        self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
+                 (VAL_PREFIX, node.var_name))
         idx = -1
-        if node_parent and node_parent in self._valid_nodes:
-            idx = node_parent.idx
+        if node.parent and node.parent in self._valid_nodes:
+            idx = node.parent.idx
         self.buf('\t.parent_idx\t= %d,\n' % idx)
         self.buf('};\n')
         self.buf('\n')
@@ -638,16 +635,14 @@ class DtbPlatdata():
             self.buf(get_value(prop.type, prop.value))
         self.buf(',\n')
 
-    def _output_values(self, var_name, struct_name, node):
+    def _output_values(self, node):
         """Output the definition of a device's struct values
 
         Args:
-            var_name (str): C name for the node
-            struct_name (str): Name for the dt struct associated with the node
-            node (Node): Node being output
+            node (Node): Node to output
         """
         self.buf('static struct %s%s %s%s = {\n' %
-                 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
+                 (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
         for pname in sorted(node.props):
             self._output_prop(node, node.props[pname])
         self.buf('};\n')
@@ -658,12 +653,10 @@ class DtbPlatdata():
         Args:
             node (fdt.Node): node to output
         """
-        struct_name, _ = self._scan.get_normalized_compat_name(node)
-        var_name = conv_name_to_c(node.name)
         self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
 
-        self._output_values(var_name, struct_name, node)
-        self._declare_device(var_name, struct_name, node.parent)
+        self._output_values(node)
+        self._declare_device(node)
 
         self.out(''.join(self.get_buf()))
 
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 12/33] dtoc: Process nodes to set up required properties
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (10 preceding siblings ...)
  2021-02-03 13:00 ` [PATCH v2 11/33] dtoc: Make use of node properties Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 13/33] dtoc: Track nodes which are actually used Simon Glass
                   ` (53 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Add logic to assign property values to nodes as required by dtoc. The
references allow nodes to refer to each other in C code. The macros used
by dtoc are not yet defined in driver model. They will be added along
with the actual driver model implementation.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 37 +++++++++++++++++++
 tools/dtoc/src_scan.py     | 11 ++++++
 tools/dtoc/test_dtoc.py    | 76 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 124 insertions(+)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 2ec22edfbf0..ad71f703e52 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -647,6 +647,38 @@ class DtbPlatdata():
             self._output_prop(node, node.props[pname])
         self.buf('};\n')
 
+    def process_nodes(self, need_drivers):
+        nodes_to_output = list(self._valid_nodes)
+
+        for node in nodes_to_output:
+            node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
+            driver = self._scan.get_driver(node.struct_name)
+            if not driver:
+                if not need_drivers:
+                    continue
+                raise ValueError("Cannot parse/find driver for '%s'" %
+                                 node.struct_name)
+            node.driver = driver
+            parent_driver = None
+            if node.parent in self._valid_nodes:
+                parent_driver = self._scan.get_driver(node.parent.struct_name)
+                if not parent_driver:
+                    if not need_drivers:
+                        continue
+                    raise ValueError(
+                        "Cannot parse/find parent driver '%s' for '%s'" %
+                        (node.parent.struct_name, node.struct_name))
+                node.parent_seq = len(node.parent.child_devs)
+                node.parent.child_devs.append(node)
+                node.parent.child_refs[node.parent_seq] = \
+                    '&%s->sibling_node' % node.dev_ref
+                node.parent_driver = parent_driver
+
+        for node in nodes_to_output:
+            ref = '&%s->child_head' % node.dev_ref
+            node.child_refs[-1] = ref
+            node.child_refs[len(node.child_devs)] = ref
+
     def output_node(self, node):
         """Output the C code for a node
 
@@ -731,6 +763,9 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
     if not scan:
         scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional)
         scan.scan_drivers()
+        do_process = True
+    else:
+        do_process = False
     plat = DtbPlatdata(scan, dtb_file, include_disabled)
     plat.scan_dtb()
     plat.scan_tree()
@@ -739,6 +774,8 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
     plat.setup_output_dirs(output_dirs)
     plat.scan_structs()
     plat.scan_phandles()
+    if do_process:
+        plat.process_nodes(False)
 
     cmds = args[0].split(',')
     if 'all' in cmds:
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index bf3e5de9b1e..504dac008d6 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -188,6 +188,17 @@ class Scanner:
         self._uclass = {}
         self._structs = {}
 
+    def get_driver(self, name):
+        """Get a driver given its name
+
+        Args:
+            name (str): Driver name
+
+        Returns:
+            Driver: Driver or None if not found
+        """
+        return self._drivers.get(name)
+
     def get_normalized_compat_name(self, node):
         """Get a node's normalized compat name
 
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 9049c2895f1..3e98e363125 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -953,3 +953,79 @@ U_BOOT_DRVINFO(spl_test2) = {
         self.assertEqual(
             {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb'},
             leafs)
+
+    def setup_process_test(self):
+        """Set up a test of process_nodes()
+
+        This uses saved_scan but returns a deep copy of it, so it is safe to
+        modify it in these tests
+
+        Returns:
+            tuple:
+                DtbPlatdata: object to test
+                Scanner: scanner to use
+        """
+        dtb_file = get_dtb_file('dtoc_test_simple.dts')
+        output = tools.GetOutputFilename('output')
+
+        # Take a copy before messing with it
+        scan = copy.deepcopy(saved_scan)
+        plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
+        plat.scan_dtb()
+        plat.scan_tree()
+        plat.prepare_nodes()
+        return plat, scan
+
+    def test_process_nodes(self):
+        """Test processing nodes to add various info"""
+        plat, scan = self.setup_process_test()
+        plat.process_nodes(True)
+
+        i2c_node = plat._fdt.GetNode('/i2c at 0')
+        pmic_node = plat._fdt.GetNode('/i2c at 0/pmic at 9')
+        pmic = scan._drivers['sandbox_pmic']
+        i2c = scan._drivers['sandbox_i2c']
+        self.assertEqual('DM_DEVICE_REF(pmic_at_9)', pmic_node.dev_ref)
+        self.assertEqual(pmic, pmic_node.driver)
+        self.assertEqual(i2c_node, pmic_node.parent)
+        self.assertEqual(i2c, pmic_node.parent_driver)
+
+        # The pmic is the only child
+        self.assertEqual(pmic_node.parent_seq, 0)
+        self.assertEqual([pmic_node], i2c_node.child_devs)
+
+        # Start and end of the list should be the child_head
+        ref = '&DM_DEVICE_REF(i2c_at_0)->child_head'
+        self.assertEqual(
+            {-1: ref, 0: '&DM_DEVICE_REF(pmic_at_9)->sibling_node', 1: ref},
+            i2c_node.child_refs)
+
+    def test_process_nodes_bad_parent(self):
+        # Pretend that i2c has a parent (the pmic) and delete that driver
+        plat, scan = self.setup_process_test()
+
+        i2c_node = plat._fdt.GetNode('/i2c at 0')
+        pmic_node = plat._fdt.GetNode('/i2c at 0/pmic at 9')
+        del scan._drivers['sandbox_pmic']
+        i2c_node.parent = pmic_node
+
+        # Process twice, the second time to generate an exception
+        plat.process_nodes(False)
+        with self.assertRaises(ValueError) as exc:
+            plat.process_nodes(True)
+        self.assertIn(
+            "Cannot parse/find parent driver 'sandbox_pmic' for 'sandbox_i2c",
+            str(exc.exception))
+
+    def test_process_nodes_bad_node(self):
+        plat, scan = self.setup_process_test()
+
+        # Now remove the pmic driver
+        del scan._drivers['sandbox_pmic']
+
+        # Process twice, the second time to generate an exception
+        plat.process_nodes(False)
+        with self.assertRaises(ValueError) as exc:
+            plat.process_nodes(True)
+        self.assertIn("Cannot parse/find driver for 'sandbox_pmic",
+                      str(exc.exception))
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 13/33] dtoc: Track nodes which are actually used
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (11 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 12/33] dtoc: Process nodes to set up required properties Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 14/33] dtoc: Support tracking the phase of U-Boot Simon Glass
                   ` (52 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Mark all nodes that are actually used, so we can perform extra checks on
them.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py  |  3 +++
 tools/dtoc/src_scan.py      | 25 ++++++++++++++++++++++---
 tools/dtoc/test_dtoc.py     | 11 +++++++++++
 tools/dtoc/test_src_scan.py |  2 +-
 4 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index ad71f703e52..28669f31217 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -650,6 +650,9 @@ class DtbPlatdata():
     def process_nodes(self, need_drivers):
         nodes_to_output = list(self._valid_nodes)
 
+        # Figure out which drivers we actually use
+        self._scan.mark_used(nodes_to_output)
+
         for node in nodes_to_output:
             node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
             driver = self._scan.get_driver(node.struct_name)
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index 504dac008d6..1a02d41063f 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -66,6 +66,7 @@ class Driver:
             e.g. 'pci_child_priv'
         child_plat (str): struct name of the per_child_plat_auto member,
             e.g. 'pci_child_plat'
+        used (bool): True if the driver is used by the structs being output
     """
     def __init__(self, name, fname):
         self.name = name
@@ -76,17 +77,19 @@ class Driver:
         self.plat = ''
         self.child_priv = ''
         self.child_plat = ''
+        self.used = False
 
     def __eq__(self, other):
         return (self.name == other.name and
                 self.uclass_id == other.uclass_id and
                 self.compat == other.compat and
                 self.priv == other.priv and
-                self.plat == other.plat)
+                self.plat == other.plat and
+                self.used == other.used)
 
     def __repr__(self):
-        return ("Driver(name='%s', uclass_id='%s', compat=%s, priv=%s)" %
-                (self.name, self.uclass_id, self.compat, self.priv))
+        return ("Driver(name='%s', used=%s, uclass_id='%s', compat=%s, priv=%s)" %
+                (self.name, self.used, self.uclass_id, self.compat, self.priv))
 
 
 class UclassDriver:
@@ -596,3 +599,19 @@ class Scanner:
                 self.scan_driver(fname)
             else:
                 self.scan_driver(self._basedir + '/' + fname)
+
+    def mark_used(self, nodes):
+        """Mark the drivers associated with a list of nodes as 'used'
+
+        This takes a list of nodes, finds the driver for each one and marks it
+        as used.
+
+        Args:
+            nodes (list of None): Nodes that are in use
+        """
+        # Figure out which drivers we actually use
+        for node in nodes:
+            struct_name, _ = self.get_normalized_compat_name(node)
+            driver = self._drivers.get(struct_name)
+            if driver:
+                driver.used = True
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 3e98e363125..d90ece205d7 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -1029,3 +1029,14 @@ U_BOOT_DRVINFO(spl_test2) = {
             plat.process_nodes(True)
         self.assertIn("Cannot parse/find driver for 'sandbox_pmic",
                       str(exc.exception))
+
+    def test_process_nodes_used(self):
+        """Test processing nodes to add various info"""
+        plat, scan = self.setup_process_test()
+        plat.process_nodes(True)
+
+        pmic = scan._drivers['sandbox_pmic']
+        self.assertTrue(pmic.used)
+
+        gpio = scan._drivers['sandbox_gpio']
+        self.assertFalse(gpio.used)
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index a7eba3005e5..ebdc12abc87 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -98,7 +98,7 @@ class TestSrcScan(unittest.TestCase):
         drv3.uclass_id = i2c
         drv3.compat = compat
         self.assertEqual(
-            "Driver(name='fred', uclass_id='I2C_UCLASS', "
+            "Driver(name='fred', used=False, uclass_id='I2C_UCLASS', "
             "compat={'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF', "
             "'rockchip,rk3288-srf': None}, priv=)", str(drv1))
         self.assertEqual(drv1, drv3)
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 14/33] dtoc: Support tracking the phase of U-Boot
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (12 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 13/33] dtoc: Track nodes which are actually used Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 15/33] Makefile: Pass the U-Boot phase to dtoc Simon Glass
                   ` (51 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

U-Boot operates in several phases, typically TPL, SPL and U-Boot proper.
The latter does not use dtoc.

In some rare cases different drivers are used for two phases. For example,
in TPL it may not be necessary to use the full PCI subsystem, so a simple
driver can be used instead.

This works in the build system simply by compiling in one driver or the
other (e.g. PCI driver + uclass for SPL; simple_bus for TPL). But dtoc has
no way of knowing which code is compiled in for which phase, since it does
not inspect Makefiles or dependency graphs.

So to make this work for dtoc, we need to be able to explicitly mark
drivers with their phase. This is done by adding an empty macro to the
driver. Add support for this in dtoc.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 include/dm/device.h         | 16 ++++++++++++++++
 tools/dtoc/dtb_platdata.py  |  7 +++++--
 tools/dtoc/main.py          |  5 ++++-
 tools/dtoc/src_scan.py      | 12 +++++++++++-
 tools/dtoc/test_dtoc.py     | 16 ++++++++--------
 tools/dtoc/test_src_scan.py |  3 +++
 6 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/include/dm/device.h b/include/dm/device.h
index e665558444b..0086070b58b 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -345,6 +345,22 @@ struct driver {
  */
 #define DM_DRIVER_ALIAS(__name, __alias)
 
+/**
+ * Declare a macro to indicate which phase of U-Boot this driver is fore.
+ *
+ *
+ * This macro produces no code but its information will be parsed by dtoc. The
+ * macro can be only be used once in a driver. Put it within the U_BOOT_DRIVER()
+ * declaration, e.g.:
+ *
+ * U_BOOT_DRIVER(cpu) = {
+ *	.name = ...
+ *	...
+ *	DM_PHASE(tpl)
+ * };
+ */
+#define DM_PHASE(_phase)
+
 /**
  * dev_get_plat() - Get the platform data for a device
  *
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 28669f31217..ef0454c8904 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -733,7 +733,7 @@ OUTPUT_FILES = {
     }
 
 
-def run_steps(args, dtb_file, include_disabled, output, output_dirs,
+def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
               warning_disabled=False, drivers_additional=None, basedir=None,
               scan=None):
     """Run all the steps of the dtoc tool
@@ -746,6 +746,8 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
         output_dirs (tuple of str):
             Directory to put C output files
             Directory to put H output files
+        phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
+             or 'tpl'. None if not known
         warning_disabled (bool): True to avoid showing warnings about missing
             drivers
         drivers_additional (list): List of additional drivers to use during
@@ -764,7 +766,8 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
         raise ValueError('Must specify either output or output_dirs, not both')
 
     if not scan:
-        scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional)
+        scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional,
+                                phase)
         scan.scan_drivers()
         do_process = True
     else:
diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py
index 355b1e62773..15a8ff167a9 100755
--- a/tools/dtoc/main.py
+++ b/tools/dtoc/main.py
@@ -85,6 +85,8 @@ parser.add_option('--include-disabled', action='store_true',
                   help='Include disabled nodes')
 parser.add_option('-o', '--output', action='store',
                   help='Select output filename')
+parser.add_option('-p', '--phase', type=str,
+                  help='set phase of U-Boot this invocation is for (spl/tpl)')
 parser.add_option('-P', '--processes', type=int,
                   help='set number of processes to use for running tests')
 parser.add_option('-t', '--test', action='store_true', dest='test',
@@ -104,4 +106,5 @@ elif options.test_coverage:
 else:
     dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled,
                            options.output,
-                           [options.c_output_dir, options.h_output_dir])
+                           [options.c_output_dir, options.h_output_dir],
+                           phase=options.phase)
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index 1a02d41063f..2699153016c 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -67,6 +67,7 @@ class Driver:
         child_plat (str): struct name of the per_child_plat_auto member,
             e.g. 'pci_child_plat'
         used (bool): True if the driver is used by the structs being output
+        phase (str): Which phase of U-Boot to use this driver
     """
     def __init__(self, name, fname):
         self.name = name
@@ -78,6 +79,7 @@ class Driver:
         self.child_priv = ''
         self.child_plat = ''
         self.used = False
+        self.phase = ''
 
     def __eq__(self, other):
         return (self.name == other.name and
@@ -173,8 +175,10 @@ class Scanner:
         _structs: Dict of all structs found in U-Boot:
             key: Name of struct
             value: Struct object
+        _phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
+             or 'tpl'. None if not known
     """
-    def __init__(self, basedir, warning_disabled, drivers_additional):
+    def __init__(self, basedir, warning_disabled, drivers_additional, phase=''):
         """Set up a new Scanner
         """
         if not basedir:
@@ -190,6 +194,7 @@ class Scanner:
         self._compat_to_driver = {}
         self._uclass = {}
         self._structs = {}
+        self._phase = phase
 
     def get_driver(self, name):
         """Get a driver given its name
@@ -428,6 +433,8 @@ class Scanner:
         re_of_match = re.compile(
             r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,')
 
+        re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$')
+
         # Matches the struct name for priv, plat
         re_priv = self._get_re_for_member('priv_auto')
         re_plat = self._get_re_for_member('plat_auto')
@@ -454,6 +461,7 @@ class Scanner:
                 m_plat = re_plat.match(line)
                 m_cplat = re_child_plat.match(line)
                 m_cpriv = re_child_priv.match(line)
+                m_phase = re_phase.match(line)
                 if m_priv:
                     driver.priv = m_priv.group(1)
                 elif m_plat:
@@ -466,6 +474,8 @@ class Scanner:
                     driver.uclass_id = m_id.group(1)
                 elif m_of_match:
                     compat = m_of_match.group(2)
+                elif m_phase:
+                    driver.phase = m_phase.group(1)
                 elif '};' in line:
                     if driver.uclass_id and compat:
                         if compat not in of_match:
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index d90ece205d7..c1fafb656fb 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -138,8 +138,8 @@ class TestDtoc(unittest.TestCase):
             dtb_file (str): Filename of .dtb file
             output (str): Filename of output file
         """
-        dtb_platdata.run_steps(args, dtb_file, False, output, [], True,
-                               None, None, scan=copy_scan())
+        dtb_platdata.run_steps(args, dtb_file, False, output, [], None,
+                               warning_disabled=True, scan=copy_scan())
 
     def test_name(self):
         """Test conversion of device tree names to C identifiers"""
@@ -365,7 +365,7 @@ U_BOOT_DRVINFO(gpios_at_0) = {
         output = tools.GetOutputFilename('output')
         with test_util.capture_sys_output() as _:
             dtb_platdata.run_steps(['struct'], dtb_file, False, output, [],
-                                   scan=copy_scan())
+                                   None, scan=copy_scan())
         with open(output) as infile:
             data = infile.read()
         self._check_strings(HEADER + '''
@@ -375,7 +375,7 @@ struct dtd_invalid {
 
         with test_util.capture_sys_output() as _:
             dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [],
-                                   scan=copy_scan())
+                                   None, scan=copy_scan())
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
@@ -927,8 +927,8 @@ U_BOOT_DRVINFO(spl_test2) = {
     def test_output_conflict(self):
         """Test a conflict between and output dirs and output file"""
         with self.assertRaises(ValueError) as exc:
-            dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], True,
-                                   scan=copy_scan())
+            dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], None,
+                                   warning_disabled=True, scan=copy_scan())
         self.assertIn("Must specify either output or output_dirs, not both",
                       str(exc.exception))
 
@@ -944,8 +944,8 @@ U_BOOT_DRVINFO(spl_test2) = {
         fnames = glob.glob(outdir + '/*')
         self.assertEqual(2, len(fnames))
 
-        dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], True,
-                               scan=copy_scan())
+        dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], None,
+                               warning_disabled=True, scan=copy_scan())
         fnames = glob.glob(outdir + '/*')
         self.assertEqual(4, len(fnames))
 
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index ebdc12abc87..8d35b33c28a 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -233,6 +233,7 @@ U_BOOT_DRIVER(i2c_tegra) = {
         self.assertIn('i2c_tegra', scan._drivers)
         drv = scan._drivers['i2c_tegra']
         self.assertEqual('i2c_tegra', drv.name)
+        self.assertEqual('', drv.phase)
 
     def test_priv(self):
         """Test collection of struct info from drivers"""
@@ -250,6 +251,7 @@ U_BOOT_DRIVER(testing) = {
 	.plat_auto = sizeof(struct some_plat),
 	.per_child_auto	= sizeof(struct some_cpriv),
 	.per_child_plat_auto = sizeof(struct some_cplat),
+	DM_PHASE(tpl)
 };
 '''
         scan = src_scan.Scanner(None, False, None)
@@ -264,6 +266,7 @@ U_BOOT_DRIVER(testing) = {
         self.assertEqual('some_plat', drv.plat)
         self.assertEqual('some_cpriv', drv.child_priv)
         self.assertEqual('some_cplat', drv.child_plat)
+        self.assertEqual('tpl', drv.phase)
         self.assertEqual(1, len(scan._drivers))
 
     def test_uclass_scan(self):
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 15/33] Makefile: Pass the U-Boot phase to dtoc
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (13 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 14/33] dtoc: Support tracking the phase of U-Boot Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 16/33] dtoc: Support headers needed for drivers Simon Glass
                   ` (50 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Pass the U-Boot phase as a parameter so dtoc can use it. At present it is
ether "spl" or "tpl".

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 scripts/Makefile.spl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index ea4e045769c..67641d0faea 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -309,7 +309,7 @@ $(obj)/$(SPL_BIN).dtb: $(obj)/dts/dt-$(SPL_NAME).dtb FORCE
 pythonpath = PYTHONPATH=scripts/dtc/pylibfdt
 
 DTOC_ARGS := $(pythonpath) $(srctree)/tools/dtoc/dtoc \
-	-d $(obj)/$(SPL_BIN).dtb
+	-d $(obj)/$(SPL_BIN).dtb -p $(SPL_NAME)
 
 quiet_cmd_dtoc = DTOC    $@
 cmd_dtoc = $(DTOC_ARGS) -c $(obj)/dts -C include/generated all
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 16/33] dtoc: Support headers needed for drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (14 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 15/33] Makefile: Pass the U-Boot phase to dtoc Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 17/33] dtoc: Process driver aliases along with drivers Simon Glass
                   ` (49 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Typically dtoc can detect the header file needed for a driver by looking
for the structs that it uses. For example, if a driver as a .priv_auto
that uses 'struct serial_priv', then dtoc can search header files for the
definition of that struct and use the file.

In some cases, enums are used in drivers, typically with the .data field
of struct udevice_id. Since dtoc does not support searching for these,
add a way to tell dtoc which header to use. This works as a macro included
in the driver definition.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 include/dm/device.h         | 18 ++++++++++++++++++
 tools/dtoc/src_scan.py      |  7 +++++++
 tools/dtoc/test_src_scan.py |  4 ++++
 3 files changed, 29 insertions(+)

diff --git a/include/dm/device.h b/include/dm/device.h
index 0086070b58b..1c52c9d3120 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -361,6 +361,24 @@ struct driver {
  */
 #define DM_PHASE(_phase)
 
+/**
+ * Declare a macro to declare a header needed for a driver. Often the correct
+ * header can be found automatically, but only for struct declarations. For
+ * enums and #defines used in the driver declaration and declared in a different
+ * header from the structs, this macro must be used.
+ *
+ * This macro produces no code but its information will be parsed by dtoc. The
+ * macro can be used multiple times with different headers, for the same driver.
+ * Put it within the U_BOOT_DRIVER() declaration, e.g.:
+ *
+ * U_BOOT_DRIVER(cpu) = {
+ *	.name = ...
+ *	...
+ *	DM_HEADER(<asm/cpu.h>)
+ * };
+ */
+#define DM_HEADER(_hdr)
+
 /**
  * dev_get_plat() - Get the platform data for a device
  *
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index 2699153016c..206b2b37583 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -68,6 +68,8 @@ class Driver:
             e.g. 'pci_child_plat'
         used (bool): True if the driver is used by the structs being output
         phase (str): Which phase of U-Boot to use this driver
+        headers (list): List of header files needed for this driver (each a str)
+            e.g. ['<asm/cpu.h>']
     """
     def __init__(self, name, fname):
         self.name = name
@@ -80,6 +82,7 @@ class Driver:
         self.child_plat = ''
         self.used = False
         self.phase = ''
+        self.headers = []
 
     def __eq__(self, other):
         return (self.name == other.name and
@@ -434,6 +437,7 @@ class Scanner:
             r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,')
 
         re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$')
+        re_hdr = re.compile('^\s*DM_HEADER\((.*)\).*$')
 
         # Matches the struct name for priv, plat
         re_priv = self._get_re_for_member('priv_auto')
@@ -462,6 +466,7 @@ class Scanner:
                 m_cplat = re_child_plat.match(line)
                 m_cpriv = re_child_priv.match(line)
                 m_phase = re_phase.match(line)
+                m_hdr = re_hdr.match(line)
                 if m_priv:
                     driver.priv = m_priv.group(1)
                 elif m_plat:
@@ -476,6 +481,8 @@ class Scanner:
                     compat = m_of_match.group(2)
                 elif m_phase:
                     driver.phase = m_phase.group(1)
+                elif m_hdr:
+                    driver.headers.append(m_hdr.group(1))
                 elif '};' in line:
                     if driver.uclass_id and compat:
                         if compat not in of_match:
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 8d35b33c28a..245b7302fd6 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -234,6 +234,7 @@ U_BOOT_DRIVER(i2c_tegra) = {
         drv = scan._drivers['i2c_tegra']
         self.assertEqual('i2c_tegra', drv.name)
         self.assertEqual('', drv.phase)
+        self.assertEqual([], drv.headers)
 
     def test_priv(self):
         """Test collection of struct info from drivers"""
@@ -252,6 +253,8 @@ U_BOOT_DRIVER(testing) = {
 	.per_child_auto	= sizeof(struct some_cpriv),
 	.per_child_plat_auto = sizeof(struct some_cplat),
 	DM_PHASE(tpl)
+	DM_HEADER(<i2c.h>)
+	DM_HEADER(<asm/clk.h>)
 };
 '''
         scan = src_scan.Scanner(None, False, None)
@@ -267,6 +270,7 @@ U_BOOT_DRIVER(testing) = {
         self.assertEqual('some_cpriv', drv.child_priv)
         self.assertEqual('some_cplat', drv.child_plat)
         self.assertEqual('tpl', drv.phase)
+        self.assertEqual(['<i2c.h>', '<asm/clk.h>'], drv.headers)
         self.assertEqual(1, len(scan._drivers))
 
     def test_uclass_scan(self):
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 17/33] dtoc: Process driver aliases along with drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (15 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 16/33] dtoc: Support headers needed for drivers Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-06-21 18:39   ` Johan Jonker
  2021-02-03 13:01 ` [PATCH v2 18/33] dtoc: Warn of duplicate drivers Simon Glass
                   ` (48 subsequent siblings)
  65 siblings, 1 reply; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Instead of using a separate step for this processing, handle it while
scanning its associated driver. This allows us to drop the code coverage
exception in this case.

Note that only files containing drivers are scanned by dtoc, so aliases
declared in a file that doesn't hold a driver will not be noticed. It
would be confusing to put them anywhere other than in the driver that they
relate to, but update the documentation to say this explicitly, just in
case.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 doc/driver-model/of-plat.rst               |  3 ++-
 tools/dtoc/src_scan.py                     | 16 +++++-----------
 tools/dtoc/test/dtoc_test_scan_drivers.cxx |  4 ++++
 3 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/doc/driver-model/of-plat.rst b/doc/driver-model/of-plat.rst
index 4ef2fe699a4..a5a6e46e3ec 100644
--- a/doc/driver-model/of-plat.rst
+++ b/doc/driver-model/of-plat.rst
@@ -183,7 +183,8 @@ each 'compatible' string.
 
 In order to make this a bit more flexible DM_DRIVER_ALIAS macro can be
 used to declare an alias for a driver name, typically a 'compatible' string.
-This macro produces no code, but it is by dtoc tool.
+This macro produces no code, but it is by dtoc tool. It must be located in the
+same file as its associated driver, ideally just after it.
 
 The parent_idx is the index of the parent driver_info structure within its
 linker list (instantiated by the U_BOOT_DRVINFO() macro). This is used to support
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index 206b2b37583..9d161a2cbc7 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -387,6 +387,7 @@ class Scanner:
                 in the file
             _of_match - updated with each compatible string found in the file
             _compat_to_driver - Maps compatible string to Driver
+            _driver_aliases - Maps alias names to driver name
 
         Args:
             fname (str): Filename being parsed (used for warnings)
@@ -438,6 +439,7 @@ class Scanner:
 
         re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$')
         re_hdr = re.compile('^\s*DM_HEADER\((.*)\).*$')
+        re_alias = re.compile(r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)')
 
         # Matches the struct name for priv, plat
         re_priv = self._get_re_for_member('priv_auto')
@@ -522,8 +524,11 @@ class Scanner:
                 driver = Driver(driver_name, fname)
             else:
                 ids_m = re_ids.search(line)
+                m_alias = re_alias.match(line)
                 if ids_m:
                     ids_name = ids_m.group(1)
+                elif m_alias:
+                    self._driver_aliases[m_alias[2]] = m_alias[1]
 
         # Make the updates based on what we found
         self._drivers.update(drivers)
@@ -557,17 +562,6 @@ class Scanner:
             if 'UCLASS_DRIVER' in buff:
                 self._parse_uclass_driver(fname, buff)
 
-            # The following re will search for driver aliases declared as
-            # DM_DRIVER_ALIAS(alias, driver_name)
-            driver_aliases = re.findall(
-                r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
-                buff)
-
-            for alias in driver_aliases: # pragma: no cover
-                if len(alias) != 2:
-                    continue
-                self._driver_aliases[alias[1]] = alias[0]
-
     def scan_header(self, fname):
         """Scan a header file to build a list of struct definitions
 
diff --git a/tools/dtoc/test/dtoc_test_scan_drivers.cxx b/tools/dtoc/test/dtoc_test_scan_drivers.cxx
index f448767670e..f370b8951d0 100644
--- a/tools/dtoc/test/dtoc_test_scan_drivers.cxx
+++ b/tools/dtoc/test/dtoc_test_scan_drivers.cxx
@@ -1 +1,5 @@
+/* Aliases must be in driver files */
+U_BOOT_DRIVER(sandbox_gpio) {
+};
+
 DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2)
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 18/33] dtoc: Warn of duplicate drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (16 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 17/33] dtoc: Process driver aliases along with drivers Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 19/33] dtoc: Read aliases for uclasses Simon Glass
                   ` (47 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

If drivers have the same name then we cannot distinguish them. This only
matters if the driver is actually used by dtoc, but in that case, issue
a warning.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 28 ++++++++++-
 tools/dtoc/test_src_scan.py | 95 +++++++++++++++++++++++++++++++++++++
 2 files changed, 122 insertions(+), 1 deletion(-)

diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index 9d161a2cbc7..fb78536e003 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -70,6 +70,10 @@ class Driver:
         phase (str): Which phase of U-Boot to use this driver
         headers (list): List of header files needed for this driver (each a str)
             e.g. ['<asm/cpu.h>']
+        dups (list): Driver objects with the same name as this one, that were
+            found after this one
+        warn_dups (bool): True if the duplicates are not distinguisble using
+            the phase
     """
     def __init__(self, name, fname):
         self.name = name
@@ -83,6 +87,8 @@ class Driver:
         self.used = False
         self.phase = ''
         self.headers = []
+        self.dups = []
+        self.warn_dups = False
 
     def __eq__(self, other):
         return (self.name == other.name and
@@ -531,7 +537,21 @@ class Scanner:
                     self._driver_aliases[m_alias[2]] = m_alias[1]
 
         # Make the updates based on what we found
-        self._drivers.update(drivers)
+        for driver in drivers.values():
+            if driver.name in self._drivers:
+                orig = self._drivers[driver.name]
+                if self._phase:
+                    # If the original driver matches our phase, use it
+                    if orig.phase == self._phase:
+                        orig.dups.append(driver)
+                        continue
+
+                    # Otherwise use the new driver, which is assumed to match
+                else:
+                    # We have no way of distinguishing them
+                    driver.warn_dups = True
+                driver.dups.append(orig)
+            self._drivers[driver.name] = driver
         self._of_match.update(of_match)
 
     def scan_driver(self, fname):
@@ -617,6 +637,8 @@ class Scanner:
         This takes a list of nodes, finds the driver for each one and marks it
         as used.
 
+        If two used drivers have the same name, issue a warning.
+
         Args:
             nodes (list of None): Nodes that are in use
         """
@@ -626,3 +648,7 @@ class Scanner:
             driver = self._drivers.get(struct_name)
             if driver:
                 driver.used = True
+                if driver.dups and driver.warn_dups:
+                    print("Warning: Duplicate driver name '%s' (orig=%s, dups=%s)" %
+                          (driver.name, driver.fname,
+                           ', '.join([drv.fname for drv in driver.dups])))
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 245b7302fd6..598ff256a60 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -371,3 +371,98 @@ struct another_struct {
         with test_util.capture_sys_output() as (stdout, _):
             scan.scan_header(output)
         self.assertIn('due to unicode error', stdout.getvalue())
+
+    def setup_dup_drivers(self, name, phase=''):
+        """Set up for a duplcate test
+
+        Returns:
+            tuple:
+                Scanner to use
+                Driver record for first driver
+                Text of second driver declaration
+                Node for driver 1
+        """
+        driver1 = '''
+static const struct udevice_id test_ids[] = {
+	{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+	{ }
+};
+
+U_BOOT_DRIVER(%s) = {
+	.name	= "testing",
+	.id	= UCLASS_I2C,
+	.of_match = test_ids,
+	%s
+};
+''' % (name, 'DM_PHASE(%s)' % phase if phase else '')
+        driver2 = '''
+static const struct udevice_id test_ids[] = {
+	{ .compatible = "nvidia,tegra114-dvc" },
+	{ }
+};
+
+U_BOOT_DRIVER(%s) = {
+	.name	= "testing",
+	.id	= UCLASS_RAM,
+	.of_match = test_ids,
+};
+''' % name
+        scan = src_scan.Scanner(None, False, None, phase)
+        scan._parse_driver('file1.c', driver1)
+        self.assertIn(name, scan._drivers)
+        drv1 = scan._drivers[name]
+
+        prop = FakeProp()
+        prop.name = 'compatible'
+        prop.value = 'nvidia,tegra114-i2c'
+        node = FakeNode()
+        node.name = 'testing'
+        node.props = {'compatible': prop}
+
+        return scan, drv1, driver2, node
+
+    def test_dup_drivers(self):
+        """Test handling of duplicate drivers"""
+        name = 'nvidia_tegra114_i2c'
+        scan, drv1, driver2, node = self.setup_dup_drivers(name)
+        self.assertEqual('', drv1.phase)
+
+        # The driver should not have a duplicate yet
+        self.assertEqual([], drv1.dups)
+
+        scan._parse_driver('file2.c', driver2)
+
+        # The first driver should now be a duplicate of the second
+        drv2 = scan._drivers[name]
+        self.assertEqual('', drv2.phase)
+        self.assertEqual(1, len(drv2.dups))
+        self.assertEqual([drv1], drv2.dups)
+
+        # There is no way to distinguish them, so we should expect a warning
+        self.assertTrue(drv2.warn_dups)
+
+        # We should see a warning
+        with test_util.capture_sys_output() as (stdout, _):
+            scan.mark_used([node])
+        self.assertEqual(
+            "Warning: Duplicate driver name 'nvidia_tegra114_i2c' (orig=file2.c, dups=file1.c)",
+            stdout.getvalue().strip())
+
+    def test_dup_drivers_phase(self):
+        """Test handling of duplicate drivers but with different phases"""
+        name = 'nvidia_tegra114_i2c'
+        scan, drv1, driver2, node = self.setup_dup_drivers(name, 'spl')
+        scan._parse_driver('file2.c', driver2)
+        self.assertEqual('spl', drv1.phase)
+
+        # The second driver should now be a duplicate of the second
+        self.assertEqual(1, len(drv1.dups))
+        drv2 = drv1.dups[0]
+
+        # The phase is different, so we should not warn of dups
+        self.assertFalse(drv1.warn_dups)
+
+        # We should not see a warning
+        with test_util.capture_sys_output() as (stdout, _):
+            scan.mark_used([node])
+        self.assertEqual('', stdout.getvalue().strip())
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 19/33] dtoc: Read aliases for uclasses
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (17 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 18/33] dtoc: Warn of duplicate drivers Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 20/33] dtoc: Detect drivers only at the start of start of line Simon Glass
                   ` (46 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Scan the aliases in the device tree to establish the number of devices
within each uclass, and the sequence number of each.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py                   | 28 ++++++++++
 tools/dtoc/src_scan.py                       | 32 ++++++++++-
 tools/dtoc/test/dtoc_test_alias_bad.dts      | 58 ++++++++++++++++++++
 tools/dtoc/test/dtoc_test_alias_bad_path.dts | 58 ++++++++++++++++++++
 tools/dtoc/test/dtoc_test_alias_bad_uc.dts   | 58 ++++++++++++++++++++
 tools/dtoc/test/dtoc_test_inst.dts           | 58 ++++++++++++++++++++
 tools/dtoc/test_dtoc.py                      | 56 ++++++++++++++++++-
 7 files changed, 345 insertions(+), 3 deletions(-)
 create mode 100644 tools/dtoc/test/dtoc_test_alias_bad.dts
 create mode 100644 tools/dtoc/test/dtoc_test_alias_bad_path.dts
 create mode 100644 tools/dtoc/test/dtoc_test_alias_bad_uc.dts
 create mode 100644 tools/dtoc/test/dtoc_test_inst.dts

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index ef0454c8904..f6dcf47d490 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -647,6 +647,29 @@ class DtbPlatdata():
             self._output_prop(node, node.props[pname])
         self.buf('};\n')
 
+    def read_aliases(self):
+        """Read the aliases and attach the information to self._alias
+
+        Raises:
+            ValueError: The alias path is not found
+        """
+        alias_node = self._fdt.GetNode('/aliases')
+        if not alias_node:
+            return
+        re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
+        for prop in alias_node.props.values():
+            m_alias = re_num.match(prop.name)
+            if not m_alias:
+                raise ValueError("Cannot decode alias '%s'" % prop.name)
+            name, num = m_alias.groups()
+            node = self._fdt.GetNode(prop.value)
+            result = self._scan.add_uclass_alias(name, num, node)
+            if result is None:
+                raise ValueError("Alias '%s' path '%s' not found" %
+                                 (prop.name, prop.value))
+            elif result is False:
+                print("Could not find uclass for alias '%s'" % prop.name)
+
     def process_nodes(self, need_drivers):
         nodes_to_output = list(self._valid_nodes)
 
@@ -757,6 +780,9 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
         scan (src_src.Scanner): Scanner from a previous run. This can help speed
             up tests. Use None for normal operation
 
+    Returns:
+        DtbPlatdata object
+
     Raises:
         ValueError: if args has no command, or an unknown command
     """
@@ -782,6 +808,7 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
     plat.scan_phandles()
     if do_process:
         plat.process_nodes(False)
+    plat.read_aliases()
 
     cmds = args[0].split(',')
     if 'all' in cmds:
@@ -796,3 +823,4 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
         plat.out_header(outfile)
         outfile.method(plat)
     plat.finish_output()
+    return plat
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index fb78536e003..a2750321791 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -116,6 +116,13 @@ class UclassDriver:
             e.g. 'pci_child_priv'
         per_child_plat (str): struct name of the per_child_plat_auto member,
             e.g. 'pci_child_plat'
+        alias_num_to_node (dict): Aliases for this uclasses (for sequence
+                numbers)
+            key (int): Alias number, e.g. 2 for "pci2"
+            value (str): Node the alias points to
+        alias_path_to_num (dict): Convert a path to an alias number
+            key (str): Full path to node (e.g. '/soc/pci')
+            seq (int): Alias number, e.g. 2 for "pci2"
     """
     def __init__(self, name):
         self.name = name
@@ -125,6 +132,8 @@ class UclassDriver:
         self.per_dev_plat = ''
         self.per_child_priv = ''
         self.per_child_plat = ''
+        self.alias_num_to_node = {}
+        self.alias_path_to_num = {}
 
     def __eq__(self, other):
         return (self.name == other.name and
@@ -622,7 +631,6 @@ class Scanner:
                     self.scan_driver(pathname)
                 elif fname.endswith('.h'):
                     self.scan_header(pathname)
-
         for fname in self._drivers_additional:
             if not isinstance(fname, str) or len(fname) == 0:
                 continue
@@ -652,3 +660,25 @@ class Scanner:
                     print("Warning: Duplicate driver name '%s' (orig=%s, dups=%s)" %
                           (driver.name, driver.fname,
                            ', '.join([drv.fname for drv in driver.dups])))
+
+    def add_uclass_alias(self, name, num, node):
+        """Add an alias to a uclass
+
+        Args:
+            name: Name of uclass, e.g. 'i2c'
+            num: Alias number, e.g. 2 for alias 'i2c2'
+            node: Node the alias points to, or None if None
+
+        Returns:
+            True if the node was added
+            False if the node was not added (uclass of that name not found)
+            None if the node could not be added because it was None
+        """
+        for uclass in self._uclass.values():
+            if uclass.name == name:
+                if node is None:
+                    return None
+                uclass.alias_num_to_node[int(num)] = node
+                uclass.alias_path_to_num[node.path] = int(num)
+                return True
+        return False
diff --git a/tools/dtoc/test/dtoc_test_alias_bad.dts b/tools/dtoc/test/dtoc_test_alias_bad.dts
new file mode 100644
index 00000000000..d4f502ad0aa
--- /dev/null
+++ b/tools/dtoc/test/dtoc_test_alias_bad.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		testbus2 = &bus2;
+		testfdt1 = &testfdt_1;
+		i2c4- = &i2c;
+	};
+
+	spl-test {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		boolval;
+		intval = <1>;
+	};
+
+	i2c: i2c {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,i2c";
+		intval = <3>;
+	};
+
+	spl-test3 {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		stringarray = "one";
+		longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+	};
+
+	bus2: some-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "denx,u-boot-test-bus";
+		reg = <3 1>;
+		ping-expect = <4>;
+		ping-add = <4>;
+		testfdt_1: test {
+			compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+			reg = <5>;
+			ping-expect = <5>;
+			ping-add = <5>;
+		};
+
+		test0 {
+			compatible = "google,another-fdt-test";
+		};
+	};
+};
diff --git a/tools/dtoc/test/dtoc_test_alias_bad_path.dts b/tools/dtoc/test/dtoc_test_alias_bad_path.dts
new file mode 100644
index 00000000000..0beca4f0d03
--- /dev/null
+++ b/tools/dtoc/test/dtoc_test_alias_bad_path.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		testbus2 = &bus2;
+		testfdt1 = &testfdt_1;
+		i2c4 = "/does/not/exist";
+	};
+
+	spl-test {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		boolval;
+		intval = <1>;
+	};
+
+	i2c: i2c {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,i2c";
+		intval = <3>;
+	};
+
+	spl-test3 {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		stringarray = "one";
+		longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+	};
+
+	bus2: some-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "denx,u-boot-test-bus";
+		reg = <3 1>;
+		ping-expect = <4>;
+		ping-add = <4>;
+		testfdt_1: test {
+			compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+			reg = <5>;
+			ping-expect = <5>;
+			ping-add = <5>;
+		};
+
+		test0 {
+			compatible = "google,another-fdt-test";
+		};
+	};
+};
diff --git a/tools/dtoc/test/dtoc_test_alias_bad_uc.dts b/tools/dtoc/test/dtoc_test_alias_bad_uc.dts
new file mode 100644
index 00000000000..ae64f5b3b29
--- /dev/null
+++ b/tools/dtoc/test/dtoc_test_alias_bad_uc.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		testbus2 = &bus2;
+		testfdt1 = &testfdt_1;
+		other1 = &testfdt_1;
+	};
+
+	spl-test {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		boolval;
+		intval = <1>;
+	};
+
+	i2c: i2c {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,i2c";
+		intval = <3>;
+	};
+
+	spl-test3 {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		stringarray = "one";
+		longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+	};
+
+	bus2: some-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "denx,u-boot-test-bus";
+		reg = <3 1>;
+		ping-expect = <4>;
+		ping-add = <4>;
+		testfdt_1: test {
+			compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+			reg = <5>;
+			ping-expect = <5>;
+			ping-add = <5>;
+		};
+
+		test0 {
+			compatible = "google,another-fdt-test";
+		};
+	};
+};
diff --git a/tools/dtoc/test/dtoc_test_inst.dts b/tools/dtoc/test/dtoc_test_inst.dts
new file mode 100644
index 00000000000..b8177fcef5f
--- /dev/null
+++ b/tools/dtoc/test/dtoc_test_inst.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		testbus2 = &bus2;
+		testfdt1 = &testfdt_1;
+		i2c4 = &i2c;
+	};
+
+	spl-test {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		boolval;
+		intval = <1>;
+	};
+
+	i2c: i2c {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,i2c";
+		intval = <3>;
+	};
+
+	spl-test3 {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		stringarray = "one";
+		longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+	};
+
+	bus2: some-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "denx,u-boot-test-bus";
+		reg = <3 1>;
+		ping-expect = <4>;
+		ping-add = <4>;
+		testfdt_1: test {
+			compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+			reg = <5>;
+			ping-expect = <5>;
+			ping-add = <5>;
+		};
+
+		test0 {
+			compatible = "google,another-fdt-test";
+		};
+	};
+};
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index c1fafb656fb..706cc39b3d5 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -137,9 +137,12 @@ class TestDtoc(unittest.TestCase):
             args (list of str): List of arguments for dtoc
             dtb_file (str): Filename of .dtb file
             output (str): Filename of output file
+
+        Returns:
+            DtbPlatdata object
         """
-        dtb_platdata.run_steps(args, dtb_file, False, output, [], None,
-                               warning_disabled=True, scan=copy_scan())
+        return dtb_platdata.run_steps(args, dtb_file, False, output, [], None,
+                                      warning_disabled=True, scan=copy_scan())
 
     def test_name(self):
         """Test conversion of device tree names to C identifiers"""
@@ -1040,3 +1043,52 @@ U_BOOT_DRVINFO(spl_test2) = {
 
         gpio = scan._drivers['sandbox_gpio']
         self.assertFalse(gpio.used)
+
+    def test_alias_read(self):
+        """Test obtaining aliases"""
+        dtb_file = get_dtb_file('dtoc_test_inst.dts')
+        output = tools.GetOutputFilename('output')
+        plat = self.run_test(['struct'], dtb_file, output)
+
+        scan = plat._scan
+        testfdt_node = plat._fdt.GetNode('/some-bus/test')
+        self.assertIn('UCLASS_TEST_FDT', scan._uclass)
+        uc = scan._uclass['UCLASS_TEST_FDT']
+        self.assertEqual({1: testfdt_node}, uc.alias_num_to_node)
+        self.assertEqual({'/some-bus/test': 1}, uc.alias_path_to_num)
+
+        # Try adding an alias that doesn't exist
+        self.assertFalse(scan.add_uclass_alias('fred', 3, None))
+
+        # Try adding an alias for a missing node
+        self.assertIsNone(scan.add_uclass_alias('testfdt', 3, None))
+
+    def test_alias_read_bad(self):
+        """Test invalid alias property name"""
+        dtb_file = get_dtb_file('dtoc_test_alias_bad.dts')
+        output = tools.GetOutputFilename('output')
+        with self.assertRaises(ValueError) as exc:
+            plat = self.run_test(['struct'], dtb_file, output)
+        self.assertIn("Cannot decode alias 'i2c4-'", str(exc.exception))
+
+    def test_alias_read_bad_path(self):
+        """Test alias pointing to a non-existent node"""
+        # This line may produce a warning, so capture it:
+        # Warning (alias_paths): /aliases:i2c4: aliases property is not a valid
+        #    node (/does/not/exist)
+        dtb_file = get_dtb_file('dtoc_test_alias_bad_path.dts', True)
+
+        output = tools.GetOutputFilename('output')
+        with self.assertRaises(ValueError) as exc:
+            plat = self.run_test(['struct'], dtb_file, output)
+        self.assertIn("Alias 'i2c4' path '/does/not/exist' not found",
+                      str(exc.exception))
+
+    def test_alias_read_bad_uclass(self):
+        """Test alias for a uclass that doesn't exist"""
+        dtb_file = get_dtb_file('dtoc_test_alias_bad_uc.dts')
+        output = tools.GetOutputFilename('output')
+        with test_util.capture_sys_output() as (stdout, _):
+            plat = self.run_test(['struct'], dtb_file, output)
+        self.assertEqual("Could not find uclass for alias 'other1'",
+                         stdout.getvalue().strip())
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 20/33] dtoc: Detect drivers only at the start of start of line
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (18 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 19/33] dtoc: Read aliases for uclasses Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 21/33] dtoc: Assign a sequence number to each node Simon Glass
                   ` (45 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

If a driver declaration is included in a comment, dtoc currently gets
confused. Update the parser to only consider declarations that begin at
the start of a line. Since multi-line comments begin with an asterisk,
this avoids the problem.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- New patch

 tools/dtoc/src_scan.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index a2750321791..bb22b0b64ff 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -331,7 +331,7 @@ class Scanner:
 
         # Collect the driver name and associated Driver
         driver = None
-        re_driver = re.compile(r'UCLASS_DRIVER\((.*)\)')
+        re_driver = re.compile(r'^UCLASS_DRIVER\((.*)\)')
 
         # Collect the uclass ID, e.g. 'UCLASS_SPI'
         re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
@@ -427,7 +427,7 @@ class Scanner:
 
         # Collect the driver info
         driver = None
-        re_driver = re.compile(r'U_BOOT_DRIVER\((.*)\)')
+        re_driver = re.compile(r'^U_BOOT_DRIVER\((.*)\)')
 
         # Collect the uclass ID, e.g. 'UCLASS_SPI'
         re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 21/33] dtoc: Assign a sequence number to each node
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (19 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 20/33] dtoc: Detect drivers only at the start of start of line Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 22/33] dtoc: Set up the uclasses that are used Simon Glass
                   ` (44 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Now that we have the alias information we can assign a sequence number
to each device in the uclass. Store this in the node associated with each
device.

This requires renaming the sandbox test drivers to have the right name.
Note that test coverage is broken with this patch, but fixed in the next
one.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 drivers/misc/test_drv.c    |  6 +++--
 test/dm/test-fdt.c         |  6 ++---
 tools/dtoc/dtb_platdata.py | 55 +++++++++++++++++++++++++++-----------
 tools/dtoc/test_dtoc.py    |  6 +++++
 4 files changed, 53 insertions(+), 20 deletions(-)

diff --git a/drivers/misc/test_drv.c b/drivers/misc/test_drv.c
index 7dd3de34c99..ac762fd9fea 100644
--- a/drivers/misc/test_drv.c
+++ b/drivers/misc/test_drv.c
@@ -85,7 +85,7 @@ static const struct udevice_id testbus_ids[] = {
 	{ }
 };
 
-U_BOOT_DRIVER(testbus_drv) = {
+U_BOOT_DRIVER(denx_u_boot_test_bus) = {
 	.name	= "testbus_drv",
 	.of_match	= testbus_ids,
 	.id	= UCLASS_TEST_BUS,
@@ -159,7 +159,9 @@ static const struct udevice_id testfdt_ids[] = {
 	{ }
 };
 
-U_BOOT_DRIVER(testfdt_drv) = {
+DM_DRIVER_ALIAS(denx_u_boot_fdt_test, google_another_fdt_test)
+
+U_BOOT_DRIVER(denx_u_boot_fdt_test) = {
 	.name	= "testfdt_drv",
 	.of_match	= testfdt_ids,
 	.id	= UCLASS_TEST_FDT,
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index b5ac9bba24e..64f7fb0ccb2 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -329,7 +329,7 @@ static int dm_test_fdt_uclass_seq_more(struct unit_test_state *uts)
 
 	/* Check creating a device with an alias */
 	node = ofnode_path("/some-bus/c-test at 1");
-	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(testfdt_drv),
+	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(denx_u_boot_fdt_test),
 				"c-test at 1", NULL, node, &dev));
 	ut_asserteq(12, dev_seq(dev));
 	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 12, &dev));
@@ -349,11 +349,11 @@ static int dm_test_fdt_uclass_seq_more(struct unit_test_state *uts)
 	 *
 	 * So next available is 19
 	 */
-	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(testfdt_drv),
+	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(denx_u_boot_fdt_test),
 				"fred", NULL, ofnode_null(), &dev));
 	ut_asserteq(19, dev_seq(dev));
 
-	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(testfdt_drv),
+	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(denx_u_boot_fdt_test),
 				"fred2", NULL, ofnode_null(), &dev));
 	ut_asserteq(20, dev_seq(dev));
 
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index f6dcf47d490..9e99c63ae70 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -136,8 +136,10 @@ class DtbPlatdata():
             from the U-Boot source code
         _fdt: Fdt object, referencing the device tree
         _dtb_fname: Filename of the input device tree binary file
-        _valid_nodes: A list of Node object with compatible strings. The list
-            is ordered by conv_name_to_c(node.name)
+        _valid_nodes_unsorted: A list of Node object with compatible strings,
+            ordered by devicetree node order
+        _valid_nodes: A list of Node object with compatible strings, ordered by
+            conv_name_to_c(node.name)
         _include_disabled: true to include nodes marked status = "disabled"
         _outfile: The current output file (sys.stdout or a real file)
         _lines: Stashed list of output lines for outputting in the future
@@ -155,6 +157,7 @@ class DtbPlatdata():
         self._fdt = None
         self._dtb_fname = dtb_fname
         self._valid_nodes = None
+        self._valid_nodes_unsorted = None
         self._include_disabled = include_disabled
         self._outfile = None
         self._lines = []
@@ -324,34 +327,38 @@ class DtbPlatdata():
         """
         self._fdt = fdt.FdtScan(self._dtb_fname)
 
-    def scan_node(self, root, valid_nodes):
+    def scan_node(self, node, valid_nodes):
         """Scan a node and subnodes to build a tree of node and phandle info
 
-        This adds each node to self._valid_nodes.
+        This adds each subnode to self._valid_nodes if it is enabled and has a
+        compatible string.
 
         Args:
-            root (Node): Root node for scan
+            node (Node): Node for scan for subnodes
             valid_nodes (list of Node): List of Node objects to add to
         """
-        for node in root.subnodes:
-            if 'compatible' in node.props:
-                status = node.props.get('status')
+        for subnode in node.subnodes:
+            if 'compatible' in subnode.props:
+                status = subnode.props.get('status')
                 if (not self._include_disabled and not status or
                         status.value != 'disabled'):
-                    valid_nodes.append(node)
+                    valid_nodes.append(subnode)
 
             # recurse to handle any subnodes
-            self.scan_node(node, valid_nodes)
+            self.scan_node(subnode, valid_nodes)
 
     def scan_tree(self):
         """Scan the device tree for useful information
 
         This fills in the following properties:
-            _valid_nodes: A list of nodes we wish to consider include in the
-                platform data
+            _valid_nodes_unsorted: A list of nodes we wish to consider include
+                in the platform data (in devicetree node order)
+            _valid_nodes: Sorted version of _valid_nodes_unsorted
         """
+        root = self._fdt.GetRoot()
         valid_nodes = []
-        self.scan_node(self._fdt.GetRoot(), valid_nodes)
+        self.scan_node(root, valid_nodes)
+        self._valid_nodes_unsorted = valid_nodes
         self._valid_nodes = sorted(valid_nodes,
                                    key=lambda x: conv_name_to_c(x.name))
 
@@ -670,6 +677,24 @@ class DtbPlatdata():
             elif result is False:
                 print("Could not find uclass for alias '%s'" % prop.name)
 
+    def assign_seq(self):
+        """Assign a sequence number to each node"""
+        for node in self._valid_nodes_unsorted:
+            if node.driver and node.seq == -1 and node.uclass:
+                uclass = node.uclass
+                num = uclass.alias_path_to_num.get(node.path)
+                if num is not None:
+                    node.seq = num
+                else:
+                    # Dynamically allocate the next available value after all
+                    # existing ones
+                    for seq in range(1000):
+                        if seq not in uclass.alias_num_to_node:
+                            break
+                    node.seq = seq
+                    uclass.alias_path_to_num[node.path] = seq
+                    uclass.alias_num_to_node[seq] = node
+
     def process_nodes(self, need_drivers):
         nodes_to_output = list(self._valid_nodes)
 
@@ -806,9 +831,9 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
     plat.setup_output_dirs(output_dirs)
     plat.scan_structs()
     plat.scan_phandles()
-    if do_process:
-        plat.process_nodes(False)
+    plat.process_nodes(False)
     plat.read_aliases()
+    plat.assign_seq()
 
     cmds = args[0].split(',')
     if 'all' in cmds:
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 706cc39b3d5..b4c0a042a9f 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -1092,3 +1092,9 @@ U_BOOT_DRVINFO(spl_test2) = {
             plat = self.run_test(['struct'], dtb_file, output)
         self.assertEqual("Could not find uclass for alias 'other1'",
                          stdout.getvalue().strip())
+
+    def test_sequence(self):
+        """Test assignment of sequence numnbers"""
+        dtb_file = get_dtb_file('dtoc_test_inst.dts')
+        output = tools.GetOutputFilename('output')
+        plat = self.run_test(['struct'], dtb_file, output)
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 22/33] dtoc: Set up the uclasses that are used
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (20 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 21/33] dtoc: Assign a sequence number to each node Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 23/33] dtoc: Support processing the root node Simon Glass
                   ` (43 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

We only care about uclasses that are actually used. This is determined by
the drivers that use them. Check all the used drivers and build a list of
'valid' uclasses.

Also add references to the uclasses so we can generate C code that uses
them. Attach a uclass to each valid driver.

For the tests, now that we have uclasses we must create an explicit test
for the case where a node does not have one. This should only happen if
the source code does not build, or the source-code scanning fails to find
it.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py  | 46 ++++++++++++++++++++++++-------------
 tools/dtoc/src_scan.py      | 45 ++++++++++++++++++++++++++++++++++++
 tools/dtoc/test_dtoc.py     | 29 +++++++++++++++++++++--
 tools/dtoc/test_src_scan.py | 17 ++++++++++++++
 4 files changed, 119 insertions(+), 18 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 9e99c63ae70..af21156659b 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -151,6 +151,8 @@ class DtbPlatdata():
                         key (str): Field name
                         value: Prop object with field information
         _basedir (str): Base directory of source tree
+        _valid_uclasses (list of src_scan.Uclass): List of uclasses needed for
+            the selected devices (see _valid_node), in alphabetical order
     """
     def __init__(self, scan, dtb_fname, include_disabled):
         self._scan = scan
@@ -164,6 +166,7 @@ class DtbPlatdata():
         self._dirnames = [None] * len(Ftype)
         self._struct_data = collections.OrderedDict()
         self._basedir = None
+        self._valid_uclasses = None
 
     def setup_output_dirs(self, output_dirs):
         """Set up the output directories
@@ -677,23 +680,12 @@ class DtbPlatdata():
             elif result is False:
                 print("Could not find uclass for alias '%s'" % prop.name)
 
-    def assign_seq(self):
+    def assign_seqs(self):
         """Assign a sequence number to each node"""
         for node in self._valid_nodes_unsorted:
-            if node.driver and node.seq == -1 and node.uclass:
-                uclass = node.uclass
-                num = uclass.alias_path_to_num.get(node.path)
-                if num is not None:
-                    node.seq = num
-                else:
-                    # Dynamically allocate the next available value after all
-                    # existing ones
-                    for seq in range(1000):
-                        if seq not in uclass.alias_num_to_node:
-                            break
-                    node.seq = seq
-                    uclass.alias_path_to_num[node.path] = seq
-                    uclass.alias_num_to_node[seq] = node
+            seq = self._scan.assign_seq(node)
+            if seq is not None:
+                node.seq = seq
 
     def process_nodes(self, need_drivers):
         nodes_to_output = list(self._valid_nodes)
@@ -710,6 +702,16 @@ class DtbPlatdata():
                 raise ValueError("Cannot parse/find driver for '%s'" %
                                  node.struct_name)
             node.driver = driver
+            uclass = self._scan._uclass.get(driver.uclass_id)
+            if not uclass:
+                raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
+                                (driver.uclass_id, node.struct_name))
+            node.uclass = uclass
+            node.uclass_seq = len(node.uclass.devs)
+            node.uclass.devs.append(node)
+            uclass.node_refs[node.uclass_seq] = \
+                '&%s->uclass_node' % node.dev_ref
+
             parent_driver = None
             if node.parent in self._valid_nodes:
                 parent_driver = self._scan.get_driver(node.parent.struct_name)
@@ -730,6 +732,18 @@ class DtbPlatdata():
             node.child_refs[-1] = ref
             node.child_refs[len(node.child_devs)] = ref
 
+        uclass_set = set()
+        for driver in self._scan._drivers.values():
+            if driver.used and driver.uclass:
+                uclass_set.add(driver.uclass)
+        self._valid_uclasses = sorted(list(uclass_set),
+                                      key=lambda uc: uc.uclass_id)
+
+        for seq, uclass in enumerate(uclass_set):
+            ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
+            uclass.node_refs[-1] = ref
+            uclass.node_refs[len(uclass.devs)] = ref
+
     def output_node(self, node):
         """Output the C code for a node
 
@@ -833,7 +847,7 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
     plat.scan_phandles()
     plat.process_nodes(False)
     plat.read_aliases()
-    plat.assign_seq()
+    plat.assign_seqs()
 
     cmds = args[0].split(',')
     if 'all' in cmds:
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index bb22b0b64ff..8619206a8d4 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -74,6 +74,7 @@ class Driver:
             found after this one
         warn_dups (bool): True if the duplicates are not distinguisble using
             the phase
+        uclass (Uclass): uclass for this driver
     """
     def __init__(self, name, fname):
         self.name = name
@@ -89,6 +90,7 @@ class Driver:
         self.headers = []
         self.dups = []
         self.warn_dups = False
+        self.uclass = None
 
     def __eq__(self, other):
         return (self.name == other.name and
@@ -123,6 +125,10 @@ class UclassDriver:
         alias_path_to_num (dict): Convert a path to an alias number
             key (str): Full path to node (e.g. '/soc/pci')
             seq (int): Alias number, e.g. 2 for "pci2"
+        devs (list): List of devices in this uclass, each a Node
+        node_refs (dict): References in the linked list of devices:
+            key (int): Sequence number (0=first, n-1=last, -1=head, n=tail)
+            value (str): Reference to the device at that position
     """
     def __init__(self, name):
         self.name = name
@@ -134,6 +140,8 @@ class UclassDriver:
         self.per_child_plat = ''
         self.alias_num_to_node = {}
         self.alias_path_to_num = {}
+        self.devs = []
+        self.node_refs = {}
 
     def __eq__(self, other):
         return (self.name == other.name and
@@ -639,6 +647,12 @@ class Scanner:
             else:
                 self.scan_driver(self._basedir + '/' + fname)
 
+        # Get the uclass for each driver
+        # TODO: Can we just get the uclass for the ones we use, e.g. in
+        # mark_used()?
+        for driver in self._drivers.values():
+            driver.uclass = self._uclass.get(driver.uclass_id)
+
     def mark_used(self, nodes):
         """Mark the drivers associated with a list of nodes as 'used'
 
@@ -682,3 +696,34 @@ class Scanner:
                 uclass.alias_path_to_num[node.path] = int(num)
                 return True
         return False
+
+    def assign_seq(self, node):
+        """Figure out the sequence number for a node
+
+        This looks in the node's uclass and assigns a sequence number if needed,
+        based on the aliases and other nodes in that uclass.
+
+        It updates the uclass alias_path_to_num and alias_num_to_node
+
+        Args:
+            node (Node): Node object to look up
+        """
+        if node.driver and node.seq == -1 and node.uclass:
+            uclass = node.uclass
+            num = uclass.alias_path_to_num.get(node.path)
+            if num is not None:
+                return num
+            else:
+                # Dynamically allocate the next available value after all
+                # existing ones
+                if uclass.alias_num_to_node:
+                    start = max(uclass.alias_num_to_node.keys())
+                else:
+                    start = -1
+                for seq in range(start + 1, 1000):
+                    if seq not in uclass.alias_num_to_node:
+                        break
+                uclass.alias_path_to_num[node.path] = seq
+                uclass.alias_num_to_node[seq] = node
+                return seq
+        return None
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index b4c0a042a9f..b077cf0e76d 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -141,6 +141,8 @@ class TestDtoc(unittest.TestCase):
         Returns:
             DtbPlatdata object
         """
+        # Make a copy of the 'scan' object, since it includes uclasses and
+        # drivers, which get updated during execution.
         return dtb_platdata.run_steps(args, dtb_file, False, output, [], None,
                                       warning_disabled=True, scan=copy_scan())
 
@@ -1033,6 +1035,16 @@ U_BOOT_DRVINFO(spl_test2) = {
         self.assertIn("Cannot parse/find driver for 'sandbox_pmic",
                       str(exc.exception))
 
+    def test_process_nodes_bad_uclass(self):
+        plat, scan = self.setup_process_test()
+
+        self.assertIn('UCLASS_I2C', scan._uclass)
+        del scan._uclass['UCLASS_I2C']
+        with self.assertRaises(ValueError) as exc:
+            plat.process_nodes(True)
+        self.assertIn("Cannot parse/find uclass 'UCLASS_I2C' for driver 'sandbox_i2c'",
+                      str(exc.exception))
+
     def test_process_nodes_used(self):
         """Test processing nodes to add various info"""
         plat, scan = self.setup_process_test()
@@ -1052,10 +1064,13 @@ U_BOOT_DRVINFO(spl_test2) = {
 
         scan = plat._scan
         testfdt_node = plat._fdt.GetNode('/some-bus/test')
+        test0_node = plat._fdt.GetNode('/some-bus/test0')
         self.assertIn('UCLASS_TEST_FDT', scan._uclass)
         uc = scan._uclass['UCLASS_TEST_FDT']
-        self.assertEqual({1: testfdt_node}, uc.alias_num_to_node)
-        self.assertEqual({'/some-bus/test': 1}, uc.alias_path_to_num)
+        self.assertEqual({1: testfdt_node, 2: test0_node},
+                         uc.alias_num_to_node)
+        self.assertEqual({'/some-bus/test': 1, '/some-bus/test0': 2},
+                         uc.alias_path_to_num)
 
         # Try adding an alias that doesn't exist
         self.assertFalse(scan.add_uclass_alias('fred', 3, None))
@@ -1098,3 +1113,13 @@ U_BOOT_DRVINFO(spl_test2) = {
         dtb_file = get_dtb_file('dtoc_test_inst.dts')
         output = tools.GetOutputFilename('output')
         plat = self.run_test(['struct'], dtb_file, output)
+
+        scan = plat._scan
+        testfdt = plat._fdt.GetNode('/some-bus/test')
+        self.assertEqual(1, testfdt.seq)
+        i2c = plat._fdt.GetNode('/i2c')
+
+        # For now this uclass is not compiled in, so no sequence is assigned
+        self.assertEqual(4, i2c.seq)
+        spl = plat._fdt.GetNode('/spl-test')
+        self.assertEqual(0, spl.seq)
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 598ff256a60..d32aa58400f 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -466,3 +466,20 @@ U_BOOT_DRIVER(%s) = {
         with test_util.capture_sys_output() as (stdout, _):
             scan.mark_used([node])
         self.assertEqual('', stdout.getvalue().strip())
+
+    def test_sequence(self):
+        """Test assignment of sequence numnbers"""
+        scan = src_scan.Scanner(None, False, None, '')
+        node = FakeNode()
+        uc = src_scan.UclassDriver('UCLASS_I2C')
+        node.uclass = uc
+        node.driver = True
+        node.seq = -1
+        node.path = 'mypath'
+        uc.alias_num_to_node[2] = node
+
+        # This should assign 3 (after the 2 that exists)
+        seq = scan.assign_seq(node)
+        self.assertEqual(3, seq)
+        self.assertEqual({'mypath': 3}, uc.alias_path_to_num)
+        self.assertEqual({2: node, 3: node}, uc.alias_num_to_node)
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 23/33] dtoc: Support processing the root node
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (21 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 22/33] dtoc: Set up the uclasses that are used Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 24/33] dtoc: Add an option for device instantiation Simon Glass
                   ` (42 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

The device for the root node is normally bound by driver model on init.
With devices being instantiated at build time, we must handle the root
device also.

Add support for processing the root node, which may not have a compatible
string.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py  | 10 ++++++++--
 tools/dtoc/src_scan.py      | 39 ++++++++++++++++++++++---------------
 tools/dtoc/test_dtoc.py     | 23 ++++++++++++++++++++--
 tools/dtoc/test_src_scan.py |  7 +++++++
 4 files changed, 59 insertions(+), 20 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index af21156659b..e08b92cf8a3 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -350,16 +350,22 @@ class DtbPlatdata():
             # recurse to handle any subnodes
             self.scan_node(subnode, valid_nodes)
 
-    def scan_tree(self):
+    def scan_tree(self, add_root):
         """Scan the device tree for useful information
 
         This fills in the following properties:
             _valid_nodes_unsorted: A list of nodes we wish to consider include
                 in the platform data (in devicetree node order)
             _valid_nodes: Sorted version of _valid_nodes_unsorted
+
+        Args:
+            add_root: True to add the root node also (which wouldn't normally
+                be added as it may not have a compatible string)
         """
         root = self._fdt.GetRoot()
         valid_nodes = []
+        if add_root:
+            valid_nodes.append(root)
         self.scan_node(root, valid_nodes)
         self._valid_nodes_unsorted = valid_nodes
         self._valid_nodes = sorted(valid_nodes,
@@ -839,7 +845,7 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
         do_process = False
     plat = DtbPlatdata(scan, dtb_file, include_disabled)
     plat.scan_dtb()
-    plat.scan_tree()
+    plat.scan_tree(add_root=False)
     plat.prepare_nodes()
     plat.scan_reg_sizes()
     plat.setup_output_dirs(output_dirs)
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index 8619206a8d4..114212cfe2d 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -33,6 +33,8 @@ def conv_name_to_c(name):
     new = new.replace('-', '_')
     new = new.replace(',', '_')
     new = new.replace('.', '_')
+    if new == '/':
+        return 'root'
     return new
 
 def get_compat_name(node):
@@ -250,7 +252,10 @@ class Scanner:
                 In case of no match found, the return will be the same as
                 get_compat_name()
         """
-        compat_list_c = get_compat_name(node)
+        if not node.parent:
+            compat_list_c = ['root_driver']
+        else:
+            compat_list_c = get_compat_name(node)
 
         for compat_c in compat_list_c:
             if not compat_c in self._drivers.keys():
@@ -509,21 +514,23 @@ class Scanner:
                 elif m_hdr:
                     driver.headers.append(m_hdr.group(1))
                 elif '};' in line:
-                    if driver.uclass_id and compat:
-                        if compat not in of_match:
-                            raise ValueError(
-                                "%s: Unknown compatible var '%s' (found: %s)" %
-                                (fname, compat, ','.join(of_match.keys())))
-                        driver.compat = of_match[compat]
-
-                        # This needs to be deterministic, since a driver may
-                        # have multiple compatible strings pointing to it.
-                        # We record the one earliest in the alphabet so it
-                        # will produce the same result on all machines.
-                        for compat_id in of_match[compat]:
-                            old = self._compat_to_driver.get(compat_id)
-                            if not old or driver.name < old.name:
-                                self._compat_to_driver[compat_id] = driver
+                    is_root = driver.name == 'root_driver'
+                    if driver.uclass_id and (compat or is_root):
+                        if not is_root:
+                            if compat not in of_match:
+                                raise ValueError(
+                                    "%s: Unknown compatible var '%s' (found: %s)" %
+                                    (fname, compat, ','.join(of_match.keys())))
+                            driver.compat = of_match[compat]
+
+                            # This needs to be deterministic, since a driver may
+                            # have multiple compatible strings pointing to it.
+                            # We record the one earliest in the alphabet so it
+                            # will produce the same result on all machines.
+                            for compat_id in of_match[compat]:
+                                old = self._compat_to_driver.get(compat_id)
+                                if not old or driver.name < old.name:
+                                    self._compat_to_driver[compat_id] = driver
                         drivers[driver.name] = driver
                     else:
                         # The driver does not have a uclass or compat string.
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index b077cf0e76d..ed8c7e47882 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -974,10 +974,10 @@ U_BOOT_DRVINFO(spl_test2) = {
         output = tools.GetOutputFilename('output')
 
         # Take a copy before messing with it
-        scan = copy.deepcopy(saved_scan)
+        scan = copy_scan()
         plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
         plat.scan_dtb()
-        plat.scan_tree()
+        plat.scan_tree(False)
         plat.prepare_nodes()
         return plat, scan
 
@@ -1123,3 +1123,22 @@ U_BOOT_DRVINFO(spl_test2) = {
         self.assertEqual(4, i2c.seq)
         spl = plat._fdt.GetNode('/spl-test')
         self.assertEqual(0, spl.seq)
+
+    def test_process_root(self):
+        """Test assignment of sequence numnbers"""
+        dtb_file = get_dtb_file('dtoc_test_simple.dts')
+        output = tools.GetOutputFilename('output')
+
+        # Take a copy before messing with it
+        scan = copy_scan()
+        plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
+        plat.scan_dtb()
+        root = plat._fdt.GetRoot()
+
+        plat.scan_tree(False)
+        self.assertNotIn(root, plat._valid_nodes)
+
+        plat.scan_tree(True)
+        self.assertIn(root, plat._valid_nodes)
+        self.assertEqual('root_driver',
+                         scan.get_normalized_compat_name(root)[0])
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index d32aa58400f..0af86dcf0c3 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -161,6 +161,10 @@ class TestSrcScan(unittest.TestCase):
         prop.value = 'rockchip,rk3288-grf'
         node = FakeNode()
         node.props = {'compatible': prop}
+
+        # get_normalized_compat_name() uses this to check for root node
+        node.parent = FakeNode()
+
         scan = src_scan.Scanner(None, False, None)
         with test_util.capture_sys_output() as (stdout, _):
             name, aliases = scan.get_normalized_compat_name(node)
@@ -419,6 +423,9 @@ U_BOOT_DRIVER(%s) = {
         node.name = 'testing'
         node.props = {'compatible': prop}
 
+        # get_normalized_compat_name() uses this to check for root node
+        node.parent = FakeNode()
+
         return scan, drv1, driver2, node
 
     def test_dup_drivers(self):
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 24/33] dtoc: Add an option for device instantiation
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (22 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 23/33] dtoc: Support processing the root node Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 25/33] dm: of-platadata: Add " Simon Glass
                   ` (41 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Add an option to instantiate devices at build time. For now this just
parses the option and sets up a few parameters.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 17 +++++++++++------
 tools/dtoc/main.py         |  4 +++-
 tools/dtoc/test_dtoc.py    | 37 ++++++++++++++++++++++---------------
 3 files changed, 36 insertions(+), 22 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index e08b92cf8a3..46e2725a86c 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -153,8 +153,10 @@ class DtbPlatdata():
         _basedir (str): Base directory of source tree
         _valid_uclasses (list of src_scan.Uclass): List of uclasses needed for
             the selected devices (see _valid_node), in alphabetical order
+        _instantiate: Instantiate devices so they don't need to be bound at
+            run-time
     """
-    def __init__(self, scan, dtb_fname, include_disabled):
+    def __init__(self, scan, dtb_fname, include_disabled, instantiate=False):
         self._scan = scan
         self._fdt = None
         self._dtb_fname = dtb_fname
@@ -167,6 +169,7 @@ class DtbPlatdata():
         self._struct_data = collections.OrderedDict()
         self._basedir = None
         self._valid_uclasses = None
+        self._instantiate = instantiate
 
     def setup_output_dirs(self, output_dirs):
         """Set up the output directories
@@ -802,8 +805,8 @@ OUTPUT_FILES = {
 
 
 def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
-              warning_disabled=False, drivers_additional=None, basedir=None,
-              scan=None):
+              instantiate, warning_disabled=False, drivers_additional=None,
+              basedir=None, scan=None):
     """Run all the steps of the dtoc tool
 
     Args:
@@ -816,6 +819,8 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
             Directory to put H output files
         phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
              or 'tpl'. None if not known
+        instantiate: Instantiate devices so they don't need to be bound at
+            run-time
         warning_disabled (bool): True to avoid showing warnings about missing
             drivers
         drivers_additional (list): List of additional drivers to use during
@@ -843,15 +848,15 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
         do_process = True
     else:
         do_process = False
-    plat = DtbPlatdata(scan, dtb_file, include_disabled)
+    plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
     plat.scan_dtb()
-    plat.scan_tree(add_root=False)
+    plat.scan_tree(add_root=instantiate)
     plat.prepare_nodes()
     plat.scan_reg_sizes()
     plat.setup_output_dirs(output_dirs)
     plat.scan_structs()
     plat.scan_phandles()
-    plat.process_nodes(False)
+    plat.process_nodes(instantiate)
     plat.read_aliases()
     plat.assign_seqs()
 
diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py
index 15a8ff167a9..93706de89bf 100755
--- a/tools/dtoc/main.py
+++ b/tools/dtoc/main.py
@@ -81,6 +81,8 @@ parser.add_option('-C', '--h-output-dir', action='store',
                   help='Select output directory for H files (defaults to --c-output-di)')
 parser.add_option('-d', '--dtb-file', action='store',
                   help='Specify the .dtb input file')
+parser.add_option('-i', '--instantiate', action='store_true', default=False,
+                  help='Instantiate devices to avoid needing device_bind()')
 parser.add_option('--include-disabled', action='store_true',
                   help='Include disabled nodes')
 parser.add_option('-o', '--output', action='store',
@@ -107,4 +109,4 @@ else:
     dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled,
                            options.output,
                            [options.c_output_dir, options.h_output_dir],
-                           phase=options.phase)
+                           options.phase, instantiate=options.instantiate)
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index ed8c7e47882..cbddd62424d 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -130,7 +130,7 @@ class TestDtoc(unittest.TestCase):
         self.assertEqual(expected, actual)
 
     @staticmethod
-    def run_test(args, dtb_file, output):
+    def run_test(args, dtb_file, output, instantiate=False):
         """Run a test using dtoc
 
         Args:
@@ -143,8 +143,9 @@ class TestDtoc(unittest.TestCase):
         """
         # Make a copy of the 'scan' object, since it includes uclasses and
         # drivers, which get updated during execution.
-        return dtb_platdata.run_steps(args, dtb_file, False, output, [], None,
-                                      warning_disabled=True, scan=copy_scan())
+        return dtb_platdata.run_steps(
+            args, dtb_file, False, output, [], None, instantiate,
+            warning_disabled=True, scan=copy_scan())
 
     def test_name(self):
         """Test conversion of device tree names to C identifiers"""
@@ -201,7 +202,8 @@ class TestDtoc(unittest.TestCase):
         output = tools.GetOutputFilename('output')
 
         # Run this one without saved_scan to complete test coverage
-        dtb_platdata.run_steps(['struct'], dtb_file, False, output, [], True)
+        dtb_platdata.run_steps(['struct'], dtb_file, False, output, [], None,
+                               False)
         with open(output) as infile:
             lines = infile.read().splitlines()
         self.assertEqual(HEADER.splitlines(), lines)
@@ -369,8 +371,9 @@ U_BOOT_DRVINFO(gpios_at_0) = {
         dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts')
         output = tools.GetOutputFilename('output')
         with test_util.capture_sys_output() as _:
-            dtb_platdata.run_steps(['struct'], dtb_file, False, output, [],
-                                   None, scan=copy_scan())
+            dtb_platdata.run_steps(
+                ['struct'], dtb_file, False, output, [], None, False,
+                scan=copy_scan())
         with open(output) as infile:
             data = infile.read()
         self._check_strings(HEADER + '''
@@ -379,8 +382,9 @@ struct dtd_invalid {
 ''', data)
 
         with test_util.capture_sys_output() as _:
-            dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [],
-                                   None, scan=copy_scan())
+            dtb_platdata.run_steps(
+                ['platdata'], dtb_file, False, output, [], None, False,
+                scan=copy_scan())
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
@@ -530,8 +534,9 @@ U_BOOT_DRVINFO(phandle_target) = {
         """Test that phandle targets are generated when unsing cd-gpios"""
         dtb_file = get_dtb_file('dtoc_test_phandle_cd_gpios.dts')
         output = tools.GetOutputFilename('output')
-        dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [], True,
-                               scan=copy_scan())
+        dtb_platdata.run_steps(
+            ['platdata'], dtb_file, False, output, [], None, False,
+            warning_disabled=True, scan=copy_scan())
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
@@ -925,15 +930,16 @@ U_BOOT_DRVINFO(spl_test2) = {
         dtb_file = get_dtb_file('dtoc_test_simple.dts')
         output = tools.GetOutputFilename('output')
         with self.assertRaises(ValueError) as exc:
-            self.run_test(['invalid-cmd'], dtb_file, output)
+            self.run_test(['invalid-cmd'], dtb_file, output, False)
         self.assertIn("Unknown command 'invalid-cmd': (use: platdata, struct)",
                       str(exc.exception))
 
     def test_output_conflict(self):
         """Test a conflict between and output dirs and output file"""
         with self.assertRaises(ValueError) as exc:
-            dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], None,
-                                   warning_disabled=True, scan=copy_scan())
+            dtb_platdata.run_steps(
+                ['all'], None, False, 'out', ['cdir'], None, False,
+                warning_disabled=True, scan=copy_scan())
         self.assertIn("Must specify either output or output_dirs, not both",
                       str(exc.exception))
 
@@ -949,8 +955,9 @@ U_BOOT_DRVINFO(spl_test2) = {
         fnames = glob.glob(outdir + '/*')
         self.assertEqual(2, len(fnames))
 
-        dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], None,
-                               warning_disabled=True, scan=copy_scan())
+        dtb_platdata.run_steps(
+            ['all'], dtb_file, False, None, [outdir], None, False,
+            warning_disabled=True, scan=copy_scan())
         fnames = glob.glob(outdir + '/*')
         self.assertEqual(4, len(fnames))
 
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 25/33] dm: of-platadata: Add option for device instantiation
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (23 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 24/33] dtoc: Add an option for device instantiation Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 26/33] dtoc: Add support for decl file Simon Glass
                   ` (40 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Add Kconfig options to support build-time device instantiation. When
fully implemented, this will allow dtoc to create U-Boot devices (i.e.
struct udevice records) at build time, thus reducing code space in
SPL.

For now this defaults to off, but will be enabled when the rest of
the implementation is in place.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 dts/Kconfig          | 23 +++++++++++++++++++++--
 scripts/Makefile.spl |  4 ++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/dts/Kconfig b/dts/Kconfig
index 71f50552e4f..e861ea48d01 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -355,15 +355,24 @@ config SPL_OF_PLATDATA
 	  compatible string, then adding platform data and U_BOOT_DRVINFO
 	  declarations for each node. See of-plat.txt for more information.
 
+if SPL_OF_PLATDATA
+
 config SPL_OF_PLATDATA_PARENT
 	bool "Support parent information in devices"
-	depends on SPL_OF_PLATDATA
 	default y
 	help
 	  Generally it is useful to be able to access the parent of a device
 	  with of-platdata. To save space this can be disabled, but in that
 	  case dev_get_parent() will always return NULL;
 
+config SPL_OF_PLATDATA_INST
+	bool "Declare devices at build time"
+	help
+	  Declare devices as udevice instances so that they do not need to be
+	  bound when U-Boot starts. This can save time and code space.
+
+endif
+
 config TPL_OF_PLATDATA
 	bool "Generate platform data for use in TPL"
 	depends on TPL_OF_CONTROL
@@ -385,13 +394,23 @@ config TPL_OF_PLATDATA
 	  compatible string, then adding platform data and U_BOOT_DRVINFO
 	  declarations for each node. See of-plat.txt for more information.
 
+if TPL_OF_PLATDATA
+
 config TPL_OF_PLATDATA_PARENT
 	bool "Support parent information in devices"
-	depends on TPL_OF_PLATDATA
 	default y
 	help
 	  Generally it is useful to be able to access the parent of a device
 	  with of-platdata. To save space this can be disabled, but in that
 	  case dev_get_parent() will always return NULL;
 
+config TPL_OF_PLATDATA_INST
+	bool "Declare devices at build time"
+
+	help
+	  Declare devices as udevice instances so that they do not need to be
+	  bound when U-Boot starts. This can save time and code space.
+
+endif
+
 endmenu
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 67641d0faea..52609112ecd 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -311,6 +311,10 @@ pythonpath = PYTHONPATH=scripts/dtc/pylibfdt
 DTOC_ARGS := $(pythonpath) $(srctree)/tools/dtoc/dtoc \
 	-d $(obj)/$(SPL_BIN).dtb -p $(SPL_NAME)
 
+ifneq ($(CONFIG_$(SPL_TPL_)OF_PLATDATA_INST),)
+DTOC_ARGS += -i
+endif
+
 quiet_cmd_dtoc = DTOC    $@
 cmd_dtoc = $(DTOC_ARGS) -c $(obj)/dts -C include/generated all
 
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 26/33] dtoc: Add support for decl file
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (24 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 25/33] dm: of-platadata: Add " Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 27/33] dtoc: Don't generate platform data with instantiation Simon Glass
                   ` (39 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Add an option to generate the declaration file, which declares all
drivers and uclasses, so references can be used in the code.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 36 +++++++++++++++
 tools/dtoc/test_dtoc.py    | 91 +++++++++++++++++++++++++++++++++++---
 2 files changed, 120 insertions(+), 7 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 46e2725a86c..040b7246787 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -689,6 +689,39 @@ class DtbPlatdata():
             elif result is False:
                 print("Could not find uclass for alias '%s'" % prop.name)
 
+    def generate_decl(self):
+        nodes_to_output = list(self._valid_nodes)
+
+        self.buf('#include <dm/device-internal.h>\n')
+        self.buf('#include <dm/uclass-internal.h>\n')
+        self.buf('\n')
+        self.buf(
+            '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
+        for node in nodes_to_output:
+            self.buf('DM_DRIVER_DECL(%s);\n' % node.struct_name);
+        self.buf('\n')
+
+        if self._instantiate:
+            self.buf(
+                '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
+            for node in nodes_to_output:
+                self.buf('DM_DEVICE_DECL(%s);\n' % node.var_name)
+            self.buf('\n')
+
+        uclass_list = self._valid_uclasses
+
+        self.buf(
+            '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
+        for uclass in uclass_list:
+            self.buf('DM_UCLASS_DRIVER_DECL(%s);\n' % uclass.name)
+
+        if self._instantiate:
+            self.buf('\n')
+            self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
+            for uclass in uclass_list:
+                self.buf('DM_UCLASS_DECL(%s);\n' % uclass.name)
+        self.out(''.join(self.get_buf()))
+
     def assign_seqs(self):
         """Assign a sequence number to each node"""
         for node in self._valid_nodes_unsorted:
@@ -794,6 +827,9 @@ class DtbPlatdata():
 # key: Command used to generate this file
 # value: OutputFile for this command
 OUTPUT_FILES = {
+    'decl':
+        OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
+                   'Declares externs for all device/uclass instances'),
     'struct':
         OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
                    DtbPlatdata.generate_structs,
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index cbddd62424d..a51a7f301ce 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -40,6 +40,14 @@ HEADER = '''/*
 #include <stdbool.h>
 #include <linux/libfdt.h>'''
 
+DECL_HEADER = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares externs for all device/uclass instances.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+'''
+
 C_HEADER = '''/*
  * DO NOT MODIFY
  *
@@ -213,6 +221,54 @@ class TestDtoc(unittest.TestCase):
             lines = infile.read().splitlines()
         self.assertEqual(C_HEADER.splitlines() + [''], lines)
 
+    decl_text = DECL_HEADER + '''
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+
+/* driver declarations - these allow DM_DRIVER_GET() to be used */
+DM_DRIVER_DECL(sandbox_i2c);
+DM_DRIVER_DECL(sandbox_pmic);
+DM_DRIVER_DECL(sandbox_spl_test);
+DM_DRIVER_DECL(sandbox_spl_test);
+DM_DRIVER_DECL(sandbox_spl_test);
+
+/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
+DM_UCLASS_DRIVER_DECL(i2c);
+DM_UCLASS_DRIVER_DECL(misc);
+DM_UCLASS_DRIVER_DECL(pmic);
+'''
+    decl_text_inst = DECL_HEADER + '''
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+
+/* driver declarations - these allow DM_DRIVER_GET() to be used */
+DM_DRIVER_DECL(sandbox_i2c);
+DM_DRIVER_DECL(sandbox_pmic);
+DM_DRIVER_DECL(root_driver);
+DM_DRIVER_DECL(sandbox_spl_test);
+DM_DRIVER_DECL(sandbox_spl_test);
+DM_DRIVER_DECL(sandbox_spl_test);
+
+/* device declarations - these allow DM_DEVICE_REF() to be used */
+DM_DEVICE_DECL(i2c_at_0);
+DM_DEVICE_DECL(pmic_at_9);
+DM_DEVICE_DECL(root);
+DM_DEVICE_DECL(spl_test);
+DM_DEVICE_DECL(spl_test2);
+DM_DEVICE_DECL(spl_test3);
+
+/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
+DM_UCLASS_DRIVER_DECL(i2c);
+DM_UCLASS_DRIVER_DECL(misc);
+DM_UCLASS_DRIVER_DECL(pmic);
+DM_UCLASS_DRIVER_DECL(root);
+
+/* uclass declarations - needed for DM_UCLASS_REF() */
+DM_UCLASS_DECL(i2c);
+DM_UCLASS_DECL(misc);
+DM_UCLASS_DECL(pmic);
+DM_UCLASS_DECL(root);
+'''
     struct_text = HEADER + '''
 struct dtd_sandbox_i2c {
 };
@@ -327,10 +383,17 @@ U_BOOT_DRVINFO(spl_test3) = {
 
         self._check_strings(self.platdata_text, data)
 
+        self.run_test(['decl'], dtb_file, output)
+        with open(output) as infile:
+            data = infile.read()
+
+        self._check_strings(self.decl_text, data)
+
         # Try the 'all' command
         self.run_test(['all'], dtb_file, output)
         data = tools.ReadFile(output, binary=False)
-        self._check_strings(self.platdata_text + self.struct_text, data)
+        self._check_strings(self.decl_text + self.platdata_text +
+                            self.struct_text, data)
 
     def test_driver_alias(self):
         """Test output from a device tree file with a driver alias"""
@@ -916,7 +979,8 @@ U_BOOT_DRVINFO(spl_test2) = {
         output = tools.GetOutputFilename('output')
         self.run_test(['all'], dtb_file, output)
         data = tools.ReadFile(output, binary=False)
-        self._check_strings(self.platdata_text + self.struct_text, data)
+        self._check_strings(self.decl_text + self.platdata_text +
+                            self.struct_text, data)
 
     def test_no_command(self):
         """Test running dtoc without a command"""
@@ -930,9 +994,10 @@ U_BOOT_DRVINFO(spl_test2) = {
         dtb_file = get_dtb_file('dtoc_test_simple.dts')
         output = tools.GetOutputFilename('output')
         with self.assertRaises(ValueError) as exc:
-            self.run_test(['invalid-cmd'], dtb_file, output, False)
-        self.assertIn("Unknown command 'invalid-cmd': (use: platdata, struct)",
-                      str(exc.exception))
+            self.run_test(['invalid-cmd'], dtb_file, output)
+        self.assertIn(
+            "Unknown command 'invalid-cmd': (use: decl, platdata, struct)",
+            str(exc.exception))
 
     def test_output_conflict(self):
         """Test a conflict between and output dirs and output file"""
@@ -959,11 +1024,12 @@ U_BOOT_DRVINFO(spl_test2) = {
             ['all'], dtb_file, False, None, [outdir], None, False,
             warning_disabled=True, scan=copy_scan())
         fnames = glob.glob(outdir + '/*')
-        self.assertEqual(4, len(fnames))
+        self.assertEqual(5, len(fnames))
 
         leafs = set(os.path.basename(fname) for fname in fnames)
         self.assertEqual(
-            {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb'},
+            {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb',
+             'dt-decl.h'},
             leafs)
 
     def setup_process_test(self):
@@ -1149,3 +1215,14 @@ U_BOOT_DRVINFO(spl_test2) = {
         self.assertIn(root, plat._valid_nodes)
         self.assertEqual('root_driver',
                          scan.get_normalized_compat_name(root)[0])
+
+    def test_simple_inst(self):
+        """Test output from some simple nodes with instantiate enabled"""
+        dtb_file = get_dtb_file('dtoc_test_simple.dts')
+        output = tools.GetOutputFilename('output')
+
+        self.run_test(['decl'], dtb_file, output, True)
+        with open(output) as infile:
+            data = infile.read()
+
+        self._check_strings(self.decl_text_inst, data)
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 27/33] dtoc: Don't generate platform data with instantiation
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (25 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 26/33] dtoc: Add support for decl file Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 28/33] sandbox: Make sandbox,emul more conventional Simon Glass
                   ` (38 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

This file is not used when instantiating devices. Update dtoc to skip
generating its contents and just add a comment instead.

Also it is useful to see the driver name and parent for each device.
Update the file to show that information, to avoid updating the same
tests twice.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 35 ++++++++++++++++++++++---
 tools/dtoc/test_dtoc.py    | 53 +++++++++++++++++++++++++++++++-------
 2 files changed, 75 insertions(+), 13 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 040b7246787..befe7c14901 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -786,19 +786,46 @@ class DtbPlatdata():
             uclass.node_refs[-1] = ref
             uclass.node_refs[len(uclass.devs)] = ref
 
-    def output_node(self, node):
+    def output_node_plat(self, node):
         """Output the C code for a node
 
         Args:
             node (fdt.Node): node to output
         """
-        self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
+        driver = node.driver
+        parent_driver = node.parent_driver
+
+        line1 = 'Node %s index %d' % (node.path, node.idx)
+        if driver:
+            self.buf('/*\n')
+            self.buf(' * %s\n' % line1)
+            self.buf(' * driver %s parent %s\n' % (driver.name,
+                parent_driver.name if parent_driver else 'None'))
+            self.buf(' */\n')
+        else:
+            self.buf('/* %s */\n' % line1)
 
         self._output_values(node)
         self._declare_device(node)
 
         self.out(''.join(self.get_buf()))
 
+    def check_instantiate(self, require):
+        """Check if self._instantiate is set to the required value
+
+        If not, this outputs a message into the current file
+
+        Args:
+            require: True to require --instantiate, False to require that it not
+                be enabled
+        """
+        if require != self._instantiate:
+            self.out(
+                '/* This file is not used: --instantiate was %senabled */\n' %
+                ('not ' if require else ''))
+            return False
+        return True
+
     def generate_plat(self):
         """Generate device defintions for the platform data
 
@@ -809,6 +836,8 @@ class DtbPlatdata():
         See the documentation in doc/driver-model/of-plat.rst for more
         information.
         """
+        if not self.check_instantiate(False):
+            return
         self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
         self.out('#define DT_PLAT_C\n')
         self.out('\n')
@@ -818,7 +847,7 @@ class DtbPlatdata():
         self.out('\n')
 
         for node in self._valid_nodes:
-            self.output_node(node)
+            self.output_node_plat(node)
 
         self.out(''.join(self.get_buf()))
 
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index a51a7f301ce..c6e33d34227 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -48,13 +48,15 @@ DECL_HEADER = '''/*
  */
 '''
 
-C_HEADER = '''/*
+C_HEADER_PRE = '''/*
  * DO NOT MODIFY
  *
  * Declares the U_BOOT_DRIVER() records and platform data.
  * This was generated by dtoc from a .dtb (device tree binary) file.
  */
+'''
 
+C_HEADER = C_HEADER_PRE + '''
 /* Allow use of U_BOOT_DRVINFO() in this file */
 #define DT_PLAT_C
 
@@ -289,9 +291,11 @@ struct dtd_sandbox_spl_test {
 \tconst char *\tstringval;
 };
 '''
-
     platdata_text = C_HEADER + '''
-/* Node /i2c at 0 index 0 */
+/*
+ * Node /i2c at 0 index 0
+ * driver sandbox_i2c parent None
+ */
 static struct dtd_sandbox_i2c dtv_i2c_at_0 = {
 };
 U_BOOT_DRVINFO(i2c_at_0) = {
@@ -301,7 +305,10 @@ U_BOOT_DRVINFO(i2c_at_0) = {
 \t.parent_idx\t= -1,
 };
 
-/* Node /i2c at 0/pmic at 9 index 1 */
+/*
+ * Node /i2c at 0/pmic at 9 index 1
+ * driver sandbox_pmic parent sandbox_i2c
+ */
 static struct dtd_sandbox_pmic dtv_pmic_at_9 = {
 \t.low_power\t\t= true,
 \t.reg\t\t\t= {0x9, 0x0},
@@ -313,7 +320,10 @@ U_BOOT_DRVINFO(pmic_at_9) = {
 \t.parent_idx\t= 0,
 };
 
-/* Node /spl-test index 2 */
+/*
+ * Node /spl-test index 2
+ * driver sandbox_spl_test parent None
+ */
 static struct dtd_sandbox_spl_test dtv_spl_test = {
 \t.boolval\t\t= true,
 \t.bytearray\t\t= {0x6, 0x0, 0x0},
@@ -333,7 +343,10 @@ U_BOOT_DRVINFO(spl_test) = {
 \t.parent_idx\t= -1,
 };
 
-/* Node /spl-test2 index 3 */
+/*
+ * Node /spl-test2 index 3
+ * driver sandbox_spl_test parent None
+ */
 static struct dtd_sandbox_spl_test dtv_spl_test2 = {
 \t.acpi_name\t\t= "\\\\_SB.GPO0",
 \t.bytearray\t\t= {0x1, 0x23, 0x34},
@@ -352,7 +365,10 @@ U_BOOT_DRVINFO(spl_test2) = {
 \t.parent_idx\t= -1,
 };
 
-/* Node /spl-test3 index 4 */
+/*
+ * Node /spl-test3 index 4
+ * driver sandbox_spl_test parent None
+ */
 static struct dtd_sandbox_spl_test dtv_spl_test3 = {
 \t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
 \t\t0x0},
@@ -414,7 +430,10 @@ struct dtd_sandbox_gpio {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
-/* Node /gpios at 0 index 0 */
+/*
+ * Node /gpios at 0 index 0
+ * driver sandbox_gpio parent None
+ */
 static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
 \t.gpio_bank_name\t\t= "a",
 \t.gpio_controller\t= true,
@@ -942,7 +961,10 @@ struct dtd_sandbox_spl_test {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
-/* Node /spl-test index 0 */
+/*
+ * Node /spl-test index 0
+ * driver sandbox_spl_test parent None
+ */
 static struct dtd_sandbox_spl_test dtv_spl_test = {
 \t.intval\t\t\t= 0x1,
 };
@@ -953,7 +975,10 @@ U_BOOT_DRVINFO(spl_test) = {
 \t.parent_idx\t= -1,
 };
 
-/* Node /spl-test2 index 1 */
+/*
+ * Node /spl-test2 index 1
+ * driver sandbox_spl_test parent None
+ */
 static struct dtd_sandbox_spl_test dtv_spl_test2 = {
 \t.intarray\t\t= 0x5,
 };
@@ -1226,3 +1251,11 @@ U_BOOT_DRVINFO(spl_test2) = {
             data = infile.read()
 
         self._check_strings(self.decl_text_inst, data)
+
+        self.run_test(['platdata'], dtb_file, output, True)
+        with open(output) as infile:
+            data = infile.read()
+
+        self._check_strings(C_HEADER_PRE + '''
+/* This file is not used: --instantiate was enabled */
+''', data)
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 28/33] sandbox: Make sandbox,emul more conventional
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (26 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 27/33] dtoc: Don't generate platform data with instantiation Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 29/33] sandbox: i2c: Rename driver names to work with of-platdata Simon Glass
                   ` (37 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

At present this property is a phandle but does not have a #xxx-cells
property to match it. Add one so that is works the same as gpio and clock
phandles.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 arch/sandbox/dts/sandbox.dtsi | 6 +++++-
 doc/driver-model/pci-info.rst | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index dc933f3bfc7..7455c99a739 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -101,15 +101,19 @@
 		};
 
 		i2c_emul: emul {
+			u-boot,dm-pre-reloc;
 			reg = <0xff>;
 			compatible = "sandbox,i2c-emul-parent";
 			emul_eeprom: emul-eeprom {
 				compatible = "sandbox,i2c-eeprom";
 				sandbox,filename = "i2c.bin";
 				sandbox,size = <256>;
+				#emul-cells = <0>;
 			};
 			emul0: emul0 {
-				compatible = "sandbox,i2c-rtc";
+				u-boot,dm-pre-reloc;
+				compatible = "sandbox,i2c-rtc-emul";
+				#emul-cells = <0>;
 			};
 		};
 	};
diff --git a/doc/driver-model/pci-info.rst b/doc/driver-model/pci-info.rst
index 8b9faa10663..251601a51e3 100644
--- a/doc/driver-model/pci-info.rst
+++ b/doc/driver-model/pci-info.rst
@@ -125,6 +125,7 @@ emulator driver. For example::
 		compatible = "sandbox,pci-emul-parent";
 		emul_1f: emul at 1f,0 {
 			compatible = "sandbox,swap-case";
+			#emul-cells = <0>;
 		};
 	};
 
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 29/33] sandbox: i2c: Rename driver names to work with of-platdata
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (27 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 28/33] sandbox: Make sandbox,emul more conventional Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 30/33] dtoc: Tidy up the list of supported phandle properties Simon Glass
                   ` (36 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Some of these do not follow the rules. Make sure the driver name matches
the compatible string in all cases.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- New patch

 arch/sandbox/dts/test.dts     | 4 ++--
 drivers/i2c/i2c-emul-uclass.c | 4 ++--
 drivers/rtc/i2c_rtc_emul.c    | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index e95f4631bf2..b8d3be543c9 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -558,10 +558,10 @@
 				sandbox,size = <256>;
 			};
 			emul0: emul0 {
-				compatible = "sandbox,i2c-rtc";
+				compatible = "sandbox,i2c-rtc-emul";
 			};
 			emul1: emull {
-				compatible = "sandbox,i2c-rtc";
+				compatible = "sandbox,i2c-rtc-emul";
 			};
 		};
 
diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c
index 085b824e895..75d79883380 100644
--- a/drivers/i2c/i2c-emul-uclass.c
+++ b/drivers/i2c/i2c-emul-uclass.c
@@ -85,8 +85,8 @@ static const struct udevice_id i2c_emul_parent_ids[] = {
 	{ }
 };
 
-U_BOOT_DRIVER(i2c_emul_parent_drv) = {
-	.name		= "i2c_emul_parent_drv",
+U_BOOT_DRIVER(sandbox_i2c_emul_parent) = {
+	.name		= "sandbox_i2c_emul_parent",
 	.id		= UCLASS_I2C_EMUL_PARENT,
 	.of_match	= i2c_emul_parent_ids,
 };
diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c
index f25b976e54d..fdc885c518b 100644
--- a/drivers/rtc/i2c_rtc_emul.c
+++ b/drivers/rtc/i2c_rtc_emul.c
@@ -223,7 +223,7 @@ static int sandbox_i2c_rtc_bind(struct udevice *dev)
 }
 
 static const struct udevice_id sandbox_i2c_rtc_ids[] = {
-	{ .compatible = "sandbox,i2c-rtc" },
+	{ .compatible = "sandbox,i2c-rtc-emul" },
 	{ }
 };
 
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 30/33] dtoc: Tidy up the list of supported phandle properties
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (28 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 29/33] sandbox: i2c: Rename driver names to work with of-platdata Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 31/33] dtoc: Generate a summary in the dt-plat.c file Simon Glass
                   ` (35 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

For now dtoc only supports a hard-coded list of phandle properties, to
avoid any situation where it makes a mistake in its determination.

Make this into a constant dict, recording both the phandle property name
and the associated #cells property in the target node. This makes it
easier to find and modify.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- New patch

 tools/dtoc/dtb_platdata.py | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index befe7c14901..ca2e55fa526 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -52,6 +52,20 @@ TYPE_NAMES = {
 STRUCT_PREFIX = 'dtd_'
 VAL_PREFIX = 'dtv_'
 
+# Properties which are considered to be phandles
+#    key: property name
+#    value: name of associated #cells property in the target node
+#
+# New phandle properties must be added here; otherwise they will come through as
+# simple integers and finding devices by phandle will not work.
+# Any property that ends with one of these (e.g. 'cd-gpios') will be considered
+# a phandle property.
+PHANDLE_PROPS = {
+    'clocks': '#clock-cells',
+    'gpios': '#gpio-cells',
+    'sandbox,emul': '#emul-cells',
+    }
+
 class Ftype(IntEnum):
     SOURCE, HEADER = range(2)
 
@@ -290,7 +304,11 @@ class DtbPlatdata():
             ValueError: if the phandle cannot be parsed or the required property
                 is not present
         """
-        if prop.name in ['clocks', 'cd-gpios']:
+        cells_prop = None
+        for name, cprop in PHANDLE_PROPS.items():
+            if prop.name.endswith(name):
+                cells_prop = cprop
+        if cells_prop:
             if not isinstance(prop.value, list):
                 prop.value = [prop.value]
             val = prop.value
@@ -310,14 +328,10 @@ class DtbPlatdata():
                 if not target:
                     raise ValueError("Cannot parse '%s' in node '%s'" %
                                      (prop.name, node_name))
-                cells = None
-                for prop_name in ['#clock-cells', '#gpio-cells']:
-                    cells = target.props.get(prop_name)
-                    if cells:
-                        break
+                cells = target.props.get(cells_prop)
                 if not cells:
                     raise ValueError("Node '%s' has no cells property" %
-                                     (target.name))
+                                     target.name)
                 num_args = fdt_util.fdt32_to_cpu(cells.value)
                 max_args = max(max_args, num_args)
                 args.append(num_args)
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 31/33] dtoc: Generate a summary in the dt-plat.c file
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (29 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 30/33] dtoc: Tidy up the list of supported phandle properties Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 32/33] dtoc: Generate uclass devices Simon Glass
                   ` (34 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Add a summary to the top of the generated code, to make it easier to see
what the file contains.

Also add a tab to .plat so that its value lines up with the others.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py |  20 +++-
 tools/dtoc/test_dtoc.py    | 184 ++++++++++++++++++++++++++++++-------
 2 files changed, 169 insertions(+), 35 deletions(-)

diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index ca2e55fa526..ab26c4adca5 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -639,7 +639,7 @@ class DtbPlatdata():
         """
         self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
         self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
-        self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
+        self.buf('\t.plat\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
         self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
                  (VAL_PREFIX, node.var_name))
         idx = -1
@@ -860,8 +860,22 @@ class DtbPlatdata():
         self.out('#include <dt-structs.h>\n')
         self.out('\n')
 
-        for node in self._valid_nodes:
-            self.output_node_plat(node)
+        if self._valid_nodes:
+            self.out('/*\n')
+            self.out(
+                " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
+            self.out(' *\n')
+            self.out(' * idx  %-20s %-s\n' % ('driver_info', 'driver'))
+            self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
+            for node in self._valid_nodes:
+                self.out(' * %3d: %-20s %-s\n' %
+                        (node.idx, node.var_name, node.struct_name))
+            self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
+            self.out(' */\n')
+            self.out('\n')
+
+            for node in self._valid_nodes:
+                self.output_node_plat(node)
 
         self.out(''.join(self.get_buf()))
 
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index c6e33d34227..56d5c8d6b38 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -292,6 +292,19 @@ struct dtd_sandbox_spl_test {
 };
 '''
     platdata_text = C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: i2c_at_0             sandbox_i2c
+ *   1: pmic_at_9            sandbox_pmic
+ *   2: spl_test             sandbox_spl_test
+ *   3: spl_test2            sandbox_spl_test
+ *   4: spl_test3            sandbox_spl_test
+ * ---  -------------------- --------------------
+ */
+
 /*
  * Node /i2c at 0 index 0
  * driver sandbox_i2c parent None
@@ -300,7 +313,7 @@ static struct dtd_sandbox_i2c dtv_i2c_at_0 = {
 };
 U_BOOT_DRVINFO(i2c_at_0) = {
 \t.name\t\t= "sandbox_i2c",
-\t.plat\t= &dtv_i2c_at_0,
+\t.plat\t\t= &dtv_i2c_at_0,
 \t.plat_size\t= sizeof(dtv_i2c_at_0),
 \t.parent_idx\t= -1,
 };
@@ -315,7 +328,7 @@ static struct dtd_sandbox_pmic dtv_pmic_at_9 = {
 };
 U_BOOT_DRVINFO(pmic_at_9) = {
 \t.name\t\t= "sandbox_pmic",
-\t.plat\t= &dtv_pmic_at_9,
+\t.plat\t\t= &dtv_pmic_at_9,
 \t.plat_size\t= sizeof(dtv_pmic_at_9),
 \t.parent_idx\t= 0,
 };
@@ -338,7 +351,7 @@ static struct dtd_sandbox_spl_test dtv_spl_test = {
 };
 U_BOOT_DRVINFO(spl_test) = {
 \t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test,
+\t.plat\t\t= &dtv_spl_test,
 \t.plat_size\t= sizeof(dtv_spl_test),
 \t.parent_idx\t= -1,
 };
@@ -360,7 +373,7 @@ static struct dtd_sandbox_spl_test dtv_spl_test2 = {
 };
 U_BOOT_DRVINFO(spl_test2) = {
 \t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test2,
+\t.plat\t\t= &dtv_spl_test2,
 \t.plat_size\t= sizeof(dtv_spl_test2),
 \t.parent_idx\t= -1,
 };
@@ -376,7 +389,7 @@ static struct dtd_sandbox_spl_test dtv_spl_test3 = {
 };
 U_BOOT_DRVINFO(spl_test3) = {
 \t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test3,
+\t.plat\t\t= &dtv_spl_test3,
 \t.plat_size\t= sizeof(dtv_spl_test3),
 \t.parent_idx\t= -1,
 };
@@ -430,6 +443,15 @@ struct dtd_sandbox_gpio {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: gpios_at_0           sandbox_gpio
+ * ---  -------------------- --------------------
+ */
+
 /*
  * Node /gpios at 0 index 0
  * driver sandbox_gpio parent None
@@ -441,7 +463,7 @@ static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
 };
 U_BOOT_DRVINFO(gpios_at_0) = {
 \t.name\t\t= "sandbox_gpio",
-\t.plat\t= &dtv_gpios_at_0,
+\t.plat\t\t= &dtv_gpios_at_0,
 \t.plat_size\t= sizeof(dtv_gpios_at_0),
 \t.parent_idx\t= -1,
 };
@@ -470,12 +492,21 @@ struct dtd_invalid {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: spl_test             invalid
+ * ---  -------------------- --------------------
+ */
+
 /* Node /spl-test index 0 */
 static struct dtd_invalid dtv_spl_test = {
 };
 U_BOOT_DRVINFO(spl_test) = {
 \t.name\t\t= "invalid",
-\t.plat\t= &dtv_spl_test,
+\t.plat\t\t= &dtv_spl_test,
 \t.plat_size\t= sizeof(dtv_spl_test),
 \t.parent_idx\t= -1,
 };
@@ -502,13 +533,26 @@ struct dtd_target {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: phandle2_target      target
+ *   1: phandle3_target      target
+ *   2: phandle_source       source
+ *   3: phandle_source2      source
+ *   4: phandle_target       target
+ * ---  -------------------- --------------------
+ */
+
 /* Node /phandle2-target index 0 */
 static struct dtd_target dtv_phandle2_target = {
 \t.intval\t\t\t= 0x1,
 };
 U_BOOT_DRVINFO(phandle2_target) = {
 \t.name\t\t= "target",
-\t.plat\t= &dtv_phandle2_target,
+\t.plat\t\t= &dtv_phandle2_target,
 \t.plat_size\t= sizeof(dtv_phandle2_target),
 \t.parent_idx\t= -1,
 };
@@ -519,7 +563,7 @@ static struct dtd_target dtv_phandle3_target = {
 };
 U_BOOT_DRVINFO(phandle3_target) = {
 \t.name\t\t= "target",
-\t.plat\t= &dtv_phandle3_target,
+\t.plat\t\t= &dtv_phandle3_target,
 \t.plat_size\t= sizeof(dtv_phandle3_target),
 \t.parent_idx\t= -1,
 };
@@ -534,7 +578,7 @@ static struct dtd_source dtv_phandle_source = {
 };
 U_BOOT_DRVINFO(phandle_source) = {
 \t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source,
+\t.plat\t\t= &dtv_phandle_source,
 \t.plat_size\t= sizeof(dtv_phandle_source),
 \t.parent_idx\t= -1,
 };
@@ -546,7 +590,7 @@ static struct dtd_source dtv_phandle_source2 = {
 };
 U_BOOT_DRVINFO(phandle_source2) = {
 \t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source2,
+\t.plat\t\t= &dtv_phandle_source2,
 \t.plat_size\t= sizeof(dtv_phandle_source2),
 \t.parent_idx\t= -1,
 };
@@ -557,7 +601,7 @@ static struct dtd_target dtv_phandle_target = {
 };
 U_BOOT_DRVINFO(phandle_target) = {
 \t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
+\t.plat\t\t= &dtv_phandle_target,
 \t.plat_size\t= sizeof(dtv_phandle_target),
 \t.parent_idx\t= -1,
 };
@@ -588,6 +632,16 @@ struct dtd_target {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: phandle_source2      source
+ *   1: phandle_target       target
+ * ---  -------------------- --------------------
+ */
+
 /* Node /phandle-source2 index 0 */
 static struct dtd_source dtv_phandle_source2 = {
 \t.clocks\t\t\t= {
@@ -595,7 +649,7 @@ static struct dtd_source dtv_phandle_source2 = {
 };
 U_BOOT_DRVINFO(phandle_source2) = {
 \t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source2,
+\t.plat\t\t= &dtv_phandle_source2,
 \t.plat_size\t= sizeof(dtv_phandle_source2),
 \t.parent_idx\t= -1,
 };
@@ -605,7 +659,7 @@ static struct dtd_target dtv_phandle_target = {
 };
 U_BOOT_DRVINFO(phandle_target) = {
 \t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
+\t.plat\t\t= &dtv_phandle_target,
 \t.plat_size\t= sizeof(dtv_phandle_target),
 \t.parent_idx\t= -1,
 };
@@ -622,13 +676,26 @@ U_BOOT_DRVINFO(phandle_target) = {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: phandle2_target      target
+ *   1: phandle3_target      target
+ *   2: phandle_source       source
+ *   3: phandle_source2      source
+ *   4: phandle_target       target
+ * ---  -------------------- --------------------
+ */
+
 /* Node /phandle2-target index 0 */
 static struct dtd_target dtv_phandle2_target = {
 \t.intval\t\t\t= 0x1,
 };
 U_BOOT_DRVINFO(phandle2_target) = {
 \t.name\t\t= "target",
-\t.plat\t= &dtv_phandle2_target,
+\t.plat\t\t= &dtv_phandle2_target,
 \t.plat_size\t= sizeof(dtv_phandle2_target),
 \t.parent_idx\t= -1,
 };
@@ -639,7 +706,7 @@ static struct dtd_target dtv_phandle3_target = {
 };
 U_BOOT_DRVINFO(phandle3_target) = {
 \t.name\t\t= "target",
-\t.plat\t= &dtv_phandle3_target,
+\t.plat\t\t= &dtv_phandle3_target,
 \t.plat_size\t= sizeof(dtv_phandle3_target),
 \t.parent_idx\t= -1,
 };
@@ -654,7 +721,7 @@ static struct dtd_source dtv_phandle_source = {
 };
 U_BOOT_DRVINFO(phandle_source) = {
 \t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source,
+\t.plat\t\t= &dtv_phandle_source,
 \t.plat_size\t= sizeof(dtv_phandle_source),
 \t.parent_idx\t= -1,
 };
@@ -666,7 +733,7 @@ static struct dtd_source dtv_phandle_source2 = {
 };
 U_BOOT_DRVINFO(phandle_source2) = {
 \t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source2,
+\t.plat\t\t= &dtv_phandle_source2,
 \t.plat_size\t= sizeof(dtv_phandle_source2),
 \t.parent_idx\t= -1,
 };
@@ -677,7 +744,7 @@ static struct dtd_target dtv_phandle_target = {
 };
 U_BOOT_DRVINFO(phandle_target) = {
 \t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
+\t.plat\t\t= &dtv_phandle_target,
 \t.plat_size\t= sizeof(dtv_phandle_target),
 \t.parent_idx\t= -1,
 };
@@ -727,13 +794,24 @@ struct dtd_test3 {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: test1                test1
+ *   1: test2                test2
+ *   2: test3                test3
+ * ---  -------------------- --------------------
+ */
+
 /* Node /test1 index 0 */
 static struct dtd_test1 dtv_test1 = {
 \t.reg\t\t\t= {0x1234, 0x5678},
 };
 U_BOOT_DRVINFO(test1) = {
 \t.name\t\t= "test1",
-\t.plat\t= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
 \t.plat_size\t= sizeof(dtv_test1),
 \t.parent_idx\t= -1,
 };
@@ -744,7 +822,7 @@ static struct dtd_test2 dtv_test2 = {
 };
 U_BOOT_DRVINFO(test2) = {
 \t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
 \t.plat_size\t= sizeof(dtv_test2),
 \t.parent_idx\t= -1,
 };
@@ -755,7 +833,7 @@ static struct dtd_test3 dtv_test3 = {
 };
 U_BOOT_DRVINFO(test3) = {
 \t.name\t\t= "test3",
-\t.plat\t= &dtv_test3,
+\t.plat\t\t= &dtv_test3,
 \t.plat_size\t= sizeof(dtv_test3),
 \t.parent_idx\t= -1,
 };
@@ -782,13 +860,23 @@ struct dtd_test2 {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: test1                test1
+ *   1: test2                test2
+ * ---  -------------------- --------------------
+ */
+
 /* Node /test1 index 0 */
 static struct dtd_test1 dtv_test1 = {
 \t.reg\t\t\t= {0x1234, 0x5678},
 };
 U_BOOT_DRVINFO(test1) = {
 \t.name\t\t= "test1",
-\t.plat\t= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
 \t.plat_size\t= sizeof(dtv_test1),
 \t.parent_idx\t= -1,
 };
@@ -799,7 +887,7 @@ static struct dtd_test2 dtv_test2 = {
 };
 U_BOOT_DRVINFO(test2) = {
 \t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
 \t.plat_size\t= sizeof(dtv_test2),
 \t.parent_idx\t= -1,
 };
@@ -829,13 +917,24 @@ struct dtd_test3 {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: test1                test1
+ *   1: test2                test2
+ *   2: test3                test3
+ * ---  -------------------- --------------------
+ */
+
 /* Node /test1 index 0 */
 static struct dtd_test1 dtv_test1 = {
 \t.reg\t\t\t= {0x123400000000, 0x5678},
 };
 U_BOOT_DRVINFO(test1) = {
 \t.name\t\t= "test1",
-\t.plat\t= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
 \t.plat_size\t= sizeof(dtv_test1),
 \t.parent_idx\t= -1,
 };
@@ -846,7 +945,7 @@ static struct dtd_test2 dtv_test2 = {
 };
 U_BOOT_DRVINFO(test2) = {
 \t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
 \t.plat_size\t= sizeof(dtv_test2),
 \t.parent_idx\t= -1,
 };
@@ -857,7 +956,7 @@ static struct dtd_test3 dtv_test3 = {
 };
 U_BOOT_DRVINFO(test3) = {
 \t.name\t\t= "test3",
-\t.plat\t= &dtv_test3,
+\t.plat\t\t= &dtv_test3,
 \t.plat_size\t= sizeof(dtv_test3),
 \t.parent_idx\t= -1,
 };
@@ -887,13 +986,24 @@ struct dtd_test3 {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: test1                test1
+ *   1: test2                test2
+ *   2: test3                test3
+ * ---  -------------------- --------------------
+ */
+
 /* Node /test1 index 0 */
 static struct dtd_test1 dtv_test1 = {
 \t.reg\t\t\t= {0x1234, 0x567800000000},
 };
 U_BOOT_DRVINFO(test1) = {
 \t.name\t\t= "test1",
-\t.plat\t= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
 \t.plat_size\t= sizeof(dtv_test1),
 \t.parent_idx\t= -1,
 };
@@ -904,7 +1014,7 @@ static struct dtd_test2 dtv_test2 = {
 };
 U_BOOT_DRVINFO(test2) = {
 \t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
 \t.plat_size\t= sizeof(dtv_test2),
 \t.parent_idx\t= -1,
 };
@@ -915,7 +1025,7 @@ static struct dtd_test3 dtv_test3 = {
 };
 U_BOOT_DRVINFO(test3) = {
 \t.name\t\t= "test3",
-\t.plat\t= &dtv_test3,
+\t.plat\t\t= &dtv_test3,
 \t.plat_size\t= sizeof(dtv_test3),
 \t.parent_idx\t= -1,
 };
@@ -961,6 +1071,16 @@ struct dtd_sandbox_spl_test {
         with open(output) as infile:
             data = infile.read()
         self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx  driver_info          driver
+ * ---  -------------------- --------------------
+ *   0: spl_test             sandbox_spl_test
+ *   1: spl_test2            sandbox_spl_test
+ * ---  -------------------- --------------------
+ */
+
 /*
  * Node /spl-test index 0
  * driver sandbox_spl_test parent None
@@ -970,7 +1090,7 @@ static struct dtd_sandbox_spl_test dtv_spl_test = {
 };
 U_BOOT_DRVINFO(spl_test) = {
 \t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test,
+\t.plat\t\t= &dtv_spl_test,
 \t.plat_size\t= sizeof(dtv_spl_test),
 \t.parent_idx\t= -1,
 };
@@ -984,7 +1104,7 @@ static struct dtd_sandbox_spl_test dtv_spl_test2 = {
 };
 U_BOOT_DRVINFO(spl_test2) = {
 \t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test2,
+\t.plat\t\t= &dtv_spl_test2,
 \t.plat_size\t= sizeof(dtv_spl_test2),
 \t.parent_idx\t= -1,
 };
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 32/33] dtoc: Generate uclass devices
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (30 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 31/33] dtoc: Generate a summary in the dt-plat.c file Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-03 13:01 ` [PATCH v2 33/33] dtoc: Generate device instances Simon Glass
                   ` (33 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Add support for generating a file containing uclass instances. This avoids
the need to create these at run time.

Update a test uclass to include a 'priv_auto' member, to increase test
coverage.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 drivers/misc/test_drv.c    |   1 +
 include/dm/test.h          |   5 ++
 tools/dtoc/dtb_platdata.py |  93 +++++++++++++++++++++
 tools/dtoc/test_dtoc.py    | 164 ++++++++++++++++++++++++++++++++++---
 4 files changed, 250 insertions(+), 13 deletions(-)

diff --git a/drivers/misc/test_drv.c b/drivers/misc/test_drv.c
index ac762fd9fea..c516d6a262d 100644
--- a/drivers/misc/test_drv.c
+++ b/drivers/misc/test_drv.c
@@ -204,6 +204,7 @@ UCLASS_DRIVER(testfdt) = {
 	.name		= "testfdt",
 	.id		= UCLASS_TEST_FDT,
 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.priv_auto	= sizeof(struct dm_test_uc_priv),
 };
 
 static const struct udevice_id testfdtm_ids[] = {
diff --git a/include/dm/test.h b/include/dm/test.h
index fe1cc2e278c..30f71edbd96 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -71,6 +71,11 @@ struct dm_test_priv {
 	int uclass_postp;
 };
 
+/* struct dm_test_uc_priv - private data for the testdrv uclass */
+struct dm_test_uc_priv {
+	int dummy;
+};
+
 /**
  * struct dm_test_perdev_class_priv - private per-device data for test uclass
  */
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index ab26c4adca5..6dadf37582f 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -246,6 +246,7 @@ class DtbPlatdata():
         """
         if self._outfile != sys.stdout:
             self._outfile.close()
+            self._outfile = None
 
     def out(self, line):
         """Output a string to the output file
@@ -649,6 +650,27 @@ class DtbPlatdata():
         self.buf('};\n')
         self.buf('\n')
 
+    def prep_priv(self, struc, name, suffix, section='.priv_data'):
+        if not struc:
+            return None
+        var_name = '_%s%s' % (name, suffix)
+        hdr = self._scan._structs.get(struc)
+        if hdr:
+            self.buf('#include <%s>\n' % hdr.fname)
+        else:
+            print('Warning: Cannot find header file for struct %s' % struc)
+        attr = '__attribute__ ((section ("%s")))' % section
+        return var_name, struc, attr
+
+    def alloc_priv(self, info, name, extra, suffix='_priv'):
+        result = self.prep_priv(info, name, suffix)
+        if not result:
+            return None
+        var_name, struc, section = result
+        self.buf('u8 %s_%s[sizeof(struct %s)]\n\t%s;\n' %
+                 (var_name, extra, struc.strip(), section))
+        return '%s_%s' % (var_name, extra)
+
     def _output_prop(self, node, prop):
         """Output a line containing the value of a struct member
 
@@ -680,6 +702,74 @@ class DtbPlatdata():
             self._output_prop(node, node.props[pname])
         self.buf('};\n')
 
+    def list_head(self, head_member, node_member, node_refs, var_name):
+        self.buf('\t.%s\t= {\n' % head_member)
+        if node_refs:
+            last = node_refs[-1].dev_ref
+            first = node_refs[0].dev_ref
+            member = node_member
+        else:
+            last = 'DM_DEVICE_REF(%s)' % var_name
+            first = last
+            member = head_member
+        self.buf('\t\t.prev = &%s->%s,\n' % (last, member))
+        self.buf('\t\t.next = &%s->%s,\n' % (first, member))
+        self.buf('\t},\n')
+
+    def list_node(self, member, node_refs, seq):
+        self.buf('\t.%s\t= {\n' % member)
+        self.buf('\t\t.prev = %s,\n' % node_refs[seq - 1])
+        self.buf('\t\t.next = %s,\n' % node_refs[seq + 1])
+        self.buf('\t},\n')
+
+    def generate_uclasses(self):
+        if not self.check_instantiate(True):
+            return
+        self.out('\n')
+        self.out('#include <common.h>\n')
+        self.out('#include <dm.h>\n')
+        self.out('#include <dt-structs.h>\n')
+        self.out('\n')
+        self.buf('/*\n')
+        self.buf(' * uclass declarations\n')
+        self.buf(' *\n')
+        self.buf(' * Sequence numbers:\n')
+        uclass_list = self._valid_uclasses
+        for uclass in uclass_list:
+            if uclass.alias_num_to_node:
+                self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
+                for seq, node in uclass.alias_num_to_node.items():
+                    self.buf(' *    %d: %s\n' % (seq, node.path))
+        self.buf(' */\n')
+
+        uclass_node = {}
+        for seq, uclass in enumerate(uclass_list):
+            uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' %
+                                uclass.name)
+        uclass_node[-1] = '&uclass_head'
+        uclass_node[len(uclass_list)] = '&uclass_head'
+        self.buf('\n')
+        self.buf('struct list_head %s = {\n' % 'uclass_head')
+        self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1])
+        self.buf('\t.next = %s,\n' % uclass_node[0])
+        self.buf('};\n')
+        self.buf('\n')
+
+        for seq, uclass in enumerate(uclass_list):
+            uc_drv = self._scan._uclass.get(uclass.uclass_id)
+
+            priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '')
+
+            self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name)
+            if priv_name:
+                self.buf('\t.priv_\t\t= %s,\n' % priv_name)
+            self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name)
+            self.list_node('sibling_node', uclass_node, seq)
+            self.list_head('dev_head', 'uclass_node', uc_drv.devs, None)
+            self.buf('};\n')
+            self.buf('\n')
+        self.out(''.join(self.get_buf()))
+
     def read_aliases(self):
         """Read the aliases and attach the information to self._alias
 
@@ -894,6 +984,9 @@ OUTPUT_FILES = {
     'platdata':
         OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
                    'Declares the U_BOOT_DRIVER() records and platform data'),
+    'uclass':
+        OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
+                   'Declares the uclass instances (struct uclass)'),
     }
 
 
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 56d5c8d6b38..053d140664e 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -16,6 +16,7 @@ import os
 import struct
 import unittest
 
+from dtb_platdata import Ftype
 from dtb_platdata import get_value
 from dtb_platdata import tab_to
 from dtoc import dtb_platdata
@@ -65,6 +66,18 @@ C_HEADER = C_HEADER_PRE + '''
 #include <dt-structs.h>
 '''
 
+UCLASS_HEADER_COMMON = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the uclass instances (struct uclass).
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+'''
+
+UCLASS_HEADER = UCLASS_HEADER_COMMON + '''
+/* This file is not used: --instantiate was not enabled */
+'''
+
 # Scanner saved from a previous run of the tests (to speed things up)
 saved_scan = None
 
@@ -245,31 +258,35 @@ DM_UCLASS_DRIVER_DECL(pmic);
 
 /* driver declarations - these allow DM_DRIVER_GET() to be used */
 DM_DRIVER_DECL(sandbox_i2c);
-DM_DRIVER_DECL(sandbox_pmic);
 DM_DRIVER_DECL(root_driver);
+DM_DRIVER_DECL(denx_u_boot_test_bus);
 DM_DRIVER_DECL(sandbox_spl_test);
 DM_DRIVER_DECL(sandbox_spl_test);
-DM_DRIVER_DECL(sandbox_spl_test);
+DM_DRIVER_DECL(denx_u_boot_fdt_test);
+DM_DRIVER_DECL(denx_u_boot_fdt_test);
 
 /* device declarations - these allow DM_DEVICE_REF() to be used */
-DM_DEVICE_DECL(i2c_at_0);
-DM_DEVICE_DECL(pmic_at_9);
+DM_DEVICE_DECL(i2c);
 DM_DEVICE_DECL(root);
+DM_DEVICE_DECL(some_bus);
 DM_DEVICE_DECL(spl_test);
-DM_DEVICE_DECL(spl_test2);
 DM_DEVICE_DECL(spl_test3);
+DM_DEVICE_DECL(test);
+DM_DEVICE_DECL(test0);
 
 /* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
 DM_UCLASS_DRIVER_DECL(i2c);
 DM_UCLASS_DRIVER_DECL(misc);
-DM_UCLASS_DRIVER_DECL(pmic);
 DM_UCLASS_DRIVER_DECL(root);
+DM_UCLASS_DRIVER_DECL(testbus);
+DM_UCLASS_DRIVER_DECL(testfdt);
 
 /* uclass declarations - needed for DM_UCLASS_REF() */
 DM_UCLASS_DECL(i2c);
 DM_UCLASS_DECL(misc);
-DM_UCLASS_DECL(pmic);
 DM_UCLASS_DECL(root);
+DM_UCLASS_DECL(testbus);
+DM_UCLASS_DECL(testfdt);
 '''
     struct_text = HEADER + '''
 struct dtd_sandbox_i2c {
@@ -394,6 +411,101 @@ U_BOOT_DRVINFO(spl_test3) = {
 \t.parent_idx\t= -1,
 };
 
+'''
+    uclass_text = UCLASS_HEADER
+    uclass_text_inst = '''
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+/*
+ * uclass declarations
+ *
+ * Sequence numbers:
+ * i2c: UCLASS_I2C
+ *    4: /i2c
+ * misc: UCLASS_MISC
+ *    0: /spl-test
+ *    1: /spl-test3
+ * root: UCLASS_ROOT
+ *    0: /
+ * testbus: UCLASS_TEST_BUS
+ *    2: /some-bus
+ * testfdt: UCLASS_TEST_FDT
+ *    1: /some-bus/test
+ *    2: /some-bus/test0
+ */
+
+struct list_head uclass_head = {
+	.prev = &DM_UCLASS_REF(testfdt)->sibling_node,
+	.next = &DM_UCLASS_REF(i2c)->sibling_node,
+};
+
+DM_UCLASS_INST(i2c) = {
+	.uc_drv		= DM_UCLASS_DRIVER_REF(i2c),
+	.sibling_node	= {
+		.prev = &uclass_head,
+		.next = &DM_UCLASS_REF(misc)->sibling_node,
+	},
+	.dev_head	= {
+		.prev = &DM_DEVICE_REF(i2c)->uclass_node,
+		.next = &DM_DEVICE_REF(i2c)->uclass_node,
+	},
+};
+
+DM_UCLASS_INST(misc) = {
+	.uc_drv		= DM_UCLASS_DRIVER_REF(misc),
+	.sibling_node	= {
+		.prev = &DM_UCLASS_REF(i2c)->sibling_node,
+		.next = &DM_UCLASS_REF(root)->sibling_node,
+	},
+	.dev_head	= {
+		.prev = &DM_DEVICE_REF(spl_test3)->uclass_node,
+		.next = &DM_DEVICE_REF(spl_test)->uclass_node,
+	},
+};
+
+DM_UCLASS_INST(root) = {
+	.uc_drv		= DM_UCLASS_DRIVER_REF(root),
+	.sibling_node	= {
+		.prev = &DM_UCLASS_REF(misc)->sibling_node,
+		.next = &DM_UCLASS_REF(testbus)->sibling_node,
+	},
+	.dev_head	= {
+		.prev = &DM_DEVICE_REF(root)->uclass_node,
+		.next = &DM_DEVICE_REF(root)->uclass_node,
+	},
+};
+
+DM_UCLASS_INST(testbus) = {
+	.uc_drv		= DM_UCLASS_DRIVER_REF(testbus),
+	.sibling_node	= {
+		.prev = &DM_UCLASS_REF(root)->sibling_node,
+		.next = &DM_UCLASS_REF(testfdt)->sibling_node,
+	},
+	.dev_head	= {
+		.prev = &DM_DEVICE_REF(some_bus)->uclass_node,
+		.next = &DM_DEVICE_REF(some_bus)->uclass_node,
+	},
+};
+
+#include <dm/test.h>
+u8 _testfdt_priv_[sizeof(struct dm_test_uc_priv)]
+	__attribute__ ((section (".priv_data")));
+DM_UCLASS_INST(testfdt) = {
+	.priv_		= _testfdt_priv_,
+	.uc_drv		= DM_UCLASS_DRIVER_REF(testfdt),
+	.sibling_node	= {
+		.prev = &DM_UCLASS_REF(testbus)->sibling_node,
+		.next = &uclass_head,
+	},
+	.dev_head	= {
+		.prev = &DM_DEVICE_REF(test0)->uclass_node,
+		.next = &DM_DEVICE_REF(test)->uclass_node,
+	},
+};
+
 '''
 
     def test_simple(self):
@@ -422,7 +534,7 @@ U_BOOT_DRVINFO(spl_test3) = {
         self.run_test(['all'], dtb_file, output)
         data = tools.ReadFile(output, binary=False)
         self._check_strings(self.decl_text + self.platdata_text +
-                            self.struct_text, data)
+                            self.struct_text + self.uclass_text, data)
 
     def test_driver_alias(self):
         """Test output from a device tree file with a driver alias"""
@@ -1125,7 +1237,7 @@ U_BOOT_DRVINFO(spl_test2) = {
         self.run_test(['all'], dtb_file, output)
         data = tools.ReadFile(output, binary=False)
         self._check_strings(self.decl_text + self.platdata_text +
-                            self.struct_text, data)
+                            self.struct_text + self.uclass_text, data)
 
     def test_no_command(self):
         """Test running dtoc without a command"""
@@ -1141,7 +1253,7 @@ U_BOOT_DRVINFO(spl_test2) = {
         with self.assertRaises(ValueError) as exc:
             self.run_test(['invalid-cmd'], dtb_file, output)
         self.assertIn(
-            "Unknown command 'invalid-cmd': (use: decl, platdata, struct)",
+            "Unknown command 'invalid-cmd': (use: decl, platdata, struct, uclass)",
             str(exc.exception))
 
     def test_output_conflict(self):
@@ -1169,12 +1281,12 @@ U_BOOT_DRVINFO(spl_test2) = {
             ['all'], dtb_file, False, None, [outdir], None, False,
             warning_disabled=True, scan=copy_scan())
         fnames = glob.glob(outdir + '/*')
-        self.assertEqual(5, len(fnames))
+        self.assertEqual(6, len(fnames))
 
         leafs = set(os.path.basename(fname) for fname in fnames)
         self.assertEqual(
             {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb',
-             'dt-decl.h'},
+             'dt-uclass.c', 'dt-decl.h'},
             leafs)
 
     def setup_process_test(self):
@@ -1363,7 +1475,7 @@ U_BOOT_DRVINFO(spl_test2) = {
 
     def test_simple_inst(self):
         """Test output from some simple nodes with instantiate enabled"""
-        dtb_file = get_dtb_file('dtoc_test_simple.dts')
+        dtb_file = get_dtb_file('dtoc_test_inst.dts')
         output = tools.GetOutputFilename('output')
 
         self.run_test(['decl'], dtb_file, output, True)
@@ -1379,3 +1491,29 @@ U_BOOT_DRVINFO(spl_test2) = {
         self._check_strings(C_HEADER_PRE + '''
 /* This file is not used: --instantiate was enabled */
 ''', data)
+
+        self.run_test(['uclass'], dtb_file, output, True)
+        with open(output) as infile:
+            data = infile.read()
+
+        self._check_strings(UCLASS_HEADER_COMMON + self.uclass_text_inst, data)
+
+    def test_inst_no_hdr(self):
+        """Test dealing with a struct that has no header"""
+        dtb_file = get_dtb_file('dtoc_test_inst.dts')
+        output = tools.GetOutputFilename('output')
+
+        # Run it once to set everything up
+        plat = self.run_test(['decl'], dtb_file, output, True)
+        scan = plat._scan
+
+        # Restart the output file and delete any record of the uclass' struct
+        plat.setup_output(Ftype.SOURCE, output)
+        del scan._structs['dm_test_uc_priv']
+
+        # Now generate the uclasses, which should provide a warning
+        with test_util.capture_sys_output() as (stdout, _):
+            plat.generate_uclasses()
+        self.assertEqual(
+            'Warning: Cannot find header file for struct dm_test_uc_priv',
+            stdout.getvalue().strip())
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 33/33] dtoc: Generate device instances
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (31 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 32/33] dtoc: Generate uclass devices Simon Glass
@ 2021-02-03 13:01 ` Simon Glass
  2021-02-07  0:16 ` Simon Glass
                   ` (32 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-03 13:01 UTC (permalink / raw)
  To: u-boot

Add support for generating a file containing udevice instances. This
avoids the need to create these at run time.

Update a test uclass to include a 'per_device_plat_auto' member, to
increase test coverage.

Add another tab to the driver_info output so it lines up nicely like the
device-instance output.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Drop patches previously applied
- Update cover letter
- Fix the naming for uclass_plat_name so it is different from uclass_priv
- Tidy up tabbing to make the code output line up better
- Add a summary to the top of the generated file

 drivers/misc/test_drv.c    |   4 +
 tools/dtoc/dtb_platdata.py | 168 ++++++++++++++++++-
 tools/dtoc/test_dtoc.py    | 327 +++++++++++++++++++++++++++++++++++--
 3 files changed, 484 insertions(+), 15 deletions(-)

diff --git a/drivers/misc/test_drv.c b/drivers/misc/test_drv.c
index c516d6a262d..a6dd013e319 100644
--- a/drivers/misc/test_drv.c
+++ b/drivers/misc/test_drv.c
@@ -97,6 +97,7 @@ U_BOOT_DRIVER(denx_u_boot_test_bus) = {
 	.per_child_plat_auto	= sizeof(struct dm_test_parent_plat),
 	.child_pre_probe = testbus_child_pre_probe,
 	.child_post_remove = testbus_child_post_remove,
+	DM_HEADER(<test.h>)
 };
 
 UCLASS_DRIVER(testbus) = {
@@ -105,6 +106,9 @@ UCLASS_DRIVER(testbus) = {
 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 	.child_pre_probe = testbus_child_pre_probe_uclass,
 	.child_post_probe = testbus_child_post_probe_uclass,
+
+	/* This is for dtoc testing only */
+	.per_device_plat_auto   = sizeof(struct dm_test_uclass_priv),
 };
 
 static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 6dadf37582f..f5b5ad5f71a 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -671,7 +671,104 @@ class DtbPlatdata():
                  (var_name, extra, struc.strip(), section))
         return '%s_%s' % (var_name, extra)
 
-    def _output_prop(self, node, prop):
+    def alloc_plat(self, info, name, extra, node):
+        result = self.prep_priv(info, name, '_plat')
+        if not result:
+            return None
+        var_name, struc, section = result
+        self.buf('struct %s %s\n\t%s_%s = {\n' %
+                 (struc.strip(), section, var_name, extra))
+        self.buf('\t.dtplat = {\n')
+        for pname in sorted(node.props):
+            self._output_prop(node, node.props[pname], 2)
+        self.buf('\t},\n')
+        self.buf('};\n')
+        return '&%s_%s' % (var_name, extra)
+
+    def _declare_device_inst(self, node, parent_driver):
+        """Add a device instance declaration to the output
+
+        This declares a DM_DEVICE_INST() for the device being processed
+
+        Args:
+            node: Node to output
+        """
+        driver = node.driver
+        uclass = node.uclass
+        self.buf('\n')
+        num_lines = len(self._lines)
+        plat_name = self.alloc_plat(driver.plat, driver.name, node.var_name,
+                                    node)
+        priv_name = self.alloc_priv(driver.priv, driver.name, node.var_name)
+        parent_plat_name = None
+        parent_priv_name = None
+        if parent_driver:
+            # TODO: deal with uclass providing these values
+            parent_plat_name = self.alloc_priv(
+                parent_driver.child_plat, driver.name, node.var_name,
+                '_parent_plat')
+            parent_priv_name = self.alloc_priv(
+                parent_driver.child_priv, driver.name, node.var_name,
+                '_parent_priv')
+        uclass_plat_name = self.alloc_priv(
+            uclass.per_dev_plat, driver.name + '_uc', node.var_name, 'plat')
+        uclass_priv_name = self.alloc_priv(uclass.per_dev_priv,
+                                           driver.name + '_uc', node.var_name)
+        for hdr in driver.headers:
+            self.buf('#include %s\n' % hdr)
+
+        # Add a blank line if we emitted any stuff above, for readability
+        if num_lines != len(self._lines):
+            self.buf('\n')
+
+        self.buf('DM_DEVICE_INST(%s) = {\n' % node.var_name)
+        self.buf('\t.driver\t\t= DM_DRIVER_REF(%s),\n' % node.struct_name)
+        self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
+        if plat_name:
+            self.buf('\t.plat_\t\t= %s,\n' % plat_name)
+        else:
+            self.buf('\t.plat_\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
+        if parent_plat_name:
+            self.buf('\t.parent_plat_\t= %s,\n' % parent_plat_name)
+        if uclass_plat_name:
+            self.buf('\t.uclass_plat_\t= %s,\n' % uclass_plat_name)
+        driver_date = None
+
+        if node != self._fdt.GetRoot():
+            compat_list = node.props['compatible'].value
+            if not isinstance(compat_list, list):
+                compat_list = [compat_list]
+            for compat in compat_list:
+                driver_data = driver.compat.get(compat)
+                if driver_data:
+                    self.buf('\t.driver_data\t= %s,\n' % driver_data)
+                    break
+
+        if node.parent and node.parent.parent:
+            self.buf('\t.parent\t\t= DM_DEVICE_REF(%s),\n' %
+                     node.parent.var_name)
+        if priv_name:
+            self.buf('\t.priv_\t\t= %s,\n' % priv_name)
+        self.buf('\t.uclass\t\t= DM_UCLASS_REF(%s),\n' % uclass.name)
+
+        if uclass_priv_name:
+            self.buf('\t.uclass_priv_ = %s,\n' % uclass_priv_name)
+        if parent_priv_name:
+            self.buf('\t.parent_priv_\t= %s,\n' % parent_priv_name)
+        self.list_node('uclass_node', uclass.node_refs, node.uclass_seq)
+        self.list_head('child_head', 'sibling_node', node.child_devs, node.var_name)
+        if node.parent in self._valid_nodes:
+            self.list_node('sibling_node', node.parent.child_refs,
+                           node.parent_seq)
+        # flags is left as 0
+
+        self.buf('\t.seq_ = %d,\n' % node.seq)
+
+        self.buf('};\n')
+        self.buf('\n')
+        return parent_plat_name
+
+    def _output_prop(self, node, prop, tabs=1):
         """Output a line containing the value of a struct member
 
         Args:
@@ -681,7 +778,7 @@ class DtbPlatdata():
         if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
             return
         member_name = conv_name_to_c(prop.name)
-        self.buf('\t%s= ' % tab_to(3, '.' + member_name))
+        self.buf('%s%s= ' % ('\t' * tabs, tab_to(3, '.' + member_name)))
 
         # Special handling for lists
         if isinstance(prop.value, list):
@@ -731,10 +828,13 @@ class DtbPlatdata():
         self.out('#include <dt-structs.h>\n')
         self.out('\n')
         self.buf('/*\n')
-        self.buf(' * uclass declarations\n')
-        self.buf(' *\n')
-        self.buf(' * Sequence numbers:\n')
+        self.buf(
+            " * uclass declarations, ordered by 'struct uclass' linker_list idx:\n")
         uclass_list = self._valid_uclasses
+        for seq, uclass in enumerate(uclass_list):
+            self.buf(' * %3d: %s\n' % (seq, uclass.name))
+        self.buf(' *\n')
+        self.buf(' * Sequence numbers allocated in each uclass:\n')
         for uclass in uclass_list:
             if uclass.alias_num_to_node:
                 self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
@@ -914,6 +1014,26 @@ class DtbPlatdata():
 
         self.out(''.join(self.get_buf()))
 
+    def output_node_instance(self, node):
+        """Output the C code for a node
+
+        Args:
+            node (fdt.Node): node to output
+        """
+        parent_driver = node.parent_driver
+
+        self.buf('/*\n')
+        self.buf(' * Node %s index %d\n' % (node.path, node.idx))
+        self.buf(' * driver %s parent %s\n' % (node.driver.name,
+                 parent_driver.name if parent_driver else 'None'))
+        self.buf('*/\n')
+
+        if not node.driver.plat:
+            self._output_values(node)
+        self._declare_device_inst(node, parent_driver)
+
+        self.out(''.join(self.get_buf()))
+
     def check_instantiate(self, require):
         """Check if self._instantiate is set to the required value
 
@@ -969,6 +1089,41 @@ class DtbPlatdata():
 
         self.out(''.join(self.get_buf()))
 
+    def generate_device(self):
+        """Generate device instances
+
+        This writes out DM_DEVICE_INST() records for each device in the
+        build.
+
+        See the documentation in doc/driver-model/of-plat.rst for more
+        information.
+        """
+        if not self.check_instantiate(True):
+            return
+        self.out('#include <common.h>\n')
+        self.out('#include <dm.h>\n')
+        self.out('#include <dt-structs.h>\n')
+        self.out('\n')
+
+        if self._valid_nodes:
+            self.out('/*\n')
+            self.out(
+                " * udevice declarations, ordered by 'struct udevice' linker_list position:\n")
+            self.out(' *\n')
+            self.out(' * idx  %-20s %-s\n' % ('udevice', 'driver'))
+            self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
+            for node in self._valid_nodes:
+                self.out(' * %3d: %-20s %-s\n' %
+                        (node.idx, node.var_name, node.struct_name))
+            self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
+            self.out(' */\n')
+            self.out('\n')
+
+            for node in self._valid_nodes:
+                self.output_node_instance(node)
+
+        self.out(''.join(self.get_buf()))
+
 
 # Types of output file we understand
 # key: Command used to generate this file
@@ -984,6 +1139,9 @@ OUTPUT_FILES = {
     'platdata':
         OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
                    'Declares the U_BOOT_DRIVER() records and platform data'),
+    'device':
+        OutputFile(Ftype.SOURCE, 'dt-device.c', DtbPlatdata.generate_device,
+                   'Declares the DM_DEVICE_INST() records'),
     'uclass':
         OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
                    'Declares the uclass instances (struct uclass)'),
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 053d140664e..bb689f3b6e9 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -420,9 +420,14 @@ U_BOOT_DRVINFO(spl_test3) = {
 #include <dt-structs.h>
 
 /*
- * uclass declarations
+ * uclass declarations, ordered by 'struct uclass' linker_list idx:
+ *   0: i2c
+ *   1: misc
+ *   2: root
+ *   3: testbus
+ *   4: testfdt
  *
- * Sequence numbers:
+ * Sequence numbers allocated in each uclass:
  * i2c: UCLASS_I2C
  *    4: /i2c
  * misc: UCLASS_MISC
@@ -506,6 +511,300 @@ DM_UCLASS_INST(testfdt) = {
 	},
 };
 
+'''
+    device_text = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the DM_DEVICE_INST() records.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+/* This file is not used: --instantiate was not enabled */
+'''
+    device_text_inst = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the DM_DEVICE_INST() records.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+/*
+ * udevice declarations, ordered by 'struct udevice' linker_list position:
+ *
+ * idx  udevice              driver
+ * ---  -------------------- --------------------
+ *   0: i2c                  sandbox_i2c
+ *   1: root                 root_driver
+ *   2: some_bus             denx_u_boot_test_bus
+ *   3: spl_test             sandbox_spl_test
+ *   4: spl_test3            sandbox_spl_test
+ *   5: test                 denx_u_boot_fdt_test
+ *   6: test0                denx_u_boot_fdt_test
+ * ---  -------------------- --------------------
+ */
+
+/*
+ * Node /i2c index 0
+ * driver sandbox_i2c parent root_driver
+*/
+static struct dtd_sandbox_i2c dtv_i2c = {
+\t.intval\t\t\t= 0x3,
+};
+
+#include <asm/i2c.h>
+u8 _sandbox_i2c_priv_i2c[sizeof(struct sandbox_i2c_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <i2c.h>
+u8 _sandbox_i2c_uc_priv_i2c[sizeof(struct dm_i2c_bus)]
+\t__attribute__ ((section (".priv_data")));
+
+DM_DEVICE_INST(i2c) = {
+\t.driver\t\t= DM_DRIVER_REF(sandbox_i2c),
+\t.name\t\t= "sandbox_i2c",
+\t.plat_\t\t= &dtv_i2c,
+\t.priv_\t\t= _sandbox_i2c_priv_i2c,
+\t.uclass\t\t= DM_UCLASS_REF(i2c),
+\t.uclass_priv_ = _sandbox_i2c_uc_priv_i2c,
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(i2c)->dev_head,
+\t\t.next = &DM_UCLASS_REF(i2c)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(i2c)->child_head,
+\t\t.next = &DM_DEVICE_REF(i2c)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(root)->child_head,
+\t\t.next = &DM_DEVICE_REF(some_bus)->sibling_node,
+\t},
+\t.seq_ = 4,
+};
+
+/*
+ * Node / index 1
+ * driver root_driver parent None
+*/
+static struct dtd_root_driver dtv_root = {
+};
+
+DM_DEVICE_INST(root) = {
+\t.driver\t\t= DM_DRIVER_REF(root_driver),
+\t.name\t\t= "root_driver",
+\t.plat_\t\t= &dtv_root,
+\t.uclass\t\t= DM_UCLASS_REF(root),
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(root)->dev_head,
+\t\t.next = &DM_UCLASS_REF(root)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test3)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(i2c)->sibling_node,
+\t},
+\t.seq_ = 0,
+};
+
+/*
+ * Node /some-bus index 2
+ * driver denx_u_boot_test_bus parent root_driver
+*/
+
+#include <dm/test.h>
+struct dm_test_pdata __attribute__ ((section (".priv_data")))
+\t_denx_u_boot_test_bus_plat_some_bus = {
+\t.dtplat = {
+\t\t.ping_add\t\t= 0x4,
+\t\t.ping_expect\t\t= 0x4,
+\t\t.reg\t\t\t= {0x3, 0x1},
+\t},
+};
+#include <dm/test.h>
+u8 _denx_u_boot_test_bus_priv_some_bus[sizeof(struct dm_test_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <test.h>
+
+DM_DEVICE_INST(some_bus) = {
+\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_test_bus),
+\t.name\t\t= "denx_u_boot_test_bus",
+\t.plat_\t\t= &_denx_u_boot_test_bus_plat_some_bus,
+\t.uclass_plat_\t= _denx_u_boot_test_bus_ucplat_some_bus,
+\t.driver_data\t= DM_TEST_TYPE_FIRST,
+\t.priv_\t\t= _denx_u_boot_test_bus_priv_some_bus,
+\t.uclass\t\t= DM_UCLASS_REF(testbus),
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(testbus)->dev_head,
+\t\t.next = &DM_UCLASS_REF(testbus)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(test0)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(test)->sibling_node,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(i2c)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(spl_test)->sibling_node,
+\t},
+\t.seq_ = 2,
+};
+
+/*
+ * Node /spl-test index 3
+ * driver sandbox_spl_test parent root_driver
+*/
+static struct dtd_sandbox_spl_test dtv_spl_test = {
+\t.boolval\t\t= true,
+\t.intval\t\t\t= 0x1,
+};
+
+DM_DEVICE_INST(spl_test) = {
+\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
+\t.name\t\t= "sandbox_spl_test",
+\t.plat_\t\t= &dtv_spl_test,
+\t.uclass\t\t= DM_UCLASS_REF(misc),
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(misc)->dev_head,
+\t\t.next = &DM_DEVICE_REF(spl_test3)->uclass_node,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test)->child_head,
+\t\t.next = &DM_DEVICE_REF(spl_test)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(some_bus)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(spl_test3)->sibling_node,
+\t},
+\t.seq_ = 0,
+};
+
+/*
+ * Node /spl-test3 index 4
+ * driver sandbox_spl_test parent root_driver
+*/
+static struct dtd_sandbox_spl_test dtv_spl_test3 = {
+\t.longbytearray\t\t= {0x90a0b0c, 0xd0e0f10},
+\t.stringarray\t\t= "one",
+};
+
+DM_DEVICE_INST(spl_test3) = {
+\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
+\t.name\t\t= "sandbox_spl_test",
+\t.plat_\t\t= &dtv_spl_test3,
+\t.uclass\t\t= DM_UCLASS_REF(misc),
+\t.uclass_node\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test)->uclass_node,
+\t\t.next = &DM_UCLASS_REF(misc)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test3)->child_head,
+\t\t.next = &DM_DEVICE_REF(spl_test3)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(root)->child_head,
+\t},
+\t.seq_ = 1,
+};
+
+/*
+ * Node /some-bus/test index 5
+ * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
+*/
+
+#include <dm/test.h>
+struct dm_test_pdata __attribute__ ((section (".priv_data")))
+\t_denx_u_boot_fdt_test_plat_test = {
+\t.dtplat = {
+\t\t.ping_add\t\t= 0x5,
+\t\t.ping_expect\t\t= 0x5,
+\t\t.reg\t\t\t= {0x5, 0x0},
+\t},
+};
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_priv_test[sizeof(struct dm_test_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_plat_test[sizeof(struct dm_test_parent_plat)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_priv_test[sizeof(struct dm_test_parent_data)]
+\t__attribute__ ((section (".priv_data")));
+
+DM_DEVICE_INST(test) = {
+\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
+\t.name\t\t= "denx_u_boot_fdt_test",
+\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test,
+\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test,
+\t.driver_data\t= DM_TEST_TYPE_FIRST,
+\t.parent\t\t= DM_DEVICE_REF(some_bus),
+\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test,
+\t.uclass\t\t= DM_UCLASS_REF(testfdt),
+\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test,
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(testfdt)->dev_head,
+\t\t.next = &DM_DEVICE_REF(test0)->uclass_node,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(test)->child_head,
+\t\t.next = &DM_DEVICE_REF(test)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(some_bus)->child_head,
+\t\t.next = &DM_DEVICE_REF(test0)->sibling_node,
+\t},
+\t.seq_ = 1,
+};
+
+/*
+ * Node /some-bus/test0 index 6
+ * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
+*/
+
+#include <dm/test.h>
+struct dm_test_pdata __attribute__ ((section (".priv_data")))
+\t_denx_u_boot_fdt_test_plat_test0 = {
+\t.dtplat = {
+\t},
+};
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_priv_test0[sizeof(struct dm_test_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_plat_test0[sizeof(struct dm_test_parent_plat)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_priv_test0[sizeof(struct dm_test_parent_data)]
+\t__attribute__ ((section (".priv_data")));
+
+DM_DEVICE_INST(test0) = {
+\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
+\t.name\t\t= "denx_u_boot_fdt_test",
+\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test0,
+\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test0,
+\t.driver_data\t= DM_TEST_TYPE_SECOND,
+\t.parent\t\t= DM_DEVICE_REF(some_bus),
+\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test0,
+\t.uclass\t\t= DM_UCLASS_REF(testfdt),
+\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test0,
+\t.uclass_node\t= {
+\t\t.prev = &DM_DEVICE_REF(test)->uclass_node,
+\t\t.next = &DM_UCLASS_REF(testfdt)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(test0)->child_head,
+\t\t.next = &DM_DEVICE_REF(test0)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(test)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(some_bus)->child_head,
+\t},
+\t.seq_ = 2,
+};
+
 '''
 
     def test_simple(self):
@@ -533,8 +832,9 @@ DM_UCLASS_INST(testfdt) = {
         # Try the 'all' command
         self.run_test(['all'], dtb_file, output)
         data = tools.ReadFile(output, binary=False)
-        self._check_strings(self.decl_text + self.platdata_text +
-                            self.struct_text + self.uclass_text, data)
+        self._check_strings(
+            self.decl_text + self.device_text + self.platdata_text +
+            self.struct_text + self.uclass_text, data)
 
     def test_driver_alias(self):
         """Test output from a device tree file with a driver alias"""
@@ -1236,8 +1536,9 @@ U_BOOT_DRVINFO(spl_test2) = {
         output = tools.GetOutputFilename('output')
         self.run_test(['all'], dtb_file, output)
         data = tools.ReadFile(output, binary=False)
-        self._check_strings(self.decl_text + self.platdata_text +
-                            self.struct_text + self.uclass_text, data)
+        self._check_strings(
+            self.decl_text + self.device_text + self.platdata_text +
+            self.struct_text + self.uclass_text, data)
 
     def test_no_command(self):
         """Test running dtoc without a command"""
@@ -1253,7 +1554,7 @@ U_BOOT_DRVINFO(spl_test2) = {
         with self.assertRaises(ValueError) as exc:
             self.run_test(['invalid-cmd'], dtb_file, output)
         self.assertIn(
-            "Unknown command 'invalid-cmd': (use: decl, platdata, struct, uclass)",
+            "Unknown command 'invalid-cmd': (use: decl, device, platdata, struct, uclass)",
             str(exc.exception))
 
     def test_output_conflict(self):
@@ -1281,12 +1582,12 @@ U_BOOT_DRVINFO(spl_test2) = {
             ['all'], dtb_file, False, None, [outdir], None, False,
             warning_disabled=True, scan=copy_scan())
         fnames = glob.glob(outdir + '/*')
-        self.assertEqual(6, len(fnames))
+        self.assertEqual(7, len(fnames))
 
         leafs = set(os.path.basename(fname) for fname in fnames)
         self.assertEqual(
             {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb',
-             'dt-uclass.c', 'dt-decl.h'},
+             'dt-uclass.c', 'dt-decl.h', 'dt-device.c'},
             leafs)
 
     def setup_process_test(self):
@@ -1498,8 +1799,14 @@ U_BOOT_DRVINFO(spl_test2) = {
 
         self._check_strings(UCLASS_HEADER_COMMON + self.uclass_text_inst, data)
 
+        self.run_test(['device'], dtb_file, output, True)
+        with open(output) as infile:
+            data = infile.read()
+
+        self._check_strings(self.device_text_inst, data)
+
     def test_inst_no_hdr(self):
-        """Test dealing with a struct that has no header"""
+        """Test dealing with a struct tsssshat has no header"""
         dtb_file = get_dtb_file('dtoc_test_inst.dts')
         output = tools.GetOutputFilename('output')
 
-- 
2.30.0.365.g02bc693789-goog

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 33/33] dtoc: Generate device instances
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (32 preceding siblings ...)
  2021-02-03 13:01 ` [PATCH v2 33/33] dtoc: Generate device instances Simon Glass
@ 2021-02-07  0:16 ` Simon Glass
  2021-02-07  0:16 ` [PATCH v2 32/33] dtoc: Generate uclass devices Simon Glass
                   ` (31 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:16 UTC (permalink / raw)
  To: u-boot

Add support for generating a file containing udevice instances. This
avoids the need to create these at run time.

Update a test uclass to include a 'per_device_plat_auto' member, to
increase test coverage.

Add another tab to the driver_info output so it lines up nicely like the
device-instance output.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Drop patches previously applied
- Update cover letter
- Fix the naming for uclass_plat_name so it is different from uclass_priv
- Tidy up tabbing to make the code output line up better
- Add a summary to the top of the generated file

 drivers/misc/test_drv.c    |   4 +
 tools/dtoc/dtb_platdata.py | 168 ++++++++++++++++++-
 tools/dtoc/test_dtoc.py    | 327 +++++++++++++++++++++++++++++++++++--
 3 files changed, 484 insertions(+), 15 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 32/33] dtoc: Generate uclass devices
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (33 preceding siblings ...)
  2021-02-07  0:16 ` Simon Glass
@ 2021-02-07  0:16 ` Simon Glass
  2021-02-07  0:16 ` [PATCH v2 31/33] dtoc: Generate a summary in the dt-plat.c file Simon Glass
                   ` (30 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:16 UTC (permalink / raw)
  To: u-boot

Add support for generating a file containing uclass instances. This avoids
the need to create these at run time.

Update a test uclass to include a 'priv_auto' member, to increase test
coverage.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 drivers/misc/test_drv.c    |   1 +
 include/dm/test.h          |   5 ++
 tools/dtoc/dtb_platdata.py |  93 +++++++++++++++++++++
 tools/dtoc/test_dtoc.py    | 164 ++++++++++++++++++++++++++++++++++---
 4 files changed, 250 insertions(+), 13 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 31/33] dtoc: Generate a summary in the dt-plat.c file
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (34 preceding siblings ...)
  2021-02-07  0:16 ` [PATCH v2 32/33] dtoc: Generate uclass devices Simon Glass
@ 2021-02-07  0:16 ` Simon Glass
  2021-02-07  0:16 ` [PATCH v2 30/33] dtoc: Tidy up the list of supported phandle properties Simon Glass
                   ` (29 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:16 UTC (permalink / raw)
  To: u-boot

Add a summary to the top of the generated code, to make it easier to see
what the file contains.

Also add a tab to .plat so that its value lines up with the others.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py |  20 +++-
 tools/dtoc/test_dtoc.py    | 184 ++++++++++++++++++++++++++++++-------
 2 files changed, 169 insertions(+), 35 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 30/33] dtoc: Tidy up the list of supported phandle properties
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (35 preceding siblings ...)
  2021-02-07  0:16 ` [PATCH v2 31/33] dtoc: Generate a summary in the dt-plat.c file Simon Glass
@ 2021-02-07  0:16 ` Simon Glass
  2021-02-07  0:16 ` [PATCH v2 29/33] sandbox: i2c: Rename driver names to work with of-platdata Simon Glass
                   ` (28 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:16 UTC (permalink / raw)
  To: u-boot

For now dtoc only supports a hard-coded list of phandle properties, to
avoid any situation where it makes a mistake in its determination.

Make this into a constant dict, recording both the phandle property name
and the associated #cells property in the target node. This makes it
easier to find and modify.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- New patch

 tools/dtoc/dtb_platdata.py | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 29/33] sandbox: i2c: Rename driver names to work with of-platdata
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (36 preceding siblings ...)
  2021-02-07  0:16 ` [PATCH v2 30/33] dtoc: Tidy up the list of supported phandle properties Simon Glass
@ 2021-02-07  0:16 ` Simon Glass
  2021-02-07  0:16 ` [PATCH v2 28/33] sandbox: Make sandbox,emul more conventional Simon Glass
                   ` (27 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:16 UTC (permalink / raw)
  To: u-boot

Some of these do not follow the rules. Make sure the driver name matches
the compatible string in all cases.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- New patch

 arch/sandbox/dts/test.dts     | 4 ++--
 drivers/i2c/i2c-emul-uclass.c | 4 ++--
 drivers/rtc/i2c_rtc_emul.c    | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 28/33] sandbox: Make sandbox,emul more conventional
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (37 preceding siblings ...)
  2021-02-07  0:16 ` [PATCH v2 29/33] sandbox: i2c: Rename driver names to work with of-platdata Simon Glass
@ 2021-02-07  0:16 ` Simon Glass
  2021-02-07  0:16 ` [PATCH v2 27/33] dtoc: Don't generate platform data with instantiation Simon Glass
                   ` (26 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:16 UTC (permalink / raw)
  To: u-boot

At present this property is a phandle but does not have a #xxx-cells
property to match it. Add one so that is works the same as gpio and clock
phandles.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 arch/sandbox/dts/sandbox.dtsi | 6 +++++-
 doc/driver-model/pci-info.rst | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 27/33] dtoc: Don't generate platform data with instantiation
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (38 preceding siblings ...)
  2021-02-07  0:16 ` [PATCH v2 28/33] sandbox: Make sandbox,emul more conventional Simon Glass
@ 2021-02-07  0:16 ` Simon Glass
  2021-02-07  0:16 ` [PATCH v2 26/33] dtoc: Add support for decl file Simon Glass
                   ` (25 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:16 UTC (permalink / raw)
  To: u-boot

This file is not used when instantiating devices. Update dtoc to skip
generating its contents and just add a comment instead.

Also it is useful to see the driver name and parent for each device.
Update the file to show that information, to avoid updating the same
tests twice.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 35 ++++++++++++++++++++++---
 tools/dtoc/test_dtoc.py    | 53 +++++++++++++++++++++++++++++++-------
 2 files changed, 75 insertions(+), 13 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 26/33] dtoc: Add support for decl file
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (39 preceding siblings ...)
  2021-02-07  0:16 ` [PATCH v2 27/33] dtoc: Don't generate platform data with instantiation Simon Glass
@ 2021-02-07  0:16 ` Simon Glass
  2021-02-07  0:16 ` [PATCH v2 25/33] dm: of-platadata: Add option for device instantiation Simon Glass
                   ` (24 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:16 UTC (permalink / raw)
  To: u-boot

Add an option to generate the declaration file, which declares all
drivers and uclasses, so references can be used in the code.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 36 +++++++++++++++
 tools/dtoc/test_dtoc.py    | 91 +++++++++++++++++++++++++++++++++++---
 2 files changed, 120 insertions(+), 7 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 25/33] dm: of-platadata: Add option for device instantiation
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (40 preceding siblings ...)
  2021-02-07  0:16 ` [PATCH v2 26/33] dtoc: Add support for decl file Simon Glass
@ 2021-02-07  0:16 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 24/33] dtoc: Add an " Simon Glass
                   ` (23 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:16 UTC (permalink / raw)
  To: u-boot

Add Kconfig options to support build-time device instantiation. When
fully implemented, this will allow dtoc to create U-Boot devices (i.e.
struct udevice records) at build time, thus reducing code space in
SPL.

For now this defaults to off, but will be enabled when the rest of
the implementation is in place.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 dts/Kconfig          | 23 +++++++++++++++++++++--
 scripts/Makefile.spl |  4 ++++
 2 files changed, 25 insertions(+), 2 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 24/33] dtoc: Add an option for device instantiation
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (41 preceding siblings ...)
  2021-02-07  0:16 ` [PATCH v2 25/33] dm: of-platadata: Add option for device instantiation Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 23/33] dtoc: Support processing the root node Simon Glass
                   ` (22 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Add an option to instantiate devices at build time. For now this just
parses the option and sets up a few parameters.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 17 +++++++++++------
 tools/dtoc/main.py         |  4 +++-
 tools/dtoc/test_dtoc.py    | 37 ++++++++++++++++++++++---------------
 3 files changed, 36 insertions(+), 22 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 23/33] dtoc: Support processing the root node
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (42 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 24/33] dtoc: Add an " Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 22/33] dtoc: Set up the uclasses that are used Simon Glass
                   ` (21 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

The device for the root node is normally bound by driver model on init.
With devices being instantiated at build time, we must handle the root
device also.

Add support for processing the root node, which may not have a compatible
string.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py  | 10 ++++++++--
 tools/dtoc/src_scan.py      | 39 ++++++++++++++++++++++---------------
 tools/dtoc/test_dtoc.py     | 23 ++++++++++++++++++++--
 tools/dtoc/test_src_scan.py |  7 +++++++
 4 files changed, 59 insertions(+), 20 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 22/33] dtoc: Set up the uclasses that are used
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (43 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 23/33] dtoc: Support processing the root node Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 21/33] dtoc: Assign a sequence number to each node Simon Glass
                   ` (20 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

We only care about uclasses that are actually used. This is determined by
the drivers that use them. Check all the used drivers and build a list of
'valid' uclasses.

Also add references to the uclasses so we can generate C code that uses
them. Attach a uclass to each valid driver.

For the tests, now that we have uclasses we must create an explicit test
for the case where a node does not have one. This should only happen if
the source code does not build, or the source-code scanning fails to find
it.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py  | 46 ++++++++++++++++++++++++-------------
 tools/dtoc/src_scan.py      | 45 ++++++++++++++++++++++++++++++++++++
 tools/dtoc/test_dtoc.py     | 29 +++++++++++++++++++++--
 tools/dtoc/test_src_scan.py | 17 ++++++++++++++
 4 files changed, 119 insertions(+), 18 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 21/33] dtoc: Assign a sequence number to each node
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (44 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 22/33] dtoc: Set up the uclasses that are used Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 20/33] dtoc: Detect drivers only at the start of start of line Simon Glass
                   ` (19 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Now that we have the alias information we can assign a sequence number
to each device in the uclass. Store this in the node associated with each
device.

This requires renaming the sandbox test drivers to have the right name.
Note that test coverage is broken with this patch, but fixed in the next
one.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 drivers/misc/test_drv.c    |  6 +++--
 test/dm/test-fdt.c         |  6 ++---
 tools/dtoc/dtb_platdata.py | 55 +++++++++++++++++++++++++++-----------
 tools/dtoc/test_dtoc.py    |  6 +++++
 4 files changed, 53 insertions(+), 20 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 20/33] dtoc: Detect drivers only at the start of start of line
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (45 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 21/33] dtoc: Assign a sequence number to each node Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 19/33] dtoc: Read aliases for uclasses Simon Glass
                   ` (18 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

If a driver declaration is included in a comment, dtoc currently gets
confused. Update the parser to only consider declarations that begin at
the start of a line. Since multi-line comments begin with an asterisk,
this avoids the problem.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- New patch

 tools/dtoc/src_scan.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 19/33] dtoc: Read aliases for uclasses
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (46 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 20/33] dtoc: Detect drivers only at the start of start of line Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 18/33] dtoc: Warn of duplicate drivers Simon Glass
                   ` (17 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Scan the aliases in the device tree to establish the number of devices
within each uclass, and the sequence number of each.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py                   | 28 ++++++++++
 tools/dtoc/src_scan.py                       | 32 ++++++++++-
 tools/dtoc/test/dtoc_test_alias_bad.dts      | 58 ++++++++++++++++++++
 tools/dtoc/test/dtoc_test_alias_bad_path.dts | 58 ++++++++++++++++++++
 tools/dtoc/test/dtoc_test_alias_bad_uc.dts   | 58 ++++++++++++++++++++
 tools/dtoc/test/dtoc_test_inst.dts           | 58 ++++++++++++++++++++
 tools/dtoc/test_dtoc.py                      | 56 ++++++++++++++++++-
 7 files changed, 345 insertions(+), 3 deletions(-)
 create mode 100644 tools/dtoc/test/dtoc_test_alias_bad.dts
 create mode 100644 tools/dtoc/test/dtoc_test_alias_bad_path.dts
 create mode 100644 tools/dtoc/test/dtoc_test_alias_bad_uc.dts
 create mode 100644 tools/dtoc/test/dtoc_test_inst.dts

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 18/33] dtoc: Warn of duplicate drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (47 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 19/33] dtoc: Read aliases for uclasses Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 17/33] dtoc: Process driver aliases along with drivers Simon Glass
                   ` (16 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

If drivers have the same name then we cannot distinguish them. This only
matters if the driver is actually used by dtoc, but in that case, issue
a warning.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 28 ++++++++++-
 tools/dtoc/test_src_scan.py | 95 +++++++++++++++++++++++++++++++++++++
 2 files changed, 122 insertions(+), 1 deletion(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 17/33] dtoc: Process driver aliases along with drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (48 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 18/33] dtoc: Warn of duplicate drivers Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 16/33] dtoc: Support headers needed for drivers Simon Glass
                   ` (15 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Instead of using a separate step for this processing, handle it while
scanning its associated driver. This allows us to drop the code coverage
exception in this case.

Note that only files containing drivers are scanned by dtoc, so aliases
declared in a file that doesn't hold a driver will not be noticed. It
would be confusing to put them anywhere other than in the driver that they
relate to, but update the documentation to say this explicitly, just in
case.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 doc/driver-model/of-plat.rst               |  3 ++-
 tools/dtoc/src_scan.py                     | 16 +++++-----------
 tools/dtoc/test/dtoc_test_scan_drivers.cxx |  4 ++++
 3 files changed, 11 insertions(+), 12 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 16/33] dtoc: Support headers needed for drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (49 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 17/33] dtoc: Process driver aliases along with drivers Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 15/33] Makefile: Pass the U-Boot phase to dtoc Simon Glass
                   ` (14 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Typically dtoc can detect the header file needed for a driver by looking
for the structs that it uses. For example, if a driver as a .priv_auto
that uses 'struct serial_priv', then dtoc can search header files for the
definition of that struct and use the file.

In some cases, enums are used in drivers, typically with the .data field
of struct udevice_id. Since dtoc does not support searching for these,
add a way to tell dtoc which header to use. This works as a macro included
in the driver definition.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 include/dm/device.h         | 18 ++++++++++++++++++
 tools/dtoc/src_scan.py      |  7 +++++++
 tools/dtoc/test_src_scan.py |  4 ++++
 3 files changed, 29 insertions(+)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 15/33] Makefile: Pass the U-Boot phase to dtoc
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (50 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 16/33] dtoc: Support headers needed for drivers Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 14/33] dtoc: Support tracking the phase of U-Boot Simon Glass
                   ` (13 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Pass the U-Boot phase as a parameter so dtoc can use it. At present it is
ether "spl" or "tpl".

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 scripts/Makefile.spl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 14/33] dtoc: Support tracking the phase of U-Boot
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (51 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 15/33] Makefile: Pass the U-Boot phase to dtoc Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 13/33] dtoc: Track nodes which are actually used Simon Glass
                   ` (12 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

U-Boot operates in several phases, typically TPL, SPL and U-Boot proper.
The latter does not use dtoc.

In some rare cases different drivers are used for two phases. For example,
in TPL it may not be necessary to use the full PCI subsystem, so a simple
driver can be used instead.

This works in the build system simply by compiling in one driver or the
other (e.g. PCI driver + uclass for SPL; simple_bus for TPL). But dtoc has
no way of knowing which code is compiled in for which phase, since it does
not inspect Makefiles or dependency graphs.

So to make this work for dtoc, we need to be able to explicitly mark
drivers with their phase. This is done by adding an empty macro to the
driver. Add support for this in dtoc.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 include/dm/device.h         | 16 ++++++++++++++++
 tools/dtoc/dtb_platdata.py  |  7 +++++--
 tools/dtoc/main.py          |  5 ++++-
 tools/dtoc/src_scan.py      | 12 +++++++++++-
 tools/dtoc/test_dtoc.py     | 16 ++++++++--------
 tools/dtoc/test_src_scan.py |  3 +++
 6 files changed, 47 insertions(+), 12 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 13/33] dtoc: Track nodes which are actually used
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (52 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 14/33] dtoc: Support tracking the phase of U-Boot Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 12/33] dtoc: Process nodes to set up required properties Simon Glass
                   ` (11 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Mark all nodes that are actually used, so we can perform extra checks on
them.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py  |  3 +++
 tools/dtoc/src_scan.py      | 25 ++++++++++++++++++++++---
 tools/dtoc/test_dtoc.py     | 11 +++++++++++
 tools/dtoc/test_src_scan.py |  2 +-
 4 files changed, 37 insertions(+), 4 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 12/33] dtoc: Process nodes to set up required properties
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (53 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 13/33] dtoc: Track nodes which are actually used Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 11/33] dtoc: Make use of node properties Simon Glass
                   ` (10 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Add logic to assign property values to nodes as required by dtoc. The
references allow nodes to refer to each other in C code. The macros used
by dtoc are not yet defined in driver model. They will be added along
with the actual driver model implementation.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 37 +++++++++++++++++++
 tools/dtoc/src_scan.py     | 11 ++++++
 tools/dtoc/test_dtoc.py    | 76 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 124 insertions(+)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 10/33] dtoc: Add some extra properties to nodes
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (55 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 11/33] dtoc: Make use of node properties Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 09/33] dtoc: Rename sandbox_i2c_test and sandbox_pmic_test Simon Glass
                   ` (8 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

It is convenient to attach drivers, etc. to nodes so that we can use the
Node object as the main data structure in this module.

Add a function which adds the new properties, along with documentation.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 11/33] dtoc: Make use of node properties
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (54 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 12/33] dtoc: Process nodes to set up required properties Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 10/33] dtoc: Add some extra properties to nodes Simon Glass
                   ` (9 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Now that we have these available, use them instead of recalculating
things each time.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 45 ++++++++++++++++----------------------
 1 file changed, 19 insertions(+), 26 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 09/33] dtoc: Rename sandbox_i2c_test and sandbox_pmic_test
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (56 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 10/33] dtoc: Add some extra properties to nodes Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 08/33] dtoc: Move test files into a test/ directory Simon Glass
                   ` (7 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

These have '_test' suffixes which are not present on the drivers in the
source code. Drop the suffixes to avoid a mismatch when scanning.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/test/dtoc_test_simple.dts |  4 ++--
 tools/dtoc/test_dtoc.py              | 12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 08/33] dtoc: Move test files into a test/ directory
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (57 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 09/33] dtoc: Rename sandbox_i2c_test and sandbox_pmic_test Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 07/33] dtoc: Support scanning of structs in header files Simon Glass
                   ` (6 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

It is confusing to have the test files in the same places as the
implementation. Move them into a separate directory.

Add a helper function for test_dtoc, to avoid repeating the same
path.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/{ => test}/dtoc_test.dts           |  0
 tools/dtoc/{ => test}/dtoc_test_add_prop.dts  |  0
 tools/dtoc/{ => test}/dtoc_test_addr32.dts    |  0
 tools/dtoc/{ => test}/dtoc_test_addr32_64.dts |  0
 tools/dtoc/{ => test}/dtoc_test_addr64.dts    |  0
 tools/dtoc/{ => test}/dtoc_test_addr64_32.dts |  0
 tools/dtoc/{ => test}/dtoc_test_aliases.dts   |  0
 tools/dtoc/{ => test}/dtoc_test_bad_reg.dts   |  0
 tools/dtoc/{ => test}/dtoc_test_bad_reg2.dts  |  0
 .../{ => test}/dtoc_test_driver_alias.dts     |  0
 tools/dtoc/{ => test}/dtoc_test_empty.dts     |  0
 .../{ => test}/dtoc_test_invalid_driver.dts   |  0
 tools/dtoc/{ => test}/dtoc_test_phandle.dts   |  0
 .../dtoc/{ => test}/dtoc_test_phandle_bad.dts |  0
 .../{ => test}/dtoc_test_phandle_bad2.dts     |  0
 .../{ => test}/dtoc_test_phandle_cd_gpios.dts |  0
 .../{ => test}/dtoc_test_phandle_reorder.dts  |  0
 .../{ => test}/dtoc_test_phandle_single.dts   |  0
 .../{ => test}/dtoc_test_scan_drivers.cxx     |  0
 tools/dtoc/{ => test}/dtoc_test_simple.dts    |  0
 tools/dtoc/test_dtoc.py                       |  2 +-
 tools/dtoc/test_fdt.py                        | 31 +++++++++++++------
 tools/dtoc/test_src_scan.py                   |  3 +-
 23 files changed, 24 insertions(+), 12 deletions(-)
 rename tools/dtoc/{ => test}/dtoc_test.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_add_prop.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr32.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr32_64.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr64.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_addr64_32.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_aliases.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_bad_reg.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_bad_reg2.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_driver_alias.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_empty.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_invalid_driver.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_bad.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_bad2.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_cd_gpios.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_reorder.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_phandle_single.dts (100%)
 rename tools/dtoc/{ => test}/dtoc_test_scan_drivers.cxx (100%)
 rename tools/dtoc/{ => test}/dtoc_test_simple.dts (100%)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 07/33] dtoc: Support scanning of structs in header files
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (58 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 08/33] dtoc: Move test files into a test/ directory Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 06/33] dtoc: Support scanning of uclasses Simon Glass
                   ` (5 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Drivers can have private / platform data contained in structs and these
struct definitions are generally kept in header files. In order to
generate build-time devices, dtoc needs to generate code that declares
the data contained in those structs. This generated code must include the
relevant header file, to avoid a build error.

We need a way for dtoc to scan header files for struct definitions. Then,
when it wants to generate code that uses a struct, it can make sure it
includes the correct header file, first.

Add a parser for struct information, similar to drivers. Keep a dict of
the structs that were found.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 86 +++++++++++++++++++++++++++++++++++--
 tools/dtoc/test_src_scan.py | 45 +++++++++++++++++++
 2 files changed, 128 insertions(+), 3 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 06/33] dtoc: Support scanning of uclasses
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (59 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 07/33] dtoc: Support scanning of structs in header files Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 05/33] dtoc: Collect priv/plat struct info from drivers Simon Glass
                   ` (4 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

Uclasses can have per-device private / platform data so dtoc needs to
scan these drivers. This allows it to find out the size of this data so
it can be allocated a build time.

Add a parser for uclass information, similar to drivers. Keep a dict of
the uclasses that were found.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 122 ++++++++++++++++++++++++++++++++++++
 tools/dtoc/test_src_scan.py |  55 ++++++++++++++++
 2 files changed, 177 insertions(+)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 05/33] dtoc: Collect priv/plat struct info from drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (60 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 06/33] dtoc: Support scanning of uclasses Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 04/33] dtoc: Ignore unwanted files when scanning for drivers Simon Glass
                   ` (3 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

In order to output variables to hold the priv/plat information used by
each device, dtoc needs to know the struct for each. With this, it can
declare this at build time:

   u8 xxx_priv [sizeof(struct <name>)];

Collect the various struct names from the drivers.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 25 +++++++++++++++++++++++--
 tools/dtoc/test_src_scan.py | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 2 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 04/33] dtoc: Ignore unwanted files when scanning for drivers
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (61 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 05/33] dtoc: Collect priv/plat struct info from drivers Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 03/33] dtoc: Save scan information across test runs Simon Glass
                   ` (2 subsequent siblings)
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

We should ignore anything in the .git directory or any of the
build-sandbox, etc. directories created by 'make check'. These can confuse
dtoc. Update the code to ignore these.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 5 +++++
 tools/dtoc/test_src_scan.py | 5 ++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 03/33] dtoc: Save scan information across test runs
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (62 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 04/33] dtoc: Ignore unwanted files when scanning for drivers Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 02/33] dtoc: Scan drivers for available information Simon Glass
  2021-02-07  0:17 ` [PATCH v2 01/33] bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT Simon Glass
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

At present most of the tests scan the U-Boot source tree as part of their
run. This information does not change across tests, so we can save time
by remembering it.

Add a way to set up this information and use it for each test, taking a
copy first, so as not to mess up the original.

This reduces the run time from about 1.6 seconds to 1.5 seconds on my
machine. For code coverage (which cannot run in parallel), it reduces from
33 seconds to 5.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/dtb_platdata.py | 11 ++++++++---
 tools/dtoc/main.py         |  2 ++
 tools/dtoc/test_dtoc.py    | 40 +++++++++++++++++++++++++++++++-------
 3 files changed, 43 insertions(+), 10 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 02/33] dtoc: Scan drivers for available information
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (63 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 03/33] dtoc: Save scan information across test runs Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  2021-02-07  0:17 ` [PATCH v2 01/33] bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT Simon Glass
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

At present we simply record the name of a driver parsed from its
implementation file. We also need to get the uclass and a few other
things so we can instantiate devices at build time. Add support for
collecting this information. This requires parsing each driver file.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 tools/dtoc/src_scan.py      | 194 ++++++++++++++++++++++++++++++++++--
 tools/dtoc/test_src_scan.py | 131 +++++++++++++++++++++++-
 2 files changed, 311 insertions(+), 14 deletions(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 01/33] bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT
  2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
                   ` (64 preceding siblings ...)
  2021-02-07  0:17 ` [PATCH v2 02/33] dtoc: Scan drivers for available information Simon Glass
@ 2021-02-07  0:17 ` Simon Glass
  65 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-02-07  0:17 UTC (permalink / raw)
  To: u-boot

At present these three Kconfigs exist even when bootstage is not enabled.
This is not necessary since bootstage.c is only built if BOOTSTAGE is
enabled.

Make them conditional. Also fix up the overflow message to mention TPL.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 common/Kconfig.boot | 3 +++
 common/bootstage.c  | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 17/33] dtoc: Process driver aliases along with drivers
  2021-02-03 13:01 ` [PATCH v2 17/33] dtoc: Process driver aliases along with drivers Simon Glass
@ 2021-06-21 18:39   ` Johan Jonker
  2021-06-26 18:32     ` Simon Glass
  0 siblings, 1 reply; 70+ messages in thread
From: Johan Jonker @ 2021-06-21 18:39 UTC (permalink / raw)
  To: Simon Glass, U-Boot Mailing List, Heiko Stuebner, Kever Yang,
	philipp.tomsich

Hi Simon, Heiko,

With introduction of rockchip-nand-controller.c in Linux and recently
rockchip_nfc.c in U-boot it offers a renewed opportunity to add support
for MK808 with a rk3066 + NAND to boot from.
rk3066 shares /arch/arm/dts/rk3xxx.dtsi with rk3188.
The only 'usable' boot loader now is closed source with proprietary FTL.

As a spinoff to that discussion I've tried to compile for
rk3188-radxarock as an example due to the lack of rk3066 support in next
and enabling the new rockchip_nfc.c driver.
I'm not familiar with Python/U-boot.
Do you have an idea what this error below is about?

Kind regards,

Johan
===

python --version
Python 2.7.13

===

From rock_defconfig:
CONFIG_SPL_OF_PLATDATA=y

===

git clone -b next
https://source.denx.de/u-boot/custodians/u-boot-rockchip.git
u-boot-next-20210619

make rock_defconfig

make CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- menuconfig

[ ]   Support for NAND controller on Rockchip SoCs (NEW)

Add to rock.h:
#define CONFIG_SYS_MAX_NAND_DEVICE	1

make CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- all

===
mkdir -p spl/dts/
  FDTGREP spl/dts/dt-spl.dtb
  COPY    spl/u-boot-spl.dtb
  CC      spl/./lib/asm-offsets.s
  CC      spl/./arch/arm/lib/asm-offsets.s
  DTOC    spl/dts/dt-plat.c
Traceback (most recent call last):
  File "./tools/dtoc/dtoc", line 112, in <module>
    options.phase, instantiate=options.instantiate)
  File
"~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/dtb_platdata.py",
line 1180, in run_steps
    scan.scan_drivers()
  File
"~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/src_scan.py", line
649, in scan_drivers
    self.scan_driver(pathname)
  File
"~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/src_scan.py", line
608, in scan_driver
    self._parse_driver(fname, buff)
  File
"~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/src_scan.py", line
558, in _parse_driver
    self._driver_aliases[m_alias[2]] = m_alias[1]
TypeError: '_sre.SRE_Match' object is not subscriptable
scripts/Makefile.spl:352: recipe for target 'spl/dts/dt-plat.c' failed
make[1]: *** [spl/dts/dt-plat.c] Error 1
Makefile:1977: recipe for target 'spl/u-boot-spl' failed
make: *** [spl/u-boot-spl] Error 2

===

Changed:
self._driver_aliases[m_alias[2]] = m_alias[1]

To:
self._driver_aliases[m_alias.group(2)] = m_alias.group(1)

Is that a correct python change of mine?

===

After that it compiles normal with only this warning.

  DTOC    spl/dts/dt-plat.c
WARNING: the driver rockchip_rk3188_grf was not found in the driver list
WARNING: the driver rockchip_rk3188_pmu was not found in the driver list
WARNING: the driver rockchip_rk3188_uart was not found in the driver list
  DTOC    include/generated/dt-structs-gen.h
WARNING: the driver rockchip_rk3188_grf was not found in the driver list
WARNING: the driver rockchip_rk3188_pmu was not found in the driver list
WARNING: the driver rockchip_rk3188_uart was not found in the driver list
  DTOC    include/generated/dt-decl.h
WARNING: the driver rockchip_rk3188_grf was not found in the driver list
WARNING: the driver rockchip_rk3188_pmu was not found in the driver list
WARNING: the driver rockchip_rk3188_uart was not found in the driver list


On 2/3/21 2:01 PM, Simon Glass wrote:
> Instead of using a separate step for this processing, handle it while
> scanning its associated driver. This allows us to drop the code coverage
> exception in this case.
> 
> Note that only files containing drivers are scanned by dtoc, so aliases
> declared in a file that doesn't hold a driver will not be noticed. It
> would be confusing to put them anywhere other than in the driver that they
> relate to, but update the documentation to say this explicitly, just in
> case.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> (no changes since v1)
> 
>  doc/driver-model/of-plat.rst               |  3 ++-
>  tools/dtoc/src_scan.py                     | 16 +++++-----------
>  tools/dtoc/test/dtoc_test_scan_drivers.cxx |  4 ++++
>  3 files changed, 11 insertions(+), 12 deletions(-)
> 
> diff --git a/doc/driver-model/of-plat.rst b/doc/driver-model/of-plat.rst
> index 4ef2fe699a4..a5a6e46e3ec 100644
> --- a/doc/driver-model/of-plat.rst
> +++ b/doc/driver-model/of-plat.rst
> @@ -183,7 +183,8 @@ each 'compatible' string.
>  
>  In order to make this a bit more flexible DM_DRIVER_ALIAS macro can be
>  used to declare an alias for a driver name, typically a 'compatible' string.
> -This macro produces no code, but it is by dtoc tool.
> +This macro produces no code, but it is by dtoc tool. It must be located in the
> +same file as its associated driver, ideally just after it.
>  
>  The parent_idx is the index of the parent driver_info structure within its
>  linker list (instantiated by the U_BOOT_DRVINFO() macro). This is used to support
> diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
> index 206b2b37583..9d161a2cbc7 100644
> --- a/tools/dtoc/src_scan.py
> +++ b/tools/dtoc/src_scan.py
> @@ -387,6 +387,7 @@ class Scanner:
>                  in the file
>              _of_match - updated with each compatible string found in the file
>              _compat_to_driver - Maps compatible string to Driver
> +            _driver_aliases - Maps alias names to driver name
>  
>          Args:
>              fname (str): Filename being parsed (used for warnings)
> @@ -438,6 +439,7 @@ class Scanner:
>  
>          re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$')
>          re_hdr = re.compile('^\s*DM_HEADER\((.*)\).*$')
> +        re_alias = re.compile(r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)')
>  
>          # Matches the struct name for priv, plat
>          re_priv = self._get_re_for_member('priv_auto')
> @@ -522,8 +524,11 @@ class Scanner:
>                  driver = Driver(driver_name, fname)
>              else:
>                  ids_m = re_ids.search(line)
> +                m_alias = re_alias.match(line)
>                  if ids_m:
>                      ids_name = ids_m.group(1)
> +                elif m_alias:
> +                    self._driver_aliases[m_alias[2]] = m_alias[1]
>  
>          # Make the updates based on what we found
>          self._drivers.update(drivers)
> @@ -557,17 +562,6 @@ class Scanner:
>              if 'UCLASS_DRIVER' in buff:
>                  self._parse_uclass_driver(fname, buff)
>  
> -            # The following re will search for driver aliases declared as
> -            # DM_DRIVER_ALIAS(alias, driver_name)
> -            driver_aliases = re.findall(
> -                r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
> -                buff)
> -
> -            for alias in driver_aliases: # pragma: no cover
> -                if len(alias) != 2:
> -                    continue
> -                self._driver_aliases[alias[1]] = alias[0]
> -
>      def scan_header(self, fname):
>          """Scan a header file to build a list of struct definitions
>  
> diff --git a/tools/dtoc/test/dtoc_test_scan_drivers.cxx b/tools/dtoc/test/dtoc_test_scan_drivers.cxx
> index f448767670e..f370b8951d0 100644
> --- a/tools/dtoc/test/dtoc_test_scan_drivers.cxx
> +++ b/tools/dtoc/test/dtoc_test_scan_drivers.cxx
> @@ -1 +1,5 @@
> +/* Aliases must be in driver files */
> +U_BOOT_DRIVER(sandbox_gpio) {
> +};
> +
>  DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2)
> 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 17/33] dtoc: Process driver aliases along with drivers
  2021-06-21 18:39   ` Johan Jonker
@ 2021-06-26 18:32     ` Simon Glass
  2021-07-04 18:18       ` Simon Glass
  0 siblings, 1 reply; 70+ messages in thread
From: Simon Glass @ 2021-06-26 18:32 UTC (permalink / raw)
  To: Johan Jonker
  Cc: U-Boot Mailing List, Heiko Stuebner, Kever Yang, Philipp Tomsich

Hi Johan,

On Mon, 21 Jun 2021 at 12:39, Johan Jonker <jbx6244@gmail.com> wrote:
>
> Hi Simon, Heiko,
>
> With introduction of rockchip-nand-controller.c in Linux and recently
> rockchip_nfc.c in U-boot it offers a renewed opportunity to add support
> for MK808 with a rk3066 + NAND to boot from.
> rk3066 shares /arch/arm/dts/rk3xxx.dtsi with rk3188.
> The only 'usable' boot loader now is closed source with proprietary FTL.
>
> As a spinoff to that discussion I've tried to compile for
> rk3188-radxarock as an example due to the lack of rk3066 support in next
> and enabling the new rockchip_nfc.c driver.
> I'm not familiar with Python/U-boot.
> Do you have an idea what this error below is about?
>
> Kind regards,
>
> Johan
> ===
>
> python --version
> Python 2.7.13
>
> ===
>
> From rock_defconfig:
> CONFIG_SPL_OF_PLATDATA=y
>
> ===
>
> git clone -b next
> https://source.denx.de/u-boot/custodians/u-boot-rockchip.git
> u-boot-next-20210619
>
> make rock_defconfig
>
> make CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- menuconfig
>
> [ ]   Support for NAND controller on Rockchip SoCs (NEW)
>
> Add to rock.h:
> #define CONFIG_SYS_MAX_NAND_DEVICE      1
>
> make CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- all
>
> ===
> mkdir -p spl/dts/
>   FDTGREP spl/dts/dt-spl.dtb
>   COPY    spl/u-boot-spl.dtb
>   CC      spl/./lib/asm-offsets.s
>   CC      spl/./arch/arm/lib/asm-offsets.s
>   DTOC    spl/dts/dt-plat.c
> Traceback (most recent call last):
>   File "./tools/dtoc/dtoc", line 112, in <module>
>     options.phase, instantiate=options.instantiate)
>   File
> "~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/dtb_platdata.py",
> line 1180, in run_steps
>     scan.scan_drivers()
>   File
> "~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/src_scan.py", line
> 649, in scan_drivers
>     self.scan_driver(pathname)
>   File
> "~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/src_scan.py", line
> 608, in scan_driver
>     self._parse_driver(fname, buff)
>   File
> "~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/src_scan.py", line
> 558, in _parse_driver
>     self._driver_aliases[m_alias[2]] = m_alias[1]
> TypeError: '_sre.SRE_Match' object is not subscriptable
> scripts/Makefile.spl:352: recipe for target 'spl/dts/dt-plat.c' failed
> make[1]: *** [spl/dts/dt-plat.c] Error 1
> Makefile:1977: recipe for target 'spl/u-boot-spl' failed
> make: *** [spl/u-boot-spl] Error 2
>
> ===
>
> Changed:
> self._driver_aliases[m_alias[2]] = m_alias[1]
>
> To:
> self._driver_aliases[m_alias.group(2)] = m_alias.group(1)
>
> Is that a correct python change of mine?

I think so, yes. I will take a look.

>
> ===
>
> After that it compiles normal with only this warning.
>
>   DTOC    spl/dts/dt-plat.c
> WARNING: the driver rockchip_rk3188_grf was not found in the driver list
> WARNING: the driver rockchip_rk3188_pmu was not found in the driver list
> WARNING: the driver rockchip_rk3188_uart was not found in the driver list
>   DTOC    include/generated/dt-structs-gen.h
> WARNING: the driver rockchip_rk3188_grf was not found in the driver list
> WARNING: the driver rockchip_rk3188_pmu was not found in the driver list
> WARNING: the driver rockchip_rk3188_uart was not found in the driver list
>   DTOC    include/generated/dt-decl.h
> WARNING: the driver rockchip_rk3188_grf was not found in the driver list
> WARNING: the driver rockchip_rk3188_pmu was not found in the driver list
> WARNING: the driver rockchip_rk3188_uart was not found in the driver list

OK that means you have the driver missing. It is not fatal unless
OF_PLATDATA_INST is enabled.

[..]

Regards,
Simon

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 17/33] dtoc: Process driver aliases along with drivers
  2021-06-26 18:32     ` Simon Glass
@ 2021-07-04 18:18       ` Simon Glass
  0 siblings, 0 replies; 70+ messages in thread
From: Simon Glass @ 2021-07-04 18:18 UTC (permalink / raw)
  To: Johan Jonker
  Cc: U-Boot Mailing List, Heiko Stuebner, Kever Yang, Philipp Tomsich

Hi Johan,

On Sat, 26 Jun 2021 at 12:32, Simon Glass <sjg@chromium.org> wrote:
>
> Hi Johan,
>
> On Mon, 21 Jun 2021 at 12:39, Johan Jonker <jbx6244@gmail.com> wrote:
> >
> > Hi Simon, Heiko,
> >
> > With introduction of rockchip-nand-controller.c in Linux and recently
> > rockchip_nfc.c in U-boot it offers a renewed opportunity to add support
> > for MK808 with a rk3066 + NAND to boot from.
> > rk3066 shares /arch/arm/dts/rk3xxx.dtsi with rk3188.
> > The only 'usable' boot loader now is closed source with proprietary FTL.
> >
> > As a spinoff to that discussion I've tried to compile for
> > rk3188-radxarock as an example due to the lack of rk3066 support in next
> > and enabling the new rockchip_nfc.c driver.
> > I'm not familiar with Python/U-boot.
> > Do you have an idea what this error below is about?
> >
> > Kind regards,
> >
> > Johan
> > ===
> >
> > python --version
> > Python 2.7.13
> >
> > ===
> >
> > From rock_defconfig:
> > CONFIG_SPL_OF_PLATDATA=y
> >
> > ===
> >
> > git clone -b next
> > https://source.denx.de/u-boot/custodians/u-boot-rockchip.git
> > u-boot-next-20210619
> >
> > make rock_defconfig
> >
> > make CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- menuconfig
> >
> > [ ]   Support for NAND controller on Rockchip SoCs (NEW)
> >
> > Add to rock.h:
> > #define CONFIG_SYS_MAX_NAND_DEVICE      1
> >
> > make CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- all
> >
> > ===
> > mkdir -p spl/dts/
> >   FDTGREP spl/dts/dt-spl.dtb
> >   COPY    spl/u-boot-spl.dtb
> >   CC      spl/./lib/asm-offsets.s
> >   CC      spl/./arch/arm/lib/asm-offsets.s
> >   DTOC    spl/dts/dt-plat.c
> > Traceback (most recent call last):
> >   File "./tools/dtoc/dtoc", line 112, in <module>
> >     options.phase, instantiate=options.instantiate)
> >   File
> > "~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/dtb_platdata.py",
> > line 1180, in run_steps
> >     scan.scan_drivers()
> >   File
> > "~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/src_scan.py", line
> > 649, in scan_drivers
> >     self.scan_driver(pathname)
> >   File
> > "~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/src_scan.py", line
> > 608, in scan_driver
> >     self._parse_driver(fname, buff)
> >   File
> > "~/Downloads/u-boot-next-20210619/tools/dtoc/../dtoc/src_scan.py", line
> > 558, in _parse_driver
> >     self._driver_aliases[m_alias[2]] = m_alias[1]
> > TypeError: '_sre.SRE_Match' object is not subscriptable
> > scripts/Makefile.spl:352: recipe for target 'spl/dts/dt-plat.c' failed
> > make[1]: *** [spl/dts/dt-plat.c] Error 1
> > Makefile:1977: recipe for target 'spl/u-boot-spl' failed
> > make: *** [spl/u-boot-spl] Error 2
> >
> > ===
> >
> > Changed:
> > self._driver_aliases[m_alias[2]] = m_alias[1]
> >
> > To:
> > self._driver_aliases[m_alias.group(2)] = m_alias.group(1)
> >
> > Is that a correct python change of mine?
>
> I think so, yes. I will take a look.

This was introduced in Python 3.6 so I suspect your Python is quite
old. I will send a patch.

>
> >
> > ===
> >
> > After that it compiles normal with only this warning.
> >
> >   DTOC    spl/dts/dt-plat.c
> > WARNING: the driver rockchip_rk3188_grf was not found in the driver list
> > WARNING: the driver rockchip_rk3188_pmu was not found in the driver list
> > WARNING: the driver rockchip_rk3188_uart was not found in the driver list
> >   DTOC    include/generated/dt-structs-gen.h
> > WARNING: the driver rockchip_rk3188_grf was not found in the driver list
> > WARNING: the driver rockchip_rk3188_pmu was not found in the driver list
> > WARNING: the driver rockchip_rk3188_uart was not found in the driver list
> >   DTOC    include/generated/dt-decl.h
> > WARNING: the driver rockchip_rk3188_grf was not found in the driver list
> > WARNING: the driver rockchip_rk3188_pmu was not found in the driver list
> > WARNING: the driver rockchip_rk3188_uart was not found in the driver list
>
> OK that means you have the driver missing. It is not fatal unless
> OF_PLATDATA_INST is enabled.

I'll send a series to improve the warnings here. The problem is in the
strange use of the .compatible memory in the rockchip driver, so I've
updated dtoc to handle it but show a warning.

Regards,
Simon

^ permalink raw reply	[flat|nested] 70+ messages in thread

end of thread, other threads:[~2021-07-04 18:18 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-03 13:00 [PATCH v2 00/33] dm: Add dtoc implementation of device instantiation (part D) Simon Glass
2021-02-03 13:00 ` [PATCH v2 01/33] bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT Simon Glass
2021-02-03 13:00 ` [PATCH v2 02/33] dtoc: Scan drivers for available information Simon Glass
2021-02-03 13:00 ` [PATCH v2 03/33] dtoc: Save scan information across test runs Simon Glass
2021-02-03 13:00 ` [PATCH v2 04/33] dtoc: Ignore unwanted files when scanning for drivers Simon Glass
2021-02-03 13:00 ` [PATCH v2 05/33] dtoc: Collect priv/plat struct info from drivers Simon Glass
2021-02-03 13:00 ` [PATCH v2 06/33] dtoc: Support scanning of uclasses Simon Glass
2021-02-03 13:00 ` [PATCH v2 07/33] dtoc: Support scanning of structs in header files Simon Glass
2021-02-03 13:00 ` [PATCH v2 08/33] dtoc: Move test files into a test/ directory Simon Glass
2021-02-03 13:00 ` [PATCH v2 09/33] dtoc: Rename sandbox_i2c_test and sandbox_pmic_test Simon Glass
2021-02-03 13:00 ` [PATCH v2 10/33] dtoc: Add some extra properties to nodes Simon Glass
2021-02-03 13:00 ` [PATCH v2 11/33] dtoc: Make use of node properties Simon Glass
2021-02-03 13:01 ` [PATCH v2 12/33] dtoc: Process nodes to set up required properties Simon Glass
2021-02-03 13:01 ` [PATCH v2 13/33] dtoc: Track nodes which are actually used Simon Glass
2021-02-03 13:01 ` [PATCH v2 14/33] dtoc: Support tracking the phase of U-Boot Simon Glass
2021-02-03 13:01 ` [PATCH v2 15/33] Makefile: Pass the U-Boot phase to dtoc Simon Glass
2021-02-03 13:01 ` [PATCH v2 16/33] dtoc: Support headers needed for drivers Simon Glass
2021-02-03 13:01 ` [PATCH v2 17/33] dtoc: Process driver aliases along with drivers Simon Glass
2021-06-21 18:39   ` Johan Jonker
2021-06-26 18:32     ` Simon Glass
2021-07-04 18:18       ` Simon Glass
2021-02-03 13:01 ` [PATCH v2 18/33] dtoc: Warn of duplicate drivers Simon Glass
2021-02-03 13:01 ` [PATCH v2 19/33] dtoc: Read aliases for uclasses Simon Glass
2021-02-03 13:01 ` [PATCH v2 20/33] dtoc: Detect drivers only at the start of start of line Simon Glass
2021-02-03 13:01 ` [PATCH v2 21/33] dtoc: Assign a sequence number to each node Simon Glass
2021-02-03 13:01 ` [PATCH v2 22/33] dtoc: Set up the uclasses that are used Simon Glass
2021-02-03 13:01 ` [PATCH v2 23/33] dtoc: Support processing the root node Simon Glass
2021-02-03 13:01 ` [PATCH v2 24/33] dtoc: Add an option for device instantiation Simon Glass
2021-02-03 13:01 ` [PATCH v2 25/33] dm: of-platadata: Add " Simon Glass
2021-02-03 13:01 ` [PATCH v2 26/33] dtoc: Add support for decl file Simon Glass
2021-02-03 13:01 ` [PATCH v2 27/33] dtoc: Don't generate platform data with instantiation Simon Glass
2021-02-03 13:01 ` [PATCH v2 28/33] sandbox: Make sandbox,emul more conventional Simon Glass
2021-02-03 13:01 ` [PATCH v2 29/33] sandbox: i2c: Rename driver names to work with of-platdata Simon Glass
2021-02-03 13:01 ` [PATCH v2 30/33] dtoc: Tidy up the list of supported phandle properties Simon Glass
2021-02-03 13:01 ` [PATCH v2 31/33] dtoc: Generate a summary in the dt-plat.c file Simon Glass
2021-02-03 13:01 ` [PATCH v2 32/33] dtoc: Generate uclass devices Simon Glass
2021-02-03 13:01 ` [PATCH v2 33/33] dtoc: Generate device instances Simon Glass
2021-02-07  0:16 ` Simon Glass
2021-02-07  0:16 ` [PATCH v2 32/33] dtoc: Generate uclass devices Simon Glass
2021-02-07  0:16 ` [PATCH v2 31/33] dtoc: Generate a summary in the dt-plat.c file Simon Glass
2021-02-07  0:16 ` [PATCH v2 30/33] dtoc: Tidy up the list of supported phandle properties Simon Glass
2021-02-07  0:16 ` [PATCH v2 29/33] sandbox: i2c: Rename driver names to work with of-platdata Simon Glass
2021-02-07  0:16 ` [PATCH v2 28/33] sandbox: Make sandbox,emul more conventional Simon Glass
2021-02-07  0:16 ` [PATCH v2 27/33] dtoc: Don't generate platform data with instantiation Simon Glass
2021-02-07  0:16 ` [PATCH v2 26/33] dtoc: Add support for decl file Simon Glass
2021-02-07  0:16 ` [PATCH v2 25/33] dm: of-platadata: Add option for device instantiation Simon Glass
2021-02-07  0:17 ` [PATCH v2 24/33] dtoc: Add an " Simon Glass
2021-02-07  0:17 ` [PATCH v2 23/33] dtoc: Support processing the root node Simon Glass
2021-02-07  0:17 ` [PATCH v2 22/33] dtoc: Set up the uclasses that are used Simon Glass
2021-02-07  0:17 ` [PATCH v2 21/33] dtoc: Assign a sequence number to each node Simon Glass
2021-02-07  0:17 ` [PATCH v2 20/33] dtoc: Detect drivers only at the start of start of line Simon Glass
2021-02-07  0:17 ` [PATCH v2 19/33] dtoc: Read aliases for uclasses Simon Glass
2021-02-07  0:17 ` [PATCH v2 18/33] dtoc: Warn of duplicate drivers Simon Glass
2021-02-07  0:17 ` [PATCH v2 17/33] dtoc: Process driver aliases along with drivers Simon Glass
2021-02-07  0:17 ` [PATCH v2 16/33] dtoc: Support headers needed for drivers Simon Glass
2021-02-07  0:17 ` [PATCH v2 15/33] Makefile: Pass the U-Boot phase to dtoc Simon Glass
2021-02-07  0:17 ` [PATCH v2 14/33] dtoc: Support tracking the phase of U-Boot Simon Glass
2021-02-07  0:17 ` [PATCH v2 13/33] dtoc: Track nodes which are actually used Simon Glass
2021-02-07  0:17 ` [PATCH v2 12/33] dtoc: Process nodes to set up required properties Simon Glass
2021-02-07  0:17 ` [PATCH v2 11/33] dtoc: Make use of node properties Simon Glass
2021-02-07  0:17 ` [PATCH v2 10/33] dtoc: Add some extra properties to nodes Simon Glass
2021-02-07  0:17 ` [PATCH v2 09/33] dtoc: Rename sandbox_i2c_test and sandbox_pmic_test Simon Glass
2021-02-07  0:17 ` [PATCH v2 08/33] dtoc: Move test files into a test/ directory Simon Glass
2021-02-07  0:17 ` [PATCH v2 07/33] dtoc: Support scanning of structs in header files Simon Glass
2021-02-07  0:17 ` [PATCH v2 06/33] dtoc: Support scanning of uclasses Simon Glass
2021-02-07  0:17 ` [PATCH v2 05/33] dtoc: Collect priv/plat struct info from drivers Simon Glass
2021-02-07  0:17 ` [PATCH v2 04/33] dtoc: Ignore unwanted files when scanning for drivers Simon Glass
2021-02-07  0:17 ` [PATCH v2 03/33] dtoc: Save scan information across test runs Simon Glass
2021-02-07  0:17 ` [PATCH v2 02/33] dtoc: Scan drivers for available information Simon Glass
2021-02-07  0:17 ` [PATCH v2 01/33] bootstage: Fix dependency for BOOTSTAGE_RECORD_COUNT Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.