// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include #include "dvfsrc-debug.h" #include "dvfsrc-common.h" #if IS_ENABLED(CONFIG_MTK_DRAMC_LEGACY) #include #endif enum dvfsrc_regs { DVFSRC_BASIC_CONTROL, DVFSRC_SW_REQ1, DVFSRC_INT, DVFSRC_INT_EN, DVFSRC_SW_BW_0, DVFSRC_VCORE_REQUEST, DVFSRC_LEVEL, DVFSRC_LAST, DVFSRC_MD_SCENARIO, DVFSRC_RECORD_0, DVFSRC_RSRV_0, }; static const int mt6761_regs[] = { [DVFSRC_BASIC_CONTROL] = 0x0, [DVFSRC_SW_REQ1] = 0x4, [DVFSRC_INT] = 0x98, [DVFSRC_INT_EN] = 0x9C, [DVFSRC_SW_BW_0] = 0x160, [DVFSRC_VCORE_REQUEST] = 0x48, [DVFSRC_LEVEL] = 0xDC, [DVFSRC_LAST] = 0x308, [DVFSRC_MD_SCENARIO] = 0x310, [DVFSRC_RECORD_0] = 0x400, [DVFSRC_RSRV_0] = 0x600, }; enum dvfsrc_spm_regs { SPM_POWERON_CONFIG_EN, SPM_PCM_IM_PTR, SPM_MD2SPM_DVFS_CON, SPM_SW_FLAG, SPM_SW_RSV_9, SPM_DVFS_EVENT_STA, SPM_DVFS_LEVEL, SPM_DFS_LEVEL, SPM_DVS_LEVEL, SPM_DVFS_CMD0, SPM_DVFS_CMD1, SPM_DVFS_CMD2, SPM_DVFS_CMD3, SPM_DVFS_CMD4, }; static const int mt6761_spm_regs[] = { [SPM_POWERON_CONFIG_EN] = 0x0, [SPM_PCM_IM_PTR] = 0x020, [SPM_MD2SPM_DVFS_CON] = 0x43C, [SPM_SW_FLAG] = 0x600, [SPM_SW_RSV_9] = 0x658, [SPM_DVFS_EVENT_STA] = 0x69C, [SPM_DVFS_LEVEL] = 0x6A4, [SPM_DFS_LEVEL] = 0x6B0, [SPM_DVS_LEVEL] = 0x6B4, [SPM_DVFS_CMD0] = 0x710, [SPM_DVFS_CMD1] = 0x714, [SPM_DVFS_CMD2] = 0x718, [SPM_DVFS_CMD3] = 0x71C, [SPM_DVFS_CMD4] = 0x720, }; #define DVFSRC_TARGET_LEVEL(x) (((x) >> 0) & 0x0000ffff) #define DVFSRC_CURRENT_LEVEL(x) (((x) >> 16) & 0x0000ffff) static u32 dvfsrc_read(struct mtk_dvfsrc *dvfs, u32 reg, u32 offset) { return readl(dvfs->regs + dvfs->dvd->config->regs[reg] + offset); } static u32 spm_read(struct mtk_dvfsrc *dvfs, u32 reg) { return readl(dvfs->spm_regs + dvfs->dvd->config->spm_regs[reg]); } #if defined(CONFIG_MACH_MT6761) || defined(CONFIG_MACH_MT6765) #define MTK_SIP_VCOREFS_DVFS_HOPPING_STATE 20 static int dvfsrc_dvfs_hopping_status(void) { struct arm_smccc_res ares; arm_smccc_smc(MTK_SIP_VCOREFS_CONTROL, MTK_SIP_VCOREFS_DVFS_HOPPING_STATE, 0, 0, 0, 0, 0, 0, &ares); if (!ares.a0) return ares.a1; return 0; } #endif #if defined(CONFIG_MACH_MT6761) || defined(CONFIG_MACH_MT6765) #define MTK_SIP_VCOREFS_GET_EFUSE 18 static int dvfsrc_dvfs_get_efuse_data(u32 idx) { struct arm_smccc_res ares; arm_smccc_smc(MTK_SIP_VCOREFS_CONTROL, MTK_SIP_VCOREFS_GET_EFUSE, idx, 0, 0, 0, 0, 0, &ares); if (!ares.a0) return ares.a1; return 0; } #endif static char *dvfsrc_dump_info(struct mtk_dvfsrc *dvfsrc, char *p, u32 size) { int vcore_uv = 0; char *buff_end = p + size; if (dvfsrc->vcore_power) vcore_uv = regulator_get_voltage(dvfsrc->vcore_power); p += snprintf(p, buff_end - p, "%-10s: %-8u uv\n", "Vcore", vcore_uv); #if IS_ENABLED(CONFIG_MTK_DRAMC_LEGACY) p += snprintf(p, buff_end - p, "%-10s: %-8u khz\n", "DDR", get_dram_data_rate() * 1000); #endif #if defined(CONFIG_MACH_MT6761) || defined(CONFIG_MACH_MT6765) p += snprintf(p, buff_end - p, "%-10s: %d\n", "GPS_HOPPING", dvfsrc_dvfs_hopping_status()); #endif #if defined(CONFIG_MACH_MT6761) p += snprintf(p, buff_end - p, "%-10s: %08x\n", "EFUSE_0", dvfsrc_dvfs_get_efuse_data(0)); #endif #if defined(CONFIG_MACH_MT6765) p += snprintf(p, buff_end - p, "%-10s: %08x\n", "PTPOD_0", dvfsrc_dvfs_get_efuse_data(0)); p += snprintf(p, buff_end - p, "%-10s: %08x\n", "PTPOD_10", dvfsrc_dvfs_get_efuse_data(1)); p += snprintf(p, buff_end - p, "%-10s: %08x\n", "INFO2", dvfsrc_dvfs_get_efuse_data(2)); #endif p += snprintf(p, buff_end - p, "\n"); return p; } static char *dvfsrc_dump_record(struct mtk_dvfsrc *dvfsrc, char *p, u32 size) { int i, rec_offset, offset; char *buff_end = p + size; p += sprintf(p, "%-17s: 0x%08x\n", "DVFSRC_LAST", dvfsrc_read(dvfsrc, DVFSRC_LAST, 0)); rec_offset = 0xC; for (i = 0; i < 8; i++) { offset = i * rec_offset; p += snprintf(p, buff_end - p, "[%d]%-14s: %08x,%08x,%08x\n", i, "DVFSRC_REC 0~2", dvfsrc_read(dvfsrc, DVFSRC_RECORD_0, offset + 0x0), dvfsrc_read(dvfsrc, DVFSRC_RECORD_0, offset + 0x4), dvfsrc_read(dvfsrc, DVFSRC_RECORD_0, offset + 0x8)); } p += snprintf(p, buff_end - p, "\n"); return p; } static char *dvfsrc_dump_reg(struct mtk_dvfsrc *dvfsrc, char *p, u32 size) { char *buff_end = p + size; p += snprintf(p, buff_end - p, "%-16s: 0x%08x\n", "BASIC_CONTROL", dvfsrc_read(dvfsrc, DVFSRC_BASIC_CONTROL, 0x0)); p += snprintf(p, buff_end - p, "%-16s: %08x, %08x\n", "SW_REQ 1~2", dvfsrc_read(dvfsrc, DVFSRC_SW_REQ1, 0x0), dvfsrc_read(dvfsrc, DVFSRC_SW_REQ1, 0x4)); p += snprintf(p, buff_end - p, "%-16s: %d, %d, %d, %d, %d\n", "SW_BW_0~4", dvfsrc_read(dvfsrc, DVFSRC_SW_BW_0, 0x0), dvfsrc_read(dvfsrc, DVFSRC_SW_BW_0, 0x4), dvfsrc_read(dvfsrc, DVFSRC_SW_BW_0, 0x8), dvfsrc_read(dvfsrc, DVFSRC_SW_BW_0, 0xC), dvfsrc_read(dvfsrc, DVFSRC_SW_BW_0, 0x10)); p += snprintf(p, buff_end - p, "%-16s: 0x%08x\n", "INT", dvfsrc_read(dvfsrc, DVFSRC_INT, 0x0)); p += snprintf(p, buff_end - p, "%-16s: 0x%08x\n", "INT_EN", dvfsrc_read(dvfsrc, DVFSRC_INT_EN, 0x0)); p += snprintf(p, buff_end - p, "%-16s: 0x%08x\n", "MD_SCENARIO", dvfsrc_read(dvfsrc, DVFSRC_MD_SCENARIO, 0x0)); p += snprintf(p, buff_end - p, "%-16s: 0x%08x\n", "MD_RSV0", dvfsrc_read(dvfsrc, DVFSRC_RSRV_0, 0x0)); p += snprintf(p, buff_end - p, "%-16s: 0x%08x\n", "SCP_VCORE_REQ", dvfsrc_read(dvfsrc, DVFSRC_VCORE_REQUEST, 0x0)); p += snprintf(p, buff_end - p, "%-16s: 0x%08x\n", "CURRENT_LEVEL", dvfsrc_read(dvfsrc, DVFSRC_LEVEL, 0x0)); p += snprintf(p, buff_end - p, "%-16s: %d\n", "FORCE_OPP_IDX", dvfsrc->force_opp_idx); p += snprintf(p, buff_end - p, "%-16s: %d\n", "CURR_DVFS_OPP", mtk_dvfsrc_query_opp_info(MTK_DVFSRC_CURR_DVFS_OPP)); p += snprintf(p, buff_end - p, "%-16s: %d\n", "CURR_VCORE_OPP", mtk_dvfsrc_query_opp_info(MTK_DVFSRC_CURR_VCORE_OPP)); p += snprintf(p, buff_end - p, "%-16s: %d\n", "CURR_DRAM_OPP", mtk_dvfsrc_query_opp_info(MTK_DVFSRC_CURR_DRAM_OPP)); p += snprintf(p, buff_end - p, "\n"); return p; } static char *dvfsrc_dump_spm_info(struct mtk_dvfsrc *dvfsrc, char *p, u32 size) { char *buff_end = p + size; if (!dvfsrc->spm_regs) return p; p += snprintf(p, buff_end - p, "%-24s: 0x%08x\n", "POWERON_CONFIG_EN", spm_read(dvfsrc, SPM_POWERON_CONFIG_EN)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x\n", "SPM_SW_FLAG", spm_read(dvfsrc, SPM_SW_FLAG)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x\n", "SPM_SW_RSV_9", spm_read(dvfsrc, SPM_SW_RSV_9)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x\n", "MD2SPM_DVFS_CON", spm_read(dvfsrc, SPM_MD2SPM_DVFS_CON)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x\n", "SPM_DVFS_EVENT_STA", spm_read(dvfsrc, SPM_DVFS_EVENT_STA)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x\n", "SPM_DVFS_LEVEL", spm_read(dvfsrc, SPM_DVFS_LEVEL)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x\n", "SPM_DFS_LEVEL", spm_read(dvfsrc, SPM_DFS_LEVEL)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x\n", "SPM_DVS_LEVEL", spm_read(dvfsrc, SPM_DVS_LEVEL)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", "SPM_DVFS_CMD0~4", spm_read(dvfsrc, SPM_DVFS_CMD0), spm_read(dvfsrc, SPM_DVFS_CMD1), spm_read(dvfsrc, SPM_DVFS_CMD2), spm_read(dvfsrc, SPM_DVFS_CMD3), spm_read(dvfsrc, SPM_DVFS_CMD4)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x\n", "PCM_IM_PTR", spm_read(dvfsrc, SPM_PCM_IM_PTR)); p += snprintf(p, buff_end - p, "\n"); return p; } static int dvfsrc_query_request_status(struct mtk_dvfsrc *dvfsrc, u32 id) { return 0; } static void dvfsrc_force_opp(struct mtk_dvfsrc *dvfsrc, u32 opp) { dvfsrc->force_opp_idx = opp; mtk_dvfsrc_send_request(dvfsrc->dev->parent, MTK_DVFSRC_CMD_FORCE_OPP_REQUEST, opp); } const struct dvfsrc_config mt6761_dvfsrc_config = { .regs = mt6761_regs, .spm_regs = mt6761_spm_regs, .dump_info = dvfsrc_dump_info, .dump_record = dvfsrc_dump_record, .dump_reg = dvfsrc_dump_reg, .dump_spm_info = dvfsrc_dump_spm_info, .force_opp = dvfsrc_force_opp, .query_request = dvfsrc_query_request_status, };