mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-19 02:54:24 +00:00
feat(fdt): add the ability to supply idle state information
Some platforms require extra firmware to implement CPU_SUSPEND, or only have working CPU_SUSPEND in certain configurations. On these platforms, CPU idle states should only be listed in the devicetree when they are actually available. Add a function BL31 can use to dynamically supply this idle state information. Change-Id: I64fcc288303faba8abec4f59efd13a04220d54dc Signed-off-by: Samuel Holland <samuel@sholland.org>
This commit is contained in:
parent
79808f10c3
commit
2b2b565717
2 changed files with 120 additions and 1 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -394,6 +394,110 @@ int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
|
|||
return offs;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* fdt_add_cpu_idle_states() - add PSCI CPU idle states to cpu nodes in the DT
|
||||
* @dtb: pointer to the device tree blob in memory
|
||||
* @states: array of idle state descriptions, ending with empty element
|
||||
*
|
||||
* Add information about CPU idle states to the devicetree. This function
|
||||
* assumes that CPU idle states are not already present in the devicetree, and
|
||||
* that all CPU states are equally applicable to all CPUs.
|
||||
*
|
||||
* See arm/idle-states.yaml and arm/psci.yaml in the (Linux kernel) DT binding
|
||||
* documentation for more details.
|
||||
*
|
||||
* Return: 0 on success, a negative error value otherwise.
|
||||
******************************************************************************/
|
||||
int fdt_add_cpu_idle_states(void *dtb, const struct psci_cpu_idle_state *state)
|
||||
{
|
||||
int cpu_node, cpus_node, idle_states_node, ret;
|
||||
uint32_t count, phandle;
|
||||
|
||||
ret = fdt_find_max_phandle(dtb, &phandle);
|
||||
phandle++;
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
cpus_node = fdt_path_offset(dtb, "/cpus");
|
||||
if (cpus_node < 0) {
|
||||
return cpus_node;
|
||||
}
|
||||
|
||||
/* Create the idle-states node and its child nodes. */
|
||||
idle_states_node = fdt_add_subnode(dtb, cpus_node, "idle-states");
|
||||
if (idle_states_node < 0) {
|
||||
return idle_states_node;
|
||||
}
|
||||
|
||||
ret = fdt_setprop_string(dtb, idle_states_node, "entry-method", "psci");
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (count = 0U; state->name != NULL; count++, phandle++, state++) {
|
||||
int idle_state_node;
|
||||
|
||||
idle_state_node = fdt_add_subnode(dtb, idle_states_node,
|
||||
state->name);
|
||||
if (idle_state_node < 0) {
|
||||
return idle_state_node;
|
||||
}
|
||||
|
||||
fdt_setprop_string(dtb, idle_state_node, "compatible",
|
||||
"arm,idle-state");
|
||||
fdt_setprop_u32(dtb, idle_state_node, "arm,psci-suspend-param",
|
||||
state->power_state);
|
||||
if (state->local_timer_stop) {
|
||||
fdt_setprop_empty(dtb, idle_state_node,
|
||||
"local-timer-stop");
|
||||
}
|
||||
fdt_setprop_u32(dtb, idle_state_node, "entry-latency-us",
|
||||
state->entry_latency_us);
|
||||
fdt_setprop_u32(dtb, idle_state_node, "exit-latency-us",
|
||||
state->exit_latency_us);
|
||||
fdt_setprop_u32(dtb, idle_state_node, "min-residency-us",
|
||||
state->min_residency_us);
|
||||
if (state->wakeup_latency_us) {
|
||||
fdt_setprop_u32(dtb, idle_state_node,
|
||||
"wakeup-latency-us",
|
||||
state->wakeup_latency_us);
|
||||
}
|
||||
fdt_setprop_u32(dtb, idle_state_node, "phandle", phandle);
|
||||
}
|
||||
|
||||
if (count == 0U) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Link each cpu node to the idle state nodes. */
|
||||
fdt_for_each_subnode(cpu_node, dtb, cpus_node) {
|
||||
const char *device_type;
|
||||
fdt32_t *value;
|
||||
|
||||
/* Only process child nodes with device_type = "cpu". */
|
||||
device_type = fdt_getprop(dtb, cpu_node, "device_type", NULL);
|
||||
if (device_type == NULL || strcmp(device_type, "cpu") != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Allocate space for the list of phandles. */
|
||||
ret = fdt_setprop_placeholder(dtb, cpu_node, "cpu-idle-states",
|
||||
count * sizeof(phandle),
|
||||
(void **)&value);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Fill in the phandles of the idle state nodes. */
|
||||
for (uint32_t i = 0U; i < count; ++i) {
|
||||
value[i] = cpu_to_fdt32(phandle - count + i);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_adjust_gic_redist() - Adjust GICv3 redistributor size
|
||||
* @dtb: Pointer to the DT blob in memory
|
||||
|
|
|
@ -7,14 +7,29 @@
|
|||
#ifndef FDT_FIXUP_H
|
||||
#define FDT_FIXUP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define INVALID_BASE_ADDR ((uintptr_t)~0UL)
|
||||
|
||||
struct psci_cpu_idle_state {
|
||||
const char *name;
|
||||
uint32_t power_state;
|
||||
bool local_timer_stop;
|
||||
uint32_t entry_latency_us;
|
||||
uint32_t exit_latency_us;
|
||||
uint32_t min_residency_us;
|
||||
uint32_t wakeup_latency_us;
|
||||
};
|
||||
|
||||
int dt_add_psci_node(void *fdt);
|
||||
int dt_add_psci_cpu_enable_methods(void *fdt);
|
||||
int fdt_add_reserved_memory(void *dtb, const char *node_name,
|
||||
uintptr_t base, size_t size);
|
||||
int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
|
||||
unsigned int afflv1, unsigned int afflv2);
|
||||
int fdt_add_cpu_idle_states(void *dtb, const struct psci_cpu_idle_state *state);
|
||||
int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores, uintptr_t gicr_base,
|
||||
unsigned int gicr_frame_size);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue