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