1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0+
3# Copyright (c) 2012 The Chromium OS Authors.
4#
5
6"""Tests for the dtb_platdata module
7
8This includes unit tests for some functions and functional tests for the dtoc
9tool.
10"""
11
12import collections
13import copy
14import glob
15import os
16import pathlib
17import struct
18import unittest
19
20from dtoc import dtb_platdata
21from dtoc import fdt
22from dtoc import fdt_util
23from dtoc import src_scan
24from dtoc.dtb_platdata import Ftype
25from dtoc.dtb_platdata import get_value
26from dtoc.dtb_platdata import tab_to
27from dtoc.src_scan import conv_name_to_c
28from dtoc.src_scan import get_compat_name
29from u_boot_pylib import test_util
30from u_boot_pylib import tools
31
32DTOC_DIR = pathlib.Path(__file__).parent
33TEST_DATA_DIR = DTOC_DIR / 'test/'
34
35
36HEADER = '''/*
37 * DO NOT MODIFY
38 *
39 * Defines the structs used to hold devicetree data.
40 * This was generated by dtoc from a .dtb (device tree binary) file.
41 */
42
43#include <stdbool.h>
44#include <linux/libfdt.h>'''
45
46DECL_HEADER = '''/*
47 * DO NOT MODIFY
48 *
49 * Declares externs for all device/uclass instances.
50 * This was generated by dtoc from a .dtb (device tree binary) file.
51 */
52'''
53
54C_HEADER_PRE = '''/*
55 * DO NOT MODIFY
56 *
57 * Declares the U_BOOT_DRIVER() records and platform data.
58 * This was generated by dtoc from a .dtb (device tree binary) file.
59 */
60'''
61
62C_HEADER = C_HEADER_PRE + '''
63/* Allow use of U_BOOT_DRVINFO() in this file */
64#define DT_PLAT_C
65
66#include <common.h>
67#include <dm.h>
68#include <dt-structs.h>
69'''
70
71UCLASS_HEADER_COMMON = '''/*
72 * DO NOT MODIFY
73 *
74 * Declares the uclass instances (struct uclass).
75 * This was generated by dtoc from a .dtb (device tree binary) file.
76 */
77'''
78
79# Scanner saved from a previous run of the tests (to speed things up)
80saved_scan = None
81
82# This is a test so is allowed to access private things in the module it is
83# testing
84# pylint: disable=W0212
85
86def get_dtb_file(dts_fname, capture_stderr=False):
87    """Compile a .dts file to a .dtb
88
89    Args:
90        dts_fname (str): Filename of .dts file in the current directory
91        capture_stderr (bool): True to capture and discard stderr output
92
93    Returns:
94        str: Filename of compiled file in output directory
95    """
96    return fdt_util.EnsureCompiled(str(TEST_DATA_DIR / dts_fname),
97                                   capture_stderr=capture_stderr)
98
99
100def setup():
101    global saved_scan
102
103    # Disable warnings so that calls to get_normalized_compat_name() will not
104    # output things.
105    saved_scan = src_scan.Scanner(None, False)
106    saved_scan.scan_drivers()
107
108def copy_scan():
109    """Get a copy of saved_scan so that each test can start clean"""
110    return copy.deepcopy(saved_scan)
111
112
113class TestDtoc(unittest.TestCase):
114    """Tests for dtoc"""
115    @classmethod
116    def setUpClass(cls):
117        tools.prepare_output_dir(None)
118        cls.maxDiff = None
119
120    @classmethod
121    def tearDownClass(cls):
122        tools.finalise_output_dir()
123
124    @staticmethod
125    def _write_python_string(fname, data):
126        """Write a string with tabs expanded as done in this Python file
127
128        Args:
129            fname (str): Filename to write to
130            data (str): Raw string to convert
131        """
132        data = data.replace('\t', '\\t')
133        with open(fname, 'w') as fout:
134            fout.write(data)
135
136    def _check_strings(self, expected, actual):
137        """Check that a string matches its expected value
138
139        If the strings do not match, they are written to the /tmp directory in
140        the same Python format as is used here in the test. This allows for
141        easy comparison and update of the tests.
142
143        Args:
144            expected (str): Expected string
145            actual (str): Actual string
146        """
147        if expected != actual:
148            self._write_python_string('/tmp/binman.expected', expected)
149            self._write_python_string('/tmp/binman.actual', actual)
150            print('Failures written to /tmp/binman.{expected,actual}')
151        self.assertEqual(expected, actual)
152
153    @staticmethod
154    def run_test(args, dtb_file, output, instantiate=False):
155        """Run a test using dtoc
156
157        Args:
158            args (list of str): List of arguments for dtoc
159            dtb_file (str): Filename of .dtb file
160            output (str): Filename of output file
161
162        Returns:
163            DtbPlatdata object
164        """
165        # Make a copy of the 'scan' object, since it includes uclasses and
166        # drivers, which get updated during execution.
167        return dtb_platdata.run_steps(
168            args, dtb_file, False, output, [], None, instantiate,
169            warning_disabled=True, scan=copy_scan())
170
171    def test_name(self):
172        """Test conversion of device tree names to C identifiers"""
173        self.assertEqual('serial_at_0x12', conv_name_to_c('serial@0x12'))
174        self.assertEqual('vendor_clock_frequency',
175                         conv_name_to_c('vendor,clock-frequency'))
176        self.assertEqual('rockchip_rk3399_sdhci_5_1',
177                         conv_name_to_c('rockchip,rk3399-sdhci-5.1'))
178
179    def test_tab_to(self):
180        """Test operation of tab_to() function"""
181        self.assertEqual('fred ', tab_to(0, 'fred'))
182        self.assertEqual('fred\t', tab_to(1, 'fred'))
183        self.assertEqual('fred was here ', tab_to(1, 'fred was here'))
184        self.assertEqual('fred was here\t\t', tab_to(3, 'fred was here'))
185        self.assertEqual('exactly8 ', tab_to(1, 'exactly8'))
186        self.assertEqual('exactly8\t', tab_to(2, 'exactly8'))
187
188    def test_get_value(self):
189        """Test operation of get_value() function"""
190        self.assertEqual('0x45',
191                         get_value(fdt.Type.INT, struct.pack('>I', 0x45)))
192        self.assertEqual('0x45',
193                         get_value(fdt.Type.BYTE, struct.pack('<I', 0x45)))
194        self.assertEqual('0x0',
195                         get_value(fdt.Type.BYTE, struct.pack('>I', 0x45)))
196        self.assertEqual('"test"', get_value(fdt.Type.STRING, 'test'))
197        self.assertEqual('true', get_value(fdt.Type.BOOL, None))
198
199    def test_get_compat_name(self):
200        """Test operation of get_compat_name() function"""
201        Prop = collections.namedtuple('Prop', ['value'])
202        Node = collections.namedtuple('Node', ['props'])
203
204        prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1'])
205        node = Node({'compatible': prop})
206        self.assertEqual((['rockchip_rk3399_sdhci_5_1', 'arasan_sdhci_5_1']),
207                         get_compat_name(node))
208
209        prop = Prop(['rockchip,rk3399-sdhci-5.1'])
210        node = Node({'compatible': prop})
211        self.assertEqual((['rockchip_rk3399_sdhci_5_1']),
212                         get_compat_name(node))
213
214        prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1', 'third'])
215        node = Node({'compatible': prop})
216        self.assertEqual((['rockchip_rk3399_sdhci_5_1',
217                           'arasan_sdhci_5_1', 'third']),
218                         get_compat_name(node))
219
220    def test_empty_file(self):
221        """Test output from a device tree file with no nodes"""
222        dtb_file = get_dtb_file('dtoc_test_empty.dts')
223        output = tools.get_output_filename('output')
224
225        # Run this one without saved_scan to complete test coverage
226        dtb_platdata.run_steps(['struct'], dtb_file, False, output, [], None,
227                               False)
228        with open(output) as infile:
229            lines = infile.read().splitlines()
230        self.assertEqual(HEADER.splitlines(), lines)
231
232        self.run_test(['platdata'], dtb_file, output)
233        with open(output) as infile:
234            lines = infile.read().splitlines()
235        self.assertEqual(C_HEADER.splitlines() + [''], lines)
236
237    decl_text = DECL_HEADER + '''
238#include <dm/device-internal.h>
239#include <dm/uclass-internal.h>
240
241/* driver declarations - these allow DM_DRIVER_GET() to be used */
242extern U_BOOT_DRIVER(sandbox_i2c);
243extern U_BOOT_DRIVER(sandbox_pmic);
244extern U_BOOT_DRIVER(sandbox_spl_test);
245extern U_BOOT_DRIVER(sandbox_spl_test);
246extern U_BOOT_DRIVER(sandbox_spl_test);
247
248/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
249extern UCLASS_DRIVER(i2c);
250extern UCLASS_DRIVER(misc);
251extern UCLASS_DRIVER(pmic);
252'''
253    decl_text_inst = DECL_HEADER + '''
254#include <dm/device-internal.h>
255#include <dm/uclass-internal.h>
256
257/* driver declarations - these allow DM_DRIVER_GET() to be used */
258extern U_BOOT_DRIVER(sandbox_i2c);
259extern U_BOOT_DRIVER(root_driver);
260extern U_BOOT_DRIVER(denx_u_boot_test_bus);
261extern U_BOOT_DRIVER(sandbox_spl_test);
262extern U_BOOT_DRIVER(sandbox_spl_test);
263extern U_BOOT_DRIVER(denx_u_boot_fdt_test);
264extern U_BOOT_DRIVER(denx_u_boot_fdt_test);
265
266/* device declarations - these allow DM_DEVICE_REF() to be used */
267extern DM_DEVICE_INST(i2c);
268extern DM_DEVICE_INST(root);
269extern DM_DEVICE_INST(some_bus);
270extern DM_DEVICE_INST(spl_test);
271extern DM_DEVICE_INST(spl_test3);
272extern DM_DEVICE_INST(test);
273extern DM_DEVICE_INST(test0);
274
275/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
276extern UCLASS_DRIVER(i2c);
277extern UCLASS_DRIVER(misc);
278extern UCLASS_DRIVER(root);
279extern UCLASS_DRIVER(testbus);
280extern UCLASS_DRIVER(testfdt);
281
282/* uclass declarations - needed for DM_UCLASS_REF() */
283extern DM_UCLASS_INST(i2c);
284extern DM_UCLASS_INST(misc);
285extern DM_UCLASS_INST(root);
286extern DM_UCLASS_INST(testbus);
287extern DM_UCLASS_INST(testfdt);
288'''
289    struct_text = HEADER + '''
290struct dtd_sandbox_i2c {
291};
292struct dtd_sandbox_pmic {
293\tbool\t\tlow_power;
294\tfdt32_t\t\treg[1];
295};
296struct dtd_sandbox_spl_test {
297\tconst char *	acpi_name;
298\tbool\t\tboolval;
299\tunsigned char\tbytearray[3];
300\tunsigned char\tbyteval;
301\tfdt32_t\t\tint64val[2];
302\tfdt32_t\t\tintarray[3];
303\tfdt32_t\t\tintval;
304\tunsigned char\tlongbytearray[9];
305\tfdt32_t\t\tmaybe_empty_int[1];
306\tunsigned char\tnotstring[5];
307\tconst char *\tstringarray[3];
308\tconst char *\tstringval;
309};
310'''
311    platdata_text = C_HEADER + '''
312/*
313 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
314 *
315 * idx  driver_info          driver
316 * ---  -------------------- --------------------
317 *   0: i2c_at_0             sandbox_i2c
318 *   1: pmic_at_9            sandbox_pmic
319 *   2: spl_test             sandbox_spl_test
320 *   3: spl_test2            sandbox_spl_test
321 *   4: spl_test3            sandbox_spl_test
322 * ---  -------------------- --------------------
323 */
324
325/*
326 * Node /i2c@0 index 0
327 * driver sandbox_i2c parent None
328 */
329static struct dtd_sandbox_i2c dtv_i2c_at_0 = {
330};
331U_BOOT_DRVINFO(i2c_at_0) = {
332\t.name\t\t= "sandbox_i2c",
333\t.plat\t\t= &dtv_i2c_at_0,
334\t.plat_size\t= sizeof(dtv_i2c_at_0),
335\t.parent_idx\t= -1,
336};
337
338/*
339 * Node /i2c@0/pmic@9 index 1
340 * driver sandbox_pmic parent sandbox_i2c
341 */
342static struct dtd_sandbox_pmic dtv_pmic_at_9 = {
343\t.low_power\t\t= true,
344\t.reg\t\t\t= {0x9},
345};
346U_BOOT_DRVINFO(pmic_at_9) = {
347\t.name\t\t= "sandbox_pmic",
348\t.plat\t\t= &dtv_pmic_at_9,
349\t.plat_size\t= sizeof(dtv_pmic_at_9),
350\t.parent_idx\t= 0,
351};
352
353/*
354 * Node /spl-test index 2
355 * driver sandbox_spl_test parent None
356 */
357static struct dtd_sandbox_spl_test dtv_spl_test = {
358\t.boolval\t\t= true,
359\t.bytearray\t\t= {0x6, 0x0, 0x0},
360\t.byteval\t\t= 0x5,
361\t.int64val\t\t= {0x12345678, 0x9abcdef0},
362\t.intarray\t\t= {0x2, 0x3, 0x4},
363\t.intval\t\t\t= 0x1,
364\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
365\t\t0x11},
366\t.maybe_empty_int\t= {0x0},
367\t.notstring\t\t= {0x20, 0x21, 0x22, 0x10, 0x0},
368\t.stringarray\t\t= {"multi-word", "message", ""},
369\t.stringval\t\t= "message",
370};
371U_BOOT_DRVINFO(spl_test) = {
372\t.name\t\t= "sandbox_spl_test",
373\t.plat\t\t= &dtv_spl_test,
374\t.plat_size\t= sizeof(dtv_spl_test),
375\t.parent_idx\t= -1,
376};
377
378/*
379 * Node /spl-test2 index 3
380 * driver sandbox_spl_test parent None
381 */
382static struct dtd_sandbox_spl_test dtv_spl_test2 = {
383\t.acpi_name\t\t= "\\\\_SB.GPO0",
384\t.bytearray\t\t= {0x1, 0x23, 0x34},
385\t.byteval\t\t= 0x8,
386\t.intarray\t\t= {0x5, 0x0, 0x0},
387\t.intval\t\t\t= 0x3,
388\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0x0, 0x0, 0x0, 0x0,
389\t\t0x0},
390\t.stringarray\t\t= {"another", "multi-word", "message"},
391\t.stringval\t\t= "message2",
392};
393U_BOOT_DRVINFO(spl_test2) = {
394\t.name\t\t= "sandbox_spl_test",
395\t.plat\t\t= &dtv_spl_test2,
396\t.plat_size\t= sizeof(dtv_spl_test2),
397\t.parent_idx\t= -1,
398};
399
400/*
401 * Node /spl-test3 index 4
402 * driver sandbox_spl_test parent None
403 */
404static struct dtd_sandbox_spl_test dtv_spl_test3 = {
405\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
406\t\t0x0},
407\t.maybe_empty_int\t= {0x1},
408\t.stringarray\t\t= {"one", "", ""},
409};
410U_BOOT_DRVINFO(spl_test3) = {
411\t.name\t\t= "sandbox_spl_test",
412\t.plat\t\t= &dtv_spl_test3,
413\t.plat_size\t= sizeof(dtv_spl_test3),
414\t.parent_idx\t= -1,
415};
416
417'''
418    uclass_text_inst = '''
419
420#include <common.h>
421#include <dm.h>
422#include <dt-structs.h>
423
424/*
425 * uclass declarations, ordered by 'struct uclass' linker_list idx:
426 *   0: i2c
427 *   1: misc
428 *   2: root
429 *   3: testbus
430 *   4: testfdt
431 *
432 * Sequence numbers allocated in each uclass:
433 * i2c: UCLASS_I2C
434 *    4: /i2c
435 * misc: UCLASS_MISC
436 *    0: /spl-test
437 *    1: /spl-test3
438 * root: UCLASS_ROOT
439 *    0: /
440 * testbus: UCLASS_TEST_BUS
441 *    2: /some-bus
442 * testfdt: UCLASS_TEST_FDT
443 *    1: /some-bus/test
444 *    2: /some-bus/test0
445 */
446
447struct list_head uclass_head = {
448	.prev = &DM_UCLASS_REF(testfdt)->sibling_node,
449	.next = &DM_UCLASS_REF(i2c)->sibling_node,
450};
451
452DM_UCLASS_INST(i2c) = {
453	.uc_drv		= DM_UCLASS_DRIVER_REF(i2c),
454	.sibling_node	= {
455		.prev = &uclass_head,
456		.next = &DM_UCLASS_REF(misc)->sibling_node,
457	},
458	.dev_head	= {
459		.prev = &DM_DEVICE_REF(i2c)->uclass_node,
460		.next = &DM_DEVICE_REF(i2c)->uclass_node,
461	},
462};
463
464DM_UCLASS_INST(misc) = {
465	.uc_drv		= DM_UCLASS_DRIVER_REF(misc),
466	.sibling_node	= {
467		.prev = &DM_UCLASS_REF(i2c)->sibling_node,
468		.next = &DM_UCLASS_REF(root)->sibling_node,
469	},
470	.dev_head	= {
471		.prev = &DM_DEVICE_REF(spl_test3)->uclass_node,
472		.next = &DM_DEVICE_REF(spl_test)->uclass_node,
473	},
474};
475
476DM_UCLASS_INST(root) = {
477	.uc_drv		= DM_UCLASS_DRIVER_REF(root),
478	.sibling_node	= {
479		.prev = &DM_UCLASS_REF(misc)->sibling_node,
480		.next = &DM_UCLASS_REF(testbus)->sibling_node,
481	},
482	.dev_head	= {
483		.prev = &DM_DEVICE_REF(root)->uclass_node,
484		.next = &DM_DEVICE_REF(root)->uclass_node,
485	},
486};
487
488DM_UCLASS_INST(testbus) = {
489	.uc_drv		= DM_UCLASS_DRIVER_REF(testbus),
490	.sibling_node	= {
491		.prev = &DM_UCLASS_REF(root)->sibling_node,
492		.next = &DM_UCLASS_REF(testfdt)->sibling_node,
493	},
494	.dev_head	= {
495		.prev = &DM_DEVICE_REF(some_bus)->uclass_node,
496		.next = &DM_DEVICE_REF(some_bus)->uclass_node,
497	},
498};
499
500#include <dm/test.h>
501u8 _testfdt_priv_[sizeof(struct dm_test_uc_priv)]
502	__attribute__ ((section (".priv_data")));
503DM_UCLASS_INST(testfdt) = {
504	.priv_		= _testfdt_priv_,
505	.uc_drv		= DM_UCLASS_DRIVER_REF(testfdt),
506	.sibling_node	= {
507		.prev = &DM_UCLASS_REF(testbus)->sibling_node,
508		.next = &uclass_head,
509	},
510	.dev_head	= {
511		.prev = &DM_DEVICE_REF(test0)->uclass_node,
512		.next = &DM_DEVICE_REF(test)->uclass_node,
513	},
514};
515
516'''
517    device_text_inst = '''/*
518 * DO NOT MODIFY
519 *
520 * Declares the DM_DEVICE_INST() records.
521 * This was generated by dtoc from a .dtb (device tree binary) file.
522 */
523
524#include <common.h>
525#include <dm.h>
526#include <dt-structs.h>
527
528/*
529 * udevice declarations, ordered by 'struct udevice' linker_list position:
530 *
531 * idx  udevice              driver
532 * ---  -------------------- --------------------
533 *   0: i2c                  sandbox_i2c
534 *   1: root                 root_driver
535 *   2: some_bus             denx_u_boot_test_bus
536 *   3: spl_test             sandbox_spl_test
537 *   4: spl_test3            sandbox_spl_test
538 *   5: test                 denx_u_boot_fdt_test
539 *   6: test0                denx_u_boot_fdt_test
540 * ---  -------------------- --------------------
541 */
542
543/*
544 * Node /i2c index 0
545 * driver sandbox_i2c parent root_driver
546*/
547static struct dtd_sandbox_i2c dtv_i2c = {
548\t.intval\t\t\t= 0x3,
549};
550
551#include <asm/i2c.h>
552u8 _sandbox_i2c_priv_i2c[sizeof(struct sandbox_i2c_priv)]
553\t__attribute__ ((section (".priv_data")));
554#include <i2c.h>
555u8 _sandbox_i2c_uc_priv_i2c[sizeof(struct dm_i2c_bus)]
556\t__attribute__ ((section (".priv_data")));
557
558DM_DEVICE_INST(i2c) = {
559\t.driver\t\t= DM_DRIVER_REF(sandbox_i2c),
560\t.name\t\t= "sandbox_i2c",
561\t.plat_\t\t= &dtv_i2c,
562\t.priv_\t\t= _sandbox_i2c_priv_i2c,
563\t.uclass\t\t= DM_UCLASS_REF(i2c),
564\t.uclass_priv_ = _sandbox_i2c_uc_priv_i2c,
565\t.uclass_node\t= {
566\t\t.prev = &DM_UCLASS_REF(i2c)->dev_head,
567\t\t.next = &DM_UCLASS_REF(i2c)->dev_head,
568\t},
569\t.child_head\t= {
570\t\t.prev = &DM_DEVICE_REF(i2c)->child_head,
571\t\t.next = &DM_DEVICE_REF(i2c)->child_head,
572\t},
573\t.sibling_node\t= {
574\t\t.prev = &DM_DEVICE_REF(root)->child_head,
575\t\t.next = &DM_DEVICE_REF(some_bus)->sibling_node,
576\t},
577\t.seq_ = 4,
578};
579
580/*
581 * Node / index 1
582 * driver root_driver parent None
583*/
584static struct dtd_root_driver dtv_root = {
585};
586
587DM_DEVICE_INST(root) = {
588\t.driver\t\t= DM_DRIVER_REF(root_driver),
589\t.name\t\t= "root_driver",
590\t.plat_\t\t= &dtv_root,
591\t.uclass\t\t= DM_UCLASS_REF(root),
592\t.uclass_node\t= {
593\t\t.prev = &DM_UCLASS_REF(root)->dev_head,
594\t\t.next = &DM_UCLASS_REF(root)->dev_head,
595\t},
596\t.child_head\t= {
597\t\t.prev = &DM_DEVICE_REF(spl_test3)->sibling_node,
598\t\t.next = &DM_DEVICE_REF(i2c)->sibling_node,
599\t},
600\t.seq_ = 0,
601};
602
603/*
604 * Node /some-bus index 2
605 * driver denx_u_boot_test_bus parent root_driver
606*/
607
608#include <dm/test.h>
609struct dm_test_pdata __attribute__ ((section (".priv_data")))
610\t_denx_u_boot_test_bus_plat_some_bus = {
611\t.dtplat = {
612\t\t.ping_add\t\t= 0x4,
613\t\t.ping_expect\t\t= 0x4,
614\t\t.reg\t\t\t= {0x3, 0x1},
615\t},
616};
617#include <dm/test.h>
618u8 _denx_u_boot_test_bus_priv_some_bus[sizeof(struct dm_test_priv)]
619\t__attribute__ ((section (".priv_data")));
620#include <dm/test.h>
621u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_plat)]
622\t__attribute__ ((section (".priv_data")));
623#include <dm/test.h>
624u8 _denx_u_boot_test_bus_uc_priv_some_bus[sizeof(struct dm_test_uclass_priv)]
625	__attribute__ ((section (".priv_data")));
626#include <test.h>
627
628DM_DEVICE_INST(some_bus) = {
629\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_test_bus),
630\t.name\t\t= "denx_u_boot_test_bus",
631\t.plat_\t\t= &_denx_u_boot_test_bus_plat_some_bus,
632\t.uclass_plat_\t= _denx_u_boot_test_bus_ucplat_some_bus,
633\t.driver_data\t= DM_TEST_TYPE_FIRST,
634\t.priv_\t\t= _denx_u_boot_test_bus_priv_some_bus,
635\t.uclass\t\t= DM_UCLASS_REF(testbus),
636\t.uclass_priv_ = _denx_u_boot_test_bus_uc_priv_some_bus,
637\t.uclass_node\t= {
638\t\t.prev = &DM_UCLASS_REF(testbus)->dev_head,
639\t\t.next = &DM_UCLASS_REF(testbus)->dev_head,
640\t},
641\t.child_head\t= {
642\t\t.prev = &DM_DEVICE_REF(test0)->sibling_node,
643\t\t.next = &DM_DEVICE_REF(test)->sibling_node,
644\t},
645\t.sibling_node\t= {
646\t\t.prev = &DM_DEVICE_REF(i2c)->sibling_node,
647\t\t.next = &DM_DEVICE_REF(spl_test)->sibling_node,
648\t},
649\t.seq_ = 2,
650};
651
652/*
653 * Node /spl-test index 3
654 * driver sandbox_spl_test parent root_driver
655*/
656static struct dtd_sandbox_spl_test dtv_spl_test = {
657\t.boolval\t\t= true,
658\t.intval\t\t\t= 0x1,
659};
660
661DM_DEVICE_INST(spl_test) = {
662\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
663\t.name\t\t= "sandbox_spl_test",
664\t.plat_\t\t= &dtv_spl_test,
665\t.uclass\t\t= DM_UCLASS_REF(misc),
666\t.uclass_node\t= {
667\t\t.prev = &DM_UCLASS_REF(misc)->dev_head,
668\t\t.next = &DM_DEVICE_REF(spl_test3)->uclass_node,
669\t},
670\t.child_head\t= {
671\t\t.prev = &DM_DEVICE_REF(spl_test)->child_head,
672\t\t.next = &DM_DEVICE_REF(spl_test)->child_head,
673\t},
674\t.sibling_node\t= {
675\t\t.prev = &DM_DEVICE_REF(some_bus)->sibling_node,
676\t\t.next = &DM_DEVICE_REF(spl_test3)->sibling_node,
677\t},
678\t.seq_ = 0,
679};
680
681/*
682 * Node /spl-test3 index 4
683 * driver sandbox_spl_test parent root_driver
684*/
685static struct dtd_sandbox_spl_test dtv_spl_test3 = {
686\t.longbytearray\t\t= {0x90a0b0c, 0xd0e0f10},
687\t.stringarray\t\t= "one",
688};
689
690DM_DEVICE_INST(spl_test3) = {
691\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
692\t.name\t\t= "sandbox_spl_test",
693\t.plat_\t\t= &dtv_spl_test3,
694\t.uclass\t\t= DM_UCLASS_REF(misc),
695\t.uclass_node\t= {
696\t\t.prev = &DM_DEVICE_REF(spl_test)->uclass_node,
697\t\t.next = &DM_UCLASS_REF(misc)->dev_head,
698\t},
699\t.child_head\t= {
700\t\t.prev = &DM_DEVICE_REF(spl_test3)->child_head,
701\t\t.next = &DM_DEVICE_REF(spl_test3)->child_head,
702\t},
703\t.sibling_node\t= {
704\t\t.prev = &DM_DEVICE_REF(spl_test)->sibling_node,
705\t\t.next = &DM_DEVICE_REF(root)->child_head,
706\t},
707\t.seq_ = 1,
708};
709
710/*
711 * Node /some-bus/test index 5
712 * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
713*/
714
715#include <dm/test.h>
716struct dm_test_pdata __attribute__ ((section (".priv_data")))
717\t_denx_u_boot_fdt_test_plat_test = {
718\t.dtplat = {
719\t\t.ping_add\t\t= 0x5,
720\t\t.ping_expect\t\t= 0x5,
721\t\t.reg\t\t\t= {0x5},
722\t},
723};
724#include <dm/test.h>
725u8 _denx_u_boot_fdt_test_priv_test[sizeof(struct dm_test_priv)]
726\t__attribute__ ((section (".priv_data")));
727#include <dm/test.h>
728u8 _denx_u_boot_fdt_test_parent_plat_test[sizeof(struct dm_test_parent_plat)]
729\t__attribute__ ((section (".priv_data")));
730#include <dm/test.h>
731u8 _denx_u_boot_fdt_test_parent_priv_test[sizeof(struct dm_test_parent_data)]
732\t__attribute__ ((section (".priv_data")));
733
734DM_DEVICE_INST(test) = {
735\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
736\t.name\t\t= "denx_u_boot_fdt_test",
737\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test,
738\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test,
739\t.driver_data\t= DM_TEST_TYPE_FIRST,
740\t.parent\t\t= DM_DEVICE_REF(some_bus),
741\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test,
742\t.uclass\t\t= DM_UCLASS_REF(testfdt),
743\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test,
744\t.uclass_node\t= {
745\t\t.prev = &DM_UCLASS_REF(testfdt)->dev_head,
746\t\t.next = &DM_DEVICE_REF(test0)->uclass_node,
747\t},
748\t.child_head\t= {
749\t\t.prev = &DM_DEVICE_REF(test)->child_head,
750\t\t.next = &DM_DEVICE_REF(test)->child_head,
751\t},
752\t.sibling_node\t= {
753\t\t.prev = &DM_DEVICE_REF(some_bus)->child_head,
754\t\t.next = &DM_DEVICE_REF(test0)->sibling_node,
755\t},
756\t.seq_ = 1,
757};
758
759/*
760 * Node /some-bus/test0 index 6
761 * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
762*/
763
764#include <dm/test.h>
765struct dm_test_pdata __attribute__ ((section (".priv_data")))
766\t_denx_u_boot_fdt_test_plat_test0 = {
767\t.dtplat = {
768\t},
769};
770#include <dm/test.h>
771u8 _denx_u_boot_fdt_test_priv_test0[sizeof(struct dm_test_priv)]
772\t__attribute__ ((section (".priv_data")));
773#include <dm/test.h>
774u8 _denx_u_boot_fdt_test_parent_plat_test0[sizeof(struct dm_test_parent_plat)]
775\t__attribute__ ((section (".priv_data")));
776#include <dm/test.h>
777u8 _denx_u_boot_fdt_test_parent_priv_test0[sizeof(struct dm_test_parent_data)]
778\t__attribute__ ((section (".priv_data")));
779
780DM_DEVICE_INST(test0) = {
781\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
782\t.name\t\t= "denx_u_boot_fdt_test",
783\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test0,
784\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test0,
785\t.driver_data\t= DM_TEST_TYPE_SECOND,
786\t.parent\t\t= DM_DEVICE_REF(some_bus),
787\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test0,
788\t.uclass\t\t= DM_UCLASS_REF(testfdt),
789\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test0,
790\t.uclass_node\t= {
791\t\t.prev = &DM_DEVICE_REF(test)->uclass_node,
792\t\t.next = &DM_UCLASS_REF(testfdt)->dev_head,
793\t},
794\t.child_head\t= {
795\t\t.prev = &DM_DEVICE_REF(test0)->child_head,
796\t\t.next = &DM_DEVICE_REF(test0)->child_head,
797\t},
798\t.sibling_node\t= {
799\t\t.prev = &DM_DEVICE_REF(test)->sibling_node,
800\t\t.next = &DM_DEVICE_REF(some_bus)->child_head,
801\t},
802\t.seq_ = 2,
803};
804
805'''
806
807    def test_simple(self):
808        """Test output from some simple nodes with various types of data"""
809        dtb_file = get_dtb_file('dtoc_test_simple.dts')
810        output = tools.get_output_filename('output')
811        self.run_test(['struct'], dtb_file, output)
812        with open(output) as infile:
813            data = infile.read()
814
815        self._check_strings(self.struct_text, data)
816
817        self.run_test(['platdata'], dtb_file, output)
818        with open(output) as infile:
819            data = infile.read()
820
821        self._check_strings(self.platdata_text, data)
822
823        self.run_test(['decl'], dtb_file, output)
824        with open(output) as infile:
825            data = infile.read()
826
827        self._check_strings(self.decl_text, data)
828
829        # Try the 'all' command
830        self.run_test(['all'], dtb_file, output)
831        data = tools.read_file(output, binary=False)
832        self._check_strings(
833            self.decl_text + self.platdata_text + self.struct_text, data)
834
835    def test_driver_alias(self):
836        """Test output from a device tree file with a driver alias"""
837        dtb_file = get_dtb_file('dtoc_test_driver_alias.dts')
838        output = tools.get_output_filename('output')
839        self.run_test(['struct'], dtb_file, output)
840        with open(output) as infile:
841            data = infile.read()
842        self._check_strings(HEADER + '''
843struct dtd_sandbox_gpio {
844\tconst char *\tgpio_bank_name;
845\tbool\t\tgpio_controller;
846\tfdt32_t\t\tsandbox_gpio_count;
847};
848''', data)
849
850        self.run_test(['platdata'], dtb_file, output)
851        with open(output) as infile:
852            data = infile.read()
853        self._check_strings(C_HEADER + '''
854/*
855 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
856 *
857 * idx  driver_info          driver
858 * ---  -------------------- --------------------
859 *   0: gpios_at_0           sandbox_gpio
860 * ---  -------------------- --------------------
861 */
862
863/*
864 * Node /gpios@0 index 0
865 * driver sandbox_gpio parent None
866 */
867static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
868\t.gpio_bank_name\t\t= "a",
869\t.gpio_controller\t= true,
870\t.sandbox_gpio_count\t= 0x14,
871};
872U_BOOT_DRVINFO(gpios_at_0) = {
873\t.name\t\t= "sandbox_gpio",
874\t.plat\t\t= &dtv_gpios_at_0,
875\t.plat_size\t= sizeof(dtv_gpios_at_0),
876\t.parent_idx\t= -1,
877};
878
879''', data)
880
881    def test_invalid_driver(self):
882        """Test output from a device tree file with an invalid driver"""
883        dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts')
884        output = tools.get_output_filename('output')
885        with test_util.capture_sys_output() as _:
886            dtb_platdata.run_steps(
887                ['struct'], dtb_file, False, output, [], None, False,
888                scan=copy_scan())
889        with open(output) as infile:
890            data = infile.read()
891        self._check_strings(HEADER + '''
892struct dtd_invalid {
893};
894''', data)
895
896        with test_util.capture_sys_output() as _:
897            dtb_platdata.run_steps(
898                ['platdata'], dtb_file, False, output, [], None, False,
899                scan=copy_scan())
900        with open(output) as infile:
901            data = infile.read()
902        self._check_strings(C_HEADER + '''
903/*
904 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
905 *
906 * idx  driver_info          driver
907 * ---  -------------------- --------------------
908 *   0: spl_test             invalid
909 * ---  -------------------- --------------------
910 */
911
912/* Node /spl-test index 0 */
913static struct dtd_invalid dtv_spl_test = {
914};
915U_BOOT_DRVINFO(spl_test) = {
916\t.name\t\t= "invalid",
917\t.plat\t\t= &dtv_spl_test,
918\t.plat_size\t= sizeof(dtv_spl_test),
919\t.parent_idx\t= -1,
920};
921
922''', data)
923
924    def test_phandle(self):
925        """Test output from a node containing a phandle reference"""
926        dtb_file = get_dtb_file('dtoc_test_phandle.dts')
927        output = tools.get_output_filename('output')
928        self.run_test(['struct'], dtb_file, output)
929        with open(output) as infile:
930            data = infile.read()
931        self._check_strings(HEADER + '''
932struct dtd_source {
933\tstruct phandle_2_arg clocks[4];
934\tunsigned char	phandle_name_offset[13];
935};
936struct dtd_target {
937\tfdt32_t\t\tintval;
938};
939''', data)
940
941        self.run_test(['platdata'], dtb_file, output)
942        with open(output) as infile:
943            data = infile.read()
944        self._check_strings(C_HEADER + '''
945/*
946 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
947 *
948 * idx  driver_info          driver
949 * ---  -------------------- --------------------
950 *   0: phandle2_target      target
951 *   1: phandle3_target      target
952 *   2: phandle_source       source
953 *   3: phandle_source2      source
954 *   4: phandle_target       target
955 * ---  -------------------- --------------------
956 */
957
958/* Node /phandle2-target index 0 */
959static struct dtd_target dtv_phandle2_target = {
960\t.intval\t\t\t= 0x1,
961};
962U_BOOT_DRVINFO(phandle2_target) = {
963\t.name\t\t= "target",
964\t.plat\t\t= &dtv_phandle2_target,
965\t.plat_size\t= sizeof(dtv_phandle2_target),
966\t.parent_idx\t= -1,
967};
968
969/* Node /phandle3-target index 1 */
970static struct dtd_target dtv_phandle3_target = {
971\t.intval\t\t\t= 0x2,
972};
973U_BOOT_DRVINFO(phandle3_target) = {
974\t.name\t\t= "target",
975\t.plat\t\t= &dtv_phandle3_target,
976\t.plat_size\t= sizeof(dtv_phandle3_target),
977\t.parent_idx\t= -1,
978};
979
980/* Node /phandle-source index 2 */
981static struct dtd_source dtv_phandle_source = {
982\t.clocks\t\t\t= {
983\t\t\t{4, {}},
984\t\t\t{0, {11}},
985\t\t\t{1, {12, 13}},
986\t\t\t{4, {}},},
987\t.phandle_name_offset	= {0x0, 0x0, 0x0, 0x3, 0x66, 0x72, 0x65, 0x64,
988\t\t0x0, 0x0, 0x0, 0x0, 0x7b},
989};
990U_BOOT_DRVINFO(phandle_source) = {
991\t.name\t\t= "source",
992\t.plat\t\t= &dtv_phandle_source,
993\t.plat_size\t= sizeof(dtv_phandle_source),
994\t.parent_idx\t= -1,
995};
996
997/* Node /phandle-source2 index 3 */
998static struct dtd_source dtv_phandle_source2 = {
999\t.clocks\t\t\t= {
1000\t\t\t{4, {}},},
1001};
1002U_BOOT_DRVINFO(phandle_source2) = {
1003\t.name\t\t= "source",
1004\t.plat\t\t= &dtv_phandle_source2,
1005\t.plat_size\t= sizeof(dtv_phandle_source2),
1006\t.parent_idx\t= -1,
1007};
1008
1009/* Node /phandle-target index 4 */
1010static struct dtd_target dtv_phandle_target = {
1011\t.intval\t\t\t= 0x0,
1012};
1013U_BOOT_DRVINFO(phandle_target) = {
1014\t.name\t\t= "target",
1015\t.plat\t\t= &dtv_phandle_target,
1016\t.plat_size\t= sizeof(dtv_phandle_target),
1017\t.parent_idx\t= -1,
1018};
1019
1020''', data)
1021
1022    def test_phandle_single(self):
1023        """Test output from a node containing a phandle reference"""
1024        dtb_file = get_dtb_file('dtoc_test_phandle_single.dts')
1025        output = tools.get_output_filename('output')
1026        self.run_test(['struct'], dtb_file, output)
1027        with open(output) as infile:
1028            data = infile.read()
1029        self._check_strings(HEADER + '''
1030struct dtd_source {
1031\tstruct phandle_0_arg clocks[1];
1032};
1033struct dtd_target {
1034\tfdt32_t\t\tintval;
1035};
1036''', data)
1037
1038    def test_phandle_reorder(self):
1039        """Test that phandle targets are generated before their references"""
1040        dtb_file = get_dtb_file('dtoc_test_phandle_reorder.dts')
1041        output = tools.get_output_filename('output')
1042        self.run_test(['platdata'], dtb_file, output)
1043        with open(output) as infile:
1044            data = infile.read()
1045        self._check_strings(C_HEADER + '''
1046/*
1047 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1048 *
1049 * idx  driver_info          driver
1050 * ---  -------------------- --------------------
1051 *   0: phandle_source2      source
1052 *   1: phandle_target       target
1053 * ---  -------------------- --------------------
1054 */
1055
1056/* Node /phandle-source2 index 0 */
1057static struct dtd_source dtv_phandle_source2 = {
1058\t.clocks\t\t\t= {
1059\t\t\t{1, {}},},
1060};
1061U_BOOT_DRVINFO(phandle_source2) = {
1062\t.name\t\t= "source",
1063\t.plat\t\t= &dtv_phandle_source2,
1064\t.plat_size\t= sizeof(dtv_phandle_source2),
1065\t.parent_idx\t= -1,
1066};
1067
1068/* Node /phandle-target index 1 */
1069static struct dtd_target dtv_phandle_target = {
1070};
1071U_BOOT_DRVINFO(phandle_target) = {
1072\t.name\t\t= "target",
1073\t.plat\t\t= &dtv_phandle_target,
1074\t.plat_size\t= sizeof(dtv_phandle_target),
1075\t.parent_idx\t= -1,
1076};
1077
1078''', data)
1079
1080    def test_phandle_cd_gpio(self):
1081        """Test that phandle targets are generated when unsing cd-gpios"""
1082        dtb_file = get_dtb_file('dtoc_test_phandle_cd_gpios.dts')
1083        output = tools.get_output_filename('output')
1084        dtb_platdata.run_steps(
1085            ['platdata'], dtb_file, False, output, [], None, False,
1086            warning_disabled=True, scan=copy_scan())
1087        with open(output) as infile:
1088            data = infile.read()
1089        self._check_strings(C_HEADER + '''
1090/*
1091 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1092 *
1093 * idx  driver_info          driver
1094 * ---  -------------------- --------------------
1095 *   0: phandle2_target      target
1096 *   1: phandle3_target      target
1097 *   2: phandle_source       source
1098 *   3: phandle_source2      source
1099 *   4: phandle_target       target
1100 * ---  -------------------- --------------------
1101 */
1102
1103/* Node /phandle2-target index 0 */
1104static struct dtd_target dtv_phandle2_target = {
1105\t.intval\t\t\t= 0x1,
1106};
1107U_BOOT_DRVINFO(phandle2_target) = {
1108\t.name\t\t= "target",
1109\t.plat\t\t= &dtv_phandle2_target,
1110\t.plat_size\t= sizeof(dtv_phandle2_target),
1111\t.parent_idx\t= -1,
1112};
1113
1114/* Node /phandle3-target index 1 */
1115static struct dtd_target dtv_phandle3_target = {
1116\t.intval\t\t\t= 0x2,
1117};
1118U_BOOT_DRVINFO(phandle3_target) = {
1119\t.name\t\t= "target",
1120\t.plat\t\t= &dtv_phandle3_target,
1121\t.plat_size\t= sizeof(dtv_phandle3_target),
1122\t.parent_idx\t= -1,
1123};
1124
1125/* Node /phandle-source index 2 */
1126static struct dtd_source dtv_phandle_source = {
1127\t.cd_gpios\t\t= {
1128\t\t\t{4, {}},
1129\t\t\t{0, {11}},
1130\t\t\t{1, {12, 13}},
1131\t\t\t{4, {}},},
1132};
1133U_BOOT_DRVINFO(phandle_source) = {
1134\t.name\t\t= "source",
1135\t.plat\t\t= &dtv_phandle_source,
1136\t.plat_size\t= sizeof(dtv_phandle_source),
1137\t.parent_idx\t= -1,
1138};
1139
1140/* Node /phandle-source2 index 3 */
1141static struct dtd_source dtv_phandle_source2 = {
1142\t.cd_gpios\t\t= {
1143\t\t\t{4, {}},},
1144};
1145U_BOOT_DRVINFO(phandle_source2) = {
1146\t.name\t\t= "source",
1147\t.plat\t\t= &dtv_phandle_source2,
1148\t.plat_size\t= sizeof(dtv_phandle_source2),
1149\t.parent_idx\t= -1,
1150};
1151
1152/* Node /phandle-target index 4 */
1153static struct dtd_target dtv_phandle_target = {
1154\t.intval\t\t\t= 0x0,
1155};
1156U_BOOT_DRVINFO(phandle_target) = {
1157\t.name\t\t= "target",
1158\t.plat\t\t= &dtv_phandle_target,
1159\t.plat_size\t= sizeof(dtv_phandle_target),
1160\t.parent_idx\t= -1,
1161};
1162
1163''', data)
1164
1165    def test_phandle_bad(self):
1166        """Test a node containing an invalid phandle fails"""
1167        dtb_file = get_dtb_file('dtoc_test_phandle_bad.dts',
1168                                capture_stderr=True)
1169        output = tools.get_output_filename('output')
1170        with self.assertRaises(ValueError) as exc:
1171            self.run_test(['struct'], dtb_file, output)
1172        self.assertIn("Cannot parse 'clocks' in node 'phandle-source'",
1173                      str(exc.exception))
1174
1175    def test_phandle_bad2(self):
1176        """Test a phandle target missing its #*-cells property"""
1177        dtb_file = get_dtb_file('dtoc_test_phandle_bad2.dts',
1178                                capture_stderr=True)
1179        output = tools.get_output_filename('output')
1180        with self.assertRaises(ValueError) as exc:
1181            self.run_test(['struct'], dtb_file, output)
1182        self.assertIn("Node 'phandle-target' has no cells property",
1183                      str(exc.exception))
1184
1185    def test_addresses64(self):
1186        """Test output from a node with a 'reg' property with na=2, ns=2"""
1187        dtb_file = get_dtb_file('dtoc_test_addr64.dts')
1188        output = tools.get_output_filename('output')
1189        self.run_test(['struct'], dtb_file, output)
1190        with open(output) as infile:
1191            data = infile.read()
1192        self._check_strings(HEADER + '''
1193struct dtd_test1 {
1194\tfdt64_t\t\treg[2];
1195};
1196struct dtd_test2 {
1197\tfdt64_t\t\treg[2];
1198};
1199struct dtd_test3 {
1200\tfdt64_t\t\treg[4];
1201};
1202''', data)
1203
1204        self.run_test(['platdata'], dtb_file, output)
1205        with open(output) as infile:
1206            data = infile.read()
1207        self._check_strings(C_HEADER + '''
1208/*
1209 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1210 *
1211 * idx  driver_info          driver
1212 * ---  -------------------- --------------------
1213 *   0: test1                test1
1214 *   1: test2                test2
1215 *   2: test3                test3
1216 * ---  -------------------- --------------------
1217 */
1218
1219/* Node /test1 index 0 */
1220static struct dtd_test1 dtv_test1 = {
1221\t.reg\t\t\t= {0x1234, 0x5678},
1222};
1223U_BOOT_DRVINFO(test1) = {
1224\t.name\t\t= "test1",
1225\t.plat\t\t= &dtv_test1,
1226\t.plat_size\t= sizeof(dtv_test1),
1227\t.parent_idx\t= -1,
1228};
1229
1230/* Node /test2 index 1 */
1231static struct dtd_test2 dtv_test2 = {
1232\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
1233};
1234U_BOOT_DRVINFO(test2) = {
1235\t.name\t\t= "test2",
1236\t.plat\t\t= &dtv_test2,
1237\t.plat_size\t= sizeof(dtv_test2),
1238\t.parent_idx\t= -1,
1239};
1240
1241/* Node /test3 index 2 */
1242static struct dtd_test3 dtv_test3 = {
1243\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
1244};
1245U_BOOT_DRVINFO(test3) = {
1246\t.name\t\t= "test3",
1247\t.plat\t\t= &dtv_test3,
1248\t.plat_size\t= sizeof(dtv_test3),
1249\t.parent_idx\t= -1,
1250};
1251
1252''', data)
1253
1254    def test_addresses32(self):
1255        """Test output from a node with a 'reg' property with na=1, ns=1"""
1256        dtb_file = get_dtb_file('dtoc_test_addr32.dts')
1257        output = tools.get_output_filename('output')
1258        self.run_test(['struct'], dtb_file, output)
1259        with open(output) as infile:
1260            data = infile.read()
1261        self._check_strings(HEADER + '''
1262struct dtd_test1 {
1263\tfdt32_t\t\treg[2];
1264};
1265struct dtd_test2 {
1266\tfdt32_t\t\treg[4];
1267};
1268''', data)
1269
1270        self.run_test(['platdata'], dtb_file, output)
1271        with open(output) as infile:
1272            data = infile.read()
1273        self._check_strings(C_HEADER + '''
1274/*
1275 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1276 *
1277 * idx  driver_info          driver
1278 * ---  -------------------- --------------------
1279 *   0: test1                test1
1280 *   1: test2                test2
1281 * ---  -------------------- --------------------
1282 */
1283
1284/* Node /test1 index 0 */
1285static struct dtd_test1 dtv_test1 = {
1286\t.reg\t\t\t= {0x1234, 0x5678},
1287};
1288U_BOOT_DRVINFO(test1) = {
1289\t.name\t\t= "test1",
1290\t.plat\t\t= &dtv_test1,
1291\t.plat_size\t= sizeof(dtv_test1),
1292\t.parent_idx\t= -1,
1293};
1294
1295/* Node /test2 index 1 */
1296static struct dtd_test2 dtv_test2 = {
1297\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
1298};
1299U_BOOT_DRVINFO(test2) = {
1300\t.name\t\t= "test2",
1301\t.plat\t\t= &dtv_test2,
1302\t.plat_size\t= sizeof(dtv_test2),
1303\t.parent_idx\t= -1,
1304};
1305
1306''', data)
1307
1308    def test_addresses64_32(self):
1309        """Test output from a node with a 'reg' property with na=2, ns=1"""
1310        dtb_file = get_dtb_file('dtoc_test_addr64_32.dts')
1311        output = tools.get_output_filename('output')
1312        self.run_test(['struct'], dtb_file, output)
1313        with open(output) as infile:
1314            data = infile.read()
1315        self._check_strings(HEADER + '''
1316struct dtd_test1 {
1317\tfdt64_t\t\treg[2];
1318};
1319struct dtd_test2 {
1320\tfdt64_t\t\treg[2];
1321};
1322struct dtd_test3 {
1323\tfdt64_t\t\treg[4];
1324};
1325''', data)
1326
1327        self.run_test(['platdata'], dtb_file, output)
1328        with open(output) as infile:
1329            data = infile.read()
1330        self._check_strings(C_HEADER + '''
1331/*
1332 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1333 *
1334 * idx  driver_info          driver
1335 * ---  -------------------- --------------------
1336 *   0: test1                test1
1337 *   1: test2                test2
1338 *   2: test3                test3
1339 * ---  -------------------- --------------------
1340 */
1341
1342/* Node /test1 index 0 */
1343static struct dtd_test1 dtv_test1 = {
1344\t.reg\t\t\t= {0x123400000000, 0x5678},
1345};
1346U_BOOT_DRVINFO(test1) = {
1347\t.name\t\t= "test1",
1348\t.plat\t\t= &dtv_test1,
1349\t.plat_size\t= sizeof(dtv_test1),
1350\t.parent_idx\t= -1,
1351};
1352
1353/* Node /test2 index 1 */
1354static struct dtd_test2 dtv_test2 = {
1355\t.reg\t\t\t= {0x1234567890123456, 0x98765432},
1356};
1357U_BOOT_DRVINFO(test2) = {
1358\t.name\t\t= "test2",
1359\t.plat\t\t= &dtv_test2,
1360\t.plat_size\t= sizeof(dtv_test2),
1361\t.parent_idx\t= -1,
1362};
1363
1364/* Node /test3 index 2 */
1365static struct dtd_test3 dtv_test3 = {
1366\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
1367};
1368U_BOOT_DRVINFO(test3) = {
1369\t.name\t\t= "test3",
1370\t.plat\t\t= &dtv_test3,
1371\t.plat_size\t= sizeof(dtv_test3),
1372\t.parent_idx\t= -1,
1373};
1374
1375''', data)
1376
1377    def test_addresses32_64(self):
1378        """Test output from a node with a 'reg' property with na=1, ns=2"""
1379        dtb_file = get_dtb_file('dtoc_test_addr32_64.dts')
1380        output = tools.get_output_filename('output')
1381        self.run_test(['struct'], dtb_file, output)
1382        with open(output) as infile:
1383            data = infile.read()
1384        self._check_strings(HEADER + '''
1385struct dtd_test1 {
1386\tfdt64_t\t\treg[2];
1387};
1388struct dtd_test2 {
1389\tfdt64_t\t\treg[2];
1390};
1391struct dtd_test3 {
1392\tfdt64_t\t\treg[4];
1393};
1394''', data)
1395
1396        self.run_test(['platdata'], dtb_file, output)
1397        with open(output) as infile:
1398            data = infile.read()
1399        self._check_strings(C_HEADER + '''
1400/*
1401 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1402 *
1403 * idx  driver_info          driver
1404 * ---  -------------------- --------------------
1405 *   0: test1                test1
1406 *   1: test2                test2
1407 *   2: test3                test3
1408 * ---  -------------------- --------------------
1409 */
1410
1411/* Node /test1 index 0 */
1412static struct dtd_test1 dtv_test1 = {
1413\t.reg\t\t\t= {0x1234, 0x567800000000},
1414};
1415U_BOOT_DRVINFO(test1) = {
1416\t.name\t\t= "test1",
1417\t.plat\t\t= &dtv_test1,
1418\t.plat_size\t= sizeof(dtv_test1),
1419\t.parent_idx\t= -1,
1420};
1421
1422/* Node /test2 index 1 */
1423static struct dtd_test2 dtv_test2 = {
1424\t.reg\t\t\t= {0x12345678, 0x9876543210987654},
1425};
1426U_BOOT_DRVINFO(test2) = {
1427\t.name\t\t= "test2",
1428\t.plat\t\t= &dtv_test2,
1429\t.plat_size\t= sizeof(dtv_test2),
1430\t.parent_idx\t= -1,
1431};
1432
1433/* Node /test3 index 2 */
1434static struct dtd_test3 dtv_test3 = {
1435\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
1436};
1437U_BOOT_DRVINFO(test3) = {
1438\t.name\t\t= "test3",
1439\t.plat\t\t= &dtv_test3,
1440\t.plat_size\t= sizeof(dtv_test3),
1441\t.parent_idx\t= -1,
1442};
1443
1444''', data)
1445
1446    def test_bad_reg(self):
1447        """Test that a reg property with an invalid type generates an error"""
1448        # Capture stderr since dtc will emit warnings for this file
1449        dtb_file = get_dtb_file('dtoc_test_bad_reg.dts', capture_stderr=True)
1450        output = tools.get_output_filename('output')
1451        with self.assertRaises(ValueError) as exc:
1452            self.run_test(['struct'], dtb_file, output)
1453        self.assertIn("Node 'spl-test' reg property is not an int",
1454                      str(exc.exception))
1455
1456    def test_bad_reg2(self):
1457        """Test that a reg property with an invalid cell count is detected"""
1458        # Capture stderr since dtc will emit warnings for this file
1459        dtb_file = get_dtb_file('dtoc_test_bad_reg2.dts', capture_stderr=True)
1460        output = tools.get_output_filename('output')
1461        with self.assertRaises(ValueError) as exc:
1462            self.run_test(['struct'], dtb_file, output)
1463        self.assertIn(
1464            "Node 'spl-test' (parent '/') reg property has 3 cells which is not a multiple of na + ns = 1 + 1)",
1465            str(exc.exception))
1466
1467    def test_add_prop(self):
1468        """Test that a subequent node can add a new property to a struct"""
1469        dtb_file = get_dtb_file('dtoc_test_add_prop.dts')
1470        output = tools.get_output_filename('output')
1471        self.run_test(['struct'], dtb_file, output)
1472        with open(output) as infile:
1473            data = infile.read()
1474        self._check_strings(HEADER + '''
1475struct dtd_sandbox_spl_test {
1476\tfdt32_t\t\tintarray;
1477\tfdt32_t\t\tintval;
1478};
1479''', data)
1480
1481        self.run_test(['platdata'], dtb_file, output)
1482        with open(output) as infile:
1483            data = infile.read()
1484        self._check_strings(C_HEADER + '''
1485/*
1486 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1487 *
1488 * idx  driver_info          driver
1489 * ---  -------------------- --------------------
1490 *   0: spl_test             sandbox_spl_test
1491 *   1: spl_test2            sandbox_spl_test
1492 * ---  -------------------- --------------------
1493 */
1494
1495/*
1496 * Node /spl-test index 0
1497 * driver sandbox_spl_test parent None
1498 */
1499static struct dtd_sandbox_spl_test dtv_spl_test = {
1500\t.intval\t\t\t= 0x1,
1501};
1502U_BOOT_DRVINFO(spl_test) = {
1503\t.name\t\t= "sandbox_spl_test",
1504\t.plat\t\t= &dtv_spl_test,
1505\t.plat_size\t= sizeof(dtv_spl_test),
1506\t.parent_idx\t= -1,
1507};
1508
1509/*
1510 * Node /spl-test2 index 1
1511 * driver sandbox_spl_test parent None
1512 */
1513static struct dtd_sandbox_spl_test dtv_spl_test2 = {
1514\t.intarray\t\t= 0x5,
1515};
1516U_BOOT_DRVINFO(spl_test2) = {
1517\t.name\t\t= "sandbox_spl_test",
1518\t.plat\t\t= &dtv_spl_test2,
1519\t.plat_size\t= sizeof(dtv_spl_test2),
1520\t.parent_idx\t= -1,
1521};
1522
1523''', data)
1524
1525    def test_stdout(self):
1526        """Test output to stdout"""
1527        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1528        with test_util.capture_sys_output() as (stdout, _):
1529            self.run_test(['struct'], dtb_file, None)
1530        self._check_strings(self.struct_text, stdout.getvalue())
1531
1532    def test_multi_to_file(self):
1533        """Test output of multiple pieces to a single file"""
1534        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1535        output = tools.get_output_filename('output')
1536        self.run_test(['all'], dtb_file, output)
1537        data = tools.read_file(output, binary=False)
1538        self._check_strings(
1539            self.decl_text + self.platdata_text + self.struct_text, data)
1540
1541    def test_no_command(self):
1542        """Test running dtoc without a command"""
1543        with self.assertRaises(ValueError) as exc:
1544            self.run_test([], '', '')
1545        self.assertIn("Please specify a command: struct, platdata",
1546                      str(exc.exception))
1547
1548    def test_bad_command(self):
1549        """Test running dtoc with an invalid command"""
1550        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1551        output = tools.get_output_filename('output')
1552        with self.assertRaises(ValueError) as exc:
1553            self.run_test(['invalid-cmd'], dtb_file, output)
1554        self.assertIn(
1555            "Unknown command 'invalid-cmd': (use: decl, platdata, struct)",
1556            str(exc.exception))
1557
1558    def test_output_conflict(self):
1559        """Test a conflict between and output dirs and output file"""
1560        with self.assertRaises(ValueError) as exc:
1561            dtb_platdata.run_steps(
1562                ['all'], None, False, 'out', ['cdir'], None, False,
1563                warning_disabled=True, scan=copy_scan())
1564        self.assertIn("Must specify either output or output_dirs, not both",
1565                      str(exc.exception))
1566
1567    def check_output_dirs(self, instantiate):
1568        # Remove the directory so that files from other tests are not there
1569        tools._remove_output_dir()
1570        tools.prepare_output_dir(None)
1571
1572        # This should create the .dts and .dtb in the output directory
1573        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1574        outdir = tools.get_output_dir()
1575        fnames = glob.glob(outdir + '/*')
1576        self.assertEqual(2, len(fnames))
1577
1578        dtb_platdata.run_steps(
1579            ['all'], dtb_file, False, None, [outdir], None, instantiate,
1580            warning_disabled=True, scan=copy_scan())
1581        fnames = glob.glob(outdir + '/*')
1582        return fnames
1583
1584    def test_output_dirs(self):
1585        """Test outputting files to a directory"""
1586        fnames = self.check_output_dirs(False)
1587        self.assertEqual(5, len(fnames))
1588
1589        leafs = set(os.path.basename(fname) for fname in fnames)
1590        self.assertEqual(
1591            {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb',
1592             'dt-decl.h'},
1593            leafs)
1594
1595    def test_output_dirs_inst(self):
1596        """Test outputting files to a directory with instantiation"""
1597        fnames = self.check_output_dirs(True)
1598        self.assertEqual(6, len(fnames))
1599
1600        leafs = set(os.path.basename(fname) for fname in fnames)
1601        self.assertEqual(
1602            {'dt-structs-gen.h', 'source.dts', 'source.dtb',
1603             'dt-uclass.c', 'dt-decl.h', 'dt-device.c'},
1604            leafs)
1605
1606    def setup_process_test(self):
1607        """Set up a test of process_nodes()
1608
1609        This uses saved_scan but returns a deep copy of it, so it is safe to
1610        modify it in these tests
1611
1612        Returns:
1613            tuple:
1614                DtbPlatdata: object to test
1615                Scanner: scanner to use
1616        """
1617        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1618        output = tools.get_output_filename('output')
1619
1620        # Take a copy before messing with it
1621        scan = copy_scan()
1622        plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
1623        plat.scan_dtb()
1624        plat.scan_tree(False)
1625        plat.prepare_nodes()
1626        return plat, scan
1627
1628    def test_process_nodes(self):
1629        """Test processing nodes to add various info"""
1630        plat, scan = self.setup_process_test()
1631        plat.process_nodes(True)
1632
1633        i2c_node = plat._fdt.GetNode('/i2c@0')
1634        pmic_node = plat._fdt.GetNode('/i2c@0/pmic@9')
1635        pmic = scan._drivers['sandbox_pmic']
1636        i2c = scan._drivers['sandbox_i2c']
1637        self.assertEqual('DM_DEVICE_REF(pmic_at_9)', pmic_node.dev_ref)
1638        self.assertEqual(pmic, pmic_node.driver)
1639        self.assertEqual(i2c_node, pmic_node.parent)
1640        self.assertEqual(i2c, pmic_node.parent_driver)
1641
1642        # The pmic is the only child
1643        self.assertEqual(pmic_node.parent_seq, 0)
1644        self.assertEqual([pmic_node], i2c_node.child_devs)
1645
1646        # Start and end of the list should be the child_head
1647        ref = '&DM_DEVICE_REF(i2c_at_0)->child_head'
1648        self.assertEqual(
1649            {-1: ref, 0: '&DM_DEVICE_REF(pmic_at_9)->sibling_node', 1: ref},
1650            i2c_node.child_refs)
1651
1652    def test_process_nodes_bad_parent(self):
1653        # Pretend that i2c has a parent (the pmic) and delete that driver
1654        plat, scan = self.setup_process_test()
1655
1656        i2c_node = plat._fdt.GetNode('/i2c@0')
1657        pmic_node = plat._fdt.GetNode('/i2c@0/pmic@9')
1658        del scan._drivers['sandbox_pmic']
1659        i2c_node.parent = pmic_node
1660
1661        # Process twice, the second time to generate an exception
1662        plat.process_nodes(False)
1663        with self.assertRaises(ValueError) as exc:
1664            plat.process_nodes(True)
1665        self.assertIn(
1666            "Cannot parse/find parent driver 'sandbox_pmic' for 'sandbox_i2c",
1667            str(exc.exception))
1668
1669    def test_process_nodes_bad_node(self):
1670        plat, scan = self.setup_process_test()
1671
1672        # Now remove the pmic driver
1673        del scan._drivers['sandbox_pmic']
1674
1675        # Process twice, the second time to generate an exception
1676        plat.process_nodes(False)
1677        with self.assertRaises(ValueError) as exc:
1678            plat.process_nodes(True)
1679        self.assertIn("Cannot parse/find driver for 'sandbox_pmic",
1680                      str(exc.exception))
1681
1682    def test_process_nodes_bad_uclass(self):
1683        plat, scan = self.setup_process_test()
1684
1685        self.assertIn('UCLASS_I2C', scan._uclass)
1686        del scan._uclass['UCLASS_I2C']
1687        with self.assertRaises(ValueError) as exc:
1688            plat.process_nodes(True)
1689        self.assertIn("Cannot parse/find uclass 'UCLASS_I2C' for driver 'sandbox_i2c'",
1690                      str(exc.exception))
1691
1692    def test_process_nodes_used(self):
1693        """Test processing nodes to add various info"""
1694        plat, scan = self.setup_process_test()
1695        plat.process_nodes(True)
1696
1697        pmic = scan._drivers['sandbox_pmic']
1698        self.assertTrue(pmic.used)
1699
1700        gpio = scan._drivers['sandbox_gpio']
1701        self.assertFalse(gpio.used)
1702
1703    def test_alias_read(self):
1704        """Test obtaining aliases"""
1705        dtb_file = get_dtb_file('dtoc_test_inst.dts')
1706        output = tools.get_output_filename('output')
1707        plat = self.run_test(['struct'], dtb_file, output)
1708
1709        scan = plat._scan
1710        testfdt_node = plat._fdt.GetNode('/some-bus/test')
1711        test0_node = plat._fdt.GetNode('/some-bus/test0')
1712        self.assertIn('UCLASS_TEST_FDT', scan._uclass)
1713        uc = scan._uclass['UCLASS_TEST_FDT']
1714        self.assertEqual({1: testfdt_node, 2: test0_node},
1715                         uc.alias_num_to_node)
1716        self.assertEqual({'/some-bus/test': 1, '/some-bus/test0': 2},
1717                         uc.alias_path_to_num)
1718
1719        # Try adding an alias that doesn't exist
1720        self.assertFalse(scan.add_uclass_alias('fred', 3, None))
1721
1722        # Try adding an alias for a missing node
1723        self.assertIsNone(scan.add_uclass_alias('testfdt', 3, None))
1724
1725    def test_alias_read_bad(self):
1726        """Test invalid alias property name"""
1727        dtb_file = get_dtb_file('dtoc_test_alias_bad.dts')
1728        output = tools.get_output_filename('output')
1729        with self.assertRaises(ValueError) as exc:
1730            plat = self.run_test(['struct'], dtb_file, output)
1731        self.assertIn("Cannot decode alias 'i2c4-'", str(exc.exception))
1732
1733    def test_alias_read_bad_path(self):
1734        """Test alias pointing to a non-existent node"""
1735        # This line may produce a warning, so capture it:
1736        # Warning (alias_paths): /aliases:i2c4: aliases property is not a valid
1737        #    node (/does/not/exist)
1738        dtb_file = get_dtb_file('dtoc_test_alias_bad_path.dts', True)
1739
1740        output = tools.get_output_filename('output')
1741        with self.assertRaises(ValueError) as exc:
1742            plat = self.run_test(['struct'], dtb_file, output)
1743        self.assertIn("Alias 'i2c4' path '/does/not/exist' not found",
1744                      str(exc.exception))
1745
1746    def test_alias_read_bad_uclass(self):
1747        """Test alias for a uclass that doesn't exist"""
1748        dtb_file = get_dtb_file('dtoc_test_alias_bad_uc.dts')
1749        output = tools.get_output_filename('output')
1750        with test_util.capture_sys_output() as (stdout, _):
1751            plat = self.run_test(['struct'], dtb_file, output)
1752        self.assertEqual("Could not find uclass for alias 'other1'",
1753                         stdout.getvalue().strip())
1754
1755    def test_sequence(self):
1756        """Test assignment of sequence numnbers"""
1757        dtb_file = get_dtb_file('dtoc_test_inst.dts')
1758        output = tools.get_output_filename('output')
1759        plat = self.run_test(['struct'], dtb_file, output)
1760
1761        scan = plat._scan
1762        testfdt = plat._fdt.GetNode('/some-bus/test')
1763        self.assertEqual(1, testfdt.seq)
1764        i2c = plat._fdt.GetNode('/i2c')
1765
1766        # For now this uclass is not compiled in, so no sequence is assigned
1767        self.assertEqual(4, i2c.seq)
1768        spl = plat._fdt.GetNode('/spl-test')
1769        self.assertEqual(0, spl.seq)
1770
1771    def test_process_root(self):
1772        """Test assignment of sequence numnbers"""
1773        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1774        output = tools.get_output_filename('output')
1775
1776        # Take a copy before messing with it
1777        scan = copy_scan()
1778        plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
1779        plat.scan_dtb()
1780        root = plat._fdt.GetRoot()
1781
1782        plat.scan_tree(False)
1783        self.assertNotIn(root, plat._valid_nodes)
1784
1785        plat.scan_tree(True)
1786        self.assertIn(root, plat._valid_nodes)
1787        self.assertEqual('root_driver',
1788                         scan.get_normalized_compat_name(root)[0])
1789
1790    def test_simple_inst(self):
1791        """Test output from some simple nodes with instantiate enabled"""
1792        dtb_file = get_dtb_file('dtoc_test_inst.dts')
1793        output = tools.get_output_filename('output')
1794
1795        self.run_test(['decl'], dtb_file, output, True)
1796        with open(output) as infile:
1797            data = infile.read()
1798
1799        self._check_strings(self.decl_text_inst, data)
1800
1801        self.run_test(['uclass'], dtb_file, output, True)
1802        with open(output) as infile:
1803            data = infile.read()
1804
1805        self._check_strings(UCLASS_HEADER_COMMON + self.uclass_text_inst, data)
1806
1807        self.run_test(['device'], dtb_file, output, True)
1808        with open(output) as infile:
1809            data = infile.read()
1810
1811        self._check_strings(self.device_text_inst, data)
1812
1813    def test_inst_no_hdr(self):
1814        """Test dealing with a struct tsssshat has no header"""
1815        dtb_file = get_dtb_file('dtoc_test_inst.dts')
1816        output = tools.get_output_filename('output')
1817
1818        # Run it once to set everything up
1819        plat = self.run_test(['decl'], dtb_file, output, True)
1820        scan = plat._scan
1821
1822        # Restart the output file and delete any record of the uclass' struct
1823        plat.setup_output(Ftype.SOURCE, output)
1824        del scan._structs['dm_test_uc_priv']
1825
1826        # Now generate the uclasses, which should provide a warning
1827        with test_util.capture_sys_output() as (stdout, _):
1828            plat.generate_uclasses()
1829        self.assertEqual(
1830            'Warning: Cannot find header file for struct dm_test_uc_priv',
1831            stdout.getvalue().strip())
1832
1833    def test_missing_props(self):
1834        """Test detection of a parent node with no properties"""
1835        dtb_file = get_dtb_file('dtoc_test_noprops.dts', capture_stderr=True)
1836        output = tools.get_output_filename('output')
1837        with self.assertRaises(ValueError) as exc:
1838            self.run_test(['struct'], dtb_file, output)
1839        self.assertIn("Parent node '/i2c@0' has no properties - do you need",
1840                      str(exc.exception))
1841
1842    def test_single_reg(self):
1843        """Test detection of a parent node with no properties"""
1844        dtb_file = get_dtb_file('dtoc_test_single_reg.dts')
1845        output = tools.get_output_filename('output')
1846        self.run_test(['struct'], dtb_file, output)
1847
1848    def test_missing_parent(self):
1849        """Test detection of a parent node with no properties"""
1850        dtb_file = get_dtb_file('dtoc_test_noparent.dts', capture_stderr=True)
1851        output = tools.get_output_filename('output')
1852        with self.assertRaises(ValueError) as exc:
1853            self.run_test(['device'], dtb_file, output, instantiate=True)
1854        self.assertIn("Node '/i2c@0/spl-test/pmic@9' requires parent node "
1855                      "'/i2c@0/spl-test' but it is not in the valid list",
1856                      str(exc.exception))
1857