summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorqctecmdr <qctecmdr@localhost>2019-12-12 02:57:39 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2019-12-12 02:57:39 -0800
commit5c6c31021ac08612f19044cb458cfdea14e4d046 (patch)
tree732cbaa66ab6d46f00c472d20206ade2f8aae9ad
parent65b4eb5967033e1bc94e89a3469a5b1bc31882ad (diff)
parentbd59bbaf0160071651f9b99a180273ad063c2305 (diff)
downloaddisplay-drivers-5c6c31021ac08612f19044cb458cfdea14e4d046.tar.gz
Merge "msm:disp:rotator: setup irq during first rotator commit"
-rw-r--r--rotator/sde_rotator_r3.c477
1 files changed, 248 insertions, 229 deletions
diff --git a/rotator/sde_rotator_r3.c b/rotator/sde_rotator_r3.c
index 45f151f6..0d36bd54 100644
--- a/rotator/sde_rotator_r3.c
+++ b/rotator/sde_rotator_r3.c
@@ -570,6 +570,33 @@ static u32 __sde_hw_rotator_get_timestamp(struct sde_hw_rotator *rot, u32 q_id)
}
/**
+ * sde_hw_rotator_disable_irq - Disable hw rotator interrupt with ref. count
+ * Also, clear rotator/regdma irq enable masks.
+ * @rot: Pointer to hw rotator
+ */
+static void sde_hw_rotator_disable_irq(struct sde_hw_rotator *rot)
+{
+ SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
+ atomic_read(&rot->irq_enabled));
+
+ if (!atomic_read(&rot->irq_enabled)) {
+ SDEROT_ERR("irq %d is already disabled\n", rot->irq_num);
+ return;
+ }
+
+ if (!atomic_dec_return(&rot->irq_enabled)) {
+ if (rot->mode == ROT_REGDMA_OFF)
+ SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_EN, 0);
+ else
+ SDE_ROTREG_WRITE(rot->mdss_base,
+ REGDMA_CSR_REGDMA_INT_EN, 0);
+ /* disable irq after last pending irq is handled, if any */
+ synchronize_irq(rot->irq_num);
+ disable_irq_nosync(rot->irq_num);
+ }
+}
+
+/**
* sde_hw_rotator_elapsed_swts - Find difference of 2 software timestamps
* @ts_curr: current software timestamp
* @ts_prev: previous software timestamp
@@ -582,6 +609,174 @@ static int sde_hw_rotator_elapsed_swts(u32 ts_curr, u32 ts_prev)
return sign_extend32(diff, (SDE_REGDMA_SWTS_SHIFT - 1));
}
+/*
+ * sde_hw_rotator_rotirq_handler - non-regdma interrupt handler
+ * @irq: Interrupt number
+ * @ptr: Pointer to private handle provided during registration
+ *
+ * This function services rotator interrupt and wakes up waiting client
+ * with pending rotation requests already submitted to h/w.
+ */
+static irqreturn_t sde_hw_rotator_rotirq_handler(int irq, void *ptr)
+{
+ struct sde_hw_rotator *rot = ptr;
+ struct sde_hw_rotator_context *ctx;
+ irqreturn_t ret = IRQ_NONE;
+ u32 isr;
+
+ isr = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_INTR_STATUS);
+
+ SDEROT_DBG("intr_status = %8.8x\n", isr);
+
+ if (isr & ROT_DONE_MASK) {
+ sde_hw_rotator_disable_irq(rot);
+ SDEROT_DBG("Notify rotator complete\n");
+
+ /* Normal rotator only 1 session, no need to lookup */
+ ctx = rot->rotCtx[0][0];
+ WARN_ON(ctx == NULL);
+ complete_all(&ctx->rot_comp);
+
+ spin_lock(&rot->rotisr_lock);
+ SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
+ ROT_DONE_CLEAR);
+ spin_unlock(&rot->rotisr_lock);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+/*
+ * sde_hw_rotator_regdmairq_handler - regdma interrupt handler
+ * @irq: Interrupt number
+ * @ptr: Pointer to private handle provided during registration
+ *
+ * This function services rotator interrupt, decoding the source of
+ * events (high/low priority queue), and wakes up all waiting clients
+ * with pending rotation requests already submitted to h/w.
+ */
+static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+ struct sde_hw_rotator *rot = ptr;
+ struct sde_hw_rotator_context *ctx, *tmp;
+ irqreturn_t ret = IRQ_NONE;
+ u32 isr, isr_tmp;
+ u32 ts;
+ u32 q_id;
+
+ isr = SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_STATUS);
+ /* acknowledge interrupt before reading latest timestamp */
+ SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr);
+
+ SDEROT_DBG("intr_status = %8.8x\n", isr);
+
+ /* Any REGDMA status, including error and watchdog timer, should
+ * trigger and wake up waiting thread
+ */
+ if (isr & (REGDMA_INT_HIGH_MASK | REGDMA_INT_LOW_MASK)) {
+ spin_lock(&rot->rotisr_lock);
+
+ /*
+ * Obtain rotator context based on timestamp from regdma
+ * and low/high interrupt status
+ */
+ if (isr & REGDMA_INT_HIGH_MASK) {
+ q_id = ROT_QUEUE_HIGH_PRIORITY;
+ } else if (isr & REGDMA_INT_LOW_MASK) {
+ q_id = ROT_QUEUE_LOW_PRIORITY;
+ } else {
+ SDEROT_ERR("unknown ISR status: isr=0x%X\n", isr);
+ goto done_isr_handle;
+ }
+
+ ts = __sde_hw_rotator_get_timestamp(rot, q_id);
+
+ /*
+ * Timestamp packet is not available in sbuf mode.
+ * Simulate timestamp update in the handler instead.
+ */
+ if (test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map) ||
+ list_empty(&rot->sbuf_ctx[q_id]))
+ goto skip_sbuf;
+
+ ctx = NULL;
+ isr_tmp = isr;
+ list_for_each_entry(tmp, &rot->sbuf_ctx[q_id], list) {
+ u32 mask;
+
+ mask = tmp->timestamp & 0x1 ? REGDMA_INT_1_MASK :
+ REGDMA_INT_0_MASK;
+ if (isr_tmp & mask) {
+ isr_tmp &= ~mask;
+ ctx = tmp;
+ ts = ctx->timestamp;
+ rot->ops.update_ts(rot, ctx->q_id, ts);
+ SDEROT_DBG("update swts:0x%X\n", ts);
+ }
+ SDEROT_EVTLOG(isr, tmp->timestamp);
+ }
+ if (ctx == NULL)
+ SDEROT_ERR("invalid swts ctx\n");
+skip_sbuf:
+ ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK];
+
+ /*
+ * Wake up all waiting context from the current and previous
+ * SW Timestamp.
+ */
+ while (ctx &&
+ sde_hw_rotator_elapsed_swts(ctx->timestamp, ts) >= 0) {
+ ctx->last_regdma_isr_status = isr;
+ ctx->last_regdma_timestamp = ts;
+ SDEROT_DBG(
+ "regdma complete: ctx:%pK, ts:%X\n", ctx, ts);
+ wake_up_all(&ctx->regdma_waitq);
+
+ ts = (ts - 1) & SDE_REGDMA_SWTS_MASK;
+ ctx = rot->rotCtx[q_id]
+ [ts & SDE_HW_ROT_REGDMA_SEG_MASK];
+ };
+
+done_isr_handle:
+ spin_unlock(&rot->rotisr_lock);
+ ret = IRQ_HANDLED;
+ } else if (isr & REGDMA_INT_ERR_MASK) {
+ /*
+ * For REGDMA Err, we save the isr info and wake up
+ * all waiting contexts
+ */
+ int i, j;
+
+ SDEROT_ERR(
+ "regdma err isr:%X, wake up all waiting contexts\n",
+ isr);
+
+ spin_lock(&rot->rotisr_lock);
+
+ for (i = 0; i < ROT_QUEUE_MAX; i++) {
+ for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) {
+ ctx = rot->rotCtx[i][j];
+ if (ctx && ctx->last_regdma_isr_status == 0) {
+ ts = __sde_hw_rotator_get_timestamp(
+ rot, i);
+ ctx->last_regdma_isr_status = isr;
+ ctx->last_regdma_timestamp = ts;
+ wake_up_all(&ctx->regdma_waitq);
+ SDEROT_DBG("Wake rotctx[%d][%d]:%pK\n",
+ i, j, ctx);
+ }
+ }
+ }
+
+ spin_unlock(&rot->rotisr_lock);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
/**
* sde_hw_rotator_pending_hwts - Check if the given context is still pending
* @rot: Pointer to hw rotator
@@ -695,54 +890,76 @@ static void sde_hw_rotator_update_swts(struct sde_hw_rotator *rot,
SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, swts);
}
-/**
- * sde_hw_rotator_enable_irq - Enable hw rotator interrupt with ref. count
- * Also, clear rotator/regdma irq status.
- * @rot: Pointer to hw rotator
+/*
+ * sde_hw_rotator_irq_setup - setup rotator irq
+ * @mgr: Pointer to rotator manager
+ * return: none
*/
-static void sde_hw_rotator_enable_irq(struct sde_hw_rotator *rot)
+static int sde_hw_rotator_irq_setup(struct sde_hw_rotator *rot)
{
- SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
- atomic_read(&rot->irq_enabled));
+ int rc = 0;
- if (!atomic_read(&rot->irq_enabled)) {
+ /* return early if irq is already setup */
+ if (rot->irq_num >= 0)
+ return 0;
+
+ rot->irq_num = platform_get_irq(rot->pdev, 0);
+ if (rot->irq_num < 0) {
+ rc = rot->irq_num;
+ SDEROT_ERR("fail to get rot irq, fallback to poll %d\n", rc);
+ } else {
if (rot->mode == ROT_REGDMA_OFF)
- SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
- ROT_DONE_MASK);
+ rc = devm_request_threaded_irq(&rot->pdev->dev,
+ rot->irq_num,
+ sde_hw_rotator_rotirq_handler,
+ NULL, 0, "sde_rotator_r3", rot);
else
- SDE_ROTREG_WRITE(rot->mdss_base,
- REGDMA_CSR_REGDMA_INT_CLEAR, REGDMA_INT_MASK);
-
- enable_irq(rot->irq_num);
+ rc = devm_request_threaded_irq(&rot->pdev->dev,
+ rot->irq_num,
+ sde_hw_rotator_regdmairq_handler,
+ NULL, 0, "sde_rotator_r3", rot);
+ if (rc) {
+ SDEROT_ERR("fail to request irq r:%d\n", rc);
+ rot->irq_num = -1;
+ } else {
+ disable_irq(rot->irq_num);
+ }
}
- atomic_inc(&rot->irq_enabled);
+
+ return rc;
}
/**
- * sde_hw_rotator_disable_irq - Disable hw rotator interrupt with ref. count
- * Also, clear rotator/regdma irq enable masks.
+ * sde_hw_rotator_enable_irq - Enable hw rotator interrupt with ref. count
+ * Also, clear rotator/regdma irq status.
* @rot: Pointer to hw rotator
*/
-static void sde_hw_rotator_disable_irq(struct sde_hw_rotator *rot)
+static int sde_hw_rotator_enable_irq(struct sde_hw_rotator *rot)
{
+ int ret = 0;
SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
atomic_read(&rot->irq_enabled));
- if (!atomic_read(&rot->irq_enabled)) {
- SDEROT_ERR("irq %d is already disabled\n", rot->irq_num);
- return;
+ ret = sde_hw_rotator_irq_setup(rot);
+ if (ret < 0) {
+ SDEROT_ERR("Rotator irq setup failed %d\n", ret);
+ return ret;
}
- if (!atomic_dec_return(&rot->irq_enabled)) {
+ if (!atomic_read(&rot->irq_enabled)) {
+
if (rot->mode == ROT_REGDMA_OFF)
- SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_EN, 0);
+ SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
+ ROT_DONE_MASK);
else
SDE_ROTREG_WRITE(rot->mdss_base,
- REGDMA_CSR_REGDMA_INT_EN, 0);
- /* disable irq after last pending irq is handled, if any */
- synchronize_irq(rot->irq_num);
- disable_irq_nosync(rot->irq_num);
+ REGDMA_CSR_REGDMA_INT_CLEAR, REGDMA_INT_MASK);
+
+ enable_irq(rot->irq_num);
}
+ atomic_inc(&rot->irq_enabled);
+
+ return ret;
}
static int sde_hw_rotator_halt_vbif_xin_client(void)
@@ -1814,11 +2031,10 @@ static u32 sde_hw_rotator_start_no_regdma(struct sde_hw_rotator_context *ctx,
mem_rdptr = sde_hw_rotator_get_regdma_segment_base(ctx);
wrptr = sde_hw_rotator_get_regdma_segment(ctx);
- if (rot->irq_num >= 0) {
+ if (!sde_hw_rotator_enable_irq(rot)) {
SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_EN, 1);
SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_CLEAR, 1);
reinit_completion(&ctx->rot_comp);
- sde_hw_rotator_enable_irq(rot);
}
SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, ctx->start_ctrl);
@@ -2526,8 +2742,7 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext(
sde_hw_rotator_swts_create(resinfo->rot);
}
- if (resinfo->rot->irq_num >= 0)
- sde_hw_rotator_enable_irq(resinfo->rot);
+ sde_hw_rotator_enable_irq(resinfo->rot);
SDEROT_DBG("New rotator resource:%pK, priority:%d\n",
resinfo, wb_id);
@@ -2555,8 +2770,7 @@ static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr,
resinfo, hw->wb_id, atomic_read(&hw->num_active),
hw->pending_count);
- if (resinfo->rot->irq_num >= 0)
- sde_hw_rotator_disable_irq(resinfo->rot);
+ sde_hw_rotator_disable_irq(resinfo->rot);
devm_kfree(&mgr->pdev->dev, resinfo);
}
@@ -3304,176 +3518,6 @@ static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot)
}
/*
- * sde_hw_rotator_rotirq_handler - non-regdma interrupt handler
- * @irq: Interrupt number
- * @ptr: Pointer to private handle provided during registration
- *
- * This function services rotator interrupt and wakes up waiting client
- * with pending rotation requests already submitted to h/w.
- */
-static irqreturn_t sde_hw_rotator_rotirq_handler(int irq, void *ptr)
-{
- struct sde_hw_rotator *rot = ptr;
- struct sde_hw_rotator_context *ctx;
- irqreturn_t ret = IRQ_NONE;
- u32 isr;
-
- isr = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_INTR_STATUS);
-
- SDEROT_DBG("intr_status = %8.8x\n", isr);
-
- if (isr & ROT_DONE_MASK) {
- if (rot->irq_num >= 0)
- sde_hw_rotator_disable_irq(rot);
- SDEROT_DBG("Notify rotator complete\n");
-
- /* Normal rotator only 1 session, no need to lookup */
- ctx = rot->rotCtx[0][0];
- WARN_ON(ctx == NULL);
- complete_all(&ctx->rot_comp);
-
- spin_lock(&rot->rotisr_lock);
- SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
- ROT_DONE_CLEAR);
- spin_unlock(&rot->rotisr_lock);
- ret = IRQ_HANDLED;
- }
-
- return ret;
-}
-
-/*
- * sde_hw_rotator_regdmairq_handler - regdma interrupt handler
- * @irq: Interrupt number
- * @ptr: Pointer to private handle provided during registration
- *
- * This function services rotator interrupt, decoding the source of
- * events (high/low priority queue), and wakes up all waiting clients
- * with pending rotation requests already submitted to h/w.
- */
-static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr)
-{
- struct sde_rot_data_type *mdata = sde_rot_get_mdata();
- struct sde_hw_rotator *rot = ptr;
- struct sde_hw_rotator_context *ctx, *tmp;
- irqreturn_t ret = IRQ_NONE;
- u32 isr, isr_tmp;
- u32 ts;
- u32 q_id;
-
- isr = SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_STATUS);
- /* acknowledge interrupt before reading latest timestamp */
- SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr);
-
- SDEROT_DBG("intr_status = %8.8x\n", isr);
-
- /* Any REGDMA status, including error and watchdog timer, should
- * trigger and wake up waiting thread
- */
- if (isr & (REGDMA_INT_HIGH_MASK | REGDMA_INT_LOW_MASK)) {
- spin_lock(&rot->rotisr_lock);
-
- /*
- * Obtain rotator context based on timestamp from regdma
- * and low/high interrupt status
- */
- if (isr & REGDMA_INT_HIGH_MASK) {
- q_id = ROT_QUEUE_HIGH_PRIORITY;
- } else if (isr & REGDMA_INT_LOW_MASK) {
- q_id = ROT_QUEUE_LOW_PRIORITY;
- } else {
- SDEROT_ERR("unknown ISR status: isr=0x%X\n", isr);
- goto done_isr_handle;
- }
-
- ts = __sde_hw_rotator_get_timestamp(rot, q_id);
-
- /*
- * Timestamp packet is not available in sbuf mode.
- * Simulate timestamp update in the handler instead.
- */
- if (test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map) ||
- list_empty(&rot->sbuf_ctx[q_id]))
- goto skip_sbuf;
-
- ctx = NULL;
- isr_tmp = isr;
- list_for_each_entry(tmp, &rot->sbuf_ctx[q_id], list) {
- u32 mask;
-
- mask = tmp->timestamp & 0x1 ? REGDMA_INT_1_MASK :
- REGDMA_INT_0_MASK;
- if (isr_tmp & mask) {
- isr_tmp &= ~mask;
- ctx = tmp;
- ts = ctx->timestamp;
- rot->ops.update_ts(rot, ctx->q_id, ts);
- SDEROT_DBG("update swts:0x%X\n", ts);
- }
- SDEROT_EVTLOG(isr, tmp->timestamp);
- }
- if (ctx == NULL)
- SDEROT_ERR("invalid swts ctx\n");
-skip_sbuf:
- ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK];
-
- /*
- * Wake up all waiting context from the current and previous
- * SW Timestamp.
- */
- while (ctx &&
- sde_hw_rotator_elapsed_swts(ctx->timestamp, ts) >= 0) {
- ctx->last_regdma_isr_status = isr;
- ctx->last_regdma_timestamp = ts;
- SDEROT_DBG(
- "regdma complete: ctx:%pK, ts:%X\n", ctx, ts);
- wake_up_all(&ctx->regdma_waitq);
-
- ts = (ts - 1) & SDE_REGDMA_SWTS_MASK;
- ctx = rot->rotCtx[q_id]
- [ts & SDE_HW_ROT_REGDMA_SEG_MASK];
- }
-
-done_isr_handle:
- spin_unlock(&rot->rotisr_lock);
- ret = IRQ_HANDLED;
- } else if (isr & REGDMA_INT_ERR_MASK) {
- /*
- * For REGDMA Err, we save the isr info and wake up
- * all waiting contexts
- */
- int i, j;
-
- SDEROT_ERR(
- "regdma err isr:%X, wake up all waiting contexts\n",
- isr);
-
- spin_lock(&rot->rotisr_lock);
-
- for (i = 0; i < ROT_QUEUE_MAX; i++) {
- for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) {
- ctx = rot->rotCtx[i][j];
- if (ctx && ctx->last_regdma_isr_status == 0) {
- ts = __sde_hw_rotator_get_timestamp(
- rot, i);
- ctx->last_regdma_isr_status = isr;
- ctx->last_regdma_timestamp = ts;
- wake_up_all(&ctx->regdma_waitq);
- SDEROT_DBG(
- "Wakeup rotctx[%d][%d]:%pK\n",
- i, j, ctx);
- }
- }
- }
-
- spin_unlock(&rot->rotisr_lock);
- ret = IRQ_HANDLED;
- }
-
- return ret;
-}
-
-/*
* sde_hw_rotator_validate_entry - validate rotation entry
* @mgr: Pointer to rotator manager
* @entry: Pointer to rotation entry
@@ -3985,30 +4029,7 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
if (ret)
goto error_parse_dt;
- rot->irq_num = platform_get_irq(mgr->pdev, 0);
- if (rot->irq_num == -EPROBE_DEFER) {
- SDEROT_INFO("irq master master not ready, defer probe\n");
- return -EPROBE_DEFER;
- } else if (rot->irq_num < 0) {
- SDEROT_ERR("fail to get rotator irq, fallback to polling\n");
- } else {
- if (rot->mode == ROT_REGDMA_OFF)
- ret = devm_request_threaded_irq(&mgr->pdev->dev,
- rot->irq_num,
- sde_hw_rotator_rotirq_handler,
- NULL, 0, "sde_rotator_r3", rot);
- else
- ret = devm_request_threaded_irq(&mgr->pdev->dev,
- rot->irq_num,
- sde_hw_rotator_regdmairq_handler,
- NULL, 0, "sde_rotator_r3", rot);
- if (ret) {
- SDEROT_ERR("fail to request irq r:%d\n", ret);
- rot->irq_num = -1;
- } else {
- disable_irq(rot->irq_num);
- }
- }
+ rot->irq_num = -EINVAL;
atomic_set(&rot->irq_enabled, 0);
ret = sde_rotator_hw_rev_init(rot);
@@ -4056,8 +4077,6 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
mdata->sde_rot_hw = rot;
return 0;
error_hw_rev_init:
- if (rot->irq_num >= 0)
- devm_free_irq(&mgr->pdev->dev, rot->irq_num, mdata);
devm_kfree(&mgr->pdev->dev, mgr->hw_data);
error_parse_dt:
return ret;