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(>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 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(>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->dev, "

[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(>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_complete)
+ 

[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 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(>irqlock, flags);
-   return IRQ_HANDLED;
-   }
-
-   ret = do_irq(run);
-out:
-   spin_unlock_irqrestore(>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(>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(>irqlock, flags);
-   return IRQ_HANDLED;
-   }
-
ret = do_irq(run);
 out:
spin_unlock_irqrestore(>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


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] 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


[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 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 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 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[] = {
,
+   ,
+   ,
+   ,
 };
 
 static const struct ipu_ic_csc_params *yuv2yuv[] = {
,
+   ,
+   ,
+   ,
 };
 
 /*
@@ -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.601 YUV limited-range to RGB limited-range */
+static const struct ipu_ic_csc_params yuvl2rgbl_601 = {
+   

[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[] = {
+   ,
+};
+
+static const struct ipu_ic_csc_params *yuv2yuv[] = {
+   ,
+};
+
+/*
+ * 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 = {
+   .coeff = {
+   {   77,  150,   29, },
+   {  -43,  -85,  128, },
+   {  128, -107,  -21, },
+   },
+

[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[] = {
_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[] = {
+   _709,
+   _709,
+   _709,
+   _709,
+};
+
+static const struct ipu_ic_csc_params *yuv2rgb_709[] = {
+   _709,
+   _709,
+   _709,
+   _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 <-> RGB encoding is required */
 
-   params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ?
-   yuv2rgb_601 

[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[] = {
+   ,
+};
+
+static const struct ipu_ic_csc_params *yuv2yuv[] = {
+   ,
+};
+
+/*
+ * 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 = {
+   .coeff = {
+   {   77,  150,   29, },
+   {  -43,  -85,  128, },
+   {  128, -107,  -21, },
+   },
+

[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 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[] = {
,
+   ,
+   ,
+   ,
 };
 
 static const struct ipu_ic_csc_params *yuv2yuv[] = {
,
+   ,
+   ,
+   ,
 };
 
 /*
@@ -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.601 YUV limited-range to RGB limited-range */
+static const struct ipu_ic_csc_params yuvl2rgbl_601 = {
+   

[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[] = {
_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[] = {
+   _709,
+   _709,
+   _709,
+   _709,
+};
+
+static const struct ipu_ic_csc_params *yuv2rgb_709[] = {
+   _709,
+   _709,
+   _709,
+   _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 <-> RGB encoding is required */
 
-   params_tbl = (csc->in_cs.cs == IPUV3_COLORSPACE_YUV) ?
-   yuv2rgb_601 

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 range to RG

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->priv;
-   const stru

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;
u32 __i

[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

[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 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 = _csc_ycbcr2rgb;
+   coeff = _encode_ycbcr2rgb_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr;
+   coeff = _encode_rgb2ycbcr_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _csc_rgb2rgb;
+   coeff = _encode_identity;
else {
dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
return -EINVAL;
}
 
/* Cast to unsigned */
-   c = (const u16 (*)[3])params->coeff;
-   a = (const u16 *)param

[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 ?
+   _encode_ycbcr2rgb_601 : _encode_rgb2ycbcr_601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   encode_coeff = inverse_encode ?
+   _encode_ycbcr2rgb_709 : _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, , 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 = _encode_ycbcr2rgb_601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   coeff = _encode_rgb2ycbcr_601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   coeff = _encode_identity;
-   else {
-   dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
-   return -EINVAL;
- 

[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 = _csc_ycbcr2rgb;
+   coeff = _encode_ycbcr2rgb_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr;
+   coeff = _encode_rgb2ycbcr_601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _csc_rgb2rgb;
+   coeff = _encode_identity;
else {
dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
return -EINVAL;
}
 
/* Cast to unsigned */
-   c = (const u16 (*)[3])params->coeff;
-   a = (const u16 *)params->of

[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 = _encode_identity;
+   else if (in->cs == IPUV3_COLORSPACE_YUV)
coeff = _encode_ycbcr2rgb_601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+   else
coeff = _encode_rgb2ycbcr_601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   coeff = _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_disable(struct ipu_ic *ic)
 EXPORT_SYMBOL_GPL(i

[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 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 ?
+   _encode_ycbcr2rgb_601 : _encode_rgb2ycbcr_601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   encode_coeff = inverse_encode ?
+   _encode_ycbcr2rgb_709 : _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;
+
+   ret 

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

2019-02-14 Thread Steve Longerbeam via dri-devel



On 2/13/19 2:35 AM, Philipp Zabel wrote:

On Tue, 2019-02-12 at 09:42 -0800, Steve Longerbeam wrote:
[...]

But what about this "SAT_MODE" field in the IC task parameter memory?

That just controls the saturation. The result after the matrix
multiplication is either saturated to [0..255] or to [16..235]/[16..240]
when converting from the internal representation to the 8 bit output.

By saturation I think you mean clipped to those ranges?

Yes, thanks. I didn't realize it sounds weird to use saturated this way.
See:https://en.wikipedia.org/wiki/Saturation_arithmetic


Ok, saturation can mean the same thing as clipping/clamping. Thanks for 
the article.


I tested a RGB->YUV pipeline with the .sat bit set in the BT.601 rgb2yuv 
table, with the following pipeline on the SabreSD:


'ov5640 1-003c':0
        [fmt:RGB565_2X8_LE/1024x768@1/30 field:none colorspace:srgb 
xfer:srgb ycbcr:601 quantization:full-range]


'imx6-mipi-csi2':0
        [fmt:RGB565_2X8_LE/1024x768 field:none colorspace:srgb 
xfer:srgb ycbcr:601 quantization:full-range]


'imx6-mipi-csi2':2
        [fmt:RGB565_2X8_LE/1024x768 field:none colorspace:srgb 
xfer:srgb ycbcr:601 quantization:full-range]


'ipu1_csi1':0
        [fmt:RGB565_2X8_LE/1024x768@1/30 field:none colorspace:srgb 
xfer:srgb ycbcr:601 quantization:full-range

         crop.bounds:(0,0)/1024x768
         crop:(0,0)/1024x768
         compose.bounds:(0,0)/1024x768
         compose:(0,0)/1024x768]

'ipu1_csi1':1
        [fmt:ARGB_1X32/1024x768@1/30 field:none colorspace:srgb 
xfer:srgb ycbcr:601 quantization:full-range]


'ipu1_ic_prp':0
        [fmt:ARGB_1X32/1024x768@1/30 field:none colorspace:srgb 
xfer:srgb ycbcr:601 quantization:full-range]


'ipu1_ic_prp':1
        [fmt:ARGB_1X32/1024x768@1/30 field:none colorspace:srgb 
xfer:srgb ycbcr:601 quantization:full-range]


'ipu1_ic_prpenc':0
        [fmt:ARGB_1X32/1024x768@1/30 field:none colorspace:srgb 
xfer:srgb ycbcr:601 quantization:full-range]


'ipu1_ic_prpenc':1
        [fmt:AYUV8_1X32/800x600@1/30 field:none colorspace:srgb 
xfer:srgb ycbcr:601 quantization:lim-range]


/dev/video0:0
Format Video Capture:
    Width/Height  : 800/600
    Pixel Format  : 'YV12'
    Field : None
    Bytes per Line    : 800
    Size Image    : 72
    Colorspace    : sRGB
    Transfer Function : sRGB
    YCbCr/HSV Encoding: ITU-R 601
    Quantization  : Limited Range
    Flags :


The result being that the captured image colors are all off (there's a 
bright pink shade to the images). But I discovered the init_csc() 
function was not setting the saturation bit at the correct bit offset 
within the TPMEM. The saturation bit is bit 42, or bit 10 of the second 
32-bit word. But the code was writing to bit 9 of the second word. After 
correcting this, saturation is working fine. I have added another patch 
that fixes this for v5 series.






SAT_MODE should be set for conversions to YUV limited range so that the
coefficients can be rounded to the closest value.

Well, we have already rounded the coefficients to the nearest int in the
tables. Do you mean the final result (coeff * color component + offset)
is rounded?

The manual says so: "The final calculation result is limited according
to the SAT_MODE parameter and rounded to 8 bits", but that's not what I
meant. Still, I might have been mistaken.

I think due to the fact that the coefficients are multiplied by up to
255 (max pixel value) and then effectively divided by 256 when
converting to 8 bit, the only way to overflow limited range is if two
coefficients are rounded away from zero in the calculation of a single
component. This doesn't seem to happen in practice.

A constructed example, conversion to YUV limited range with carefully
chosen coefficients.

   Y = R * .1817 + G * .6153 + B * .0618 + 16;

Note that .1817 + .6153 + .0618 < 219/255.
With rounded coefficients though:

   Y = (R * 47 + G * 158 + B * 16 + (64 << 6)) / 256 = 236.136


Yes, for a rec.709 conversion and max/worst-case RGB signal = (255,255,255).

But the rec.709 coefficients for Y are actually

Y = (R * 47 + G * 157 + B * 16 + (16 << 8)) / 256


which for RGB = (255,255,255), Y = 235.14, which doesn't overflow 
limited range.


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 via dri-devel



On 2/12/19 2:17 AM, Philipp Zabel wrote:

Hi Steve,

On Mon, 2019-02-11 at 10:24 -0800, Steve Longerbeam wrote:
[...]

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?

That just controls the saturation. The result after the matrix
multiplication is either saturated to [0..255] or to [16..235]/[16..240]
when converting from the internal representation to the 8 bit output.


By saturation I think you mean clipped to those ranges?




According to the manual the hardware will automatically convert the
written coefficients to the correct limited ranges.

Where did you get that from? "The final calculation result is limited
according to the SAT_MODE parameter and rounded to 8 bits." I see no
mention of coefficients being modified.


Well, as is often the case with this manual, I was interpreting based on 
poorly written information. By "final calculation result is limited 
according to the SAT_MODE parameter" I interpreted that to mean the 
hardware enables scaling from full range to limited range. But I concede 
that it more likely means it clips the output to those 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.

SAT_MODE should be set for conversions to YUV limited range so that the
coefficients can be rounded to the closest value.


Well, we have already rounded the coefficients to the nearest int in the 
tables. Do you mean the final result (coeff * color component + offset) 
is rounded?



  Otherwise we'd have to
round towards zero, possibly with a larger error, to make sure the
results are inside the valid ranges.


Makes sense, I will turn on that bit for limited range YUV output for 
v5, so that the final color component result is clipped to limited range 
and rounded.



Steve


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

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

2019-02-12 Thread Steve Longerbeam via dri-devel



On 2/12/19 3:34 AM, Philipp Zabel wrote:

Hi Steve,

On Mon, 2019-02-11 at 17:20 -0800, Steve Longerbeam wrote:
[...]

Should we support YUV BT.601 <-> YUV REC.709 conversions? That would
require separate encodings for input and output.

How about if we pass the input and output encodings to the init ic task
functions, but for now require they be the same? We can support
transcoding in a later series.

[...]

Again, I think for now, just include input/output quantization but
require full range for RGB and limited range for YUV.

Yes, that is fine. I'd just like to avoid unnecessary interface changes
between ipu-v3 and imx-media. So if we have to change it right now, why
not plan ahead.


Agreed!




But that really balloons the arguments to ipu_ic_task_init_*(). Should
we create an ipu_ic_task_init structure?

I wonder if we should just expose struct ic_csc_params


I had basically the same idea. I wasn't thinking of creating a helper to 
fill in the params but sure, I'll add that.


Steve



  and provide a
helper to fill it given colorspace and V4L2 encoding/quantization
parameters. Something like:

struct ipu_ic_csc_params csc;

imx_media_init_ic_csc_params(,
in_cs, in_encoding, in_quantization,
out_cs, out_encoding, out_quantization);

ipu_ic_task_init(ic,
in_width, in_height,
out_width, out_height, );
// or
ipu_ic_task_init_rsc(ic, rsc, );

regards
Philipp


___
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 via dri-devel



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;


   */
-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.


Agreed, the coefficients in the comments are correct, but the actual 
table values were a bit off. I will correct them for v5 (Green offset 
should be 272 in the table, not 266).


Steve




-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 = _csc_ycbcr2rgb;
+   params = _csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr;
+   params = _csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _csc_rgb2rgb;
+   params = _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

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 = _csc_ycbcr2rgb;
+   params = _csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr;
+   params = _csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _csc_rgb2rgb;
+   params = _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

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

2019-02-12 Thread Steve Longerbeam via dri-devel



On 2/11/19 2:12 AM, Philipp Zabel wrote:

On Fri, 2019-02-08 at 17:47 -0800, 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 
---
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.;

This is a conversion to YUV full range. Limited range should be:

Y   R *  .1826 + G *  .6142 + B *  .0620 + 16;
U = R * -.1007 + G * -.3385 + B *  .4392 + 128;
V   R *  .4392 + G * -.3990 + B * -.0402 + 128;


Yep, I fixed these to encode to limited range YUV, and ...


+ */
+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);

The coefficients look like full range again, conversion from limited
range YUV should look like:

   R = (1.1644 * (Y - 16)) + (1.7927 * (Cr - 128));
   G = (1.1644 * (Y - 16)) - (0.2132 * (Cb - 128)) - (0.5329 * (Cr - 128));
   B = (1.1644 * (Y - 16)) + (2.1124 * (Cb - 128);


fixed these to inverse encode from limited range YUV.


+ */
+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,

Should we support YUV BT.601 <-> YUV REC.709 conversions? That would
require separate encodings for input and output.


How about if we pass the input and output encodings to the init ic task 
functions, but for now require they be the same? We can support 
transcoding in a later series.



  Also, this might be a
good time to think about adding quantization range parameters as well.


Again, I think for now, just include input/output quantization but 
require full range for RGB and limited range for YUV.


But that really balloons the arguments to ipu_ic_task_init_*(). Should 
we create an ipu_ic_task_init structure?


Steve

___
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 = _csc_identity;
 else if (inf == IPUV3_COLORSPACE_YUV)
-   params = _csc_ycbcr2rgb_bt601;
+   params = _csc_ycbcr2rgb;


Steve,

compile issue...

params = params_yuv2rgb;


 else
-   params = _csc_rgb2ycbcr_bt601;
+   params = _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


[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 = _csc_identity;
+   else if (inf == IPUV3_COLORSPACE_YUV)
params = _csc_ycbcr2rgb_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+   else
params = _csc_rgb2ycbcr_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _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 =  _csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = _csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  _csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = _csc_ycbcr2rgb_bt709;
+   break;
+   default:
+   if (inf != outf) {
+   dev_err(priv->ipu->dev,
+   "Unsupported YCbCr encoding\n");
+   return -EINVAL;
+   }
+   break;
+   }
+
if (inf == outf)
params = _csc_identity;
else if (inf == IPUV3_COLORSPACE_YUV)
-   params = _csc_ycbcr2rgb_bt601;
+   params = _csc_ycbcr2rgb;
else
-   params = _csc_rgb2ycbcr_bt601;
+   params = _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 +505,7 @@ int ipu_ic_task_init_rsc(struct ipu_ic *ic,
 

[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 = _csc_identity;
+   else if (inf == IPUV3_COLORSPACE_YUV)
params = _csc_ycbcr2rgb_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+   else
params = _csc_rgb2ycbcr_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _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 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 =  _csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = _csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  _csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = _csc_ycbcr2rgb_bt709;
+   break;
+   default:
+   if (inf != outf) {
+   dev_err(priv->ipu->dev,
+   "Unsupported YCbCr encoding\n");
+   return -EINVAL;
+   }
+   break;
+   }
+
if (inf == outf)
params = _csc_identity;
else if (inf == IPUV3_COLORSPACE_YUV)
-   params = _csc_ycbcr2rgb_bt601;
+   params = _csc_ycbcr2rgb;
else
-   params = _csc_rgb2ycbcr_bt601;
+   params = _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 +505,7 @@ int ipu_ic_task_init_rsc(s

[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 = _csc_ycbcr2rgb;
+   params = _csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr;
+   params = _csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _csc_rgb2rgb;
+   params = _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 = _csc_ycbcr2rgb;
+   params = _csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr;
+   params = _csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _csc_rgb2rgb;
+   params = _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 =  _csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = _csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  _csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = _csc_ycbcr2rgb_bt709;
+   break;
+   default:
+   if (inf != outf) {
+   dev_err(priv->ipu->dev,
+   "Unsupported YCbCr encoding\n");
+   return -EINVAL;
+   }
+   break;
+   }
+
if (inf == outf)
params = _csc_identity;
else if (inf == IPUV3_COLORSPACE_YUV)
-   params = _csc_ycbcr2rgb_bt601;
+   params = params_yuv2rgb;
else
-   params = _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)
goto unlock;
}
@@ -450,6 +505,7 @@ 

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 =  _csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = _csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  _csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = _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 = _csc_ycbcr2rgb_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr_bt601;
+   if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB) {
+   params = (encoding == V4L2_YCBCR_ENC_601) ?
+   _csc_ycbcr2rgb_bt601 : _csc_ycbcr2rgb_bt709;
+   }
+   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV) {
+   params = (encoding == V4L2_YCBCR_ENC_601) ?
+   _csc_rgb2ycbcr_bt601 : _csc_rgb2ycbcr_bt709;
+   }
 el

[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 = _csc_ycbcr2rgb;
+   params = _csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr;
+   params = _csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _csc_rgb2rgb;
+   params = _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 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 = _csc_identity;
+   else if (inf == IPUV3_COLORSPACE_YUV)
params = _csc_ycbcr2rgb_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+   else
params = _csc_rgb2ycbcr_bt601;
-   else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
-   params = _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 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 = _csc_ycbcr2rgb;
+   params = _csc_ycbcr2rgb_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr;
+   params = _csc_rgb2ycbcr_bt601;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
params = _csc_rgb2rgb;
else {
-- 
2.17.1

___
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 =  _csc_rgb2ycbcr_bt601;
+   params_yuv2rgb = _csc_ycbcr2rgb_bt601;
+   break;
+   case V4L2_YCBCR_ENC_709:
+   params_rgb2yuv =  _csc_rgb2ycbcr_bt709;
+   params_yuv2rgb = _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 = _csc_ycbcr2rgb_bt601;
+   params = params_yuv2rgb;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
-   params = _csc_rgb2ycbcr_bt601;
+   params = params_rgb2yuv;
else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
params = _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_space in_cs,
 e

[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 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 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 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_config *m

[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 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


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_CCIR_CODE

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 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-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(, mbus_cfg, mbus_fmt);

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

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

2018-10-17 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] gpu: ipu-v3: Fix CSI offsets for imx53

2018-10-17 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 02/12] gpu: ipu-csi: Swap fields according to input/output field types

2018-10-17 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(, mbus_cfg, mbus_fmt);
+   ret = fill_csi_bus_cfg(, mbus_cfg, infmt);
if (ret < 0)
return ret;
 
/* set default sensor frame width and height */
-   width = mbus_fmt->width;
-   height = mbus_fmt->height;
+   w

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(>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 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


[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(, mbus_cfg, mbus_fmt);
+   ret = fill_csi_bus_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;
 
/* Set the CSI_SENS_CONF

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(>hw_mutex);

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


___
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


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 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 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


[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(, mbus_cfg, mbus_fmt);
+   fill_csi_bus_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_width <

[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 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 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 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 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


[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 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(>event_lock, flags);
+
+   if (event)
+   drm_crtc_send_vblank_event(crtc, event);
+
+   spin_unlock_irqrestore(>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] gpu: ipu-v3: Fix CSI selection for VDIC

2017-06-04 Thread Steve Longerbeam
From: Marek Vasut <ma...@denx.de>

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 <ma...@denx.de>
Signed-off-by: Steve Longerbeam <steve_longerb...@mentor.com>
---
 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(>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(>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: 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 <steve_longerb...@mentor.com>
---
 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(>lock, flags);
-- 
2.7.4

___
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 <li...@armlinux.org.uk>
Fixes: 867341b95891 ("gpu: ipu-v3: add ipu_csi_set_downsize")
Signed-off-by: Philipp Zabel <p.za...@pengutronix.de>
---
  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(>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 <steve_longerb...@mentor.com>

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


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 <li...@armlinux.org.uk>
Signed-off-by: Philipp Zabel <p.za...@pengutronix.de>
---
 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 <steve_longerb...@mentor.com>
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 12/12] gpu: ipu-v3: Add smfc and ic client devices

2016-12-07 Thread Steve Longerbeam
Adds IPU client devices for the SMFC and IC task units.

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

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index b6ca36b..729581d 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -1161,18 +1161,77 @@ static struct ipu_platform_reg client_reg[] = {
.pdata = {
.type = IPU_CSI,
.csi = 0,
-   .dma[0] = IPUV3_CHANNEL_CSI0,
-   .dma[1] = -EINVAL,
+   .dma[0] = -EINVAL,
},
.name = "imx-ipuv3-csi",
}, {
.pdata = {
.type = IPU_CSI,
.csi = 1,
+   .dma[0] = -EINVAL,
+   },
+   .name = "imx-ipuv3-csi",
+   }, {
+   .pdata = {
+   .type = IPU_SMFC,
+   .smfc = 0,
+   .dma[0] = IPUV3_CHANNEL_CSI0,
+   .dma[1] = -EINVAL,
+   },
+   .name = "imx-ipuv3-smfc",
+   }, {
+   .pdata = {
+   .type = IPU_SMFC,
+   .smfc = 1,
.dma[0] = IPUV3_CHANNEL_CSI1,
.dma[1] = -EINVAL,
},
-   .name = "imx-ipuv3-csi",
+   .name = "imx-ipuv3-smfc",
+   }, {
+   .pdata = {
+   .type = IPU_IC,
+   .ic_task = IC_TASK_ENCODER,
+   .ic = 0,
+   .dma[0] = IPUV3_CHANNEL_IC_PRP_ENC_MEM,
+   .dma[1] = -EINVAL,
+   },
+   .name = "imx-ipuv3-ic",
+   }, {
+   .pdata = {
+   .type = IPU_IC,
+   .ic_task = IC_TASK_VIEWFINDER,
+   .ic = 0,
+   .dma[0] = IPUV3_CHANNEL_IC_PRP_VF_MEM,
+   .dma[1] = -EINVAL,
+   },
+   .name = "imx-ipuv3-ic",
+   }, {
+   .pdata = {
+   .type = IPU_IC,
+   .ic_task = IC_TASK_POST_PROCESSOR,
+   .ic = 0,
+   .dma[0] = IPUV3_CHANNEL_IC_PP_MEM,
+   .dma[1] = -EINVAL,
+   },
+   .name = "imx-ipuv3-ic",
+   }, {
+   .pdata = {
+   .type = IPU_IC,
+   .ic_task = IC_TASK_POST_PROCESSOR,
+   .ic = 1,
+   .dma[0] = IPUV3_CHANNEL_IC_PP_MEM,
+   .dma[1] = -EINVAL,
+   },
+   .name = "imx-ipuv3-ic",
+   }, {
+   .pdata = {
+   .type = IPU_IC,
+   .ic_task = IC_TASK_POST_PROCESSOR,
+   .ic = 2,
+   .dma[0] = IPUV3_CHANNEL_IC_PP_MEM,
+   .dma[1] = -EINVAL,
+   },
+   .name = "imx-ipuv3-ic",
}, {
.pdata = {
.type = IPU_DI,
@@ -1213,6 +1272,28 @@ of_get_ipu_client_node(struct ipu_soc *ipu, struct 
ipu_platform_reg *reg)
 "ipu%d_csi", ipu->id + 1);
client_id = reg->pdata.csi;
break;
+   case IPU_SMFC:
+   snprintf(node_name, sizeof(node_name), "ipu%d_smfc",
+ipu->id + 1);
+   client_id = reg->pdata.smfc;
+   break;
+   case IPU_IC:
+   switch (reg->pdata.ic_task) {
+   case IC_TASK_ENCODER:
+   snprintf(node_name, sizeof(node_name),
+"ipu%d_ic_prpenc", ipu->id + 1);
+   break;
+   case IC_TASK_VIEWFINDER:
+   snprintf(node_name, sizeof(node_name),
+"ipu%d_ic_prpvf", ipu->id + 1);
+   break;
+   case IC_TASK_POST_PROCESSOR:
+   snprintf(node_name, sizeof(node_name),
+"ipu%d_ic_pp", ipu->id + 1);
+   break;
+   }
+   client_id = reg->pdata.ic;
+   break;
case IPU_DI:
snprintf(node_name, sizeof(node_name),
 "ipu%d_di", ipu->id + 1);
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 7709af7..4e70ca4 100644
--- a/include/video/imx-ipu-v3.

[PATCH 11/12] gpu: ipu-v3: lookup ipu client nodes by name

2016-12-07 Thread Steve Longerbeam
To allow for IPU clients containing multiple ports, they are no longer
a single port node name, but have a name of the format
"ipu_". So we can no longer use of_graph_get_port_by_id()
to lookup the client node.

Create the function of_get_ipu_client_node() that looks up the client
node by node name and unit id. The ipu_unit_type enumeration is added
to the client_reg[] entries to compose the node names.

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

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 97218af..b6ca36b 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -1159,6 +1159,7 @@ struct ipu_platform_reg {
 static struct ipu_platform_reg client_reg[] = {
{
.pdata = {
+   .type = IPU_CSI,
.csi = 0,
.dma[0] = IPUV3_CHANNEL_CSI0,
.dma[1] = -EINVAL,
@@ -1166,6 +1167,7 @@ static struct ipu_platform_reg client_reg[] = {
.name = "imx-ipuv3-csi",
}, {
.pdata = {
+   .type = IPU_CSI,
.csi = 1,
.dma[0] = IPUV3_CHANNEL_CSI1,
.dma[1] = -EINVAL,
@@ -1173,6 +1175,7 @@ static struct ipu_platform_reg client_reg[] = {
.name = "imx-ipuv3-csi",
}, {
.pdata = {
+   .type = IPU_DI,
.di = 0,
.dc = 5,
.dp = IPU_DP_FLOW_SYNC_BG,
@@ -1182,6 +1185,7 @@ static struct ipu_platform_reg client_reg[] = {
.name = "imx-ipuv3-crtc",
}, {
.pdata = {
+   .type = IPU_DI,
.di = 1,
.dc = 1,
.dp = -EINVAL,
@@ -1195,6 +1199,46 @@ static struct ipu_platform_reg client_reg[] = {
 static DEFINE_MUTEX(ipu_client_id_mutex);
 static int ipu_client_id;

+static struct device_node *
+of_get_ipu_client_node(struct ipu_soc *ipu, struct ipu_platform_reg *reg)
+{
+   struct device *dev = ipu->dev;
+   struct device_node *client;
+   char node_name[32];
+   u32 id, client_id = 0;
+
+   switch (reg->pdata.type) {
+   case IPU_CSI:
+   snprintf(node_name, sizeof(node_name),
+"ipu%d_csi", ipu->id + 1);
+   client_id = reg->pdata.csi;
+   break;
+   case IPU_DI:
+   snprintf(node_name, sizeof(node_name),
+"ipu%d_di", ipu->id + 1);
+   client_id = reg->pdata.di;
+   break;
+   default:
+   client = NULL;
+   goto out;
+   }
+
+   for_each_child_of_node(dev->of_node, client) {
+   if (client->name &&
+   (of_node_cmp(client->name, node_name) == 0)) {
+   of_property_read_u32(client, "reg", );
+   if (id == client_id)
+   break;
+   }
+   }
+out:
+   if (!client)
+   dev_info(dev, "no %s%d node in %s, not using %s%d\n",
+node_name, client_id, dev->of_node->full_name,
+node_name, client_id);
+   return client;
+}
+
 static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
 {
struct device *dev = ipu->dev;
@@ -1211,15 +1255,10 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, 
unsigned long ipu_base)
struct platform_device *pdev;
struct device_node *of_node;

-   /* Associate subdevice with the corresponding port node */
-   of_node = of_graph_get_port_by_id(dev->of_node, i);
-   if (!of_node) {
-   dev_info(dev,
-"no port@%d node in %s, not using %s%d\n",
-i, dev->of_node->full_name,
-(i / 2) ? "DI" : "CSI", i % 2);
+   /* Associate subdevice with the corresponding client node */
+   of_node = of_get_ipu_client_node(ipu, reg);
+   if (!of_node)
continue;
-   }

pdev = platform_device_alloc(reg->name, id++);
if (!pdev) {
-- 
2.7.4



[PATCH 10/12] gpu: ipu-v3: Add ipu_unit_type enumeration

2016-12-07 Thread Steve Longerbeam
Adds an enumeration of the major IPUv3 subunits. Provide that info
in struct ipu_client_platformdata to more easily determine the IPU
client type.

Signed-off-by: Steve Longerbeam 
---
 include/video/imx-ipu-v3.h | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 53cd07c..7709af7 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -28,6 +28,23 @@ enum ipuv3_type {
IPUV3H,
 };

+/*
+ * Enumeration of the major IPU subunits
+ */
+enum ipu_unit_type {
+   IPU_IDMAC = 0,
+   IPU_CM,
+   IPU_CSI,
+   IPU_SMFC,
+   IPU_IC,
+   IPU_VDI,
+   IPU_IRT,
+   IPU_DC,
+   IPU_DI,
+   IPU_DP,
+   IPU_DMFC,
+};
+
 #define IPU_PIX_FMT_GBR24  v4l2_fourcc('G', 'B', 'R', '3')

 /*
@@ -399,6 +416,7 @@ int ipu_rot_mode_to_degrees(int *degrees, enum 
ipu_rotate_mode mode,
bool hflip, bool vflip);

 struct ipu_client_platformdata {
+   enum ipu_unit_type type;
int csi;
int di;
int dc;
-- 
2.7.4



[PATCH 09/12] ARM: dts: imx6-sabreauto: add the ADV7180 video decoder

2016-12-07 Thread Steve Longerbeam
Enables the ADV7180 decoder sensor. The ADV7180 connects to the
parallel-bus mux input on ipu1_csi0_mux.

On the sabreauto, two analog video inputs are routed to the ADV7180,
composite on Ain1, and composite on Ain3. Those inputs are defined
via inputs and input-names under the ADV7180 node. The ADV7180 power
pin is via max7310_b port expander.

Signed-off-by: Steve Longerbeam 
---
 arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 62 
 1 file changed, 62 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 
b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index d74882a..9222026 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -147,10 +147,48 @@
gpio-controller;
#gpio-cells = <2>;
};
+
+   camera: adv7180 at 21 {
+   compatible = "adi,adv7180";
+   reg = <0x21>;
+   powerdown-gpios = <_b 2 
GPIO_ACTIVE_LOW>;
+   interrupt-parent = <>;
+   interrupts = <27 0x8>;
+   inputs = <0x00 0x02>;
+   input-names = "ADV7180 Composite on Ain1",
+   "ADV7180 Composite on Ain3";
+
+   port {
+   adv7180_to_ipu1_csi0_mux: endpoint {
+   remote-endpoint = 
<_csi0_mux_from_parallel_sensor>;
+   bus-width = <8>;
+   };
+   };
+   };
};
};
 };

+_smfc0 {
+   fim {
+   enable = <1>;
+   };
+};
+
+_csi0_from_ipu1_csi0_mux {
+   bus-width = <8>;
+};
+
+_csi0_mux_from_parallel_sensor {
+   remote-endpoint = <_to_ipu1_csi0_mux>;
+   bus-width = <8>;
+};
+
+_csi0 {
+   pinctrl-names = "default";
+   pinctrl-0 = <_ipu1_csi0>;
+};
+
  {
assigned-clocks = < IMX6QDL_PLL4_BYPASS_SRC>,
  < IMX6QDL_PLL4_BYPASS>,
@@ -451,6 +489,30 @@
>;
};

+   pinctrl_ipu1_csi0: ipu1grp-csi0 {
+   fsl,pins = <
+   MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04   
0x8000
+   MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05   
0x8000
+   MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06   
0x8000
+   MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07   
0x8000
+   MX6QDL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08   
0x8000
+   MX6QDL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09   
0x8000
+   MX6QDL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10  
0x8000
+   MX6QDL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11  
0x8000
+   MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12  
0x8000
+   MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13  
0x8000
+   MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14  
0x8000
+   MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15  
0x8000
+   MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16  
0x8000
+   MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17  
0x8000
+   MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18  
0x8000
+   MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19  
0x8000
+   MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 
0x8000
+   MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC
0x8000
+   MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC   
0x8000
+   >;
+   };
+
pinctrl_pwm3: pwm1grp {
fsl,pins = <
MX6QDL_PAD_SD4_DAT1__PWM3_OUT   0x1b0b1
-- 
2.7.4



[PATCH 08/12] ARM: dts: imx6-sabreauto: add pinctrl for gpt input capture

2016-12-07 Thread Steve Longerbeam
Add pinctrl groups for both GPT input capture channels.

Signed-off-by: Steve Longerbeam 
---
 arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 12 
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 
b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index 944a4fa..d74882a 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -457,6 +457,18 @@
>;
};

+   pinctrl_gpt_input_capture0: gptinputcapture0grp {
+   fsl,pins = <
+   MX6QDL_PAD_SD1_DAT0__GPT_CAPTURE1   
0x8000
+   >;
+   };
+
+   pinctrl_gpt_input_capture1: gptinputcapture1grp {
+   fsl,pins = <
+   MX6QDL_PAD_SD1_DAT1__GPT_CAPTURE2   
0x8000
+   >;
+   };
+
pinctrl_spdif: spdifgrp {
fsl,pins = <
MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0
-- 
2.7.4



[PATCH 07/12] ARM: dts: imx6-sabreauto: add reset-gpios property for max7310_b

2016-12-07 Thread Steve Longerbeam
The reset pin to the port expander chip (MAX7310) is controlled by a gpio,
so define a reset-gpios property to control it. There are three MAX7310's
on the SabreAuto CPU card (max7310_[abc]), but all use the same pin for
their reset. Since all can't acquire the same pin, assign it to max7310_b,
that chip is needed by more functions (usb and adv7180).

Signed-off-by: Steve Longerbeam 
---
 arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 9 +
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 
b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index 043d20c..944a4fa 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -136,6 +136,9 @@
reg = <0x32>;
gpio-controller;
#gpio-cells = <2>;
+   pinctrl-names = "default";
+   pinctrl-0 = <_max7310>;
+   reset-gpios = < 15 GPIO_ACTIVE_LOW>;
};

max7310_c: gpio at 34 {
@@ -442,6 +445,12 @@
>;
};

+   pinctrl_max7310: max7310grp {
+   fsl,pins = <
+   MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x8000
+   >;
+   };
+
pinctrl_pwm3: pwm1grp {
fsl,pins = <
MX6QDL_PAD_SD4_DAT1__PWM3_OUT   0x1b0b1
-- 
2.7.4



[PATCH 06/12] ARM: dts: imx6-sabreauto: create i2cmux for i2c3

2016-12-07 Thread Steve Longerbeam
The sabreauto uses a steering pin to select between the SDA signal on
i2c3 bus, and a data-in pin for an SPI NOR chip. Use i2cmux to control
this steering pin. Idle state of the i2cmux selects SPI NOR. This is not
a classic way to use i2cmux, since one side of the mux selects something
other than an i2c bus, but it works and is probably the cleanest
solution. Note that if one thread is attempting to access SPI NOR while
another thread is accessing i2c3, the SPI NOR access will fail since the
i2cmux has selected the SDA pin rather than SPI NOR data-in. This couldn't
be avoided in any case, the board is not designed to allow concurrent
i2c3 and SPI NOR functions (and the default device-tree does not enable
SPI NOR anyway).

Devices hanging off i2c3 should now be defined under i2cmux, so
that the steering pin can be properly controlled to access those
devices. The port expanders (MAX7310) are thus moved into i2cmux.

Signed-off-by: Steve Longerbeam 
---
 arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 65 +---
 1 file changed, 44 insertions(+), 21 deletions(-)

diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 
b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index e000e6f..043d20c 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -108,6 +108,44 @@
default-brightness-level = <7>;
status = "okay";
};
+
+   i2cmux {
+   compatible = "i2c-mux-gpio";
+   #address-cells = <1>;
+   #size-cells = <0>;
+   pinctrl-names = "default";
+   pinctrl-0 = <_i2c3mux>;
+   mux-gpios = < 4 0>;
+   i2c-parent = <>;
+   idle-state = <0>;
+
+   i2c at 1 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   reg = <1>;
+
+   max7310_a: gpio at 30 {
+   compatible = "maxim,max7310";
+   reg = <0x30>;
+   gpio-controller;
+   #gpio-cells = <2>;
+   };
+
+   max7310_b: gpio at 32 {
+   compatible = "maxim,max7310";
+   reg = <0x32>;
+   gpio-controller;
+   #gpio-cells = <2>;
+   };
+
+   max7310_c: gpio at 34 {
+   compatible = "maxim,max7310";
+   reg = <0x34>;
+   gpio-controller;
+   #gpio-cells = <2>;
+   };
+   };
+   };
 };

  {
@@ -291,27 +329,6 @@
pinctrl-names = "default";
pinctrl-0 = <_i2c3>;
status = "okay";
-
-   max7310_a: gpio at 30 {
-   compatible = "maxim,max7310";
-   reg = <0x30>;
-   gpio-controller;
-   #gpio-cells = <2>;
-   };
-
-   max7310_b: gpio at 32 {
-   compatible = "maxim,max7310";
-   reg = <0x32>;
-   gpio-controller;
-   #gpio-cells = <2>;
-   };
-
-   max7310_c: gpio at 34 {
-   compatible = "maxim,max7310";
-   reg = <0x34>;
-   gpio-controller;
-   #gpio-cells = <2>;
-   };
 };

  {
@@ -419,6 +436,12 @@
>;
};

+   pinctrl_i2c3mux: i2c3muxgrp {
+   fsl,pins = <
+   MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x8000
+   >;
+   };
+
pinctrl_pwm3: pwm1grp {
fsl,pins = <
MX6QDL_PAD_SD4_DAT1__PWM3_OUT   0x1b0b1
-- 
2.7.4



[PATCH 05/12] ARM: dts: imx6-sabresd: add OV5642 and OV5640 camera sensors

2016-12-07 Thread Steve Longerbeam
Enables the OV5642 parallel-bus sensor, and the OV5640 MIPI CSI-2 sensor.

The OV5642 connects to the parallel-bus mux input port on ipu1_csi0_mux.

The OV5640 connects to the input port on the MIPI CSI-2 receiver on
mipi_csi. It is set to transmit over MIPI virtual channel 1.

Until the OV5652 sensor module compatible with the SabreSD becomes
available for testing, the ov5642 node is currently disabled.

Signed-off-by: Steve Longerbeam 
---
 arch/arm/boot/dts/imx6dl-sabresd.dts   |   5 ++
 arch/arm/boot/dts/imx6q-sabresd.dts|   5 ++
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 114 -
 3 files changed, 123 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/imx6dl-sabresd.dts 
b/arch/arm/boot/dts/imx6dl-sabresd.dts
index 1e45f2f..6cf7a50 100644
--- a/arch/arm/boot/dts/imx6dl-sabresd.dts
+++ b/arch/arm/boot/dts/imx6dl-sabresd.dts
@@ -15,3 +15,8 @@
model = "Freescale i.MX6 DualLite SABRE Smart Device Board";
compatible = "fsl,imx6dl-sabresd", "fsl,imx6dl";
 };
+
+_csi1_from_ipu1_csi1_mux {
+   data-lanes = <0 1>;
+   clock-lanes = <2>;
+};
diff --git a/arch/arm/boot/dts/imx6q-sabresd.dts 
b/arch/arm/boot/dts/imx6q-sabresd.dts
index 9cbdfe7..8c1d7ad 100644
--- a/arch/arm/boot/dts/imx6q-sabresd.dts
+++ b/arch/arm/boot/dts/imx6q-sabresd.dts
@@ -23,3 +23,8 @@
  {
status = "okay";
 };
+
+_csi1_from_mipi_vc1 {
+   data-lanes = <0 1>;
+   clock-lanes = <2>;
+};
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi 
b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index 8e9e0d9..e36e1e7 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -10,6 +10,7 @@
  * http://www.gnu.org/copyleft/gpl.html
  */

+#include 
 #include 
 #include 

@@ -146,6 +147,33 @@
};
 };

+_csi0_from_ipu1_csi0_mux {
+   bus-width = <8>;
+   data-shift = <12>; /* Lines 19:12 used */
+   hsync-active = <1>;
+   vsync-active = <1>;
+};
+
+_csi0_mux_from_parallel_sensor {
+   remote-endpoint = <_to_ipu1_csi0_mux>;
+};
+
+_csi0 {
+   pinctrl-names = "default";
+   pinctrl-0 = <_ipu1_csi0>;
+};
+
+_csi {
+   status = "okay";
+};
+
+/* Incoming port from sensor */
+_csi_from_mipi_sensor {
+   remote-endpoint = <_to_mipi_csi>;
+   data-lanes = <0 1>;
+   clock-lanes = <2>;
+};
+
  {
pinctrl-names = "default";
pinctrl-0 = <_audmux>;
@@ -214,7 +242,33 @@
0x8014 /* 4:FN_DMICCDAT */
0x /* 5:Default */
>;
-   };
+   };
+
+   camera: ov5642 at 3c {
+   compatible = "ovti,ov5642";
+   pinctrl-names = "default";
+   pinctrl-0 = <_ov5642>;
+   clocks = < IMX6QDL_CLK_CKO>;
+   clock-names = "xclk";
+   reg = <0x3c>;
+   xclk = <2400>;
+   DOVDD-supply = <_reg>; /* 1.8v */
+   AVDD-supply = <_reg>;  /* 2.8v, rev C board is VGEN3
+   rev B board is VGEN5 */
+   DVDD-supply = <_reg>;  /* 1.5v*/
+   pwdn-gpios = < 16 GPIO_ACTIVE_HIGH>; /* SD1_DAT0 */
+   reset-gpios = < 17 GPIO_ACTIVE_LOW>; /* SD1_DAT1 */
+   status = "disabled";
+
+   port {
+   ov5642_to_ipu1_csi0_mux: endpoint {
+   remote-endpoint = 
<_csi0_mux_from_parallel_sensor>;
+   bus-width = <8>;
+   hsync-active = <1>;
+   vsync-active = <1>;
+   };
+   };
+   };
 };

  {
@@ -322,6 +376,34 @@
};
};
};
+
+   mipi_camera: ov5640 at 3c {
+   compatible = "ovti,ov5640_mipi";
+   pinctrl-names = "default";
+   pinctrl-0 = <_ov5640>;
+   reg = <0x3c>;
+   clocks = < IMX6QDL_CLK_CKO>;
+   clock-names = "xclk";
+   xclk = <2400>;
+   DOVDD-supply = <_reg>; /* 1.8v */
+   AVDD-supply = <_reg>;  /* 2.8v, rev C board is VGEN3
+   rev B board is VGEN5 */
+   DVDD-supply = <_reg>;  /* 1.5v*/
+   pwdn-gpios = < 19 GPIO_ACTIVE_HIGH>; /* SD1_DAT2 */
+   reset-gpios = < 20 GPIO_ACTIVE_LOW>; /* SD1_CLK */
+
+   port {
+   #address-cells = <1>;
+   #size-cells = <0&

[PATCH 04/12] ARM: dts: imx6-sabrelite: add OV5642 and OV5640 camera sensors

2016-12-07 Thread Steve Longerbeam
Enables the OV5642 parallel-bus sensor, and the OV5640 MIPI CSI-2 sensor.
Both hang off the same i2c2 bus, so they require different (and non-
default) i2c slave addresses.

The OV5642 connects to the parallel-bus mux input port on ipu1_csi0_mux.

The OV5640 connects to the input port on the MIPI CSI-2 receiver on
mipi_csi. It is set to transmit over MIPI virtual channel 1.

Note there is a pin conflict with GPIO6. This pin functions as a power
input pin to the OV5642, but ENET uses it as the h/w workaround for
erratum ERR006687, to wake-up the ARM cores on normal RX and TX packet
done events (see 6261c4c8). So workaround 6261c4c8 is reverted here to
support the OV5642, and the "fsl,err006687-workaround-present" boolean
also must be removed. The result is that the CPUidle driver will no longer
allow entering the deep idle states on the sabrelite.

Signed-off-by: Steve Longerbeam 
---
 arch/arm/boot/dts/imx6dl-sabrelite.dts   |   5 ++
 arch/arm/boot/dts/imx6q-sabrelite.dts|   6 ++
 arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 122 ++-
 3 files changed, 129 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl-sabrelite.dts 
b/arch/arm/boot/dts/imx6dl-sabrelite.dts
index 0f06ca5..fec2524 100644
--- a/arch/arm/boot/dts/imx6dl-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6dl-sabrelite.dts
@@ -48,3 +48,8 @@
model = "Freescale i.MX6 DualLite SABRE Lite Board";
compatible = "fsl,imx6dl-sabrelite", "fsl,imx6dl";
 };
+
+_csi1_from_ipu1_csi1_mux {
+   data-lanes = <0 1>;
+   clock-lanes = <2>;
+};
diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts 
b/arch/arm/boot/dts/imx6q-sabrelite.dts
index 66d10d8..9e2d26d 100644
--- a/arch/arm/boot/dts/imx6q-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6q-sabrelite.dts
@@ -52,3 +52,9 @@
  {
status = "okay";
 };
+
+_csi1_from_mipi_vc1 {
+   data-lanes = <0 1>;
+   clock-lanes = <2>;
+};
+
diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi 
b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
index 81dd6cd..d7fcb1a2 100644
--- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
@@ -39,6 +39,8 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  */
+
+#include 
 #include 
 #include 

@@ -96,6 +98,15 @@
};
};

+   mipi_xclk: mipi_xclk {
+   compatible = "pwm-clock";
+   #clock-cells = <0>;
+   clock-frequency = <2200>;
+   clock-output-names = "mipi_pwm3";
+   pwms = < 0 45>; /* 1 / 45 ns = 22 MHz */
+   status = "okay";
+   };
+
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
@@ -220,6 +231,22 @@
};
 };

+_csi0_from_ipu1_csi0_mux {
+   bus-width = <8>;
+   data-shift = <12>; /* Lines 19:12 used */
+   hsync-active = <1>;
+   vync-active = <1>;
+};
+
+_csi0_mux_from_parallel_sensor {
+   remote-endpoint = <_to_ipu1_csi0_mux>;
+};
+
+_csi0 {
+   pinctrl-names = "default";
+   pinctrl-0 = <_ipu1_csi0>;
+};
+
  {
pinctrl-names = "default";
pinctrl-0 = <_audmux>;
@@ -271,9 +298,6 @@
txd1-skew-ps = <0>;
txd2-skew-ps = <0>;
txd3-skew-ps = <0>;
-   interrupts-extended = < 6 IRQ_TYPE_LEVEL_HIGH>,
- < 0 119 IRQ_TYPE_LEVEL_HIGH>;
-   fsl,err006687-workaround-present;
status = "okay";
 };

@@ -302,6 +326,52 @@
pinctrl-names = "default";
pinctrl-0 = <_i2c2>;
status = "okay";
+
+   camera: ov5642 at 42 {
+   compatible = "ovti,ov5642";
+   pinctrl-names = "default";
+   pinctrl-0 = <_ov5642>;
+   clocks = < IMX6QDL_CLK_CKO2>;
+   clock-names = "xclk";
+   reg = <0x42>;
+   xclk = <2400>;
+   reset-gpios = < 8 GPIO_ACTIVE_LOW>;
+   pwdn-gpios = < 6 GPIO_ACTIVE_HIGH>;
+   gp-gpios = < 16 GPIO_ACTIVE_HIGH>;
+
+   port {
+   ov5642_to_ipu1_csi0_mux: endpoint {
+   remote-endpoint = 
<_csi0_mux_from_parallel_sensor>;
+   bus-width = <8>;
+   hsync-active = <1>;
+   vsync-active = <1>;
+   };
+   };
+   };
+
+   mipi_camera: ov5640 at 40 {
+   compatible = "ovti,ov5640_mipi";
+   pinctrl-names = "default&q

[PATCH 03/12] ARM: dts: imx6qdl: add video capture devices and connections

2016-12-07 Thread Steve Longerbeam
From: Philipp Zabel <p.za...@pengutronix.de>

This patch adds the IPU subunit devices involved in video capture and
image conversion, and defines all the possible hardware connections
between them via OF graphs.

External to the IPU:

Video input multiplexers are defined that multiplex inputs from camera
sensors and the MIPI-CSI2 gasket, to the IPU CSIs.

On i.MX6Q/D two two-input multiplexers in front of IPU1 CSI0 and IPU2 CSI1
allow to select between CSI0/1 parallel input pads and the MIPI CSI-2 virtual
channels 0/3.

On i.MX6DL/S two five-input multiplexers in front of IPU1 CSI0 and IPU1 CSI1
allow to select between CSI0/1 parallel input pads and any of the four MIPI
CSI-2 virtual channels.

Internal to the IPU:

The IPU CSI, SMFC, IC-PRPENC, IC-PRPVF, and IC-PP subunits are added
as children of the IPUs, along with the hardware-supported connections
between them.

Finally, a media device node is defined. A video camera interface
and mem2mem device are defined as children of the media device.

Signed-off-by: Steve Longerbeam 
Signed-off-by: Philipp Zabel 
---
 arch/arm/boot/dts/imx6dl.dtsi  | 190 
 arch/arm/boot/dts/imx6q.dtsi   | 487 +
 arch/arm/boot/dts/imx6qdl.dtsi | 368 +++
 3 files changed, 1045 insertions(+)

diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 1ade195..4bab076 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -109,6 +109,120 @@
compatible = "fsl,imx-gpu-subsystem";
cores = <_2d>, <_3d>;
};
+
+   ipu1_csi0_mux: ipu1_csi0_mux at 34 {
+   compatible = "imx-video-mux";
+   reg = <0x34 0x07>;
+   gpr = <>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+   status = "okay";
+   sink-ports = <5>;
+
+   port at 0 {
+   reg = <0>;
+
+   ipu1_csi0_mux_from_mipi_vc0: endpoint {
+   remote-endpoint = <_vc0_to_ipu1_csi0_mux>;
+   };
+   };
+
+   port at 1 {
+   reg = <1>;
+
+   ipu1_csi0_mux_from_mipi_vc1: endpoint {
+   remote-endpoint = <_vc1_to_ipu1_csi0_mux>;
+   };
+   };
+
+   port at 2 {
+   reg = <2>;
+
+   ipu1_csi0_mux_from_mipi_vc2: endpoint {
+   remote-endpoint = <_vc2_to_ipu1_csi0_mux>;
+   };
+   };
+
+   port at 3 {
+   reg = <3>;
+
+   ipu1_csi0_mux_from_mipi_vc3: endpoint {
+   remote-endpoint = <_vc3_to_ipu1_csi0_mux>;
+   };
+   };
+
+   port at 4 {
+   reg = <4>;
+
+   ipu1_csi0_mux_from_parallel_sensor: endpoint {
+   };
+   };
+
+   port at 5 {
+   reg = <5>;
+
+   ipu1_csi0_mux_to_ipu1_csi0: endpoint {
+   remote-endpoint = 
<_csi0_from_ipu1_csi0_mux>;
+   };
+   };
+   };
+
+   ipu1_csi1_mux: ipu1_csi1_mux at 34 {
+   compatible = "imx-video-mux";
+   reg = <0x34 0x38>;
+   gpr = <>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+   status = "okay";
+   sink-ports = <5>;
+
+   port at 0 {
+   reg = <0>;
+
+   ipu1_csi1_mux_from_mipi_vc0: endpoint {
+   remote-endpoint = <_vc0_to_ipu1_csi1_mux>;
+   };
+   };
+
+   port at 1 {
+   reg = <1>;
+
+   ipu1_csi1_mux_from_mipi_vc1: endpoint {
+   remote-endpoint = <_vc1_to_ipu1_csi1_mux>;
+   };
+   };
+
+   port at 2 {
+   reg = <2>;
+
+   ipu1_csi1_mux_from_mipi_vc2: endpoint {
+   remote-endpoint = <_vc2_to_ipu1_csi1_mux>;
+   };
+   };
+
+   port at 3 {
+   reg = <3>;
+
+   ipu1_csi1_mux_from_mipi_vc3: endpoint {
+   remote-endpoint = <_vc3_to_ipu1_csi1_mux>;
+   };
+   };
+
+   port at 4 {
+   reg = <4>

[PATCH 02/12] ARM: dts: imx6qdl: rename ipu client nodes

2016-12-07 Thread Steve Longerbeam
To allow for IPU client devices that are composed of more than one
port for input and output (SMFC and IC), change the nodes from being
a single port node to nodes that can contain multiple ports. Rename
the nodes to use the following format: "ipu_".

The IPUv3 driver will then need to lookup the client nodes by name
rather than by port id.

Signed-off-by: Steve Longerbeam 
---
 arch/arm/boot/dts/imx6q.dtsi   | 12 ++--
 arch/arm/boot/dts/imx6qdl.dtsi | 12 ++--
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index e9a5d0b..2b261ba 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -141,18 +141,18 @@
clock-names = "bus", "di0", "di1";
resets = < 4>;

-   ipu2_csi0: port at 0 {
+   ipu2_csi0: ipu2_csi at 0 {
reg = <0>;
};

-   ipu2_csi1: port at 1 {
+   ipu2_csi1: ipu2_csi at 1 {
reg = <1>;
};

-   ipu2_di0: port at 2 {
+   ipu2_di0: ipu2_di at 0 {
#address-cells = <1>;
#size-cells = <0>;
-   reg = <2>;
+   reg = <0>;

ipu2_di0_disp0: disp0-endpoint {
};
@@ -174,10 +174,10 @@
};
};

-   ipu2_di1: port at 3 {
+   ipu2_di1: ipu2_di at 1 {
#address-cells = <1>;
#size-cells = <0>;
-   reg = <3>;
+   reg = <1>;

ipu2_di1_hdmi: hdmi-endpoint {
remote-endpoint = <_mux_3>;
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index e01e5d5..2465187 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1226,18 +1226,18 @@
clock-names = "bus", "di0", "di1";
resets = < 2>;

-   ipu1_csi0: port at 0 {
+   ipu1_csi0: ipu1_csi at 0 {
reg = <0>;
};

-   ipu1_csi1: port at 1 {
+   ipu1_csi1: ipu1_csi at 1 {
reg = <1>;
};

-   ipu1_di0: port at 2 {
+   ipu1_di0: ipu1_di at 0 {
#address-cells = <1>;
#size-cells = <0>;
-   reg = <2>;
+   reg = <0>;

ipu1_di0_disp0: disp0-endpoint {
};
@@ -1259,10 +1259,10 @@
};
};

-   ipu1_di1: port at 3 {
+   ipu1_di1: ipu1_di at 1 {
#address-cells = <1>;
#size-cells = <0>;
-   reg = <3>;
+   reg = <1>;

ipu1_di1_disp1: disp1-endpoint {
};
-- 
2.7.4



[PATCH 01/12] ARM: dts: imx6qdl: Add compatible, clocks, irqs to MIPI CSI-2 node

2016-12-07 Thread Steve Longerbeam
Add to the MIPI CSI2 receiver node: compatible string, interrupt sources,
clocks.

Signed-off-by: Steve Longerbeam 
---
 arch/arm/boot/dts/imx6qdl.dtsi | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index b13b0b2..e01e5d5 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1121,7 +1121,14 @@
};

mipi_csi: mipi at 021dc000 {
+   compatible = "fsl,imx-mipi-csi2";
reg = <0x021dc000 0x4000>;
+   interrupts = <0 100 0x04>, <0 101 0x04>;
+   clocks = < IMX6QDL_CLK_HSI_TX>,
+< IMX6QDL_CLK_VIDEO_27M>,
+< IMX6QDL_CLK_EIM_SEL>;
+   clock-names = "dphy_clk", "cfg_clk", "pix_clk";
+   status = "disabled";
};

mipi_dsi: mipi at 021e {
-- 
2.7.4



[PATCH 00/12] i.MX media devices and connections

2016-12-07 Thread Steve Longerbeam
Hi Philipp, Sascha, Shawn, et al,

I've been working for the past few months on a media driver for i.MX.
In addition to the media entities for the IPU-external units involved
with video capture (video mux and MIPI CSI-2 receiver), I've created
media entities for the IPU CSI, SMFC, and IC subunits. The IC entities
carry out scaling, CSC, horizontal/vertical flip, and rotation. In
addition, the IC-PRPVF entity carries out motion compensated
de-interlace.

The following series adds the OF device nodes and graphs that define
all the possible hardware connections supported by the i.MX involved
in video capture and image conversion.

Here are some of the pipelines defined by the OF graphs:

CSI -> IC-PRPENC
CSI -> IC-PRPVF
CSI -> IC-PRPVF -> IC-PP
CSI -> SMFC
CSI -> SMFC -> IC-PRPVF
CSI -> SMFC -> IC-PP
CSI -> SMFC -> IC-PRPVF -> IC-PP

You will notice that three IC-PP nodes are defined (ipu1_ic_pp0,
ipu1_ic_pp1, ipu1_ic_pp2, and same for ipu2). The reason for that
is that the IC-PP media entity uses the new ipu-image-conversion
API, which allows for multiple conversion contexts to be created.
Each IC-PP entity thus creates its own conversion context, and there
can be any number of IC-PP entities instantiated as needed by the OF
graph.

Camera sensor nodes are also added for the SabreAuto, SabreSD, and
SabreLite reference platforms.

The media driver is now in fairly good shape. It parses the OF graphs
to create the media pads and links. All the pipelines defined by the
OF graphs have been tested and are working. My media driver work is
at:

git at github.com:slongerbeam/mediatree.git, branch imx-media-staging-md-v2.

For an overview of the pipelines supported and usage notes for the
reference boards, you can refer to Documentation/media/v4l-drivers/imx.rst.

I realize there is collision here with the recent patch series posted by
Philipp, particularly around the video multiplexer and mipi csi-2 receiver
subdevs and OF graphs, as well as v4l2 capture drivers.



Philipp Zabel (1):
  ARM: dts: imx6qdl: add video capture devices and connections

Steve Longerbeam (11):
  ARM: dts: imx6qdl: Add compatible, clocks, irqs to MIPI CSI-2 node
  ARM: dts: imx6qdl: rename ipu client nodes
  ARM: dts: imx6-sabrelite: add OV5642 and OV5640 camera sensors
  ARM: dts: imx6-sabresd: add OV5642 and OV5640 camera sensors
  ARM: dts: imx6-sabreauto: create i2cmux for i2c3
  ARM: dts: imx6-sabreauto: add reset-gpios property for max7310_b
  ARM: dts: imx6-sabreauto: add pinctrl for gpt input capture
  ARM: dts: imx6-sabreauto: add the ADV7180 video decoder
  gpu: ipu-v3: Add ipu_unit_type enumeration
  gpu: ipu-v3: lookup ipu client nodes by name
  gpu: ipu-v3: Add smfc and ic client devices

 arch/arm/boot/dts/imx6dl-sabrelite.dts   |   5 +
 arch/arm/boot/dts/imx6dl-sabresd.dts |   5 +
 arch/arm/boot/dts/imx6dl.dtsi| 190 
 arch/arm/boot/dts/imx6q-sabrelite.dts|   6 +
 arch/arm/boot/dts/imx6q-sabresd.dts  |   5 +
 arch/arm/boot/dts/imx6q.dtsi | 497 ++-
 arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 148 +++--
 arch/arm/boot/dts/imx6qdl-sabrelite.dtsi | 122 +++-
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi   | 114 ++-
 arch/arm/boot/dts/imx6qdl.dtsi   | 385 +++-
 drivers/gpu/ipu-v3/ipu-common.c  | 142 -
 include/video/imx-ipu-v3.h   |  21 ++
 12 files changed, 1593 insertions(+), 47 deletions(-)

-- 
2.7.4



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

2016-09-17 Thread Steve Longerbeam


On 09/16/2016 07:16 AM, Philipp Zabel wrote:
> Hi Steve,
>
> thanks for the update.
>
> Am Mittwoch, den 14.09.2016, 18:45 -0700 schrieb Steve Longerbeam:
>> I added comment headers for all the image conversion prototypes.
>> It caused bloat in imx-ipu-v3.h, so I moved it to a new header:
>> include/video/imx-image-convert.h, but let me know if we should put
>> this somewhere else and/or under Documentation/ somewhere.
> I think that is the right place already. imx-image-convert.h could be
> renamed to imx-ipu-image-convert.h, to make clear that this is about the
> IPU image converter.

Ok, I'll send another update with the name change in the next
version (v7).
>
>>>> +#define MIN_W 128
>>>> +#define MIN_H 128
>>> Where does this minimum come from?
>> Nowhere really :) This is just some sane minimums, to pass
>> to clamp_align() when aligning input/output width/height in
>> ipu_image_convert_adjust().
> Let's use hardware minimum in the low level code. Sane defaults are for
> the V4L2 API. Would that be 8x2 pixels per input tile?

I searched the imx6 reference manual, I can't find any mention
of width/height minimums for the IC. So I suppose 8x2 would be fine,
or maybe 16x8, to account for planar and IRT conversions.

>
>>>> +  if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
>>>> +  /* this is a rotation operation, just ignore */
>>>> +  spin_unlock_irqrestore(>irqlock, flags);
>>>> +  return IRQ_HANDLED;
>>>> +  }
>>> Why enable the out_chan EOF irq at all when using the IRT mode?
>> Because (see above), all the IPU resources that might be needed
>> for any conversion context that is queued to a image conversion
>> channel (IC task) are acquired when the first context is queued,
>> including rotation resources. So by acquiring the non-rotation EOF
>> irq, it will get fielded even for rotation conversions, so we have to
>> handle it.
> There is nothing wrong with acquiring the irq. It could still be
> disabled while it is not needed.

It would be difficult to disable the irq. Remember the irq handlers must
field all EOF interrupts in an ipu_image_convert_chan (IC task). If one
context in that channel disables the irq, it will break other runnings
contexts in that channel that are using it.

>
>>>> +/* Adjusts input/output images to IPU restrictions */
>>>> +int ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
>>>> +   enum ipu_rotate_mode rot_mode)
>>>> +{
>>>> +  const struct ipu_ic_pixfmt *infmt, *outfmt;
>>>> +  unsigned int num_in_rows, num_in_cols;
>>>> +  unsigned int num_out_rows, num_out_cols;
>>>> +  u32 w_align, h_align;
>>>> +
>>>> +  infmt = ipu_ic_get_format(in->pix.pixelformat);
>>>> +  outfmt = ipu_ic_get_format(out->pix.pixelformat);
>>>> +
>>>> +  /* set some defaults if needed */
>>> Is this our task at all?
>> ipu_image_convert_adjust() is meant to be called by v4l2 try_format(),
>> which should never return EINVAL but should return a supported format
>> when the passed format is not supported. So I added this here to return
>> some default pixel formats and width/heights if needed.
> I'd prefer to move this into the mem2mem driver try_format, then.

We could move the 0 width/height checks to v4l2, but the pixel
format defaults should probably remain in ipu-image-convert, since
it knows what formats it supports converting to/from.

Steve



[PATCH v6 3/3] gpu: ipu-v3: Add queued image conversion support

2016-09-15 Thread Steve Longerbeam
This patch implements image conversion support using the IC tasks, with
tiling to support scaling to and from images up to 4096x4096. Image
rotation is also supported. Image conversion requests are added to
a run queue under the IC tasks.

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 and 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 ipu_image_converter_ctx *
ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
  struct ipu_image *in, struct ipu_image *out,
  enum ipu_rotate_mode rot_mode,
  ipu_image_converter_cb_t complete,
  void *complete_context);

A new conversion context is created that is added to an IC task
context queue. The caller is given the new conversion context,
which can then be passed to the further APIs:

int ipu_image_convert_queue(struct ipu_image_converter_run *run);

This queues the given image conversion request run 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(). When the conversion completes, the run
pointer is returned to the completion callback.

void ipu_image_convert_abort(struct ipu_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 ipu_image_converter_ctx *ctx);

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

Signed-off-by: Steve Longerbeam 

---

v6:
- fixed call to ipu_image_convert_adjust() in ipu_image_convert_verify().

v5:
- moved all the ipu_image_convert support to ipu-image-convert.c.
  Prototypes moved to include/video/imx-image-convert.h with comment
  headers.
- removed the IC_TASK_ENCODE channels from image_convert_dma_chan[] list.
  The encode task cannnot be used by the image converter, since this
  task has no memory source IDMAC channels (buffers come directly from
  CSI).
- renamed some structs and a few of the exported APIs: struct
  image_converter is renamed ipu_image_convert_chan, ipu_image_convert_run()
  is renamed ipu_image_convert_queue().
- the ipu_ic handle passed to ipu_image_convert_prepare() is replaced by
  the IPU handle and IC task that are requested for carrying out the
  conversion. The image converter acquires the ipu_ic handle internally,
  in get_ipu_resources() along with the other resources required.
- removed .name field in the supported pixel format list, and
  ipu_image_convert_enum_format() no longer takes a char* desc arg.
- y_depth in 'struct ipu_image_pixfmt' replaced with boolean planar
  (Y pixel depth is always 8 bits).
- removed dmabuf reallocation in alloc_dma_buf().
- added lockdep_assert_held() to functions that require the irqlock.
- added IC task number to dev_dbg() output.
- exported 'struct ipu_image_convert_run'. ipu_image_convert_queue() now
  takes a run pointer. Caller must dynamically allocate and fill the run
  with a conversion context handle and the input/output buffer dma addresses,
  and free the run object when it is returned in the completion callback.
- ipu_image_convert_adjust() is now a void.

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/Makefile|3 +-
 drivers/gpu/ipu-v3/ipu-common.c|9 +
 drivers/gpu/ipu-v3/ipu-image-convert.c | 1718 
 drivers/gpu/ipu-v3/ipu-prv.h   |5 +
 include/video/imx-image-convert.h  |  207 
 5 files changed, 1941 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/ipu-v3/ipu-image-convert.c
 create mode 100644 include/video/imx-image-convert.h

diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile
index 107ec23..8ac08e3 100644
--- a/drivers/gpu/ipu-v3/Makefile
+++ b/drivers/gpu/ipu-v3/Makefile
@@ -1,4 +1,5 @@
 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-image-convert.o \
+   ipu-smfc.o
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index fe389dd..a1219fb

  1   2   3   >