diff options
Diffstat (limited to 'drivers')
5 files changed, 119 insertions, 3 deletions
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index 3e5cbdecfba4..041a8219e145 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -278,6 +278,10 @@ static void sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on) SDEROT_EVTLOG(on); SDEROT_DBG("%s: rotator regulators", on ? "Enable" : "Disable"); + + if (mgr->ops_hw_pre_pmevent) + mgr->ops_hw_pre_pmevent(mgr, on); + ret = sde_rot_enable_vreg(mgr->module_power.vreg_config, mgr->module_power.num_vreg, on); if (ret) { @@ -286,10 +290,13 @@ static void sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on) return; } + if (mgr->ops_hw_post_pmevent) + mgr->ops_hw_post_pmevent(mgr, on); + mgr->regulator_enable = on; } -static int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable) +int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable) { struct clk *clk; int ret = 0; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h index 8659d361be07..aa17341de7c2 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h @@ -293,6 +293,8 @@ struct sde_rot_mgr { void (*ops_hw_free)(struct sde_rot_mgr *mgr, struct sde_rot_hw_resource *hw); int (*ops_hw_init)(struct sde_rot_mgr *mgr); + void (*ops_hw_pre_pmevent)(struct sde_rot_mgr *mgr, bool pmon); + void (*ops_hw_post_pmevent)(struct sde_rot_mgr *mgr, bool pmon); void (*ops_hw_destroy)(struct sde_rot_mgr *mgr); ssize_t (*ops_hw_show_caps)(struct sde_rot_mgr *mgr, struct device_attribute *attr, char *buf, ssize_t len); @@ -405,6 +407,8 @@ int sde_rotator_validate_request(struct sde_rot_mgr *rot_dev, struct sde_rot_file_private *ctx, struct sde_rot_entry_container *req); +int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable); + static inline void sde_rot_mgr_lock(struct sde_rot_mgr *mgr) { mutex_lock(&mgr->lock); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c index e9d2dd5ec972..d2bc76874c48 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -271,6 +271,7 @@ static int sde_hw_rotator_pending_swts(struct sde_hw_rotator *rot, SDEROT_DBG("ts:0x%x, queue_id:%d, swts:0x%x, pending:%d\n", ctx->timestamp, ctx->q_id, swts, pending); + SDEROT_EVTLOG(ctx->timestamp, swts, ctx->q_id, ts_diff); return pending; } @@ -1240,6 +1241,94 @@ static void sde_hw_rotator_swtc_destroy(struct sde_hw_rotator *rot) } /* + * sde_hw_rotator_pre_pmevent - SDE rotator core will call this before a + * PM event occurs + * @mgr: Pointer to rotator manager + * @pmon: Boolean indicate an on/off power event + */ +void sde_hw_rotator_pre_pmevent(struct sde_rot_mgr *mgr, bool pmon) +{ + struct sde_hw_rotator *rot; + u32 l_ts, h_ts, swts, hwts; + u32 rotsts, regdmasts; + + /* + * Check last HW timestamp with SW timestamp before power off event. + * If there is a mismatch, that will be quite possible the rotator HW + * is either hang or not finishing last submitted job. In that case, + * it is best to do a timeout eventlog to capture some good events + * log data for analysis. + */ + if (!pmon && mgr && mgr->hw_data) { + rot = mgr->hw_data; + h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]); + l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]); + + /* contruct the combined timstamp */ + swts = (h_ts & SDE_REGDMA_SWTS_MASK) | + ((l_ts & SDE_REGDMA_SWTS_MASK) << + SDE_REGDMA_SWTS_SHIFT); + + /* Need to turn on clock to access rotator register */ + sde_rotator_clk_ctrl(mgr, true); + hwts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG); + regdmasts = SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_BLOCK_STATUS); + rotsts = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS); + + SDEROT_DBG( + "swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n", + swts, hwts, regdmasts, rotsts); + SDEROT_EVTLOG(swts, hwts, regdmasts, rotsts); + + if ((swts != hwts) && ((regdmasts & REGDMA_BUSY) || + (rotsts & ROT_STATUS_MASK))) { + SDEROT_ERR( + "Mismatch SWTS with HWTS: swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n", + swts, hwts, regdmasts, rotsts); + SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus", + "panic"); + } + + /* Turn off rotator clock after checking rotator registers */ + sde_rotator_clk_ctrl(mgr, false); + } +} + +/* + * sde_hw_rotator_post_pmevent - SDE rotator core will call this after a + * PM event occurs + * @mgr: Pointer to rotator manager + * @pmon: Boolean indicate an on/off power event + */ +void sde_hw_rotator_post_pmevent(struct sde_rot_mgr *mgr, bool pmon) +{ + struct sde_hw_rotator *rot; + u32 l_ts, h_ts, swts; + + /* + * After a power on event, the rotator HW is reset to default setting. + * It is necessary to synchronize the SW timestamp with the HW. + */ + if (pmon && mgr && mgr->hw_data) { + rot = mgr->hw_data; + h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]); + l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]); + + /* contruct the combined timstamp */ + swts = (h_ts & SDE_REGDMA_SWTS_MASK) | + ((l_ts & SDE_REGDMA_SWTS_MASK) << + SDE_REGDMA_SWTS_SHIFT); + + SDEROT_DBG("swts:0x%x, h_ts:0x%x, l_ts;0x%x\n", + swts, h_ts, l_ts); + SDEROT_EVTLOG(swts, h_ts, l_ts); + rot->reset_hw_ts = true; + rot->last_hw_ts = swts; + } +} + +/* * sde_hw_rotator_destroy - Destroy hw rotator and free allocated resources * @mgr: Pointer to rotator manager */ @@ -1455,6 +1544,15 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw, return -EINVAL; } + if (rot->reset_hw_ts) { + SDEROT_EVTLOG(rot->last_hw_ts); + SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, + rot->last_hw_ts); + /* ensure write is issued to the rotator HW */ + wmb(); + rot->reset_hw_ts = false; + } + flags = (item->flags & SDE_ROTATION_FLIP_LR) ? SDE_ROT_FLAG_FLIP_LR : 0; flags |= (item->flags & SDE_ROTATION_FLIP_UD) ? @@ -1511,7 +1609,8 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw, &entry->dst_buf); } - SDEROT_EVTLOG(flags, item->input.width, item->input.height, + SDEROT_EVTLOG(ctx->timestamp, flags, + item->input.width, item->input.height, item->output.width, item->output.height, entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr); @@ -1715,6 +1814,7 @@ static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot) mdata->regdump = sde_rot_r3_regdump; mdata->regdump_size = ARRAY_SIZE(sde_rot_r3_regdump); + SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, 0); return 0; } @@ -2174,6 +2274,8 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr) mgr->ops_hw_create_debugfs = sde_rotator_r3_create_debugfs; mgr->ops_hw_get_pixfmt = sde_hw_rotator_get_pixfmt; mgr->ops_hw_is_valid_pixfmt = sde_hw_rotator_is_valid_pixfmt; + mgr->ops_hw_pre_pmevent = sde_hw_rotator_pre_pmevent; + mgr->ops_hw_post_pmevent = sde_hw_rotator_post_pmevent; ret = sde_hw_rotator_parse_dt(mgr->hw_data, mgr->pdev); if (ret) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h index 3267e4418b3a..a748b87a231a 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h @@ -250,9 +250,10 @@ /* General defines */ #define ROT_DONE_MASK 0x1 #define ROT_DONE_CLEAR 0x1 -#define ROT_BUSY_BIT BIT(1) +#define ROT_BUSY_BIT BIT(0) #define ROT_ERROR_BIT BIT(8) #define ROT_STATUS_MASK (ROT_BUSY_BIT | ROT_ERROR_BIT) +#define REGDMA_BUSY BIT(0) #define REGDMA_EN 0x1 #define REGDMA_SECURE_EN BIT(8) #define REGDMA_HALT BIT(16) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h index b95f838f463b..91ac3d0371fa 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h @@ -270,6 +270,8 @@ struct sde_hw_rotator { spinlock_t rotisr_lock; bool dbgmem; + bool reset_hw_ts; + u32 last_hw_ts; }; /** |