306 lines
8.3 KiB
C
306 lines
8.3 KiB
C
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
|
/*
|
||
|
|
* Copyright (C) 2018 MediaTek Inc.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <linux/device.h>
|
||
|
|
#include <linux/sysfs.h>
|
||
|
|
|
||
|
|
#include <helio-dvfsrc.h>
|
||
|
|
#if defined(CONFIG_MTK_DRAMC)
|
||
|
|
#include <mtk_dramc.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#include <mt-plat/upmu_common.h>
|
||
|
|
#include "mtk_dvfsrc_reg.h"
|
||
|
|
|
||
|
|
#include <linux/pm_qos.h>
|
||
|
|
#include <helio-dvfsrc-opp.h>
|
||
|
|
#include <mtk_vcorefs_governor.h>
|
||
|
|
|
||
|
|
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);
|
||
|
|
}
|