linux-renesas-soc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v2 0/5] media: vsp1: Partition phased overlap support
@ 2019-03-01 17:08 Kieran Bingham
  2019-03-01 17:08 ` [RFC PATCH v2 1/5] media: vsp1: Define partition algorithm helper Kieran Bingham
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Kieran Bingham @ 2019-03-01 17:08 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media, linux-renesas-soc; +Cc: Kieran Bingham

From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

The UDS and SRU (and SHP) require expanded partition windows to support
overlapping partition windows as a means of discarding discontinous pixel data,
due to repeated pixels in their input filters.

The first four patches are clean ups and helpers to facilitate the
implementation of an updated procedure for calculating the partition windows.

The entities are iterated first backwards through the pipeline allowing them to
request an expanded input window if needed to satisfy their required output.

Then, as only the WPF can support clipping on the left edge, (though the UDS
can clip on it's right edge) the partition window is then propagated forwards
through the entity list allowing them to update any offset which will mark left
pixels to be discarded by the WPF.

Any expanded pixels to the right edge will automatically be clipped by the WPF
as it's partition window will remain fixed.

TODO:

There is one component left in this patch which is still to be completed. The
UDS calculation for the left input pixel position requires the output position
to be a multiple of the mp prefilter multiplier.

Getting the right correction to pull back the left window for this is still a
work in progress, and may be posted separately.

This series is posted as an RFC to get some review coverage (I'm looking at you
Laurent of course) while I continue to investigate the pull-back factor.


Kieran Bingham (5):
  media: vsp1: Define partition algorithm helper
  media: vsp1: Initialise partition windows
  media: vsp1: Document partition algorithm in code header
  media: vsp1: Split out pre-filter multiplier
  media: vsp1: Provide partition overlap algorithm

 drivers/media/platform/vsp1/vsp1_entity.h |   2 +-
 drivers/media/platform/vsp1/vsp1_pipe.c   |  48 +++++-
 drivers/media/platform/vsp1/vsp1_pipe.h   |   7 +
 drivers/media/platform/vsp1/vsp1_rpf.c    |  10 +-
 drivers/media/platform/vsp1/vsp1_sru.c    |  37 ++++-
 drivers/media/platform/vsp1/vsp1_uds.c    | 173 ++++++++++++++++++++--
 drivers/media/platform/vsp1/vsp1_video.c  |  13 +-
 drivers/media/platform/vsp1/vsp1_wpf.c    |  16 +-
 8 files changed, 276 insertions(+), 30 deletions(-)

-- 
2.19.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [RFC PATCH v2 1/5] media: vsp1: Define partition algorithm helper
  2019-03-01 17:08 [RFC PATCH v2 0/5] media: vsp1: Partition phased overlap support Kieran Bingham
@ 2019-03-01 17:08 ` Kieran Bingham
  2019-03-01 17:08 ` [RFC PATCH v2 2/5] media: vsp1: Initialise partition windows Kieran Bingham
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Kieran Bingham @ 2019-03-01 17:08 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media, linux-renesas-soc; +Cc: Kieran Bingham

From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

Provide a helper to describe when the partition algorithm is in use on a
given pipeline.  This improves readability to the purpose of the code,
rather than obtusely checking the number of partitions.

Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_pipe.c  | 8 ++++++++
 drivers/media/platform/vsp1/vsp1_pipe.h  | 1 +
 drivers/media/platform/vsp1/vsp1_rpf.c   | 2 +-
 drivers/media/platform/vsp1/vsp1_video.c | 2 +-
 drivers/media/platform/vsp1/vsp1_wpf.c   | 2 +-
 5 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 54ff539ffea0..f1bd21a01bcd 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -364,6 +364,14 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 	vsp1_uds_set_alpha(pipe->uds, dlb, alpha);
 }
 
+/*
+ * Identify if the partition algorithm is in use or not
+ */
+bool vsp1_pipeline_partitioned(struct vsp1_pipeline *pipe)
+{
+	return pipe->partitions > 1;
+}
+
 /*
  * Propagate the partition calculations through the pipeline
  *
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index ae646c9ef337..dd8b2cdc6452 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -164,6 +164,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 				   struct vsp1_dl_body *dlb,
 				   unsigned int alpha);
 
+bool vsp1_pipeline_partitioned(struct vsp1_pipeline *pipe);
 void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
 				       struct vsp1_partition *partition,
 				       unsigned int index,
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 616afa7e165f..ef9bf5dd55a0 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -269,7 +269,7 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
 	 * matching the expected partition window. Only 'left' and
 	 * 'width' need to be adjusted.
 	 */
-	if (pipe->partitions > 1) {
+	if (vsp1_pipeline_partitioned(pipe)) {
 		crop.width = pipe->partition->rpf.width;
 		crop.left += pipe->partition->rpf.left;
 	}
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 7ceaf3222145..ee2fb8261a6a 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -201,7 +201,7 @@ static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe,
 					    RWPF_PAD_SINK);
 
 	/* A single partition simply processes the output size in full. */
-	if (pipe->partitions <= 1) {
+	if (!vsp1_pipeline_partitioned(pipe)) {
 		window.left = 0;
 		window.width = format->width;
 
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 32bb207b2007..9e8dbf99878b 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -376,7 +376,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
 	 * Cropping. The partition algorithm can split the image into
 	 * multiple slices.
 	 */
-	if (pipe->partitions > 1)
+	if (vsp1_pipeline_partitioned(pipe))
 		width = pipe->partition->wpf.width;
 
 	vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFC PATCH v2 2/5] media: vsp1: Initialise partition windows
  2019-03-01 17:08 [RFC PATCH v2 0/5] media: vsp1: Partition phased overlap support Kieran Bingham
  2019-03-01 17:08 ` [RFC PATCH v2 1/5] media: vsp1: Define partition algorithm helper Kieran Bingham
@ 2019-03-01 17:08 ` Kieran Bingham
  2019-03-01 17:08 ` [RFC PATCH v2 3/5] media: vsp1: Document partition algorithm in code header Kieran Bingham
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Kieran Bingham @ 2019-03-01 17:08 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media, linux-renesas-soc; +Cc: Kieran Bingham

From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

Ensure that the partition window is correctly initialised before being
utilised.

Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index ee2fb8261a6a..563f9a02c373 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -189,7 +189,7 @@ static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe,
 					   unsigned int index)
 {
 	const struct v4l2_mbus_framefmt *format;
-	struct vsp1_partition_window window;
+	struct vsp1_partition_window window = { 0, };
 	unsigned int modulus;
 
 	/*
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFC PATCH v2 3/5] media: vsp1: Document partition algorithm in code header
  2019-03-01 17:08 [RFC PATCH v2 0/5] media: vsp1: Partition phased overlap support Kieran Bingham
  2019-03-01 17:08 ` [RFC PATCH v2 1/5] media: vsp1: Define partition algorithm helper Kieran Bingham
  2019-03-01 17:08 ` [RFC PATCH v2 2/5] media: vsp1: Initialise partition windows Kieran Bingham
@ 2019-03-01 17:08 ` Kieran Bingham
  2019-03-01 17:08 ` [RFC PATCH v2 4/5] media: vsp1: Split out pre-filter multiplier Kieran Bingham
  2019-03-01 17:08 ` [RFC PATCH v2 5/5] media: vsp1: Provide partition overlap algorithm Kieran Bingham
  4 siblings, 0 replies; 7+ messages in thread
From: Kieran Bingham @ 2019-03-01 17:08 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media, linux-renesas-soc; +Cc: Kieran Bingham

From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

The image partition algorithm operates on the image dimensions as input
into the WPF entity. Document this in the code block header.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 563f9a02c373..d1ecc3d91290 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -173,6 +173,14 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
 
 /* -----------------------------------------------------------------------------
  * VSP1 Partition Algorithm support
+ *
+ * VSP hardware can have restrictions on image width dependent on the hardware
+ * configuration of the pipeline. Adapting for these restrictions is implemented
+ * via the partition algorithm.
+ *
+ * The partition windows and sizes are based on the output size of the WPF
+ * before rotation, which is represented by the input parameters to the WPF
+ * entity in our pipeline.
  */
 
 /**
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFC PATCH v2 4/5] media: vsp1: Split out pre-filter multiplier
  2019-03-01 17:08 [RFC PATCH v2 0/5] media: vsp1: Partition phased overlap support Kieran Bingham
                   ` (2 preceding siblings ...)
  2019-03-01 17:08 ` [RFC PATCH v2 3/5] media: vsp1: Document partition algorithm in code header Kieran Bingham
@ 2019-03-01 17:08 ` Kieran Bingham
  2019-03-01 17:08 ` [RFC PATCH v2 5/5] media: vsp1: Provide partition overlap algorithm Kieran Bingham
  4 siblings, 0 replies; 7+ messages in thread
From: Kieran Bingham @ 2019-03-01 17:08 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media, linux-renesas-soc; +Cc: Kieran Bingham

From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

The 'mp' value is used through many calculations in determining the scaling
factors of the UDS. Factor this out so that it can be reused in further
calculations, and also ensure that if the BLADV control is ever changed only a
single function needs to be modified.

Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_uds.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 27012af973b2..c71c24363d54 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -46,6 +46,18 @@ void vsp1_uds_set_alpha(struct vsp1_entity *entity, struct vsp1_dl_body *dlb,
 		       alpha << VI6_UDS_ALPVAL_VAL0_SHIFT);
 }
 
+/*
+ * Determine the pre-filter multiplication value.
+ *
+ * This calculation assumes that the BLADV control is unset.
+ */
+static unsigned int uds_multiplier(int ratio)
+{
+	unsigned int mp = ratio / 4096;
+
+	return mp < 4 ? 1 : (mp < 8 ? 2 : 4);
+}
+
 /*
  * uds_output_size - Return the output size for an input size and scaling ratio
  * @input: input size in pixels
@@ -55,10 +67,7 @@ static unsigned int uds_output_size(unsigned int input, unsigned int ratio)
 {
 	if (ratio > 4096) {
 		/* Down-scaling */
-		unsigned int mp;
-
-		mp = ratio / 4096;
-		mp = mp < 4 ? 1 : (mp < 8 ? 2 : 4);
+		unsigned int mp = uds_multiplier(ratio);
 
 		return (input - 1) / mp * mp * 4096 / ratio + 1;
 	} else {
@@ -88,10 +97,7 @@ static unsigned int uds_passband_width(unsigned int ratio)
 {
 	if (ratio >= 4096) {
 		/* Down-scaling */
-		unsigned int mp;
-
-		mp = ratio / 4096;
-		mp = mp < 4 ? 1 : (mp < 8 ? 2 : 4);
+		unsigned int mp = uds_multiplier(ratio);
 
 		return 64 * 4096 * mp / ratio;
 	} else {
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFC PATCH v2 5/5] media: vsp1: Provide partition overlap algorithm
  2019-03-01 17:08 [RFC PATCH v2 0/5] media: vsp1: Partition phased overlap support Kieran Bingham
                   ` (3 preceding siblings ...)
  2019-03-01 17:08 ` [RFC PATCH v2 4/5] media: vsp1: Split out pre-filter multiplier Kieran Bingham
@ 2019-03-01 17:08 ` Kieran Bingham
  2019-03-04 11:46   ` Kieran Bingham
  4 siblings, 1 reply; 7+ messages in thread
From: Kieran Bingham @ 2019-03-01 17:08 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media, linux-renesas-soc; +Cc: Kieran Bingham

From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

To improve image quality when scaling using the UDS we need to correctly
determine the start phase value for each partition window, and apply a
margin to overlap discontinous pixels.

Provide helper functions for calculating the phase parameters, and source
locations for a given output position and use these values to calculate our
parition window parameters.

Extend the partition algorithm to sweep first backwards, then forwards
through the entity list. Each entity is given the opportunity to expand it's window on the reverse sweep, and clip
or increase the offset on the forwards sweep.

Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

---
v2:
 - Configure HSTP and HEDP in uds_configure_partition for single partitions
 - refactored to use individual functions for various phase and position calculations
 - squashed forwards and backwards propagation work to a single patch
 - Fixed a few 'off-by-ones'
 - considerable other changes :)
---
 drivers/media/platform/vsp1/vsp1_entity.h |   2 +-
 drivers/media/platform/vsp1/vsp1_pipe.c   |  40 +++++-
 drivers/media/platform/vsp1/vsp1_pipe.h   |   6 +
 drivers/media/platform/vsp1/vsp1_rpf.c    |   8 +-
 drivers/media/platform/vsp1/vsp1_sru.c    |  37 +++++-
 drivers/media/platform/vsp1/vsp1_uds.c    | 151 +++++++++++++++++++++-
 drivers/media/platform/vsp1/vsp1_video.c  |   1 +
 drivers/media/platform/vsp1/vsp1_wpf.c    |  16 ++-
 8 files changed, 242 insertions(+), 19 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 97acb7795cf1..772492877764 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -88,7 +88,7 @@ struct vsp1_entity_operations {
 	unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *);
 	void (*partition)(struct vsp1_entity *, struct vsp1_pipeline *,
 			  struct vsp1_partition *, unsigned int,
-			  struct vsp1_partition_window *);
+			  struct vsp1_partition_window *, bool);
 };
 
 struct vsp1_entity {
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index f1bd21a01bcd..137ebe0ecad2 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -375,10 +375,32 @@ bool vsp1_pipeline_partitioned(struct vsp1_pipeline *pipe)
 /*
  * Propagate the partition calculations through the pipeline
  *
- * Work backwards through the pipe, allowing each entity to update the partition
- * parameters based on its configuration, and the entity connected to its
- * source. Each entity must produce the partition required for the previous
- * entity in the pipeline.
+ * Work backwards through the pipe, allowing each entity to update the
+ * partition parameters based on its configuration. Each entity must produce
+ * the partition window required for the previous entity in the pipeline
+ * to generate. This window can be passed through if no changes are necessary.
+ *
+ * Entities are processed in reverse order:
+ *	DDDD = Destination pixels
+ *	SSSS = Source pixels
+ *	==== = Intermediate pixels
+ *	____ = Disposable pixels
+ *
+ * WPF			    |DDDD|	WPF determines it's required partition
+ * SRU			    |====|	Interconnected entities pass through
+ * UDS(source)		   |<====>|	UDS Source requests overlap
+ * UDS(sink)		|<-|======|->|	UDS Sink calculates input size
+ * RPF			|__SSSSSSSS__|	RPF provides extra pixels
+ *
+ * Then work forwards through the pipe allowing entities to communicate any
+ * clipping required based on any overlap and expansions they may have
+ * generated.
+ *
+ * RPF			|__SSSSSSSS__|	Partition window is propagated forwards
+ * UDS(sink)		|============|
+ * UDS(source)		   |<====>|	UDS Source reports overlap
+ * SRU			   |======|	Interconnected entities are updated
+ * WPF			   |_DDDD_|	WPF handles clipping
  */
 void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
 				       struct vsp1_partition *partition,
@@ -387,10 +409,18 @@ void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
 {
 	struct vsp1_entity *entity;
 
+	/* Move backwards through the pipeline to propagate any expansion. */
 	list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) {
 		if (entity->ops->partition)
 			entity->ops->partition(entity, pipe, partition, index,
-					       window);
+					       window, false);
+	}
+
+	/* Move forwards through the pipeline and propagate any updates. */
+	list_for_each_entry(entity, &pipe->entities, list_pipe) {
+		if (entity->ops->partition)
+			entity->ops->partition(entity, pipe, partition, index,
+					       window, true);
 	}
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index dd8b2cdc6452..3e263a60f79b 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -58,10 +58,12 @@ enum vsp1_pipeline_state {
  * @left: horizontal coordinate of the partition start in pixels relative to the
  *	  left edge of the image
  * @width: partition width in pixels
+ * @offset: The number of pixels from the left edge of the window to clip
  */
 struct vsp1_partition_window {
 	unsigned int left;
 	unsigned int width;
+	unsigned int offset;
 };
 
 /*
@@ -71,6 +73,8 @@ struct vsp1_partition_window {
  * @uds_source: The UDS output partition window configuration
  * @sru: The SRU partition window configuration
  * @wpf: The WPF partition window configuration
+ * @start_phase: The UDS start phase for this partition
+ * @end_phase: The UDS end phase for this partition
  */
 struct vsp1_partition {
 	struct vsp1_partition_window rpf;
@@ -78,6 +82,8 @@ struct vsp1_partition {
 	struct vsp1_partition_window uds_source;
 	struct vsp1_partition_window sru;
 	struct vsp1_partition_window wpf;
+	unsigned int start_phase;
+	unsigned int end_phase;
 };
 
 /*
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index ef9bf5dd55a0..46d270644fe2 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -324,9 +324,13 @@ static void rpf_partition(struct vsp1_entity *entity,
 			  struct vsp1_pipeline *pipe,
 			  struct vsp1_partition *partition,
 			  unsigned int partition_idx,
-			  struct vsp1_partition_window *window)
+			  struct vsp1_partition_window *window,
+			  bool forwards)
 {
-	partition->rpf = *window;
+	if (forwards)
+		*window = partition->rpf;
+	else
+		partition->rpf = *window;
 }
 
 static const struct vsp1_entity_operations rpf_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index b1617cb1f2b9..39f6e80a02a9 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -327,24 +327,57 @@ static void sru_partition(struct vsp1_entity *entity,
 			  struct vsp1_pipeline *pipe,
 			  struct vsp1_partition *partition,
 			  unsigned int partition_idx,
-			  struct vsp1_partition_window *window)
+			  struct vsp1_partition_window *window,
+			  bool forwards)
 {
 	struct vsp1_sru *sru = to_sru(&entity->subdev);
 	struct v4l2_mbus_framefmt *input;
 	struct v4l2_mbus_framefmt *output;
+	int scale_up;
+
+	/* The partition->sru represents the SRU sink pad configuration. */
 
 	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
 					   SRU_PAD_SINK);
 	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
 					    SRU_PAD_SOURCE);
 
+	scale_up = (input->width != output->width);
+
+	if (forwards) {
+		/* Propagate the clipping offsets forwards. */
+		window->offset += partition->sru.offset;
+
+		if (scale_up)
+			window->offset *= 2;
+
+		return;
+	}
+
 	/* Adapt if SRUx2 is enabled. */
-	if (input->width != output->width) {
+	if (scale_up) {
+		/* Clipping offsets are not back-propagated. */
 		window->width /= 2;
 		window->left /= 2;
+
+		/* SRUx2 requires an extra pixel at the right edge. */
+		window->width++;
 	}
 
+	/* Store our adapted sink window. */
 	partition->sru = *window;
+
+	/* Expand to the left edge. */
+	if (window->left != 0) {
+		window->left--;
+		window->width++;
+		partition->sru.offset = 1;
+	} else {
+		partition->sru.offset = 0;
+	}
+
+	/* Expand to the right edge. */
+	window->width++;
 }
 
 static const struct vsp1_entity_operations sru_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index c71c24363d54..e2bd44740ad6 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -58,6 +58,85 @@ static unsigned int uds_multiplier(int ratio)
 	return mp < 4 ? 1 : (mp < 8 ? 2 : 4);
 }
 
+/*
+ *  These functions all assume a starting phase of 0.
+ *	i.e. the left edge of the image.
+ */
+
+/*
+ * uds_residual - Return the residual phase cycle at the given position
+ * @pos: source destination position
+ * @ratio: scaling ratio in U4.12 fixed-point format
+ */
+static unsigned int uds_residual(unsigned int pos, unsigned int ratio)
+{
+	unsigned int mp = uds_multiplier(ratio);
+	unsigned int residual = (pos * ratio) % (mp * 4096);
+
+	return residual;
+}
+
+/*
+ * uds_left_src_pixel - Return the sink pixel location for the given source
+ * position
+ *
+ * @pos: source destination position
+ * @ratio: scaling ratio in U4.12 fixed-point format
+ */
+static unsigned int uds_left_src_pixel(unsigned int pos, unsigned int ratio)
+{
+	unsigned int mp = uds_multiplier(ratio);
+	unsigned int prefilter_out = (pos * ratio) / (mp * 4096);
+	unsigned int residual = (pos * ratio) % (mp * 4096);
+
+	/* Todo: Section 32.3.7.5 : Procedure 3
+	 *
+	 * A restriction is described where the destination position must
+	 * satisfy the following conditions:
+	 *
+	 *  (pos * ratio) must be a multiple of mp
+	 *
+	 * This is not yet guaranteed and thus this check is in place
+	 * until the pull-back is correctly calculated for all ratio
+	 * and position values.
+	 */
+	WARN_ONCE((mp == 2 && (residual & 0x01)) ||
+		  (mp == 4 && (residual & 0x03)),
+		       "uds_left_pixel restrictions failed");
+
+	return mp * (prefilter_out + (residual ? 1 : 0));
+}
+
+/*
+ * uds_right_src_pixel - Return the sink pixel location for the given source
+ * position
+ *
+ * @pos: source destination position
+ * @ratio: scaling ratio in U4.12 fixed-point format
+ */
+static unsigned int uds_right_src_pixel(unsigned int pos, unsigned int ratio)
+{
+	unsigned int mp = uds_multiplier(ratio);
+	unsigned int prefilter_out = (pos * ratio) / (mp * 4096);
+
+	return mp * (prefilter_out + 2) + (mp / 2);
+}
+
+/*
+ * uds_start_phase - Return the sink pixel location for the given source
+ * position
+ *
+ * @pos: source destination position
+ * @ratio: scaling ratio in U4.12 fixed-point format
+ */
+static unsigned int uds_start_phase(unsigned int pos, unsigned int ratio)
+{
+	unsigned int mp = uds_multiplier(ratio);
+	unsigned int residual = (pos * ratio) % (mp * 4096);
+
+	return residual ? (4096 - residual / mp) : 0;
+}
+
 /*
  * uds_output_size - Return the output size for an input size and scaling ratio
  * @input: input size in pixels
@@ -270,6 +349,7 @@ static void uds_configure_stream(struct vsp1_entity *entity,
 	const struct v4l2_mbus_framefmt *input;
 	unsigned int hscale;
 	unsigned int vscale;
+	bool manual_phase = vsp1_pipeline_partitioned(pipe);
 	bool multitap;
 
 	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
@@ -294,7 +374,8 @@ static void uds_configure_stream(struct vsp1_entity *entity,
 
 	vsp1_uds_write(uds, dlb, VI6_UDS_CTRL,
 		       (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
-		       (multitap ? VI6_UDS_CTRL_BC : 0));
+		       (multitap ? VI6_UDS_CTRL_BC : 0) |
+		       (manual_phase ? VI6_UDS_CTRL_AMDSLH : 0));
 
 	vsp1_uds_write(uds, dlb, VI6_UDS_PASS_BWIDTH,
 		       (uds_passband_width(hscale)
@@ -332,6 +413,12 @@ static void uds_configure_partition(struct vsp1_entity *entity,
 				<< VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
 		       (output->height
 				<< VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
+
+	vsp1_uds_write(uds, dlb, VI6_UDS_HPHASE,
+		       (partition->start_phase
+				<< VI6_UDS_HPHASE_HSTP_SHIFT) |
+		       (partition->end_phase
+				<< VI6_UDS_HPHASE_HEDP_SHIFT));
 }
 
 static unsigned int uds_max_width(struct vsp1_entity *entity,
@@ -374,11 +461,23 @@ static void uds_partition(struct vsp1_entity *entity,
 			  struct vsp1_pipeline *pipe,
 			  struct vsp1_partition *partition,
 			  unsigned int partition_idx,
-			  struct vsp1_partition_window *window)
+			  struct vsp1_partition_window *window,
+			  bool forwards)
 {
 	struct vsp1_uds *uds = to_uds(&entity->subdev);
 	const struct v4l2_mbus_framefmt *output;
 	const struct v4l2_mbus_framefmt *input;
+	unsigned int hscale;
+	unsigned int right_sink;
+	unsigned int margin;
+	unsigned int left;
+	unsigned int right;
+
+	/* For forwards propagation - simply pass on our output. */
+	if (forwards) {
+		*window = partition->uds_source;
+		return;
+	}
 
 	/* Initialise the partition state. */
 	partition->uds_sink = *window;
@@ -389,11 +488,51 @@ static void uds_partition(struct vsp1_entity *entity,
 	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
 					    UDS_PAD_SOURCE);
 
-	partition->uds_sink.width = window->width * input->width
-				  / output->width;
-	partition->uds_sink.left = window->left * input->width
-				 / output->width;
+	hscale = uds_compute_ratio(input->width, output->width);
+
+	/*
+	 * Quantify the margin required for discontinuous overlap, and expand
+	 * the window no further than the limits of the image.
+	 */
+	margin = hscale < 0x200 ? 32 : /* 8 <  scale */
+		 hscale < 0x400 ? 16 : /* 4 <  scale <= 8 */
+		 hscale < 0x800 ?  8 : /* 2 <  scale <= 4 */
+				   4;  /*      scale <= 2 */
+
+	left = max_t(int, 0, window->left - margin);
+	right = min_t(int, output->width - 1,
+			   window->left + window->width - 1 + margin);
+
+	/*
+	 * Handle our output partition configuration.
+	 * We can clip the pixels from the right edge, thus the
+	 * uds_source.width does not include the right margin.
+	 */
+	partition->uds_source.left = left;
+	partition->uds_source.width = window->left - left + window->width;
+
+	/*
+	 * The UDS can not clip the left pixels so this value will be
+	 * propagated forwards until it reaches the WPF.
+	 */
+	partition->uds_source.offset = window->left - left;
+
+	/* Identify the input positions from the expanded partition. */
+	partition->uds_sink.left = uds_left_src_pixel(left, hscale);
+
+	right_sink = uds_right_src_pixel(right, hscale);
+	partition->uds_sink.width = right_sink - partition->uds_sink.left;
+
+	/*
+	 * We do not currently use VI6_UDS_CTRL_AMD from VI6_UDS_CTRL.
+	 * In the event that we enable VI6_UDS_CTRL_AMD, we must set the end
+	 * phase for the final partition to the phase_edge.
+	 */
+	partition->end_phase = 0;
+	partition->start_phase = uds_start_phase(partition->uds_source.left,
+						 hscale);
 
+	/* Pass a copy of our sink down to the previous entity. */
 	*window = partition->uds_sink;
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index d1ecc3d91290..3638a4e9bb19 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -221,6 +221,7 @@ static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe,
 	/* Initialise the partition with sane starting conditions. */
 	window.left = index * div_size;
 	window.width = div_size;
+	window.offset = 0;
 
 	modulus = format->width % div_size;
 
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 9e8dbf99878b..2e8cc4195c31 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -371,16 +371,19 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
 						 RWPF_PAD_SINK);
 	width = sink_format->width;
 	height = sink_format->height;
+	offset = 0;
 
 	/*
 	 * Cropping. The partition algorithm can split the image into
 	 * multiple slices.
 	 */
-	if (vsp1_pipeline_partitioned(pipe))
+	if (vsp1_pipeline_partitioned(pipe)) {
 		width = pipe->partition->wpf.width;
+		offset = pipe->partition->wpf.offset;
+	}
 
 	vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
-		       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
+		       (offset << VI6_WPF_SZCLIP_OFST_SHIFT) |
 		       (width << VI6_WPF_SZCLIP_SIZE_SHIFT));
 	vsp1_wpf_write(wpf, dlb, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
 		       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
@@ -491,8 +494,15 @@ static void wpf_partition(struct vsp1_entity *entity,
 			  struct vsp1_pipeline *pipe,
 			  struct vsp1_partition *partition,
 			  unsigned int partition_idx,
-			  struct vsp1_partition_window *window)
+			  struct vsp1_partition_window *window,
+			  bool forwards)
 {
+	if (forwards) {
+		/* Only handle incoming cropping requirements. */
+		partition->wpf.offset = window->offset;
+		return;
+	}
+
 	partition->wpf = *window;
 }
 
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH v2 5/5] media: vsp1: Provide partition overlap algorithm
  2019-03-01 17:08 ` [RFC PATCH v2 5/5] media: vsp1: Provide partition overlap algorithm Kieran Bingham
@ 2019-03-04 11:46   ` Kieran Bingham
  0 siblings, 0 replies; 7+ messages in thread
From: Kieran Bingham @ 2019-03-04 11:46 UTC (permalink / raw)
  To: Kieran Bingham, Laurent Pinchart, linux-media, linux-renesas-soc

On 01/03/2019 17:08, Kieran Bingham wrote:
> From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> 
> To improve image quality when scaling using the UDS we need to correctly
> determine the start phase value for each partition window, and apply a
> margin to overlap discontinous pixels.
> 
> Provide helper functions for calculating the phase parameters, and source
> locations for a given output position and use these values to calculate our
> parition window parameters.
> 
> Extend the partition algorithm to sweep first backwards, then forwards
> through the entity list. Each entity is given the opportunity to expand it's window on the reverse sweep, and clip


An oddly long line there - I'll rewrap on next iteration.

> or increase the offset on the forwards sweep.
> 
> Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> 
> ---
> v2:
>  - Configure HSTP and HEDP in uds_configure_partition for single partitions
>  - refactored to use individual functions for various phase and position calculations
>  - squashed forwards and backwards propagation work to a single patch
>  - Fixed a few 'off-by-ones'
>  - considerable other changes :)
> ---
>  drivers/media/platform/vsp1/vsp1_entity.h |   2 +-
>  drivers/media/platform/vsp1/vsp1_pipe.c   |  40 +++++-
>  drivers/media/platform/vsp1/vsp1_pipe.h   |   6 +
>  drivers/media/platform/vsp1/vsp1_rpf.c    |   8 +-
>  drivers/media/platform/vsp1/vsp1_sru.c    |  37 +++++-
>  drivers/media/platform/vsp1/vsp1_uds.c    | 151 +++++++++++++++++++++-
>  drivers/media/platform/vsp1/vsp1_video.c  |   1 +
>  drivers/media/platform/vsp1/vsp1_wpf.c    |  16 ++-
>  8 files changed, 242 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
> index 97acb7795cf1..772492877764 100644
> --- a/drivers/media/platform/vsp1/vsp1_entity.h
> +++ b/drivers/media/platform/vsp1/vsp1_entity.h
> @@ -88,7 +88,7 @@ struct vsp1_entity_operations {
>  	unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *);
>  	void (*partition)(struct vsp1_entity *, struct vsp1_pipeline *,
>  			  struct vsp1_partition *, unsigned int,
> -			  struct vsp1_partition_window *);
> +			  struct vsp1_partition_window *, bool);
>  };
>  
>  struct vsp1_entity {
> diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
> index f1bd21a01bcd..137ebe0ecad2 100644
> --- a/drivers/media/platform/vsp1/vsp1_pipe.c
> +++ b/drivers/media/platform/vsp1/vsp1_pipe.c
> @@ -375,10 +375,32 @@ bool vsp1_pipeline_partitioned(struct vsp1_pipeline *pipe)
>  /*
>   * Propagate the partition calculations through the pipeline
>   *
> - * Work backwards through the pipe, allowing each entity to update the partition
> - * parameters based on its configuration, and the entity connected to its
> - * source. Each entity must produce the partition required for the previous
> - * entity in the pipeline.
> + * Work backwards through the pipe, allowing each entity to update the
> + * partition parameters based on its configuration. Each entity must produce
> + * the partition window required for the previous entity in the pipeline
> + * to generate. This window can be passed through if no changes are necessary.
> + *
> + * Entities are processed in reverse order:
> + *	DDDD = Destination pixels
> + *	SSSS = Source pixels
> + *	==== = Intermediate pixels
> + *	____ = Disposable pixels
> + *
> + * WPF			    |DDDD|	WPF determines it's required partition
> + * SRU			    |====|	Interconnected entities pass through
> + * UDS(source)		   |<====>|	UDS Source requests overlap
> + * UDS(sink)		|<-|======|->|	UDS Sink calculates input size
> + * RPF			|__SSSSSSSS__|	RPF provides extra pixels
> + *
> + * Then work forwards through the pipe allowing entities to communicate any
> + * clipping required based on any overlap and expansions they may have
> + * generated.
> + *
> + * RPF			|__SSSSSSSS__|	Partition window is propagated forwards
> + * UDS(sink)		|============|
> + * UDS(source)		   |<====>|	UDS Source reports overlap
> + * SRU			   |======|	Interconnected entities are updated
> + * WPF			   |_DDDD_|	WPF handles clipping
>   */
>  void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
>  				       struct vsp1_partition *partition,
> @@ -387,10 +409,18 @@ void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
>  {
>  	struct vsp1_entity *entity;
>  
> +	/* Move backwards through the pipeline to propagate any expansion. */
>  	list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) {
>  		if (entity->ops->partition)
>  			entity->ops->partition(entity, pipe, partition, index,
> -					       window);
> +					       window, false);
> +	}
> +
> +	/* Move forwards through the pipeline and propagate any updates. */
> +	list_for_each_entry(entity, &pipe->entities, list_pipe) {
> +		if (entity->ops->partition)
> +			entity->ops->partition(entity, pipe, partition, index,
> +					       window, true);
>  	}
>  }
>  
> diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
> index dd8b2cdc6452..3e263a60f79b 100644
> --- a/drivers/media/platform/vsp1/vsp1_pipe.h
> +++ b/drivers/media/platform/vsp1/vsp1_pipe.h
> @@ -58,10 +58,12 @@ enum vsp1_pipeline_state {
>   * @left: horizontal coordinate of the partition start in pixels relative to the
>   *	  left edge of the image
>   * @width: partition width in pixels
> + * @offset: The number of pixels from the left edge of the window to clip
>   */
>  struct vsp1_partition_window {
>  	unsigned int left;
>  	unsigned int width;
> +	unsigned int offset;
>  };
>  
>  /*
> @@ -71,6 +73,8 @@ struct vsp1_partition_window {
>   * @uds_source: The UDS output partition window configuration
>   * @sru: The SRU partition window configuration
>   * @wpf: The WPF partition window configuration
> + * @start_phase: The UDS start phase for this partition
> + * @end_phase: The UDS end phase for this partition
>   */
>  struct vsp1_partition {
>  	struct vsp1_partition_window rpf;
> @@ -78,6 +82,8 @@ struct vsp1_partition {
>  	struct vsp1_partition_window uds_source;
>  	struct vsp1_partition_window sru;
>  	struct vsp1_partition_window wpf;
> +	unsigned int start_phase;
> +	unsigned int end_phase;
>  };
>  
>  /*
> diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
> index ef9bf5dd55a0..46d270644fe2 100644
> --- a/drivers/media/platform/vsp1/vsp1_rpf.c
> +++ b/drivers/media/platform/vsp1/vsp1_rpf.c
> @@ -324,9 +324,13 @@ static void rpf_partition(struct vsp1_entity *entity,
>  			  struct vsp1_pipeline *pipe,
>  			  struct vsp1_partition *partition,
>  			  unsigned int partition_idx,
> -			  struct vsp1_partition_window *window)
> +			  struct vsp1_partition_window *window,
> +			  bool forwards)
>  {
> -	partition->rpf = *window;
> +	if (forwards)
> +		*window = partition->rpf;
> +	else
> +		partition->rpf = *window;
>  }
>  
>  static const struct vsp1_entity_operations rpf_entity_ops = {
> diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
> index b1617cb1f2b9..39f6e80a02a9 100644
> --- a/drivers/media/platform/vsp1/vsp1_sru.c
> +++ b/drivers/media/platform/vsp1/vsp1_sru.c
> @@ -327,24 +327,57 @@ static void sru_partition(struct vsp1_entity *entity,
>  			  struct vsp1_pipeline *pipe,
>  			  struct vsp1_partition *partition,
>  			  unsigned int partition_idx,
> -			  struct vsp1_partition_window *window)
> +			  struct vsp1_partition_window *window,
> +			  bool forwards)
>  {
>  	struct vsp1_sru *sru = to_sru(&entity->subdev);
>  	struct v4l2_mbus_framefmt *input;
>  	struct v4l2_mbus_framefmt *output;
> +	int scale_up;
> +
> +	/* The partition->sru represents the SRU sink pad configuration. */

In actual fact, only the 'offset' needs to be stored for the SRU. It's
more of a passive entity, and no partition parameters get programmed at
runtime.

For consistency, I think it's still worth keeping partition->sru the
same type as the other entities.

I'll remove this line and update the comment where the structure is
stored...

>  
>  	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
>  					   SRU_PAD_SINK);
>  	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
>  					    SRU_PAD_SOURCE);
>  
> +	scale_up = (input->width != output->width);
> +
> +	if (forwards) {
> +		/* Propagate the clipping offsets forwards. */
> +		window->offset += partition->sru.offset;
> +
> +		if (scale_up)
> +			window->offset *= 2;
> +
> +		return;
> +	}
> +
>  	/* Adapt if SRUx2 is enabled. */
> -	if (input->width != output->width) {
> +	if (scale_up) {
> +		/* Clipping offsets are not back-propagated. */
>  		window->width /= 2;
>  		window->left /= 2;
> +
> +		/* SRUx2 requires an extra pixel at the right edge. */
> +		window->width++;
>  	}
>  
> +	/* Store our adapted sink window. */


/*
 * The partition->sru represents the SRU sink pad configuration.
 * However, the SRU is a passive component in the partition algorithm.
 */

>  	partition->sru = *window;> +
> +	/* Expand to the left edge. */
> +	if (window->left != 0) {
> +		window->left--;
> +		window->width++;
> +		partition->sru.offset = 1;
> +	} else {
> +		partition->sru.offset = 0;
> +	}
> +
> +	/* Expand to the right edge. */
> +	window->width++;
>  }
>  
>  static const struct vsp1_entity_operations sru_entity_ops = {
> diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
> index c71c24363d54..e2bd44740ad6 100644
> --- a/drivers/media/platform/vsp1/vsp1_uds.c
> +++ b/drivers/media/platform/vsp1/vsp1_uds.c
> @@ -58,6 +58,85 @@ static unsigned int uds_multiplier(int ratio)
>  	return mp < 4 ? 1 : (mp < 8 ? 2 : 4);
>  }
>  
> +/*
> + *  These functions all assume a starting phase of 0.
> + *	i.e. the left edge of the image.
> + */
> +
> +/*
> + * uds_residual - Return the residual phase cycle at the given position
> + * @pos: source destination position

Source destination position is horrible here.

I think I'll reword this (and the others) as

@pos: source output position.

Even that might need some more thought...


> + * @ratio: scaling ratio in U4.12 fixed-point format
> + */
> +static unsigned int uds_residual(unsigned int pos, unsigned int ratio)
> +{
> +	unsigned int mp = uds_multiplier(ratio);
> +	unsigned int residual = (pos * ratio) % (mp * 4096);
> +
> +	return residual;
> +}
> +
> +/*
> + * uds_left_src_pixel - Return the sink pixel location for the given source
> + * position
> + *
> + * @pos: source destination position
> + * @ratio: scaling ratio in U4.12 fixed-point format
> + */
> +static unsigned int uds_left_src_pixel(unsigned int pos, unsigned int ratio)


This function needs to be renamed to uds_left_sink_pixel

s/src/sink/...

> +{
> +	unsigned int mp = uds_multiplier(ratio);
> +	unsigned int prefilter_out = (pos * ratio) / (mp * 4096);
> +	unsigned int residual = (pos * ratio) % (mp * 4096);
> +
> +	/* Todo: Section 32.3.7.5 : Procedure 3
> +	 *
> +	 * A restriction is described where the destination position must
> +	 * satisfy the following conditions:
> +	 *
> +	 *  (pos * ratio) must be a multiple of mp
> +	 *
> +	 * This is not yet guaranteed and thus this check is in place
> +	 * until the pull-back is correctly calculated for all ratio
> +	 * and position values.
> +	 */
> +	WARN_ONCE((mp == 2 && (residual & 0x01)) ||
> +		  (mp == 4 && (residual & 0x03)),
> +		       "uds_left_pixel restrictions failed");
> +
> +	return mp * (prefilter_out + (residual ? 1 : 0));
> +}
> +
> +/*
> + * uds_right_src_pixel - Return the sink pixel location for the given source
> + * position
> + *
> + * @pos: source destination position
> + * @ratio: scaling ratio in U4.12 fixed-point format
> + */
> +static unsigned int uds_right_src_pixel(unsigned int pos, unsigned int ratio)

And the same here, it should be uds_right_sink_pixel.

It's the 'source' of the UDS - but in our system the input to the UDS is
the 'sink'


> +{
> +	unsigned int mp = uds_multiplier(ratio);
> +	unsigned int prefilter_out = (pos * ratio) / (mp * 4096);
> +
> +	return mp * (prefilter_out + 2) + (mp / 2);
> +}
> +
> +/*
> + * uds_start_phase - Return the sink pixel location for the given source
> + * position
> + *
> + * @pos: source destination position
> + * @ratio: scaling ratio in U4.12 fixed-point format
> + */
> +static unsigned int uds_start_phase(unsigned int pos, unsigned int ratio)
> +{
> +	unsigned int mp = uds_multiplier(ratio);
> +	unsigned int residual = (pos * ratio) % (mp * 4096);
> +
> +	return residual ? (4096 - residual / mp) : 0;
> +}
> +
>  /*
>   * uds_output_size - Return the output size for an input size and scaling ratio
>   * @input: input size in pixels
> @@ -270,6 +349,7 @@ static void uds_configure_stream(struct vsp1_entity *entity,
>  	const struct v4l2_mbus_framefmt *input;
>  	unsigned int hscale;
>  	unsigned int vscale;
> +	bool manual_phase = vsp1_pipeline_partitioned(pipe);
>  	bool multitap;
>  
>  	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
> @@ -294,7 +374,8 @@ static void uds_configure_stream(struct vsp1_entity *entity,
>  
>  	vsp1_uds_write(uds, dlb, VI6_UDS_CTRL,
>  		       (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
> -		       (multitap ? VI6_UDS_CTRL_BC : 0));
> +		       (multitap ? VI6_UDS_CTRL_BC : 0) |
> +		       (manual_phase ? VI6_UDS_CTRL_AMDSLH : 0));
>  
>  	vsp1_uds_write(uds, dlb, VI6_UDS_PASS_BWIDTH,
>  		       (uds_passband_width(hscale)
> @@ -332,6 +413,12 @@ static void uds_configure_partition(struct vsp1_entity *entity,
>  				<< VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
>  		       (output->height
>  				<< VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
> +
> +	vsp1_uds_write(uds, dlb, VI6_UDS_HPHASE,
> +		       (partition->start_phase
> +				<< VI6_UDS_HPHASE_HSTP_SHIFT) |
> +		       (partition->end_phase
> +				<< VI6_UDS_HPHASE_HEDP_SHIFT));
>  }
>  
>  static unsigned int uds_max_width(struct vsp1_entity *entity,
> @@ -374,11 +461,23 @@ static void uds_partition(struct vsp1_entity *entity,
>  			  struct vsp1_pipeline *pipe,
>  			  struct vsp1_partition *partition,
>  			  unsigned int partition_idx,
> -			  struct vsp1_partition_window *window)
> +			  struct vsp1_partition_window *window,
> +			  bool forwards)
>  {
>  	struct vsp1_uds *uds = to_uds(&entity->subdev);
>  	const struct v4l2_mbus_framefmt *output;
>  	const struct v4l2_mbus_framefmt *input;
> +	unsigned int hscale;
> +	unsigned int right_sink;
> +	unsigned int margin;
> +	unsigned int left;
> +	unsigned int right;
> +
> +	/* For forwards propagation - simply pass on our output. */
> +	if (forwards) {
> +		*window = partition->uds_source;
> +		return;
> +	}
>  
>  	/* Initialise the partition state. */
>  	partition->uds_sink = *window;
> @@ -389,11 +488,51 @@ static void uds_partition(struct vsp1_entity *entity,
>  	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
>  					    UDS_PAD_SOURCE);
>  
> -	partition->uds_sink.width = window->width * input->width
> -				  / output->width;
> -	partition->uds_sink.left = window->left * input->width
> -				 / output->width;
> +	hscale = uds_compute_ratio(input->width, output->width);
> +
> +	/*
> +	 * Quantify the margin required for discontinuous overlap, and expand
> +	 * the window no further than the limits of the image.
> +	 */
> +	margin = hscale < 0x200 ? 32 : /* 8 <  scale */
> +		 hscale < 0x400 ? 16 : /* 4 <  scale <= 8 */
> +		 hscale < 0x800 ?  8 : /* 2 <  scale <= 4 */
> +				   4;  /*      scale <= 2 */
> +
> +	left = max_t(int, 0, window->left - margin);
> +	right = min_t(int, output->width - 1,
> +			   window->left + window->width - 1 + margin);
> +
> +	/*
> +	 * Handle our output partition configuration.
> +	 * We can clip the pixels from the right edge, thus the
> +	 * uds_source.width does not include the right margin.
> +	 */
> +	partition->uds_source.left = left;
> +	partition->uds_source.width = window->left - left + window->width;
> +
> +	/*
> +	 * The UDS can not clip the left pixels so this value will be
> +	 * propagated forwards until it reaches the WPF.
> +	 */
> +	partition->uds_source.offset = window->left - left;
> +
> +	/* Identify the input positions from the expanded partition. */
> +	partition->uds_sink.left = uds_left_src_pixel(left, hscale);
> +
> +	right_sink = uds_right_src_pixel(right, hscale);
> +	partition->uds_sink.width = right_sink - partition->uds_sink.left;
> +
> +	/*
> +	 * We do not currently use VI6_UDS_CTRL_AMD from VI6_UDS_CTRL.
> +	 * In the event that we enable VI6_UDS_CTRL_AMD, we must set the end
> +	 * phase for the final partition to the phase_edge.
> +	 */
> +	partition->end_phase = 0;
> +	partition->start_phase = uds_start_phase(partition->uds_source.left,
> +						 hscale);
>  
> +	/* Pass a copy of our sink down to the previous entity. */
>  	*window = partition->uds_sink;
>  }
>  
> diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
> index d1ecc3d91290..3638a4e9bb19 100644
> --- a/drivers/media/platform/vsp1/vsp1_video.c
> +++ b/drivers/media/platform/vsp1/vsp1_video.c
> @@ -221,6 +221,7 @@ static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe,
>  	/* Initialise the partition with sane starting conditions. */
>  	window.left = index * div_size;
>  	window.width = div_size;
> +	window.offset = 0;
>  
>  	modulus = format->width % div_size;
>  
> diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
> index 9e8dbf99878b..2e8cc4195c31 100644
> --- a/drivers/media/platform/vsp1/vsp1_wpf.c
> +++ b/drivers/media/platform/vsp1/vsp1_wpf.c
> @@ -371,16 +371,19 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
>  						 RWPF_PAD_SINK);
>  	width = sink_format->width;
>  	height = sink_format->height;
> +	offset = 0;
>  
>  	/*
>  	 * Cropping. The partition algorithm can split the image into
>  	 * multiple slices.
>  	 */
> -	if (vsp1_pipeline_partitioned(pipe))
> +	if (vsp1_pipeline_partitioned(pipe)) {
>  		width = pipe->partition->wpf.width;
> +		offset = pipe->partition->wpf.offset;
> +	}
>  
>  	vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
> -		       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
> +		       (offset << VI6_WPF_SZCLIP_OFST_SHIFT) |
>  		       (width << VI6_WPF_SZCLIP_SIZE_SHIFT));
>  	vsp1_wpf_write(wpf, dlb, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
>  		       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
> @@ -491,8 +494,15 @@ static void wpf_partition(struct vsp1_entity *entity,
>  			  struct vsp1_pipeline *pipe,
>  			  struct vsp1_partition *partition,
>  			  unsigned int partition_idx,
> -			  struct vsp1_partition_window *window)
> +			  struct vsp1_partition_window *window,
> +			  bool forwards)
>  {
> +	if (forwards) {
> +		/* Only handle incoming cropping requirements. */
> +		partition->wpf.offset = window->offset;
> +		return;
> +	}
> +
>  	partition->wpf = *window;
>  }
>  
> 


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-03-04 11:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-01 17:08 [RFC PATCH v2 0/5] media: vsp1: Partition phased overlap support Kieran Bingham
2019-03-01 17:08 ` [RFC PATCH v2 1/5] media: vsp1: Define partition algorithm helper Kieran Bingham
2019-03-01 17:08 ` [RFC PATCH v2 2/5] media: vsp1: Initialise partition windows Kieran Bingham
2019-03-01 17:08 ` [RFC PATCH v2 3/5] media: vsp1: Document partition algorithm in code header Kieran Bingham
2019-03-01 17:08 ` [RFC PATCH v2 4/5] media: vsp1: Split out pre-filter multiplier Kieran Bingham
2019-03-01 17:08 ` [RFC PATCH v2 5/5] media: vsp1: Provide partition overlap algorithm Kieran Bingham
2019-03-04 11:46   ` Kieran Bingham

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).