// 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 #include #include #include #include #include "mtk-interconnect.h" #include 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); } } }