1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2024-11-19 13:27:49 +00:00
a155-U-u1/kernel-5.10/drivers/misc/mediatek/dvfsrc/dvfsrc-helper.c
2024-03-11 06:53:12 +11:00

1097 lines
24 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/interconnect.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/soc/mediatek/mtk_sip_svc.h>
#include <linux/soc/mediatek/mtk_dvfsrc.h>
#include <linux/regmap.h>
#include <linux/mfd/mt6397/core.h>
#if IS_ENABLED(CONFIG_MTK_DRAMC)
#include <soc/mediatek/dramc.h>
#endif
#include "dvfsrc-helper.h"
#include "dvfsrc-common.h"
#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)
#include <aee.h>
#endif
static struct mtk_dvfsrc *dvfsrc_drv;
static struct regmap *dvfsrc_regmap;
/* OPP */
#define MT_DVFSRC_OPP(_num_vcore, _num_ddr, _opp_table) \
{ \
.num_vcore_opp = _num_vcore, \
.num_dram_opp = _num_ddr, \
.opps = _opp_table, \
.num_opp = ARRAY_SIZE(_opp_table), \
}
int (*dvfsrc_query_opp_info)(u32 id);
void register_dvfsrc_opp_handler(int (*handler)(u32 id))
{
dvfsrc_query_opp_info = handler;
}
int mtk_dvfsrc_query_opp_info(u32 id)
{
if (dvfsrc_query_opp_info != NULL)
return dvfsrc_query_opp_info(id);
return 0;
}
EXPORT_SYMBOL(mtk_dvfsrc_query_opp_info);
int mtk_dvfsrc_vcore_uv_table(u32 opp)
{
u32 opp_idx;
if (!dvfsrc_drv)
return 0;
if (opp >= dvfsrc_drv->opp_desc->num_vcore_opp)
return 0;
opp_idx = dvfsrc_drv->opp_desc->num_vcore_opp - opp - 1;
return dvfsrc_drv->vopp_uv_tlb[opp_idx];
}
EXPORT_SYMBOL(mtk_dvfsrc_vcore_uv_table);
static void dvfsrc_setup_opp_table(struct mtk_dvfsrc *dvfsrc)
{
int i;
struct dvfsrc_opp *opp;
struct arm_smccc_res ares;
for (i = 0; i < dvfsrc->opp_desc->num_vcore_opp; i++) {
arm_smccc_smc(MTK_SIP_VCOREFS_CONTROL,
MTK_SIP_VCOREFS_GET_VCORE_UV,
i, 0, 0, 0, 0, 0,
&ares);
if (!ares.a0)
dvfsrc->vopp_uv_tlb[i] = ares.a1;
}
for (i = 0; i < dvfsrc->opp_desc->num_vcore_opp; i++)
dev_info(dvfsrc->dev, "dvfsrc vopp[%d] = %d\n",
i, dvfsrc->vopp_uv_tlb[i]);
for (i = 0; i < dvfsrc->opp_desc->num_opp; i++) {
opp = &dvfsrc->opp_desc->opps[i];
arm_smccc_smc(MTK_SIP_VCOREFS_CONTROL,
MTK_SIP_VCOREFS_GET_VCORE_UV,
opp->vcore_opp, 0, 0, 0, 0, 0,
&ares);
if (!ares.a0)
opp->vcore_uv = ares.a1;
arm_smccc_smc(MTK_SIP_VCOREFS_CONTROL,
MTK_SIP_VCOREFS_GET_DRAM_FREQ,
opp->dram_opp, 0, 0, 0, 0, 0,
&ares);
if (!ares.a0)
opp->dram_khz = ares.a1;
}
}
static int dvfsrc_query_sw_req_vcore_opp(struct mtk_dvfsrc *dvfsrc, int vcore_opp)
{
int sw_req_opp;
int sw_req = 0;
int scp_req = 0;
if (dvfsrc->force_opp_idx >= dvfsrc->opp_desc->num_opp) {
mtk_dvfsrc_query_info(dvfsrc->dev->parent,
MTK_DVFSRC_CMD_VCORE_LEVEL_QUERY,
&sw_req);
mtk_dvfsrc_query_info(dvfsrc->dev->parent,
MTK_DVFSRC_CMD_VSCP_LEVEL_QUERY,
&scp_req);
sw_req_opp = (sw_req > scp_req) ? sw_req : scp_req;
sw_req_opp = dvfsrc->opp_desc->num_vcore_opp - (sw_req_opp + 1);
if (vcore_opp > sw_req_opp) {
pr_info("Error vcore request = %d %d %d\n", sw_req, vcore_opp,
dvfsrc->force_opp_idx);
}
return sw_req_opp;
}
return vcore_opp;
}
int get_sw_req_vcore_opp(void)
{
return mtk_dvfsrc_query_opp_info(MTK_DVFSRC_SW_REQ_VCORE_OPP);
}
EXPORT_SYMBOL(get_sw_req_vcore_opp);
static int dvfsrc_query_info(u32 id)
{
struct mtk_dvfsrc *dvfsrc = dvfsrc_drv;
const struct dvfsrc_opp *opp;
int ret = 0;
int level = 0;
ret = mtk_dvfsrc_query_info(dvfsrc->dev->parent,
MTK_DVFSRC_CMD_CURR_LEVEL_QUERY, &level);
if (ret || level >= dvfsrc->opp_desc->num_opp)
return 0;
opp = &dvfsrc->opp_desc->opps[level];
switch (id) {
case MTK_DVFSRC_NUM_DVFS_OPP:
ret = dvfsrc->opp_desc->num_opp;
break;
case MTK_DVFSRC_NUM_DRAM_OPP:
ret = dvfsrc->opp_desc->num_dram_opp;
break;
case MTK_DVFSRC_NUM_VCORE_OPP:
ret = dvfsrc->opp_desc->num_vcore_opp;
break;
case MTK_DVFSRC_CURR_DVFS_OPP:
ret = dvfsrc->opp_desc->num_opp
- (level + 1);
break;
case MTK_DVFSRC_CURR_DRAM_OPP:
ret = dvfsrc->opp_desc->num_dram_opp
- (opp->dram_opp + 1);
break;
case MTK_DVFSRC_CURR_VCORE_OPP:
ret = dvfsrc->opp_desc->num_vcore_opp
- (opp->vcore_opp + 1);
break;
case MTK_DVFSRC_CURR_DVFS_LEVEL:
ret = level;
break;
case MTK_DVFSRC_CURR_DRAM_KHZ:
ret = opp->dram_khz;
break;
case MTK_DVFSRC_CURR_VCORE_UV:
ret = opp->vcore_uv;
break;
case MTK_DVFSRC_SW_REQ_VCORE_OPP:
ret = dvfsrc->opp_desc->num_vcore_opp - (opp->vcore_opp + 1);
ret = dvfsrc_query_sw_req_vcore_opp(dvfsrc, ret);
break;
}
return ret;
}
static int mtk_dvfsrc_opp_setting(struct mtk_dvfsrc *dvfsrc)
{
struct arm_smccc_res ares;
arm_smccc_smc(MTK_SIP_VCOREFS_CONTROL, MTK_SIP_VCOREFS_GET_OPP_TYPE,
0, 0, 0, 0, 0, 0,
&ares);
if (!ares.a0)
dvfsrc->opp_type = ares.a1;
else {
dev_info(dvfsrc->dev, "get opp type fails\n");
return ares.a0;
}
arm_smccc_smc(MTK_SIP_VCOREFS_CONTROL, MTK_SIP_VCOREFS_GET_FW_TYPE,
0, 0, 0, 0, 0, 0,
&ares);
if (!ares.a0)
dvfsrc->fw_type = ares.a1;
else {
dev_info(dvfsrc->dev, "get fw type fails\n");
return ares.a0;
}
if (dvfsrc->opp_type > dvfsrc->dvd->num_opp_desc)
return -EINVAL;
dvfsrc->opp_desc = &dvfsrc->dvd->opps_desc[dvfsrc->opp_type];
dvfsrc->vopp_uv_tlb = devm_kzalloc(dvfsrc->dev,
dvfsrc->opp_desc->num_vcore_opp * sizeof(u32),
GFP_KERNEL);
if (!dvfsrc->vopp_uv_tlb)
return -ENOMEM;
dvfsrc_setup_opp_table(dvfsrc);
dvfsrc->force_opp_idx = 0xFF;
return 0;
}
/* OPP END */
/* DEBUG */
int (*query_debug_info_handle)(u32 id);
void register_dvfsrc_debug_handler(int (*handler)(u32 id))
{
query_debug_info_handle = handler;
}
EXPORT_SYMBOL(register_dvfsrc_debug_handler);
int mtk_dvfsrc_query_debug_info(u32 id)
{
if (query_debug_info_handle != NULL)
return query_debug_info_handle(id);
return 0;
}
EXPORT_SYMBOL(mtk_dvfsrc_query_debug_info);
static int dvfsrc_query_debug_info(u32 id)
{
struct mtk_dvfsrc *dvfsrc = dvfsrc_drv;
const struct dvfsrc_config *config;
int ret;
config = dvfsrc_drv->dvd->config;
ret = config->query_request(dvfsrc, id);
return ret;
}
#define DVFSRC_DEBUG_DUMP 0
#define DVFSRC_DEBUG_AEE 1
#define DVFSRC_DEBUG_VCORE_CHK 2
#define DVFSRC_AEE_LEVEL_ERROR 0
#define DVFSRC_AEE_FORCE_ERROR 1
#define DVFSRC_AEE_VCORE_CHK_ERROR 2
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)
p += snprintf(p, buff_end - p, "%-10s: %-8u khz\n",
"DDR", mtk_dramc_get_data_rate() * 1000);
#endif
p += snprintf(p, buff_end - p, "%-15s: %d\n",
"FORCE_OPP_IDX",
dvfsrc->force_opp_idx);
p += snprintf(p, buff_end - p, "%-15s: %d\n",
"CURR_DVFS_OPP",
mtk_dvfsrc_query_opp_info(MTK_DVFSRC_CURR_DVFS_OPP));
p += snprintf(p, buff_end - p, "%-15s: %d\n",
"CURR_VCORE_OPP",
mtk_dvfsrc_query_opp_info(MTK_DVFSRC_CURR_VCORE_OPP));
p += snprintf(p, buff_end - p, "%-15s: %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 int dvfsrc_aee_trigger(struct mtk_dvfsrc *dvfsrc, u32 aee_type)
{
#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)
switch (aee_type) {
case DVFSRC_AEE_LEVEL_ERROR:
aee_kernel_warning("DVFSRC", "LEVEL Change fail");
break;
case DVFSRC_AEE_FORCE_ERROR:
aee_kernel_warning("DVFSRC", "Force opp fail");
break;
case DVFSRC_AEE_VCORE_CHK_ERROR:
aee_kernel_warning("DVFSRC", "vcore check fail");
break;
default:
dev_info(dvfsrc->dev, "unknown aee type\n");
break;
}
#endif
return NOTIFY_DONE;
}
static int dvfsrc_get_vcore_voltage(struct mtk_dvfsrc *dvfsrc)
{
int ret;
unsigned int regval = 0;
if (!dvfsrc_regmap)
return -EINVAL;
ret = regmap_read(dvfsrc_regmap, dvfsrc->vcore_vsel_reg, &regval);
if (ret != 0) {
dev_info(dvfsrc->dev,
"Failed to get vcore Buck vsel reg %x: %d\n",
dvfsrc->vcore_vsel_reg, ret);
return -EINVAL;
}
ret = (regval >> dvfsrc->vcore_vsel_shift) & dvfsrc->vcore_vsel_mask;
ret = dvfsrc->vcore_range_min_uV + (dvfsrc->vcore_range_step * ret);
return ret;
}
static int dvfsrc_vcore_check(struct mtk_dvfsrc *dvfsrc, u32 vcore_level)
{
int vcore_uv = 0;
int predict_uv;
if (!dvfsrc->vchk_enable || !dvfsrc_regmap)
return NOTIFY_DONE;
if (vcore_level > dvfsrc->opp_desc->num_vcore_opp) {
dev_info(dvfsrc->dev, "VCORE OPP ERROR = %d\n",
vcore_level);
return NOTIFY_BAD;
}
predict_uv = dvfsrc->vopp_uv_tlb[vcore_level];
vcore_uv = dvfsrc_get_vcore_voltage(dvfsrc);
if (vcore_uv < predict_uv) {
dev_info(dvfsrc->dev, "VCORE CHECK FAIL= %d %d, %d\n",
vcore_level, vcore_uv, predict_uv);
return NOTIFY_BAD;
}
return NOTIFY_DONE;
}
static void dvfsrc_dump(struct mtk_dvfsrc *dvfsrc)
{
char *p;
ssize_t dump_size = DUMP_BUF_SIZE - 1;
const struct dvfsrc_config *config;
config = dvfsrc->dvd->config;
mutex_lock(&dvfsrc->dump_lock);
p = dvfsrc->dump_buf;
config->dump_reg(dvfsrc, p, dump_size);
pr_info("%s", dvfsrc->dump_buf);
p = dvfsrc->dump_buf;
config->dump_record(dvfsrc, p, dump_size);
pr_info("%s", dvfsrc->dump_buf);
if (config->dump_spm_info && dvfsrc->spm_regs) {
p = dvfsrc->dump_buf;
config->dump_spm_info(dvfsrc, p, dump_size);
pr_info("%s", dvfsrc->dump_buf);
}
if (config->dump_spm_timer_latch && dvfsrc->spm_regs && dvfsrc->dvd->spm_stamp_en) {
p = dvfsrc->dump_buf;
config->dump_spm_timer_latch(dvfsrc, p, dump_size);
pr_info("%s", dvfsrc->dump_buf);
}
mutex_unlock(&dvfsrc->dump_lock);
}
static int dvfsrc_debug_notifier_handler(struct notifier_block *b,
unsigned long l, void *v)
{
int ret = NOTIFY_DONE;
struct mtk_dvfsrc *dvfsrc;
dvfsrc = container_of(b, struct mtk_dvfsrc, debug_notifier);
switch (l) {
case DVFSRC_DEBUG_DUMP:
dvfsrc_dump(dvfsrc);
break;
case DVFSRC_DEBUG_AEE:
ret = dvfsrc_aee_trigger(dvfsrc, *(u32 *) v);
break;
case DVFSRC_DEBUG_VCORE_CHK:
ret = dvfsrc_vcore_check(dvfsrc, *(u32 *) v);
break;
default:
dev_dbg(dvfsrc->dev, "unknown debug type\n");
break;
}
return ret;
}
static void dvfsrc_debug_notifier_register(struct mtk_dvfsrc *dvfsrc)
{
dvfsrc->debug_notifier.notifier_call = dvfsrc_debug_notifier_handler;
register_dvfsrc_debug_notifier(&dvfsrc->debug_notifier);
}
static DEFINE_RATELIMIT_STATE(dvfsrc_ratelimit_force, 1 * HZ, 1);
static void dvfsrc_force_opp(struct mtk_dvfsrc *dvfsrc, u32 opp)
{
if (dvfsrc->force_opp_idx != opp) {
if (__ratelimit(&dvfsrc_ratelimit_force))
pr_info("dvfsrc_force_opp\n");
mtk_dvfsrc_send_request(dvfsrc->dev->parent,
MTK_DVFSRC_CMD_FORCEOPP_REQUEST,
opp);
}
dvfsrc->force_opp_idx = opp;
}
static void mtk_dvfsrc_get_perf_bw(struct mtk_dvfsrc *dvfsrc,
struct device_node *np)
{
int i;
for (i = 0; i < dvfsrc->num_perf; i++) {
dvfsrc->perfs_peak_bw[i] =
dvfsrc_get_required_opp_peak_bw(np, i);
}
}
static int mtk_dvfsrc_debug_setting(struct mtk_dvfsrc *dvfsrc)
{
struct device_node *np = dvfsrc->dev->of_node;
dvfsrc->num_perf = of_count_phandle_with_args(np,
"required-opps", NULL);
if (dvfsrc->num_perf > 0) {
dvfsrc->perfs_peak_bw = devm_kzalloc(dvfsrc->dev,
dvfsrc->num_perf * sizeof(u32),
GFP_KERNEL);
if (!dvfsrc->perfs_peak_bw)
return -ENOMEM;
mtk_dvfsrc_get_perf_bw(dvfsrc, np);
} else {
dvfsrc->num_perf = 0;
}
dvfsrc->vcore_power =
regulator_get_optional(dvfsrc->dev, "vcore");
if (IS_ERR(dvfsrc->vcore_power)) {
dev_info(dvfsrc->dev, "get vcore failed = %ld\n",
PTR_ERR(dvfsrc->vcore_power));
dvfsrc->vcore_power = NULL;
}
dvfsrc->dvfsrc_vcore_power =
regulator_get_optional(dvfsrc->dev, "rc-vcore");
if (IS_ERR(dvfsrc->dvfsrc_vcore_power)) {
dev_info(dvfsrc->dev, "get dvfsrc_vcore failed = %ld\n",
PTR_ERR(dvfsrc->dvfsrc_vcore_power));
dvfsrc->dvfsrc_vcore_power = NULL;
}
dvfsrc->bw_path = of_icc_get(dvfsrc->dev, "icc-bw");
if (IS_ERR(dvfsrc->bw_path)) {
dev_info(dvfsrc->dev, "get icc-bw fail\n");
dvfsrc->bw_path = NULL;
}
dvfsrc->hrt_path = of_icc_get(dvfsrc->dev, "icc-hrt-bw");
if (IS_ERR(dvfsrc->hrt_path)) {
dev_info(dvfsrc->dev, "get icc-hrt_bw fail\n");
dvfsrc->hrt_path = NULL;
}
dvfsrc->perf_path = of_icc_get(dvfsrc->dev, "icc-perf-bw");
if (IS_ERR(dvfsrc->hrt_path)) {
dev_info(dvfsrc->dev, "get icc-perf_bw fail\n");
dvfsrc->hrt_path = NULL;
}
dvfsrc->force_opp = dvfsrc_force_opp;
dvfsrc->dump_info = dvfsrc_dump_info;
return 0;
}
static int mtk_dvfsrc_mt6397_probe(struct platform_device *pdev)
{
struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
dvfsrc_regmap = mt6397->regmap;
return 0;
}
static const struct of_device_id mtk_dvfsrc_mt6397_of_match[] = {
{
.compatible = "mediatek,mt6359p-dvfsrc-debug",
}, {
/* sentinel */
},
};
static struct platform_driver mtk_dvfsrc_mt6397_driver = {
.probe = mtk_dvfsrc_mt6397_probe,
.driver = {
.name = "mtk-dvfsrc-vcore-debug",
.of_match_table = of_match_ptr(mtk_dvfsrc_mt6397_of_match),
},
};
static int mtk_dvfsrc_regmap_debug_setting(struct mtk_dvfsrc *dvfsrc)
{
int ret;
struct device_node *np = dvfsrc->dev->of_node;
ret = of_property_read_u32(np, "vcore_vsel_reg", &dvfsrc->vcore_vsel_reg);
if (ret)
goto no_property;
ret = of_property_read_u32(np, "vcore_vsel_mask", &dvfsrc->vcore_vsel_mask);
if (ret)
goto no_property;
ret = of_property_read_u32(np, "vcore_vsel_shift", &dvfsrc->vcore_vsel_shift);
if (ret)
goto no_property;
ret = of_property_read_u32(np, "vcore_range_min_uV", &dvfsrc->vcore_range_min_uV);
if (ret)
goto no_property;
ret = of_property_read_u32(np, "vcore_range_step", &dvfsrc->vcore_range_step);
if (ret)
goto no_property;
ret = platform_driver_register(&mtk_dvfsrc_mt6397_driver);
if (ret) {
dev_info(dvfsrc->dev, "register regmap fail\n");
goto no_property;
}
dvfsrc->vchk_enable = true;
dev_info(dvfsrc->dev, "vcore checker is enabled\n");
return 0;
no_property:
dev_info(dvfsrc->dev, "vcore checker is disabled\n");
return 0;
}
/* DEBUG END*/
static struct dvfsrc_opp dvfsrc_opp_mt6873_lp4[] = {
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, 0, 0, 0},
{3, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{2, 1, 0, 0},
{3, 1, 0, 0},
{0, 2, 0, 0},
{1, 2, 0, 0},
{2, 2, 0, 0},
{3, 2, 0, 0},
{1, 3, 0, 0},
{2, 3, 0, 0},
{3, 3, 0, 0},
{1, 4, 0, 0},
{2, 4, 0, 0},
{3, 4, 0, 0},
{2, 5, 0, 0},
{3, 5, 0, 0},
{3, 6, 0, 0},
};
static struct dvfsrc_opp_desc dvfsrc_opp_mt6873_desc[] = {
MT_DVFSRC_OPP(4, 7, dvfsrc_opp_mt6873_lp4),
};
static const struct dvfsrc_debug_data mt6873_data = {
.version = 0x6873,
.config = &mt6873_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6873_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6873_desc),
};
static const struct dvfsrc_debug_data mt6853_data = {
.version = 0x6853,
.config = &mt6873_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6873_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6873_desc),
};
static const struct dvfsrc_debug_data mt6789_data = {
.version = 0x6789,
.config = &mt6873_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6873_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6873_desc),
};
static struct dvfsrc_opp dvfsrc_opp_mt6885_lp4[] = {
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, 0, 0, 0},
{3, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{2, 1, 0, 0},
{3, 1, 0, 0},
{0, 2, 0, 0},
{1, 2, 0, 0},
{2, 2, 0, 0},
{3, 2, 0, 0},
{0, 3, 0, 0},
{1, 3, 0, 0},
{2, 3, 0, 0},
{3, 3, 0, 0},
{1, 4, 0, 0},
{2, 4, 0, 0},
{3, 4, 0, 0},
{2, 5, 0, 0},
{3, 5, 0, 0},
{3, 6, 0, 0},
};
static struct dvfsrc_opp_desc dvfsrc_opp_mt6885_desc[] = {
MT_DVFSRC_OPP(4, 7, dvfsrc_opp_mt6885_lp4),
};
static const struct dvfsrc_debug_data mt6885_data = {
.version = 0x6885,
.config = &mt6873_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6885_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6885_desc),
};
static struct dvfsrc_opp dvfsrc_opp_mt6893_lp4[] = {
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, 0, 0, 0},
{3, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{2, 1, 0, 0},
{3, 1, 0, 0},
{0, 2, 0, 0},
{1, 2, 0, 0},
{2, 2, 0, 0},
{3, 2, 0, 0},
{0, 3, 0, 0},
{1, 3, 0, 0},
{2, 3, 0, 0},
{3, 3, 0, 0},
{1, 4, 0, 0},
{2, 4, 0, 0},
{3, 4, 0, 0},
{2, 5, 0, 0},
{3, 5, 0, 0},
{3, 6, 0, 0},
{4, 6, 0, 0},
{4, 7, 0, 0},
};
static struct dvfsrc_opp_desc dvfsrc_opp_mt6893_desc[] = {
MT_DVFSRC_OPP(5, 8, dvfsrc_opp_mt6893_lp4),
};
static const struct dvfsrc_debug_data mt6893_data = {
.version = 0x6893,
.config = &mt6893_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6893_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6893_desc),
};
static struct dvfsrc_opp dvfsrc_opp_mt6833_lp4[] = {
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, 0, 0, 0},
{3, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{2, 1, 0, 0},
{3, 1, 0, 0},
{0, 2, 0, 0},
{1, 2, 0, 0},
{2, 2, 0, 0},
{3, 2, 0, 0},
{0, 3, 0, 0},
{1, 3, 0, 0},
{2, 3, 0, 0},
{3, 3, 0, 0},
{1, 4, 0, 0},
{2, 4, 0, 0},
{3, 4, 0, 0},
{1, 5, 0, 0},
{2, 5, 0, 0},
{3, 5, 0, 0},
{2, 6, 0, 0},
{3, 6, 0, 0},
{3, 7, 0, 0},
};
static struct dvfsrc_opp_desc dvfsrc_opp_mt6833_desc[] = {
MT_DVFSRC_OPP(4, 8, dvfsrc_opp_mt6833_lp4),
};
static const struct dvfsrc_debug_data mt6833_data = {
.version = 0x6833,
.config = &mt6873_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6833_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6833_desc),
};
static struct dvfsrc_opp dvfsrc_opp_mt6877_lp4[] = {
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, 0, 0, 0},
{3, 0, 0, 0},
{4, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{2, 1, 0, 0},
{3, 1, 0, 0},
{4, 1, 0, 0},
{0, 2, 0, 0},
{1, 2, 0, 0},
{2, 2, 0, 0},
{3, 2, 0, 0},
{4, 2, 0, 0},
{0, 3, 0, 0},
{1, 3, 0, 0},
{2, 3, 0, 0},
{3, 3, 0, 0},
{4, 3, 0, 0},
{1, 4, 0, 0},
{2, 4, 0, 0},
{3, 4, 0, 0},
{4, 4, 0, 0},
{2, 5, 0, 0},
{3, 5, 0, 0},
{4, 5, 0, 0},
{3, 6, 0, 0},
{4, 6, 0, 0},
{4, 7, 0, 0},
};
static struct dvfsrc_opp_desc dvfsrc_opp_mt6877_desc[] = {
MT_DVFSRC_OPP(5, 8, dvfsrc_opp_mt6877_lp4),
};
static const struct dvfsrc_debug_data mt6877_data = {
.version = 0x6877,
.config = &mt6877_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6877_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6877_desc),
};
static struct dvfsrc_opp dvfsrc_opp_mt6983[] = {
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, 0, 0, 0},
{3, 0, 0, 0},
{4, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{2, 1, 0, 0},
{3, 1, 0, 0},
{4, 1, 0, 0},
{1, 2, 0, 0},
{2, 2, 0, 0},
{3, 2, 0, 0},
{4, 2, 0, 0},
{1, 3, 0, 0},
{2, 3, 0, 0},
{3, 3, 0, 0},
{4, 3, 0, 0},
{2, 4, 0, 0},
{3, 4, 0, 0},
{4, 4, 0, 0},
{3, 5, 0, 0},
{4, 5, 0, 0},
{3, 6, 0, 0},
{4, 6, 0, 0},
{4, 7, 0, 0},
{4, 8, 0, 0},
};
static struct dvfsrc_opp_desc dvfsrc_opp_mt6983_desc[] = {
MT_DVFSRC_OPP(5, 9, dvfsrc_opp_mt6983),
};
static const struct dvfsrc_debug_data mt6983_data = {
.version = 0x6983,
.config = &mt6983_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6983_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6983_desc),
.spm_stamp_en = true,
};
static const struct dvfsrc_debug_data mt6895_data = {
.version = 0x6895,
.config = &mt6983_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6983_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6983_desc),
};
static struct dvfsrc_opp dvfsrc_opp_mt6855[] = {
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, 0, 0, 0},
{3, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{2, 1, 0, 0},
{3, 1, 0, 0},
{0, 2, 0, 0},
{1, 2, 0, 0},
{2, 2, 0, 0},
{3, 2, 0, 0},
{0, 3, 0, 0},
{1, 3, 0, 0},
{2, 3, 0, 0},
{3, 3, 0, 0},
{0, 4, 0, 0},
{1, 4, 0, 0},
{2, 4, 0, 0},
{3, 4, 0, 0},
{1, 5, 0, 0},
{2, 5, 0, 0},
{3, 5, 0, 0},
{2, 6, 0, 0},
{3, 6, 0, 0},
{3, 7, 0, 0},
};
static struct dvfsrc_opp_desc dvfsrc_opp_mt6855_desc[] = {
MT_DVFSRC_OPP(4, 8, dvfsrc_opp_mt6855),
};
static const struct dvfsrc_debug_data mt6855_data = {
.version = 0x6855,
.config = &mt6983_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6855_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6855_desc),
};
static struct dvfsrc_opp dvfsrc_opp_mt6879[] = {
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, 0, 0, 0},
{3, 0, 0, 0},
{4, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{2, 1, 0, 0},
{3, 1, 0, 0},
{4, 1, 0, 0},
{0, 2, 0, 0},
{1, 2, 0, 0},
{2, 2, 0, 0},
{3, 2, 0, 0},
{4, 2, 0, 0},
{0, 3, 0, 0},
{1, 3, 0, 0},
{2, 3, 0, 0},
{3, 3, 0, 0},
{4, 3, 0, 0},
{0, 4, 0, 0},
{1, 4, 0, 0},
{2, 4, 0, 0},
{3, 4, 0, 0},
{4, 4, 0, 0},
{1, 5, 0, 0},
{2, 5, 0, 0},
{3, 5, 0, 0},
{4, 5, 0, 0},
{2, 6, 0, 0},
{3, 6, 0, 0},
{4, 6, 0, 0},
{4, 7, 0, 0},
};
static struct dvfsrc_opp_desc dvfsrc_opp_mt6879_desc[] = {
MT_DVFSRC_OPP(5, 8, dvfsrc_opp_mt6879),
};
static const struct dvfsrc_debug_data mt6879_data = {
.version = 0x6879,
.config = &mt6983_dvfsrc_config,
.opps_desc = dvfsrc_opp_mt6879_desc,
.num_opp_desc = ARRAY_SIZE(dvfsrc_opp_mt6879_desc),
};
static const struct of_device_id dvfsrc_helper_of_match[] = {
{
.compatible = "mediatek,mt6789-dvfsrc",
.data = &mt6789_data,
}, {
.compatible = "mediatek,mt6873-dvfsrc",
.data = &mt6873_data,
}, {
.compatible = "mediatek,mt6853-dvfsrc",
.data = &mt6853_data,
}, {
.compatible = "mediatek,mt6885-dvfsrc",
.data = &mt6885_data,
}, {
.compatible = "mediatek,mt6893-dvfsrc",
.data = &mt6893_data,
}, {
.compatible = "mediatek,mt6833-dvfsrc",
.data = &mt6833_data,
}, {
.compatible = "mediatek,mt6877-dvfsrc",
.data = &mt6877_data,
}, {
.compatible = "mediatek,mt6983-dvfsrc",
.data = &mt6983_data,
}, {
.compatible = "mediatek,mt6895-dvfsrc",
.data = &mt6895_data,
}, {
.compatible = "mediatek,mt6879-dvfsrc",
.data = &mt6879_data,
}, {
.compatible = "mediatek,mt6855-dvfsrc",
.data = &mt6855_data,
}, {
/* sentinel */
},
};
static int mtk_dvfsrc_helper_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct platform_device *parent_dev;
struct resource *res;
struct mtk_dvfsrc *dvfsrc;
int ret;
match = of_match_node(dvfsrc_helper_of_match, dev->parent->of_node);
if (!match) {
dev_info(dev, "invalid compatible string\n");
return -ENODEV;
}
parent_dev = to_platform_device(dev->parent);
dvfsrc = devm_kzalloc(&pdev->dev, sizeof(*dvfsrc), GFP_KERNEL);
if (!dvfsrc)
return -ENOMEM;
dvfsrc->dvd = match->data;
dvfsrc->dev = &pdev->dev;
res = platform_get_resource_byname(parent_dev, IORESOURCE_MEM, "dvfsrc");
if (!res) {
dev_info(dev, "resource not found\n");
return -ENODEV;
}
dvfsrc->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (IS_ERR(dvfsrc->regs))
return PTR_ERR(dvfsrc->regs);
res = platform_get_resource_byname(parent_dev,
IORESOURCE_MEM, "spm");
if (res) {
dvfsrc->spm_regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (IS_ERR(dvfsrc->spm_regs))
dvfsrc->spm_regs = NULL;
}
ret = mtk_dvfsrc_opp_setting(dvfsrc);
if (ret) {
dev_info(dev, "dvfsrc opp setting fail\n");
return ret;
}
ret = mtk_dvfsrc_debug_setting(dvfsrc);
if (ret) {
dev_info(dev, "dvfsrc debug setting fail\n");
return ret;
}
mutex_init(&dvfsrc->dump_lock);
dvfsrc_drv = dvfsrc;
platform_set_drvdata(pdev, dvfsrc);
mtk_dvfsrc_regmap_debug_setting(dvfsrc);
register_dvfsrc_opp_handler(dvfsrc_query_info);
dvfsrc_debug_notifier_register(dvfsrc);
dvfsrc_register_sysfs(dev);
register_dvfsrc_debug_handler(dvfsrc_query_debug_info);
return 0;
}
static int mtk_dvfsrc_helper_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_dvfsrc *dvfsrc = platform_get_drvdata(pdev);
unregister_dvfsrc_debug_notifier(&dvfsrc->debug_notifier);
dvfsrc_unregister_sysfs(dev);
platform_driver_unregister(&mtk_dvfsrc_mt6397_driver);
dvfsrc_drv = NULL;
return 0;
}
static const struct of_device_id mtk_dvfsrc_helper_of_match[] = {
{
.compatible = "mediatek,dvfsrc-helper",
}, {
/* sentinel */
},
};
static struct platform_driver mtk_dvfsrc_helper_driver = {
.probe = mtk_dvfsrc_helper_probe,
.remove = mtk_dvfsrc_helper_remove,
.driver = {
.name = "mtk-dvfsrc-helper",
.of_match_table = of_match_ptr(mtk_dvfsrc_helper_of_match),
},
};
static int __init mtk_dvfsrc_helper_init(void)
{
int ret;
ret = platform_driver_register(&mtk_dvfsrc_helper_driver);
if (ret)
return ret;
#if IS_ENABLED(CONFIG_MTK_DVFSRC_MET)
ret = mtk_dvfsrc_met_init();
if (ret) {
platform_driver_unregister(&mtk_dvfsrc_helper_driver);
return ret;
}
#endif
return 0;
}
late_initcall_sync(mtk_dvfsrc_helper_init)
static void __exit mtk_dvfsrc_helper_exit(void)
{
platform_driver_unregister(&mtk_dvfsrc_helper_driver);
#if IS_ENABLED(CONFIG_MTK_DVFSRC_MET)
mtk_dvfsrc_met_exit();
#endif
}
module_exit(mtk_dvfsrc_helper_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MTK DVFSRC helper driver");