diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c index 35b76865191..6454684a772 100644 --- a/drivers/media/video/mxc/output/mxc_v4l2_output.c +++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c @@ -831,6 +831,7 @@ static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt, IPU_ROTATE_NONE, vout->v4l2_bufs[vout->ipu_buf[0]].m.offset, vout->v4l2_bufs[vout->ipu_buf[0]].m.offset, + 0, u_offset, v_offset) != 0) { dev_err(dev, "Error initializing VDI current input buffer\n"); return -EINVAL; @@ -842,6 +843,7 @@ static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt, stride, IPU_ROTATE_NONE, vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset+vout->bytesperline, vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset+vout->bytesperline, + 0, u_offset, v_offset) != 0) { dev_err(dev, "Error initializing VDI previous input buffer\n"); return -EINVAL; @@ -852,6 +854,7 @@ static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt, stride, IPU_ROTATE_NONE, vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset+vout->bytesperline, vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset+vout->bytesperline, + 0, u_offset, v_offset) != 0) { dev_err(dev, "Error initializing VDI next input buffer\n"); return -EINVAL; @@ -915,7 +918,7 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout, out_height, out_width, IPU_ROTATE_NONE, vout->rot_pp_bufs[0], - vout->rot_pp_bufs[1], 0, 0) != 0) { + vout->rot_pp_bufs[1], 0, 0, 0) != 0) { dev_err(dev, "Error initializing PRP output buffer\n"); return -EINVAL; } @@ -931,7 +934,7 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout, out_height, out_width, vout->rotate, vout->rot_pp_bufs[0], - vout->rot_pp_bufs[1], 0, 0) != 0) { + vout->rot_pp_bufs[1], 0, 0, 0) != 0) { dev_err(dev, "Error initializing PP ROT input buffer\n"); return -EINVAL; @@ -950,7 +953,7 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout, out_height, out_width, IPU_ROTATE_NONE, vout->display_bufs[0], - vout->display_bufs[1], 0, 0) != 0) { + vout->display_bufs[1], 0, 0, 0) != 0) { dev_err(dev, "Error initializing PP-VDI output buffer\n"); return -EINVAL; @@ -971,7 +974,7 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout, out_height, out_width, vout->rotate, vout->display_bufs[0], - vout->display_bufs[1], 0, 0) != 0) { + vout->display_bufs[1], 0, 0, 0) != 0) { dev_err(dev, "Error initializing PP-VDI output buffer\n"); return -EINVAL; @@ -1106,6 +1109,7 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, IPU_ROTATE_NONE, phy_addr0, phy_addr1, + 0, vout->offset.u_offset, vout->offset.v_offset) != 0) { dev_err(dev, "Error initializing PP input buffer\n"); @@ -1131,7 +1135,7 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, out_height, out_stride, IPU_ROTATE_NONE, vout->rot_pp_bufs[0] + eba_offset, - vout->rot_pp_bufs[1] + eba_offset, 0, 0) != 0) { + vout->rot_pp_bufs[1] + eba_offset, 0, 0, 0) != 0) { dev_err(dev, "Error initializing PP output buffer\n"); return -EINVAL; } @@ -1147,7 +1151,7 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, out_height, out_stride, vout->rotate, vout->rot_pp_bufs[0], - vout->rot_pp_bufs[1], 0, 0) != 0) { + vout->rot_pp_bufs[1], 0, 0, 0) != 0) { dev_err(dev, "Error initializing PP ROT input buffer\n"); return -EINVAL; @@ -1166,7 +1170,7 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, out_height, out_stride, IPU_ROTATE_NONE, vout->display_bufs[0] + eba_offset, - vout->display_bufs[1] + eba_offset, 0, 0) != 0) { + vout->display_bufs[1] + eba_offset, 0, 0, 0) != 0) { dev_err(dev, "Error initializing PP output buffer\n"); return -EINVAL; } @@ -1186,7 +1190,7 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, out_height, out_stride, vout->rotate, vout->display_bufs[0] + eba_offset, - vout->display_bufs[1] + eba_offset, 0, 0) != 0) { + vout->display_bufs[1] + eba_offset, 0, 0, 0) != 0) { dev_err(dev, "Error initializing PP output buffer\n"); return -EINVAL; } @@ -1421,6 +1425,7 @@ static int mxc_v4l2out_streamon(vout_data *vout) /* Init display channel through fb API */ fbvar.yoffset = 0; + fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG; fbvar.activate |= FB_ACTIVATE_FORCE; acquire_console_sem(); fbi->flags |= FBINFO_MISC_USEREVENT; @@ -1708,6 +1713,7 @@ static int mxc_v4l2out_streamoff(vout_data * vout) } if (vout->ic_bypass) { + fbi->var.accel_flags = FB_ACCEL_TRIPLE_FLAG; fbi->var.activate |= FB_ACTIVATE_FORCE; acquire_console_sem(); fbi->flags |= FBINFO_MISC_USEREVENT; @@ -1738,6 +1744,7 @@ static int mxc_v4l2out_streamoff(vout_data * vout) } ipu_disable_channel(MEM_PP_MEM, true); + fbi->var.accel_flags = FB_ACCEL_TRIPLE_FLAG; fbi->var.activate |= FB_ACTIVATE_FORCE; acquire_console_sem(); fbi->flags |= FBINFO_MISC_USEREVENT; @@ -1777,6 +1784,7 @@ static int mxc_v4l2out_streamoff(vout_data * vout) ipu_disable_channel(MEM_VDI_PRP_VF_MEM_N, true); } + fbi->var.accel_flags = FB_ACCEL_TRIPLE_FLAG; fbi->var.activate |= FB_ACTIVATE_FORCE; acquire_console_sem(); fbi->flags |= FBINFO_MISC_USEREVENT; diff --git a/drivers/mxc/ipu/ipu_common.c b/drivers/mxc/ipu/ipu_common.c index d6a030f8048..004ff2730b3 100644 --- a/drivers/mxc/ipu/ipu_common.c +++ b/drivers/mxc/ipu/ipu_common.c @@ -491,6 +491,9 @@ void ipu_uninit_channel(ipu_channel_t channel) * Setting this to a value other than NULL enables * double buffering mode. * + * @param phyaddr_2 Input parameter buffer 2 physical address. + * Dummy for IPUv1 + * * @param u private u offset for additional cropping, * zero if not used. * @@ -505,6 +508,7 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, uint32_t stride, ipu_rotate_mode_t rot_mode, dma_addr_t phyaddr_0, dma_addr_t phyaddr_1, + dma_addr_t phyaddr_2, uint32_t u, uint32_t v) { uint32_t params[10]; diff --git a/drivers/mxc/ipu/ipu_device.c b/drivers/mxc/ipu/ipu_device.c index 5fd1c51ec9b..79d36ff880e 100644 --- a/drivers/mxc/ipu/ipu_device.c +++ b/drivers/mxc/ipu/ipu_device.c @@ -177,6 +177,7 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, parm.rot_mode, parm.phyaddr_0, parm.phyaddr_1, + 0, parm.u_offset, parm.v_offset); diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index 204f49d9dc2..9a7b56bae80 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -80,9 +80,12 @@ static ipu_channel_t using_ic_dirct_ch; static uint32_t ipu_conf_reg; static uint32_t ic_conf_reg; static uint32_t ipu_cha_db_mode_reg[4]; +static uint32_t ipu_cha_trb_mode_reg[2]; static uint32_t ipu_cha_cur_buf_reg[4]; +static uint32_t ipu_cha_triple_cur_buf_reg[4]; +static uint32_t idma_sub_addr_reg[5]; static uint32_t idma_enable_reg[2]; -static uint32_t buf_ready_reg[8]; +static uint32_t buf_ready_reg[10]; u32 *ipu_cm_reg; u32 *ipu_idmac_reg; @@ -138,9 +141,20 @@ static inline int _ipu_is_smfc_chan(uint32_t dma_chan) return ((dma_chan >= 0) && (dma_chan <= 3)); } +static inline int _ipu_is_trb_chan(uint32_t dma_chan) +{ + return (((dma_chan == 8) || (dma_chan == 9) || + (dma_chan == 10) || (dma_chan == 13) || + (dma_chan == 21) || (dma_chan == 23) || + (dma_chan == 27) || (dma_chan == 28)) && + (g_ipu_hw_rev >= 2)); +} + #define idma_is_valid(ch) (ch != NO_DMA) #define idma_mask(ch) (idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0) #define idma_is_set(reg, dma) (__raw_readl(reg(dma)) & idma_mask(dma)) +#define tri_cur_buf_mask(ch) (idma_mask(ch*2) * 3) +#define tri_cur_buf_shift(ch) (ffs(idma_mask(ch*2)) - 1) static void _ipu_pixel_clk_recalc(struct clk *clk) { @@ -312,7 +326,7 @@ static int ipu_probe(struct platform_device *pdev) ipu_smfc_reg = ioremap(ipu_base + IPU_SMFC_REG_BASE, PAGE_SIZE); ipu_csi_reg[0] = ioremap(ipu_base + IPU_CSI0_REG_BASE, PAGE_SIZE); ipu_csi_reg[1] = ioremap(ipu_base + IPU_CSI1_REG_BASE, PAGE_SIZE); - ipu_cpmem_base = ioremap(ipu_base + IPU_CPMEM_REG_BASE, PAGE_SIZE); + ipu_cpmem_base = ioremap(ipu_base + IPU_CPMEM_REG_BASE, SZ_128K); ipu_tpmem_base = ioremap(ipu_base + IPU_TPM_REG_BASE, SZ_64K); ipu_dc_tmpl_reg = ioremap(ipu_base + IPU_DC_TMPL_REG_BASE, SZ_128K); ipu_disp_base[1] = ioremap(ipu_base + IPU_DISP1_BASE, SZ_4K); @@ -433,6 +447,12 @@ void ipu_dump_registers(void) __raw_readl(IPU_CHA_DB_MODE_SEL(0))); printk(KERN_DEBUG "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n", __raw_readl(IPU_CHA_DB_MODE_SEL(32))); + if (g_ipu_hw_rev >= 2) { + printk(KERN_DEBUG "IPU_CHA_TRB_MODE_SEL0 = \t0x%08X\n", + __raw_readl(IPU_CHA_TRB_MODE_SEL(0))); + printk(KERN_DEBUG "IPU_CHA_TRB_MODE_SEL1 = \t0x%08X\n", + __raw_readl(IPU_CHA_TRB_MODE_SEL(32))); + } printk(KERN_DEBUG "DMFC_WR_CHAN = \t0x%08X\n", __raw_readl(DMFC_WR_CHAN)); printk(KERN_DEBUG "DMFC_WR_CHAN_DEF = \t0x%08X\n", @@ -489,6 +509,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) { dev_err(g_ipu_dev, "Warning: channel already initialized %d\n", IPU_CHAN_ID(channel)); + ret = -EINVAL; + goto err; } ipu_conf = __raw_readl(IPU_CONF); @@ -728,7 +750,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) break; default: dev_err(g_ipu_dev, "Missing channel initialization\n"); - break; + ret = -EINVAL; + goto err; } /* Enable IPU sub module */ @@ -754,9 +777,12 @@ void ipu_uninit_channel(ipu_channel_t channel) uint32_t in_dma, out_dma = 0; uint32_t ipu_conf; + spin_lock_irqsave(&ipu_lock, lock_flags); + if ((g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) { dev_info(g_ipu_dev, "Channel already uninitialized %d\n", IPU_CHAN_ID(channel)); + spin_unlock_irqrestore(&ipu_lock, lock_flags); return; } @@ -770,11 +796,10 @@ void ipu_uninit_channel(ipu_channel_t channel) dev_err(g_ipu_dev, "Channel %d is not disabled, disable first\n", IPU_CHAN_ID(channel)); + spin_unlock_irqrestore(&ipu_lock, lock_flags); return; } - spin_lock_irqsave(&ipu_lock, lock_flags); - ipu_conf = __raw_readl(IPU_CONF); /* Reset the double buffer */ @@ -783,6 +808,12 @@ void ipu_uninit_channel(ipu_channel_t channel) reg = __raw_readl(IPU_CHA_DB_MODE_SEL(out_dma)); __raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma)); + /* Reset the triple buffer */ + reg = __raw_readl(IPU_CHA_TRB_MODE_SEL(in_dma)); + __raw_writel(reg & ~idma_mask(in_dma), IPU_CHA_TRB_MODE_SEL(in_dma)); + reg = __raw_readl(IPU_CHA_TRB_MODE_SEL(out_dma)); + __raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_TRB_MODE_SEL(out_dma)); + if (_ipu_is_ic_chan(in_dma) || _ipu_is_dp_graphic_chan(in_dma)) { g_sec_chan_en[IPU_CHAN_ID(channel)] = false; g_thrd_chan_en[IPU_CHAN_ID(channel)] = false; @@ -946,7 +977,7 @@ void ipu_uninit_channel(ipu_channel_t channel) EXPORT_SYMBOL(ipu_uninit_channel); /*! - * This function is called to initialize a buffer for logical IPU channel. + * This function is called to initialize buffer(s) for logical IPU channel. * * @param channel Input parameter for the logical channel ID. * @@ -974,6 +1005,11 @@ EXPORT_SYMBOL(ipu_uninit_channel); * Setting this to a value other than NULL enables * double buffering mode. * + * @param phyaddr_2 Input parameter buffer 2 physical address. + * Setting this to a value other than NULL enables + * triple buffering mode, phyaddr_1 should not be + * NULL then. + * * @param u private u offset for additional cropping, * zero if not used. * @@ -988,6 +1024,7 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, uint32_t stride, ipu_rotate_mode_t rot_mode, dma_addr_t phyaddr_0, dma_addr_t phyaddr_1, + dma_addr_t phyaddr_2, uint32_t u, uint32_t v) { unsigned long lock_flags; @@ -1014,9 +1051,21 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, return -EINVAL; } + /* IPUv3EX and IPUv3M support triple buffer */ + if ((!_ipu_is_trb_chan(dma_chan)) && phyaddr_2) { + dev_err(g_ipu_dev, "Chan%d doesn't support triple buffer " + "mode\n", dma_chan); + return -EINVAL; + } + if (!phyaddr_1 && phyaddr_2) { + dev_err(g_ipu_dev, "Chan%d's buf1 physical addr is NULL for " + "triple buffer mode\n", dma_chan); + return -EINVAL; + } + /* Build parameter memory data for DMA channel */ _ipu_ch_param_init(dma_chan, pixel_fmt, width, height, stride, u, v, 0, - phyaddr_0, phyaddr_1); + phyaddr_0, phyaddr_1, phyaddr_2); /* Set correlative channel parameter of local alpha channel */ if ((_ipu_is_ic_graphic_chan(dma_chan) || @@ -1123,17 +1172,41 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, _ipu_ch_param_dump(dma_chan); spin_lock_irqsave(&ipu_lock, lock_flags); - - reg = __raw_readl(IPU_CHA_DB_MODE_SEL(dma_chan)); - if (phyaddr_1) - reg |= idma_mask(dma_chan); - else + if (phyaddr_2 && g_ipu_hw_rev >= 2) { + reg = __raw_readl(IPU_CHA_DB_MODE_SEL(dma_chan)); reg &= ~idma_mask(dma_chan); - __raw_writel(reg, IPU_CHA_DB_MODE_SEL(dma_chan)); + __raw_writel(reg, IPU_CHA_DB_MODE_SEL(dma_chan)); - /* Reset to buffer 0 */ - __raw_writel(idma_mask(dma_chan), IPU_CHA_CUR_BUF(dma_chan)); + reg = __raw_readl(IPU_CHA_TRB_MODE_SEL(dma_chan)); + reg |= idma_mask(dma_chan); + __raw_writel(reg, IPU_CHA_TRB_MODE_SEL(dma_chan)); + /* Set IDMAC third buffer's cpmem number */ + /* See __ipu_ch_get_third_buf_cpmem_num() for mapping */ + __raw_writel(0x00444047L, IDMAC_SUB_ADDR_4); + __raw_writel(0x46004241L, IDMAC_SUB_ADDR_3); + __raw_writel(0x00000045L, IDMAC_SUB_ADDR_1); + + /* Reset to buffer 0 */ + __raw_writel(tri_cur_buf_mask(dma_chan), + IPU_CHA_TRIPLE_CUR_BUF(dma_chan)); + } else { + reg = __raw_readl(IPU_CHA_TRB_MODE_SEL(dma_chan)); + reg &= ~idma_mask(dma_chan); + __raw_writel(reg, IPU_CHA_TRB_MODE_SEL(dma_chan)); + + reg = __raw_readl(IPU_CHA_DB_MODE_SEL(dma_chan)); + if (phyaddr_1) + reg |= idma_mask(dma_chan); + else + reg &= ~idma_mask(dma_chan); + __raw_writel(reg, IPU_CHA_DB_MODE_SEL(dma_chan)); + + /* Reset to buffer 0 */ + __raw_writel(idma_mask(dma_chan), + IPU_CHA_CUR_BUF(dma_chan)); + + } spin_unlock_irqrestore(&ipu_lock, lock_flags); return 0; @@ -1170,8 +1243,10 @@ int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, if (bufNum == 0) reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan)); - else + else if (bufNum == 1) reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan)); + else + reg = __raw_readl(IPU_CHA_BUF2_RDY(dma_chan)); if ((reg & idma_mask(dma_chan)) == 0) _ipu_ch_param_set_buffer(dma_chan, bufNum, phyaddr); @@ -1236,7 +1311,10 @@ int32_t ipu_update_channel_offset(ipu_channel_t channel, ipu_buffer_t type, spin_lock_irqsave(&ipu_lock, lock_flags); if ((__raw_readl(IPU_CHA_BUF0_RDY(dma_chan)) & idma_mask(dma_chan)) || - (__raw_readl(IPU_CHA_BUF0_RDY(dma_chan)) & idma_mask(dma_chan))) + (__raw_readl(IPU_CHA_BUF1_RDY(dma_chan)) & idma_mask(dma_chan)) || + ((__raw_readl(IPU_CHA_BUF2_RDY(dma_chan)) & idma_mask(dma_chan)) && + (__raw_readl(IPU_CHA_TRB_MODE_SEL(dma_chan)) & idma_mask(dma_chan)) && + _ipu_is_trb_chan(dma_chan))) ret = -EACCES; else _ipu_ch_offset_update(dma_chan, pixel_fmt, width, height, stride, @@ -1264,22 +1342,23 @@ int32_t ipu_select_buffer(ipu_channel_t channel, ipu_buffer_t type, uint32_t bufNum) { uint32_t dma_chan = channel_2_dma(channel, type); - uint32_t reg; + unsigned long lock_flags; if (dma_chan == IDMA_CHAN_INVALID) return -EINVAL; - if (bufNum == 0) { - /*Mark buffer 0 as ready. */ - reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan)); - __raw_writel(idma_mask(dma_chan) | reg, + /* Mark buffer to be ready. */ + spin_lock_irqsave(&ipu_lock, lock_flags); + if (bufNum == 0) + __raw_writel(idma_mask(dma_chan), IPU_CHA_BUF0_RDY(dma_chan)); - } else { - /*Mark buffer 1 as ready. */ - reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan)); - __raw_writel(idma_mask(dma_chan) | reg, + else if (bufNum == 1) + __raw_writel(idma_mask(dma_chan), IPU_CHA_BUF1_RDY(dma_chan)); - } + else + __raw_writel(idma_mask(dma_chan), + IPU_CHA_BUF2_RDY(dma_chan)); + spin_unlock_irqrestore(&ipu_lock, lock_flags); return 0; } EXPORT_SYMBOL(ipu_select_buffer); @@ -1300,17 +1379,15 @@ int32_t ipu_select_multi_vdi_buffer(uint32_t bufNum) idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_P, IPU_INPUT_BUFFER))| idma_mask(dma_chan)| idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_N, IPU_INPUT_BUFFER)); - uint32_t reg; + unsigned long lock_flags; - if (bufNum == 0) { - /*Mark buffer 0 as ready. */ - reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan)); - __raw_writel(mask_bit | reg, IPU_CHA_BUF0_RDY(dma_chan)); - } else { - /*Mark buffer 1 as ready. */ - reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan)); - __raw_writel(mask_bit | reg, IPU_CHA_BUF1_RDY(dma_chan)); - } + /* Mark buffers to be ready. */ + spin_lock_irqsave(&ipu_lock, lock_flags); + if (bufNum == 0) + __raw_writel(mask_bit, IPU_CHA_BUF0_RDY(dma_chan)); + else + __raw_writel(mask_bit, IPU_CHA_BUF1_RDY(dma_chan)); + spin_unlock_irqrestore(&ipu_lock, lock_flags); return 0; } EXPORT_SYMBOL(ipu_select_multi_vdi_buffer); @@ -1819,8 +1896,10 @@ int32_t ipu_check_buffer_ready(ipu_channel_t channel, ipu_buffer_t type, if (bufNum == 0) reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan)); - else + else if (bufNum == 1) reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan)); + else + reg = __raw_readl(IPU_CHA_BUF2_RDY(dma_chan)); if (reg & idma_mask(dma_chan)) return 1; @@ -1850,24 +1929,56 @@ void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type, return; spin_lock_irqsave(&ipu_lock, lock_flags); - - __raw_writel(0xF0000000, IPU_GPR); /* write one to clear */ + __raw_writel(0xF0300000, IPU_GPR); /* write one to clear */ if (bufNum == 0) { if (idma_is_set(IPU_CHA_BUF0_RDY, dma_ch)) { __raw_writel(idma_mask(dma_ch), IPU_CHA_BUF0_RDY(dma_ch)); } - } else { + } else if (bufNum == 1) { if (idma_is_set(IPU_CHA_BUF1_RDY, dma_ch)) { __raw_writel(idma_mask(dma_ch), IPU_CHA_BUF1_RDY(dma_ch)); } + } else { + if (idma_is_set(IPU_CHA_BUF2_RDY, dma_ch)) { + __raw_writel(idma_mask(dma_ch), + IPU_CHA_BUF2_RDY(dma_ch)); + } } __raw_writel(0x0, IPU_GPR); /* write one to set */ spin_unlock_irqrestore(&ipu_lock, lock_flags); } EXPORT_SYMBOL(ipu_clear_buffer_ready); +void _ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type, + uint32_t bufNum) +{ + uint32_t dma_ch = channel_2_dma(channel, type); + + if (!idma_is_valid(dma_ch)) + return; + + __raw_writel(0xF0300000, IPU_GPR); /* write one to clear */ + if (bufNum == 0) { + if (idma_is_set(IPU_CHA_BUF0_RDY, dma_ch)) { + __raw_writel(idma_mask(dma_ch), + IPU_CHA_BUF0_RDY(dma_ch)); + } + } else if (bufNum == 1) { + if (idma_is_set(IPU_CHA_BUF1_RDY, dma_ch)) { + __raw_writel(idma_mask(dma_ch), + IPU_CHA_BUF1_RDY(dma_ch)); + } + } else { + if (idma_is_set(IPU_CHA_BUF2_RDY, dma_ch)) { + __raw_writel(idma_mask(dma_ch), + IPU_CHA_BUF2_RDY(dma_ch)); + } + } + __raw_writel(0x0, IPU_GPR); /* write one to set */ +} + static irqreturn_t disable_chan_irq_handler(int irq, void *dev_id) { struct completion *comp = dev_id; @@ -2010,11 +2121,15 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) reg = __raw_readl(IDMAC_CHA_EN(in_dma)); __raw_writel(reg & ~idma_mask(in_dma), IDMAC_CHA_EN(in_dma)); __raw_writel(idma_mask(in_dma), IPU_CHA_CUR_BUF(in_dma)); + __raw_writel(tri_cur_buf_mask(in_dma), + IPU_CHA_TRIPLE_CUR_BUF(in_dma)); } if (idma_is_valid(out_dma)) { reg = __raw_readl(IDMAC_CHA_EN(out_dma)); __raw_writel(reg & ~idma_mask(out_dma), IDMAC_CHA_EN(out_dma)); __raw_writel(idma_mask(out_dma), IPU_CHA_CUR_BUF(out_dma)); + __raw_writel(tri_cur_buf_mask(out_dma), + IPU_CHA_TRIPLE_CUR_BUF(out_dma)); } if (g_sec_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(sec_dma)) { reg = __raw_readl(IDMAC_CHA_EN(sec_dma)); @@ -2034,28 +2149,29 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) __raw_writel(idma_mask(thrd_dma), IPU_CHA_CUR_BUF(thrd_dma)); } + /* Set channel buffers NOT to be ready */ + if (idma_is_valid(in_dma)) { + _ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0); + _ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 1); + _ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 2); + } + if (idma_is_valid(out_dma)) { + _ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 0); + _ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 1); + } + if (g_sec_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(sec_dma)) { + _ipu_clear_buffer_ready(channel, IPU_GRAPH_IN_BUFFER, 0); + _ipu_clear_buffer_ready(channel, IPU_GRAPH_IN_BUFFER, 1); + } + if (g_thrd_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(thrd_dma)) { + _ipu_clear_buffer_ready(channel, IPU_ALPHA_IN_BUFFER, 0); + _ipu_clear_buffer_ready(channel, IPU_ALPHA_IN_BUFFER, 1); + } + g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel)); spin_unlock_irqrestore(&ipu_lock, lock_flags); - /* Set channel buffers NOT to be ready */ - if (idma_is_valid(in_dma)) { - ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0); - ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 1); - } - if (idma_is_valid(out_dma)) { - ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 0); - ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 1); - } - if (g_sec_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(sec_dma)) { - ipu_clear_buffer_ready(channel, IPU_GRAPH_IN_BUFFER, 0); - ipu_clear_buffer_ready(channel, IPU_GRAPH_IN_BUFFER, 1); - } - if (g_thrd_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(thrd_dma)) { - ipu_clear_buffer_ready(channel, IPU_ALPHA_IN_BUFFER, 0); - ipu_clear_buffer_ready(channel, IPU_ALPHA_IN_BUFFER, 1); - } - return 0; } EXPORT_SYMBOL(ipu_disable_channel); @@ -2350,11 +2466,18 @@ uint32_t ipu_get_cur_buffer_idx(ipu_channel_t channel, ipu_buffer_t type) if (!idma_is_valid(dma_chan)) return -EINVAL; - reg = __raw_readl(IPU_CHA_CUR_BUF(dma_chan/32)); - if (reg & idma_mask(dma_chan)) - return 1; - else - return 0; + reg = __raw_readl(IPU_CHA_TRB_MODE_SEL(dma_chan)); + if ((reg & idma_mask(dma_chan)) && _ipu_is_trb_chan(dma_chan)) { + reg = __raw_readl(IPU_CHA_TRIPLE_CUR_BUF(dma_chan)); + return (reg & tri_cur_buf_mask(dma_chan)) >> + tri_cur_buf_shift(dma_chan); + } else { + reg = __raw_readl(IPU_CHA_CUR_BUF(dma_chan)); + if (reg & idma_mask(dma_chan)) + return 1; + else + return 0; + } } EXPORT_SYMBOL(ipu_get_cur_buffer_idx); @@ -2424,6 +2547,12 @@ int32_t ipu_swap_channel(ipu_channel_t from_ch, ipu_channel_t to_ch) reg = __raw_readl(IDMAC_CHA_EN(from_dma)); __raw_writel(reg & ~idma_mask(from_dma), IDMAC_CHA_EN(from_dma)); __raw_writel(idma_mask(from_dma), IPU_CHA_CUR_BUF(from_dma)); + __raw_writel(tri_cur_buf_mask(from_dma), + IPU_CHA_TRIPLE_CUR_BUF(from_dma)); + + _ipu_clear_buffer_ready(from_ch, IPU_VIDEO_IN_BUFFER, 0); + _ipu_clear_buffer_ready(from_ch, IPU_VIDEO_IN_BUFFER, 1); + _ipu_clear_buffer_ready(from_ch, IPU_VIDEO_IN_BUFFER, 2); g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(from_ch)); @@ -2517,6 +2646,8 @@ EXPORT_SYMBOL(ipu_set_csc_coefficients); static int ipu_suspend(struct platform_device *pdev, pm_message_t state) { if (g_ipu_clk_enabled) { + uint32_t chan_should_disable, timeout = 1000, time = 0; + /* save and disable enabled channels*/ idma_enable_reg[0] = __raw_readl(IDMAC_CHA_EN(0)); idma_enable_reg[1] = __raw_readl(IDMAC_CHA_EN(32)); @@ -2524,8 +2655,6 @@ static int ipu_suspend(struct platform_device *pdev, pm_message_t state) || (__raw_readl(IDMAC_CHA_BUSY(32)) & idma_enable_reg[1])) { /* disable channel not busy already */ - uint32_t chan_should_disable, timeout = 1000, time = 0; - chan_should_disable = __raw_readl(IDMAC_CHA_BUSY(0)) ^ idma_enable_reg[0]; @@ -2552,12 +2681,33 @@ static int ipu_suspend(struct platform_device *pdev, pm_message_t state) ipu_cha_db_mode_reg[3] = __raw_readl(IPU_ALT_CHA_DB_MODE_SEL(32)); + /* save triple buffer select regs */ + ipu_cha_trb_mode_reg[0] = __raw_readl(IPU_CHA_TRB_MODE_SEL(0)); + ipu_cha_trb_mode_reg[1] = __raw_readl(IPU_CHA_TRB_MODE_SEL(32)); + /* save current buffer regs */ ipu_cha_cur_buf_reg[0] = __raw_readl(IPU_CHA_CUR_BUF(0)); ipu_cha_cur_buf_reg[1] = __raw_readl(IPU_CHA_CUR_BUF(32)); ipu_cha_cur_buf_reg[2] = __raw_readl(IPU_ALT_CUR_BUF0); ipu_cha_cur_buf_reg[3] = __raw_readl(IPU_ALT_CUR_BUF1); + /* save current triple buffer regs */ + ipu_cha_triple_cur_buf_reg[0] = + __raw_readl(IPU_CHA_TRIPLE_CUR_BUF(0)); + ipu_cha_triple_cur_buf_reg[1] = + __raw_readl(IPU_CHA_TRIPLE_CUR_BUF(32)); + ipu_cha_triple_cur_buf_reg[2] = + __raw_readl(IPU_CHA_TRIPLE_CUR_BUF(64)); + ipu_cha_triple_cur_buf_reg[3] = + __raw_readl(IPU_CHA_TRIPLE_CUR_BUF(96)); + + /* save idamc sub addr regs */ + idma_sub_addr_reg[0] = __raw_readl(IDMAC_SUB_ADDR_0); + idma_sub_addr_reg[1] = __raw_readl(IDMAC_SUB_ADDR_1); + idma_sub_addr_reg[2] = __raw_readl(IDMAC_SUB_ADDR_2); + idma_sub_addr_reg[3] = __raw_readl(IDMAC_SUB_ADDR_3); + idma_sub_addr_reg[4] = __raw_readl(IDMAC_SUB_ADDR_4); + /* save sub-modules status and disable all */ ic_conf_reg = __raw_readl(IC_CONF); __raw_writel(0, IC_CONF); @@ -2573,6 +2723,8 @@ static int ipu_suspend(struct platform_device *pdev, pm_message_t state) buf_ready_reg[5] = __raw_readl(IPU_ALT_CHA_BUF0_RDY(32)); buf_ready_reg[6] = __raw_readl(IPU_ALT_CHA_BUF1_RDY(0)); buf_ready_reg[7] = __raw_readl(IPU_ALT_CHA_BUF1_RDY(32)); + buf_ready_reg[8] = __raw_readl(IPU_CHA_BUF2_RDY(0)); + buf_ready_reg[9] = __raw_readl(IPU_CHA_BUF2_RDY(32)); } mxc_pg_enable(pdev); @@ -2595,6 +2747,8 @@ static int ipu_resume(struct platform_device *pdev) __raw_writel(buf_ready_reg[5], IPU_ALT_CHA_BUF0_RDY(32)); __raw_writel(buf_ready_reg[6], IPU_ALT_CHA_BUF1_RDY(0)); __raw_writel(buf_ready_reg[7], IPU_ALT_CHA_BUF1_RDY(32)); + __raw_writel(buf_ready_reg[8], IPU_CHA_BUF2_RDY(0)); + __raw_writel(buf_ready_reg[9], IPU_CHA_BUF2_RDY(32)); /* re-enable sub-modules*/ __raw_writel(ipu_conf_reg, IPU_CONF); @@ -2608,12 +2762,33 @@ static int ipu_resume(struct platform_device *pdev) __raw_writel(ipu_cha_db_mode_reg[3], IPU_ALT_CHA_DB_MODE_SEL(32)); + /* restore triple buffer select regs */ + __raw_writel(ipu_cha_trb_mode_reg[0], IPU_CHA_TRB_MODE_SEL(0)); + __raw_writel(ipu_cha_trb_mode_reg[1], IPU_CHA_TRB_MODE_SEL(32)); + /* restore current buffer select regs */ __raw_writel(~(ipu_cha_cur_buf_reg[0]), IPU_CHA_CUR_BUF(0)); __raw_writel(~(ipu_cha_cur_buf_reg[1]), IPU_CHA_CUR_BUF(32)); __raw_writel(~(ipu_cha_cur_buf_reg[2]), IPU_ALT_CUR_BUF0); __raw_writel(~(ipu_cha_cur_buf_reg[3]), IPU_ALT_CUR_BUF1); + /* restore triple current buffer select regs */ + __raw_writel(~(ipu_cha_triple_cur_buf_reg[0]), + IPU_CHA_TRIPLE_CUR_BUF(0)); + __raw_writel(~(ipu_cha_triple_cur_buf_reg[1]), + IPU_CHA_TRIPLE_CUR_BUF(32)); + __raw_writel(~(ipu_cha_triple_cur_buf_reg[2]), + IPU_CHA_TRIPLE_CUR_BUF(64)); + __raw_writel(~(ipu_cha_triple_cur_buf_reg[3]), + IPU_CHA_TRIPLE_CUR_BUF(96)); + + /* restore idamc sub addr regs */ + __raw_writel(idma_sub_addr_reg[0], IDMAC_SUB_ADDR_0); + __raw_writel(idma_sub_addr_reg[1], IDMAC_SUB_ADDR_1); + __raw_writel(idma_sub_addr_reg[2], IDMAC_SUB_ADDR_2); + __raw_writel(idma_sub_addr_reg[3], IDMAC_SUB_ADDR_3); + __raw_writel(idma_sub_addr_reg[4], IDMAC_SUB_ADDR_4); + /* restart idma channel*/ __raw_writel(idma_enable_reg[0], IDMAC_CHA_EN(0)); __raw_writel(idma_enable_reg[1], IDMAC_CHA_EN(32)); @@ -2623,7 +2798,7 @@ static int ipu_resume(struct platform_device *pdev) _ipu_init_dc_mappings(); /* Set sync refresh channels as high priority */ - __raw_writel(0x18800000L, IDMAC_CHA_PRI(0)); + __raw_writel(0x18800001L, IDMAC_CHA_PRI(0)); clk_disable(g_ipu_clk); } diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c index f8cab9ba517..564213c8d32 100644 --- a/drivers/mxc/ipu3/ipu_device.c +++ b/drivers/mxc/ipu3/ipu_device.c @@ -134,6 +134,7 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, parm.rot_mode, parm.phyaddr_0, parm.phyaddr_1, + parm.phyaddr_2, parm.u_offset, parm.v_offset); diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h index 00ce4ea6c60..66a28e876b2 100644 --- a/drivers/mxc/ipu3/ipu_param_mem.h +++ b/drivers/mxc/ipu3/ipu_param_mem.h @@ -71,6 +71,31 @@ struct ipu_ch_param { temp1; \ }) +static inline int __ipu_ch_get_third_buf_cpmem_num(int ch) +{ + switch (ch) { + case 8: + return 64; + case 9: + return 65; + case 10: + return 66; + case 13: + return 67; + case 21: + return 68; + case 23: + return 69; + case 27: + return 70; + case 28: + return 71; + default: + return -EINVAL; + } + return 0; +} + static inline void _ipu_ch_params_set_packing(struct ipu_ch_param *p, int red_width, int red_offset, int green_width, int green_offset, @@ -137,10 +162,11 @@ static inline void _ipu_ch_param_init(int ch, uint32_t height, uint32_t stride, uint32_t u, uint32_t v, uint32_t uv_stride, dma_addr_t addr0, - dma_addr_t addr1) + dma_addr_t addr1, dma_addr_t addr2) { uint32_t u_offset = 0; uint32_t v_offset = 0; + int32_t sub_ch = 0; struct ipu_ch_param params; memset(¶ms, 0, sizeof(params)); @@ -339,13 +365,33 @@ static inline void _ipu_ch_param_init(int ch, pr_debug("initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ch)); memcpy(ipu_ch_param_addr(ch), ¶ms, sizeof(params)); + if (addr2) { + ipu_ch_param_set_field(¶ms, 1, 0, 29, addr2 >> 3); + ipu_ch_param_set_field(¶ms, 1, 29, 29, 0); + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + + pr_debug("initializing idma ch %d @ %p sub cpmem\n", ch, + ipu_ch_param_addr(sub_ch)); + memcpy(ipu_ch_param_addr(sub_ch), ¶ms, sizeof(params)); + } }; static inline void _ipu_ch_param_set_burst_size(uint32_t ch, uint16_t burst_pixels) { + int32_t sub_ch = 0; + ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 78, 7, burst_pixels - 1); + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 1, 78, 7, + burst_pixels - 1); }; static inline int _ipu_ch_param_get_burst_size(uint32_t ch) @@ -361,6 +407,13 @@ static inline int _ipu_ch_param_get_bpp(uint32_t ch) static inline void _ipu_ch_param_set_buffer(uint32_t ch, int bufNum, dma_addr_t phyaddr) { + if (bufNum == 2) { + ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (ch <= 0) + return; + bufNum = 0; + } + ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 29 * bufNum, 29, phyaddr / 8); }; @@ -369,32 +422,66 @@ static inline void _ipu_ch_param_set_rotation(uint32_t ch, ipu_rotate_mode_t rot) { u32 temp_rot = bitrev8(rot) >> 5; + int32_t sub_ch = 0; + ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 119, 3, temp_rot); + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 0, 119, 3, temp_rot); }; static inline void _ipu_ch_param_set_block_mode(uint32_t ch) { + int32_t sub_ch = 0; + ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 117, 2, 1); + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 0, 117, 2, 1); }; static inline void _ipu_ch_param_set_alpha_use_separate_channel(uint32_t ch, bool option) { + int32_t sub_ch = 0; + if (option) { ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 89, 1, 1); } else { ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 89, 1, 0); } + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + + if (option) { + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 1, 89, 1, 1); + } else { + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 1, 89, 1, 0); + } }; static inline void _ipu_ch_param_set_alpha_condition_read(uint32_t ch) { + int32_t sub_ch = 0; + ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 149, 1, 1); + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 1, 149, 1, 1); }; static inline void _ipu_ch_param_set_alpha_buffer_memory(uint32_t ch) { int alp_mem_idx; + int32_t sub_ch = 0; switch (ch) { case 14: /* PRP graphic */ @@ -416,12 +503,23 @@ static inline void _ipu_ch_param_set_alpha_buffer_memory(uint32_t ch) } ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 90, 3, alp_mem_idx); + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 1, 90, 3, alp_mem_idx); }; static inline void _ipu_ch_param_set_interlaced_scan(uint32_t ch) { u32 stride; + int32_t sub_ch = 0; + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 113, 1, 1); + if (sub_ch > 0) + ipu_ch_param_set_field(ipu_ch_param_addr(sub_ch), 0, 113, 1, 1); stride = ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 102, 14) + 1; /* ILO is 20-bit and 8-byte aligned */ if (stride/8 > 0xfffff) @@ -431,13 +529,26 @@ static inline void _ipu_ch_param_set_interlaced_scan(uint32_t ch) dev_warn(g_ipu_dev, "IDMAC%d's ILO is not 8-byte aligned\n", ch); ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 58, 20, stride / 8); + if (sub_ch > 0) + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 1, 58, 20, + stride / 8); stride *= 2; ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 102, 14, stride - 1); + if (sub_ch > 0) + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 1, 102, 14, + stride - 1); }; static inline void _ipu_ch_param_set_high_priority(uint32_t ch) { + int32_t sub_ch = 0; + ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 93, 2, 1); + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 1, 93, 2, 1); }; /* IDMAC U/V offset changing support */ @@ -459,6 +570,7 @@ static inline void _ipu_ch_offset_update(int ch, uint32_t v_offset = 0; uint32_t u_fix = 0; uint32_t v_fix = 0; + int32_t sub_ch = 0; switch (pixel_fmt) { case IPU_PIX_FMT_GENERIC: @@ -594,11 +706,23 @@ static inline void _ipu_ch_offset_update(int ch, ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 46, 22, u_offset / 8); ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 68, 22, v_offset / 8); + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 0, 46, 22, u_offset / 8); + ipu_ch_param_mod_field(ipu_ch_param_addr(sub_ch), 0, 68, 22, v_offset / 8); }; static inline void _ipu_ch_params_set_alpha_width(uint32_t ch, int alpha_width) { + int32_t sub_ch = 0; + ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 125, 3, alpha_width - 1); + + sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); + if (sub_ch <= 0) + return; + ipu_ch_param_set_field(ipu_ch_param_addr(sub_ch), 1, 125, 3, alpha_width - 1); }; #endif diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h index 4e62b256889..c1d6fb345b5 100644 --- a/drivers/mxc/ipu3/ipu_prv.h +++ b/drivers/mxc/ipu3/ipu_prv.h @@ -98,5 +98,7 @@ void _ipu_csi_ccir_err_detection_disable(uint32_t csi); void _ipu_smfc_init(ipu_channel_t channel, uint32_t mipi_id, uint32_t csi); void _ipu_smfc_set_burst_size(ipu_channel_t channel, uint32_t bs); void _ipu_dp_set_csc_coefficients(ipu_channel_t channel, int32_t param[][3]); +void _ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type, + uint32_t bufNum); #endif /* __INCLUDE_IPU_PRV_H__ */ diff --git a/drivers/mxc/ipu3/ipu_regs.h b/drivers/mxc/ipu3/ipu_regs.h index dc64af54d82..95502f3e2b0 100644 --- a/drivers/mxc/ipu3/ipu_regs.h +++ b/drivers/mxc/ipu3/ipu_regs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -87,6 +87,21 @@ extern u32 *ipu_vdi_reg; #define IPU_GPR (ipu_cm_reg + 0x00E4/4) #define IPU_CHA_DB_MODE_SEL(ch) (ipu_cm_reg + 0x0150/4 + (ch / 32)) #define IPU_ALT_CHA_DB_MODE_SEL(ch) (ipu_cm_reg + 0x0168/4 + (ch / 32)) +/* + * IPUv3D doesn't support triple buffer, so point + * IPU_CHA_TRB_MODE_SEL, IPU_CHA_TRIPLE_CUR_BUF and + * IPU_CHA_BUF2_RDY to readonly + * IPU_ALT_CUR_BUF0 for IPUv3D. + */ +#define IPU_CHA_TRB_MODE_SEL(ch) ({g_ipu_hw_rev >= 2 ? \ + (ipu_cm_reg + 0x0178/4 + (ch / 32)) : \ + (ipu_cm_reg + 0x012C/4); }) +#define IPU_CHA_TRIPLE_CUR_BUF(ch) ({g_ipu_hw_rev >= 2 ? \ + (ipu_cm_reg + 0x0258/4 + ((ch*2) / 32)) : \ + (ipu_cm_reg + 0x012C/4); }) +#define IPU_CHA_BUF2_RDY(ch) ({g_ipu_hw_rev >= 2 ? \ + (ipu_cm_reg + 0x0288/4 + (ch / 32)) : \ + (ipu_cm_reg + 0x012C/4); }) #define IPU_CHA_CUR_BUF(ch) ({g_ipu_hw_rev >= 2 ? \ (ipu_cm_reg + 0x023C/4 + (ch / 32)) : \ (ipu_cm_reg + 0x0124/4 + (ch / 32)); }) @@ -192,6 +207,16 @@ extern u32 *ipu_vdi_reg; #define IDMAC_SUB_ADDR_2 ({g_ipu_hw_rev >= 2 ? \ (ipu_idmac_reg + 0x0034/4) : \ (ipu_idmac_reg + 0x0030/4); }) +/* + * IPUv3D doesn't support IDMAC_SUB_ADDR_3 and IDMAC_SUB_ADDR_4, + * so point them to readonly IDMAC_CHA_BUSY1 for IPUv3D. + */ +#define IDMAC_SUB_ADDR_3 ({g_ipu_hw_rev >= 2 ? \ + (ipu_idmac_reg + 0x0038/4) : \ + (ipu_idmac_reg + 0x0040/4); }) +#define IDMAC_SUB_ADDR_4 ({g_ipu_hw_rev >= 2 ? \ + (ipu_idmac_reg + 0x003c/4) : \ + (ipu_idmac_reg + 0x0040/4); }) #define IDMAC_BAND_EN(ch) ({g_ipu_hw_rev >= 2 ? \ (ipu_idmac_reg + 0x0040/4 + (ch/32)) : \ (ipu_idmac_reg + 0x0034/4 + (ch/32)); }) diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c index fe453fa0272..fbbf5ca5f61 100644 --- a/drivers/video/mxc/mxc_ipuv3_fb.c +++ b/drivers/video/mxc/mxc_ipuv3_fb.c @@ -79,7 +79,6 @@ struct mxcfb_info { u32 pseudo_palette[16]; bool wait4vsync; - uint32_t waitcnt; struct semaphore flip_sem; struct semaphore alpha_flip_sem; struct completion vsync_complete; @@ -250,7 +249,7 @@ static int _setup_disp_channel2(struct fb_info *fbi) fb_stride = fbi->fix.line_length; } - mxc_fbi->cur_ipu_buf = 1; + mxc_fbi->cur_ipu_buf = 2; sema_init(&mxc_fbi->flip_sem, 1); if (mxc_fbi->alpha_chan_en) { mxc_fbi->cur_ipu_alpha_buf = 1; @@ -269,6 +268,8 @@ static int _setup_disp_channel2(struct fb_info *fbi) IPU_ROTATE_NONE, base, base, + (fbi->var.accel_flags == + FB_ACCEL_TRIPLE_FLAG) ? base : 0, 0, 0); if (retval) { dev_err(fbi->device, @@ -284,6 +285,7 @@ static int _setup_disp_channel2(struct fb_info *fbi) IPU_ROTATE_NONE, mxc_fbi->alpha_phy_addr1, mxc_fbi->alpha_phy_addr0, + 0, 0, 0); if (retval) { dev_err(fbi->device, @@ -307,15 +309,6 @@ static int mxcfb_set_par(struct fb_info *fbi) ipu_di_signal_cfg_t sig_cfg; struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; - /* - * stubbornly refuse to clock a mode less than 12.5MHz. This fixes the - * issue where a "dummy" 320x240 mode gives us all kinds of hassle when - * we catch framebuffer registration. There is no standard mode that - * goes this low so everything should still work :) - */ - if (fbi->var.pixclock > 80000) - return 0; - dev_dbg(fbi->device, "Reconfiguring framebuffer\n"); ipu_disable_irq(mxc_fbi->ipu_ch_irq); @@ -1255,12 +1248,13 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) loc_alpha_en = true; mxc_graphic_fbi = (struct mxcfb_info *) (registered_fb[i]->par); - active_alpha_phy_addr = mxc_fbi->cur_ipu_buf ? + active_alpha_phy_addr = + mxc_fbi->cur_ipu_alpha_buf ? mxc_graphic_fbi->alpha_phy_addr1 : mxc_graphic_fbi->alpha_phy_addr0; - dev_dbg(info->device, "Updating SDC graphic " + dev_dbg(info->device, "Updating SDC alpha " "buf %d address=0x%08lX\n", - mxc_fbi->cur_ipu_buf, + !mxc_fbi->cur_ipu_alpha_buf, active_alpha_phy_addr); break; } @@ -1269,7 +1263,8 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) down(&mxc_fbi->flip_sem); - mxc_fbi->cur_ipu_buf = !mxc_fbi->cur_ipu_buf; + mxc_fbi->cur_ipu_buf = (++mxc_fbi->cur_ipu_buf) % 3; + mxc_fbi->cur_ipu_alpha_buf = !mxc_fbi->cur_ipu_alpha_buf; dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n", info->fix.id, mxc_fbi->cur_ipu_buf, base); @@ -1280,11 +1275,11 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) if (loc_alpha_en && mxc_graphic_fbi == mxc_fbi && ipu_update_channel_buffer(mxc_graphic_fbi->ipu_ch, IPU_ALPHA_IN_BUFFER, - mxc_fbi->cur_ipu_buf, + mxc_fbi->cur_ipu_alpha_buf, active_alpha_phy_addr) == 0) { ipu_select_buffer(mxc_graphic_fbi->ipu_ch, IPU_ALPHA_IN_BUFFER, - mxc_fbi->cur_ipu_buf); + mxc_fbi->cur_ipu_alpha_buf); } ipu_select_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER, @@ -1293,9 +1288,20 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ipu_enable_irq(mxc_fbi->ipu_ch_irq); } else { dev_err(info->device, - "Error updating SDC buf %d to address=0x%08lX\n", - mxc_fbi->cur_ipu_buf, base); - mxc_fbi->cur_ipu_buf = !mxc_fbi->cur_ipu_buf; + "Error updating SDC buf %d to address=0x%08lX, " + "current buf %d, buf0 ready %d, buf1 ready %d, " + "buf2 ready %d\n", mxc_fbi->cur_ipu_buf, base, + ipu_get_cur_buffer_idx(mxc_fbi->ipu_ch, + IPU_INPUT_BUFFER), + ipu_check_buffer_ready(mxc_fbi->ipu_ch, + IPU_INPUT_BUFFER, 0), + ipu_check_buffer_ready(mxc_fbi->ipu_ch, + IPU_INPUT_BUFFER, 1), + ipu_check_buffer_ready(mxc_fbi->ipu_ch, + IPU_INPUT_BUFFER, 2)); + mxc_fbi->cur_ipu_buf = (++mxc_fbi->cur_ipu_buf) % 3; + mxc_fbi->cur_ipu_buf = (++mxc_fbi->cur_ipu_buf) % 3; + mxc_fbi->cur_ipu_alpha_buf = !mxc_fbi->cur_ipu_alpha_buf; ipu_clear_irq(mxc_fbi->ipu_ch_irq); ipu_enable_irq(mxc_fbi->ipu_ch_irq); return -EBUSY; @@ -1397,23 +1403,8 @@ static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id) ipu_disable_irq(irq); mxc_fbi->wait4vsync = 0; } else { - if (!ipu_check_buffer_ready(mxc_fbi->ipu_ch, - IPU_INPUT_BUFFER, mxc_fbi->cur_ipu_buf) - || (mxc_fbi->waitcnt > 2)) { - /* - * This interrupt come after pan display select - * cur_ipu_buf buffer, this buffer should become - * idle after show. If it keep busy, clear it manually. - */ - if (mxc_fbi->waitcnt > 2) - ipu_clear_buffer_ready(mxc_fbi->ipu_ch, - IPU_INPUT_BUFFER, - mxc_fbi->cur_ipu_buf); - up(&mxc_fbi->flip_sem); - ipu_disable_irq(irq); - mxc_fbi->waitcnt = 0; - } else - mxc_fbi->waitcnt++; + up(&mxc_fbi->flip_sem); + ipu_disable_irq(irq); } return IRQ_HANDLED; } @@ -1729,8 +1720,8 @@ static int mxcfb_probe(struct platform_device *pdev) if (plat_data && !mxcfbi->ipu_di_pix_fmt) { mxcfbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt; /* try and use a bit depth closest to the bit depth we use for the panel */ - if (!mxcfbi->default_bpp) - mxcfbi->default_bpp = pixfmt_to_bpp(plat_data->interface_pix_fmt); +// if (!mxcfbi->default_bpp) +// mxcfbi->default_bpp = pixfmt_to_bpp(plat_data->interface_pix_fmt); } if (!mxcfbi->default_bpp) diff --git a/drivers/video/mxc/mxcfb.c b/drivers/video/mxc/mxcfb.c index 5152a885014..e79572e700b 100644 --- a/drivers/video/mxc/mxcfb.c +++ b/drivers/video/mxc/mxcfb.c @@ -244,6 +244,7 @@ static int mxcfb_set_par(struct fb_info *fbi) fbi->fix.smem_start + (fbi->fix.line_length * fbi->var.yres), fbi->fix.smem_start, + 0, 0, 0); if (retval) { dev_err(fbi->device, diff --git a/include/linux/ipu.h b/include/linux/ipu.h index 39f4ef78906..d47bf76ad06 100644 --- a/include/linux/ipu.h +++ b/include/linux/ipu.h @@ -887,6 +887,7 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, uint32_t stride, ipu_rotate_mode_t rot_mode, dma_addr_t phyaddr_0, dma_addr_t phyaddr_1, + dma_addr_t phyaddr_2, uint32_t u_offset, uint32_t v_offset); int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, @@ -1079,6 +1080,7 @@ typedef struct _ipu_channel_buf_parm { ipu_rotate_mode_t rot_mode; dma_addr_t phyaddr_0; dma_addr_t phyaddr_1; + dma_addr_t phyaddr_2; uint32_t u_offset; uint32_t v_offset; uint32_t bufNum; diff --git a/include/linux/mxcfb.h b/include/linux/mxcfb.h index ad3ca388f4a..f83ba477082 100644 --- a/include/linux/mxcfb.h +++ b/include/linux/mxcfb.h @@ -29,6 +29,8 @@ #define FB_SYNC_CLK_IDLE_EN 0x10000000 #define FB_SYNC_SHARP_MODE 0x08000000 #define FB_SYNC_SWAP_RGB 0x04000000 +#define FB_ACCEL_TRIPLE_FLAG 0x00000000 +#define FB_ACCEL_DOUBLE_FLAG 0x00000001 struct mxcfb_gbl_alpha { int enable;