^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * CPU frequency scaling support for Armada 37xx platform.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2017 Marvell
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Gregory CLEMENT <gregory.clement@free-electrons.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/pm_opp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "cpufreq-dt.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* Clk register set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define ARMADA_37XX_CLK_TBG_SEL 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define ARMADA_37XX_CLK_TBG_SEL_CPU_OFF 22
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* Power management in North Bridge register set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define ARMADA_37XX_NB_L0L1 0x18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define ARMADA_37XX_NB_L2L3 0x1C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define ARMADA_37XX_NB_TBG_DIV_OFF 13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define ARMADA_37XX_NB_TBG_DIV_MASK 0x7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define ARMADA_37XX_NB_CLK_SEL_OFF 11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define ARMADA_37XX_NB_CLK_SEL_MASK 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define ARMADA_37XX_NB_CLK_SEL_TBG 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define ARMADA_37XX_NB_TBG_SEL_OFF 9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define ARMADA_37XX_NB_TBG_SEL_MASK 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define ARMADA_37XX_NB_VDD_SEL_OFF 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define ARMADA_37XX_NB_VDD_SEL_MASK 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define ARMADA_37XX_NB_CONFIG_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define ARMADA_37XX_NB_DYN_MOD 0x24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define ARMADA_37XX_NB_CLK_SEL_EN BIT(26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define ARMADA_37XX_NB_TBG_EN BIT(28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define ARMADA_37XX_NB_DIV_EN BIT(29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define ARMADA_37XX_NB_VDD_EN BIT(30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define ARMADA_37XX_NB_DFS_EN BIT(31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define ARMADA_37XX_NB_CPU_LOAD 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define ARMADA_37XX_NB_CPU_LOAD_MASK 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define ARMADA_37XX_DVFS_LOAD_0 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define ARMADA_37XX_DVFS_LOAD_1 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define ARMADA_37XX_DVFS_LOAD_2 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define ARMADA_37XX_DVFS_LOAD_3 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* AVS register set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define ARMADA_37XX_AVS_CTL0 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define ARMADA_37XX_AVS_ENABLE BIT(30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define ARMADA_37XX_AVS_HIGH_VDD_LIMIT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define ARMADA_37XX_AVS_LOW_VDD_LIMIT 22
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define ARMADA_37XX_AVS_VDD_MASK 0x3F
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define ARMADA_37XX_AVS_CTL2 0x8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define ARMADA_37XX_AVS_LOW_VDD_EN BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define ARMADA_37XX_AVS_VSET(x) (0x1C + 4 * (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * On Armada 37xx the Power management manages 4 level of CPU load,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * each level can be associated with a CPU clock source, a CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * divider, a VDD level, etc...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define LOAD_LEVEL_NR 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define MIN_VOLT_MV 1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define MIN_VOLT_MV_FOR_L1_1000MHZ 1108
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define MIN_VOLT_MV_FOR_L1_1200MHZ 1155
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* AVS value for the corresponding voltage (in mV) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int avs_map[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) 747, 758, 770, 782, 793, 805, 817, 828, 840, 852, 863, 875, 887, 898,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) 910, 922, 933, 945, 957, 968, 980, 992, 1003, 1015, 1027, 1038, 1050,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) 1062, 1073, 1085, 1097, 1108, 1120, 1132, 1143, 1155, 1167, 1178, 1190,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) 1202, 1213, 1225, 1237, 1248, 1260, 1272, 1283, 1295, 1307, 1318, 1330,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) 1342
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct armada37xx_cpufreq_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) u32 nb_l0l1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u32 nb_l2l3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u32 nb_dyn_mod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) u32 nb_cpu_load;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static struct armada37xx_cpufreq_state *armada37xx_cpufreq_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct armada_37xx_dvfs {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) u32 cpu_freq_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) u8 divider[LOAD_LEVEL_NR];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u32 avs[LOAD_LEVEL_NR];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static struct armada_37xx_dvfs armada_37xx_dvfs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * The cpufreq scaling for 1.2 GHz variant of the SOC is currently
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * unstable because we do not know how to configure it properly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /* {.cpu_freq_max = 1200*1000*1000, .divider = {1, 2, 4, 6} }, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {.cpu_freq_max = 1000*1000*1000, .divider = {1, 2, 4, 5} },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {.cpu_freq_max = 800*1000*1000, .divider = {1, 2, 3, 4} },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {.cpu_freq_max = 600*1000*1000, .divider = {2, 4, 5, 6} },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static struct armada_37xx_dvfs *armada_37xx_cpu_freq_info_get(u32 freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) for (i = 0; i < ARRAY_SIZE(armada_37xx_dvfs); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (freq == armada_37xx_dvfs[i].cpu_freq_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return &armada_37xx_dvfs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) pr_err("Unsupported CPU frequency %d MHz\n", freq/1000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * Setup the four level managed by the hardware. Once the four level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * will be configured then the DVFS will be enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct regmap *clk_base, u8 *divider)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) u32 cpu_tbg_sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int load_lvl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* Determine to which TBG clock is CPU connected */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) regmap_read(clk_base, ARMADA_37XX_CLK_TBG_SEL, &cpu_tbg_sel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) cpu_tbg_sel >>= ARMADA_37XX_CLK_TBG_SEL_CPU_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) cpu_tbg_sel &= ARMADA_37XX_NB_TBG_SEL_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) for (load_lvl = 0; load_lvl < LOAD_LEVEL_NR; load_lvl++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) unsigned int reg, mask, val, offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (load_lvl <= ARMADA_37XX_DVFS_LOAD_1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) reg = ARMADA_37XX_NB_L0L1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) reg = ARMADA_37XX_NB_L2L3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (load_lvl == ARMADA_37XX_DVFS_LOAD_0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) load_lvl == ARMADA_37XX_DVFS_LOAD_2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) offset += ARMADA_37XX_NB_CONFIG_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* Set cpu clock source, for all the level we use TBG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) val = ARMADA_37XX_NB_CLK_SEL_TBG << ARMADA_37XX_NB_CLK_SEL_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) mask = (ARMADA_37XX_NB_CLK_SEL_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) << ARMADA_37XX_NB_CLK_SEL_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* Set TBG index, for all levels we use the same TBG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) val = cpu_tbg_sel << ARMADA_37XX_NB_TBG_SEL_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) mask = (ARMADA_37XX_NB_TBG_SEL_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) << ARMADA_37XX_NB_TBG_SEL_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * Set cpu divider based on the pre-computed array in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * order to have balanced step.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) val |= divider[load_lvl] << ARMADA_37XX_NB_TBG_DIV_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) mask |= (ARMADA_37XX_NB_TBG_DIV_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) << ARMADA_37XX_NB_TBG_DIV_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /* Set VDD divider which is actually the load level. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) val |= load_lvl << ARMADA_37XX_NB_VDD_SEL_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) mask |= (ARMADA_37XX_NB_VDD_SEL_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) << ARMADA_37XX_NB_VDD_SEL_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) val <<= offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) mask <<= offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) regmap_update_bits(base, reg, mask, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * Find out the armada 37x supported AVS value whose voltage value is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * the round-up closest to the target voltage value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static u32 armada_37xx_avs_val_match(int target_vm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) u32 avs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /* Find out the round-up closest supported voltage value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) for (avs = 0; avs < ARRAY_SIZE(avs_map); avs++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (avs_map[avs] >= target_vm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * If all supported voltages are smaller than target one,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * choose the largest supported voltage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (avs == ARRAY_SIZE(avs_map))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) avs = ARRAY_SIZE(avs_map) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return avs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * For Armada 37xx soc, L0(VSET0) VDD AVS value is set to SVC revision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * value or a default value when SVC is not supported.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * - L0 can be read out from the register of AVS_CTRL_0 and L0 voltage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * can be got from the mapping table of avs_map.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * - L1 voltage should be about 100mv smaller than L0 voltage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * - L2 & L3 voltage should be about 150mv smaller than L0 voltage.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * This function calculates L1 & L2 & L3 AVS values dynamically based
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * on L0 voltage and fill all AVS values to the AVS value table.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * When base CPU frequency is 1000 or 1200 MHz then there is additional
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * minimal avs value for load L1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) struct armada_37xx_dvfs *dvfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) unsigned int target_vm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) int load_level = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) u32 l0_vdd_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (base == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /* Get L0 VDD min value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) regmap_read(base, ARMADA_37XX_AVS_CTL0, &l0_vdd_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) l0_vdd_min = (l0_vdd_min >> ARMADA_37XX_AVS_LOW_VDD_LIMIT) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) ARMADA_37XX_AVS_VDD_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (l0_vdd_min >= ARRAY_SIZE(avs_map)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) pr_err("L0 VDD MIN %d is not correct.\n", l0_vdd_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) dvfs->avs[0] = l0_vdd_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (avs_map[l0_vdd_min] <= MIN_VOLT_MV) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * If L0 voltage is smaller than 1000mv, then all VDD sets
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * use L0 voltage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) u32 avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) dvfs->avs[load_level] = avs_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * Set the avs values for load L0 and L1 when base CPU frequency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * is 1000/1200 MHz to its typical initial values according to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * the Armada 3700 Hardware Specifications.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (dvfs->cpu_freq_max >= 1000*1000*1000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (dvfs->cpu_freq_max >= 1200*1000*1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1200MHZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1000MHZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) dvfs->avs[0] = dvfs->avs[1] = avs_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * L1 voltage is equal to L0 voltage - 100mv and it must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * larger than 1000mv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) target_vm = avs_map[l0_vdd_min] - 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) dvfs->avs[1] = armada_37xx_avs_val_match(target_vm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * L2 & L3 voltage is equal to L0 voltage - 150mv and it must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * be larger than 1000mv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) target_vm = avs_map[l0_vdd_min] - 150;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * Fix the avs value for load L1 when base CPU frequency is 1000/1200 MHz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * otherwise the CPU gets stuck when switching from load L1 to load L0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * Also ensure that avs value for load L1 is not higher than for L0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (dvfs->cpu_freq_max >= 1000*1000*1000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) u32 avs_min_l1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (dvfs->cpu_freq_max >= 1200*1000*1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) avs_min_l1 = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1200MHZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) avs_min_l1 = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1000MHZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (avs_min_l1 > dvfs->avs[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) avs_min_l1 = dvfs->avs[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (dvfs->avs[1] < avs_min_l1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) dvfs->avs[1] = avs_min_l1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) struct armada_37xx_dvfs *dvfs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) unsigned int avs_val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) int load_level = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (base == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) /* Disable AVS before the configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) regmap_update_bits(base, ARMADA_37XX_AVS_CTL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) ARMADA_37XX_AVS_ENABLE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) /* Enable low voltage mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) regmap_update_bits(base, ARMADA_37XX_AVS_CTL2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) ARMADA_37XX_AVS_LOW_VDD_EN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) ARMADA_37XX_AVS_LOW_VDD_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) avs_val = dvfs->avs[load_level];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) regmap_update_bits(base, ARMADA_37XX_AVS_VSET(load_level-1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_HIGH_VDD_LIMIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_LOW_VDD_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) avs_val << ARMADA_37XX_AVS_HIGH_VDD_LIMIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) avs_val << ARMADA_37XX_AVS_LOW_VDD_LIMIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) /* Enable AVS after the configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) regmap_update_bits(base, ARMADA_37XX_AVS_CTL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) ARMADA_37XX_AVS_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) ARMADA_37XX_AVS_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static void armada37xx_cpufreq_disable_dvfs(struct regmap *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) unsigned int reg = ARMADA_37XX_NB_DYN_MOD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) mask = ARMADA_37XX_NB_DFS_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) regmap_update_bits(base, reg, mask, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static void __init armada37xx_cpufreq_enable_dvfs(struct regmap *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) unsigned int val, reg = ARMADA_37XX_NB_CPU_LOAD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) mask = ARMADA_37XX_NB_CPU_LOAD_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /* Start with the highest load (0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) val = ARMADA_37XX_DVFS_LOAD_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) regmap_update_bits(base, reg, mask, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /* Now enable DVFS for the CPUs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) reg = ARMADA_37XX_NB_DYN_MOD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) mask = ARMADA_37XX_NB_CLK_SEL_EN | ARMADA_37XX_NB_TBG_EN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ARMADA_37XX_NB_DIV_EN | ARMADA_37XX_NB_VDD_EN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) ARMADA_37XX_NB_DFS_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) regmap_update_bits(base, reg, mask, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) static int armada37xx_cpufreq_suspend(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct armada37xx_cpufreq_state *state = armada37xx_cpufreq_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) regmap_read(state->regmap, ARMADA_37XX_NB_L0L1, &state->nb_l0l1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) regmap_read(state->regmap, ARMADA_37XX_NB_L2L3, &state->nb_l2l3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) regmap_read(state->regmap, ARMADA_37XX_NB_CPU_LOAD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) &state->nb_cpu_load);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) regmap_read(state->regmap, ARMADA_37XX_NB_DYN_MOD, &state->nb_dyn_mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static int armada37xx_cpufreq_resume(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) struct armada37xx_cpufreq_state *state = armada37xx_cpufreq_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) /* Ensure DVFS is disabled otherwise the following registers are RO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) armada37xx_cpufreq_disable_dvfs(state->regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) regmap_write(state->regmap, ARMADA_37XX_NB_L0L1, state->nb_l0l1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) regmap_write(state->regmap, ARMADA_37XX_NB_L2L3, state->nb_l2l3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) regmap_write(state->regmap, ARMADA_37XX_NB_CPU_LOAD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) state->nb_cpu_load);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * NB_DYN_MOD register is the one that actually enable back DVFS if it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * was enabled before the suspend operation. This must be done last
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * otherwise other registers are not writable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) regmap_write(state->regmap, ARMADA_37XX_NB_DYN_MOD, state->nb_dyn_mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) static int __init armada37xx_cpufreq_driver_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) struct cpufreq_dt_platform_data pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct armada_37xx_dvfs *dvfs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) unsigned long freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) unsigned int cur_frequency, base_frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) struct regmap *nb_clk_base, *nb_pm_base, *avs_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) struct device *cpu_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) int load_lvl, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) struct clk *clk, *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) nb_clk_base =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) syscon_regmap_lookup_by_compatible("marvell,armada-3700-periph-clock-nb");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (IS_ERR(nb_clk_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) nb_pm_base =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (IS_ERR(nb_pm_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) avs_base =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) syscon_regmap_lookup_by_compatible("marvell,armada-3700-avs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /* if AVS is not present don't use it but still try to setup dvfs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (IS_ERR(avs_base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) pr_info("Syscon failed for Adapting Voltage Scaling: skip it\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) avs_base = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* Before doing any configuration on the DVFS first, disable it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) armada37xx_cpufreq_disable_dvfs(nb_pm_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * On CPU 0 register the operating points supported (which are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * the nominal CPU frequency and full integer divisions of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * it).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) cpu_dev = get_cpu_device(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (!cpu_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) dev_err(cpu_dev, "Cannot get CPU\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) clk = clk_get(cpu_dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) dev_err(cpu_dev, "Cannot get clock for CPU0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return PTR_ERR(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) parent = clk_get_parent(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (IS_ERR(parent)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) dev_err(cpu_dev, "Cannot get parent clock for CPU0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) clk_put(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) return PTR_ERR(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) /* Get parent CPU frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) base_frequency = clk_get_rate(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (!base_frequency) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) dev_err(cpu_dev, "Failed to get parent clock rate for CPU\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) clk_put(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /* Get nominal (current) CPU frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) cur_frequency = clk_get_rate(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (!cur_frequency) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) dev_err(cpu_dev, "Failed to get clock rate for CPU\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) clk_put(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) dvfs = armada_37xx_cpu_freq_info_get(base_frequency);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (!dvfs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) clk_put(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) armada37xx_cpufreq_state = kmalloc(sizeof(*armada37xx_cpufreq_state),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (!armada37xx_cpufreq_state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) clk_put(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) armada37xx_cpufreq_state->regmap = nb_pm_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) armada37xx_cpufreq_avs_configure(avs_base, dvfs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) armada37xx_cpufreq_avs_setup(avs_base, dvfs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) armada37xx_cpufreq_dvfs_setup(nb_pm_base, nb_clk_base, dvfs->divider);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) clk_put(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) load_lvl++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) unsigned long u_volt = avs_map[dvfs->avs[load_lvl]] * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) freq = base_frequency / dvfs->divider[load_lvl];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) ret = dev_pm_opp_add(cpu_dev, freq, u_volt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) goto remove_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) /* Now that everything is setup, enable the DVFS at hardware level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) armada37xx_cpufreq_enable_dvfs(nb_pm_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) memset(&pdata, 0, sizeof(pdata));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) pdata.suspend = armada37xx_cpufreq_suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) pdata.resume = armada37xx_cpufreq_resume;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) pdev = platform_device_register_data(NULL, "cpufreq-dt", -1, &pdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) sizeof(pdata));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) ret = PTR_ERR_OR_ZERO(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) goto disable_dvfs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) disable_dvfs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) armada37xx_cpufreq_disable_dvfs(nb_pm_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) remove_opp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) /* clean-up the already added opp before leaving */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) freq = base_frequency / dvfs->divider[load_lvl];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) dev_pm_opp_remove(cpu_dev, freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) kfree(armada37xx_cpufreq_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) /* late_initcall, to guarantee the driver is loaded after A37xx clock driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) late_initcall(armada37xx_cpufreq_driver_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) static const struct of_device_id __maybe_unused armada37xx_cpufreq_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) { .compatible = "marvell,armada-3700-nb-pm" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) MODULE_DEVICE_TABLE(of, armada37xx_cpufreq_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) MODULE_DESCRIPTION("Armada 37xx cpufreq driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) MODULE_LICENSE("GPL");