The patches were generated from the RPi repo with the following command: git format-patch v6.6.34..rpi-6.1.y Some patches needed rebasing and, as usual, the applied and reverted, wireless drivers, Github workflows, READMEs and defconfigs patches were removed. Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
		
			
				
	
	
		
			344 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			344 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 7f6ca6fa24baa9e39baffd192ed9a5726a2551db Mon Sep 17 00:00:00 2001
 | 
						|
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
 | 
						|
Date: Thu, 11 Jan 2024 12:13:03 +0000
 | 
						|
Subject: [PATCH 0841/1085] drm: rp1: rp1-vec: Allow non-standard modes with
 | 
						|
 various crops
 | 
						|
 | 
						|
Tweak sync timings in the advertised modelines.
 | 
						|
 | 
						|
Accept other, custom modes, provided they fit within the active
 | 
						|
area of one of the existing hardware-supported TV modes.
 | 
						|
 | 
						|
Instead of always padding symmetrically, try to respect the user's
 | 
						|
[hv]sync_start values, allowing the image to be shifted around
 | 
						|
the screen (to fine-tune overscan correction).
 | 
						|
 | 
						|
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
 | 
						|
---
 | 
						|
 drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c    | 66 ++++++++++++---------
 | 
						|
 drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 74 ++++++++++++++++++------
 | 
						|
 2 files changed, 96 insertions(+), 44 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
 | 
						|
+++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
 | 
						|
@@ -19,7 +19,6 @@
 | 
						|
 #include <linux/list.h>
 | 
						|
 #include <linux/platform_device.h>
 | 
						|
 #include <linux/clk.h>
 | 
						|
-#include <linux/printk.h>
 | 
						|
 #include <linux/console.h>
 | 
						|
 #include <linux/debugfs.h>
 | 
						|
 #include <linux/uaccess.h>
 | 
						|
@@ -208,26 +207,26 @@ static void rp1vec_connector_destroy(str
 | 
						|
 static const struct drm_display_mode rp1vec_modes[4] = {
 | 
						|
 	{ /* Full size 525/60i with Rec.601 pixel rate */
 | 
						|
 		DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500,
 | 
						|
-			 720, 720 + 14, 720 + 14 + 64, 858, 0,
 | 
						|
-			 480, 480 + 7, 480 + 7 + 6, 525, 0,
 | 
						|
+			 720, 720 + 16, 720 + 16 + 64, 858, 0,
 | 
						|
+			 480, 480 + 6, 480 + 6 + 6, 525, 0,
 | 
						|
 			 DRM_MODE_FLAG_INTERLACE)
 | 
						|
 	},
 | 
						|
 	{ /* Cropped and horizontally squashed to be TV-safe */
 | 
						|
 		DRM_MODE("704x432i", DRM_MODE_TYPE_DRIVER, 15429,
 | 
						|
-			 704, 704 + 72, 704 + 72 + 72, 980, 0,
 | 
						|
-			 432, 432 + 31, 432 + 31 + 6, 525, 0,
 | 
						|
+			 704, 704 + 76, 704 + 76 + 72, 980, 0,
 | 
						|
+			 432, 432 + 30, 432 + 30 + 6, 525, 0,
 | 
						|
 			 DRM_MODE_FLAG_INTERLACE)
 | 
						|
 	},
 | 
						|
 	{ /* Full size 625/50i with Rec.601 pixel rate */
 | 
						|
 		DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
 | 
						|
 			 720, 720 + 20, 720 + 20 + 64, 864, 0,
 | 
						|
-			 576, 576 + 4, 576 + 4 + 6, 625, 0,
 | 
						|
+			 576, 576 + 5, 576 + 5 + 5, 625, 0,
 | 
						|
 			 DRM_MODE_FLAG_INTERLACE)
 | 
						|
 	},
 | 
						|
 	{ /* Cropped and squashed, for square(ish) pixels */
 | 
						|
 		DRM_MODE("704x512i", DRM_MODE_TYPE_DRIVER, 15429,
 | 
						|
 			 704, 704 + 80, 704 + 80 + 72, 987, 0,
 | 
						|
-			 512, 512 + 36, 512 + 36 + 6, 625, 0,
 | 
						|
+			 512, 512 + 37, 512 + 37 + 5, 625, 0,
 | 
						|
 			 DRM_MODE_FLAG_INTERLACE)
 | 
						|
 	}
 | 
						|
 };
 | 
						|
@@ -298,27 +297,42 @@ static enum drm_mode_status rp1vec_mode_
 | 
						|
 					      const struct drm_display_mode *mode)
 | 
						|
 {
 | 
						|
 	/*
 | 
						|
-	 * Check the mode roughly matches one of our standard modes
 | 
						|
-	 * (optionally half-height and progressive). Ignore H/V sync
 | 
						|
-	 * timings which for interlaced TV are approximate at best.
 | 
						|
+	 * Check the mode roughly matches something we can generate.
 | 
						|
+	 * The hardware driver is very prescriptive about pixel clocks,
 | 
						|
+	 * line and frame durations, but we'll tolerate rounding errors.
 | 
						|
+	 * Within each hardware mode, allow image size and position to vary
 | 
						|
+	 * (to fine-tune overscan correction or emulate retro devices).
 | 
						|
+	 * Don't check sync timings here: the HW driver will sanitize them.
 | 
						|
 	 */
 | 
						|
-	int i, prog;
 | 
						|
 
 | 
						|
-	prog = !(mode->flags & DRM_MODE_FLAG_INTERLACE);
 | 
						|
-
 | 
						|
-	for (i = 0; i < ARRAY_SIZE(rp1vec_modes); i++) {
 | 
						|
-		const struct drm_display_mode *ref = rp1vec_modes + i;
 | 
						|
+	int prog = !(mode->flags & DRM_MODE_FLAG_INTERLACE);
 | 
						|
+	int vtotal_full = mode->vtotal << prog;
 | 
						|
+	int vdisplay_full = mode->vdisplay << prog;
 | 
						|
+
 | 
						|
+	/* Reject very small frames */
 | 
						|
+	if (vtotal_full < 256 || mode->hdisplay < 256)
 | 
						|
+		return MODE_BAD;
 | 
						|
+
 | 
						|
+	/* Check lines, frame period (ms) and vertical size limit */
 | 
						|
+	if (vtotal_full >= 524 && vtotal_full <= 526 &&
 | 
						|
+	    mode->htotal * vtotal_full > 33 * mode->clock &&
 | 
						|
+	    mode->htotal * vtotal_full < 34 * mode->clock &&
 | 
						|
+	    vdisplay_full <= 480)
 | 
						|
+		goto vgood;
 | 
						|
+	if (vtotal_full >= 624 && vtotal_full <= 626 &&
 | 
						|
+	    mode->htotal * vtotal_full > 39 * mode->clock &&
 | 
						|
+	    mode->htotal * vtotal_full < 41 * mode->clock &&
 | 
						|
+	    vdisplay_full <= 576)
 | 
						|
+		goto vgood;
 | 
						|
+	return MODE_BAD;
 | 
						|
 
 | 
						|
-		if (mode->hdisplay == ref->hdisplay           &&
 | 
						|
-		    mode->vdisplay == (ref->vdisplay >> prog) &&
 | 
						|
-		    mode->clock + 2 >= ref->clock             &&
 | 
						|
-		    mode->clock <= ref->clock + 2             &&
 | 
						|
-		    mode->htotal + 2 >= ref->htotal           &&
 | 
						|
-		    mode->htotal <= ref->htotal + 2           &&
 | 
						|
-		    mode->vtotal + 2 >= (ref->vtotal >> prog) &&
 | 
						|
-		    mode->vtotal <= (ref->vtotal >> prog) + 2)
 | 
						|
-			return MODE_OK;
 | 
						|
-	}
 | 
						|
+vgood:
 | 
						|
+	/* Check pixel rate (kHz) and horizontal size limit */
 | 
						|
+	if (mode->clock == 13500 && mode->hdisplay <= 720)
 | 
						|
+		return MODE_OK;
 | 
						|
+	if (mode->clock >= 15428 && mode->clock <= 15429 &&
 | 
						|
+	    mode->hdisplay <= 800)
 | 
						|
+		return MODE_OK;
 | 
						|
 	return MODE_BAD;
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -440,7 +454,7 @@ static int rp1vec_platform_probe(struct
 | 
						|
 	ret = drmm_mode_config_init(drm);
 | 
						|
 	if (ret)
 | 
						|
 		goto err_free_drm;
 | 
						|
-	drm->mode_config.max_width  = 768;
 | 
						|
+	drm->mode_config.max_width  = 800;
 | 
						|
 	drm->mode_config.max_height = 576;
 | 
						|
 	drm->mode_config.preferred_depth = 32;
 | 
						|
 	drm->mode_config.prefer_shadow	 = 0;
 | 
						|
--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
 | 
						|
+++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
 | 
						|
@@ -11,7 +11,6 @@
 | 
						|
 #include <linux/delay.h>
 | 
						|
 #include <linux/interrupt.h>
 | 
						|
 #include <linux/platform_device.h>
 | 
						|
-#include <linux/printk.h>
 | 
						|
 #include <drm/drm_fourcc.h>
 | 
						|
 #include <drm/drm_print.h>
 | 
						|
 #include <drm/drm_vblank.h>
 | 
						|
@@ -82,13 +81,13 @@ static const struct rp1vec_ipixfmt my_fo
 | 
						|
 /*
 | 
						|
  * Hardware mode descriptions (@ 108 MHz clock rate).
 | 
						|
  * These rely largely on "canned" register settings.
 | 
						|
- * TODO: Port the generating software from FP to integer,
 | 
						|
- * or better factorize the differences between modes.
 | 
						|
  */
 | 
						|
 
 | 
						|
 struct rp1vec_hwmode {
 | 
						|
-	u16  total_cols;	/* active columns, plus padding for filter context  */
 | 
						|
+	u16  total_cols;	/* max active columns incl. padding and windowing   */
 | 
						|
 	u16  rows_per_field;	/* active lines per field (including partial ones)  */
 | 
						|
+	u16  ref_hfp;		/* nominal (hsync_start - hdisplay) when max width  */
 | 
						|
+	u16  ref_vfp;		/* nominal (vsync_start - vdisplay) when max height */
 | 
						|
 	bool interlaced;	/* set for interlaced				    */
 | 
						|
 	bool first_field_odd;	/* set for interlaced and 30fps			    */
 | 
						|
 	u32  yuv_scaling;	/* three 10-bit fields {Y, U, V} in 2.8 format	    */
 | 
						|
@@ -103,6 +102,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			{
 | 
						|
 				.total_cols = 724,
 | 
						|
 				.rows_per_field = 240,
 | 
						|
+				.ref_hfp = 12,
 | 
						|
+				.ref_vfp = 2,
 | 
						|
 				.interlaced = false,
 | 
						|
 				.first_field_odd = false,
 | 
						|
 				.yuv_scaling = 0x1071d0cf,
 | 
						|
@@ -118,6 +119,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			}, {
 | 
						|
 				.total_cols = 815,
 | 
						|
 				.rows_per_field = 240,
 | 
						|
+				.ref_hfp = 16,
 | 
						|
+				.ref_vfp = 2,
 | 
						|
 				.interlaced = false,
 | 
						|
 				.first_field_odd = false,
 | 
						|
 				.yuv_scaling = 0x1c131962,
 | 
						|
@@ -135,6 +138,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			{
 | 
						|
 				.total_cols = 724,
 | 
						|
 				.rows_per_field = 243,
 | 
						|
+				.ref_hfp = 12,
 | 
						|
+				.ref_vfp = 3,
 | 
						|
 				.interlaced = true,
 | 
						|
 				.first_field_odd = true,
 | 
						|
 				.yuv_scaling = 0x1071d0cf,
 | 
						|
@@ -150,6 +155,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			}, {
 | 
						|
 				.total_cols = 815,
 | 
						|
 				.rows_per_field = 243,
 | 
						|
+				.ref_hfp = 16,
 | 
						|
+				.ref_vfp = 3,
 | 
						|
 				.interlaced = true,
 | 
						|
 				.first_field_odd = true,
 | 
						|
 				.yuv_scaling = 0x1c131962,
 | 
						|
@@ -170,6 +177,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			{
 | 
						|
 				.total_cols = 724,
 | 
						|
 				.rows_per_field = 288,
 | 
						|
+				.ref_hfp = 16,
 | 
						|
+				.ref_vfp = 2,
 | 
						|
 				.interlaced = false,
 | 
						|
 				.first_field_odd = false,
 | 
						|
 				.yuv_scaling = 0x11c1f8e0,
 | 
						|
@@ -185,6 +194,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			}, {
 | 
						|
 				.total_cols = 804,
 | 
						|
 				.rows_per_field = 288,
 | 
						|
+				.ref_hfp = 24,
 | 
						|
+				.ref_vfp = 2,
 | 
						|
 				.interlaced = false,
 | 
						|
 				.first_field_odd = false,
 | 
						|
 				.yuv_scaling = 0x1e635d7f,
 | 
						|
@@ -202,6 +213,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			{
 | 
						|
 				.total_cols = 724,
 | 
						|
 				.rows_per_field = 288,
 | 
						|
+				.ref_hfp = 16,
 | 
						|
+				.ref_vfp = 5,
 | 
						|
 				.interlaced = true,
 | 
						|
 				.first_field_odd = false,
 | 
						|
 				.yuv_scaling = 0x11c1f8e0,
 | 
						|
@@ -217,6 +230,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			}, {
 | 
						|
 				.total_cols = 804,
 | 
						|
 				.rows_per_field = 288,
 | 
						|
+				.ref_hfp = 24,
 | 
						|
+				.ref_vfp = 5,
 | 
						|
 				.interlaced = true,
 | 
						|
 				.first_field_odd = false,
 | 
						|
 				.yuv_scaling = 0x1e635d7f,
 | 
						|
@@ -237,6 +252,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			{
 | 
						|
 				.total_cols = 724,
 | 
						|
 				.rows_per_field = 240,
 | 
						|
+				.ref_hfp = 12,
 | 
						|
+				.ref_vfp = 2,
 | 
						|
 				.interlaced = false,
 | 
						|
 				.first_field_odd = false,
 | 
						|
 				.yuv_scaling = 0x11c1f8e0,
 | 
						|
@@ -252,6 +269,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			}, {
 | 
						|
 				.total_cols = 815,
 | 
						|
 				.rows_per_field = 240,
 | 
						|
+				.ref_hfp = 16,
 | 
						|
+				.ref_vfp = 2,
 | 
						|
 				.interlaced = false,
 | 
						|
 				.first_field_odd = false,
 | 
						|
 				.yuv_scaling = 0x1e635d7f,
 | 
						|
@@ -269,6 +288,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			{
 | 
						|
 				.total_cols = 724,
 | 
						|
 				.rows_per_field = 243,
 | 
						|
+				.ref_hfp = 12,
 | 
						|
+				.ref_vfp = 3,
 | 
						|
 				.interlaced = true,
 | 
						|
 				.first_field_odd = true,
 | 
						|
 				.yuv_scaling = 0x11c1f8e0,
 | 
						|
@@ -284,6 +305,8 @@ static const struct rp1vec_hwmode rp1vec
 | 
						|
 			}, {
 | 
						|
 				.total_cols = 815,
 | 
						|
 				.rows_per_field = 243,
 | 
						|
+				.ref_hfp = 16,
 | 
						|
+				.ref_vfp = 3,
 | 
						|
 				.interlaced = true,
 | 
						|
 				.first_field_odd = true,
 | 
						|
 				.yuv_scaling = 0x1e635d7f,
 | 
						|
@@ -308,11 +331,11 @@ void rp1vec_hw_setup(struct rp1_vec *vec
 | 
						|
 {
 | 
						|
 	unsigned int i, mode_family, mode_ilaced, mode_narrow;
 | 
						|
 	const struct rp1vec_hwmode *hwm;
 | 
						|
-	unsigned int w, h;
 | 
						|
+	int w, h, hpad, vpad;
 | 
						|
 
 | 
						|
 	/* Pick the appropriate "base" mode, which we may modify */
 | 
						|
 	mode_ilaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
 | 
						|
-	if (mode->vtotal > 263 * (1 + mode_ilaced))
 | 
						|
+	if (mode->vtotal >= 272 * (1 + mode_ilaced))
 | 
						|
 		mode_family = 1;
 | 
						|
 	else
 | 
						|
 		mode_family = (tvstd == RP1VEC_TVSTD_PAL_M || tvstd == RP1VEC_TVSTD_PAL60) ? 2 : 0;
 | 
						|
@@ -326,13 +349,28 @@ void rp1vec_hw_setup(struct rp1_vec *vec
 | 
						|
 		tvstd, rp1vec_tvstd_names[tvstd]);
 | 
						|
 
 | 
						|
 	w = mode->hdisplay;
 | 
						|
-	h = mode->vdisplay;
 | 
						|
-	if (mode_ilaced)
 | 
						|
-		h >>= 1;
 | 
						|
+	h = mode->vdisplay >> mode_ilaced;
 | 
						|
 	if (w > hwm->total_cols)
 | 
						|
 		w = hwm->total_cols;
 | 
						|
 	if (h > hwm->rows_per_field)
 | 
						|
-		w = hwm->rows_per_field;
 | 
						|
+		h = hwm->rows_per_field;
 | 
						|
+
 | 
						|
+	/*
 | 
						|
+	 * Add padding so a framebuffer with the given dimensions and
 | 
						|
+	 * [hv]sync_start can be displayed in the chosen hardware mode.
 | 
						|
+	 *
 | 
						|
+	 *          |<----- mode->hsync_start ----->|
 | 
						|
+	 *          |<------ w ------>|             |
 | 
						|
+	 *          |                 |         >|--|<  ref_hfp
 | 
						|
+	 *                            |<- hpad ->|
 | 
						|
+	 * |<------------ total_cols ----------->|
 | 
						|
+	 *  ________FRAMEBUFFERCONTENTS__________
 | 
						|
+	 * '                                     `--\____/-<\/\/\>-'
 | 
						|
+	 */
 | 
						|
+	hpad = max(0, mode->hsync_start - hwm->ref_hfp - w);
 | 
						|
+	hpad = min(hpad, hwm->total_cols - w);
 | 
						|
+	vpad = max(0, ((mode->vsync_start - hwm->ref_vfp) >> mode_ilaced) - h);
 | 
						|
+	vpad = min(vpad, hwm->rows_per_field - h);
 | 
						|
 
 | 
						|
 	/* Configure the hardware */
 | 
						|
 	VEC_WRITE(VEC_APB_TIMEOUT, 0x38);
 | 
						|
@@ -347,18 +385,18 @@ void rp1vec_hw_setup(struct rp1_vec *vec
 | 
						|
 		  BITS(VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1, h - 1));
 | 
						|
 	VEC_WRITE(VEC_YUV_SCALING, hwm->yuv_scaling);
 | 
						|
 	VEC_WRITE(VEC_BACK_PORCH,
 | 
						|
-		  BITS(VEC_BACK_PORCH_HBP_MINUS1, (hwm->total_cols - w - 1) >> 1) |
 | 
						|
-		  BITS(VEC_BACK_PORCH_VBP_MINUS1, (hwm->rows_per_field - h - 1) >> 1));
 | 
						|
+		  BITS(VEC_BACK_PORCH_HBP_MINUS1, hwm->total_cols - w - hpad - 1) |
 | 
						|
+		  BITS(VEC_BACK_PORCH_VBP_MINUS1, hwm->rows_per_field - h - vpad - 1));
 | 
						|
 	VEC_WRITE(VEC_FRONT_PORCH,
 | 
						|
-		  BITS(VEC_FRONT_PORCH_HFP_MINUS1, (hwm->total_cols - w - 2) >> 1) |
 | 
						|
-		  BITS(VEC_FRONT_PORCH_VFP_MINUS1, (hwm->rows_per_field - h - 2) >> 1));
 | 
						|
+		  BITS(VEC_FRONT_PORCH_HFP_MINUS1, hpad - 1) |
 | 
						|
+		  BITS(VEC_FRONT_PORCH_VFP_MINUS1, vpad - 1));
 | 
						|
 	VEC_WRITE(VEC_MODE,
 | 
						|
 		  BITS(VEC_MODE_HIGH_WATER, 0xE0)			  |
 | 
						|
 		  BITS(VEC_MODE_ALIGN16, !((w | mode->hdisplay) & 15))	  |
 | 
						|
-		  BITS(VEC_MODE_VFP_EN, (hwm->rows_per_field > h + 1))	  |
 | 
						|
-		  BITS(VEC_MODE_VBP_EN, (hwm->rows_per_field > h))	  |
 | 
						|
-		  BITS(VEC_MODE_HFP_EN, (hwm->total_cols > w + 1))          |
 | 
						|
-		  BITS(VEC_MODE_HBP_EN, (hwm->total_cols > w))		  |
 | 
						|
+		  BITS(VEC_MODE_VFP_EN, (vpad > 0))			  |
 | 
						|
+		  BITS(VEC_MODE_VBP_EN, (hwm->rows_per_field > h + vpad)) |
 | 
						|
+		  BITS(VEC_MODE_HFP_EN, (hpad > 0))			  |
 | 
						|
+		  BITS(VEC_MODE_HBP_EN, (hwm->total_cols > w + hpad))	  |
 | 
						|
 		  BITS(VEC_MODE_FIELDS_PER_FRAME_MINUS1, hwm->interlaced) |
 | 
						|
 		  BITS(VEC_MODE_FIRST_FIELD_ODD, hwm->first_field_odd));
 | 
						|
 	for (i = 0; i < ARRAY_SIZE(hwm->back_end_regs); ++i) {
 |