blob: 53b70f8f5e7061ae43eec7a23f723dc2bf79776f [file] [log] [blame]
Tom Rini8b0c8a12018-05-06 18:27:01 -04001/* SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause */
Simon Glassa13d9022017-05-27 07:38:11 -06002/*
3 * pylibfdt - Flat Device Tree manipulation in Python
4 * Copyright (C) 2017 Google, Inc.
5 * Written by Simon Glass <sjg@chromium.org>
Simon Glassa13d9022017-05-27 07:38:11 -06006 */
7
8%module libfdt
9
Simon Glass1c879312017-08-13 16:02:54 -060010%include <stdint.i>
11
Simon Glassa13d9022017-05-27 07:38:11 -060012%{
13#define SWIG_FILE_WITH_INIT
14#include "libfdt.h"
Simon Glass70cd0d72018-07-06 10:27:20 -060015
16/*
17 * We rename this function here to avoid problems with swig, since we also have
18 * a struct called fdt_property. That struct causes swig to create a class in
19 * libfdt.py called fdt_property(), which confuses things.
20 */
Simon Glassb474c762018-07-26 14:02:13 -060021static int fdt_property_stub(void *fdt, const char *name, const char *val,
22 int len)
Simon Glass70cd0d72018-07-06 10:27:20 -060023{
24 return fdt_property(fdt, name, val, len);
25}
26
Simon Glassa13d9022017-05-27 07:38:11 -060027%}
28
29%pythoncode %{
30
31import struct
32
33# Error codes, corresponding to FDT_ERR_... in libfdt.h
34(NOTFOUND,
35 EXISTS,
36 NOSPACE,
37 BADOFFSET,
38 BADPATH,
39 BADPHANDLE,
40 BADSTATE,
41 TRUNCATED,
42 BADMAGIC,
43 BADVERSION,
44 BADSTRUCTURE,
45 BADLAYOUT,
46 INTERNAL,
47 BADNCELLS,
48 BADVALUE,
49 BADOVERLAY,
50 NOPHANDLES) = QUIET_ALL = range(1, 18)
51# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
52# altogether. All # functions passed this value will return an error instead
53# of raising an exception.
54
55# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
56# instead of raising an exception.
57QUIET_NOTFOUND = (NOTFOUND,)
Simon Glassb474c762018-07-26 14:02:13 -060058QUIET_NOSPACE = (NOSPACE,)
Simon Glassa13d9022017-05-27 07:38:11 -060059
60
61class FdtException(Exception):
62 """An exception caused by an error such as one of the codes above"""
63 def __init__(self, err):
64 self.err = err
65
66 def __str__(self):
67 return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
68
69def strerror(fdt_err):
70 """Get the string for an error number
71
72 Args:
73 fdt_err: Error number (-ve)
74
75 Returns:
76 String containing the associated error
77 """
78 return fdt_strerror(fdt_err)
79
80def check_err(val, quiet=()):
81 """Raise an error if the return value is -ve
82
83 This is used to check for errors returned by libfdt C functions.
84
85 Args:
86 val: Return value from a libfdt function
87 quiet: Errors to ignore (empty to raise on all errors)
88
89 Returns:
90 val if val >= 0
91
92 Raises
93 FdtException if val < 0
94 """
95 if val < 0:
96 if -val not in quiet:
97 raise FdtException(val)
98 return val
99
100def check_err_null(val, quiet=()):
101 """Raise an error if the return value is NULL
102
103 This is used to check for a NULL return value from certain libfdt C
104 functions
105
106 Args:
107 val: Return value from a libfdt function
108 quiet: Errors to ignore (empty to raise on all errors)
109
110 Returns:
111 val if val is a list, None if not
112
113 Raises
114 FdtException if val indicates an error was reported and the error
115 is not in @quiet.
116 """
117 # Normally a list is returned which contains the data and its length.
118 # If we get just an integer error code, it means the function failed.
119 if not isinstance(val, list):
120 if -val not in quiet:
121 raise FdtException(val)
122 return val
123
Simon Glassb474c762018-07-26 14:02:13 -0600124class FdtRo(object):
125 """Class for a read-only device-tree
Simon Glass70cd0d72018-07-06 10:27:20 -0600126
Simon Glassb474c762018-07-26 14:02:13 -0600127 This is a base class used by FdtRw (read-write access) and FdtSw
128 (sequential-write access). It implements read-only access to the
129 device tree.
Simon Glassa13d9022017-05-27 07:38:11 -0600130
Simon Glassb474c762018-07-26 14:02:13 -0600131 Here are the three classes and when you should use them:
Simon Glassa13d9022017-05-27 07:38:11 -0600132
Simon Glassb474c762018-07-26 14:02:13 -0600133 FdtRo - read-only access to an existing FDT
134 FdtRw - read-write access to an existing FDT (most common case)
135 FdtSw - for creating a new FDT, as well as allowing read-only access
Simon Glassa13d9022017-05-27 07:38:11 -0600136 """
137 def __init__(self, data):
138 self._fdt = bytearray(data)
139 check_err(fdt_check_header(self._fdt));
140
Simon Glass70cd0d72018-07-06 10:27:20 -0600141 def as_bytearray(self):
142 """Get the device tree contents as a bytearray
143
144 This can be passed directly to libfdt functions that access a
145 const void * for the device tree.
146
147 Returns:
148 bytearray containing the device tree
149 """
150 return bytearray(self._fdt)
151
152 def next_node(self, nodeoffset, depth, quiet=()):
153 """Find the next subnode
154
155 Args:
156 nodeoffset: Node offset of previous node
Simon Glassb474c762018-07-26 14:02:13 -0600157 depth: The depth of the node at nodeoffset. This is used to
158 calculate the depth of the returned node
Simon Glass70cd0d72018-07-06 10:27:20 -0600159 quiet: Errors to ignore (empty to raise on all errors)
160
161 Returns:
Simon Glassb474c762018-07-26 14:02:13 -0600162 Typle:
163 Offset of the next node, if any, else a -ve error
164 Depth of the returned node, if any, else undefined
Simon Glass70cd0d72018-07-06 10:27:20 -0600165
166 Raises:
167 FdtException if no more nodes found or other error occurs
168 """
169 return check_err(fdt_next_node(self._fdt, nodeoffset, depth), quiet)
170
171 def first_subnode(self, nodeoffset, quiet=()):
172 """Find the first subnode of a parent node
173
174 Args:
175 nodeoffset: Node offset of parent node
176 quiet: Errors to ignore (empty to raise on all errors)
177
178 Returns:
179 The offset of the first subnode, if any
180
181 Raises:
182 FdtException if no subnodes found or other error occurs
183 """
184 return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
185
186 def next_subnode(self, nodeoffset, quiet=()):
187 """Find the next subnode
188
189 Args:
190 nodeoffset: Node offset of previous subnode
191 quiet: Errors to ignore (empty to raise on all errors)
192
193 Returns:
194 The offset of the next subnode, if any
195
196 Raises:
197 FdtException if no more subnodes found or other error occurs
198 """
199 return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
200
201 def magic(self):
202 """Return the magic word from the header
203
204 Returns:
205 Magic word
206 """
Simon Glassb474c762018-07-26 14:02:13 -0600207 return fdt_magic(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600208
209 def totalsize(self):
210 """Return the total size of the device tree
211
212 Returns:
213 Total tree size in bytes
214 """
Simon Glassb474c762018-07-26 14:02:13 -0600215 return fdt_totalsize(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600216
217 def off_dt_struct(self):
218 """Return the start of the device-tree struct area
219
220 Returns:
221 Start offset of struct area
222 """
Simon Glassb474c762018-07-26 14:02:13 -0600223 return fdt_off_dt_struct(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600224
225 def off_dt_strings(self):
226 """Return the start of the device-tree string area
227
228 Returns:
229 Start offset of string area
230 """
Simon Glassb474c762018-07-26 14:02:13 -0600231 return fdt_off_dt_strings(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600232
233 def off_mem_rsvmap(self):
234 """Return the start of the memory reserve map
235
236 Returns:
237 Start offset of memory reserve map
238 """
Simon Glassb474c762018-07-26 14:02:13 -0600239 return fdt_off_mem_rsvmap(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600240
241 def version(self):
242 """Return the version of the device tree
243
244 Returns:
245 Version number of the device tree
246 """
Simon Glassb474c762018-07-26 14:02:13 -0600247 return fdt_version(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600248
249 def last_comp_version(self):
250 """Return the last compatible version of the device tree
251
252 Returns:
253 Last compatible version number of the device tree
254 """
Simon Glassb474c762018-07-26 14:02:13 -0600255 return fdt_last_comp_version(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600256
257 def boot_cpuid_phys(self):
258 """Return the physical boot CPU ID
259
260 Returns:
261 Physical boot CPU ID
262 """
Simon Glassb474c762018-07-26 14:02:13 -0600263 return fdt_boot_cpuid_phys(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600264
265 def size_dt_strings(self):
266 """Return the start of the device-tree string area
267
268 Returns:
269 Start offset of string area
270 """
Simon Glassb474c762018-07-26 14:02:13 -0600271 return fdt_size_dt_strings(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600272
273 def size_dt_struct(self):
274 """Return the start of the device-tree struct area
275
276 Returns:
277 Start offset of struct area
278 """
Simon Glassb474c762018-07-26 14:02:13 -0600279 return fdt_size_dt_struct(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600280
281 def num_mem_rsv(self, quiet=()):
282 """Return the number of memory reserve-map records
283
284 Returns:
285 Number of memory reserve-map records
286 """
287 return check_err(fdt_num_mem_rsv(self._fdt), quiet)
288
289 def get_mem_rsv(self, index, quiet=()):
290 """Return the indexed memory reserve-map record
291
292 Args:
293 index: Record to return (0=first)
294
295 Returns:
296 Number of memory reserve-map records
297 """
298 return check_err(fdt_get_mem_rsv(self._fdt, index), quiet)
299
Simon Glass460b2522017-08-29 14:15:46 -0600300 def subnode_offset(self, parentoffset, name, quiet=()):
301 """Get the offset of a named subnode
302
303 Args:
304 parentoffset: Offset of the parent node to check
305 name: Name of the required subnode, e.g. 'subnode@1'
306 quiet: Errors to ignore (empty to raise on all errors)
307
308 Returns:
309 The node offset of the found node, if any
310
311 Raises
312 FdtException if there is no node with that name, or other error
313 """
314 return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
315 quiet)
316
Simon Glassa13d9022017-05-27 07:38:11 -0600317 def path_offset(self, path, quiet=()):
318 """Get the offset for a given path
319
320 Args:
321 path: Path to the required node, e.g. '/node@3/subnode@1'
322 quiet: Errors to ignore (empty to raise on all errors)
323
324 Returns:
325 Node offset
326
327 Raises
328 FdtException if the path is not valid or not found
329 """
330 return check_err(fdt_path_offset(self._fdt, path), quiet)
331
Simon Glass70cd0d72018-07-06 10:27:20 -0600332 def get_name(self, nodeoffset):
333 """Get the name of a node
334
335 Args:
336 nodeoffset: Offset of node to check
337
338 Returns:
339 Node name
340
341 Raises:
342 FdtException on error (e.g. nodeoffset is invalid)
343 """
344 return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
345
Simon Glassa13d9022017-05-27 07:38:11 -0600346 def first_property_offset(self, nodeoffset, quiet=()):
347 """Get the offset of the first property in a node offset
348
349 Args:
350 nodeoffset: Offset to the node to check
351 quiet: Errors to ignore (empty to raise on all errors)
352
353 Returns:
354 Offset of the first property
355
356 Raises
357 FdtException if the associated node has no properties, or some
358 other error occurred
359 """
360 return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
361 quiet)
362
363 def next_property_offset(self, prop_offset, quiet=()):
364 """Get the next property in a node
365
366 Args:
367 prop_offset: Offset of the previous property
368 quiet: Errors to ignore (empty to raise on all errors)
369
370 Returns:
371 Offset of the next property
372
373 Raises:
374 FdtException if the associated node has no more properties, or
375 some other error occurred
376 """
377 return check_err(fdt_next_property_offset(self._fdt, prop_offset),
378 quiet)
379
Simon Glassa13d9022017-05-27 07:38:11 -0600380 def get_property_by_offset(self, prop_offset, quiet=()):
381 """Obtains a property that can be examined
382
383 Args:
384 prop_offset: Offset of property (e.g. from first_property_offset())
385 quiet: Errors to ignore (empty to raise on all errors)
386
387 Returns:
388 Property object, or None if not found
389
390 Raises:
391 FdtException on error (e.g. invalid prop_offset or device
392 tree format)
393 """
394 pdata = check_err_null(
395 fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
396 if isinstance(pdata, (int)):
397 return pdata
398 return Property(pdata[0], pdata[1])
399
Simon Glassb474c762018-07-26 14:02:13 -0600400 def getprop(self, nodeoffset, prop_name, quiet=()):
401 """Get a property from a node
Simon Glass0537c552018-07-06 10:27:22 -0600402
403 Args:
Simon Glassb474c762018-07-26 14:02:13 -0600404 nodeoffset: Node offset containing property to get
Simon Glass0537c552018-07-06 10:27:22 -0600405 prop_name: Name of property to get
406 quiet: Errors to ignore (empty to raise on all errors)
407
408 Returns:
Simon Glassb474c762018-07-26 14:02:13 -0600409 Value of property as a Property object (which can be used as a
410 bytearray/string), or -ve error number. On failure, returns an
411 integer error
Simon Glass0537c552018-07-06 10:27:22 -0600412
413 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600414 FdtError if any error occurs (e.g. the property is not found)
Simon Glass0537c552018-07-06 10:27:22 -0600415 """
Simon Glassb474c762018-07-26 14:02:13 -0600416 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
417 quiet)
Simon Glass0537c552018-07-06 10:27:22 -0600418 if isinstance(pdata, (int)):
419 return pdata
Simon Glassb474c762018-07-26 14:02:13 -0600420 return Property(prop_name, bytearray(pdata[0]))
421
422 def get_phandle(self, nodeoffset):
423 """Get the phandle of a node
424
425 Args:
426 nodeoffset: Node offset to check
427
428 Returns:
429 phandle of node, or 0 if the node has no phandle or another error
430 occurs
431 """
432 return fdt_get_phandle(self._fdt, nodeoffset)
433
434 def parent_offset(self, nodeoffset, quiet=()):
435 """Get the offset of a node's parent
436
437 Args:
438 nodeoffset: Node offset to check
439 quiet: Errors to ignore (empty to raise on all errors)
440
441 Returns:
442 The offset of the parent node, if any
443
444 Raises:
445 FdtException if no parent found or other error occurs
446 """
447 return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
448
449 def node_offset_by_phandle(self, phandle, quiet=()):
450 """Get the offset of a node with the given phandle
451
452 Args:
453 phandle: Phandle to search for
454 quiet: Errors to ignore (empty to raise on all errors)
455
456 Returns:
457 The offset of node with that phandle, if any
458
459 Raises:
460 FdtException if no node found or other error occurs
461 """
462 return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
463
464
465class Fdt(FdtRo):
466 """Device tree class, supporting all operations
467
468 The Fdt object is created is created from a device tree binary file,
469 e.g. with something like:
470
471 fdt = Fdt(open("filename.dtb").read())
472
473 Operations can then be performed using the methods in this class. Each
474 method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
475
476 All methods raise an FdtException if an error occurs. To avoid this
477 behaviour a 'quiet' parameter is provided for some functions. This
478 defaults to empty, but you can pass a list of errors that you expect.
479 If one of these errors occurs, the function will return an error number
480 (e.g. -NOTFOUND).
481 """
482 def __init__(self, data):
483 FdtRo.__init__(self, data)
Simon Glass0537c552018-07-06 10:27:22 -0600484
Simon Glass70cd0d72018-07-06 10:27:20 -0600485 @staticmethod
486 def create_empty_tree(size, quiet=()):
487 """Create an empty device tree ready for use
Simon Glassa13d9022017-05-27 07:38:11 -0600488
489 Args:
Simon Glass70cd0d72018-07-06 10:27:20 -0600490 size: Size of device tree in bytes
Simon Glassa13d9022017-05-27 07:38:11 -0600491
492 Returns:
Simon Glass70cd0d72018-07-06 10:27:20 -0600493 Fdt object containing the device tree
Simon Glassa13d9022017-05-27 07:38:11 -0600494 """
Simon Glass70cd0d72018-07-06 10:27:20 -0600495 data = bytearray(size)
496 err = check_err(fdt_create_empty_tree(data, size), quiet)
497 if err:
498 return err
499 return Fdt(data)
Simon Glassa13d9022017-05-27 07:38:11 -0600500
Simon Glassb474c762018-07-26 14:02:13 -0600501 def resize(self, size, quiet=()):
Simon Glass70cd0d72018-07-06 10:27:20 -0600502 """Move the device tree into a larger or smaller space
Simon Glassa13d9022017-05-27 07:38:11 -0600503
Simon Glass70cd0d72018-07-06 10:27:20 -0600504 This creates a new device tree of size @size and moves the existing
505 device tree contents over to that. It can be used to create more space
Simon Glassb474c762018-07-26 14:02:13 -0600506 in a device tree. Note that the Fdt object remains the same, but it
507 now has a new bytearray holding the contents.
Simon Glassa13d9022017-05-27 07:38:11 -0600508
Simon Glass70cd0d72018-07-06 10:27:20 -0600509 Args:
510 size: Required new size of device tree in bytes
Simon Glassa13d9022017-05-27 07:38:11 -0600511 """
Simon Glass70cd0d72018-07-06 10:27:20 -0600512 fdt = bytearray(size)
Simon Glass70cd0d72018-07-06 10:27:20 -0600513 err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
514 if err:
515 return err
516 self._fdt = fdt
Simon Glassa13d9022017-05-27 07:38:11 -0600517
518 def pack(self, quiet=()):
519 """Pack the device tree to remove unused space
520
521 This adjusts the tree in place.
522
523 Args:
524 quiet: Errors to ignore (empty to raise on all errors)
525
Simon Glassb474c762018-07-26 14:02:13 -0600526 Returns:
527 Error code, or 0 if OK
528
Simon Glassa13d9022017-05-27 07:38:11 -0600529 Raises:
530 FdtException if any error occurs
531 """
Simon Glass04402d32018-07-06 10:27:21 -0600532 err = check_err(fdt_pack(self._fdt), quiet)
533 if err:
534 return err
535 del self._fdt[self.totalsize():]
536 return err
Simon Glassa13d9022017-05-27 07:38:11 -0600537
Simon Glass70cd0d72018-07-06 10:27:20 -0600538 def set_name(self, nodeoffset, name, quiet=()):
539 """Set the name of a node
540
541 Args:
542 nodeoffset: Node offset of node to update
Simon Glassb474c762018-07-26 14:02:13 -0600543 name: New node name (string without \0)
Simon Glass70cd0d72018-07-06 10:27:20 -0600544
545 Returns:
546 Error code, or 0 if OK
547
548 Raises:
549 FdtException if no parent found or other error occurs
550 """
Simon Glassb474c762018-07-26 14:02:13 -0600551 if chr(0) in name:
552 raise ValueError('Property contains embedded nul characters')
Simon Glass70cd0d72018-07-06 10:27:20 -0600553 return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
554
555 def setprop(self, nodeoffset, prop_name, val, quiet=()):
556 """Set the value of a property
557
558 Args:
559 nodeoffset: Node offset containing the property to create/update
560 prop_name: Name of property
561 val: Value to write (string or bytearray)
562 quiet: Errors to ignore (empty to raise on all errors)
563
564 Returns:
565 Error code, or 0 if OK
566
567 Raises:
568 FdtException if no parent found or other error occurs
569 """
570 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
571 len(val)), quiet)
572
573 def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
574 """Set the value of a property
575
576 Args:
577 nodeoffset: Node offset containing the property to create/update
578 prop_name: Name of property
579 val: Value to write (integer)
580 quiet: Errors to ignore (empty to raise on all errors)
581
582 Returns:
583 Error code, or 0 if OK
584
585 Raises:
586 FdtException if no parent found or other error occurs
587 """
588 return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
589 quiet)
590
591 def setprop_u64(self, nodeoffset, prop_name, val, quiet=()):
592 """Set the value of a property
593
594 Args:
595 nodeoffset: Node offset containing the property to create/update
596 prop_name: Name of property
597 val: Value to write (integer)
598 quiet: Errors to ignore (empty to raise on all errors)
599
600 Returns:
601 Error code, or 0 if OK
602
603 Raises:
604 FdtException if no parent found or other error occurs
605 """
606 return check_err(fdt_setprop_u64(self._fdt, nodeoffset, prop_name, val),
607 quiet)
608
609 def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
610 """Set the string value of a property
611
612 The property is set to the string, with a nul terminator added
613
614 Args:
615 nodeoffset: Node offset containing the property to create/update
616 prop_name: Name of property
Simon Glassb474c762018-07-26 14:02:13 -0600617 val: Value to write (string without nul terminator). Unicode is
618 supposed by encoding to UTF-8
Simon Glass70cd0d72018-07-06 10:27:20 -0600619 quiet: Errors to ignore (empty to raise on all errors)
620
621 Returns:
622 Error code, or 0 if OK
623
624 Raises:
625 FdtException if no parent found or other error occurs
626 """
Simon Glass7ccca832019-10-31 07:42:59 -0600627 val = val.encode('utf-8') + b'\0'
Simon Glass70cd0d72018-07-06 10:27:20 -0600628 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
629 val, len(val)), quiet)
630
Simon Glass5be24552018-09-14 04:57:06 -0600631 def delprop(self, nodeoffset, prop_name, quiet=()):
Simon Glass70cd0d72018-07-06 10:27:20 -0600632 """Delete a property from a node
633
634 Args:
635 nodeoffset: Node offset containing property to delete
636 prop_name: Name of property to delete
Simon Glass5be24552018-09-14 04:57:06 -0600637 quiet: Errors to ignore (empty to raise on all errors)
638
639 Returns:
640 Error code, or 0 if OK
Simon Glass70cd0d72018-07-06 10:27:20 -0600641
642 Raises:
643 FdtError if the property does not exist, or another error occurs
644 """
Simon Glass5be24552018-09-14 04:57:06 -0600645 return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name), quiet)
646
647 def add_subnode(self, parentoffset, name, quiet=()):
648 """Add a new subnode to a node
649
650 Args:
651 parentoffset: Parent offset to add the subnode to
652 name: Name of node to add
653
654 Returns:
655 offset of the node created, or negative error code on failure
656
657 Raises:
658 FdtError if there is not enough space, or another error occurs
659 """
660 return check_err(fdt_add_subnode(self._fdt, parentoffset, name), quiet)
Simon Glass70cd0d72018-07-06 10:27:20 -0600661
Simon Glass5be24552018-09-14 04:57:06 -0600662 def del_node(self, nodeoffset, quiet=()):
Simon Glass0537c552018-07-06 10:27:22 -0600663 """Delete a node
664
665 Args:
Simon Glass5be24552018-09-14 04:57:06 -0600666 nodeoffset: Offset of node to delete
667
668 Returns:
669 Error code, or 0 if OK
Simon Glass0537c552018-07-06 10:27:22 -0600670
671 Raises:
Simon Glass5be24552018-09-14 04:57:06 -0600672 FdtError if an error occurs
Simon Glass0537c552018-07-06 10:27:22 -0600673 """
Simon Glass5be24552018-09-14 04:57:06 -0600674 return check_err(fdt_del_node(self._fdt, nodeoffset), quiet)
Simon Glass0537c552018-07-06 10:27:22 -0600675
Simon Glass70cd0d72018-07-06 10:27:20 -0600676
677class Property(bytearray):
Simon Glassa13d9022017-05-27 07:38:11 -0600678 """Holds a device tree property name and value.
679
680 This holds a copy of a property taken from the device tree. It does not
681 reference the device tree, so if anything changes in the device tree,
682 a Property object will remain valid.
683
684 Properties:
685 name: Property name
Simon Glass70cd0d72018-07-06 10:27:20 -0600686 value: Property value as a bytearray
Simon Glassa13d9022017-05-27 07:38:11 -0600687 """
688 def __init__(self, name, value):
Simon Glass70cd0d72018-07-06 10:27:20 -0600689 bytearray.__init__(self, value)
Simon Glassa13d9022017-05-27 07:38:11 -0600690 self.name = name
Simon Glass70cd0d72018-07-06 10:27:20 -0600691
692 def as_cell(self, fmt):
693 return struct.unpack('>' + fmt, self)[0]
694
695 def as_uint32(self):
696 return self.as_cell('L')
697
698 def as_int32(self):
699 return self.as_cell('l')
700
701 def as_uint64(self):
702 return self.as_cell('Q')
703
704 def as_int64(self):
705 return self.as_cell('q')
706
707 def as_str(self):
Simon Glassb474c762018-07-26 14:02:13 -0600708 """Unicode is supported by decoding from UTF-8"""
709 if self[-1] != 0:
710 raise ValueError('Property lacks nul termination')
711 if 0 in self[:-1]:
712 raise ValueError('Property contains embedded nul characters')
713 return self[:-1].decode('utf-8')
Simon Glass70cd0d72018-07-06 10:27:20 -0600714
715
Simon Glassb474c762018-07-26 14:02:13 -0600716class FdtSw(FdtRo):
Simon Glass70cd0d72018-07-06 10:27:20 -0600717 """Software interface to create a device tree from scratch
718
719 The methods in this class work by adding to an existing 'partial' device
720 tree buffer of a fixed size created by instantiating this class. When the
Simon Glassb474c762018-07-26 14:02:13 -0600721 tree is complete, call as_fdt() to obtain a device tree ready to be used.
Simon Glass70cd0d72018-07-06 10:27:20 -0600722
723 Similarly with nodes, a new node is started with begin_node() and finished
724 with end_node().
725
726 The context manager functions can be used to make this a bit easier:
727
728 # First create the device tree with a node and property:
Simon Glassb474c762018-07-26 14:02:13 -0600729 sw = FdtSw()
730 with sw.add_node('node'):
731 sw.property_u32('reg', 2)
732 fdt = sw.as_fdt()
Simon Glass70cd0d72018-07-06 10:27:20 -0600733
734 # Now we can use it as a real device tree
735 fdt.setprop_u32(0, 'reg', 3)
Simon Glassb474c762018-07-26 14:02:13 -0600736
737 The size hint provides a starting size for the space to be used by the
738 device tree. This will be increased automatically as needed as new items
739 are added to the tree.
Simon Glass70cd0d72018-07-06 10:27:20 -0600740 """
Simon Glassb474c762018-07-26 14:02:13 -0600741 INC_SIZE = 1024 # Expand size by this much when out of space
Simon Glass70cd0d72018-07-06 10:27:20 -0600742
Simon Glassb474c762018-07-26 14:02:13 -0600743 def __init__(self, size_hint=None):
744 """Create a new FdtSw object
Simon Glass70cd0d72018-07-06 10:27:20 -0600745
Simon Glassb474c762018-07-26 14:02:13 -0600746 Args:
747 size_hint: A hint as to the initial size to use
748
749 Raises:
750 ValueError if size_hint is negative
Simon Glass70cd0d72018-07-06 10:27:20 -0600751
Simon Glassb474c762018-07-26 14:02:13 -0600752 Returns:
753 FdtSw object on success, else integer error code (if not raising)
754 """
755 if not size_hint:
756 size_hint = self.INC_SIZE
757 fdtsw = bytearray(size_hint)
758 err = check_err(fdt_create(fdtsw, size_hint))
759 if err:
760 return err
761 self._fdt = fdtsw
762
763 def as_fdt(self):
Simon Glass70cd0d72018-07-06 10:27:20 -0600764 """Convert a FdtSw into an Fdt so it can be accessed as normal
765
Simon Glassb474c762018-07-26 14:02:13 -0600766 Creates a new Fdt object from the work-in-progress device tree. This
767 does not call fdt_finish() on the current object, so it is possible to
768 add more nodes/properties and call as_fdt() again to get an updated
769 tree.
Simon Glass70cd0d72018-07-06 10:27:20 -0600770
771 Returns:
772 Fdt object allowing access to the newly created device tree
773 """
Simon Glassb474c762018-07-26 14:02:13 -0600774 fdtsw = bytearray(self._fdt)
775 check_err(fdt_finish(fdtsw))
776 return Fdt(fdtsw)
Simon Glass70cd0d72018-07-06 10:27:20 -0600777
Simon Glassb474c762018-07-26 14:02:13 -0600778 def check_space(self, val):
779 """Check if we need to add more space to the FDT
780
781 This should be called with the error code from an operation. If this is
782 -NOSPACE then the FDT will be expanded to have more space, and True will
783 be returned, indicating that the operation needs to be tried again.
784
785 Args:
786 val: Return value from the operation that was attempted
787
788 Returns:
789 True if the operation must be retried, else False
790 """
791 if check_err(val, QUIET_NOSPACE) < 0:
792 self.resize(len(self._fdt) + self.INC_SIZE)
793 return True
794 return False
795
796 def resize(self, size):
Simon Glass70cd0d72018-07-06 10:27:20 -0600797 """Resize the buffer to accommodate a larger tree
798
799 Args:
800 size: New size of tree
Simon Glass70cd0d72018-07-06 10:27:20 -0600801
802 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600803 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600804 """
805 fdt = bytearray(size)
Simon Glassb474c762018-07-26 14:02:13 -0600806 err = check_err(fdt_resize(self._fdt, fdt, size))
807 self._fdt = fdt
Simon Glass70cd0d72018-07-06 10:27:20 -0600808
Simon Glassb474c762018-07-26 14:02:13 -0600809 def add_reservemap_entry(self, addr, size):
Simon Glass70cd0d72018-07-06 10:27:20 -0600810 """Add a new memory reserve map entry
811
812 Once finished adding, you must call finish_reservemap().
813
814 Args:
815 addr: 64-bit start address
816 size: 64-bit size
Simon Glass70cd0d72018-07-06 10:27:20 -0600817
818 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600819 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600820 """
Simon Glassb474c762018-07-26 14:02:13 -0600821 while self.check_space(fdt_add_reservemap_entry(self._fdt, addr,
822 size)):
823 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600824
Simon Glassb474c762018-07-26 14:02:13 -0600825 def finish_reservemap(self):
Simon Glass70cd0d72018-07-06 10:27:20 -0600826 """Indicate that there are no more reserve map entries to add
827
Simon Glass70cd0d72018-07-06 10:27:20 -0600828 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600829 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600830 """
Simon Glassb474c762018-07-26 14:02:13 -0600831 while self.check_space(fdt_finish_reservemap(self._fdt)):
832 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600833
Simon Glassb474c762018-07-26 14:02:13 -0600834 def begin_node(self, name):
Simon Glass70cd0d72018-07-06 10:27:20 -0600835 """Begin a new node
836
837 Use this before adding properties to the node. Then call end_node() to
838 finish it. You can also use the context manager as shown in the FdtSw
839 class comment.
840
841 Args:
842 name: Name of node to begin
Simon Glass70cd0d72018-07-06 10:27:20 -0600843
844 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600845 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600846 """
Simon Glassb474c762018-07-26 14:02:13 -0600847 while self.check_space(fdt_begin_node(self._fdt, name)):
848 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600849
Simon Glassb474c762018-07-26 14:02:13 -0600850 def property_string(self, name, string):
Simon Glass70cd0d72018-07-06 10:27:20 -0600851 """Add a property with a string value
852
853 The string will be nul-terminated when written to the device tree
854
855 Args:
856 name: Name of property to add
857 string: String value of property
Simon Glass70cd0d72018-07-06 10:27:20 -0600858
859 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600860 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600861 """
Simon Glassb474c762018-07-26 14:02:13 -0600862 while self.check_space(fdt_property_string(self._fdt, name, string)):
863 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600864
Simon Glassb474c762018-07-26 14:02:13 -0600865 def property_u32(self, name, val):
Simon Glass70cd0d72018-07-06 10:27:20 -0600866 """Add a property with a 32-bit value
867
868 Write a single-cell value to the device tree
869
870 Args:
871 name: Name of property to add
872 val: Value of property
Simon Glass70cd0d72018-07-06 10:27:20 -0600873
874 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600875 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600876 """
Simon Glassb474c762018-07-26 14:02:13 -0600877 while self.check_space(fdt_property_u32(self._fdt, name, val)):
878 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600879
Simon Glassb474c762018-07-26 14:02:13 -0600880 def property_u64(self, name, val):
Simon Glass70cd0d72018-07-06 10:27:20 -0600881 """Add a property with a 64-bit value
882
883 Write a double-cell value to the device tree in big-endian format
884
885 Args:
886 name: Name of property to add
887 val: Value of property
Simon Glass70cd0d72018-07-06 10:27:20 -0600888
889 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600890 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600891 """
Simon Glassb474c762018-07-26 14:02:13 -0600892 while self.check_space(fdt_property_u64(self._fdt, name, val)):
893 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600894
Simon Glassb474c762018-07-26 14:02:13 -0600895 def property_cell(self, name, val):
Simon Glass70cd0d72018-07-06 10:27:20 -0600896 """Add a property with a single-cell value
897
898 Write a single-cell value to the device tree
899
900 Args:
901 name: Name of property to add
902 val: Value of property
903 quiet: Errors to ignore (empty to raise on all errors)
904
905 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600906 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600907 """
Simon Glassb474c762018-07-26 14:02:13 -0600908 while self.check_space(fdt_property_cell(self._fdt, name, val)):
909 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600910
Simon Glassb474c762018-07-26 14:02:13 -0600911 def property(self, name, val):
Simon Glass70cd0d72018-07-06 10:27:20 -0600912 """Add a property
913
914 Write a new property with the given value to the device tree. The value
915 is taken as is and is not nul-terminated
916
917 Args:
918 name: Name of property to add
919 val: Value of property
920 quiet: Errors to ignore (empty to raise on all errors)
921
922 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600923 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600924 """
Simon Glassb474c762018-07-26 14:02:13 -0600925 while self.check_space(fdt_property_stub(self._fdt, name, val,
926 len(val))):
927 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600928
Simon Glassb474c762018-07-26 14:02:13 -0600929 def end_node(self):
Simon Glass70cd0d72018-07-06 10:27:20 -0600930 """End a node
931
932 Use this after adding properties to a node to close it off. You can also
933 use the context manager as shown in the FdtSw class comment.
934
935 Args:
936 quiet: Errors to ignore (empty to raise on all errors)
937
938 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600939 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600940 """
Simon Glassb474c762018-07-26 14:02:13 -0600941 while self.check_space(fdt_end_node(self._fdt)):
942 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600943
Simon Glassb474c762018-07-26 14:02:13 -0600944 def add_node(self, name):
Simon Glass70cd0d72018-07-06 10:27:20 -0600945 """Create a new context for adding a node
946
947 When used in a 'with' clause this starts a new node and finishes it
948 afterward.
949
950 Args:
951 name: Name of node to add
952 """
Simon Glassb474c762018-07-26 14:02:13 -0600953 return NodeAdder(self, name)
Simon Glass70cd0d72018-07-06 10:27:20 -0600954
955
956class NodeAdder():
957 """Class to provide a node context
958
959 This allows you to add nodes in a more natural way:
960
Simon Glassb474c762018-07-26 14:02:13 -0600961 with fdtsw.add_node('name'):
Simon Glass70cd0d72018-07-06 10:27:20 -0600962 fdtsw.property_string('test', 'value')
963
964 The node is automatically completed with a call to end_node() when the
965 context exits.
966 """
Simon Glassb474c762018-07-26 14:02:13 -0600967 def __init__(self, fdtsw, name):
968 self._fdt = fdtsw
Simon Glass70cd0d72018-07-06 10:27:20 -0600969 self._name = name
970
971 def __enter__(self):
Simon Glassb474c762018-07-26 14:02:13 -0600972 self._fdt.begin_node(self._name)
Simon Glass70cd0d72018-07-06 10:27:20 -0600973
974 def __exit__(self, type, value, traceback):
Simon Glassb474c762018-07-26 14:02:13 -0600975 self._fdt.end_node()
Simon Glassa13d9022017-05-27 07:38:11 -0600976%}
977
978%rename(fdt_property) fdt_property_func;
979
Simon Glassb474c762018-07-26 14:02:13 -0600980/*
981 * fdt32_t is a big-endian 32-bit value defined to uint32_t in libfdt_env.h
982 * so use the same type here.
983 */
984typedef uint32_t fdt32_t;
Simon Glassa13d9022017-05-27 07:38:11 -0600985
986%include "libfdt/fdt.h"
987
988%include "typemaps.i"
989
990/* Most functions don't change the device tree, so use a const void * */
991%typemap(in) (const void *)(const void *fdt) {
992 if (!PyByteArray_Check($input)) {
993 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
994 "', argument " "$argnum"" of type '" "$type""'");
995 }
996 $1 = (void *)PyByteArray_AsString($input);
997 fdt = $1;
998 fdt = fdt; /* avoid unused variable warning */
999}
1000
1001/* Some functions do change the device tree, so use void * */
1002%typemap(in) (void *)(const void *fdt) {
1003 if (!PyByteArray_Check($input)) {
1004 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1005 "', argument " "$argnum"" of type '" "$type""'");
1006 }
1007 $1 = PyByteArray_AsString($input);
1008 fdt = $1;
1009 fdt = fdt; /* avoid unused variable warning */
1010}
1011
Simon Glass70cd0d72018-07-06 10:27:20 -06001012/* typemap used for fdt_get_property_by_offset() */
Simon Glassa13d9022017-05-27 07:38:11 -06001013%typemap(out) (struct fdt_property *) {
1014 PyObject *buff;
1015
1016 if ($1) {
1017 resultobj = PyString_FromString(
1018 fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
1019 buff = PyByteArray_FromStringAndSize(
1020 (const char *)($1 + 1), fdt32_to_cpu($1->len));
1021 resultobj = SWIG_Python_AppendOutput(resultobj, buff);
1022 }
1023}
1024
1025%apply int *OUTPUT { int *lenp };
1026
1027/* typemap used for fdt_getprop() */
1028%typemap(out) (const void *) {
1029 if (!$1)
1030 $result = Py_None;
1031 else
1032 $result = Py_BuildValue("s#", $1, *arg4);
1033}
1034
Simon Glass70cd0d72018-07-06 10:27:20 -06001035/* typemap used for fdt_setprop() */
1036%typemap(in) (const void *val) {
1037 $1 = PyString_AsString($input); /* char *str */
1038}
1039
1040/* typemap used for fdt_add_reservemap_entry() */
1041%typemap(in) uint64_t {
1042 $1 = PyLong_AsUnsignedLong($input);
1043}
1044
1045/* typemaps used for fdt_next_node() */
1046%typemap(in, numinputs=1) int *depth (int depth) {
1047 depth = (int) PyInt_AsLong($input);
1048 $1 = &depth;
1049}
1050
1051%typemap(argout) int *depth {
1052 PyObject *val = Py_BuildValue("i", *arg$argnum);
1053 resultobj = SWIG_Python_AppendOutput(resultobj, val);
1054}
1055
1056%apply int *depth { int *depth };
1057
1058/* typemaps for fdt_get_mem_rsv */
1059%typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
1060 $1 = &temp;
1061}
1062
1063%typemap(argout) uint64_t * {
1064 PyObject *val = PyLong_FromUnsignedLong(*arg$argnum);
1065 if (!result) {
1066 if (PyTuple_GET_SIZE(resultobj) == 0)
1067 resultobj = val;
1068 else
1069 resultobj = SWIG_Python_AppendOutput(resultobj, val);
1070 }
1071}
1072
Simon Glassa13d9022017-05-27 07:38:11 -06001073/* We have both struct fdt_property and a function fdt_property() */
1074%warnfilter(302) fdt_property;
1075
1076/* These are macros in the header so have to be redefined here */
Simon Glassb474c762018-07-26 14:02:13 -06001077uint32_t fdt_magic(const void *fdt);
1078uint32_t fdt_totalsize(const void *fdt);
1079uint32_t fdt_off_dt_struct(const void *fdt);
1080uint32_t fdt_off_dt_strings(const void *fdt);
1081uint32_t fdt_off_mem_rsvmap(const void *fdt);
1082uint32_t fdt_version(const void *fdt);
1083uint32_t fdt_last_comp_version(const void *fdt);
1084uint32_t fdt_boot_cpuid_phys(const void *fdt);
1085uint32_t fdt_size_dt_strings(const void *fdt);
1086uint32_t fdt_size_dt_struct(const void *fdt);
1087
Simon Glass70cd0d72018-07-06 10:27:20 -06001088int fdt_property_string(void *fdt, const char *name, const char *val);
1089int fdt_property_cell(void *fdt, const char *name, uint32_t val);
1090
1091/*
1092 * This function has a stub since the name fdt_property is used for both a
1093 * function and a struct, which confuses SWIG.
1094 */
Simon Glassb474c762018-07-26 14:02:13 -06001095int fdt_property_stub(void *fdt, const char *name, const char *val, int len);
Simon Glassa13d9022017-05-27 07:38:11 -06001096
1097%include <../libfdt/libfdt.h>