mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-02 09:12:44 +00:00
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>
254 lines
6.9 KiB
Python
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
|