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