[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