Add support to export a /cpus node to the device tree.
This patch creates and populates the /cpus node in a device tree based on the existing topology. It uses the minimum required nodes and properties to satisfy the binding as specified in https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/cpus.txt Signed-off-by: Javier Almansa Sobrino <javier.almansasobrino@arm.com> Change-Id: I03bf4e9a6427da0a3b8ed013f93d7bc43b5c4df0
This commit is contained in:
parent
d35403feab
commit
780dd2b310
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -14,15 +14,20 @@
|
||||||
* that.
|
* that.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include <arch.h>
|
||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
|
#include <common/fdt_fixup.h>
|
||||||
|
#include <common/fdt_wrappers.h>
|
||||||
#include <drivers/console.h>
|
#include <drivers/console.h>
|
||||||
#include <lib/psci/psci.h>
|
#include <lib/psci/psci.h>
|
||||||
|
#include <plat/common/platform.h>
|
||||||
|
|
||||||
#include <common/fdt_fixup.h>
|
|
||||||
|
|
||||||
static int append_psci_compatible(void *fdt, int offs, const char *str)
|
static int append_psci_compatible(void *fdt, int offs, const char *str)
|
||||||
{
|
{
|
||||||
|
@ -210,3 +215,165 @@ int fdt_add_reserved_memory(void *dtb, const char *node_name,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* fdt_add_cpu() Add a new CPU node to the DT
|
||||||
|
* @dtb: Pointer to the device tree blob in memory
|
||||||
|
* @parent: Offset of the parent node
|
||||||
|
* @mpidr: MPIDR for the current CPU
|
||||||
|
*
|
||||||
|
* Create and add a new cpu node to a DTB.
|
||||||
|
*
|
||||||
|
* Return the offset of the new node or a negative value in case of error
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
static int fdt_add_cpu(void *dtb, int parent, u_register_t mpidr)
|
||||||
|
{
|
||||||
|
int cpu_offs;
|
||||||
|
int err;
|
||||||
|
char snode_name[15];
|
||||||
|
uint64_t reg_prop;
|
||||||
|
|
||||||
|
reg_prop = mpidr & MPID_MASK & ~MPIDR_MT_MASK;
|
||||||
|
|
||||||
|
snprintf(snode_name, sizeof(snode_name), "cpu@%x",
|
||||||
|
(unsigned int)reg_prop);
|
||||||
|
|
||||||
|
cpu_offs = fdt_add_subnode(dtb, parent, snode_name);
|
||||||
|
if (cpu_offs < 0) {
|
||||||
|
ERROR ("FDT: add subnode \"%s\" failed: %i\n",
|
||||||
|
snode_name, cpu_offs);
|
||||||
|
return cpu_offs;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_setprop_string(dtb, cpu_offs, "compatible", "arm,armv8");
|
||||||
|
if (err < 0) {
|
||||||
|
ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
|
||||||
|
"compatible", cpu_offs);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_setprop_u64(dtb, cpu_offs, "reg", reg_prop);
|
||||||
|
if (err < 0) {
|
||||||
|
ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
|
||||||
|
"reg", cpu_offs);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_setprop_string(dtb, cpu_offs, "device_type", "cpu");
|
||||||
|
if (err < 0) {
|
||||||
|
ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
|
||||||
|
"device_type", cpu_offs);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_setprop_string(dtb, cpu_offs, "enable-method", "psci");
|
||||||
|
if (err < 0) {
|
||||||
|
ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
|
||||||
|
"enable-method", cpu_offs);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu_offs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* fdt_add_cpus_node() - Add the cpus node to the DTB
|
||||||
|
* @dtb: pointer to the device tree blob in memory
|
||||||
|
* @afflv0: Maximum number of threads per core (affinity level 0).
|
||||||
|
* @afflv1: Maximum number of CPUs per cluster (affinity level 1).
|
||||||
|
* @afflv2: Maximum number of clusters (affinity level 2).
|
||||||
|
*
|
||||||
|
* Iterate over all the possible MPIDs given the maximum affinity levels and
|
||||||
|
* add a cpus node to the DTB with all the valid CPUs on the system.
|
||||||
|
* If there is already a /cpus node, exit gracefully
|
||||||
|
*
|
||||||
|
* A system with two CPUs would generate a node equivalent or similar to:
|
||||||
|
*
|
||||||
|
* cpus {
|
||||||
|
* #address-cells = <2>;
|
||||||
|
* #size-cells = <0>;
|
||||||
|
*
|
||||||
|
* cpu0: cpu@0 {
|
||||||
|
* compatible = "arm,armv8";
|
||||||
|
* reg = <0x0 0x0>;
|
||||||
|
* device_type = "cpu";
|
||||||
|
* enable-method = "psci";
|
||||||
|
* };
|
||||||
|
* cpu1: cpu@10000 {
|
||||||
|
* compatible = "arm,armv8";
|
||||||
|
* reg = <0x0 0x100>;
|
||||||
|
* device_type = "cpu";
|
||||||
|
* enable-method = "psci";
|
||||||
|
* };
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* Full documentation about the CPU bindings can be found at:
|
||||||
|
* https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/cpus.txt
|
||||||
|
*
|
||||||
|
* Return the offset of the node or a negative value on error.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
|
||||||
|
unsigned int afflv1, unsigned int afflv2)
|
||||||
|
{
|
||||||
|
int offs;
|
||||||
|
int err;
|
||||||
|
unsigned int i, j, k;
|
||||||
|
u_register_t mpidr;
|
||||||
|
int cpuid;
|
||||||
|
|
||||||
|
if (fdt_path_offset(dtb, "/cpus") >= 0) {
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
offs = fdt_add_subnode(dtb, 0, "cpus");
|
||||||
|
if (offs < 0) {
|
||||||
|
ERROR ("FDT: add subnode \"cpus\" node to parent node failed");
|
||||||
|
return offs;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_setprop_u32(dtb, offs, "#address-cells", 2);
|
||||||
|
if (err < 0) {
|
||||||
|
ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
|
||||||
|
"#address-cells", offs);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_setprop_u32(dtb, offs, "#size-cells", 0);
|
||||||
|
if (err < 0) {
|
||||||
|
ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
|
||||||
|
"#size-cells", offs);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Populate the node with the CPUs.
|
||||||
|
* As libfdt prepends subnodes within a node, reverse the index count
|
||||||
|
* so the CPU nodes would be better ordered.
|
||||||
|
*/
|
||||||
|
for (i = afflv2; i > 0U; i--) {
|
||||||
|
for (j = afflv1; j > 0U; j--) {
|
||||||
|
for (k = afflv0; k > 0U; k--) {
|
||||||
|
mpidr = ((i - 1) << MPIDR_AFF2_SHIFT) |
|
||||||
|
((j - 1) << MPIDR_AFF1_SHIFT) |
|
||||||
|
((k - 1) << MPIDR_AFF0_SHIFT) |
|
||||||
|
(read_mpidr_el1() & MPIDR_MT_MASK);
|
||||||
|
|
||||||
|
cpuid = plat_core_pos_by_mpidr(mpidr);
|
||||||
|
if (cpuid >= 0) {
|
||||||
|
/* Valid MPID found */
|
||||||
|
err = fdt_add_cpu(dtb, offs, mpidr);
|
||||||
|
if (err < 0) {
|
||||||
|
ERROR ("FDT: %s 0x%08x\n",
|
||||||
|
"error adding CPU",
|
||||||
|
(uint32_t)mpidr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return offs;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -11,5 +11,7 @@ int dt_add_psci_node(void *fdt);
|
||||||
int dt_add_psci_cpu_enable_methods(void *fdt);
|
int dt_add_psci_cpu_enable_methods(void *fdt);
|
||||||
int fdt_add_reserved_memory(void *dtb, const char *node_name,
|
int fdt_add_reserved_memory(void *dtb, const char *node_name,
|
||||||
uintptr_t base, size_t size);
|
uintptr_t base, size_t size);
|
||||||
|
int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
|
||||||
|
unsigned int afflv1, unsigned int afflv2);
|
||||||
|
|
||||||
#endif /* FDT_FIXUP_H */
|
#endif /* FDT_FIXUP_H */
|
||||||
|
|
Loading…
Reference in New Issue