// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2018 MediaTek Inc. */ #include #include #include #if defined(CONFIG_MTK_DRAMC) #include #endif #include #include "mtk_dvfsrc_reg.h" #include #include #include static struct pm_qos_request dvfsrc_emi_request; static struct pm_qos_request dvfsrc_vcore_request; #if !defined(CONFIG_MACH_MT6771) __weak unsigned int get_dram_data_rate(void) { return 0; } __weak unsigned int get_vcore_opp_volt(unsigned int seg) { return 0; } __weak int dram_steps_freq(unsigned int step) { return 0; } int vcorefs_get_curr_vcore(void) { int ret = 0; #if !defined(CONFIG_FPGA_EARLY_PORTING) ret = pmic_get_register_value(PMIC_VCORE_ADDR); ret = vcore_pmic_to_uv(ret); #endif return ret; } int vcorefs_get_curr_ddr(void) { return get_dram_data_rate() * 1000; } int dvfsrc_get_vcore_by_steps(u32 opp) { return vcore_pmic_to_uv(get_vcore_opp_volt(opp)); } int dvfsrc_get_ddr_by_steps(u32 opp) { int ddr_khz; ddr_khz = dram_steps_freq(opp) * 1000; return ddr_khz; } #endif static ssize_t opp_table_show(struct device *dev, struct device_attribute *attr, char *buf) { char *p = buf; dvfsrc_update_opp_table(); p = dvfsrc_get_opp_table_info(p); return p - buf; } static DEVICE_ATTR_RO(opp_table); static ssize_t dvfsrc_debug_show(struct device *dev, struct device_attribute *attr, char *buf) { struct helio_dvfsrc *dvfsrc; char *p = buf; char *buff_end = p + PAGE_SIZE; int uv = vcorefs_get_curr_vcore(); dvfsrc = dev_get_drvdata(dev); if (!dvfsrc) return sprintf(buf, "Failed to access dvfsrc\n"); p += snprintf(p, buff_end - p, "[%-12s] uv : %-8u (0x%x)\n", "vcore", uv, vcore_uv_to_pmic(uv)); p += snprintf(p, buff_end - p, "[%-12s] khz: %-8u\n", "ddr", vcorefs_get_curr_ddr()); p += snprintf(p, buff_end - p, "[%-12s]: %d\n", "Enable", dvfsrc->enable); p += snprintf(p, buff_end - p, "[%-12s]: %d\n", "skip", dvfsrc->skip); p += snprintf(p, buff_end - p, "[%-12s]: %d\n", "log_mask", dvfsrc->log_mask); p += snprintf(p, buff_end - p, "[vcore_dvs]: %d\n", dvfsrc->vcore_dvs); p += snprintf(p, buff_end - p, "[ddr_dfs ]: %d\n", dvfsrc->ddr_dfs); p += snprintf(p, buff_end - p, "[mm_clk ]: %d\n", dvfsrc->mm_clk); p += snprintf(p, buff_end - p, "%-24s: 0x%x\n", "DVFSRC_RECORD_COUNT", dvfsrc_read(dvfsrc, DVFSRC_RECORD_COUNT)); p += snprintf(p, buff_end - p, "%-24s: 0x%x\n", "DVFSRC_LAST", dvfsrc_read(dvfsrc, DVFSRC_LAST)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", "DVFSRC_RECORD_0_1~3_1", dvfsrc_read(dvfsrc, DVFSRC_RECORD_0_1), dvfsrc_read(dvfsrc, DVFSRC_RECORD_1_1), dvfsrc_read(dvfsrc, DVFSRC_RECORD_2_1), dvfsrc_read(dvfsrc, DVFSRC_RECORD_3_1)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", "DVFSRC_RECORD_4_1~7_1", dvfsrc_read(dvfsrc, DVFSRC_RECORD_4_1), dvfsrc_read(dvfsrc, DVFSRC_RECORD_5_1), dvfsrc_read(dvfsrc, DVFSRC_RECORD_6_1), dvfsrc_read(dvfsrc, DVFSRC_RECORD_7_1)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", "DVFSRC_RECORD_0_0~3_0", dvfsrc_read(dvfsrc, DVFSRC_RECORD_0_0), dvfsrc_read(dvfsrc, DVFSRC_RECORD_1_0), dvfsrc_read(dvfsrc, DVFSRC_RECORD_2_0), dvfsrc_read(dvfsrc, DVFSRC_RECORD_3_0)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", "DVFSRC_RECORD_4_0~7_0", dvfsrc_read(dvfsrc, DVFSRC_RECORD_4_0), dvfsrc_read(dvfsrc, DVFSRC_RECORD_5_0), dvfsrc_read(dvfsrc, DVFSRC_RECORD_6_0), dvfsrc_read(dvfsrc, DVFSRC_RECORD_7_0)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", "DVFSRC_RECORD_MD_0~3", dvfsrc_read(dvfsrc, DVFSRC_RECORD_MD_0), dvfsrc_read(dvfsrc, DVFSRC_RECORD_MD_1), dvfsrc_read(dvfsrc, DVFSRC_RECORD_MD_2), dvfsrc_read(dvfsrc, DVFSRC_RECORD_MD_3)); p += snprintf(p, buff_end - p, "%-24s: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", "DVFSRC_RECORD_MD_4~7", dvfsrc_read(dvfsrc, DVFSRC_RECORD_MD_4), dvfsrc_read(dvfsrc, DVFSRC_RECORD_MD_5), dvfsrc_read(dvfsrc, DVFSRC_RECORD_MD_6), dvfsrc_read(dvfsrc, DVFSRC_RECORD_MD_7)); p += snprintf(p, buff_end - p, "%-24s: 0x%x\n", "DVFSRC_LEVEL", dvfsrc_read(dvfsrc, DVFSRC_LEVEL)); p += snprintf(p, buff_end - p, "%-24s: 0x%x\n", "DVFSRC_VCORE_REQUEST", dvfsrc_read(dvfsrc, DVFSRC_VCORE_REQUEST)); p += snprintf(p, buff_end - p, "%-24s: 0x%x\n", "DVFSRC_EMI_REQUEST", dvfsrc_read(dvfsrc, DVFSRC_EMI_REQUEST)); p += snprintf(p, buff_end - p, "%-24s: 0x%x\n", "DVFSRC_MD_REQUEST", dvfsrc_read(dvfsrc, DVFSRC_MD_REQUEST)); p += snprintf(p, buff_end - p, "%-24s: 0x%x\n", "DVFSRC_RSRV_0", dvfsrc_read(dvfsrc, DVFSRC_RSRV_0)); p += snprintf(p, buff_end - p, "\n"); p += snprintf(p, buff_end - p, "%-24s: %d\n", "QOS_EMI_OPP", pm_qos_request(PM_QOS_EMI_OPP)); p += snprintf(p, buff_end - p, "%-24s: %d\n", "QOS_VCORE_OPP", pm_qos_request(PM_QOS_VCORE_OPP)); p += snprintf(p, buff_end - p, "%-24s: %3d (100MB/s)\n", "DVFSRC_EMI_QOS0 THRES", dvfsrc_read(dvfsrc, DVFSRC_EMI_QOS0)); p += snprintf(p, buff_end - p, "%-24s: %3d (100MB/s)\n", "DVFSRC_EMI_QOS1 THRES", dvfsrc_read(dvfsrc, DVFSRC_EMI_QOS1)); p += snprintf(p, buff_end - p, "%-24s: %3d (100MB/s)\n", "DVFSRC_SW_BW_0 (Test)", dvfsrc_read(dvfsrc, DVFSRC_SW_BW_0)); p += snprintf(p, buff_end - p, "%-24s: %3d (100MB/s)\n", "DVFSRC_SW_BW_1 (CPU)", dvfsrc_read(dvfsrc, DVFSRC_SW_BW_1)); p += snprintf(p, buff_end - p, "%-24s: %3d (100MB/s)\n", "DVFSRC_SW_BW_2 (GPU)", dvfsrc_read(dvfsrc, DVFSRC_SW_BW_2)); p += snprintf(p, buff_end - p, "%-24s: %3d (100MB/s)\n", "DVFSRC_SW_BW_3 (MM)", dvfsrc_read(dvfsrc, DVFSRC_SW_BW_3)); p += snprintf(p, buff_end - p, "%-24s: %3d (100MB/s)\n", "DVFSRC_SW_BW_4 (OTHER)", dvfsrc_read(dvfsrc, DVFSRC_SW_BW_4)); p += snprintf(p, buff_end - p, "\n"); return p - buf; } static ssize_t dvfsrc_debug_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int val, val2, r = 0; char cmd[32]; struct helio_dvfsrc *dvfsrc; dvfsrc = dev_get_drvdata(dev); if (!dvfsrc) return -ENODEV; if (sscanf(buf, "%31s 0x%x 0x%x", cmd, &val, &val2) == 3 || sscanf(buf, "%31s %d %d", cmd, &val, &val2) == 3) pr_info("dvfsrc_debug cmd: %s, val1: %d(0x%x) val2: %d(0x%x)\n", cmd, val, val, val2, val2); else if (sscanf(buf, "%31s 0x%x", cmd, &val) == 2 || sscanf(buf, "%31s %d", cmd, &val) == 2) pr_info("dvfsrc_debug cmd: %s, val: %d(0x%x)\n", cmd, val, val); if (!strcmp(cmd, "kir_emi")) pm_qos_update_request(&dvfsrc_emi_request, val); else if (!strcmp(cmd, "kir_vcore")) pm_qos_update_request(&dvfsrc_vcore_request, val); else if (!strcmp(cmd, "skip")) dvfsrc->skip = val; else if (!strcmp(cmd, "log_mask")) dvfsrc->log_mask = val; else r = -EPERM; return count; } static DEVICE_ATTR_RW(dvfsrc_debug); static ssize_t dvfsrc_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct helio_dvfsrc *dvfsrc; dvfsrc = dev_get_drvdata(dev); if (!dvfsrc) return sprintf(buf, "Failed to access dvfsrc\n"); return sprintf(buf, "%d\n", dvfsrc->enable); } static ssize_t dvfsrc_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct helio_dvfsrc *dvfsrc; s32 value; dvfsrc = dev_get_drvdata(dev); if (!dvfsrc) return -ENODEV; if (kstrtos32(buf, 0, &value)) return -EINVAL; if (value < 0) return -EINVAL; dvfsrc->enable = value; /* ToDo: If disable, fix highest opp? */ return count; } static DEVICE_ATTR_RW(dvfsrc_enable); static struct attribute *helio_dvfsrc_attrs[] = { &dev_attr_dvfsrc_debug.attr, &dev_attr_dvfsrc_enable.attr, &dev_attr_opp_table.attr, NULL, }; static struct attribute_group helio_dvfsrc_attr_group = { .name = "helio-dvfsrc", .attrs = helio_dvfsrc_attrs, }; int helio_dvfsrc_add_interface(struct device *dev) { pm_qos_add_request(&dvfsrc_emi_request, PM_QOS_EMI_OPP, PM_QOS_EMI_OPP_DEFAULT_VALUE); pm_qos_add_request(&dvfsrc_vcore_request, PM_QOS_VCORE_OPP, PM_QOS_VCORE_OPP_DEFAULT_VALUE); return sysfs_create_group(&dev->kobj, &helio_dvfsrc_attr_group); } void helio_dvfsrc_remove_interface(struct device *dev) { sysfs_remove_group(&dev->kobj, &helio_dvfsrc_attr_group); }