diff --git a/driver/variant/iris2/src/msm_vidc_iris2.c b/driver/variant/iris2/src/msm_vidc_iris2.c index 4e0a6e78ba..947f9606b4 100644 --- a/driver/variant/iris2/src/msm_vidc_iris2.c +++ b/driver/variant/iris2/src/msm_vidc_iris2.c @@ -432,8 +432,7 @@ static int __setup_ucregion_memory_map_iris2(struct msm_vidc_core *vidc_core) static int __power_off_iris2_hardware(struct msm_vidc_core *core) { int rc = 0, i; - u32 value = 0, count = 0; - const u32 max_count = 10; + u32 value = 0; if (core->hw_power_control) { d_vpr_h("%s: hardware power control enabled\n", __func__); @@ -459,18 +458,9 @@ static int __power_off_iris2_hardware(struct msm_vidc_core *core) * poll for NoC DMA idle -> HPG 6.1.1 */ for (i = 0; i < core->capabilities[NUM_VPP_PIPE].value; i++) { - count = 0; - do { - value = __read_register(core, - VCODEC_SS_IDLE_STATUSn + 4*i); - if (value & 0x400000) - break; - else - usleep_range(1000, 2000); - count++; - } while (count < max_count); - - if (count == max_count) + rc = __read_register_with_poll_timeout(core, VCODEC_SS_IDLE_STATUSn + 4*i, + 0x400000, 0x400000, 2000, 20000); + if (rc) d_vpr_h("%s: VCODEC_SS_IDLE_STATUSn (%d) is not idle (%#x)\n", __func__, i, value); } @@ -479,32 +469,20 @@ static int __power_off_iris2_hardware(struct msm_vidc_core *core) rc = __write_register(core, AON_WRAPPER_MVP_NOC_RESET_REQ, 0x3); if (rc) return rc; - count = 0; - do { - value = __read_register(core, AON_WRAPPER_MVP_NOC_RESET_ACK); - if ((value & 0x3) == 0x3) - break; - else - usleep_range(100, 200); - count++; - } while (count < max_count); - if (count == max_count) + + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_RESET_ACK, + 0x3, 0x3, 200, 2000); + if (rc) d_vpr_h("%s: AON_WRAPPER_MVP_NOC_RESET assert failed\n", __func__); /* De-assert partial reset on MSF interface and wait for ACK */ rc = __write_register(core, AON_WRAPPER_MVP_NOC_RESET_REQ, 0x0); if (rc) return rc; - count = 0; - do { - value = __read_register(core, AON_WRAPPER_MVP_NOC_RESET_ACK); - if ((value & 0x3) == 0x0) - break; - else - usleep_range(100, 200); - count++; - } while (count < max_count); - if (count == max_count) + + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_RESET_ACK, + 0x3, 0x0, 200, 2000); + if (rc) d_vpr_h("%s: AON_WRAPPER_MVP_NOC_RESET de-assert failed\n", __func__); /* @@ -540,8 +518,6 @@ disable_power: static int __power_off_iris2_controller(struct msm_vidc_core *core) { int rc = 0; - u32 value = 0, count = 0; - const u32 max_count = 10; /* * mask fal10_veto QLPAC error since fal10_veto can go 1 @@ -556,33 +532,20 @@ static int __power_off_iris2_controller(struct msm_vidc_core *core) 0x1, BIT(0)); if (rc) return rc; - count = 0; - do { - value = __read_register(core, AON_WRAPPER_MVP_NOC_LPI_STATUS); - if ((value & 0x1) == 0x1) - break; - else - usleep_range(100, 200); - count++; - } while (count < max_count); - if (count == max_count) + + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_LPI_STATUS, + 0x1, 0x1, 200, 2000); + if (rc) d_vpr_h("%s: AON_WRAPPER_MVP_NOC_LPI_CONTROL failed\n", __func__); /* Set Debug bridge Low power */ rc = __write_register(core, WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2, 0x7); if (rc) return rc; - count = 0; - do { - value = __read_register(core, - WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2); - if ((value & 0x7) == 0x7) - break; - else - usleep_range(100, 200); - count++; - } while (count < max_count); - if (count == max_count) + + rc = __read_register_with_poll_timeout(core, WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2, + 0x7, 0x7, 200, 2000); + if (rc) d_vpr_h("%s: debug bridge low power failed\n", __func__); /* Debug bridge LPI release */ @@ -590,17 +553,9 @@ static int __power_off_iris2_controller(struct msm_vidc_core *core) if (rc) return rc; - count = 0; - do { - value = __read_register(core, - WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2); - if (value == 0x0) - break; - else - usleep_range(100, 200); - count++; - } while (count < max_count); - if (count == max_count) + rc = __read_register_with_poll_timeout(core, WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2, + 0xffffffff, 0x0, 200, 2000); + if (rc) d_vpr_h("%s: debug bridge release failed\n", __func__); /* power down process */ @@ -767,8 +722,6 @@ static int __prepare_pc_iris2(struct msm_vidc_core *vidc_core) int rc = 0; u32 wfi_status = 0, idle_status = 0, pc_ready = 0; u32 ctrl_status = 0; - int count = 0; - const int max_tries = 10; struct msm_vidc_core *core = vidc_core; if (!core) { @@ -797,25 +750,25 @@ static int __prepare_pc_iris2(struct msm_vidc_core *vidc_core) goto skip_power_off; } - while (count < max_tries) { - wfi_status = BIT(0) & __read_register(core, - WRAPPER_TZ_CPU_STATUS); - ctrl_status = __read_register(core, - CTRL_STATUS_IRIS2); - if (wfi_status && (ctrl_status & CTRL_STATUS_PC_READY_IRIS2)) - break; - usleep_range(150, 250); - count++; - } - - if (count == max_tries) { - d_vpr_e("Skip PC. Core is not in right state\n"); + rc = __read_register_with_poll_timeout(core, CTRL_STATUS_IRIS2, + CTRL_STATUS_PC_READY_IRIS2, CTRL_STATUS_PC_READY_IRIS2, 250, 2500); + if (rc) { + d_vpr_e("%s: Skip PC. Ctrl status not set\n", __func__); goto skip_power_off; } + rc = __read_register_with_poll_timeout(core, WRAPPER_TZ_CPU_STATUS, + BIT(0), 0x1, 250, 2500); + if (rc) { + d_vpr_e("%s: Skip PC. Wfi status not set\n", __func__); + goto skip_power_off; + } return rc; skip_power_off: + wfi_status = BIT(0) & __read_register(core, WRAPPER_TZ_CPU_STATUS); + ctrl_status = __read_register(core, CTRL_STATUS_IRIS2); + d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n", wfi_status, idle_status, pc_ready, ctrl_status); return -EAGAIN; diff --git a/driver/vidc/inc/venus_hfi.h b/driver/vidc/inc/venus_hfi.h index 2049fe0903..67ede90468 100644 --- a/driver/vidc/inc/venus_hfi.h +++ b/driver/vidc/inc/venus_hfi.h @@ -67,6 +67,8 @@ int __write_register_masked(struct msm_vidc_core *core, int __write_register(struct msm_vidc_core *core, u32 reg, u32 value); int __read_register(struct msm_vidc_core *core, u32 reg); +int __read_register_with_poll_timeout(struct msm_vidc_core *core, + u32 reg, u32 mask, u32 exp_val, u32 sleep_us, u32 timeout_us); int __iface_cmdq_write(struct msm_vidc_core *core, void *pkt); int __iface_msgq_read(struct msm_vidc_core *core, void *pkt); diff --git a/driver/vidc/src/venus_hfi.c b/driver/vidc/src/venus_hfi.c index 44c98b0a57..bcc0a6808d 100644 --- a/driver/vidc/src/venus_hfi.c +++ b/driver/vidc/src/venus_hfi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "venus_hfi.h" #include "msm_vidc_core.h" @@ -335,6 +336,39 @@ int __read_register(struct msm_vidc_core *core, u32 reg) return rc; } +int __read_register_with_poll_timeout(struct msm_vidc_core *core, + u32 reg, u32 mask, u32 exp_val, u32 sleep_us, u32 timeout_us) +{ + int rc = 0; + u32 val = 0; + u8 *addr; + + if (!core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!core->power_enabled) { + d_vpr_e("%s failed: Power is OFF\n", __func__); + return -EINVAL; + } + + addr = (u8 *)core->register_base_addr + reg; + + rc = readl_relaxed_poll_timeout(addr, val, ((val & mask) == exp_val), sleep_us, timeout_us); + /* + * Memory barrier to make sure value is read correctly from the + * register. + */ + rmb(); + d_vpr_l( + "regread(%pK + %#x) = %#x. rc %d, mask %#x, exp_val %#x, cond %u, sleep %u, timeout %u\n", + core->register_base_addr, reg, val, rc, mask, exp_val, + ((val & mask) == exp_val), sleep_us, timeout_us); + + return rc; +} + static void __schedule_power_collapse_work(struct msm_vidc_core *core) { if (!core || !core->capabilities) {