Link: https://lore.kernel.org/r/20260217200002.683975158@linuxfoundation.org Tested-by: Florian Fainelli <florian.fainelli@broadcom.com> Tested-by: Takeshi Ogasawara <takeshi.ogasawara@futuring-girl.com> Tested-by: Peter Schneider <pschneider1968@googlemail.com> Tested-by: Jon Hunter <jonathanh@nvidia.com> Tested-by: Salvatore Bonaccorso <carnil@debian.org> Tested-by: Brett A C Sheffield <bacs@librecast.net> Tested-by: Mark Brown <broonie@kernel.org> Tested-by: Luna Jernberg <droidbittin@gmail.com> Tested-by: Ronald Warsow <rwarsow@gmx.de> Tested-by: Justin M. Forbes <jforbes@fedoraproject.org> Tested-by: Ron Economos <re@w6rz.net> Tested-by: Miguel Ojeda <ojeda@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
447 lines
16 KiB
C
447 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright 2025 Linaro Ltd.
|
|
*
|
|
* GS101 PMU (Power Management Unit) support
|
|
*/
|
|
|
|
#include <linux/arm-smccc.h>
|
|
#include <linux/array_size.h>
|
|
#include <linux/soc/samsung/exynos-pmu.h>
|
|
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
|
#include <linux/regmap.h>
|
|
|
|
#include "exynos-pmu.h"
|
|
|
|
#define PMUALIVE_MASK GENMASK(13, 0)
|
|
#define TENSOR_SET_BITS (BIT(15) | BIT(14))
|
|
#define TENSOR_CLR_BITS BIT(15)
|
|
#define TENSOR_SMC_PMU_SEC_REG 0x82000504
|
|
#define TENSOR_PMUREG_READ 0
|
|
#define TENSOR_PMUREG_WRITE 1
|
|
#define TENSOR_PMUREG_RMW 2
|
|
|
|
static const struct regmap_range gs101_pmu_registers[] = {
|
|
regmap_reg_range(GS101_OM_STAT, GS101_SYSTEM_INFO),
|
|
regmap_reg_range(GS101_IDLE_IP(0), GS101_IDLE_IP_MASK(3)),
|
|
regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(0),
|
|
GS101_PPMPURAM_INFORM_SCL_CH(3)),
|
|
regmap_reg_range(GS101_INFORM0, GS101_SYSIP_DAT(0)),
|
|
/* skip SYSIP_DAT1 SYSIP_DAT2 */
|
|
regmap_reg_range(GS101_SYSIP_DAT(3), GS101_PWR_HOLD_SW_TRIP),
|
|
regmap_reg_range(GS101_GSA_INFORM(0), GS101_GSA_INFORM(1)),
|
|
regmap_reg_range(GS101_INFORM4, GS101_IROM_INFORM),
|
|
regmap_reg_range(GS101_IROM_CPU_INFORM(0), GS101_IROM_CPU_INFORM(7)),
|
|
regmap_reg_range(GS101_PMU_SPARE(0), GS101_PMU_SPARE(3)),
|
|
/* skip most IROM_xxx registers */
|
|
regmap_reg_range(GS101_DREX_CALIBRATION(0), GS101_DREX_CALIBRATION(7)),
|
|
|
|
#define CLUSTER_CPU_RANGE(cl, cpu) \
|
|
regmap_reg_range(GS101_CLUSTER_CPU_CONFIGURATION(cl, cpu), \
|
|
GS101_CLUSTER_CPU_OPTION(cl, cpu)), \
|
|
regmap_reg_range(GS101_CLUSTER_CPU_OUT(cl, cpu), \
|
|
GS101_CLUSTER_CPU_IN(cl, cpu)), \
|
|
regmap_reg_range(GS101_CLUSTER_CPU_INT_IN(cl, cpu), \
|
|
GS101_CLUSTER_CPU_INT_DIR(cl, cpu))
|
|
|
|
/* cluster 0..2 and cpu 0..4 or 0..1 */
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 0),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 1),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 2),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 3),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER1_OFFSET, 0),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER1_OFFSET, 1),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER2_OFFSET, 0),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER2_OFFSET, 1),
|
|
#undef CLUSTER_CPU_RANGE
|
|
|
|
#define CLUSTER_NONCPU_RANGE(cl) \
|
|
regmap_reg_range(GS101_CLUSTER_NONCPU_CONFIGURATION(cl), \
|
|
GS101_CLUSTER_NONCPU_OPTION(cl)), \
|
|
regmap_reg_range(GS101_CLUSTER_NONCPU_OUT(cl), \
|
|
GS101_CLUSTER_NONCPU_IN(cl)), \
|
|
regmap_reg_range(GS101_CLUSTER_NONCPU_INT_IN(cl), \
|
|
GS101_CLUSTER_NONCPU_INT_DIR(cl)), \
|
|
regmap_reg_range(GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_OUT(cl), \
|
|
GS101_CLUSTER_NONCPU_DUALRAIL_POS_OUT(cl)), \
|
|
regmap_reg_range(GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_IN(cl), \
|
|
GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_IN(cl))
|
|
|
|
CLUSTER_NONCPU_RANGE(0),
|
|
regmap_reg_range(GS101_CLUSTER0_NONCPU_DSU_PCH,
|
|
GS101_CLUSTER0_NONCPU_DSU_PCH),
|
|
CLUSTER_NONCPU_RANGE(1),
|
|
CLUSTER_NONCPU_RANGE(2),
|
|
#undef CLUSTER_NONCPU_RANGE
|
|
|
|
#define SUBBLK_RANGE(blk) \
|
|
regmap_reg_range(GS101_SUBBLK_CONFIGURATION(blk), \
|
|
GS101_SUBBLK_CTRL(blk)), \
|
|
regmap_reg_range(GS101_SUBBLK_OUT(blk), GS101_SUBBLK_IN(blk)), \
|
|
regmap_reg_range(GS101_SUBBLK_INT_IN(blk), \
|
|
GS101_SUBBLK_INT_DIR(blk)), \
|
|
regmap_reg_range(GS101_SUBBLK_MEMORY_OUT(blk), \
|
|
GS101_SUBBLK_MEMORY_IN(blk))
|
|
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_ALIVE),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_AOC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_APM),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CMU),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS2),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CORE),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EH),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL2),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G3D),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EMBEDDED_CPUCL0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EMBEDDED_G3D),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI2),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DPU),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DISP),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G2D),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MFC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CSIS),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PDP),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DNS),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G3AA),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_IPP),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_ITP),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MCSC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_GDC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_TNR),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BO),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_TPU),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF2),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF3),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MISC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PERIC0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PERIC1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_S2D),
|
|
#undef SUBBLK_RANGE
|
|
|
|
#define SUBBLK_CPU_RANGE(blk) \
|
|
regmap_reg_range(GS101_SUBBLK_CPU_CONFIGURATION(blk), \
|
|
GS101_SUBBLK_CPU_OPTION(blk)), \
|
|
regmap_reg_range(GS101_SUBBLK_CPU_OUT(blk), \
|
|
GS101_SUBBLK_CPU_IN(blk)), \
|
|
regmap_reg_range(GS101_SUBBLK_CPU_INT_IN(blk), \
|
|
GS101_SUBBLK_CPU_INT_DIR(blk))
|
|
|
|
SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_APM),
|
|
SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_DBGCORE),
|
|
SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_SSS),
|
|
#undef SUBBLK_CPU_RANGE
|
|
|
|
regmap_reg_range(GS101_MIF_CONFIGURATION, GS101_MIF_CTRL),
|
|
regmap_reg_range(GS101_MIF_OUT, GS101_MIF_IN),
|
|
regmap_reg_range(GS101_MIF_INT_IN, GS101_MIF_INT_DIR),
|
|
regmap_reg_range(GS101_TOP_CONFIGURATION, GS101_TOP_OPTION),
|
|
regmap_reg_range(GS101_TOP_OUT, GS101_TOP_IN),
|
|
regmap_reg_range(GS101_TOP_INT_IN, GS101_WAKEUP2_STAT),
|
|
regmap_reg_range(GS101_WAKEUP2_INT_IN, GS101_WAKEUP2_INT_DIR),
|
|
regmap_reg_range(GS101_SYSTEM_CONFIGURATION, GS101_USER_DEFINED_OUT),
|
|
regmap_reg_range(GS101_SYSTEM_OUT, GS101_SYSTEM_IN),
|
|
regmap_reg_range(GS101_SYSTEM_INT_IN, GS101_EINT_WAKEUP_MASK3),
|
|
regmap_reg_range(GS101_USER_DEFINED_INT_IN, GS101_SCAN2DRAM_INT_DIR),
|
|
/* skip HCU_START */
|
|
regmap_reg_range(GS101_CUSTOM_OUT, GS101_CUSTOM_IN),
|
|
regmap_reg_range(GS101_CUSTOM_INT_IN, GS101_CUSTOM_INT_DIR),
|
|
regmap_reg_range(GS101_ACK_LAST_CPU, GS101_HCU_R(3)),
|
|
regmap_reg_range(GS101_HCU_SP, GS101_HCU_PC),
|
|
/* skip PMU_RAM_CTRL */
|
|
regmap_reg_range(GS101_APM_HCU_CTRL, GS101_APM_HCU_CTRL),
|
|
regmap_reg_range(GS101_APM_NMI_ENABLE, GS101_RST_STAT_PMU),
|
|
regmap_reg_range(GS101_HPM_INT_IN, GS101_BOOT_STAT),
|
|
regmap_reg_range(GS101_PMLINK_OUT, GS101_PMLINK_AOC_CTRL),
|
|
regmap_reg_range(GS101_TCXO_BUF_CTRL, GS101_ADD_CTRL),
|
|
regmap_reg_range(GS101_HCU_TIMEOUT_RESET, GS101_HCU_TIMEOUT_SCAN2DRAM),
|
|
regmap_reg_range(GS101_TIMER(0), GS101_TIMER(3)),
|
|
regmap_reg_range(GS101_PPC_MIF(0), GS101_PPC_EH),
|
|
/* PPC_OFFSET, skip PPC_CPUCL1_0 PPC_CPUCL1_1 */
|
|
regmap_reg_range(GS101_EXT_REGULATOR_MIF_DURATION, GS101_TCXO_DURATION),
|
|
regmap_reg_range(GS101_BURNIN_CTRL, GS101_TMU_SUB_TRIP),
|
|
regmap_reg_range(GS101_MEMORY_CEN, GS101_MEMORY_SMX_FEEDBACK),
|
|
regmap_reg_range(GS101_SLC_PCH_CHANNEL, GS101_SLC_PCH_CB),
|
|
regmap_reg_range(GS101_FORCE_NOMC, GS101_FORCE_NOMC),
|
|
regmap_reg_range(GS101_FORCE_BOOST, GS101_PMLINK_SLC_BUSY),
|
|
regmap_reg_range(GS101_BOOTSYNC_OUT, GS101_CTRL_SECJTAG_ALIVE),
|
|
regmap_reg_range(GS101_CTRL_DIV_PLL_ALV_DIVLOW, GS101_CTRL_CLKDIV__CLKRTC),
|
|
regmap_reg_range(GS101_CTRL_SOC32K, GS101_CTRL_SBU_SW_EN),
|
|
regmap_reg_range(GS101_PAD_CTRL_CLKOUT0, GS101_PAD_CTRL_WRESETO_n),
|
|
regmap_reg_range(GS101_PHY_CTRL_USB20, GS101_PHY_CTRL_UFS),
|
|
};
|
|
|
|
static const struct regmap_range gs101_pmu_ro_registers[] = {
|
|
regmap_reg_range(GS101_OM_STAT, GS101_VERSION),
|
|
regmap_reg_range(GS101_OTP_STATUS, GS101_OTP_STATUS),
|
|
|
|
regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(0),
|
|
GS101_PPMPURAM_STATE_SLC_CH(0)),
|
|
regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(1),
|
|
GS101_PPMPURAM_STATE_SLC_CH(1)),
|
|
regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(2),
|
|
GS101_PPMPURAM_STATE_SLC_CH(2)),
|
|
regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(3),
|
|
GS101_PPMPURAM_STATE_SLC_CH(3)),
|
|
|
|
#define CLUSTER_CPU_RANGE(cl, cpu) \
|
|
regmap_reg_range(GS101_CLUSTER_CPU_IN(cl, cpu), \
|
|
GS101_CLUSTER_CPU_IN(cl, cpu)), \
|
|
regmap_reg_range(GS101_CLUSTER_CPU_INT_IN(cl, cpu), \
|
|
GS101_CLUSTER_CPU_INT_IN(cl, cpu))
|
|
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 0),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 1),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 2),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 3),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER1_OFFSET, 0),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER1_OFFSET, 1),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER2_OFFSET, 0),
|
|
CLUSTER_CPU_RANGE(GS101_CLUSTER2_OFFSET, 1),
|
|
#undef CLUSTER_CPU_RANGE
|
|
|
|
#define CLUSTER_NONCPU_RANGE(cl) \
|
|
regmap_reg_range(GS101_CLUSTER_NONCPU_IN(cl), \
|
|
GS101_CLUSTER_NONCPU_IN(cl)), \
|
|
regmap_reg_range(GS101_CLUSTER_NONCPU_INT_IN(cl), \
|
|
GS101_CLUSTER_NONCPU_INT_IN(cl)), \
|
|
regmap_reg_range(GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_IN(cl), \
|
|
GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_IN(cl))
|
|
|
|
CLUSTER_NONCPU_RANGE(0),
|
|
CLUSTER_NONCPU_RANGE(1),
|
|
CLUSTER_NONCPU_RANGE(2),
|
|
regmap_reg_range(GS101_CLUSTER_NONCPU_INT_EN(2),
|
|
GS101_CLUSTER_NONCPU_INT_DIR(2)),
|
|
#undef CLUSTER_NONCPU_RANGE
|
|
|
|
#define SUBBLK_RANGE(blk) \
|
|
regmap_reg_range(GS101_SUBBLK_IN(blk), GS101_SUBBLK_IN(blk)), \
|
|
regmap_reg_range(GS101_SUBBLK_INT_IN(blk), \
|
|
GS101_SUBBLK_INT_IN(blk)), \
|
|
regmap_reg_range(GS101_SUBBLK_MEMORY_IN(blk), \
|
|
GS101_SUBBLK_MEMORY_IN(blk))
|
|
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_ALIVE),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_AOC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_APM),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CMU),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS2),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CORE),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EH),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL2),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G3D),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EMBEDDED_CPUCL0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EMBEDDED_G3D),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI2),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DPU),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DISP),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G2D),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MFC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CSIS),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PDP),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DNS),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G3AA),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_IPP),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_ITP),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MCSC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_GDC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_TNR),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BO),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_TPU),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF2),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF3),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MISC),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PERIC0),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PERIC1),
|
|
SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_S2D),
|
|
#undef SUBBLK_RANGE
|
|
|
|
#define SUBBLK_CPU_RANGE(blk) \
|
|
regmap_reg_range(GS101_SUBBLK_CPU_IN(blk), \
|
|
GS101_SUBBLK_CPU_IN(blk)), \
|
|
regmap_reg_range(GS101_SUBBLK_CPU_INT_IN(blk), \
|
|
GS101_SUBBLK_CPU_INT_IN(blk))
|
|
|
|
SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_APM),
|
|
SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_DBGCORE),
|
|
SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_SSS),
|
|
#undef SUBBLK_CPU_RANGE
|
|
|
|
regmap_reg_range(GS101_MIF_CONFIGURATION, GS101_MIF_CONFIGURATION),
|
|
regmap_reg_range(GS101_MIF_IN, GS101_MIF_IN),
|
|
regmap_reg_range(GS101_MIF_INT_IN, GS101_MIF_INT_IN),
|
|
regmap_reg_range(GS101_TOP_IN, GS101_TOP_IN),
|
|
regmap_reg_range(GS101_TOP_INT_IN, GS101_TOP_INT_IN),
|
|
regmap_reg_range(GS101_WAKEUP2_INT_IN, GS101_WAKEUP2_INT_IN),
|
|
regmap_reg_range(GS101_SYSTEM_IN, GS101_SYSTEM_IN),
|
|
regmap_reg_range(GS101_SYSTEM_INT_IN, GS101_SYSTEM_INT_IN),
|
|
regmap_reg_range(GS101_EINT_INT_IN, GS101_EINT_INT_IN),
|
|
regmap_reg_range(GS101_EINT2_INT_IN, GS101_EINT2_INT_IN),
|
|
regmap_reg_range(GS101_EINT3_INT_IN, GS101_EINT3_INT_IN),
|
|
regmap_reg_range(GS101_USER_DEFINED_INT_IN, GS101_USER_DEFINED_INT_IN),
|
|
regmap_reg_range(GS101_SCAN2DRAM_INT_IN, GS101_SCAN2DRAM_INT_IN),
|
|
regmap_reg_range(GS101_CUSTOM_IN, GS101_CUSTOM_IN),
|
|
regmap_reg_range(GS101_CUSTOM_INT_IN, GS101_CUSTOM_INT_IN),
|
|
regmap_reg_range(GS101_HCU_R(0), GS101_HCU_R(3)),
|
|
regmap_reg_range(GS101_HCU_SP, GS101_HCU_PC),
|
|
regmap_reg_range(GS101_NMI_SRC_IN, GS101_NMI_SRC_IN),
|
|
regmap_reg_range(GS101_HPM_INT_IN, GS101_HPM_INT_IN),
|
|
regmap_reg_range(GS101_MEMORY_PGEN_FEEDBACK, GS101_MEMORY_PGEN_FEEDBACK),
|
|
regmap_reg_range(GS101_MEMORY_SMX_FEEDBACK, GS101_MEMORY_SMX_FEEDBACK),
|
|
regmap_reg_range(GS101_PMLINK_SLC_ACK, GS101_PMLINK_SLC_BUSY),
|
|
regmap_reg_range(GS101_BOOTSYNC_IN, GS101_BOOTSYNC_IN),
|
|
regmap_reg_range(GS101_SCAN_READY_IN, GS101_SCAN_READY_IN),
|
|
regmap_reg_range(GS101_CTRL_PLL_ALV_LOCK, GS101_CTRL_PLL_ALV_LOCK),
|
|
};
|
|
|
|
static const struct regmap_access_table gs101_pmu_rd_table = {
|
|
.yes_ranges = gs101_pmu_registers,
|
|
.n_yes_ranges = ARRAY_SIZE(gs101_pmu_registers),
|
|
};
|
|
|
|
static const struct regmap_access_table gs101_pmu_wr_table = {
|
|
.yes_ranges = gs101_pmu_registers,
|
|
.n_yes_ranges = ARRAY_SIZE(gs101_pmu_registers),
|
|
.no_ranges = gs101_pmu_ro_registers,
|
|
.n_no_ranges = ARRAY_SIZE(gs101_pmu_ro_registers),
|
|
};
|
|
|
|
const struct exynos_pmu_data gs101_pmu_data = {
|
|
.pmu_secure = true,
|
|
.pmu_cpuhp = true,
|
|
.rd_table = &gs101_pmu_rd_table,
|
|
.wr_table = &gs101_pmu_wr_table,
|
|
};
|
|
|
|
/*
|
|
* Tensor SoCs are configured so that PMU_ALIVE registers can only be written
|
|
* from EL3, but are still read accessible. As Linux needs to write some of
|
|
* these registers, the following functions are provided and exposed via
|
|
* regmap.
|
|
*
|
|
* Note: This SMC interface is known to be implemented on gs101 and derivative
|
|
* SoCs.
|
|
*/
|
|
|
|
/* Write to a protected PMU register. */
|
|
int tensor_sec_reg_write(void *context, unsigned int reg, unsigned int val)
|
|
{
|
|
struct arm_smccc_res res;
|
|
unsigned long pmu_base = (unsigned long)context;
|
|
|
|
arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
|
|
TENSOR_PMUREG_WRITE, val, 0, 0, 0, 0, &res);
|
|
|
|
/* returns -EINVAL if access isn't allowed or 0 */
|
|
if (res.a0)
|
|
pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
|
|
|
|
return (int)res.a0;
|
|
}
|
|
|
|
/* Read/Modify/Write a protected PMU register. */
|
|
static int tensor_sec_reg_rmw(void *context, unsigned int reg,
|
|
unsigned int mask, unsigned int val)
|
|
{
|
|
struct arm_smccc_res res;
|
|
unsigned long pmu_base = (unsigned long)context;
|
|
|
|
arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
|
|
TENSOR_PMUREG_RMW, mask, val, 0, 0, 0, &res);
|
|
|
|
/* returns -EINVAL if access isn't allowed or 0 */
|
|
if (res.a0)
|
|
pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
|
|
|
|
return (int)res.a0;
|
|
}
|
|
|
|
/*
|
|
* Read a protected PMU register. All PMU registers can be read by Linux.
|
|
* Note: The SMC read register is not used, as only registers that can be
|
|
* written are readable via SMC.
|
|
*/
|
|
int tensor_sec_reg_read(void *context, unsigned int reg, unsigned int *val)
|
|
{
|
|
*val = pmu_raw_readl(reg);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* For SoCs that have set/clear bit hardware this function can be used when
|
|
* the PMU register will be accessed by multiple masters.
|
|
*
|
|
* For example, to set bits 13:8 in PMU reg offset 0x3e80
|
|
* tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00);
|
|
*
|
|
* Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80
|
|
* tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00);
|
|
*/
|
|
static int tensor_set_bits_atomic(void *context, unsigned int offset, u32 val,
|
|
u32 mask)
|
|
{
|
|
int ret;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
if (!(mask & BIT(i)))
|
|
continue;
|
|
|
|
offset &= ~TENSOR_SET_BITS;
|
|
|
|
if (val & BIT(i))
|
|
offset |= TENSOR_SET_BITS;
|
|
else
|
|
offset |= TENSOR_CLR_BITS;
|
|
|
|
ret = tensor_sec_reg_write(context, offset, i);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static bool tensor_is_atomic(unsigned int reg)
|
|
{
|
|
/*
|
|
* Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF)
|
|
* as the target registers can be accessed by multiple masters. SFRs
|
|
* that don't support atomic are added to the switch statement below.
|
|
*/
|
|
if (reg > PMUALIVE_MASK)
|
|
return false;
|
|
|
|
switch (reg) {
|
|
case GS101_SYSIP_DAT(0):
|
|
case GS101_SYSTEM_CONFIGURATION:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
int tensor_sec_update_bits(void *context, unsigned int reg, unsigned int mask,
|
|
unsigned int val)
|
|
{
|
|
if (!tensor_is_atomic(reg))
|
|
return tensor_sec_reg_rmw(context, reg, mask, val);
|
|
|
|
return tensor_set_bits_atomic(context, reg, val, mask);
|
|
}
|