[PATCH 2/3] mach-k3: refactor A53 speed grade clock-rate fixup
Aniket Limaye
a-limaye at ti.com
Sat Nov 1 05:00:22 CET 2025
On 30/10/25 18:33, Anshul Dalal wrote:
> The K3 ARM64 rproc driver uses the "assigned-clock-rates" value in the
> respective "/a53 at 0" node to properly configure the clocks for the A53
> core.
>
> Although the clock value in the DT node might need to be fixed based on
> SoC's speed grade at runtime. Certain SoCs such as AM62p and AM62x
> already had this implemented, this patch moves the common code to
> common.c to avoid duplication and simplify speed grade handling.
>
> The logic to detect the correct entry in the "assigned-clock-rates"
> property has also changed. Where we earlier relied on per SoC specific
> device and clock IDs for the A53 core, we now use the "clock-names"
> property which is device agnostic.
>
> Signed-off-by: Anshul Dalal <anshuld at ti.com>
> ---
> arch/arm/mach-k3/am62px/am62p5_init.c | 87 ++++++--------------
> arch/arm/mach-k3/am62x/am625_init.c | 84 ++++++-------------
> arch/arm/mach-k3/common.c | 108 +++++++++++++++++++++++++
> arch/arm/mach-k3/common.h | 11 ++-
> arch/arm/mach-k3/include/mach/am62_hardware.h | 24 ------
> arch/arm/mach-k3/include/mach/am62p_hardware.h | 17 ----
> 6 files changed, 165 insertions(+), 166 deletions(-)
>
> diff --git a/arch/arm/mach-k3/am62px/am62p5_init.c b/arch/arm/mach-k3/am62px/am62p5_init.c
> index aebd5200b0db9959805d04408b34d283e21b6e2c..eeb054d575ad94040370817f648c5319850fe7f8 100644
> --- a/arch/arm/mach-k3/am62px/am62p5_init.c
> +++ b/arch/arm/mach-k3/am62px/am62p5_init.c
> @@ -11,14 +11,10 @@
> #include <dm.h>
> #include <dm/uclass-internal.h>
> #include <dm/pinctrl.h>
> -#include <dm/ofnode.h>
>
> #include "../sysfw-loader.h"
> #include "../common.h"
>
> -/* TISCI DEV ID for A53 Clock */
> -#define AM62PX_DEV_A53SS0_CORE_0_DEV_ID 135
> -
> #define CTRLMMR_MCU_RST_CTRL 0x04518170
> #define RST_CTRL_ESM_ERROR_RST_EN_Z_MASK 0xFFFDFFFF
>
> @@ -26,6 +22,29 @@ struct fwl_data cbass_main_fwls[] = {
> { "FSS_DAT_REG3", 7, 8 },
> };
>
> +const struct k3_speed_grade_map am62p_map[] = {
> + {'O', 1000000000},
> + {'S', 1250000000},
> + {'T', 1250000000},
> + {'U', 1250000000},
> + {'V', 1250000000},
> + {/* List Terminator */ },
> +};
> +
> +char k3_get_speed_grade(void)
> +{
> + u32 efuse_val = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID);
> + u32 efuse_speed = (efuse_val & JTAG_DEV_SPEED_MASK) >>
> + JTAG_DEV_SPEED_SHIFT;
> +
> + return ('A' - 1) + efuse_speed;
> +}
> +
> +const struct k3_speed_grade_map *k3_get_speed_grade_map(void)
> +{
> + return am62p_map;
> +}
> +
> /*
> * This uninitialized global variable would normal end up in the .bss section,
> * but the .bss is cleared between writing and reading this variable, so move
> @@ -74,62 +93,6 @@ static void ctrl_mmr_unlock(void)
> mmr_unlock(PADCFG_MMR1_BASE, 1);
> }
>
> -#if CONFIG_IS_ENABLED(OF_CONTROL)
> -static int get_a53_cpu_clock_index(ofnode node)
> -{
> - int count, i;
> - struct ofnode_phandle_args *args;
> - ofnode clknode;
> -
> - clknode = ofnode_path("/bus at f0000/system-controller at 44043000/clock-controller");
> - if (!ofnode_valid(clknode))
> - return -1;
> -
> - count = ofnode_count_phandle_with_args(node, "assigned-clocks", "#clock-cells", 0);
> -
> - for (i = 0; i < count; i++) {
> - if (!ofnode_parse_phandle_with_args(node, "assigned-clocks",
> - "#clock-cells", 0, i, args)) {
> - if (ofnode_equal(clknode, args->node) &&
> - args->args[0] == AM62PX_DEV_A53SS0_CORE_0_DEV_ID)
> - return i;
> - }
> - }
> -
> - return -1;
> -}
> -
> -static void fixup_a53_cpu_freq_by_speed_grade(void)
> -{
> - int index, size;
> - u32 *rates;
> - ofnode node;
> -
> - node = ofnode_path("/a53 at 0");
> - if (!ofnode_valid(node))
> - return;
> -
> - rates = fdt_getprop_w(ofnode_to_fdt(node), ofnode_to_offset(node),
> - "assigned-clock-rates", &size);
> -
> - index = get_a53_cpu_clock_index(node);
> -
> - if (!rates || index < 0 || index >= (size / sizeof(u32))) {
> - printf("Wrong A53 assigned-clocks configuration\n");
> - return;
> - }
> -
> - rates[index] = cpu_to_fdt32(k3_get_a53_max_frequency());
> -
> - printf("Changed A53 CPU frequency to %dHz (%c grade) in DT\n",
> - k3_get_a53_max_frequency(), k3_get_speed_grade());
> -}
> -#else
> -static void fixup_a53_cpu_freq_by_speed_grade(void)
> -{
> -}
> -#endif
The original function here was implemented behind #if
CONFIG_IS_ENABLED(OF_CONTROL). (With an empty function in the else case)
While the new common implementation does not have such the config check.
Is this intentional?
Regards,
Aniket
> -
> static __maybe_unused void enable_mcu_esm_reset(void)
> {
> /* Set CTRLMMR_MCU_RST_CTRL:MCU_ESM_ERROR_RST_EN_Z to '0' (low active) */
> @@ -251,9 +214,7 @@ void board_init_f(ulong dummy)
> spl_enable_cache();
>
> setup_qos();
> - debug("am62px_init: %s done\n", __func__);
> -
> - fixup_a53_cpu_freq_by_speed_grade();
> + k3_fix_rproc_clock("/a53 at 0");
> }
>
> u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device)
> diff --git a/arch/arm/mach-k3/am62x/am625_init.c b/arch/arm/mach-k3/am62x/am625_init.c
> index 14f93ac998f7d11997b753550c0ea38926e35e64..9f7f2d8c084654b1b55a23a6fa889161cd1c8cb2 100644
> --- a/arch/arm/mach-k3/am62x/am625_init.c
> +++ b/arch/arm/mach-k3/am62x/am625_init.c
> @@ -12,7 +12,6 @@
> #include <dm.h>
> #include <dm/uclass-internal.h>
> #include <dm/pinctrl.h>
> -#include <dm/ofnode.h>
>
> #include "../sysfw-loader.h"
> #include "../common.h"
> @@ -26,15 +25,34 @@
> #define K3RTC_KICK0_UNLOCK_VALUE 0x83e70b13
> #define K3RTC_KICK1_UNLOCK_VALUE 0x95a4f1e0
>
> -/* TISCI DEV ID for A53 Clock */
> -#define AM62X_DEV_A53SS0_CORE_0_DEV_ID 135
> -
> struct fwl_data rom_fwls[] = {
> { "SOC_DEVGRP_MAIN", 641, 1 },
> { "SOC_DEVGRP_MAIN", 642, 1 },
> { "SOC_DEVGRP_MAIN", 642, 2 },
> };
>
> +const struct k3_speed_grade_map am62x_map[] = {
> + {'G', 300000000},
> + {'K', 800000000},
> + {'S', 1000000000},
> + {'T', 1250000000},
> + {/* List Terminator */ },
> +};
> +
> +char k3_get_speed_grade(void)
> +{
> + u32 efuse_val = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID);
> + u32 efuse_speed = (efuse_val & JTAG_DEV_SPEED_MASK) >>
> + JTAG_DEV_SPEED_SHIFT;
> +
> + return ('A' - 1) + efuse_speed;
> +}
> +
> +const struct k3_speed_grade_map *k3_get_speed_grade_map(void)
> +{
> + return am62x_map;
> +}
> +
> /*
> * This uninitialized global variable would normal end up in the .bss section,
> * but the .bss is cleared between writing and reading this variable, so move
> @@ -123,62 +141,6 @@ static __maybe_unused void rtc_erratumi2327_init(void)
> writel(K3RTC_KICK1_UNLOCK_VALUE, REG_K3RTC_KICK1);
> }
>
> -#if CONFIG_IS_ENABLED(OF_CONTROL)
> -static int get_a53_cpu_clock_index(ofnode node)
> -{
> - int count, i;
> - struct ofnode_phandle_args *args;
> - ofnode clknode;
> -
> - clknode = ofnode_path("/bus at f0000/system-controller at 44043000/clock-controller");
> - if (!ofnode_valid(clknode))
> - return -1;
> -
> - count = ofnode_count_phandle_with_args(node, "assigned-clocks", "#clock-cells", 0);
> -
> - for (i = 0; i < count; i++) {
> - if (!ofnode_parse_phandle_with_args(node, "assigned-clocks",
> - "#clock-cells", 0, i, args)) {
> - if (ofnode_equal(clknode, args->node) &&
> - args->args[0] == AM62X_DEV_A53SS0_CORE_0_DEV_ID)
> - return i;
> - }
> - }
> -
> - return -1;
> -}
> -
> -static void fixup_a53_cpu_freq_by_speed_grade(void)
> -{
> - int index, size;
> - u32 *rates;
> - ofnode node;
> -
> - node = ofnode_path("/a53 at 0");
> - if (!ofnode_valid(node))
> - return;
> -
> - rates = fdt_getprop_w(ofnode_to_fdt(node), ofnode_to_offset(node),
> - "assigned-clock-rates", &size);
> -
> - index = get_a53_cpu_clock_index(node);
> -
> - if (!rates || index < 0 || index >= (size / sizeof(u32))) {
> - printf("Wrong A53 assigned-clocks configuration\n");
> - return;
> - }
> -
> - rates[index] = cpu_to_fdt32(k3_get_a53_max_frequency());
> -
> - printf("Changed A53 CPU frequency to %dHz (%c grade) in DT\n",
> - k3_get_a53_max_frequency(), k3_get_speed_grade());
> -}
> -#else
> -static void fixup_a53_cpu_freq_by_speed_grade(void)
> -{
> -}
> -#endif
> -
> void board_init_f(ulong dummy)
> {
> struct udevice *dev;
> @@ -294,7 +256,7 @@ void board_init_f(ulong dummy)
> }
> spl_enable_cache();
>
> - fixup_a53_cpu_freq_by_speed_grade();
> + k3_fix_rproc_clock("/a53 at 0");
> }
>
> u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device)
> diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
> index 7c06764af8256b7fd27f8e7f208a597b1b91652b..3a97b70259e965c6ab400d5fbebd8b46f0a55173 100644
> --- a/arch/arm/mach-k3/common.c
> +++ b/arch/arm/mach-k3/common.c
> @@ -304,6 +304,114 @@ void enable_caches(void)
> }
> #endif
>
> +__weak char k3_get_speed_grade(void)
> +{
> + return K3_SPEED_GRADE_UNKNOWN;
> +}
> +
> +__weak const struct k3_speed_grade_map *k3_get_speed_grade_map(void)
> +{
> + return NULL;
> +}
> +
> +static int k3_fdt_set_assigned_clk_rate(const char *path, const char *clk_name,
> + unsigned int new_clk_rate)
> +{
> + int size, clk_name_index, phandle_count;
> + struct ofnode_phandle_args phandle_args;
> + unsigned int dev_id, clock_id, i;
> + ofnode node = ofnode_path(path);
> + u32 *clk_rates;
> + int ret;
> +
> + debug("%s: Setting clock '%s' frequency of '%s' to %u\n", __func__,
> + path, clk_name, new_clk_rate);
> +
> + clk_name_index =
> + ofnode_stringlist_search(node, "clock-names", clk_name);
> + if (clk_name_index < 0)
> + return clk_name_index;
> +
> + ret = ofnode_parse_phandle_with_args(node, "clocks", "#clock-cells", 0,
> + clk_name_index, &phandle_args);
> +
> + if (ret || phandle_args.args_count != 2)
> + return -EINVAL;
> +
> + dev_id = phandle_args.args[0];
> + clock_id = phandle_args.args[1];
> +
> + debug("%s: Found dev_id: %u, clock_id: %u\n", __func__, dev_id,
> + clock_id);
> +
> + phandle_count = ofnode_count_phandle_with_args(node, "assigned-clocks",
> + "#clock-cells", 0);
> +
> + for (i = 0; i < phandle_count; i++) {
> + ret = ofnode_parse_phandle_with_args(node, "assigned-clocks",
> + "#clock-cells", 0, i,
> + &phandle_args);
> +
> + if (ret || phandle_args.args_count != 2)
> + continue;
> +
> + if (phandle_args.args[0] == dev_id &&
> + phandle_args.args[1] == clock_id) {
> + clk_rates = (u32 *)ofnode_read_prop(node,
> + "assigned-clock-rates", &size);
> +
> + if (i >= (size / sizeof(u32)))
> + return -EOVERFLOW;
> +
> + clk_rates[i] = cpu_to_fdt32(new_clk_rate);
> + return 0;
> + }
> + }
> +
> + return -EINVAL;
> +}
> +
> +static u32 k3_get_a_core_frequency(char speed_grade)
> +{
> + const struct k3_speed_grade_map *map = k3_get_speed_grade_map();
> + unsigned int i;
> +
> + if (!map)
> + return 0;
> +
> + for (i = 0; map[i].speed_grade != 0; i++) {
> + if (map[i].speed_grade == speed_grade)
> + return map[i].a_core_frequency;
> + }
> +
> + return 0;
> +}
> +
> +void k3_fix_rproc_clock(const char *path)
> +{
> + u32 a_core_frequency;
> + char speed_grade;
> + int ret;
> +
> + if (IS_ENABLED(CONFIG_ARM64))
> + return;
> +
> + speed_grade = k3_get_speed_grade();
> + a_core_frequency = k3_get_a_core_frequency(speed_grade);
> +
> + if (!a_core_frequency) {
> + printf("%s: Failed to get speed grade frequency\n", __func__);
> + return;
> + }
> +
> + ret = k3_fdt_set_assigned_clk_rate(path, "core", a_core_frequency);
> + if (ret)
> + printf("Failed to set clock rates for '%s': %d\n", path, ret);
> + else
> + printf("Set clock rates for '%s', CPU: %dMHz at Speed Grade '%c'\n",
> + path, a_core_frequency / 1000000, speed_grade);
> +}
> +
> void spl_enable_cache(void)
> {
> #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
> diff --git a/arch/arm/mach-k3/common.h b/arch/arm/mach-k3/common.h
> index 52d3faaab5c94578cf4f7e288cbf840500d490a1..6452188bd1949da83be20dcff6e59a282c3ff51e 100644
> --- a/arch/arm/mach-k3/common.h
> +++ b/arch/arm/mach-k3/common.h
> @@ -13,7 +13,8 @@
> /* keep ram_top in the 32-bit address space */
> #define CFG_MAX_MEM_MAPPED 0x100000000
>
> -#define K3_FIREWALL_BACKGROUND_BIT (8)
> +#define K3_FIREWALL_BACKGROUND_BIT (8)
> +#define K3_SPEED_GRADE_UNKNOWN '\0'
>
> struct fwl_data {
> const char *name;
> @@ -21,6 +22,11 @@ struct fwl_data {
> u16 regions;
> };
>
> +struct k3_speed_grade_map {
> + char speed_grade;
> + u32 a_core_frequency;
> +};
> +
> enum k3_firewall_region_type {
> K3_FIREWALL_REGION_FOREGROUND,
> K3_FIREWALL_REGION_BACKGROUND
> @@ -44,6 +50,9 @@ int load_firmware(char *name_fw, char *name_loadaddr, u32 *loadaddr);
> void k3_sysfw_print_ver(void);
> void k3_dm_print_ver(void);
> void spl_enable_cache(void);
> +char k3_get_speed_grade(void);
> +const struct k3_speed_grade_map *k3_get_speed_grade_map(void);
> +void k3_fix_rproc_clock(const char *path);
> void mmr_unlock(uintptr_t base, u32 partition);
> bool is_rom_loaded_sysfw(struct rom_extended_boot_data *data);
> enum k3_device_type get_device_type(void);
> diff --git a/arch/arm/mach-k3/include/mach/am62_hardware.h b/arch/arm/mach-k3/include/mach/am62_hardware.h
> index 2f5655bf24ac64cb807e282650712c36ebca0f36..9b8fd6276f112375828acd0e2c3d14fd38dc6940 100644
> --- a/arch/arm/mach-k3/include/mach/am62_hardware.h
> +++ b/arch/arm/mach-k3/include/mach/am62_hardware.h
> @@ -113,15 +113,6 @@ static inline int k3_get_core_nr(void)
> return (full_devid & JTAG_DEV_CORE_NR_MASK) >> JTAG_DEV_CORE_NR_SHIFT;
> }
>
> -static inline char k3_get_speed_grade(void)
> -{
> - u32 full_devid = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID);
> - u32 speed_grade = (full_devid & JTAG_DEV_SPEED_MASK) >>
> - JTAG_DEV_SPEED_SHIFT;
> -
> - return 'A' - 1 + speed_grade;
> -}
> -
> static inline int k3_get_temp_grade(void)
> {
> u32 full_devid = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID);
> @@ -142,21 +133,6 @@ static inline int k3_get_max_temp(void)
> }
> }
>
> -static inline int k3_get_a53_max_frequency(void)
> -{
> - switch (k3_get_speed_grade()) {
> - case 'K':
> - return 800000000;
> - case 'S':
> - return 1000000000;
> - case 'T':
> - return 1250000000;
> - case 'G':
> - default:
> - return 300000000;
> - }
> -}
> -
> static inline int k3_has_pru(void)
> {
> u32 full_devid = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID);
> diff --git a/arch/arm/mach-k3/include/mach/am62p_hardware.h b/arch/arm/mach-k3/include/mach/am62p_hardware.h
> index a310b52b45dc5cb76c215c598deee287a2e8e3c6..3c8fbb6b4211153b34fd156ca87b484c5ac9322e 100644
> --- a/arch/arm/mach-k3/include/mach/am62p_hardware.h
> +++ b/arch/arm/mach-k3/include/mach/am62p_hardware.h
> @@ -120,23 +120,6 @@ static inline int k3_get_max_temp(void)
> return JTAG_DEV_TEMP_EXTENDED_VALUE;
> }
>
> -static inline char k3_get_speed_grade(void)
> -{
> - u32 dev_id = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID);
> - u32 speed_grade = (dev_id & JTAG_DEV_SPEED_MASK) >>
> - JTAG_DEV_SPEED_SHIFT;
> -
> - return 'A' - 1 + speed_grade;
> -}
> -
> -static inline int k3_get_a53_max_frequency(void)
> -{
> - if (k3_get_speed_grade() == 'O')
> - return 1000000000;
> - else
> - return 1250000000;
> -}
> -
> #if defined(CONFIG_SYS_K3_SPL_ATF) && !defined(__ASSEMBLY__)
>
> static const u32 put_device_ids[] = {};
>
More information about the U-Boot
mailing list