summaryrefslogtreecommitdiff
path: root/drivers/mxc
diff options
context:
space:
mode:
authorLiu Ying <Ying.Liu@freescale.com>2011-06-07 15:48:41 +0800
committerLiu Ying <Ying.Liu@freescale.com>2011-06-08 16:28:38 +0800
commit1f5502296f6ab5062ce6169cb28b36f704b731c3 (patch)
tree935de63dfb8f9a2fffc3ad055b8a41639275154d /drivers/mxc
parent6843a490d7e14551592670c9ff0ae68bc7916617 (diff)
ENGR00151175 IPUv3:Improve driver
1) Return error when initializing channel fails. 2) Protect g_channel_init_mask in ipu_uninit_channel() with ipu spinlock. 3) Support low level clear buffer ready function so that we can call it with ipu spinlock locked for once. 4) Fix potential infinite loop in suspend function when ipu clock is enabled. Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
Diffstat (limited to 'drivers/mxc')
-rw-r--r--drivers/mxc/ipu3/ipu_common.c77
-rw-r--r--drivers/mxc/ipu3/ipu_prv.h2
2 files changed, 57 insertions, 22 deletions
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
index c3b09da5b2f2..d837cf4140dd 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -504,6 +504,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);
@@ -743,7 +745,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 */
@@ -769,9 +772,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_err(g_ipu_dev, "Channel already uninitialized %d\n",
IPU_CHAN_ID(channel));
+ spin_unlock_irqrestore(&ipu_lock, lock_flags);
return;
}
@@ -785,11 +791,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 */
@@ -1894,6 +1899,34 @@ void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type,
}
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;
@@ -2063,29 +2096,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));
}
- 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);
- ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 2);
+ _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);
+ _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);
+ _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);
+ _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);
+
return 0;
}
EXPORT_SYMBOL(ipu_disable_channel);
@@ -2464,14 +2497,14 @@ int32_t ipu_swap_channel(ipu_channel_t from_ch, ipu_channel_t to_ch)
__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));
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);
@@ -2560,6 +2593,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));
@@ -2567,8 +2602,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];
diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h
index ec27264c47e3..df55b1c8c1f7 100644
--- a/drivers/mxc/ipu3/ipu_prv.h
+++ b/drivers/mxc/ipu3/ipu_prv.h
@@ -99,5 +99,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__ */