Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
e0b3e6b3
Commit
e0b3e6b3
authored
May 21, 2020
by
Mark Dykes
Committed by
TrustedFirmware Code Review
May 21, 2020
Browse files
Merge "plat/fvp: Support for extracting UART serial node info from DT" into integration
parents
fc721f83
447870bf
Changes
6
Show whitespace changes
Inline
Side-by-side
common/fdt_wrappers.c
View file @
e0b3e6b3
...
...
@@ -341,3 +341,199 @@ int fdt_get_stdout_node_offset(const void *dtb)
return
fdt_path_offset
(
dtb
,
path
);
}
/*******************************************************************************
* Only devices which are direct children of root node use CPU address domain.
* All other devices use addresses that are local to the device node and cannot
* directly used by CPU. Device tree provides an address translation mechanism
* through "ranges" property which provides mappings from local address space to
* parent address space. Since a device could be a child of a child node to the
* root node, there can be more than one level of address translation needed to
* map the device local address space to CPU address space.
* fdtw_translate_address() API performs address translation of a local address
* to a global address with help of various helper functions.
******************************************************************************/
static
bool
fdtw_xlat_hit
(
const
uint32_t
*
value
,
int
child_addr_size
,
int
parent_addr_size
,
int
range_size
,
uint64_t
base_address
,
uint64_t
*
translated_addr
)
{
uint64_t
local_address
,
parent_address
,
addr_range
;
local_address
=
fdt_read_prop_cells
(
value
,
child_addr_size
);
parent_address
=
fdt_read_prop_cells
(
value
+
child_addr_size
,
parent_addr_size
);
addr_range
=
fdt_read_prop_cells
(
value
+
child_addr_size
+
parent_addr_size
,
range_size
);
VERBOSE
(
"DT: Address %llx mapped to %llx with range %llx
\n
"
,
local_address
,
parent_address
,
addr_range
);
/* Perform range check */
if
((
base_address
<
local_address
)
||
(
base_address
>=
local_address
+
addr_range
))
{
return
false
;
}
/* Found hit for the addr range that needs to be translated */
*
translated_addr
=
parent_address
+
(
base_address
-
local_address
);
VERBOSE
(
"DT: child address %llx mapped to %llx in parent bus
\n
"
,
local_address
,
parent_address
);
return
true
;
}
#define ILLEGAL_ADDR ULL(~0)
static
uint64_t
fdtw_search_all_xlat_entries
(
const
void
*
dtb
,
const
struct
fdt_property
*
ranges_prop
,
int
local_bus
,
uint64_t
base_address
)
{
uint64_t
translated_addr
;
const
uint32_t
*
next_entry
;
int
parent_bus_node
,
nxlat_entries
,
length
;
int
self_addr_cells
,
parent_addr_cells
,
self_size_cells
,
ncells_xlat
;
/*
* The number of cells in one translation entry in ranges is the sum of
* the following values:
* self#address-cells + parent#address-cells + self#size-cells
* Ex: the iofpga ranges property has one translation entry with 4 cells
* They represent iofpga#addr-cells + motherboard#addr-cells + iofpga#size-cells
* = 1 + 2 + 1
*/
parent_bus_node
=
fdt_parent_offset
(
dtb
,
local_bus
);
self_addr_cells
=
fdt_address_cells
(
dtb
,
local_bus
);
self_size_cells
=
fdt_size_cells
(
dtb
,
local_bus
);
parent_addr_cells
=
fdt_address_cells
(
dtb
,
parent_bus_node
);
/* Number of cells per translation entry i.e., mapping */
ncells_xlat
=
self_addr_cells
+
parent_addr_cells
+
self_size_cells
;
assert
(
ncells_xlat
>
0
);
/*
* Find the number of translations(mappings) specified in the current
* `ranges` property. Note that length represents number of bytes and
* is stored in big endian mode.
*/
length
=
fdt32_to_cpu
(
ranges_prop
->
len
);
nxlat_entries
=
(
length
/
sizeof
(
uint32_t
))
/
ncells_xlat
;
assert
(
nxlat_entries
>
0
);
next_entry
=
(
const
uint32_t
*
)
ranges_prop
->
data
;
/* Iterate over the entries in the "ranges" */
for
(
int
i
=
0
;
i
<
nxlat_entries
;
i
++
)
{
if
(
fdtw_xlat_hit
(
next_entry
,
self_addr_cells
,
parent_addr_cells
,
self_size_cells
,
base_address
,
&
translated_addr
)){
return
translated_addr
;
}
next_entry
=
next_entry
+
ncells_xlat
;
}
INFO
(
"DT: No translation found for address %llx in node %s
\n
"
,
base_address
,
fdt_get_name
(
dtb
,
local_bus
,
NULL
));
return
ILLEGAL_ADDR
;
}
/*******************************************************************************
* address mapping needs to be done recursively starting from current node to
* root node through all intermediate parent nodes.
* Sample device tree is shown here:
smb@0,0 {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0 0x08000000 0x04000000>,
<1 0 0 0x14000000 0x04000000>,
<2 0 0 0x18000000 0x04000000>,
<3 0 0 0x1c000000 0x04000000>,
<4 0 0 0x0c000000 0x04000000>,
<5 0 0 0x10000000 0x04000000>;
motherboard {
arm,v2m-memory-map = "rs1";
compatible = "arm,vexpress,v2m-p1", "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
ranges;
iofpga@3,00000000 {
compatible = "arm,amba-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 3 0 0x200000>;
v2m_serial1: uart@a0000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x0a0000 0x1000>;
interrupts = <0 6 4>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
};
};
* As seen above, there are 3 levels of address translations needed. An empty
* `ranges` property denotes identity mapping (as seen in `motherboard` node).
* Each ranges property can map a set of child addresses to parent bus. Hence
* there can be more than 1 (translation) entry in the ranges property as seen
* in the `smb` node which has 6 translation entries.
******************************************************************************/
/* Recursive implementation */
uint64_t
fdtw_translate_address
(
const
void
*
dtb
,
int
node
,
uint64_t
base_address
)
{
int
length
,
local_bus_node
;
const
char
*
node_name
;
uint64_t
global_address
;
local_bus_node
=
fdt_parent_offset
(
dtb
,
node
);
node_name
=
fdt_get_name
(
dtb
,
local_bus_node
,
NULL
);
/*
* In the example given above, starting from the leaf node:
* uart@a000 represents the current node
* iofpga@3,00000000 represents the local bus
* motherboard represents the parent bus
*/
/* Read the ranges property */
const
struct
fdt_property
*
property
=
fdt_get_property
(
dtb
,
local_bus_node
,
"ranges"
,
&
length
);
if
(
property
==
NULL
)
{
if
(
local_bus_node
==
0
)
{
/*
* root node doesn't have range property as addresses
* are in CPU address space.
*/
return
base_address
;
}
INFO
(
"DT: Couldn't find ranges property in node %s
\n
"
,
node_name
);
return
ILLEGAL_ADDR
;
}
else
if
(
length
==
0
)
{
/* empty ranges indicates identity map to parent bus */
return
fdtw_translate_address
(
dtb
,
local_bus_node
,
base_address
);
}
VERBOSE
(
"DT: Translation lookup in node %s at offset %d
\n
"
,
node_name
,
local_bus_node
);
global_address
=
fdtw_search_all_xlat_entries
(
dtb
,
property
,
local_bus_node
,
base_address
);
if
(
global_address
==
ILLEGAL_ADDR
)
{
return
ILLEGAL_ADDR
;
}
/* Translate the local device address recursively */
return
fdtw_translate_address
(
dtb
,
local_bus_node
,
global_address
);
}
include/common/fdt_wrappers.h
View file @
e0b3e6b3
...
...
@@ -34,4 +34,7 @@ int fdt_get_reg_props_by_name(const void *dtb, int node, const char *name,
uintptr_t
*
base
,
size_t
*
size
);
int
fdt_get_stdout_node_offset
(
const
void
*
dtb
);
uint64_t
fdtw_translate_address
(
const
void
*
dtb
,
int
bus_node
,
uint64_t
base_address
);
#endif
/* FDT_WRAPPERS_H */
plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
View file @
e0b3e6b3
...
...
@@ -13,6 +13,9 @@
struct
gicv3_config_t
gicv3_config
;
struct
hw_topology_t
soc_topology
;
struct
uart_serial_config_t
uart_serial_config
;
#define ILLEGAL_ADDR ULL(~0)
int
fconf_populate_gicv3_config
(
uintptr_t
config
)
{
...
...
@@ -147,7 +150,8 @@ int fconf_populate_topology(uintptr_t config)
return
-
1
;
}
INFO
(
"CLUSTER ID: %d cpu-count: %d
\n
"
,
cluster_count
,
cpus_per_cluster
[
cluster_count
]);
VERBOSE
(
"CLUSTER ID: %d cpu-count: %d
\n
"
,
cluster_count
,
cpus_per_cluster
[
cluster_count
]);
/* Find the maximum number of cpus in any cluster */
max_cpu_per_cluster
=
MAX
(
max_cpu_per_cluster
,
cpus_per_cluster
[
cluster_count
]);
...
...
@@ -170,5 +174,95 @@ int fconf_populate_topology(uintptr_t config)
return
0
;
}
int
fconf_populate_uart_config
(
uintptr_t
config
)
{
int
uart_node
,
node
,
err
;
uintptr_t
addr
;
const
char
*
path
;
uint32_t
phandle
;
uint64_t
translated_addr
;
/* Necessary to work with libfdt APIs */
const
void
*
hw_config_dtb
=
(
const
void
*
)
config
;
/*
* uart child node is indirectly referenced through its path which is
* specified in the `serial1` property of the "aliases" node.
* Note that TF-A boot console is mapped to serial0 while runtime
* console is mapped to serial1.
*/
path
=
fdt_get_alias
(
hw_config_dtb
,
"serial1"
);
if
(
path
==
NULL
)
{
ERROR
(
"FCONF: Could not read serial1 property in aliases node
\n
"
);
return
-
1
;
}
/* Find the offset of the uart serial node */
uart_node
=
fdt_path_offset
(
hw_config_dtb
,
path
);
if
(
uart_node
<
0
)
{
ERROR
(
"FCONF: Failed to locate uart serial node using its path
\n
"
);
return
-
1
;
}
/* uart serial node has its offset and size of address in reg property */
err
=
fdt_get_reg_props_by_index
(
hw_config_dtb
,
uart_node
,
0
,
&
addr
,
NULL
);
if
(
err
<
0
)
{
ERROR
(
"FCONF: Failed to read reg property of '%s' node
\n
"
,
"uart serial"
);
return
err
;
}
VERBOSE
(
"FCONF: UART node address: %lx
\n
"
,
addr
);
/*
* Perform address translation of local device address to CPU address
* domain.
*/
translated_addr
=
fdtw_translate_address
(
hw_config_dtb
,
uart_node
,
(
uint64_t
)
addr
);
if
(
translated_addr
==
ILLEGAL_ADDR
)
{
ERROR
(
"FCONF: failed to translate UART node base address"
);
return
-
1
;
}
uart_serial_config
.
uart_base
=
translated_addr
;
VERBOSE
(
"FCONF: UART serial device base address: %llx
\n
"
,
uart_serial_config
.
uart_base
);
/*
* The phandle of the DT node which captures the clock info of uart
* serial node is specified in the "clocks" property.
*/
err
=
fdt_read_uint32
(
hw_config_dtb
,
uart_node
,
"clocks"
,
&
phandle
);
if
(
err
<
0
)
{
ERROR
(
"FCONF: Could not read clocks property in uart serial node
\n
"
);
return
err
;
}
node
=
fdt_node_offset_by_phandle
(
hw_config_dtb
,
phandle
);
if
(
node
<
0
)
{
ERROR
(
"FCONF: Failed to locate clk node using its path
\n
"
);
return
node
;
}
/*
* Retrieve clock frequency. We assume clock provider generates a fixed
* clock.
*/
err
=
fdt_read_uint32
(
hw_config_dtb
,
node
,
"clock-frequency"
,
&
uart_serial_config
.
uart_clk
);
if
(
err
<
0
)
{
ERROR
(
"FCONF: Could not read clock-frequency property in clk node
\n
"
);
return
err
;
}
VERBOSE
(
"FCONF: UART serial device clk frequency: %x
\n
"
,
uart_serial_config
.
uart_clk
);
return
0
;
}
FCONF_REGISTER_POPULATOR
(
HW_CONFIG
,
gicv3_config
,
fconf_populate_gicv3_config
);
FCONF_REGISTER_POPULATOR
(
HW_CONFIG
,
topology
,
fconf_populate_topology
);
FCONF_REGISTER_POPULATOR
(
HW_CONFIG
,
uart_config
,
fconf_populate_uart_config
);
plat/arm/board/fvp/include/fconf_hw_config_getter.h
View file @
e0b3e6b3
...
...
@@ -14,6 +14,8 @@
#define hw_config__topology_getter(prop) soc_topology.prop
#define hw_config__uart_serial_config_getter(prop) uart_serial_config.prop
struct
gicv3_config_t
{
uint64_t
gicd_base
;
uint64_t
gicr_base
;
...
...
@@ -26,10 +28,17 @@ struct hw_topology_t {
uint32_t
plat_max_pwr_level
;
};
struct
uart_serial_config_t
{
uint64_t
uart_base
;
uint32_t
uart_clk
;
};
int
fconf_populate_gicv3_config
(
uintptr_t
config
);
int
fconf_populate_topology
(
uintptr_t
config
);
int
fconf_populate_uart_config
(
uintptr_t
config
);
extern
struct
gicv3_config_t
gicv3_config
;
extern
struct
hw_topology_t
soc_topology
;
extern
struct
uart_serial_config_t
uart_serial_config
;
#endif
/* FCONF_HW_CONFIG_GETTER_H */
plat/arm/board/fvp/jmptbl.i
View file @
e0b3e6b3
...
...
@@ -16,6 +16,7 @@
rom
rom_lib_init
fdt
fdt_getprop
fdt
fdt_get_property
fdt
fdt_getprop_namelen
fdt
fdt_setprop_inplace
fdt
fdt_check_header
...
...
@@ -31,6 +32,9 @@ fdt fdt_size_cells
fdt
fdt_parent_offset
fdt
fdt_stringlist_search
fdt
fdt_get_alias_namelen
fdt
fdt_get_name
fdt
fdt_get_alias
fdt
fdt_node_offset_by_phandle
mbedtls
mbedtls_asn1_get_alg
mbedtls
mbedtls_asn1_get_alg_null
mbedtls
mbedtls_asn1_get_bitstring_null
...
...
plat/arm/board/juno/jmptbl.i
View file @
e0b3e6b3
...
...
@@ -16,6 +16,7 @@
rom
rom_lib_init
fdt
fdt_getprop
fdt
fdt_get_property
fdt
fdt_getprop_namelen
fdt
fdt_setprop_inplace
fdt
fdt_check_header
...
...
@@ -28,6 +29,9 @@ fdt fdt_stringlist_search
fdt
fdt_get_alias_namelen
fdt
fdt_path_offset
fdt
fdt_path_offset_namelen
fdt
fdt_get_name
fdt
fdt_get_alias
fdt
fdt_node_offset_by_phandle
mbedtls
mbedtls_asn1_get_alg
mbedtls
mbedtls_asn1_get_alg_null
mbedtls
mbedtls_asn1_get_bitstring_null
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment