Loading drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +166 −46 Original line number Diff line number Diff line Loading @@ -77,6 +77,142 @@ #define SDE_ROTREG_READ(base, off) \ readl_relaxed(base + (off)) /* Invalid software timestamp value for initialization */ #define SDE_REGDMA_SWTS_INVALID (~0) /** * sde_hw_rotator_elapsed_swts - Find difference of 2 software timestamps * @ts_curr: current software timestamp * @ts_prev: previous software timestamp * @return: the amount ts_curr is ahead of ts_prev */ static int sde_hw_rotator_elapsed_swts(u32 ts_curr, u32 ts_prev) { u32 diff = (ts_curr - ts_prev) & SDE_REGDMA_SWTS_MASK; return sign_extend32(diff, (SDE_REGDMA_SWTS_SHIFT - 1)); } /** * sde_hw_rotator_pending_swts - Check if the given context is still pending * @rot: Pointer to hw rotator * @ctx: Pointer to rotator context * @pswts: Pointer to returned reference software timestamp, optional * @return: true if context has pending requests */ static int sde_hw_rotator_pending_swts(struct sde_hw_rotator *rot, struct sde_hw_rotator_context *ctx, u32 *pswts) { u32 swts; int ts_diff; bool pending; if (ctx->last_regdma_timestamp == SDE_REGDMA_SWTS_INVALID) swts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG); else swts = ctx->last_regdma_timestamp; if (ctx->q_id == ROT_QUEUE_LOW_PRIORITY) swts >>= SDE_REGDMA_SWTS_SHIFT; swts &= SDE_REGDMA_SWTS_MASK; ts_diff = sde_hw_rotator_elapsed_swts(ctx->timestamp, swts); if (pswts) *pswts = swts; pending = (ts_diff > 0) ? true : false; SDEROT_DBG("ts:0x%x, queue_id:%d, swts:0x%x, pending:%d\n", ctx->timestamp, ctx->q_id, swts, pending); return pending; } /** * 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_enable_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)) { if (rot->mode == ROT_REGDMA_OFF) SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR, ROT_DONE_MASK); else SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, REGDMA_INT_MASK); enable_irq(rot->irq_num); } atomic_inc(&rot->irq_enabled); } /** * 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_dump_status - Dump hw rotator status on error * @rot: Pointer to hw rotator */ static void sde_hw_rotator_dump_status(struct sde_hw_rotator *rot) { SDEROT_ERR( "op_mode = %x, int_en = %x, int_status = %x\n", SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_OP_MODE), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_EN), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_STATUS)); SDEROT_ERR( "ts = %x, q0_status = %x, q1_status = %x, block_status = %x\n", SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_QUEUE_0_STATUS), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_QUEUE_1_STATUS), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_BLOCK_STATUS)); SDEROT_ERR( "invalid_cmd_offset = %x, fsm_state = %x\n", SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INVALID_CMD_RAM_OFFSET), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_FSM_STATE)); } /** * sde_hw_rotator_get_ctx(): Retrieve rotator context from rotator HW based * on provided session_id. Each rotator has a different session_id. Loading Loading @@ -476,7 +612,7 @@ static u32 sde_hw_rotator_start_no_regdma(struct sde_hw_rotator_context *ctx, SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_EN, 1); SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_CLEAR, 1); reinit_completion(&ctx->rot_comp); enable_irq(rot->irq_num); sde_hw_rotator_enable_irq(rot); } SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, 1); Loading Loading @@ -572,9 +708,6 @@ static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx, wrptr = sde_hw_rotator_get_regdma_segment(ctx); if (rot->irq_num >= 0) reinit_completion(&ctx->regdma_comp); /* * Last ROT command must be ROT_START before REGDMA start */ Loading Loading @@ -676,7 +809,7 @@ static u32 sde_hw_rotator_wait_done_no_regdma( SDEROT_WARN( "Timeout waiting, but rotator job is done!!\n"); disable_irq_nosync(rot->irq_num); sde_hw_rotator_disable_irq(rot); } spin_unlock_irqrestore(&rot->rotisr_lock, flags); } else { Loading Loading @@ -719,13 +852,15 @@ static u32 sde_hw_rotator_wait_done_regdma( u32 last_isr; u32 last_ts; u32 int_id; u32 swts; u32 sts = 0; unsigned long flags; if (rot->irq_num >= 0) { SDEROT_DBG("Wait for REGDMA completion, ctx:%p, ts:%X\n", ctx, ctx->timestamp); rc = wait_for_completion_timeout(&ctx->regdma_comp, rc = wait_event_timeout(ctx->regdma_waitq, !sde_hw_rotator_pending_swts(rot, ctx, &swts), KOFF_TIMEOUT); spin_lock_irqsave(&rot->rotisr_lock, flags); Loading @@ -738,11 +873,12 @@ static u32 sde_hw_rotator_wait_done_regdma( status, int_id, last_ts); if (rc == 0 || (status & REGDMA_INT_ERR_MASK)) { bool pending; pending = sde_hw_rotator_pending_swts(rot, ctx, &swts); SDEROT_ERR( "Timeout wait for regdma interrupt status, ts:%X\n", ctx->timestamp); SDEROT_ERR("last_isr:0x%X, last_ts:0x%X, rc=%d\n", last_isr, last_ts, rc); "Timeout wait for regdma interrupt status, ts:0x%X/0x%X pending:%d\n", ctx->timestamp, swts, pending); if (status & REGDMA_WATCHDOG_INT) SDEROT_ERR("REGDMA watchdog interrupt\n"); Loading @@ -753,24 +889,13 @@ static u32 sde_hw_rotator_wait_done_regdma( else if (status & REGDMA_INVALID_CMD) SDEROT_ERR("REGDMA invalid command\n"); sde_hw_rotator_dump_status(rot); status = ROT_ERROR_BIT; } else if (queue_id == ROT_QUEUE_HIGH_PRIORITY) { /* Got to match exactly with interrupt ID */ int_id = REGDMA_QUEUE0_INT0 << int_id; SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, int_id); status = 0; } else if (queue_id == ROT_QUEUE_LOW_PRIORITY) { /* Matching interrupt ID */ int_id = REGDMA_QUEUE1_INT0 << int_id; SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, int_id); } else { if (rc == 1) SDEROT_WARN( "REGDMA done but no irq, ts:0x%X/0x%X\n", ctx->timestamp, swts); status = 0; } Loading Loading @@ -1007,7 +1132,7 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext( } if (resinfo->rot->irq_num >= 0) enable_irq(resinfo->rot->irq_num); sde_hw_rotator_enable_irq(resinfo->rot); SDEROT_DBG("New rotator resource:%p, priority:%d\n", resinfo, wb_id); Loading Loading @@ -1036,7 +1161,7 @@ static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr, hw->pending_count); if (resinfo->rot->irq_num >= 0) disable_irq(resinfo->rot->irq_num); sde_hw_rotator_disable_irq(resinfo->rot); devm_kfree(&mgr->pdev->dev, resinfo); } Loading Loading @@ -1078,8 +1203,10 @@ static struct sde_hw_rotator_context *sde_hw_rotator_alloc_rotctx( ctx->q_id * SDE_HW_ROT_REGDMA_TOTAL_CTX + sde_hw_rotator_get_regdma_ctxidx(ctx)); ctx->last_regdma_timestamp = SDE_REGDMA_SWTS_INVALID; init_completion(&ctx->rot_comp); init_completion(&ctx->regdma_comp); init_waitqueue_head(&ctx->regdma_waitq); /* Store rotator context for lookup purpose */ sde_hw_rotator_put_ctx(ctx); Loading Loading @@ -1419,7 +1546,7 @@ static irqreturn_t sde_hw_rotator_rotirq_handler(int irq, void *ptr) if (isr & ROT_DONE_MASK) { if (rot->irq_num >= 0) disable_irq_nosync(rot->irq_num); sde_hw_rotator_disable_irq(rot); SDEROT_DBG("Notify rotator complete\n"); /* Normal rotator only 1 session, no need to lookup */ Loading Loading @@ -1456,6 +1583,8 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) 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); ts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG); SDEROT_DBG("intr_status = %8.8x, sw_TS:%X\n", isr, ts); Loading @@ -1480,30 +1609,23 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) } ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK]; WARN_ON(ctx == NULL); /* * Wake up all waiting context from the current and previous * SW Timestamp. */ do { 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:%p, ts:%X\n", ctx, ts); complete_all(&ctx->regdma_comp); 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]; } while (ctx && (ctx->last_regdma_timestamp == 0)); /* * Clear corresponding regdma interrupt because it is a level * interrupt */ SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr); }; spin_unlock(&rot->rotisr_lock); ret = IRQ_HANDLED; Loading @@ -1526,16 +1648,13 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) if (ctx && ctx->last_regdma_isr_status == 0) { ctx->last_regdma_isr_status = isr; ctx->last_regdma_timestamp = ts; complete_all(&ctx->regdma_comp); wake_up_all(&ctx->regdma_waitq); SDEROT_DBG("Wakeup rotctx[%d][%d]:%p\n", i, j, ctx); } } } SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr); spin_unlock(&rot->rotisr_lock); ret = IRQ_HANDLED; } Loading Loading @@ -1810,6 +1929,7 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr) disable_irq(rot->irq_num); } } atomic_set(&rot->irq_enabled, 0); setup_rotator_ops(&rot->ops, rot->mode); Loading drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h +2 −3 Original line number Diff line number Diff line Loading @@ -202,7 +202,7 @@ struct sde_hw_rotator_context { u32 *regdma_wrptr; u32 timestamp; struct completion rot_comp; struct completion regdma_comp; wait_queue_head_t regdma_waitq; struct sde_dbg_buf src_dbgbuf; struct sde_dbg_buf dst_dbgbuf; u32 last_regdma_isr_status; Loading Loading @@ -253,6 +253,7 @@ struct sde_hw_rotator { /* logical interrupt number */ int irq_num; atomic_t irq_enabled; /* internal ION memory for SW timestamp */ struct ion_client *iclient; Loading @@ -260,8 +261,6 @@ struct sde_hw_rotator { void *swts_buffer; u32 highest_bank; struct completion rot_comp; struct completion regdma_comp; spinlock_t rotctx_lock; spinlock_t rotisr_lock; Loading Loading
drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +166 −46 Original line number Diff line number Diff line Loading @@ -77,6 +77,142 @@ #define SDE_ROTREG_READ(base, off) \ readl_relaxed(base + (off)) /* Invalid software timestamp value for initialization */ #define SDE_REGDMA_SWTS_INVALID (~0) /** * sde_hw_rotator_elapsed_swts - Find difference of 2 software timestamps * @ts_curr: current software timestamp * @ts_prev: previous software timestamp * @return: the amount ts_curr is ahead of ts_prev */ static int sde_hw_rotator_elapsed_swts(u32 ts_curr, u32 ts_prev) { u32 diff = (ts_curr - ts_prev) & SDE_REGDMA_SWTS_MASK; return sign_extend32(diff, (SDE_REGDMA_SWTS_SHIFT - 1)); } /** * sde_hw_rotator_pending_swts - Check if the given context is still pending * @rot: Pointer to hw rotator * @ctx: Pointer to rotator context * @pswts: Pointer to returned reference software timestamp, optional * @return: true if context has pending requests */ static int sde_hw_rotator_pending_swts(struct sde_hw_rotator *rot, struct sde_hw_rotator_context *ctx, u32 *pswts) { u32 swts; int ts_diff; bool pending; if (ctx->last_regdma_timestamp == SDE_REGDMA_SWTS_INVALID) swts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG); else swts = ctx->last_regdma_timestamp; if (ctx->q_id == ROT_QUEUE_LOW_PRIORITY) swts >>= SDE_REGDMA_SWTS_SHIFT; swts &= SDE_REGDMA_SWTS_MASK; ts_diff = sde_hw_rotator_elapsed_swts(ctx->timestamp, swts); if (pswts) *pswts = swts; pending = (ts_diff > 0) ? true : false; SDEROT_DBG("ts:0x%x, queue_id:%d, swts:0x%x, pending:%d\n", ctx->timestamp, ctx->q_id, swts, pending); return pending; } /** * 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_enable_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)) { if (rot->mode == ROT_REGDMA_OFF) SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR, ROT_DONE_MASK); else SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, REGDMA_INT_MASK); enable_irq(rot->irq_num); } atomic_inc(&rot->irq_enabled); } /** * 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_dump_status - Dump hw rotator status on error * @rot: Pointer to hw rotator */ static void sde_hw_rotator_dump_status(struct sde_hw_rotator *rot) { SDEROT_ERR( "op_mode = %x, int_en = %x, int_status = %x\n", SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_OP_MODE), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_EN), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_STATUS)); SDEROT_ERR( "ts = %x, q0_status = %x, q1_status = %x, block_status = %x\n", SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_QUEUE_0_STATUS), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_QUEUE_1_STATUS), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_BLOCK_STATUS)); SDEROT_ERR( "invalid_cmd_offset = %x, fsm_state = %x\n", SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INVALID_CMD_RAM_OFFSET), SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_FSM_STATE)); } /** * sde_hw_rotator_get_ctx(): Retrieve rotator context from rotator HW based * on provided session_id. Each rotator has a different session_id. Loading Loading @@ -476,7 +612,7 @@ static u32 sde_hw_rotator_start_no_regdma(struct sde_hw_rotator_context *ctx, SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_EN, 1); SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_CLEAR, 1); reinit_completion(&ctx->rot_comp); enable_irq(rot->irq_num); sde_hw_rotator_enable_irq(rot); } SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, 1); Loading Loading @@ -572,9 +708,6 @@ static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx, wrptr = sde_hw_rotator_get_regdma_segment(ctx); if (rot->irq_num >= 0) reinit_completion(&ctx->regdma_comp); /* * Last ROT command must be ROT_START before REGDMA start */ Loading Loading @@ -676,7 +809,7 @@ static u32 sde_hw_rotator_wait_done_no_regdma( SDEROT_WARN( "Timeout waiting, but rotator job is done!!\n"); disable_irq_nosync(rot->irq_num); sde_hw_rotator_disable_irq(rot); } spin_unlock_irqrestore(&rot->rotisr_lock, flags); } else { Loading Loading @@ -719,13 +852,15 @@ static u32 sde_hw_rotator_wait_done_regdma( u32 last_isr; u32 last_ts; u32 int_id; u32 swts; u32 sts = 0; unsigned long flags; if (rot->irq_num >= 0) { SDEROT_DBG("Wait for REGDMA completion, ctx:%p, ts:%X\n", ctx, ctx->timestamp); rc = wait_for_completion_timeout(&ctx->regdma_comp, rc = wait_event_timeout(ctx->regdma_waitq, !sde_hw_rotator_pending_swts(rot, ctx, &swts), KOFF_TIMEOUT); spin_lock_irqsave(&rot->rotisr_lock, flags); Loading @@ -738,11 +873,12 @@ static u32 sde_hw_rotator_wait_done_regdma( status, int_id, last_ts); if (rc == 0 || (status & REGDMA_INT_ERR_MASK)) { bool pending; pending = sde_hw_rotator_pending_swts(rot, ctx, &swts); SDEROT_ERR( "Timeout wait for regdma interrupt status, ts:%X\n", ctx->timestamp); SDEROT_ERR("last_isr:0x%X, last_ts:0x%X, rc=%d\n", last_isr, last_ts, rc); "Timeout wait for regdma interrupt status, ts:0x%X/0x%X pending:%d\n", ctx->timestamp, swts, pending); if (status & REGDMA_WATCHDOG_INT) SDEROT_ERR("REGDMA watchdog interrupt\n"); Loading @@ -753,24 +889,13 @@ static u32 sde_hw_rotator_wait_done_regdma( else if (status & REGDMA_INVALID_CMD) SDEROT_ERR("REGDMA invalid command\n"); sde_hw_rotator_dump_status(rot); status = ROT_ERROR_BIT; } else if (queue_id == ROT_QUEUE_HIGH_PRIORITY) { /* Got to match exactly with interrupt ID */ int_id = REGDMA_QUEUE0_INT0 << int_id; SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, int_id); status = 0; } else if (queue_id == ROT_QUEUE_LOW_PRIORITY) { /* Matching interrupt ID */ int_id = REGDMA_QUEUE1_INT0 << int_id; SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, int_id); } else { if (rc == 1) SDEROT_WARN( "REGDMA done but no irq, ts:0x%X/0x%X\n", ctx->timestamp, swts); status = 0; } Loading Loading @@ -1007,7 +1132,7 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext( } if (resinfo->rot->irq_num >= 0) enable_irq(resinfo->rot->irq_num); sde_hw_rotator_enable_irq(resinfo->rot); SDEROT_DBG("New rotator resource:%p, priority:%d\n", resinfo, wb_id); Loading Loading @@ -1036,7 +1161,7 @@ static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr, hw->pending_count); if (resinfo->rot->irq_num >= 0) disable_irq(resinfo->rot->irq_num); sde_hw_rotator_disable_irq(resinfo->rot); devm_kfree(&mgr->pdev->dev, resinfo); } Loading Loading @@ -1078,8 +1203,10 @@ static struct sde_hw_rotator_context *sde_hw_rotator_alloc_rotctx( ctx->q_id * SDE_HW_ROT_REGDMA_TOTAL_CTX + sde_hw_rotator_get_regdma_ctxidx(ctx)); ctx->last_regdma_timestamp = SDE_REGDMA_SWTS_INVALID; init_completion(&ctx->rot_comp); init_completion(&ctx->regdma_comp); init_waitqueue_head(&ctx->regdma_waitq); /* Store rotator context for lookup purpose */ sde_hw_rotator_put_ctx(ctx); Loading Loading @@ -1419,7 +1546,7 @@ static irqreturn_t sde_hw_rotator_rotirq_handler(int irq, void *ptr) if (isr & ROT_DONE_MASK) { if (rot->irq_num >= 0) disable_irq_nosync(rot->irq_num); sde_hw_rotator_disable_irq(rot); SDEROT_DBG("Notify rotator complete\n"); /* Normal rotator only 1 session, no need to lookup */ Loading Loading @@ -1456,6 +1583,8 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) 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); ts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG); SDEROT_DBG("intr_status = %8.8x, sw_TS:%X\n", isr, ts); Loading @@ -1480,30 +1609,23 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) } ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK]; WARN_ON(ctx == NULL); /* * Wake up all waiting context from the current and previous * SW Timestamp. */ do { 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:%p, ts:%X\n", ctx, ts); complete_all(&ctx->regdma_comp); 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]; } while (ctx && (ctx->last_regdma_timestamp == 0)); /* * Clear corresponding regdma interrupt because it is a level * interrupt */ SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr); }; spin_unlock(&rot->rotisr_lock); ret = IRQ_HANDLED; Loading @@ -1526,16 +1648,13 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) if (ctx && ctx->last_regdma_isr_status == 0) { ctx->last_regdma_isr_status = isr; ctx->last_regdma_timestamp = ts; complete_all(&ctx->regdma_comp); wake_up_all(&ctx->regdma_waitq); SDEROT_DBG("Wakeup rotctx[%d][%d]:%p\n", i, j, ctx); } } } SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr); spin_unlock(&rot->rotisr_lock); ret = IRQ_HANDLED; } Loading Loading @@ -1810,6 +1929,7 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr) disable_irq(rot->irq_num); } } atomic_set(&rot->irq_enabled, 0); setup_rotator_ops(&rot->ops, rot->mode); Loading
drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h +2 −3 Original line number Diff line number Diff line Loading @@ -202,7 +202,7 @@ struct sde_hw_rotator_context { u32 *regdma_wrptr; u32 timestamp; struct completion rot_comp; struct completion regdma_comp; wait_queue_head_t regdma_waitq; struct sde_dbg_buf src_dbgbuf; struct sde_dbg_buf dst_dbgbuf; u32 last_regdma_isr_status; Loading Loading @@ -253,6 +253,7 @@ struct sde_hw_rotator { /* logical interrupt number */ int irq_num; atomic_t irq_enabled; /* internal ION memory for SW timestamp */ struct ion_client *iclient; Loading @@ -260,8 +261,6 @@ struct sde_hw_rotator { void *swts_buffer; u32 highest_bank; struct completion rot_comp; struct completion regdma_comp; spinlock_t rotctx_lock; spinlock_t rotisr_lock; Loading