^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * CPU frequency scaling for Broadcom SoCs with AVS firmware that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * supports DVS or DVFS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2016 Broadcom
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This program is free software; you can redistribute it and/or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * modify it under the terms of the GNU General Public License as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * published by the Free Software Foundation version 2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * This program is distributed "as is" WITHOUT ANY WARRANTY of any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * kind, whether express or implied; without even the implied warranty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * GNU General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * "AVS" is the name of a firmware developed at Broadcom. It derives
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * its name from the technique called "Adaptive Voltage Scaling".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * Adaptive voltage scaling was the original purpose of this firmware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * The AVS firmware still supports "AVS mode", where all it does is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * adaptive voltage scaling. However, on some newer Broadcom SoCs, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * AVS Firmware, despite its unchanged name, also supports DFS mode and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * DVFS mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * In the context of this document and the related driver, "AVS" by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * itself always means the Broadcom firmware and never refers to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * technique called "Adaptive Voltage Scaling".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * The Broadcom STB AVS CPUfreq driver provides voltage and frequency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * scaling on Broadcom SoCs using AVS firmware with support for DFS and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * DVFS. The AVS firmware is running on its own co-processor. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * driver supports both uniprocessor (UP) and symmetric multiprocessor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * (SMP) systems which share clock and voltage across all CPUs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * Actual voltage and frequency scaling is done solely by the AVS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * firmware. This driver does not change frequency or voltage itself.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * It provides a standard CPUfreq interface to the rest of the kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * and to userland. It interfaces with the AVS firmware to effect the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * requested changes and to report back the current system status in a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * way that is expected by existing tools.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #include <linux/semaphore.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /* Max number of arguments AVS calls take */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define AVS_MAX_CMD_ARGS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * This macro is used to generate AVS parameter register offsets. For
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * x >= AVS_MAX_CMD_ARGS, it returns 0 to protect against accidental memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * access outside of the parameter range. (Offset 0 is the first parameter.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define AVS_PARAM_MULT(x) ((x) < AVS_MAX_CMD_ARGS ? (x) : 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* AVS Mailbox Register offsets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define AVS_MBOX_COMMAND 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define AVS_MBOX_STATUS 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define AVS_MBOX_VOLTAGE0 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define AVS_MBOX_TEMP0 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define AVS_MBOX_PV0 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define AVS_MBOX_MV0 0x14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define AVS_MBOX_PARAM(x) (0x18 + AVS_PARAM_MULT(x) * sizeof(u32))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define AVS_MBOX_REVISION 0x28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define AVS_MBOX_PSTATE 0x2c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define AVS_MBOX_HEARTBEAT 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define AVS_MBOX_MAGIC 0x34
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define AVS_MBOX_SIGMA_HVT 0x38
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define AVS_MBOX_SIGMA_SVT 0x3c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define AVS_MBOX_VOLTAGE1 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define AVS_MBOX_TEMP1 0x44
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define AVS_MBOX_PV1 0x48
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define AVS_MBOX_MV1 0x4c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define AVS_MBOX_FREQUENCY 0x50
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* AVS Commands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define AVS_CMD_AVAILABLE 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define AVS_CMD_DISABLE 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define AVS_CMD_ENABLE 0x11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define AVS_CMD_S2_ENTER 0x12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define AVS_CMD_S2_EXIT 0x13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define AVS_CMD_BBM_ENTER 0x14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define AVS_CMD_BBM_EXIT 0x15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define AVS_CMD_S3_ENTER 0x16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define AVS_CMD_S3_EXIT 0x17
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define AVS_CMD_BALANCE 0x18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* PMAP and P-STATE commands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define AVS_CMD_GET_PMAP 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define AVS_CMD_SET_PMAP 0x31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define AVS_CMD_GET_PSTATE 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define AVS_CMD_SET_PSTATE 0x41
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* Different modes AVS supports (for GET_PMAP/SET_PMAP) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #define AVS_MODE_AVS 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define AVS_MODE_DFS 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define AVS_MODE_DVS 0x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #define AVS_MODE_DVFS 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * PMAP parameter p1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * unused:31-24, mdiv_p0:23-16, unused:15-14, pdiv:13-10 , ndiv_int:9-0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define NDIV_INT_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define NDIV_INT_MASK 0x3ff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) #define PDIV_SHIFT 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define PDIV_MASK 0xf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define MDIV_P0_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #define MDIV_P0_MASK 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * PMAP parameter p2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * mdiv_p4:31-24, mdiv_p3:23-16, mdiv_p2:15:8, mdiv_p1:7:0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define MDIV_P1_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define MDIV_P1_MASK 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define MDIV_P2_SHIFT 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define MDIV_P2_MASK 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define MDIV_P3_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define MDIV_P3_MASK 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #define MDIV_P4_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #define MDIV_P4_MASK 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* Different P-STATES AVS supports (for GET_PSTATE/SET_PSTATE) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #define AVS_PSTATE_P0 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #define AVS_PSTATE_P1 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) #define AVS_PSTATE_P2 0x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #define AVS_PSTATE_P3 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #define AVS_PSTATE_P4 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #define AVS_PSTATE_MAX AVS_PSTATE_P4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /* CPU L2 Interrupt Controller Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define AVS_CPU_L2_SET0 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define AVS_CPU_L2_INT_MASK BIT(31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /* AVS Command Status Values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define AVS_STATUS_CLEAR 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /* Command/notification accepted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #define AVS_STATUS_SUCCESS 0xf0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* Command/notification rejected */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #define AVS_STATUS_FAILURE 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* Invalid command/notification (unknown) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define AVS_STATUS_INVALID 0xf1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /* Non-AVS modes are not supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #define AVS_STATUS_NO_SUPP 0xf2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* Cannot set P-State until P-Map supplied */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define AVS_STATUS_NO_MAP 0xf3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* Cannot change P-Map after initial P-Map set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) #define AVS_STATUS_MAP_SET 0xf4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* Max AVS status; higher numbers are used for debugging */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) #define AVS_STATUS_MAX 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* Other AVS related constants */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #define AVS_LOOP_LIMIT 10000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #define AVS_TIMEOUT 300 /* in ms; expected completion is < 10ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #define AVS_FIRMWARE_MAGIC 0xa11600d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #define BRCM_AVS_CPUFREQ_PREFIX "brcmstb-avs"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #define BRCM_AVS_CPUFREQ_NAME BRCM_AVS_CPUFREQ_PREFIX "-cpufreq"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #define BRCM_AVS_CPU_DATA "brcm,avs-cpu-data-mem"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #define BRCM_AVS_CPU_INTR "brcm,avs-cpu-l2-intr"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #define BRCM_AVS_HOST_INTR "sw_intr"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) struct pmap {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) unsigned int mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) unsigned int p1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) unsigned int p2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) unsigned int state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) struct private_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) void __iomem *avs_intr_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) struct completion done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct semaphore sem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) struct pmap pmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) int host_irq;
^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) static void __iomem *__map_region(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) void __iomem *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) np = of_find_compatible_node(NULL, NULL, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) ptr = of_iomap(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static unsigned long wait_for_avs_command(struct private_data *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) unsigned long timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) unsigned long time_left = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /* Event driven, wait for the command interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (priv->host_irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return wait_for_completion_timeout(&priv->done,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) msecs_to_jiffies(timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /* Polling for command completion */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) time_left = timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) val = readl(priv->base + AVS_MBOX_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) } while (--timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return time_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) static int __issue_avs_command(struct private_data *priv, unsigned int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) unsigned int num_in, unsigned int num_out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) u32 args[])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) void __iomem *base = priv->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) unsigned long time_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) ret = down_interruptible(&priv->sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * Make sure no other command is currently running: cmd is 0 if AVS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * co-processor is idle. Due to the guard above, we should almost never
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * have to wait here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) for (i = 0, val = 1; val != 0 && i < AVS_LOOP_LIMIT; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) val = readl(base + AVS_MBOX_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) /* Give the caller a chance to retry if AVS is busy. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (i == AVS_LOOP_LIMIT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) ret = -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /* Clear status before we begin. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) writel(AVS_STATUS_CLEAR, base + AVS_MBOX_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /* Provide input parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) for (i = 0; i < num_in; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) writel(args[i], base + AVS_MBOX_PARAM(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /* Protect from spurious interrupts. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) reinit_completion(&priv->done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /* Now issue the command & tell firmware to wake up to process it. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) writel(cmd, base + AVS_MBOX_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) writel(AVS_CPU_L2_INT_MASK, priv->avs_intr_base + AVS_CPU_L2_SET0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) /* Wait for AVS co-processor to finish processing the command. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) time_left = wait_for_avs_command(priv, AVS_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * If the AVS status is not in the expected range, it means AVS didn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * complete our command in time, and we return an error. Also, if there
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * is no "time left", we timed out waiting for the interrupt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) val = readl(base + AVS_MBOX_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (time_left == 0 || val == 0 || val > AVS_STATUS_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dev_err(priv->dev, "AVS command %#x didn't complete in time\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) dev_err(priv->dev, " Time left: %u ms, AVS status: %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) jiffies_to_msecs(time_left), val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) ret = -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) goto out;
^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) /* Process returned values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) for (i = 0; i < num_out; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) args[i] = readl(base + AVS_MBOX_PARAM(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) /* Clear status to tell AVS co-processor we are done. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) writel(AVS_STATUS_CLEAR, base + AVS_MBOX_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* Convert firmware errors to errno's as much as possible. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) case AVS_STATUS_INVALID:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) case AVS_STATUS_NO_SUPP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) ret = -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) case AVS_STATUS_NO_MAP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) case AVS_STATUS_MAP_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) ret = -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) case AVS_STATUS_FAILURE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) ret = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) up(&priv->sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) static irqreturn_t irq_handler(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) struct private_data *priv = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) /* AVS command completed execution. Wake up __issue_avs_command(). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) complete(&priv->done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static char *brcm_avs_mode_to_string(unsigned int mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) switch (mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) case AVS_MODE_AVS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return "AVS";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) case AVS_MODE_DFS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return "DFS";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) case AVS_MODE_DVS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return "DVS";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) case AVS_MODE_DVFS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return "DVFS";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) static void brcm_avs_parse_p1(u32 p1, unsigned int *mdiv_p0, unsigned int *pdiv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) unsigned int *ndiv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) *mdiv_p0 = (p1 >> MDIV_P0_SHIFT) & MDIV_P0_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) *pdiv = (p1 >> PDIV_SHIFT) & PDIV_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) *ndiv = (p1 >> NDIV_INT_SHIFT) & NDIV_INT_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) static void brcm_avs_parse_p2(u32 p2, unsigned int *mdiv_p1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) unsigned int *mdiv_p2, unsigned int *mdiv_p3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) unsigned int *mdiv_p4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) *mdiv_p4 = (p2 >> MDIV_P4_SHIFT) & MDIV_P4_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) *mdiv_p3 = (p2 >> MDIV_P3_SHIFT) & MDIV_P3_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) *mdiv_p2 = (p2 >> MDIV_P2_SHIFT) & MDIV_P2_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) *mdiv_p1 = (p2 >> MDIV_P1_SHIFT) & MDIV_P1_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) static int brcm_avs_get_pmap(struct private_data *priv, struct pmap *pmap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) u32 args[AVS_MAX_CMD_ARGS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) ret = __issue_avs_command(priv, AVS_CMD_GET_PMAP, 0, 4, args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (ret || !pmap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) pmap->mode = args[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) pmap->p1 = args[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) pmap->p2 = args[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) pmap->state = args[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) static int brcm_avs_set_pmap(struct private_data *priv, struct pmap *pmap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) u32 args[AVS_MAX_CMD_ARGS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) args[0] = pmap->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) args[1] = pmap->p1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) args[2] = pmap->p2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) args[3] = pmap->state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return __issue_avs_command(priv, AVS_CMD_SET_PMAP, 4, 0, args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) static int brcm_avs_get_pstate(struct private_data *priv, unsigned int *pstate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) u32 args[AVS_MAX_CMD_ARGS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) ret = __issue_avs_command(priv, AVS_CMD_GET_PSTATE, 0, 1, args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) *pstate = args[0];
^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 brcm_avs_set_pstate(struct private_data *priv, unsigned int pstate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) u32 args[AVS_MAX_CMD_ARGS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) args[0] = pstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, 1, 0, args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) static u32 brcm_avs_get_voltage(void __iomem *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) return readl(base + AVS_MBOX_VOLTAGE1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) static u32 brcm_avs_get_frequency(void __iomem *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return readl(base + AVS_MBOX_FREQUENCY) * 1000; /* in kHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) * We determine which frequencies are supported by cycling through all P-states
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) * and reading back what frequency we are running at for each P-state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static struct cpufreq_frequency_table *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) brcm_avs_get_freq_table(struct device *dev, struct private_data *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) struct cpufreq_frequency_table *table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) unsigned int pstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* Remember P-state for later */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) ret = brcm_avs_get_pstate(priv, &pstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) table = devm_kcalloc(dev, AVS_PSTATE_MAX + 1, sizeof(*table),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) for (i = AVS_PSTATE_P0; i <= AVS_PSTATE_MAX; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) ret = brcm_avs_set_pstate(priv, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) table[i].frequency = brcm_avs_get_frequency(priv->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) table[i].driver_data = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) table[i].frequency = CPUFREQ_TABLE_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /* Restore P-state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) ret = brcm_avs_set_pstate(priv, pstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) return table;
^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) * To ensure the right firmware is running we need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) * - check the MAGIC matches what we expect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) * - brcm_avs_get_pmap() doesn't return -ENOTSUPP or -EINVAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * We need to set up our interrupt handling before calling brcm_avs_get_pmap()!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) static bool brcm_avs_is_firmware_loaded(struct private_data *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) u32 magic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) rc = brcm_avs_get_pmap(priv, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) magic = readl(priv->base + AVS_MBOX_MAGIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) (rc != -EINVAL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) struct private_data *priv = policy->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) cpufreq_cpu_put(policy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) return brcm_avs_get_frequency(priv->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static int brcm_avs_target_index(struct cpufreq_policy *policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) unsigned int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return brcm_avs_set_pstate(policy->driver_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) policy->freq_table[index].driver_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) static int brcm_avs_suspend(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) struct private_data *priv = policy->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) ret = brcm_avs_get_pmap(priv, &priv->pmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) * We can't use the P-state returned by brcm_avs_get_pmap(), since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * that's the initial P-state from when the P-map was downloaded to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) * AVS co-processor, not necessarily the P-state we are running at now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * So, we get the current P-state explicitly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) ret = brcm_avs_get_pstate(priv, &priv->pmap.state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) /* This is best effort. Nothing to do if it fails. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) (void)__issue_avs_command(priv, AVS_CMD_S2_ENTER, 0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) static int brcm_avs_resume(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) struct private_data *priv = policy->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) /* This is best effort. Nothing to do if it fails. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) (void)__issue_avs_command(priv, AVS_CMD_S2_EXIT, 0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) ret = brcm_avs_set_pmap(priv, &priv->pmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (ret == -EEXIST) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) struct platform_device *pdev = cpufreq_get_driver_data();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) dev_warn(dev, "PMAP was already set\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) * All initialization code that we only want to execute once goes here. Setup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) * code that can be re-tried on every core (if it failed before) can go into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) * brcm_avs_cpufreq_init().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) static int brcm_avs_prepare_init(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) struct private_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) priv->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) sema_init(&priv->sem, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) init_completion(&priv->done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) platform_set_drvdata(pdev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) priv->base = __map_region(BRCM_AVS_CPU_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) if (!priv->base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) dev_err(dev, "Couldn't find property %s in device tree.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) BRCM_AVS_CPU_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) priv->avs_intr_base = __map_region(BRCM_AVS_CPU_INTR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (!priv->avs_intr_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) dev_err(dev, "Couldn't find property %s in device tree.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) BRCM_AVS_CPU_INTR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) goto unmap_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) priv->host_irq = platform_get_irq_byname(pdev, BRCM_AVS_HOST_INTR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) ret = devm_request_irq(dev, priv->host_irq, irq_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) IRQF_TRIGGER_RISING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) BRCM_AVS_HOST_INTR, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (ret && priv->host_irq >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) dev_err(dev, "IRQ request failed: %s (%d) -- %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) BRCM_AVS_HOST_INTR, priv->host_irq, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) goto unmap_intr_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (brcm_avs_is_firmware_loaded(priv))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) dev_err(dev, "AVS firmware is not loaded or doesn't support DVFS\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) unmap_intr_base:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) iounmap(priv->avs_intr_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) unmap_base:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) iounmap(priv->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) static void brcm_avs_prepare_uninit(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) struct private_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) priv = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) iounmap(priv->avs_intr_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) iounmap(priv->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) static int brcm_avs_cpufreq_init(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) struct cpufreq_frequency_table *freq_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) struct private_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) pdev = cpufreq_get_driver_data();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) priv = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) policy->driver_data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) freq_table = brcm_avs_get_freq_table(dev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (IS_ERR(freq_table)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) ret = PTR_ERR(freq_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) dev_err(dev, "Couldn't determine frequency table (%d).\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) policy->freq_table = freq_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) /* All cores share the same clock and thus the same policy. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) cpumask_setall(policy->cpus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) ret = __issue_avs_command(priv, AVS_CMD_ENABLE, 0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) unsigned int pstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) ret = brcm_avs_get_pstate(priv, &pstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) policy->cur = freq_table[pstate].frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) dev_info(dev, "registered\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) dev_err(dev, "couldn't initialize driver (%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) static ssize_t show_brcm_avs_pstate(struct cpufreq_policy *policy, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) struct private_data *priv = policy->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) unsigned int pstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (brcm_avs_get_pstate(priv, &pstate))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return sprintf(buf, "<unknown>\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return sprintf(buf, "%u\n", pstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) static ssize_t show_brcm_avs_mode(struct cpufreq_policy *policy, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) struct private_data *priv = policy->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) struct pmap pmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (brcm_avs_get_pmap(priv, &pmap))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) return sprintf(buf, "<unknown>\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) return sprintf(buf, "%s %u\n", brcm_avs_mode_to_string(pmap.mode),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) pmap.mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static ssize_t show_brcm_avs_pmap(struct cpufreq_policy *policy, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) unsigned int mdiv_p0, mdiv_p1, mdiv_p2, mdiv_p3, mdiv_p4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) struct private_data *priv = policy->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) unsigned int ndiv, pdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) struct pmap pmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) if (brcm_avs_get_pmap(priv, &pmap))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) return sprintf(buf, "<unknown>\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) brcm_avs_parse_p1(pmap.p1, &mdiv_p0, &pdiv, &ndiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) brcm_avs_parse_p2(pmap.p2, &mdiv_p1, &mdiv_p2, &mdiv_p3, &mdiv_p4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return sprintf(buf, "0x%08x 0x%08x %u %u %u %u %u %u %u %u %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) pmap.p1, pmap.p2, ndiv, pdiv, mdiv_p0, mdiv_p1, mdiv_p2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) mdiv_p3, mdiv_p4, pmap.mode, pmap.state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) static ssize_t show_brcm_avs_voltage(struct cpufreq_policy *policy, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) struct private_data *priv = policy->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) return sprintf(buf, "0x%08x\n", brcm_avs_get_voltage(priv->base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) struct private_data *priv = policy->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) return sprintf(buf, "0x%08x\n", brcm_avs_get_frequency(priv->base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) cpufreq_freq_attr_ro(brcm_avs_pstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) cpufreq_freq_attr_ro(brcm_avs_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) cpufreq_freq_attr_ro(brcm_avs_pmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) cpufreq_freq_attr_ro(brcm_avs_voltage);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) cpufreq_freq_attr_ro(brcm_avs_frequency);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) static struct freq_attr *brcm_avs_cpufreq_attr[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) &cpufreq_freq_attr_scaling_available_freqs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) &brcm_avs_pstate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) &brcm_avs_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) &brcm_avs_pmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) &brcm_avs_voltage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) &brcm_avs_frequency,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) static struct cpufreq_driver brcm_avs_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) .verify = cpufreq_generic_frequency_table_verify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) .target_index = brcm_avs_target_index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) .get = brcm_avs_cpufreq_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) .suspend = brcm_avs_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) .resume = brcm_avs_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) .init = brcm_avs_cpufreq_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) .attr = brcm_avs_cpufreq_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) .name = BRCM_AVS_CPUFREQ_PREFIX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) static int brcm_avs_cpufreq_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) ret = brcm_avs_prepare_init(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) brcm_avs_driver.driver_data = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) ret = cpufreq_register_driver(&brcm_avs_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) brcm_avs_prepare_uninit(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) static int brcm_avs_cpufreq_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) ret = cpufreq_unregister_driver(&brcm_avs_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) WARN_ON(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) brcm_avs_prepare_uninit(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) static const struct of_device_id brcm_avs_cpufreq_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) { .compatible = BRCM_AVS_CPU_DATA },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) MODULE_DEVICE_TABLE(of, brcm_avs_cpufreq_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) static struct platform_driver brcm_avs_cpufreq_platdrv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) .name = BRCM_AVS_CPUFREQ_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) .of_match_table = brcm_avs_cpufreq_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) .probe = brcm_avs_cpufreq_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) .remove = brcm_avs_cpufreq_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) module_platform_driver(brcm_avs_cpufreq_platdrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) MODULE_AUTHOR("Markus Mayer <mmayer@broadcom.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) MODULE_DESCRIPTION("CPUfreq driver for Broadcom STB AVS");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) MODULE_LICENSE("GPL");