summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiu Ying <Ying.Liu@freescale.com>2013-11-21 16:39:08 +0800
committerLiu Ying <Ying.Liu@freescale.com>2013-12-05 18:04:46 +0800
commit25e98bf6307fa601f8bce5da92baaa77a68df593 (patch)
treefc19b10899f3f5584e4ed9d9fecd88267897c87a
parentb2a5b16079133faf018f6800b5fa57d663db2686 (diff)
ENGR00290361-1 IPUv3 IC:Add check for a IDMAC errata
The IPUv3 IDMAC has a bug to read 32bpp pixels from a graphics plane whose alpha component is at the most significant 8 bits. The bug only impacts on cases in which the relevant separate alpha channel is enabled. This patch adds check for the errata so that the bad cases won't be triggered. Signed-off-by: Liu Ying <Ying.Liu@freescale.com> (cherry picked from commit 4f972f7f972e88802c848b930e83824360801484)
-rw-r--r--drivers/mxc/ipu3/ipu_common.c58
-rw-r--r--drivers/mxc/ipu3/ipu_param_mem.h20
-rw-r--r--include/linux/ipu-v3.h2
3 files changed, 69 insertions, 11 deletions
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
index 8303bc8bf131..16b520be9c4c 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -586,8 +586,8 @@ void ipu_dump_registers(struct ipu_soc *ipu)
int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
{
int ret = 0;
- uint32_t ipu_conf;
- uint32_t reg;
+ bool bad_pixfmt;
+ uint32_t ipu_conf, reg, in_g_pixel_fmt, sec_dma;
dev_dbg(ipu->dev, "init channel = %d\n", IPU_CHAN_ID(channel));
@@ -741,16 +741,30 @@ int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel
_ipu_ic_init_prpvf(ipu, params, true);
break;
case MEM_PRP_VF_MEM:
- ipu->ic_use_count++;
+ if (params->mem_prp_vf_mem.graphics_combine_en) {
+ sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+ in_g_pixel_fmt = params->mem_prp_vf_mem.in_g_pixel_fmt;
+ bad_pixfmt =
+ _ipu_ch_param_bad_alpha_pos(in_g_pixel_fmt);
+
+ if (params->mem_prp_vf_mem.alpha_chan_en) {
+ if (bad_pixfmt) {
+ dev_err(ipu->dev, "bad pixel format "
+ "for graphics plane from "
+ "ch%d\n", sec_dma);
+ ret = -EINVAL;
+ goto err;
+ }
+ ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+ }
+ ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+ }
+
reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
ipu_cm_write(ipu, reg | FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
- if (params->mem_prp_vf_mem.graphics_combine_en)
- ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
- if (params->mem_prp_vf_mem.alpha_chan_en)
- ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
-
_ipu_ic_init_prpvf(ipu, params, false);
+ ipu->ic_use_count++;
break;
case MEM_VDI_PRP_VF_MEM:
if ((ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM) ||
@@ -807,10 +821,26 @@ int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel
_ipu_ic_init_rotate_enc(ipu, params);
break;
case MEM_PP_MEM:
- if (params->mem_pp_mem.graphics_combine_en)
+ if (params->mem_pp_mem.graphics_combine_en) {
+ sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+ in_g_pixel_fmt = params->mem_pp_mem.in_g_pixel_fmt;
+ bad_pixfmt =
+ _ipu_ch_param_bad_alpha_pos(in_g_pixel_fmt);
+
+ if (params->mem_pp_mem.alpha_chan_en) {
+ if (bad_pixfmt) {
+ dev_err(ipu->dev, "bad pixel format "
+ "for graphics plane from "
+ "ch%d\n", sec_dma);
+ ret = -EINVAL;
+ goto err;
+ }
+ ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+ }
+
ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
- if (params->mem_pp_mem.alpha_chan_en)
- ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+ }
+
_ipu_ic_init_pp(ipu, params);
ipu->ic_use_count++;
break;
@@ -3012,6 +3042,12 @@ bool ipu_pixel_format_has_alpha(uint32_t fmt)
return false;
}
+bool ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt)
+{
+ return _ipu_ch_param_bad_alpha_pos(pixel_fmt);
+}
+EXPORT_SYMBOL(ipu_ch_param_bad_alpha_pos);
+
#ifdef CONFIG_PM
static int ipu_suspend(struct device *dev)
{
diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h
index f0e2f17a5f37..2ff622b54824 100644
--- a/drivers/mxc/ipu3/ipu_param_mem.h
+++ b/drivers/mxc/ipu3/ipu_param_mem.h
@@ -898,4 +898,24 @@ static inline void _ipu_ch_param_set_bandmode(struct ipu_soc *ipu,
dev_dbg(ipu->dev, "BNDM 0x%x, ",
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 114, 3));
}
+
+/*
+ * The IPUv3 IDMAC has a bug to read 32bpp pixels from a graphics plane
+ * whose alpha component is at the most significant 8 bits. The bug only
+ * impacts on cases in which the relevant separate alpha channel is enabled.
+ *
+ * Return true on bad alpha component position, otherwise, return false.
+ */
+static inline bool _ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt)
+{
+ switch (pixel_fmt) {
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_RGB32:
+ return true;
+ }
+
+ return false;
+}
#endif
diff --git a/include/linux/ipu-v3.h b/include/linux/ipu-v3.h
index b3a9954e71d9..c57d7ded4f6a 100644
--- a/include/linux/ipu-v3.h
+++ b/include/linux/ipu-v3.h
@@ -728,6 +728,8 @@ void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, ui
uint32_t bytes_per_pixel(uint32_t fmt);
+bool ipu_ch_param_bad_alpha_pos(uint32_t fmt);
+
struct ipuv3_fb_platform_data {
char disp_dev[32];
u32 interface_pix_fmt;