The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH] drm/fb-helper: add fbdev screen expended mode display support
@ 2025-11-07  9:26 oushixiong1025
  2025-11-07 10:06 ` Thomas Zimmermann
  2025-11-10 12:54 ` kernel test robot
  0 siblings, 2 replies; 5+ messages in thread
From: oushixiong1025 @ 2025-11-07  9:26 UTC (permalink / raw)
  To: Maarten Lankhorst
  Cc: Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	dri-devel, linux-kernel, Shixiong Ou, Tiger Liu

From: Shixiong Ou <oushixiong@kylinos.cn>

Add fbdev screen extended mode display support

Signed-off-by: Tiger Liu <liuyihu@kylinos.cn>
Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
---
 drivers/gpu/drm/drm_fb_helper.c | 143 ++++++++++++++++++++++++++++++--
 1 file changed, 135 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 53e9dc0543de..a6ec03bf3aef 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -78,6 +78,17 @@ MODULE_PARM_DESC(drm_leak_fbdev_smem,
 		 "Allow unsafe leaking fbdev physical smem address [default=false]");
 #endif
 
+#define SCREEN_CLONE			0x0
+#define SCREEN_EXPAND_HORIZONTAL	0x1
+#define SCREEN_EXPAND_VERTICAL		0x2
+
+static bool drm_fbdev_screen_expand_mode_enabled;
+static int drm_fbdev_screen_mode = SCREEN_CLONE;
+module_param_named(screen_mode, drm_fbdev_screen_mode, int, 0444);
+MODULE_PARM_DESC(screen_mode,
+		 "Screen display of the fbdev. [0 = clone(default), 1 = expand horizontally,"
+		 "2 = expand vertically]");
+
 static LIST_HEAD(kernel_fb_helper_list);
 static DEFINE_MUTEX(kernel_fb_helper_lock);
 
@@ -1345,15 +1356,35 @@ int drm_fb_helper_set_par(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_set_par);
 
-static void pan_set(struct drm_fb_helper *fb_helper, int dx, int dy)
+static void pan_set_locked(struct drm_client_dev *client,
+			   int dx, int dy)
 {
 	struct drm_mode_set *mode_set;
+	int screen_x_offset = dx;
+	int screen_y_offset = dy;
 
-	mutex_lock(&fb_helper->client.modeset_mutex);
-	drm_client_for_each_modeset(mode_set, &fb_helper->client) {
-		mode_set->x += dx;
-		mode_set->y += dy;
+	drm_client_for_each_modeset(mode_set, client) {
+		if (drm_fbdev_screen_expand_mode_enabled) {
+			if (drm_fbdev_screen_mode == SCREEN_EXPAND_HORIZONTAL) {
+				mode_set->x += screen_x_offset;
+				mode_set->y += screen_y_offset;
+				screen_x_offset += mode_set->mode->hdisplay;
+			} else if (drm_fbdev_screen_mode == SCREEN_EXPAND_VERTICAL) {
+				mode_set->x += screen_x_offset;
+				mode_set->y += screen_y_offset;
+				screen_y_offset += mode_set->mode->vdisplay;
+			}
+		} else {
+			mode_set->x = screen_x_offset;
+			mode_set->y = screen_y_offset;
+		}
 	}
+}
+
+static void pan_set(struct drm_fb_helper *fb_helper, int dx, int dy)
+{
+	mutex_lock(&fb_helper->client.modeset_mutex);
+	pan_set_locked(&fb_helper->client, dx, dy);
 	mutex_unlock(&fb_helper->client.modeset_mutex);
 }
 
@@ -1387,10 +1418,8 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
 
 	mutex_lock(&client->modeset_mutex);
 	drm_modeset_lock_all(fb_helper->dev);
+	pan_set_locked(client, var->xoffset, var->yoffset);
 	drm_client_for_each_modeset(modeset, client) {
-		modeset->x = var->xoffset;
-		modeset->y = var->yoffset;
-
 		if (modeset->num_connectors) {
 			ret = drm_mode_set_config_internal(modeset);
 			if (!ret) {
@@ -1461,6 +1490,94 @@ static uint32_t drm_fb_helper_find_format(struct drm_fb_helper *fb_helper, const
 	return DRM_FORMAT_INVALID;
 }
 
+/*
+ * Check if the device supports extended mode
+ *
+ * return true if the device supports extended mode,
+ * otherwise return false.
+ */
+static bool drm_fb_helper_validate_extended_mode(struct drm_fb_helper *fb_helper,
+						 struct drm_fb_helper_surface_size *sizes)
+{
+	struct drm_client_dev *client = &fb_helper->client;
+	struct drm_device *dev = fb_helper->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_mode_set *mode_set;
+	u32 crtc_count;
+
+	drm_client_for_each_modeset(mode_set, client) {
+		crtc_count++;
+
+		for (int j = 0; j < mode_set->num_connectors; j++) {
+			struct drm_connector *connector = mode_set->connectors[j];
+
+			if (connector->has_tile) {
+				drm_dbg_kms(client->dev,
+					    "Don't support extended with tile mode connector yet\n");
+				return false;
+			}
+		}
+	}
+
+	if (crtc_count < 2) {
+		drm_dbg_kms(client->dev,
+			    "Only support extended mode when device have mult-crtcs\n");
+		return false;
+	}
+
+	if (drm_fbdev_screen_mode == SCREEN_EXPAND_HORIZONTAL) {
+		u32 x = 0;
+
+		drm_client_for_each_modeset(mode_set, client) {
+			struct drm_display_mode *desired_mode;
+
+			desired_mode = mode_set->mode;
+			x = mode_set->x;
+			sizes->fb_width = sizes->surface_width  += desired_mode->hdisplay;
+			sizes->surface_height =
+				min_t(u32, desired_mode->vdisplay + mode_set->y,
+				      sizes->surface_height);
+			sizes->fb_height = min_t(u32, desired_mode->vdisplay + mode_set->y,
+						 sizes->fb_height);
+		}
+		sizes->fb_width = sizes->surface_width += x;
+
+		if (sizes->fb_width > config->max_width) {
+			drm_dbg_kms(client->dev,
+				    "screen_buffer total width %d > config width %d\n",
+				    sizes->fb_width, config->max_width);
+			return false;
+		}
+	} else if (drm_fbdev_screen_mode == SCREEN_EXPAND_VERTICAL) {
+		u32 y = 0;
+
+		drm_client_for_each_modeset(mode_set, client) {
+			struct drm_display_mode *desired_mode;
+
+			desired_mode = mode_set->mode;
+			y = mode_set->y;
+			sizes->fb_height = sizes->surface_height += desired_mode->vdisplay;
+			sizes->surface_width =
+				min_t(u32, desired_mode->hdisplay + mode_set->x,
+				      sizes->surface_width);
+			sizes->fb_width = min_t(u32, desired_mode->hdisplay + mode_set->x,
+						sizes->fb_width);
+		}
+		sizes->fb_height = sizes->surface_height += y;
+
+		if (sizes->fb_height > config->max_height) {
+			drm_dbg_kms(client->dev,
+				    "screen_buffer_total_height %d > config height %d\n",
+				    sizes->fb_height, config->max_height);
+			return false;
+		}
+	} else {
+		return false;
+	}
+
+	return true;
+}
+
 static int __drm_fb_helper_find_sizes(struct drm_fb_helper *fb_helper,
 				      struct drm_fb_helper_surface_size *sizes)
 {
@@ -1527,6 +1644,16 @@ static int __drm_fb_helper_find_sizes(struct drm_fb_helper *fb_helper,
 
 	/* first up get a count of crtcs now in use and new min/maxes width/heights */
 	crtc_count = 0;
+
+	/* Check if we support extended mode. If we do, we will adjust the sizes accordingly. */
+	if (drm_fbdev_screen_mode &&
+		drm_fb_helper_validate_extended_mode(fb_helper, sizes)) {
+		drm_fbdev_screen_expand_mode_enabled = true;
+		drm_dbg_kms(dev, "Extended mode: horizontal expansion, width: %d, height: %d\n",
+			    sizes->surface_width, sizes->surface_height);
+		return 0;
+	}
+
 	drm_client_for_each_modeset(mode_set, client) {
 		struct drm_display_mode *desired_mode;
 		int x, y, j;
-- 
2.25.1


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

* Re: [PATCH] drm/fb-helper: add fbdev screen expended mode display support
  2025-11-07  9:26 [PATCH] drm/fb-helper: add fbdev screen expended mode display support oushixiong1025
@ 2025-11-07 10:06 ` Thomas Zimmermann
  2025-11-10  5:54   ` Shixiong Ou
  2025-11-10 12:54 ` kernel test robot
  1 sibling, 1 reply; 5+ messages in thread
From: Thomas Zimmermann @ 2025-11-07 10:06 UTC (permalink / raw)
  To: oushixiong1025, Maarten Lankhorst
  Cc: Maxime Ripard, David Airlie, Simona Vetter, dri-devel,
	linux-kernel, Shixiong Ou, Tiger Liu



Am 07.11.25 um 10:26 schrieb oushixiong1025@163.com:
> From: Shixiong Ou <oushixiong@kylinos.cn>
>
> Add fbdev screen extended mode display support

What? What is this about?

>
> Signed-off-by: Tiger Liu <liuyihu@kylinos.cn>
> Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
> ---
>   drivers/gpu/drm/drm_fb_helper.c | 143 ++++++++++++++++++++++++++++++--
>   1 file changed, 135 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 53e9dc0543de..a6ec03bf3aef 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -78,6 +78,17 @@ MODULE_PARM_DESC(drm_leak_fbdev_smem,
>   		 "Allow unsafe leaking fbdev physical smem address [default=false]");
>   #endif
>   
> +#define SCREEN_CLONE			0x0
> +#define SCREEN_EXPAND_HORIZONTAL	0x1
> +#define SCREEN_EXPAND_VERTICAL		0x2
> +
> +static bool drm_fbdev_screen_expand_mode_enabled;
> +static int drm_fbdev_screen_mode = SCREEN_CLONE;
> +module_param_named(screen_mode, drm_fbdev_screen_mode, int, 0444);
> +MODULE_PARM_DESC(screen_mode,
> +		 "Screen display of the fbdev. [0 = clone(default), 1 = expand horizontally,"
> +		 "2 = expand vertically]");
> +
>   static LIST_HEAD(kernel_fb_helper_list);
>   static DEFINE_MUTEX(kernel_fb_helper_lock);
>   
> @@ -1345,15 +1356,35 @@ int drm_fb_helper_set_par(struct fb_info *info)
>   }
>   EXPORT_SYMBOL(drm_fb_helper_set_par);
>   
> -static void pan_set(struct drm_fb_helper *fb_helper, int dx, int dy)
> +static void pan_set_locked(struct drm_client_dev *client,
> +			   int dx, int dy)
>   {
>   	struct drm_mode_set *mode_set;
> +	int screen_x_offset = dx;
> +	int screen_y_offset = dy;
>   
> -	mutex_lock(&fb_helper->client.modeset_mutex);
> -	drm_client_for_each_modeset(mode_set, &fb_helper->client) {
> -		mode_set->x += dx;
> -		mode_set->y += dy;
> +	drm_client_for_each_modeset(mode_set, client) {
> +		if (drm_fbdev_screen_expand_mode_enabled) {
> +			if (drm_fbdev_screen_mode == SCREEN_EXPAND_HORIZONTAL) {
> +				mode_set->x += screen_x_offset;
> +				mode_set->y += screen_y_offset;
> +				screen_x_offset += mode_set->mode->hdisplay;
> +			} else if (drm_fbdev_screen_mode == SCREEN_EXPAND_VERTICAL) {
> +				mode_set->x += screen_x_offset;
> +				mode_set->y += screen_y_offset;
> +				screen_y_offset += mode_set->mode->vdisplay;
> +			}
> +		} else {
> +			mode_set->x = screen_x_offset;
> +			mode_set->y = screen_y_offset;
> +		}
>   	}
> +}
> +
> +static void pan_set(struct drm_fb_helper *fb_helper, int dx, int dy)
> +{
> +	mutex_lock(&fb_helper->client.modeset_mutex);
> +	pan_set_locked(&fb_helper->client, dx, dy);
>   	mutex_unlock(&fb_helper->client.modeset_mutex);
>   }
>   
> @@ -1387,10 +1418,8 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
>   
>   	mutex_lock(&client->modeset_mutex);
>   	drm_modeset_lock_all(fb_helper->dev);
> +	pan_set_locked(client, var->xoffset, var->yoffset);
>   	drm_client_for_each_modeset(modeset, client) {
> -		modeset->x = var->xoffset;
> -		modeset->y = var->yoffset;
> -
>   		if (modeset->num_connectors) {
>   			ret = drm_mode_set_config_internal(modeset);
>   			if (!ret) {
> @@ -1461,6 +1490,94 @@ static uint32_t drm_fb_helper_find_format(struct drm_fb_helper *fb_helper, const
>   	return DRM_FORMAT_INVALID;
>   }
>   
> +/*
> + * Check if the device supports extended mode
> + *
> + * return true if the device supports extended mode,
> + * otherwise return false.
> + */
> +static bool drm_fb_helper_validate_extended_mode(struct drm_fb_helper *fb_helper,
> +						 struct drm_fb_helper_surface_size *sizes)
> +{
> +	struct drm_client_dev *client = &fb_helper->client;
> +	struct drm_device *dev = fb_helper->dev;
> +	struct drm_mode_config *config = &dev->mode_config;
> +	struct drm_mode_set *mode_set;
> +	u32 crtc_count;
> +
> +	drm_client_for_each_modeset(mode_set, client) {
> +		crtc_count++;
> +
> +		for (int j = 0; j < mode_set->num_connectors; j++) {
> +			struct drm_connector *connector = mode_set->connectors[j];
> +
> +			if (connector->has_tile) {
> +				drm_dbg_kms(client->dev,
> +					    "Don't support extended with tile mode connector yet\n");
> +				return false;
> +			}
> +		}
> +	}
> +
> +	if (crtc_count < 2) {
> +		drm_dbg_kms(client->dev,
> +			    "Only support extended mode when device have mult-crtcs\n");
> +		return false;
> +	}
> +
> +	if (drm_fbdev_screen_mode == SCREEN_EXPAND_HORIZONTAL) {
> +		u32 x = 0;
> +
> +		drm_client_for_each_modeset(mode_set, client) {
> +			struct drm_display_mode *desired_mode;
> +
> +			desired_mode = mode_set->mode;
> +			x = mode_set->x;
> +			sizes->fb_width = sizes->surface_width  += desired_mode->hdisplay;
> +			sizes->surface_height =
> +				min_t(u32, desired_mode->vdisplay + mode_set->y,
> +				      sizes->surface_height);
> +			sizes->fb_height = min_t(u32, desired_mode->vdisplay + mode_set->y,
> +						 sizes->fb_height);
> +		}
> +		sizes->fb_width = sizes->surface_width += x;
> +
> +		if (sizes->fb_width > config->max_width) {
> +			drm_dbg_kms(client->dev,
> +				    "screen_buffer total width %d > config width %d\n",
> +				    sizes->fb_width, config->max_width);
> +			return false;
> +		}
> +	} else if (drm_fbdev_screen_mode == SCREEN_EXPAND_VERTICAL) {
> +		u32 y = 0;
> +
> +		drm_client_for_each_modeset(mode_set, client) {
> +			struct drm_display_mode *desired_mode;
> +
> +			desired_mode = mode_set->mode;
> +			y = mode_set->y;
> +			sizes->fb_height = sizes->surface_height += desired_mode->vdisplay;
> +			sizes->surface_width =
> +				min_t(u32, desired_mode->hdisplay + mode_set->x,
> +				      sizes->surface_width);
> +			sizes->fb_width = min_t(u32, desired_mode->hdisplay + mode_set->x,
> +						sizes->fb_width);
> +		}
> +		sizes->fb_height = sizes->surface_height += y;
> +
> +		if (sizes->fb_height > config->max_height) {
> +			drm_dbg_kms(client->dev,
> +				    "screen_buffer_total_height %d > config height %d\n",
> +				    sizes->fb_height, config->max_height);
> +			return false;
> +		}
> +	} else {
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
>   static int __drm_fb_helper_find_sizes(struct drm_fb_helper *fb_helper,
>   				      struct drm_fb_helper_surface_size *sizes)
>   {
> @@ -1527,6 +1644,16 @@ static int __drm_fb_helper_find_sizes(struct drm_fb_helper *fb_helper,
>   
>   	/* first up get a count of crtcs now in use and new min/maxes width/heights */
>   	crtc_count = 0;
> +
> +	/* Check if we support extended mode. If we do, we will adjust the sizes accordingly. */
> +	if (drm_fbdev_screen_mode &&
> +		drm_fb_helper_validate_extended_mode(fb_helper, sizes)) {
> +		drm_fbdev_screen_expand_mode_enabled = true;
> +		drm_dbg_kms(dev, "Extended mode: horizontal expansion, width: %d, height: %d\n",
> +			    sizes->surface_width, sizes->surface_height);
> +		return 0;
> +	}
> +
>   	drm_client_for_each_modeset(mode_set, client) {
>   		struct drm_display_mode *desired_mode;
>   		int x, y, j;

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)



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

* Re: [PATCH] drm/fb-helper: add fbdev screen expended mode display support
  2025-11-07 10:06 ` Thomas Zimmermann
@ 2025-11-10  5:54   ` Shixiong Ou
  2025-11-10  7:17     ` Thomas Zimmermann
  0 siblings, 1 reply; 5+ messages in thread
From: Shixiong Ou @ 2025-11-10  5:54 UTC (permalink / raw)
  To: Thomas Zimmermann, oushixiong1025, Maarten Lankhorst
  Cc: Maxime Ripard, David Airlie, Simona Vetter, dri-devel,
	linux-kernel, Tiger Liu


在 2025/11/7 18:06, Thomas Zimmermann 写道:
>
>
> Am 07.11.25 um 10:26 schrieb oushixiong1025@163.com:
>> From: Shixiong Ou <oushixiong@kylinos.cn>
>>
>> Add fbdev screen extended mode display support
>
> What? What is this about?
>
If an fbdev device has multiple screens, they are mirrored by default.
This patch aims to enable extended display for the tty, allowing 
horizontal or
vertical expansion to achieve a screen splicing effect in the tty terminal.

Best regards,
Shixiong

>>
>> Signed-off-by: Tiger Liu <liuyihu@kylinos.cn>
>> Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
>> ---
>>   drivers/gpu/drm/drm_fb_helper.c | 143 ++++++++++++++++++++++++++++++--
>>   1 file changed, 135 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c 
>> b/drivers/gpu/drm/drm_fb_helper.c
>> index 53e9dc0543de..a6ec03bf3aef 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -78,6 +78,17 @@ MODULE_PARM_DESC(drm_leak_fbdev_smem,
>>            "Allow unsafe leaking fbdev physical smem address 
>> [default=false]");
>>   #endif
>>   +#define SCREEN_CLONE            0x0
>> +#define SCREEN_EXPAND_HORIZONTAL    0x1
>> +#define SCREEN_EXPAND_VERTICAL        0x2
>> +
>> +static bool drm_fbdev_screen_expand_mode_enabled;
>> +static int drm_fbdev_screen_mode = SCREEN_CLONE;
>> +module_param_named(screen_mode, drm_fbdev_screen_mode, int, 0444);
>> +MODULE_PARM_DESC(screen_mode,
>> +         "Screen display of the fbdev. [0 = clone(default), 1 = 
>> expand horizontally,"
>> +         "2 = expand vertically]");
>> +
>>   static LIST_HEAD(kernel_fb_helper_list);
>>   static DEFINE_MUTEX(kernel_fb_helper_lock);
>>   @@ -1345,15 +1356,35 @@ int drm_fb_helper_set_par(struct fb_info 
>> *info)
>>   }
>>   EXPORT_SYMBOL(drm_fb_helper_set_par);
>>   -static void pan_set(struct drm_fb_helper *fb_helper, int dx, int dy)
>> +static void pan_set_locked(struct drm_client_dev *client,
>> +               int dx, int dy)
>>   {
>>       struct drm_mode_set *mode_set;
>> +    int screen_x_offset = dx;
>> +    int screen_y_offset = dy;
>>   -    mutex_lock(&fb_helper->client.modeset_mutex);
>> -    drm_client_for_each_modeset(mode_set, &fb_helper->client) {
>> -        mode_set->x += dx;
>> -        mode_set->y += dy;
>> +    drm_client_for_each_modeset(mode_set, client) {
>> +        if (drm_fbdev_screen_expand_mode_enabled) {
>> +            if (drm_fbdev_screen_mode == SCREEN_EXPAND_HORIZONTAL) {
>> +                mode_set->x += screen_x_offset;
>> +                mode_set->y += screen_y_offset;
>> +                screen_x_offset += mode_set->mode->hdisplay;
>> +            } else if (drm_fbdev_screen_mode == 
>> SCREEN_EXPAND_VERTICAL) {
>> +                mode_set->x += screen_x_offset;
>> +                mode_set->y += screen_y_offset;
>> +                screen_y_offset += mode_set->mode->vdisplay;
>> +            }
>> +        } else {
>> +            mode_set->x = screen_x_offset;
>> +            mode_set->y = screen_y_offset;
>> +        }
>>       }
>> +}
>> +
>> +static void pan_set(struct drm_fb_helper *fb_helper, int dx, int dy)
>> +{
>> +    mutex_lock(&fb_helper->client.modeset_mutex);
>> +    pan_set_locked(&fb_helper->client, dx, dy);
>>       mutex_unlock(&fb_helper->client.modeset_mutex);
>>   }
>>   @@ -1387,10 +1418,8 @@ static int pan_display_legacy(struct 
>> fb_var_screeninfo *var,
>>         mutex_lock(&client->modeset_mutex);
>>       drm_modeset_lock_all(fb_helper->dev);
>> +    pan_set_locked(client, var->xoffset, var->yoffset);
>>       drm_client_for_each_modeset(modeset, client) {
>> -        modeset->x = var->xoffset;
>> -        modeset->y = var->yoffset;
>> -
>>           if (modeset->num_connectors) {
>>               ret = drm_mode_set_config_internal(modeset);
>>               if (!ret) {
>> @@ -1461,6 +1490,94 @@ static uint32_t 
>> drm_fb_helper_find_format(struct drm_fb_helper *fb_helper, const
>>       return DRM_FORMAT_INVALID;
>>   }
>>   +/*
>> + * Check if the device supports extended mode
>> + *
>> + * return true if the device supports extended mode,
>> + * otherwise return false.
>> + */
>> +static bool drm_fb_helper_validate_extended_mode(struct 
>> drm_fb_helper *fb_helper,
>> +                         struct drm_fb_helper_surface_size *sizes)
>> +{
>> +    struct drm_client_dev *client = &fb_helper->client;
>> +    struct drm_device *dev = fb_helper->dev;
>> +    struct drm_mode_config *config = &dev->mode_config;
>> +    struct drm_mode_set *mode_set;
>> +    u32 crtc_count;
>> +
>> +    drm_client_for_each_modeset(mode_set, client) {
>> +        crtc_count++;
>> +
>> +        for (int j = 0; j < mode_set->num_connectors; j++) {
>> +            struct drm_connector *connector = mode_set->connectors[j];
>> +
>> +            if (connector->has_tile) {
>> +                drm_dbg_kms(client->dev,
>> +                        "Don't support extended with tile mode 
>> connector yet\n");
>> +                return false;
>> +            }
>> +        }
>> +    }
>> +
>> +    if (crtc_count < 2) {
>> +        drm_dbg_kms(client->dev,
>> +                "Only support extended mode when device have 
>> mult-crtcs\n");
>> +        return false;
>> +    }
>> +
>> +    if (drm_fbdev_screen_mode == SCREEN_EXPAND_HORIZONTAL) {
>> +        u32 x = 0;
>> +
>> +        drm_client_for_each_modeset(mode_set, client) {
>> +            struct drm_display_mode *desired_mode;
>> +
>> +            desired_mode = mode_set->mode;
>> +            x = mode_set->x;
>> +            sizes->fb_width = sizes->surface_width  += 
>> desired_mode->hdisplay;
>> +            sizes->surface_height =
>> +                min_t(u32, desired_mode->vdisplay + mode_set->y,
>> +                      sizes->surface_height);
>> +            sizes->fb_height = min_t(u32, desired_mode->vdisplay + 
>> mode_set->y,
>> +                         sizes->fb_height);
>> +        }
>> +        sizes->fb_width = sizes->surface_width += x;
>> +
>> +        if (sizes->fb_width > config->max_width) {
>> +            drm_dbg_kms(client->dev,
>> +                    "screen_buffer total width %d > config width %d\n",
>> +                    sizes->fb_width, config->max_width);
>> +            return false;
>> +        }
>> +    } else if (drm_fbdev_screen_mode == SCREEN_EXPAND_VERTICAL) {
>> +        u32 y = 0;
>> +
>> +        drm_client_for_each_modeset(mode_set, client) {
>> +            struct drm_display_mode *desired_mode;
>> +
>> +            desired_mode = mode_set->mode;
>> +            y = mode_set->y;
>> +            sizes->fb_height = sizes->surface_height += 
>> desired_mode->vdisplay;
>> +            sizes->surface_width =
>> +                min_t(u32, desired_mode->hdisplay + mode_set->x,
>> +                      sizes->surface_width);
>> +            sizes->fb_width = min_t(u32, desired_mode->hdisplay + 
>> mode_set->x,
>> +                        sizes->fb_width);
>> +        }
>> +        sizes->fb_height = sizes->surface_height += y;
>> +
>> +        if (sizes->fb_height > config->max_height) {
>> +            drm_dbg_kms(client->dev,
>> +                    "screen_buffer_total_height %d > config height 
>> %d\n",
>> +                    sizes->fb_height, config->max_height);
>> +            return false;
>> +        }
>> +    } else {
>> +        return false;
>> +    }
>> +
>> +    return true;
>> +}
>> +
>>   static int __drm_fb_helper_find_sizes(struct drm_fb_helper *fb_helper,
>>                         struct drm_fb_helper_surface_size *sizes)
>>   {
>> @@ -1527,6 +1644,16 @@ static int __drm_fb_helper_find_sizes(struct 
>> drm_fb_helper *fb_helper,
>>         /* first up get a count of crtcs now in use and new min/maxes 
>> width/heights */
>>       crtc_count = 0;
>> +
>> +    /* Check if we support extended mode. If we do, we will adjust 
>> the sizes accordingly. */
>> +    if (drm_fbdev_screen_mode &&
>> +        drm_fb_helper_validate_extended_mode(fb_helper, sizes)) {
>> +        drm_fbdev_screen_expand_mode_enabled = true;
>> +        drm_dbg_kms(dev, "Extended mode: horizontal expansion, 
>> width: %d, height: %d\n",
>> +                sizes->surface_width, sizes->surface_height);
>> +        return 0;
>> +    }
>> +
>>       drm_client_for_each_modeset(mode_set, client) {
>>           struct drm_display_mode *desired_mode;
>>           int x, y, j;
>

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

* Re: [PATCH] drm/fb-helper: add fbdev screen expended mode display support
  2025-11-10  5:54   ` Shixiong Ou
@ 2025-11-10  7:17     ` Thomas Zimmermann
  0 siblings, 0 replies; 5+ messages in thread
From: Thomas Zimmermann @ 2025-11-10  7:17 UTC (permalink / raw)
  To: Shixiong Ou, oushixiong1025, Maarten Lankhorst
  Cc: Maxime Ripard, David Airlie, Simona Vetter, dri-devel,
	linux-kernel, Tiger Liu

Hi

Am 10.11.25 um 06:54 schrieb Shixiong Ou:
>
> 在 2025/11/7 18:06, Thomas Zimmermann 写道:
>>
>>
>> Am 07.11.25 um 10:26 schrieb oushixiong1025@163.com:
>>> From: Shixiong Ou <oushixiong@kylinos.cn>
>>>
>>> Add fbdev screen extended mode display support
>>
>> What? What is this about?
>>
> If an fbdev device has multiple screens, they are mirrored by default.
> This patch aims to enable extended display for the tty, allowing 
> horizontal or
> vertical expansion to achieve a screen splicing effect in the tty 
> terminal.

We won't merge that. The mirroring happens because we cannot easily say 
which display is the correct one. But the console is a necessity that we 
cannot not provide. Its code is already badly maintained and overly 
complicated for what it does. Therefore in the framebuffer console we 
want to reduce complexity, not add more.

If you want complex screen layouts, please implement a console in user 
space or use a compositor.

Best regards
Thomas


>
> Best regards,
> Shixiong
>
>>>
>>> Signed-off-by: Tiger Liu <liuyihu@kylinos.cn>
>>> Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
>>> ---
>>>   drivers/gpu/drm/drm_fb_helper.c | 143 
>>> ++++++++++++++++++++++++++++++--
>>>   1 file changed, 135 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/drm_fb_helper.c 
>>> b/drivers/gpu/drm/drm_fb_helper.c
>>> index 53e9dc0543de..a6ec03bf3aef 100644
>>> --- a/drivers/gpu/drm/drm_fb_helper.c
>>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>>> @@ -78,6 +78,17 @@ MODULE_PARM_DESC(drm_leak_fbdev_smem,
>>>            "Allow unsafe leaking fbdev physical smem address 
>>> [default=false]");
>>>   #endif
>>>   +#define SCREEN_CLONE            0x0
>>> +#define SCREEN_EXPAND_HORIZONTAL    0x1
>>> +#define SCREEN_EXPAND_VERTICAL        0x2
>>> +
>>> +static bool drm_fbdev_screen_expand_mode_enabled;
>>> +static int drm_fbdev_screen_mode = SCREEN_CLONE;
>>> +module_param_named(screen_mode, drm_fbdev_screen_mode, int, 0444);
>>> +MODULE_PARM_DESC(screen_mode,
>>> +         "Screen display of the fbdev. [0 = clone(default), 1 = 
>>> expand horizontally,"
>>> +         "2 = expand vertically]");
>>> +
>>>   static LIST_HEAD(kernel_fb_helper_list);
>>>   static DEFINE_MUTEX(kernel_fb_helper_lock);
>>>   @@ -1345,15 +1356,35 @@ int drm_fb_helper_set_par(struct fb_info 
>>> *info)
>>>   }
>>>   EXPORT_SYMBOL(drm_fb_helper_set_par);
>>>   -static void pan_set(struct drm_fb_helper *fb_helper, int dx, int dy)
>>> +static void pan_set_locked(struct drm_client_dev *client,
>>> +               int dx, int dy)
>>>   {
>>>       struct drm_mode_set *mode_set;
>>> +    int screen_x_offset = dx;
>>> +    int screen_y_offset = dy;
>>>   -    mutex_lock(&fb_helper->client.modeset_mutex);
>>> -    drm_client_for_each_modeset(mode_set, &fb_helper->client) {
>>> -        mode_set->x += dx;
>>> -        mode_set->y += dy;
>>> +    drm_client_for_each_modeset(mode_set, client) {
>>> +        if (drm_fbdev_screen_expand_mode_enabled) {
>>> +            if (drm_fbdev_screen_mode == SCREEN_EXPAND_HORIZONTAL) {
>>> +                mode_set->x += screen_x_offset;
>>> +                mode_set->y += screen_y_offset;
>>> +                screen_x_offset += mode_set->mode->hdisplay;
>>> +            } else if (drm_fbdev_screen_mode == 
>>> SCREEN_EXPAND_VERTICAL) {
>>> +                mode_set->x += screen_x_offset;
>>> +                mode_set->y += screen_y_offset;
>>> +                screen_y_offset += mode_set->mode->vdisplay;
>>> +            }
>>> +        } else {
>>> +            mode_set->x = screen_x_offset;
>>> +            mode_set->y = screen_y_offset;
>>> +        }
>>>       }
>>> +}
>>> +
>>> +static void pan_set(struct drm_fb_helper *fb_helper, int dx, int dy)
>>> +{
>>> +    mutex_lock(&fb_helper->client.modeset_mutex);
>>> +    pan_set_locked(&fb_helper->client, dx, dy);
>>>       mutex_unlock(&fb_helper->client.modeset_mutex);
>>>   }
>>>   @@ -1387,10 +1418,8 @@ static int pan_display_legacy(struct 
>>> fb_var_screeninfo *var,
>>>         mutex_lock(&client->modeset_mutex);
>>>       drm_modeset_lock_all(fb_helper->dev);
>>> +    pan_set_locked(client, var->xoffset, var->yoffset);
>>>       drm_client_for_each_modeset(modeset, client) {
>>> -        modeset->x = var->xoffset;
>>> -        modeset->y = var->yoffset;
>>> -
>>>           if (modeset->num_connectors) {
>>>               ret = drm_mode_set_config_internal(modeset);
>>>               if (!ret) {
>>> @@ -1461,6 +1490,94 @@ static uint32_t 
>>> drm_fb_helper_find_format(struct drm_fb_helper *fb_helper, const
>>>       return DRM_FORMAT_INVALID;
>>>   }
>>>   +/*
>>> + * Check if the device supports extended mode
>>> + *
>>> + * return true if the device supports extended mode,
>>> + * otherwise return false.
>>> + */
>>> +static bool drm_fb_helper_validate_extended_mode(struct 
>>> drm_fb_helper *fb_helper,
>>> +                         struct drm_fb_helper_surface_size *sizes)
>>> +{
>>> +    struct drm_client_dev *client = &fb_helper->client;
>>> +    struct drm_device *dev = fb_helper->dev;
>>> +    struct drm_mode_config *config = &dev->mode_config;
>>> +    struct drm_mode_set *mode_set;
>>> +    u32 crtc_count;
>>> +
>>> +    drm_client_for_each_modeset(mode_set, client) {
>>> +        crtc_count++;
>>> +
>>> +        for (int j = 0; j < mode_set->num_connectors; j++) {
>>> +            struct drm_connector *connector = mode_set->connectors[j];
>>> +
>>> +            if (connector->has_tile) {
>>> +                drm_dbg_kms(client->dev,
>>> +                        "Don't support extended with tile mode 
>>> connector yet\n");
>>> +                return false;
>>> +            }
>>> +        }
>>> +    }
>>> +
>>> +    if (crtc_count < 2) {
>>> +        drm_dbg_kms(client->dev,
>>> +                "Only support extended mode when device have 
>>> mult-crtcs\n");
>>> +        return false;
>>> +    }
>>> +
>>> +    if (drm_fbdev_screen_mode == SCREEN_EXPAND_HORIZONTAL) {
>>> +        u32 x = 0;
>>> +
>>> +        drm_client_for_each_modeset(mode_set, client) {
>>> +            struct drm_display_mode *desired_mode;
>>> +
>>> +            desired_mode = mode_set->mode;
>>> +            x = mode_set->x;
>>> +            sizes->fb_width = sizes->surface_width  += 
>>> desired_mode->hdisplay;
>>> +            sizes->surface_height =
>>> +                min_t(u32, desired_mode->vdisplay + mode_set->y,
>>> +                      sizes->surface_height);
>>> +            sizes->fb_height = min_t(u32, desired_mode->vdisplay + 
>>> mode_set->y,
>>> +                         sizes->fb_height);
>>> +        }
>>> +        sizes->fb_width = sizes->surface_width += x;
>>> +
>>> +        if (sizes->fb_width > config->max_width) {
>>> +            drm_dbg_kms(client->dev,
>>> +                    "screen_buffer total width %d > config width 
>>> %d\n",
>>> +                    sizes->fb_width, config->max_width);
>>> +            return false;
>>> +        }
>>> +    } else if (drm_fbdev_screen_mode == SCREEN_EXPAND_VERTICAL) {
>>> +        u32 y = 0;
>>> +
>>> +        drm_client_for_each_modeset(mode_set, client) {
>>> +            struct drm_display_mode *desired_mode;
>>> +
>>> +            desired_mode = mode_set->mode;
>>> +            y = mode_set->y;
>>> +            sizes->fb_height = sizes->surface_height += 
>>> desired_mode->vdisplay;
>>> +            sizes->surface_width =
>>> +                min_t(u32, desired_mode->hdisplay + mode_set->x,
>>> +                      sizes->surface_width);
>>> +            sizes->fb_width = min_t(u32, desired_mode->hdisplay + 
>>> mode_set->x,
>>> +                        sizes->fb_width);
>>> +        }
>>> +        sizes->fb_height = sizes->surface_height += y;
>>> +
>>> +        if (sizes->fb_height > config->max_height) {
>>> +            drm_dbg_kms(client->dev,
>>> +                    "screen_buffer_total_height %d > config height 
>>> %d\n",
>>> +                    sizes->fb_height, config->max_height);
>>> +            return false;
>>> +        }
>>> +    } else {
>>> +        return false;
>>> +    }
>>> +
>>> +    return true;
>>> +}
>>> +
>>>   static int __drm_fb_helper_find_sizes(struct drm_fb_helper 
>>> *fb_helper,
>>>                         struct drm_fb_helper_surface_size *sizes)
>>>   {
>>> @@ -1527,6 +1644,16 @@ static int __drm_fb_helper_find_sizes(struct 
>>> drm_fb_helper *fb_helper,
>>>         /* first up get a count of crtcs now in use and new 
>>> min/maxes width/heights */
>>>       crtc_count = 0;
>>> +
>>> +    /* Check if we support extended mode. If we do, we will adjust 
>>> the sizes accordingly. */
>>> +    if (drm_fbdev_screen_mode &&
>>> +        drm_fb_helper_validate_extended_mode(fb_helper, sizes)) {
>>> +        drm_fbdev_screen_expand_mode_enabled = true;
>>> +        drm_dbg_kms(dev, "Extended mode: horizontal expansion, 
>>> width: %d, height: %d\n",
>>> +                sizes->surface_width, sizes->surface_height);
>>> +        return 0;
>>> +    }
>>> +
>>>       drm_client_for_each_modeset(mode_set, client) {
>>>           struct drm_display_mode *desired_mode;
>>>           int x, y, j;
>>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)



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

* Re: [PATCH] drm/fb-helper: add fbdev screen expended mode display support
  2025-11-07  9:26 [PATCH] drm/fb-helper: add fbdev screen expended mode display support oushixiong1025
  2025-11-07 10:06 ` Thomas Zimmermann
@ 2025-11-10 12:54 ` kernel test robot
  1 sibling, 0 replies; 5+ messages in thread
From: kernel test robot @ 2025-11-10 12:54 UTC (permalink / raw)
  To: oushixiong1025, Maarten Lankhorst
  Cc: llvm, oe-kbuild-all, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, dri-devel, linux-kernel, Shixiong Ou,
	Tiger Liu

Hi,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on linus/master v6.18-rc5 next-20251110]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/oushixiong1025-163-com/drm-fb-helper-add-fbdev-screen-expended-mode-display-support/20251107-172927
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20251107092641.111431-1-oushixiong1025%40163.com
patch subject: [PATCH] drm/fb-helper: add fbdev screen expended mode display support
config: arm-randconfig-003-20251110 (https://download.01.org/0day-ci/archive/20251110/202511102026.2kvJOVYL-lkp@intel.com/config)
compiler: clang version 16.0.6 (https://github.com/llvm/llvm-project 7cbf1a2591520c2491aa35339f227775f4d3adf6)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251110/202511102026.2kvJOVYL-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511102026.2kvJOVYL-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/gpu/drm/drm_fb_helper.c:1509:3: warning: variable 'crtc_count' is uninitialized when used here [-Wuninitialized]
                   crtc_count++;
                   ^~~~~~~~~~
   drivers/gpu/drm/drm_fb_helper.c:1506:16: note: initialize the variable 'crtc_count' to silence this warning
           u32 crtc_count;
                         ^
                          = 0
   1 warning generated.


vim +/crtc_count +1509 drivers/gpu/drm/drm_fb_helper.c

  1492	
  1493	/*
  1494	 * Check if the device supports extended mode
  1495	 *
  1496	 * return true if the device supports extended mode,
  1497	 * otherwise return false.
  1498	 */
  1499	static bool drm_fb_helper_validate_extended_mode(struct drm_fb_helper *fb_helper,
  1500							 struct drm_fb_helper_surface_size *sizes)
  1501	{
  1502		struct drm_client_dev *client = &fb_helper->client;
  1503		struct drm_device *dev = fb_helper->dev;
  1504		struct drm_mode_config *config = &dev->mode_config;
  1505		struct drm_mode_set *mode_set;
  1506		u32 crtc_count;
  1507	
  1508		drm_client_for_each_modeset(mode_set, client) {
> 1509			crtc_count++;
  1510	
  1511			for (int j = 0; j < mode_set->num_connectors; j++) {
  1512				struct drm_connector *connector = mode_set->connectors[j];
  1513	
  1514				if (connector->has_tile) {
  1515					drm_dbg_kms(client->dev,
  1516						    "Don't support extended with tile mode connector yet\n");
  1517					return false;
  1518				}
  1519			}
  1520		}
  1521	
  1522		if (crtc_count < 2) {
  1523			drm_dbg_kms(client->dev,
  1524				    "Only support extended mode when device have mult-crtcs\n");
  1525			return false;
  1526		}
  1527	
  1528		if (drm_fbdev_screen_mode == SCREEN_EXPAND_HORIZONTAL) {
  1529			u32 x = 0;
  1530	
  1531			drm_client_for_each_modeset(mode_set, client) {
  1532				struct drm_display_mode *desired_mode;
  1533	
  1534				desired_mode = mode_set->mode;
  1535				x = mode_set->x;
  1536				sizes->fb_width = sizes->surface_width  += desired_mode->hdisplay;
  1537				sizes->surface_height =
  1538					min_t(u32, desired_mode->vdisplay + mode_set->y,
  1539					      sizes->surface_height);
  1540				sizes->fb_height = min_t(u32, desired_mode->vdisplay + mode_set->y,
  1541							 sizes->fb_height);
  1542			}
  1543			sizes->fb_width = sizes->surface_width += x;
  1544	
  1545			if (sizes->fb_width > config->max_width) {
  1546				drm_dbg_kms(client->dev,
  1547					    "screen_buffer total width %d > config width %d\n",
  1548					    sizes->fb_width, config->max_width);
  1549				return false;
  1550			}
  1551		} else if (drm_fbdev_screen_mode == SCREEN_EXPAND_VERTICAL) {
  1552			u32 y = 0;
  1553	
  1554			drm_client_for_each_modeset(mode_set, client) {
  1555				struct drm_display_mode *desired_mode;
  1556	
  1557				desired_mode = mode_set->mode;
  1558				y = mode_set->y;
  1559				sizes->fb_height = sizes->surface_height += desired_mode->vdisplay;
  1560				sizes->surface_width =
  1561					min_t(u32, desired_mode->hdisplay + mode_set->x,
  1562					      sizes->surface_width);
  1563				sizes->fb_width = min_t(u32, desired_mode->hdisplay + mode_set->x,
  1564							sizes->fb_width);
  1565			}
  1566			sizes->fb_height = sizes->surface_height += y;
  1567	
  1568			if (sizes->fb_height > config->max_height) {
  1569				drm_dbg_kms(client->dev,
  1570					    "screen_buffer_total_height %d > config height %d\n",
  1571					    sizes->fb_height, config->max_height);
  1572				return false;
  1573			}
  1574		} else {
  1575			return false;
  1576		}
  1577	
  1578		return true;
  1579	}
  1580	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

end of thread, other threads:[~2025-11-10 12:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-07  9:26 [PATCH] drm/fb-helper: add fbdev screen expended mode display support oushixiong1025
2025-11-07 10:06 ` Thomas Zimmermann
2025-11-10  5:54   ` Shixiong Ou
2025-11-10  7:17     ` Thomas Zimmermann
2025-11-10 12:54 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox