1#!/usr/bin/python 2# SPDX-License-Identifier: GPL-2.0+ 3# 4# Copyright (C) 2016 Google, Inc 5# Written by Simon Glass <sjg@chromium.org> 6# 7 8# Utility functions for reading from a device tree. Once the upstream pylibfdt 9# implementation advances far enough, we should be able to drop these. 10 11import os 12import struct 13import sys 14import tempfile 15 16import command 17import tools 18 19def fdt32_to_cpu(val): 20 """Convert a device tree cell to an integer 21 22 Args: 23 Value to convert (4-character string representing the cell value) 24 25 Return: 26 A native-endian integer value 27 """ 28 return struct.unpack('>I', val)[0] 29 30def fdt_cells_to_cpu(val, cells): 31 """Convert one or two cells to a long integer 32 33 Args: 34 Value to convert (array of one or more 4-character strings) 35 36 Return: 37 A native-endian integer value 38 """ 39 if not cells: 40 return 0 41 out = int(fdt32_to_cpu(val[0])) 42 if cells == 2: 43 out = out << 32 | fdt32_to_cpu(val[1]) 44 return out 45 46def EnsureCompiled(fname, tmpdir=None, capture_stderr=False): 47 """Compile an fdt .dts source file into a .dtb binary blob if needed. 48 49 Args: 50 fname: Filename (if .dts it will be compiled). It not it will be 51 left alone 52 tmpdir: Temporary directory for output files, or None to use the 53 tools-module output directory 54 55 Returns: 56 Filename of resulting .dtb file 57 """ 58 _, ext = os.path.splitext(fname) 59 if ext != '.dts': 60 return fname 61 62 if tmpdir: 63 dts_input = os.path.join(tmpdir, 'source.dts') 64 dtb_output = os.path.join(tmpdir, 'source.dtb') 65 else: 66 dts_input = tools.GetOutputFilename('source.dts') 67 dtb_output = tools.GetOutputFilename('source.dtb') 68 69 search_paths = [os.path.join(os.getcwd(), 'include')] 70 root, _ = os.path.splitext(fname) 71 args = ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__'] 72 args += ['-Ulinux'] 73 for path in search_paths: 74 args.extend(['-I', path]) 75 args += ['-o', dts_input, fname] 76 command.Run('cc', *args) 77 78 # If we don't have a directory, put it in the tools tempdir 79 search_list = [] 80 for path in search_paths: 81 search_list.extend(['-i', path]) 82 args = ['-I', 'dts', '-o', dtb_output, '-O', 'dtb', 83 '-W', 'no-unit_address_vs_reg'] 84 args.extend(search_list) 85 args.append(dts_input) 86 dtc = os.environ.get('DTC') or 'dtc' 87 command.Run(dtc, *args, capture_stderr=capture_stderr) 88 return dtb_output 89 90def GetInt(node, propname, default=None): 91 """Get an integer from a property 92 93 Args: 94 node: Node object to read from 95 propname: property name to read 96 default: Default value to use if the node/property do not exist 97 98 Returns: 99 Integer value read, or default if none 100 """ 101 prop = node.props.get(propname) 102 if not prop: 103 return default 104 if isinstance(prop.value, list): 105 raise ValueError("Node '%s' property '%s' has list value: expecting " 106 "a single integer" % (node.name, propname)) 107 value = fdt32_to_cpu(prop.value) 108 return value 109 110def GetString(node, propname, default=None): 111 """Get a string from a property 112 113 Args: 114 node: Node object to read from 115 propname: property name to read 116 default: Default value to use if the node/property do not exist 117 118 Returns: 119 String value read, or default if none 120 """ 121 prop = node.props.get(propname) 122 if not prop: 123 return default 124 value = prop.value 125 if isinstance(value, list): 126 raise ValueError("Node '%s' property '%s' has list value: expecting " 127 "a single string" % (node.name, propname)) 128 return value 129 130def GetBool(node, propname, default=False): 131 """Get an boolean from a property 132 133 Args: 134 node: Node object to read from 135 propname: property name to read 136 default: Default value to use if the node/property do not exist 137 138 Returns: 139 Boolean value read, or default if none (if you set this to True the 140 function will always return True) 141 """ 142 if propname in node.props: 143 return True 144 return default 145 146def GetByte(node, propname, default=None): 147 """Get an byte from a property 148 149 Args: 150 node: Node object to read from 151 propname: property name to read 152 default: Default value to use if the node/property do not exist 153 154 Returns: 155 Byte value read, or default if none 156 """ 157 prop = node.props.get(propname) 158 if not prop: 159 return default 160 value = prop.value 161 if isinstance(value, list): 162 raise ValueError("Node '%s' property '%s' has list value: expecting " 163 "a single byte" % (node.name, propname)) 164 if len(value) != 1: 165 raise ValueError("Node '%s' property '%s' has length %d, expecting %d" % 166 (node.name, propname, len(value), 1)) 167 return ord(value[0]) 168 169def GetPhandleList(node, propname): 170 """Get a list of phandles from a property 171 172 Args: 173 node: Node object to read from 174 propname: property name to read 175 176 Returns: 177 List of phandles read, each an integer 178 """ 179 prop = node.props.get(propname) 180 if not prop: 181 return None 182 value = prop.value 183 if not isinstance(value, list): 184 value = [value] 185 return [fdt32_to_cpu(v) for v in value] 186 187def GetDatatype(node, propname, datatype): 188 """Get a value of a given type from a property 189 190 Args: 191 node: Node object to read from 192 propname: property name to read 193 datatype: Type to read (str or int) 194 195 Returns: 196 value read, or None if none 197 198 Raises: 199 ValueError if datatype is not str or int 200 """ 201 if datatype == str: 202 return GetString(node, propname) 203 elif datatype == int: 204 return GetInt(node, propname) 205 raise ValueError("fdt_util internal error: Unknown data type '%s'" % 206 datatype) 207