diff mbox series

[v2,03/14] dtoc: add support to scan drivers

Message ID 20200619145555.863-4-walter.lozano@collabora.com
State New
Headers show
Series improve OF_PLATDATA support | expand

Commit Message

Walter Lozano June 19, 2020, 2:55 p.m. UTC
Currently dtoc scans dtbs to convert them to struct platdata and
to generate U_BOOT_DEVICE entries. These entries need to be filled
with the driver name, but at this moment the information used is the
compatible name present in the dtb. This causes that only nodes with
a compatible name that matches a driver name generate a working
entry.

In order to improve this behaviour, this patch adds to dtoc the
capability of scan drivers source code to generate a list of valid driver
names. This allows to rise a warning in the case that an U_BOOT_DEVICE
entry will try to use a name not valid.

Additionally, in order to add more flexibility to the solution, adds the
U_BOOT_DRIVER_ALIAS macro, which generates no code at all, but allows an
easy way to declare driver name aliases. Thanks to this, dtoc can look
for the driver name based on its alias when it populates the U_BOOT_DEVICE
entry.

Signed-off-by: Walter Lozano <walter.lozano at collabora.com>
---
 drivers/clk/at91/pmc.c                |  2 +
 drivers/gpio/mxs_gpio.c               |  2 +
 drivers/gpio/sandbox.c                |  2 +
 drivers/i2c/rk_i2c.c                  |  2 +
 drivers/mmc/mxsmmc.c                  |  1 +
 drivers/mmc/rockchip_dw_mmc.c         |  3 +
 drivers/mtd/spi/sf_probe.c            |  2 +
 drivers/pinctrl/nxp/pinctrl-mxs.c     |  2 +
 drivers/pinctrl/pinctrl-at91.c        |  2 +
 drivers/power/pmic/rk8xx.c            |  2 +
 drivers/serial/ns16550.c              |  4 ++
 drivers/spi/mxs_spi.c                 |  2 +
 drivers/spi/rk_spi.c                  |  2 +
 include/dm/device.h                   |  7 +++
 tools/dtoc/dtb_platdata.py            | 89 +++++++++++++++++++++++++--
 tools/dtoc/dtoc_test_driver_alias.dts | 20 ++++++
 tools/dtoc/test_dtoc.py               | 33 ++++++++++
 17 files changed, 173 insertions(+), 4 deletions(-)
 create mode 100644 tools/dtoc/dtoc_test_driver_alias.dts

Comments

Simon Glass June 23, 2020, 12:28 p.m. UTC | #1
Hi Walter,

On Fri, 19 Jun 2020 at 08:56, Walter Lozano <walter.lozano at collabora.com> wrote:
>
> Currently dtoc scans dtbs to convert them to struct platdata and
> to generate U_BOOT_DEVICE entries. These entries need to be filled
> with the driver name, but at this moment the information used is the
> compatible name present in the dtb. This causes that only nodes with
> a compatible name that matches a driver name generate a working
> entry.
>
> In order to improve this behaviour, this patch adds to dtoc the
> capability of scan drivers source code to generate a list of valid driver
> names. This allows to rise a warning in the case that an U_BOOT_DEVICE
> entry will try to use a name not valid.
>
> Additionally, in order to add more flexibility to the solution, adds the
> U_BOOT_DRIVER_ALIAS macro, which generates no code at all, but allows an
> easy way to declare driver name aliases. Thanks to this, dtoc can look
> for the driver name based on its alias when it populates the U_BOOT_DEVICE
> entry.
>
> Signed-off-by: Walter Lozano <walter.lozano at collabora.com>
> ---
>  drivers/clk/at91/pmc.c                |  2 +
>  drivers/gpio/mxs_gpio.c               |  2 +
>  drivers/gpio/sandbox.c                |  2 +
>  drivers/i2c/rk_i2c.c                  |  2 +
>  drivers/mmc/mxsmmc.c                  |  1 +
>  drivers/mmc/rockchip_dw_mmc.c         |  3 +
>  drivers/mtd/spi/sf_probe.c            |  2 +
>  drivers/pinctrl/nxp/pinctrl-mxs.c     |  2 +
>  drivers/pinctrl/pinctrl-at91.c        |  2 +
>  drivers/power/pmic/rk8xx.c            |  2 +
>  drivers/serial/ns16550.c              |  4 ++
>  drivers/spi/mxs_spi.c                 |  2 +
>  drivers/spi/rk_spi.c                  |  2 +
>  include/dm/device.h                   |  7 +++
>  tools/dtoc/dtb_platdata.py            | 89 +++++++++++++++++++++++++--
>  tools/dtoc/dtoc_test_driver_alias.dts | 20 ++++++
>  tools/dtoc/test_dtoc.py               | 33 ++++++++++
>  17 files changed, 173 insertions(+), 4 deletions(-)
>  create mode 100644 tools/dtoc/dtoc_test_driver_alias.dts
>

Reviewed-by: Simon Glass <sjg at chromium.org>

But please can you split out the changes to drivers and device.h into
a separate, earlier patch? I'd like to keep tools changes separate
where possible.

Regards,
Simon
Walter Lozano June 23, 2020, 7:54 p.m. UTC | #2
Hi Simon,

On 23/6/20 09:28, Simon Glass wrote:
> Hi Walter,
>
> On Fri, 19 Jun 2020 at 08:56, Walter Lozano <walter.lozano at collabora.com> wrote:
>> Currently dtoc scans dtbs to convert them to struct platdata and
>> to generate U_BOOT_DEVICE entries. These entries need to be filled
>> with the driver name, but at this moment the information used is the
>> compatible name present in the dtb. This causes that only nodes with
>> a compatible name that matches a driver name generate a working
>> entry.
>>
>> In order to improve this behaviour, this patch adds to dtoc the
>> capability of scan drivers source code to generate a list of valid driver
>> names. This allows to rise a warning in the case that an U_BOOT_DEVICE
>> entry will try to use a name not valid.
>>
>> Additionally, in order to add more flexibility to the solution, adds the
>> U_BOOT_DRIVER_ALIAS macro, which generates no code at all, but allows an
>> easy way to declare driver name aliases. Thanks to this, dtoc can look
>> for the driver name based on its alias when it populates the U_BOOT_DEVICE
>> entry.
>>
>> Signed-off-by: Walter Lozano <walter.lozano at collabora.com>
>> ---
>>   drivers/clk/at91/pmc.c                |  2 +
>>   drivers/gpio/mxs_gpio.c               |  2 +
>>   drivers/gpio/sandbox.c                |  2 +
>>   drivers/i2c/rk_i2c.c                  |  2 +
>>   drivers/mmc/mxsmmc.c                  |  1 +
>>   drivers/mmc/rockchip_dw_mmc.c         |  3 +
>>   drivers/mtd/spi/sf_probe.c            |  2 +
>>   drivers/pinctrl/nxp/pinctrl-mxs.c     |  2 +
>>   drivers/pinctrl/pinctrl-at91.c        |  2 +
>>   drivers/power/pmic/rk8xx.c            |  2 +
>>   drivers/serial/ns16550.c              |  4 ++
>>   drivers/spi/mxs_spi.c                 |  2 +
>>   drivers/spi/rk_spi.c                  |  2 +
>>   include/dm/device.h                   |  7 +++
>>   tools/dtoc/dtb_platdata.py            | 89 +++++++++++++++++++++++++--
>>   tools/dtoc/dtoc_test_driver_alias.dts | 20 ++++++
>>   tools/dtoc/test_dtoc.py               | 33 ++++++++++
>>   17 files changed, 173 insertions(+), 4 deletions(-)
>>   create mode 100644 tools/dtoc/dtoc_test_driver_alias.dts
>>
> Reviewed-by: Simon Glass <sjg at chromium.org>
>
> But please can you split out the changes to drivers and device.h into
> a separate, earlier patch? I'd like to keep tools changes separate
> where possible.


Sure, thanks for your suggestion.

Regards,

Walter
diff mbox series

Patch

diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 1fede16a0c..793a506d27 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -30,6 +30,8 @@  U_BOOT_DRIVER(atmel_at91rm9200_pmc) = {
 	.of_match = at91_pmc_match,
 };
 
+U_BOOT_DRIVER_ALIAS(atmel_at91rm9200_pmc, atmel_at91sam9260_pmc)
+
 /*---------------------------------------------------------*/
 
 int at91_pmc_core_probe(struct udevice *dev)
diff --git a/drivers/gpio/mxs_gpio.c b/drivers/gpio/mxs_gpio.c
index e43484d13a..bcdf08c255 100644
--- a/drivers/gpio/mxs_gpio.c
+++ b/drivers/gpio/mxs_gpio.c
@@ -309,4 +309,6 @@  U_BOOT_DRIVER(fsl_imx23_gpio) = {
 	.ofdata_to_platdata = mxs_ofdata_to_platdata,
 #endif
 };
+
+U_BOOT_DRIVER_ALIAS(fsl_imx23_gpio, fsl_imx28_gpio)
 #endif /* DM_GPIO */
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index ff46d3c8d1..8923e54867 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -253,6 +253,8 @@  U_BOOT_DRIVER(sandbox_gpio) = {
 	.ops	= &gpio_sandbox_ops,
 };
 
+U_BOOT_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias)
+
 /* pincontrol: used only to check GPIO pin configuration (pinmux command) */
 
 struct sb_pinctrl_priv {
diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c
index eceef80e70..e76c087b1d 100644
--- a/drivers/i2c/rk_i2c.c
+++ b/drivers/i2c/rk_i2c.c
@@ -492,3 +492,5 @@  U_BOOT_DRIVER(rockchip_rk3066_i2c) = {
 	.priv_auto_alloc_size = sizeof(struct rk_i2c),
 	.ops	= &rockchip_i2c_ops,
 };
+
+U_BOOT_DRIVER_ALIAS(rockchip_rk3066_i2c, rockchip_rk3288_i2c)
diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c
index 35c336b499..afa95e57ee 100644
--- a/drivers/mmc/mxsmmc.c
+++ b/drivers/mmc/mxsmmc.c
@@ -724,4 +724,5 @@  U_BOOT_DRIVER(fsl_imx23_mmc) = {
 	.platdata_auto_alloc_size = sizeof(struct mxsmmc_platdata),
 };
 
+U_BOOT_DRIVER_ALIAS(fsl_imx23_mmc, fsl_imx28_mmc)
 #endif /* CONFIG_DM_MMC */
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index ef75367b3e..ac710324c8 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -178,6 +178,9 @@  U_BOOT_DRIVER(rockchip_rk3288_dw_mshc) = {
 	.platdata_auto_alloc_size = sizeof(struct rockchip_mmc_plat),
 };
 
+U_BOOT_DRIVER_ALIAS(rockchip_rk3288_dw_mshc, rockchip_rk3328_dw_mshc)
+U_BOOT_DRIVER_ALIAS(rockchip_rk3288_dw_mshc, rockchip_rk3368_dw_mshc)
+
 #ifdef CONFIG_PWRSEQ
 static int rockchip_dwmmc_pwrseq_set_power(struct udevice *dev, bool enable)
 {
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 1b44cc68c6..97fa22a4b3 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -180,4 +180,6 @@  U_BOOT_DRIVER(jedec_spi_nor) = {
 	.ops		= &spi_flash_std_ops,
 };
 
+U_BOOT_DRIVER_ALIAS(jedec_spi_nor, spansion_m25p16)
+
 #endif /* CONFIG_DM_SPI_FLASH */
diff --git a/drivers/pinctrl/nxp/pinctrl-mxs.c b/drivers/pinctrl/nxp/pinctrl-mxs.c
index bd434667b1..da6b95acc5 100644
--- a/drivers/pinctrl/nxp/pinctrl-mxs.c
+++ b/drivers/pinctrl/nxp/pinctrl-mxs.c
@@ -190,3 +190,5 @@  U_BOOT_DRIVER(fsl_imx23_pinctrl) = {
 	.priv_auto_alloc_size = sizeof(struct mxs_pinctrl_priv),
 	.ops = &mxs_pinctrl_ops,
 };
+
+U_BOOT_DRIVER_ALIAS(fsl_imx23_pinctrl, fsl_imx28_pinctrl)
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 0cc35042f5..b40ff8c823 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -525,3 +525,5 @@  U_BOOT_DRIVER(atmel_sama5d3_pinctrl) = {
 	.priv_auto_alloc_size = sizeof(struct at91_pinctrl_priv),
 	.ops = &at91_pinctrl_ops,
 };
+
+U_BOOT_DRIVER_ALIAS(atmel_sama5d3_pinctrl, atmel_at91rm9200_pinctrl)
diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c
index d870ed7113..c8ae28b8f3 100644
--- a/drivers/power/pmic/rk8xx.c
+++ b/drivers/power/pmic/rk8xx.c
@@ -193,3 +193,5 @@  U_BOOT_DRIVER(rockchip_rk805) = {
 	.probe = rk8xx_probe,
 	.ops = &rk8xx_ops,
 };
+
+U_BOOT_DRIVER_ALIAS(rockchip_rk805, rockchip_rk808)
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 6415d2e1e5..df958a688b 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -619,6 +619,10 @@  U_BOOT_DRIVER(ns16550_serial) = {
 	.flags	= DM_FLAG_PRE_RELOC,
 #endif
 };
+
+U_BOOT_DRIVER_ALIAS(ns16550_serial, rockchip_rk3328_uart)
+U_BOOT_DRIVER_ALIAS(ns16550_serial, rockchip_rk3368_uart)
+U_BOOT_DRIVER_ALIAS(ns16550_serial, ti_da830_uart)
 #endif
 #endif /* SERIAL_PRESENT */
 
diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c
index 087cd50788..2779501176 100644
--- a/drivers/spi/mxs_spi.c
+++ b/drivers/spi/mxs_spi.c
@@ -618,4 +618,6 @@  U_BOOT_DRIVER(fsl_imx23_spi) = {
 	.priv_auto_alloc_size = sizeof(struct mxs_spi_priv),
 	.probe	= mxs_spi_probe,
 };
+
+U_BOOT_DRIVER_ALIAS(fsl_imx23_spi, fsl_imx28_spi)
 #endif
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c
index d25a87fad6..0ac7f767ca 100644
--- a/drivers/spi/rk_spi.c
+++ b/drivers/spi/rk_spi.c
@@ -561,3 +561,5 @@  U_BOOT_DRIVER(rockchip_rk3288_spi) = {
 	.priv_auto_alloc_size = sizeof(struct rockchip_spi_priv),
 	.probe	= rockchip_spi_probe,
 };
+
+U_BOOT_DRIVER_ALIAS(rockchip_rk3288_spi, rockchip_rk3368_spi)
diff --git a/include/dm/device.h b/include/dm/device.h
index 975eec5d0e..2cfe10766f 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -282,6 +282,13 @@  struct driver {
 #define DM_GET_DRIVER(__name)						\
 	ll_entry_get(struct driver, __name, driver)
 
+/**
+ * Declare a macro to state a alias for a driver name. This macro will
+ * produce no code but its information will be parsed by tools like
+ * dtoc
+ */
+#define U_BOOT_DRIVER_ALIAS(__name, __alias)
+
 /**
  * dev_get_platdata() - Get the platform data for a device
  *
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index bc0de426a9..c4701d3211 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -13,6 +13,8 @@  static data.
 
 import collections
 import copy
+import os
+import re
 import sys
 
 from dtoc import fdt
@@ -143,6 +145,11 @@  class DtbPlatdata(object):
         _aliases: Dict that hold aliases for compatible strings
             key: First compatible string declared in a node
             value: List of additional compatible strings declared in a node
+        _drivers: List of valid driver names found in drivers/
+        _driver_aliases: Dict that holds aliases for driver names
+            key: Driver alias declared with
+                U_BOOT_DRIVER_ALIAS(driver_alias, driver_name)
+            value: Driver name declared with U_BOOT_DRIVER(driver_name)
     """
     def __init__(self, dtb_fname, include_disabled):
         self._fdt = None
@@ -152,6 +159,37 @@  class DtbPlatdata(object):
         self._outfile = None
         self._lines = []
         self._aliases = {}
+        self._drivers = []
+        self._driver_aliases = {}
+
+    def get_normalized_compat_name(self, node):
+        """Get a node's normalized compat name
+
+        Returns a valid driver name by retrieving node's first compatible
+        string as a C identifier and performing a check against _drivers
+        and a lookup in driver_aliases printing a warning in case of failure.
+
+        Args:
+            node: Node object to check
+        Return:
+            Tuple:
+                Driver name associated with the first compatible string
+                List of C identifiers for all the other compatible strings
+                    (possibly empty)
+                In case of no match found, the return will be the same as
+                get_compat_name()
+        """
+        compat_c, aliases_c = get_compat_name(node)
+        if compat_c not in self._drivers:
+            compat_c_old = compat_c
+            compat_c = self._driver_aliases.get(compat_c)
+            if not compat_c:
+                print('WARNING: the driver %s was not found in the driver list' % (compat_c_old))
+                compat_c = compat_c_old
+            else:
+                aliases_c = [compat_c_old] + aliases_c
+
+        return compat_c, aliases_c
 
     def setup_output(self, fname):
         """Set up the output destination
@@ -246,6 +284,48 @@  class DtbPlatdata(object):
             return PhandleInfo(max_args, args)
         return None
 
+    def scan_driver(self, fn):
+        """Scan a driver file to build a list of driver names and aliases
+
+        This procedure will populate self._drivers and self._driver_aliases
+
+        Args
+            fn: Driver filename to scan
+        """
+        with open(fn) as fd:
+            buff = fd.read()
+
+            # The following re will search for driver names declared as
+            # U_BOOT_DRIVER(driver_name)
+            drivers = re.findall('U_BOOT_DRIVER\((.*)\)', buff)
+
+            for driver in drivers:
+                self._drivers.append(driver)
+
+            # The following re will search for driver aliases declared as
+            # U_BOOT_DRIVER_ALIAS(alias, driver_name)
+            driver_aliases = re.findall('U_BOOT_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_drivers(self):
+        """Scan the driver folders to build a list of driver names and aliases
+
+        This procedure will populate self._drivers and self._driver_aliases
+
+        """
+        basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
+        if basedir == '':
+            basedir = './'
+        for (dirpath, dirnames, filenames) in os.walk(basedir):
+            for fn in filenames:
+                if not fn.endswith('.c'):
+                    continue
+                self.scan_driver(dirpath + '/' + fn)
+
     def scan_dtb(self):
         """Scan the device tree to obtain a tree of nodes and properties
 
@@ -356,7 +436,7 @@  class DtbPlatdata(object):
         """
         structs = {}
         for node in self._valid_nodes:
-            node_name, _ = get_compat_name(node)
+            node_name, _ = self.get_normalized_compat_name(node)
             fields = {}
 
             # Get a list of all the valid properties in this node.
@@ -380,14 +460,14 @@  class DtbPlatdata(object):
 
         upto = 0
         for node in self._valid_nodes:
-            node_name, _ = get_compat_name(node)
+            node_name, _ = self.get_normalized_compat_name(node)
             struct = structs[node_name]
             for name, prop in node.props.items():
                 if name not in PROP_IGNORE_LIST and name[0] != '#':
                     prop.Widen(struct[name])
             upto += 1
 
-            struct_name, aliases = get_compat_name(node)
+            struct_name, aliases = self.get_normalized_compat_name(node)
             for alias in aliases:
                 self._aliases[alias] = struct_name
 
@@ -464,7 +544,7 @@  class DtbPlatdata(object):
         Args:
             node: node to output
         """
-        struct_name, _ = get_compat_name(node)
+        struct_name, _ = self.get_normalized_compat_name(node)
         var_name = conv_name_to_c(node.name)
         self.buf('static const struct %s%s %s%s = {\n' %
                  (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
@@ -565,6 +645,7 @@  def run_steps(args, dtb_file, include_disabled, output):
         raise ValueError('Please specify a command: struct, platdata')
 
     plat = DtbPlatdata(dtb_file, include_disabled)
+    plat.scan_drivers()
     plat.scan_dtb()
     plat.scan_tree()
     plat.scan_reg_sizes()
diff --git a/tools/dtoc/dtoc_test_driver_alias.dts b/tools/dtoc/dtoc_test_driver_alias.dts
new file mode 100644
index 0000000000..da7973b2e5
--- /dev/null
+++ b/tools/dtoc/dtoc_test_driver_alias.dts
@@ -0,0 +1,20 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2020 Collabora Ltd.
+ */
+
+/dts-v1/;
+
+/ {
+	gpio_a: gpios at 0 {
+		u-boot,dm-pre-reloc;
+		gpio-controller;
+		compatible = "sandbox_gpio_alias";
+		#gpio-cells = <1>;
+		gpio-bank-name = "a";
+		sandbox,gpio-count = <20>;
+	};
+
+};
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 8498e8303c..91fc9d77f3 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -266,6 +266,39 @@  U_BOOT_DEVICE(pmic_at_9) = {
 \t.platdata_size\t= sizeof(dtv_pmic_at_9),
 };
 
+''', data)
+
+    def test_driver_alias(self):
+        """Test output from a device tree file with a driver alias"""
+        dtb_file = get_dtb_file('dtoc_test_driver_alias.dts')
+        output = tools.GetOutputFilename('output')
+        dtb_platdata.run_steps(['struct'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self._CheckStrings(HEADER + '''
+struct dtd_sandbox_gpio {
+\tconst char *\tgpio_bank_name;
+\tbool\t\tgpio_controller;
+\tfdt32_t\t\tsandbox_gpio_count;
+};
+#define dtd_sandbox_gpio_alias dtd_sandbox_gpio
+''', data)
+
+        dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self._CheckStrings(C_HEADER + '''
+static const struct dtd_sandbox_gpio dtv_gpios_at_0 = {
+\t.gpio_bank_name\t\t= "a",
+\t.gpio_controller\t= true,
+\t.sandbox_gpio_count\t= 0x14,
+};
+U_BOOT_DEVICE(gpios_at_0) = {
+\t.name\t\t= "sandbox_gpio",
+\t.platdata\t= &dtv_gpios_at_0,
+\t.platdata_size\t= sizeof(dtv_gpios_at_0),
+};
+
 ''', data)
 
     def test_phandle(self):