[PATCH v1 1/5] arm: mach-mvebu: armada8k: add CPU and clock info display

Vincent Jardin vjardin at free.fr
Tue Mar 10 15:12:48 CET 2026


Add CPU information display for Armada 8040 platforms.

The soc_info.c reads the AP806 Sample-At-Reset (SAR) register to
determine the PLL clock configuration and converts it to actual
CPU, DDR, and Fabric frequencies using the PLL frequency table.
It also reports LLC (Last Level Cache) status.

Based on soc_info.c from Marvell's U-Boot 2015.01 vendor tree.

Signed-off-by: Vincent Jardin <vjardin at free.fr>
---
 arch/arm/mach-mvebu/armada8k/Makefile   |   2 +-
 arch/arm/mach-mvebu/armada8k/cpu.c      |  10 ++
 arch/arm/mach-mvebu/armada8k/soc_info.c | 192 ++++++++++++++++++++++++
 arch/arm/mach-mvebu/armada8k/soc_info.h |  14 ++
 4 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-mvebu/armada8k/soc_info.c
 create mode 100644 arch/arm/mach-mvebu/armada8k/soc_info.h

diff --git a/arch/arm/mach-mvebu/armada8k/Makefile b/arch/arm/mach-mvebu/armada8k/Makefile
index 0a4756717a3..723239d9894 100644
--- a/arch/arm/mach-mvebu/armada8k/Makefile
+++ b/arch/arm/mach-mvebu/armada8k/Makefile
@@ -2,4 +2,4 @@
 #
 # Copyright (C) 2016 Stefan Roese <sr at denx.de>
 
-obj-y = cpu.o cache_llc.o dram.o
+obj-y = cpu.o cache_llc.o dram.o soc_info.o
diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c
index 3eb93c82387..22767f143c2 100644
--- a/arch/arm/mach-mvebu/armada8k/cpu.c
+++ b/arch/arm/mach-mvebu/armada8k/cpu.c
@@ -15,6 +15,8 @@
 #include <asm/armv8/mmu.h>
 #include <mach/fw_info.h>
 
+#include "soc_info.h"
+
 /* Armada 7k/8k */
 #define MVEBU_RFU_BASE			(MVEBU_REGISTER(0x6f0000))
 #define RFU_GLOBAL_SW_RST		(MVEBU_RFU_BASE + 0x84)
@@ -111,3 +113,11 @@ int mmc_get_env_dev(void)
 
 	return CONFIG_ENV_MMC_DEVICE_INDEX;
 }
+
+int print_cpuinfo(void)
+{
+	soc_print_clock_info();
+	soc_print_soc_info();
+
+	return 0;
+}
diff --git a/arch/arm/mach-mvebu/armada8k/soc_info.c b/arch/arm/mach-mvebu/armada8k/soc_info.c
new file mode 100644
index 00000000000..a5c3b17cb7d
--- /dev/null
+++ b/arch/arm/mach-mvebu/armada8k/soc_info.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Marvell International Ltd.
+ *
+ * Marvell Armada 8K SoC info: SAR, Clock frequencies, LLC status
+ * Ported from Marvell U-Boot 2015.01 to mainline U-Boot.
+ */
+
+#include <config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <vsprintf.h>
+#include <asm/io.h>
+#include <asm/arch/soc.h>
+
+/* Clock frequency unit */
+#define MHz			1000000
+
+/* AP806 SAR (Sample-At-Reset) register */
+#define AP806_SAR_REG_BASE		(SOC_REGS_PHY_BASE + 0x6F4400)
+#define SAR_CLOCK_FREQ_MODE_OFFSET	0
+#define SAR_CLOCK_FREQ_MODE_MASK	(0x1f << SAR_CLOCK_FREQ_MODE_OFFSET)
+
+/* LLC (Last Level Cache) registers */
+#define LLC_BASE			(SOC_REGS_PHY_BASE + 0x8000)
+#define LLC_CTRL			0x100
+#define LLC_CTRL_EN			0x1
+#define LLC_EXCLUSIVE_EN		0x100
+
+/* MSS clock is fixed at 200MHz on AP806 */
+#define AP806_MSS_CLOCK			(200 * MHz)
+
+/* Clock ID indices in PLL frequency table */
+#define CPU_CLOCK_ID	0
+#define DDR_CLOCK_ID	1
+#define RING_CLOCK_ID	2
+
+/* Clocking options (SAR field values) */
+enum clocking_options {
+	CPU_2000_DDR_1200_RCLK_1200 = 0x0,
+	CPU_2000_DDR_1050_RCLK_1050 = 0x1,
+	CPU_1600_DDR_800_RCLK_800 = 0x4,
+	CPU_1800_DDR_1200_RCLK_1200 = 0x6,
+	CPU_1800_DDR_1050_RCLK_1050 = 0x7,
+	CPU_1600_DDR_900_RCLK_900 = 0x0b,
+	CPU_1600_DDR_1050_RCLK_1050 = 0x0d,
+	CPU_1600_DDR_900_RCLK_900_2 = 0x0e,
+	CPU_1000_DDR_650_RCLK_650 = 0x13,
+	CPU_1300_DDR_800_RCLK_800 = 0x14,
+	CPU_1300_DDR_650_RCLK_650 = 0x17,
+	CPU_1200_DDR_800_RCLK_800 = 0x19,
+	CPU_1400_DDR_800_RCLK_800 = 0x1a,
+	CPU_600_DDR_800_RCLK_800 = 0x1b,
+	CPU_800_DDR_800_RCLK_800 = 0x1c,
+	CPU_1000_DDR_800_RCLK_800 = 0x1d,
+};
+
+/*
+ * PLL frequency table: maps SAR clock mode to actual frequencies.
+ * Format: { CPU_freq, DDR_freq, RING_freq, SAR_value }
+ */
+static const u32 pll_freq_tbl[16][4] = {
+	/* CPU */	/* DDR */	/* Ring */
+	{2000 * MHz,	1200 * MHz,	1200 * MHz,	CPU_2000_DDR_1200_RCLK_1200},
+	{2000 * MHz,	1050 * MHz,	1050 * MHz,	CPU_2000_DDR_1050_RCLK_1050},
+	{1800 * MHz,	1200 * MHz,	1200 * MHz,	CPU_1800_DDR_1200_RCLK_1200},
+	{1800 * MHz,	1050 * MHz,	1050 * MHz,	CPU_1800_DDR_1050_RCLK_1050},
+	{1600 * MHz,	1050 * MHz,	1050 * MHz,	CPU_1600_DDR_1050_RCLK_1050},
+	{1600 * MHz,	900 * MHz,	900 * MHz,	CPU_1600_DDR_900_RCLK_900_2},
+	{1300 * MHz,	800 * MHz,	800 * MHz,	CPU_1300_DDR_800_RCLK_800},
+	{1300 * MHz,	650 * MHz,	650 * MHz,	CPU_1300_DDR_650_RCLK_650},
+	{1600 * MHz,	800 * MHz,	800 * MHz,	CPU_1600_DDR_800_RCLK_800},
+	{1600 * MHz,	900 * MHz,	900 * MHz,	CPU_1600_DDR_900_RCLK_900},
+	{1000 * MHz,	650 * MHz,	650 * MHz,	CPU_1000_DDR_650_RCLK_650},
+	{1200 * MHz,	800 * MHz,	800 * MHz,	CPU_1200_DDR_800_RCLK_800},
+	{1400 * MHz,	800 * MHz,	800 * MHz,	CPU_1400_DDR_800_RCLK_800},
+	{600 * MHz,	800 * MHz,	800 * MHz,	CPU_600_DDR_800_RCLK_800},
+	{800 * MHz,	800 * MHz,	800 * MHz,	CPU_800_DDR_800_RCLK_800},
+	{1000 * MHz,	800 * MHz,	800 * MHz,	CPU_1000_DDR_800_RCLK_800}
+};
+
+/*
+ * Get the clock frequency mode index from SAR register.
+ * Returns index into pll_freq_tbl, or -1 if not found.
+ */
+static int sar_get_clock_freq_mode(void)
+{
+	u32 i;
+	u32 clock_freq;
+
+	clock_freq = (readl(AP806_SAR_REG_BASE) & SAR_CLOCK_FREQ_MODE_MASK)
+			>> SAR_CLOCK_FREQ_MODE_OFFSET;
+
+	for (i = 0; i < ARRAY_SIZE(pll_freq_tbl); i++) {
+		if (pll_freq_tbl[i][3] == clock_freq)
+			return i;
+	}
+
+	pr_err("SAR: unsupported clock freq mode %d\n", clock_freq);
+	return -1;
+}
+
+/*
+ * Get CPU clock frequency in Hz.
+ */
+static u32 soc_cpu_clk_get(void)
+{
+	int mode = sar_get_clock_freq_mode();
+
+	if (mode < 0)
+		return 0;
+	return pll_freq_tbl[mode][CPU_CLOCK_ID];
+}
+
+/*
+ * Get DDR clock frequency in Hz.
+ */
+static u32 soc_ddr_clk_get(void)
+{
+	int mode = sar_get_clock_freq_mode();
+
+	if (mode < 0)
+		return 0;
+	return pll_freq_tbl[mode][DDR_CLOCK_ID];
+}
+
+/*
+ * Get Ring (Fabric) clock frequency in Hz.
+ */
+static u32 soc_ring_clk_get(void)
+{
+	int mode = sar_get_clock_freq_mode();
+
+	if (mode < 0)
+		return 0;
+	return pll_freq_tbl[mode][RING_CLOCK_ID];
+}
+
+/*
+ * Get MSS clock frequency in Hz.
+ */
+static u32 soc_mss_clk_get(void)
+{
+	return AP806_MSS_CLOCK;
+}
+
+/*
+ * Get LLC status and mode.
+ * Returns 1 if LLC is enabled, 0 otherwise.
+ * If excl_mode is not NULL, sets it to 1 if exclusive mode is enabled.
+ */
+static int llc_mode_get(int *excl_mode)
+{
+	u32 val;
+	int ret = 0, excl = 0;
+
+	val = readl(LLC_BASE + LLC_CTRL);
+	if (val & LLC_CTRL_EN) {
+		ret = 1;
+		if (val & LLC_EXCLUSIVE_EN)
+			excl = 1;
+	}
+	if (excl_mode)
+		*excl_mode = excl;
+
+	return ret;
+}
+
+/*
+ * Print SoC clock information.
+ */
+void soc_print_clock_info(void)
+{
+	printf("Clock:  CPU     %-4d [MHz]\n", soc_cpu_clk_get() / MHz);
+	printf("\tDDR     %-4d [MHz]\n", soc_ddr_clk_get() / MHz);
+	printf("\tFABRIC  %-4d [MHz]\n", soc_ring_clk_get() / MHz);
+	printf("\tMSS     %-4d [MHz]\n", soc_mss_clk_get() / MHz);
+}
+
+/*
+ * Print SoC-specific information: DDR width and LLC status.
+ */
+void soc_print_soc_info(void)
+{
+	int llc_en, llc_excl_mode;
+
+	printf("\tDDR 64 Bit width\n");
+
+	llc_en = llc_mode_get(&llc_excl_mode);
+	printf("\tLLC %s%s\n", llc_en ? "Enabled" : "Disabled",
+	       llc_excl_mode ? " (Exclusive Mode)" : "");
+}
diff --git a/arch/arm/mach-mvebu/armada8k/soc_info.h b/arch/arm/mach-mvebu/armada8k/soc_info.h
new file mode 100644
index 00000000000..41afe7a2508
--- /dev/null
+++ b/arch/arm/mach-mvebu/armada8k/soc_info.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2015 Marvell International Ltd.
+ *
+ * Marvell Armada 8K SoC info functions
+ */
+
+#ifndef _ARMADA8K_SOC_INFO_H_
+#define _ARMADA8K_SOC_INFO_H_
+
+void soc_print_clock_info(void);
+void soc_print_soc_info(void);
+
+#endif /* _ARMADA8K_SOC_INFO_H_ */
-- 
2.43.0



More information about the U-Boot mailing list