zephyr/scripts/dts/extract/globals.py
Kumar Gala c922788d0a scripts/dts/extract: Add support for translating range properties
For now we've used range properties as a pass through.  However range
properties can translate from one address space to another.  This is
typically used one address spaces translate from one physical bus to
another (For example going from PCI address space to internal SoC memory
map).  However, we can also use this for cases where we want to reduce
duplication (For example with ARMv8-M for secure v non-secure MMIO
registers).

'ranges' takes either the form of:
	ranges; /* pass through translation */
or:
	ranges = <child-bus-address parent-bus-address length>;

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
2018-10-05 13:19:39 -05:00

254 lines
6.9 KiB
Python

#
# Copyright (c) 2017 Linaro
# Copyright (c) 2017 Bobby Noelte
#
# SPDX-License-Identifier: Apache-2.0
#
from collections import defaultdict
from copy import deepcopy
# globals
phandles = {}
aliases = defaultdict(list)
chosen = {}
reduced = {}
defs = {}
structs = {}
regs_config = {
'zephyr,flash' : 'CONFIG_FLASH',
'zephyr,sram' : 'CONFIG_SRAM',
'zephyr,ccm' : 'CONFIG_CCM'
}
name_config = {
'zephyr,console' : 'CONFIG_UART_CONSOLE_ON_DEV_NAME',
'zephyr,bt-uart' : 'CONFIG_BT_UART_ON_DEV_NAME',
'zephyr,uart-pipe' : 'CONFIG_UART_PIPE_ON_DEV_NAME',
'zephyr,bt-mon-uart' : 'CONFIG_BT_MONITOR_ON_DEV_NAME',
'zephyr,uart-mcumgr' : 'CONFIG_UART_MCUMGR_ON_DEV_NAME'
}
def convert_string_to_label(s):
# Transmute ,-@/ to _
s = s.replace("-", "_")
s = s.replace(",", "_")
s = s.replace("@", "_")
s = s.replace("/", "_")
# Uppercase the string
s = s.upper()
return s
def get_all_compatibles(d, name, comp_dict):
if 'props' in d:
compat = d['props'].get('compatible')
enabled = d['props'].get('status')
if enabled == "disabled":
return comp_dict
if compat is not None:
comp_dict[name] = compat
if name != '/':
name += '/'
if isinstance(d, dict):
if d['children']:
for k, v in d['children'].items():
get_all_compatibles(v, name + k, comp_dict)
return comp_dict
def get_aliases(root):
if 'children' in root:
if 'aliases' in root['children']:
for k, v in root['children']['aliases']['props'].items():
aliases[v].append(k)
# Treat alternate names as aliases
for k in reduced.keys():
if reduced[k].get('alt_name', None) is not None:
aliases[k].append(reduced[k]['alt_name'])
def get_compat(node_address):
compat = None
try:
if 'props' in reduced[node_address].keys():
compat = reduced[node_address]['props'].get('compatible')
if compat == None:
compat = find_parent_prop(node_address, 'compatible')
if isinstance(compat, list):
compat = compat[0]
except:
pass
return compat
def get_chosen(root):
if 'children' in root:
if 'chosen' in root['children']:
for k, v in root['children']['chosen']['props'].items():
chosen[k] = v
def get_phandles(root, name, handles):
if 'props' in root:
handle = root['props'].get('phandle')
enabled = root['props'].get('status')
if enabled == "disabled":
return
if handle is not None:
phandles[handle] = name
if name != '/':
name += '/'
if isinstance(root, dict):
if root['children']:
for k, v in root['children'].items():
get_phandles(v, name + k, handles)
def insert_defs(node_address, new_defs, new_aliases):
for key in new_defs.keys():
if key.startswith('CONFIG_DT_COMPAT_'):
node_address = 'Compatibles'
if node_address in defs:
if 'aliases' in defs[node_address]:
defs[node_address]['aliases'].update(new_aliases)
else:
defs[node_address]['aliases'] = new_aliases
defs[node_address].update(new_defs)
else:
new_defs['aliases'] = new_aliases
defs[node_address] = new_defs
def find_node_by_path(nodes, path):
d = nodes
for k in path[1:].split('/'):
d = d['children'][k]
return d
def get_reduced(nodes, path):
# compress nodes list to nodes w/ paths, add interrupt parent
if 'props' in nodes:
status = nodes['props'].get('status')
if status == "disabled":
return
if isinstance(nodes, dict):
reduced[path] = dict(nodes)
reduced[path].pop('children', None)
if path != '/':
path += '/'
if nodes['children']:
for k, v in nodes['children'].items():
get_reduced(v, path + k)
def get_node_label(node_compat, node_address):
def_label = convert_string_to_label(node_compat)
if '@' in node_address:
# See if we have number we can convert
try:
unit_addr = int(node_address.split('@')[-1], 16)
(nr_addr_cells, nr_size_cells) = get_addr_size_cells(node_address)
unit_addr += translate_addr(unit_addr, node_address,
nr_addr_cells, nr_size_cells)
unit_addr = "%x" % unit_addr
except:
unit_addr = node_address.split('@')[-1]
def_label += '_' + convert_string_to_label(unit_addr)
else:
def_label += '_' + \
convert_string_to_label(node_address.split('/')[-1])
return def_label
def get_parent_address(node_address):
parent_address = ''
for comp in node_address.split('/')[1:-1]:
parent_address += '/' + comp
return parent_address
def find_parent_prop(node_address, prop):
parent_address = get_parent_address(node_address)
if prop in reduced[parent_address]['props']:
parent_prop = reduced[parent_address]['props'].get(prop)
else:
raise Exception("Parent of node " + node_address +
" has no " + prop + " property")
return parent_prop
# Get the #{address,size}-cells for a given node
def get_addr_size_cells(node_address):
parent_addr = get_parent_address(node_address)
if parent_addr == '':
parent_addr = '/'
# The DT spec says that if #address-cells is missing default to 2
# if #size-cells is missing default to 1
nr_addr = reduced[parent_addr]['props'].get('#address-cells', 2)
nr_size = reduced[parent_addr]['props'].get('#size-cells', 1)
return (nr_addr, nr_size)
def translate_addr(addr, node_address, nr_addr_cells, nr_size_cells):
try:
ranges = deepcopy(find_parent_prop(node_address, 'ranges'))
if type(ranges) is not list: ranges = [ ]
except:
return 0
parent_address = get_parent_address(node_address)
(nr_p_addr_cells, nr_p_size_cells) = get_addr_size_cells(parent_address)
range_offset = 0
while ranges:
child_bus_addr = 0
parent_bus_addr = 0
range_len = 0
for x in range(nr_addr_cells):
val = ranges.pop(0) << (32 * (nr_addr_cells - x - 1))
child_bus_addr += val
for x in range(nr_p_addr_cells):
val = ranges.pop(0) << (32 * (nr_p_addr_cells - x - 1))
parent_bus_addr += val
for x in range(nr_size_cells):
range_len += ranges.pop(0) << (32 * (nr_size_cells - x - 1))
# if we are outside of the range we don't need to translate
if child_bus_addr <= addr <= (child_bus_addr + range_len):
range_offset = parent_bus_addr - child_bus_addr
break
parent_range_offset = translate_addr(addr + range_offset,
parent_address, nr_p_addr_cells, nr_p_size_cells)
range_offset += parent_range_offset
return range_offset