blob: ce6d2585a4054a8f067ae357f80b7b18a9caa921 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass9d2eb922017-06-18 22:09:06 -06002# Copyright (c) 2012 The Chromium OS Authors.
3#
Simon Glass9d2eb922017-06-18 22:09:06 -06004
5"""Tests for the dtb_platdata module
6
Simon Glass70cd0d72018-07-06 10:27:20 -06007This includes unit tests for some functions and functional tests for the dtoc
8tool.
Simon Glass9d2eb922017-06-18 22:09:06 -06009"""
10
11import collections
12import os
13import struct
14import unittest
15
16import dtb_platdata
17from dtb_platdata import conv_name_to_c
18from dtb_platdata import get_compat_name
19from dtb_platdata import get_value
20from dtb_platdata import tab_to
21import fdt
22import fdt_util
23import tools
24
25our_path = os.path.dirname(os.path.realpath(__file__))
26
27
Simon Glasseb37e2d2017-11-12 21:52:17 -070028HEADER = '''/*
29 * DO NOT MODIFY
30 *
31 * This file was generated by dtoc from a .dtb (device tree binary) file.
32 */
33
34#include <stdbool.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090035#include <linux/libfdt.h>'''
Simon Glasseb37e2d2017-11-12 21:52:17 -070036
37C_HEADER = '''/*
38 * DO NOT MODIFY
39 *
40 * This file was generated by dtoc from a .dtb (device tree binary) file.
41 */
42
43#include <common.h>
44#include <dm.h>
45#include <dt-structs.h>
46'''
47
48
Simon Glass9d2eb922017-06-18 22:09:06 -060049def get_dtb_file(dts_fname):
50 """Compile a .dts file to a .dtb
51
52 Args:
53 dts_fname: Filename of .dts file in the current directory
54
55 Returns:
56 Filename of compiled file in output directory
57 """
58 return fdt_util.EnsureCompiled(os.path.join(our_path, dts_fname))
59
60
61class TestDtoc(unittest.TestCase):
62 """Tests for dtoc"""
63 @classmethod
64 def setUpClass(cls):
65 tools.PrepareOutputDir(None)
66
67 @classmethod
68 def tearDownClass(cls):
69 tools._RemoveOutputDir()
70
Simon Glassc47c2b32018-07-06 10:27:25 -060071 def _WritePythonString(self, fname, data):
72 """Write a string with tabs expanded as done in this Python file
73
74 Args:
75 fname: Filename to write to
76 data: Raw string to convert
77 """
78 data = data.replace('\t', '\\t')
79 with open(fname, 'w') as fd:
80 fd.write(data)
81
82 def _CheckStrings(self, expected, actual):
83 """Check that a string matches its expected value
84
85 If the strings do not match, they are written to the /tmp directory in
86 the same Python format as is used here in the test. This allows for
87 easy comparison and update of the tests.
88
89 Args:
90 expected: Expected string
91 actual: Actual string
92 """
93 if expected != actual:
94 self._WritePythonString('/tmp/binman.expected', expected)
95 self._WritePythonString('/tmp/binman.actual', actual)
96 print 'Failures written to /tmp/binman.{expected,actual}'
97 self.assertEquals(expected, actual)
98
Simon Glass9d2eb922017-06-18 22:09:06 -060099 def test_name(self):
100 """Test conversion of device tree names to C identifiers"""
101 self.assertEqual('serial_at_0x12', conv_name_to_c('serial@0x12'))
102 self.assertEqual('vendor_clock_frequency',
103 conv_name_to_c('vendor,clock-frequency'))
104 self.assertEqual('rockchip_rk3399_sdhci_5_1',
105 conv_name_to_c('rockchip,rk3399-sdhci-5.1'))
106
107 def test_tab_to(self):
108 """Test operation of tab_to() function"""
109 self.assertEqual('fred ', tab_to(0, 'fred'))
110 self.assertEqual('fred\t', tab_to(1, 'fred'))
111 self.assertEqual('fred was here ', tab_to(1, 'fred was here'))
112 self.assertEqual('fred was here\t\t', tab_to(3, 'fred was here'))
113 self.assertEqual('exactly8 ', tab_to(1, 'exactly8'))
114 self.assertEqual('exactly8\t', tab_to(2, 'exactly8'))
115
116 def test_get_value(self):
117 """Test operation of get_value() function"""
118 self.assertEqual('0x45',
119 get_value(fdt.TYPE_INT, struct.pack('>I', 0x45)))
120 self.assertEqual('0x45',
121 get_value(fdt.TYPE_BYTE, struct.pack('<I', 0x45)))
122 self.assertEqual('0x0',
123 get_value(fdt.TYPE_BYTE, struct.pack('>I', 0x45)))
124 self.assertEqual('"test"', get_value(fdt.TYPE_STRING, 'test'))
125 self.assertEqual('true', get_value(fdt.TYPE_BOOL, None))
126
127 def test_get_compat_name(self):
128 """Test operation of get_compat_name() function"""
129 Prop = collections.namedtuple('Prop', ['value'])
130 Node = collections.namedtuple('Node', ['props'])
131
132 prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1'])
133 node = Node({'compatible': prop})
134 self.assertEqual(('rockchip_rk3399_sdhci_5_1', ['arasan_sdhci_5_1']),
135 get_compat_name(node))
136
137 prop = Prop(['rockchip,rk3399-sdhci-5.1'])
138 node = Node({'compatible': prop})
139 self.assertEqual(('rockchip_rk3399_sdhci_5_1', []),
140 get_compat_name(node))
141
142 prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1', 'third'])
143 node = Node({'compatible': prop})
144 self.assertEqual(('rockchip_rk3399_sdhci_5_1',
145 ['arasan_sdhci_5_1', 'third']),
146 get_compat_name(node))
147
148 def test_empty_file(self):
149 """Test output from a device tree file with no nodes"""
150 dtb_file = get_dtb_file('dtoc_test_empty.dts')
151 output = tools.GetOutputFilename('output')
152 dtb_platdata.run_steps(['struct'], dtb_file, False, output)
153 with open(output) as infile:
154 lines = infile.read().splitlines()
Simon Glasseb37e2d2017-11-12 21:52:17 -0700155 self.assertEqual(HEADER.splitlines(), lines)
Simon Glass9d2eb922017-06-18 22:09:06 -0600156
157 dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
158 with open(output) as infile:
159 lines = infile.read().splitlines()
Simon Glasseb37e2d2017-11-12 21:52:17 -0700160 self.assertEqual(C_HEADER.splitlines() + [''], lines)
Simon Glass9d2eb922017-06-18 22:09:06 -0600161
162 def test_simple(self):
163 """Test output from some simple nodes with various types of data"""
164 dtb_file = get_dtb_file('dtoc_test_simple.dts')
165 output = tools.GetOutputFilename('output')
166 dtb_platdata.run_steps(['struct'], dtb_file, False, output)
167 with open(output) as infile:
168 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600169 self._CheckStrings(HEADER + '''
Simon Glass90e5f0a2017-08-29 14:15:51 -0600170struct dtd_sandbox_i2c_test {
171};
172struct dtd_sandbox_pmic_test {
173\tbool\t\tlow_power;
174\tfdt64_t\t\treg[2];
175};
Simon Glass9d2eb922017-06-18 22:09:06 -0600176struct dtd_sandbox_spl_test {
177\tbool\t\tboolval;
178\tunsigned char\tbytearray[3];
179\tunsigned char\tbyteval;
180\tfdt32_t\t\tintarray[4];
181\tfdt32_t\t\tintval;
182\tunsigned char\tlongbytearray[9];
183\tconst char *\tstringarray[3];
184\tconst char *\tstringval;
185};
186struct dtd_sandbox_spl_test_2 {
187};
188''', data)
189
190 dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
191 with open(output) as infile:
192 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600193 self._CheckStrings(C_HEADER + '''
Simon Glass9d2eb922017-06-18 22:09:06 -0600194static struct dtd_sandbox_spl_test dtv_spl_test = {
195\t.bytearray\t\t= {0x6, 0x0, 0x0},
196\t.byteval\t\t= 0x5,
197\t.intval\t\t\t= 0x1,
Simon Glass131e0b02017-08-29 14:15:49 -0600198\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
199\t\t0x11},
Simon Glass9d2eb922017-06-18 22:09:06 -0600200\t.stringval\t\t= "message",
201\t.boolval\t\t= true,
202\t.intarray\t\t= {0x2, 0x3, 0x4, 0x0},
203\t.stringarray\t\t= {"multi-word", "message", ""},
204};
205U_BOOT_DEVICE(spl_test) = {
206\t.name\t\t= "sandbox_spl_test",
207\t.platdata\t= &dtv_spl_test,
208\t.platdata_size\t= sizeof(dtv_spl_test),
209};
210
211static struct dtd_sandbox_spl_test dtv_spl_test2 = {
212\t.bytearray\t\t= {0x1, 0x23, 0x34},
213\t.byteval\t\t= 0x8,
214\t.intval\t\t\t= 0x3,
Simon Glass131e0b02017-08-29 14:15:49 -0600215\t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
216\t\t0x0},
Simon Glass9d2eb922017-06-18 22:09:06 -0600217\t.stringval\t\t= "message2",
218\t.intarray\t\t= {0x5, 0x0, 0x0, 0x0},
219\t.stringarray\t\t= {"another", "multi-word", "message"},
220};
221U_BOOT_DEVICE(spl_test2) = {
222\t.name\t\t= "sandbox_spl_test",
223\t.platdata\t= &dtv_spl_test2,
224\t.platdata_size\t= sizeof(dtv_spl_test2),
225};
226
227static struct dtd_sandbox_spl_test dtv_spl_test3 = {
228\t.stringarray\t\t= {"one", "", ""},
229};
230U_BOOT_DEVICE(spl_test3) = {
231\t.name\t\t= "sandbox_spl_test",
232\t.platdata\t= &dtv_spl_test3,
233\t.platdata_size\t= sizeof(dtv_spl_test3),
234};
235
236static struct dtd_sandbox_spl_test_2 dtv_spl_test4 = {
237};
238U_BOOT_DEVICE(spl_test4) = {
239\t.name\t\t= "sandbox_spl_test_2",
240\t.platdata\t= &dtv_spl_test4,
241\t.platdata_size\t= sizeof(dtv_spl_test4),
242};
243
Simon Glass90e5f0a2017-08-29 14:15:51 -0600244static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
245};
246U_BOOT_DEVICE(i2c_at_0) = {
247\t.name\t\t= "sandbox_i2c_test",
248\t.platdata\t= &dtv_i2c_at_0,
249\t.platdata_size\t= sizeof(dtv_i2c_at_0),
250};
251
252static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
253\t.low_power\t\t= true,
254\t.reg\t\t\t= {0x9, 0x0},
255};
256U_BOOT_DEVICE(pmic_at_9) = {
257\t.name\t\t= "sandbox_pmic_test",
258\t.platdata\t= &dtv_pmic_at_9,
259\t.platdata_size\t= sizeof(dtv_pmic_at_9),
260};
261
Simon Glass9d2eb922017-06-18 22:09:06 -0600262''', data)
263
264 def test_phandle(self):
265 """Test output from a node containing a phandle reference"""
266 dtb_file = get_dtb_file('dtoc_test_phandle.dts')
267 output = tools.GetOutputFilename('output')
268 dtb_platdata.run_steps(['struct'], dtb_file, False, output)
269 with open(output) as infile:
270 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600271 self._CheckStrings(HEADER + '''
Simon Glass9d2eb922017-06-18 22:09:06 -0600272struct dtd_source {
Simon Glass3deeb472017-08-29 14:15:59 -0600273\tstruct phandle_2_arg clocks[4];
Simon Glass9d2eb922017-06-18 22:09:06 -0600274};
275struct dtd_target {
276\tfdt32_t\t\tintval;
277};
278''', data)
279
280 dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
281 with open(output) as infile:
282 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600283 self._CheckStrings(C_HEADER + '''
Simon Glass9d2eb922017-06-18 22:09:06 -0600284static struct dtd_target dtv_phandle_target = {
Simon Glass3deeb472017-08-29 14:15:59 -0600285\t.intval\t\t\t= 0x0,
Simon Glass9d2eb922017-06-18 22:09:06 -0600286};
287U_BOOT_DEVICE(phandle_target) = {
288\t.name\t\t= "target",
289\t.platdata\t= &dtv_phandle_target,
290\t.platdata_size\t= sizeof(dtv_phandle_target),
291};
292
Simon Glass3deeb472017-08-29 14:15:59 -0600293static struct dtd_target dtv_phandle2_target = {
294\t.intval\t\t\t= 0x1,
295};
296U_BOOT_DEVICE(phandle2_target) = {
297\t.name\t\t= "target",
298\t.platdata\t= &dtv_phandle2_target,
299\t.platdata_size\t= sizeof(dtv_phandle2_target),
300};
301
302static struct dtd_target dtv_phandle3_target = {
303\t.intval\t\t\t= 0x2,
304};
305U_BOOT_DEVICE(phandle3_target) = {
306\t.name\t\t= "target",
307\t.platdata\t= &dtv_phandle3_target,
308\t.platdata_size\t= sizeof(dtv_phandle3_target),
309};
310
Simon Glass9d2eb922017-06-18 22:09:06 -0600311static struct dtd_source dtv_phandle_source = {
Simon Glassd0cd0752017-08-29 14:15:57 -0600312\t.clocks\t\t\t= {
Simon Glass3deeb472017-08-29 14:15:59 -0600313\t\t\t{&dtv_phandle_target, {}},
314\t\t\t{&dtv_phandle2_target, {11}},
315\t\t\t{&dtv_phandle3_target, {12, 13}},
316\t\t\t{&dtv_phandle_target, {}},},
Simon Glass9d2eb922017-06-18 22:09:06 -0600317};
318U_BOOT_DEVICE(phandle_source) = {
319\t.name\t\t= "source",
320\t.platdata\t= &dtv_phandle_source,
321\t.platdata_size\t= sizeof(dtv_phandle_source),
322};
323
324''', data)
325
326 def test_aliases(self):
327 """Test output from a node with multiple compatible strings"""
328 dtb_file = get_dtb_file('dtoc_test_aliases.dts')
329 output = tools.GetOutputFilename('output')
330 dtb_platdata.run_steps(['struct'], dtb_file, False, output)
331 with open(output) as infile:
332 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600333 self._CheckStrings(HEADER + '''
Simon Glass9d2eb922017-06-18 22:09:06 -0600334struct dtd_compat1 {
335\tfdt32_t\t\tintval;
336};
337#define dtd_compat2_1_fred dtd_compat1
338#define dtd_compat3 dtd_compat1
339''', data)
340
341 dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
342 with open(output) as infile:
343 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600344 self._CheckStrings(C_HEADER + '''
Simon Glass9d2eb922017-06-18 22:09:06 -0600345static struct dtd_compat1 dtv_spl_test = {
346\t.intval\t\t\t= 0x1,
347};
348U_BOOT_DEVICE(spl_test) = {
349\t.name\t\t= "compat1",
350\t.platdata\t= &dtv_spl_test,
351\t.platdata_size\t= sizeof(dtv_spl_test),
352};
353
354''', data)
Simon Glass1b1fe412017-08-29 14:15:50 -0600355
356 def test_addresses64(self):
357 """Test output from a node with a 'reg' property with na=2, ns=2"""
358 dtb_file = get_dtb_file('dtoc_test_addr64.dts')
359 output = tools.GetOutputFilename('output')
360 dtb_platdata.run_steps(['struct'], dtb_file, False, output)
361 with open(output) as infile:
362 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600363 self._CheckStrings(HEADER + '''
Simon Glass1b1fe412017-08-29 14:15:50 -0600364struct dtd_test1 {
365\tfdt64_t\t\treg[2];
366};
367struct dtd_test2 {
368\tfdt64_t\t\treg[2];
369};
370struct dtd_test3 {
371\tfdt64_t\t\treg[4];
372};
373''', data)
374
375 dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
376 with open(output) as infile:
377 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600378 self._CheckStrings(C_HEADER + '''
Simon Glass1b1fe412017-08-29 14:15:50 -0600379static struct dtd_test1 dtv_test1 = {
380\t.reg\t\t\t= {0x1234, 0x5678},
381};
382U_BOOT_DEVICE(test1) = {
383\t.name\t\t= "test1",
384\t.platdata\t= &dtv_test1,
385\t.platdata_size\t= sizeof(dtv_test1),
386};
387
388static struct dtd_test2 dtv_test2 = {
389\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
390};
391U_BOOT_DEVICE(test2) = {
392\t.name\t\t= "test2",
393\t.platdata\t= &dtv_test2,
394\t.platdata_size\t= sizeof(dtv_test2),
395};
396
397static struct dtd_test3 dtv_test3 = {
398\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
399};
400U_BOOT_DEVICE(test3) = {
401\t.name\t\t= "test3",
402\t.platdata\t= &dtv_test3,
403\t.platdata_size\t= sizeof(dtv_test3),
404};
405
406''', data)
407
408 def test_addresses32(self):
409 """Test output from a node with a 'reg' property with na=1, ns=1"""
410 dtb_file = get_dtb_file('dtoc_test_addr32.dts')
411 output = tools.GetOutputFilename('output')
412 dtb_platdata.run_steps(['struct'], dtb_file, False, output)
413 with open(output) as infile:
414 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600415 self._CheckStrings(HEADER + '''
Simon Glass1b1fe412017-08-29 14:15:50 -0600416struct dtd_test1 {
417\tfdt32_t\t\treg[2];
418};
419struct dtd_test2 {
420\tfdt32_t\t\treg[4];
421};
422''', data)
423
424 dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
425 with open(output) as infile:
426 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600427 self._CheckStrings(C_HEADER + '''
Simon Glass1b1fe412017-08-29 14:15:50 -0600428static struct dtd_test1 dtv_test1 = {
429\t.reg\t\t\t= {0x1234, 0x5678},
430};
431U_BOOT_DEVICE(test1) = {
432\t.name\t\t= "test1",
433\t.platdata\t= &dtv_test1,
434\t.platdata_size\t= sizeof(dtv_test1),
435};
436
437static struct dtd_test2 dtv_test2 = {
438\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
439};
440U_BOOT_DEVICE(test2) = {
441\t.name\t\t= "test2",
442\t.platdata\t= &dtv_test2,
443\t.platdata_size\t= sizeof(dtv_test2),
444};
445
446''', data)
447
448 def test_addresses64_32(self):
449 """Test output from a node with a 'reg' property with na=2, ns=1"""
450 dtb_file = get_dtb_file('dtoc_test_addr64_32.dts')
451 output = tools.GetOutputFilename('output')
452 dtb_platdata.run_steps(['struct'], dtb_file, False, output)
453 with open(output) as infile:
454 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600455 self._CheckStrings(HEADER + '''
Simon Glass1b1fe412017-08-29 14:15:50 -0600456struct dtd_test1 {
457\tfdt64_t\t\treg[2];
458};
459struct dtd_test2 {
460\tfdt64_t\t\treg[2];
461};
462struct dtd_test3 {
463\tfdt64_t\t\treg[4];
464};
465''', data)
466
467 dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
468 with open(output) as infile:
469 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600470 self._CheckStrings(C_HEADER + '''
Simon Glass1b1fe412017-08-29 14:15:50 -0600471static struct dtd_test1 dtv_test1 = {
472\t.reg\t\t\t= {0x123400000000, 0x5678},
473};
474U_BOOT_DEVICE(test1) = {
475\t.name\t\t= "test1",
476\t.platdata\t= &dtv_test1,
477\t.platdata_size\t= sizeof(dtv_test1),
478};
479
480static struct dtd_test2 dtv_test2 = {
481\t.reg\t\t\t= {0x1234567890123456, 0x98765432},
482};
483U_BOOT_DEVICE(test2) = {
484\t.name\t\t= "test2",
485\t.platdata\t= &dtv_test2,
486\t.platdata_size\t= sizeof(dtv_test2),
487};
488
489static struct dtd_test3 dtv_test3 = {
490\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
491};
492U_BOOT_DEVICE(test3) = {
493\t.name\t\t= "test3",
494\t.platdata\t= &dtv_test3,
495\t.platdata_size\t= sizeof(dtv_test3),
496};
497
498''', data)
499
500 def test_addresses32_64(self):
501 """Test output from a node with a 'reg' property with na=1, ns=2"""
502 dtb_file = get_dtb_file('dtoc_test_addr32_64.dts')
503 output = tools.GetOutputFilename('output')
504 dtb_platdata.run_steps(['struct'], dtb_file, False, output)
505 with open(output) as infile:
506 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600507 self._CheckStrings(HEADER + '''
Simon Glass1b1fe412017-08-29 14:15:50 -0600508struct dtd_test1 {
509\tfdt64_t\t\treg[2];
510};
511struct dtd_test2 {
512\tfdt64_t\t\treg[2];
513};
514struct dtd_test3 {
515\tfdt64_t\t\treg[4];
516};
517''', data)
518
519 dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
520 with open(output) as infile:
521 data = infile.read()
Simon Glassc47c2b32018-07-06 10:27:25 -0600522 self._CheckStrings(C_HEADER + '''
Simon Glass1b1fe412017-08-29 14:15:50 -0600523static struct dtd_test1 dtv_test1 = {
524\t.reg\t\t\t= {0x1234, 0x567800000000},
525};
526U_BOOT_DEVICE(test1) = {
527\t.name\t\t= "test1",
528\t.platdata\t= &dtv_test1,
529\t.platdata_size\t= sizeof(dtv_test1),
530};
531
532static struct dtd_test2 dtv_test2 = {
533\t.reg\t\t\t= {0x12345678, 0x9876543210987654},
534};
535U_BOOT_DEVICE(test2) = {
536\t.name\t\t= "test2",
537\t.platdata\t= &dtv_test2,
538\t.platdata_size\t= sizeof(dtv_test2),
539};
540
541static struct dtd_test3 dtv_test3 = {
542\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
543};
544U_BOOT_DEVICE(test3) = {
545\t.name\t\t= "test3",
546\t.platdata\t= &dtv_test3,
547\t.platdata_size\t= sizeof(dtv_test3),
548};
549
550''', data)