dtoc: add support to scan drivers
[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 os
14 import struct
15 import unittest
16
17 from dtoc import dtb_platdata
18 from dtb_platdata import conv_name_to_c
19 from dtb_platdata import get_compat_name
20 from dtb_platdata import get_value
21 from dtb_platdata import tab_to
22 from dtoc import fdt
23 from dtoc import fdt_util
24 from patman import test_util
25 from patman import tools
26
27 our_path = os.path.dirname(os.path.realpath(__file__))
28
29
30 HEADER = '''/*
31  * DO NOT MODIFY
32  *
33  * This file was generated by dtoc from a .dtb (device tree binary) file.
34  */
35
36 #include <stdbool.h>
37 #include <linux/libfdt.h>'''
38
39 C_HEADER = '''/*
40  * DO NOT MODIFY
41  *
42  * This file was generated by dtoc from a .dtb (device tree binary) file.
43  */
44
45 #include <common.h>
46 #include <dm.h>
47 #include <dt-structs.h>
48 '''
49
50
51
52 def get_dtb_file(dts_fname, capture_stderr=False):
53     """Compile a .dts file to a .dtb
54
55     Args:
56         dts_fname: Filename of .dts file in the current directory
57         capture_stderr: True to capture and discard stderr output
58
59     Returns:
60         Filename of compiled file in output directory
61     """
62     return fdt_util.EnsureCompiled(os.path.join(our_path, dts_fname),
63                                    capture_stderr=capture_stderr)
64
65
66 class TestDtoc(unittest.TestCase):
67     """Tests for dtoc"""
68     @classmethod
69     def setUpClass(cls):
70         tools.PrepareOutputDir(None)
71
72     @classmethod
73     def tearDownClass(cls):
74         tools._RemoveOutputDir()
75
76     def _WritePythonString(self, fname, data):
77         """Write a string with tabs expanded as done in this Python file
78
79         Args:
80             fname: Filename to write to
81             data: Raw string to convert
82         """
83         data = data.replace('\t', '\\t')
84         with open(fname, 'w') as fd:
85             fd.write(data)
86
87     def _CheckStrings(self, expected, actual):
88         """Check that a string matches its expected value
89
90         If the strings do not match, they are written to the /tmp directory in
91         the same Python format as is used here in the test. This allows for
92         easy comparison and update of the tests.
93
94         Args:
95             expected: Expected string
96             actual: Actual string
97         """
98         if expected != actual:
99             self._WritePythonString('/tmp/binman.expected', expected)
100             self._WritePythonString('/tmp/binman.actual', actual)
101             print('Failures written to /tmp/binman.{expected,actual}')
102         self.assertEquals(expected, actual)
103
104     def test_name(self):
105         """Test conversion of device tree names to C identifiers"""
106         self.assertEqual('serial_at_0x12', conv_name_to_c('serial@0x12'))
107         self.assertEqual('vendor_clock_frequency',
108                          conv_name_to_c('vendor,clock-frequency'))
109         self.assertEqual('rockchip_rk3399_sdhci_5_1',
110                          conv_name_to_c('rockchip,rk3399-sdhci-5.1'))
111
112     def test_tab_to(self):
113         """Test operation of tab_to() function"""
114         self.assertEqual('fred ', tab_to(0, 'fred'))
115         self.assertEqual('fred\t', tab_to(1, 'fred'))
116         self.assertEqual('fred was here ', tab_to(1, 'fred was here'))
117         self.assertEqual('fred was here\t\t', tab_to(3, 'fred was here'))
118         self.assertEqual('exactly8 ', tab_to(1, 'exactly8'))
119         self.assertEqual('exactly8\t', tab_to(2, 'exactly8'))
120
121     def test_get_value(self):
122         """Test operation of get_value() function"""
123         self.assertEqual('0x45',
124                          get_value(fdt.TYPE_INT, struct.pack('>I', 0x45)))
125         self.assertEqual('0x45',
126                          get_value(fdt.TYPE_BYTE, struct.pack('<I', 0x45)))
127         self.assertEqual('0x0',
128                          get_value(fdt.TYPE_BYTE, struct.pack('>I', 0x45)))
129         self.assertEqual('"test"', get_value(fdt.TYPE_STRING, 'test'))
130         self.assertEqual('true', get_value(fdt.TYPE_BOOL, None))
131
132     def test_get_compat_name(self):
133         """Test operation of get_compat_name() function"""
134         Prop = collections.namedtuple('Prop', ['value'])
135         Node = collections.namedtuple('Node', ['props'])
136
137         prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1'])
138         node = Node({'compatible': prop})
139         self.assertEqual(('rockchip_rk3399_sdhci_5_1', ['arasan_sdhci_5_1']),
140                          get_compat_name(node))
141
142         prop = Prop(['rockchip,rk3399-sdhci-5.1'])
143         node = Node({'compatible': prop})
144         self.assertEqual(('rockchip_rk3399_sdhci_5_1', []),
145                          get_compat_name(node))
146
147         prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1', 'third'])
148         node = Node({'compatible': prop})
149         self.assertEqual(('rockchip_rk3399_sdhci_5_1',
150                           ['arasan_sdhci_5_1', 'third']),
151                          get_compat_name(node))
152
153     def test_empty_file(self):
154         """Test output from a device tree file with no nodes"""
155         dtb_file = get_dtb_file('dtoc_test_empty.dts')
156         output = tools.GetOutputFilename('output')
157         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
158         with open(output) as infile:
159             lines = infile.read().splitlines()
160         self.assertEqual(HEADER.splitlines(), lines)
161
162         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
163         with open(output) as infile:
164             lines = infile.read().splitlines()
165         self.assertEqual(C_HEADER.splitlines() + [''], lines)
166
167     def test_simple(self):
168         """Test output from some simple nodes with various types of data"""
169         dtb_file = get_dtb_file('dtoc_test_simple.dts')
170         output = tools.GetOutputFilename('output')
171         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
172         with open(output) as infile:
173             data = infile.read()
174         self._CheckStrings(HEADER + '''
175 struct dtd_sandbox_i2c_test {
176 };
177 struct dtd_sandbox_pmic_test {
178 \tbool\t\tlow_power;
179 \tfdt64_t\t\treg[2];
180 };
181 struct dtd_sandbox_spl_test {
182 \tbool\t\tboolval;
183 \tunsigned char\tbytearray[3];
184 \tunsigned char\tbyteval;
185 \tfdt32_t\t\tintarray[4];
186 \tfdt32_t\t\tintval;
187 \tunsigned char\tlongbytearray[9];
188 \tunsigned char\tnotstring[5];
189 \tconst char *\tstringarray[3];
190 \tconst char *\tstringval;
191 };
192 struct dtd_sandbox_spl_test_2 {
193 };
194 ''', data)
195
196         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
197         with open(output) as infile:
198             data = infile.read()
199         self._CheckStrings(C_HEADER + '''
200 static const struct dtd_sandbox_spl_test dtv_spl_test = {
201 \t.boolval\t\t= true,
202 \t.bytearray\t\t= {0x6, 0x0, 0x0},
203 \t.byteval\t\t= 0x5,
204 \t.intarray\t\t= {0x2, 0x3, 0x4, 0x0},
205 \t.intval\t\t\t= 0x1,
206 \t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
207 \t\t0x11},
208 \t.notstring\t\t= {0x20, 0x21, 0x22, 0x10, 0x0},
209 \t.stringarray\t\t= {"multi-word", "message", ""},
210 \t.stringval\t\t= "message",
211 };
212 U_BOOT_DEVICE(spl_test) = {
213 \t.name\t\t= "sandbox_spl_test",
214 \t.platdata\t= &dtv_spl_test,
215 \t.platdata_size\t= sizeof(dtv_spl_test),
216 };
217
218 static const struct dtd_sandbox_spl_test dtv_spl_test2 = {
219 \t.bytearray\t\t= {0x1, 0x23, 0x34},
220 \t.byteval\t\t= 0x8,
221 \t.intarray\t\t= {0x5, 0x0, 0x0, 0x0},
222 \t.intval\t\t\t= 0x3,
223 \t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
224 \t\t0x0},
225 \t.stringarray\t\t= {"another", "multi-word", "message"},
226 \t.stringval\t\t= "message2",
227 };
228 U_BOOT_DEVICE(spl_test2) = {
229 \t.name\t\t= "sandbox_spl_test",
230 \t.platdata\t= &dtv_spl_test2,
231 \t.platdata_size\t= sizeof(dtv_spl_test2),
232 };
233
234 static const struct dtd_sandbox_spl_test dtv_spl_test3 = {
235 \t.stringarray\t\t= {"one", "", ""},
236 };
237 U_BOOT_DEVICE(spl_test3) = {
238 \t.name\t\t= "sandbox_spl_test",
239 \t.platdata\t= &dtv_spl_test3,
240 \t.platdata_size\t= sizeof(dtv_spl_test3),
241 };
242
243 static const struct dtd_sandbox_spl_test_2 dtv_spl_test4 = {
244 };
245 U_BOOT_DEVICE(spl_test4) = {
246 \t.name\t\t= "sandbox_spl_test_2",
247 \t.platdata\t= &dtv_spl_test4,
248 \t.platdata_size\t= sizeof(dtv_spl_test4),
249 };
250
251 static const struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
252 };
253 U_BOOT_DEVICE(i2c_at_0) = {
254 \t.name\t\t= "sandbox_i2c_test",
255 \t.platdata\t= &dtv_i2c_at_0,
256 \t.platdata_size\t= sizeof(dtv_i2c_at_0),
257 };
258
259 static const struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
260 \t.low_power\t\t= true,
261 \t.reg\t\t\t= {0x9, 0x0},
262 };
263 U_BOOT_DEVICE(pmic_at_9) = {
264 \t.name\t\t= "sandbox_pmic_test",
265 \t.platdata\t= &dtv_pmic_at_9,
266 \t.platdata_size\t= sizeof(dtv_pmic_at_9),
267 };
268
269 ''', data)
270
271     def test_driver_alias(self):
272         """Test output from a device tree file with a driver alias"""
273         dtb_file = get_dtb_file('dtoc_test_driver_alias.dts')
274         output = tools.GetOutputFilename('output')
275         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
276         with open(output) as infile:
277             data = infile.read()
278         self._CheckStrings(HEADER + '''
279 struct dtd_sandbox_gpio {
280 \tconst char *\tgpio_bank_name;
281 \tbool\t\tgpio_controller;
282 \tfdt32_t\t\tsandbox_gpio_count;
283 };
284 #define dtd_sandbox_gpio_alias dtd_sandbox_gpio
285 ''', data)
286
287         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
288         with open(output) as infile:
289             data = infile.read()
290         self._CheckStrings(C_HEADER + '''
291 static const struct dtd_sandbox_gpio dtv_gpios_at_0 = {
292 \t.gpio_bank_name\t\t= "a",
293 \t.gpio_controller\t= true,
294 \t.sandbox_gpio_count\t= 0x14,
295 };
296 U_BOOT_DEVICE(gpios_at_0) = {
297 \t.name\t\t= "sandbox_gpio",
298 \t.platdata\t= &dtv_gpios_at_0,
299 \t.platdata_size\t= sizeof(dtv_gpios_at_0),
300 };
301
302 ''', data)
303
304     def test_phandle(self):
305         """Test output from a node containing a phandle reference"""
306         dtb_file = get_dtb_file('dtoc_test_phandle.dts')
307         output = tools.GetOutputFilename('output')
308         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
309         with open(output) as infile:
310             data = infile.read()
311         self._CheckStrings(HEADER + '''
312 struct dtd_source {
313 \tstruct phandle_2_arg clocks[4];
314 };
315 struct dtd_target {
316 \tfdt32_t\t\tintval;
317 };
318 ''', data)
319
320         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
321         with open(output) as infile:
322             data = infile.read()
323         self._CheckStrings(C_HEADER + '''
324 static const struct dtd_target dtv_phandle_target = {
325 \t.intval\t\t\t= 0x0,
326 };
327 U_BOOT_DEVICE(phandle_target) = {
328 \t.name\t\t= "target",
329 \t.platdata\t= &dtv_phandle_target,
330 \t.platdata_size\t= sizeof(dtv_phandle_target),
331 };
332
333 static const struct dtd_target dtv_phandle2_target = {
334 \t.intval\t\t\t= 0x1,
335 };
336 U_BOOT_DEVICE(phandle2_target) = {
337 \t.name\t\t= "target",
338 \t.platdata\t= &dtv_phandle2_target,
339 \t.platdata_size\t= sizeof(dtv_phandle2_target),
340 };
341
342 static const struct dtd_target dtv_phandle3_target = {
343 \t.intval\t\t\t= 0x2,
344 };
345 U_BOOT_DEVICE(phandle3_target) = {
346 \t.name\t\t= "target",
347 \t.platdata\t= &dtv_phandle3_target,
348 \t.platdata_size\t= sizeof(dtv_phandle3_target),
349 };
350
351 static const struct dtd_source dtv_phandle_source = {
352 \t.clocks\t\t\t= {
353 \t\t\t{&dtv_phandle_target, {}},
354 \t\t\t{&dtv_phandle2_target, {11}},
355 \t\t\t{&dtv_phandle3_target, {12, 13}},
356 \t\t\t{&dtv_phandle_target, {}},},
357 };
358 U_BOOT_DEVICE(phandle_source) = {
359 \t.name\t\t= "source",
360 \t.platdata\t= &dtv_phandle_source,
361 \t.platdata_size\t= sizeof(dtv_phandle_source),
362 };
363
364 static const struct dtd_source dtv_phandle_source2 = {
365 \t.clocks\t\t\t= {
366 \t\t\t{&dtv_phandle_target, {}},},
367 };
368 U_BOOT_DEVICE(phandle_source2) = {
369 \t.name\t\t= "source",
370 \t.platdata\t= &dtv_phandle_source2,
371 \t.platdata_size\t= sizeof(dtv_phandle_source2),
372 };
373
374 ''', data)
375
376     def test_phandle_single(self):
377         """Test output from a node containing a phandle reference"""
378         dtb_file = get_dtb_file('dtoc_test_phandle_single.dts')
379         output = tools.GetOutputFilename('output')
380         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
381         with open(output) as infile:
382             data = infile.read()
383         self._CheckStrings(HEADER + '''
384 struct dtd_source {
385 \tstruct phandle_0_arg clocks[1];
386 };
387 struct dtd_target {
388 \tfdt32_t\t\tintval;
389 };
390 ''', data)
391
392     def test_phandle_reorder(self):
393         """Test that phandle targets are generated before their references"""
394         dtb_file = get_dtb_file('dtoc_test_phandle_reorder.dts')
395         output = tools.GetOutputFilename('output')
396         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
397         with open(output) as infile:
398             data = infile.read()
399         self._CheckStrings(C_HEADER + '''
400 static const struct dtd_target dtv_phandle_target = {
401 };
402 U_BOOT_DEVICE(phandle_target) = {
403 \t.name\t\t= "target",
404 \t.platdata\t= &dtv_phandle_target,
405 \t.platdata_size\t= sizeof(dtv_phandle_target),
406 };
407
408 static const struct dtd_source dtv_phandle_source2 = {
409 \t.clocks\t\t\t= {
410 \t\t\t{&dtv_phandle_target, {}},},
411 };
412 U_BOOT_DEVICE(phandle_source2) = {
413 \t.name\t\t= "source",
414 \t.platdata\t= &dtv_phandle_source2,
415 \t.platdata_size\t= sizeof(dtv_phandle_source2),
416 };
417
418 ''', data)
419
420     def test_phandle_bad(self):
421         """Test a node containing an invalid phandle fails"""
422         dtb_file = get_dtb_file('dtoc_test_phandle_bad.dts',
423                                 capture_stderr=True)
424         output = tools.GetOutputFilename('output')
425         with self.assertRaises(ValueError) as e:
426             dtb_platdata.run_steps(['struct'], dtb_file, False, output)
427         self.assertIn("Cannot parse 'clocks' in node 'phandle-source'",
428                       str(e.exception))
429
430     def test_phandle_bad2(self):
431         """Test a phandle target missing its #*-cells property"""
432         dtb_file = get_dtb_file('dtoc_test_phandle_bad2.dts',
433                                 capture_stderr=True)
434         output = tools.GetOutputFilename('output')
435         with self.assertRaises(ValueError) as e:
436             dtb_platdata.run_steps(['struct'], dtb_file, False, output)
437         self.assertIn("Node 'phandle-target' has no '#clock-cells' property",
438                       str(e.exception))
439
440     def test_aliases(self):
441         """Test output from a node with multiple compatible strings"""
442         dtb_file = get_dtb_file('dtoc_test_aliases.dts')
443         output = tools.GetOutputFilename('output')
444         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
445         with open(output) as infile:
446             data = infile.read()
447         self._CheckStrings(HEADER + '''
448 struct dtd_compat1 {
449 \tfdt32_t\t\tintval;
450 };
451 #define dtd_compat2_1_fred dtd_compat1
452 #define dtd_compat3 dtd_compat1
453 ''', data)
454
455         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
456         with open(output) as infile:
457             data = infile.read()
458         self._CheckStrings(C_HEADER + '''
459 static const struct dtd_compat1 dtv_spl_test = {
460 \t.intval\t\t\t= 0x1,
461 };
462 U_BOOT_DEVICE(spl_test) = {
463 \t.name\t\t= "compat1",
464 \t.platdata\t= &dtv_spl_test,
465 \t.platdata_size\t= sizeof(dtv_spl_test),
466 };
467
468 ''', data)
469
470     def test_addresses64(self):
471         """Test output from a node with a 'reg' property with na=2, ns=2"""
472         dtb_file = get_dtb_file('dtoc_test_addr64.dts')
473         output = tools.GetOutputFilename('output')
474         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
475         with open(output) as infile:
476             data = infile.read()
477         self._CheckStrings(HEADER + '''
478 struct dtd_test1 {
479 \tfdt64_t\t\treg[2];
480 };
481 struct dtd_test2 {
482 \tfdt64_t\t\treg[2];
483 };
484 struct dtd_test3 {
485 \tfdt64_t\t\treg[4];
486 };
487 ''', data)
488
489         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
490         with open(output) as infile:
491             data = infile.read()
492         self._CheckStrings(C_HEADER + '''
493 static const struct dtd_test1 dtv_test1 = {
494 \t.reg\t\t\t= {0x1234, 0x5678},
495 };
496 U_BOOT_DEVICE(test1) = {
497 \t.name\t\t= "test1",
498 \t.platdata\t= &dtv_test1,
499 \t.platdata_size\t= sizeof(dtv_test1),
500 };
501
502 static const struct dtd_test2 dtv_test2 = {
503 \t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
504 };
505 U_BOOT_DEVICE(test2) = {
506 \t.name\t\t= "test2",
507 \t.platdata\t= &dtv_test2,
508 \t.platdata_size\t= sizeof(dtv_test2),
509 };
510
511 static const struct dtd_test3 dtv_test3 = {
512 \t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
513 };
514 U_BOOT_DEVICE(test3) = {
515 \t.name\t\t= "test3",
516 \t.platdata\t= &dtv_test3,
517 \t.platdata_size\t= sizeof(dtv_test3),
518 };
519
520 ''', data)
521
522     def test_addresses32(self):
523         """Test output from a node with a 'reg' property with na=1, ns=1"""
524         dtb_file = get_dtb_file('dtoc_test_addr32.dts')
525         output = tools.GetOutputFilename('output')
526         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
527         with open(output) as infile:
528             data = infile.read()
529         self._CheckStrings(HEADER + '''
530 struct dtd_test1 {
531 \tfdt32_t\t\treg[2];
532 };
533 struct dtd_test2 {
534 \tfdt32_t\t\treg[4];
535 };
536 ''', data)
537
538         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
539         with open(output) as infile:
540             data = infile.read()
541         self._CheckStrings(C_HEADER + '''
542 static const struct dtd_test1 dtv_test1 = {
543 \t.reg\t\t\t= {0x1234, 0x5678},
544 };
545 U_BOOT_DEVICE(test1) = {
546 \t.name\t\t= "test1",
547 \t.platdata\t= &dtv_test1,
548 \t.platdata_size\t= sizeof(dtv_test1),
549 };
550
551 static const struct dtd_test2 dtv_test2 = {
552 \t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
553 };
554 U_BOOT_DEVICE(test2) = {
555 \t.name\t\t= "test2",
556 \t.platdata\t= &dtv_test2,
557 \t.platdata_size\t= sizeof(dtv_test2),
558 };
559
560 ''', data)
561
562     def test_addresses64_32(self):
563         """Test output from a node with a 'reg' property with na=2, ns=1"""
564         dtb_file = get_dtb_file('dtoc_test_addr64_32.dts')
565         output = tools.GetOutputFilename('output')
566         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
567         with open(output) as infile:
568             data = infile.read()
569         self._CheckStrings(HEADER + '''
570 struct dtd_test1 {
571 \tfdt64_t\t\treg[2];
572 };
573 struct dtd_test2 {
574 \tfdt64_t\t\treg[2];
575 };
576 struct dtd_test3 {
577 \tfdt64_t\t\treg[4];
578 };
579 ''', data)
580
581         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
582         with open(output) as infile:
583             data = infile.read()
584         self._CheckStrings(C_HEADER + '''
585 static const struct dtd_test1 dtv_test1 = {
586 \t.reg\t\t\t= {0x123400000000, 0x5678},
587 };
588 U_BOOT_DEVICE(test1) = {
589 \t.name\t\t= "test1",
590 \t.platdata\t= &dtv_test1,
591 \t.platdata_size\t= sizeof(dtv_test1),
592 };
593
594 static const struct dtd_test2 dtv_test2 = {
595 \t.reg\t\t\t= {0x1234567890123456, 0x98765432},
596 };
597 U_BOOT_DEVICE(test2) = {
598 \t.name\t\t= "test2",
599 \t.platdata\t= &dtv_test2,
600 \t.platdata_size\t= sizeof(dtv_test2),
601 };
602
603 static const struct dtd_test3 dtv_test3 = {
604 \t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
605 };
606 U_BOOT_DEVICE(test3) = {
607 \t.name\t\t= "test3",
608 \t.platdata\t= &dtv_test3,
609 \t.platdata_size\t= sizeof(dtv_test3),
610 };
611
612 ''', data)
613
614     def test_addresses32_64(self):
615         """Test output from a node with a 'reg' property with na=1, ns=2"""
616         dtb_file = get_dtb_file('dtoc_test_addr32_64.dts')
617         output = tools.GetOutputFilename('output')
618         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
619         with open(output) as infile:
620             data = infile.read()
621         self._CheckStrings(HEADER + '''
622 struct dtd_test1 {
623 \tfdt64_t\t\treg[2];
624 };
625 struct dtd_test2 {
626 \tfdt64_t\t\treg[2];
627 };
628 struct dtd_test3 {
629 \tfdt64_t\t\treg[4];
630 };
631 ''', data)
632
633         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
634         with open(output) as infile:
635             data = infile.read()
636         self._CheckStrings(C_HEADER + '''
637 static const struct dtd_test1 dtv_test1 = {
638 \t.reg\t\t\t= {0x1234, 0x567800000000},
639 };
640 U_BOOT_DEVICE(test1) = {
641 \t.name\t\t= "test1",
642 \t.platdata\t= &dtv_test1,
643 \t.platdata_size\t= sizeof(dtv_test1),
644 };
645
646 static const struct dtd_test2 dtv_test2 = {
647 \t.reg\t\t\t= {0x12345678, 0x9876543210987654},
648 };
649 U_BOOT_DEVICE(test2) = {
650 \t.name\t\t= "test2",
651 \t.platdata\t= &dtv_test2,
652 \t.platdata_size\t= sizeof(dtv_test2),
653 };
654
655 static const struct dtd_test3 dtv_test3 = {
656 \t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
657 };
658 U_BOOT_DEVICE(test3) = {
659 \t.name\t\t= "test3",
660 \t.platdata\t= &dtv_test3,
661 \t.platdata_size\t= sizeof(dtv_test3),
662 };
663
664 ''', data)
665
666     def test_bad_reg(self):
667         """Test that a reg property with an invalid type generates an error"""
668         # Capture stderr since dtc will emit warnings for this file
669         dtb_file = get_dtb_file('dtoc_test_bad_reg.dts', capture_stderr=True)
670         output = tools.GetOutputFilename('output')
671         with self.assertRaises(ValueError) as e:
672             dtb_platdata.run_steps(['struct'], dtb_file, False, output)
673         self.assertIn("Node 'spl-test' reg property is not an int",
674                       str(e.exception))
675
676     def test_bad_reg2(self):
677         """Test that a reg property with an invalid cell count is detected"""
678         # Capture stderr since dtc will emit warnings for this file
679         dtb_file = get_dtb_file('dtoc_test_bad_reg2.dts', capture_stderr=True)
680         output = tools.GetOutputFilename('output')
681         with self.assertRaises(ValueError) as e:
682             dtb_platdata.run_steps(['struct'], dtb_file, False, output)
683         self.assertIn("Node 'spl-test' reg property has 3 cells which is not a multiple of na + ns = 1 + 1)",
684                       str(e.exception))
685
686     def test_add_prop(self):
687         """Test that a subequent node can add a new property to a struct"""
688         dtb_file = get_dtb_file('dtoc_test_add_prop.dts')
689         output = tools.GetOutputFilename('output')
690         dtb_platdata.run_steps(['struct'], dtb_file, False, output)
691         with open(output) as infile:
692             data = infile.read()
693         self._CheckStrings(HEADER + '''
694 struct dtd_sandbox_spl_test {
695 \tfdt32_t\t\tintarray;
696 \tfdt32_t\t\tintval;
697 };
698 ''', data)
699
700         dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
701         with open(output) as infile:
702             data = infile.read()
703         self._CheckStrings(C_HEADER + '''
704 static const struct dtd_sandbox_spl_test dtv_spl_test = {
705 \t.intval\t\t\t= 0x1,
706 };
707 U_BOOT_DEVICE(spl_test) = {
708 \t.name\t\t= "sandbox_spl_test",
709 \t.platdata\t= &dtv_spl_test,
710 \t.platdata_size\t= sizeof(dtv_spl_test),
711 };
712
713 static const struct dtd_sandbox_spl_test dtv_spl_test2 = {
714 \t.intarray\t\t= 0x5,
715 };
716 U_BOOT_DEVICE(spl_test2) = {
717 \t.name\t\t= "sandbox_spl_test",
718 \t.platdata\t= &dtv_spl_test2,
719 \t.platdata_size\t= sizeof(dtv_spl_test2),
720 };
721
722 ''', data)
723
724     def testStdout(self):
725         """Test output to stdout"""
726         dtb_file = get_dtb_file('dtoc_test_simple.dts')
727         with test_util.capture_sys_output() as (stdout, stderr):
728             dtb_platdata.run_steps(['struct'], dtb_file, False, '-')
729
730     def testNoCommand(self):
731         """Test running dtoc without a command"""
732         with self.assertRaises(ValueError) as e:
733             dtb_platdata.run_steps([], '', False, '')
734         self.assertIn("Please specify a command: struct, platdata",
735                       str(e.exception))
736
737     def testBadCommand(self):
738         """Test running dtoc with an invalid command"""
739         dtb_file = get_dtb_file('dtoc_test_simple.dts')
740         output = tools.GetOutputFilename('output')
741         with self.assertRaises(ValueError) as e:
742             dtb_platdata.run_steps(['invalid-cmd'], dtb_file, False, output)
743         self.assertIn("Unknown command 'invalid-cmd': (use: struct, platdata)",
744                       str(e.exception))