Prepare v2023.10
[platform/kernel/u-boot.git] / tools / dtoc / test_dtoc.py
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
8 This includes unit tests for some functions and functional tests for the dtoc
9 tool.
10 """
11
12 import collections
13 import copy
14 import glob
15 import os
16 import pathlib
17 import struct
18 import unittest
19
20 from dtoc import dtb_platdata
21 from dtoc import fdt
22 from dtoc import fdt_util
23 from dtoc import src_scan
24 from dtoc.dtb_platdata import Ftype
25 from dtoc.dtb_platdata import get_value
26 from dtoc.dtb_platdata import tab_to
27 from dtoc.src_scan import conv_name_to_c
28 from dtoc.src_scan import get_compat_name
29 from u_boot_pylib import test_util
30 from u_boot_pylib import tools
31
32 DTOC_DIR = pathlib.Path(__file__).parent
33 TEST_DATA_DIR = DTOC_DIR / 'test/'
34
35
36 HEADER = '''/*
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
46 DECL_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
54 C_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
62 C_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
71 UCLASS_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)
80 saved_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
86 def 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
100 def 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
108 def copy_scan():
109     """Get a copy of saved_scan so that each test can start clean"""
110     return copy.deepcopy(saved_scan)
111
112
113 class 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 */
242 extern U_BOOT_DRIVER(sandbox_i2c);
243 extern U_BOOT_DRIVER(sandbox_pmic);
244 extern U_BOOT_DRIVER(sandbox_spl_test);
245 extern U_BOOT_DRIVER(sandbox_spl_test);
246 extern U_BOOT_DRIVER(sandbox_spl_test);
247
248 /* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
249 extern UCLASS_DRIVER(i2c);
250 extern UCLASS_DRIVER(misc);
251 extern 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 */
258 extern U_BOOT_DRIVER(sandbox_i2c);
259 extern U_BOOT_DRIVER(root_driver);
260 extern U_BOOT_DRIVER(denx_u_boot_test_bus);
261 extern U_BOOT_DRIVER(sandbox_spl_test);
262 extern U_BOOT_DRIVER(sandbox_spl_test);
263 extern U_BOOT_DRIVER(denx_u_boot_fdt_test);
264 extern U_BOOT_DRIVER(denx_u_boot_fdt_test);
265
266 /* device declarations - these allow DM_DEVICE_REF() to be used */
267 extern DM_DEVICE_INST(i2c);
268 extern DM_DEVICE_INST(root);
269 extern DM_DEVICE_INST(some_bus);
270 extern DM_DEVICE_INST(spl_test);
271 extern DM_DEVICE_INST(spl_test3);
272 extern DM_DEVICE_INST(test);
273 extern DM_DEVICE_INST(test0);
274
275 /* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
276 extern UCLASS_DRIVER(i2c);
277 extern UCLASS_DRIVER(misc);
278 extern UCLASS_DRIVER(root);
279 extern UCLASS_DRIVER(testbus);
280 extern UCLASS_DRIVER(testfdt);
281
282 /* uclass declarations - needed for DM_UCLASS_REF() */
283 extern DM_UCLASS_INST(i2c);
284 extern DM_UCLASS_INST(misc);
285 extern DM_UCLASS_INST(root);
286 extern DM_UCLASS_INST(testbus);
287 extern DM_UCLASS_INST(testfdt);
288 '''
289     struct_text = HEADER + '''
290 struct dtd_sandbox_i2c {
291 };
292 struct dtd_sandbox_pmic {
293 \tbool\t\tlow_power;
294 \tfdt32_t\t\treg[1];
295 };
296 struct 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  */
329 static struct dtd_sandbox_i2c dtv_i2c_at_0 = {
330 };
331 U_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  */
342 static struct dtd_sandbox_pmic dtv_pmic_at_9 = {
343 \t.low_power\t\t= true,
344 \t.reg\t\t\t= {0x9},
345 };
346 U_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  */
357 static 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 };
371 U_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  */
382 static 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 };
393 U_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  */
404 static 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 };
410 U_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
447 struct list_head uclass_head = {
448         .prev = &DM_UCLASS_REF(testfdt)->sibling_node,
449         .next = &DM_UCLASS_REF(i2c)->sibling_node,
450 };
451
452 DM_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
464 DM_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
476 DM_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
488 DM_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>
501 u8 _testfdt_priv_[sizeof(struct dm_test_uc_priv)]
502         __attribute__ ((section (".priv_data")));
503 DM_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 */
547 static struct dtd_sandbox_i2c dtv_i2c = {
548 \t.intval\t\t\t= 0x3,
549 };
550
551 #include <asm/i2c.h>
552 u8 _sandbox_i2c_priv_i2c[sizeof(struct sandbox_i2c_priv)]
553 \t__attribute__ ((section (".priv_data")));
554 #include <i2c.h>
555 u8 _sandbox_i2c_uc_priv_i2c[sizeof(struct dm_i2c_bus)]
556 \t__attribute__ ((section (".priv_data")));
557
558 DM_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 */
584 static struct dtd_root_driver dtv_root = {
585 };
586
587 DM_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>
609 struct 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>
618 u8 _denx_u_boot_test_bus_priv_some_bus[sizeof(struct dm_test_priv)]
619 \t__attribute__ ((section (".priv_data")));
620 #include <dm/test.h>
621 u8 _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>
624 u8 _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
628 DM_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 */
656 static struct dtd_sandbox_spl_test dtv_spl_test = {
657 \t.boolval\t\t= true,
658 \t.intval\t\t\t= 0x1,
659 };
660
661 DM_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 */
685 static struct dtd_sandbox_spl_test dtv_spl_test3 = {
686 \t.longbytearray\t\t= {0x90a0b0c, 0xd0e0f10},
687 \t.stringarray\t\t= "one",
688 };
689
690 DM_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>
716 struct 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>
725 u8 _denx_u_boot_fdt_test_priv_test[sizeof(struct dm_test_priv)]
726 \t__attribute__ ((section (".priv_data")));
727 #include <dm/test.h>
728 u8 _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>
731 u8 _denx_u_boot_fdt_test_parent_priv_test[sizeof(struct dm_test_parent_data)]
732 \t__attribute__ ((section (".priv_data")));
733
734 DM_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>
765 struct 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>
771 u8 _denx_u_boot_fdt_test_priv_test0[sizeof(struct dm_test_priv)]
772 \t__attribute__ ((section (".priv_data")));
773 #include <dm/test.h>
774 u8 _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>
777 u8 _denx_u_boot_fdt_test_parent_priv_test0[sizeof(struct dm_test_parent_data)]
778 \t__attribute__ ((section (".priv_data")));
779
780 DM_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 + '''
843 struct 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  */
867 static 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 };
872 U_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 + '''
892 struct 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 */
913 static struct dtd_invalid dtv_spl_test = {
914 };
915 U_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 + '''
932 struct dtd_source {
933 \tstruct phandle_2_arg clocks[4];
934 \tunsigned char phandle_name_offset[13];
935 };
936 struct 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 */
959 static struct dtd_target dtv_phandle2_target = {
960 \t.intval\t\t\t= 0x1,
961 };
962 U_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 */
970 static struct dtd_target dtv_phandle3_target = {
971 \t.intval\t\t\t= 0x2,
972 };
973 U_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 */
981 static 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 };
990 U_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 */
998 static struct dtd_source dtv_phandle_source2 = {
999 \t.clocks\t\t\t= {
1000 \t\t\t{4, {}},},
1001 };
1002 U_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 */
1010 static struct dtd_target dtv_phandle_target = {
1011 \t.intval\t\t\t= 0x0,
1012 };
1013 U_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 + '''
1030 struct dtd_source {
1031 \tstruct phandle_0_arg clocks[1];
1032 };
1033 struct 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 */
1057 static struct dtd_source dtv_phandle_source2 = {
1058 \t.clocks\t\t\t= {
1059 \t\t\t{1, {}},},
1060 };
1061 U_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 */
1069 static struct dtd_target dtv_phandle_target = {
1070 };
1071 U_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 */
1104 static struct dtd_target dtv_phandle2_target = {
1105 \t.intval\t\t\t= 0x1,
1106 };
1107 U_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 */
1115 static struct dtd_target dtv_phandle3_target = {
1116 \t.intval\t\t\t= 0x2,
1117 };
1118 U_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 */
1126 static 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 };
1133 U_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 */
1141 static struct dtd_source dtv_phandle_source2 = {
1142 \t.cd_gpios\t\t= {
1143 \t\t\t{4, {}},},
1144 };
1145 U_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 */
1153 static struct dtd_target dtv_phandle_target = {
1154 \t.intval\t\t\t= 0x0,
1155 };
1156 U_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 + '''
1193 struct dtd_test1 {
1194 \tfdt64_t\t\treg[2];
1195 };
1196 struct dtd_test2 {
1197 \tfdt64_t\t\treg[2];
1198 };
1199 struct 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 */
1220 static struct dtd_test1 dtv_test1 = {
1221 \t.reg\t\t\t= {0x1234, 0x5678},
1222 };
1223 U_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 */
1231 static struct dtd_test2 dtv_test2 = {
1232 \t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
1233 };
1234 U_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 */
1242 static struct dtd_test3 dtv_test3 = {
1243 \t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
1244 };
1245 U_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 + '''
1262 struct dtd_test1 {
1263 \tfdt32_t\t\treg[2];
1264 };
1265 struct 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 */
1285 static struct dtd_test1 dtv_test1 = {
1286 \t.reg\t\t\t= {0x1234, 0x5678},
1287 };
1288 U_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 */
1296 static struct dtd_test2 dtv_test2 = {
1297 \t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
1298 };
1299 U_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 + '''
1316 struct dtd_test1 {
1317 \tfdt64_t\t\treg[2];
1318 };
1319 struct dtd_test2 {
1320 \tfdt64_t\t\treg[2];
1321 };
1322 struct 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 */
1343 static struct dtd_test1 dtv_test1 = {
1344 \t.reg\t\t\t= {0x123400000000, 0x5678},
1345 };
1346 U_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 */
1354 static struct dtd_test2 dtv_test2 = {
1355 \t.reg\t\t\t= {0x1234567890123456, 0x98765432},
1356 };
1357 U_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 */
1365 static struct dtd_test3 dtv_test3 = {
1366 \t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
1367 };
1368 U_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 + '''
1385 struct dtd_test1 {
1386 \tfdt64_t\t\treg[2];
1387 };
1388 struct dtd_test2 {
1389 \tfdt64_t\t\treg[2];
1390 };
1391 struct 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 */
1412 static struct dtd_test1 dtv_test1 = {
1413 \t.reg\t\t\t= {0x1234, 0x567800000000},
1414 };
1415 U_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 */
1423 static struct dtd_test2 dtv_test2 = {
1424 \t.reg\t\t\t= {0x12345678, 0x9876543210987654},
1425 };
1426 U_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 */
1434 static struct dtd_test3 dtv_test3 = {
1435 \t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
1436 };
1437 U_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 + '''
1475 struct 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  */
1499 static struct dtd_sandbox_spl_test dtv_spl_test = {
1500 \t.intval\t\t\t= 0x1,
1501 };
1502 U_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  */
1513 static struct dtd_sandbox_spl_test dtv_spl_test2 = {
1514 \t.intarray\t\t= 0x5,
1515 };
1516 U_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))