fdt_util.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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. # Utility functions for reading from a device tree. Once the upstream pylibfdt
  8. # implementation advances far enough, we should be able to drop these.
  9. import os
  10. import struct
  11. import sys
  12. import tempfile
  13. from u_boot_pylib import command
  14. from u_boot_pylib import tools
  15. def fdt32_to_cpu(val):
  16. """Convert a device tree cell to an integer
  17. Args:
  18. Value to convert (4-character string representing the cell value)
  19. Return:
  20. A native-endian integer value
  21. """
  22. return struct.unpack('>I', val)[0]
  23. def fdt64_to_cpu(val):
  24. """Convert a device tree cell to an integer
  25. Args:
  26. val (list): Value to convert (list of 2 4-character strings representing
  27. the cell value)
  28. Return:
  29. int: A native-endian integer value
  30. """
  31. return fdt32_to_cpu(val[0]) << 32 | fdt32_to_cpu(val[1])
  32. def fdt_cells_to_cpu(val, cells):
  33. """Convert one or two cells to a long integer
  34. Args:
  35. Value to convert (array of one or more 4-character strings)
  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. def EnsureCompiled(fname, tmpdir=None, capture_stderr=False):
  46. """Compile an fdt .dts source file into a .dtb binary blob if needed.
  47. Args:
  48. fname: Filename (if .dts it will be compiled). It not it will be
  49. left alone
  50. tmpdir: Temporary directory for output files, or None to use the
  51. tools-module output directory
  52. Returns:
  53. Filename of resulting .dtb file
  54. """
  55. _, ext = os.path.splitext(fname)
  56. if ext != '.dts':
  57. return fname
  58. if tmpdir:
  59. dts_input = os.path.join(tmpdir, 'source.dts')
  60. dtb_output = os.path.join(tmpdir, 'source.dtb')
  61. else:
  62. dts_input = tools.get_output_filename('source.dts')
  63. dtb_output = tools.get_output_filename('source.dtb')
  64. search_paths = [os.path.join(os.getcwd(), 'include')]
  65. root, _ = os.path.splitext(fname)
  66. cc, args = tools.get_target_compile_tool('cc')
  67. args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__']
  68. args += ['-Ulinux']
  69. for path in search_paths:
  70. args.extend(['-I', path])
  71. args += ['-o', dts_input, fname]
  72. command.run(cc, *args)
  73. # If we don't have a directory, put it in the tools tempdir
  74. search_list = []
  75. for path in search_paths:
  76. search_list.extend(['-i', path])
  77. dtc, args = tools.get_target_compile_tool('dtc')
  78. args += ['-I', 'dts', '-o', dtb_output, '-O', 'dtb',
  79. '-W', 'no-unit_address_vs_reg']
  80. args.extend(search_list)
  81. args.append(dts_input)
  82. command.run(dtc, *args, capture_stderr=capture_stderr)
  83. return dtb_output
  84. def GetInt(node, propname, default=None):
  85. """Get an integer from a property
  86. Args:
  87. node: Node object to read from
  88. propname: property name to read
  89. default: Default value to use if the node/property do not exist
  90. Returns:
  91. Integer value read, or default if none
  92. """
  93. prop = node.props.get(propname)
  94. if not prop:
  95. return default
  96. if isinstance(prop.value, list):
  97. raise ValueError("Node '%s' property '%s' has list value: expecting "
  98. "a single integer" % (node.name, propname))
  99. value = fdt32_to_cpu(prop.value)
  100. return value
  101. def GetInt64(node, propname, default=None):
  102. """Get a 64-bit integer from a property
  103. Args:
  104. node (Node): Node object to read from
  105. propname (str): property name to read
  106. default (int): Default value to use if the node/property do not exist
  107. Returns:
  108. int: value read, or default if none
  109. Raises:
  110. ValueError: Property is not of the correct size
  111. """
  112. prop = node.props.get(propname)
  113. if not prop:
  114. return default
  115. if not isinstance(prop.value, list) or len(prop.value) != 2:
  116. raise ValueError("Node '%s' property '%s' should be a list with 2 items for 64-bit values" %
  117. (node.name, propname))
  118. value = fdt64_to_cpu(prop.value)
  119. return value
  120. def GetString(node, propname, default=None):
  121. """Get a string from a property
  122. Args:
  123. node: Node object to read from
  124. propname: property name to read
  125. default: Default value to use if the node/property do not exist
  126. Returns:
  127. String value read, or default if none
  128. """
  129. prop = node.props.get(propname)
  130. if not prop:
  131. return default
  132. value = prop.value
  133. if not prop.bytes:
  134. return ''
  135. if isinstance(value, list):
  136. raise ValueError("Node '%s' property '%s' has list value: expecting "
  137. "a single string" % (node.name, propname))
  138. return value
  139. def GetStringList(node, propname, default=None):
  140. """Get a string list from a property
  141. Args:
  142. node (Node): Node object to read from
  143. propname (str): property name to read
  144. default (list of str): Default value to use if the node/property do not
  145. exist, or None
  146. Returns:
  147. String value read, or default if none
  148. """
  149. prop = node.props.get(propname)
  150. if not prop:
  151. return default
  152. value = prop.value
  153. if not prop.bytes:
  154. return []
  155. if not isinstance(value, list):
  156. strval = GetString(node, propname)
  157. return [strval]
  158. return value
  159. def GetArgs(node, propname):
  160. prop = node.props.get(propname)
  161. if not prop:
  162. raise ValueError(f"Node '{node.path}': Expected property '{propname}'")
  163. if prop.bytes:
  164. value = GetStringList(node, propname)
  165. else:
  166. value = []
  167. if not value:
  168. args = []
  169. elif len(value) == 1:
  170. args = value[0].split()
  171. else:
  172. args = value
  173. return args
  174. def GetBool(node, propname, default=False):
  175. """Get an boolean from a property
  176. Args:
  177. node: Node object to read from
  178. propname: property name to read
  179. default: Default value to use if the node/property do not exist
  180. Returns:
  181. Boolean value read, or default if none (if you set this to True the
  182. function will always return True)
  183. """
  184. if propname in node.props:
  185. return True
  186. return default
  187. def GetByte(node, propname, default=None):
  188. """Get an byte from a property
  189. Args:
  190. node: Node object to read from
  191. propname: property name to read
  192. default: Default value to use if the node/property do not exist
  193. Returns:
  194. Byte value read, or default if none
  195. """
  196. prop = node.props.get(propname)
  197. if not prop:
  198. return default
  199. value = prop.value
  200. if isinstance(value, list):
  201. raise ValueError("Node '%s' property '%s' has list value: expecting "
  202. "a single byte" % (node.name, propname))
  203. if len(value) != 1:
  204. raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
  205. (node.name, propname, len(value), 1))
  206. return ord(value[0])
  207. def GetBytes(node, propname, size, default=None):
  208. """Get a set of bytes from a property
  209. Args:
  210. node (Node): Node object to read from
  211. propname (str): property name to read
  212. size (int): Number of bytes to expect
  213. default (bytes): Default value or None
  214. Returns:
  215. bytes: Bytes value read, or default if none
  216. """
  217. prop = node.props.get(propname)
  218. if not prop:
  219. return default
  220. if len(prop.bytes) != size:
  221. raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
  222. (node.name, propname, len(prop.bytes), size))
  223. return prop.bytes
  224. def GetPhandleList(node, propname):
  225. """Get a list of phandles from a property
  226. Args:
  227. node: Node object to read from
  228. propname: property name to read
  229. Returns:
  230. List of phandles read, each an integer
  231. """
  232. prop = node.props.get(propname)
  233. if not prop:
  234. return None
  235. value = prop.value
  236. if not isinstance(value, list):
  237. value = [value]
  238. return [fdt32_to_cpu(v) for v in value]
  239. def GetPhandleNameOffset(node, propname):
  240. """Get a <&phandle>, "string", <offset> value from a property
  241. Args:
  242. node: Node object to read from
  243. propname: property name to read
  244. Returns:
  245. tuple:
  246. Node object
  247. str
  248. int
  249. or None if the property does not exist
  250. """
  251. prop = node.props.get(propname)
  252. if not prop:
  253. return None
  254. value = prop.bytes
  255. phandle = fdt32_to_cpu(value[:4])
  256. node = node.GetFdt().LookupPhandle(phandle)
  257. name = ''
  258. for byte in value[4:]:
  259. if not byte:
  260. break
  261. name += chr(byte)
  262. val = fdt32_to_cpu(value[4 + len(name) + 1:])
  263. return node, name, val
  264. def GetDatatype(node, propname, datatype):
  265. """Get a value of a given type from a property
  266. Args:
  267. node: Node object to read from
  268. propname: property name to read
  269. datatype: Type to read (str or int)
  270. Returns:
  271. value read, or None if none
  272. Raises:
  273. ValueError if datatype is not str or int
  274. """
  275. if datatype == str:
  276. return GetString(node, propname)
  277. elif datatype == int:
  278. return GetInt(node, propname)
  279. raise ValueError("fdt_util internal error: Unknown data type '%s'" %
  280. datatype)