[PATCH 2/3] mach-k3: refactor A53 speed grade clock-rate fixup

Anshul Dalal anshuld at ti.com
Thu Oct 30 14:03:21 CET 2025


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
-
 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[] = {};

-- 
2.51.0



More information about the U-Boot mailing list