diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-04-14 08:51:33 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-04-14 08:51:33 -0700 |
commit | 85a3685852d9ac7d92be9d824533c915a4597fa4 (patch) | |
tree | b7c542e2061cf96c9f7ad500fa12567f9ff0b39f /drivers/gpu/ipu-v3 | |
parent | 92bac83dd79e60e65c475222e41a992a70434beb (diff) | |
parent | 8b8a518ef16be2de27207991e32fc32b0475c767 (diff) | |
download | op-kernel-dev-85a3685852d9ac7d92be9d824533c915a4597fa4.zip op-kernel-dev-85a3685852d9ac7d92be9d824533c915a4597fa4.tar.gz |
Merge branch 'next' into for-linus
Prepare first round of input updates for 4.1 merge window.
Diffstat (limited to 'drivers/gpu/ipu-v3')
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-common.c | 4 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-dc.c | 30 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-di.c | 123 |
3 files changed, 104 insertions, 53 deletions
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index f707d25..67bab5c 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -742,7 +742,7 @@ static struct ipu_devtype ipu_type_imx51 = { .tpm_ofs = 0x1f060000, .csi0_ofs = 0x1f030000, .csi1_ofs = 0x1f038000, - .ic_ofs = 0x1f020000, + .ic_ofs = 0x1e020000, .disp0_ofs = 0x1e040000, .disp1_ofs = 0x1e048000, .dc_tmpl_ofs = 0x1f080000, @@ -758,7 +758,7 @@ static struct ipu_devtype ipu_type_imx53 = { .tpm_ofs = 0x07060000, .csi0_ofs = 0x07030000, .csi1_ofs = 0x07038000, - .ic_ofs = 0x07020000, + .ic_ofs = 0x06020000, .disp0_ofs = 0x06040000, .disp1_ofs = 0x06048000, .dc_tmpl_ofs = 0x07080000, diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index 2326c75..4864f83 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c @@ -114,6 +114,7 @@ struct ipu_dc_priv { struct completion comp; int dc_irq; int dp_irq; + int use_count; }; static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority) @@ -232,7 +233,16 @@ EXPORT_SYMBOL_GPL(ipu_dc_init_sync); void ipu_dc_enable(struct ipu_soc *ipu) { - ipu_module_enable(ipu, IPU_CONF_DC_EN); + struct ipu_dc_priv *priv = ipu->dc_priv; + + mutex_lock(&priv->mutex); + + if (!priv->use_count) + ipu_module_enable(priv->ipu, IPU_CONF_DC_EN); + + priv->use_count++; + + mutex_unlock(&priv->mutex); } EXPORT_SYMBOL_GPL(ipu_dc_enable); @@ -267,7 +277,8 @@ static irqreturn_t dc_irq_handler(int irq, void *dev_id) void ipu_dc_disable_channel(struct ipu_dc *dc) { struct ipu_dc_priv *priv = dc->priv; - int irq, ret; + int irq; + unsigned long ret; u32 val; /* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */ @@ -282,7 +293,7 @@ void ipu_dc_disable_channel(struct ipu_dc *dc) enable_irq(irq); ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50)); disable_irq(irq); - if (ret <= 0) { + if (ret == 0) { dev_warn(priv->dev, "DC stop timeout after 50 ms\n"); val = readl(dc->base + DC_WR_CH_CONF); @@ -294,7 +305,18 @@ EXPORT_SYMBOL_GPL(ipu_dc_disable_channel); void ipu_dc_disable(struct ipu_soc *ipu) { - ipu_module_disable(ipu, IPU_CONF_DC_EN); + struct ipu_dc_priv *priv = ipu->dc_priv; + + mutex_lock(&priv->mutex); + + priv->use_count--; + if (!priv->use_count) + ipu_module_disable(priv->ipu, IPU_CONF_DC_EN); + + if (priv->use_count < 0) + priv->use_count = 0; + + mutex_unlock(&priv->mutex); } EXPORT_SYMBOL_GPL(ipu_dc_disable); diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c index c490ba4..3ddfb3d 100644 --- a/drivers/gpu/ipu-v3/ipu-di.c +++ b/drivers/gpu/ipu-v3/ipu-di.c @@ -207,10 +207,10 @@ static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config, static void ipu_di_sync_config_interlaced(struct ipu_di *di, struct ipu_di_signal_cfg *sig) { - u32 h_total = sig->width + sig->h_sync_width + - sig->h_start_width + sig->h_end_width; - u32 v_total = sig->height + sig->v_sync_width + - sig->v_start_width + sig->v_end_width; + u32 h_total = sig->mode.hactive + sig->mode.hsync_len + + sig->mode.hback_porch + sig->mode.hfront_porch; + u32 v_total = sig->mode.vactive + sig->mode.vsync_len + + sig->mode.vback_porch + sig->mode.vfront_porch; u32 reg; struct di_sync_config cfg[] = { { @@ -229,13 +229,13 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di, }, { .run_count = v_total / 2 - 1, .run_src = DI_SYNC_HSYNC, - .offset_count = sig->v_start_width, + .offset_count = sig->mode.vback_porch, .offset_src = DI_SYNC_HSYNC, .repeat_count = 2, .cnt_clr_src = DI_SYNC_VSYNC, }, { .run_src = DI_SYNC_HSYNC, - .repeat_count = sig->height / 2, + .repeat_count = sig->mode.vactive / 2, .cnt_clr_src = 4, }, { .run_count = v_total - 1, @@ -249,9 +249,9 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di, .cnt_clr_src = DI_SYNC_VSYNC, }, { .run_src = DI_SYNC_CLK, - .offset_count = sig->h_start_width, + .offset_count = sig->mode.hback_porch, .offset_src = DI_SYNC_CLK, - .repeat_count = sig->width, + .repeat_count = sig->mode.hactive, .cnt_clr_src = 5, }, { .run_count = v_total - 1, @@ -277,10 +277,10 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di, static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, struct ipu_di_signal_cfg *sig, int div) { - u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width + - sig->h_end_width; - u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width + - sig->v_end_width; + u32 h_total = sig->mode.hactive + sig->mode.hsync_len + + sig->mode.hback_porch + sig->mode.hfront_porch; + u32 v_total = sig->mode.vactive + sig->mode.vsync_len + + sig->mode.vback_porch + sig->mode.vfront_porch; struct di_sync_config cfg[] = { { /* 1: INT_HSYNC */ @@ -294,27 +294,29 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, .offset_src = DI_SYNC_CLK, .cnt_polarity_gen_en = 1, .cnt_polarity_trigger_src = DI_SYNC_CLK, - .cnt_down = sig->h_sync_width * 2, + .cnt_down = sig->mode.hsync_len * 2, } , { /* PIN3: VSYNC */ .run_count = v_total - 1, .run_src = DI_SYNC_INT_HSYNC, .cnt_polarity_gen_en = 1, .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC, - .cnt_down = sig->v_sync_width * 2, + .cnt_down = sig->mode.vsync_len * 2, } , { /* 4: Line Active */ .run_src = DI_SYNC_HSYNC, - .offset_count = sig->v_sync_width + sig->v_start_width, + .offset_count = sig->mode.vsync_len + + sig->mode.vback_porch, .offset_src = DI_SYNC_HSYNC, - .repeat_count = sig->height, + .repeat_count = sig->mode.vactive, .cnt_clr_src = DI_SYNC_VSYNC, } , { /* 5: Pixel Active, referenced by DC */ .run_src = DI_SYNC_CLK, - .offset_count = sig->h_sync_width + sig->h_start_width, + .offset_count = sig->mode.hsync_len + + sig->mode.hback_porch, .offset_src = DI_SYNC_CLK, - .repeat_count = sig->width, + .repeat_count = sig->mode.hactive, .cnt_clr_src = 5, /* Line Active */ } , { /* unused */ @@ -339,9 +341,10 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, } , { /* 3: Line Active */ .run_src = DI_SYNC_INT_HSYNC, - .offset_count = sig->v_sync_width + sig->v_start_width, + .offset_count = sig->mode.vsync_len + + sig->mode.vback_porch, .offset_src = DI_SYNC_INT_HSYNC, - .repeat_count = sig->height, + .repeat_count = sig->mode.vactive, .cnt_clr_src = 3 /* VSYNC */, } , { /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */ @@ -351,13 +354,14 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, .offset_src = DI_SYNC_CLK, .cnt_polarity_gen_en = 1, .cnt_polarity_trigger_src = DI_SYNC_CLK, - .cnt_down = sig->h_sync_width * 2, + .cnt_down = sig->mode.hsync_len * 2, } , { /* 5: Pixel Active signal to DC */ .run_src = DI_SYNC_CLK, - .offset_count = sig->h_sync_width + sig->h_start_width, + .offset_count = sig->mode.hsync_len + + sig->mode.hback_porch, .offset_src = DI_SYNC_CLK, - .repeat_count = sig->width, + .repeat_count = sig->mode.hactive, .cnt_clr_src = 4, /* Line Active */ } , { /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */ @@ -367,7 +371,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, .offset_src = DI_SYNC_INT_HSYNC, .cnt_polarity_gen_en = 1, .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC, - .cnt_down = sig->v_sync_width * 2, + .cnt_down = sig->mode.vsync_len * 2, } , { /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */ .run_count = h_total - 1, @@ -376,7 +380,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, .offset_src = DI_SYNC_CLK, .cnt_polarity_gen_en = 1, .cnt_polarity_trigger_src = DI_SYNC_CLK, - .cnt_down = sig->h_sync_width * 2, + .cnt_down = sig->mode.hsync_len * 2, } , { /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */ .run_count = v_total - 1, @@ -385,7 +389,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, .offset_src = DI_SYNC_INT_HSYNC, .cnt_polarity_gen_en = 1, .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC, - .cnt_down = sig->v_sync_width * 2, + .cnt_down = sig->mode.vsync_len * 2, } , { /* unused */ }, @@ -433,10 +437,10 @@ static void ipu_di_config_clock(struct ipu_di *di, unsigned long in_rate; unsigned div; - clk_set_rate(clk, sig->pixelclock); + clk_set_rate(clk, sig->mode.pixelclock); in_rate = clk_get_rate(clk); - div = (in_rate + sig->pixelclock / 2) / sig->pixelclock; + div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock); if (div == 0) div = 1; @@ -454,10 +458,12 @@ static void ipu_di_config_clock(struct ipu_di *di, unsigned div, error; clkrate = clk_get_rate(di->clk_ipu); - div = (clkrate + sig->pixelclock / 2) / sig->pixelclock; + div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock); + if (div == 0) + div = 1; rate = clkrate / div; - error = rate / (sig->pixelclock / 1000); + error = rate / (sig->mode.pixelclock / 1000); dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n", rate, div, (signed)(error - 1000) / 10, error % 10); @@ -473,10 +479,10 @@ static void ipu_di_config_clock(struct ipu_di *di, clk = di->clk_di; - clk_set_rate(clk, sig->pixelclock); + clk_set_rate(clk, sig->mode.pixelclock); in_rate = clk_get_rate(clk); - div = (in_rate + sig->pixelclock / 2) / sig->pixelclock; + div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock); if (div == 0) div = 1; @@ -504,35 +510,58 @@ static void ipu_di_config_clock(struct ipu_di *di, ipu_di_write(di, val, DI_GENERAL); dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n", - sig->pixelclock, + sig->mode.pixelclock, clk_get_rate(di->clk_ipu), clk_get_rate(di->clk_di), clk == di->clk_di ? "DI" : "IPU", clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4)); } +/* + * This function is called to adjust a video mode to IPU restrictions. + * It is meant to be called from drm crtc mode_fixup() methods. + */ +int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode) +{ + u32 diff; + + if (mode->vfront_porch >= 2) + return 0; + + diff = 2 - mode->vfront_porch; + + if (mode->vback_porch >= diff) { + mode->vfront_porch = 2; + mode->vback_porch -= diff; + } else if (mode->vsync_len > diff) { + mode->vfront_porch = 2; + mode->vsync_len = mode->vsync_len - diff; + } else { + dev_warn(di->ipu->dev, "failed to adjust videomode\n"); + return -EINVAL; + } + + dev_warn(di->ipu->dev, "videomode adapted for IPU restrictions\n"); + return 0; +} +EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode); + int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) { u32 reg; u32 di_gen, vsync_cnt; u32 div; - u32 h_total, v_total; dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n", - di->id, sig->width, sig->height); + di->id, sig->mode.hactive, sig->mode.vactive); - if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0)) + if ((sig->mode.vsync_len == 0) || (sig->mode.hsync_len == 0)) return -EINVAL; - h_total = sig->width + sig->h_sync_width + sig->h_start_width + - sig->h_end_width; - v_total = sig->height + sig->v_sync_width + sig->v_start_width + - sig->v_end_width; - dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n", clk_get_rate(di->clk_ipu), clk_get_rate(di->clk_di), - sig->pixelclock); + sig->mode.pixelclock); mutex_lock(&di_mutex); @@ -551,7 +580,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT; di_gen |= DI_GEN_DI_VSYNC_EXT; - if (sig->interlaced) { + if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) { ipu_di_sync_config_interlaced(di, sig); /* set y_sel = 1 */ @@ -561,9 +590,9 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) vsync_cnt = 7; - if (sig->Hsync_pol) + if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) di_gen |= DI_GEN_POLARITY_3; - if (sig->Vsync_pol) + if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) di_gen |= DI_GEN_POLARITY_2; } else { ipu_di_sync_config_noninterlaced(di, sig, div); @@ -577,7 +606,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3)) vsync_cnt = 6; - if (sig->Hsync_pol) { + if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) { if (sig->hsync_pin == 2) di_gen |= DI_GEN_POLARITY_2; else if (sig->hsync_pin == 4) @@ -585,7 +614,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) else if (sig->hsync_pin == 7) di_gen |= DI_GEN_POLARITY_7; } - if (sig->Vsync_pol) { + if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) { if (sig->vsync_pin == 3) di_gen |= DI_GEN_POLARITY_3; else if (sig->vsync_pin == 6) |