diff mbox series

drm/vc4: Add support for X/Y reflection

Message ID 20181203133412.24442-1-boris.brezillon@bootlin.com (mailing list archive)
State New, archived
Headers show
Series drm/vc4: Add support for X/Y reflection | expand

Commit Message

Boris Brezillon Dec. 3, 2018, 1:34 p.m. UTC
Add support for X/Y reflection when the plane is using linear or T-tiled
formats. X/Y reflection hasn't been tested on SAND formats, so we reject
them until proper testing/debugging has been done.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
 drivers/gpu/drm/vc4/vc4_plane.c | 55 ++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 11 deletions(-)

Comments

Ville Syrjälä Dec. 3, 2018, 1:50 p.m. UTC | #1
On Mon, Dec 03, 2018 at 02:34:12PM +0100, Boris Brezillon wrote:
> Add support for X/Y reflection when the plane is using linear or T-tiled
> formats. X/Y reflection hasn't been tested on SAND formats, so we reject
> them until proper testing/debugging has been done.

BTW you could also expose 180 degress easily. See
drm_rotation_simplify().

> 
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> ---
>  drivers/gpu/drm/vc4/vc4_plane.c | 55 ++++++++++++++++++++++++++-------
>  1 file changed, 44 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
> index 75db62cbe468..bdcccf65cde0 100644
> --- a/drivers/gpu/drm/vc4/vc4_plane.c
> +++ b/drivers/gpu/drm/vc4/vc4_plane.c
> @@ -492,7 +492,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
>  	bool mix_plane_alpha;
>  	bool covers_screen;
>  	u32 scl0, scl1, pitch0;
> -	u32 tiling;
> +	u32 tiling, src_y;
>  	u32 hvs_format = format->hvs;
>  	int ret, i;
>  
> @@ -520,6 +520,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
>  	h_subsample = drm_format_horz_chroma_subsampling(format->drm);
>  	v_subsample = drm_format_vert_chroma_subsampling(format->drm);
>  
> +	/* We must point to the last line when Y reflection is enabled. */
> +	src_y = vc4_state->src_y;
> +	if (state->rotation & DRM_MODE_REFLECT_Y)
> +		src_y += vc4_state->src_h[0] - 1;
> +
>  	switch (base_format_mod) {
>  	case DRM_FORMAT_MOD_LINEAR:
>  		tiling = SCALER_CTL0_TILING_LINEAR;
> @@ -529,9 +534,10 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
>  		 * out.
>  		 */
>  		for (i = 0; i < num_planes; i++) {
> -			vc4_state->offsets[i] += vc4_state->src_y /
> +			vc4_state->offsets[i] += src_y /
>  						 (i ? v_subsample : 1) *
>  						 fb->pitches[i];
> +
>  			vc4_state->offsets[i] += vc4_state->src_x /
>  						 (i ? h_subsample : 1) *
>  						 fb->format->cpp[i];
> @@ -557,22 +563,38 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
>  		u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
>  		u32 tiles_l = vc4_state->src_x >> tile_w_shift;
>  		u32 tiles_r = tiles_w - tiles_l;
> -		u32 tiles_t = vc4_state->src_y >> tile_h_shift;
> +		u32 tiles_t = src_y >> tile_h_shift;
>  		/* Intra-tile offsets, which modify the base address (the
>  		 * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
>  		 * base address).
>  		 */
> -		u32 tile_y = (vc4_state->src_y >> 4) & 1;
> -		u32 subtile_y = (vc4_state->src_y >> 2) & 3;
> -		u32 utile_y = vc4_state->src_y & 3;
> +		u32 tile_y = (src_y >> 4) & 1;
> +		u32 subtile_y = (src_y >> 2) & 3;
> +		u32 utile_y = src_y & 3;
>  		u32 x_off = vc4_state->src_x & tile_w_mask;
> -		u32 y_off = vc4_state->src_y & tile_h_mask;
> +		u32 y_off = src_y & tile_h_mask;
> +
> +		/* When Y reflection is requested we must set the
> +		 * SCALER_PITCH0_TILE_LINE_DIR flag to tell HVS that all lines
> +		 * after the initial one should be fetched in descending order,
> +		 * which makes sense since we start from the last line and go
> +		 * backward.
> +		 * Don't know why we need y_off = max_y_off - y_off, but it's
> +		 * definitely required (I guess it's also related to the "going
> +		 * backward" situation).
> +		 */
> +		if (state->rotation & DRM_MODE_REFLECT_Y) {
> +			y_off = tile_h_mask - y_off;
> +			pitch0 = SCALER_PITCH0_TILE_LINE_DIR;
> +		} else {
> +			pitch0 = 0;
> +		}
>  
>  		tiling = SCALER_CTL0_TILING_256B_OR_T;
> -		pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
> -			  VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
> -			  VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
> -			  VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
> +		pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
> +			   VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
> +			   VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
> +			   VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
>  		vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
>  		vc4_state->offsets[0] += subtile_y << 8;
>  		vc4_state->offsets[0] += utile_y << 4;
> @@ -611,6 +633,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
>  			}
>  		}
>  
> +		if (state->rotation & DRM_MODE_REFLECT_MASK) {
> +			DRM_DEBUG_KMS("X/Y reflection not supported on SAND formats\n");
> +			return -ENOTSUPP;
> +		}
> +
>  		switch (base_format_mod) {
>  		case DRM_FORMAT_MOD_BROADCOM_SAND64:
>  			tiling = SCALER_CTL0_TILING_64B;
> @@ -643,6 +670,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
>  	/* Control word */
>  	vc4_dlist_write(vc4_state,
>  			SCALER_CTL0_VALID |
> +			(state->rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |
> +			(state->rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |
>  			VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
>  			(format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
>  			(hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
> @@ -1123,6 +1152,10 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
>  	drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
>  
>  	drm_plane_create_alpha_property(plane);
> +	drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
> +					   DRM_MODE_ROTATE_0 |
> +					   DRM_MODE_REFLECT_X |
> +					   DRM_MODE_REFLECT_Y);
>  
>  	return plane;
>  }
> -- 
> 2.17.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
Boris Brezillon Dec. 3, 2018, 3:13 p.m. UTC | #2
On Mon, 3 Dec 2018 15:50:26 +0200
Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:

> On Mon, Dec 03, 2018 at 02:34:12PM +0100, Boris Brezillon wrote:
> > Add support for X/Y reflection when the plane is using linear or T-tiled
> > formats. X/Y reflection hasn't been tested on SAND formats, so we reject
> > them until proper testing/debugging has been done.  
> 
> BTW you could also expose 180 degress easily. See
> drm_rotation_simplify().

Thanks for the tip. I'll add it in v2.
Eric Anholt Dec. 3, 2018, 4:02 p.m. UTC | #3
Boris Brezillon <boris.brezillon@bootlin.com> writes:

> Add support for X/Y reflection when the plane is using linear or T-tiled
> formats. X/Y reflection hasn't been tested on SAND formats, so we reject
> them until proper testing/debugging has been done.

Reviewed-by: Eric Anholt <eric@anholt.net>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 75db62cbe468..bdcccf65cde0 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -492,7 +492,7 @@  static int vc4_plane_mode_set(struct drm_plane *plane,
 	bool mix_plane_alpha;
 	bool covers_screen;
 	u32 scl0, scl1, pitch0;
-	u32 tiling;
+	u32 tiling, src_y;
 	u32 hvs_format = format->hvs;
 	int ret, i;
 
@@ -520,6 +520,11 @@  static int vc4_plane_mode_set(struct drm_plane *plane,
 	h_subsample = drm_format_horz_chroma_subsampling(format->drm);
 	v_subsample = drm_format_vert_chroma_subsampling(format->drm);
 
+	/* We must point to the last line when Y reflection is enabled. */
+	src_y = vc4_state->src_y;
+	if (state->rotation & DRM_MODE_REFLECT_Y)
+		src_y += vc4_state->src_h[0] - 1;
+
 	switch (base_format_mod) {
 	case DRM_FORMAT_MOD_LINEAR:
 		tiling = SCALER_CTL0_TILING_LINEAR;
@@ -529,9 +534,10 @@  static int vc4_plane_mode_set(struct drm_plane *plane,
 		 * out.
 		 */
 		for (i = 0; i < num_planes; i++) {
-			vc4_state->offsets[i] += vc4_state->src_y /
+			vc4_state->offsets[i] += src_y /
 						 (i ? v_subsample : 1) *
 						 fb->pitches[i];
+
 			vc4_state->offsets[i] += vc4_state->src_x /
 						 (i ? h_subsample : 1) *
 						 fb->format->cpp[i];
@@ -557,22 +563,38 @@  static int vc4_plane_mode_set(struct drm_plane *plane,
 		u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
 		u32 tiles_l = vc4_state->src_x >> tile_w_shift;
 		u32 tiles_r = tiles_w - tiles_l;
-		u32 tiles_t = vc4_state->src_y >> tile_h_shift;
+		u32 tiles_t = src_y >> tile_h_shift;
 		/* Intra-tile offsets, which modify the base address (the
 		 * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
 		 * base address).
 		 */
-		u32 tile_y = (vc4_state->src_y >> 4) & 1;
-		u32 subtile_y = (vc4_state->src_y >> 2) & 3;
-		u32 utile_y = vc4_state->src_y & 3;
+		u32 tile_y = (src_y >> 4) & 1;
+		u32 subtile_y = (src_y >> 2) & 3;
+		u32 utile_y = src_y & 3;
 		u32 x_off = vc4_state->src_x & tile_w_mask;
-		u32 y_off = vc4_state->src_y & tile_h_mask;
+		u32 y_off = src_y & tile_h_mask;
+
+		/* When Y reflection is requested we must set the
+		 * SCALER_PITCH0_TILE_LINE_DIR flag to tell HVS that all lines
+		 * after the initial one should be fetched in descending order,
+		 * which makes sense since we start from the last line and go
+		 * backward.
+		 * Don't know why we need y_off = max_y_off - y_off, but it's
+		 * definitely required (I guess it's also related to the "going
+		 * backward" situation).
+		 */
+		if (state->rotation & DRM_MODE_REFLECT_Y) {
+			y_off = tile_h_mask - y_off;
+			pitch0 = SCALER_PITCH0_TILE_LINE_DIR;
+		} else {
+			pitch0 = 0;
+		}
 
 		tiling = SCALER_CTL0_TILING_256B_OR_T;
-		pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
-			  VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
-			  VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
-			  VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
+		pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
+			   VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
+			   VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
+			   VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
 		vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
 		vc4_state->offsets[0] += subtile_y << 8;
 		vc4_state->offsets[0] += utile_y << 4;
@@ -611,6 +633,11 @@  static int vc4_plane_mode_set(struct drm_plane *plane,
 			}
 		}
 
+		if (state->rotation & DRM_MODE_REFLECT_MASK) {
+			DRM_DEBUG_KMS("X/Y reflection not supported on SAND formats\n");
+			return -ENOTSUPP;
+		}
+
 		switch (base_format_mod) {
 		case DRM_FORMAT_MOD_BROADCOM_SAND64:
 			tiling = SCALER_CTL0_TILING_64B;
@@ -643,6 +670,8 @@  static int vc4_plane_mode_set(struct drm_plane *plane,
 	/* Control word */
 	vc4_dlist_write(vc4_state,
 			SCALER_CTL0_VALID |
+			(state->rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |
+			(state->rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |
 			VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
 			(format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
 			(hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
@@ -1123,6 +1152,10 @@  struct drm_plane *vc4_plane_init(struct drm_device *dev,
 	drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
 
 	drm_plane_create_alpha_property(plane);
+	drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
+					   DRM_MODE_ROTATE_0 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y);
 
 	return plane;
 }