blob: e3ceff1b2b31e19769dc39112ddbac6fd08da1e4 [file] [log] [blame]
Anas Nashifed3d7c12017-04-10 08:53:23 -04001#!/usr/bin/env python3
Tomasz Bursztyka6a9ebdc2018-03-07 15:17:28 +01002#
3# Copyright (c) 2017, Linaro Limited
Bobby Noelteca7fc2a2018-06-16 20:11:52 +02004# Copyright (c) 2018, Bobby Noelte
Tomasz Bursztyka6a9ebdc2018-03-07 15:17:28 +01005#
6# SPDX-License-Identifier: Apache-2.0
7#
Anas Nashif6b081412017-05-20 19:16:39 -04008
Ulf Magnusson7de2f4d2019-07-25 09:43:35 +02009# NOTE: This file is part of the old device tree scripts, which will be removed
10# later. They are kept to generate some legacy #defines via the
11# --deprecated-only flag.
12#
13# The new scripts are gen_defines.py, edtlib.py, and dtlib.py.
14
Anas Nashif6b081412017-05-20 19:16:39 -040015# vim: ai:ts=4:sw=4
16
Kumar Gala03fb9ff2017-10-23 02:32:15 -050017import os, fnmatch
Andy Grossbb063162017-01-29 23:53:17 -060018import re
19import yaml
Anas Nashif6b081412017-05-20 19:16:39 -040020import argparse
Ulf Magnusson3f8616a2019-02-12 05:54:58 +010021from collections import defaultdict
Andy Grossbb063162017-01-29 23:53:17 -060022
23from devicetree import parse_file
Bobby Noelteb6005bf2017-12-30 12:06:27 +010024from extract.globals import *
Kumar Gala112b0f52018-12-04 13:30:20 -060025import extract.globals
Andy Gross70e54f92017-06-15 13:15:23 -040026
Bobby Noelte08216f52018-06-16 19:59:39 +020027from extract.clocks import clocks
Erwan Gouriouc5ada392018-09-14 13:33:38 +020028from extract.compatible import compatible
Bobby Noelte08216f52018-06-16 19:59:39 +020029from extract.interrupts import interrupts
30from extract.reg import reg
31from extract.flash import flash
Bobby Noelte08216f52018-06-16 19:59:39 +020032from extract.default import default
33
Ulf Magnussona1f19692019-02-13 02:13:43 +010034
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010035def extract_bus_name(node_path, def_label):
Ulf Magnusson6127f0a2019-02-07 16:31:55 +010036 label = def_label + '_BUS_NAME'
Erwan Gouriou074c90c2018-03-29 17:25:13 +020037 prop_alias = {}
Andy Grossbb063162017-01-29 23:53:17 -060038
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010039 add_compat_alias(node_path, 'BUS_NAME', label, prop_alias)
Andy Grossbb063162017-01-29 23:53:17 -060040
Ulf Magnusson6127f0a2019-02-07 16:31:55 +010041 # Generate defines for node aliases
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010042 if node_path in aliases:
Ulf Magnussonf5ee8f62019-02-07 15:09:31 +010043 add_prop_aliases(
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010044 node_path,
Ulf Magnussonc631edd2019-02-07 15:30:46 +010045 lambda alias: str_to_label(alias) + '_BUS_NAME',
Ulf Magnussonf5ee8f62019-02-07 15:09:31 +010046 label,
47 prop_alias)
Andy Grossbb063162017-01-29 23:53:17 -060048
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010049 insert_defs(node_path,
50 {label: '"' + find_parent_prop(node_path, 'label') + '"'},
Ulf Magnusson6127f0a2019-02-07 16:31:55 +010051 prop_alias)
Andy Grossbb063162017-01-29 23:53:17 -060052
Ulf Magnusson9eb0d332019-02-08 19:57:24 +010053
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010054def extract_string_prop(node_path, key, label):
55 if node_path not in defs:
Ulf Magnusson00c43d42019-02-07 19:31:07 +010056 # Make all defs have the special 'aliases' key, to remove existence
57 # checks elsewhere
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010058 defs[node_path] = {'aliases': {}}
Ulf Magnusson9eb0d332019-02-08 19:57:24 +010059
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010060 defs[node_path][label] = '"' + reduced[node_path]['props'][key] + '"'
Kumar Gala65e72be2017-07-07 11:05:05 -050061
Kumar Gala65e72be2017-07-07 11:05:05 -050062
Ulf Magnussone04139f2019-02-20 21:21:46 +010063def generate_prop_defines(node_path, prop):
Ulf Magnusson79906fc2019-02-20 21:29:48 +010064 # Generates #defines (and .conf file values) from the prop
65 # named 'prop' on the device tree node at 'node_path'
66
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010067 binding = get_binding(node_path)
Ulf Magnusson5b791d12019-02-20 17:54:33 +010068 if 'parent' in binding and 'bus' in binding['parent']:
69 # If the binding specifies a parent for the node, then include the
70 # parent in the #define's generated for the properties
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010071 parent_path = get_parent_path(node_path)
Ulf Magnusson0a3f00a2019-02-27 19:32:08 +010072 def_label = 'DT_' + node_label(parent_path) + '_' \
73 + node_label(node_path)
Ulf Magnusson5b791d12019-02-20 17:54:33 +010074 else:
Ulf Magnusson0a3f00a2019-02-27 19:32:08 +010075 def_label = 'DT_' + node_label(node_path)
Erwan Gourioufa477482017-11-20 16:43:20 +010076
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010077 names = prop_names(reduced[node_path], prop)
Ulf Magnussone5394792019-02-18 21:35:23 +010078
Erwan Gourioue099f382018-04-27 14:40:13 +020079 if prop == 'reg':
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010080 reg.extract(node_path, names, def_label, 1)
Bobby Noelte08216f52018-06-16 19:59:39 +020081 elif prop == 'interrupts' or prop == 'interrupts-extended':
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010082 interrupts.extract(node_path, prop, names, def_label)
Erwan Gouriouc5ada392018-09-14 13:33:38 +020083 elif prop == 'compatible':
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010084 compatible.extract(node_path, prop, def_label)
Erwan Gouriou93d3a422018-05-04 14:37:31 +020085 elif 'clocks' in prop:
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010086 clocks.extract(node_path, prop, def_label)
Kumar Gala30960e62018-11-01 11:24:36 -050087 elif 'pwms' in prop or 'gpios' in prop:
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010088 prop_values = reduced[node_path]['props'][prop]
Ulf Magnussonb2785002019-02-06 20:49:29 +010089 generic = prop[:-1] # Drop the 's' from the prop
Erwan Gouriou93d3a422018-05-04 14:37:31 +020090
Kumar Gala5c78b932019-06-19 18:07:05 -050091 # Deprecated the non-'S' form
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010092 extract_controller(node_path, prop, prop_values, 0,
Kumar Gala5c78b932019-06-19 18:07:05 -050093 def_label, generic, deprecate=True)
Kumar Gala593d6282019-06-19 16:53:52 -050094 extract_controller(node_path, prop, prop_values, 0,
95 def_label, prop)
Kumar Gala5c78b932019-06-19 18:07:05 -050096 # Deprecated the non-'S' form
Ulf Magnussonf5b17d42019-02-20 19:32:15 +010097 extract_cells(node_path, prop, prop_values,
Kumar Gala5c78b932019-06-19 18:07:05 -050098 names, 0, def_label, generic, deprecate=True)
Kumar Gala593d6282019-06-19 16:53:52 -050099 extract_cells(node_path, prop, prop_values,
100 names, 0, def_label, prop)
Andy Gross70e54f92017-06-15 13:15:23 -0400101 else:
Ulf Magnussonf5b17d42019-02-20 19:32:15 +0100102 default.extract(node_path, prop,
Ulf Magnusson5b791d12019-02-20 17:54:33 +0100103 binding['properties'][prop]['type'],
Ulf Magnusson797eaa72019-02-18 21:43:55 +0100104 def_label)
Andy Grossbb063162017-01-29 23:53:17 -0600105
Andy Grossbb063162017-01-29 23:53:17 -0600106
Ulf Magnusson44467ef2019-02-14 09:29:46 +0100107def generate_node_defines(node_path):
Ulf Magnusson79906fc2019-02-20 21:29:48 +0100108 # Generates #defines (and .conf file values) from the device
109 # tree node at 'node_path'
110
Ulf Magnusson75c6d2c2019-02-18 22:29:46 +0100111 if get_compat(node_path) not in get_binding_compats():
Ulf Magnusson44467ef2019-02-14 09:29:46 +0100112 return
Andy Grossbb063162017-01-29 23:53:17 -0600113
Ulf Magnussonedc1f6a2019-02-20 17:12:42 +0100114 # We extract a few different #defines for a flash partition, so it's easier
115 # to handle it in one step
116 if 'partition@' in node_path:
117 flash.extract_partition(node_path)
118 return
119
Kumar Galabf0f6d92019-06-21 01:29:57 -0500120 if get_binding(node_path) is None:
121 return
122
Ulf Magnusson5b791d12019-02-20 17:54:33 +0100123 generate_bus_defines(node_path)
124
125 # Generate per-property ('foo = <1 2 3>', etc.) #defines
Ulf Magnusson75c6d2c2019-02-18 22:29:46 +0100126 for yaml_prop, yaml_val in get_binding(node_path)['properties'].items():
Kumar Gala31052832019-07-10 12:28:23 -0500127 if yaml_prop.startswith("#") or yaml_prop.endswith("-map"):
Ulf Magnussonaf3580c2019-02-18 13:39:03 +0100128 continue
Kumar Gala6fd3fbb2018-10-30 14:53:02 -0500129
Ulf Magnussonaf3580c2019-02-18 13:39:03 +0100130 match = False
131
132 # Handle each property individually, this ends up handling common
133 # patterns for things like reg, interrupts, etc that we don't need
134 # any special case handling at a node level
Ulf Magnusson75c6d2c2019-02-18 22:29:46 +0100135 for prop in reduced[node_path]['props']:
Ulf Magnusson75c6d2c2019-02-18 22:29:46 +0100136 if re.fullmatch(yaml_prop, prop):
Ulf Magnussonaf3580c2019-02-18 13:39:03 +0100137 match = True
Ulf Magnussone04139f2019-02-20 21:21:46 +0100138 generate_prop_defines(node_path, prop)
Andy Grossbb063162017-01-29 23:53:17 -0600139
Ulf Magnussonaf3580c2019-02-18 13:39:03 +0100140 # Handle the case that we have a boolean property, but its not
141 # in the dts
Ulf Magnusson75c6d2c2019-02-18 22:29:46 +0100142 if not match and yaml_val['type'] == 'boolean':
Ulf Magnussone04139f2019-02-20 21:21:46 +0100143 generate_prop_defines(node_path, yaml_prop)
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100144
Ulf Magnusson7bb57fe2019-02-18 20:39:51 +0100145
Ulf Magnusson5b791d12019-02-20 17:54:33 +0100146def generate_bus_defines(node_path):
147 # Generates any node-level #defines related to
148 #
149 # parent:
150 # bus: ...
151
152 binding = get_binding(node_path)
153 if not ('parent' in binding and 'bus' in binding['parent']):
154 return
155
Ulf Magnussonf5b17d42019-02-20 19:32:15 +0100156 parent_path = get_parent_path(node_path)
Ulf Magnusson5b791d12019-02-20 17:54:33 +0100157
158 # Check that parent has matching child bus value
159 try:
160 parent_binding = get_binding(parent_path)
161 parent_bus = parent_binding['child']['bus']
Ulf Magnusson399c04c2019-03-19 18:47:39 +0100162 except (KeyError, TypeError):
Ulf Magnusson5b791d12019-02-20 17:54:33 +0100163 raise Exception("{0} defines parent {1} as bus master, but {1} is not "
164 "configured as bus master in binding"
165 .format(node_path, parent_path))
166
167 if parent_bus != binding['parent']['bus']:
168 raise Exception("{0} defines parent {1} as {2} bus master, but {1} is "
169 "configured as {3} bus master"
170 .format(node_path, parent_path,
171 binding['parent']['bus'], parent_bus))
172
Ulf Magnusson5b791d12019-02-20 17:54:33 +0100173 # Generate *_BUS_NAME #define
174 extract_bus_name(
175 node_path,
Ulf Magnusson0a3f00a2019-02-27 19:32:08 +0100176 'DT_' + node_label(parent_path) + '_' + node_label(node_path))
Ulf Magnusson5b791d12019-02-20 17:54:33 +0100177
178
Ulf Magnusson7bb57fe2019-02-18 20:39:51 +0100179def prop_names(node, prop_name):
180 # Returns a list with the *-names for the property (reg-names,
181 # interrupt-names, etc.) The list is copied so that it can be modified
182 # in-place later without stomping on the device tree data.
183
Kumar Gala1c558822019-06-06 15:36:26 -0500184 # The first case turns 'interrupts' into 'interrupt-names'
185 names = node['props'].get(prop_name[:-1] + '-names', []) or \
186 node['props'].get(prop_name + '-names', [])
Ulf Magnusson7bb57fe2019-02-18 20:39:51 +0100187
188 if isinstance(names, list):
189 # Allow the list of names to be modified in-place without
190 # stomping on the property
191 return names.copy()
192
193 return [names]
194
195
Ulf Magnusson732fa652019-02-13 09:13:40 +0100196def merge_properties(parent, fname, to_dict, from_dict):
197 # Recursively merges the 'from_dict' dictionary into 'to_dict', to
198 # implement !include. 'parent' is the current parent key being looked at.
199 # 'fname' is the top-level .yaml file.
Andy Grossbb063162017-01-29 23:53:17 -0600200
Ulf Magnusson399c04c2019-03-19 18:47:39 +0100201 for k in from_dict:
Ulf Magnusson14de9972019-02-13 08:51:34 +0100202 if (k in to_dict and isinstance(to_dict[k], dict)
Ulf Magnusson732fa652019-02-13 09:13:40 +0100203 and isinstance(from_dict[k], dict)):
204 merge_properties(k, fname, to_dict[k], from_dict[k])
Erwan Gouriou104553d2017-11-23 08:48:10 +0100205 else:
Ulf Magnusson14de9972019-02-13 08:51:34 +0100206 to_dict[k] = from_dict[k]
Andy Grossad704932017-08-18 00:04:05 -0500207
Ulf Magnusson298b4432019-02-13 08:23:34 +0100208 # Warn when overriding a property and changing its value...
Ulf Magnusson14de9972019-02-13 08:51:34 +0100209 if (k in to_dict and to_dict[k] != from_dict[k] and
Ulf Magnusson298b4432019-02-13 08:23:34 +0100210 # ...unless it's the 'title', 'description', or 'version'
Anas Nashiff2cb20c2019-06-18 14:45:40 -0400211 # property. These are overridden deliberately.
Ulf Magnusson298b4432019-02-13 08:23:34 +0100212 not k in {'title', 'version', 'description'} and
213 # Also allow the category to be changed from 'optional' to
214 # 'required' without a warning
Ulf Magnusson14de9972019-02-13 08:51:34 +0100215 not (k == "category" and to_dict[k] == "optional" and
216 from_dict[k] == "required")):
Ulf Magnusson298b4432019-02-13 08:23:34 +0100217
218 print("extract_dts_includes.py: {}('{}') merge of property "
219 "'{}': '{}' overwrites '{}'"
Ulf Magnusson14de9972019-02-13 08:51:34 +0100220 .format(fname, parent, k, from_dict[k], to_dict[k]))
Ulf Magnusson298b4432019-02-13 08:23:34 +0100221
Erwan Gouriou1ee8eea2017-11-22 13:26:04 +0100222
Ulf Magnusson6a151302019-02-12 05:20:08 +0100223def merge_included_bindings(fname, node):
Ulf Magnusson2b8766d2019-02-12 06:32:34 +0100224 # Recursively merges properties from files !include'd from the 'inherits'
225 # section of the binding. 'fname' is the path to the top-level binding
226 # file, and 'node' the current top-level YAML node being processed.
Andy Grossad704932017-08-18 00:04:05 -0500227
Ulf Magnussonb29a5b02019-02-12 06:40:30 +0100228 check_binding_properties(node)
Bobby Noelteca7fc2a2018-06-16 20:11:52 +0200229
Bobby Noelte58967c72018-04-15 11:50:21 +0200230 if 'inherits' in node:
Ulf Magnusson298b4432019-02-13 08:23:34 +0100231 for inherited in node.pop('inherits'):
232 inherited = merge_included_bindings(fname, inherited)
Ulf Magnusson732fa652019-02-13 09:13:40 +0100233 merge_properties(None, fname, inherited, node)
Ulf Magnusson298b4432019-02-13 08:23:34 +0100234 node = inherited
Ulf Magnussonb29a5b02019-02-12 06:40:30 +0100235
Erwan Gouriou104553d2017-11-23 08:48:10 +0100236 return node
Andy Grossad704932017-08-18 00:04:05 -0500237
238
Ulf Magnussonb29a5b02019-02-12 06:40:30 +0100239def check_binding_properties(node):
240 # Checks that the top-level YAML node 'node' has the expected properties.
241 # Prints warnings and substitutes defaults otherwise.
242
243 if 'title' not in node:
244 print("extract_dts_includes.py: node without 'title' -", node)
245
Ulf Magnusson0ec0c842019-07-19 23:59:17 +0200246 for prop in 'title', 'description':
Ulf Magnussonb29a5b02019-02-12 06:40:30 +0100247 if prop not in node:
248 node[prop] = "<unknown {}>".format(prop)
249 print("extract_dts_includes.py: '{}' property missing "
250 "in '{}' binding. Using '{}'."
251 .format(prop, node['title'], node[prop]))
252
253 if 'id' in node:
254 print("extract_dts_includes.py: WARNING: id field set "
255 "in '{}', should be removed.".format(node['title']))
256
257
Kumar Gala561d6dd2019-02-08 10:10:57 -0600258def define_str(name, value, value_tabs, is_deprecated=False):
Ulf Magnusson298f9e12019-02-07 23:10:14 +0100259 line = "#define " + name
Kumar Gala561d6dd2019-02-08 10:10:57 -0600260 if is_deprecated:
261 line += " __DEPRECATED_MACRO "
Ulf Magnusson298f9e12019-02-07 23:10:14 +0100262 return line + (value_tabs - len(line)//8)*'\t' + str(value) + '\n'
Andy Gross70e54f92017-06-15 13:15:23 -0400263
Andy Grossbb063162017-01-29 23:53:17 -0600264
Ulf Magnusson72f01252019-02-07 20:03:56 +0100265def write_conf(f):
Ulf Magnusson00c43d42019-02-07 19:31:07 +0100266 for node in sorted(defs):
Ulf Magnusson72f01252019-02-07 20:03:56 +0100267 f.write('# ' + node.split('/')[-1] + '\n')
Anas Nashifb60ff2f2017-05-20 19:44:46 -0400268
Ulf Magnusson00c43d42019-02-07 19:31:07 +0100269 for prop in sorted(defs[node]):
Kumar Gala1f1282a2019-02-09 06:30:51 -0600270 if prop != 'aliases' and prop.startswith("DT_"):
Ulf Magnusson72f01252019-02-07 20:03:56 +0100271 f.write('%s=%s\n' % (prop, defs[node][prop]))
Anas Nashifb60ff2f2017-05-20 19:44:46 -0400272
Ulf Magnusson00c43d42019-02-07 19:31:07 +0100273 for alias in sorted(defs[node]['aliases']):
274 alias_target = defs[node]['aliases'][alias]
Kumar Galae3e87f62019-02-08 16:03:44 -0600275 if alias_target not in defs[node]:
276 alias_target = defs[node]['aliases'][alias_target]
Kumar Gala1f1282a2019-02-09 06:30:51 -0600277 if alias.startswith("DT_"):
278 f.write('%s=%s\n' % (alias, defs[node].get(alias_target)))
Ulf Magnusson00c43d42019-02-07 19:31:07 +0100279
Ulf Magnusson72f01252019-02-07 20:03:56 +0100280 f.write('\n')
Tomasz Bursztyka11343932018-03-07 11:15:00 +0100281
Anas Nashifb60ff2f2017-05-20 19:44:46 -0400282
Ulf Magnussona72e4512019-07-25 01:05:54 +0200283def write_header(f, deprecated_only):
Ulf Magnusson72f01252019-02-07 20:03:56 +0100284 f.write('''\
Sebastian Bøe361daf82019-01-24 10:18:05 +0100285/**********************************************
286* Generated include file
287* DO NOT MODIFY
288*/
289#ifndef GENERATED_DTS_BOARD_UNFIXED_H
290#define GENERATED_DTS_BOARD_UNFIXED_H
Ulf Magnusson0e922bf2019-02-07 20:11:23 +0100291''')
Andy Grossbb063162017-01-29 23:53:17 -0600292
Ulf Magnusson638e89b2019-02-07 22:38:24 +0100293 def max_dict_key(dct):
294 return max(len(key) for key in dct)
295
Ulf Magnusson0e922bf2019-02-07 20:11:23 +0100296 for node in sorted(defs):
297 f.write('/* ' + node.split('/')[-1] + ' */\n')
Andy Grossbb063162017-01-29 23:53:17 -0600298
Ulf Magnusson638e89b2019-02-07 22:38:24 +0100299 maxlen = max_dict_key(defs[node])
Ulf Magnusson0e922bf2019-02-07 20:11:23 +0100300 if defs[node]['aliases']:
Ulf Magnusson638e89b2019-02-07 22:38:24 +0100301 maxlen = max(maxlen, max_dict_key(defs[node]['aliases']))
302 maxlen += len('#define ')
Aska Wu729a7b12017-09-13 17:53:18 +0800303
Ulf Magnusson638e89b2019-02-07 22:38:24 +0100304 value_tabs = (maxlen + 8)//8 # Tabstop index for value
305 if 8*value_tabs - maxlen <= 2:
306 # Add some minimum room between the macro name and the value
307 value_tabs += 1
Andy Grossbb063162017-01-29 23:53:17 -0600308
Ulf Magnusson0e922bf2019-02-07 20:11:23 +0100309 for prop in sorted(defs[node]):
310 if prop != 'aliases':
Kumar Gala08a5f9f2019-06-22 10:38:30 -0500311 deprecated_warn = False
312 if prop in deprecated_main:
313 deprecated_warn = True
Kumar Gala81072b52019-06-21 13:15:13 -0500314 if not prop.startswith('DT_'):
315 deprecated_warn = True
Ulf Magnussona72e4512019-07-25 01:05:54 +0200316 if deprecated_only and not deprecated_warn:
Kumar Gala4d2625c2019-07-10 07:41:50 -0500317 continue
Kumar Gala08a5f9f2019-06-22 10:38:30 -0500318 f.write(define_str(prop, defs[node][prop], value_tabs, deprecated_warn))
Anas Nashifb60ff2f2017-05-20 19:44:46 -0400319
Ulf Magnusson0e922bf2019-02-07 20:11:23 +0100320 for alias in sorted(defs[node]['aliases']):
321 alias_target = defs[node]['aliases'][alias]
Kumar Gala561d6dd2019-02-08 10:10:57 -0600322 deprecated_warn = False
323 # Mark any non-DT_ prefixed define as deprecated except
324 # for now we special case LED, SW, and *PWM_LED*
Kumar Gala81072b52019-06-21 13:15:13 -0500325 if not alias.startswith('DT_'):
Kumar Gala561d6dd2019-02-08 10:10:57 -0600326 deprecated_warn = True
Kumar Gala01e54a52019-06-07 15:36:57 -0500327 if alias in deprecated:
328 deprecated_warn = True
Ulf Magnussona72e4512019-07-25 01:05:54 +0200329 if deprecated_only and not deprecated_warn:
Kumar Gala4d2625c2019-07-10 07:41:50 -0500330 continue
Kumar Gala561d6dd2019-02-08 10:10:57 -0600331 f.write(define_str(alias, alias_target, value_tabs, deprecated_warn))
Andy Grossbb063162017-01-29 23:53:17 -0600332
Ulf Magnusson0e922bf2019-02-07 20:11:23 +0100333 f.write('\n')
334
335 f.write('#endif\n')
Anas Nashif6b081412017-05-20 19:16:39 -0400336
Andy Gross70e54f92017-06-15 13:15:23 -0400337
Ulf Magnussona1f19692019-02-13 02:13:43 +0100338def load_bindings(root, binding_dirs):
339 find_binding_files(binding_dirs)
Ulf Magnusson32e65652019-02-13 02:44:39 +0100340 dts_compats = all_compats(root)
Ulf Magnussona1f19692019-02-13 02:13:43 +0100341
Ulf Magnusson32e65652019-02-13 02:44:39 +0100342 compat_to_binding = {}
343 # Maps buses to dictionaries that map compats to YAML nodes
344 bus_to_binding = defaultdict(dict)
345 compats = []
Andy Gross70e54f92017-06-15 13:15:23 -0400346
Ulf Magnusson35b3d442019-02-13 04:37:59 +0100347 # Add '!include foo.yaml' handling
Michael Scott4278bf52019-03-13 15:04:40 -0700348 yaml.Loader.add_constructor('!include', yaml_include)
Ulf Magnusson35b3d442019-02-13 04:37:59 +0100349
Ulf Magnusson32e65652019-02-13 02:44:39 +0100350 loaded_yamls = set()
351
352 for file in binding_files:
353 # Extract compat from 'constraint:' line
354 for line in open(file, 'r', encoding='utf-8'):
355 match = re.match(r'\s+constraint:\s*"([^"]*)"', line)
356 if match:
357 break
358 else:
359 # No 'constraint:' line found. Move on to next yaml file.
360 continue
361
362 compat = match.group(1)
363 if compat not in dts_compats or file in loaded_yamls:
364 # The compat does not appear in the device tree, or the yaml
365 # file has already been loaded
366 continue
367
368 # Found a binding (.yaml file) for a 'compatible' value that
369 # appears in DTS. Load it.
370
371 loaded_yamls.add(file)
372
373 if compat not in compats:
374 compats.append(compat)
375
376 with open(file, 'r', encoding='utf-8') as yf:
Michael Scott4278bf52019-03-13 15:04:40 -0700377 binding = merge_included_bindings(file,
378 yaml.load(yf, Loader=yaml.Loader))
Ulf Magnusson32e65652019-02-13 02:44:39 +0100379
380 if 'parent' in binding:
381 bus_to_binding[binding['parent']['bus']][compat] = binding
Henrik Brix Andersenf9dd5362019-03-24 20:32:42 +0100382
383 compat_to_binding[compat] = binding
Ulf Magnusson32e65652019-02-13 02:44:39 +0100384
385 if not compat_to_binding:
386 raise Exception("No bindings found in '{}'".format(binding_dirs))
387
388 extract.globals.bindings = compat_to_binding
389 extract.globals.bus_bindings = bus_to_binding
Ulf Magnusson59a0c432019-02-21 21:34:45 +0100390 extract.globals.binding_compats = compats
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100391
392
Ulf Magnussona1f19692019-02-13 02:13:43 +0100393def find_binding_files(binding_dirs):
394 # Initializes the global 'binding_files' variable with a list of paths to
395 # binding (.yaml) files
396
397 global binding_files
398
399 binding_files = []
400
401 for binding_dir in binding_dirs:
Ulf Magnusson399c04c2019-03-19 18:47:39 +0100402 for root, _, filenames in os.walk(binding_dir):
Ulf Magnussona1f19692019-02-13 02:13:43 +0100403 for filename in fnmatch.filter(filenames, '*.yaml'):
404 binding_files.append(os.path.join(root, filename))
405
406
Ulf Magnusson35b3d442019-02-13 04:37:59 +0100407def yaml_include(loader, node):
408 # Implements !include. Returns a list with the top-level YAML structures
409 # for the included files (a single-element list if there's just one file).
410
411 if isinstance(node, yaml.ScalarNode):
412 # !include foo.yaml
413 return [load_binding_file(loader.construct_scalar(node))]
414
415 if isinstance(node, yaml.SequenceNode):
416 # !include [foo.yaml, bar.yaml]
417 return [load_binding_file(fname)
418 for fname in loader.construct_sequence(node)]
419
Ulf Magnussonf0eeb112019-02-13 07:46:03 +0100420 yaml_inc_error("Error: unrecognised node type in !include statement")
Ulf Magnusson35b3d442019-02-13 04:37:59 +0100421
422
423def load_binding_file(fname):
424 # yaml_include() helper for loading an !include'd file. !include takes just
425 # the basename of the file, so we need to make sure that there aren't
426 # multiple candidates.
427
428 filepaths = [filepath for filepath in binding_files
429 if os.path.basename(filepath) == os.path.basename(fname)]
430
431 if not filepaths:
Ulf Magnussonf0eeb112019-02-13 07:46:03 +0100432 yaml_inc_error("Error: unknown file name '{}' in !include statement"
433 .format(fname))
Ulf Magnusson35b3d442019-02-13 04:37:59 +0100434
435 if len(filepaths) > 1:
Ulf Magnussonf0eeb112019-02-13 07:46:03 +0100436 yaml_inc_error("Error: multiple candidates for file name '{}' in "
437 "!include statement: {}".format(fname, filepaths))
Ulf Magnusson35b3d442019-02-13 04:37:59 +0100438
439 with open(filepaths[0], 'r', encoding='utf-8') as f:
Michael Scott4278bf52019-03-13 15:04:40 -0700440 return yaml.load(f, Loader=yaml.Loader)
Ulf Magnusson35b3d442019-02-13 04:37:59 +0100441
442
Ulf Magnussonf0eeb112019-02-13 07:46:03 +0100443def yaml_inc_error(msg):
444 # Helper for reporting errors in the !include implementation
445
446 raise yaml.constructor.ConstructorError(None, None, msg)
447
448
Ulf Magnussoncbf9afc2019-02-14 05:53:03 +0100449def generate_defines():
Ulf Magnusson79906fc2019-02-20 21:29:48 +0100450 # Generates #defines (and .conf file values) from DTS
451
Marc Herbert73cb0bf2019-03-06 11:43:37 -0800452 # sorted() otherwise Python < 3.6 randomizes the order of the flash
453 # partition table
454 for node_path in sorted(reduced.keys()):
Ulf Magnusson858701f2019-02-19 09:12:14 +0100455 generate_node_defines(node_path)
Andy Gross70e54f92017-06-15 13:15:23 -0400456
Ulf Magnusson87193b02019-02-07 17:50:44 +0100457 if not defs:
Andy Gross70e54f92017-06-15 13:15:23 -0400458 raise Exception("No information parsed from dts file.")
459
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100460 for k, v in regs_config.items():
461 if k in chosen:
Kumar Gala35afcc92018-12-04 13:26:05 -0600462 reg.extract(chosen[k], None, v, 1024)
Kumar Gala8a6381d2018-01-18 13:31:54 -0600463
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100464 for k, v in name_config.items():
465 if k in chosen:
Kumar Gala35afcc92018-12-04 13:26:05 -0600466 extract_string_prop(chosen[k], "label", v)
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100467
Ulf Magnusson958e2d32019-02-27 23:59:17 +0100468 flash.extract_flash()
469 flash.extract_code_partition()
Andy Grossbb063162017-01-29 23:53:17 -0600470
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100471
472def parse_arguments():
473 rdh = argparse.RawDescriptionHelpFormatter
474 parser = argparse.ArgumentParser(description=__doc__, formatter_class=rdh)
475
Ulf Magnusson2528b532019-02-07 17:26:52 +0100476 parser.add_argument("-d", "--dts", required=True, help="DTS file")
Bobby Noelte5a16b902018-08-21 11:02:48 +0200477 parser.add_argument("-y", "--yaml", nargs='+', required=True,
478 help="YAML file directories, we allow multiple")
Ulf Magnusson2528b532019-02-07 17:26:52 +0100479 parser.add_argument("-i", "--include",
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100480 help="Generate include file for the build system")
Ulf Magnusson2528b532019-02-07 17:26:52 +0100481 parser.add_argument("-k", "--keyvalue",
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100482 help="Generate config file for the build system")
Andrzej Głąbeka7c430f2018-10-31 19:19:54 +0100483 parser.add_argument("--old-alias-names", action='store_true',
484 help="Generate aliases also in the old way, without "
485 "compatibility information in their labels")
Ulf Magnussona72e4512019-07-25 01:05:54 +0200486 parser.add_argument("--deprecated-only", action='store_true',
Kumar Gala4d2625c2019-07-10 07:41:50 -0500487 help="Generate only the deprecated defines")
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100488 return parser.parse_args()
489
490
491def main():
492 args = parse_arguments()
Andrzej Głąbeka7c430f2018-10-31 19:19:54 +0100493 enable_old_alias_names(args.old_alias_names)
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100494
Ulf Magnussoncb507882019-02-08 21:40:33 +0100495 # Parse DTS and fetch the root node
Ulf Magnusson4217de02019-02-07 17:40:01 +0100496 with open(args.dts, 'r', encoding='utf-8') as f:
Ulf Magnussoncb507882019-02-08 21:40:33 +0100497 root = parse_file(f)['/']
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100498
Ulf Magnussoncb507882019-02-08 21:40:33 +0100499 # Create some global data structures from the parsed DTS
500 create_reduced(root, '/')
Ulf Magnusson8c515b22019-02-08 22:26:51 +0100501 create_phandles(root, '/')
Ulf Magnussoncb507882019-02-08 21:40:33 +0100502 create_aliases(root)
503 create_chosen(root)
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100504
Kumar Gala062bd062019-06-10 11:23:09 -0500505 # Re-sort instance_id by reg addr
506 #
507 # Note: this is a short term fix and should be removed when
508 # generate defines for instance with a prefix like 'DT_INST'
509 #
510 # Build a dict of dicts, first level is index by compat
511 # second level is index by reg addr
512 compat_reg_dict = defaultdict(dict)
513 for node in reduced.values():
514 instance = node.get('instance_id')
515 if instance and node['addr'] is not None:
516 for compat in instance:
517 reg = node['addr']
518 compat_reg_dict[compat][reg] = node
519
520 # Walk the reg addr in sorted order to re-index 'instance_id'
521 for compat in compat_reg_dict:
522 # only update if we have more than one instance
523 if len(compat_reg_dict[compat]) > 1:
524 for idx, reg_addr in enumerate(sorted(compat_reg_dict[compat])):
525 compat_reg_dict[compat][reg_addr]['instance_id'][compat] = idx
526
Ulf Magnusson0e40c962019-02-14 05:57:58 +0100527 # Load any bindings (.yaml files) that match 'compatible' values from the
528 # DTS
Ulf Magnussond859f4f2019-02-13 02:03:19 +0100529 load_bindings(root, args.yaml)
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100530
Ulf Magnusson0e40c962019-02-14 05:57:58 +0100531 # Generate keys and values for the configuration file and the header file
Ulf Magnussoncbf9afc2019-02-14 05:53:03 +0100532 generate_defines()
Tomasz Bursztyka7ef3dde2018-03-07 15:03:27 +0100533
Ulf Magnusson0e40c962019-02-14 05:57:58 +0100534 # Write the configuration file and the header file
Ulf Magnusson4217de02019-02-07 17:40:01 +0100535
Ulf Magnussone8a077b2019-02-06 21:14:34 +0100536 if args.keyvalue is not None:
Ulf Magnusson4217de02019-02-07 17:40:01 +0100537 with open(args.keyvalue, 'w', encoding='utf-8') as f:
Ulf Magnusson72f01252019-02-07 20:03:56 +0100538 write_conf(f)
Tomasz Bursztyka11343932018-03-07 11:15:00 +0100539
Ulf Magnussone8a077b2019-02-06 21:14:34 +0100540 if args.include is not None:
Ulf Magnusson4217de02019-02-07 17:40:01 +0100541 with open(args.include, 'w', encoding='utf-8') as f:
Ulf Magnussona72e4512019-07-25 01:05:54 +0200542 write_header(f, args.deprecated_only)
Andy Gross70e54f92017-06-15 13:15:23 -0400543
Andy Grossbb063162017-01-29 23:53:17 -0600544
545if __name__ == '__main__':
Anas Nashif6b081412017-05-20 19:16:39 -0400546 main()