1# 2# Copyright (c) 2012 The Chromium OS Authors. 3# 4# SPDX-License-Identifier: GPL-2.0+ 5# 6 7"""Tests for the dtb_platdata module 8 9This includes unit tests for some functions and functional tests for 10""" 11 12import collections 13import os 14import struct 15import unittest 16 17import dtb_platdata 18from dtb_platdata import conv_name_to_c 19from dtb_platdata import get_compat_name 20from dtb_platdata import get_value 21from dtb_platdata import tab_to 22import fdt 23import fdt_util 24import tools 25 26our_path = os.path.dirname(os.path.realpath(__file__)) 27 28 29HEADER = '''/* 30 * DO NOT MODIFY 31 * 32 * This file was generated by dtoc from a .dtb (device tree binary) file. 33 */ 34 35#include <stdbool.h> 36#include <libfdt.h>''' 37 38C_HEADER = '''/* 39 * DO NOT MODIFY 40 * 41 * This file was generated by dtoc from a .dtb (device tree binary) file. 42 */ 43 44#include <common.h> 45#include <dm.h> 46#include <dt-structs.h> 47''' 48 49 50def get_dtb_file(dts_fname): 51 """Compile a .dts file to a .dtb 52 53 Args: 54 dts_fname: Filename of .dts file in the current directory 55 56 Returns: 57 Filename of compiled file in output directory 58 """ 59 return fdt_util.EnsureCompiled(os.path.join(our_path, dts_fname)) 60 61 62class TestDtoc(unittest.TestCase): 63 """Tests for dtoc""" 64 @classmethod 65 def setUpClass(cls): 66 tools.PrepareOutputDir(None) 67 68 @classmethod 69 def tearDownClass(cls): 70 tools._RemoveOutputDir() 71 72 def test_name(self): 73 """Test conversion of device tree names to C identifiers""" 74 self.assertEqual('serial_at_0x12', conv_name_to_c('serial@0x12')) 75 self.assertEqual('vendor_clock_frequency', 76 conv_name_to_c('vendor,clock-frequency')) 77 self.assertEqual('rockchip_rk3399_sdhci_5_1', 78 conv_name_to_c('rockchip,rk3399-sdhci-5.1')) 79 80 def test_tab_to(self): 81 """Test operation of tab_to() function""" 82 self.assertEqual('fred ', tab_to(0, 'fred')) 83 self.assertEqual('fred\t', tab_to(1, 'fred')) 84 self.assertEqual('fred was here ', tab_to(1, 'fred was here')) 85 self.assertEqual('fred was here\t\t', tab_to(3, 'fred was here')) 86 self.assertEqual('exactly8 ', tab_to(1, 'exactly8')) 87 self.assertEqual('exactly8\t', tab_to(2, 'exactly8')) 88 89 def test_get_value(self): 90 """Test operation of get_value() function""" 91 self.assertEqual('0x45', 92 get_value(fdt.TYPE_INT, struct.pack('>I', 0x45))) 93 self.assertEqual('0x45', 94 get_value(fdt.TYPE_BYTE, struct.pack('<I', 0x45))) 95 self.assertEqual('0x0', 96 get_value(fdt.TYPE_BYTE, struct.pack('>I', 0x45))) 97 self.assertEqual('"test"', get_value(fdt.TYPE_STRING, 'test')) 98 self.assertEqual('true', get_value(fdt.TYPE_BOOL, None)) 99 100 def test_get_compat_name(self): 101 """Test operation of get_compat_name() function""" 102 Prop = collections.namedtuple('Prop', ['value']) 103 Node = collections.namedtuple('Node', ['props']) 104 105 prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1']) 106 node = Node({'compatible': prop}) 107 self.assertEqual(('rockchip_rk3399_sdhci_5_1', ['arasan_sdhci_5_1']), 108 get_compat_name(node)) 109 110 prop = Prop(['rockchip,rk3399-sdhci-5.1']) 111 node = Node({'compatible': prop}) 112 self.assertEqual(('rockchip_rk3399_sdhci_5_1', []), 113 get_compat_name(node)) 114 115 prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1', 'third']) 116 node = Node({'compatible': prop}) 117 self.assertEqual(('rockchip_rk3399_sdhci_5_1', 118 ['arasan_sdhci_5_1', 'third']), 119 get_compat_name(node)) 120 121 def test_empty_file(self): 122 """Test output from a device tree file with no nodes""" 123 dtb_file = get_dtb_file('dtoc_test_empty.dts') 124 output = tools.GetOutputFilename('output') 125 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 126 with open(output) as infile: 127 lines = infile.read().splitlines() 128 self.assertEqual(HEADER.splitlines(), lines) 129 130 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 131 with open(output) as infile: 132 lines = infile.read().splitlines() 133 self.assertEqual(C_HEADER.splitlines() + [''], lines) 134 135 def test_simple(self): 136 """Test output from some simple nodes with various types of data""" 137 dtb_file = get_dtb_file('dtoc_test_simple.dts') 138 output = tools.GetOutputFilename('output') 139 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 140 with open(output) as infile: 141 data = infile.read() 142 self.assertEqual(HEADER + ''' 143struct dtd_sandbox_i2c_test { 144}; 145struct dtd_sandbox_pmic_test { 146\tbool\t\tlow_power; 147\tfdt64_t\t\treg[2]; 148}; 149struct dtd_sandbox_spl_test { 150\tbool\t\tboolval; 151\tunsigned char\tbytearray[3]; 152\tunsigned char\tbyteval; 153\tfdt32_t\t\tintarray[4]; 154\tfdt32_t\t\tintval; 155\tunsigned char\tlongbytearray[9]; 156\tconst char *\tstringarray[3]; 157\tconst char *\tstringval; 158}; 159struct dtd_sandbox_spl_test_2 { 160}; 161''', data) 162 163 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 164 with open(output) as infile: 165 data = infile.read() 166 self.assertEqual(C_HEADER + ''' 167static struct dtd_sandbox_spl_test dtv_spl_test = { 168\t.bytearray\t\t= {0x6, 0x0, 0x0}, 169\t.byteval\t\t= 0x5, 170\t.intval\t\t\t= 0x1, 171\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 172\t\t0x11}, 173\t.stringval\t\t= "message", 174\t.boolval\t\t= true, 175\t.intarray\t\t= {0x2, 0x3, 0x4, 0x0}, 176\t.stringarray\t\t= {"multi-word", "message", ""}, 177}; 178U_BOOT_DEVICE(spl_test) = { 179\t.name\t\t= "sandbox_spl_test", 180\t.platdata\t= &dtv_spl_test, 181\t.platdata_size\t= sizeof(dtv_spl_test), 182}; 183 184static struct dtd_sandbox_spl_test dtv_spl_test2 = { 185\t.bytearray\t\t= {0x1, 0x23, 0x34}, 186\t.byteval\t\t= 0x8, 187\t.intval\t\t\t= 0x3, 188\t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 189\t\t0x0}, 190\t.stringval\t\t= "message2", 191\t.intarray\t\t= {0x5, 0x0, 0x0, 0x0}, 192\t.stringarray\t\t= {"another", "multi-word", "message"}, 193}; 194U_BOOT_DEVICE(spl_test2) = { 195\t.name\t\t= "sandbox_spl_test", 196\t.platdata\t= &dtv_spl_test2, 197\t.platdata_size\t= sizeof(dtv_spl_test2), 198}; 199 200static struct dtd_sandbox_spl_test dtv_spl_test3 = { 201\t.stringarray\t\t= {"one", "", ""}, 202}; 203U_BOOT_DEVICE(spl_test3) = { 204\t.name\t\t= "sandbox_spl_test", 205\t.platdata\t= &dtv_spl_test3, 206\t.platdata_size\t= sizeof(dtv_spl_test3), 207}; 208 209static struct dtd_sandbox_spl_test_2 dtv_spl_test4 = { 210}; 211U_BOOT_DEVICE(spl_test4) = { 212\t.name\t\t= "sandbox_spl_test_2", 213\t.platdata\t= &dtv_spl_test4, 214\t.platdata_size\t= sizeof(dtv_spl_test4), 215}; 216 217static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = { 218}; 219U_BOOT_DEVICE(i2c_at_0) = { 220\t.name\t\t= "sandbox_i2c_test", 221\t.platdata\t= &dtv_i2c_at_0, 222\t.platdata_size\t= sizeof(dtv_i2c_at_0), 223}; 224 225static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = { 226\t.low_power\t\t= true, 227\t.reg\t\t\t= {0x9, 0x0}, 228}; 229U_BOOT_DEVICE(pmic_at_9) = { 230\t.name\t\t= "sandbox_pmic_test", 231\t.platdata\t= &dtv_pmic_at_9, 232\t.platdata_size\t= sizeof(dtv_pmic_at_9), 233}; 234 235''', data) 236 237 def test_phandle(self): 238 """Test output from a node containing a phandle reference""" 239 dtb_file = get_dtb_file('dtoc_test_phandle.dts') 240 output = tools.GetOutputFilename('output') 241 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 242 with open(output) as infile: 243 data = infile.read() 244 self.assertEqual(HEADER + ''' 245struct dtd_source { 246\tstruct phandle_2_arg clocks[4]; 247}; 248struct dtd_target { 249\tfdt32_t\t\tintval; 250}; 251''', data) 252 253 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 254 with open(output) as infile: 255 data = infile.read() 256 self.assertEqual(C_HEADER + ''' 257static struct dtd_target dtv_phandle_target = { 258\t.intval\t\t\t= 0x0, 259}; 260U_BOOT_DEVICE(phandle_target) = { 261\t.name\t\t= "target", 262\t.platdata\t= &dtv_phandle_target, 263\t.platdata_size\t= sizeof(dtv_phandle_target), 264}; 265 266static struct dtd_target dtv_phandle2_target = { 267\t.intval\t\t\t= 0x1, 268}; 269U_BOOT_DEVICE(phandle2_target) = { 270\t.name\t\t= "target", 271\t.platdata\t= &dtv_phandle2_target, 272\t.platdata_size\t= sizeof(dtv_phandle2_target), 273}; 274 275static struct dtd_target dtv_phandle3_target = { 276\t.intval\t\t\t= 0x2, 277}; 278U_BOOT_DEVICE(phandle3_target) = { 279\t.name\t\t= "target", 280\t.platdata\t= &dtv_phandle3_target, 281\t.platdata_size\t= sizeof(dtv_phandle3_target), 282}; 283 284static struct dtd_source dtv_phandle_source = { 285\t.clocks\t\t\t= { 286\t\t\t{&dtv_phandle_target, {}}, 287\t\t\t{&dtv_phandle2_target, {11}}, 288\t\t\t{&dtv_phandle3_target, {12, 13}}, 289\t\t\t{&dtv_phandle_target, {}},}, 290}; 291U_BOOT_DEVICE(phandle_source) = { 292\t.name\t\t= "source", 293\t.platdata\t= &dtv_phandle_source, 294\t.platdata_size\t= sizeof(dtv_phandle_source), 295}; 296 297''', data) 298 299 def test_aliases(self): 300 """Test output from a node with multiple compatible strings""" 301 dtb_file = get_dtb_file('dtoc_test_aliases.dts') 302 output = tools.GetOutputFilename('output') 303 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 304 with open(output) as infile: 305 data = infile.read() 306 self.assertEqual(HEADER + ''' 307struct dtd_compat1 { 308\tfdt32_t\t\tintval; 309}; 310#define dtd_compat2_1_fred dtd_compat1 311#define dtd_compat3 dtd_compat1 312''', data) 313 314 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 315 with open(output) as infile: 316 data = infile.read() 317 self.assertEqual(C_HEADER + ''' 318static struct dtd_compat1 dtv_spl_test = { 319\t.intval\t\t\t= 0x1, 320}; 321U_BOOT_DEVICE(spl_test) = { 322\t.name\t\t= "compat1", 323\t.platdata\t= &dtv_spl_test, 324\t.platdata_size\t= sizeof(dtv_spl_test), 325}; 326 327''', data) 328 329 def test_addresses64(self): 330 """Test output from a node with a 'reg' property with na=2, ns=2""" 331 dtb_file = get_dtb_file('dtoc_test_addr64.dts') 332 output = tools.GetOutputFilename('output') 333 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 334 with open(output) as infile: 335 data = infile.read() 336 self.assertEqual(HEADER + ''' 337struct dtd_test1 { 338\tfdt64_t\t\treg[2]; 339}; 340struct dtd_test2 { 341\tfdt64_t\t\treg[2]; 342}; 343struct dtd_test3 { 344\tfdt64_t\t\treg[4]; 345}; 346''', data) 347 348 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 349 with open(output) as infile: 350 data = infile.read() 351 self.assertEqual(C_HEADER + ''' 352static struct dtd_test1 dtv_test1 = { 353\t.reg\t\t\t= {0x1234, 0x5678}, 354}; 355U_BOOT_DEVICE(test1) = { 356\t.name\t\t= "test1", 357\t.platdata\t= &dtv_test1, 358\t.platdata_size\t= sizeof(dtv_test1), 359}; 360 361static struct dtd_test2 dtv_test2 = { 362\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654}, 363}; 364U_BOOT_DEVICE(test2) = { 365\t.name\t\t= "test2", 366\t.platdata\t= &dtv_test2, 367\t.platdata_size\t= sizeof(dtv_test2), 368}; 369 370static struct dtd_test3 dtv_test3 = { 371\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3}, 372}; 373U_BOOT_DEVICE(test3) = { 374\t.name\t\t= "test3", 375\t.platdata\t= &dtv_test3, 376\t.platdata_size\t= sizeof(dtv_test3), 377}; 378 379''', data) 380 381 def test_addresses32(self): 382 """Test output from a node with a 'reg' property with na=1, ns=1""" 383 dtb_file = get_dtb_file('dtoc_test_addr32.dts') 384 output = tools.GetOutputFilename('output') 385 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 386 with open(output) as infile: 387 data = infile.read() 388 self.assertEqual(HEADER + ''' 389struct dtd_test1 { 390\tfdt32_t\t\treg[2]; 391}; 392struct dtd_test2 { 393\tfdt32_t\t\treg[4]; 394}; 395''', data) 396 397 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 398 with open(output) as infile: 399 data = infile.read() 400 self.assertEqual(C_HEADER + ''' 401static struct dtd_test1 dtv_test1 = { 402\t.reg\t\t\t= {0x1234, 0x5678}, 403}; 404U_BOOT_DEVICE(test1) = { 405\t.name\t\t= "test1", 406\t.platdata\t= &dtv_test1, 407\t.platdata_size\t= sizeof(dtv_test1), 408}; 409 410static struct dtd_test2 dtv_test2 = { 411\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3}, 412}; 413U_BOOT_DEVICE(test2) = { 414\t.name\t\t= "test2", 415\t.platdata\t= &dtv_test2, 416\t.platdata_size\t= sizeof(dtv_test2), 417}; 418 419''', data) 420 421 def test_addresses64_32(self): 422 """Test output from a node with a 'reg' property with na=2, ns=1""" 423 dtb_file = get_dtb_file('dtoc_test_addr64_32.dts') 424 output = tools.GetOutputFilename('output') 425 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 426 with open(output) as infile: 427 data = infile.read() 428 self.assertEqual(HEADER + ''' 429struct dtd_test1 { 430\tfdt64_t\t\treg[2]; 431}; 432struct dtd_test2 { 433\tfdt64_t\t\treg[2]; 434}; 435struct dtd_test3 { 436\tfdt64_t\t\treg[4]; 437}; 438''', data) 439 440 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 441 with open(output) as infile: 442 data = infile.read() 443 self.assertEqual(C_HEADER + ''' 444static struct dtd_test1 dtv_test1 = { 445\t.reg\t\t\t= {0x123400000000, 0x5678}, 446}; 447U_BOOT_DEVICE(test1) = { 448\t.name\t\t= "test1", 449\t.platdata\t= &dtv_test1, 450\t.platdata_size\t= sizeof(dtv_test1), 451}; 452 453static struct dtd_test2 dtv_test2 = { 454\t.reg\t\t\t= {0x1234567890123456, 0x98765432}, 455}; 456U_BOOT_DEVICE(test2) = { 457\t.name\t\t= "test2", 458\t.platdata\t= &dtv_test2, 459\t.platdata_size\t= sizeof(dtv_test2), 460}; 461 462static struct dtd_test3 dtv_test3 = { 463\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3}, 464}; 465U_BOOT_DEVICE(test3) = { 466\t.name\t\t= "test3", 467\t.platdata\t= &dtv_test3, 468\t.platdata_size\t= sizeof(dtv_test3), 469}; 470 471''', data) 472 473 def test_addresses32_64(self): 474 """Test output from a node with a 'reg' property with na=1, ns=2""" 475 dtb_file = get_dtb_file('dtoc_test_addr32_64.dts') 476 output = tools.GetOutputFilename('output') 477 dtb_platdata.run_steps(['struct'], dtb_file, False, output) 478 with open(output) as infile: 479 data = infile.read() 480 self.assertEqual(HEADER + ''' 481struct dtd_test1 { 482\tfdt64_t\t\treg[2]; 483}; 484struct dtd_test2 { 485\tfdt64_t\t\treg[2]; 486}; 487struct dtd_test3 { 488\tfdt64_t\t\treg[4]; 489}; 490''', data) 491 492 dtb_platdata.run_steps(['platdata'], dtb_file, False, output) 493 with open(output) as infile: 494 data = infile.read() 495 self.assertEqual(C_HEADER + ''' 496static struct dtd_test1 dtv_test1 = { 497\t.reg\t\t\t= {0x1234, 0x567800000000}, 498}; 499U_BOOT_DEVICE(test1) = { 500\t.name\t\t= "test1", 501\t.platdata\t= &dtv_test1, 502\t.platdata_size\t= sizeof(dtv_test1), 503}; 504 505static struct dtd_test2 dtv_test2 = { 506\t.reg\t\t\t= {0x12345678, 0x9876543210987654}, 507}; 508U_BOOT_DEVICE(test2) = { 509\t.name\t\t= "test2", 510\t.platdata\t= &dtv_test2, 511\t.platdata_size\t= sizeof(dtv_test2), 512}; 513 514static struct dtd_test3 dtv_test3 = { 515\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3}, 516}; 517U_BOOT_DEVICE(test3) = { 518\t.name\t\t= "test3", 519\t.platdata\t= &dtv_test3, 520\t.platdata_size\t= sizeof(dtv_test3), 521}; 522 523''', data) 524