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