1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 */ 5 6 #include <linux/iopoll.h> 7 8 #include "iris_instance.h" 9 #include "iris_vpu_common.h" 10 #include "iris_vpu_register_defines.h" 11 12 #define AON_MVP_NOC_RESET 0x0001F000 13 14 #define WRAPPER_CORE_CLOCK_CONFIG (WRAPPER_BASE_OFFS + 0x88) 15 #define CORE_CLK_RUN 0x0 16 17 #define CPU_CS_AHB_BRIDGE_SYNC_RESET (CPU_CS_BASE_OFFS + 0x160) 18 #define CORE_BRIDGE_SW_RESET BIT(0) 19 #define CORE_BRIDGE_HW_RESET_DISABLE BIT(1) 20 21 #define AON_WRAPPER_MVP_NOC_RESET_REQ (AON_MVP_NOC_RESET + 0x000) 22 #define VIDEO_NOC_RESET_REQ (BIT(0) | BIT(1)) 23 24 #define AON_WRAPPER_MVP_NOC_RESET_ACK (AON_MVP_NOC_RESET + 0x004) 25 26 #define VCODEC_SS_IDLE_STATUSN (VCODEC_BASE_OFFS + 0x70) 27 28 static bool iris_vpu3_hw_power_collapsed(struct iris_core *core) 29 { 30 u32 value, pwr_status; 31 32 value = readl(core->reg_base + WRAPPER_CORE_POWER_STATUS); 33 pwr_status = value & BIT(1); 34 35 return pwr_status ? false : true; 36 } 37 38 static void iris_vpu3_power_off_hardware(struct iris_core *core) 39 { 40 u32 reg_val = 0, value, i; 41 int ret; 42 43 if (iris_vpu3_hw_power_collapsed(core)) 44 goto disable_power; 45 46 dev_err(core->dev, "video hw is power on\n"); 47 48 value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); 49 if (value) 50 writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); 51 52 for (i = 0; i < core->iris_platform_data->num_vpp_pipe; i++) { 53 ret = readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN + 4 * i, 54 reg_val, reg_val & 0x400000, 2000, 20000); 55 if (ret) 56 goto disable_power; 57 } 58 59 writel(VIDEO_NOC_RESET_REQ, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); 60 61 ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, 62 reg_val, reg_val & 0x3, 200, 2000); 63 if (ret) 64 goto disable_power; 65 66 writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); 67 68 ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, 69 reg_val, !(reg_val & 0x3), 200, 2000); 70 if (ret) 71 goto disable_power; 72 73 writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, 74 core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); 75 writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); 76 writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); 77 78 disable_power: 79 iris_vpu_power_off_hw(core); 80 } 81 82 static u64 iris_vpu3_calculate_frequency(struct iris_inst *inst, size_t data_size) 83 { 84 struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; 85 struct v4l2_format *inp_f = inst->fmt_src; 86 u32 height, width, mbs_per_second, mbpf; 87 u64 fw_cycles, fw_vpp_cycles; 88 u64 vsp_cycles, vpp_cycles; 89 u32 fps = DEFAULT_FPS; 90 91 width = max(inp_f->fmt.pix_mp.width, inst->crop.width); 92 height = max(inp_f->fmt.pix_mp.height, inst->crop.height); 93 94 mbpf = NUM_MBS_PER_FRAME(height, width); 95 mbs_per_second = mbpf * fps; 96 97 fw_cycles = fps * caps->mb_cycles_fw; 98 fw_vpp_cycles = fps * caps->mb_cycles_fw_vpp; 99 100 vpp_cycles = mult_frac(mbs_per_second, caps->mb_cycles_vpp, (u32)inst->fw_caps[PIPE].value); 101 /* 21 / 20 is minimum overhead factor */ 102 vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); 103 104 /* 1.059 is multi-pipe overhead */ 105 if (inst->fw_caps[PIPE].value > 1) 106 vpp_cycles += div_u64(vpp_cycles * 59, 1000); 107 108 vsp_cycles = fps * data_size * 8; 109 vsp_cycles = div_u64(vsp_cycles, 2); 110 /* VSP FW overhead 1.05 */ 111 vsp_cycles = div_u64(vsp_cycles * 21, 20); 112 113 if (inst->fw_caps[STAGE].value == STAGE_1) 114 vsp_cycles = vsp_cycles * 3; 115 116 return max3(vpp_cycles, vsp_cycles, fw_cycles); 117 } 118 119 const struct vpu_ops iris_vpu3_ops = { 120 .power_off_hw = iris_vpu3_power_off_hardware, 121 .calc_freq = iris_vpu3_calculate_frequency, 122 }; 123