diff options
Diffstat (limited to 'drivers/gpu/imx/dcss')
-rw-r--r-- | drivers/gpu/imx/dcss/dcss-ctxld.c | 48 | ||||
-rw-r--r-- | drivers/gpu/imx/dcss/dcss-dpr.c | 21 | ||||
-rw-r--r-- | drivers/gpu/imx/dcss/dcss-dtg.c | 74 | ||||
-rw-r--r-- | drivers/gpu/imx/dcss/dcss-prv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/imx/dcss/dcss-scaler.c | 21 |
5 files changed, 135 insertions, 32 deletions
diff --git a/drivers/gpu/imx/dcss/dcss-ctxld.c b/drivers/gpu/imx/dcss/dcss-ctxld.c index c6c4eb3a1014..a42a969a253f 100644 --- a/drivers/gpu/imx/dcss/dcss-ctxld.c +++ b/drivers/gpu/imx/dcss/dcss-ctxld.c @@ -106,7 +106,7 @@ struct dcss_ctxld_priv { u8 current_ctx; bool in_use; - bool run_again; + bool armed; spinlock_t lock; /* protects concurent access to private data */ }; @@ -141,11 +141,6 @@ static irqreturn_t dcss_ctxld_irq_handler(int irq, void *data) !(irq_status & CTXLD_ENABLE) && priv->in_use) { priv->in_use = false; - if (priv->run_again) { - priv->run_again = false; - __dcss_ctxld_enable(priv); - goto exit; - } if (priv->dcss->dcss_disable_callback) { struct dcss_dtg_priv *dtg = priv->dcss->dtg_priv; @@ -165,9 +160,8 @@ static irqreturn_t dcss_ctxld_irq_handler(int irq, void *data) priv->ctx_size[priv->current_ctx ^ 1][CTX_SB_LP]); } -exit: dcss_clr(irq_status & (CTXLD_IRQ_ERROR | CTXLD_IRQ_COMPLETION), - priv->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS); + priv->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS); return IRQ_HANDLED; } @@ -291,10 +285,13 @@ static int __dcss_ctxld_enable(struct dcss_ctxld_priv *ctxld) u32 db_base, sb_base, sb_count; u32 sb_hp_cnt, sb_lp_cnt, db_cnt; + dcss_dpr_write_sysctrl(ctxld->dcss); + dcss_scaler_write_sclctrl(ctxld->dcss); + if (dcss_dtrc_is_running(ctxld->dcss, 1) || dcss_dtrc_is_running(ctxld->dcss, 2)) { dcss_dtrc_switch_banks(ctxld->dcss); - ctxld->run_again = true; + ctxld->armed = true; } sb_hp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_HP]; @@ -360,20 +357,27 @@ int dcss_ctxld_enable(struct dcss_soc *dcss) unsigned long flags; spin_lock_irqsave(&ctxld->lock, flags); - if (ctxld->in_use) { - ctxld->run_again = true; - spin_unlock_irqrestore(&ctxld->lock, flags); - return 0; - } - - __dcss_ctxld_enable(ctxld); - + ctxld->armed = true; spin_unlock_irqrestore(&ctxld->lock, flags); return 0; } EXPORT_SYMBOL(dcss_ctxld_enable); +void dcss_ctxld_kick(struct dcss_soc *dcss) +{ + struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv; + unsigned long flags; + + spin_lock_irqsave(&ctxld->lock, flags); + if (ctxld->armed) { + ctxld->armed = false; + __dcss_ctxld_enable(dcss->ctxld_priv); + } + spin_unlock_irqrestore(&ctxld->lock, flags); +} +EXPORT_SYMBOL(dcss_ctxld_kick); + void dcss_ctxld_write_irqsafe(struct dcss_soc *dcss, u32 ctx_id, u32 val, u32 reg_ofs) { @@ -404,6 +408,16 @@ void dcss_ctxld_write(struct dcss_soc *dcss, u32 ctx_id, u32 val, u32 reg_ofs) spin_unlock_irqrestore(&ctxld->lock, flags); } +bool dcss_ctxld_is_flushed(struct dcss_soc *dcss) +{ + struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv; + + return ctxld->ctx_size[ctxld->current_ctx][CTX_DB] == 0 && + ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] == 0 && + ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] == 0; +} +EXPORT_SYMBOL(dcss_ctxld_is_flushed); + int dcss_ctxld_resume(struct dcss_soc *dcss) { struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv; diff --git a/drivers/gpu/imx/dcss/dcss-dpr.c b/drivers/gpu/imx/dcss/dcss-dpr.c index ba89a37c4247..ebf2b06957b5 100644 --- a/drivers/gpu/imx/dcss/dcss-dpr.c +++ b/drivers/gpu/imx/dcss/dcss-dpr.c @@ -111,6 +111,8 @@ struct dcss_dpr_ch { u32 sys_ctrl; u32 rtram_ctrl; + bool sys_ctrl_chgd; + u32 pitch; bool use_dtrc; @@ -431,8 +433,7 @@ void dcss_dpr_enable(struct dcss_soc *dcss, int ch_num, bool en) } if (ch->sys_ctrl != sys_ctrl) - dcss_dpr_write(dpr, ch_num, sys_ctrl, - DCSS_DPR_SYSTEM_CTRL0); + ch->sys_ctrl_chgd = true; ch->sys_ctrl = sys_ctrl; } @@ -651,3 +652,19 @@ void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format, dcss_dpr_rtram_set(dcss, ch_num, pix_format); } EXPORT_SYMBOL(dcss_dpr_format_set); + +void dcss_dpr_write_sysctrl(struct dcss_soc *dcss) +{ + int chnum; + + for (chnum = 0; chnum < 3; chnum++) { + struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[chnum]; + + if (ch->sys_ctrl_chgd) { + dcss_ctxld_write_irqsafe(dcss, ch->ctx_id, ch->sys_ctrl, + ch->base_ofs + + DCSS_DPR_SYSTEM_CTRL0); + ch->sys_ctrl_chgd = false; + } + } +} diff --git a/drivers/gpu/imx/dcss/dcss-dtg.c b/drivers/gpu/imx/dcss/dcss-dtg.c index c93925653fef..9b85c53237ec 100644 --- a/drivers/gpu/imx/dcss/dcss-dtg.c +++ b/drivers/gpu/imx/dcss/dcss-dtg.c @@ -17,6 +17,8 @@ #include <linux/io.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> #include <drm/drm_fourcc.h> #include <video/imx-dcss.h> @@ -136,6 +138,8 @@ struct dcss_dtg_priv { u32 alpha; u32 use_global; + int ctxld_kick_irq; + /* * This will be passed on by DRM CRTC so that we can signal when DTG has * been successfully stopped. Otherwise, any modesetting while DTG is @@ -169,6 +173,44 @@ void dcss_dtg_dump_regs(struct seq_file *s, void *data) } #endif +static irqreturn_t dcss_dtg_irq_handler(int irq, void *data) +{ + struct dcss_dtg_priv *dtg = data; + u32 status; + + status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS); + + dcss_ctxld_kick(dtg->dcss); + + dcss_writel(status & LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL); + + return IRQ_HANDLED; +} + +static int dcss_dtg_irq_config(struct dcss_dtg_priv *dtg) +{ + struct dcss_soc *dcss = dtg->dcss; + struct platform_device *pdev = to_platform_device(dcss->dev); + int ret; + + dtg->ctxld_kick_irq = platform_get_irq_byname(pdev, "ctxld_kick"); + if (dtg->ctxld_kick_irq < 0) { + dev_err(dcss->dev, "dtg: can't get line2 irq number\n"); + return dtg->ctxld_kick_irq; + } + + ret = devm_request_irq(dcss->dev, dtg->ctxld_kick_irq, + dcss_dtg_irq_handler, + IRQF_TRIGGER_HIGH, + "dcss_ctxld_kick", dtg); + if (ret) { + dev_err(dcss->dev, "dtg: irq request failed.\n"); + return ret; + } + + return 0; +} + int dcss_dtg_init(struct dcss_soc *dcss, unsigned long dtg_base) { struct dcss_dtg_priv *dtg; @@ -198,7 +240,7 @@ int dcss_dtg_init(struct dcss_soc *dcss, unsigned long dtg_base) dtg->control_status |= OVL_DATA_MODE | BLENDER_VIDEO_ALPHA_SEL | ((dtg->alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK); - return 0; + return dcss_dtg_irq_config(dtg); } void dcss_dtg_exit(struct dcss_soc *dcss) @@ -215,6 +257,7 @@ void dcss_dtg_sync_set(struct dcss_soc *dcss, struct videomode *vm) u16 dtg_lrc_x, dtg_lrc_y; u16 dis_ulc_x, dis_ulc_y; u16 dis_lrc_x, dis_lrc_y; + u32 sb_ctxld_trig, db_ctxld_trig; dev_dbg(dcss->dev, "hfront_porch = %d\n", vm->hfront_porch); dev_dbg(dcss->dev, "hback_porch = %d\n", vm->hback_porch); @@ -253,14 +296,18 @@ void dcss_dtg_sync_set(struct dcss_soc *dcss, struct videomode *vm) dtg->dis_ulc_x = dis_ulc_x; dtg->dis_ulc_y = dis_ulc_y; - /* - * If the dis_ulc_y is too small, then the context loader will not have - * time to load the DB context. This happens with LCD panels which have - * small vfront_porch, vback_porch and/or vsync_len. - */ - dcss_dtg_write(dtg, ((0 << TC_CTXLD_SB_Y_POS) & TC_CTXLD_SB_Y_MASK) | - (dis_ulc_y < 50 ? 50 : dis_ulc_y), - DCSS_DTG_TC_CTXLD); + sb_ctxld_trig = ((0 * dis_lrc_y / 100) << TC_CTXLD_SB_Y_POS) & + TC_CTXLD_SB_Y_MASK; + db_ctxld_trig = ((99 * dis_lrc_y / 100) << TC_CTXLD_DB_Y_POS) & + TC_CTXLD_DB_Y_MASK; + + dcss_dtg_write(dtg, sb_ctxld_trig | db_ctxld_trig, DCSS_DTG_TC_CTXLD); + + /* vblank trigger */ + dcss_dtg_write(dtg, 0, DCSS_DTG_LINE0_INT); + + /* CTXLD trigger */ + dcss_dtg_write(dtg, ((98 * dis_lrc_y) / 100) << 16, DCSS_DTG_LINE1_INT); } EXPORT_SYMBOL(dcss_dtg_sync_set); @@ -424,11 +471,16 @@ void dcss_dtg_vblank_irq_enable(struct dcss_soc *dcss, bool en) { void __iomem *reg; struct dcss_dtg_priv *dtg = dcss->dtg_priv; - u32 val = en ? LINE0_IRQ : 0; + u32 val = en ? (LINE0_IRQ | LINE1_IRQ) : 0; + + /* need to keep the CTXLD kick interrupt ON if DTRC is used */ + if (!en && (dcss_dtrc_is_running(dcss, 1) || + dcss_dtrc_is_running(dcss, 2))) + val |= LINE1_IRQ; reg = dtg->base_reg + DCSS_DTG_INT_MASK; - dcss_update(val, LINE0_IRQ, reg); + dcss_update(val, LINE0_IRQ | LINE1_IRQ, reg); } void dcss_dtg_vblank_irq_clear(struct dcss_soc *dcss) diff --git a/drivers/gpu/imx/dcss/dcss-prv.h b/drivers/gpu/imx/dcss/dcss-prv.h index ae9551a8953f..1911076fd09d 100644 --- a/drivers/gpu/imx/dcss/dcss-prv.h +++ b/drivers/gpu/imx/dcss/dcss-prv.h @@ -80,10 +80,12 @@ int dcss_ctxld_resume(struct dcss_soc *dcss); int dcss_ctxld_suspend(struct dcss_soc *dcss); void dcss_ctxld_write_irqsafe(struct dcss_soc *dcss, u32 ctx_id, u32 val, u32 reg_ofs); +void dcss_ctxld_kick(struct dcss_soc *dcss); /* DPR */ int dcss_dpr_init(struct dcss_soc *dcss, unsigned long dpr_base); void dcss_dpr_exit(struct dcss_soc *dcss); +void dcss_dpr_write_sysctrl(struct dcss_soc *dcss); /* DTG */ int dcss_dtg_init(struct dcss_soc *dcss, unsigned long dtg_base); @@ -103,6 +105,7 @@ void dcss_hdr10_cfg(struct dcss_soc *dcss); /* SCALER */ int dcss_scaler_init(struct dcss_soc *dcss, unsigned long scaler_base); void dcss_scaler_exit(struct dcss_soc *dcss); +void dcss_scaler_write_sclctrl(struct dcss_soc *dcss); /* DTRC */ int dcss_dtrc_init(struct dcss_soc *dcss, unsigned long dtrc_base); diff --git a/drivers/gpu/imx/dcss/dcss-scaler.c b/drivers/gpu/imx/dcss/dcss-scaler.c index b948a96a7a4c..586dc1a0cffd 100644 --- a/drivers/gpu/imx/dcss/dcss-scaler.c +++ b/drivers/gpu/imx/dcss/dcss-scaler.c @@ -107,6 +107,8 @@ struct dcss_scaler_ch { u32 sdata_ctrl; u32 scaler_ctrl; + bool scaler_ctrl_chgd; + u32 c_vstart; u32 c_hstart; }; @@ -397,8 +399,7 @@ void dcss_scaler_enable(struct dcss_soc *dcss, int ch_num, bool en) DCSS_SCALER_SDATA_CTRL); if (ch->scaler_ctrl != scaler_ctrl) - dcss_scaler_write(dcss->scaler_priv, ch_num, scaler_ctrl, - DCSS_SCALER_CTRL); + ch->scaler_ctrl_chgd = true; ch->scaler_ctrl = scaler_ctrl; } @@ -975,3 +976,19 @@ void dcss_scaler_setup(struct dcss_soc *dcss, int ch_num, u32 pix_format, dst_yres, vrefresh_hz, wrscl_needed); } EXPORT_SYMBOL(dcss_scaler_setup); + +void dcss_scaler_write_sclctrl(struct dcss_soc *dcss) +{ + int chnum; + + for (chnum = 0; chnum < 3; chnum++) { + struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[chnum]; + + if (ch->scaler_ctrl_chgd) { + dcss_ctxld_write_irqsafe(dcss, ch->ctx_id, + ch->scaler_ctrl, + ch->base_ofs + DCSS_SCALER_CTRL); + ch->scaler_ctrl_chgd = false; + } + } +} |