openwrt/target/linux/bmips/patches-5.10/200-bmips-automatically-detect-CPU-frequency.patch
Álvaro Fernández Rojas a3b863dc9f bmips: automatically detect CPU frequency
Some BCM63xx SoCs support multiple CPU frequencies depending on HW
configuration.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2021-03-08 09:45:32 +01:00

240 lines
6.3 KiB
Diff

From 38d5e4b3bcc25db14a2d5f428acf56dff862c97e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
Date: Fri, 5 Mar 2021 15:14:32 +0100
Subject: [PATCH] bmips: automatically detect CPU frequency
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Some BCM63xx SoCs support multiple CPU frequencies depending on HW config.
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
arch/mips/bmips/setup.c | 197 +++++++++++++++++++++-
arch/mips/configs/bmips_bcm63xx_defconfig | 91 ++++++++++
2 files changed, 281 insertions(+), 7 deletions(-)
create mode 100644 arch/mips/configs/bmips_bcm63xx_defconfig
--- a/arch/mips/bmips/setup.c
+++ b/arch/mips/bmips/setup.c
@@ -31,11 +31,51 @@
#define RELO_NORMAL_VEC BIT(18)
+#define REG_BCM6318_SOB ((void __iomem *)CKSEG1ADDR(0x10000900))
+#define BCM6318_FREQ_SHIFT 23
+#define BCM6318_FREQ_MASK (0x3 << BCM6318_FREQ_SHIFT)
+
#define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c))
#define BCM6328_TP1_DISABLED BIT(9)
+#define REG_BCM6328_MISC_SB ((void __iomem *)CKSEG1ADDR(0x10001a40))
+#define BCM6328_FCVO_SHIFT 7
+#define BCM6328_FCVO_MASK (0x1f << BCM6328_FCVO_SHIFT)
+
+#define REG_BCM6358_DDR_PLLC ((void __iomem *)CKSEG1ADDR(0x100012b8))
+#define BCM6358_PLLC_M1_SHIFT 0
+#define BCM6358_PLLC_M1_MASK (0xff << BCM6358_PLLC_M1_SHIFT)
+#define BCM6358_PLLC_N1_SHIFT 23
+#define BCM6358_PLLC_N1_MASK (0x3f << BCM6358_PLLC_N1_SHIFT)
+#define BCM6358_PLLC_N2_SHIFT 29
+#define BCM6358_PLLC_N2_MASK (0x7 << BCM6358_PLLC_N2_SHIFT)
+
+#define REG_BCM6362_MISC_SB ((void __iomem *)CKSEG1ADDR(0x10001814))
+#define BCM6362_FCVO_SHIFT 1
+#define BCM6362_FCVO_MASK (0x1f << BCM6362_FCVO_SHIFT)
+
+#define REG_BCM6368_DDR_PLLC ((void __iomem *)CKSEG1ADDR(0x100012a0))
+#define BCM6368_PLLC_P1_SHIFT 0
+#define BCM6368_PLLC_P1_MASK (0xf << BCM6368_PLLC_P1_SHIFT)
+#define BCM6368_PLLC_P2_SHIFT 4
+#define BCM6368_PLLC_P2_MASK (0xf << BCM6368_PLLC_P2_SHIFT)
+#define BCM6368_PLLC_NDIV_SHIFT 16
+#define BCM6368_PLLC_NDIV_MASK (0x1ff << BCM6368_PLLC_NDIV_SHIFT)
+#define REG_BCM6368_DDR_PLLD ((void __iomem *)CKSEG1ADDR(0x100012a4))
+#define BCM6368_PLLD_MDIV_SHIFT 0
+#define BCM6368_PLLD_MDIV_MASK (0xff << BCM6368_PLLD_MDIV_SHIFT)
+
+#define REG_BCM63268_MISC_SB ((void __iomem *)CKSEG1ADDR(0x10001814))
+#define BCM63268_FCVO_SHIFT 21
+#define BCM63268_FCVO_MASK (0xf << BCM63268_FCVO_SHIFT)
+
static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000;
+struct bmips_cpufreq {
+ const char *compatible;
+ u32 (*cpu_freq)(void);
+};
+
struct bmips_quirk {
const char *compatible;
void (*quirk_fn)(void);
@@ -138,17 +178,160 @@ const char *get_system_type(void)
return "Generic BMIPS kernel";
}
+static u32 bcm6318_cpufreq(void)
+{
+ u32 val = __raw_readl(REG_BCM6318_SOB);
+
+ switch ((val & BCM6318_FREQ_MASK) >> BCM6318_FREQ_SHIFT) {
+ case 0:
+ return 166000000;
+ case 2:
+ return 250000000;
+ case 3:
+ return 333000000;
+ case 1:
+ return 400000000;
+ default:
+ return 0;
+ }
+}
+
+static u32 bcm6328_cpufreq(void)
+{
+ u32 val = __raw_readl(REG_BCM6328_MISC_SB);
+
+ switch ((val & BCM6328_FCVO_MASK) >> BCM6328_FCVO_SHIFT) {
+ case 0x12:
+ case 0x14:
+ case 0x19:
+ return 160000000;
+ case 0x1c:
+ return 192000000;
+ case 0x13:
+ case 0x15:
+ return 200000000;
+ case 0x1a:
+ return 384000000;
+ case 0x16:
+ return 400000000;
+ default:
+ return 320000000;
+ }
+}
+
+static u32 bcm6358_cpufreq(void)
+{
+ u32 val, n1, n2, m1;
+
+ val = __raw_readl(REG_BCM6358_DDR_PLLC);
+ n1 = (val & BCM6358_PLLC_M1_MASK) >> BCM6358_PLLC_N1_SHIFT;
+ n2 = (val & BCM6358_PLLC_N2_MASK) >> BCM6358_PLLC_N2_SHIFT;
+ m1 = (val & BCM6358_PLLC_M1_MASK) >> BCM6358_PLLC_M1_SHIFT;
+
+ return (16 * 1000000 * n1 * n2) / m1;
+}
+
+static u32 bcm6362_cpufreq(void)
+{
+ u32 val = __raw_readl(REG_BCM6362_MISC_SB);
+
+ switch ((val & BCM6362_FCVO_MASK) >> BCM6362_FCVO_SHIFT) {
+ case 0x04:
+ case 0x0c:
+ case 0x14:
+ case 0x1c:
+ return 160000000;
+ case 0x15:
+ case 0x1d:
+ return 200000000;
+ case 0x03:
+ case 0x0b:
+ case 0x13:
+ case 0x1b:
+ return 240000000;
+ case 0x07:
+ case 0x17:
+ return 384000000;
+ case 0x05:
+ case 0x0e:
+ case 0x16:
+ case 0x1e:
+ case 0x1f:
+ return 400000000;
+ case 0x06:
+ return 440000000;
+ default:
+ return 320000000;
+ }
+}
+
+static u32 bcm6368_cpufreq(void)
+{
+ unsigned int val, p1, p2, ndiv, m1;
+
+ val = __raw_readl(REG_BCM6368_DDR_PLLC);
+ p1 = (val & BCM6368_PLLC_P1_MASK) >> BCM6368_PLLC_P1_SHIFT;
+ p2 = (val & BCM6368_PLLC_P2_MASK) >> BCM6368_PLLC_P2_SHIFT;
+ ndiv = (val & BCM6368_PLLC_NDIV_MASK) >>
+ BCM6368_PLLC_NDIV_SHIFT;
+
+ val = __raw_readl(REG_BCM6368_DDR_PLLD);
+ m1 = (val & BCM6368_PLLD_MDIV_MASK) >> BCM6368_PLLD_MDIV_SHIFT;
+
+ return (((64 * 1000000) / p1) * p2 * ndiv) / m1;
+}
+
+static u32 bcm63268_cpufreq(void)
+{
+ u32 val = __raw_readl(REG_BCM63268_MISC_SB);
+
+ switch ((val & BCM63268_FCVO_MASK) >> BCM63268_FCVO_SHIFT) {
+ case 0x3:
+ case 0xe:
+ return 320000000;
+ case 0xa:
+ return 333000000;
+ case 0x2:
+ case 0xb:
+ case 0xf:
+ return 400000000;
+ default:
+ return 0;
+ }
+}
+
+static const struct bmips_cpufreq bmips_cpufreq_list[] = {
+ { "brcm,bcm6318", &bcm6318_cpufreq },
+ { "brcm,bcm6328", &bcm6328_cpufreq },
+ { "brcm,bcm6358", &bcm6358_cpufreq },
+ { "brcm,bcm6362", &bcm6362_cpufreq },
+ { "brcm,bcm6368", &bcm6368_cpufreq },
+ { "brcm,bcm63268", &bcm63268_cpufreq },
+ { /* sentinel */ }
+};
+
void __init plat_time_init(void)
{
+ const struct bmips_cpufreq *cf;
struct device_node *np;
- u32 freq;
+ u32 freq = 0;
- np = of_find_node_by_name(NULL, "cpus");
- if (!np)
- panic("missing 'cpus' DT node");
- if (of_property_read_u32(np, "mips-hpt-frequency", &freq) < 0)
- panic("missing 'mips-hpt-frequency' property");
- of_node_put(np);
+ for (cf = bmips_cpufreq_list; cf->cpu_freq; cf++) {
+ if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
+ cf->compatible)) {
+ freq = cf->cpu_freq() / 2;
+ printk("%s detected @ %u MHz\n", cf->compatible, freq / 500000);
+ }
+ }
+
+ if (!freq) {
+ np = of_find_node_by_name(NULL, "cpus");
+ if (!np)
+ panic("missing 'cpus' DT node");
+ if (of_property_read_u32(np, "mips-hpt-frequency", &freq) < 0)
+ panic("missing 'mips-hpt-frequency' property");
+ of_node_put(np);
+ }
mips_hpt_frequency = freq;
}