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.
Signed-off-by: Vincent Jardin <[email protected]> Reviewed-by: Stefan Roese <[email protected]> --- Changes in v3: - Move per-patch changelog below --- per U-Boot guidelines (Stefan) Changes in v2: - Added Reviewed-by Stefan arch/arm/mach-mvebu/armada8k/Makefile | 2 +- arch/arm/mach-mvebu/armada8k/cpu.c | 12 ++ arch/arm/mach-mvebu/armada8k/soc_info.c | 194 ++++++++++++++++++++++++ arch/arm/mach-mvebu/armada8k/soc_info.h | 14 ++ 4 files changed, 221 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 <[email protected]> -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..220b32dd025 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,13 @@ int mmc_get_env_dev(void) return CONFIG_ENV_MMC_DEVICE_INDEX; } + +int print_cpuinfo(void) +{ + if (!IS_ENABLED(CONFIG_DISPLAY_CPUINFO)) + return 0; + + 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..18cc083c0db --- /dev/null +++ b/arch/arm/mach-mvebu/armada8k/soc_info.c @@ -0,0 +1,194 @@ +// 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 <stdio.h> +#include <asm/io.h> +#include <asm/arch/soc.h> + +/* Clock frequency units */ +#define KHz 1000 +#define MHz 1000000 +#define GHz 1000000000 + +/* 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.53.0

