kernel-brax3-ubuntu-touch/drivers/misc/mediatek/vdec_fmt/vdec_fmt_pm.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

251 lines
6.8 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include "vdec_fmt_pm.h"
#include "vdec_fmt_dmabuf.h"
#include "vdec_fmt_utils.h"
#include <linux/clk.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <soc/mediatek/smi.h>
#include "mtk-interconnect.h"
#include <linux/timekeeping.h>
void fmt_get_module_clock_by_name(struct mtk_vdec_fmt *fmt,
const char *clkName, struct clk **clk_module)
{
*clk_module = of_clk_get_by_name(fmt->dev->of_node, clkName);
if (IS_ERR(*clk_module)) {
fmt_err("cannot get module clock:%s", clkName);
*clk_module = NULL;
} else
fmt_debug(0, "get module clock:%s", clkName);
}
/* Common Clock Framework */
void fmt_init_pm(struct mtk_vdec_fmt *fmt)
{
fmt_debug(0, "+");
fmt_get_module_clock_by_name(fmt, "MT_CG_VDEC",
&fmt->clk_VDEC);
fmt_get_module_clock_by_name(fmt, "MT_CG_MINI_MDP",
&fmt->clk_MINI_MDP);
pm_runtime_enable(fmt->dev);
}
int32_t fmt_clock_on(struct mtk_vdec_fmt *fmt)
{
int ret = 0;
mtk_mmdvfs_enable_vcp(true, VCP_PWR_USR_VFMT);
cmdq_mbox_enable(fmt->clt_fmt[0]->chan);
if (fmt->fmtLarb) {
ret = mtk_smi_larb_get(fmt->fmtLarb);
if (ret) {
fmt_debug(0, "mtk_smi_larb_get failed %d",
ret);
return ret;
}
}
if (fmt->clk_VDEC) {
ret = clk_prepare_enable(fmt->clk_VDEC);
if (ret)
fmt_debug(0, "clk_prepare_enable VDEC_SOC failed %d", ret);
}
if (fmt->clk_MINI_MDP) {
ret = clk_prepare_enable(fmt->clk_MINI_MDP);
if (ret)
fmt_debug(0, "clk_prepare_enable VDEC_MINI_MDP failed %d", ret);
}
cmdq_util_prebuilt_init(CMDQ_PREBUILT_VFMT);
return ret;
}
int32_t fmt_clock_off(struct mtk_vdec_fmt *fmt)
{
if (fmt->clk_MINI_MDP)
clk_disable_unprepare(fmt->clk_MINI_MDP);
if (fmt->clk_VDEC)
clk_disable_unprepare(fmt->clk_VDEC);
if (fmt->fmtLarb)
mtk_smi_larb_put(fmt->fmtLarb);
cmdq_mbox_disable(fmt->clt_fmt[0]->chan);
atomic_set(&fmt->fmt_error, 0);
mtk_mmdvfs_enable_vcp(false, VCP_PWR_USR_VFMT);
return 0;
}
void fmt_prepare_dvfs_emi_bw(struct mtk_vdec_fmt *fmt)
{
int ret;
struct dev_pm_opp *opp = 0;
unsigned long freq = 0;
int i = 0;
ret = dev_pm_opp_of_add_table(fmt->dev);
if (ret < 0) {
fmt_debug(0, "Failed to get opp table (%d)\n", ret);
return;
}
fmt->fmt_reg = devm_regulator_get_optional(fmt->dev,
"mmdvfs-dvfsrc-vcore");
if (IS_ERR_OR_NULL(fmt->fmt_reg)) {
fmt_debug(0, "Failed to get regulator\n");
fmt->dvfs_clk = devm_clk_get(fmt->dev, "mmdvfs_clk");
if (IS_ERR_OR_NULL(fmt->dvfs_clk)) {
fmt_debug(0, "Failed to get mmdvfs clk\n");
return;
}
}
fmt->fmt_freq_cnt = dev_pm_opp_get_opp_count(fmt->dev);
freq = 0;
while (!IS_ERR(opp =
dev_pm_opp_find_freq_ceil(fmt->dev, &freq))) {
fmt->fmt_freqs[i] = freq;
freq++;
i++;
dev_pm_opp_put(opp);
}
i = 0;
for (i = 0; i < FMT_PORT_NUM; i++)
fmt->fmt_qos_req[i] = 0;
i = 0;
fmt->fmt_qos_req[i++] = of_mtk_icc_get(fmt->dev, "path_mini_mdp_r0");
fmt->fmt_qos_req[i++] = of_mtk_icc_get(fmt->dev, "path_mini_mdp_r1");
fmt->fmt_qos_req[i++] = of_mtk_icc_get(fmt->dev, "path_mini_mdp_w0");
fmt->fmt_qos_req[i++] = of_mtk_icc_get(fmt->dev, "path_mini_mdp_w1");
}
void fmt_unprepare_dvfs_emi_bw(void)
{
}
void fmt_start_dvfs_emi_bw(struct mtk_vdec_fmt *fmt, struct fmt_pmqos pmqos_param, int id)
{
struct dev_pm_opp *opp = 0;
int volt = 0;
int ret = 0;
unsigned long request_freq;
u64 request_freq64;
struct timespec64 curr_time;
s32 duration;
u32 rdma_bandwidth, wdma_bandwidth;
fmt_debug(1, "tv_sec %d tv_usec %d pixel_size %d rdma_datasize %d wdma_datasize %d",
pmqos_param.tv_sec,
pmqos_param.tv_usec,
pmqos_param.pixel_size,
pmqos_param.rdma_datasize,
pmqos_param.wdma_datasize);
ktime_get_real_ts64(&curr_time);
fmt_debug(1, "curr time tv_sec %ld tv_nsec %ld", curr_time.tv_sec, curr_time.tv_nsec);
FMT_TIMER_GET_DURATION_IN_MS(curr_time, pmqos_param, duration);
request_freq64 = (u64)pmqos_param.pixel_size * 1000 / duration;
request_freq = (unsigned long)((request_freq64 > ULONG_MAX) ? ULONG_MAX : request_freq64);
fmt_debug(1, "request_freq %lu", request_freq);
if (request_freq > fmt->fmt_freqs[fmt->fmt_freq_cnt-1]) {
request_freq = fmt->fmt_freqs[fmt->fmt_freq_cnt-1];
fmt_debug(1, "request_freq %lu limited by highest fmt_freq %lu",
request_freq, fmt->fmt_freqs[fmt->fmt_freq_cnt-1]);
}
if (!IS_ERR_OR_NULL(fmt->fmt_reg)) {
opp = dev_pm_opp_find_freq_ceil(fmt->dev,
&request_freq);
fmt_debug(1, "actual request freq %lu", request_freq);
volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
ret = regulator_set_voltage(fmt->fmt_reg, volt, INT_MAX);
if (ret)
fmt_debug(0, "Failed to set regulator voltage %d\n",
volt);
} else if (!IS_ERR_OR_NULL(fmt->dvfs_clk)) {
fmt_debug(1, "actual request freq %lu", request_freq);
ret = clk_set_rate(fmt->dvfs_clk, request_freq);
if (ret)
fmt_debug(0, "Failed to set mmdvfs rate %d\n", request_freq);
}
if (id >= 0 && id < fmt->gce_th_num) {
FMT_BANDWIDTH(pmqos_param.rdma_datasize, pmqos_param.pixel_size,
request_freq, rdma_bandwidth);
FMT_BANDWIDTH(pmqos_param.wdma_datasize, pmqos_param.pixel_size,
request_freq, wdma_bandwidth);
fmt_debug(1, "MMQoS: id:%d, data_size: (%d, %d), req_freq: %d, pix_size: %d",
id, pmqos_param.rdma_datasize, pmqos_param.wdma_datasize,
request_freq, pmqos_param.pixel_size);
if (fmt->fmt_qos_req[id] != 0 && fmt->fmt_qos_req[id+2] != 0) {
if (rdma_bandwidth + wdma_bandwidth <= fmt->min_qos_threshold) {
mtk_icc_set_bw(fmt->fmt_qos_req[id],
MBps_to_icc(0), 0);
mtk_icc_set_bw(fmt->fmt_qos_req[id+2],
MBps_to_icc(0), 0);
fmt_debug(1, "MMQoS: r_bw: %d(0), w_bw: %d(0), lower than min qos",
rdma_bandwidth, wdma_bandwidth);
} else {
mtk_icc_set_bw(fmt->fmt_qos_req[id],
MBps_to_icc(rdma_bandwidth), 0);
mtk_icc_set_bw(fmt->fmt_qos_req[id+2],
MBps_to_icc(wdma_bandwidth), 0);
fmt_debug(1, "MMQoS: r_bw: %d, w_bw: %d",
rdma_bandwidth, wdma_bandwidth);
}
}
}
}
void fmt_end_dvfs_emi_bw(struct mtk_vdec_fmt *fmt, int id)
{
struct dev_pm_opp *opp = 0;
int volt = 0;
int ret = 0;
if (!IS_ERR_OR_NULL(fmt->fmt_reg)) {
fmt_debug(1, "request freq %lu", fmt->fmt_freqs[0]);
opp = dev_pm_opp_find_freq_ceil(fmt->dev,
&fmt->fmt_freqs[0]);
volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
ret = regulator_set_voltage(fmt->fmt_reg, volt, INT_MAX);
if (ret) {
fmt_debug(0, "Failed to set regulator voltage %d\n",
volt);
}
} else if (!IS_ERR_OR_NULL(fmt->dvfs_clk)) {
fmt_debug(1, "request freq 0\n");
ret = clk_set_rate(fmt->dvfs_clk, 0);
if (ret)
fmt_debug(0, "Failed to set mmdvfs rate 0\n");
}
if (id >= 0 && id < fmt->gce_th_num) {
if (fmt->fmt_qos_req[id] != 0) {
mtk_icc_set_bw(fmt->fmt_qos_req[id],
MBps_to_icc(0), 0);
}
if (fmt->fmt_qos_req[id+2] != 0) {
mtk_icc_set_bw(fmt->fmt_qos_req[id+2],
MBps_to_icc(0), 0);
}
}
}