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 16from patman import command 17from patman import 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 cc, args = tools.GetTargetCompileTool('cc') 72 args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__'] 73 args += ['-Ulinux'] 74 for path in search_paths: 75 args.extend(['-I', path]) 76 args += ['-o', dts_input, fname] 77 command.Run(cc, *args) 78 79 # If we don't have a directory, put it in the tools tempdir 80 search_list = [] 81 for path in search_paths: 82 search_list.extend(['-i', path]) 83 dtc, args = tools.GetTargetCompileTool('dtc') 84 args += ['-I', 'dts', '-o', dtb_output, '-O', 'dtb', 85 '-W', 'no-unit_address_vs_reg'] 86 args.extend(search_list) 87 args.append(dts_input) 88 command.Run(dtc, *args, capture_stderr=capture_stderr) 89 return dtb_output 90 91def GetInt(node, propname, default=None): 92 """Get an integer from a property 93 94 Args: 95 node: Node object to read from 96 propname: property name to read 97 default: Default value to use if the node/property do not exist 98 99 Returns: 100 Integer value read, or default if none 101 """ 102 prop = node.props.get(propname) 103 if not prop: 104 return default 105 if isinstance(prop.value, list): 106 raise ValueError("Node '%s' property '%s' has list value: expecting " 107 "a single integer" % (node.name, propname)) 108 value = fdt32_to_cpu(prop.value) 109 return value 110 111def GetString(node, propname, default=None): 112 """Get a string from a property 113 114 Args: 115 node: Node object to read from 116 propname: property name to read 117 default: Default value to use if the node/property do not exist 118 119 Returns: 120 String value read, or default if none 121 """ 122 prop = node.props.get(propname) 123 if not prop: 124 return default 125 value = prop.value 126 if isinstance(value, list): 127 raise ValueError("Node '%s' property '%s' has list value: expecting " 128 "a single string" % (node.name, propname)) 129 return value 130 131def GetBool(node, propname, default=False): 132 """Get an boolean from a property 133 134 Args: 135 node: Node object to read from 136 propname: property name to read 137 default: Default value to use if the node/property do not exist 138 139 Returns: 140 Boolean value read, or default if none (if you set this to True the 141 function will always return True) 142 """ 143 if propname in node.props: 144 return True 145 return default 146 147def GetByte(node, propname, default=None): 148 """Get an byte from a property 149 150 Args: 151 node: Node object to read from 152 propname: property name to read 153 default: Default value to use if the node/property do not exist 154 155 Returns: 156 Byte value read, or default if none 157 """ 158 prop = node.props.get(propname) 159 if not prop: 160 return default 161 value = prop.value 162 if isinstance(value, list): 163 raise ValueError("Node '%s' property '%s' has list value: expecting " 164 "a single byte" % (node.name, propname)) 165 if len(value) != 1: 166 raise ValueError("Node '%s' property '%s' has length %d, expecting %d" % 167 (node.name, propname, len(value), 1)) 168 return ord(value[0]) 169 170def GetPhandleList(node, propname): 171 """Get a list of phandles from a property 172 173 Args: 174 node: Node object to read from 175 propname: property name to read 176 177 Returns: 178 List of phandles read, each an integer 179 """ 180 prop = node.props.get(propname) 181 if not prop: 182 return None 183 value = prop.value 184 if not isinstance(value, list): 185 value = [value] 186 return [fdt32_to_cpu(v) for v in value] 187 188def GetDatatype(node, propname, datatype): 189 """Get a value of a given type from a property 190 191 Args: 192 node: Node object to read from 193 propname: property name to read 194 datatype: Type to read (str or int) 195 196 Returns: 197 value read, or None if none 198 199 Raises: 200 ValueError if datatype is not str or int 201 """ 202 if datatype == str: 203 return GetString(node, propname) 204 elif datatype == int: 205 return GetInt(node, propname) 206 raise ValueError("fdt_util internal error: Unknown data type '%s'" % 207 datatype) 208