summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiu Ying <Ying.Liu@freescale.com>2011-05-24 09:58:49 +0800
committerJason Liu <r64343@freescale.com>2012-07-20 13:13:55 +0800
commit13779c15725efcd1da2710d97a72ff21f145b5ec (patch)
tree5c8ea3d9dea8a94bc0f87789ead1d281f02a5f2e
parentd2d8c9bc3a155dcfd19bb5c8dea0c9cf5ff6ea66 (diff)
ENGR00142551-1 IPUv3:Support triple buffer
This patch supports IPUv3 triple buffer. Only channel 23, 27 and 28 are tested. Test was done on MX51 BBG and MX53 SMD. IPUv1 interface is changed accordingly to pass building. Signed-off-by: Liu Ying <Ying.Liu@freescale.com> (cherry picked from commit 73ef4408712acfee2d132f73555085a61be7b17c)
-rw-r--r--drivers/mxc/ipu/ipu_common.c4
-rw-r--r--drivers/mxc/ipu/ipu_device.c1
-rw-r--r--drivers/mxc/ipu3/ipu_common.c226
-rw-r--r--drivers/mxc/ipu3/ipu_device.c1
-rw-r--r--drivers/mxc/ipu3/ipu_param_mem.h126
-rw-r--r--drivers/mxc/ipu3/ipu_regs.h25
-rw-r--r--include/linux/ipu.h2
7 files changed, 342 insertions, 43 deletions
diff --git a/drivers/mxc/ipu/ipu_common.c b/drivers/mxc/ipu/ipu_common.c
index fd4345283180..47a6f5a43da7 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 bd8d9e35c141..7bf37f5041cd 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 c78c0e9337a9..185352250ac3 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -81,9 +81,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;
@@ -139,9 +142,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 unsigned long _ipu_pixel_clk_get_rate(struct clk *clk)
{
@@ -397,7 +411,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);
@@ -525,6 +539,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",
@@ -874,6 +894,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;
@@ -1037,7 +1063,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.
*
@@ -1065,6 +1091,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.
*
@@ -1079,6 +1110,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;
@@ -1105,9 +1137,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) ||
@@ -1168,17 +1212,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);
+ 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));
- reg = __raw_readl(IPU_CHA_DB_MODE_SEL(dma_chan));
- if (phyaddr_1)
+ reg = __raw_readl(IPU_CHA_TRB_MODE_SEL(dma_chan));
reg |= idma_mask(dma_chan);
- else
+ __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_DB_MODE_SEL(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));
+ /* 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;
@@ -1215,8 +1283,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);
@@ -1281,7 +1351,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,
@@ -1309,22 +1382,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);
@@ -1345,17 +1419,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);
@@ -1863,8 +1935,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;
@@ -1894,18 +1968,22 @@ 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);
@@ -2053,11 +2131,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));
@@ -2085,6 +2167,7 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop)
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);
@@ -2393,11 +2476,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);
@@ -2467,11 +2557,17 @@ 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));
g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(from_ch));
spin_unlock_irqrestore(&ipu_lock, lock_flags);
+ 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);
+
return 0;
}
EXPORT_SYMBOL(ipu_swap_channel);
@@ -2597,12 +2693,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);
@@ -2618,6 +2735,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));
}
if (plat_data->pg)
@@ -2644,6 +2763,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);
@@ -2657,12 +2778,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));
@@ -2672,7 +2814,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 057ddf6e447b..316207a288fa 100644
--- a/drivers/mxc/ipu3/ipu_device.c
+++ b/drivers/mxc/ipu3/ipu_device.c
@@ -135,6 +135,7 @@ static long mxc_ipu_ioctl(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 b2049de52f2b..fbe15f9927a8 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(&params, 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), &params, sizeof(params));
+ if (addr2) {
+ ipu_ch_param_set_field(&params, 1, 0, 29, addr2 >> 3);
+ ipu_ch_param_set_field(&params, 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), &params, 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_regs.h b/drivers/mxc/ipu3/ipu_regs.h
index b9392b71b58d..5c94c7b935a8 100644
--- a/drivers/mxc/ipu3/ipu_regs.h
+++ b/drivers/mxc/ipu3/ipu_regs.h
@@ -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/include/linux/ipu.h b/include/linux/ipu.h
index 768ec3de9937..64428ab7cb77 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,
@@ -1081,6 +1082,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;