/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2016 MediaTek Inc. */ #include "vdec_fmt_pm.h" #include "vdec_fmt_ion.h" #include "vdec_fmt_utils.h" #include #include #include #include "smi_public.h" static struct mtk_pm_qos_request fmt_qos_req_f; static u32 fmt_freq_step_size; static u64 fmt_freq_steps[MAX_FREQ_STEP]; static struct plist_head fmt_rlist[FMT_CORE_NUM]; static struct mm_qos_request fmt_rdma_request[FMT_CORE_NUM]; static struct mm_qos_request fmt_wdma_request[FMT_CORE_NUM]; #ifdef CONFIG_MTK_PSEUDO_M4U #include #include "mach/pseudo_m4u.h" #include "smi_port.h" #endif 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); 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); } int32_t fmt_clock_on(struct mtk_vdec_fmt *fmt) { int ret = 0; #ifdef CONFIG_MTK_PSEUDO_M4U int i, larb_id; struct M4U_PORT_STRUCT port; #endif smi_bus_prepare_enable(SMI_LARB4, "FMT"); ret = clk_prepare_enable(fmt->clk_VDEC); if (ret) fmt_debug(0, "clk_prepare_enable VDEC_SOC failed %d", ret); #ifdef CONFIG_MTK_PSEUDO_M4U larb_id = 4; //enable 34bits port configs for (i = 12; i < 14; i++) { port.ePortID = MTK_M4U_ID(larb_id, i); port.Direction = 0; port.Distance = 1; port.domain = 0; port.Security = 0; port.Virtuality = 1; m4u_config_port(&port); fmt_debug(1, "port.ePortID %d m4u_config_port", port.ePortID); } #endif return ret; } int32_t fmt_clock_off(struct mtk_vdec_fmt *fmt) { clk_disable_unprepare(fmt->clk_VDEC); smi_bus_disable_unprepare(SMI_LARB4, "FMT"); return 0; } void fmt_prepare_dvfs_emi_bw(void) { int ret, i; mtk_pm_qos_add_request(&fmt_qos_req_f, PM_QOS_VDEC_FREQ, PM_QOS_DEFAULT_VALUE); fmt_freq_step_size = 1; ret = mmdvfs_qos_get_freq_steps(PM_QOS_VDEC_FREQ, &fmt_freq_steps[0], &fmt_freq_step_size); if (ret < 0) fmt_err("Failed to get fmt freq steps (%d)", ret); for (i = 0; i < fmt_freq_step_size; i++) fmt_debug(1, "freq_steps[%d] %ld", i, fmt_freq_steps[i]); plist_head_init(&fmt_rlist[0]); mm_qos_add_request(&fmt_rlist[0], &fmt_rdma_request[0], M4U_PORT_L4_MINI_MDP_R0_EXT); mm_qos_add_request(&fmt_rlist[0], &fmt_wdma_request[0], M4U_PORT_L4_MINI_MDP_W0_EXT); } void fmt_unprepare_dvfs_emi_bw(void) { int freq_idx = 0; freq_idx = (fmt_freq_step_size == 0) ? 0 : (fmt_freq_step_size - 1); mtk_pm_qos_update_request(&fmt_qos_req_f, fmt_freq_steps[freq_idx]); mtk_pm_qos_remove_request(&fmt_qos_req_f); mm_qos_remove_all_request(&fmt_rlist[0]); } void fmt_start_dvfs_emi_bw(struct fmt_pmqos pmqos_param) { u64 request_freq; struct timeval curr_time; s32 duration; u32 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); do_gettimeofday(&curr_time); fmt_debug(1, "curr time tv_sec %d tv_usec %d", curr_time.tv_sec, curr_time.tv_usec); FMT_TIMER_GET_DURATION_IN_US(curr_time, pmqos_param, duration); request_freq = pmqos_param.pixel_size / duration; if (request_freq > fmt_freq_steps[0]) request_freq = fmt_freq_steps[0]; fmt_debug(1, "request_freq %d", request_freq); mtk_pm_qos_update_request(&fmt_qos_req_f, request_freq); FMT_BANDWIDTH(pmqos_param.rdma_datasize, pmqos_param.pixel_size, request_freq, bandwidth); mm_qos_set_request(&fmt_rdma_request[0], bandwidth, 0, BW_COMP_NONE); fmt_debug(1, "rdma bandwidth %d", bandwidth); FMT_BANDWIDTH(pmqos_param.wdma_datasize, pmqos_param.pixel_size, request_freq, bandwidth); mm_qos_set_request(&fmt_wdma_request[0], bandwidth, 0, BW_COMP_NONE); fmt_debug(1, "wdma bandwidth %d", bandwidth); mm_qos_update_all_request(&fmt_rlist[0]); } void fmt_end_dvfs_emi_bw(void) { mtk_pm_qos_update_request(&fmt_qos_req_f, 0); mm_qos_set_request(&fmt_rdma_request[0], 0, 0, BW_COMP_NONE); mm_qos_set_request(&fmt_wdma_request[0], 0, 0, BW_COMP_NONE); mm_qos_update_all_request(&fmt_rlist[0]); } void fmt_dump_addr_reg(struct mtk_vdec_fmt *fmt, int port) { int i; switch (port) { case M4U_PORT_L4_MINI_MDP_R0_EXT: for (i = 0; i < 313; i++) fmt_debug(0, "FMT RDMA0(0x%x) 0x%x", fmt->map_base[0].base + i*4, FMT_GET32(fmt->map_base[0].va + i*4)); for (i = 960; i < 982; i++) fmt_debug(0, "FMT RDMA0(0x%x) 0x%x", fmt->map_base[0].base + i*4, FMT_GET32(fmt->map_base[0].va + i*4)); break; case M4U_PORT_L4_MINI_MDP_W0_EXT: for (i = 0; i < 60; i++) fmt_debug(0, "FMT WROT0(0x%x) 0x%x", fmt->map_base[1].base + i*4, FMT_GET32(fmt->map_base[1].va + i*4)); for (i = 960; i < 973; i++) fmt_debug(0, "FMT WROT0(0x%x) 0x%x", fmt->map_base[1].base + i*4, FMT_GET32(fmt->map_base[1].va + i*4)); break; default: break; } } #ifdef CONFIG_MTK_IOMMU_V2 enum mtk_iommu_callback_ret_t fmt_translation_fault_callback( int port, unsigned long mva, void *data) { struct mtk_vdec_fmt *fmt = (struct mtk_vdec_fmt *) data; fmt_debug(0, "TF callback, port:%d, mva:0x%x", port, mva); fmt_dump_addr_reg(fmt, port); return MTK_IOMMU_CALLBACK_HANDLED; } #endif void fmt_translation_fault_callback_setting(struct mtk_vdec_fmt *fmt) { #ifdef CONFIG_MTK_IOMMU_V2 mtk_iommu_register_fault_callback(M4U_PORT_L4_MINI_MDP_R0_EXT, (mtk_iommu_fault_callback_t)fmt_translation_fault_callback, fmt); mtk_iommu_register_fault_callback(M4U_PORT_L4_MINI_MDP_W0_EXT, (mtk_iommu_fault_callback_t)fmt_translation_fault_callback, fmt); #endif }