]>
git.ipfire.org Git - people/ms/u-boot.git/blob - tools/dtoc/dtb_platdata.py
3 # Copyright (C) 2017 Google, Inc
4 # Written by Simon Glass <sjg@chromium.org>
6 # SPDX-License-Identifier: GPL-2.0+
14 # When we see these properties we ignore them - i.e. do not create a structure member
23 'u-boot,dm-pre-reloc',
28 # C type declarations for the tyues we support
30 fdt
.TYPE_INT
: 'fdt32_t',
31 fdt
.TYPE_BYTE
: 'unsigned char',
32 fdt
.TYPE_STRING
: 'const char *',
33 fdt
.TYPE_BOOL
: 'bool',
36 STRUCT_PREFIX
= 'dtd_'
39 def Conv_name_to_c(name
):
40 """Convert a device-tree name to a C identifier
45 String containing the C version of this name
47 str = name
.replace('@', '_at_')
48 str = str.replace('-', '_')
49 str = str.replace(',', '_')
50 str = str.replace('.', '_')
51 str = str.replace('/', '__')
54 def TabTo(num_tabs
, str):
55 if len(str) >= num_tabs
* 8:
57 return str + '\t' * (num_tabs
- len(str) // 8)
60 """Provide a means to convert device tree binary data to platform data
62 The output of this process is C structures which can be used in space-
63 constrained encvironments where the ~3KB code overhead of device tree
64 code is not affordable.
67 fdt: Fdt object, referencing the device tree
68 _dtb_fname: Filename of the input device tree binary file
69 _valid_nodes: A list of Node object with compatible strings
70 _options: Command-line options
71 _phandle_node: A dict of nodes indexed by phandle number (1, 2...)
72 _outfile: The current output file (sys.stdout or a real file)
73 _lines: Stashed list of output lines for outputting in the future
74 _phandle_node: A dict of Nodes indexed by phandle (an integer)
76 def __init__(self
, dtb_fname
, options
):
77 self
._dtb
_fname
= dtb_fname
78 self
._valid
_nodes
= None
79 self
._options
= options
80 self
._phandle
_node
= {}
85 def SetupOutput(self
, fname
):
86 """Set up the output destination
88 Once this is done, future calls to self.Out() will output to this
92 fname: Filename to send output to, or '-' for stdout
95 self
._outfile
= sys
.stdout
97 self
._outfile
= open(fname
, 'w')
100 """Output a string to the output file
103 str: String to output
105 self
._outfile
.write(str)
108 """Buffer up a string to send later
111 str: String to add to our 'buffer' list
113 self
._lines
.append(str)
116 """Get the contents of the output buffer, and clear it
119 The output buffer, which is then cleared for future use
125 def GetValue(self
, type, value
):
126 """Get a value as a C expression
128 For integers this returns a byte-swapped (little-endian) hex string
129 For bytes this returns a hex string, e.g. 0x12
130 For strings this returns a literal string enclosed in quotes
131 For booleans this return 'true'
134 type: Data type (fdt_util)
135 value: Data value, as a string of bytes
137 if type == fdt
.TYPE_INT
:
138 return '%#x' % fdt_util
.fdt32_to_cpu(value
)
139 elif type == fdt
.TYPE_BYTE
:
140 return '%#x' % ord(value
[0])
141 elif type == fdt
.TYPE_STRING
:
142 return '"%s"' % value
143 elif type == fdt
.TYPE_BOOL
:
146 def GetCompatName(self
, node
):
147 """Get a node's first compatible string as a C identifier
150 node: Node object to check
152 C identifier for the first compatible string
154 compat
= node
.props
['compatible'].value
156 if type(compat
) == list:
157 compat
, aliases
= compat
[0], compat
[1:]
158 return Conv_name_to_c(compat
), [Conv_name_to_c(a
) for a
in aliases
]
161 """Scan the device tree to obtain a tree of notes and properties
163 Once this is done, self.fdt.GetRoot() can be called to obtain the
164 device tree root node, and progress from there.
166 self
.fdt
= fdt
.FdtScan(self
._dtb
_fname
)
168 def ScanNode(self
, root
):
169 for node
in root
.subnodes
:
170 if 'compatible' in node
.props
:
171 status
= node
.props
.get('status')
172 if (not self
._options
.include_disabled
and not status
or
173 status
.value
!= 'disabled'):
174 self
._valid
_nodes
.append(node
)
175 phandle_prop
= node
.props
.get('phandle')
177 phandle
= phandle_prop
.GetPhandle()
178 self
._phandle
_node
[phandle
] = node
180 # recurse to handle any subnodes
184 """Scan the device tree for useful information
186 This fills in the following properties:
187 _phandle_node: A dict of Nodes indexed by phandle (an integer)
188 _valid_nodes: A list of nodes we wish to consider include in the
191 self
._phandle
_node
= {}
192 self
._valid
_nodes
= []
193 return self
.ScanNode(self
.fdt
.GetRoot());
195 for node
in self
.fdt
.GetRoot().subnodes
:
196 if 'compatible' in node
.props
:
197 status
= node
.props
.get('status')
198 if (not self
._options
.include_disabled
and not status
or
199 status
.value
!= 'disabled'):
200 node_list
.append(node
)
201 phandle_prop
= node
.props
.get('phandle')
203 phandle
= phandle_prop
.GetPhandle()
204 self
._phandle
_node
[phandle
] = node
206 self
._valid
_nodes
= node_list
208 def IsPhandle(self
, prop
):
209 """Check if a node contains phandles
211 We have no reliable way of detecting whether a node uses a phandle
212 or not. As an interim measure, use a list of known property names.
215 prop: Prop object to check
217 True if the object value contains phandles, else False
219 if prop
.name
in ['clocks']:
223 def ScanStructs(self
):
224 """Scan the device tree building up the C structures we will use.
226 Build a dict keyed by C struct name containing a dict of Prop
227 object for each struct field (keyed by property name). Where the
228 same struct appears multiple times, try to use the 'widest'
229 property, i.e. the one with a type which can express all others.
231 Once the widest property is determined, all other properties are
232 updated to match that width.
235 for node
in self
._valid
_nodes
:
236 node_name
, _
= self
.GetCompatName(node
)
239 # Get a list of all the valid properties in this node.
240 for name
, prop
in node
.props
.items():
241 if name
not in PROP_IGNORE_LIST
and name
[0] != '#':
242 fields
[name
] = copy
.deepcopy(prop
)
244 # If we've seen this node_name before, update the existing struct.
245 if node_name
in structs
:
246 struct
= structs
[node_name
]
247 for name
, prop
in fields
.items():
248 oldprop
= struct
.get(name
)
254 # Otherwise store this as a new struct.
256 structs
[node_name
] = fields
259 for node
in self
._valid
_nodes
:
260 node_name
, _
= self
.GetCompatName(node
)
261 struct
= structs
[node_name
]
262 for name
, prop
in node
.props
.items():
263 if name
not in PROP_IGNORE_LIST
and name
[0] != '#':
264 prop
.Widen(struct
[name
])
267 struct_name
, aliases
= self
.GetCompatName(node
)
268 for alias
in aliases
:
269 self
._aliases
[alias
] = struct_name
273 def ScanPhandles(self
):
274 """Figure out what phandles each node uses
276 We need to be careful when outputing nodes that use phandles since
277 they must come after the declaration of the phandles in the C file.
278 Otherwise we get a compiler error since the phandle struct is not yet
281 This function adds to each node a list of phandle nodes that the node
282 depends on. This allows us to output things in the right order.
284 for node
in self
._valid
_nodes
:
285 node
.phandles
= set()
286 for pname
, prop
in node
.props
.items():
287 if pname
in PROP_IGNORE_LIST
or pname
[0] == '#':
289 if type(prop
.value
) == list:
290 if self
.IsPhandle(prop
):
291 # Process the list as pairs of (phandle, id)
292 it
= iter(prop
.value
)
293 for phandle_cell
, id_cell
in zip(it
, it
):
294 phandle
= fdt_util
.fdt32_to_cpu(phandle_cell
)
295 id = fdt_util
.fdt32_to_cpu(id_cell
)
296 target_node
= self
._phandle
_node
[phandle
]
297 node
.phandles
.add(target_node
)
300 def GenerateStructs(self
, structs
):
301 """Generate struct defintions for the platform data
303 This writes out the body of a header file consisting of structure
304 definitions for node in self._valid_nodes. See the documentation in
305 README.of-plat for more information.
307 self
.Out('#include <stdbool.h>\n')
308 self
.Out('#include <libfdt.h>\n')
310 # Output the struct definition
311 for name
in sorted(structs
):
312 self
.Out('struct %s%s {\n' % (STRUCT_PREFIX
, name
));
313 for pname
in sorted(structs
[name
]):
314 prop
= structs
[name
][pname
]
315 if self
.IsPhandle(prop
):
316 # For phandles, include a reference to the target
317 self
.Out('\t%s%s[%d]' % (TabTo(2, 'struct phandle_2_cell'),
318 Conv_name_to_c(prop
.name
),
319 len(prop
.value
) / 2))
321 ptype
= TYPE_NAMES
[prop
.type]
322 self
.Out('\t%s%s' % (TabTo(2, ptype
),
323 Conv_name_to_c(prop
.name
)))
324 if type(prop
.value
) == list:
325 self
.Out('[%d]' % len(prop
.value
))
329 for alias
, struct_name
in self
._aliases
.iteritems():
330 self
.Out('#define %s%s %s%s\n'% (STRUCT_PREFIX
, alias
,
331 STRUCT_PREFIX
, struct_name
))
333 def OutputNode(self
, node
):
334 """Output the C code for a node
339 struct_name
, _
= self
.GetCompatName(node
)
340 var_name
= Conv_name_to_c(node
.name
)
341 self
.Buf('static struct %s%s %s%s = {\n' %
342 (STRUCT_PREFIX
, struct_name
, VAL_PREFIX
, var_name
))
343 for pname
, prop
in node
.props
.items():
344 if pname
in PROP_IGNORE_LIST
or pname
[0] == '#':
346 ptype
= TYPE_NAMES
[prop
.type]
347 member_name
= Conv_name_to_c(prop
.name
)
348 self
.Buf('\t%s= ' % TabTo(3, '.' + member_name
))
350 # Special handling for lists
351 if type(prop
.value
) == list:
354 # For phandles, output a reference to the platform data
355 # of the target node.
356 if self
.IsPhandle(prop
):
357 # Process the list as pairs of (phandle, id)
358 it
= iter(prop
.value
)
359 for phandle_cell
, id_cell
in zip(it
, it
):
360 phandle
= fdt_util
.fdt32_to_cpu(phandle_cell
)
361 id = fdt_util
.fdt32_to_cpu(id_cell
)
362 target_node
= self
._phandle
_node
[phandle
]
363 name
= Conv_name_to_c(target_node
.name
)
364 vals
.append('{&%s%s, %d}' % (VAL_PREFIX
, name
, id))
366 for val
in prop
.value
:
367 vals
.append(self
.GetValue(prop
.type, val
))
368 self
.Buf(', '.join(vals
))
371 self
.Buf(self
.GetValue(prop
.type, prop
.value
))
375 # Add a device declaration
376 self
.Buf('U_BOOT_DEVICE(%s) = {\n' % var_name
)
377 self
.Buf('\t.name\t\t= "%s",\n' % struct_name
)
378 self
.Buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX
, var_name
))
379 self
.Buf('\t.platdata_size\t= sizeof(%s%s),\n' %
380 (VAL_PREFIX
, var_name
))
384 self
.Out(''.join(self
.GetBuf()))
386 def GenerateTables(self
):
387 """Generate device defintions for the platform data
389 This writes out C platform data initialisation data and
390 U_BOOT_DEVICE() declarations for each valid node. Where a node has
391 multiple compatible strings, a #define is used to make them equivalent.
393 See the documentation in doc/driver-model/of-plat.txt for more
396 self
.Out('#include <common.h>\n')
397 self
.Out('#include <dm.h>\n')
398 self
.Out('#include <dt-structs.h>\n')
400 nodes_to_output
= list(self
._valid
_nodes
)
402 # Keep outputing nodes until there is none left
403 while nodes_to_output
:
404 node
= nodes_to_output
[0]
405 # Output all the node's dependencies first
406 for req_node
in node
.phandles
:
407 if req_node
in nodes_to_output
:
408 self
.OutputNode(req_node
)
409 nodes_to_output
.remove(req_node
)
410 self
.OutputNode(node
)
411 nodes_to_output
.remove(node
)