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 terminal
30from u_boot_pylib import test_util
31from u_boot_pylib import tools
32
33DTOC_DIR = pathlib.Path(__file__).parent
34TEST_DATA_DIR = DTOC_DIR / 'test/'
35
36
37HEADER = '''/*
38 * DO NOT MODIFY
39 *
40 * Defines the structs used to hold devicetree data.
41 * This was generated by dtoc from a .dtb (device tree binary) file.
42 */
43
44#include <stdbool.h>
45#include <linux/libfdt.h>'''
46
47DECL_HEADER = '''/*
48 * DO NOT MODIFY
49 *
50 * Declares externs for all device/uclass instances.
51 * This was generated by dtoc from a .dtb (device tree binary) file.
52 */
53'''
54
55C_HEADER_PRE = '''/*
56 * DO NOT MODIFY
57 *
58 * Declares the U_BOOT_DRIVER() records and platform data.
59 * This was generated by dtoc from a .dtb (device tree binary) file.
60 */
61'''
62
63C_HEADER = C_HEADER_PRE + '''
64/* Allow use of U_BOOT_DRVINFO() in this file */
65#define DT_PLAT_C
66
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 <dm.h>
421#include <dt-structs.h>
422
423/*
424 * uclass declarations, ordered by 'struct uclass' linker_list idx:
425 *   0: i2c
426 *   1: misc
427 *   2: root
428 *   3: testbus
429 *   4: testfdt
430 *
431 * Sequence numbers allocated in each uclass:
432 * i2c: UCLASS_I2C
433 *    4: /i2c
434 * misc: UCLASS_MISC
435 *    0: /spl-test
436 *    1: /spl-test3
437 * root: UCLASS_ROOT
438 *    0: /
439 * testbus: UCLASS_TEST_BUS
440 *    2: /some-bus
441 * testfdt: UCLASS_TEST_FDT
442 *    1: /some-bus/test
443 *    2: /some-bus/test0
444 */
445
446struct list_head uclass_head = {
447	.prev = &DM_UCLASS_REF(testfdt)->sibling_node,
448	.next = &DM_UCLASS_REF(i2c)->sibling_node,
449};
450
451DM_UCLASS_INST(i2c) = {
452	.uc_drv		= DM_UCLASS_DRIVER_REF(i2c),
453	.sibling_node	= {
454		.prev = &uclass_head,
455		.next = &DM_UCLASS_REF(misc)->sibling_node,
456	},
457	.dev_head	= {
458		.prev = &DM_DEVICE_REF(i2c)->uclass_node,
459		.next = &DM_DEVICE_REF(i2c)->uclass_node,
460	},
461};
462
463DM_UCLASS_INST(misc) = {
464	.uc_drv		= DM_UCLASS_DRIVER_REF(misc),
465	.sibling_node	= {
466		.prev = &DM_UCLASS_REF(i2c)->sibling_node,
467		.next = &DM_UCLASS_REF(root)->sibling_node,
468	},
469	.dev_head	= {
470		.prev = &DM_DEVICE_REF(spl_test3)->uclass_node,
471		.next = &DM_DEVICE_REF(spl_test)->uclass_node,
472	},
473};
474
475DM_UCLASS_INST(root) = {
476	.uc_drv		= DM_UCLASS_DRIVER_REF(root),
477	.sibling_node	= {
478		.prev = &DM_UCLASS_REF(misc)->sibling_node,
479		.next = &DM_UCLASS_REF(testbus)->sibling_node,
480	},
481	.dev_head	= {
482		.prev = &DM_DEVICE_REF(root)->uclass_node,
483		.next = &DM_DEVICE_REF(root)->uclass_node,
484	},
485};
486
487DM_UCLASS_INST(testbus) = {
488	.uc_drv		= DM_UCLASS_DRIVER_REF(testbus),
489	.sibling_node	= {
490		.prev = &DM_UCLASS_REF(root)->sibling_node,
491		.next = &DM_UCLASS_REF(testfdt)->sibling_node,
492	},
493	.dev_head	= {
494		.prev = &DM_DEVICE_REF(some_bus)->uclass_node,
495		.next = &DM_DEVICE_REF(some_bus)->uclass_node,
496	},
497};
498
499#include <dm/test.h>
500u8 _testfdt_priv_[sizeof(struct dm_test_uc_priv)]
501	__attribute__ ((section (".priv_data")));
502DM_UCLASS_INST(testfdt) = {
503	.priv_		= _testfdt_priv_,
504	.uc_drv		= DM_UCLASS_DRIVER_REF(testfdt),
505	.sibling_node	= {
506		.prev = &DM_UCLASS_REF(testbus)->sibling_node,
507		.next = &uclass_head,
508	},
509	.dev_head	= {
510		.prev = &DM_DEVICE_REF(test0)->uclass_node,
511		.next = &DM_DEVICE_REF(test)->uclass_node,
512	},
513};
514
515'''
516    device_text_inst = '''/*
517 * DO NOT MODIFY
518 *
519 * Declares the DM_DEVICE_INST() records.
520 * This was generated by dtoc from a .dtb (device tree binary) file.
521 */
522
523#include <dm.h>
524#include <dt-structs.h>
525
526/*
527 * udevice declarations, ordered by 'struct udevice' linker_list position:
528 *
529 * idx  udevice              driver
530 * ---  -------------------- --------------------
531 *   0: i2c                  sandbox_i2c
532 *   1: root                 root_driver
533 *   2: some_bus             denx_u_boot_test_bus
534 *   3: spl_test             sandbox_spl_test
535 *   4: spl_test3            sandbox_spl_test
536 *   5: test                 denx_u_boot_fdt_test
537 *   6: test0                denx_u_boot_fdt_test
538 * ---  -------------------- --------------------
539 */
540
541/*
542 * Node /i2c index 0
543 * driver sandbox_i2c parent root_driver
544*/
545static struct dtd_sandbox_i2c dtv_i2c = {
546\t.intval\t\t\t= 0x3,
547};
548
549#include <asm/i2c.h>
550u8 _sandbox_i2c_priv_i2c[sizeof(struct sandbox_i2c_priv)]
551\t__attribute__ ((section (".priv_data")));
552#include <i2c.h>
553u8 _sandbox_i2c_uc_priv_i2c[sizeof(struct dm_i2c_bus)]
554\t__attribute__ ((section (".priv_data")));
555
556DM_DEVICE_INST(i2c) = {
557\t.driver\t\t= DM_DRIVER_REF(sandbox_i2c),
558\t.name\t\t= "sandbox_i2c",
559\t.plat_\t\t= &dtv_i2c,
560\t.priv_\t\t= _sandbox_i2c_priv_i2c,
561\t.uclass\t\t= DM_UCLASS_REF(i2c),
562\t.uclass_priv_ = _sandbox_i2c_uc_priv_i2c,
563\t.uclass_node\t= {
564\t\t.prev = &DM_UCLASS_REF(i2c)->dev_head,
565\t\t.next = &DM_UCLASS_REF(i2c)->dev_head,
566\t},
567\t.child_head\t= {
568\t\t.prev = &DM_DEVICE_REF(i2c)->child_head,
569\t\t.next = &DM_DEVICE_REF(i2c)->child_head,
570\t},
571\t.sibling_node\t= {
572\t\t.prev = &DM_DEVICE_REF(root)->child_head,
573\t\t.next = &DM_DEVICE_REF(some_bus)->sibling_node,
574\t},
575\t.seq_ = 4,
576};
577
578/*
579 * Node / index 1
580 * driver root_driver parent None
581*/
582static struct dtd_root_driver dtv_root = {
583};
584
585DM_DEVICE_INST(root) = {
586\t.driver\t\t= DM_DRIVER_REF(root_driver),
587\t.name\t\t= "root_driver",
588\t.plat_\t\t= &dtv_root,
589\t.uclass\t\t= DM_UCLASS_REF(root),
590\t.uclass_node\t= {
591\t\t.prev = &DM_UCLASS_REF(root)->dev_head,
592\t\t.next = &DM_UCLASS_REF(root)->dev_head,
593\t},
594\t.child_head\t= {
595\t\t.prev = &DM_DEVICE_REF(spl_test3)->sibling_node,
596\t\t.next = &DM_DEVICE_REF(i2c)->sibling_node,
597\t},
598\t.seq_ = 0,
599};
600
601/*
602 * Node /some-bus index 2
603 * driver denx_u_boot_test_bus parent root_driver
604*/
605
606#include <dm/test.h>
607struct dm_test_pdata __attribute__ ((section (".priv_data")))
608\t_denx_u_boot_test_bus_plat_some_bus = {
609\t.dtplat = {
610\t\t.ping_add\t\t= 0x4,
611\t\t.ping_expect\t\t= 0x4,
612\t\t.reg\t\t\t= {0x3, 0x1},
613\t},
614};
615#include <dm/test.h>
616u8 _denx_u_boot_test_bus_priv_some_bus[sizeof(struct dm_test_priv)]
617\t__attribute__ ((section (".priv_data")));
618#include <dm/test.h>
619u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_plat)]
620\t__attribute__ ((section (".priv_data")));
621#include <dm/test.h>
622u8 _denx_u_boot_test_bus_uc_priv_some_bus[sizeof(struct dm_test_uclass_priv)]
623	__attribute__ ((section (".priv_data")));
624#include <test.h>
625
626DM_DEVICE_INST(some_bus) = {
627\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_test_bus),
628\t.name\t\t= "denx_u_boot_test_bus",
629\t.plat_\t\t= &_denx_u_boot_test_bus_plat_some_bus,
630\t.uclass_plat_\t= _denx_u_boot_test_bus_ucplat_some_bus,
631\t.driver_data\t= DM_TEST_TYPE_FIRST,
632\t.priv_\t\t= _denx_u_boot_test_bus_priv_some_bus,
633\t.uclass\t\t= DM_UCLASS_REF(testbus),
634\t.uclass_priv_ = _denx_u_boot_test_bus_uc_priv_some_bus,
635\t.uclass_node\t= {
636\t\t.prev = &DM_UCLASS_REF(testbus)->dev_head,
637\t\t.next = &DM_UCLASS_REF(testbus)->dev_head,
638\t},
639\t.child_head\t= {
640\t\t.prev = &DM_DEVICE_REF(test0)->sibling_node,
641\t\t.next = &DM_DEVICE_REF(test)->sibling_node,
642\t},
643\t.sibling_node\t= {
644\t\t.prev = &DM_DEVICE_REF(i2c)->sibling_node,
645\t\t.next = &DM_DEVICE_REF(spl_test)->sibling_node,
646\t},
647\t.seq_ = 2,
648};
649
650/*
651 * Node /spl-test index 3
652 * driver sandbox_spl_test parent root_driver
653*/
654static struct dtd_sandbox_spl_test dtv_spl_test = {
655\t.boolval\t\t= true,
656\t.intval\t\t\t= 0x1,
657};
658
659DM_DEVICE_INST(spl_test) = {
660\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
661\t.name\t\t= "sandbox_spl_test",
662\t.plat_\t\t= &dtv_spl_test,
663\t.uclass\t\t= DM_UCLASS_REF(misc),
664\t.uclass_node\t= {
665\t\t.prev = &DM_UCLASS_REF(misc)->dev_head,
666\t\t.next = &DM_DEVICE_REF(spl_test3)->uclass_node,
667\t},
668\t.child_head\t= {
669\t\t.prev = &DM_DEVICE_REF(spl_test)->child_head,
670\t\t.next = &DM_DEVICE_REF(spl_test)->child_head,
671\t},
672\t.sibling_node\t= {
673\t\t.prev = &DM_DEVICE_REF(some_bus)->sibling_node,
674\t\t.next = &DM_DEVICE_REF(spl_test3)->sibling_node,
675\t},
676\t.seq_ = 0,
677};
678
679/*
680 * Node /spl-test3 index 4
681 * driver sandbox_spl_test parent root_driver
682*/
683static struct dtd_sandbox_spl_test dtv_spl_test3 = {
684\t.longbytearray\t\t= {0x90a0b0c, 0xd0e0f10},
685\t.stringarray\t\t= "one",
686};
687
688DM_DEVICE_INST(spl_test3) = {
689\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
690\t.name\t\t= "sandbox_spl_test",
691\t.plat_\t\t= &dtv_spl_test3,
692\t.uclass\t\t= DM_UCLASS_REF(misc),
693\t.uclass_node\t= {
694\t\t.prev = &DM_DEVICE_REF(spl_test)->uclass_node,
695\t\t.next = &DM_UCLASS_REF(misc)->dev_head,
696\t},
697\t.child_head\t= {
698\t\t.prev = &DM_DEVICE_REF(spl_test3)->child_head,
699\t\t.next = &DM_DEVICE_REF(spl_test3)->child_head,
700\t},
701\t.sibling_node\t= {
702\t\t.prev = &DM_DEVICE_REF(spl_test)->sibling_node,
703\t\t.next = &DM_DEVICE_REF(root)->child_head,
704\t},
705\t.seq_ = 1,
706};
707
708/*
709 * Node /some-bus/test index 5
710 * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
711*/
712
713#include <dm/test.h>
714struct dm_test_pdata __attribute__ ((section (".priv_data")))
715\t_denx_u_boot_fdt_test_plat_test = {
716\t.dtplat = {
717\t\t.ping_add\t\t= 0x5,
718\t\t.ping_expect\t\t= 0x5,
719\t\t.reg\t\t\t= {0x5},
720\t},
721};
722#include <dm/test.h>
723u8 _denx_u_boot_fdt_test_priv_test[sizeof(struct dm_test_priv)]
724\t__attribute__ ((section (".priv_data")));
725#include <dm/test.h>
726u8 _denx_u_boot_fdt_test_parent_plat_test[sizeof(struct dm_test_parent_plat)]
727\t__attribute__ ((section (".priv_data")));
728#include <dm/test.h>
729u8 _denx_u_boot_fdt_test_parent_priv_test[sizeof(struct dm_test_parent_data)]
730\t__attribute__ ((section (".priv_data")));
731
732DM_DEVICE_INST(test) = {
733\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
734\t.name\t\t= "denx_u_boot_fdt_test",
735\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test,
736\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test,
737\t.driver_data\t= DM_TEST_TYPE_FIRST,
738\t.parent\t\t= DM_DEVICE_REF(some_bus),
739\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test,
740\t.uclass\t\t= DM_UCLASS_REF(testfdt),
741\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test,
742\t.uclass_node\t= {
743\t\t.prev = &DM_UCLASS_REF(testfdt)->dev_head,
744\t\t.next = &DM_DEVICE_REF(test0)->uclass_node,
745\t},
746\t.child_head\t= {
747\t\t.prev = &DM_DEVICE_REF(test)->child_head,
748\t\t.next = &DM_DEVICE_REF(test)->child_head,
749\t},
750\t.sibling_node\t= {
751\t\t.prev = &DM_DEVICE_REF(some_bus)->child_head,
752\t\t.next = &DM_DEVICE_REF(test0)->sibling_node,
753\t},
754\t.seq_ = 1,
755};
756
757/*
758 * Node /some-bus/test0 index 6
759 * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
760*/
761
762#include <dm/test.h>
763struct dm_test_pdata __attribute__ ((section (".priv_data")))
764\t_denx_u_boot_fdt_test_plat_test0 = {
765\t.dtplat = {
766\t},
767};
768#include <dm/test.h>
769u8 _denx_u_boot_fdt_test_priv_test0[sizeof(struct dm_test_priv)]
770\t__attribute__ ((section (".priv_data")));
771#include <dm/test.h>
772u8 _denx_u_boot_fdt_test_parent_plat_test0[sizeof(struct dm_test_parent_plat)]
773\t__attribute__ ((section (".priv_data")));
774#include <dm/test.h>
775u8 _denx_u_boot_fdt_test_parent_priv_test0[sizeof(struct dm_test_parent_data)]
776\t__attribute__ ((section (".priv_data")));
777
778DM_DEVICE_INST(test0) = {
779\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
780\t.name\t\t= "denx_u_boot_fdt_test",
781\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test0,
782\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test0,
783\t.driver_data\t= DM_TEST_TYPE_SECOND,
784\t.parent\t\t= DM_DEVICE_REF(some_bus),
785\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test0,
786\t.uclass\t\t= DM_UCLASS_REF(testfdt),
787\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test0,
788\t.uclass_node\t= {
789\t\t.prev = &DM_DEVICE_REF(test)->uclass_node,
790\t\t.next = &DM_UCLASS_REF(testfdt)->dev_head,
791\t},
792\t.child_head\t= {
793\t\t.prev = &DM_DEVICE_REF(test0)->child_head,
794\t\t.next = &DM_DEVICE_REF(test0)->child_head,
795\t},
796\t.sibling_node\t= {
797\t\t.prev = &DM_DEVICE_REF(test)->sibling_node,
798\t\t.next = &DM_DEVICE_REF(some_bus)->child_head,
799\t},
800\t.seq_ = 2,
801};
802
803'''
804
805    def test_simple(self):
806        """Test output from some simple nodes with various types of data"""
807        dtb_file = get_dtb_file('dtoc_test_simple.dts')
808        output = tools.get_output_filename('output')
809        self.run_test(['struct'], dtb_file, output)
810        with open(output) as infile:
811            data = infile.read()
812
813        self._check_strings(self.struct_text, data)
814
815        self.run_test(['platdata'], dtb_file, output)
816        with open(output) as infile:
817            data = infile.read()
818
819        self._check_strings(self.platdata_text, data)
820
821        self.run_test(['decl'], dtb_file, output)
822        with open(output) as infile:
823            data = infile.read()
824
825        self._check_strings(self.decl_text, data)
826
827        # Try the 'all' command
828        self.run_test(['all'], dtb_file, output)
829        data = tools.read_file(output, binary=False)
830        self._check_strings(
831            self.decl_text + self.platdata_text + self.struct_text, data)
832
833    def test_driver_alias(self):
834        """Test output from a device tree file with a driver alias"""
835        dtb_file = get_dtb_file('dtoc_test_driver_alias.dts')
836        output = tools.get_output_filename('output')
837        self.run_test(['struct'], dtb_file, output)
838        with open(output) as infile:
839            data = infile.read()
840        self._check_strings(HEADER + '''
841struct dtd_sandbox_gpio {
842\tconst char *\tgpio_bank_name;
843\tbool\t\tgpio_controller;
844\tfdt32_t\t\tsandbox_gpio_count;
845};
846''', data)
847
848        self.run_test(['platdata'], dtb_file, output)
849        with open(output) as infile:
850            data = infile.read()
851        self._check_strings(C_HEADER + '''
852/*
853 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
854 *
855 * idx  driver_info          driver
856 * ---  -------------------- --------------------
857 *   0: gpios_at_0           sandbox_gpio
858 * ---  -------------------- --------------------
859 */
860
861/*
862 * Node /gpios@0 index 0
863 * driver sandbox_gpio parent None
864 */
865static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
866\t.gpio_bank_name\t\t= "a",
867\t.gpio_controller\t= true,
868\t.sandbox_gpio_count\t= 0x14,
869};
870U_BOOT_DRVINFO(gpios_at_0) = {
871\t.name\t\t= "sandbox_gpio",
872\t.plat\t\t= &dtv_gpios_at_0,
873\t.plat_size\t= sizeof(dtv_gpios_at_0),
874\t.parent_idx\t= -1,
875};
876
877''', data)
878
879    def test_invalid_driver(self):
880        """Test output from a device tree file with an invalid driver"""
881        dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts')
882        output = tools.get_output_filename('output')
883        with terminal.capture() as _:
884            dtb_platdata.run_steps(
885                ['struct'], dtb_file, False, output, [], None, False,
886                scan=copy_scan())
887        with open(output) as infile:
888            data = infile.read()
889        self._check_strings(HEADER + '''
890struct dtd_invalid {
891};
892''', data)
893
894        with terminal.capture() as _:
895            dtb_platdata.run_steps(
896                ['platdata'], dtb_file, False, output, [], None, False,
897                scan=copy_scan())
898        with open(output) as infile:
899            data = infile.read()
900        self._check_strings(C_HEADER + '''
901/*
902 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
903 *
904 * idx  driver_info          driver
905 * ---  -------------------- --------------------
906 *   0: spl_test             invalid
907 * ---  -------------------- --------------------
908 */
909
910/* Node /spl-test index 0 */
911static struct dtd_invalid dtv_spl_test = {
912};
913U_BOOT_DRVINFO(spl_test) = {
914\t.name\t\t= "invalid",
915\t.plat\t\t= &dtv_spl_test,
916\t.plat_size\t= sizeof(dtv_spl_test),
917\t.parent_idx\t= -1,
918};
919
920''', data)
921
922    def test_phandle(self):
923        """Test output from a node containing a phandle reference"""
924        dtb_file = get_dtb_file('dtoc_test_phandle.dts')
925        output = tools.get_output_filename('output')
926        self.run_test(['struct'], dtb_file, output)
927        with open(output) as infile:
928            data = infile.read()
929        self._check_strings(HEADER + '''
930struct dtd_source {
931\tstruct phandle_2_arg clocks[4];
932\tunsigned char	phandle_name_offset[13];
933};
934struct dtd_target {
935\tfdt32_t\t\tintval;
936};
937''', data)
938
939        self.run_test(['platdata'], dtb_file, output)
940        with open(output) as infile:
941            data = infile.read()
942        self._check_strings(C_HEADER + '''
943/*
944 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
945 *
946 * idx  driver_info          driver
947 * ---  -------------------- --------------------
948 *   0: phandle2_target      target
949 *   1: phandle3_target      target
950 *   2: phandle_source       source
951 *   3: phandle_source2      source
952 *   4: phandle_target       target
953 * ---  -------------------- --------------------
954 */
955
956/* Node /phandle2-target index 0 */
957static struct dtd_target dtv_phandle2_target = {
958\t.intval\t\t\t= 0x1,
959};
960U_BOOT_DRVINFO(phandle2_target) = {
961\t.name\t\t= "target",
962\t.plat\t\t= &dtv_phandle2_target,
963\t.plat_size\t= sizeof(dtv_phandle2_target),
964\t.parent_idx\t= -1,
965};
966
967/* Node /phandle3-target index 1 */
968static struct dtd_target dtv_phandle3_target = {
969\t.intval\t\t\t= 0x2,
970};
971U_BOOT_DRVINFO(phandle3_target) = {
972\t.name\t\t= "target",
973\t.plat\t\t= &dtv_phandle3_target,
974\t.plat_size\t= sizeof(dtv_phandle3_target),
975\t.parent_idx\t= -1,
976};
977
978/* Node /phandle-source index 2 */
979static struct dtd_source dtv_phandle_source = {
980\t.clocks\t\t\t= {
981\t\t\t{4, {}},
982\t\t\t{0, {11}},
983\t\t\t{1, {12, 13}},
984\t\t\t{4, {}},},
985\t.phandle_name_offset	= {0x0, 0x0, 0x0, 0x3, 0x66, 0x72, 0x65, 0x64,
986\t\t0x0, 0x0, 0x0, 0x0, 0x7b},
987};
988U_BOOT_DRVINFO(phandle_source) = {
989\t.name\t\t= "source",
990\t.plat\t\t= &dtv_phandle_source,
991\t.plat_size\t= sizeof(dtv_phandle_source),
992\t.parent_idx\t= -1,
993};
994
995/* Node /phandle-source2 index 3 */
996static struct dtd_source dtv_phandle_source2 = {
997\t.clocks\t\t\t= {
998\t\t\t{4, {}},},
999};
1000U_BOOT_DRVINFO(phandle_source2) = {
1001\t.name\t\t= "source",
1002\t.plat\t\t= &dtv_phandle_source2,
1003\t.plat_size\t= sizeof(dtv_phandle_source2),
1004\t.parent_idx\t= -1,
1005};
1006
1007/* Node /phandle-target index 4 */
1008static struct dtd_target dtv_phandle_target = {
1009\t.intval\t\t\t= 0x0,
1010};
1011U_BOOT_DRVINFO(phandle_target) = {
1012\t.name\t\t= "target",
1013\t.plat\t\t= &dtv_phandle_target,
1014\t.plat_size\t= sizeof(dtv_phandle_target),
1015\t.parent_idx\t= -1,
1016};
1017
1018''', data)
1019
1020    def test_phandle_single(self):
1021        """Test output from a node containing a phandle reference"""
1022        dtb_file = get_dtb_file('dtoc_test_phandle_single.dts')
1023        output = tools.get_output_filename('output')
1024        self.run_test(['struct'], dtb_file, output)
1025        with open(output) as infile:
1026            data = infile.read()
1027        self._check_strings(HEADER + '''
1028struct dtd_source {
1029\tstruct phandle_0_arg clocks[1];
1030};
1031struct dtd_target {
1032\tfdt32_t\t\tintval;
1033};
1034''', data)
1035
1036    def test_phandle_reorder(self):
1037        """Test that phandle targets are generated before their references"""
1038        dtb_file = get_dtb_file('dtoc_test_phandle_reorder.dts')
1039        output = tools.get_output_filename('output')
1040        self.run_test(['platdata'], dtb_file, output)
1041        with open(output) as infile:
1042            data = infile.read()
1043        self._check_strings(C_HEADER + '''
1044/*
1045 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1046 *
1047 * idx  driver_info          driver
1048 * ---  -------------------- --------------------
1049 *   0: phandle_source2      source
1050 *   1: phandle_target       target
1051 * ---  -------------------- --------------------
1052 */
1053
1054/* Node /phandle-source2 index 0 */
1055static struct dtd_source dtv_phandle_source2 = {
1056\t.clocks\t\t\t= {
1057\t\t\t{1, {}},},
1058};
1059U_BOOT_DRVINFO(phandle_source2) = {
1060\t.name\t\t= "source",
1061\t.plat\t\t= &dtv_phandle_source2,
1062\t.plat_size\t= sizeof(dtv_phandle_source2),
1063\t.parent_idx\t= -1,
1064};
1065
1066/* Node /phandle-target index 1 */
1067static struct dtd_target dtv_phandle_target = {
1068};
1069U_BOOT_DRVINFO(phandle_target) = {
1070\t.name\t\t= "target",
1071\t.plat\t\t= &dtv_phandle_target,
1072\t.plat_size\t= sizeof(dtv_phandle_target),
1073\t.parent_idx\t= -1,
1074};
1075
1076''', data)
1077
1078    def test_phandle_cd_gpio(self):
1079        """Test that phandle targets are generated when unsing cd-gpios"""
1080        dtb_file = get_dtb_file('dtoc_test_phandle_cd_gpios.dts')
1081        output = tools.get_output_filename('output')
1082        dtb_platdata.run_steps(
1083            ['platdata'], dtb_file, False, output, [], None, False,
1084            warning_disabled=True, scan=copy_scan())
1085        with open(output) as infile:
1086            data = infile.read()
1087        self._check_strings(C_HEADER + '''
1088/*
1089 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1090 *
1091 * idx  driver_info          driver
1092 * ---  -------------------- --------------------
1093 *   0: phandle2_target      target
1094 *   1: phandle3_target      target
1095 *   2: phandle_source       source
1096 *   3: phandle_source2      source
1097 *   4: phandle_target       target
1098 * ---  -------------------- --------------------
1099 */
1100
1101/* Node /phandle2-target index 0 */
1102static struct dtd_target dtv_phandle2_target = {
1103\t.intval\t\t\t= 0x1,
1104};
1105U_BOOT_DRVINFO(phandle2_target) = {
1106\t.name\t\t= "target",
1107\t.plat\t\t= &dtv_phandle2_target,
1108\t.plat_size\t= sizeof(dtv_phandle2_target),
1109\t.parent_idx\t= -1,
1110};
1111
1112/* Node /phandle3-target index 1 */
1113static struct dtd_target dtv_phandle3_target = {
1114\t.intval\t\t\t= 0x2,
1115};
1116U_BOOT_DRVINFO(phandle3_target) = {
1117\t.name\t\t= "target",
1118\t.plat\t\t= &dtv_phandle3_target,
1119\t.plat_size\t= sizeof(dtv_phandle3_target),
1120\t.parent_idx\t= -1,
1121};
1122
1123/* Node /phandle-source index 2 */
1124static struct dtd_source dtv_phandle_source = {
1125\t.cd_gpios\t\t= {
1126\t\t\t{4, {}},
1127\t\t\t{0, {11}},
1128\t\t\t{1, {12, 13}},
1129\t\t\t{4, {}},},
1130};
1131U_BOOT_DRVINFO(phandle_source) = {
1132\t.name\t\t= "source",
1133\t.plat\t\t= &dtv_phandle_source,
1134\t.plat_size\t= sizeof(dtv_phandle_source),
1135\t.parent_idx\t= -1,
1136};
1137
1138/* Node /phandle-source2 index 3 */
1139static struct dtd_source dtv_phandle_source2 = {
1140\t.cd_gpios\t\t= {
1141\t\t\t{4, {}},},
1142};
1143U_BOOT_DRVINFO(phandle_source2) = {
1144\t.name\t\t= "source",
1145\t.plat\t\t= &dtv_phandle_source2,
1146\t.plat_size\t= sizeof(dtv_phandle_source2),
1147\t.parent_idx\t= -1,
1148};
1149
1150/* Node /phandle-target index 4 */
1151static struct dtd_target dtv_phandle_target = {
1152\t.intval\t\t\t= 0x0,
1153};
1154U_BOOT_DRVINFO(phandle_target) = {
1155\t.name\t\t= "target",
1156\t.plat\t\t= &dtv_phandle_target,
1157\t.plat_size\t= sizeof(dtv_phandle_target),
1158\t.parent_idx\t= -1,
1159};
1160
1161''', data)
1162
1163    def test_phandle_bad(self):
1164        """Test a node containing an invalid phandle fails"""
1165        dtb_file = get_dtb_file('dtoc_test_phandle_bad.dts',
1166                                capture_stderr=True)
1167        output = tools.get_output_filename('output')
1168        with self.assertRaises(ValueError) as exc:
1169            self.run_test(['struct'], dtb_file, output)
1170        self.assertIn("Cannot parse 'clocks' in node 'phandle-source'",
1171                      str(exc.exception))
1172
1173    def test_phandle_bad2(self):
1174        """Test a phandle target missing its #*-cells property"""
1175        dtb_file = get_dtb_file('dtoc_test_phandle_bad2.dts',
1176                                capture_stderr=True)
1177        output = tools.get_output_filename('output')
1178        with self.assertRaises(ValueError) as exc:
1179            self.run_test(['struct'], dtb_file, output)
1180        self.assertIn("Node 'phandle-target' has no cells property",
1181                      str(exc.exception))
1182
1183    def test_addresses64(self):
1184        """Test output from a node with a 'reg' property with na=2, ns=2"""
1185        dtb_file = get_dtb_file('dtoc_test_addr64.dts')
1186        output = tools.get_output_filename('output')
1187        self.run_test(['struct'], dtb_file, output)
1188        with open(output) as infile:
1189            data = infile.read()
1190        self._check_strings(HEADER + '''
1191struct dtd_test1 {
1192\tfdt64_t\t\treg[2];
1193};
1194struct dtd_test2 {
1195\tfdt64_t\t\treg[2];
1196};
1197struct dtd_test3 {
1198\tfdt64_t\t\treg[4];
1199};
1200''', data)
1201
1202        self.run_test(['platdata'], dtb_file, output)
1203        with open(output) as infile:
1204            data = infile.read()
1205        self._check_strings(C_HEADER + '''
1206/*
1207 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1208 *
1209 * idx  driver_info          driver
1210 * ---  -------------------- --------------------
1211 *   0: test1                test1
1212 *   1: test2                test2
1213 *   2: test3                test3
1214 * ---  -------------------- --------------------
1215 */
1216
1217/* Node /test1 index 0 */
1218static struct dtd_test1 dtv_test1 = {
1219\t.reg\t\t\t= {0x1234, 0x5678},
1220};
1221U_BOOT_DRVINFO(test1) = {
1222\t.name\t\t= "test1",
1223\t.plat\t\t= &dtv_test1,
1224\t.plat_size\t= sizeof(dtv_test1),
1225\t.parent_idx\t= -1,
1226};
1227
1228/* Node /test2 index 1 */
1229static struct dtd_test2 dtv_test2 = {
1230\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
1231};
1232U_BOOT_DRVINFO(test2) = {
1233\t.name\t\t= "test2",
1234\t.plat\t\t= &dtv_test2,
1235\t.plat_size\t= sizeof(dtv_test2),
1236\t.parent_idx\t= -1,
1237};
1238
1239/* Node /test3 index 2 */
1240static struct dtd_test3 dtv_test3 = {
1241\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
1242};
1243U_BOOT_DRVINFO(test3) = {
1244\t.name\t\t= "test3",
1245\t.plat\t\t= &dtv_test3,
1246\t.plat_size\t= sizeof(dtv_test3),
1247\t.parent_idx\t= -1,
1248};
1249
1250''', data)
1251
1252    def test_addresses32(self):
1253        """Test output from a node with a 'reg' property with na=1, ns=1"""
1254        dtb_file = get_dtb_file('dtoc_test_addr32.dts')
1255        output = tools.get_output_filename('output')
1256        self.run_test(['struct'], dtb_file, output)
1257        with open(output) as infile:
1258            data = infile.read()
1259        self._check_strings(HEADER + '''
1260struct dtd_test1 {
1261\tfdt32_t\t\treg[2];
1262};
1263struct dtd_test2 {
1264\tfdt32_t\t\treg[4];
1265};
1266''', data)
1267
1268        self.run_test(['platdata'], dtb_file, output)
1269        with open(output) as infile:
1270            data = infile.read()
1271        self._check_strings(C_HEADER + '''
1272/*
1273 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1274 *
1275 * idx  driver_info          driver
1276 * ---  -------------------- --------------------
1277 *   0: test1                test1
1278 *   1: test2                test2
1279 * ---  -------------------- --------------------
1280 */
1281
1282/* Node /test1 index 0 */
1283static struct dtd_test1 dtv_test1 = {
1284\t.reg\t\t\t= {0x1234, 0x5678},
1285};
1286U_BOOT_DRVINFO(test1) = {
1287\t.name\t\t= "test1",
1288\t.plat\t\t= &dtv_test1,
1289\t.plat_size\t= sizeof(dtv_test1),
1290\t.parent_idx\t= -1,
1291};
1292
1293/* Node /test2 index 1 */
1294static struct dtd_test2 dtv_test2 = {
1295\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
1296};
1297U_BOOT_DRVINFO(test2) = {
1298\t.name\t\t= "test2",
1299\t.plat\t\t= &dtv_test2,
1300\t.plat_size\t= sizeof(dtv_test2),
1301\t.parent_idx\t= -1,
1302};
1303
1304''', data)
1305
1306    def test_addresses64_32(self):
1307        """Test output from a node with a 'reg' property with na=2, ns=1"""
1308        dtb_file = get_dtb_file('dtoc_test_addr64_32.dts')
1309        output = tools.get_output_filename('output')
1310        self.run_test(['struct'], dtb_file, output)
1311        with open(output) as infile:
1312            data = infile.read()
1313        self._check_strings(HEADER + '''
1314struct dtd_test1 {
1315\tfdt64_t\t\treg[2];
1316};
1317struct dtd_test2 {
1318\tfdt64_t\t\treg[2];
1319};
1320struct dtd_test3 {
1321\tfdt64_t\t\treg[4];
1322};
1323''', data)
1324
1325        self.run_test(['platdata'], dtb_file, output)
1326        with open(output) as infile:
1327            data = infile.read()
1328        self._check_strings(C_HEADER + '''
1329/*
1330 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1331 *
1332 * idx  driver_info          driver
1333 * ---  -------------------- --------------------
1334 *   0: test1                test1
1335 *   1: test2                test2
1336 *   2: test3                test3
1337 * ---  -------------------- --------------------
1338 */
1339
1340/* Node /test1 index 0 */
1341static struct dtd_test1 dtv_test1 = {
1342\t.reg\t\t\t= {0x123400000000, 0x5678},
1343};
1344U_BOOT_DRVINFO(test1) = {
1345\t.name\t\t= "test1",
1346\t.plat\t\t= &dtv_test1,
1347\t.plat_size\t= sizeof(dtv_test1),
1348\t.parent_idx\t= -1,
1349};
1350
1351/* Node /test2 index 1 */
1352static struct dtd_test2 dtv_test2 = {
1353\t.reg\t\t\t= {0x1234567890123456, 0x98765432},
1354};
1355U_BOOT_DRVINFO(test2) = {
1356\t.name\t\t= "test2",
1357\t.plat\t\t= &dtv_test2,
1358\t.plat_size\t= sizeof(dtv_test2),
1359\t.parent_idx\t= -1,
1360};
1361
1362/* Node /test3 index 2 */
1363static struct dtd_test3 dtv_test3 = {
1364\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
1365};
1366U_BOOT_DRVINFO(test3) = {
1367\t.name\t\t= "test3",
1368\t.plat\t\t= &dtv_test3,
1369\t.plat_size\t= sizeof(dtv_test3),
1370\t.parent_idx\t= -1,
1371};
1372
1373''', data)
1374
1375    def test_addresses32_64(self):
1376        """Test output from a node with a 'reg' property with na=1, ns=2"""
1377        dtb_file = get_dtb_file('dtoc_test_addr32_64.dts')
1378        output = tools.get_output_filename('output')
1379        self.run_test(['struct'], dtb_file, output)
1380        with open(output) as infile:
1381            data = infile.read()
1382        self._check_strings(HEADER + '''
1383struct dtd_test1 {
1384\tfdt64_t\t\treg[2];
1385};
1386struct dtd_test2 {
1387\tfdt64_t\t\treg[2];
1388};
1389struct dtd_test3 {
1390\tfdt64_t\t\treg[4];
1391};
1392''', data)
1393
1394        self.run_test(['platdata'], dtb_file, output)
1395        with open(output) as infile:
1396            data = infile.read()
1397        self._check_strings(C_HEADER + '''
1398/*
1399 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1400 *
1401 * idx  driver_info          driver
1402 * ---  -------------------- --------------------
1403 *   0: test1                test1
1404 *   1: test2                test2
1405 *   2: test3                test3
1406 * ---  -------------------- --------------------
1407 */
1408
1409/* Node /test1 index 0 */
1410static struct dtd_test1 dtv_test1 = {
1411\t.reg\t\t\t= {0x1234, 0x567800000000},
1412};
1413U_BOOT_DRVINFO(test1) = {
1414\t.name\t\t= "test1",
1415\t.plat\t\t= &dtv_test1,
1416\t.plat_size\t= sizeof(dtv_test1),
1417\t.parent_idx\t= -1,
1418};
1419
1420/* Node /test2 index 1 */
1421static struct dtd_test2 dtv_test2 = {
1422\t.reg\t\t\t= {0x12345678, 0x9876543210987654},
1423};
1424U_BOOT_DRVINFO(test2) = {
1425\t.name\t\t= "test2",
1426\t.plat\t\t= &dtv_test2,
1427\t.plat_size\t= sizeof(dtv_test2),
1428\t.parent_idx\t= -1,
1429};
1430
1431/* Node /test3 index 2 */
1432static struct dtd_test3 dtv_test3 = {
1433\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
1434};
1435U_BOOT_DRVINFO(test3) = {
1436\t.name\t\t= "test3",
1437\t.plat\t\t= &dtv_test3,
1438\t.plat_size\t= sizeof(dtv_test3),
1439\t.parent_idx\t= -1,
1440};
1441
1442''', data)
1443
1444    def test_bad_reg(self):
1445        """Test that a reg property with an invalid type generates an error"""
1446        # Capture stderr since dtc will emit warnings for this file
1447        dtb_file = get_dtb_file('dtoc_test_bad_reg.dts', capture_stderr=True)
1448        output = tools.get_output_filename('output')
1449        with self.assertRaises(ValueError) as exc:
1450            self.run_test(['struct'], dtb_file, output)
1451        self.assertIn("Node 'spl-test' reg property is not an int",
1452                      str(exc.exception))
1453
1454    def test_bad_reg2(self):
1455        """Test that a reg property with an invalid cell count is detected"""
1456        # Capture stderr since dtc will emit warnings for this file
1457        dtb_file = get_dtb_file('dtoc_test_bad_reg2.dts', capture_stderr=True)
1458        output = tools.get_output_filename('output')
1459        with self.assertRaises(ValueError) as exc:
1460            self.run_test(['struct'], dtb_file, output)
1461        self.assertIn(
1462            "Node 'spl-test' (parent '/') reg property has 3 cells which is not a multiple of na + ns = 1 + 1)",
1463            str(exc.exception))
1464
1465    def test_add_prop(self):
1466        """Test that a subequent node can add a new property to a struct"""
1467        dtb_file = get_dtb_file('dtoc_test_add_prop.dts')
1468        output = tools.get_output_filename('output')
1469        self.run_test(['struct'], dtb_file, output)
1470        with open(output) as infile:
1471            data = infile.read()
1472        self._check_strings(HEADER + '''
1473struct dtd_sandbox_spl_test {
1474\tfdt32_t\t\tintarray;
1475\tfdt32_t\t\tintval;
1476};
1477''', data)
1478
1479        self.run_test(['platdata'], dtb_file, output)
1480        with open(output) as infile:
1481            data = infile.read()
1482        self._check_strings(C_HEADER + '''
1483/*
1484 * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
1485 *
1486 * idx  driver_info          driver
1487 * ---  -------------------- --------------------
1488 *   0: spl_test             sandbox_spl_test
1489 *   1: spl_test2            sandbox_spl_test
1490 * ---  -------------------- --------------------
1491 */
1492
1493/*
1494 * Node /spl-test index 0
1495 * driver sandbox_spl_test parent None
1496 */
1497static struct dtd_sandbox_spl_test dtv_spl_test = {
1498\t.intval\t\t\t= 0x1,
1499};
1500U_BOOT_DRVINFO(spl_test) = {
1501\t.name\t\t= "sandbox_spl_test",
1502\t.plat\t\t= &dtv_spl_test,
1503\t.plat_size\t= sizeof(dtv_spl_test),
1504\t.parent_idx\t= -1,
1505};
1506
1507/*
1508 * Node /spl-test2 index 1
1509 * driver sandbox_spl_test parent None
1510 */
1511static struct dtd_sandbox_spl_test dtv_spl_test2 = {
1512\t.intarray\t\t= 0x5,
1513};
1514U_BOOT_DRVINFO(spl_test2) = {
1515\t.name\t\t= "sandbox_spl_test",
1516\t.plat\t\t= &dtv_spl_test2,
1517\t.plat_size\t= sizeof(dtv_spl_test2),
1518\t.parent_idx\t= -1,
1519};
1520
1521''', data)
1522
1523    def test_stdout(self):
1524        """Test output to stdout"""
1525        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1526        with terminal.capture() as (stdout, _):
1527            self.run_test(['struct'], dtb_file, None)
1528        self._check_strings(self.struct_text, stdout.getvalue())
1529
1530    def test_multi_to_file(self):
1531        """Test output of multiple pieces to a single file"""
1532        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1533        output = tools.get_output_filename('output')
1534        self.run_test(['all'], dtb_file, output)
1535        data = tools.read_file(output, binary=False)
1536        self._check_strings(
1537            self.decl_text + self.platdata_text + self.struct_text, data)
1538
1539    def test_no_command(self):
1540        """Test running dtoc without a command"""
1541        with self.assertRaises(ValueError) as exc:
1542            self.run_test([], '', '')
1543        self.assertIn("Please specify a command: struct, platdata",
1544                      str(exc.exception))
1545
1546    def test_bad_command(self):
1547        """Test running dtoc with an invalid command"""
1548        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1549        output = tools.get_output_filename('output')
1550        with self.assertRaises(ValueError) as exc:
1551            self.run_test(['invalid-cmd'], dtb_file, output)
1552        self.assertIn(
1553            "Unknown command 'invalid-cmd': (use: decl, platdata, struct)",
1554            str(exc.exception))
1555
1556    def test_output_conflict(self):
1557        """Test a conflict between and output dirs and output file"""
1558        with self.assertRaises(ValueError) as exc:
1559            dtb_platdata.run_steps(
1560                ['all'], None, False, 'out', ['cdir'], None, False,
1561                warning_disabled=True, scan=copy_scan())
1562        self.assertIn("Must specify either output or output_dirs, not both",
1563                      str(exc.exception))
1564
1565    def check_output_dirs(self, instantiate):
1566        # Remove the directory so that files from other tests are not there
1567        tools._remove_output_dir()
1568        tools.prepare_output_dir(None)
1569
1570        # This should create the .dts and .dtb in the output directory
1571        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1572        outdir = tools.get_output_dir()
1573        fnames = glob.glob(outdir + '/*')
1574        self.assertEqual(2, len(fnames))
1575
1576        dtb_platdata.run_steps(
1577            ['all'], dtb_file, False, None, [outdir], None, instantiate,
1578            warning_disabled=True, scan=copy_scan())
1579        fnames = glob.glob(outdir + '/*')
1580        return fnames
1581
1582    def test_output_dirs(self):
1583        """Test outputting files to a directory"""
1584        fnames = self.check_output_dirs(False)
1585        self.assertEqual(5, len(fnames))
1586
1587        leafs = set(os.path.basename(fname) for fname in fnames)
1588        self.assertEqual(
1589            {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb',
1590             'dt-decl.h'},
1591            leafs)
1592
1593    def test_output_dirs_inst(self):
1594        """Test outputting files to a directory with instantiation"""
1595        fnames = self.check_output_dirs(True)
1596        self.assertEqual(6, len(fnames))
1597
1598        leafs = set(os.path.basename(fname) for fname in fnames)
1599        self.assertEqual(
1600            {'dt-structs-gen.h', 'source.dts', 'source.dtb',
1601             'dt-uclass.c', 'dt-decl.h', 'dt-device.c'},
1602            leafs)
1603
1604    def setup_process_test(self):
1605        """Set up a test of process_nodes()
1606
1607        This uses saved_scan but returns a deep copy of it, so it is safe to
1608        modify it in these tests
1609
1610        Returns:
1611            tuple:
1612                DtbPlatdata: object to test
1613                Scanner: scanner to use
1614        """
1615        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1616        output = tools.get_output_filename('output')
1617
1618        # Take a copy before messing with it
1619        scan = copy_scan()
1620        plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
1621        plat.scan_dtb()
1622        plat.scan_tree(False)
1623        plat.prepare_nodes()
1624        return plat, scan
1625
1626    def test_process_nodes(self):
1627        """Test processing nodes to add various info"""
1628        plat, scan = self.setup_process_test()
1629        plat.process_nodes(True)
1630
1631        i2c_node = plat._fdt.GetNode('/i2c@0')
1632        pmic_node = plat._fdt.GetNode('/i2c@0/pmic@9')
1633        pmic = scan._drivers['sandbox_pmic']
1634        i2c = scan._drivers['sandbox_i2c']
1635        self.assertEqual('DM_DEVICE_REF(pmic_at_9)', pmic_node.dev_ref)
1636        self.assertEqual(pmic, pmic_node.driver)
1637        self.assertEqual(i2c_node, pmic_node.parent)
1638        self.assertEqual(i2c, pmic_node.parent_driver)
1639
1640        # The pmic is the only child
1641        self.assertEqual(pmic_node.parent_seq, 0)
1642        self.assertEqual([pmic_node], i2c_node.child_devs)
1643
1644        # Start and end of the list should be the child_head
1645        ref = '&DM_DEVICE_REF(i2c_at_0)->child_head'
1646        self.assertEqual(
1647            {-1: ref, 0: '&DM_DEVICE_REF(pmic_at_9)->sibling_node', 1: ref},
1648            i2c_node.child_refs)
1649
1650    def test_process_nodes_bad_parent(self):
1651        # Pretend that i2c has a parent (the pmic) and delete that driver
1652        plat, scan = self.setup_process_test()
1653
1654        i2c_node = plat._fdt.GetNode('/i2c@0')
1655        pmic_node = plat._fdt.GetNode('/i2c@0/pmic@9')
1656        del scan._drivers['sandbox_pmic']
1657        i2c_node.parent = pmic_node
1658
1659        # Process twice, the second time to generate an exception
1660        plat.process_nodes(False)
1661        with self.assertRaises(ValueError) as exc:
1662            plat.process_nodes(True)
1663        self.assertIn(
1664            "Cannot parse/find parent driver 'sandbox_pmic' for 'sandbox_i2c",
1665            str(exc.exception))
1666
1667    def test_process_nodes_bad_node(self):
1668        plat, scan = self.setup_process_test()
1669
1670        # Now remove the pmic driver
1671        del scan._drivers['sandbox_pmic']
1672
1673        # Process twice, the second time to generate an exception
1674        plat.process_nodes(False)
1675        with self.assertRaises(ValueError) as exc:
1676            plat.process_nodes(True)
1677        self.assertIn("Cannot parse/find driver for 'sandbox_pmic",
1678                      str(exc.exception))
1679
1680    def test_process_nodes_bad_uclass(self):
1681        plat, scan = self.setup_process_test()
1682
1683        self.assertIn('UCLASS_I2C', scan._uclass)
1684        del scan._uclass['UCLASS_I2C']
1685        with self.assertRaises(ValueError) as exc:
1686            plat.process_nodes(True)
1687        self.assertIn("Cannot parse/find uclass 'UCLASS_I2C' for driver 'sandbox_i2c'",
1688                      str(exc.exception))
1689
1690    def test_process_nodes_used(self):
1691        """Test processing nodes to add various info"""
1692        plat, scan = self.setup_process_test()
1693        plat.process_nodes(True)
1694
1695        pmic = scan._drivers['sandbox_pmic']
1696        self.assertTrue(pmic.used)
1697
1698        gpio = scan._drivers['sandbox_gpio']
1699        self.assertFalse(gpio.used)
1700
1701    def test_alias_read(self):
1702        """Test obtaining aliases"""
1703        dtb_file = get_dtb_file('dtoc_test_inst.dts')
1704        output = tools.get_output_filename('output')
1705        plat = self.run_test(['struct'], dtb_file, output)
1706
1707        scan = plat._scan
1708        testfdt_node = plat._fdt.GetNode('/some-bus/test')
1709        test0_node = plat._fdt.GetNode('/some-bus/test0')
1710        self.assertIn('UCLASS_TEST_FDT', scan._uclass)
1711        uc = scan._uclass['UCLASS_TEST_FDT']
1712        self.assertEqual({1: testfdt_node, 2: test0_node},
1713                         uc.alias_num_to_node)
1714        self.assertEqual({'/some-bus/test': 1, '/some-bus/test0': 2},
1715                         uc.alias_path_to_num)
1716
1717        # Try adding an alias that doesn't exist
1718        self.assertFalse(scan.add_uclass_alias('fred', 3, None))
1719
1720        # Try adding an alias for a missing node
1721        self.assertIsNone(scan.add_uclass_alias('testfdt', 3, None))
1722
1723    def test_alias_read_bad(self):
1724        """Test invalid alias property name"""
1725        dtb_file = get_dtb_file('dtoc_test_alias_bad.dts')
1726        output = tools.get_output_filename('output')
1727        with self.assertRaises(ValueError) as exc:
1728            plat = self.run_test(['struct'], dtb_file, output)
1729        self.assertIn("Cannot decode alias 'i2c4-'", str(exc.exception))
1730
1731    def test_alias_read_bad_path(self):
1732        """Test alias pointing to a non-existent node"""
1733        # This line may produce a warning, so capture it:
1734        # Warning (alias_paths): /aliases:i2c4: aliases property is not a valid
1735        #    node (/does/not/exist)
1736        dtb_file = get_dtb_file('dtoc_test_alias_bad_path.dts', True)
1737
1738        output = tools.get_output_filename('output')
1739        with self.assertRaises(ValueError) as exc:
1740            plat = self.run_test(['struct'], dtb_file, output)
1741        self.assertIn("Alias 'i2c4' path '/does/not/exist' not found",
1742                      str(exc.exception))
1743
1744    def test_alias_read_bad_uclass(self):
1745        """Test alias for a uclass that doesn't exist"""
1746        dtb_file = get_dtb_file('dtoc_test_alias_bad_uc.dts')
1747        output = tools.get_output_filename('output')
1748        with terminal.capture() as (stdout, _):
1749            plat = self.run_test(['struct'], dtb_file, output)
1750        self.assertEqual("Could not find uclass for alias 'other1'",
1751                         stdout.getvalue().strip())
1752
1753    def test_sequence(self):
1754        """Test assignment of sequence numnbers"""
1755        dtb_file = get_dtb_file('dtoc_test_inst.dts')
1756        output = tools.get_output_filename('output')
1757        plat = self.run_test(['struct'], dtb_file, output)
1758
1759        scan = plat._scan
1760        testfdt = plat._fdt.GetNode('/some-bus/test')
1761        self.assertEqual(1, testfdt.seq)
1762        i2c = plat._fdt.GetNode('/i2c')
1763
1764        # For now this uclass is not compiled in, so no sequence is assigned
1765        self.assertEqual(4, i2c.seq)
1766        spl = plat._fdt.GetNode('/spl-test')
1767        self.assertEqual(0, spl.seq)
1768
1769    def test_process_root(self):
1770        """Test assignment of sequence numnbers"""
1771        dtb_file = get_dtb_file('dtoc_test_simple.dts')
1772        output = tools.get_output_filename('output')
1773
1774        # Take a copy before messing with it
1775        scan = copy_scan()
1776        plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
1777        plat.scan_dtb()
1778        root = plat._fdt.GetRoot()
1779
1780        plat.scan_tree(False)
1781        self.assertNotIn(root, plat._valid_nodes)
1782
1783        plat.scan_tree(True)
1784        self.assertIn(root, plat._valid_nodes)
1785        self.assertEqual('root_driver',
1786                         scan.get_normalized_compat_name(root)[0])
1787
1788    def test_simple_inst(self):
1789        """Test output from some simple nodes with instantiate enabled"""
1790        dtb_file = get_dtb_file('dtoc_test_inst.dts')
1791        output = tools.get_output_filename('output')
1792
1793        self.run_test(['decl'], dtb_file, output, True)
1794        with open(output) as infile:
1795            data = infile.read()
1796
1797        self._check_strings(self.decl_text_inst, data)
1798
1799        self.run_test(['uclass'], dtb_file, output, True)
1800        with open(output) as infile:
1801            data = infile.read()
1802
1803        self._check_strings(UCLASS_HEADER_COMMON + self.uclass_text_inst, data)
1804
1805        self.run_test(['device'], dtb_file, output, True)
1806        with open(output) as infile:
1807            data = infile.read()
1808
1809        self._check_strings(self.device_text_inst, data)
1810
1811    def test_inst_no_hdr(self):
1812        """Test dealing with a struct tsssshat has no header"""
1813        dtb_file = get_dtb_file('dtoc_test_inst.dts')
1814        output = tools.get_output_filename('output')
1815
1816        # Run it once to set everything up
1817        plat = self.run_test(['decl'], dtb_file, output, True)
1818        scan = plat._scan
1819
1820        # Restart the output file and delete any record of the uclass' struct
1821        plat.setup_output(Ftype.SOURCE, output)
1822        del scan._structs['dm_test_uc_priv']
1823
1824        # Now generate the uclasses, which should provide a warning
1825        with terminal.capture() as (stdout, _):
1826            plat.generate_uclasses()
1827        self.assertEqual(
1828            'Warning: Cannot find header file for struct dm_test_uc_priv',
1829            stdout.getvalue().strip())
1830
1831    def test_missing_props(self):
1832        """Test detection of a parent node with no properties"""
1833        dtb_file = get_dtb_file('dtoc_test_noprops.dts', capture_stderr=True)
1834        output = tools.get_output_filename('output')
1835        with self.assertRaises(ValueError) as exc:
1836            self.run_test(['struct'], dtb_file, output)
1837        self.assertIn("Parent node '/i2c@0' has no properties - do you need",
1838                      str(exc.exception))
1839
1840    def test_single_reg(self):
1841        """Test detection of a parent node with no properties"""
1842        dtb_file = get_dtb_file('dtoc_test_single_reg.dts')
1843        output = tools.get_output_filename('output')
1844        self.run_test(['struct'], dtb_file, output)
1845
1846    def test_missing_parent(self):
1847        """Test detection of a parent node with no properties"""
1848        dtb_file = get_dtb_file('dtoc_test_noparent.dts', capture_stderr=True)
1849        output = tools.get_output_filename('output')
1850        with self.assertRaises(ValueError) as exc:
1851            self.run_test(['device'], dtb_file, output, instantiate=True)
1852        self.assertIn("Node '/i2c@0/spl-test/pmic@9' requires parent node "
1853                      "'/i2c@0/spl-test' but it is not in the valid list",
1854                      str(exc.exception))
1855