[PATCH v3 01/12] gpu: ipu-cpmem: Add ipu_cpmem_set_uv_offset()

2016-08-01 Thread Steve Longerbeam
On 08/01/2016 02:13 AM, Philipp Zabel wrote:
> Am Sonntag, den 31.07.2016, 12:42 -0700 schrieb Steve Longerbeam:
>> Adds ipu_cpmem_set_uv_offset(), to set planar U/V offsets.
>>
>> Signed-off-by: Steve Longerbeam 
> There is no need to resend already applied patches.
>

Ok, I wasn't sure whether to include or not, you said you
applied these, should have read that as an implicit Ack.

Steve




[PATCH v3 10/12] gpu: ipu-v3: Add FSU channel linking support

2016-08-01 Thread Steve Longerbeam
On 08/01/2016 02:13 AM, Philipp Zabel wrote:
> Am Sonntag, den 31.07.2016, 12:42 -0700 schrieb Steve Longerbeam:
>> Adds functions to link and unlink source channels to sink
>> channels in the FSU:
>>
>> int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch);
>> int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch);
>>
>> The channels numbers are usually IDMAC channels, but they can also be
>> channels that do not transfer data to or from memory. The following
>> convenience functions can be used in place of ipu_fsu_link/unlink()
>> when both source and sink channels are IDMAC channels:
>>
>> int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink);
>> int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink);
>>
>> So far the following links are supported:
>>
>> IPUV3_CHANNEL_IC_PRP_ENC_MEM -> IPUV3_CHANNEL_MEM_ROT_ENC
>> PUV3_CHANNEL_IC_PRP_VF_MEM   -> IPUV3_CHANNEL_MEM_ROT_VF
>> IPUV3_CHANNEL_IC_PP_MEM  -> IPUV3_CHANNEL_MEM_ROT_PP
>> IPUV3_CHANNEL_CSI_DIRECT -> IPUV3_CHANNEL_CSI_VDI_PREV
> Looks good to me, thanks. Are you sure though that the target of the CSI
> direct channel is VDI_PREV? I would have assumed the CSI input is fed
> into VDI_NEXT, while CUR and PREV are read from memory.

Reprinting from the TRM:

37.4.11.4 Real Time Mode
In Real Time Mode the F(n-1) are coming from CSI. The CSI write to FIFO1. The DI
sub-block read F(n-1) from processing. In addition IDMAC read the field from 
FIFO1
and store in external memory. Then stored frames are used as F(n) and F(n+1).


Steve




[PATCH v3 09/12] gpu: ipu-v3: Add Video Deinterlacer unit

2016-08-01 Thread Steve Longerbeam
On 08/01/2016 02:13 AM, Philipp Zabel wrote:
>
> Please remove the unused headers. I think you can remove all but
> export.h, types.h, errno.h, and io.h.
> Other than that, the patch now looks fine to me.
>

I was able to prune all but io.h, the rest is provided by ipu-prv.h.

Steve



[PATCH v2 11/13] gpu: ipu-ic: Add complete image conversion support with tiling

2016-08-03 Thread Steve Longerbeam
On 08/01/2016 02:29 AM, Philipp Zabel wrote:
> Am Donnerstag, den 28.07.2016, 16:09 -0700 schrieb Steve Longerbeam:
>>> Now split the frame in half and suddenly pixel x' = 640 is the start of
>>> a new tile, so it is sampled at x = 160, and pixel x' = 1279 will be
>>> sampled at x = 160 + (1279 - 640) * 8192/32846. = 319.37, reading over
>>> the edge of the source image.
>> Here's where we part.
>>
>> The 320x200 --> 1280x800 conversion is split into two 160x200 -->
>> 640x800 conversions. The DMA controller and ipu_ic_task_init() are given
>> those width/height dimensions, not the dimensions of the original images.
>> So this is simply two separate 160x200 --> 640x800 conversions. The only
>> difference from a true 160x200 --> 640x800 image conversion is that the DMA
>> controller must be given the stride lengths of the original 320x200 and 
>> 1280x800
>> images.
>>
>> The rsc for the 160x200 --> 640x800 conversions is
>>
>> x = x' * (160-1)/(640-1) = x' * 8192/rsc, so rsc = 32923
>>
>>
>> So original horizontal position 640 is really x' = 0 of the second 
>> conversion,
>> which is sampled at x = 0 of the second conversion. And the pixel at x' 
>> = 1279
>> is really x' = 639 of the second conversion, which is sampled at x = 639 
>> * 8192/32923
>> = 158.98, which does not read over the edge of the source tile.
> My bad, I somehow thought that the scaling factor is calculated per
> image (as it IMHO should be), not just per tile.
>
> Of course in that case you won't ever read over the edge, but on the
> other hand the visual problems are worse because you underestimate the
> scaling factor and introduce a sharp edge at the center: even if the
> source pixel step per target pixel step is a fraction, between pixels
> width/2-1 and width/2 there's always a whole source pixel step.
>
> Take the extreme example of scaling 32x32 to 1080x1080 pixels. The ideal
> source pixels for x' = 519 and 520 should be x = 14.911 and 14.939,
> respectively. Due to tiling they will be x = 15 and 16, introducing a
> sharp seam in the otherwise blurry mess.

I think you mean at x' = 539 and x' = 540.

But yes I agree. Due to tiling, at x' = 539, the input pixel is sampled at x = 
15.
If the interpolation were to continue (no tiling), at x' = 540, the input pixel
would be sampled at (31/1079)*540 = 15.514. Instead, because of tiling,
there is a discontinuity in the interpolation (it is reset), beginning again at
x' = 0 (540), which is sampled at x = 0 (16).

The only way I can think of to resolve this problem is to add some width
to the output tiles such that the interpolation completes a full span between
input position w - 2 and w - 1. That is, add to w' until floor(F*w') increments
to the next whole integer, where F = (w-1)/(w'-1) is the scaling factor.

But that will likely cause the next tile DMA addrs to fail to fall on the IDMAC
8 byte alignment.


>
>
>> That said, I _have_ noticed seams, but I have always attributed them to the
>> fact that we have a discontinuity in color-space conversion and/or resize
>> interpolation at the boundary between tiles.
>>
>> I've also found that the seams are quite noticeable when rendered to a
>> display overlay, but become significantly less pronounced if the images are
>> converted to a back buffer, and then page-flipped to front buffer when the
>> conversion (all tiles) completes.
> I don't know what to make of this. Maybe it is a timing issue and what
> you are actually seeing is tearing between tiles of different frames?

Yes, that's always been my assumption, a scan-out contains a mix
of tiles from different frames, when page-flip is not used.

Steve



[PATCH v4 0/4] IPUv3 prep for i.MX5/6 v4l2 staging drivers, v4

2016-08-17 Thread Steve Longerbeam
In this version:

- rebased against latest drm-next.
- cleaned up header includes in ipu-vdi.c.
- do away with struct ipu_ic_tile_off in ipu-ic.c, and move tile offsets
  into struct ipu_ic_tile. This paves the way for possibly allowing for
  each tile to have different dimensions in the future.


Steve Longerbeam (4):
  gpu: ipu-v3: Add Video Deinterlacer unit
  gpu: ipu-v3: Add FSU channel linking support
  gpu: ipu-ic: Add complete image conversion support with tiling
  gpu: ipu-ic: allow multiple handles to ic

 drivers/gpu/ipu-v3/Makefile |2 +-
 drivers/gpu/ipu-v3/ipu-common.c |  142 
 drivers/gpu/ipu-v3/ipu-ic.c | 1719 ++-
 drivers/gpu/ipu-v3/ipu-prv.h|   33 +
 drivers/gpu/ipu-v3/ipu-vdi.c|  243 ++
 include/video/imx-ipu-v3.h  |   93 ++-
 6 files changed, 2195 insertions(+), 37 deletions(-)
 create mode 100644 drivers/gpu/ipu-v3/ipu-vdi.c

-- 
1.9.1



[PATCH v4 1/4] gpu: ipu-v3: Add Video Deinterlacer unit

2016-08-17 Thread Steve Longerbeam
Adds the Video Deinterlacer (VDIC) unit.

Signed-off-by: Steve Longerbeam 

---

v4:
- pruned included headers.

v3:
- renamed and exported ipu_vdi_set_top_field_man() to
  ipu_vdi_set_field_order(). Args include std and field to determine
  correct field order.
- exported ipu_vdi_set_motion().
- ipu_vdi_setup() does not need to call ipu_vdi_set_top_field_man() or
  ipu_vdi_set_motion(), since latter are exported. This simplifies args.
- removed ipu_vdi_toggle_top_field_man().
- removed ipu_vdi_set_src().

v2:
- removed include of module.h
- corrected V4L2 field type checks
- cleaned up use_count decrement in ipu_vdi_disable()
---
 drivers/gpu/ipu-v3/Makefile |   2 +-
 drivers/gpu/ipu-v3/ipu-common.c |  11 ++
 drivers/gpu/ipu-v3/ipu-prv.h|   6 +
 drivers/gpu/ipu-v3/ipu-vdi.c| 243 
 include/video/imx-ipu-v3.h  |  23 
 5 files changed, 284 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/ipu-v3/ipu-vdi.c

diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile
index 107ec23..aeba9dc 100644
--- a/drivers/gpu/ipu-v3/Makefile
+++ b/drivers/gpu/ipu-v3/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o

 imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
-   ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o
+   ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o ipu-vdi.o
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index d230988..9d3584b 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -839,6 +839,14 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
goto err_ic;
}

+   ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
+  IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
+  IPU_CONF_IC_INPUT);
+   if (ret) {
+   unit = "vdi";
+   goto err_vdi;
+   }
+
ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
  IPU_CONF_DI0_EN, ipu_clk);
if (ret) {
@@ -893,6 +901,8 @@ err_dc:
 err_di_1:
ipu_di_exit(ipu, 0);
 err_di_0:
+   ipu_vdi_exit(ipu);
+err_vdi:
ipu_ic_exit(ipu);
 err_ic:
ipu_csi_exit(ipu, 1);
@@ -977,6 +987,7 @@ static void ipu_submodules_exit(struct ipu_soc *ipu)
ipu_dc_exit(ipu);
ipu_di_exit(ipu, 1);
ipu_di_exit(ipu, 0);
+   ipu_vdi_exit(ipu);
ipu_ic_exit(ipu);
ipu_csi_exit(ipu, 1);
ipu_csi_exit(ipu, 0);
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index fd47f8f..02057d8 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -138,6 +138,7 @@ struct ipu_dc_priv;
 struct ipu_dmfc_priv;
 struct ipu_di;
 struct ipu_ic_priv;
+struct ipu_vdi;
 struct ipu_smfc_priv;

 struct ipu_devtype;
@@ -170,6 +171,7 @@ struct ipu_soc {
struct ipu_di   *di_priv[2];
struct ipu_csi  *csi_priv[2];
struct ipu_ic_priv  *ic_priv;
+   struct ipu_vdi  *vdi_priv;
struct ipu_smfc_priv*smfc_priv;
 };

@@ -200,6 +202,10 @@ int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
unsigned long base, unsigned long tpmem_base);
 void ipu_ic_exit(struct ipu_soc *ipu);

+int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
+unsigned long base, u32 module);
+void ipu_vdi_exit(struct ipu_soc *ipu);
+
 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
unsigned long base, u32 module, struct clk *ipu_clk);
 void ipu_di_exit(struct ipu_soc *ipu, int id);
diff --git a/drivers/gpu/ipu-v3/ipu-vdi.c b/drivers/gpu/ipu-v3/ipu-vdi.c
new file mode 100644
index 000..f27bf5a
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-vdi.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2012-2016 Mentor Graphics Inc.
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include 
+#include "ipu-prv.h"
+
+struct ipu_vdi {
+   void __iomem *base;
+   u32 module;
+   spinlock_t lock;
+   int use_count;
+   struct ipu_soc *ipu;
+};
+
+
+/* VDI Register Offsets */
+#define VDI_FSIZE 0x
+#define VDI_C 0x0004
+
+/* VDI Register Fields */
+#define VDI_C_CH_420 (0 << 1)
+#define VDI_C_CH_422 (1 << 1)
+#define VDI_C_MOT_SEL_MASK   (0x3 << 2)
+#defin

[PATCH v4 3/4] gpu: ipu-ic: Add complete image conversion support with tiling

2016-08-17 Thread Steve Longerbeam
This patch implements complete image conversion support to ipu-ic,
with tiling to support scaling to and from images up to 4096x4096.
Image rotation is also supported.

The internal API is subsystem agnostic (no V4L2 dependency except
for the use of V4L2 fourcc pixel formats).

Callers prepare for image conversion by calling
ipu_image_convert_prepare(), which initializes the parameters of
the conversion. The caller passes in the ipu_ic task to use for
the conversion, the input and output image formats, a rotation mode,
and a completion callback and completion context pointer:

struct image_converter_ctx *
ipu_image_convert_prepare(struct ipu_ic *ic,
  struct ipu_image *in, struct ipu_image *out,
  enum ipu_rotate_mode rot_mode,
  image_converter_cb_t complete,
  void *complete_context);

The caller is given a new conversion context that must be passed to
the further APIs:

struct image_converter_run *
ipu_image_convert_run(struct image_converter_ctx *ctx,
  dma_addr_t in_phys, dma_addr_t out_phys);

This queues a new image conversion request to a run queue, and
starts the conversion immediately if the run queue is empty. Only
the physaddr's of the input and output image buffers are needed,
since the conversion context was created previously with
ipu_image_convert_prepare(). Returns a new run object pointer. When
the conversion completes, the run pointer is returned to the
completion callback.

void image_convert_abort(struct image_converter_ctx *ctx);

This will abort any active or pending conversions for this context.
Any currently active or pending runs belonging to this context are
returned via the completion callback with an error status.

void ipu_image_convert_unprepare(struct image_converter_ctx *ctx);

Unprepares the conversion context. Any active or pending runs will
be aborted by calling image_convert_abort().

Signed-off-by: Steve Longerbeam 

---

v4:
- do away with struct ipu_ic_tile_off, and move tile offsets into
  struct ipu_ic_tile. This paves the way for possibly allowing for
  each tile to have different dimensions in the future.

v3: no changes
v2: no changes
---
 drivers/gpu/ipu-v3/ipu-ic.c | 1694 ++-
 include/video/imx-ipu-v3.h  |   57 +-
 2 files changed, 1739 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 1a37afc..01b1b56 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -17,6 +17,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include "ipu-prv.h"

 /* IC Register Offsets */
@@ -82,6 +84,40 @@
 #define IC_IDMAC_3_PP_WIDTH_MASK(0x3ff << 20)
 #define IC_IDMAC_3_PP_WIDTH_OFFSET  20

+/*
+ * The IC Resizer has a restriction that the output frame from the
+ * resizer must be 1024 or less in both width (pixels) and height
+ * (lines).
+ *
+ * The image conversion support attempts to split up a conversion when
+ * the desired output (converted) frame resolution exceeds the IC resizer
+ * limit of 1024 in either dimension.
+ *
+ * If either dimension of the output frame exceeds the limit, the
+ * dimension is split into 1, 2, or 4 equal stripes, for a maximum
+ * of 4*4 or 16 tiles. A conversion is then carried out for each
+ * tile (but taking care to pass the full frame stride length to
+ * the DMA channel's parameter memory!). IDMA double-buffering is used
+ * to convert each tile back-to-back when possible (see note below
+ * when double_buffering boolean is set).
+ *
+ * Note that the input frame must be split up into the same number
+ * of tiles as the output frame.
+ */
+#define MAX_STRIPES_W4
+#define MAX_STRIPES_H4
+#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
+
+#define MIN_W 128
+#define MIN_H 128
+#define MAX_W 4096
+#define MAX_H 4096
+
+enum image_convert_type {
+   IMAGE_CONVERT_IN = 0,
+   IMAGE_CONVERT_OUT,
+};
+
 struct ic_task_regoffs {
u32 rsc;
u32 tpmem_csc[2];
@@ -96,6 +132,16 @@ struct ic_task_bitfields {
u32 ic_cmb_galpha_bit;
 };

+struct ic_task_channels {
+   int in;
+   int out;
+   int rot_in;
+   int rot_out;
+   int vdi_in_p;
+   int vdi_in;
+   int vdi_in_n;
+};
+
 static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
[IC_TASK_ENCODER] = {
.rsc = IC_PRP_ENC_RSC,
@@ -138,12 +184,155 @@ static const struct ic_task_bitfields 
ic_task_bit[IC_NUM_TASKS] = {
},
 };

+static const struct ic_task_channels ic_task_ch[IC_NUM_TASKS] = {
+   [IC_TASK_ENCODER] = {
+   .out = IPUV3_CHANNEL_IC_PRP_ENC_MEM,
+   .rot_in = IPUV3_CHANNEL_MEM_ROT_ENC,
+   .rot_out = IPUV3_CHANNEL_ROT_ENC_MEM,
+   },
+   [IC_TASK_VIEWFINDER] = {
+   .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
+   .out = I

[PATCH v4 4/4] gpu: ipu-ic: allow multiple handles to ic

2016-08-17 Thread Steve Longerbeam
The image converter kernel API supports conversion contexts and
job queues, so we should allow more than one handle to the IC, so
that multiple users can add jobs to the queue.

Note however that users that control the IC manually (that do not
use the image converter APIs but setup the IC task by hand via calls
to ipu_ic_task_enable(), ipu_ic_enable(), etc.) must still be careful not
to share the IC handle with other threads. At this point, the only user
that still controls the IC manually is the i.mx capture driver. In that
case the capture driver only allows one open context to get a handle
to the IC at a time, so we should be ok there.

Signed-off-by: Steve Longerbeam 

---

v4: no changes
v3: no changes
v2: no changes
---
 drivers/gpu/ipu-v3/ipu-ic.c | 25 +
 1 file changed, 1 insertion(+), 24 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 01b1b56..c44aeba 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -338,7 +338,6 @@ struct ipu_ic {
enum ipu_color_space out_cs;
bool graphics;
bool rotation;
-   bool in_use;

struct image_converter cvt;

@@ -2370,38 +2369,16 @@ EXPORT_SYMBOL_GPL(ipu_ic_disable);
 struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
 {
struct ipu_ic_priv *priv = ipu->ic_priv;
-   unsigned long flags;
-   struct ipu_ic *ic, *ret;

if (task >= IC_NUM_TASKS)
return ERR_PTR(-EINVAL);

-   ic = &priv->task[task];
-
-   spin_lock_irqsave(&priv->lock, flags);
-
-   if (ic->in_use) {
-   ret = ERR_PTR(-EBUSY);
-   goto unlock;
-   }
-
-   ic->in_use = true;
-   ret = ic;
-
-unlock:
-   spin_unlock_irqrestore(&priv->lock, flags);
-   return ret;
+   return &priv->task[task];
 }
 EXPORT_SYMBOL_GPL(ipu_ic_get);

 void ipu_ic_put(struct ipu_ic *ic)
 {
-   struct ipu_ic_priv *priv = ic->priv;
-   unsigned long flags;
-
-   spin_lock_irqsave(&priv->lock, flags);
-   ic->in_use = false;
-   spin_unlock_irqrestore(&priv->lock, flags);
 }
 EXPORT_SYMBOL_GPL(ipu_ic_put);

-- 
1.9.1



[PATCH v4 2/4] gpu: ipu-v3: Add FSU channel linking support

2016-08-17 Thread Steve Longerbeam
Adds functions to link and unlink source channels to sink
channels in the FSU:

int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch);
int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch);

The channels numbers are usually IDMAC channels, but they can also be
channels that do not transfer data to or from memory. The following
convenience functions can be used in place of ipu_fsu_link/unlink()
when both source and sink channels are IDMAC channels:

int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink);
int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink);

So far the following links are supported:

IPUV3_CHANNEL_IC_PRP_ENC_MEM -> IPUV3_CHANNEL_MEM_ROT_ENC
PUV3_CHANNEL_IC_PRP_VF_MEM   -> IPUV3_CHANNEL_MEM_ROT_VF
IPUV3_CHANNEL_IC_PP_MEM  -> IPUV3_CHANNEL_MEM_ROT_PP
IPUV3_CHANNEL_CSI_DIRECT -> IPUV3_CHANNEL_CSI_VDI_PREV

More links can be added to the fsu_link_info[] array.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-common.c | 131 
 drivers/gpu/ipu-v3/ipu-prv.h|  27 +
 include/video/imx-ipu-v3.h  |  13 
 3 files changed, 171 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 9d3584b..891cbef 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -730,6 +730,137 @@ void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, 
bool vdi)
 }
 EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);

+
+/* Frame Synchronization Unit Channel Linking */
+
+struct fsu_link_reg_info {
+   int chno;
+   u32 reg;
+   u32 mask;
+   u32 val;
+};
+
+struct fsu_link_info {
+   struct fsu_link_reg_info src;
+   struct fsu_link_reg_info sink;
+};
+
+static const struct fsu_link_info fsu_link_info[] = {
+   {
+   .src  = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
+ FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC 
},
+   .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
+ FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC 
},
+   }, {
+   .src =  { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
+ FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
+   .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
+ FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
+   }, {
+   .src =  { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
+ FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
+   .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
+ FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
+   }, {
+   .src =  { IPUV3_CHANNEL_CSI_DIRECT, 0 },
+   .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
+ FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
+   },
+};
+
+static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
+{
+   int i;
+
+   for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
+   if (src == fsu_link_info[i].src.chno &&
+   sink == fsu_link_info[i].sink.chno)
+   return &fsu_link_info[i];
+   }
+
+   return NULL;
+}
+
+/*
+ * Links a source channel to a sink channel in the FSU.
+ */
+int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
+{
+   const struct fsu_link_info *link;
+   u32 src_reg, sink_reg;
+   unsigned long flags;
+
+   link = find_fsu_link_info(src_ch, sink_ch);
+   if (!link)
+   return -EINVAL;
+
+   spin_lock_irqsave(&ipu->lock, flags);
+
+   if (link->src.mask) {
+   src_reg = ipu_cm_read(ipu, link->src.reg);
+   src_reg &= ~link->src.mask;
+   src_reg |= link->src.val;
+   ipu_cm_write(ipu, src_reg, link->src.reg);
+   }
+
+   if (link->sink.mask) {
+   sink_reg = ipu_cm_read(ipu, link->sink.reg);
+   sink_reg &= ~link->sink.mask;
+   sink_reg |= link->sink.val;
+   ipu_cm_write(ipu, sink_reg, link->sink.reg);
+   }
+
+   spin_unlock_irqrestore(&ipu->lock, flags);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_fsu_link);
+
+/*
+ * Unlinks source and sink channels in the FSU.
+ */
+int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
+{
+   const struct fsu_link_info *link;
+   u32 src_reg, sink_reg;
+   unsigned long flags;
+
+   link = find_fsu_link_info(src_ch, sink_ch);
+   if (!link)
+   return -EINVAL;
+
+   spin_lock_irqsave(&ipu->lock, flags);
+
+   if (link->src.mask) {
+   src_reg = ipu_cm_read(ipu, link->src.reg);
+   src_reg &= ~link->src.mask;

Re: [PATCH] gpu: ipu-v3: Stop overwriting pdev->dev.of_node of child devices

2017-02-16 Thread Steve Longerbeam



On 02/16/2017 07:42 AM, Philipp Zabel wrote:

Setting dev->of_node changes the modalias and breaks module autoloading.
Since there is an of_node field in the platform data passed to child
devices, we don't even need this anymore.

Suggested-by: Russell King 
Signed-off-by: Philipp Zabel 
---
 drivers/gpu/ipu-v3/ipu-common.c | 6 --
 1 file changed, 6 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 97218af4fe75c..8368e6f766ee5 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -1238,12 +1238,6 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, 
unsigned long ipu_base)
platform_device_put(pdev);
goto err_register;
}
-
-   /*
-* Set of_node only after calling platform_device_add. Otherwise
-* the platform:imx-ipuv3-crtc modalias won't be used.
-*/
-   pdev->dev.of_node = of_node;
}

return 0;




Acked-by: Steve Longerbeam 
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH] gpu: ipu-v3: export ipu_csi_set_downsize

2017-02-16 Thread Steve Longerbeam



On 02/16/2017 03:40 AM, Philipp Zabel wrote:

This function will be used by the media drivers and needs to be exported
to allow them to be built as modules.

Reported-by: Russell King 
Fixes: 867341b95891 ("gpu: ipu-v3: add ipu_csi_set_downsize")
Signed-off-by: Philipp Zabel 
---
  drivers/gpu/ipu-v3/ipu-csi.c | 1 +
  1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index 63c7292f427a2..24e12b87a0cbe 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -544,6 +544,7 @@ void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, 
bool vert)
  
  	spin_unlock_irqrestore(&csi->lock, flags);

  }
+EXPORT_SYMBOL_GPL(ipu_csi_set_downsize);
  
  void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,

u32 r_value, u32 g_value, u32 b_value,


Acked-by: Steve Longerbeam 

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH] gpu: ipu-v3: vdic: include AUTO field order bit in ipu_vdi_set_field_order

2017-05-21 Thread Steve Longerbeam
The field order selection in VDIC_C register uses different bits
depending on whether the VDIC is receiving from a CSI ("AUTO") or
from memory ("MAN"). Since the VDIC cannot receive from both CSI
and memory at the same time, set or clear both field order bits to
cover both cases.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-vdi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-vdi.c b/drivers/gpu/ipu-v3/ipu-vdi.c
index f27bf5a..a663893 100644
--- a/drivers/gpu/ipu-v3/ipu-vdi.c
+++ b/drivers/gpu/ipu-v3/ipu-vdi.c
@@ -88,9 +88,9 @@ void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id 
std, u32 field)
 
reg = ipu_vdi_read(vdi, VDI_C);
if (top_field_0)
-   reg &= ~VDI_C_TOP_FIELD_MAN_1;
+   reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
else
-   reg |= VDI_C_TOP_FIELD_MAN_1;
+   reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
ipu_vdi_write(vdi, reg, VDI_C);
 
spin_unlock_irqrestore(&vdi->lock, flags);
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH] gpu: ipu-v3: Fix CSI selection for VDIC

2017-06-04 Thread Steve Longerbeam
From: Marek Vasut 

The description of the CSI_SEL bit in the i.MX6 reference manual is
incorrect. It states "This bit defines which CSI is the input to the
IC. This bit is effective only if IC_INPUT is bit cleared".

From experiment it was found this is in fact not correct. The CSI_SEL
bit selects which CSI is input to _both_ the VDIC _and_ the IC. If the
IC_INPUT bit is set so that the IC is receiving from the VDIC, the IC
ignores the CSI_SEL bit, but CSI_SEL still selects which CSI the VDIC
receives from in that case.

Signed-off-by: Marek Vasut 
Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-common.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 16d5568..2fb5f43 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -725,15 +725,16 @@ void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, 
bool vdi)
spin_lock_irqsave(&ipu->lock, flags);
 
val = ipu_cm_read(ipu, IPU_CONF);
-   if (vdi) {
+   if (vdi)
val |= IPU_CONF_IC_INPUT;
-   } else {
+   else
val &= ~IPU_CONF_IC_INPUT;
-   if (csi_id == 1)
-   val |= IPU_CONF_CSI_SEL;
-   else
-   val &= ~IPU_CONF_CSI_SEL;
-   }
+
+   if (csi_id == 1)
+   val |= IPU_CONF_CSI_SEL;
+   else
+   val &= ~IPU_CONF_CSI_SEL;
+
ipu_cm_write(ipu, val, IPU_CONF);
 
spin_unlock_irqrestore(&ipu->lock, flags);
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 02/11] gpu: ipu-csi: Swap fields according to input/output field types

2018-10-05 Thread Steve Longerbeam
The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-csi.c  | 132 +++---
 drivers/staging/media/imx/imx-media-csi.c |  13 +--
 include/video/imx-ipu-v3.h|   3 +-
 3 files changed, 97 insertions(+), 51 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index 954eefe144e2..759fcd724ff9 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,6 +325,15 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code,
return 0;
 }
 
+/* translate alternate field mode based on given standard */
+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
 /*
  * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
  */
@@ -374,22 +383,75 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
return 0;
 }
 
+static int ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt,
+  v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   }
+
+   ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
+
+   return 0;
+}
+
+
 int ipu_csi_init_interface(struct ipu_csi *csi,
   struct v4l2_mbus_config *mbus_cfg,
-  struct v4l2_mbus_framefmt *mbus_fmt)
+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt)
 {
struct ipu_csi_bus_config cfg;
unsigned long flags;
u32 width, height, data = 0;
+   v4l2_std_id std;
int ret;
 
-   ret = fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
+   ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
if (ret < 0)
return ret;
 
/* set default sensor frame width and height */
-   width = mbus_fmt->width;
-   height = mbus_fmt->height;
+   width = infmt->width;
+   height = infmt->height;
+   if (infmt->field == V4L2_FIELD_ALTERNATE)
+   height *= 2;
 
  

[PATCH v4 03/11] gpu: ipu-v3: Add planar support to interlaced scan

2018-10-05 Thread Steve Longerbeam
To support interlaced scan with planar formats, cpmem SLUV must
be programmed with the correct chroma line stride. For full and
partial planar 4:2:2 (YUV422P, NV16), chroma line stride must
be doubled. For full and partial planar 4:2:0 (YUV420, YVU420, NV12),
chroma line stride must _not_ be doubled, since a single chroma line
is shared by two luma lines.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c  | 26 +++--
 drivers/staging/media/imx/imx-ic-prpencvf.c |  3 ++-
 drivers/staging/media/imx/imx-media-csi.c   |  3 ++-
 include/video/imx-ipu-v3.h  |  3 ++-
 4 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index a9d2501500a1..d41df8034c5b 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -273,9 +273,10 @@ void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 
u_off, u32 v_off)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
 
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat)
 {
-   u32 ilo, sly;
+   u32 ilo, sly, sluv;
 
if (stride < 0) {
stride = -stride;
@@ -286,9 +287,30 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, 
int stride)
 
sly = (stride * 2) - 1;
 
+   switch (pixelformat) {
+   case V4L2_PIX_FMT_YUV420:
+   case V4L2_PIX_FMT_YVU420:
+   sluv = stride / 2 - 1;
+   break;
+   case V4L2_PIX_FMT_NV12:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_YUV422P:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_NV16:
+   sluv = stride * 2 - 1;
+   break;
+   default:
+   sluv = 0;
+   break;
+   }
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+   if (sluv)
+   ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c 
b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 28f41caba05d..af7224846bd5 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -412,7 +412,8 @@ static int prp_setup_channel(struct prp_priv *priv,
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field) &&
channel == priv->out_ch)
-   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline);
+   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline,
+ image.pix.pixelformat);
 
ret = ipu_ic_task_idma_init(priv->ic, channel,
image.pix.width, image.pix.height,
diff --git a/drivers/staging/media/imx/imx-media-csi.c 
b/drivers/staging/media/imx/imx-media-csi.c
index ad66f007d395..5e3aa4f3a1dd 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -512,7 +512,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field))
ipu_cpmem_interlaced_scan(priv->idmac_ch,
- image.pix.bytesperline);
+ image.pix.bytesperline,
+ image.pix.pixelformat);
 
ipu_idmac_set_double_buffer(priv->idmac_ch, true);
 
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index f44a35192313..e888c66b9d9d 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -255,7 +255,8 @@ void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int 
stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t 
buf);
 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v4 02/11] gpu: ipu-csi: Swap fields according to input/output field types

2018-10-09 Thread Steve Longerbeam

Hi Philipp,


On 10/05/2018 02:44 AM, Philipp Zabel wrote:

Hi Steve,

On Thu, 2018-10-04 at 11:53 -0700, Steve Longerbeam wrote:



+
+   /* framelines for NTSC / PAL */
+   height = (std & V4L2_STD_525_60) ? 525 : 625;

I think this is a bit convoluted. Instead of initializing std, then
possibly changing it, and then comparing to the inital value, and then
checking it again to determine the new height, why not just:

if (width == 720 && height == 480) {
std = V4L2_STD_NTSC;
height = 525;
} else if (width == 720 && height == 576) {
std = V4L2_STD_PAL;
height = 625;
} else {
dev_err(csi->ipu->dev,
"Unsupported interlaced video mode\n");
ret = -EINVAL;
goto out_unlock;
}

?


Yes that was a bit convoluted, fixed.



  
  	/*

 * if cycles is set, we need to handle this over multiple cycles as
 * generic/bayer data
 */
-   if (is_parallel_bus(&priv->upstream_ep) && incc->cycles) {
-   if_fmt.width *= incc->cycles;

If the input format width passed to ipu_csi_init_interface is not
multiplied by the number of cycles per pixel anymore, width in the
CSI_SENS_FRM_SIZE register will be set to the unmultiplied value from
infmt.
This breaks 779680e2e793 ("media: imx: add support for RGB565_2X8 on
parallel bus").


Oops, that was a mistake, thanks for catching, fixed.

Steve

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v4 03/11] gpu: ipu-v3: Add planar support to interlaced scan

2018-10-09 Thread Steve Longerbeam



On 10/05/2018 02:48 AM, Philipp Zabel wrote:

On Thu, 2018-10-04 at 11:53 -0700, Steve Longerbeam wrote:

To support interlaced scan with planar formats, cpmem SLUV must
be programmed with the correct chroma line stride. For full and
partial planar 4:2:2 (YUV422P, NV16), chroma line stride must
be doubled. For full and partial planar 4:2:0 (YUV420, YVU420, NV12),
chroma line stride must _not_ be doubled, since a single chroma line
is shared by two luma lines.

Signed-off-by: Steve Longerbeam 
---
  drivers/gpu/ipu-v3/ipu-cpmem.c  | 26 +++--
  drivers/staging/media/imx/imx-ic-prpencvf.c |  3 ++-
  drivers/staging/media/imx/imx-media-csi.c   |  3 ++-
  include/video/imx-ipu-v3.h  |  3 ++-
  4 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index a9d2501500a1..d41df8034c5b 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -273,9 +273,10 @@ void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 
u_off, u32 v_off)
  }
  EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
  
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)

+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat)
  {
-   u32 ilo, sly;
+   u32 ilo, sly, sluv;
  
  	if (stride < 0) {

stride = -stride;
@@ -286,9 +287,30 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, 
int stride)
  
  	sly = (stride * 2) - 1;
  
+	switch (pixelformat) {

+   case V4L2_PIX_FMT_YUV420:
+   case V4L2_PIX_FMT_YVU420:
+   sluv = stride / 2 - 1;
+   break;
+   case V4L2_PIX_FMT_NV12:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_YUV422P:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_NV16:
+   sluv = stride * 2 - 1;
+   break;
+   default:
+   sluv = 0;
+   break;
+   }
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+   if (sluv)
+   ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
  };
  EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);

[...]

Reviewed-by: Philipp Zabel 

and

Acked-by: Philipp Zabel 

to be merged with the rest of the series via the media tree. I'll take
care not to introduce nontrivial conflicts in imx-drm.


Ok thanks.

Hans, for v5 I will just include the two IPU patches as before. As Philipp
stated, he is OK with merging them to the media tree (after his ack of
course), along with the rest of the patches in this series.

Steve


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v5 02/12] gpu: ipu-csi: Swap fields according to input/output field types

2018-10-16 Thread Steve Longerbeam
The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
---
Changes since v4:
- Cleaned up some convoluted code in ipu_csi_init_interface(), suggested
  by Philipp Zabel.
- Fixed a regression in csi_setup(), caught by Philipp.
---
 drivers/gpu/ipu-v3/ipu-csi.c  | 119 +++---
 drivers/staging/media/imx/imx-media-csi.c |  17 +---
 include/video/imx-ipu-v3.h|   3 +-
 3 files changed, 88 insertions(+), 51 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index aa0e30a2ba18..4a15e513fa05 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,6 +325,15 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code,
return 0;
 }
 
+/* translate alternate field mode based on given standard */
+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
 /*
  * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
  */
@@ -374,22 +383,75 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
return 0;
 }
 
+static int ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt,
+  v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   }
+
+   ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
+
+   return 0;
+}
+
+
 int ipu_csi_init_interface(struct ipu_csi *csi,
   struct v4l2_mbus_config *mbus_cfg,
-  struct v4l2_mbus_framefmt *mbus_fmt)
+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt)
 {
struct ipu_csi_bus_config cfg;
unsigned long flags;
u32 width, height, data = 0;
+   v4l2_std_id std;
int ret;
 
-   ret = fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
+   ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
if (ret < 0)
return ret;
 
/* set default sensor frame width and height */
-   width = mbus_fmt->width;
-   height = mbus_fmt->height;
+

[PATCH] gpu: ipu-v3: Fix CSI offsets for imx53

2018-10-16 Thread Steve Longerbeam
The CSI offsets are wrong for both CSI0 and CSI1. They are at
physical address 0x1e03 and 0x1e038000 respectively.

Fixes: 2ffd48f2e7 ("gpu: ipu-v3: Add Camera Sensor Interface unit")

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-common.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 48685cddbad1..f487f25ed577 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -910,8 +910,8 @@ static struct ipu_devtype ipu_type_imx53 = {
.cpmem_ofs = 0x0700,
.srm_ofs = 0x0704,
.tpm_ofs = 0x0706,
-   .csi0_ofs = 0x0703,
-   .csi1_ofs = 0x07038000,
+   .csi0_ofs = 0x0603,
+   .csi1_ofs = 0x06038000,
.ic_ofs = 0x0602,
.disp0_ofs = 0x0604,
.disp1_ofs = 0x06048000,
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v5 03/12] gpu: ipu-v3: Add planar support to interlaced scan

2018-10-16 Thread Steve Longerbeam
To support interlaced scan with planar formats, cpmem SLUV must
be programmed with the correct chroma line stride. For full and
partial planar 4:2:2 (YUV422P, NV16), chroma line stride must
be doubled. For full and partial planar 4:2:0 (YUV420, YVU420, NV12),
chroma line stride must _not_ be doubled, since a single chroma line
is shared by two luma lines.

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
Acked-by: Philipp Zabel 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c  | 26 +++--
 drivers/staging/media/imx/imx-ic-prpencvf.c |  3 ++-
 drivers/staging/media/imx/imx-media-csi.c   |  3 ++-
 include/video/imx-ipu-v3.h  |  3 ++-
 4 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index a9d2501500a1..d41df8034c5b 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -273,9 +273,10 @@ void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 
u_off, u32 v_off)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
 
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat)
 {
-   u32 ilo, sly;
+   u32 ilo, sly, sluv;
 
if (stride < 0) {
stride = -stride;
@@ -286,9 +287,30 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, 
int stride)
 
sly = (stride * 2) - 1;
 
+   switch (pixelformat) {
+   case V4L2_PIX_FMT_YUV420:
+   case V4L2_PIX_FMT_YVU420:
+   sluv = stride / 2 - 1;
+   break;
+   case V4L2_PIX_FMT_NV12:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_YUV422P:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_NV16:
+   sluv = stride * 2 - 1;
+   break;
+   default:
+   sluv = 0;
+   break;
+   }
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+   if (sluv)
+   ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c 
b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 28f41caba05d..af7224846bd5 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -412,7 +412,8 @@ static int prp_setup_channel(struct prp_priv *priv,
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field) &&
channel == priv->out_ch)
-   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline);
+   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline,
+ image.pix.pixelformat);
 
ret = ipu_ic_task_idma_init(priv->ic, channel,
image.pix.width, image.pix.height,
diff --git a/drivers/staging/media/imx/imx-media-csi.c 
b/drivers/staging/media/imx/imx-media-csi.c
index 7ecbd4d76d09..4aa20ae72608 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -512,7 +512,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field))
ipu_cpmem_interlaced_scan(priv->idmac_ch,
- image.pix.bytesperline);
+ image.pix.bytesperline,
+ image.pix.pixelformat);
 
ipu_idmac_set_double_buffer(priv->idmac_ch, true);
 
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index f44a35192313..e888c66b9d9d 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -255,7 +255,8 @@ void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int 
stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t 
buf);
 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 2/2] staging: vboxvideo: Add page-flip support

2018-07-23 Thread Steve Longerbeam
Adds crtc page-flip support by passing the new requested framebuffer
to vbox_crtc_do_set_base().

Note there is no attempt to support vblank interrupts, it's not
not known how to do this in VBOX or if it is even possible. Since
this page-flip implementation does not try to sync the page-flip
to vertical blanking, tearing effects are possible.

Signed-off-by: Steve Longerbeam 
---
 drivers/staging/vboxvideo/vbox_mode.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/drivers/staging/vboxvideo/vbox_mode.c 
b/drivers/staging/vboxvideo/vbox_mode.c
index 688e80d..285d8ad 100644
--- a/drivers/staging/vboxvideo/vbox_mode.c
+++ b/drivers/staging/vboxvideo/vbox_mode.c
@@ -308,6 +308,31 @@ static int vbox_crtc_mode_set(struct drm_crtc *crtc,
return ret;
 }
 
+static int vbox_crtc_page_flip(struct drm_crtc *crtc,
+  struct drm_framebuffer *fb,
+  struct drm_pending_vblank_event *event,
+  uint32_t page_flip_flags,
+  struct drm_modeset_acquire_ctx *ctx)
+{
+   struct vbox_private *vbox = crtc->dev->dev_private;
+   struct drm_device *drm = vbox->dev;
+   unsigned long flags;
+   int rc;
+
+   rc = vbox_crtc_do_set_base(crtc, CRTC_FB(crtc), fb, 0, 0);
+   if (rc)
+   return rc;
+
+   spin_lock_irqsave(&drm->event_lock, flags);
+
+   if (event)
+   drm_crtc_send_vblank_event(crtc, event);
+
+   spin_unlock_irqrestore(&drm->event_lock, flags);
+
+   return 0;
+}
+
 static void vbox_crtc_disable(struct drm_crtc *crtc)
 {
 }
@@ -346,6 +371,7 @@ static const struct drm_crtc_funcs vbox_crtc_funcs = {
.reset = vbox_crtc_reset,
.set_config = drm_crtc_helper_set_config,
/* .gamma_set = vbox_crtc_gamma_set, */
+   .page_flip = vbox_crtc_page_flip,
.destroy = vbox_crtc_destroy,
 };
 
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 0/2] staging: vboxvideo: Add page-flip support

2018-07-23 Thread Steve Longerbeam
Adds crtc page-flip support by passing the new requested framebuffer
to vbox_crtc_do_set_base().

There is no attempt to support vblank interrupts, so this page-flip
implementation does not try to sync the page-flip to vertical blanking,
so expect tearing effects. Is it possible to access the host vblank
intervals in VBOX?


Steve Longerbeam (2):
  staging: vboxvideo: Pass a new framebuffer to vbox_crtc_do_set_base
  staging: vboxvideo: Add page-flip support

 drivers/staging/vboxvideo/vbox_mode.c | 34 +++---
 1 file changed, 31 insertions(+), 3 deletions(-)

-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 1/2] staging: vboxvideo: Pass a new framebuffer to vbox_crtc_do_set_base

2018-07-23 Thread Steve Longerbeam
This modifies vbox_crtc_do_set_base() to take a new framebuffer to
be activated, instead of the existing framebuffer attached to the crtc.
This change allows the function to be given the new framebuffer from
a page-flip request.

Signed-off-by: Steve Longerbeam 
---
 drivers/staging/vboxvideo/vbox_mode.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/vboxvideo/vbox_mode.c 
b/drivers/staging/vboxvideo/vbox_mode.c
index b265fe9..688e80d 100644
--- a/drivers/staging/vboxvideo/vbox_mode.c
+++ b/drivers/staging/vboxvideo/vbox_mode.c
@@ -222,7 +222,9 @@ static bool vbox_set_up_input_mapping(struct vbox_private 
*vbox)
 }
 
 static int vbox_crtc_do_set_base(struct drm_crtc *crtc,
-struct drm_framebuffer *old_fb, int x, int y)
+struct drm_framebuffer *old_fb,
+struct drm_framebuffer *new_fb,
+int x, int y)
 {
struct vbox_private *vbox = crtc->dev->dev_private;
struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
@@ -245,7 +247,7 @@ static int vbox_crtc_do_set_base(struct drm_crtc *crtc,
vbox_bo_unreserve(bo);
}
 
-   vbox_fb = to_vbox_framebuffer(CRTC_FB(crtc));
+   vbox_fb = to_vbox_framebuffer(new_fb);
obj = vbox_fb->obj;
bo = gem_to_vbox_bo(obj);
 
@@ -281,7 +283,7 @@ static int vbox_crtc_do_set_base(struct drm_crtc *crtc,
 static int vbox_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
   struct drm_framebuffer *old_fb)
 {
-   return vbox_crtc_do_set_base(crtc, old_fb, x, y);
+   return vbox_crtc_do_set_base(crtc, old_fb, CRTC_FB(crtc), x, y);
 }
 
 static int vbox_crtc_mode_set(struct drm_crtc *crtc,
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 4.19 regression fix 2/2] staging: vboxvideo: Change address of scanout buffer on page-flip

2018-09-11 Thread Steve Longerbeam

Hi Hans,


On 09/10/2018 11:30 AM, Hans de Goede wrote:

Commit 2408898e3b6c ("staging: vboxvideo: Add page-flip support") only
calls vbox_crtc_do_set_base() on page-flips, but despite that function's
name it only pins the new fb, unpins the old fb and sets
vbox_crtc->fb_offset. It does not program the hardware to scan out at the
new vbox_crtc->fb_offset value.


Has that always been the case of vbox_crtc_do_set_base()? Or was
there a recent commit that changed that behavior?

I tested this patch using a Weston EGL mock navigation test app around
4.14 time-frame, that exercises page flip and it was scanning out the
new fb, but maybe what I was looking at was a scan-out of an old/now stale
fb from a previous page-flip.

In any case thanks for fixing.

Steve


This was causing only every other frame (assuming page-flipping between 2
buffers) to be shown since we kept scanning out of the old (now unpinned!)
buffer.

This commit fixes this by adding code to vbox_crtc_page_flip() to tell
the hardware to scanout from the new fb_offset.

Fixes: 2408898e3b6c ("staging: vboxvideo: Add page-flip support")
Cc: Steve Longerbeam 
Signed-off-by: Hans de Goede 
---
  drivers/staging/vboxvideo/vbox_mode.c | 5 +
  1 file changed, 5 insertions(+)

diff --git a/drivers/staging/vboxvideo/vbox_mode.c 
b/drivers/staging/vboxvideo/vbox_mode.c
index a83eac8668d0..79836c8fb909 100644
--- a/drivers/staging/vboxvideo/vbox_mode.c
+++ b/drivers/staging/vboxvideo/vbox_mode.c
@@ -323,6 +323,11 @@ static int vbox_crtc_page_flip(struct drm_crtc *crtc,
if (rc)
return rc;
  
+	mutex_lock(&vbox->hw_mutex);

+   vbox_set_view(crtc);
+   vbox_do_modeset(crtc, &crtc->mode);
+   mutex_unlock(&vbox->hw_mutex);
+
spin_lock_irqsave(&drm->event_lock, flags);
  
  	if (event)


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 05/14] gpu: ipu-v3: Allow negative offsets for interlaced scanning

2018-08-02 Thread Steve Longerbeam
From: Philipp Zabel 

The IPU also supports interlaced buffers that start with the bottom field.
To achieve this, the the base address EBA has to be increased by a stride
length and the interlace offset ILO has to be set to the negative stride.

Signed-off-by: Philipp Zabel 
Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index e68e473..8cd9e37 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -269,9 +269,20 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
 
 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
 {
+   u32 ilo, sly;
+
+   if (stride < 0) {
+   stride = -stride;
+   ilo = 0x10 - (stride / 8);
+   } else {
+   ilo = stride / 8;
+   }
+
+   sly = (stride * 2) - 1;
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
-   ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8);
-   ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1);
+   ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
+   ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 04/14] gpu: ipu-v3: Fix U/V offset macros for planar 4:2:0

2018-08-02 Thread Steve Longerbeam
The U and V offset macros for planar 4:2:0 (U_OFFSET, V_OFFSET, and
UV_OFFSET), are not correct. The height component to the offset was
calculated as:

(pix->width * y / 4)

But this does not produce correct offsets for odd values of y (luma
line #). The luma line # must be decimated by two to produce the
correct U/V line #, so the correct formula is:

(pix->width * (y / 2) / 2)

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 9f2d9ec..e68e473 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -530,17 +530,17 @@ static const struct ipu_rgb def_bgra_16 = {
 
 #define Y_OFFSET(pix, x, y)((x) + pix->width * (y))
 #define U_OFFSET(pix, x, y)((pix->width * pix->height) +   \
-(pix->width * (y) / 4) + (x) / 2)
+(pix->width * ((y) / 2) / 2) + (x) / 2)
 #define V_OFFSET(pix, x, y)((pix->width * pix->height) +   \
 (pix->width * pix->height / 4) +   \
-(pix->width * (y) / 4) + (x) / 2)
+(pix->width * ((y) / 2) / 2) + (x) / 2)
 #define U2_OFFSET(pix, x, y)   ((pix->width * pix->height) +   \
 (pix->width * (y) / 2) + (x) / 2)
 #define V2_OFFSET(pix, x, y)   ((pix->width * pix->height) +   \
 (pix->width * pix->height / 2) +   \
 (pix->width * (y) / 2) + (x) / 2)
 #define UV_OFFSET(pix, x, y)   ((pix->width * pix->height) +   \
-(pix->width * (y) / 2) + (x))
+(pix->width * ((y) / 2)) + (x))
 #define UV2_OFFSET(pix, x, y)  ((pix->width * pix->height) +   \
 (pix->width * y) + (x))
 
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 02/14] gpu: ipu-csi: Check for field type alternate

2018-08-02 Thread Steve Longerbeam
When the CSI is receiving from a bt.656 bus, include a check for
field type 'alternate' when determining whether to set CSI clock
mode to CCIR656_INTERLACED or CCIR656_PROGRESSIVE.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-csi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index caa05b0..5450a2d 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -339,7 +339,8 @@ static void fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
break;
case V4L2_MBUS_BT656:
csicfg->ext_vsync = 0;
-   if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field))
+   if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
+   mbus_fmt->field == V4L2_FIELD_ALTERNATE)
csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
else
csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 06/14] gpu: ipu-v3: Add planar support to interlaced scan

2018-08-02 Thread Steve Longerbeam
To support interlaced scan with planar formats, cpmem SLUV must
be programmed with the correct chroma line stride. For full and
partial planar 4:2:2 (YUV422P, NV16), chroma line stride must
be doubled. For full and partial planar 4:2:0 (YUV420, YVU420, NV12),
chroma line stride must _not_ be doubled, since a single chroma line
is shared by two luma lines.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c  | 26 --
 drivers/staging/media/imx/imx-ic-prpencvf.c |  3 ++-
 drivers/staging/media/imx/imx-media-csi.c   |  3 ++-
 include/video/imx-ipu-v3.h  |  3 ++-
 4 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 8cd9e37..eae0f63 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -267,9 +267,10 @@ void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 
u_off, u32 v_off)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
 
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat)
 {
-   u32 ilo, sly;
+   u32 ilo, sly, sluv;
 
if (stride < 0) {
stride = -stride;
@@ -280,9 +281,30 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, 
int stride)
 
sly = (stride * 2) - 1;
 
+   switch (pixelformat) {
+   case V4L2_PIX_FMT_YUV420:
+   case V4L2_PIX_FMT_YVU420:
+   sluv = stride / 2 - 1;
+   break;
+   case V4L2_PIX_FMT_NV12:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_YUV422P:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_NV16:
+   sluv = stride * 2 - 1;
+   break;
+   default:
+   sluv = 0;
+   break;
+   }
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+   if (sluv)
+   ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c 
b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 28f41ca..af72248 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -412,7 +412,8 @@ static int prp_setup_channel(struct prp_priv *priv,
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field) &&
channel == priv->out_ch)
-   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline);
+   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline,
+ image.pix.pixelformat);
 
ret = ipu_ic_task_idma_init(priv->ic, channel,
image.pix.width, image.pix.height,
diff --git a/drivers/staging/media/imx/imx-media-csi.c 
b/drivers/staging/media/imx/imx-media-csi.c
index 2fdd21d..1c468ec 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -509,7 +509,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field))
ipu_cpmem_interlaced_scan(priv->idmac_ch,
- image.pix.bytesperline);
+ image.pix.bytesperline,
+ image.pix.pixelformat);
 
ipu_idmac_set_double_buffer(priv->idmac_ch, true);
 
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index f44a351..e888c66 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -255,7 +255,8 @@ void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int 
stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t 
buf);
 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
-- 
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 03/14] gpu: ipu-csi: Swap fields according to input/output field types

2018-08-02 Thread Steve Longerbeam
The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-csi.c  | 133 +-
 drivers/staging/media/imx/imx-media-csi.c |  13 +--
 include/video/imx-ipu-v3.h|   3 +-
 3 files changed, 98 insertions(+), 51 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index 5450a2d..7a845c9 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -315,6 +315,15 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code)
return 0;
 }
 
+/* translate alternate field mode based on given standard */
+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
 /*
  * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
  */
@@ -358,19 +367,73 @@ static void fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
}
 }
 
+static int ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt,
+  v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   }
+
+   ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
+
+   return 0;
+}
+
+
 int ipu_csi_init_interface(struct ipu_csi *csi,
   struct v4l2_mbus_config *mbus_cfg,
-  struct v4l2_mbus_framefmt *mbus_fmt)
+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt)
 {
struct ipu_csi_bus_config cfg;
unsigned long flags;
u32 width, height, data = 0;
+   v4l2_std_id std;
+   int ret = 0;
 
-   fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
+   fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
 
/* set default sensor frame width and height */
-   width = mbus_fmt->width;
-   height = mbus_fmt->height;
+   width = infmt->width;
+   height = infmt->height;
+   if (infmt->field == V4L2_FIELD_ALTERNATE)
+   height *= 2;
 
/* Set the CSI_SENS_CONF register remaining fields */
data |= cfg.data_wi

Re: [PATCH v3 05/14] gpu: ipu-v3: Allow negative offsets for interlaced scanning

2018-08-06 Thread Steve Longerbeam

Hi Philipp,


On 08/02/2018 02:46 AM, Philipp Zabel wrote:

On Wed, 2018-08-01 at 12:12 -0700, Steve Longerbeam wrote:

From: Philipp Zabel 

The IPU also supports interlaced buffers that start with the bottom field.
To achieve this, the the base address EBA has to be increased by a stride
length and the interlace offset ILO has to be set to the negative stride.

Signed-off-by: Philipp Zabel 
Signed-off-by: Steve Longerbeam 
---
  drivers/gpu/ipu-v3/ipu-cpmem.c | 15 +--
  1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index e68e473..8cd9e37 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -269,9 +269,20 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
  
  void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)

  {
+   u32 ilo, sly;
+
+   if (stride < 0) {
+   stride = -stride;
+   ilo = 0x10 - (stride / 8);
+   } else {
+   ilo = stride / 8;
+   }
+
+   sly = (stride * 2) - 1;
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
-   ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8);
-   ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1);
+   ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
+   ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
  };
  EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);

This patch is merged in drm-next: 4e3c5d7e05be ("gpu: ipu-v3: Allow
negative offsets for interlaced scanning")


I don't see it in drm-next, but I see it in linux-next/master. Thanks.

Steve

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v3 02/14] gpu: ipu-csi: Check for field type alternate

2018-08-06 Thread Steve Longerbeam

Hi Philipp,


On 08/02/2018 02:42 AM, Philipp Zabel wrote:

Hi Steve,

On Wed, 2018-08-01 at 12:12 -0700, Steve Longerbeam wrote:

When the CSI is receiving from a bt.656 bus, include a check for
field type 'alternate' when determining whether to set CSI clock
mode to CCIR656_INTERLACED or CCIR656_PROGRESSIVE.

Signed-off-by: Steve Longerbeam 
---
  drivers/gpu/ipu-v3/ipu-csi.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index caa05b0..5450a2d 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -339,7 +339,8 @@ static void fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
break;
case V4L2_MBUS_BT656:
csicfg->ext_vsync = 0;
-   if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field))
+   if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
+   mbus_fmt->field == V4L2_FIELD_ALTERNATE)
csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
else
csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;

this patch is already merged in v4.18-rc7.


Ah, I just noticed that after a fetch from kernel.org, thanks.

Steve


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 0/2] staging: vboxvideo: Add page-flip support

2018-08-11 Thread Steve Longerbeam



On 08/06/2018 01:34 AM, Daniel Vetter wrote:

On Fri, Jul 20, 2018 at 10:17:29AM -0700, Steve Longerbeam wrote:

Adds crtc page-flip support by passing the new requested framebuffer
to vbox_crtc_do_set_base().

There is no attempt to support vblank interrupts, so this page-flip
implementation does not try to sync the page-flip to vertical blanking,
so expect tearing effects. Is it possible to access the host vblank
intervals in VBOX?

I think it'd be great to move vboxvideo over to atomic instead, which is
required for destaging anyway, and would give you page flip support for
free.


Hi Daniel, yes I agree vboxvideo needs to move to the DRM atomic
framework.

Steve





Steve Longerbeam (2):
   staging: vboxvideo: Pass a new framebuffer to vbox_crtc_do_set_base
   staging: vboxvideo: Add page-flip support

  drivers/staging/vboxvideo/vbox_mode.c | 34 +++---
  1 file changed, 31 insertions(+), 3 deletions(-)

--
2.7.4

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 0/2] staging: vboxvideo: Add page-flip support

2018-08-31 Thread Steve Longerbeam

Hi all,

On 08/07/2018 02:57 PM, Steve Longerbeam wrote:



On 08/06/2018 01:34 AM, Daniel Vetter wrote:

On Fri, Jul 20, 2018 at 10:17:29AM -0700, Steve Longerbeam wrote:

Adds crtc page-flip support by passing the new requested framebuffer
to vbox_crtc_do_set_base().

There is no attempt to support vblank interrupts, so this page-flip
implementation does not try to sync the page-flip to vertical blanking,
so expect tearing effects. Is it possible to access the host vblank
intervals in VBOX?

I think it'd be great to move vboxvideo over to atomic instead, which is
required for destaging anyway, and would give you page flip support for
free.


Hi Daniel, yes I agree vboxvideo needs to move to the DRM atomic
framework.



Irrespective of moving vboxvideo to atomic framework, I still need to get an
answer to the question, is it possible to access the host vblank 
intervals in
order to sync page-flip to vblank, to prevent tearing. Is this possible 
somehow,

perhaps by calling into the VBOX hypervisor?

Thanks,
Steve


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 2/3] gpu: ipu-v3: ipu-ic: Add support for BT.709 encoding

2019-02-04 Thread Steve Longerbeam
Pass v4l2 encoding enum to the ipu_ic task init functions, and add
support for the BT.709 encoding and inverse encoding matrices.

Reported-by: Tim Harvey 
Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 67 ++---
 drivers/gpu/ipu-v3/ipu-image-convert.c  |  1 +
 drivers/staging/media/imx/imx-ic-prpencvf.c |  4 +-
 include/video/imx-ipu-v3.h  |  5 +-
 4 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 35ae86ff0585..63362b4fff81 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -199,6 +199,23 @@ static const struct ic_csc_params ic_csc_rgb2ycbcr_bt601 = 
{
.scale = 1,
 };
 
+/*
+ * BT.709 encoding from RGB full range to YUV limited range:
+ *
+ * Y = R *  .2126 + G *  .7152 + B *  .0722;
+ * U = R * -.1146 + G * -.3854 + B *  .5000 + 128.;
+ * V = R *  .5000 + G * -.4542 + B * -.0458 + 128.;
+ */
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt709 = {
+   .coeff = {
+   { 54, 183, 18 },
+   { 483, 413, 128 },
+   { 128, 396, 500 },
+   },
+   .offset = { 0, 512, 512 },
+   .scale = 1,
+};
+
 /* transparent RGB->RGB matrix for graphics combining */
 static const struct ic_csc_params ic_csc_rgb2rgb = {
.coeff = {
@@ -226,12 +243,31 @@ static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 
= {
.scale = 2,
 };
 
+/*
+ * Inverse BT.709 encoding from YUV limited range to RGB full range:
+ *
+ * R = (1. * (Y - 16)) + (1.5748 * (Cr - 128));
+ * G = (1. * (Y - 16)) - (0.1873 * (Cb - 128)) - (0.4681 * (Cr - 128));
+ * B = (1. * (Y - 16)) + (1.8556 * (Cb - 128);
+ */
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt709 = {
+   .coeff = {
+   { 128, 0, 202 },
+   { 128, 488, 452 },
+   { 128, 238, 0 },
+   },
+   .offset = { -435, 136, -507 },
+   .scale = 2,
+};
+
 static int init_csc(struct ipu_ic *ic,
enum ipu_color_space inf,
enum ipu_color_space outf,
+   enum v4l2_ycbcr_encoding encoding,
int csc_index)
 {
struct ipu_ic_priv *priv = ic->priv;
+   const struct ic_csc_params *params_rgb2yuv, *params_yuv2rgb;
const struct ic_csc_params *params;
u32 __iomem *base;
const u16 (*c)[3];
@@ -241,10 +277,24 @@ static int init_csc(struct ipu_ic *ic,
base = (u32 __iomem *)
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
+   switch (encoding) {
+   case V4L2_YCBCR_ENC_601:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt709;
+   break;
+   default:
+   dev_err(priv->ipu->dev, "Unsupported YCbCr encoding\n");
+   return -EINVAL;
+   }
+
if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_ycbcr2rgb_bt601;
+   params = params_yuv2rgb;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_rgb2ycbcr_bt601;
+   params = params_rgb2yuv;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
params = &ic_csc_rgb2rgb;
else {
@@ -391,6 +441,7 @@ EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
 
 int ipu_ic_task_graphics_init(struct ipu_ic *ic,
  enum ipu_color_space in_g_cs,
+ enum v4l2_ycbcr_encoding encoding,
  bool galpha_en, u32 galpha,
  bool colorkey_en, u32 colorkey)
 {
@@ -409,7 +460,7 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic,
if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
/* need transparent CSC1 conversion */
ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
-  IPUV3_COLORSPACE_RGB, 0);
+  IPUV3_COLORSPACE_RGB, encoding, 0);
if (ret)
goto unlock;
}
@@ -417,7 +468,7 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic,
ic->g_in_cs = in_g_cs;
 
if (ic->g_in_cs != ic->out_cs) {
-   ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
+   ret = init_csc(ic, ic->g_in_cs, ic->out_cs, encoding, 1);
if (ret)
goto unlock;
}
@@ -451,6 +502,7 @@ int ipu_ic_task_init_rsc(struct ipu_ic *ic,
 int out_width, int out_height,
 enum ipu_color_sp

[PATCH 1/3] gpu: ipu-v3: ipu-ic: Rename yuv2rgb encoding matrices

2019-02-04 Thread Steve Longerbeam
The ycbcr2rgb and inverse rgb2ycbcr matrices define the BT.601 encoding
coefficients, so rename them to indicate that. And add some comments
to make clear these are BT.601 coefficients encoding between YUV limited
range and RGB full range. No functional changes.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 594c3cbc8291..35ae86ff0585 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -183,11 +183,13 @@ struct ic_csc_params {
 };
 
 /*
+ * BT.601 encoding from RGB full range to YUV limited range:
+ *
  * Y = R *  .299 + G *  .587 + B *  .114;
  * U = R * -.169 + G * -.332 + B *  .500 + 128.;
  * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
  */
-static const struct ic_csc_params ic_csc_rgb2ycbcr = {
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt601 = {
.coeff = {
{ 77, 150, 29 },
{ 469, 427, 128 },
@@ -208,11 +210,13 @@ static const struct ic_csc_params ic_csc_rgb2rgb = {
 };
 
 /*
+ * Inverse BT.601 encoding from YUV limited range to RGB full range:
+ *
  * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
  * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
  * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
  */
-static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 = {
.coeff = {
{ 149, 0, 204 },
{ 149, 462, 408 },
@@ -238,9 +242,9 @@ static int init_csc(struct ipu_ic *ic,
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_ycbcr2rgb;
+   params = &ic_csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_rgb2ycbcr;
+   params = &ic_csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
params = &ic_csc_rgb2rgb;
else {
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 2/4] gpu: ipu-v3: ipu-ic: Simplify selection of encoding matrix

2019-02-09 Thread Steve Longerbeam
Simplify the selection of the Y'CbCr encoding matrices in init_csc().
A side-effect of this change is that init_csc() now allows YUV->YUV
using the identity matrix, intead of returning error.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 12 
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 3ef61f0b509b..e459615a49a1 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -244,16 +244,12 @@ static int init_csc(struct ipu_ic *ic,
base = (u32 __iomem *)
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
-   if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
+   if (inf == outf)
+   params = &ic_csc_identity;
+   else if (inf == IPUV3_COLORSPACE_YUV)
params = &ic_csc_ycbcr2rgb_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+   else
params = &ic_csc_rgb2ycbcr_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_identity;
-   else {
-   dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
-   return -EINVAL;
-   }
 
/* Cast to unsigned */
c = (const u16 (*)[3])params->coeff;
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 1/4] gpu: ipu-v3: ipu-ic: Rename yuv2rgb encoding matrices

2019-02-09 Thread Steve Longerbeam
The ycbcr2rgb and inverse rgb2ycbcr matrices define the BT.601 encoding
coefficients, so rename them to indicate that. And add some comments
to make clear these are BT.601 coefficients encoding between YUV limited
range and RGB full range. The ic_csc_rgb2rgb matrix is just an identity
matrix, so rename to ic_csc_identity. No functional changes.

Signed-off-by: Steve Longerbeam 
---
Changes in v2:
- rename ic_csc_rgb2rgb matrix to ic_csc_identity.
---
 drivers/gpu/ipu-v3/ipu-ic.c | 21 ++---
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 594c3cbc8291..3ef61f0b509b 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -183,11 +183,13 @@ struct ic_csc_params {
 };
 
 /*
+ * BT.601 encoding from RGB full range to YUV limited range:
+ *
  * Y = R *  .299 + G *  .587 + B *  .114;
  * U = R * -.169 + G * -.332 + B *  .500 + 128.;
  * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
  */
-static const struct ic_csc_params ic_csc_rgb2ycbcr = {
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt601 = {
.coeff = {
{ 77, 150, 29 },
{ 469, 427, 128 },
@@ -197,8 +199,11 @@ static const struct ic_csc_params ic_csc_rgb2ycbcr = {
.scale = 1,
 };
 
-/* transparent RGB->RGB matrix for graphics combining */
-static const struct ic_csc_params ic_csc_rgb2rgb = {
+/*
+ * identity matrix, used for transparent RGB->RGB graphics
+ * combining.
+ */
+static const struct ic_csc_params ic_csc_identity = {
.coeff = {
{ 128, 0, 0 },
{ 0, 128, 0 },
@@ -208,11 +213,13 @@ static const struct ic_csc_params ic_csc_rgb2rgb = {
 };
 
 /*
+ * Inverse BT.601 encoding from YUV limited range to RGB full range:
+ *
  * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
  * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
  * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
  */
-static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 = {
.coeff = {
{ 149, 0, 204 },
{ 149, 462, 408 },
@@ -238,11 +245,11 @@ static int init_csc(struct ipu_ic *ic,
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_ycbcr2rgb;
+   params = &ic_csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_rgb2ycbcr;
+   params = &ic_csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_rgb2rgb;
+   params = &ic_csc_identity;
else {
dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
return -EINVAL;
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 3/4] gpu: ipu-v3: ipu-ic: Add support for BT.709 encoding

2019-02-09 Thread Steve Longerbeam
Pass v4l2 encoding enum to the ipu_ic task init functions, and add
support for the BT.709 encoding and inverse encoding matrices.

Reported-by: Tim Harvey 
Signed-off-by: Steve Longerbeam 
---
Changes in v4:
- fix compile error.
Chnges in v3:
- none.
Changes in v2:
- only return "Unsupported YCbCr encoding" error if inf != outf,
  since if inf == outf, the identity matrix can be used. Reported
  by Tim Harvey.
---
 drivers/gpu/ipu-v3/ipu-ic.c | 71 +++--
 drivers/gpu/ipu-v3/ipu-image-convert.c  |  1 +
 drivers/staging/media/imx/imx-ic-prpencvf.c |  4 +-
 include/video/imx-ipu-v3.h  |  5 +-
 4 files changed, 71 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index e459615a49a1..c5f83d7e357f 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -212,6 +212,23 @@ static const struct ic_csc_params ic_csc_identity = {
.scale = 2,
 };
 
+/*
+ * BT.709 encoding from RGB full range to YUV limited range:
+ *
+ * Y = R *  .2126 + G *  .7152 + B *  .0722;
+ * U = R * -.1146 + G * -.3854 + B *  .5000 + 128.;
+ * V = R *  .5000 + G * -.4542 + B * -.0458 + 128.;
+ */
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt709 = {
+   .coeff = {
+   { 54, 183, 18 },
+   { 483, 413, 128 },
+   { 128, 396, 500 },
+   },
+   .offset = { 0, 512, 512 },
+   .scale = 1,
+};
+
 /*
  * Inverse BT.601 encoding from YUV limited range to RGB full range:
  *
@@ -229,12 +246,31 @@ static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 
= {
.scale = 2,
 };
 
+/*
+ * Inverse BT.709 encoding from YUV limited range to RGB full range:
+ *
+ * R = (1. * (Y - 16)) + (1.5748 * (Cr - 128));
+ * G = (1. * (Y - 16)) - (0.1873 * (Cb - 128)) - (0.4681 * (Cr - 128));
+ * B = (1. * (Y - 16)) + (1.8556 * (Cb - 128);
+ */
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt709 = {
+   .coeff = {
+   { 128, 0, 202 },
+   { 128, 488, 452 },
+   { 128, 238, 0 },
+   },
+   .offset = { -435, 136, -507 },
+   .scale = 2,
+};
+
 static int init_csc(struct ipu_ic *ic,
enum ipu_color_space inf,
enum ipu_color_space outf,
+   enum v4l2_ycbcr_encoding encoding,
int csc_index)
 {
struct ipu_ic_priv *priv = ic->priv;
+   const struct ic_csc_params *params_rgb2yuv, *params_yuv2rgb;
const struct ic_csc_params *params;
u32 __iomem *base;
const u16 (*c)[3];
@@ -244,12 +280,30 @@ static int init_csc(struct ipu_ic *ic,
base = (u32 __iomem *)
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
+   switch (encoding) {
+   case V4L2_YCBCR_ENC_601:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt709;
+   break;
+   default:
+   if (inf != outf) {
+   dev_err(priv->ipu->dev,
+   "Unsupported YCbCr encoding\n");
+   return -EINVAL;
+   }
+   break;
+   }
+
if (inf == outf)
params = &ic_csc_identity;
else if (inf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_ycbcr2rgb_bt601;
+   params = params_yuv2rgb;
else
-   params = &ic_csc_rgb2ycbcr_bt601;
+   params = params_rgb2yuv;
 
/* Cast to unsigned */
c = (const u16 (*)[3])params->coeff;
@@ -390,6 +444,7 @@ EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
 
 int ipu_ic_task_graphics_init(struct ipu_ic *ic,
  enum ipu_color_space in_g_cs,
+ enum v4l2_ycbcr_encoding encoding,
  bool galpha_en, u32 galpha,
  bool colorkey_en, u32 colorkey)
 {
@@ -408,7 +463,7 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic,
if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
/* need transparent CSC1 conversion */
ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
-  IPUV3_COLORSPACE_RGB, 0);
+  IPUV3_COLORSPACE_RGB, encoding, 0);
if (ret)
goto unlock;
}
@@ -416,7 +471,7 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic,
ic->g_in_cs = in_g_cs;
 
if (ic->g_in_cs != ic->out_cs) {
-   ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
+   ret = init_csc(ic, ic->g_in_cs, ic->out_cs, encoding, 1);
if (ret)
 

Re: [PATCH 2/3] gpu: ipu-v3: ipu-ic: Add support for BT.709 encoding

2019-02-09 Thread Steve Longerbeam



On 2/8/19 8:24 AM, Tim Harvey wrote:

On Sun, Feb 3, 2019 at 11:48 AM Steve Longerbeam  wrote:

Pass v4l2 encoding enum to the ipu_ic task init functions, and add
support for the BT.709 encoding and inverse encoding matrices.

Reported-by: Tim Harvey 
Signed-off-by: Steve Longerbeam 
---
  drivers/gpu/ipu-v3/ipu-ic.c | 67 ++---
  drivers/gpu/ipu-v3/ipu-image-convert.c  |  1 +
  drivers/staging/media/imx/imx-ic-prpencvf.c |  4 +-
  include/video/imx-ipu-v3.h  |  5 +-
  4 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 35ae86ff0585..63362b4fff81 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -199,6 +199,23 @@ static const struct ic_csc_params ic_csc_rgb2ycbcr_bt601 = 
{
 .scale = 1,
  };

+/*
+ * BT.709 encoding from RGB full range to YUV limited range:
+ *
+ * Y = R *  .2126 + G *  .7152 + B *  .0722;
+ * U = R * -.1146 + G * -.3854 + B *  .5000 + 128.;
+ * V = R *  .5000 + G * -.4542 + B * -.0458 + 128.;
+ */
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt709 = {
+   .coeff = {
+   { 54, 183, 18 },
+   { 483, 413, 128 },
+   { 128, 396, 500 },
+   },
+   .offset = { 0, 512, 512 },
+   .scale = 1,
+};
+
  /* transparent RGB->RGB matrix for graphics combining */
  static const struct ic_csc_params ic_csc_rgb2rgb = {
 .coeff = {
@@ -226,12 +243,31 @@ static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 
= {
 .scale = 2,
  };

+/*
+ * Inverse BT.709 encoding from YUV limited range to RGB full range:
+ *
+ * R = (1. * (Y - 16)) + (1.5748 * (Cr - 128));
+ * G = (1. * (Y - 16)) - (0.1873 * (Cb - 128)) - (0.4681 * (Cr - 128));
+ * B = (1. * (Y - 16)) + (1.8556 * (Cb - 128);
+ */
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt709 = {
+   .coeff = {
+   { 128, 0, 202 },
+   { 128, 488, 452 },
+   { 128, 238, 0 },
+   },
+   .offset = { -435, 136, -507 },
+   .scale = 2,
+};
+
  static int init_csc(struct ipu_ic *ic,
 enum ipu_color_space inf,
 enum ipu_color_space outf,
+   enum v4l2_ycbcr_encoding encoding,
 int csc_index)
  {
 struct ipu_ic_priv *priv = ic->priv;
+   const struct ic_csc_params *params_rgb2yuv, *params_yuv2rgb;
 const struct ic_csc_params *params;
 u32 __iomem *base;
 const u16 (*c)[3];
@@ -241,10 +277,24 @@ static int init_csc(struct ipu_ic *ic,
 base = (u32 __iomem *)
 (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);

+   switch (encoding) {
+   case V4L2_YCBCR_ENC_601:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt709;
+   break;
+   default:
+   dev_err(priv->ipu->dev, "Unsupported YCbCr encoding\n");
+   return -EINVAL;
+   }
+

Steve,

This will fail for RGB to RGB with 'Unsupported YCbCr encoding. We
need to account for the RGB->RGB case.

How about something like:



Thanks for reporting Tim

I rather keep the check for supported encoding, and instead get rid of 
"Unsupported color space conversion" error, because that is the YUV->YUV 
case which can be allowed using the identity matrix.


Steve



  static int init_csc(struct ipu_ic *ic,
 enum ipu_color_space inf,
 enum ipu_color_space outf,
+   enum v4l2_ycbcr_encoding encoding,
 int csc_index)
  {
 struct ipu_ic_priv *priv = ic->priv;
-   const struct ic_csc_params *params;
+   const struct ic_csc_params *params = NULL;
 u32 __iomem *base;
 const u16 (*c)[3];
 const u16 *a;
@@ -241,13 +276,18 @@ static int init_csc(struct ipu_ic *ic,
 base = (u32 __iomem *)
 (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);

-   if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_ycbcr2rgb_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_rgb2ycbcr_bt601;
+   if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB) {
+   params = (encoding == V4L2_YCBCR_ENC_601) ?
+   &ic_csc_ycbcr2rgb_bt601 : &ic_csc_ycbcr2rgb_bt709;
+   }
+   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV) {
+   params = (encoding == V4L2_YCBCR_ENC_601) ?
+   &ic_cs

[PATCH v2 3/4] gpu: ipu-v3: ipu-ic: Add support for BT.709 encoding

2019-02-09 Thread Steve Longerbeam
From: Steve Longerbeam 

Pass v4l2 encoding enum to the ipu_ic task init functions, and add
support for the BT.709 encoding and inverse encoding matrices.

Reported-by: Tim Harvey 
Signed-off-by: Steve Longerbeam 
---
Changes in v2:
- only return "Unsupported YCbCr encoding" error if inf != outf,
  since if inf == outf, the identity matrix can be used. Reported
  by Tim Harvey.
---
 drivers/gpu/ipu-v3/ipu-ic.c | 71 +++--
 drivers/gpu/ipu-v3/ipu-image-convert.c  |  1 +
 drivers/staging/media/imx/imx-ic-prpencvf.c |  4 +-
 include/video/imx-ipu-v3.h  |  5 +-
 4 files changed, 71 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index e459615a49a1..0d57ca7ba18e 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -212,6 +212,23 @@ static const struct ic_csc_params ic_csc_identity = {
.scale = 2,
 };
 
+/*
+ * BT.709 encoding from RGB full range to YUV limited range:
+ *
+ * Y = R *  .2126 + G *  .7152 + B *  .0722;
+ * U = R * -.1146 + G * -.3854 + B *  .5000 + 128.;
+ * V = R *  .5000 + G * -.4542 + B * -.0458 + 128.;
+ */
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt709 = {
+   .coeff = {
+   { 54, 183, 18 },
+   { 483, 413, 128 },
+   { 128, 396, 500 },
+   },
+   .offset = { 0, 512, 512 },
+   .scale = 1,
+};
+
 /*
  * Inverse BT.601 encoding from YUV limited range to RGB full range:
  *
@@ -229,12 +246,31 @@ static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 
= {
.scale = 2,
 };
 
+/*
+ * Inverse BT.709 encoding from YUV limited range to RGB full range:
+ *
+ * R = (1. * (Y - 16)) + (1.5748 * (Cr - 128));
+ * G = (1. * (Y - 16)) - (0.1873 * (Cb - 128)) - (0.4681 * (Cr - 128));
+ * B = (1. * (Y - 16)) + (1.8556 * (Cb - 128);
+ */
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt709 = {
+   .coeff = {
+   { 128, 0, 202 },
+   { 128, 488, 452 },
+   { 128, 238, 0 },
+   },
+   .offset = { -435, 136, -507 },
+   .scale = 2,
+};
+
 static int init_csc(struct ipu_ic *ic,
enum ipu_color_space inf,
enum ipu_color_space outf,
+   enum v4l2_ycbcr_encoding encoding,
int csc_index)
 {
struct ipu_ic_priv *priv = ic->priv;
+   const struct ic_csc_params *params_rgb2yuv, *params_yuv2rgb;
const struct ic_csc_params *params;
u32 __iomem *base;
const u16 (*c)[3];
@@ -244,12 +280,30 @@ static int init_csc(struct ipu_ic *ic,
base = (u32 __iomem *)
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
+   switch (encoding) {
+   case V4L2_YCBCR_ENC_601:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt709;
+   break;
+   default:
+   if (inf != outf) {
+   dev_err(priv->ipu->dev,
+   "Unsupported YCbCr encoding\n");
+   return -EINVAL;
+   }
+   break;
+   }
+
if (inf == outf)
params = &ic_csc_identity;
else if (inf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_ycbcr2rgb_bt601;
+   params = &ic_csc_ycbcr2rgb;
else
-   params = &ic_csc_rgb2ycbcr_bt601;
+   params = &ic_csc_rgb2ycbcr;
 
/* Cast to unsigned */
c = (const u16 (*)[3])params->coeff;
@@ -390,6 +444,7 @@ EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
 
 int ipu_ic_task_graphics_init(struct ipu_ic *ic,
  enum ipu_color_space in_g_cs,
+ enum v4l2_ycbcr_encoding encoding,
  bool galpha_en, u32 galpha,
  bool colorkey_en, u32 colorkey)
 {
@@ -408,7 +463,7 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic,
if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
/* need transparent CSC1 conversion */
ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
-  IPUV3_COLORSPACE_RGB, 0);
+  IPUV3_COLORSPACE_RGB, encoding, 0);
if (ret)
goto unlock;
}
@@ -416,7 +471,7 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic,
ic->g_in_cs = in_g_cs;
 
if (ic->g_in_cs != ic->out_cs) {
-   ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
+   ret = init_csc(ic, ic->g_in_cs, ic->out_cs, encoding, 1);
if (ret)
goto un

[PATCH v2 1/4] gpu: ipu-v3: ipu-ic: Rename yuv2rgb encoding matrices

2019-02-09 Thread Steve Longerbeam
From: Steve Longerbeam 

The ycbcr2rgb and inverse rgb2ycbcr matrices define the BT.601 encoding
coefficients, so rename them to indicate that. And add some comments
to make clear these are BT.601 coefficients encoding between YUV limited
range and RGB full range. The ic_csc_rgb2rgb matrix is just an identity
matrix, so rename to ic_csc_identity. No functional changes.

Signed-off-by: Steve Longerbeam 
---
Changes in v2:
- rename ic_csc_rgb2rgb matrix to ic_csc_identity.
---
 drivers/gpu/ipu-v3/ipu-ic.c | 21 ++---
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 594c3cbc8291..3ef61f0b509b 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -183,11 +183,13 @@ struct ic_csc_params {
 };
 
 /*
+ * BT.601 encoding from RGB full range to YUV limited range:
+ *
  * Y = R *  .299 + G *  .587 + B *  .114;
  * U = R * -.169 + G * -.332 + B *  .500 + 128.;
  * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
  */
-static const struct ic_csc_params ic_csc_rgb2ycbcr = {
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt601 = {
.coeff = {
{ 77, 150, 29 },
{ 469, 427, 128 },
@@ -197,8 +199,11 @@ static const struct ic_csc_params ic_csc_rgb2ycbcr = {
.scale = 1,
 };
 
-/* transparent RGB->RGB matrix for graphics combining */
-static const struct ic_csc_params ic_csc_rgb2rgb = {
+/*
+ * identity matrix, used for transparent RGB->RGB graphics
+ * combining.
+ */
+static const struct ic_csc_params ic_csc_identity = {
.coeff = {
{ 128, 0, 0 },
{ 0, 128, 0 },
@@ -208,11 +213,13 @@ static const struct ic_csc_params ic_csc_rgb2rgb = {
 };
 
 /*
+ * Inverse BT.601 encoding from YUV limited range to RGB full range:
+ *
  * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
  * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
  * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
  */
-static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 = {
.coeff = {
{ 149, 0, 204 },
{ 149, 462, 408 },
@@ -238,11 +245,11 @@ static int init_csc(struct ipu_ic *ic,
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_ycbcr2rgb;
+   params = &ic_csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_rgb2ycbcr;
+   params = &ic_csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_rgb2rgb;
+   params = &ic_csc_identity;
else {
dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
return -EINVAL;
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 1/4] gpu: ipu-v3: ipu-ic: Rename yuv2rgb encoding matrices

2019-02-09 Thread Steve Longerbeam
The ycbcr2rgb and inverse rgb2ycbcr matrices define the BT.601 encoding
coefficients, so rename them to indicate that. And add some comments
to make clear these are BT.601 coefficients encoding between YUV limited
range and RGB full range. The ic_csc_rgb2rgb matrix is just an identity
matrix, so rename to ic_csc_identity. No functional changes.

Signed-off-by: Steve Longerbeam 
---
Changes in v2:
- rename ic_csc_rgb2rgb matrix to ic_csc_identity.
---
 drivers/gpu/ipu-v3/ipu-ic.c | 21 ++---
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 594c3cbc8291..3ef61f0b509b 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -183,11 +183,13 @@ struct ic_csc_params {
 };
 
 /*
+ * BT.601 encoding from RGB full range to YUV limited range:
+ *
  * Y = R *  .299 + G *  .587 + B *  .114;
  * U = R * -.169 + G * -.332 + B *  .500 + 128.;
  * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
  */
-static const struct ic_csc_params ic_csc_rgb2ycbcr = {
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt601 = {
.coeff = {
{ 77, 150, 29 },
{ 469, 427, 128 },
@@ -197,8 +199,11 @@ static const struct ic_csc_params ic_csc_rgb2ycbcr = {
.scale = 1,
 };
 
-/* transparent RGB->RGB matrix for graphics combining */
-static const struct ic_csc_params ic_csc_rgb2rgb = {
+/*
+ * identity matrix, used for transparent RGB->RGB graphics
+ * combining.
+ */
+static const struct ic_csc_params ic_csc_identity = {
.coeff = {
{ 128, 0, 0 },
{ 0, 128, 0 },
@@ -208,11 +213,13 @@ static const struct ic_csc_params ic_csc_rgb2rgb = {
 };
 
 /*
+ * Inverse BT.601 encoding from YUV limited range to RGB full range:
+ *
  * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
  * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
  * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
  */
-static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 = {
.coeff = {
{ 149, 0, 204 },
{ 149, 462, 408 },
@@ -238,11 +245,11 @@ static int init_csc(struct ipu_ic *ic,
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_ycbcr2rgb;
+   params = &ic_csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_rgb2ycbcr;
+   params = &ic_csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_rgb2rgb;
+   params = &ic_csc_identity;
else {
dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
return -EINVAL;
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 2/4] gpu: ipu-v3: ipu-ic: Simplify selection of encoding matrix

2019-02-09 Thread Steve Longerbeam
Simplify the selection of the Y'CbCr encoding matrices in init_csc().
A side-effect of this change is that init_csc() now allows YUV->YUV
using the identity matrix, intead of returning error.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 12 
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 3ef61f0b509b..e459615a49a1 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -244,16 +244,12 @@ static int init_csc(struct ipu_ic *ic,
base = (u32 __iomem *)
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
-   if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
+   if (inf == outf)
+   params = &ic_csc_identity;
+   else if (inf == IPUV3_COLORSPACE_YUV)
params = &ic_csc_ycbcr2rgb_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+   else
params = &ic_csc_rgb2ycbcr_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_identity;
-   else {
-   dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
-   return -EINVAL;
-   }
 
/* Cast to unsigned */
c = (const u16 (*)[3])params->coeff;
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 3/4] gpu: ipu-v3: ipu-ic: Add support for BT.709 encoding

2019-02-09 Thread Steve Longerbeam
Pass v4l2 encoding enum to the ipu_ic task init functions, and add
support for the BT.709 encoding and inverse encoding matrices.

Reported-by: Tim Harvey 
Signed-off-by: Steve Longerbeam 
---
Changes in v2:
- only return "Unsupported YCbCr encoding" error if inf != outf,
  since if inf == outf, the identity matrix can be used. Reported
  by Tim Harvey.
---
 drivers/gpu/ipu-v3/ipu-ic.c | 71 +++--
 drivers/gpu/ipu-v3/ipu-image-convert.c  |  1 +
 drivers/staging/media/imx/imx-ic-prpencvf.c |  4 +-
 include/video/imx-ipu-v3.h  |  5 +-
 4 files changed, 71 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index e459615a49a1..0d57ca7ba18e 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -212,6 +212,23 @@ static const struct ic_csc_params ic_csc_identity = {
.scale = 2,
 };
 
+/*
+ * BT.709 encoding from RGB full range to YUV limited range:
+ *
+ * Y = R *  .2126 + G *  .7152 + B *  .0722;
+ * U = R * -.1146 + G * -.3854 + B *  .5000 + 128.;
+ * V = R *  .5000 + G * -.4542 + B * -.0458 + 128.;
+ */
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt709 = {
+   .coeff = {
+   { 54, 183, 18 },
+   { 483, 413, 128 },
+   { 128, 396, 500 },
+   },
+   .offset = { 0, 512, 512 },
+   .scale = 1,
+};
+
 /*
  * Inverse BT.601 encoding from YUV limited range to RGB full range:
  *
@@ -229,12 +246,31 @@ static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 
= {
.scale = 2,
 };
 
+/*
+ * Inverse BT.709 encoding from YUV limited range to RGB full range:
+ *
+ * R = (1. * (Y - 16)) + (1.5748 * (Cr - 128));
+ * G = (1. * (Y - 16)) - (0.1873 * (Cb - 128)) - (0.4681 * (Cr - 128));
+ * B = (1. * (Y - 16)) + (1.8556 * (Cb - 128);
+ */
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt709 = {
+   .coeff = {
+   { 128, 0, 202 },
+   { 128, 488, 452 },
+   { 128, 238, 0 },
+   },
+   .offset = { -435, 136, -507 },
+   .scale = 2,
+};
+
 static int init_csc(struct ipu_ic *ic,
enum ipu_color_space inf,
enum ipu_color_space outf,
+   enum v4l2_ycbcr_encoding encoding,
int csc_index)
 {
struct ipu_ic_priv *priv = ic->priv;
+   const struct ic_csc_params *params_rgb2yuv, *params_yuv2rgb;
const struct ic_csc_params *params;
u32 __iomem *base;
const u16 (*c)[3];
@@ -244,12 +280,30 @@ static int init_csc(struct ipu_ic *ic,
base = (u32 __iomem *)
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
+   switch (encoding) {
+   case V4L2_YCBCR_ENC_601:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  &ic_csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = &ic_csc_ycbcr2rgb_bt709;
+   break;
+   default:
+   if (inf != outf) {
+   dev_err(priv->ipu->dev,
+   "Unsupported YCbCr encoding\n");
+   return -EINVAL;
+   }
+   break;
+   }
+
if (inf == outf)
params = &ic_csc_identity;
else if (inf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_ycbcr2rgb_bt601;
+   params = &ic_csc_ycbcr2rgb;
else
-   params = &ic_csc_rgb2ycbcr_bt601;
+   params = &ic_csc_rgb2ycbcr;
 
/* Cast to unsigned */
c = (const u16 (*)[3])params->coeff;
@@ -390,6 +444,7 @@ EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
 
 int ipu_ic_task_graphics_init(struct ipu_ic *ic,
  enum ipu_color_space in_g_cs,
+ enum v4l2_ycbcr_encoding encoding,
  bool galpha_en, u32 galpha,
  bool colorkey_en, u32 colorkey)
 {
@@ -408,7 +463,7 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic,
if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
/* need transparent CSC1 conversion */
ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
-  IPUV3_COLORSPACE_RGB, 0);
+  IPUV3_COLORSPACE_RGB, encoding, 0);
if (ret)
goto unlock;
}
@@ -416,7 +471,7 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic,
ic->g_in_cs = in_g_cs;
 
if (ic->g_in_cs != ic->out_cs) {
-   ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
+   ret = init_csc(ic, ic->g_in_cs, ic->out_cs, encoding, 1);
if (ret)
goto unlock;
}
@@ -450,6 

[PATCH v4 2/4] gpu: ipu-v3: ipu-ic: Simplify selection of encoding matrix

2019-02-09 Thread Steve Longerbeam
Simplify the selection of the Y'CbCr encoding matrices in init_csc().
A side-effect of this change is that init_csc() now allows YUV->YUV
using the identity matrix, intead of returning error.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 12 
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 3ef61f0b509b..e459615a49a1 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -244,16 +244,12 @@ static int init_csc(struct ipu_ic *ic,
base = (u32 __iomem *)
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
-   if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
+   if (inf == outf)
+   params = &ic_csc_identity;
+   else if (inf == IPUV3_COLORSPACE_YUV)
params = &ic_csc_ycbcr2rgb_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+   else
params = &ic_csc_rgb2ycbcr_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_identity;
-   else {
-   dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
-   return -EINVAL;
-   }
 
/* Cast to unsigned */
c = (const u16 (*)[3])params->coeff;
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v3 3/4] gpu: ipu-v3: ipu-ic: Add support for BT.709 encoding

2019-02-09 Thread Steve Longerbeam



On 2/8/19 4:20 PM, Tim Harvey wrote:

On Fri, Feb 8, 2019 at 11:28 AM Steve Longerbeam  wrote:

 if (inf == outf)
 params = &ic_csc_identity;
 else if (inf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_ycbcr2rgb_bt601;
+   params = &ic_csc_ycbcr2rgb;


Steve,

compile issue...

params = params_yuv2rgb;


 else
-   params = &ic_csc_rgb2ycbcr_bt601;
+   params = &ic_csc_rgb2ycbcr;

params = params_rgb2yuv;


Wow, did I not even compile test that? Must be my head cold :-/
Sending v4.



But, I'm still failing when using the mem2mem element (gst-launch-1.0
v4l2src device=/dev/video4 ! v4l2video8convert
output-io-mode=dmabuf-import ! fbdevsink) with 'Unsupported YCbCr
encoding' because of inf=IPU_COLORSPACE_YCBCR outf=IPU_COLORSPACE_RGB
and a seemingly unset encoding being passed in.

It looks like maybe something in the mem2mem driver isn't defaulting
encoding. The call path is (v4l2_m2m_streamon -> device_run ->
ipu_image_convert_queue -> convert_start -> ipu_ic_task_init_rsc ->
init_csc).


Looking at v7 of the mem2mem driver, it will set ycbcr_enc at the output 
side to V4L2_YCBCR_ENC_DEFAULT if colorspace is default. So colorspace 
will need to be set to something non-default in addition to setting 
ycbcr_enc, at the output side. I don't know whether gstreamer 
v4l2videoNconvertelement will do this, but you could hack the driver for 
now to get around it, and let Philipp know this may need a workaround in 
mem2mem for v8.


Steve
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v4 1/4] gpu: ipu-v3: ipu-ic: Rename yuv2rgb encoding matrices

2019-02-12 Thread Steve Longerbeam

Hi Philipp,

On 2/11/19 1:58 AM, Philipp Zabel wrote:

On Fri, 2019-02-08 at 17:47 -0800, Steve Longerbeam wrote:

The ycbcr2rgb and inverse rgb2ycbcr matrices define the BT.601 encoding
coefficients, so rename them to indicate that. And add some comments
to make clear these are BT.601 coefficients encoding between YUV limited
range and RGB full range. The ic_csc_rgb2rgb matrix is just an identity
matrix, so rename to ic_csc_identity. No functional changes.

Signed-off-by: Steve Longerbeam 
---
Changes in v2:
- rename ic_csc_rgb2rgb matrix to ic_csc_identity.
---
  drivers/gpu/ipu-v3/ipu-ic.c | 21 ++---
  1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 594c3cbc8291..3ef61f0b509b 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -183,11 +183,13 @@ struct ic_csc_params {
  };
  
  /*

+ * BT.601 encoding from RGB full range to YUV limited range:
+ *
   * Y = R *  .299 + G *  .587 + B *  .114;
   * U = R * -.169 + G * -.332 + B *  .500 + 128.;
   * V = R *  .500 + G * -.419 + B * -.0813 + 128.;

Hm, this is a conversion to full range BT.601. For limited range, the
matrix coefficients

0.2990  0.5870  0.1140
   -0.1687 -0.3313  0.5000
0.5000 -0.4187 -0.0813

should be multiplied with 219/255 (Y) and 224/255 (U,V), respectively:

   Y = R *  .2568 + G *  .5041 + B *  .0979 + 16;
   U = R * -.1482 + G * -.2910 + B *  .4392 + 128;
   V = R *  .4392 + G * -.3678 + B * -.0714 + 128;


Looking more closely at these coefficients now, I see you are right, 
they are the BT.601 YUV full-range coefficients (Y range 0 to 1, U and V 
range -0.5 to 0.5). Well, not even that -- the coefficients are not 
being scaled to the limited ranges, but the 0.5 offset (128) _is_ being 
added to U/V, but no offset for Y. So it is even more messed up.


Your corrected coefficients and offsets look correct to me: Y 
coefficients scaled to (235 - 16) / 255 and U/V coefficients scaled to 
(240 - 16)  / 255, and add the offsets for both Y and U/V.


But what about this "SAT_MODE" field in the IC task parameter memory? 
According to the manual the hardware will automatically convert the 
written coefficients to the correct limited ranges. I see there is a 
"sat" field defined in the struct but is not being set in the tables.


So what should we do, define the full range coefficients, and make use 
of SAT_MODE h/w feature, or scale/offset the coefficients ourselves and 
not use SAT_MODE? I'm inclined to do the former.


Steve






   */
-static const struct ic_csc_params ic_csc_rgb2ycbcr = {
+static const struct ic_csc_params ic_csc_rgb2ycbcr_bt601 = {
.coeff = {
{ 77, 150, 29 },
{ 469, 427, 128 },
@@ -197,8 +199,11 @@ static const struct ic_csc_params ic_csc_rgb2ycbcr = {
.scale = 1,
  };
  
-/* transparent RGB->RGB matrix for graphics combining */

-static const struct ic_csc_params ic_csc_rgb2rgb = {
+/*
+ * identity matrix, used for transparent RGB->RGB graphics
+ * combining.
+ */
+static const struct ic_csc_params ic_csc_identity = {
.coeff = {
{ 128, 0, 0 },
{ 0, 128, 0 },
@@ -208,11 +213,13 @@ static const struct ic_csc_params ic_csc_rgb2rgb = {
  };
  
  /*

+ * Inverse BT.601 encoding from YUV limited range to RGB full range:
+ *
   * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
   * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
   * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
   */

This looks correct.


-static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+static const struct ic_csc_params ic_csc_ycbcr2rgb_bt601 = {
.coeff = {
{ 149, 0, 204 },
{ 149, 462, 408 },
@@ -238,11 +245,11 @@ static int init_csc(struct ipu_ic *ic,
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
  
  	if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)

-   params = &ic_csc_ycbcr2rgb;
+   params = &ic_csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_rgb2ycbcr;
+   params = &ic_csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_rgb2rgb;
+   params = &ic_csc_identity;
else {
dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
return -EINVAL;

regards
Philipp


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v5 4/7] gpu: ipu-v3: ipu-ic: Add support for Rec.709 encoding

2019-02-19 Thread Steve Longerbeam
Add support for Rec.709 encoding and inverse encoding.

The determination of the CSC coefficients based on the input/output
colorspace parameters are moved to a new function calc_csc_coeffs().

Reported-by: Tim Harvey 
Signed-off-by: Steve Longerbeam 
---
Changes in v5:
- moved API changes to a previous patch.
- moved CSC coeff calc to new function calc_csc_coeffs().
Changes in v4:
- fix compile error.
Chnges in v3:
- none.
Changes in v2:
- only return "Unsupported YCbCr encoding" error if inf != outf,
  since if inf == outf, the identity matrix can be used. Reported
  by Tim Harvey.
---
 drivers/gpu/ipu-v3/ipu-ic.c | 120 
 1 file changed, 94 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 02043f23f411..012ea2239e97 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -214,6 +214,23 @@ static const struct ic_encode_coeff ic_encode_identity = {
.scale = 2,
 };
 
+/*
+ * REC.709 encoding from RGB full range to YUV full range:
+ *
+ * Y =  .2126 * R + .7152 * G + .0722 * B
+ * U = -.1146 * R - .3854 * G + .5000 * B + 128
+ * V =  .5000 * R - .4542 * G - .0458 * B + 128
+ */
+static const struct ic_encode_coeff ic_encode_rgb2ycbcr_709 = {
+   .coeff = {
+   {  54, 183,  19 },
+   { 483, 413, 128 },
+   { 128, 396, 500 },
+   },
+   .offset = { 0, 512, 512 },
+   .scale = 1,
+};
+
 /*
  * Inverse BT.601 encoding from YUV full range to RGB full range:
  *
@@ -237,28 +254,42 @@ static const struct ic_encode_coeff 
ic_encode_ycbcr2rgb_601 = {
.scale = 2,
 };
 
-static int init_csc(struct ipu_ic *ic,
-   const struct ipu_ic_colorspace *in,
-   const struct ipu_ic_colorspace *out,
-   int csc_index)
+/*
+ * Inverse REC.709 encoding from YUV full range to RGB full range:
+ *
+ * R = 1. * Y +  0 * (Cb - 128) + 1.5748 * (Cr - 128)
+ * G = 1. * Y -  .1873 * (Cb - 128) -  .4681 * (Cr - 128)
+ * B = 1. * Y + 1.8556 * (Cb - 128) +  0 * (Cr - 128)
+ *
+ * equivalently (factoring out the offsets):
+ *
+ * R = 1. * Y  +  0 * Cb + 1.5748 * Cr - 201.574
+ * G = 1. * Y  -  .1873 * Cb -  .4681 * Cr +  83.891
+ * B = 1. * Y  + 1.8556 * Cb +  0 * Cr - 237.517
+ */
+static const struct ic_encode_coeff ic_encode_ycbcr2rgb_709 = {
+   .coeff = {
+   {  128,   0, 202 },
+   {  128, 488, 452 },
+   {  128, 238,   0 },
+   },
+   .offset = { -403, 168, -475 },
+   .scale = 2,
+};
+
+static int calc_csc_coeffs(struct ipu_ic_priv *priv,
+  struct ic_encode_coeff *coeff_out,
+  const struct ipu_ic_colorspace *in,
+  const struct ipu_ic_colorspace *out)
 {
-   struct ipu_ic_priv *priv = ic->priv;
-   const struct ic_encode_coeff *coeff;
-   u32 __iomem *base;
-   const u16 (*c)[3];
-   const u16 *a;
-   u32 param;
+   const struct ic_encode_coeff *encode_coeff;
+   bool inverse_encode;
 
if (in->colorspace != out->colorspace) {
dev_err(priv->ipu->dev, "Cannot convert colorspaces\n");
return -ENOTSUPP;
}
 
-   if (out->enc != V4L2_YCBCR_ENC_601) {
-   dev_err(priv->ipu->dev, "Only BT.601 encoding supported\n");
-   return -ENOTSUPP;
-   }
-
if ((in->cs == IPUV3_COLORSPACE_YUV &&
 in->quant != V4L2_QUANTIZATION_FULL_RANGE) ||
(out->cs == IPUV3_COLORSPACE_YUV &&
@@ -275,26 +306,63 @@ static int init_csc(struct ipu_ic *ic,
return -ENOTSUPP;
}
 
+   if (in->cs == out->cs) {
+   *coeff_out = ic_encode_identity;
+
+   return 0;
+   }
+
+   inverse_encode = (in->cs == IPUV3_COLORSPACE_YUV);
+
+   switch (out->enc) {
+   case V4L2_YCBCR_ENC_601:
+   encode_coeff = inverse_encode ?
+   &ic_encode_ycbcr2rgb_601 : &ic_encode_rgb2ycbcr_601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   encode_coeff = inverse_encode ?
+   &ic_encode_ycbcr2rgb_709 : &ic_encode_rgb2ycbcr_709;
+   break;
+   default:
+   dev_err(priv->ipu->dev, "Unsupported YCbCr encoding\n");
+   return -ENOTSUPP;
+   }
+
+   *coeff_out = *encode_coeff;
+
+   return 0;
+}
+
+static int init_csc(struct ipu_ic *ic,
+   const struct ipu_ic_colorspace *in,
+   const struct ipu_ic_colorspace *out,
+   int csc_index)
+{
+   struct ipu_ic_priv *priv = ic->priv;
+   struct ic_encode_coeff coeff;
+   u32 __iomem *base;
+   const u16 (*c)[3];
+   const u16 *a;
+   u32 param;
+   int ret;
+
+ 

[PATCH v5 1/7] gpu: ipu-v3: ipu-ic: Fix saturation bit offset in TPMEM

2019-02-19 Thread Steve Longerbeam
The saturation bit was being set at bit 9 in the second 32-bit word
of the TPMEM CSC. This isn't correct, the saturation bit is bit 42,
which is bit 10 of the second word.

Fixes: 1aa8ea0d2bd5d ("gpu: ipu-v3: Add Image Converter unit")

Signed-off-by: Steve Longerbeam 
Cc: sta...@vger.kernel.org
---
 drivers/gpu/ipu-v3/ipu-ic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 594c3cbc8291..18816ccf600e 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -257,7 +257,7 @@ static int init_csc(struct ipu_ic *ic,
writel(param, base++);
 
param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
-   (params->sat << 9);
+   (params->sat << 10);
writel(param, base++);
 
param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v5 3/7] gpu: ipu-v3: ipu-ic: Fully describe colorspace conversions

2019-02-19 Thread Steve Longerbeam
Only providing the input and output RGB/YUV space to the IC task init
functions is not sufficient. To fully characterize a colorspace
conversion, the colorspace (chromaticities), Y'CbCr encoding standard,
and quantization also need to be specified.

Define a 'struct ipu_ic_colorspace' that includes all the above, and pass
the input and output ipu_ic_colorspace to the IC task init functions.

This allows to actually enforce the fact that the IC:

- can only encode to/from YUV full range (follow-up patch will remove
  this restriction).
- can only encode to/from RGB full range.
- can only encode using BT.601 standard (follow-up patch will add
  Rec.709 encoding support).
- cannot convert colorspaces from input to output, the
  input and output colorspace chromaticities must be the same.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 101 
 drivers/gpu/ipu-v3/ipu-image-convert.c  |  27 --
 drivers/staging/media/imx/imx-ic-prpencvf.c |  22 +++--
 include/video/imx-ipu-v3.h  |  37 +--
 4 files changed, 127 insertions(+), 60 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 71a0409093e6..02043f23f411 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -146,8 +146,10 @@ struct ipu_ic {
const struct ic_task_regoffs *reg;
const struct ic_task_bitfields *bit;
 
-   enum ipu_color_space in_cs, g_in_cs;
-   enum ipu_color_space out_cs;
+   struct ipu_ic_colorspace in_cs;
+   struct ipu_ic_colorspace g_in_cs;
+   struct ipu_ic_colorspace out_cs;
+
bool graphics;
bool rotation;
bool in_use;
@@ -236,8 +238,8 @@ static const struct ic_encode_coeff ic_encode_ycbcr2rgb_601 
= {
 };
 
 static int init_csc(struct ipu_ic *ic,
-   enum ipu_color_space inf,
-   enum ipu_color_space outf,
+   const struct ipu_ic_colorspace *in,
+   const struct ipu_ic_colorspace *out,
int csc_index)
 {
struct ipu_ic_priv *priv = ic->priv;
@@ -247,19 +249,41 @@ static int init_csc(struct ipu_ic *ic,
const u16 *a;
u32 param;
 
+   if (in->colorspace != out->colorspace) {
+   dev_err(priv->ipu->dev, "Cannot convert colorspaces\n");
+   return -ENOTSUPP;
+   }
+
+   if (out->enc != V4L2_YCBCR_ENC_601) {
+   dev_err(priv->ipu->dev, "Only BT.601 encoding supported\n");
+   return -ENOTSUPP;
+   }
+
+   if ((in->cs == IPUV3_COLORSPACE_YUV &&
+in->quant != V4L2_QUANTIZATION_FULL_RANGE) ||
+   (out->cs == IPUV3_COLORSPACE_YUV &&
+out->quant != V4L2_QUANTIZATION_FULL_RANGE)) {
+   dev_err(priv->ipu->dev, "Limited range YUV not supported\n");
+   return -ENOTSUPP;
+   }
+
+   if ((in->cs == IPUV3_COLORSPACE_RGB &&
+in->quant != V4L2_QUANTIZATION_FULL_RANGE) ||
+   (out->cs == IPUV3_COLORSPACE_RGB &&
+out->quant != V4L2_QUANTIZATION_FULL_RANGE)) {
+   dev_err(priv->ipu->dev, "Limited range RGB not supported\n");
+   return -ENOTSUPP;
+   }
+
base = (u32 __iomem *)
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
-   if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
+   if (in->cs == out->cs)
+   coeff = &ic_encode_identity;
+   else if (in->cs == IPUV3_COLORSPACE_YUV)
coeff = &ic_encode_ycbcr2rgb_601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+   else
coeff = &ic_encode_rgb2ycbcr_601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   coeff = &ic_encode_identity;
-   else {
-   dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
-   return -EINVAL;
-   }
 
/* Cast to unsigned */
c = (const u16 (*)[3])coeff->coeff;
@@ -357,14 +381,14 @@ void ipu_ic_task_enable(struct ipu_ic *ic)
if (ic->rotation)
ic_conf |= ic->bit->ic_conf_rot_en;
 
-   if (ic->in_cs != ic->out_cs)
+   if (ic->in_cs.cs != ic->out_cs.cs)
ic_conf |= ic->bit->ic_conf_csc1_en;
 
if (ic->graphics) {
ic_conf |= ic->bit->ic_conf_cmb_en;
ic_conf |= ic->bit->ic_conf_csc1_en;
 
-   if (ic->g_in_cs != ic->out_cs)
+   if (ic->g_in_cs.cs != ic->out_cs.cs)
ic_conf |= ic->bit->ic_conf_csc2_en;
}
 
@@ -399,7 +423,7 @@ void ipu_ic_task_d

[PATCH v5 5/7] gpu: ipu-v3: ipu-ic: Add support for limited range encoding

2019-02-19 Thread Steve Longerbeam
Add support for the following conversions:

- YUV full-range to YUV limited-range
- YUV limited-range to YUV full-range
- YUV limited-range to RGB full-range
- RGB full-range to YUV limited-range

The last two conversions require operating on the YUV full-range
encoding and inverse encoding coefficients, with the YUV-to-YUV
limited<->full coefficients. The formula to convert is

M_c = M_a * M_b
O_c = M_a * O_b + O_a

For calculating the RGB full-range to YUV limited-range coefficients:

[M_a, O_a] = YUV full-range to YUV limited-range coefficients.
[M_b, O_b] = RGB full-range to YUV full-range coefficients.

For calculating the YUV limited-range to RGB full-range coefficients:

[M_a, O_a] = YUV full-range to RGB full-range coefficients.
[M_b, O_b] = YUV limited-range to YUV full-range coefficients.

The calculation of [M_c, O_c] is carried out by the function
transform_coeffs().

In the future if RGB limited range encoding is required, the same
function can be used. And cascaded to create all combinations of
encoding for YUV limited/full range <-> RGB limited/full range,
passing the output coefficients from one call as the input for the
next.

For example, to create YUV full-range to RGB limited-range coefficients:

[M_a, O_a] = RGB full-range to RGB limited-range coefficients.
[M_b, O_b] = YUV full-range to RGB full-range coefficients.

and that output sent as input to create YUV limited-range to RGB
limited-range coefficients:

[M_a, O_a] = YUV full-range to RGB limited-range coefficients.
[M_b, O_b] = YUV limited-range to YUV full-range coefficients.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 281 +---
 1 file changed, 263 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 012ea2239e97..861f43556df4 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -178,10 +178,10 @@ static inline void ipu_ic_write(struct ipu_ic *ic, u32 
value, unsigned offset)
 }
 
 struct ic_encode_coeff {
-   s16 coeff[3][3];/* signed 9-bit integer coefficients */
-   s16 offset[3];  /* signed 11+2-bit fixed point offset */
-   u8 scale:2; /* scale coefficients * 2^(scale-1) */
-   bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */
+   int coeff[3][3];/* signed 9-bit integer coefficients */
+   int offset[3];  /* signed 13-bit integer offset */
+   int scale;  /* scale coefficients * 2^(scale-1) */
+   bool sat;   /* saturate to (16, 235(Y) / 240(U, V)) */
 };
 
 /*
@@ -277,6 +277,231 @@ static const struct ic_encode_coeff 
ic_encode_ycbcr2rgb_709 = {
.scale = 2,
 };
 
+/*
+ * YUV full range to YUV limited range:
+ *
+ * Y_lim  = 0.8588 * Y_full + 16
+ * Cb_lim = 0.8784 * (Cb_full - 128) + 128
+ * Cr_lim = 0.8784 * (Cr_full - 128) + 128
+ */
+static const struct ic_encode_coeff ic_encode_ycbcr_full2lim = {
+   .coeff = {
+   { 219, 0, 0 },
+   { 0, 224, 0 },
+   { 0, 0, 224 },
+   },
+   .offset = { 64, 62, 62 },
+   .scale = 1,
+};
+
+/*
+ * YUV limited range to YUV full range:
+ *
+ * Y_full  = 1.1644 * (Y_lim - 16)
+ * Cb_full = 1.1384 * (Cb_lim - 128) + 128
+ * Cr_full = 1.1384 * (Cr_lim - 128) + 128
+ */
+static const struct ic_encode_coeff ic_encode_ycbcr_lim2full = {
+   .coeff = {
+   { 149, 0, 0 },
+   { 0, 145, 0 },
+   { 0, 0, 145 },
+   },
+   .offset = { -37, -35, -35 },
+   .scale = 2,
+};
+
+/*
+ * RGB full range to RGB limited range:
+ *
+ * R_lim = 0.8588 * R_full + 16
+ * G_lim = 0.8588 * G_full + 16
+ * B_lim = 0.8588 * B_full + 16
+ */
+static const struct ic_encode_coeff
+ic_encode_rgb_full2lim __maybe_unused = {
+   .coeff = {
+   { 219, 0, 0 },
+   { 0, 219, 0 },
+   { 0, 0, 219 },
+   },
+   .offset = { 64, 64, 64 },
+   .scale = 1,
+};
+
+/*
+ * RGB limited range to RGB full range:
+ *
+ * R_full = 1.1644 * (R_lim - 16)
+ * G_full = 1.1644 * (G_lim - 16)
+ * B_full = 1.1644 * (B_lim - 16)
+ */
+static const struct ic_encode_coeff
+ic_encode_rgb_lim2full __maybe_unused = {
+   .coeff = {
+   { 149, 0, 0 },
+   { 0, 149, 0 },
+   { 0, 0, 149 },
+   },
+   .offset = { -37, -37, -37 },
+   .scale = 2,
+};
+
+/*
+ * Convert a coefficient and scale value in TPMEM register format
+ * to a signed int times 256 (fix the radix point). The TPMEM register
+ * coefficient format is a signed 9-bit value (sign bit at bit 8,
+ * mantissa = coeff * 2 ^ (8 - scale - 1)).
+ */
+static int coeff_fix(int coeff, int scale)
+{
+   if (coeff >= 256)
+   coeff -= 512;
+   if (scale == 0)
+   return DIV_ROUND_CLOSEST(coeff, 2);
+   return coeff << (scale - 1);
+}
+
+/*
+ * Convert a signed int coefficie

[PATCH v5 2/7] gpu: ipu-v3: ipu-ic: Fix BT.601 coefficients

2019-02-19 Thread Steve Longerbeam
The ycbcr2rgb and inverse rgb2ycbcr tables define the BT.601 Y'CbCr
encoding coefficients.

The rgb2ycbcr table specifically describes the BT.601 encoding from
full range RGB to full range YUV. Add table comments to make this more
clear.

The ycbcr2rgb inverse table describes encoding YUV limited range to RGB
full range. To be consistent with the rgb2ycbcr table, convert this to
YUV full range to RGB full range, and adjust/expand on the comments.

The ic_csc_rgb2rgb table is just an identity matrix, so rename to
ic_encode_identity.

Fixes: 1aa8ea0d2bd5d ("gpu: ipu-v3: Add Image Converter unit")

Suggested-by: Philipp Zabel 
Signed-off-by: Steve Longerbeam 
Cc: sta...@vger.kernel.org
---
 drivers/gpu/ipu-v3/ipu-ic.c | 63 ++---
 1 file changed, 38 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 18816ccf600e..71a0409093e6 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -175,7 +175,7 @@ static inline void ipu_ic_write(struct ipu_ic *ic, u32 
value, unsigned offset)
writel(value, ic->priv->base + offset);
 }
 
-struct ic_csc_params {
+struct ic_encode_coeff {
s16 coeff[3][3];/* signed 9-bit integer coefficients */
s16 offset[3];  /* signed 11+2-bit fixed point offset */
u8 scale:2; /* scale coefficients * 2^(scale-1) */
@@ -183,22 +183,27 @@ struct ic_csc_params {
 };
 
 /*
- * Y = R *  .299 + G *  .587 + B *  .114;
- * U = R * -.169 + G * -.332 + B *  .500 + 128.;
- * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
+ * BT.601 encoding from RGB full range to YUV full range:
+ *
+ * Y =  .2990 * R + .5870 * G + .1140 * B
+ * U = -.1687 * R - .3313 * G + .5000 * B + 128
+ * V =  .5000 * R - .4187 * G - .0813 * B + 128
  */
-static const struct ic_csc_params ic_csc_rgb2ycbcr = {
+static const struct ic_encode_coeff ic_encode_rgb2ycbcr_601 = {
.coeff = {
-   { 77, 150, 29 },
-   { 469, 427, 128 },
+   {  76, 150,  29 },
+   { 469, 428, 128 },
{ 128, 405, 491 },
},
.offset = { 0, 512, 512 },
.scale = 1,
 };
 
-/* transparent RGB->RGB matrix for graphics combining */
-static const struct ic_csc_params ic_csc_rgb2rgb = {
+/*
+ * identity matrix, used for transparent RGB->RGB graphics
+ * combining.
+ */
+static const struct ic_encode_coeff ic_encode_identity = {
.coeff = {
{ 128, 0, 0 },
{ 0, 128, 0 },
@@ -208,17 +213,25 @@ static const struct ic_csc_params ic_csc_rgb2rgb = {
 };
 
 /*
- * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
- * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
- * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
+ * Inverse BT.601 encoding from YUV full range to RGB full range:
+ *
+ * R = 1. * Y +  0 * (Cb - 128) + 1.4020 * (Cr - 128)
+ * G = 1. * Y -  .3442 * (Cb - 128) - 0.7142 * (Cr - 128)
+ * B = 1. * Y + 1.7720 * (Cb - 128) +  0 * (Cr - 128)
+ *
+ * equivalently (factoring out the offsets):
+ *
+ * R = 1. * Y  +  0 * Cb + 1.4020 * Cr - 179.456
+ * G = 1. * Y  -  .3442 * Cb - 0.7142 * Cr + 135.475
+ * B = 1. * Y  + 1.7720 * Cb +  0 * Cr - 226.816
  */
-static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+static const struct ic_encode_coeff ic_encode_ycbcr2rgb_601 = {
.coeff = {
-   { 149, 0, 204 },
-   { 149, 462, 408 },
-   { 149, 255, 0 },
+   { 128,   0, 179 },
+   { 128, 468, 421 },
+   { 128, 226,   0 },
},
-   .offset = { -446, 266, -554 },
+   .offset = { -359, 271, -454 },
.scale = 2,
 };
 
@@ -228,7 +241,7 @@ static int init_csc(struct ipu_ic *ic,
int csc_index)
 {
struct ipu_ic_priv *priv = ic->priv;
-   const struct ic_csc_params *params;
+   const struct ic_encode_coeff *coeff;
u32 __iomem *base;
const u16 (*c)[3];
const u16 *a;
@@ -238,26 +251,26 @@ static int init_csc(struct ipu_ic *ic,
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_ycbcr2rgb;
+   coeff = &ic_encode_ycbcr2rgb_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_rgb2ycbcr;
+   coeff = &ic_encode_rgb2ycbcr_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_rgb2rgb;
+   coeff = &ic_encode_identity;
else {
dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
return -EINVAL;
}
 
/* Cast to unsigned */
-   c = (const u16 (*)[3])params

Re: [PATCH v6] gpu: ipu-csi: Swap fields according to input/output field types

2019-01-09 Thread Steve Longerbeam
Please disregard. This patch can't be submitted stand-alone, I will 
re-submit as part of a v6 of "imx-media: Fixes for interlaced capture" 
patchset.


Steve


On 12/14/18 3:46 PM, Steve Longerbeam wrote:

The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
---
Changes since v5:
- Convert to const the infmt, outfmt, and mbus_cfg pointer args to
   ipu_csi_init_interface(), suggested by Philipp Zabel.
- Bring back if_fmt local var and don't copy outfmt to local stack in
   csi_setup(), suggested by Philipp.

Changes since v4:
- Cleaned up some convoluted code in ipu_csi_init_interface(), suggested
   by Philipp.
- Fixed a regression in csi_setup(), caught by Philipp.
---
  drivers/gpu/ipu-v3/ipu-csi.c  | 126 +++---
  drivers/staging/media/imx/imx-media-csi.c |   7 +-
  include/video/imx-ipu-v3.h|   5 +-
  3 files changed, 89 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index aa0e30a2ba18..d1e575571a8d 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,12 +325,21 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code,
return 0;
  }
  
+/* translate alternate field mode based on given standard */

+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
  /*
   * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
   */
  static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
-struct v4l2_mbus_config *mbus_cfg,
-struct v4l2_mbus_framefmt *mbus_fmt)
+   const struct v4l2_mbus_config *mbus_cfg,
+   const struct v4l2_mbus_framefmt *mbus_fmt)
  {
int ret;
  
@@ -374,22 +383,76 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,

return 0;
  }
  
+static int

+ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+   const struct v4l2_mbus_framefmt *infmt,
+   const struct v4l2_mbus_framefmt *outfmt,
+   v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI

[PATCH v6 03/12] gpu: ipu-v3: Add planar support to interlaced scan

2019-01-09 Thread Steve Longerbeam
To support interlaced scan with planar formats, cpmem SLUV must
be programmed with the correct chroma line stride. For full and
partial planar 4:2:2 (YUV422P, NV16), chroma line stride must
be doubled. For full and partial planar 4:2:0 (YUV420, YVU420, NV12),
chroma line stride must _not_ be doubled, since a single chroma line
is shared by two luma lines.

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
Acked-by: Philipp Zabel 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c  | 26 +++--
 drivers/staging/media/imx/imx-ic-prpencvf.c |  3 ++-
 drivers/staging/media/imx/imx-media-csi.c   |  3 ++-
 include/video/imx-ipu-v3.h  |  3 ++-
 4 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 163fadb8a33a..d047a6867c59 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -277,9 +277,10 @@ void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 
u_off, u32 v_off)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
 
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat)
 {
-   u32 ilo, sly;
+   u32 ilo, sly, sluv;
 
if (stride < 0) {
stride = -stride;
@@ -290,9 +291,30 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, 
int stride)
 
sly = (stride * 2) - 1;
 
+   switch (pixelformat) {
+   case V4L2_PIX_FMT_YUV420:
+   case V4L2_PIX_FMT_YVU420:
+   sluv = stride / 2 - 1;
+   break;
+   case V4L2_PIX_FMT_NV12:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_YUV422P:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_NV16:
+   sluv = stride * 2 - 1;
+   break;
+   default:
+   sluv = 0;
+   break;
+   }
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+   if (sluv)
+   ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c 
b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 28f41caba05d..af7224846bd5 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -412,7 +412,8 @@ static int prp_setup_channel(struct prp_priv *priv,
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field) &&
channel == priv->out_ch)
-   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline);
+   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline,
+ image.pix.pixelformat);
 
ret = ipu_ic_task_idma_init(priv->ic, channel,
image.pix.width, image.pix.height,
diff --git a/drivers/staging/media/imx/imx-media-csi.c 
b/drivers/staging/media/imx/imx-media-csi.c
index c2a8d9cd31b7..da4808348845 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -512,7 +512,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field))
ipu_cpmem_interlaced_scan(priv->idmac_ch,
- image.pix.bytesperline);
+ image.pix.bytesperline,
+ image.pix.pixelformat);
 
ipu_idmac_set_double_buffer(priv->idmac_ch, true);
 
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index bbc8481f567d..c887f4bee5f8 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -258,7 +258,8 @@ void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int 
stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t 
buf);
 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v6 02/12] gpu: ipu-csi: Swap fields according to input/output field types

2019-01-09 Thread Steve Longerbeam
The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
---
Changes since v5:
- Convert to const the infmt, outfmt, and mbus_cfg pointer args to
  ipu_csi_init_interface(), suggested by Philipp Zabel.
- Bring back if_fmt local var and don't copy outfmt to local stack in
  csi_setup(), suggested by Philipp.

Changes since v4:
- Cleaned up some convoluted code in ipu_csi_init_interface(), suggested
  by Philipp.
- Fixed a regression in csi_setup(), caught by Philipp.
---
 drivers/gpu/ipu-v3/ipu-csi.c  | 126 +++---
 drivers/staging/media/imx/imx-media-csi.c |   7 +-
 include/video/imx-ipu-v3.h|   5 +-
 3 files changed, 89 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index aa0e30a2ba18..d1e575571a8d 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,12 +325,21 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code,
return 0;
 }
 
+/* translate alternate field mode based on given standard */
+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
 /*
  * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
  */
 static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
-struct v4l2_mbus_config *mbus_cfg,
-struct v4l2_mbus_framefmt *mbus_fmt)
+   const struct v4l2_mbus_config *mbus_cfg,
+   const struct v4l2_mbus_framefmt *mbus_fmt)
 {
int ret;
 
@@ -374,22 +383,76 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
return 0;
 }
 
+static int
+ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+   const struct v4l2_mbus_framefmt *infmt,
+   const struct v4l2_mbus_framefmt *outfmt,
+   v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   }
+
+   ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
+
+   return 0;
+}
+
+
 int ipu_csi_init_interface(struct ipu_csi *csi,
-  struct v4l2_mbus_config *mbus_cfg,
-  

[PATCH v8 02/11] gpu: ipu-csi: Swap fields according to input/output field types

2019-01-10 Thread Steve Longerbeam
The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
Acked-by: Philipp Zabel 
---
Changes since v5:
- Convert to const the infmt, outfmt, and mbus_cfg pointer args to
  ipu_csi_init_interface(), suggested by Philipp Zabel.
- Bring back if_fmt local var and don't copy outfmt to local stack in
  csi_setup(), suggested by Philipp.

Changes since v4:
- Cleaned up some convoluted code in ipu_csi_init_interface(), suggested
  by Philipp.
- Fixed a regression in csi_setup(), caught by Philipp.
---
 drivers/gpu/ipu-v3/ipu-csi.c  | 126 +++---
 drivers/staging/media/imx/imx-media-csi.c |   7 +-
 include/video/imx-ipu-v3.h|   5 +-
 3 files changed, 89 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index aa0e30a2ba18..d1e575571a8d 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,12 +325,21 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code,
return 0;
 }
 
+/* translate alternate field mode based on given standard */
+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
 /*
  * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
  */
 static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
-struct v4l2_mbus_config *mbus_cfg,
-struct v4l2_mbus_framefmt *mbus_fmt)
+   const struct v4l2_mbus_config *mbus_cfg,
+   const struct v4l2_mbus_framefmt *mbus_fmt)
 {
int ret;
 
@@ -374,22 +383,76 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
return 0;
 }
 
+static int
+ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+   const struct v4l2_mbus_framefmt *infmt,
+   const struct v4l2_mbus_framefmt *outfmt,
+   v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   }
+
+   ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
+
+   return 0;
+}
+
+
 int ipu_csi_init_interface(struct ipu_csi *csi,
-  struct v4l2_mbus_conf

[PATCH v7 02/11] gpu: ipu-csi: Swap fields according to input/output field types

2019-01-10 Thread Steve Longerbeam
The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
---
Changes since v5:
- Convert to const the infmt, outfmt, and mbus_cfg pointer args to
  ipu_csi_init_interface(), suggested by Philipp Zabel.
- Bring back if_fmt local var and don't copy outfmt to local stack in
  csi_setup(), suggested by Philipp.

Changes since v4:
- Cleaned up some convoluted code in ipu_csi_init_interface(), suggested
  by Philipp.
- Fixed a regression in csi_setup(), caught by Philipp.
---
 drivers/gpu/ipu-v3/ipu-csi.c  | 126 +++---
 drivers/staging/media/imx/imx-media-csi.c |   7 +-
 include/video/imx-ipu-v3.h|   5 +-
 3 files changed, 89 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index aa0e30a2ba18..d1e575571a8d 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,12 +325,21 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code,
return 0;
 }
 
+/* translate alternate field mode based on given standard */
+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
 /*
  * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
  */
 static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
-struct v4l2_mbus_config *mbus_cfg,
-struct v4l2_mbus_framefmt *mbus_fmt)
+   const struct v4l2_mbus_config *mbus_cfg,
+   const struct v4l2_mbus_framefmt *mbus_fmt)
 {
int ret;
 
@@ -374,22 +383,76 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
return 0;
 }
 
+static int
+ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+   const struct v4l2_mbus_framefmt *infmt,
+   const struct v4l2_mbus_framefmt *outfmt,
+   v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   }
+
+   ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
+
+   return 0;
+}
+
+
 int ipu_csi_init_interface(struct ipu_csi *csi,
-  struct v4l2_mbus_config *mbus_cfg,
-  

[PATCH v7 03/11] gpu: ipu-v3: Add planar support to interlaced scan

2019-01-10 Thread Steve Longerbeam
To support interlaced scan with planar formats, cpmem SLUV must
be programmed with the correct chroma line stride. For full and
partial planar 4:2:2 (YUV422P, NV16), chroma line stride must
be doubled. For full and partial planar 4:2:0 (YUV420, YVU420, NV12),
chroma line stride must _not_ be doubled, since a single chroma line
is shared by two luma lines.

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
Acked-by: Philipp Zabel 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c  | 26 +++--
 drivers/staging/media/imx/imx-ic-prpencvf.c |  3 ++-
 drivers/staging/media/imx/imx-media-csi.c   |  3 ++-
 include/video/imx-ipu-v3.h  |  3 ++-
 4 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 163fadb8a33a..d047a6867c59 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -277,9 +277,10 @@ void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 
u_off, u32 v_off)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
 
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat)
 {
-   u32 ilo, sly;
+   u32 ilo, sly, sluv;
 
if (stride < 0) {
stride = -stride;
@@ -290,9 +291,30 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, 
int stride)
 
sly = (stride * 2) - 1;
 
+   switch (pixelformat) {
+   case V4L2_PIX_FMT_YUV420:
+   case V4L2_PIX_FMT_YVU420:
+   sluv = stride / 2 - 1;
+   break;
+   case V4L2_PIX_FMT_NV12:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_YUV422P:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_NV16:
+   sluv = stride * 2 - 1;
+   break;
+   default:
+   sluv = 0;
+   break;
+   }
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+   if (sluv)
+   ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c 
b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 28f41caba05d..af7224846bd5 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -412,7 +412,8 @@ static int prp_setup_channel(struct prp_priv *priv,
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field) &&
channel == priv->out_ch)
-   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline);
+   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline,
+ image.pix.pixelformat);
 
ret = ipu_ic_task_idma_init(priv->ic, channel,
image.pix.width, image.pix.height,
diff --git a/drivers/staging/media/imx/imx-media-csi.c 
b/drivers/staging/media/imx/imx-media-csi.c
index c2a8d9cd31b7..da4808348845 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -512,7 +512,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field))
ipu_cpmem_interlaced_scan(priv->idmac_ch,
- image.pix.bytesperline);
+ image.pix.bytesperline,
+ image.pix.pixelformat);
 
ipu_idmac_set_double_buffer(priv->idmac_ch, true);
 
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index bbc8481f567d..c887f4bee5f8 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -258,7 +258,8 @@ void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int 
stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t 
buf);
 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v8 03/11] gpu: ipu-v3: Add planar support to interlaced scan

2019-01-10 Thread Steve Longerbeam
To support interlaced scan with planar formats, cpmem SLUV must
be programmed with the correct chroma line stride. For full and
partial planar 4:2:2 (YUV422P, NV16), chroma line stride must
be doubled. For full and partial planar 4:2:0 (YUV420, YVU420, NV12),
chroma line stride must _not_ be doubled, since a single chroma line
is shared by two luma lines.

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
Acked-by: Philipp Zabel 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c  | 26 +++--
 drivers/staging/media/imx/imx-ic-prpencvf.c |  3 ++-
 drivers/staging/media/imx/imx-media-csi.c   |  3 ++-
 include/video/imx-ipu-v3.h  |  3 ++-
 4 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 163fadb8a33a..d047a6867c59 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -277,9 +277,10 @@ void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 
u_off, u32 v_off)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
 
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat)
 {
-   u32 ilo, sly;
+   u32 ilo, sly, sluv;
 
if (stride < 0) {
stride = -stride;
@@ -290,9 +291,30 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, 
int stride)
 
sly = (stride * 2) - 1;
 
+   switch (pixelformat) {
+   case V4L2_PIX_FMT_YUV420:
+   case V4L2_PIX_FMT_YVU420:
+   sluv = stride / 2 - 1;
+   break;
+   case V4L2_PIX_FMT_NV12:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_YUV422P:
+   sluv = stride - 1;
+   break;
+   case V4L2_PIX_FMT_NV16:
+   sluv = stride * 2 - 1;
+   break;
+   default:
+   sluv = 0;
+   break;
+   }
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+   if (sluv)
+   ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c 
b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 28f41caba05d..af7224846bd5 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -412,7 +412,8 @@ static int prp_setup_channel(struct prp_priv *priv,
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field) &&
channel == priv->out_ch)
-   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline);
+   ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline,
+ image.pix.pixelformat);
 
ret = ipu_ic_task_idma_init(priv->ic, channel,
image.pix.width, image.pix.height,
diff --git a/drivers/staging/media/imx/imx-media-csi.c 
b/drivers/staging/media/imx/imx-media-csi.c
index c2a8d9cd31b7..da4808348845 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -512,7 +512,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
if (image.pix.field == V4L2_FIELD_NONE &&
V4L2_FIELD_HAS_BOTH(infmt->field))
ipu_cpmem_interlaced_scan(priv->idmac_ch,
- image.pix.bytesperline);
+ image.pix.bytesperline,
+ image.pix.pixelformat);
 
ipu_idmac_set_double_buffer(priv->idmac_ch, true);
 
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index bbc8481f567d..c887f4bee5f8 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -258,7 +258,8 @@ void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int 
stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t 
buf);
 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+  u32 pixelformat);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH] gpu: ipu-v3: image-convert: Enable double write reduction

2019-06-13 Thread Steve Longerbeam
For the write channels with 4:2:0 subsampled YUV formats, avoid chroma
overdraw by only writing chroma for even lines (skip odd chroma rows).
This reduces necessary write memory bandwidth by at least 25% (more
with rotation enabled).

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-image-convert.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index 36e88434513a..3036e01d8d42 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -1279,6 +1279,15 @@ static void init_idmac_channel(struct 
ipu_image_convert_ctx *ctx,
if (rot_mode)
ipu_cpmem_set_rotation(channel, rot_mode);
 
+   /*
+* Skip writing U and V components to odd rows in the output
+* channels for planar 4:2:0.
+*/
+   if ((channel == chan->out_chan ||
+channel == chan->rotation_out_chan) &&
+   image->fmt->planar && image->fmt->uv_height_dec == 2)
+   ipu_cpmem_skip_odd_chroma_rows(channel);
+
if (channel == chan->rotation_in_chan ||
channel == chan->rotation_out_chan) {
burst_size = 8;
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v6 4/7] gpu: ipu-v3: ipu-ic: Add support for Rec.709 encoding

2019-03-07 Thread Steve Longerbeam
Add support for Rec.709 encoding and inverse encoding.

Reported-by: Tim Harvey 
Signed-off-by: Steve Longerbeam 
---
Changes in v5:
- moved API changes to a previous patch.
- moved CSC coeff calc to new function calc_csc_coeffs().
Changes in v4:
- fix compile error.
Chnges in v3:
- none.
Changes in v2:
- only return "Unsupported YCbCr encoding" error if inf != outf,
  since if inf == outf, the identity matrix can be used. Reported
  by Tim Harvey.
---
 drivers/gpu/ipu-v3/ipu-ic.c | 63 -
 1 file changed, 56 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index c4048c921801..1460901af9b5 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -214,6 +214,23 @@ static const struct ic_encode_coeff ic_encode_identity = {
.scale = 2,
 };
 
+/*
+ * REC.709 encoding from RGB full range to YUV full range:
+ *
+ * Y =  .2126 * R + .7152 * G + .0722 * B
+ * U = -.1146 * R - .3854 * G + .5000 * B + 128
+ * V =  .5000 * R - .4542 * G - .0458 * B + 128
+ */
+static const struct ic_encode_coeff ic_encode_rgb2ycbcr_709 = {
+   .coeff = {
+   {  54, 183,  19 },
+   { 483, 413, 128 },
+   { 128, 396, 500 },
+   },
+   .offset = { 0, 512, 512 },
+   .scale = 1,
+};
+
 /*
  * Inverse BT.601 encoding from YUV full range to RGB full range:
  *
@@ -237,11 +254,35 @@ static const struct ic_encode_coeff 
ic_encode_ycbcr2rgb_601 = {
.scale = 2,
 };
 
+/*
+ * Inverse REC.709 encoding from YUV full range to RGB full range:
+ *
+ * R = 1. * Y +  0 * (Cb - 128) + 1.5748 * (Cr - 128)
+ * G = 1. * Y -  .1873 * (Cb - 128) -  .4681 * (Cr - 128)
+ * B = 1. * Y + 1.8556 * (Cb - 128) +  0 * (Cr - 128)
+ *
+ * equivalently (factoring out the offsets):
+ *
+ * R = 1. * Y  +  0 * Cb + 1.5748 * Cr - 201.574
+ * G = 1. * Y  -  .1873 * Cb -  .4681 * Cr +  83.891
+ * B = 1. * Y  + 1.8556 * Cb +  0 * Cr - 237.517
+ */
+static const struct ic_encode_coeff ic_encode_ycbcr2rgb_709 = {
+   .coeff = {
+   {  128,   0, 202 },
+   {  128, 488, 452 },
+   {  128, 238,   0 },
+   },
+   .offset = { -403, 168, -475 },
+   .scale = 2,
+};
+
 static int calc_csc_coeffs(struct ipu_ic_priv *priv,
   struct ic_encode_coeff *coeff_out,
   const struct ipu_ic_colorspace *in,
   const struct ipu_ic_colorspace *out)
 {
+   const struct ic_encode_coeff *encode_coeff;
bool inverse_encode;
 
if (in->colorspace != out->colorspace) {
@@ -249,11 +290,6 @@ static int calc_csc_coeffs(struct ipu_ic_priv *priv,
return -ENOTSUPP;
}
 
-   if (out->enc != V4L2_YCBCR_ENC_601) {
-   dev_err(priv->ipu->dev, "Only BT.601 encoding supported\n");
-   return -ENOTSUPP;
-   }
-
if ((in->cs == IPUV3_COLORSPACE_YUV &&
 in->quant != V4L2_QUANTIZATION_FULL_RANGE) ||
(out->cs == IPUV3_COLORSPACE_YUV &&
@@ -278,8 +314,21 @@ static int calc_csc_coeffs(struct ipu_ic_priv *priv,
 
inverse_encode = (in->cs == IPUV3_COLORSPACE_YUV);
 
-   *coeff_out = inverse_encode ?
-   ic_encode_ycbcr2rgb_601 : ic_encode_rgb2ycbcr_601;
+   switch (out->enc) {
+   case V4L2_YCBCR_ENC_601:
+   encode_coeff = inverse_encode ?
+   &ic_encode_ycbcr2rgb_601 : &ic_encode_rgb2ycbcr_601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   encode_coeff = inverse_encode ?
+   &ic_encode_ycbcr2rgb_709 : &ic_encode_rgb2ycbcr_709;
+   break;
+   default:
+   dev_err(priv->ipu->dev, "Unsupported YCbCr encoding\n");
+   return -ENOTSUPP;
+   }
+
+   *coeff_out = *encode_coeff;
 
return 0;
 }
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v6 3/7] gpu: ipu-v3: ipu-ic: Fully describe colorspace conversions

2019-03-07 Thread Steve Longerbeam
Only providing the input and output RGB/YUV space to the IC task init
functions is not sufficient. To fully characterize a colorspace
conversion, the colorspace (chromaticities), Y'CbCr encoding standard,
and quantization also need to be specified.

Define a 'struct ipu_ic_colorspace' that includes all the above, and pass
the input and output ipu_ic_colorspace to the IC task init functions.

This allows to actually enforce the fact that the IC:

- can only encode to/from YUV full range (follow-up patch will remove
  this restriction).
- can only encode to/from RGB full range.
- can only encode using BT.601 standard (follow-up patch will add
  Rec.709 encoding support).
- cannot convert colorspaces from input to output, the
  input and output colorspace chromaticities must be the same.

The determination of the CSC coefficients based on the input/output
colorspace parameters are moved to a new function calc_csc_coeffs(),
called by init_csc().

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 136 +---
 drivers/gpu/ipu-v3/ipu-image-convert.c  |  27 ++--
 drivers/staging/media/imx/imx-ic-prpencvf.c |  22 +++-
 include/video/imx-ipu-v3.h  |  37 +-
 4 files changed, 154 insertions(+), 68 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index b63a2826b629..c4048c921801 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -146,8 +146,10 @@ struct ipu_ic {
const struct ic_task_regoffs *reg;
const struct ic_task_bitfields *bit;
 
-   enum ipu_color_space in_cs, g_in_cs;
-   enum ipu_color_space out_cs;
+   struct ipu_ic_colorspace in_cs;
+   struct ipu_ic_colorspace g_in_cs;
+   struct ipu_ic_colorspace out_cs;
+
bool graphics;
bool rotation;
bool in_use;
@@ -235,42 +237,83 @@ static const struct ic_encode_coeff 
ic_encode_ycbcr2rgb_601 = {
.scale = 2,
 };
 
+static int calc_csc_coeffs(struct ipu_ic_priv *priv,
+  struct ic_encode_coeff *coeff_out,
+  const struct ipu_ic_colorspace *in,
+  const struct ipu_ic_colorspace *out)
+{
+   bool inverse_encode;
+
+   if (in->colorspace != out->colorspace) {
+   dev_err(priv->ipu->dev, "Cannot convert colorspaces\n");
+   return -ENOTSUPP;
+   }
+
+   if (out->enc != V4L2_YCBCR_ENC_601) {
+   dev_err(priv->ipu->dev, "Only BT.601 encoding supported\n");
+   return -ENOTSUPP;
+   }
+
+   if ((in->cs == IPUV3_COLORSPACE_YUV &&
+in->quant != V4L2_QUANTIZATION_FULL_RANGE) ||
+   (out->cs == IPUV3_COLORSPACE_YUV &&
+out->quant != V4L2_QUANTIZATION_FULL_RANGE)) {
+   dev_err(priv->ipu->dev, "Limited range YUV not supported\n");
+   return -ENOTSUPP;
+   }
+
+   if ((in->cs == IPUV3_COLORSPACE_RGB &&
+in->quant != V4L2_QUANTIZATION_FULL_RANGE) ||
+   (out->cs == IPUV3_COLORSPACE_RGB &&
+out->quant != V4L2_QUANTIZATION_FULL_RANGE)) {
+   dev_err(priv->ipu->dev, "Limited range RGB not supported\n");
+   return -ENOTSUPP;
+   }
+
+   if (in->cs == out->cs) {
+   *coeff_out = ic_encode_identity;
+
+   return 0;
+   }
+
+   inverse_encode = (in->cs == IPUV3_COLORSPACE_YUV);
+
+   *coeff_out = inverse_encode ?
+   ic_encode_ycbcr2rgb_601 : ic_encode_rgb2ycbcr_601;
+
+   return 0;
+}
+
 static int init_csc(struct ipu_ic *ic,
-   enum ipu_color_space inf,
-   enum ipu_color_space outf,
+   const struct ipu_ic_colorspace *in,
+   const struct ipu_ic_colorspace *out,
int csc_index)
 {
struct ipu_ic_priv *priv = ic->priv;
-   const struct ic_encode_coeff *coeff;
+   struct ic_encode_coeff coeff;
u32 __iomem *base;
const u16 (*c)[3];
const u16 *a;
u32 param;
+   int ret;
+
+   ret = calc_csc_coeffs(priv, &coeff, in, out);
+   if (ret)
+   return ret;
 
base = (u32 __iomem *)
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
-   if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
-   coeff = &ic_encode_ycbcr2rgb_601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   coeff = &ic_encode_rgb2ycbcr_601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   coeff = &ic_encode_identity;
-   else {
-   dev_err(priv->ipu->dev, "Unsupported color space conversion\

[PATCH v6 2/7] gpu: ipu-v3: ipu-ic: Fix BT.601 coefficients

2019-03-07 Thread Steve Longerbeam
The ycbcr2rgb and inverse rgb2ycbcr tables define the BT.601 Y'CbCr
encoding coefficients.

The rgb2ycbcr table specifically describes the BT.601 encoding from
full range RGB to full range YUV. Add table comments to make this more
clear.

The ycbcr2rgb inverse table describes encoding YUV limited range to RGB
full range. To be consistent with the rgb2ycbcr table, convert this to
YUV full range to RGB full range, and adjust/expand on the comments.

The ic_csc_rgb2rgb table is just an identity matrix, so rename to
ic_encode_identity.

Fixes: 1aa8ea0d2bd5d ("gpu: ipu-v3: Add Image Converter unit")

Suggested-by: Philipp Zabel 
Signed-off-by: Steve Longerbeam 
Cc: sta...@vger.kernel.org
---
 drivers/gpu/ipu-v3/ipu-ic.c | 61 ++---
 1 file changed, 37 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 18816ccf600e..b63a2826b629 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -175,7 +175,7 @@ static inline void ipu_ic_write(struct ipu_ic *ic, u32 
value, unsigned offset)
writel(value, ic->priv->base + offset);
 }
 
-struct ic_csc_params {
+struct ic_encode_coeff {
s16 coeff[3][3];/* signed 9-bit integer coefficients */
s16 offset[3];  /* signed 11+2-bit fixed point offset */
u8 scale:2; /* scale coefficients * 2^(scale-1) */
@@ -183,13 +183,15 @@ struct ic_csc_params {
 };
 
 /*
- * Y = R *  .299 + G *  .587 + B *  .114;
- * U = R * -.169 + G * -.332 + B *  .500 + 128.;
- * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
+ * BT.601 encoding from RGB full range to YUV full range:
+ *
+ * Y =  .2990 * R + .5870 * G + .1140 * B
+ * U = -.1687 * R - .3313 * G + .5000 * B + 128
+ * V =  .5000 * R - .4187 * G - .0813 * B + 128
  */
-static const struct ic_csc_params ic_csc_rgb2ycbcr = {
+static const struct ic_encode_coeff ic_encode_rgb2ycbcr_601 = {
.coeff = {
-   { 77, 150, 29 },
+   {  77, 150,  29 },
{ 469, 427, 128 },
{ 128, 405, 491 },
},
@@ -197,8 +199,11 @@ static const struct ic_csc_params ic_csc_rgb2ycbcr = {
.scale = 1,
 };
 
-/* transparent RGB->RGB matrix for graphics combining */
-static const struct ic_csc_params ic_csc_rgb2rgb = {
+/*
+ * identity matrix, used for transparent RGB->RGB graphics
+ * combining.
+ */
+static const struct ic_encode_coeff ic_encode_identity = {
.coeff = {
{ 128, 0, 0 },
{ 0, 128, 0 },
@@ -208,17 +213,25 @@ static const struct ic_csc_params ic_csc_rgb2rgb = {
 };
 
 /*
- * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
- * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
- * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
+ * Inverse BT.601 encoding from YUV full range to RGB full range:
+ *
+ * R = 1. * Y +  0 * (Cb - 128) + 1.4020 * (Cr - 128)
+ * G = 1. * Y -  .3442 * (Cb - 128) - 0.7142 * (Cr - 128)
+ * B = 1. * Y + 1.7720 * (Cb - 128) +  0 * (Cr - 128)
+ *
+ * equivalently (factoring out the offsets):
+ *
+ * R = 1. * Y  +  0 * Cb + 1.4020 * Cr - 179.456
+ * G = 1. * Y  -  .3442 * Cb - 0.7142 * Cr + 135.475
+ * B = 1. * Y  + 1.7720 * Cb +  0 * Cr - 226.816
  */
-static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+static const struct ic_encode_coeff ic_encode_ycbcr2rgb_601 = {
.coeff = {
-   { 149, 0, 204 },
-   { 149, 462, 408 },
-   { 149, 255, 0 },
+   { 128,   0, 179 },
+   { 128, 468, 421 },
+   { 128, 227,   0 },
},
-   .offset = { -446, 266, -554 },
+   .offset = { -359, 271, -454 },
.scale = 2,
 };
 
@@ -228,7 +241,7 @@ static int init_csc(struct ipu_ic *ic,
int csc_index)
 {
struct ipu_ic_priv *priv = ic->priv;
-   const struct ic_csc_params *params;
+   const struct ic_encode_coeff *coeff;
u32 __iomem *base;
const u16 (*c)[3];
const u16 *a;
@@ -238,26 +251,26 @@ static int init_csc(struct ipu_ic *ic,
(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
 
if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_ycbcr2rgb;
+   coeff = &ic_encode_ycbcr2rgb_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = &ic_csc_rgb2ycbcr;
+   coeff = &ic_encode_rgb2ycbcr_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = &ic_csc_rgb2rgb;
+   coeff = &ic_encode_identity;
else {
dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
return -EINVAL;
}
 
/* Cast to unsigned */
-   c = (const u16 (*)[3])params

[PATCH v6 1/7] gpu: ipu-v3: ipu-ic: Fix saturation bit offset in TPMEM

2019-03-07 Thread Steve Longerbeam
The saturation bit was being set at bit 9 in the second 32-bit word
of the TPMEM CSC. This isn't correct, the saturation bit is bit 42,
which is bit 10 of the second word.

Fixes: 1aa8ea0d2bd5d ("gpu: ipu-v3: Add Image Converter unit")

Signed-off-by: Steve Longerbeam 
Cc: sta...@vger.kernel.org
---
 drivers/gpu/ipu-v3/ipu-ic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 594c3cbc8291..18816ccf600e 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -257,7 +257,7 @@ static int init_csc(struct ipu_ic *ic,
writel(param, base++);
 
param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
-   (params->sat << 9);
+   (params->sat << 10);
writel(param, base++);
 
param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v6 5/7] gpu: ipu-v3: ipu-ic: Add support for limited range encoding

2019-03-07 Thread Steve Longerbeam
Add support for the following conversions:

- YUV full-range to YUV limited-range
- YUV limited-range to YUV full-range
- YUV limited-range to RGB full-range
- RGB full-range to YUV limited-range

The last two conversions require operating on the YUV full-range
encoding and inverse encoding coefficients, with the YUV-to-YUV
limited<->full coefficients. The formula to convert is

M_c = M_a * M_b
O_c = M_a * O_b + O_a

For calculating the RGB full-range to YUV limited-range coefficients:

[M_a, O_a] = YUV full-range to YUV limited-range coefficients.
[M_b, O_b] = RGB full-range to YUV full-range coefficients.

For calculating the YUV limited-range to RGB full-range coefficients:

[M_a, O_a] = YUV full-range to RGB full-range coefficients.
[M_b, O_b] = YUV limited-range to YUV full-range coefficients.

The calculation of [M_c, O_c] is carried out by the function
transform_coeffs().

In the future if RGB limited range encoding is required, the same
function can be used. And cascaded to create all combinations of
encoding for YUV limited/full range <-> RGB limited/full range,
passing the output coefficients from one call as the input for the
next.

For example, to create YUV full-range to RGB limited-range coefficients:

[M_a, O_a] = RGB full-range to RGB limited-range coefficients.
[M_b, O_b] = YUV full-range to RGB full-range coefficients.

and that output sent as input to create YUV limited-range to RGB
limited-range coefficients:

[M_a, O_a] = YUV full-range to RGB limited-range coefficients.
[M_b, O_b] = YUV limited-range to YUV full-range coefficients.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 281 +---
 1 file changed, 263 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 1460901af9b5..a7dd85f8d832 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -178,10 +178,10 @@ static inline void ipu_ic_write(struct ipu_ic *ic, u32 
value, unsigned offset)
 }
 
 struct ic_encode_coeff {
-   s16 coeff[3][3];/* signed 9-bit integer coefficients */
-   s16 offset[3];  /* signed 11+2-bit fixed point offset */
-   u8 scale:2; /* scale coefficients * 2^(scale-1) */
-   bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */
+   int coeff[3][3];/* signed 9-bit integer coefficients */
+   int offset[3];  /* signed 13-bit integer offset */
+   int scale;  /* scale coefficients * 2^(scale-1) */
+   bool sat;   /* saturate to (16, 235(Y) / 240(U, V)) */
 };
 
 /*
@@ -277,6 +277,231 @@ static const struct ic_encode_coeff 
ic_encode_ycbcr2rgb_709 = {
.scale = 2,
 };
 
+/*
+ * YUV full range to YUV limited range:
+ *
+ * Y_lim  = 0.8588 * Y_full + 16
+ * Cb_lim = 0.8784 * (Cb_full - 128) + 128
+ * Cr_lim = 0.8784 * (Cr_full - 128) + 128
+ */
+static const struct ic_encode_coeff ic_encode_ycbcr_full2lim = {
+   .coeff = {
+   { 219, 0, 0 },
+   { 0, 224, 0 },
+   { 0, 0, 224 },
+   },
+   .offset = { 64, 62, 62 },
+   .scale = 1,
+};
+
+/*
+ * YUV limited range to YUV full range:
+ *
+ * Y_full  = 1.1644 * (Y_lim - 16)
+ * Cb_full = 1.1384 * (Cb_lim - 128) + 128
+ * Cr_full = 1.1384 * (Cr_lim - 128) + 128
+ */
+static const struct ic_encode_coeff ic_encode_ycbcr_lim2full = {
+   .coeff = {
+   { 149, 0, 0 },
+   { 0, 145, 0 },
+   { 0, 0, 145 },
+   },
+   .offset = { -37, -35, -35 },
+   .scale = 2,
+};
+
+/*
+ * RGB full range to RGB limited range:
+ *
+ * R_lim = 0.8588 * R_full + 16
+ * G_lim = 0.8588 * G_full + 16
+ * B_lim = 0.8588 * B_full + 16
+ */
+static const struct ic_encode_coeff
+ic_encode_rgb_full2lim __maybe_unused = {
+   .coeff = {
+   { 220, 0, 0 },
+   { 0, 220, 0 },
+   { 0, 0, 220 },
+   },
+   .offset = { 64, 64, 64 },
+   .scale = 1,
+};
+
+/*
+ * RGB limited range to RGB full range:
+ *
+ * R_full = 1.1644 * (R_lim - 16)
+ * G_full = 1.1644 * (G_lim - 16)
+ * B_full = 1.1644 * (B_lim - 16)
+ */
+static const struct ic_encode_coeff
+ic_encode_rgb_lim2full __maybe_unused = {
+   .coeff = {
+   { 149, 0, 0 },
+   { 0, 149, 0 },
+   { 0, 0, 149 },
+   },
+   .offset = { -37, -37, -37 },
+   .scale = 2,
+};
+
+/*
+ * Convert a coefficient and scale value in TPMEM register format
+ * to a signed int times 256 (fix the radix point). The TPMEM register
+ * coefficient format is a signed 9-bit value (sign bit at bit 8,
+ * mantissa = coeff * 2 ^ (8 - scale - 1)).
+ */
+static int coeff_fix(int coeff, int scale)
+{
+   if (coeff >= 256)
+   coeff -= 512;
+   if (scale == 0)
+   return DIV_ROUND_CLOSEST(coeff, 2);
+   return coeff << (scale - 1);
+}
+
+/*
+ * Convert a signed int coefficie

Re: [PATCH v6 2/7] gpu: ipu-v3: ipu-ic: Fix BT.601 coefficients

2019-03-08 Thread Steve Longerbeam



On 3/8/19 2:23 AM, Philipp Zabel wrote:

Hi Steve,

On Thu, 2019-03-07 at 15:33 -0800, Steve Longerbeam wrote:

The ycbcr2rgb and inverse rgb2ycbcr tables define the BT.601 Y'CbCr
encoding coefficients.

The rgb2ycbcr table specifically describes the BT.601 encoding from
full range RGB to full range YUV. Add table comments to make this more
clear.

The ycbcr2rgb inverse table describes encoding YUV limited range to RGB
full range. To be consistent with the rgb2ycbcr table, convert this to
YUV full range to RGB full range, and adjust/expand on the comments.

The ic_csc_rgb2rgb table is just an identity matrix, so rename to
ic_encode_identity.

Fixes: 1aa8ea0d2bd5d ("gpu: ipu-v3: Add Image Converter unit")

Suggested-by: Philipp Zabel 
Signed-off-by: Steve Longerbeam 
Cc: sta...@vger.kernel.org
---
  drivers/gpu/ipu-v3/ipu-ic.c | 61 ++---
  1 file changed, 37 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 18816ccf600e..b63a2826b629 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -175,7 +175,7 @@ static inline void ipu_ic_write(struct ipu_ic *ic, u32 
value, unsigned offset)
writel(value, ic->priv->base + offset);
  }
  
-struct ic_csc_params {

+struct ic_encode_coeff {

This less accurate. These are called IC (Task) Parameters in the
reference manual, the 64-bit aligned words are called CSC words. Beside
the coefficients, this structure also contains the coefficient scale,
the offsets, and the saturation mode flag.


It seemed to me the renaming was more clear, but I agree the former name 
conforms better to the manual nomenclature. I will revert this renaming.






s16 coeff[3][3];/* signed 9-bit integer coefficients */
s16 offset[3];  /* signed 11+2-bit fixed point offset */
u8 scale:2; /* scale coefficients * 2^(scale-1) */
@@ -183,13 +183,15 @@ struct ic_csc_params {
  };
  
  /*

- * Y = R *  .299 + G *  .587 + B *  .114;
- * U = R * -.169 + G * -.332 + B *  .500 + 128.;
- * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
+ * BT.601 encoding from RGB full range to YUV full range:
+ *
+ * Y =  .2990 * R + .5870 * G + .1140 * B
+ * U = -.1687 * R - .3313 * G + .5000 * B + 128
+ * V =  .5000 * R - .4187 * G - .0813 * B + 128
   */
-static const struct ic_csc_params ic_csc_rgb2ycbcr = {
+static const struct ic_encode_coeff ic_encode_rgb2ycbcr_601 = {
.coeff = {
-   { 77, 150, 29 },
+   {  77, 150,  29 },
{ 469, 427, 128 },
{ 128, 405, 491 },

We could subtract 512 from the negative values, to improve readability.


Agreed.




},
@@ -197,8 +199,11 @@ static const struct ic_csc_params ic_csc_rgb2ycbcr = {
.scale = 1,
  };
  
-/* transparent RGB->RGB matrix for graphics combining */

-static const struct ic_csc_params ic_csc_rgb2rgb = {
+/*
+ * identity matrix, used for transparent RGB->RGB graphics
+ * combining.
+ */
+static const struct ic_encode_coeff ic_encode_identity = {
.coeff = {
{ 128, 0, 0 },
{ 0, 128, 0 },
@@ -208,17 +213,25 @@ static const struct ic_csc_params ic_csc_rgb2rgb = {
  };
  
  /*

- * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
- * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
- * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
+ * Inverse BT.601 encoding from YUV full range to RGB full range:
+ *
+ * R = 1. * Y +  0 * (Cb - 128) + 1.4020 * (Cr - 128)
+ * G = 1. * Y -  .3442 * (Cb - 128) - 0.7142 * (Cr - 128)

Should that be  ^ .3441   and ^ .7141 ?
The coefficients and offsets after rounding should end up the same.


Ok.



Also, let's consistently either add the leading zero, or leave it out.


Yes.




+ * B = 1. * Y + 1.7720 * (Cb - 128) +  0 * (Cr - 128)
+ *
+ * equivalently (factoring out the offsets):
+ *
+ * R = 1. * Y  +  0 * Cb + 1.4020 * Cr - 179.456
+ * G = 1. * Y  -  .3442 * Cb - 0.7142 * Cr + 135.475
+ * B = 1. * Y  + 1.7720 * Cb +  0 * Cr - 226.816
   */
-static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+static const struct ic_encode_coeff ic_encode_ycbcr2rgb_601 = {
.coeff = {
-   { 149, 0, 204 },
-   { 149, 462, 408 },
-   { 149, 255, 0 },
+   { 128,   0, 179 },
+   { 128, 468, 421 },
+   { 128, 227,   0 },
},
-   .offset = { -446, 266, -554 },
+   .offset = { -359, 271, -454 },

These seem to be correct. Again, I think this would be easier to read if
the negative coefficients were written with a sign as well.


.scale = 2,
  };
  
@@ -228,7 +241,7 @@ static int init_csc(struct ipu_ic *ic,

int csc_index)
  {
struct ipu_ic_priv *priv = ic->priv;
-   const struct ic_csc_params *params;
+   const struct ic_encode_coeff *coeff;
 

Re: [PATCH v6 3/7] gpu: ipu-v3: ipu-ic: Fully describe colorspace conversions

2019-03-08 Thread Steve Longerbeam



On 3/8/19 3:46 AM, Philipp Zabel wrote:

On Thu, 2019-03-07 at 15:33 -0800, Steve Longerbeam wrote:

Only providing the input and output RGB/YUV space to the IC task init
functions is not sufficient. To fully characterize a colorspace
conversion, the colorspace (chromaticities), Y'CbCr encoding standard,
and quantization also need to be specified.

Define a 'struct ipu_ic_colorspace' that includes all the above, and pass
the input and output ipu_ic_colorspace to the IC task init functions.

This allows to actually enforce the fact that the IC:

- can only encode to/from YUV full range (follow-up patch will remove
   this restriction).
- can only encode to/from RGB full range.
- can only encode using BT.601 standard (follow-up patch will add
   Rec.709 encoding support).
- cannot convert colorspaces from input to output, the
   input and output colorspace chromaticities must be the same.

The determination of the CSC coefficients based on the input/output
colorspace parameters are moved to a new function calc_csc_coeffs(),
called by init_csc().

Signed-off-by: Steve Longerbeam 
---
  drivers/gpu/ipu-v3/ipu-ic.c | 136 +---
  drivers/gpu/ipu-v3/ipu-image-convert.c  |  27 ++--
  drivers/staging/media/imx/imx-ic-prpencvf.c |  22 +++-
  include/video/imx-ipu-v3.h  |  37 +-
  4 files changed, 154 insertions(+), 68 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index b63a2826b629..c4048c921801 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -146,8 +146,10 @@ struct ipu_ic {
const struct ic_task_regoffs *reg;
const struct ic_task_bitfields *bit;
  
-	enum ipu_color_space in_cs, g_in_cs;

-   enum ipu_color_space out_cs;
+   struct ipu_ic_colorspace in_cs;
+   struct ipu_ic_colorspace g_in_cs;
+   struct ipu_ic_colorspace out_cs;
+
bool graphics;
bool rotation;
bool in_use;
@@ -235,42 +237,83 @@ static const struct ic_encode_coeff 
ic_encode_ycbcr2rgb_601 = {
.scale = 2,
  };
  
+static int calc_csc_coeffs(struct ipu_ic_priv *priv,

+  struct ic_encode_coeff *coeff_out,
+  const struct ipu_ic_colorspace *in,
+  const struct ipu_ic_colorspace *out)
+{
+   bool inverse_encode;
+
+   if (in->colorspace != out->colorspace) {
+   dev_err(priv->ipu->dev, "Cannot convert colorspaces\n");
+   return -ENOTSUPP;
+   }

I don't think this is useful enough to warrant having the colorspace
field in ipu_ic_colorspace. Let the caller make sure of this, same as
for xfer_func.


Ok, for xfer_func it is implicit that the gamma function must be the 
same for input and output, so I agree it might as well be implicit for 
chromaticities too.






+   if (out->enc != V4L2_YCBCR_ENC_601) {
+   dev_err(priv->ipu->dev, "Only BT.601 encoding supported\n");
+   return -ENOTSUPP;
+   }

This is only important if out->cs is IPUV3_COLORSPACE_YUV, right? If the
output is RGB this field shouldn't matter.


It matters for encoding YUV to RGB, or the inverse RGB to YUV. The 
encoding standard doesn't matter only if no encoding/inverse encoding is 
requested (YUV to YUV or RGB to RGB).





+
+   if ((in->cs == IPUV3_COLORSPACE_YUV &&
+in->quant != V4L2_QUANTIZATION_FULL_RANGE) ||
+   (out->cs == IPUV3_COLORSPACE_YUV &&
+out->quant != V4L2_QUANTIZATION_FULL_RANGE)) {
+   dev_err(priv->ipu->dev, "Limited range YUV not supported\n");
+   return -ENOTSUPP;
+   }
+
+   if ((in->cs == IPUV3_COLORSPACE_RGB &&
+in->quant != V4L2_QUANTIZATION_FULL_RANGE) ||
+   (out->cs == IPUV3_COLORSPACE_RGB &&
+out->quant != V4L2_QUANTIZATION_FULL_RANGE)) {
+   dev_err(priv->ipu->dev, "Limited range RGB not supported\n");
+   return -ENOTSUPP;
+   }
+
+   if (in->cs == out->cs) {
+   *coeff_out = ic_encode_identity;
+
+   return 0;
+   }
+
+   inverse_encode = (in->cs == IPUV3_COLORSPACE_YUV);

What does inverse_encode mean in this context?


It means YUV to RGB. At this point in the function it is determined that 
encoding or inverse encoding is requested.





+
+   *coeff_out = inverse_encode ?
+   ic_encode_ycbcr2rgb_601 : ic_encode_rgb2ycbcr_601;
+
+   return 0;
+}
+
  static int init_csc(struct ipu_ic *ic,
-   enum ipu_color_space inf,
-   enum ipu_color_space outf,
+   const struct ipu_ic_colorspace *in,
+   const struct ipu_ic_colorspace *out,
int csc_index)
  {
struct ipu_ic_priv *priv = ic-&

Re: [PATCH v6 5/7] gpu: ipu-v3: ipu-ic: Add support for limited range encoding

2019-03-08 Thread Steve Longerbeam



On 3/8/19 3:57 AM, Philipp Zabel wrote:

On Thu, 2019-03-07 at 15:33 -0800, Steve Longerbeam wrote:

Add support for the following conversions:

- YUV full-range to YUV limited-range
- YUV limited-range to YUV full-range
- YUV limited-range to RGB full-range
- RGB full-range to YUV limited-range

The last two conversions require operating on the YUV full-range
encoding and inverse encoding coefficients, with the YUV-to-YUV
limited<->full coefficients. The formula to convert is

M_c = M_a * M_b
O_c = M_a * O_b + O_a

For calculating the RGB full-range to YUV limited-range coefficients:

[M_a, O_a] = YUV full-range to YUV limited-range coefficients.
[M_b, O_b] = RGB full-range to YUV full-range coefficients.

For calculating the YUV limited-range to RGB full-range coefficients:

[M_a, O_a] = YUV full-range to RGB full-range coefficients.
[M_b, O_b] = YUV limited-range to YUV full-range coefficients.

The calculation of [M_c, O_c] is carried out by the function
transform_coeffs().

In the future if RGB limited range encoding is required, the same
function can be used. And cascaded to create all combinations of
encoding for YUV limited/full range <-> RGB limited/full range,
passing the output coefficients from one call as the input for the
next.

For example, to create YUV full-range to RGB limited-range coefficients:

[M_a, O_a] = RGB full-range to RGB limited-range coefficients.
[M_b, O_b] = YUV full-range to RGB full-range coefficients.

and that output sent as input to create YUV limited-range to RGB
limited-range coefficients:

[M_a, O_a] = YUV full-range to RGB limited-range coefficients.
[M_b, O_b] = YUV limited-range to YUV full-range coefficients.

Signed-off-by: Steve Longerbeam 

I'm not a big fan of this. Wouldn't it be much easier to compute all
necessary task parameter sets offline with high precision, and store the
precomputed sets in the compact representation?


I am thinking of when support might be added for the other encoding 
standards. With this transform function, only two new task parameter 
structs need to be added, one for yuv-full-to-rgb-full, and one for 
rgb-full-to-yuv-full. Without transform_coeffs(), four structs would 
have to be added (adding encoding to and from yuv-limited). And if 
rgb-limited support is added, it would mean a total of eight new structs 
for a new encoding standard. But with transform_coeffs(), still only the 
two structs above are needed, and the function would compute the others 
automatically in runtime.


Steve





---
  drivers/gpu/ipu-v3/ipu-ic.c | 281 +---
  1 file changed, 263 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 1460901af9b5..a7dd85f8d832 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -178,10 +178,10 @@ static inline void ipu_ic_write(struct ipu_ic *ic, u32 
value, unsigned offset)
  }
  
  struct ic_encode_coeff {

-   s16 coeff[3][3];/* signed 9-bit integer coefficients */
-   s16 offset[3];  /* signed 11+2-bit fixed point offset */
-   u8 scale:2; /* scale coefficients * 2^(scale-1) */
-   bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */
+   int coeff[3][3];/* signed 9-bit integer coefficients */
+   int offset[3];  /* signed 13-bit integer offset */
+   int scale;  /* scale coefficients * 2^(scale-1) */
+   bool sat;   /* saturate to (16, 235(Y) / 240(U, V)) */
  };
  
  /*

@@ -277,6 +277,231 @@ static const struct ic_encode_coeff 
ic_encode_ycbcr2rgb_709 = {
.scale = 2,
  };
  
+/*

+ * YUV full range to YUV limited range:
+ *
+ * Y_lim  = 0.8588 * Y_full + 16
+ * Cb_lim = 0.8784 * (Cb_full - 128) + 128
+ * Cr_lim = 0.8784 * (Cr_full - 128) + 128
+ */
+static const struct ic_encode_coeff ic_encode_ycbcr_full2lim = {
+   .coeff = {
+   { 219, 0, 0 },
+   { 0, 224, 0 },
+   { 0, 0, 224 },
+   },
+   .offset = { 64, 62, 62 },
+   .scale = 1,
+};
+
+/*
+ * YUV limited range to YUV full range:
+ *
+ * Y_full  = 1.1644 * (Y_lim - 16)
+ * Cb_full = 1.1384 * (Cb_lim - 128) + 128
+ * Cr_full = 1.1384 * (Cr_lim - 128) + 128
+ */
+static const struct ic_encode_coeff ic_encode_ycbcr_lim2full = {
+   .coeff = {
+   { 149, 0, 0 },
+   { 0, 145, 0 },
+   { 0, 0, 145 },
+   },
+   .offset = { -37, -35, -35 },
+   .scale = 2,
+};
+
+/*
+ * RGB full range to RGB limited range:
+ *
+ * R_lim = 0.8588 * R_full + 16
+ * G_lim = 0.8588 * G_full + 16
+ * B_lim = 0.8588 * B_full + 16
+ */
+static const struct ic_encode_coeff
+ic_encode_rgb_full2lim __maybe_unused = {
+   .coeff = {
+   { 220, 0, 0 },
+   { 0, 220, 0 },
+   { 0, 0, 220 },
+   },
+   .offset = { 64, 64, 64 },
+   .scale = 1,
+};
+
+/*
+ * RGB limited r

[PATCH v8 4/5] gpu: ipu-v3: ipu-ic-csc: Add support for Rec.709 encoding

2019-05-21 Thread Steve Longerbeam
Add support for Rec.709 encoding and inverse encoding.

Reported-by: Tim Harvey 
Signed-off-by: Steve Longerbeam 
---
Changes in v7:
- moved CSC tables to new module ipu-ic-csc.c.
- express negative coefficients as true signed int's, for better
  readability.
Changes in v5:
- moved API changes to a previous patch.
- moved CSC coeff calc to new function calc_csc_coeffs().
Changes in v4:
- fix compile error.
Chnges in v3:
- none.
Changes in v2:
- only return "Unsupported YCbCr encoding" error if inf != outf,
  since if inf == outf, the identity matrix can be used. Reported
  by Tim Harvey.
---
 drivers/gpu/ipu-v3/ipu-ic-csc.c | 139 ++--
 1 file changed, 134 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic-csc.c b/drivers/gpu/ipu-v3/ipu-ic-csc.c
index 8e9150b1d668..09e94aa12c40 100644
--- a/drivers/gpu/ipu-v3/ipu-ic-csc.c
+++ b/drivers/gpu/ipu-v3/ipu-ic-csc.c
@@ -230,14 +230,133 @@ static const struct ipu_ic_csc_params *yuv2rgb_601[] = {
&yuvl2rgbl_601,
 };
 
+/*
+ * REC.709 encoding from RGB full range to YUV full range:
+ *
+ * Y =  .2126 * R + .7152 * G + .0722 * B
+ * U = -.1146 * R - .3854 * G + .5000 * B + 128
+ * V =  .5000 * R - .4542 * G - .0458 * B + 128
+ */
+static const struct ipu_ic_csc_params rgbf2yuvf_709 = {
+   .coeff = {
+   {  54,  183,  19 },
+   { -29,  -99, 128 },
+   { 128, -116, -12 },
+   },
+   .offset = { 0, 512, 512 },
+   .scale = 1,
+};
+
+/* Rec.709 RGB full-range to YUV limited-range */
+static const struct ipu_ic_csc_params rgbf2yuvl_709 = {
+   .coeff = {
+   {   47,  157,   16, },
+   {  -26,  -87,  112, },
+   {  112, -102,  -10, },
+   },
+   .offset = { 64, 512, 512, },
+   .scale = 1,
+   .sat = true,
+};
+
+/* Rec.709 RGB limited-range to YUV full-range */
+static const struct ipu_ic_csc_params rgbl2yuvf_709 = {
+   .coeff = {
+   {   63,  213,   22, },
+   {  -34, -115,  149, },
+   {  149, -135,  -14, },
+   },
+   .offset = { -75, 512, 512, },
+   .scale = 1,
+};
+
+/* Rec.709 RGB limited-range to YUV limited-range */
+static const struct ipu_ic_csc_params rgbl2yuvl_709 = {
+   .coeff = {
+   {   54,  183,   18, },
+   {  -30, -101,  131, },
+   {  131, -119,  -12, },
+   },
+   .offset = { 0, 512, 512, },
+   .scale = 1,
+   .sat = true,
+};
+
+/*
+ * Inverse REC.709 encoding from YUV full range to RGB full range:
+ *
+ * R = 1. * Y +  0 * (Cb - 128) + 1.5748 * (Cr - 128)
+ * G = 1. * Y -  .1873 * (Cb - 128) -  .4681 * (Cr - 128)
+ * B = 1. * Y + 1.8556 * (Cb - 128) +  0 * (Cr - 128)
+ *
+ * equivalently (factoring out the offsets):
+ *
+ * R = 1. * Y  +  0 * Cb + 1.5748 * Cr - 201.574
+ * G = 1. * Y  -  .1873 * Cb -  .4681 * Cr +  83.891
+ * B = 1. * Y  + 1.8556 * Cb +  0 * Cr - 237.517
+ */
+static const struct ipu_ic_csc_params yuvf2rgbf_709 = {
+   .coeff = {
+   {  128,   0, 202 },
+   {  128, -24, -60 },
+   {  128, 238,   0 },
+   },
+   .offset = { -403, 168, -475 },
+   .scale = 2,
+};
+
+/* Rec.709 YUV full-range to RGB limited-range */
+static const struct ipu_ic_csc_params yuvf2rgbl_709 = {
+   .coeff = {
+   {  110,0,  173, },
+   {  110,  -21,  -51, },
+   {  110,  204,0, },
+   },
+   .offset = { -314, 176, -376, },
+   .scale = 2,
+};
+
+/* Rec.709 YUV limited-range to RGB full-range */
+static const struct ipu_ic_csc_params yuvl2rgbf_709 = {
+   .coeff = {
+   {   75,0,  115, },
+   {   75,  -14,  -34, },
+   {   75,  135,0, },
+   },
+   .offset = { -248, 77, -289, },
+   .scale = 3,
+};
+
+/* Rec.709 YUV limited-range to RGB limited-range */
+static const struct ipu_ic_csc_params yuvl2rgbl_709 = {
+   .coeff = {
+   {  128,0,  197, },
+   {  128,  -23,  -59, },
+   {  128,  232,0, },
+   },
+   .offset = { -394, 164, -464, },
+   .scale = 2,
+};
+
+static const struct ipu_ic_csc_params *rgb2yuv_709[] = {
+   &rgbf2yuvf_709,
+   &rgbf2yuvl_709,
+   &rgbl2yuvf_709,
+   &rgbl2yuvl_709,
+};
+
+static const struct ipu_ic_csc_params *yuv2rgb_709[] = {
+   &yuvf2rgbf_709,
+   &yuvf2rgbl_709,
+   &yuvl2rgbf_709,
+   &yuvl2rgbl_709,
+};
+
 static int calc_csc_coeffs(struct ipu_ic_csc *csc)
 {
const struct ipu_ic_csc_params **params_tbl;
int tbl_idx;
 
-   if (csc->out_cs.enc != V4L2_YCBCR_ENC_601)
-   return -ENOTSUPP;
-
tbl_idx = (QUANT_MAP(csc->in_cs.quant) << 1) |
QUANT_MAP(csc->out_cs.quant);
 
@@ -250,8 +369,18 @@ static int calc_csc_coeffs(struct ipu_ic_csc *csc)
 
/* YUV <

[PATCH v8 1/5] gpu: ipu-v3: ipu-ic: Fix saturation bit offset in TPMEM

2019-05-21 Thread Steve Longerbeam
The saturation bit was being set at bit 9 in the second 32-bit word
of the TPMEM CSC. This isn't correct, the saturation bit is bit 42,
which is bit 10 of the second word.

Fixes: 1aa8ea0d2bd5d ("gpu: ipu-v3: Add Image Converter unit")

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
Cc: sta...@vger.kernel.org
---
 drivers/gpu/ipu-v3/ipu-ic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 594c3cbc8291..18816ccf600e 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -257,7 +257,7 @@ static int init_csc(struct ipu_ic *ic,
writel(param, base++);
 
param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
-   (params->sat << 9);
+   (params->sat << 10);
writel(param, base++);
 
param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v8 2/5] gpu: ipu-v3: ipu-ic: Fully describe colorspace conversions

2019-05-21 Thread Steve Longerbeam
Only providing the input and output RGB/YUV space to the IC task init
functions is not sufficient. To fully characterize a colorspace
conversion, the Y'CbCr encoding standard, and quantization also
need to be specified.

Define a 'struct ipu_ic_colorspace' that includes all the above.

This allows to actually enforce the fact that the IC:

- can only encode to/from YUV and RGB full range. A follow-up patch will
  remove this restriction.
- can only encode using BT.601 standard. A follow-up patch will add
  Rec.709 encoding support.

The determination of the CSC coefficients based on the input/output
'struct ipu_ic_colorspace' are moved to a new exported function
ipu_ic_calc_csc(), and 'struct ic_csc_params' is exported as
'struct ipu_ic_csc_params'. ipu_ic_calc_csc() fills a 'struct ipu_ic_csc'
with the input/output 'struct ipu_ic_colorspace' and the calculated
'struct ic_csc_params' from those input/output colorspaces.

The functions ipu_ic_task_init(_rsc)() now take a filled 'struct
ipu_ic_csc'.

The existing CSC coefficient tables and ipu_ic_calc_csc() are moved
to a new module ipu-ic-csc.c. This is in preparation for adding more
coefficient tables for limited range quantization and more encoding
standards.

The existing ycbcr2rgb and inverse rgb2ycbcr tables defined the BT.601
Y'CbCr encoding coefficients. The rgb2ycbcr table specifically described
the BT.601 encoding from full range RGB to full range YUV. Table
comments have been added in ipu-ic-csc.c to make this more clear.

The ycbcr2rgb inverse table described encoding YUV limited range to RGB
full range. To be consistent with the rgb2ycbcr table, this table is
converted to YUV full range to RGB full range, and the comments are
expanded in ipu-ic-csc.c.

The ic_csc_rgb2rgb table was just an identity matrix, so it is renamed
'identity' in ipu-ic-csc.c.

Signed-off-by: Steve Longerbeam 
---
Changes in v8:
- remove Fixes: and cc: stable. This patch is too difficult to backport
  to stable trees.
Changes in v7:
- squashed with "gpu: ipu-v3: ipu-ic: Fix BT.601 coefficients".
- moved the coefficient tables and calc_csc_coeffs() to a new
  module ipu-ic-csc.c, and added exported ipu_ic_calc_csc() to it.
- drop v4l2_colorspace (chromaticities) from 'struct ipu_ic_colorspace'.
  It's implied that xfer_func (gamma function) must be the same for input
  and output, so make that implicit for chromaticities too.
- drop passing priv to calc_csc_coeffs(), was only used to print error
  messages.
- removed the inverse_encode boolean in calc_csc_coeffs().
- express negative coefficients as true signed int's, for better
  readability.
- tweak inverse coeff in comments, no change to rounded table values.
---
 drivers/gpu/ipu-v3/Makefile |   4 +-
 drivers/gpu/ipu-v3/ipu-ic-csc.c | 129 ++
 drivers/gpu/ipu-v3/ipu-ic.c | 138 +++-
 drivers/gpu/ipu-v3/ipu-image-convert.c  |  28 ++--
 drivers/staging/media/imx/imx-ic-prpencvf.c |  34 -
 include/video/imx-ipu-v3.h  |  56 +++-
 6 files changed, 271 insertions(+), 118 deletions(-)
 create mode 100644 drivers/gpu/ipu-v3/ipu-ic-csc.c

diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile
index 7cc8b47e488b..5fe5ef20701a 100644
--- a/drivers/gpu/ipu-v3/Makefile
+++ b/drivers/gpu/ipu-v3/Makefile
@@ -2,8 +2,8 @@
 obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
 
 imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
-   ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-image-convert.o \
-   ipu-smfc.o ipu-vdi.o
+   ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
+   ipu-image-convert.o ipu-smfc.o ipu-vdi.o
 
 ifdef CONFIG_DRM
imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
diff --git a/drivers/gpu/ipu-v3/ipu-ic-csc.c b/drivers/gpu/ipu-v3/ipu-ic-csc.c
new file mode 100644
index ..5fb469cd64fe
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-ic-csc.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Mentor Graphics Inc.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "ipu-prv.h"
+
+/* identity matrix */
+static const struct ipu_ic_csc_params identity = {
+   .coeff = {
+   {  128,0,0, },
+   {0,  128,0, },
+   {0,0,  128, },
+   },
+   .offset = { 0, 0, 0, },
+   .scale = 2,
+};
+
+static const struct ipu_ic_csc_params *rgb2rgb[] = {
+   &identity,
+};
+
+static const struct ipu_ic_csc_params *yuv2yuv[] = {
+   &identity,
+};
+
+/*
+ * BT.601 RGB full-range to YUV full-range
+ *
+ * Y =  .2990 * R + .5870 * G + .1140 * B
+ * U = -.1687 * R - .3313 * G + .5000 * B + 128
+ * V =  .5000 * R - .4187 * G - .0813 * B + 128
+ */
+static const struct ipu_ic_csc_params r

[PATCH v8 3/5] gpu: ipu-v3: ipu-ic-csc: Add support for limited range encoding

2019-05-21 Thread Steve Longerbeam
Add support for encodings to or from limited range quantization.

Signed-off-by: Steve Longerbeam 
---
Changes in v7:
- hard-code the coefficients instead of deriving the limited range
  coefficients from the full2full coefficients on the fly with
  fixed-point math.
- add support for RGB limited-range.
---
 drivers/gpu/ipu-v3/ipu-ic-csc.c | 180 +---
 1 file changed, 166 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic-csc.c b/drivers/gpu/ipu-v3/ipu-ic-csc.c
index 5fb469cd64fe..8e9150b1d668 100644
--- a/drivers/gpu/ipu-v3/ipu-ic-csc.c
+++ b/drivers/gpu/ipu-v3/ipu-ic-csc.c
@@ -10,6 +10,10 @@
 #include 
 #include "ipu-prv.h"
 
+#define QUANT_MAP(q)   \
+   ((q) == V4L2_QUANTIZATION_FULL_RANGE || \
+(q) == V4L2_QUANTIZATION_DEFAULT ? 0 : 1)
+
 /* identity matrix */
 static const struct ipu_ic_csc_params identity = {
.coeff = {
@@ -21,12 +25,87 @@ static const struct ipu_ic_csc_params identity = {
.scale = 2,
 };
 
+/*
+ * RGB full-range to RGB limited-range
+ *
+ * R_lim = 0.8588 * R_full + 16
+ * G_lim = 0.8588 * G_full + 16
+ * B_lim = 0.8588 * B_full + 16
+ */
+static const struct ipu_ic_csc_params rgbf2rgbl = {
+   .coeff = {
+   {  220,0,0, },
+   {0,  220,0, },
+   {0,0,  220, },
+   },
+   .offset = { 64, 64, 64, },
+   .scale = 1,
+};
+
+/*
+ * RGB limited-range to RGB full-range
+ *
+ * R_full = 1.1644 * (R_lim - 16)
+ * G_full = 1.1644 * (G_lim - 16)
+ * B_full = 1.1644 * (B_lim - 16)
+ */
+static const struct ipu_ic_csc_params rgbl2rgbf = {
+   .coeff = {
+   {  149,0,0, },
+   {0,  149,0, },
+   {0,0,  149, },
+   },
+   .offset = { -37, -37, -37, },
+   .scale = 2,
+};
+
+/*
+ * YUV full-range to YUV limited-range
+ *
+ * Y_lim  = 0.8588 * Y_full + 16
+ * Cb_lim = 0.8784 * (Cb_full - 128) + 128
+ * Cr_lim = 0.8784 * (Cr_full - 128) + 128
+ */
+static const struct ipu_ic_csc_params yuvf2yuvl = {
+   .coeff = {
+   {  220,0,0, },
+   {0,  225,0, },
+   {0,0,  225, },
+   },
+   .offset = { 64, 62, 62, },
+   .scale = 1,
+   .sat = true,
+};
+
+/*
+ * YUV limited-range to YUV full-range
+ *
+ * Y_full  = 1.1644 * (Y_lim - 16)
+ * Cb_full = 1.1384 * (Cb_lim - 128) + 128
+ * Cr_full = 1.1384 * (Cr_lim - 128) + 128
+ */
+static const struct ipu_ic_csc_params yuvl2yuvf = {
+   .coeff = {
+   {  149,0,0, },
+   {0,  146,0, },
+   {0,0,  146, },
+   },
+   .offset = { -37, -35, -35, },
+   .scale = 2,
+};
+
 static const struct ipu_ic_csc_params *rgb2rgb[] = {
&identity,
+   &rgbf2rgbl,
+   &rgbl2rgbf,
+   &identity,
 };
 
 static const struct ipu_ic_csc_params *yuv2yuv[] = {
&identity,
+   &yuvf2yuvl,
+   &yuvl2yuvf,
+   &identity,
 };
 
 /*
@@ -46,6 +125,41 @@ static const struct ipu_ic_csc_params rgbf2yuvf_601 = {
.scale = 1,
 };
 
+/* BT.601 RGB full-range to YUV limited-range */
+static const struct ipu_ic_csc_params rgbf2yuvl_601 = {
+   .coeff = {
+   {   66,  129,   25, },
+   {  -38,  -74,  112, },
+   {  112,  -94,  -18, },
+   },
+   .offset = { 64, 512, 512, },
+   .scale = 1,
+   .sat = true,
+};
+
+/* BT.601 RGB limited-range to YUV full-range */
+static const struct ipu_ic_csc_params rgbl2yuvf_601 = {
+   .coeff = {
+   {   89,  175,   34, },
+   {  -50,  -99,  149, },
+   {  149, -125,  -24, },
+   },
+   .offset = { -75, 512, 512, },
+   .scale = 1,
+};
+
+/* BT.601 RGB limited-range to YUV limited-range */
+static const struct ipu_ic_csc_params rgbl2yuvl_601 = {
+   .coeff = {
+   {   77,  150,   29, },
+   {  -44,  -87,  131, },
+   {  131, -110,  -21, },
+   },
+   .offset = { 0, 512, 512, },
+   .scale = 1,
+   .sat = true,
+};
+
 /*
  * BT.601 YUV full-range to RGB full-range
  *
@@ -69,39 +183,77 @@ static const struct ipu_ic_csc_params yuvf2rgbf_601 = {
.scale = 2,
 };
 
+/* BT.601 YUV full-range to RGB limited-range */
+static const struct ipu_ic_csc_params yuvf2rgbl_601 = {
+   .coeff = {
+   {  110,0,  154, },
+   {  110,  -38,  -78, },
+   {  110,  195,0, },
+   },
+   .offset = { -276, 265, -358, },
+   .scale = 2,
+};
+
+/* BT.601 YUV limited-range to RGB full-range */
+static const struct ipu_ic_csc_params yuvl2rgbf_601 = {
+   .coeff = {
+   {   75,0,  102, },
+   {   75,  -25,  -52, },
+   {   75,  129,0, },
+   },
+   .offset = { -223, 136, -277, },
+   .scale = 3,
+};
+
+/* BT.

[PATCH 1/3] gpu: ipu-v3: image-convert: Fix input bytesperline width/height align

2019-06-11 Thread Steve Longerbeam
The output width and height alignment values were being used in the
input bytesperline calculation. Fix by separating local vars w_align
and h_align into w_align_in, h_align_in, w_align_out, and h_align_out.

Fixes: d966e23d61a2c ("gpu: ipu-v3: image-convert: fix bytesperline
adjustment")

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-image-convert.c | 32 +-
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index 36e88434513a..36eb4c77ad91 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -1876,7 +1876,8 @@ void ipu_image_convert_adjust(struct ipu_image *in, 
struct ipu_image *out,
  enum ipu_rotate_mode rot_mode)
 {
const struct ipu_image_pixfmt *infmt, *outfmt;
-   u32 w_align, h_align;
+   u32 w_align_out, h_align_out;
+   u32 w_align_in, h_align_in;
 
infmt = get_format(in->pix.pixelformat);
outfmt = get_format(out->pix.pixelformat);
@@ -1908,22 +1909,31 @@ void ipu_image_convert_adjust(struct ipu_image *in, 
struct ipu_image *out,
}
 
/* align input width/height */
-   w_align = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt, rot_mode));
-   h_align = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt, rot_mode));
-   in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W, w_align);
-   in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H, h_align);
+   w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
+   rot_mode));
+   h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
+rot_mode));
+   in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
+   w_align_in);
+   in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
+h_align_in);
 
/* align output width/height */
-   w_align = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt, rot_mode));
-   h_align = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt, rot_mode));
-   out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W, w_align);
-   out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H, h_align);
+   w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
+rot_mode));
+   h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
+ rot_mode));
+   out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
+w_align_out);
+   out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
+ h_align_out);
 
/* set input/output strides and image sizes */
in->pix.bytesperline = infmt->planar ?
-   clamp_align(in->pix.width, 2 << w_align, MAX_W, w_align) :
+   clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
+   w_align_in) :
clamp_align((in->pix.width * infmt->bpp) >> 3,
-   2 << w_align, MAX_W, w_align);
+   2 << w_align_in, MAX_W, w_align_in);
in->pix.sizeimage = infmt->planar ?
(in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
in->pix.height * in->pix.bytesperline;
-- 
2.17.1



[PATCH 2/3] gpu: ipu-v3: image-convert: Fix input bytesperline for packed formats

2019-06-11 Thread Steve Longerbeam
The input bytesperline calculation for packed pixel formats was
incorrect. The min/max clamping values must be multiplied by the
packed bits-per-pixel. This was causing corrupted converted images
when the input format was RGB4 (probably also other input packed
formats).

Fixes: d966e23d61a2c ("gpu: ipu-v3: image-convert: fix bytesperline
adjustment")

Reported-by: Harsha Manjula Mallikarjun 
Suggested-by: Harsha Manjula Mallikarjun 

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-image-convert.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index 36eb4c77ad91..4dfdbd1adf0d 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -1933,7 +1933,9 @@ void ipu_image_convert_adjust(struct ipu_image *in, 
struct ipu_image *out,
clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
w_align_in) :
clamp_align((in->pix.width * infmt->bpp) >> 3,
-   2 << w_align_in, MAX_W, w_align_in);
+   ((2 << w_align_in) * infmt->bpp) >> 3,
+   (MAX_W * infmt->bpp) >> 3,
+   w_align_in);
in->pix.sizeimage = infmt->planar ?
(in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
in->pix.height * in->pix.bytesperline;
-- 
2.17.1



[PATCH 3/3] gpu: ipu-v3: image-convert: Fix image downsize coefficients

2019-06-11 Thread Steve Longerbeam
The output of the IC downsizer unit in both dimensions must be <= 1024
before being passed to the IC resizer unit. This was causing corrupted
images when:

input_dim > 1024, and
input_dim / 2 < output_dim < input_dim

Some broken examples were 1920x1080 -> 1024x768 and 1920x1080 ->
1280x1080.

Fixes: 70b9b6b3bcb21 ("gpu: ipu-v3: image-convert: calculate per-tile
resize coefficients")

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-image-convert.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index 4dfdbd1adf0d..e744f3527ce1 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -400,12 +400,14 @@ static int calc_image_resize_coefficients(struct 
ipu_image_convert_ctx *ctx,
if (WARN_ON(resized_width == 0 || resized_height == 0))
return -EINVAL;
 
-   while (downsized_width >= resized_width * 2) {
+   while (downsized_width > 1024 ||
+  downsized_width >= resized_width * 2) {
downsized_width >>= 1;
downsize_coeff_h++;
}
 
-   while (downsized_height >= resized_height * 2) {
+   while (downsized_height > 1024 ||
+  downsized_height >= resized_height * 2) {
downsized_height >>= 1;
downsize_coeff_v++;
}
-- 
2.17.1



[PATCH v7 3/5] gpu: ipu-v3: ipu-ic-csc: Add support for limited range encoding

2019-04-06 Thread Steve Longerbeam
Add support for encodings to or from limited range quantization.

Signed-off-by: Steve Longerbeam 
---
Changes in v7:
- hard-code the coefficients instead of deriving the limited range
  coefficients from the full2full coefficients on the fly with
  fixed-point math.
- add support for RGB limited-range.
---
 drivers/gpu/ipu-v3/ipu-ic-csc.c | 180 +---
 1 file changed, 166 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic-csc.c b/drivers/gpu/ipu-v3/ipu-ic-csc.c
index 5fb469cd64fe..8e9150b1d668 100644
--- a/drivers/gpu/ipu-v3/ipu-ic-csc.c
+++ b/drivers/gpu/ipu-v3/ipu-ic-csc.c
@@ -10,6 +10,10 @@
 #include 
 #include "ipu-prv.h"
 
+#define QUANT_MAP(q)   \
+   ((q) == V4L2_QUANTIZATION_FULL_RANGE || \
+(q) == V4L2_QUANTIZATION_DEFAULT ? 0 : 1)
+
 /* identity matrix */
 static const struct ipu_ic_csc_params identity = {
.coeff = {
@@ -21,12 +25,87 @@ static const struct ipu_ic_csc_params identity = {
.scale = 2,
 };
 
+/*
+ * RGB full-range to RGB limited-range
+ *
+ * R_lim = 0.8588 * R_full + 16
+ * G_lim = 0.8588 * G_full + 16
+ * B_lim = 0.8588 * B_full + 16
+ */
+static const struct ipu_ic_csc_params rgbf2rgbl = {
+   .coeff = {
+   {  220,0,0, },
+   {0,  220,0, },
+   {0,0,  220, },
+   },
+   .offset = { 64, 64, 64, },
+   .scale = 1,
+};
+
+/*
+ * RGB limited-range to RGB full-range
+ *
+ * R_full = 1.1644 * (R_lim - 16)
+ * G_full = 1.1644 * (G_lim - 16)
+ * B_full = 1.1644 * (B_lim - 16)
+ */
+static const struct ipu_ic_csc_params rgbl2rgbf = {
+   .coeff = {
+   {  149,0,0, },
+   {0,  149,0, },
+   {0,0,  149, },
+   },
+   .offset = { -37, -37, -37, },
+   .scale = 2,
+};
+
+/*
+ * YUV full-range to YUV limited-range
+ *
+ * Y_lim  = 0.8588 * Y_full + 16
+ * Cb_lim = 0.8784 * (Cb_full - 128) + 128
+ * Cr_lim = 0.8784 * (Cr_full - 128) + 128
+ */
+static const struct ipu_ic_csc_params yuvf2yuvl = {
+   .coeff = {
+   {  220,0,0, },
+   {0,  225,0, },
+   {0,0,  225, },
+   },
+   .offset = { 64, 62, 62, },
+   .scale = 1,
+   .sat = true,
+};
+
+/*
+ * YUV limited-range to YUV full-range
+ *
+ * Y_full  = 1.1644 * (Y_lim - 16)
+ * Cb_full = 1.1384 * (Cb_lim - 128) + 128
+ * Cr_full = 1.1384 * (Cr_lim - 128) + 128
+ */
+static const struct ipu_ic_csc_params yuvl2yuvf = {
+   .coeff = {
+   {  149,0,0, },
+   {0,  146,0, },
+   {0,0,  146, },
+   },
+   .offset = { -37, -35, -35, },
+   .scale = 2,
+};
+
 static const struct ipu_ic_csc_params *rgb2rgb[] = {
&identity,
+   &rgbf2rgbl,
+   &rgbl2rgbf,
+   &identity,
 };
 
 static const struct ipu_ic_csc_params *yuv2yuv[] = {
&identity,
+   &yuvf2yuvl,
+   &yuvl2yuvf,
+   &identity,
 };
 
 /*
@@ -46,6 +125,41 @@ static const struct ipu_ic_csc_params rgbf2yuvf_601 = {
.scale = 1,
 };
 
+/* BT.601 RGB full-range to YUV limited-range */
+static const struct ipu_ic_csc_params rgbf2yuvl_601 = {
+   .coeff = {
+   {   66,  129,   25, },
+   {  -38,  -74,  112, },
+   {  112,  -94,  -18, },
+   },
+   .offset = { 64, 512, 512, },
+   .scale = 1,
+   .sat = true,
+};
+
+/* BT.601 RGB limited-range to YUV full-range */
+static const struct ipu_ic_csc_params rgbl2yuvf_601 = {
+   .coeff = {
+   {   89,  175,   34, },
+   {  -50,  -99,  149, },
+   {  149, -125,  -24, },
+   },
+   .offset = { -75, 512, 512, },
+   .scale = 1,
+};
+
+/* BT.601 RGB limited-range to YUV limited-range */
+static const struct ipu_ic_csc_params rgbl2yuvl_601 = {
+   .coeff = {
+   {   77,  150,   29, },
+   {  -44,  -87,  131, },
+   {  131, -110,  -21, },
+   },
+   .offset = { 0, 512, 512, },
+   .scale = 1,
+   .sat = true,
+};
+
 /*
  * BT.601 YUV full-range to RGB full-range
  *
@@ -69,39 +183,77 @@ static const struct ipu_ic_csc_params yuvf2rgbf_601 = {
.scale = 2,
 };
 
+/* BT.601 YUV full-range to RGB limited-range */
+static const struct ipu_ic_csc_params yuvf2rgbl_601 = {
+   .coeff = {
+   {  110,0,  154, },
+   {  110,  -38,  -78, },
+   {  110,  195,0, },
+   },
+   .offset = { -276, 265, -358, },
+   .scale = 2,
+};
+
+/* BT.601 YUV limited-range to RGB full-range */
+static const struct ipu_ic_csc_params yuvl2rgbf_601 = {
+   .coeff = {
+   {   75,0,  102, },
+   {   75,  -25,  -52, },
+   {   75,  129,0, },
+   },
+   .offset = { -223, 136, -277, },
+   .scale = 3,
+};
+
+/* BT.

[PATCH v7 4/5] gpu: ipu-v3: ipu-ic-csc: Add support for Rec.709 encoding

2019-04-06 Thread Steve Longerbeam
Add support for Rec.709 encoding and inverse encoding.

Reported-by: Tim Harvey 
Signed-off-by: Steve Longerbeam 
---
Changes in v7:
- moved CSC tables to new module ipu-ic-csc.c.
- express negative coefficients as true signed int's, for better
  readability.
Changes in v5:
- moved API changes to a previous patch.
- moved CSC coeff calc to new function calc_csc_coeffs().
Changes in v4:
- fix compile error.
Chnges in v3:
- none.
Changes in v2:
- only return "Unsupported YCbCr encoding" error if inf != outf,
  since if inf == outf, the identity matrix can be used. Reported
  by Tim Harvey.
---
 drivers/gpu/ipu-v3/ipu-ic-csc.c | 139 ++--
 1 file changed, 134 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic-csc.c b/drivers/gpu/ipu-v3/ipu-ic-csc.c
index 8e9150b1d668..09e94aa12c40 100644
--- a/drivers/gpu/ipu-v3/ipu-ic-csc.c
+++ b/drivers/gpu/ipu-v3/ipu-ic-csc.c
@@ -230,14 +230,133 @@ static const struct ipu_ic_csc_params *yuv2rgb_601[] = {
&yuvl2rgbl_601,
 };
 
+/*
+ * REC.709 encoding from RGB full range to YUV full range:
+ *
+ * Y =  .2126 * R + .7152 * G + .0722 * B
+ * U = -.1146 * R - .3854 * G + .5000 * B + 128
+ * V =  .5000 * R - .4542 * G - .0458 * B + 128
+ */
+static const struct ipu_ic_csc_params rgbf2yuvf_709 = {
+   .coeff = {
+   {  54,  183,  19 },
+   { -29,  -99, 128 },
+   { 128, -116, -12 },
+   },
+   .offset = { 0, 512, 512 },
+   .scale = 1,
+};
+
+/* Rec.709 RGB full-range to YUV limited-range */
+static const struct ipu_ic_csc_params rgbf2yuvl_709 = {
+   .coeff = {
+   {   47,  157,   16, },
+   {  -26,  -87,  112, },
+   {  112, -102,  -10, },
+   },
+   .offset = { 64, 512, 512, },
+   .scale = 1,
+   .sat = true,
+};
+
+/* Rec.709 RGB limited-range to YUV full-range */
+static const struct ipu_ic_csc_params rgbl2yuvf_709 = {
+   .coeff = {
+   {   63,  213,   22, },
+   {  -34, -115,  149, },
+   {  149, -135,  -14, },
+   },
+   .offset = { -75, 512, 512, },
+   .scale = 1,
+};
+
+/* Rec.709 RGB limited-range to YUV limited-range */
+static const struct ipu_ic_csc_params rgbl2yuvl_709 = {
+   .coeff = {
+   {   54,  183,   18, },
+   {  -30, -101,  131, },
+   {  131, -119,  -12, },
+   },
+   .offset = { 0, 512, 512, },
+   .scale = 1,
+   .sat = true,
+};
+
+/*
+ * Inverse REC.709 encoding from YUV full range to RGB full range:
+ *
+ * R = 1. * Y +  0 * (Cb - 128) + 1.5748 * (Cr - 128)
+ * G = 1. * Y -  .1873 * (Cb - 128) -  .4681 * (Cr - 128)
+ * B = 1. * Y + 1.8556 * (Cb - 128) +  0 * (Cr - 128)
+ *
+ * equivalently (factoring out the offsets):
+ *
+ * R = 1. * Y  +  0 * Cb + 1.5748 * Cr - 201.574
+ * G = 1. * Y  -  .1873 * Cb -  .4681 * Cr +  83.891
+ * B = 1. * Y  + 1.8556 * Cb +  0 * Cr - 237.517
+ */
+static const struct ipu_ic_csc_params yuvf2rgbf_709 = {
+   .coeff = {
+   {  128,   0, 202 },
+   {  128, -24, -60 },
+   {  128, 238,   0 },
+   },
+   .offset = { -403, 168, -475 },
+   .scale = 2,
+};
+
+/* Rec.709 YUV full-range to RGB limited-range */
+static const struct ipu_ic_csc_params yuvf2rgbl_709 = {
+   .coeff = {
+   {  110,0,  173, },
+   {  110,  -21,  -51, },
+   {  110,  204,0, },
+   },
+   .offset = { -314, 176, -376, },
+   .scale = 2,
+};
+
+/* Rec.709 YUV limited-range to RGB full-range */
+static const struct ipu_ic_csc_params yuvl2rgbf_709 = {
+   .coeff = {
+   {   75,0,  115, },
+   {   75,  -14,  -34, },
+   {   75,  135,0, },
+   },
+   .offset = { -248, 77, -289, },
+   .scale = 3,
+};
+
+/* Rec.709 YUV limited-range to RGB limited-range */
+static const struct ipu_ic_csc_params yuvl2rgbl_709 = {
+   .coeff = {
+   {  128,0,  197, },
+   {  128,  -23,  -59, },
+   {  128,  232,0, },
+   },
+   .offset = { -394, 164, -464, },
+   .scale = 2,
+};
+
+static const struct ipu_ic_csc_params *rgb2yuv_709[] = {
+   &rgbf2yuvf_709,
+   &rgbf2yuvl_709,
+   &rgbl2yuvf_709,
+   &rgbl2yuvl_709,
+};
+
+static const struct ipu_ic_csc_params *yuv2rgb_709[] = {
+   &yuvf2rgbf_709,
+   &yuvf2rgbl_709,
+   &yuvl2rgbf_709,
+   &yuvl2rgbl_709,
+};
+
 static int calc_csc_coeffs(struct ipu_ic_csc *csc)
 {
const struct ipu_ic_csc_params **params_tbl;
int tbl_idx;
 
-   if (csc->out_cs.enc != V4L2_YCBCR_ENC_601)
-   return -ENOTSUPP;
-
tbl_idx = (QUANT_MAP(csc->in_cs.quant) << 1) |
QUANT_MAP(csc->out_cs.quant);
 
@@ -250,8 +369,18 @@ static int calc_csc_coeffs(struct ipu_ic_csc *csc)
 
/* YUV <

[PATCH v7 1/5] gpu: ipu-v3: ipu-ic: Fix saturation bit offset in TPMEM

2019-04-06 Thread Steve Longerbeam
The saturation bit was being set at bit 9 in the second 32-bit word
of the TPMEM CSC. This isn't correct, the saturation bit is bit 42,
which is bit 10 of the second word.

Fixes: 1aa8ea0d2bd5d ("gpu: ipu-v3: Add Image Converter unit")

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
Cc: sta...@vger.kernel.org
---
 drivers/gpu/ipu-v3/ipu-ic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 594c3cbc8291..18816ccf600e 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -257,7 +257,7 @@ static int init_csc(struct ipu_ic *ic,
writel(param, base++);
 
param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
-   (params->sat << 9);
+   (params->sat << 10);
writel(param, base++);
 
param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v7 2/5] gpu: ipu-v3: ipu-ic: Fully describe colorspace conversions

2019-04-06 Thread Steve Longerbeam
Only providing the input and output RGB/YUV space to the IC task init
functions is not sufficient. To fully characterize a colorspace
conversion, the Y'CbCr encoding standard, and quantization also
need to be specified.

Define a 'struct ipu_ic_colorspace' that includes all the above.

This allows to actually enforce the fact that the IC:

- can only encode to/from YUV and RGB full range. A follow-up patch will
  remove this restriction.
- can only encode using BT.601 standard. A follow-up patch will add
  Rec.709 encoding support.

The determination of the CSC coefficients based on the input/output
'struct ipu_ic_colorspace' are moved to a new exported function
ipu_ic_calc_csc(), and 'struct ic_csc_params' is exported as
'struct ipu_ic_csc_params'. ipu_ic_calc_csc() fills a 'struct ipu_ic_csc'
with the input/output 'struct ipu_ic_colorspace' and the calculated
'struct ic_csc_params' from those input/output colorspaces.

The functions ipu_ic_task_init(_rsc)() now take a filled 'struct
ipu_ic_csc'.

The existing CSC coefficient tables and ipu_ic_calc_csc() are moved
to a new module ipu-ic-csc.c. This is in preparation for adding more
coefficient tables for limited range quantization and more encoding
standards.

The existing ycbcr2rgb and inverse rgb2ycbcr tables defined the BT.601
Y'CbCr encoding coefficients. The rgb2ycbcr table specifically described
the BT.601 encoding from full range RGB to full range YUV. Table
comments have been added in ipu-ic-csc.c to make this more clear.

The ycbcr2rgb inverse table described encoding YUV limited range to RGB
full range. To be consistent with the rgb2ycbcr table, this table is
converted to YUV full range to RGB full range, and the comments are
expanded in ipu-ic-csc.c.

The ic_csc_rgb2rgb table was just an identity matrix, so it is renamed
'identity' in ipu-ic-csc.c.

Fixes: 1aa8ea0d2bd5d ("gpu: ipu-v3: Add Image Converter unit")

Signed-off-by: Steve Longerbeam 
Cc: sta...@vger.kernel.org
---
Changes in v7:
- squashed with "gpu: ipu-v3: ipu-ic: Fix BT.601 coefficients".
- moved the coefficient tables and calc_csc_coeffs() to a new
  module ipu-ic-csc.c, and added exported ipu_ic_calc_csc() to it.
- drop v4l2_colorspace (chromaticities) from 'struct ipu_ic_colorspace'.
  It's implied that xfer_func (gamma function) must be the same for input
  and output, so make that implicit for chromaticities too.
- drop passing priv to calc_csc_coeffs(), was only used to print error
  messages.
- removed the inverse_encode boolean in calc_csc_coeffs().
- express negative coefficients as true signed int's, for better
  readability.
- tweak inverse coeff in comments, no change to rounded table values.
---
 drivers/gpu/ipu-v3/Makefile |   4 +-
 drivers/gpu/ipu-v3/ipu-ic-csc.c | 129 ++
 drivers/gpu/ipu-v3/ipu-ic.c | 138 +++-
 drivers/gpu/ipu-v3/ipu-image-convert.c  |  28 ++--
 drivers/staging/media/imx/imx-ic-prpencvf.c |  34 -
 include/video/imx-ipu-v3.h  |  56 +++-
 6 files changed, 271 insertions(+), 118 deletions(-)
 create mode 100644 drivers/gpu/ipu-v3/ipu-ic-csc.c

diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile
index 7cc8b47e488b..5fe5ef20701a 100644
--- a/drivers/gpu/ipu-v3/Makefile
+++ b/drivers/gpu/ipu-v3/Makefile
@@ -2,8 +2,8 @@
 obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
 
 imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
-   ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-image-convert.o \
-   ipu-smfc.o ipu-vdi.o
+   ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
+   ipu-image-convert.o ipu-smfc.o ipu-vdi.o
 
 ifdef CONFIG_DRM
imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
diff --git a/drivers/gpu/ipu-v3/ipu-ic-csc.c b/drivers/gpu/ipu-v3/ipu-ic-csc.c
new file mode 100644
index ..5fb469cd64fe
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-ic-csc.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Mentor Graphics Inc.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "ipu-prv.h"
+
+/* identity matrix */
+static const struct ipu_ic_csc_params identity = {
+   .coeff = {
+   {  128,0,0, },
+   {0,  128,0, },
+   {0,0,  128, },
+   },
+   .offset = { 0, 0, 0, },
+   .scale = 2,
+};
+
+static const struct ipu_ic_csc_params *rgb2rgb[] = {
+   &identity,
+};
+
+static const struct ipu_ic_csc_params *yuv2yuv[] = {
+   &identity,
+};
+
+/*
+ * BT.601 RGB full-range to YUV full-range
+ *
+ * Y =  .2990 * R + .5870 * G + .1140 * B
+ * U = -.1687 * R - .3313 * G + .5000 * B + 128
+ * V =  .5000 * R - .4187 * G - .0813 * B + 128
+ */
+static const struct ipu_ic_csc_params rgbf2yuvf_601 = {
+   

Re: [PATCH v5 02/12] gpu: ipu-csi: Swap fields according to input/output field types

2018-12-10 Thread Steve Longerbeam

Hi Philipp, can you review this patch and give it your ack?

Thanks,
Steve


On 10/16/18 5:00 PM, Steve Longerbeam wrote:

The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
---
Changes since v4:
- Cleaned up some convoluted code in ipu_csi_init_interface(), suggested
   by Philipp Zabel.
- Fixed a regression in csi_setup(), caught by Philipp.
---
  drivers/gpu/ipu-v3/ipu-csi.c  | 119 +++---
  drivers/staging/media/imx/imx-media-csi.c |  17 +---
  include/video/imx-ipu-v3.h|   3 +-
  3 files changed, 88 insertions(+), 51 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index aa0e30a2ba18..4a15e513fa05 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,6 +325,15 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code,
return 0;
  }
  
+/* translate alternate field mode based on given standard */

+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
  /*
   * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
   */
@@ -374,22 +383,75 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
return 0;
  }
  
+static int ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,

+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt,
+  v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   }
+
+   ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
+
+   return 0;
+}
+
+
  int ipu_csi_init_interface(struct ipu_csi *csi,
   struct v4l2_mbus_config *mbus_cfg,
-  struct v4l2_mbus_framefmt *mbus_fmt)
+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt)
  {
struct ipu_csi_bus_config cfg;
unsigned long flags;
u32 width, height, data = 0;
+   v4l2_std_id std;
int ret;
  
-	ret = fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);

+   ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
if (ret < 0)
return re

[PATCH v6] gpu: ipu-csi: Swap fields according to input/output field types

2018-12-16 Thread Steve Longerbeam
The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
Reviewed-by: Philipp Zabel 
---
Changes since v5:
- Convert to const the infmt, outfmt, and mbus_cfg pointer args to
  ipu_csi_init_interface(), suggested by Philipp Zabel.
- Bring back if_fmt local var and don't copy outfmt to local stack in
  csi_setup(), suggested by Philipp.

Changes since v4:
- Cleaned up some convoluted code in ipu_csi_init_interface(), suggested
  by Philipp.
- Fixed a regression in csi_setup(), caught by Philipp.
---
 drivers/gpu/ipu-v3/ipu-csi.c  | 126 +++---
 drivers/staging/media/imx/imx-media-csi.c |   7 +-
 include/video/imx-ipu-v3.h|   5 +-
 3 files changed, 89 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index aa0e30a2ba18..d1e575571a8d 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,12 +325,21 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code,
return 0;
 }
 
+/* translate alternate field mode based on given standard */
+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
 /*
  * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
  */
 static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
-struct v4l2_mbus_config *mbus_cfg,
-struct v4l2_mbus_framefmt *mbus_fmt)
+   const struct v4l2_mbus_config *mbus_cfg,
+   const struct v4l2_mbus_framefmt *mbus_fmt)
 {
int ret;
 
@@ -374,22 +383,76 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
return 0;
 }
 
+static int
+ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+   const struct v4l2_mbus_framefmt *infmt,
+   const struct v4l2_mbus_framefmt *outfmt,
+   v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   }
+
+   ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
+
+   return 0;
+}
+
+
 int ipu_csi_init_interface(struct ipu_csi *csi,
-  struct v4l2_mbus_config *mbus_cfg,
-  

Re: [PATCH v5 02/12] gpu: ipu-csi: Swap fields according to input/output field types

2018-12-16 Thread Steve Longerbeam



On 12/13/18 4:59 AM, Philipp Zabel wrote:

Hi Steve,

On Tue, 2018-10-16 at 17:00 -0700, Steve Longerbeam wrote:

The function ipu_csi_init_interface() was inverting the F-bit for
NTSC case, in the CCIR_CODE_1/2 registers. The result being that
for NTSC bottom-top field order, the CSI would swap fields and
capture in top-bottom order.

Instead, base field swap on the field order of the input to the CSI,
and the field order of the requested output. If the input/output
fields are sequential but different, swap fields, otherwise do
not swap. This requires passing both the input and output mbus
frame formats to ipu_csi_init_interface().

Move this code to a new private function ipu_csi_set_bt_interlaced_codes()
that programs the CCIR_CODE_1/2 registers for interlaced BT.656 (and
possibly interlaced BT.1120 in the future).

When detecting input video standard from the input frame width/height,
make sure to double height if input field type is alternate, since
in that case input height only includes lines for one field.

Signed-off-by: Steve Longerbeam 
---
Changes since v4:
- Cleaned up some convoluted code in ipu_csi_init_interface(), suggested
   by Philipp Zabel.
- Fixed a regression in csi_setup(), caught by Philipp.
---
  drivers/gpu/ipu-v3/ipu-csi.c  | 119 +++---
  drivers/staging/media/imx/imx-media-csi.c |  17 +---
  include/video/imx-ipu-v3.h|   3 +-
  3 files changed, 88 insertions(+), 51 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index aa0e30a2ba18..4a15e513fa05 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,6 +325,15 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code,
return 0;
  }
  
+/* translate alternate field mode based on given standard */

+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+   return (field != V4L2_FIELD_ALTERNATE) ? field :
+   ((std & V4L2_STD_525_60) ?
+V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
  /*
   * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
   */
@@ -374,22 +383,75 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config 
*csicfg,
return 0;
  }
  
+static int ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,

+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt,

infmt and outfmt parameters could be const.


Agreed, I will convert these pointer args to const. And since we are 
changing the API to ipu_csi_init_interface() anyway, I went ahead and 
converted the mbus_cfg, infmt, and outfmt pointer args to const there as 
well.




+  v4l2_std_id std)
+{
+   enum v4l2_field infield, outfield;
+   bool swap_fields;
+
+   /* get translated field type of input and output */
+   infield = ipu_csi_translate_field(infmt->field, std);
+   outfield = ipu_csi_translate_field(outfmt->field, std);
+
+   /*
+* Write the H-V-F codes the CSI will match against the
+* incoming data for start/end of active and blanking
+* field intervals. If input and output field types are
+* sequential but not the same (one is SEQ_BT and the other
+* is SEQ_TB), swap the F-bit so that the CSI will capture
+* field 1 lines before field 0 lines.
+*/
+   swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+  V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+  infield != outfield);
+
+   if (!swap_fields) {
+   /*
+* Field0BlankEnd  = 110, Field0BlankStart  = 010
+* Field0ActiveEnd = 100, Field0ActiveStart = 000
+* Field1BlankEnd  = 111, Field1BlankStart  = 011
+* Field1ActiveEnd = 101, Field1ActiveStart = 001
+*/
+   ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+   } else {
+   dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+   /* same as above but with F-bit inverted */
+   ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   }
+
+   ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
+
+   return 0;
+}
+
+
  int ipu_csi_init_interface(struct ipu_csi *csi,
   struct v4l2_mbus_config *mbus_cfg,
-  struct v4l2_mbus_framefmt *mbus_fmt)
+  struct v4l2_mbus_framefmt *infmt,
+  struct v4l2_mbus_framefmt *outfmt)
  {
struct ipu_csi_bus_config cfg;
unsi

[PATCH] gpu: ipu-v3: image-convert: Wait for channels before disabling

2020-06-09 Thread Steve Longerbeam
Call ipu_idmac_wait_busy() on each idmac channel to busy wait for the
channel to be idle before disabling. Otherwise it was found that a
conversion would stall after the completion of a tile and the start
of the next tile.

Fixes: 0537db801bb01 ("gpu: ipu-v3: image-convert: reconfigure IC per tile")
Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-image-convert.c | 21 +
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index eeca50d9a1ee..f0938015d2fd 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -1251,6 +1251,19 @@ static int get_run_count(struct ipu_image_convert_ctx 
*ctx,
return count;
 }
 
+static void stop_channel(struct ipu_image_convert_chan *chan,
+struct ipuv3_channel *channel)
+{
+   struct ipu_image_convert_priv *priv = chan->priv;
+   int ret;
+
+   ret = ipu_idmac_wait_busy(channel, 1);
+   if (ret == -ETIMEDOUT)
+   dev_warn(priv->ipu->dev, "IDMAC timeout\n");
+
+   ipu_idmac_disable_channel(channel);
+}
+
 static void convert_stop(struct ipu_image_convert_run *run)
 {
struct ipu_image_convert_ctx *ctx = run->ctx;
@@ -1262,12 +1275,12 @@ static void convert_stop(struct ipu_image_convert_run 
*run)
 
/* disable IC tasks and the channels */
ipu_ic_task_disable(chan->ic);
-   ipu_idmac_disable_channel(chan->in_chan);
-   ipu_idmac_disable_channel(chan->out_chan);
+   stop_channel(chan, chan->in_chan);
+   stop_channel(chan, chan->out_chan);
 
if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
-   ipu_idmac_disable_channel(chan->rotation_in_chan);
-   ipu_idmac_disable_channel(chan->rotation_out_chan);
+   stop_channel(chan, chan->rotation_in_chan);
+   stop_channel(chan, chan->rotation_out_chan);
ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
}
 
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH] gpu: ipu-v3: image-convert: Wait for channels before disabling

2020-06-17 Thread Steve Longerbeam

Hi Philpp,

Please disregard this patch. A better solution to a busy wait with a 
spin lock held is to wait for all required EOF interrupts before doing 
tile completion processing. I will submit a new patch series.


Steve


On 6/9/20 5:51 PM, Steve Longerbeam wrote:

Call ipu_idmac_wait_busy() on each idmac channel to busy wait for the
channel to be idle before disabling. Otherwise it was found that a
conversion would stall after the completion of a tile and the start
of the next tile.

Fixes: 0537db801bb01 ("gpu: ipu-v3: image-convert: reconfigure IC per tile")
Signed-off-by: Steve Longerbeam 
---
  drivers/gpu/ipu-v3/ipu-image-convert.c | 21 +
  1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index eeca50d9a1ee..f0938015d2fd 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -1251,6 +1251,19 @@ static int get_run_count(struct ipu_image_convert_ctx 
*ctx,
return count;
  }
  
+static void stop_channel(struct ipu_image_convert_chan *chan,

+struct ipuv3_channel *channel)
+{
+   struct ipu_image_convert_priv *priv = chan->priv;
+   int ret;
+
+   ret = ipu_idmac_wait_busy(channel, 1);
+   if (ret == -ETIMEDOUT)
+   dev_warn(priv->ipu->dev, "IDMAC timeout\n");
+
+   ipu_idmac_disable_channel(channel);
+}
+
  static void convert_stop(struct ipu_image_convert_run *run)
  {
struct ipu_image_convert_ctx *ctx = run->ctx;
@@ -1262,12 +1275,12 @@ static void convert_stop(struct ipu_image_convert_run 
*run)
  
  	/* disable IC tasks and the channels */

ipu_ic_task_disable(chan->ic);
-   ipu_idmac_disable_channel(chan->in_chan);
-   ipu_idmac_disable_channel(chan->out_chan);
+   stop_channel(chan, chan->in_chan);
+   stop_channel(chan, chan->out_chan);
  
  	if (ipu_rot_mode_is_irt(ctx->rot_mode)) {

-   ipu_idmac_disable_channel(chan->rotation_in_chan);
-   ipu_idmac_disable_channel(chan->rotation_out_chan);
+   stop_channel(chan, chan->rotation_in_chan);
+   stop_channel(chan, chan->rotation_out_chan);
ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
}
  


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 3/3] gpu: ipu-v3: image-convert: Wait for all EOFs before completing a tile

2020-06-17 Thread Steve Longerbeam
Use a bit-mask of EOF irqs to determine when all required idmac
channel EOFs have been received for a tile conversion, and only do
tile completion processing after all EOFs have been received. Otherwise
it was found that a conversion would stall after the completion of a
tile and the start of the next tile, because the input/read idmac
channel had not completed and entered idle state, thus locking up the
channel when attempting to re-start it for the next tile.

Fixes: 0537db801bb01 ("gpu: ipu-v3: image-convert: reconfigure IC per tile")
Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-image-convert.c | 108 ++---
 1 file changed, 81 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index f8b031ded3cf..43e82eb79a08 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -137,6 +137,17 @@ struct ipu_image_convert_ctx;
 struct ipu_image_convert_chan;
 struct ipu_image_convert_priv;
 
+enum eof_irq_mask {
+   EOF_IRQ_IN  = BIT(0),
+   EOF_IRQ_ROT_IN  = BIT(1),
+   EOF_IRQ_OUT = BIT(2),
+   EOF_IRQ_ROT_OUT = BIT(3),
+};
+
+#define EOF_IRQ_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT)
+#define EOF_IRQ_ROT_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT |   \
+ EOF_IRQ_ROT_IN | EOF_IRQ_ROT_OUT)
+
 struct ipu_image_convert_ctx {
struct ipu_image_convert_chan *chan;
 
@@ -173,6 +184,9 @@ struct ipu_image_convert_ctx {
/* where to place converted tile in dest image */
unsigned int out_tile_map[MAX_TILES];
 
+   /* mask of completed EOF irqs at every tile conversion */
+   enum eof_irq_mask eof_mask;
+
struct list_head list;
 };
 
@@ -189,6 +203,8 @@ struct ipu_image_convert_chan {
struct ipuv3_channel *rotation_out_chan;
 
/* the IPU end-of-frame irqs */
+   int in_eof_irq;
+   int rot_in_eof_irq;
int out_eof_irq;
int rot_out_eof_irq;
 
@@ -1380,6 +1396,9 @@ static int convert_start(struct ipu_image_convert_run 
*run, unsigned int tile)
dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> 
%u\n",
__func__, chan->ic_task, ctx, run, tile, dst_tile);
 
+   /* clear EOF irq mask */
+   ctx->eof_mask = 0;
+
if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
/* swap width/height for resizer */
dest_width = d_image->tile[dst_tile].height;
@@ -1615,7 +1634,7 @@ static bool ic_settings_changed(struct 
ipu_image_convert_ctx *ctx)
 }
 
 /* hold irqlock when calling */
-static irqreturn_t do_irq(struct ipu_image_convert_run *run)
+static irqreturn_t do_tile_complete(struct ipu_image_convert_run *run)
 {
struct ipu_image_convert_ctx *ctx = run->ctx;
struct ipu_image_convert_chan *chan = ctx->chan;
@@ -1715,8 +1734,9 @@ static irqreturn_t eof_irq(int irq, void *data)
struct ipu_image_convert_priv *priv = chan->priv;
struct ipu_image_convert_ctx *ctx;
struct ipu_image_convert_run *run;
+   irqreturn_t ret = IRQ_HANDLED;
+   bool tile_complete = false;
unsigned long flags;
-   irqreturn_t ret;
 
spin_lock_irqsave(&chan->irqlock, flags);
 
@@ -1729,27 +1749,33 @@ static irqreturn_t eof_irq(int irq, void *data)
 
ctx = run->ctx;
 
-   if (irq == chan->out_eof_irq) {
-   if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
-   /* this is a rotation op, just ignore */
-   ret = IRQ_HANDLED;
-   goto out;
-   }
-   } else if (irq == chan->rot_out_eof_irq) {
+   if (irq == chan->in_eof_irq) {
+   ctx->eof_mask |= EOF_IRQ_IN;
+   } else if (irq == chan->out_eof_irq) {
+   ctx->eof_mask |= EOF_IRQ_OUT;
+   } else if (irq == chan->rot_in_eof_irq ||
+  irq == chan->rot_out_eof_irq) {
if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
/* this was NOT a rotation op, shouldn't happen */
dev_err(priv->ipu->dev,
"Unexpected rotation interrupt\n");
-   ret = IRQ_HANDLED;
goto out;
}
+   ctx->eof_mask |= (irq == chan->rot_in_eof_irq) ?
+   EOF_IRQ_ROT_IN : EOF_IRQ_ROT_OUT;
} else {
dev_err(priv->ipu->dev, "Received unknown irq %d\n", irq);
ret = IRQ_NONE;
goto out;
}
 
-   ret = do_irq(run);
+   if (ipu_rot_mode_is_irt(ctx->rot_mode))
+   tile_complete = (ctx->eof_mask == EOF_IRQ_ROT_COMPLETE);
+   else
+   tile_complete = (ctx->eof_mask == EOF_IRQ_COMPLETE);
+
+   if (tile_comp

[PATCH 2/3] gpu: ipu-v3: image-convert: Combine rotate/no-rotate irq handlers

2020-06-17 Thread Steve Longerbeam
Combine the rotate_irq() and norotate_irq() handlers into a single
eof_irq() handler.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-image-convert.c | 58 +-
 1 file changed, 20 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index eeca50d9a1ee..f8b031ded3cf 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -1709,9 +1709,10 @@ static irqreturn_t do_irq(struct ipu_image_convert_run 
*run)
return IRQ_WAKE_THREAD;
 }
 
-static irqreturn_t norotate_irq(int irq, void *data)
+static irqreturn_t eof_irq(int irq, void *data)
 {
struct ipu_image_convert_chan *chan = data;
+   struct ipu_image_convert_priv *priv = chan->priv;
struct ipu_image_convert_ctx *ctx;
struct ipu_image_convert_run *run;
unsigned long flags;
@@ -1728,45 +1729,26 @@ static irqreturn_t norotate_irq(int irq, void *data)
 
ctx = run->ctx;
 
-   if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
-   /* this is a rotation operation, just ignore */
-   spin_unlock_irqrestore(&chan->irqlock, flags);
-   return IRQ_HANDLED;
-   }
-
-   ret = do_irq(run);
-out:
-   spin_unlock_irqrestore(&chan->irqlock, flags);
-   return ret;
-}
-
-static irqreturn_t rotate_irq(int irq, void *data)
-{
-   struct ipu_image_convert_chan *chan = data;
-   struct ipu_image_convert_priv *priv = chan->priv;
-   struct ipu_image_convert_ctx *ctx;
-   struct ipu_image_convert_run *run;
-   unsigned long flags;
-   irqreturn_t ret;
-
-   spin_lock_irqsave(&chan->irqlock, flags);
-
-   /* get current run and its context */
-   run = chan->current_run;
-   if (!run) {
+   if (irq == chan->out_eof_irq) {
+   if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+   /* this is a rotation op, just ignore */
+   ret = IRQ_HANDLED;
+   goto out;
+   }
+   } else if (irq == chan->rot_out_eof_irq) {
+   if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
+   /* this was NOT a rotation op, shouldn't happen */
+   dev_err(priv->ipu->dev,
+   "Unexpected rotation interrupt\n");
+   ret = IRQ_HANDLED;
+   goto out;
+   }
+   } else {
+   dev_err(priv->ipu->dev, "Received unknown irq %d\n", irq);
ret = IRQ_NONE;
goto out;
}
 
-   ctx = run->ctx;
-
-   if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
-   /* this was NOT a rotation operation, shouldn't happen */
-   dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
-   spin_unlock_irqrestore(&chan->irqlock, flags);
-   return IRQ_HANDLED;
-   }
-
ret = do_irq(run);
 out:
spin_unlock_irqrestore(&chan->irqlock, flags);
@@ -1859,7 +1841,7 @@ static int get_ipu_resources(struct 
ipu_image_convert_chan *chan)
  chan->out_chan,
  IPU_IRQ_EOF);
 
-   ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
+   ret = request_threaded_irq(chan->out_eof_irq, eof_irq, do_bh,
   0, "ipu-ic", chan);
if (ret < 0) {
dev_err(priv->ipu->dev, "could not acquire irq %d\n",
@@ -1872,7 +1854,7 @@ static int get_ipu_resources(struct 
ipu_image_convert_chan *chan)
 chan->rotation_out_chan,
 IPU_IRQ_EOF);
 
-   ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
+   ret = request_threaded_irq(chan->rot_out_eof_irq, eof_irq, do_bh,
   0, "ipu-ic", chan);
if (ret < 0) {
dev_err(priv->ipu->dev, "could not acquire irq %d\n",
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 1/3] gpu: ipu-v3: Restore RGB32, BGR32

2020-06-17 Thread Steve Longerbeam
RGB32 and BGR32 formats were inadvertently removed from the switch
statement in ipu_pixelformat_to_colorspace(). Restore them.

Fixes: a59957172b0c ("gpu: ipu-v3: enable remaining 32-bit RGB V4L2 pixel 
formats")
Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-common.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index ee2a025e54cf..b3dae9ec1a38 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -124,6 +124,8 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 
pixelformat)
case V4L2_PIX_FMT_RGBX32:
case V4L2_PIX_FMT_ARGB32:
case V4L2_PIX_FMT_XRGB32:
+   case V4L2_PIX_FMT_RGB32:
+   case V4L2_PIX_FMT_BGR32:
return IPUV3_COLORSPACE_RGB;
default:
return IPUV3_COLORSPACE_UNKNOWN;
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 3/3] gpu: ipu-v3: image-convert: Wait for all EOFs before completing a tile

2020-06-25 Thread Steve Longerbeam
Use a bit-mask of EOF irqs to determine when all required idmac
channel EOFs have been received for a tile conversion, and only do
tile completion processing after all EOFs have been received. Otherwise
it was found that a conversion would stall after the completion of a
tile and the start of the next tile, because the input/read idmac
channel had not completed and entered idle state, thus locking up the
channel when attempting to re-start it for the next tile.

Fixes: 0537db801bb01 ("gpu: ipu-v3: image-convert: reconfigure IC per tile")
Signed-off-by: Steve Longerbeam 
---
Changes in v2:
- need to clear eof_mask at completion of every tile, not just in
  convert_start().
---
 drivers/gpu/ipu-v3/ipu-image-convert.c | 109 +++--
 1 file changed, 82 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index f8b031ded3cf..aa1d4b6d278f 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -137,6 +137,17 @@ struct ipu_image_convert_ctx;
 struct ipu_image_convert_chan;
 struct ipu_image_convert_priv;
 
+enum eof_irq_mask {
+   EOF_IRQ_IN  = BIT(0),
+   EOF_IRQ_ROT_IN  = BIT(1),
+   EOF_IRQ_OUT = BIT(2),
+   EOF_IRQ_ROT_OUT = BIT(3),
+};
+
+#define EOF_IRQ_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT)
+#define EOF_IRQ_ROT_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT |   \
+ EOF_IRQ_ROT_IN | EOF_IRQ_ROT_OUT)
+
 struct ipu_image_convert_ctx {
struct ipu_image_convert_chan *chan;
 
@@ -173,6 +184,9 @@ struct ipu_image_convert_ctx {
/* where to place converted tile in dest image */
unsigned int out_tile_map[MAX_TILES];
 
+   /* mask of completed EOF irqs at every tile conversion */
+   enum eof_irq_mask eof_mask;
+
struct list_head list;
 };
 
@@ -189,6 +203,8 @@ struct ipu_image_convert_chan {
struct ipuv3_channel *rotation_out_chan;
 
/* the IPU end-of-frame irqs */
+   int in_eof_irq;
+   int rot_in_eof_irq;
int out_eof_irq;
int rot_out_eof_irq;
 
@@ -1380,6 +1396,9 @@ static int convert_start(struct ipu_image_convert_run 
*run, unsigned int tile)
dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> 
%u\n",
__func__, chan->ic_task, ctx, run, tile, dst_tile);
 
+   /* clear EOF irq mask */
+   ctx->eof_mask = 0;
+
if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
/* swap width/height for resizer */
dest_width = d_image->tile[dst_tile].height;
@@ -1615,7 +1634,7 @@ static bool ic_settings_changed(struct 
ipu_image_convert_ctx *ctx)
 }
 
 /* hold irqlock when calling */
-static irqreturn_t do_irq(struct ipu_image_convert_run *run)
+static irqreturn_t do_tile_complete(struct ipu_image_convert_run *run)
 {
struct ipu_image_convert_ctx *ctx = run->ctx;
struct ipu_image_convert_chan *chan = ctx->chan;
@@ -1700,6 +1719,7 @@ static irqreturn_t do_irq(struct ipu_image_convert_run 
*run)
ctx->cur_buf_num ^= 1;
}
 
+   ctx->eof_mask = 0; /* clear EOF irq mask for next tile */
ctx->next_tile++;
return IRQ_HANDLED;
 done:
@@ -1715,8 +1735,9 @@ static irqreturn_t eof_irq(int irq, void *data)
struct ipu_image_convert_priv *priv = chan->priv;
struct ipu_image_convert_ctx *ctx;
struct ipu_image_convert_run *run;
+   irqreturn_t ret = IRQ_HANDLED;
+   bool tile_complete = false;
unsigned long flags;
-   irqreturn_t ret;
 
spin_lock_irqsave(&chan->irqlock, flags);
 
@@ -1729,27 +1750,33 @@ static irqreturn_t eof_irq(int irq, void *data)
 
ctx = run->ctx;
 
-   if (irq == chan->out_eof_irq) {
-   if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
-   /* this is a rotation op, just ignore */
-   ret = IRQ_HANDLED;
-   goto out;
-   }
-   } else if (irq == chan->rot_out_eof_irq) {
+   if (irq == chan->in_eof_irq) {
+   ctx->eof_mask |= EOF_IRQ_IN;
+   } else if (irq == chan->out_eof_irq) {
+   ctx->eof_mask |= EOF_IRQ_OUT;
+   } else if (irq == chan->rot_in_eof_irq ||
+  irq == chan->rot_out_eof_irq) {
if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
/* this was NOT a rotation op, shouldn't happen */
dev_err(priv->ipu->dev,
"Unexpected rotation interrupt\n");
-   ret = IRQ_HANDLED;
goto out;
}
+   ctx->eof_mask |= (irq == chan->rot_in_eof_irq) ?
+   EOF_IRQ_ROT_IN : EOF_IRQ_ROT_OUT;
} else {
dev_err(priv->ipu->de

Re: [PATCH v2 3/3] gpu: ipu-v3: image-convert: Wait for all EOFs before completing a tile

2020-06-26 Thread Steve Longerbeam

Hi Philipp,

On 6/26/20 2:38 AM, Philipp Zabel wrote:

Hi Steve,

On Thu, 2020-06-25 at 11:13 -0700, Steve Longerbeam wrote:

Use a bit-mask of EOF irqs to determine when all required idmac
channel EOFs have been received for a tile conversion, and only do
tile completion processing after all EOFs have been received. Otherwise
it was found that a conversion would stall after the completion of a
tile and the start of the next tile, because the input/read idmac
channel had not completed and entered idle state, thus locking up the
channel when attempting to re-start it for the next tile.

Do I understand correctly that there are cases where the output channel
EOF IRQ has triggered and the next tile processing is kicked off before
the input channel EOF IRQ triggers even without rotation?


Yes.

What is the cause of this? It would seem that the read channel EOF 
should occur before the write channel EOF, but there are cases seen 
where the opposite occurs. Maybe this has to do with idmac channel 
priorities, the IC PP read/write channels are set to the same priority 
(low), in which case the IPU should resort to round-robin when handling 
requests on those channels. Maybe the EOF irq is not signalled until 
after the IPU has updated CPMEM with status info after the transfers 
complete, and round-robin selects the write channel before the read 
channel for the CPMEM updates?




Do you have any way to reproduce this?


Yes, try a scaling only conversion, 1920x1080.422p -> 1024x768.422p. No 
rotation needed.


Steve



regards
Philipp


Fixes: 0537db801bb01 ("gpu: ipu-v3: image-convert: reconfigure IC per tile")
Signed-off-by: Steve Longerbeam 
---
Changes in v2:
- need to clear eof_mask at completion of every tile, not just in
   convert_start().
---
  drivers/gpu/ipu-v3/ipu-image-convert.c | 109 +++--
  1 file changed, 82 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c 
b/drivers/gpu/ipu-v3/ipu-image-convert.c
index f8b031ded3cf..aa1d4b6d278f 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -137,6 +137,17 @@ struct ipu_image_convert_ctx;
  struct ipu_image_convert_chan;
  struct ipu_image_convert_priv;
  
+enum eof_irq_mask {

+   EOF_IRQ_IN  = BIT(0),
+   EOF_IRQ_ROT_IN  = BIT(1),
+   EOF_IRQ_OUT = BIT(2),
+   EOF_IRQ_ROT_OUT = BIT(3),
+};
+
+#define EOF_IRQ_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT)
+#define EOF_IRQ_ROT_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT |   \
+ EOF_IRQ_ROT_IN | EOF_IRQ_ROT_OUT)
+
  struct ipu_image_convert_ctx {
struct ipu_image_convert_chan *chan;
  
@@ -173,6 +184,9 @@ struct ipu_image_convert_ctx {

/* where to place converted tile in dest image */
unsigned int out_tile_map[MAX_TILES];
  
+	/* mask of completed EOF irqs at every tile conversion */

+   enum eof_irq_mask eof_mask;
+
struct list_head list;
  };
  
@@ -189,6 +203,8 @@ struct ipu_image_convert_chan {

struct ipuv3_channel *rotation_out_chan;
  
  	/* the IPU end-of-frame irqs */

+   int in_eof_irq;
+   int rot_in_eof_irq;
int out_eof_irq;
int rot_out_eof_irq;
  
@@ -1380,6 +1396,9 @@ static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)

dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> 
%u\n",
__func__, chan->ic_task, ctx, run, tile, dst_tile);
  
+	/* clear EOF irq mask */

+   ctx->eof_mask = 0;
+
if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
/* swap width/height for resizer */
dest_width = d_image->tile[dst_tile].height;
@@ -1615,7 +1634,7 @@ static bool ic_settings_changed(struct 
ipu_image_convert_ctx *ctx)
  }
  
  /* hold irqlock when calling */

-static irqreturn_t do_irq(struct ipu_image_convert_run *run)
+static irqreturn_t do_tile_complete(struct ipu_image_convert_run *run)
  {
struct ipu_image_convert_ctx *ctx = run->ctx;
struct ipu_image_convert_chan *chan = ctx->chan;
@@ -1700,6 +1719,7 @@ static irqreturn_t do_irq(struct ipu_image_convert_run 
*run)
ctx->cur_buf_num ^= 1;
}
  
+	ctx->eof_mask = 0; /* clear EOF irq mask for next tile */

ctx->next_tile++;
return IRQ_HANDLED;
  done:
@@ -1715,8 +1735,9 @@ static irqreturn_t eof_irq(int irq, void *data)
struct ipu_image_convert_priv *priv = chan->priv;
struct ipu_image_convert_ctx *ctx;
struct ipu_image_convert_run *run;
+   irqreturn_t ret = IRQ_HANDLED;
+   bool tile_complete = false;
unsigned long flags;
-   irqreturn_t ret;
  
  	spin_lock_irqsave(&chan->irqlock, flags);
  
@@ -1729,27 +1750,33 @@ static irqreturn_t eof_irq(int irq, void *data)
  
  	ctx = run->ctx;
  
-	if (irq == chan->out_eof_irq) {

-   if (ipu_rot_mode_is_irt(ctx-

[PATCH 01/16] gpu: ipu-v3: Add Video Deinterlacer unit

2016-07-07 Thread Steve Longerbeam
Adds the Video Deinterlacer (VDIC) unit.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/Makefile |   2 +-
 drivers/gpu/ipu-v3/ipu-common.c |  11 ++
 drivers/gpu/ipu-v3/ipu-prv.h|   6 +
 drivers/gpu/ipu-v3/ipu-vdi.c| 266 
 include/video/imx-ipu-v3.h  |  27 
 5 files changed, 311 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/ipu-v3/ipu-vdi.c

diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile
index 107ec23..aeba9dc 100644
--- a/drivers/gpu/ipu-v3/Makefile
+++ b/drivers/gpu/ipu-v3/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o

 imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
-   ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o
+   ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o ipu-vdi.o
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 99dcacf..30dc115 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -833,6 +833,14 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
goto err_ic;
}

+   ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
+  IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
+  IPU_CONF_IC_INPUT);
+   if (ret) {
+   unit = "vdi";
+   goto err_vdi;
+   }
+
ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
  IPU_CONF_DI0_EN, ipu_clk);
if (ret) {
@@ -887,6 +895,8 @@ err_dc:
 err_di_1:
ipu_di_exit(ipu, 0);
 err_di_0:
+   ipu_vdi_exit(ipu);
+err_vdi:
ipu_ic_exit(ipu);
 err_ic:
ipu_csi_exit(ipu, 1);
@@ -971,6 +981,7 @@ static void ipu_submodules_exit(struct ipu_soc *ipu)
ipu_dc_exit(ipu);
ipu_di_exit(ipu, 1);
ipu_di_exit(ipu, 0);
+   ipu_vdi_exit(ipu);
ipu_ic_exit(ipu);
ipu_csi_exit(ipu, 1);
ipu_csi_exit(ipu, 0);
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index bfb1e8a..845f64c 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -138,6 +138,7 @@ struct ipu_dc_priv;
 struct ipu_dmfc_priv;
 struct ipu_di;
 struct ipu_ic_priv;
+struct ipu_vdi;
 struct ipu_smfc_priv;

 struct ipu_devtype;
@@ -169,6 +170,7 @@ struct ipu_soc {
struct ipu_di   *di_priv[2];
struct ipu_csi  *csi_priv[2];
struct ipu_ic_priv  *ic_priv;
+   struct ipu_vdi  *vdi_priv;
struct ipu_smfc_priv*smfc_priv;
 };

@@ -199,6 +201,10 @@ int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
unsigned long base, unsigned long tpmem_base);
 void ipu_ic_exit(struct ipu_soc *ipu);

+int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
+unsigned long base, u32 module);
+void ipu_vdi_exit(struct ipu_soc *ipu);
+
 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
unsigned long base, u32 module, struct clk *ipu_clk);
 void ipu_di_exit(struct ipu_soc *ipu, int id);
diff --git a/drivers/gpu/ipu-v3/ipu-vdi.c b/drivers/gpu/ipu-v3/ipu-vdi.c
new file mode 100644
index 000..1303bcc
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-vdi.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2012 Mentor Graphics Inc.
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "ipu-prv.h"
+
+struct ipu_vdi {
+   void __iomem *base;
+   u32 module;
+   spinlock_t lock;
+   int use_count;
+   struct ipu_soc *ipu;
+};
+
+
+/* VDI Register Offsets */
+#define VDI_FSIZE 0x
+#define VDI_C 0x0004
+
+/* VDI Register Fields */
+#define VDI_C_CH_420 (0 << 1)
+#define VDI_C_CH_422 (1 << 1)
+#define VDI_C_MOT_SEL_MASK   (0x3 << 2)
+#define VDI_C_MOT_SEL_FULL   (2 << 2)
+#define VDI_C_MOT_SEL_LOW(1 << 2)
+#define VDI_C_MOT_SEL_MED(0 << 2)
+#define VDI_C_BURST_SIZE1_4  (3 << 4)
+#define VDI_C_BURST_SIZE2_4  (3 << 8)
+#define VDI_C_BURST_SIZE3_4  (3 << 12)
+#define VDI_C_BURST_SIZE_MASK0xF
+#define VDI_C_BURST_SIZE1_OFFSET 4
+#define VDI_C_BURST_SIZE2_OFFSET 8
+#define VDI_C_BURST_SIZE3_OFFSET 12
+#define VDI_C_V

[PATCH 02/16] gpu: ipu-cpmem: Add ipu_cpmem_set_uv_offset()

2016-07-07 Thread Steve Longerbeam
Adds ipu_cpmem_set_uv_offset(), to set planar U/V offsets.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c | 7 +++
 include/video/imx-ipu-v3.h | 1 +
 2 files changed, 8 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 6494a4d..a36c35e 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -253,6 +253,13 @@ void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int 
bufnum, dma_addr_t buf)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);

+void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
+{
+   ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
+   ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
+
 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
 {
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 22662a1..904fd12 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -194,6 +194,7 @@ void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int 
xres, int yres);
 void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t 
buf);
+void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
-- 
1.9.1



[PATCH 03/16] gpu: ipu-cpmem: Add ipu_cpmem_get_burstsize()

2016-07-07 Thread Steve Longerbeam
Adds ipu_cpmem_get_burstsize().

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-cpmem.c | 6 ++
 include/video/imx-ipu-v3.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index a36c35e..fcb7dc8 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -275,6 +275,12 @@ void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);

+int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
+{
+   return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
+
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
 {
ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 904fd12..60540ead 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -197,6 +197,7 @@ void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int 
bufnum, dma_addr_t buf);
 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
+int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
 void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
 void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
-- 
1.9.1



[PATCH 04/16] gpu: ipu-v3: Add ipu_get_num()

2016-07-07 Thread Steve Longerbeam
Adds of-alias id to ipu_soc and retrieve with ipu_get_num().

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-common.c | 8 
 drivers/gpu/ipu-v3/ipu-prv.h| 1 +
 include/video/imx-ipu-v3.h  | 1 +
 3 files changed, 10 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 30dc115..49af121 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -45,6 +45,12 @@ static inline void ipu_cm_write(struct ipu_soc *ipu, u32 
value, unsigned offset)
writel(value, ipu->cm_reg + offset);
 }

+int ipu_get_num(struct ipu_soc *ipu)
+{
+   return ipu->id;
+}
+EXPORT_SYMBOL_GPL(ipu_get_num);
+
 void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
 {
u32 val;
@@ -1220,6 +1226,7 @@ static int ipu_probe(struct platform_device *pdev)
 {
const struct of_device_id *of_id =
of_match_device(imx_ipu_dt_ids, &pdev->dev);
+   struct device_node *np = pdev->dev.of_node;
struct ipu_soc *ipu;
struct resource *res;
unsigned long ipu_base;
@@ -1248,6 +1255,7 @@ static int ipu_probe(struct platform_device *pdev)
ipu->channel[i].ipu = ipu;
ipu->devtype = devtype;
ipu->ipu_type = devtype->type;
+   ipu->id = of_alias_get_id(np, "ipu");

spin_lock_init(&ipu->lock);
mutex_init(&ipu->channel_lock);
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index 845f64c..02057d8 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -153,6 +153,7 @@ struct ipu_soc {
void __iomem*cm_reg;
void __iomem*idmac_reg;

+   int id;
int usecount;

struct clk  *clk;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 60540ead..b174f8a 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -148,6 +148,7 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct 
ipuv3_channel *channel,
 /*
  * IPU Common functions
  */
+int ipu_get_num(struct ipu_soc *ipu);
 void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
 void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
 void ipu_dump(struct ipu_soc *ipu);
-- 
1.9.1



[PATCH 00/16] IPUv3 prep for i.MX5/6 v4l2 staging drivers

2016-07-07 Thread Steve Longerbeam
These updates to IPUv3 are needed for media staging drivers
for i.MX5/6 video capture and mem2mem.

Steve Longerbeam (15):
  gpu: ipu-v3: Add Video Deinterlacer unit
  gpu: ipu-cpmem: Add ipu_cpmem_set_uv_offset()
  gpu: ipu-cpmem: Add ipu_cpmem_get_burstsize()
  gpu: ipu-v3: Add ipu_get_num()
  gpu: ipu-v3: Add IDMA channel linking support
  gpu: ipu-v3: Add ipu_set_vdi_src_mux()
  gpu: ipu-v3: Add VDI input IDMAC channels
  gpu: ipu-v3: Add ipu_csi_set_src()
  gpu: ipu-v3: Add ipu_ic_set_src()
  gpu: ipu-v3: set correct full sensor frame for PAL/NTSC
  gpu: ipu-v3: Fix CSI data format for 16-bit media bus formats
  gpu: ipu-v3: Fix IRT usage
  gpu: ipu-ic: Add complete image conversion support with tiling
  gpu: ipu-ic: allow multiple handles to ic
  gpu: ipu-v3: rename CSI client device

Suresh Dhandapani (1):
  gpu: ipu-v3: Fix CSI0 blur in NTSC format

 drivers/gpu/ipu-v3/Makefile |2 +-
 drivers/gpu/ipu-v3/ipu-common.c |  155 +++-
 drivers/gpu/ipu-v3/ipu-cpmem.c  |   13 +
 drivers/gpu/ipu-v3/ipu-csi.c|   36 +-
 drivers/gpu/ipu-v3/ipu-ic.c | 1769 ++-
 drivers/gpu/ipu-v3/ipu-prv.h|7 +
 drivers/gpu/ipu-v3/ipu-vdi.c|  266 ++
 include/video/imx-ipu-v3.h  |   96 ++-
 8 files changed, 2283 insertions(+), 61 deletions(-)
 create mode 100644 drivers/gpu/ipu-v3/ipu-vdi.c

-- 
1.9.1



[PATCH 06/16] gpu: ipu-v3: Add ipu_set_vdi_src_mux()

2016-07-07 Thread Steve Longerbeam
Adds ipu_set_vdi_src_mux() that selects the VDIC input
(from CSI or memory).

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-common.c | 20 
 include/video/imx-ipu-v3.h  |  1 +
 2 files changed, 21 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 6d1676e..374100e 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -730,6 +730,26 @@ void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, 
bool vdi)
 }
 EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);

+/*
+ * Set the source for the VDIC. Selects either from CSI[01] or memory.
+ */
+void ipu_set_vdi_src_mux(struct ipu_soc *ipu, bool csi)
+{
+   unsigned long flags;
+   u32 val;
+
+   spin_lock_irqsave(&ipu->lock, flags);
+
+   val = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+   val &= ~(0x3 << 28);
+   if (csi)
+   val |= (0x01 << 28);
+   ipu_cm_write(ipu, val, IPU_FS_PROC_FLOW1);
+
+   spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_set_vdi_src_mux);
+

 /* IDMAC Channel Linking */

diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 0a39c64..586979e 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -152,6 +152,7 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct 
ipuv3_channel *channel,
 int ipu_get_num(struct ipu_soc *ipu);
 void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
 void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
+void ipu_set_vdi_src_mux(struct ipu_soc *ipu, bool csi);
 void ipu_dump(struct ipu_soc *ipu);

 /*
-- 
1.9.1



[PATCH 08/16] gpu: ipu-v3: Add ipu_csi_set_src()

2016-07-07 Thread Steve Longerbeam
Adds ipu_csi_set_src() which is just a wrapper around
ipu_set_csi_src_mux().

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-csi.c | 8 
 include/video/imx-ipu-v3.h   | 1 +
 2 files changed, 9 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index 06631ac..336dc06 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -609,6 +609,14 @@ int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
 }
 EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);

+int ipu_csi_set_src(struct ipu_csi *csi, u32 vc, bool select_mipi_csi2)
+{
+   ipu_set_csi_src_mux(csi->ipu, csi->id, select_mipi_csi2);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_src);
+
 int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
 {
unsigned long flags;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 2302fc5..57b487d 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -301,6 +301,7 @@ int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
  struct v4l2_mbus_framefmt *mbus_fmt);
 int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
  u32 max_ratio, u32 id);
+int ipu_csi_set_src(struct ipu_csi *csi, u32 vc, bool select_mipi_csi2);
 int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest);
 int ipu_csi_enable(struct ipu_csi *csi);
 int ipu_csi_disable(struct ipu_csi *csi);
-- 
1.9.1



[PATCH 09/16] gpu: ipu-v3: Add ipu_ic_set_src()

2016-07-07 Thread Steve Longerbeam
Adds ipu_ic_set_src() which is just aa wrapper around
ipu_set_ic_src_mux().

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-ic.c | 10 ++
 include/video/imx-ipu-v3.h  |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 1dcb96c..f306a9c 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -629,6 +629,16 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);

+int ipu_ic_set_src(struct ipu_ic *ic, int csi_id, bool vdi)
+{
+   struct ipu_ic_priv *priv = ic->priv;
+
+   ipu_set_ic_src_mux(priv->ipu, csi_id, vdi);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_set_src);
+
 int ipu_ic_enable(struct ipu_ic *ic)
 {
struct ipu_ic_priv *priv = ic->priv;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 57b487d..8f77ddb 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -334,6 +334,7 @@ void ipu_ic_task_disable(struct ipu_ic *ic);
 int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
  u32 width, u32 height, int burst_size,
  enum ipu_rotate_mode rot);
+int ipu_ic_set_src(struct ipu_ic *ic, int csi_id, bool vdi);
 int ipu_ic_enable(struct ipu_ic *ic);
 int ipu_ic_disable(struct ipu_ic *ic);
 struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task);
-- 
1.9.1



[PATCH 10/16] gpu: ipu-v3: set correct full sensor frame for PAL/NTSC

2016-07-07 Thread Steve Longerbeam
Set the sensor full frame based on whether the passed in mbus_fmt
is 720x480 (NTSC) or 720x576 (PAL).

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-csi.c | 20 +---
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index 336dc06..07c7091 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -365,10 +365,14 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
 {
struct ipu_csi_bus_config cfg;
unsigned long flags;
-   u32 data = 0;
+   u32 width, height, data = 0;

fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);

+   /* set default sensor frame width and height */
+   width = mbus_fmt->width;
+   height = mbus_fmt->height;
+
/* Set the CSI_SENS_CONF register remaining fields */
data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
@@ -386,11 +390,6 @@ int ipu_csi_init_interface(struct ipu_csi *csi,

ipu_csi_write(csi, data, CSI_SENS_CONF);

-   /* Setup sensor frame size */
-   ipu_csi_write(csi,
- (mbus_fmt->width - 1) | ((mbus_fmt->height - 1) << 16),
- CSI_SENS_FRM_SIZE);
-
/* Set CCIR registers */

switch (cfg.clk_mode) {
@@ -408,11 +407,12 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
 * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
 * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
 */
+   height = 625; /* framelines for PAL */
+
ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
  CSI_CCIR_CODE_1);
ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
-
} else if (mbus_fmt->width == 720 && mbus_fmt->height == 480) {
/*
 * NTSC case
@@ -422,6 +422,8 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
 * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
 * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
 */
+   height = 525; /* framelines for NTSC */
+
ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
  CSI_CCIR_CODE_1);
ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
@@ -447,6 +449,10 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
break;
}

+   /* Setup sensor frame size */
+   ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
+ CSI_SENS_FRM_SIZE);
+
dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
ipu_csi_read(csi, CSI_SENS_CONF));
dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
-- 
1.9.1



[PATCH 11/16] gpu: ipu-v3: Fix CSI data format for 16-bit media bus formats

2016-07-07 Thread Steve Longerbeam
The CSI data format was being programmed incorrectly for the
1x16 media bus formats. The CSI data format for 16-bit must
be bayer/generic (CSI_SENS_CONF_DATA_FMT_BAYER).

Suggested-by: Carsten Resch 
Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-csi.c | 6 +-
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index 07c7091..0eac28c 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -258,12 +258,8 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config 
*cfg, u32 mbus_code)
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
break;
case MEDIA_BUS_FMT_UYVY8_1X16:
-   cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
-   cfg->mipi_dt = MIPI_DT_YUV422;
-   cfg->data_width = IPU_CSI_DATA_WIDTH_16;
-   break;
case MEDIA_BUS_FMT_YUYV8_1X16:
-   cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+   cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_YUV422;
cfg->data_width = IPU_CSI_DATA_WIDTH_16;
break;
-- 
1.9.1



[PATCH 12/16] gpu: ipu-v3: Fix CSI0 blur in NTSC format

2016-07-07 Thread Steve Longerbeam
From: Suresh Dhandapani 

This patch will change the register IPU_CSI0_CCIR_CODE_2 value from
0x40596 to 0x405A6. The change is related to the Start of field 1
first blanking line command bit[5-3] for NTSC format only. This
change is dependent with ADV chip where the NEWAVMODE is set to 0
in register 0x31. Setting NEWAVMODE to "0" in ADV means "EAV/SAV
codes generated to suit analog devices encoders".

Signed-off-by: Suresh Dhandapani 
---
 drivers/gpu/ipu-v3/ipu-csi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index 0eac28c..ec81958 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -422,7 +422,7 @@ int ipu_csi_init_interface(struct ipu_csi *csi,

ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
  CSI_CCIR_CODE_1);
-   ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+   ipu_csi_write(csi, 0x405A6, CSI_CCIR_CODE_2);
ipu_csi_write(csi, 0xFF, CSI_CCIR_CODE_3);
} else {
dev_err(csi->ipu->dev,
-- 
1.9.1



  1   2   3   >