// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: Tiffany Lin */ #include #include #include #include #include #include #include #include //#include "smi_public.h" #include "mtk_vcodec_dec_pm.h" #include "mtk_vcodec_dec_pm_plat.h" #include "mtk_vcodec_util.h" #include "mtk_vcu.h" #ifdef CONFIG_MTK_PSEUDO_M4U #include #include "mach/pseudo_m4u.h" #include "smi_port.h" #endif #if IS_ENABLED(CONFIG_MTK_IOMMU_MISC_DBG) #include "iommu_debug.h" #endif #if IS_ENABLED(CONFIG_MTK_TINYSYS_VCP_SUPPORT) extern void vdec_dump_mem_buf(unsigned long h_vdec); #endif static char *dec_port_name[NUM_MAX_VDEC_M4U_PORT+1] = { [VDEC_M4U_PORT_MC] = "MC", [VDEC_M4U_PORT_UFO] = "UFO", [VDEC_M4U_PORT_PP] = "PP", [VDEC_M4U_PORT_PRED_RD] = "PRED_RD", [VDEC_M4U_PORT_PRED_WR] = "PRED_WR", [VDEC_M4U_PORT_PPWRAP] = "PPWRAP", [VDEC_M4U_PORT_TILE] = "TILE", [VDEC_M4U_PORT_VLD] = "VLD", [VDEC_M4U_PORT_VLD2] = "VLD2", [VDEC_M4U_PORT_AVC_MV] = "MV", [VDEC_M4U_PORT_RG_CTRL_DMA] = "RG_CTRL_DMA", [VDEC_M4U_PORT_UFO_ENC] = "UFO_ENC", [VDEC_M4U_PORT_LAT0_VLD] = "LAT_VLD", [VDEC_M4U_PORT_LAT0_VLD2] = "LAT_VLD2", [VDEC_M4U_PORT_LAT0_AVC_MV] = "LAT_MV", [VDEC_M4U_PORT_LAT0_PRED_RD] = "LAT_PRED_RD", [VDEC_M4U_PORT_LAT0_TILE] = "LAT_TILE", [VDEC_M4U_PORT_LAT0_WDMA] = "LAT_WDMA", [VDEC_M4U_PORT_LAT0_RG_CTRL_DMA] = "LAT_RG_CTRL_DMA", [VDEC_M4U_PORT_LAT0_MC] = "LAT_MC", [VDEC_M4U_PORT_LAT0_UFO] = "LAT_UFO", [VDEC_M4U_PORT_LAT0_UFO_C] = "LAT_UFO_C", [VDEC_M4U_PORT_VIDEO_UP_SEC] = "VIDEO_UP_SEC", [VDEC_M4U_PORT_VIDEO_UP_NOR] = "VIDEO_UP_NOR", [VDEC_M4U_PORT_UP_1] = "UP_1", [VDEC_M4U_PORT_UP_2] = "UP_2", [VDEC_M4U_PORT_UP_3] = "UP_3", [VDEC_M4U_PORT_UP_4] = "UP_4", [NUM_MAX_VDEC_M4U_PORT] = "UNKNOWN", }; void mtk_dec_init_ctx_pm(struct mtk_vcodec_ctx *ctx) { ctx->input_driven = 0; ctx->decoded_frame_cnt = 0; ctx->last_decoded_frame_cnt = 0; ctx->is_active = 1; } int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) { int ret = 0; #ifndef FPGA_PWRCLK_API_DISABLE struct device_node *node; struct platform_device *pdev; struct mtk_vcodec_pm *pm; int larb_index; int i = 0; int clk_id = 0; const char *clk_name; struct mtk_vdec_clks_data *clks_data; pdev = mtkdev->plat_dev; pm = &mtkdev->pm; pm->dev = &pdev->dev; pm->mtkdev = mtkdev; clks_data = &pm->vdec_clks_data; if (!pdev->dev.of_node) { mtk_v4l2_err("[VCODEC][ERROR] DTS went wrong..."); return -ENODEV; } pm->vdecpll_ck = devm_clk_get(&pdev->dev, "vdecpll_ck"); if (IS_ERR(pm->vdecpll_ck)) { mtk_v4l2_debug(2, "[VCODEC] Unable to found vdecpll_ck\n"); } else { ret = clk_set_rate(pm->vdecpll_ck, 680 * 1000 * 1000); if (ret) mtk_v4l2_err("set vdecpll_ck fail, ret:%d\n", ret); } // parse "mediatek,larbs" for (larb_index = 0; larb_index < MTK_VDEC_MAX_LARB_COUNT; larb_index++) { node = of_parse_phandle(pdev->dev.of_node, "mediatek,larbs", larb_index); if (!node) break; pdev = of_find_device_by_node(node); if (WARN_ON(!pdev)) { of_node_put(node); return -1; } pm->larbvdecs[larb_index] = &pdev->dev; mtk_v4l2_debug(2, "larbvdecs[%d] = %p", larb_index, pm->larbvdecs[larb_index]); pdev = mtkdev->plat_dev; } memset(clks_data, 0x00, sizeof(struct mtk_vdec_clks_data)); while (!of_property_read_string_index( pdev->dev.of_node, "clock-names", clk_id, &clk_name)) { mtk_v4l2_debug(2, "init clock, id: %d, name: %s", clk_id, clk_name); pm->vdec_clks[clk_id] = devm_clk_get(&pdev->dev, clk_name); if (IS_ERR(pm->vdec_clks[clk_id])) { mtk_v4l2_err( "[VCODEC][ERROR] Unable to devm_clk_get id: %d, name: %s\n", clk_id, clk_name); return PTR_ERR(pm->vdec_clks[clk_id]); } if (IS_SPECIFIC_CLK_TYPE(clk_name, MTK_VDEC_CLK_MAIN_PREFIX)) { clks_data->main_clks[clks_data->main_clks_len].clk_id = clk_id; clks_data->main_clks[clks_data->main_clks_len].clk_name = clk_name; clks_data->main_clks_len++; } else if (IS_SPECIFIC_CLK_TYPE(clk_name, MTK_VDEC_CLK_SOC_PREFIX)) { clks_data->soc_clks[clks_data->soc_clks_len].clk_id = clk_id; clks_data->soc_clks[clks_data->soc_clks_len].clk_name = clk_name; clks_data->soc_clks_len++; } else if (IS_SPECIFIC_CLK_TYPE(clk_name, MTK_VDEC_CLK_CORE_PREFIX)) { clks_data->core_clks[clks_data->core_clks_len].clk_id = clk_id; clks_data->core_clks[clks_data->core_clks_len].clk_name = clk_name; clks_data->core_clks_len++; } else if (IS_SPECIFIC_CLK_TYPE(clk_name, MTK_VDEC_CLK_LAT_PREFIX)) { clks_data->lat_clks[clks_data->lat_clks_len].clk_id = clk_id; clks_data->lat_clks[clks_data->lat_clks_len].clk_name = clk_name; clks_data->lat_clks_len++; } clk_id++; } #if DEBUG_GKI // dump main clocks for (i = 0; i < clks_data->main_clks_len; i++) { mtk_v4l2_debug(8, "main_clks id: %d, name: %s", clks_data->main_clks[i].clk_id, clks_data->main_clks[i].clk_name); } // dump soc clocks for (i = 0; i < clks_data->soc_clks_len; i++) { mtk_v4l2_debug(8, "core_clks id: %d, name: %s", clks_data->soc_clks[i].clk_id, clks_data->soc_clks[i].clk_name); } // dump core clocks for (i = 0; i < clks_data->core_clks_len; i++) { mtk_v4l2_debug(8, "core_clks id: %d, name: %s", clks_data->core_clks[i].clk_id, clks_data->core_clks[i].clk_name); } // dump lat clocks for (i = 0; i < clks_data->lat_clks_len; i++) { mtk_v4l2_debug(8, "lat_clks id: %d, name: %s", clks_data->lat_clks[i].clk_id, clks_data->lat_clks[i].clk_name); } #endif if (pm->mtkdev->vdec_hw_ipm == VCODEC_IPM_V2) { atomic_set(&pm->dec_active_cnt, 0); memset(pm->vdec_racing_info, 0, sizeof(pm->vdec_racing_info)); mutex_init(&pm->dec_racing_info_mutex); } pm_runtime_enable(&pdev->dev); #endif return ret; } void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev) { #if DEC_DVFS mutex_lock(&dev->dec_dvfs_mutex); mutex_unlock(&dev->dec_dvfs_mutex); #endif pm_runtime_disable(dev->pm.dev); } void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) { int ret, larb_index; struct mtk_vcodec_dev *dev = container_of(pm, struct mtk_vcodec_dev, pm); atomic_inc(&dev->dec_larb_ref_cnt); for (larb_index = 0; larb_index < MTK_VDEC_MAX_LARB_COUNT; larb_index++) { if (pm->larbvdecs[larb_index]) { ret = mtk_smi_larb_get(pm->larbvdecs[larb_index]); if (ret) mtk_v4l2_err("Failed to get vdec larb. index: %d", larb_index); } } } void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) { int larb_index; int hw_lock_cnt = 0, i; struct mtk_vcodec_dev *dev = container_of(pm, struct mtk_vcodec_dev, pm); if (atomic_read(&dev->dec_larb_ref_cnt) <= 0) { mtk_v4l2_err("dec_larb_ref_cnt %d invalid !!", atomic_read(&dev->dec_larb_ref_cnt)); // BUG(); // return; } for (i = 0; i < MTK_VDEC_HW_NUM; i++) hw_lock_cnt += atomic_read(&dev->dec_hw_active[i]); if (atomic_read(&dev->dec_larb_ref_cnt) == 1 && hw_lock_cnt > 0) { mtk_v4l2_err("error off last larb ref cnt (%d) when some hw locked %d (%d %d)", atomic_read(&dev->dec_larb_ref_cnt), hw_lock_cnt, atomic_read(&dev->dec_hw_active[MTK_VDEC_LAT]), atomic_read(&dev->dec_hw_active[MTK_VDEC_CORE])); // BUG(); dump_stack(); // return; } atomic_dec(&dev->dec_larb_ref_cnt); for (larb_index = 0; larb_index < MTK_VDEC_MAX_LARB_COUNT; larb_index++) { if (pm->larbvdecs[larb_index]) mtk_smi_larb_put(pm->larbvdecs[larb_index]); } } #ifdef VDEC_DEBUG_DUMP static void mtk_vdec_hw_break_dump( void __iomem *reg_addr, char *debug_str, int off_start, int off_end) { int idx, cnt, total, remainder, off[4]; unsigned long val[4]; if (reg_addr > 0 && off_start >= 0 && off_end >= 0 && off_end >= off_start) { total = off_end - off_start + 1; remainder = total - ((total >> 2) << 2); for (idx = off_start; idx < off_start + remainder; idx++) { off[0] = idx; val[0] = readl(reg_addr + (off[0] << 2)); mtk_v4l2_err("[DEBUG][%s] 0x%x(%d) = 0x%lx", debug_str, off[0] << 2, off[0], val[0]); } for (; idx <= off_end; idx += 4) { for (cnt = 0; cnt < 4; cnt++) { off[cnt] = idx + cnt; val[cnt] = readl(reg_addr + (off[cnt] << 2)); } mtk_v4l2_err("[DEBUG][%s] 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx", debug_str, off[0] << 2, off[0], val[0], off[1] << 2, off[1], val[1], off[2] << 2, off[2], val[2], off[3] << 2, off[3], val[3]); } } } static void mtk_vdec_hw_break_vld_top_dump( void __iomem *vld_top_addr, char *debug_str) { int vld_top_offset[7] = {33, 41, 50, 51, 64, 65, 94}; int idx, off[7]; unsigned long val[7]; if (vld_top_addr > 0) { for (idx = 0; idx < 7; idx++) { off[idx] = vld_top_offset[idx]; val[idx] = readl(vld_top_addr + (off[idx] << 2)); } mtk_v4l2_err("[DEBUG][%s] 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx", debug_str, off[0] << 2, off[0], val[0], off[1] << 2, off[1], val[1], off[2] << 2, off[2], val[2], off[3] << 2, off[3], val[3], off[4] << 2, off[4], val[4], off[5] << 2, off[5], val[5], off[6] << 2, off[6], val[6]); mtk_vdec_hw_break_dump( vld_top_addr, debug_str, 68, 112); } } static void mtk_vdec_hw_break(struct mtk_vcodec_dev *dev, int hw_id) { u32 cg_status = 0, ufo_cg_status = 0; void __iomem *vdec_misc_addr = dev->dec_reg_base[VDEC_MISC]; void __iomem *vdec_vld_addr = dev->dec_reg_base[VDEC_VLD]; void __iomem *vdec_vld_top_addr = dev->dec_reg_base[VDEC_VLD] + 0x800; void __iomem *vdec_gcon_addr = dev->dec_reg_base[VDEC_SYS]; void __iomem *vdec_ufo_addr = dev->dec_reg_base[VDEC_BASE] + 0x800; void __iomem *vdec_lat_misc_addr = dev->dec_reg_base[VDEC_LAT_MISC]; void __iomem *lat_wdma_addr = dev->dec_reg_base[VDEC_LAT_MISC] + 0x800; void __iomem *vdec_lat_vld_addr = dev->dec_reg_base[VDEC_LAT_VLD]; void __iomem *vdec_lat_vld_top_addr = dev->dec_reg_base[VDEC_LAT_VLD] + 0x800; void __iomem *vdec_lat_avc_vld_addr = dev->dec_reg_base[VDEC_LAT_AVC_VLD]; void __iomem *vdec_avc_vld_addr = dev->dec_reg_base[VDEC_AVC_VLD]; struct mtk_vcodec_ctx *ctx = NULL; struct timespec64 tv_start; struct timespec64 tv_end; s32 usec, timeout = 20000; u32 fourcc; u32 is_ufo = 0; if (hw_id == MTK_VDEC_CORE) { ctx = dev->curr_dec_ctx[hw_id]; if (ctx) fourcc = ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc; else fourcc = v4l2_fourcc('U', 'N', 'K', 'N'); if (vdec_vld_addr == NULL || vdec_misc_addr == NULL) { mtk_v4l2_debug(4, "VDEC codec:0x%08x(%c%c%c%c) HW break fail since vdec_vld_addr 0x%x vdec_misc_addr 0x%x", fourcc, fourcc & 0xFF, (fourcc >> 8) & 0xFF, (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF, vdec_vld_addr, vdec_misc_addr); return; } if (fourcc != V4L2_PIX_FMT_AV1 && dev->dec_reg_base[VDEC_BASE] != NULL) is_ufo = readl(vdec_ufo_addr + 0x08C) & 0x1; /* hw break */ writel((readl(vdec_misc_addr + 0x0100) | 0x1), vdec_misc_addr + 0x0100); if (is_ufo) writel((readl(vdec_ufo_addr + 0x01C) & 0xFFFFFFFD), vdec_ufo_addr + 0x01C); mtk_vdec_do_gettimeofday(&tv_start); cg_status = readl(vdec_misc_addr + 0x0104); if (is_ufo) ufo_cg_status = readl(vdec_ufo_addr + 0x08C); while (((cg_status & 0x11) != 0x11) || (is_ufo && ((ufo_cg_status & 0x11000) != 0x11000))) { mtk_vdec_do_gettimeofday(&tv_end); usec = (tv_end.tv_sec - tv_start.tv_sec) * 1000000 + (tv_end.tv_nsec - tv_start.tv_nsec); if (usec > timeout) { mtk_v4l2_err("VDEC HW break timeout. codec:0x%08x(%c%c%c%c) ufo %d", fourcc, fourcc & 0xFF, (fourcc >> 8) & 0xFF, (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF, is_ufo); if (timeout == 20000) timeout = 1000000; else if (timeout == 1000000) { mtk_vdec_hw_break_dump( vdec_gcon_addr, "GCON", 0, 0); mtk_vdec_hw_break_dump( vdec_gcon_addr, "GCON", 6, 6); mtk_vdec_hw_break_dump( vdec_misc_addr, "MISC", 64, 79); if (is_ufo) mtk_v4l2_err("[DEBUG][UFO] 0x%x(%d) = 0x%lx", 0x08C, 0x08C >> 2, ufo_cg_status); mtk_vdec_hw_break_vld_top_dump( vdec_vld_top_addr, "VLD_TOP"); mtk_vdec_hw_break_dump( vdec_vld_addr, "VLD", 33, 255); mtk_vdec_hw_break_dump( vdec_avc_vld_addr, "AVC_VLD", 0, 0); mtk_vdec_hw_break_dump( vdec_avc_vld_addr, "AVC_VLD", 33, 141); mtk_vdec_hw_break_dump( vdec_avc_vld_addr, "AVC_VLD", 145, 511); mtk_smi_dbg_hang_detect("VDEC_CORE"); /* v4l2_aee_print( * "%s %p codec:0x%08x(%c%c%c%c) hw break timeout\n", * __func__, ctx, fourcc, * fourcc & 0xFF, (fourcc >> 8) & 0xFF, * (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF); */ break; } mtk_vdec_do_gettimeofday(&tv_start); //smi_debug_bus_hang_detect(0, "VCODEC"); } cg_status = readl(vdec_misc_addr + 0x0104); if (is_ufo) ufo_cg_status = readl(vdec_ufo_addr + 0x08C); } /* sw reset */ if (is_ufo) writel((readl(vdec_ufo_addr + 0x01C) | 0x2), vdec_ufo_addr + 0x01C); writel(0x1, vdec_vld_addr + 0x0108); writel(0x0, vdec_vld_addr + 0x0108); } else if (dev->pm.mtkdev->vdec_hw_ipm == VCODEC_IPM_V2 && hw_id == MTK_VDEC_LAT) { ctx = dev->curr_dec_ctx[hw_id]; if (ctx) fourcc = ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc; else fourcc = v4l2_fourcc('U', 'N', 'K', 'N'); if (vdec_lat_vld_addr == NULL || vdec_lat_misc_addr == NULL) { mtk_v4l2_debug(4, "VDEC codec:0x%08x(%c%c%c%c) HW break fail since vdec_lat_vld_addr 0x%x vdec_lat_misc_addr 0x%x", fourcc, fourcc & 0xFF, (fourcc >> 8) & 0xFF, (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF, vdec_lat_vld_addr, vdec_lat_misc_addr); return; } /* hw break */ writel((readl(vdec_lat_misc_addr + 0x0100) | 0x1), vdec_lat_misc_addr + 0x0100); mtk_vdec_do_gettimeofday(&tv_start); cg_status = readl(vdec_lat_misc_addr + 0x0104); while (!((cg_status & 0x1) && (cg_status & 0x10))) { mtk_vdec_do_gettimeofday(&tv_end); usec = (tv_end.tv_sec - tv_start.tv_sec) * 1000000 + (tv_end.tv_nsec - tv_start.tv_nsec); if (usec > timeout) { mtk_v4l2_err("VDEC HW %d break timeout. codec:0x%08x(%c%c%c%c)", hw_id, fourcc, fourcc & 0xFF, (fourcc >> 8) & 0xFF, (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF); if (timeout == 20000) timeout = 1000000; else if (timeout == 1000000) { mtk_vdec_hw_break_dump( vdec_lat_misc_addr, "LAT_MISC", 64, 79); mtk_vdec_hw_break_vld_top_dump( vdec_lat_vld_top_addr, "LAT_VLD_TOP"); mtk_vdec_hw_break_dump( vdec_lat_vld_addr, "LAT_VLD", 33, 255); mtk_vdec_hw_break_dump( vdec_lat_avc_vld_addr, "LAT_AVC_VLD", 0, 0); mtk_vdec_hw_break_dump( vdec_lat_avc_vld_addr, "LAT_AVC_VLD", 33, 141); mtk_vdec_hw_break_dump( vdec_lat_avc_vld_addr, "LAT_AVC_VLD", 145, 511); mtk_vdec_hw_break_dump( lat_wdma_addr, "LAT_WDMA", 0, 127); mtk_smi_dbg_hang_detect("VDEC_LAT"); /* v4l2_aee_print( * "%s %p codec:0x%08x(%c%c%c%c) hw %d break timeout\n", * __func__, ctx, fourcc, * fourcc & 0xFF, (fourcc >> 8) & 0xFF, * (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF, hw_id); */ break; } mtk_vdec_do_gettimeofday(&tv_start); //smi_debug_bus_hang_detect(0, "VCODEC"); } cg_status = readl(vdec_lat_misc_addr + 0x0104); } /* sw reset */ writel(0x1, vdec_lat_vld_addr + 0x0108); writel(0x0, vdec_lat_vld_addr + 0x0108); } else { mtk_v4l2_err("hw_id (%d) is unknown or unsupport\n", hw_id); } } #endif void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm, int hw_id) { #ifdef CONFIG_MTK_PSEUDO_M4U int i, larb_port_num, larb_id; struct M4U_PORT_STRUCT port; #endif #ifndef FPGA_PWRCLK_API_DISABLE int j, ret; struct mtk_vcodec_dev *dev; void __iomem *vdec_racing_addr; int clk_id; struct mtk_vdec_clks_data *clks_data; unsigned long flags; if (hw_id < 0 || hw_id >= MTK_VDEC_HW_NUM) { mtk_v4l2_err("invalid hw_id %d", hw_id); return; } time_check_start(MTK_FMT_DEC, hw_id); clks_data = &pm->vdec_clks_data; dev = container_of(pm, struct mtk_vcodec_dev, pm); atomic_inc(&dev->dec_clk_ref_cnt[hw_id]); mtk_vcodec_dec_pw_on(pm); // enable main clocks for (j = 0; j < clks_data->main_clks_len; j++) { clk_id = clks_data->main_clks[j].clk_id; ret = clk_prepare_enable(pm->vdec_clks[clk_id]); if (ret) mtk_v4l2_err("clk_prepare_enable id: %d, name: %s fail %d", clk_id, clks_data->main_clks[j].clk_name, ret); } // enable soc clocks for (j = 0; j < clks_data->soc_clks_len; j++) { clk_id = clks_data->soc_clks[j].clk_id; ret = clk_prepare_enable(pm->vdec_clks[clk_id]); if (ret) mtk_v4l2_err("clk_prepare_enable id: %d, name: %s fail %d", clk_id, clks_data->soc_clks[j].clk_name, ret); } if (hw_id == MTK_VDEC_CORE || hw_id == MTK_VDEC_CORE1) { // enable core clocks for (j = 0; j < clks_data->core_clks_len; j++) { clk_id = clks_data->core_clks[j].clk_id; ret = clk_prepare_enable(pm->vdec_clks[clk_id]); if (ret) mtk_v4l2_err("clk_prepare_enable id: %d, name: %s fail %d", clk_id, clks_data->core_clks[j].clk_name, ret); } } else if (hw_id == MTK_VDEC_LAT || hw_id == MTK_VDEC_LAT1) { // enable lat clocks for (j = 0; j < clks_data->lat_clks_len; j++) { clk_id = clks_data->lat_clks[j].clk_id; ret = clk_prepare_enable(pm->vdec_clks[clk_id]); if (ret) mtk_v4l2_err("clk_prepare_enable id: %d, name: %s fail %d", clk_id, clks_data->lat_clks[j].clk_name, ret); } } else mtk_v4l2_err("invalid hw_id %d", hw_id); if (!ret) { spin_lock_irqsave(&dev->dec_power_lock[hw_id], flags); dev->dec_is_power_on[hw_id] = true; spin_unlock_irqrestore(&dev->dec_power_lock[hw_id], flags); } if (pm->mtkdev->vdec_hw_ipm == VCODEC_IPM_V2) { mutex_lock(&pm->dec_racing_info_mutex); if (atomic_inc_return(&pm->dec_active_cnt) == 1) { /* restore racing info read/write ptr */ vdec_racing_addr = dev->dec_reg_base[VDEC_RACING_CTRL] + MTK_VDEC_RACING_INFO_OFFSET; for (j = 0; j < MTK_VDEC_RACING_INFO_SIZE; j++) writel(pm->vdec_racing_info[j], vdec_racing_addr + j * 4); } mutex_unlock(&pm->dec_racing_info_mutex); } time_check_end(MTK_FMT_DEC, hw_id, 50); #endif #ifdef CONFIG_MTK_PSEUDO_M4U time_check_start(MTK_FMT_DEC, hw_id); if (hw_id == MTK_VDEC_CORE) { larb_port_num = SMI_LARB4_PORT_NUM; larb_id = 4; //enable UFO port port.ePortID = M4U_PORT_L5_VDEC_UFO_ENC_EXT; port.Direction = 0; port.Distance = 1; port.domain = 0; port.Security = 0; port.Virtuality = 1; m4u_config_port(&port); } else if (hw_id == MTK_VDEC_LAT) { larb_port_num = SMI_LARB5_PORT_NUM; larb_id = 5; } //enable 34bits port configs & sram settings for (i = 0; i < larb_port_num; 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); } time_check_end(MTK_FMT_DEC, hw_id, 50); #endif } void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm, int hw_id) { #ifndef FPGA_PWRCLK_API_DISABLE struct mtk_vcodec_dev *dev; void __iomem *vdec_racing_addr; int i; int clk_id; struct mtk_vdec_clks_data *clks_data; unsigned long flags; if (hw_id < 0 || hw_id >= MTK_VDEC_HW_NUM) { mtk_v4l2_err("invalid hw_id %d", hw_id); return; } clks_data = &pm->vdec_clks_data; dev = container_of(pm, struct mtk_vcodec_dev, pm); if (atomic_read(&dev->dec_clk_ref_cnt[hw_id]) <= 0) { mtk_v4l2_err("dec_clk_ref_cnt[%d] %d invalid !!", hw_id, atomic_read(&dev->dec_larb_ref_cnt)); // BUG(); // return; } atomic_dec(&dev->dec_clk_ref_cnt[hw_id]); if (pm->mtkdev->vdec_hw_ipm == VCODEC_IPM_V2) { mutex_lock(&pm->dec_racing_info_mutex); if (atomic_dec_and_test(&pm->dec_active_cnt)) { /* backup racing info read/write ptr */ vdec_racing_addr = dev->dec_reg_base[VDEC_RACING_CTRL] + MTK_VDEC_RACING_INFO_OFFSET; for (i = 0; i < MTK_VDEC_RACING_INFO_SIZE; i++) pm->vdec_racing_info[i] = readl(vdec_racing_addr + i * 4); } mutex_unlock(&pm->dec_racing_info_mutex); } // remove for security, handle decode timeout hw break in vcp //mtk_vdec_hw_break(dev, hw_id); /* avoid translation fault callback dump reg not done */ spin_lock_irqsave(&dev->dec_power_lock[hw_id], flags); dev->dec_is_power_on[hw_id] = false; spin_unlock_irqrestore(&dev->dec_power_lock[hw_id], flags); // disable soc clocks if (clks_data->soc_clks_len > 0) { for (i = clks_data->soc_clks_len - 1; i >= 0; i--) { clk_id = clks_data->soc_clks[i].clk_id; clk_disable_unprepare(pm->vdec_clks[clk_id]); } } if (hw_id == MTK_VDEC_CORE || hw_id == MTK_VDEC_CORE1) { // disable core clocks if (clks_data->core_clks_len > 0) { for (i = clks_data->core_clks_len - 1; i >= 0; i--) { clk_id = clks_data->core_clks[i].clk_id; clk_disable_unprepare(pm->vdec_clks[clk_id]); } } } else if (hw_id == MTK_VDEC_LAT || hw_id == MTK_VDEC_LAT1) { // disable lat clocks if (clks_data->lat_clks_len > 0) { for (i = clks_data->lat_clks_len - 1; i >= 0; i--) { clk_id = clks_data->lat_clks[i].clk_id; clk_disable_unprepare(pm->vdec_clks[clk_id]); } } } else mtk_v4l2_err("invalid hw_id %d", hw_id); if (clks_data->main_clks_len > 0) { for (i = clks_data->main_clks_len - 1; i >= 0; i--) { clk_id = clks_data->main_clks[i].clk_id; clk_disable_unprepare(pm->vdec_clks[clk_id]); } } mtk_vcodec_dec_pw_off(pm); #endif } #ifdef VDEC_DEBUG_DUMP static void mtk_vdec_dump_addr_reg( struct mtk_vcodec_dev *dev, int hw_id, enum mtk_dec_dump_addr_type type) { struct mtk_vcodec_ctx *ctx; u32 fourcc; void __iomem *vld_addr = dev->dec_reg_base[VDEC_VLD]; void __iomem *mc_addr = dev->dec_reg_base[VDEC_MC]; void __iomem *mv_addr = dev->dec_reg_base[VDEC_MV]; void __iomem *ufo_addr = dev->dec_reg_base[VDEC_BASE] + 0x800; void __iomem *lat_vld_addr = dev->dec_reg_base[VDEC_LAT_VLD]; void __iomem *lat_wdma_addr = dev->dec_reg_base[VDEC_LAT_MISC] + 0x800; void __iomem *rctrl_addr = dev->dec_reg_base[VDEC_RACING_CTRL]; enum mtk_vcodec_ipm vdec_hw_ipm; unsigned long value, values[6]; bool is_ufo = false; int i, j, start, end; unsigned long flags; #define INPUT_LAT_VLD_NUM 7 const unsigned int input_lat_vld_reg[INPUT_LAT_VLD_NUM] = { 0xB0, 0xB4, 0xB8, 0x110, 0xEC, 0xF8, 0xFC}; // RPTR, VSTART, VEND, WPTR, VBAR, VWPTR, VRPTR #define OUTPUT_MC_NUM 2 const unsigned int output_mc_reg[OUTPUT_MC_NUM] = { 0x224, 0x228}; // PY_ADD, PC_ADD #define OUTPUT_UFO_MC_NUM 5 const unsigned int output_ufo_mc_reg[OUTPUT_UFO_MC_NUM] = { 0xB5C, 0xAE8, 0xAEC, 0xCE4, 0xCE8}; // YC_SEP, LEN_Y, LEN_C, LEN_Y_OFFSET, LEN_C_OFFSET #define OUTPUT_UFO_NUM 4 const unsigned int output_ufo_reg[OUTPUT_UFO_NUM] = { 0x7C, 0x80, 0x84, 0x88}; // LEN_Y, LEN_C, BS_Y, BS_C #define REF_MC_NUM 7 const unsigned int ref_mc_base[REF_MC_NUM] = { 0x3DC, 0xB60, 0x45C, 0xBE0, 0x4DC, 0xC60, 0xD28}; // P_L0_Y, P_L0_C, B_L0_Y, B_L0_C, B_L1_Y, B_L1_C, REF #define UBE_CORE_VLD_NUM 3 const unsigned int ube_core_vld_reg[UBE_CORE_VLD_NUM] = { 0xB0, 0xB4, 0xB8}; if (dev->pm.mtkdev == NULL) { mtk_v4l2_err("fail to get vdec_hw_ipm"); vdec_hw_ipm = VCODEC_IPM_V2; } else { vdec_hw_ipm = dev->pm.mtkdev->vdec_hw_ipm; } if (hw_id != MTK_VDEC_CORE && (hw_id != MTK_VDEC_LAT || vdec_hw_ipm == VCODEC_IPM_V1)) { mtk_v4l2_err("hw_id %d not support !!", hw_id); return; } if (vdec_hw_ipm == VCODEC_IPM_V1) lat_vld_addr = vld_addr; // for ipm v1 input buffer ctx = dev->curr_dec_ctx[hw_id]; if (ctx) fourcc = ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc; else fourcc = v4l2_fourcc('U', 'N', 'K', 'N'); spin_lock_irqsave(&dev->dec_power_lock[hw_id], flags); if (dev->dec_is_power_on[hw_id] == false) { mtk_v4l2_err("hw %d power is off !!", hw_id); spin_unlock_irqrestore(&dev->dec_power_lock[hw_id], flags); return; } if (hw_id == MTK_VDEC_CORE && fourcc != V4L2_PIX_FMT_AV1 && (ufo_addr - 0x800) != NULL) is_ufo = (readl(ufo_addr + 0x08C) & 0x1) == 0x1; switch (type) { case DUMP_VDEC_IN_BUF: if (lat_vld_addr == NULL) break; for (i = 0; i < INPUT_LAT_VLD_NUM; i++) { value = readl(lat_vld_addr + input_lat_vld_reg[i]); mtk_v4l2_err("[LAT][VLD] 0x%x(%d) = 0x%lx", input_lat_vld_reg[i], input_lat_vld_reg[i]/4, value); } break; case DUMP_VDEC_OUT_BUF: if (mc_addr == NULL) break; for (i = 0; i < OUTPUT_MC_NUM; i++) { value = readl(mc_addr + output_mc_reg[i]); mtk_v4l2_err("[CORE][MC] 0x%x(%d) = 0x%lx", output_mc_reg[i], output_mc_reg[i]/4, value); } if (is_ufo) { for (i = 0; i < OUTPUT_UFO_MC_NUM; i++) { value = readl(mc_addr + output_ufo_mc_reg[i]); mtk_v4l2_err("[CORE][MC] 0x%x(%d) = 0x%lx", output_ufo_mc_reg[i], output_ufo_mc_reg[i]/4, value); } if ((ufo_addr - 0x800) == NULL) break; for (i = 0; i < OUTPUT_UFO_NUM; i++) { value = readl(ufo_addr + output_ufo_reg[i]); mtk_v4l2_err("[CORE][UFO] 0x%x(%d) = 0x%lx", output_ufo_reg[i], output_ufo_reg[i]/4, value); } } break; case DUMP_VDEC_REF_BUF: if (mc_addr == NULL) break; for (i = 0; i < 32; i++) { for (j = 0; j < 6; j++) values[j] = readl(mc_addr + (ref_mc_base[j] + i * 4)); mtk_v4l2_err("[CORE][MC] 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx", ref_mc_base[0] + i * 4, ref_mc_base[0]/4 + i, values[0], ref_mc_base[1] + i * 4, ref_mc_base[1]/4 + i, values[1], ref_mc_base[2] + i * 4, ref_mc_base[2]/4 + i, values[2], ref_mc_base[3] + i * 4, ref_mc_base[3]/4 + i, values[3], ref_mc_base[4] + i * 4, ref_mc_base[4]/4 + i, values[4], ref_mc_base[5] + i * 4, ref_mc_base[5]/4 + i, values[5]); } for (i = 0; i < 4; i++) values[i] = readl(mc_addr + i * 4); mtk_v4l2_err("[CORE][MC] 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx", i * 4, i, values[0], i * 4, i, values[1], i * 4, i, values[2], i * 4, i, values[3]); for (i = 0; i < 6; i++) values[i] = readl(mc_addr + (ref_mc_base[6] + i * 4)); mtk_v4l2_err("[CORE][MC] 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx, 0x%x(%d) = 0x%lx", ref_mc_base[6], ref_mc_base[6]/4 + 0, values[0], ref_mc_base[6] + 1 * 4, ref_mc_base[6]/4 + 1, values[1], ref_mc_base[6] + 2 * 4, ref_mc_base[6]/4 + 2, values[2], ref_mc_base[6] + 3 * 4, ref_mc_base[6]/4 + 3, values[3], ref_mc_base[6] + 4 * 4, ref_mc_base[6]/4 + 4, values[4], ref_mc_base[6] + 5 * 4, ref_mc_base[6]/4 + 5, values[5]); break; case DUMP_VDEC_MV_BUF: if (hw_id != MTK_VDEC_CORE) { mtk_v4l2_err("not support dump MV at hw_id %d", hw_id); break; } if (mv_addr == NULL) break; value = readl(mv_addr + 0x20C); mtk_v4l2_err("[CORE][MV] 0x%x(%d) = 0x%lx", 0x20C, 0x20C/4, value); switch (fourcc) { case V4L2_PIX_FMT_H265: start = 0; end = 32; break; case V4L2_PIX_FMT_H264: start = 96; end = 128; break; case V4L2_PIX_FMT_VP9: start = 240; end = 241; break; case V4L2_PIX_FMT_AV1: start = 353; end = 356; break; default: start = 195; end = 198; } for (i = start; i < end; i++) { value = readl(mv_addr + i * 4); mtk_v4l2_err("[CORE][MV] 0x%x(%d) = 0x%lx", i * 4, i, value); } break; case DUMP_VDEC_UBE_BUF: if (hw_id == MTK_VDEC_LAT) { if ((lat_wdma_addr - 0x800) != NULL) { value = readl(lat_wdma_addr + 0x50); mtk_v4l2_err("[LAT][WDMA] 0x%x(%d) = 0x%lx", 0x50, 0x50/4, value); value = readl(lat_wdma_addr + 0x44); mtk_v4l2_err("[LAT][WDMA] 0x%x(%d) = 0x%lx", 0x44, 0x44/4, value); } if (rctrl_addr != NULL) { value = readl(rctrl_addr + 0x78); mtk_v4l2_err("[RACING_CTRL] 0x%x(%d) = 0x%lx", 0x78, 0x78/4, value); } } else { if (rctrl_addr != NULL) { value = readl(rctrl_addr + 0x7C); mtk_v4l2_err("[RACING_CTRL] 0x%x(%d) = 0x%lx", 0x7C, 0x7C/4, value); } if (vld_addr != NULL) { for (i = 0; i < UBE_CORE_VLD_NUM; i++) { value = readl(vld_addr + ube_core_vld_reg[i]); mtk_v4l2_err("[CORE][VLD] 0x%x(%d) = 0x%lx", ube_core_vld_reg[i], ube_core_vld_reg[i]/4, value); } } } break; default: mtk_v4l2_err("unknown addr type"); } spin_unlock_irqrestore(&dev->dec_power_lock[hw_id], flags); } #endif void mtk_vdec_uP_TF_dump_handler(struct work_struct *ws) { #if IS_ENABLED(CONFIG_MTK_TINYSYS_VCP_SUPPORT) struct mtk_vcodec_dev *dev; struct mtk_vcodec_ctx *ctx; struct list_head *list_ptr, *tmp; dev = container_of(ws, struct mtk_vcodec_dev, vdec_buf_work); mtk_v4l2_err("dec working buffer:"); mutex_lock(&dev->ctx_mutex); list_for_each_safe(list_ptr, tmp, &dev->ctx_list) { ctx = list_entry(list_ptr, struct mtk_vcodec_ctx, list); if (ctx != NULL && ctx->state >= MTK_STATE_INIT && ctx->state < MTK_STATE_ABORT) vdec_dump_mem_buf(ctx->drv_handle); } mutex_unlock(&dev->ctx_mutex); #endif } #if IS_ENABLED(CONFIG_MTK_IOMMU_MISC_DBG) static int mtk_vdec_translation_fault_callback( int port, dma_addr_t mva, void *data) { struct mtk_vcodec_dev *dev = (struct mtk_vcodec_dev *)data; int hw_id; struct mtk_vcodec_ctx *ctx; u32 fourcc; enum mtk_vcodec_ipm vdec_hw_ipm; int port_idx; if (dev->pm.mtkdev == NULL) { mtk_v4l2_err("fail to get vdec_hw_ipm"); vdec_hw_ipm = VCODEC_IPM_V2; } else { vdec_hw_ipm = dev->pm.mtkdev->vdec_hw_ipm; } for (port_idx = 0; port_idx < NUM_MAX_VDEC_M4U_PORT; port_idx++) if (port == dev->dec_m4u_ports[port_idx]) break; if (port_idx == VDEC_M4U_PORT_LAT0_UFO || port_idx == VDEC_M4U_PORT_LAT0_UFO_C || port_idx == VDEC_M4U_PORT_LAT0_MC) hw_id = MTK_VDEC_CORE; else if (MTK_M4U_TO_LARB(port) == 4) hw_id = MTK_VDEC_CORE; // larb4 CORE else if (MTK_M4U_TO_LARB(port) == 5 && vdec_hw_ipm == VCODEC_IPM_V2) hw_id = MTK_VDEC_LAT; // larb5 LAT else { mtk_v4l2_err("unknown larb port %d of m4u port 0x%x", MTK_M4U_TO_LARB(port), port); return 0; } if (dev->tf_info != NULL) { dev->tf_info->hw_id = (__u32)hw_id; dev->tf_info->port = (__u32)port_idx; dev->tf_info->tf_mva = (__u64)mva; dev->tf_info->has_tf = 1; mtk_v4l2_err("TF set tf_info 0x%lx hw_id %d port %s(%d) mva 0x%llx", (unsigned long)dev->tf_info, dev->tf_info->hw_id, dec_port_name[dev->tf_info->port], dev->tf_info->port, dev->tf_info->tf_mva); } ctx = dev->curr_dec_ctx[hw_id]; if (ctx) { fourcc = ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc; mtk_v4l2_err("[%d] codec:0x%08x(%c%c%c%c) %s(%d) TF larb %d port %s(%x) mva 0x%llx", ctx->id, fourcc, fourcc & 0xFF, (fourcc >> 8) & 0xFF, (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF, (hw_id == MTK_VDEC_LAT) ? "LAT" : "CORE", hw_id, MTK_M4U_TO_LARB(port), dec_port_name[port_idx], port, (u64)mva); } else { mtk_v4l2_err("ctx NULL codec unknown, %s(%d) TF larb %d port %s(%x) mva 0x%llx", (hw_id == MTK_VDEC_LAT) ? "LAT" : "CORE", hw_id, MTK_M4U_TO_LARB(port), dec_port_name[port_idx], port, (u64)mva); } #ifdef VDEC_DEBUG_DUMP // remove for security if (port == dev->dec_m4u_ports[VDEC_M4U_PORT_LAT0_VLD] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_LAT0_VLD2]) { mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_IN_BUF); } else if (port == dev->dec_m4u_ports[VDEC_M4U_PORT_PP] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_UFO] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_UFO_ENC] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_LAT0_UFO] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_LAT0_UFO_C]) { mtk_vdec_dump_addr_reg(dev, MTK_VDEC_CORE, DUMP_VDEC_OUT_BUF); if (port == dev->dec_m4u_ports[VDEC_M4U_PORT_UFO] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_UFO_ENC]) mtk_vdec_dump_addr_reg(dev, MTK_VDEC_CORE, DUMP_VDEC_REF_BUF); } else if (port == dev->dec_m4u_ports[VDEC_M4U_PORT_MC] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_LAT0_MC]) { mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_REF_BUF); } else if (port == dev->dec_m4u_ports[VDEC_M4U_PORT_AVC_MV]) { mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_MV_BUF); } else if (port == dev->dec_m4u_ports[VDEC_M4U_PORT_VLD] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_VLD2] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_RG_CTRL_DMA] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_LAT0_RG_CTRL_DMA] || port == dev->dec_m4u_ports[VDEC_M4U_PORT_LAT0_WDMA]) { if (vdec_hw_ipm == VCODEC_IPM_V2) mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_UBE_BUF); else mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_IN_BUF); } else { if (vdec_hw_ipm == VCODEC_IPM_V2) { if (hw_id == MTK_VDEC_CORE) { mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_UBE_BUF); mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_OUT_BUF); } else { mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_IN_BUF); mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_UBE_BUF); } } else { mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_IN_BUF); mtk_vdec_dump_addr_reg(dev, hw_id, DUMP_VDEC_OUT_BUF); } } #endif return 0; } static int mtk_vdec_uP_translation_fault_callback( int port, dma_addr_t mva, void *data) { struct mtk_vcodec_dev *dev = (struct mtk_vcodec_dev *)data; struct mtk_vcodec_ctx *dec_ctx[MTK_VDEC_HW_NUM]; u32 dec_fourcc[MTK_VDEC_HW_NUM]; char dec_codec_name[MTK_VDEC_HW_NUM][5]; int dec_ctx_id[MTK_VDEC_HW_NUM]; enum mtk_vcodec_ipm vdec_hw_ipm; int hw_id, i; if (dev->pm.mtkdev == NULL) { mtk_v4l2_err("fail to get vdec_hw_ipm"); vdec_hw_ipm = VCODEC_IPM_V2; } else { vdec_hw_ipm = dev->pm.mtkdev->vdec_hw_ipm; } for (hw_id = 0; hw_id < MTK_VDEC_HW_NUM; hw_id++) { dec_ctx[hw_id] = dev->curr_dec_ctx[hw_id]; if (dec_ctx[hw_id]) { dec_ctx_id[hw_id] = dec_ctx[hw_id]->id; dec_fourcc[hw_id] = dec_ctx[hw_id]->q_data[MTK_Q_DATA_SRC].fmt->fourcc; for (i = 0; i < 4; i++) dec_codec_name[hw_id][i] = (dec_fourcc[hw_id] >> (i * 8)) & 0xFF; } else { dec_ctx_id[hw_id] = 0; dec_fourcc[hw_id] = 0; if (sprintf(dec_codec_name[hw_id], "NULL") < 0) mtk_v4l2_err("dec_codec_name access failure"); } dec_codec_name[hw_id][4] = '\0'; } mtk_v4l2_err("larb %d port VIDEO_uP(%x) translation fault, mva 0x%llx", MTK_M4U_TO_LARB(port), port, (u64)mva); mtk_v4l2_err("current dec ctx: LAT ctx_id %d codec:%s(0x%08x), CORE ctx_id %d codec:%s(0x%08x) (ipm v%d)", dec_ctx_id[MTK_VDEC_LAT], dec_codec_name[MTK_VDEC_LAT], dec_fourcc[MTK_VDEC_LAT], dec_ctx_id[MTK_VDEC_CORE], dec_codec_name[MTK_VDEC_CORE], dec_fourcc[MTK_VDEC_CORE], vdec_hw_ipm); #if IS_ENABLED(CONFIG_MTK_TINYSYS_VCP_SUPPORT) /* trigger all ctx working buffer info dump (need mutex lock so can't dump at isr) */ queue_work(dev->vdec_buf_wq, &dev->vdec_buf_work); #endif return 0; } #endif int mtk_vdec_m4u_port_name_to_index(const char *name) { if (!strcmp(MTK_VDEC_M4U_PORT_NAME_MC, name)) return VDEC_M4U_PORT_MC; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_UFO, name)) return VDEC_M4U_PORT_UFO; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_PP, name)) return VDEC_M4U_PORT_PP; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_PRED_RD, name)) return VDEC_M4U_PORT_PRED_RD; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_PRED_WR, name)) return VDEC_M4U_PORT_PRED_WR; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_PPWRAP, name)) return VDEC_M4U_PORT_PPWRAP; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_TILE, name)) return VDEC_M4U_PORT_TILE; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_VLD, name)) return VDEC_M4U_PORT_VLD; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_VLD2, name)) return VDEC_M4U_PORT_VLD2; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_AVC_MV, name)) return VDEC_M4U_PORT_AVC_MV; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_RG_CTRL_DMA, name)) return VDEC_M4U_PORT_RG_CTRL_DMA; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_UFO_ENC, name)) return VDEC_M4U_PORT_UFO_ENC; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_VLD, name)) return VDEC_M4U_PORT_LAT0_VLD; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_VLD2, name)) return VDEC_M4U_PORT_LAT0_VLD2; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_AVC_MV, name)) return VDEC_M4U_PORT_LAT0_AVC_MV; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_PRED_RD, name)) return VDEC_M4U_PORT_LAT0_PRED_RD; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_TILE, name)) return VDEC_M4U_PORT_LAT0_TILE; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_WDMA, name)) return VDEC_M4U_PORT_LAT0_WDMA; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_RG_CTRL_DMA, name)) return VDEC_M4U_PORT_LAT0_RG_CTRL_DMA; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_MC, name)) return VDEC_M4U_PORT_LAT0_MC; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_UFO_ENC, name)) return VDEC_M4U_PORT_LAT0_UFO; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_LAT0_UFO_ENC_C, name)) return VDEC_M4U_PORT_LAT0_UFO_C; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_VIDEO_UP_SEC, name)) return VDEC_M4U_PORT_VIDEO_UP_SEC; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_VIDEO_UP_NOR, name)) return VDEC_M4U_PORT_VIDEO_UP_NOR; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_UP_1, name)) return VDEC_M4U_PORT_UP_1; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_UP_2, name)) return VDEC_M4U_PORT_UP_2; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_UP_3, name)) return VDEC_M4U_PORT_UP_3; else if (!strcmp(MTK_VDEC_M4U_PORT_NAME_UP_4, name)) return VDEC_M4U_PORT_UP_4; else return -1; } void mtk_vdec_translation_fault_callback_setting( struct mtk_vcodec_dev *dev) { #if IS_ENABLED(CONFIG_MTK_IOMMU_MISC_DBG) int i; for (i = 0; i < NUM_MAX_VDEC_M4U_PORT; i++) { if (dev->dec_m4u_ports[i] != 0 && i < VDEC_M4U_PORT_VIDEO_UP_SEC) mtk_iommu_register_fault_callback(dev->dec_m4u_ports[i], mtk_vdec_translation_fault_callback, (void *)dev, false); if (dev->dec_m4u_ports[i] != 0 && i >= VDEC_M4U_PORT_VIDEO_UP_SEC) mtk_iommu_register_fault_callback(dev->dec_m4u_ports[i], mtk_vdec_uP_translation_fault_callback, (void *)dev, false); } #endif }