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