diff mbox series

[37/49] dtoc: Support headers needed for drivers

Message ID 20201229033535.99990-38-sjg@chromium.org
State Superseded
Delegated to: Simon Glass
Headers show
Series dm: Add dtoc implementation of device instantiation (part D) | expand

Commit Message

Simon Glass Dec. 29, 2020, 3:35 a.m. UTC
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>
---

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

Patch

diff --git a/include/dm/device.h b/include/dm/device.h
index 51b550d8ed2..e08a11c4a18 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):