diff --git a/drivers/media/platform/qcom/iris/iris_vpu3x.c b/drivers/media/platform/qcom/iris/iris_vpu3x.c index cd53bcda3b3e..fe4423b951b1 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu3x.c +++ b/drivers/media/platform/qcom/iris/iris_vpu3x.c @@ -16,8 +16,6 @@ #define AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL (AON_BASE_OFFS + 0x20) #define NOC_HALT BIT(0) #define AON_WRAPPER_SPARE (AON_BASE_OFFS + 0x28) -#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL (AON_BASE_OFFS + 0x2C) -#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS (AON_BASE_OFFS + 0x30) static bool iris_vpu3x_hw_power_collapsed(struct iris_core *core) { @@ -262,155 +260,12 @@ static void iris_vpu35_power_off_hw(struct iris_core *core) iris_disable_unprepare_clock(core, IRIS_AXI_CLK); } -static int iris_vpu35_power_off_controller(struct iris_core *core) -{ - u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; - unsigned int count = 0; - u32 val = 0; - bool handshake_done, handshake_busy; - int ret; - - writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); - - writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); - - ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, - val, val & BIT(0), 200, 2000); - if (ret) - goto disable_power; - - writel(0, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); - - /* Retry up to 1000 times as recommended by hardware documentation */ - do { - /* set MNoC to low power */ - writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); - - udelay(15); - - val = readl(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS); - - handshake_done = val & NOC_LPI_STATUS_DONE; - handshake_busy = val & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); - - if (handshake_done || !handshake_busy) - break; - - writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); - - udelay(15); - - } while (++count < 1000); - - if (!handshake_done && handshake_busy) - dev_err(core->dev, "LPI handshake timeout\n"); - - ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS, - val, val & BIT(0), 200, 2000); - if (ret) - goto disable_power; - - writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); - - writel(0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); - - ret = readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, - val, val == 0, 200, 2000); - if (ret) - goto disable_power; - -disable_power: - iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); - iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); - iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); - - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); - - reset_control_bulk_reset(clk_rst_tbl_size, core->resets); - - return 0; -} - -static int iris_vpu35_power_on_controller(struct iris_core *core) -{ - int ret; - - ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); - if (ret) - return ret; - - ret = iris_prepare_enable_clock(core, IRIS_AXI1_CLK); - if (ret) - goto err_disable_power; - - ret = iris_prepare_enable_clock(core, IRIS_CTRL_FREERUN_CLK); - if (ret) - goto err_disable_axi1_clk; - - ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); - if (ret) - goto err_disable_ctrl_free_clk; - - return 0; - -err_disable_ctrl_free_clk: - iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); -err_disable_axi1_clk: - iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); -err_disable_power: - iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); - - return ret; -} - -static void iris_vpu35_program_bootup_registers(struct iris_core *core) -{ - writel(0x1, core->reg_base + WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0); -} - -static u64 iris_vpu3x_calculate_frequency(struct iris_inst *inst, size_t data_size) -{ - struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; - struct v4l2_format *inp_f = inst->fmt_src; - u32 height, width, mbs_per_second, mbpf; - u64 fw_cycles, fw_vpp_cycles; - u64 vsp_cycles, vpp_cycles; - u32 fps = DEFAULT_FPS; - - width = max(inp_f->fmt.pix_mp.width, inst->crop.width); - height = max(inp_f->fmt.pix_mp.height, inst->crop.height); - - mbpf = NUM_MBS_PER_FRAME(height, width); - mbs_per_second = mbpf * fps; - - fw_cycles = fps * caps->mb_cycles_fw; - fw_vpp_cycles = fps * caps->mb_cycles_fw_vpp; - - vpp_cycles = mult_frac(mbs_per_second, caps->mb_cycles_vpp, (u32)inst->fw_caps[PIPE].value); - /* 21 / 20 is minimum overhead factor */ - vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); - - /* 1.059 is multi-pipe overhead */ - if (inst->fw_caps[PIPE].value > 1) - vpp_cycles += div_u64(vpp_cycles * 59, 1000); - - vsp_cycles = fps * data_size * 8; - vsp_cycles = div_u64(vsp_cycles, 2); - /* VSP FW overhead 1.05 */ - vsp_cycles = div_u64(vsp_cycles * 21, 20); - - if (inst->fw_caps[STAGE].value == STAGE_1) - vsp_cycles = vsp_cycles * 3; - - return max3(vpp_cycles, vsp_cycles, fw_cycles); -} - const struct vpu_ops iris_vpu3_ops = { .power_off_hw = iris_vpu3_power_off_hardware, .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu_power_off_controller, .power_on_controller = iris_vpu_power_on_controller, - .calc_freq = iris_vpu3x_calculate_frequency, + .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, }; const struct vpu_ops iris_vpu33_ops = { @@ -418,14 +273,14 @@ const struct vpu_ops iris_vpu33_ops = { .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu33_power_off_controller, .power_on_controller = iris_vpu_power_on_controller, - .calc_freq = iris_vpu3x_calculate_frequency, + .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, }; const struct vpu_ops iris_vpu35_ops = { .power_off_hw = iris_vpu35_power_off_hw, .power_on_hw = iris_vpu35_power_on_hw, - .power_off_controller = iris_vpu35_power_off_controller, - .power_on_controller = iris_vpu35_power_on_controller, - .program_bootup_registers = iris_vpu35_program_bootup_registers, - .calc_freq = iris_vpu3x_calculate_frequency, + .power_off_controller = iris_vpu35_vpu4x_power_off_controller, + .power_on_controller = iris_vpu35_vpu4x_power_on_controller, + .program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers, + .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, }; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index 50242fc6b465..548e5f1727fd 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -8,9 +8,12 @@ #include #include "iris_core.h" +#include "iris_instance.h" #include "iris_vpu_common.h" #include "iris_vpu_register_defines.h" +#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL (AON_BASE_OFFS + 0x2C) +#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS (AON_BASE_OFFS + 0x30) #define CTRL_INIT (CPU_CS_BASE_OFFS + 0x48) #define CTRL_STATUS (CPU_CS_BASE_OFFS + 0x4C) @@ -305,6 +308,144 @@ int iris_vpu_power_on_hw(struct iris_core *core) return ret; } +int iris_vpu35_vpu4x_power_off_controller(struct iris_core *core) +{ + u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; + bool handshake_done, handshake_busy; + u32 count = 0, val = 0; + int ret; + + writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); + + writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + /* Retry up to 1000 times as recommended by hardware documentation */ + do { + /* set MNoC to low power */ + writel(REQ_POWER_DOWN_PREP, core->reg_base + + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + usleep_range(10, 20); + val = readl(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS); + + handshake_done = val & NOC_LPI_STATUS_DONE; + handshake_busy = val & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); + + if (handshake_done || !handshake_busy) + break; + + writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + usleep_range(10, 20); + + } while (++count < 1000); + + if (!handshake_done && handshake_busy) + dev_err(core->dev, "LPI handshake timeout\n"); + + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + + writel(0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); + + readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, + val, val == 0, 200, 2000); + +disable_power: + iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); + iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); + iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); + + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + + reset_control_bulk_reset(clk_rst_tbl_size, core->resets); + + return 0; +} + +int iris_vpu35_vpu4x_power_on_controller(struct iris_core *core) +{ + int ret; + + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + if (ret) + return ret; + + ret = iris_prepare_enable_clock(core, IRIS_AXI1_CLK); + if (ret) + goto err_disable_power; + + ret = iris_prepare_enable_clock(core, IRIS_CTRL_FREERUN_CLK); + if (ret) + goto err_disable_axi1_clk; + + ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); + if (ret) + goto err_disable_ctrl_free_clk; + + return 0; + +err_disable_ctrl_free_clk: + iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); +err_disable_axi1_clk: + iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); +err_disable_power: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + + return ret; +} + +void iris_vpu35_vpu4x_program_bootup_registers(struct iris_core *core) +{ + writel(0x1, core->reg_base + WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0); +} + +u64 iris_vpu3x_vpu4x_calculate_frequency(struct iris_inst *inst, size_t data_size) +{ + struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; + struct v4l2_format *inp_f = inst->fmt_src; + u32 height, width, mbs_per_second, mbpf; + u64 fw_cycles, fw_vpp_cycles; + u64 vsp_cycles, vpp_cycles; + u32 fps = DEFAULT_FPS; + + width = max(inp_f->fmt.pix_mp.width, inst->crop.width); + height = max(inp_f->fmt.pix_mp.height, inst->crop.height); + + mbpf = NUM_MBS_PER_FRAME(height, width); + mbs_per_second = mbpf * fps; + + fw_cycles = fps * caps->mb_cycles_fw; + fw_vpp_cycles = fps * caps->mb_cycles_fw_vpp; + + vpp_cycles = mult_frac(mbs_per_second, caps->mb_cycles_vpp, (u32)inst->fw_caps[PIPE].value); + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); + + /* 1.059 is multi-pipe overhead */ + if (inst->fw_caps[PIPE].value > 1) + vpp_cycles += div_u64(vpp_cycles * 59, 1000); + + vsp_cycles = fps * data_size * 8; + vsp_cycles = div_u64(vsp_cycles, 2); + /* VSP FW overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + + if (inst->fw_caps[STAGE].value == STAGE_1) + vsp_cycles = vsp_cycles * 3; + + return max3(vpp_cycles, vsp_cycles, fw_cycles); +} + int iris_vpu_power_on(struct iris_core *core) { u32 freq; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h index d636e287457a..7cf4304604cc 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h @@ -33,5 +33,9 @@ int iris_vpu_power_on(struct iris_core *core); int iris_vpu_power_off_controller(struct iris_core *core); void iris_vpu_power_off_hw(struct iris_core *core); void iris_vpu_power_off(struct iris_core *core); +int iris_vpu35_vpu4x_power_off_controller(struct iris_core *core); +int iris_vpu35_vpu4x_power_on_controller(struct iris_core *core); +void iris_vpu35_vpu4x_program_bootup_registers(struct iris_core *core); +u64 iris_vpu3x_vpu4x_calculate_frequency(struct iris_inst *inst, size_t data_size); #endif