[PATCH v2 0/4] Add fdt-fixups for AM62P variants

This series implements fdt fixups, by reading hardware information from registers and accordingly delete/modify the DT nodes, at run-time.
Logs for AM62P boot: https://gist.github.com/itsme-aparna/b889fe59882c1acf0ef25a644bd325c4
Changes from v1 to v2: - Add another patch to set A53 CPU freq before core boots, as mentioned by Bryan.
Aparna Patra (4): arm: mach-k3: am62p: Fixup CPU core, CAN-FD and Video-codec nodes in fdt arm: mach-k3: am62p: Fixup thermal zone critical points arm: mach-k3: am62p: Fixup a53 max cpu frequency by speed-grade arm: mach-k3: am62p: Set a53 cpu freq based on speed-grade
arch/arm/mach-k3/am62px/am62p5_fdt.c | 83 +++++++++++++++++++ arch/arm/mach-k3/am62px/am62p5_init.c | 62 ++++++++++++++ .../arm/mach-k3/include/mach/am62p_hardware.h | 65 +++++++++++++++ 3 files changed, 210 insertions(+)
base-commit: 56accc56b9aab87ef4809ccc588e1257969cd271

AM62P SOC is available in multiple variants: -CPU cores (Cortex-A) AM62Px1 (1 core), AM62Px2 (2 cores), AM62Px4 (4 cores) -With and without CAN-FD & Video-codec support
Remove the relevant FDT nodes by reading the actual configuration from the SoC registers, with that change it is possible to have a single dts/dtb file handling the different variant at runtime.
Signed-off-by: Aparna Patra a-patra@ti.com --- arch/arm/mach-k3/am62px/am62p5_fdt.c | 34 +++++++++++++++++++ .../arm/mach-k3/include/mach/am62p_hardware.h | 29 ++++++++++++++++ 2 files changed, 63 insertions(+)
diff --git a/arch/arm/mach-k3/am62px/am62p5_fdt.c b/arch/arm/mach-k3/am62px/am62p5_fdt.c index 29c832d28a..e88760ea51 100644 --- a/arch/arm/mach-k3/am62px/am62p5_fdt.c +++ b/arch/arm/mach-k3/am62px/am62p5_fdt.c @@ -7,8 +7,42 @@ #include "../common_fdt.h" #include <fdt_support.h>
+static void fdt_fixup_cores_wdt_nodes_am62p(void *blob, int core_nr) +{ + char node_path[32]; + + if (core_nr < 1) + return; + + for (; core_nr < 4; core_nr++) { + snprintf(node_path, sizeof(node_path), "/cpus/cpu@%d", core_nr); + fdt_del_node_path(blob, node_path); + snprintf(node_path, sizeof(node_path), "/cpus/cpu-map/cluster0/core%d", core_nr); + fdt_del_node_path(blob, node_path); + snprintf(node_path, sizeof(node_path), "/bus@f0000/watchdog@e0%d0000", core_nr); + fdt_del_node_path(blob, node_path); + } +} + +static void fdt_fixup_video_codec_nodes_am62p(void *blob, bool has_video_codec) +{ + if (!has_video_codec) + fdt_del_node_path(blob, "/bus@f0000/video-codec@30210000"); +} + +static void fdt_fixup_canfd_nodes_am62p(void *blob, bool has_canfd) +{ + if (!has_canfd) { + fdt_del_node_path(blob, "/bus@f0000/can@20701000"); + fdt_del_node_path(blob, "/bus@f0000/can@20711000"); + } +} + int ft_system_setup(void *blob, struct bd_info *bd) { + fdt_fixup_cores_wdt_nodes_am62p(blob, k3_get_core_nr()); + fdt_fixup_video_codec_nodes_am62p(blob, k3_has_video_codec()); + fdt_fixup_canfd_nodes_am62p(blob, k3_has_canfd()); fdt_fixup_reserved(blob, "tfa", CONFIG_K3_ATF_LOAD_ADDR, 0x80000); fdt_fixup_reserved(blob, "optee", CONFIG_K3_OPTEE_LOAD_ADDR, 0x1800000);
diff --git a/arch/arm/mach-k3/include/mach/am62p_hardware.h b/arch/arm/mach-k3/include/mach/am62p_hardware.h index 923466c41f..339562722d 100644 --- a/arch/arm/mach-k3/include/mach/am62p_hardware.h +++ b/arch/arm/mach-k3/include/mach/am62p_hardware.h @@ -19,6 +19,14 @@ #define MCU_CTRL_MMR0_BASE 0x04500000 #define WKUP_CTRL_MMR0_BASE 0x43000000
+#define CTRLMMR_WKUP_JTAG_DEVICE_ID (WKUP_CTRL_MMR0_BASE + 0x18) +#define JTAG_DEV_CORE_NR_MASK GENMASK(19, 18) +#define JTAG_DEV_CORE_NR_SHIFT 18 +#define JTAG_DEV_CANFD_MASK BIT(15) +#define JTAG_DEV_CANFD_SHIFT 15 +#define JTAG_DEV_VIDEO_CODEC_MASK BIT(14) +#define JTAG_DEV_VIDEO_CODEC_SHIFT 14 + #define CTRLMMR_MAIN_DEVSTAT (WKUP_CTRL_MMR0_BASE + 0x30) #define MAIN_DEVSTAT_PRIMARY_BOOTMODE_MASK GENMASK(6, 3) #define MAIN_DEVSTAT_PRIMARY_BOOTMODE_SHIFT 3 @@ -72,6 +80,27 @@
#define TI_SRAM_SCRATCH_BOARD_EEPROM_START 0x43c30000
+static inline int k3_get_core_nr(void) +{ + u32 dev_id = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID); + + return ((dev_id & JTAG_DEV_CORE_NR_MASK) >> JTAG_DEV_CORE_NR_SHIFT) + 1; +} + +static inline int k3_has_video_codec(void) +{ + u32 dev_id = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID); + + return !((dev_id & JTAG_DEV_VIDEO_CODEC_MASK) >> JTAG_DEV_VIDEO_CODEC_SHIFT); +} + +static inline int k3_has_canfd(void) +{ + u32 dev_id = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID); + + return (dev_id & JTAG_DEV_CANFD_MASK) >> JTAG_DEV_CANFD_SHIFT; +} + #if defined(CONFIG_SYS_K3_SPL_ATF) && !defined(__ASSEMBLY__)
static const u32 put_device_ids[] = {};

Read the max temperature for the SoC temperature grade from the hardware and modify the critical trip nodes on each thermal zone of FDT at runtime so they are correct with the hardware value for its grade.
Signed-off-by: Aparna Patra a-patra@ti.com --- arch/arm/mach-k3/am62px/am62p5_fdt.c | 37 +++++++++++++++++++ .../arm/mach-k3/include/mach/am62p_hardware.h | 17 +++++++++ 2 files changed, 54 insertions(+)
diff --git a/arch/arm/mach-k3/am62px/am62p5_fdt.c b/arch/arm/mach-k3/am62px/am62p5_fdt.c index e88760ea51..96194cebcd 100644 --- a/arch/arm/mach-k3/am62px/am62p5_fdt.c +++ b/arch/arm/mach-k3/am62px/am62p5_fdt.c @@ -38,11 +38,48 @@ static void fdt_fixup_canfd_nodes_am62p(void *blob, bool has_canfd) } }
+static int fdt_fixup_trips_node(void *blob, int zoneoffset, int maxc) +{ + int node, trip; + + node = fdt_subnode_offset(blob, zoneoffset, "trips"); + if (node < 0) + return -1; + + fdt_for_each_subnode(trip, blob, node) { + const char *type = fdt_getprop(blob, trip, "type", NULL); + + if (!type || (strncmp(type, "critical", 8) != 0)) + continue; + + if (fdt_setprop_u32(blob, trip, "temperature", 1000 * maxc) < 0) + return -1; + } + + return 0; +} + +static void fdt_fixup_thermal_zone_nodes_am62p(void *blob, int maxc) +{ + int node, zone; + + node = fdt_path_offset(blob, "/thermal-zones"); + if (node < 0) + return; + + fdt_for_each_subnode(zone, blob, node) { + if (fdt_fixup_trips_node(blob, zone, maxc) < 0) + printf("Failed to set temperature in %s critical trips\n", + fdt_get_name(blob, zone, NULL)); + } +} + int ft_system_setup(void *blob, struct bd_info *bd) { fdt_fixup_cores_wdt_nodes_am62p(blob, k3_get_core_nr()); fdt_fixup_video_codec_nodes_am62p(blob, k3_has_video_codec()); fdt_fixup_canfd_nodes_am62p(blob, k3_has_canfd()); + fdt_fixup_thermal_zone_nodes_am62p(blob, k3_get_max_temp()); fdt_fixup_reserved(blob, "tfa", CONFIG_K3_ATF_LOAD_ADDR, 0x80000); fdt_fixup_reserved(blob, "optee", CONFIG_K3_OPTEE_LOAD_ADDR, 0x1800000);
diff --git a/arch/arm/mach-k3/include/mach/am62p_hardware.h b/arch/arm/mach-k3/include/mach/am62p_hardware.h index 339562722d..2f1c8517e6 100644 --- a/arch/arm/mach-k3/include/mach/am62p_hardware.h +++ b/arch/arm/mach-k3/include/mach/am62p_hardware.h @@ -26,6 +26,12 @@ #define JTAG_DEV_CANFD_SHIFT 15 #define JTAG_DEV_VIDEO_CODEC_MASK BIT(14) #define JTAG_DEV_VIDEO_CODEC_SHIFT 14 +#define JTAG_DEV_TEMP_MASK GENMASK(5, 3) +#define JTAG_DEV_TEMP_SHIFT 3 + +#define JTAG_DEV_TEMP_AUTOMOTIVE 0x5 +#define JTAG_DEV_TEMP_EXTENDED_VALUE 105 +#define JTAG_DEV_TEMP_AUTOMOTIVE_VALUE 125
#define CTRLMMR_MAIN_DEVSTAT (WKUP_CTRL_MMR0_BASE + 0x30) #define MAIN_DEVSTAT_PRIMARY_BOOTMODE_MASK GENMASK(6, 3) @@ -101,6 +107,17 @@ static inline int k3_has_canfd(void) return (dev_id & JTAG_DEV_CANFD_MASK) >> JTAG_DEV_CANFD_SHIFT; }
+static inline int k3_get_max_temp(void) +{ + u32 dev_id = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID); + u32 dev_temp = (dev_id & JTAG_DEV_TEMP_MASK) >> JTAG_DEV_TEMP_SHIFT; + + if (dev_temp == JTAG_DEV_TEMP_AUTOMOTIVE) + return JTAG_DEV_TEMP_AUTOMOTIVE_VALUE; + else + return JTAG_DEV_TEMP_EXTENDED_VALUE; +} + #if defined(CONFIG_SYS_K3_SPL_ATF) && !defined(__ASSEMBLY__)
static const u32 put_device_ids[] = {};

AM62P SoC has multiple speed grades. Add function to delete non-relevant CPU frequency nodes, based on the information retrieved from hardware registers. Fastest grade's maximum frequency also depends on PMIC voltage, hence to simplify implementation use the smaller value.
Signed-off-by: Aparna Patra a-patra@ti.com --- arch/arm/mach-k3/am62px/am62p5_fdt.c | 12 ++++++++++++ .../arm/mach-k3/include/mach/am62p_hardware.h | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+)
diff --git a/arch/arm/mach-k3/am62px/am62p5_fdt.c b/arch/arm/mach-k3/am62px/am62p5_fdt.c index 96194cebcd..2c40fa5a59 100644 --- a/arch/arm/mach-k3/am62px/am62p5_fdt.c +++ b/arch/arm/mach-k3/am62px/am62p5_fdt.c @@ -74,12 +74,24 @@ static void fdt_fixup_thermal_zone_nodes_am62p(void *blob, int maxc) } }
+static void fdt_fixup_cpu_freq_nodes_am62p(void *blob, int max_freq) +{ + if (max_freq >= 1250000000) + return; + + if (max_freq <= 1000000000) { + fdt_del_node_path(blob, "/opp-table/opp-1250000000"); + fdt_del_node_path(blob, "/opp-table/opp-1400000000"); + } +} + int ft_system_setup(void *blob, struct bd_info *bd) { fdt_fixup_cores_wdt_nodes_am62p(blob, k3_get_core_nr()); fdt_fixup_video_codec_nodes_am62p(blob, k3_has_video_codec()); fdt_fixup_canfd_nodes_am62p(blob, k3_has_canfd()); fdt_fixup_thermal_zone_nodes_am62p(blob, k3_get_max_temp()); + fdt_fixup_cpu_freq_nodes_am62p(blob, k3_get_a53_max_frequency()); fdt_fixup_reserved(blob, "tfa", CONFIG_K3_ATF_LOAD_ADDR, 0x80000); fdt_fixup_reserved(blob, "optee", CONFIG_K3_OPTEE_LOAD_ADDR, 0x1800000);
diff --git a/arch/arm/mach-k3/include/mach/am62p_hardware.h b/arch/arm/mach-k3/include/mach/am62p_hardware.h index 2f1c8517e6..95af5c5c54 100644 --- a/arch/arm/mach-k3/include/mach/am62p_hardware.h +++ b/arch/arm/mach-k3/include/mach/am62p_hardware.h @@ -26,6 +26,8 @@ #define JTAG_DEV_CANFD_SHIFT 15 #define JTAG_DEV_VIDEO_CODEC_MASK BIT(14) #define JTAG_DEV_VIDEO_CODEC_SHIFT 14 +#define JTAG_DEV_SPEED_MASK GENMASK(10, 6) +#define JTAG_DEV_SPEED_SHIFT 6 #define JTAG_DEV_TEMP_MASK GENMASK(5, 3) #define JTAG_DEV_TEMP_SHIFT 3
@@ -118,6 +120,23 @@ 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[] = {};

The maximum frequency of the A53 CPU on the AM62P depends on the speed grade of the SoC. This value is hardcoded in the DT for all AM62P variants, potentially causing specifications to be exceeded. Moreover, setting a common lower frequency for all variants increases boot time. To prevent these issues, modify the DT at runtime from the R5 core to adjust the A53 CPU frequency.
Signed-off-by: Aparna Patra a-patra@ti.com --- arch/arm/mach-k3/am62px/am62p5_init.c | 62 +++++++++++++++++++++++++++ 1 file changed, 62 insertions(+)
diff --git a/arch/arm/mach-k3/am62px/am62p5_init.c b/arch/arm/mach-k3/am62px/am62p5_init.c index 34ed01cd78..74631a4ce9 100644 --- a/arch/arm/mach-k3/am62px/am62p5_init.c +++ b/arch/arm/mach-k3/am62px/am62p5_init.c @@ -11,10 +11,14 @@ #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 + struct fwl_data cbass_main_fwls[] = { { "FSS_DAT_REG3", 7, 8 }, }; @@ -67,6 +71,62 @@ 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@f0000/system-controller@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@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; @@ -160,6 +220,8 @@ void board_init_f(ulong dummy)
spl_enable_cache(); debug("am62px_init: %s done\n", __func__); + + fixup_a53_cpu_freq_by_speed_grade(); }
u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device)

On January 8, 2025 thus sayeth Aparna Patra:
This series implements fdt fixups, by reading hardware information from registers and accordingly delete/modify the DT nodes, at run-time.
Logs for AM62P boot: https://gist.github.com/itsme-aparna/b889fe59882c1acf0ef25a644bd325c4
Changes from v1 to v2:
- Add another patch to set A53 CPU freq before core boots, as mentioned by Bryan.
Aparna Patra (4): arm: mach-k3: am62p: Fixup CPU core, CAN-FD and Video-codec nodes in fdt arm: mach-k3: am62p: Fixup thermal zone critical points arm: mach-k3: am62p: Fixup a53 max cpu frequency by speed-grade arm: mach-k3: am62p: Set a53 cpu freq based on speed-grade
arch/arm/mach-k3/am62px/am62p5_fdt.c | 83 +++++++++++++++++++ arch/arm/mach-k3/am62px/am62p5_init.c | 62 ++++++++++++++ .../arm/mach-k3/include/mach/am62p_hardware.h | 65 +++++++++++++++ 3 files changed, 210 insertions(+)
Thanks Aparna!
Reviewed-by: Bryan Brattlof bb@ti.com
~Bryan

On Wed, 08 Jan 2025 10:19:35 +0530, Aparna Patra wrote:
This series implements fdt fixups, by reading hardware information from registers and accordingly delete/modify the DT nodes, at run-time.
Logs for AM62P boot: https://gist.github.com/itsme-aparna/b889fe59882c1acf0ef25a644bd325c4
[...]
Applied to u-boot/master, thanks!
participants (3)
-
Aparna Patra
-
Bryan Brattlof
-
Tom Rini