diff mbox series

drm: Don't return unsupported formats in drm_mode_legacy_fb_format

Message ID 20240310152803.3315-1-frej.drejhammar@gmail.com (mailing list archive)
State New, archived
Headers show
Series drm: Don't return unsupported formats in drm_mode_legacy_fb_format | expand

Commit Message

Frej Drejhammar March 10, 2024, 3:28 p.m. UTC
This patch changes drm_mode_legacy_fb_format() to only return formats
which are supported by the current drm-device. The motivation for this
change is to fix a regression introduced by commit
c91acda3a380 ("drm/gem: Check for valid formats") which stops the Xorg
modesetting driver from working on the Beagleboard Black (it uses the
tilcdc kernel driver).

When the Xorg modesetting driver starts up, it tries to determine the
default bpp for the device. It does this by allocating a dumb 32bpp
frame buffer (using DRM_IOCTL_MODE_CREATE_DUMB) and then calling
drmModeAddFB() with that frame buffer asking for a 24-bit depth and 32
bpp. As the modesetting driver uses drmModeAddFB() which doesn't
supply a format, the kernel's drm_mode_legacy_fb_format() is called to
provide a format matching the requested depth and bpp. If the
drmModeAddFB() call fails, it forces both depth and bpp to 24. If
drmModeAddFB() succeeds, depth is assumed to be 24 and bpp 32. The
dummy frame buffer is then removed (using drmModeRmFB()).

If the modesetting driver finds that both the default bpp and depth
are 24, it forces the use of a 32bpp shadow buffer and a 24bpp front
buffer. Following this, the driver reads the user-specified color
depth option and tries to create a framebuffer of that depth, but if
the use of a shadow buffer has been forced, the bpp and depth of it
overrides the user-supplied option.

The Xorg modesetting driver on top of the tilcdc kernel driver used to
work on the Beagleboard Black if a 16 bit color depth was
configured. The hardware in the Beagleboard Black supports the RG16,
BG24, and XB24 formats. When drm_mode_legacy_fb_format() was called to
request a format for a 24-bit depth and 32 bpp, it would return the
unsupported RG24 format which drmModeAddFB() would happily accept (as
there was no check for a valid format). As a shadow buffer wasn't
forced, the modesetting driver would try the user specified 16 bit
color depth and drm_mode_legacy_fb_format() would return RG16 which is
supported by the hardware. Color depths of 24 bits were not supported,
as the unsupported RG24 would be detected when drmModeSetCrtc() was
called.

Following commit c91acda3a380 ("drm/gem: Check for valid formats"),
which adds a check for a valid (supported by the hardware) format to
the code path for the kernel part of drmModeAddFB(), the modesetting
driver fails to configure and add a frame buffer. This is because the
call to create a 24-bit depth and 32 bpp framebuffer during detection
of the default bpp will now fail and a 24-bit depth and 24 bpp front
buffer will be forced. As drm_mode_legacy_fb_format() will return RG24
which isn't supported, the creation of that framebuffer will also
fail.

To fix the regression, this patch extends drm_mode_legacy_fb_format()
to list all formats with a particular bpp and color depth known to the
kernel, and have it probe the current drm-device for a supported
format. This fixes the regression and, as a bonus, a color depth of 24
bits on the Beagleboard Black is now working.

As this patch changes drm_mode_legacy_fb_format() which is used by
other drivers, it has, in addition to the Beagleboard Black, also been
tested with the nouveau and modesetting drivers on a NVIDIA NV96, and
with the intel and modesetting drivers on an intel HD Graphics 4000
chipset.

Signed-off-by: Frej Drejhammar <frej.drejhammar@gmail.com>
Fixes: c91acda3a380 ("drm/gem: Check for valid formats")
Cc: stable@vger.kernel.org
Cc: Russell King <linux@armlinux.org.uk>
Cc: David Airlie <airlied@gmail.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Cc: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
Cc: Rob Clark <robdclark@gmail.com>
Cc: Abhinav Kumar <quic_abhinavk@quicinc.com>
Cc: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Cc: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Cc: Javier Martinez Canillas <javierm@redhat.com>
Cc: "Maíra Canal" <mcanal@igalia.com>
Cc: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
Cc: dri-devel@lists.freedesktop.org
---
 drivers/gpu/drm/armada/armada_fbdev.c         |  2 +-
 drivers/gpu/drm/drm_fb_helper.c               |  2 +-
 drivers/gpu/drm/drm_fbdev_dma.c               |  3 +-
 drivers/gpu/drm/drm_fbdev_generic.c           |  3 +-
 drivers/gpu/drm/drm_fourcc.c                  | 91 ++++++++++++++++---
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c     |  3 +-
 drivers/gpu/drm/gma500/fbdev.c                |  2 +-
 drivers/gpu/drm/i915/display/intel_fbdev_fb.c |  3 +-
 drivers/gpu/drm/msm/msm_fbdev.c               |  3 +-
 drivers/gpu/drm/omapdrm/omap_fbdev.c          |  2 +-
 drivers/gpu/drm/radeon/radeon_fbdev.c         |  3 +-
 drivers/gpu/drm/tegra/fbdev.c                 |  3 +-
 drivers/gpu/drm/tiny/ofdrm.c                  |  6 +-
 drivers/gpu/drm/xe/display/intel_fbdev_fb.c   |  3 +-
 include/drm/drm_fourcc.h                      |  3 +-
 15 files changed, 104 insertions(+), 28 deletions(-)


base-commit: b9511c6d277c31b13d4f3128eba46f4e0733d734

Comments

Thomas Zimmermann March 11, 2024, 8:40 a.m. UTC | #1
Hi,

thanks for the patch.

Am 10.03.24 um 16:28 schrieb Frej Drejhammar:
[...]
>   	size = cmd.pitches[0] * cmd.height;
> diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
> index ab89b7fc7bf6..ded868601aea 100644
> --- a/drivers/gpu/drm/tiny/ofdrm.c
> +++ b/drivers/gpu/drm/tiny/ofdrm.c
> @@ -100,14 +100,14 @@ static const struct drm_format_info *display_get_validated_format(struct drm_dev
>   
>   	switch (depth) {
>   	case 8:
> -		format = drm_mode_legacy_fb_format(8, 8);
> +		format = drm_mode_legacy_fb_format(dev, 8, 8);
>   		break;
>   	case 15:
>   	case 16:
> -		format = drm_mode_legacy_fb_format(16, depth);
> +		format = drm_mode_legacy_fb_format(dev, 16, depth);
>   		break;
>   	case 32:
> -		format = drm_mode_legacy_fb_format(32, 24);
> +		format = drm_mode_legacy_fb_format(dev, 32, 24);
>   		break;

This will break ofdrm, which needs the returned value as-is to build its 
internal list of plane formats.

I suggest to switch all fbdev code over to drm_driver_legacy_fb_format 
<https://elixir.bootlin.com/linux/latest/C/ident/drm_driver_legacy_fb_format>() 
first and then modify the format indrm_driver_legacy_fb_format 
<https://elixir.bootlin.com/linux/latest/C/ident/drm_driver_legacy_fb_format>() 
after reading it from drm_fb_legacy_fb_format(). I can help a bit with 
testing the fbdev changes.

Best regards
Thomas


>   	default:
>   		drm_err(dev, "unsupported framebuffer depth %u\n", depth);
> diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c
> index 51ae3561fd0d..a38a8143d632 100644
> --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c
> +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c
> @@ -32,7 +32,8 @@ struct drm_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper,
>   
>   	mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
>   				    DIV_ROUND_UP(sizes->surface_bpp, 8), XE_PAGE_SIZE);
> -	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
> +	mode_cmd.pixel_format = drm_mode_legacy_fb_format(dev,
> +							  sizes->surface_bpp,
>   							  sizes->surface_depth);
>   
>   	size = mode_cmd.pitches[0] * mode_cmd.height;
> diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
> index ccf91daa4307..75d06393a564 100644
> --- a/include/drm/drm_fourcc.h
> +++ b/include/drm/drm_fourcc.h
> @@ -310,7 +310,8 @@ const struct drm_format_info *drm_format_info(u32 format);
>   const struct drm_format_info *
>   drm_get_format_info(struct drm_device *dev,
>   		    const struct drm_mode_fb_cmd2 *mode_cmd);
> -uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth);
> +uint32_t drm_mode_legacy_fb_format(struct drm_device *dev,
> +				   uint32_t bpp, uint32_t depth);
>   uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
>   				     uint32_t bpp, uint32_t depth);
>   unsigned int drm_format_info_block_width(const struct drm_format_info *info,
>
> base-commit: b9511c6d277c31b13d4f3128eba46f4e0733d734
Frej Drejhammar March 11, 2024, 7:34 p.m. UTC | #2
Hi Thomas,

Thanks for the review and suggestions. My experience with the drm parts
of the kernel is limited to some weekends trying to fix the regression,
so I'm afraid I have some questions to check my understanding before
making a v2 of the patch.

Thomas Zimmermann <tzimmermann@suse.de> writes:

> I suggest to switch all fbdev code over to drm_driver_legacy_fb_format
> <https://elixir.bootlin.com/linux/latest/C/ident/drm_driver_legacy_fb_format>()
> first and then modify the format indrm_driver_legacy_fb_format
> <https://elixir.bootlin.com/linux/latest/C/ident/drm_driver_legacy_fb_format>()
> after reading it from drm_fb_legacy_fb_format().

I see how doing the format massaging in drm_driver_legacy_fb_format()
would fix the original regression (starting with the format returned by
drm_mode_legacy_fb_format(), drm_fb_legacy_fb_format() is a typo,
right?). As drm_driver_legacy_fb_format() has only two callers,
drm_mode_addfb() and __drm_fb_helper_find_sizes() that change is
probably less likely to do something unintended. As far as I can tell,
drm_driver_legacy_fb_format() is only used when userland hasn't
specified a format or the kernel is initializing and have no format
information. For these code paths it's clear that only formats which are
actually supported by the hardware are meaningful.

What I can't really see is what "switch all fbdev code over to
drm_driver_legacy_fb_format" would entail and what the benefit would
be. How do I determine when drm_mode_legacy_fb_format() should be
replaced with drm_driver_legacy_fb_format()? I have already mistakenly
considered the change to drm_mode_legacy_fb_format() as harmless and
broken ofdrm... Shouldn't it be enough to make
drm_driver_legacy_fb_format() select a format which is supported by the
driver?

Best regards,

Frej
Thomas Zimmermann March 12, 2024, 8:31 a.m. UTC | #3
Hi

Am 11.03.24 um 20:34 schrieb Frej Drejhammar:
> Hi Thomas,
>
> Thanks for the review and suggestions. My experience with the drm parts
> of the kernel is limited to some weekends trying to fix the regression,
> so I'm afraid I have some questions to check my understanding before
> making a v2 of the patch.
>
> Thomas Zimmermann <tzimmermann@suse.de> writes:
>
>> I suggest to switch all fbdev code over to drm_driver_legacy_fb_format
>> <https://elixir.bootlin.com/linux/latest/C/ident/drm_driver_legacy_fb_format>()
>> first and then modify the format indrm_driver_legacy_fb_format
>> <https://elixir.bootlin.com/linux/latest/C/ident/drm_driver_legacy_fb_format>()
>> after reading it from drm_fb_legacy_fb_format().
> I see how doing the format massaging in drm_driver_legacy_fb_format()
> would fix the original regression (starting with the format returned by
> drm_mode_legacy_fb_format(), drm_fb_legacy_fb_format() is a typo,
> right?).

Yeah, a typo.

>   As drm_driver_legacy_fb_format() has only two callers,
> drm_mode_addfb() and __drm_fb_helper_find_sizes() that change is
> probably less likely to do something unintended. As far as I can tell,
> drm_driver_legacy_fb_format() is only used when userland hasn't
> specified a format or the kernel is initializing and have no format
> information. For these code paths it's clear that only formats which are
> actually supported by the hardware are meaningful.

Right.

>
> What I can't really see is what "switch all fbdev code over to
> drm_driver_legacy_fb_format" would entail and what the benefit would
> be. How do I determine when drm_mode_legacy_fb_format() should be
> replaced with drm_driver_legacy_fb_format()? I have already mistakenly
> considered the change to drm_mode_legacy_fb_format() as harmless and
> broken ofdrm... Shouldn't it be enough to make
> drm_driver_legacy_fb_format() select a format which is supported by the
> driver?

Your patch modifies drm_mode_legacy_fb_format() in a number of 
*_fbdev_*.c files. In those instances, the code could certainly use 
drm_driver_legacy_fb_format() instead.

The fbdev files provide the base for the kernel framebuffer console and 
should behave like DRM clients in userspace; just that they are 
implemented in the kernel. As userspace ioctls use 
drm_driver_legacy_fb_format(), converting the in-kernel clients makes 
sense. And that's it. We keep drm_mode_legacy_fb_format(), but call 
drm_driver_legacy_fb_format() where necessary.

About tilcdc: it uses fbdev-dma, which sets up an XRGB format [1]. 
Shouldn't this already fail? Do you see a framebuffer console?

[1] 
https://elixir.bootlin.com/linux/v6.8/source/drivers/gpu/drm/drm_fbdev_dma.c#L93



>
> Best regards,
>
> Frej
>
>
Frej Drejhammar March 12, 2024, 7:31 p.m. UTC | #4
Hi Thomas,

Thomas Zimmermann <tzimmermann@suse.de> writes:

> Am 11.03.24 um 20:34 schrieb Frej Drejhammar:
>
>> What I can't really see is what "switch all fbdev code over to
>> drm_driver_legacy_fb_format" would entail [...]
>
> Your patch modifies drm_mode_legacy_fb_format() in a number of
> *_fbdev_*.c files. In those instances, the code could certainly use
> drm_driver_legacy_fb_format() instead.
>
> The fbdev files provide the base for the kernel framebuffer console
> and should behave like DRM clients in userspace;

That's the understanding I was missing, thank you for the explanation!
I'll work up a two-patch series during the week-end.

> About tilcdc: it uses fbdev-dma, which sets up an XRGB format
> [1]. Shouldn't this already fail? Do you see a framebuffer console?

I get the penguin, but I'm running this particular Beagleboard with a
serial console, so I don't know if the rest of the console works. From
some extra kprints I can see that (the unmodified)
drm_mode_legacy_fb_format() returns RG16 which means that the
framebuffer asked for a depth=16, bpp=16 format, and RG16 is one of the
supported formats, so the check that triggers the regression won't
trigger.

Best regards,

Frej
diff mbox series

Patch

diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c
index d223176912b6..82f312f76980 100644
--- a/drivers/gpu/drm/armada/armada_fbdev.c
+++ b/drivers/gpu/drm/armada/armada_fbdev.c
@@ -54,7 +54,7 @@  static int armada_fbdev_create(struct drm_fb_helper *fbh,
 	mode.width = sizes->surface_width;
 	mode.height = sizes->surface_height;
 	mode.pitches[0] = armada_pitch(mode.width, sizes->surface_bpp);
-	mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+	mode.pixel_format = drm_mode_legacy_fb_format(dev, sizes->surface_bpp,
 					sizes->surface_depth);
 
 	size = mode.pitches[0] * mode.height;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index d612133e2cf7..62f81a14fb2e 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1453,7 +1453,7 @@  static uint32_t drm_fb_helper_find_format(struct drm_fb_helper *fb_helper, const
 	 * the framebuffer emulation can only deal with such
 	 * formats, specifically RGB/BGA formats.
 	 */
-	format = drm_mode_legacy_fb_format(bpp, depth);
+	format = drm_mode_legacy_fb_format(dev, bpp, depth);
 	if (!format)
 		goto err;
 
diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
index 6c9427bb4053..cdb315c6d110 100644
--- a/drivers/gpu/drm/drm_fbdev_dma.c
+++ b/drivers/gpu/drm/drm_fbdev_dma.c
@@ -90,7 +90,8 @@  static int drm_fbdev_dma_helper_fb_probe(struct drm_fb_helper *fb_helper,
 		    sizes->surface_width, sizes->surface_height,
 		    sizes->surface_bpp);
 
-	format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
+	format = drm_mode_legacy_fb_format(dev,
+					   sizes->surface_bpp, sizes->surface_depth);
 	buffer = drm_client_framebuffer_create(client, sizes->surface_width,
 					       sizes->surface_height, format);
 	if (IS_ERR(buffer))
diff --git a/drivers/gpu/drm/drm_fbdev_generic.c b/drivers/gpu/drm/drm_fbdev_generic.c
index d647d89764cb..aba8c272560c 100644
--- a/drivers/gpu/drm/drm_fbdev_generic.c
+++ b/drivers/gpu/drm/drm_fbdev_generic.c
@@ -84,7 +84,8 @@  static int drm_fbdev_generic_helper_fb_probe(struct drm_fb_helper *fb_helper,
 		    sizes->surface_width, sizes->surface_height,
 		    sizes->surface_bpp);
 
-	format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
+	format = drm_mode_legacy_fb_format(dev,
+					   sizes->surface_bpp, sizes->surface_depth);
 	buffer = drm_client_framebuffer_create(client, sizes->surface_width,
 					       sizes->surface_height, format);
 	if (IS_ERR(buffer))
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 193cf8ed7912..034f2087af9a 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -29,47 +29,97 @@ 
 
 #include <drm/drm_device.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_print.h>
+
+/*
+ * Internal helper to find a valid format among a list of potentially
+ * valid formats.
+ *
+ * Traverses the variadic arguments until a format supported by @dev
+ * or an DRM_FORMAT_INVALID argument is found. If a supported format
+ * is found it is returned, otherwise DRM_FORMAT_INVALID is returned.
+ */
+static uint32_t select_valid_format(struct drm_device *dev, ...)
+{
+	va_list va;
+	uint32_t fmt = DRM_FORMAT_INVALID;
+	uint32_t to_try;
+
+	va_start(va, dev);
+
+	for (to_try = va_arg(va, uint32_t);
+	     to_try != DRM_FORMAT_INVALID;
+	     to_try = va_arg(va, uint32_t)) {
+		if (drm_any_plane_has_format(dev, to_try, 0)) {
+			fmt = to_try;
+			break;
+		}
+	}
+
+	va_end(va);
+
+	return fmt;
+}
 
 /**
  * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
+ * @dev: DRM device
  * @bpp: bits per pixels
  * @depth: bit depth per pixel
  *
  * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
  * Useful in fbdev emulation code, since that deals in those values.
  */
-uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
+uint32_t drm_mode_legacy_fb_format(struct drm_device *dev,
+				   uint32_t bpp, uint32_t depth)
 {
 	uint32_t fmt = DRM_FORMAT_INVALID;
 
 	switch (bpp) {
 	case 1:
 		if (depth == 1)
-			fmt = DRM_FORMAT_C1;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_C1,
+						  DRM_FORMAT_INVALID);
 		break;
 
 	case 2:
 		if (depth == 2)
-			fmt = DRM_FORMAT_C2;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_C2,
+						  DRM_FORMAT_INVALID);
 		break;
 
 	case 4:
 		if (depth == 4)
-			fmt = DRM_FORMAT_C4;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_C4,
+						  DRM_FORMAT_INVALID);
 		break;
 
 	case 8:
 		if (depth == 8)
-			fmt = DRM_FORMAT_C8;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_C8,
+						  DRM_FORMAT_INVALID);
 		break;
 
 	case 16:
 		switch (depth) {
 		case 15:
-			fmt = DRM_FORMAT_XRGB1555;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_XRGB1555,
+						  DRM_FORMAT_XBGR1555,
+						  DRM_FORMAT_RGBX5551,
+						  DRM_FORMAT_BGRX5551,
+						  DRM_FORMAT_INVALID);
 			break;
 		case 16:
-			fmt = DRM_FORMAT_RGB565;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_RGB565,
+						  DRM_FORMAT_BGR565,
+						  DRM_FORMAT_INVALID);
 			break;
 		default:
 			break;
@@ -78,19 +128,36 @@  uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
 
 	case 24:
 		if (depth == 24)
-			fmt = DRM_FORMAT_RGB888;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_RGB888,
+						  DRM_FORMAT_BGR888);
 		break;
 
 	case 32:
 		switch (depth) {
 		case 24:
-			fmt = DRM_FORMAT_XRGB8888;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_XRGB8888,
+						  DRM_FORMAT_XBGR8888,
+						  DRM_FORMAT_RGBX8888,
+						  DRM_FORMAT_BGRX8888,
+						  DRM_FORMAT_INVALID);
 			break;
 		case 30:
-			fmt = DRM_FORMAT_XRGB2101010;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_XRGB2101010,
+						  DRM_FORMAT_XBGR2101010,
+						  DRM_FORMAT_RGBX1010102,
+						  DRM_FORMAT_BGRX1010102,
+						  DRM_FORMAT_INVALID);
 			break;
 		case 32:
-			fmt = DRM_FORMAT_ARGB8888;
+			fmt = select_valid_format(dev,
+						  DRM_FORMAT_ARGB8888,
+						  DRM_FORMAT_ABGR8888,
+						  DRM_FORMAT_RGBA8888,
+						  DRM_FORMAT_BGRA8888,
+						  DRM_FORMAT_INVALID);
 			break;
 		default:
 			break;
@@ -119,7 +186,7 @@  EXPORT_SYMBOL(drm_mode_legacy_fb_format);
 uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
 				     uint32_t bpp, uint32_t depth)
 {
-	uint32_t fmt = drm_mode_legacy_fb_format(bpp, depth);
+	uint32_t fmt = drm_mode_legacy_fb_format(dev, bpp, depth);
 
 	if (dev->mode_config.quirk_addfb_prefer_host_byte_order) {
 		if (fmt == DRM_FORMAT_XRGB8888)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index a379c8ca435a..e114ebd44169 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -104,7 +104,8 @@  static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
 	mode_cmd.width = sizes->surface_width;
 	mode_cmd.height = sizes->surface_height;
 	mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);
-	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(dev,
+							  sizes->surface_bpp,
 							  sizes->surface_depth);
 
 	size = mode_cmd.pitches[0] * mode_cmd.height;
diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c
index 98b44974d42d..811ae5cccf2c 100644
--- a/drivers/gpu/drm/gma500/fbdev.c
+++ b/drivers/gpu/drm/gma500/fbdev.c
@@ -189,7 +189,7 @@  static int psb_fbdev_fb_probe(struct drm_fb_helper *fb_helper,
 	mode_cmd.width = sizes->surface_width;
 	mode_cmd.height = sizes->surface_height;
 	mode_cmd.pitches[0] = ALIGN(mode_cmd.width * DIV_ROUND_UP(bpp, 8), 64);
-	mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(dev, bpp, depth);
 
 	size = mode_cmd.pitches[0] * mode_cmd.height;
 	size = ALIGN(size, PAGE_SIZE);
diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c
index 0665f943f65f..cb32fcff8fb5 100644
--- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c
+++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c
@@ -30,7 +30,8 @@  struct drm_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper,
 
 	mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
 				    DIV_ROUND_UP(sizes->surface_bpp, 8), 64);
-	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(dev,
+							  sizes->surface_bpp,
 							  sizes->surface_depth);
 
 	size = mode_cmd.pitches[0] * mode_cmd.height;
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index 030bedac632d..8748610299b4 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -77,7 +77,8 @@  static int msm_fbdev_create(struct drm_fb_helper *helper,
 	uint32_t format;
 	int ret, pitch;
 
-	format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
+	format = drm_mode_legacy_fb_format(dev,
+					   sizes->surface_bpp, sizes->surface_depth);
 
 	DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
 			sizes->surface_height, sizes->surface_bpp,
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 6b08b137af1a..98f01d80abd8 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -139,7 +139,7 @@  static int omap_fbdev_create(struct drm_fb_helper *helper,
 			sizes->surface_height, sizes->surface_bpp,
 			sizes->fb_width, sizes->fb_height);
 
-	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(dev, sizes->surface_bpp,
 			sizes->surface_depth);
 
 	mode_cmd.width = sizes->surface_width;
diff --git a/drivers/gpu/drm/radeon/radeon_fbdev.c b/drivers/gpu/drm/radeon/radeon_fbdev.c
index 02bf25759059..bf1843529c7c 100644
--- a/drivers/gpu/drm/radeon/radeon_fbdev.c
+++ b/drivers/gpu/drm/radeon/radeon_fbdev.c
@@ -221,7 +221,8 @@  static int radeon_fbdev_fb_helper_fb_probe(struct drm_fb_helper *fb_helper,
 	if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
 		sizes->surface_bpp = 32;
 
-	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(dev,
+							  sizes->surface_bpp,
 							  sizes->surface_depth);
 
 	ret = radeon_fbdev_create_pinned_object(fb_helper, &mode_cmd, &gobj);
diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c
index db6eaac3d30e..290e8c426b0c 100644
--- a/drivers/gpu/drm/tegra/fbdev.c
+++ b/drivers/gpu/drm/tegra/fbdev.c
@@ -87,7 +87,8 @@  static int tegra_fbdev_probe(struct drm_fb_helper *helper,
 	cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel,
 				  tegra->pitch_align);
 
-	cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+	cmd.pixel_format = drm_mode_legacy_fb_format(dev,
+						     sizes->surface_bpp,
 						     sizes->surface_depth);
 
 	size = cmd.pitches[0] * cmd.height;
diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
index ab89b7fc7bf6..ded868601aea 100644
--- a/drivers/gpu/drm/tiny/ofdrm.c
+++ b/drivers/gpu/drm/tiny/ofdrm.c
@@ -100,14 +100,14 @@  static const struct drm_format_info *display_get_validated_format(struct drm_dev
 
 	switch (depth) {
 	case 8:
-		format = drm_mode_legacy_fb_format(8, 8);
+		format = drm_mode_legacy_fb_format(dev, 8, 8);
 		break;
 	case 15:
 	case 16:
-		format = drm_mode_legacy_fb_format(16, depth);
+		format = drm_mode_legacy_fb_format(dev, 16, depth);
 		break;
 	case 32:
-		format = drm_mode_legacy_fb_format(32, 24);
+		format = drm_mode_legacy_fb_format(dev, 32, 24);
 		break;
 	default:
 		drm_err(dev, "unsupported framebuffer depth %u\n", depth);
diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c
index 51ae3561fd0d..a38a8143d632 100644
--- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c
+++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c
@@ -32,7 +32,8 @@  struct drm_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper,
 
 	mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
 				    DIV_ROUND_UP(sizes->surface_bpp, 8), XE_PAGE_SIZE);
-	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(dev,
+							  sizes->surface_bpp,
 							  sizes->surface_depth);
 
 	size = mode_cmd.pitches[0] * mode_cmd.height;
diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
index ccf91daa4307..75d06393a564 100644
--- a/include/drm/drm_fourcc.h
+++ b/include/drm/drm_fourcc.h
@@ -310,7 +310,8 @@  const struct drm_format_info *drm_format_info(u32 format);
 const struct drm_format_info *
 drm_get_format_info(struct drm_device *dev,
 		    const struct drm_mode_fb_cmd2 *mode_cmd);
-uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth);
+uint32_t drm_mode_legacy_fb_format(struct drm_device *dev,
+				   uint32_t bpp, uint32_t depth);
 uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
 				     uint32_t bpp, uint32_t depth);
 unsigned int drm_format_info_block_width(const struct drm_format_info *info,