From 21bdd686e9ae332547b59ee0764bc02b2220b554 Mon Sep 17 00:00:00 2001 From: Anton Burticica Date: Sat, 17 Jan 2026 00:55:17 +0200 Subject: [PATCH] cpu: armv8: Add Cortex-A5x/A7x CPU support and enhance driver functionality Extend the ARMv8 CPU driver with the following improvements: 1. Add compatible strings for modern ARM Cortex-A cores: - arm,cortex-a53 - arm,cortex-a55 - arm,cortex-a72 - arm,cortex-a73 - arm,cortex-a75 - arm,cortex-a76 2. Implement human-readable CPU name detection by reading the MIDR register and mapping known part numbers to descriptive names. 3. Add clock frequency reporting via the clk framework. The driver now probes for an optional clock and reports the CPU frequency in cpu_get_info() when available. 4. Implement get_vendor() callback returning "ARM" as the vendor. 5. Implement is_current() callback that compares the MPIDR register value against the device tree "reg" property to identify if this CPU device corresponds to the currently executing CPU. 6. Add private data structure to track per-CPU state including the optional clock reference. These changes enable proper CPU enumeration and information display on SoCs using Cortex-A5x and Cortex-A7x cores, which are common in modern Rockchip, NXP, and other ARM-based platforms. Change-Id: 6372f41d-a192-4117-9c1a-b5c75db2617a batch-01 Signed-off-by: Anton Burticica --- drivers/cpu/armv8_cpu.c | 127 ++++++++++++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 25 deletions(-) diff --git a/drivers/cpu/armv8_cpu.c b/drivers/cpu/armv8_cpu.c index 4eedfe5e2c5..94ba3074f9c 100644 --- a/drivers/cpu/armv8_cpu.c +++ b/drivers/cpu/armv8_cpu.c @@ -3,39 +3,106 @@ * Copyright 2024 9elements GmbH */ #include +#include #include #include #include #include #include +#include #include #include #include #include -static int armv8_cpu_get_desc(const struct udevice *dev, char *buf, int size) +/* MIDR part numbers */ +#define MIDR_PARTNUM_CORTEX_A53 0xD03 +#define MIDR_PARTNUM_CORTEX_A72 0xD08 +#define MIDR_PARTNUM_CORTEX_A55 0xD05 +#define MIDR_PARTNUM_CORTEX_A76 0xD0B + +struct armv8_cpu_priv { + struct clk clk; + bool has_clk; +}; + +static const char *armv8_cpu_get_name(void) { - int cpuid; + u32 partnum = (read_midr() & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT; + + switch (partnum) { + case MIDR_PARTNUM_CORTEX_A53: + return "Cortex-A53"; + case MIDR_PARTNUM_CORTEX_A72: + return "Cortex-A72"; + case MIDR_PARTNUM_CORTEX_A55: + return "Cortex-A55"; + case MIDR_PARTNUM_CORTEX_A76: + return "Cortex-A76"; + default: + return "Unknown"; + } +} - cpuid = (read_midr() & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT; +static int armv8_cpu_get_desc(const struct udevice *dev, char *buf, int size) +{ + u32 partnum = (read_midr() & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT; - snprintf(buf, size, "CPU MIDR %04x", cpuid); + snprintf(buf, size, "ARM %s (MIDR %04x)", armv8_cpu_get_name(), partnum); - return 0; + return 0; } -static int armv8_cpu_get_info(const struct udevice *dev, - struct cpu_info *info) +static int armv8_cpu_get_info(const struct udevice *dev, struct cpu_info *info) { - info->cpu_freq = 0; - info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU); + struct armv8_cpu_priv *priv = dev_get_priv(dev); - return 0; + info->cpu_freq = 0; + info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU); + + if (priv && priv->has_clk) + info->cpu_freq = clk_get_rate(&priv->clk); + + return 0; } static int armv8_cpu_get_count(const struct udevice *dev) { - return uclass_id_count(UCLASS_CPU); + return uclass_id_count(UCLASS_CPU); +} + +static int armv8_cpu_get_vendor(const struct udevice *dev, char *buf, int size) +{ + snprintf(buf, size, "ARM"); + return 0; +} + +static int armv8_cpu_is_current(struct udevice *dev) +{ + u64 mpidr = read_mpidr(); + u64 cpu_reg; + + /* Get reg property (MPIDR value for this CPU) */ + cpu_reg = dev_read_u64_default(dev, "reg", 0); + if (!cpu_reg) + cpu_reg = dev_read_u32_default(dev, "reg", 0); + + /* Compare affinity fields */ + return (mpidr & 0xFFFFFF) == (cpu_reg & 0xFFFFFF); +} + +static int armv8_cpu_probe(struct udevice *dev) +{ + struct armv8_cpu_priv *priv = dev_get_priv(dev); + int ret; + + priv->has_clk = false; + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (!ret) + priv->has_clk = true; + + return 0; } #ifdef CONFIG_ACPIGEN @@ -130,22 +197,32 @@ struct acpi_ops armv8_cpu_acpi_ops = { }; #endif -static const struct cpu_ops cpu_ops = { - .get_count = armv8_cpu_get_count, - .get_desc = armv8_cpu_get_desc, - .get_info = armv8_cpu_get_info, +static const struct cpu_ops armv8_cpu_ops = { + .get_count = armv8_cpu_get_count, + .get_desc = armv8_cpu_get_desc, + .get_info = armv8_cpu_get_info, + .get_vendor = armv8_cpu_get_vendor, + .is_current = armv8_cpu_is_current, }; -static const struct udevice_id cpu_ids[] = { - { .compatible = "arm,armv8" }, - {} +static const struct udevice_id armv8_cpu_ids[] = { + { .compatible = "arm,cortex-a53" }, + { .compatible = "arm,cortex-a55" }, + { .compatible = "arm,cortex-a72" }, + { .compatible = "arm,cortex-a73" }, + { .compatible = "arm,cortex-a75" }, + { .compatible = "arm,cortex-a76" }, + { .compatible = "arm,armv8" }, + {} }; -U_BOOT_DRIVER(arm_cpu) = { - .name = "arm-cpu", - .id = UCLASS_CPU, - .of_match = cpu_ids, - .ops = &cpu_ops, - .flags = DM_FLAG_PRE_RELOC, - ACPI_OPS_PTR(&armv8_cpu_acpi_ops) +U_BOOT_DRIVER(armv8_cpu) = { + .name = "armv8-cpu", + .id = UCLASS_CPU, + .of_match = armv8_cpu_ids, + .ops = &armv8_cpu_ops, + .probe = armv8_cpu_probe, + .priv_auto = sizeof(struct armv8_cpu_priv), + .flags = DM_FLAG_PRE_RELOC, + ACPI_OPS_PTR(&armv8_cpu_acpi_ops) };