]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00290361-1 IPUv3 IC:Add check for a IDMAC errata
authorLiu Ying <Ying.Liu@freescale.com>
Thu, 21 Nov 2013 08:39:08 +0000 (16:39 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Wed, 20 Aug 2014 08:06:47 +0000 (10:06 +0200)
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>
drivers/mxc/ipu3/ipu_common.c
drivers/mxc/ipu3/ipu_param_mem.h
include/linux/ipu-v3.h

index b1930398ece5280b78953fa90ab3cb4a6227841c..a31fb9765603d080de091418a36c1f7f1b60e50c 100644 (file)
@@ -587,8 +587,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));
 
@@ -742,16 +742,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) ||
@@ -808,10 +822,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;
@@ -3013,6 +3043,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)
 {
index f0e2f17a5f37ab286145295078b5a3c5f74cfb08..2ff622b54824a7a9c2b2e6c5ab7455e005b3f5de 100644 (file)
@@ -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
index b3a9954e71d9f5856bb49419877a1b5cabe8168b..c57d7ded4f6a79090732924bddbeaa01f67e00aa 100644 (file)
@@ -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;