summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Chan <bkchan@codeaurora.org>2016-09-16 16:01:09 -0400
committerGerrit - the friendly Code Review server <code-review@localhost>2016-09-20 07:04:23 -0700
commit1db5844b624a028df9ddbb76ca7e354669c025fe (patch)
tree826c4f937d62826d2caa23ac9c84f9f6a3a834ba
parent4b91c1a0f78b6b4071e66c9a5879a784cedd6693 (diff)
msm: sde: Add pre/post power event handler in SDE rotator
For pre power off event, we want to check for rotator IDLE status and generate a timeout event logging if the rotator is still in BUSY state. For post power on event, rotator is reset to default HW state. It is necessary to synchronize the SW timestamp with the HW register location. CRs-Fixed: 1066270 Change-Id: I1041141b8dc80db0baec7ffe71a5c2a7b41e2cbb Signed-off-by: Benjamin Chan <bkchan@codeaurora.org>
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.c9
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.h4
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c104
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h3
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h2
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;
};
/**