diff options
author | qctecmdr <qctecmdr@localhost> | 2019-12-12 02:57:39 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2019-12-12 02:57:39 -0800 |
commit | 5c6c31021ac08612f19044cb458cfdea14e4d046 (patch) | |
tree | 732cbaa66ab6d46f00c472d20206ade2f8aae9ad | |
parent | 65b4eb5967033e1bc94e89a3469a5b1bc31882ad (diff) | |
parent | bd59bbaf0160071651f9b99a180273ad063c2305 (diff) | |
download | display-drivers-5c6c31021ac08612f19044cb458cfdea14e4d046.tar.gz |
Merge "msm:disp:rotator: setup irq during first rotator commit"
-rw-r--r-- | rotator/sde_rotator_r3.c | 477 |
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; |