* [PATCH 01/18] drm/ofdrm: Remove struct ofdrm_device.pdev
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-23 10:10 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 02/18] drm/ofdrm: Open-code drm_simple_encoder_init() Thomas Zimmermann
` (17 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
The field pdev is unused. Remove it.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/tiny/ofdrm.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
index 13491c0e704a..7469dd281083 100644
--- a/drivers/gpu/drm/tiny/ofdrm.c
+++ b/drivers/gpu/drm/tiny/ofdrm.c
@@ -291,7 +291,6 @@ struct ofdrm_device_funcs {
struct ofdrm_device {
struct drm_device dev;
- struct platform_device *pdev;
const struct ofdrm_device_funcs *funcs;
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 01/18] drm/ofdrm: Remove struct ofdrm_device.pdev
2025-03-19 7:45 ` [PATCH 01/18] drm/ofdrm: Remove struct ofdrm_device.pdev Thomas Zimmermann
@ 2025-03-23 10:10 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-23 10:10 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> The field pdev is unused. Remove it.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/tiny/ofdrm.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
> index 13491c0e704a..7469dd281083 100644
> --- a/drivers/gpu/drm/tiny/ofdrm.c
> +++ b/drivers/gpu/drm/tiny/ofdrm.c
> @@ -291,7 +291,6 @@ struct ofdrm_device_funcs {
>
> struct ofdrm_device {
> struct drm_device dev;
> - struct platform_device *pdev;
>
> const struct ofdrm_device_funcs *funcs;
>
> --
> 2.48.1
>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 02/18] drm/ofdrm: Open-code drm_simple_encoder_init()
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
2025-03-19 7:45 ` [PATCH 01/18] drm/ofdrm: Remove struct ofdrm_device.pdev Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-23 10:12 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 03/18] drm/simpledrm: Remove struct simpledrm_device.nformats Thomas Zimmermann
` (16 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
The helper drm_simple_encoder_init() is a trivial helper around
drm_encoder_init() and therefore deprecated. Open-code the function
and remove the dependency.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/tiny/ofdrm.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
index 7469dd281083..7d5beaf6a42c 100644
--- a/drivers/gpu/drm/tiny/ofdrm.c
+++ b/drivers/gpu/drm/tiny/ofdrm.c
@@ -21,7 +21,6 @@
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#define DRIVER_NAME "ofdrm"
#define DRIVER_DESC "DRM driver for OF platform devices"
@@ -999,6 +998,10 @@ static const struct drm_crtc_funcs ofdrm_crtc_funcs = {
.atomic_destroy_state = ofdrm_crtc_atomic_destroy_state,
};
+static const struct drm_encoder_funcs ofdrm_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static int ofdrm_connector_helper_get_modes(struct drm_connector *connector)
{
struct ofdrm_device *odev = ofdrm_device_of_dev(connector->dev);
@@ -1309,7 +1312,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
/* Encoder */
encoder = &odev->encoder;
- ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
+ ret = drm_encoder_init(dev, encoder, &ofdrm_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL);
if (ret)
return ERR_PTR(ret);
encoder->possible_crtcs = drm_crtc_mask(crtc);
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 02/18] drm/ofdrm: Open-code drm_simple_encoder_init()
2025-03-19 7:45 ` [PATCH 02/18] drm/ofdrm: Open-code drm_simple_encoder_init() Thomas Zimmermann
@ 2025-03-23 10:12 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-23 10:12 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> The helper drm_simple_encoder_init() is a trivial helper around
> drm_encoder_init() and therefore deprecated. Open-code the function
> and remove the dependency.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 03/18] drm/simpledrm: Remove struct simpledrm_device.nformats
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
2025-03-19 7:45 ` [PATCH 01/18] drm/ofdrm: Remove struct ofdrm_device.pdev Thomas Zimmermann
2025-03-19 7:45 ` [PATCH 02/18] drm/ofdrm: Open-code drm_simple_encoder_init() Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-23 10:17 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 04/18] drm: Move sysfb drivers into separate subdirectory Thomas Zimmermann
` (15 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
The field nformats is unused. Remove it.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/tiny/simpledrm.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 5d9ab8adf800..d949713f5ff6 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -246,7 +246,6 @@ struct simpledrm_device {
/* modesetting */
uint32_t formats[8];
- size_t nformats;
struct drm_plane primary_plane;
struct drm_crtc crtc;
struct drm_encoder encoder;
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 03/18] drm/simpledrm: Remove struct simpledrm_device.nformats
2025-03-19 7:45 ` [PATCH 03/18] drm/simpledrm: Remove struct simpledrm_device.nformats Thomas Zimmermann
@ 2025-03-23 10:17 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-23 10:17 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> The field nformats is unused. Remove it.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/tiny/simpledrm.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
> index 5d9ab8adf800..d949713f5ff6 100644
> --- a/drivers/gpu/drm/tiny/simpledrm.c
> +++ b/drivers/gpu/drm/tiny/simpledrm.c
> @@ -246,7 +246,6 @@ struct simpledrm_device {
>
> /* modesetting */
> uint32_t formats[8];
> - size_t nformats;
> struct drm_plane primary_plane;
> struct drm_crtc crtc;
> struct drm_encoder encoder;
> --
> 2.48.1
>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 04/18] drm: Move sysfb drivers into separate subdirectory
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (2 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 03/18] drm/simpledrm: Remove struct simpledrm_device.nformats Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-23 10:21 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 05/18] drm/sysfb: Add struct drm_sysfb_device Thomas Zimmermann
` (14 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
The ofdrm and simpledrm drivers are special as they operate on
externally provided framebuffers. Move them into their own sub-
directory. Will let them share common code.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
MAINTAINERS | 3 +-
drivers/gpu/drm/Kconfig | 2 ++
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/sysfb/Kconfig | 38 +++++++++++++++++++++
drivers/gpu/drm/sysfb/Makefile | 4 +++
drivers/gpu/drm/{tiny => sysfb}/ofdrm.c | 0
drivers/gpu/drm/{tiny => sysfb}/simpledrm.c | 0
drivers/gpu/drm/tiny/Kconfig | 32 -----------------
drivers/gpu/drm/tiny/Makefile | 2 --
9 files changed, 46 insertions(+), 36 deletions(-)
create mode 100644 drivers/gpu/drm/sysfb/Kconfig
create mode 100644 drivers/gpu/drm/sysfb/Makefile
rename drivers/gpu/drm/{tiny => sysfb}/ofdrm.c (100%)
rename drivers/gpu/drm/{tiny => sysfb}/simpledrm.c (100%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9df9b25fffc3..588cea0e8630 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7247,8 +7247,7 @@ M: Javier Martinez Canillas <javierm@redhat.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
-F: drivers/gpu/drm/tiny/ofdrm.c
-F: drivers/gpu/drm/tiny/simpledrm.c
+F: drivers/gpu/drm/sysfb/
F: drivers/video/aperture.c
F: drivers/video/nomodeset.c
F: include/linux/aperture.h
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 1be14d8634f4..200bfbb9f093 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -335,6 +335,8 @@ config DRM_SCHED
tristate
depends on DRM
+source "drivers/gpu/drm/sysfb/Kconfig"
+
source "drivers/gpu/drm/arm/Kconfig"
source "drivers/gpu/drm/radeon/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ed54a546bbe2..bf5cb7936a1d 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -204,6 +204,7 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
obj-y += hisilicon/
obj-y += mxsfb/
+obj-y += sysfb/
obj-y += tiny/
obj-$(CONFIG_DRM_PL111) += pl111/
obj-$(CONFIG_DRM_TVE200) += tve200/
diff --git a/drivers/gpu/drm/sysfb/Kconfig b/drivers/gpu/drm/sysfb/Kconfig
new file mode 100644
index 000000000000..9eafc06b7192
--- /dev/null
+++ b/drivers/gpu/drm/sysfb/Kconfig
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menu "Drivers for system framebuffers"
+ depends on DRM
+
+config DRM_OFDRM
+ tristate "Open Firmware display driver"
+ depends on DRM && MMU && OF && (PPC || COMPILE_TEST)
+ select APERTURE_HELPERS
+ select DRM_CLIENT_SELECTION
+ select DRM_GEM_SHMEM_HELPER
+ select DRM_KMS_HELPER
+ help
+ DRM driver for Open Firmware framebuffers.
+
+ This driver assumes that the display hardware has been initialized
+ by the Open Firmware before the kernel boots. Scanout buffer, size,
+ and display format must be provided via device tree.
+
+config DRM_SIMPLEDRM
+ tristate "Simple framebuffer driver"
+ depends on DRM && MMU
+ select APERTURE_HELPERS
+ select DRM_CLIENT_SELECTION
+ select DRM_GEM_SHMEM_HELPER
+ select DRM_KMS_HELPER
+ help
+ DRM driver for simple platform-provided framebuffers.
+
+ This driver assumes that the display hardware has been initialized
+ by the firmware or bootloader before the kernel boots. Scanout
+ buffer, size, and display format must be provided via device tree,
+ UEFI, VESA, etc.
+
+ On x86 BIOS or UEFI systems, you should also select SYSFB_SIMPLEFB
+ to use UEFI and VESA framebuffers.
+
+endmenu
diff --git a/drivers/gpu/drm/sysfb/Makefile b/drivers/gpu/drm/sysfb/Makefile
new file mode 100644
index 000000000000..f6c03629accb
--- /dev/null
+++ b/drivers/gpu/drm/sysfb/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_DRM_OFDRM) += ofdrm.o
+obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o
diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
similarity index 100%
rename from drivers/gpu/drm/tiny/ofdrm.c
rename to drivers/gpu/drm/sysfb/ofdrm.c
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
similarity index 100%
rename from drivers/gpu/drm/tiny/simpledrm.c
rename to drivers/gpu/drm/sysfb/simpledrm.c
diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index 54c84c9801c1..95c1457d7730 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -65,20 +65,6 @@ config DRM_GM12U320
This is a KMS driver for projectors which use the GM12U320 chipset
for video transfer over USB2/3, such as the Acer C120 mini projector.
-config DRM_OFDRM
- tristate "Open Firmware display driver"
- depends on DRM && MMU && OF && (PPC || COMPILE_TEST)
- select APERTURE_HELPERS
- select DRM_CLIENT_SELECTION
- select DRM_GEM_SHMEM_HELPER
- select DRM_KMS_HELPER
- help
- DRM driver for Open Firmware framebuffers.
-
- This driver assumes that the display hardware has been initialized
- by the Open Firmware before the kernel boots. Scanout buffer, size,
- and display format must be provided via device tree.
-
config DRM_PANEL_MIPI_DBI
tristate "DRM support for MIPI DBI compatible panels"
depends on DRM && SPI
@@ -95,24 +81,6 @@ config DRM_PANEL_MIPI_DBI
https://github.com/notro/panel-mipi-dbi/wiki.
To compile this driver as a module, choose M here.
-config DRM_SIMPLEDRM
- tristate "Simple framebuffer driver"
- depends on DRM && MMU
- select APERTURE_HELPERS
- select DRM_CLIENT_SELECTION
- select DRM_GEM_SHMEM_HELPER
- select DRM_KMS_HELPER
- help
- DRM driver for simple platform-provided framebuffers.
-
- This driver assumes that the display hardware has been initialized
- by the firmware or bootloader before the kernel boots. Scanout
- buffer, size, and display format must be provided via device tree,
- UEFI, VESA, etc.
-
- On x86 BIOS or UEFI systems, you should also select SYSFB_SIMPLEFB
- to use UEFI and VESA framebuffers.
-
config TINYDRM_HX8357D
tristate "DRM support for HX8357D display panels"
depends on DRM && SPI
diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
index 0a3a7837a58b..ba4a60bb72bd 100644
--- a/drivers/gpu/drm/tiny/Makefile
+++ b/drivers/gpu/drm/tiny/Makefile
@@ -5,9 +5,7 @@ obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o
obj-$(CONFIG_DRM_BOCHS) += bochs.o
obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus-qemu.o
obj-$(CONFIG_DRM_GM12U320) += gm12u320.o
-obj-$(CONFIG_DRM_OFDRM) += ofdrm.o
obj-$(CONFIG_DRM_PANEL_MIPI_DBI) += panel-mipi-dbi.o
-obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o
obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o
obj-$(CONFIG_TINYDRM_ILI9163) += ili9163.o
obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 04/18] drm: Move sysfb drivers into separate subdirectory
2025-03-19 7:45 ` [PATCH 04/18] drm: Move sysfb drivers into separate subdirectory Thomas Zimmermann
@ 2025-03-23 10:21 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-23 10:21 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> The ofdrm and simpledrm drivers are special as they operate on
> externally provided framebuffers. Move them into their own sub-
> directory. Will let them share common code.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 05/18] drm/sysfb: Add struct drm_sysfb_device
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (3 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 04/18] drm: Move sysfb drivers into separate subdirectory Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-23 10:39 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 06/18] drm/sysfb: Provide single mode-init helper Thomas Zimmermann
` (13 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Add struct drm_sysfb_device that stores the system display's hardware
settings. Further helpers for the mode-setting pipeline will use these
fields. Convert ofdrm and simpledrm by embedding the sysfb device in
their device structs.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/Kconfig | 6 ++
drivers/gpu/drm/sysfb/Makefile | 2 +
drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 8 +++
drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 35 +++++++++
drivers/gpu/drm/sysfb/ofdrm.c | 78 ++++++++++----------
drivers/gpu/drm/sysfb/simpledrm.c | 90 ++++++++++++------------
6 files changed, 135 insertions(+), 84 deletions(-)
create mode 100644 drivers/gpu/drm/sysfb/drm_sysfb_helper.c
create mode 100644 drivers/gpu/drm/sysfb/drm_sysfb_helper.h
diff --git a/drivers/gpu/drm/sysfb/Kconfig b/drivers/gpu/drm/sysfb/Kconfig
index 9eafc06b7192..87094da417f6 100644
--- a/drivers/gpu/drm/sysfb/Kconfig
+++ b/drivers/gpu/drm/sysfb/Kconfig
@@ -3,6 +3,10 @@
menu "Drivers for system framebuffers"
depends on DRM
+config DRM_SYSFB_HELPER
+ tristate
+ depends on DRM
+
config DRM_OFDRM
tristate "Open Firmware display driver"
depends on DRM && MMU && OF && (PPC || COMPILE_TEST)
@@ -10,6 +14,7 @@ config DRM_OFDRM
select DRM_CLIENT_SELECTION
select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
+ select DRM_SYSFB_HELPER
help
DRM driver for Open Firmware framebuffers.
@@ -24,6 +29,7 @@ config DRM_SIMPLEDRM
select DRM_CLIENT_SELECTION
select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
+ select DRM_SYSFB_HELPER
help
DRM driver for simple platform-provided framebuffers.
diff --git a/drivers/gpu/drm/sysfb/Makefile b/drivers/gpu/drm/sysfb/Makefile
index f6c03629accb..f1e8700c3e35 100644
--- a/drivers/gpu/drm/sysfb/Makefile
+++ b/drivers/gpu/drm/sysfb/Makefile
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_DRM_SYSFB_HELPER) += drm_sysfb_helper.o
+
obj-$(CONFIG_DRM_OFDRM) += ofdrm.o
obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
new file mode 100644
index 000000000000..c083d21fd9ca
--- /dev/null
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+
+#include "drm_sysfb_helper.h"
+
+MODULE_DESCRIPTION("Helpers for DRM sysfb drivers");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
new file mode 100644
index 000000000000..8f05eee7f49e
--- /dev/null
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef DRM_SYSFB_HELPER_H
+#define DRM_SYSFB_HELPER_H
+
+#include <linux/container_of.h>
+#include <linux/iosys-map.h>
+
+#include <drm/drm_device.h>
+#include <drm/drm_modes.h>
+
+struct drm_format_info;
+
+/*
+ * Device
+ */
+
+struct drm_sysfb_device {
+ struct drm_device dev;
+
+ /* hardware settings */
+ struct drm_display_mode fb_mode;
+ const struct drm_format_info *fb_format;
+ unsigned int fb_pitch;
+
+ /* hardware-framebuffer kernel address */
+ struct iosys_map fb_addr;
+};
+
+static inline struct drm_sysfb_device *to_drm_sysfb_device(struct drm_device *dev)
+{
+ return container_of(dev, struct drm_sysfb_device, dev);
+}
+
+#endif
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index 7d5beaf6a42c..d42704facb45 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -22,6 +22,8 @@
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
+#include "drm_sysfb_helper.h"
+
#define DRIVER_NAME "ofdrm"
#define DRIVER_DESC "DRM driver for OF platform devices"
#define DRIVER_MAJOR 1
@@ -289,16 +291,10 @@ struct ofdrm_device_funcs {
};
struct ofdrm_device {
- struct drm_device dev;
+ struct drm_sysfb_device sysfb;
const struct ofdrm_device_funcs *funcs;
- /* firmware-buffer settings */
- struct iosys_map screen_base;
- struct drm_display_mode mode;
- const struct drm_format_info *format;
- unsigned int pitch;
-
/* colormap */
void __iomem *cmap_base;
@@ -312,7 +308,7 @@ struct ofdrm_device {
static struct ofdrm_device *ofdrm_device_of_dev(struct drm_device *dev)
{
- return container_of(dev, struct ofdrm_device, dev);
+ return container_of(to_drm_sysfb_device(dev), struct ofdrm_device, sysfb);
}
/*
@@ -352,7 +348,7 @@ static void ofdrm_pci_release(void *data)
static int ofdrm_device_init_pci(struct ofdrm_device *odev)
{
- struct drm_device *dev = &odev->dev;
+ struct drm_device *dev = &odev->sysfb.dev;
struct platform_device *pdev = to_platform_device(dev->dev);
struct device_node *of_node = pdev->dev.of_node;
struct pci_dev *pcidev;
@@ -395,7 +391,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev)
static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev,
struct resource *fb_res)
{
- struct platform_device *pdev = to_platform_device(odev->dev.dev);
+ struct platform_device *pdev = to_platform_device(odev->sysfb.dev.dev);
struct resource *res, *max_res = NULL;
u32 i;
@@ -421,7 +417,7 @@ static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev,
static void __iomem *get_cmap_address_of(struct ofdrm_device *odev, struct device_node *of_node,
int bar_no, unsigned long offset, unsigned long size)
{
- struct drm_device *dev = &odev->dev;
+ struct drm_device *dev = &odev->sysfb.dev;
const __be32 *addr_p;
u64 max_size, address;
unsigned int flags;
@@ -454,7 +450,7 @@ static void __iomem *ofdrm_mach64_cmap_ioremap(struct ofdrm_device *odev,
struct device_node *of_node,
u64 fb_base)
{
- struct drm_device *dev = &odev->dev;
+ struct drm_device *dev = &odev->sysfb.dev;
u64 address;
void __iomem *cmap_base;
@@ -616,7 +612,7 @@ static void __iomem *ofdrm_qemu_cmap_ioremap(struct ofdrm_device *odev,
cpu_to_be32(0x00),
};
- struct drm_device *dev = &odev->dev;
+ struct drm_device *dev = &odev->sysfb.dev;
u64 address;
void __iomem *cmap_base;
@@ -646,7 +642,7 @@ static void ofdrm_qemu_cmap_write(struct ofdrm_device *odev, unsigned char index
static void ofdrm_device_set_gamma_linear(struct ofdrm_device *odev,
const struct drm_format_info *format)
{
- struct drm_device *dev = &odev->dev;
+ struct drm_device *dev = &odev->sysfb.dev;
int i;
switch (format->format) {
@@ -685,7 +681,7 @@ static void ofdrm_device_set_gamma(struct ofdrm_device *odev,
const struct drm_format_info *format,
struct drm_color_lut *lut)
{
- struct drm_device *dev = &odev->dev;
+ struct drm_device *dev = &odev->sysfb.dev;
int i;
switch (format->format) {
@@ -756,7 +752,7 @@ static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
struct drm_atomic_state *new_state)
{
struct drm_device *dev = plane->dev;
- struct ofdrm_device *odev = ofdrm_device_of_dev(dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
struct drm_shadow_plane_state *new_shadow_plane_state =
to_drm_shadow_plane_state(new_plane_state);
@@ -778,12 +774,12 @@ static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
else if (!new_plane_state->visible)
return 0;
- if (new_fb->format != odev->format) {
+ if (new_fb->format != sysfb->fb_format) {
void *buf;
/* format conversion necessary; reserve buffer */
buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state,
- odev->pitch, GFP_KERNEL);
+ sysfb->fb_pitch, GFP_KERNEL);
if (!buf)
return -ENOMEM;
}
@@ -800,13 +796,13 @@ static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
struct drm_atomic_state *state)
{
struct drm_device *dev = plane->dev;
- struct ofdrm_device *odev = ofdrm_device_of_dev(dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
- unsigned int dst_pitch = odev->pitch;
- const struct drm_format_info *dst_format = odev->format;
+ unsigned int dst_pitch = sysfb->fb_pitch;
+ const struct drm_format_info *dst_format = sysfb->fb_format;
struct drm_atomic_helper_damage_iter iter;
struct drm_rect damage;
int ret, idx;
@@ -820,7 +816,7 @@ static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
drm_atomic_for_each_plane_damage(&iter, &damage) {
- struct iosys_map dst = odev->screen_base;
+ struct iosys_map dst = sysfb->fb_addr;
struct drm_rect dst_clip = plane_state->dst;
if (!drm_rect_intersect(&dst_clip, &damage))
@@ -840,12 +836,12 @@ static void ofdrm_primary_plane_helper_atomic_disable(struct drm_plane *plane,
struct drm_atomic_state *state)
{
struct drm_device *dev = plane->dev;
- struct ofdrm_device *odev = ofdrm_device_of_dev(dev);
- struct iosys_map dst = odev->screen_base;
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
+ struct iosys_map dst = sysfb->fb_addr;
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
void __iomem *dst_vmap = dst.vaddr_iomem; /* TODO: Use mapping abstraction */
- unsigned int dst_pitch = odev->pitch;
- const struct drm_format_info *dst_format = odev->format;
+ unsigned int dst_pitch = sysfb->fb_pitch;
+ const struct drm_format_info *dst_format = sysfb->fb_format;
struct drm_rect dst_clip;
unsigned long lines, linepixels, i;
int idx;
@@ -887,9 +883,9 @@ static const struct drm_plane_funcs ofdrm_primary_plane_funcs = {
static enum drm_mode_status ofdrm_crtc_helper_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
- struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(crtc->dev);
- return drm_crtc_helper_mode_valid_fixed(crtc, mode, &odev->mode);
+ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sysfb->fb_mode);
}
static int ofdrm_crtc_helper_atomic_check(struct drm_crtc *crtc,
@@ -1004,9 +1000,9 @@ static const struct drm_encoder_funcs ofdrm_encoder_funcs = {
static int ofdrm_connector_helper_get_modes(struct drm_connector *connector)
{
- struct ofdrm_device *odev = ofdrm_device_of_dev(connector->dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
- return drm_connector_helper_get_modes_fixed(connector, &odev->mode);
+ return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
}
static const struct drm_connector_helper_funcs ofdrm_connector_helper_funcs = {
@@ -1094,6 +1090,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
{
struct device_node *of_node = pdev->dev.of_node;
struct ofdrm_device *odev;
+ struct drm_sysfb_device *sysfb;
struct drm_device *dev;
enum ofdrm_model model;
bool big_endian;
@@ -1111,10 +1108,11 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
size_t nformats;
int ret;
- odev = devm_drm_dev_alloc(&pdev->dev, drv, struct ofdrm_device, dev);
+ odev = devm_drm_dev_alloc(&pdev->dev, drv, struct ofdrm_device, sysfb.dev);
if (IS_ERR(odev))
return ERR_CAST(odev);
- dev = &odev->dev;
+ sysfb = &odev->sysfb;
+ dev = &sysfb->dev;
platform_set_drvdata(pdev, dev);
ret = ofdrm_device_init_pci(odev);
@@ -1252,12 +1250,12 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
* Firmware framebuffer
*/
- iosys_map_set_vaddr_iomem(&odev->screen_base, screen_base);
- odev->mode = ofdrm_mode(width, height);
- odev->format = format;
- odev->pitch = linebytes;
+ iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
+ sysfb->fb_mode = ofdrm_mode(width, height);
+ sysfb->fb_format = format;
+ sysfb->fb_pitch = linebytes;
- drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&odev->mode));
+ drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sysfb->fb_mode));
drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n",
&format->format, width, height, linebytes);
@@ -1362,19 +1360,21 @@ static struct drm_driver ofdrm_driver = {
static int ofdrm_probe(struct platform_device *pdev)
{
struct ofdrm_device *odev;
+ struct drm_sysfb_device *sysfb;
struct drm_device *dev;
int ret;
odev = ofdrm_device_create(&ofdrm_driver, pdev);
if (IS_ERR(odev))
return PTR_ERR(odev);
- dev = &odev->dev;
+ sysfb = &odev->sysfb;
+ dev = &sysfb->dev;
ret = drm_dev_register(dev, 0);
if (ret)
return ret;
- drm_client_setup(dev, odev->format);
+ drm_client_setup(dev, sysfb->fb_format);
return 0;
}
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index d949713f5ff6..f258d8cdb6b6 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -29,6 +29,8 @@
#include <drm/drm_panic.h>
#include <drm/drm_probe_helper.h>
+#include "drm_sysfb_helper.h"
+
#define DRIVER_NAME "simpledrm"
#define DRIVER_DESC "DRM driver for simple-framebuffer platform devices"
#define DRIVER_MAJOR 1
@@ -217,7 +219,7 @@ simplefb_get_memory_of(struct drm_device *dev, struct device_node *of_node)
*/
struct simpledrm_device {
- struct drm_device dev;
+ struct drm_sysfb_device sysfb;
/* clocks */
#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
@@ -236,14 +238,6 @@ struct simpledrm_device {
struct device_link **pwr_dom_links;
#endif
- /* simplefb settings */
- struct drm_display_mode mode;
- const struct drm_format_info *format;
- unsigned int pitch;
-
- /* memory management */
- struct iosys_map screen_base;
-
/* modesetting */
uint32_t formats[8];
struct drm_plane primary_plane;
@@ -254,7 +248,7 @@ struct simpledrm_device {
static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev)
{
- return container_of(dev, struct simpledrm_device, dev);
+ return container_of(to_drm_sysfb_device(dev), struct simpledrm_device, sysfb);
}
/*
@@ -296,7 +290,7 @@ static void simpledrm_device_release_clocks(void *res)
static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
{
- struct drm_device *dev = &sdev->dev;
+ struct drm_device *dev = &sdev->sysfb.dev;
struct platform_device *pdev = to_platform_device(dev->dev);
struct device_node *of_node = pdev->dev.of_node;
struct clk *clock;
@@ -394,7 +388,7 @@ static void simpledrm_device_release_regulators(void *res)
static int simpledrm_device_init_regulators(struct simpledrm_device *sdev)
{
- struct drm_device *dev = &sdev->dev;
+ struct drm_device *dev = &sdev->sysfb.dev;
struct platform_device *pdev = to_platform_device(dev->dev);
struct device_node *of_node = pdev->dev.of_node;
struct property *prop;
@@ -515,7 +509,7 @@ static void simpledrm_device_detach_genpd(void *res)
static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev)
{
- struct device *dev = sdev->dev.dev;
+ struct device *dev = sdev->sysfb.dev.dev;
int i;
sdev->pwr_dom_count = of_count_phandle_with_args(dev->of_node, "power-domains",
@@ -547,7 +541,7 @@ static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev)
simpledrm_device_detach_genpd(sdev);
return ret;
}
- drm_warn(&sdev->dev,
+ drm_warn(&sdev->sysfb.dev,
"pm_domain_attach_by_id(%u) failed: %d\n", i, ret);
continue;
}
@@ -558,7 +552,7 @@ static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev)
DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
if (!sdev->pwr_dom_links[i])
- drm_warn(&sdev->dev, "failed to link power-domain %d\n", i);
+ drm_warn(&sdev->sysfb.dev, "failed to link power-domain %d\n", i);
}
return devm_add_action_or_reset(dev, simpledrm_device_detach_genpd, sdev);
@@ -589,7 +583,7 @@ static int simpledrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
struct drm_crtc *new_crtc = new_plane_state->crtc;
struct drm_crtc_state *new_crtc_state = NULL;
struct drm_device *dev = plane->dev;
- struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
int ret;
if (new_crtc)
@@ -604,12 +598,12 @@ static int simpledrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
else if (!new_plane_state->visible)
return 0;
- if (new_fb->format != sdev->format) {
+ if (new_fb->format != sysfb->fb_format) {
void *buf;
/* format conversion necessary; reserve buffer */
buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state,
- sdev->pitch, GFP_KERNEL);
+ sysfb->fb_pitch, GFP_KERNEL);
if (!buf)
return -ENOMEM;
}
@@ -625,7 +619,7 @@ static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
struct drm_device *dev = plane->dev;
- struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
struct drm_atomic_helper_damage_iter iter;
struct drm_rect damage;
int ret, idx;
@@ -640,13 +634,15 @@ static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
drm_atomic_for_each_plane_damage(&iter, &damage) {
struct drm_rect dst_clip = plane_state->dst;
- struct iosys_map dst = sdev->screen_base;
+ struct iosys_map dst = sysfb->fb_addr;
if (!drm_rect_intersect(&dst_clip, &damage))
continue;
- iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip));
- drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data,
+ iosys_map_incr(&dst, drm_fb_clip_offset(sysfb->fb_pitch, sysfb->fb_format,
+ &dst_clip));
+ drm_fb_blit(&dst, &sysfb->fb_pitch, sysfb->fb_format->format,
+ shadow_plane_state->data,
fb, &damage, &shadow_plane_state->fmtcnv_state);
}
@@ -659,14 +655,14 @@ static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plan
struct drm_atomic_state *state)
{
struct drm_device *dev = plane->dev;
- struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
int idx;
if (!drm_dev_enter(dev, &idx))
return;
/* Clear screen to black if disabled */
- iosys_map_memset(&sdev->screen_base, 0, 0, sdev->pitch * sdev->mode.vdisplay);
+ iosys_map_memset(&sysfb->fb_addr, 0, 0, sysfb->fb_pitch * sysfb->fb_mode.vdisplay);
drm_dev_exit(idx);
}
@@ -674,13 +670,13 @@ static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plan
static int simpledrm_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane,
struct drm_scanout_buffer *sb)
{
- struct simpledrm_device *sdev = simpledrm_device_of_dev(plane->dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
- sb->width = sdev->mode.hdisplay;
- sb->height = sdev->mode.vdisplay;
- sb->format = sdev->format;
- sb->pitch[0] = sdev->pitch;
- sb->map[0] = sdev->screen_base;
+ sb->width = sysfb->fb_mode.hdisplay;
+ sb->height = sysfb->fb_mode.vdisplay;
+ sb->format = sysfb->fb_format;
+ sb->pitch[0] = sysfb->fb_pitch;
+ sb->map[0] = sysfb->fb_addr;
return 0;
}
@@ -703,9 +699,9 @@ static const struct drm_plane_funcs simpledrm_primary_plane_funcs = {
static enum drm_mode_status simpledrm_crtc_helper_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
- struct simpledrm_device *sdev = simpledrm_device_of_dev(crtc->dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(crtc->dev);
- return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sdev->mode);
+ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sysfb->fb_mode);
}
/*
@@ -733,9 +729,9 @@ static const struct drm_encoder_funcs simpledrm_encoder_funcs = {
static int simpledrm_connector_helper_get_modes(struct drm_connector *connector)
{
- struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev);
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
- return drm_connector_helper_get_modes_fixed(connector, &sdev->mode);
+ return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
}
static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = {
@@ -778,6 +774,7 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
struct device_node *of_node = pdev->dev.of_node;
struct simpledrm_device *sdev;
+ struct drm_sysfb_device *sysfb;
struct drm_device *dev;
int width, height, stride;
int width_mm = 0, height_mm = 0;
@@ -792,10 +789,11 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
size_t nformats;
int ret;
- sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device, dev);
+ sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device, sysfb.dev);
if (IS_ERR(sdev))
return ERR_CAST(sdev);
- dev = &sdev->dev;
+ sysfb = &sdev->sysfb;
+ dev = &sysfb->dev;
platform_set_drvdata(pdev, sdev);
/*
@@ -866,11 +864,11 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
if (!height_mm)
height_mm = DRM_MODE_RES_MM(height, 96ul);
- sdev->mode = simpledrm_mode(width, height, width_mm, height_mm);
- sdev->format = format;
- sdev->pitch = stride;
+ sysfb->fb_mode = simpledrm_mode(width, height, width_mm, height_mm);
+ sysfb->fb_format = format;
+ sysfb->fb_pitch = stride;
- drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sdev->mode));
+ drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sysfb->fb_mode));
drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d byte\n",
&format->format, width, height, stride);
@@ -894,7 +892,7 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
if (IS_ERR(screen_base))
return screen_base;
- iosys_map_set_vaddr(&sdev->screen_base, screen_base);
+ iosys_map_set_vaddr(&sysfb->fb_addr, screen_base);
} else {
void __iomem *screen_base;
@@ -927,7 +925,7 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
if (!screen_base)
return ERR_PTR(-ENOMEM);
- iosys_map_set_vaddr_iomem(&sdev->screen_base, screen_base);
+ iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
}
/*
@@ -1026,19 +1024,21 @@ static struct drm_driver simpledrm_driver = {
static int simpledrm_probe(struct platform_device *pdev)
{
struct simpledrm_device *sdev;
+ struct drm_sysfb_device *sysfb;
struct drm_device *dev;
int ret;
sdev = simpledrm_device_create(&simpledrm_driver, pdev);
if (IS_ERR(sdev))
return PTR_ERR(sdev);
- dev = &sdev->dev;
+ sysfb = &sdev->sysfb;
+ dev = &sysfb->dev;
ret = drm_dev_register(dev, 0);
if (ret)
return ret;
- drm_client_setup(dev, sdev->format);
+ drm_client_setup(dev, sdev->sysfb.fb_format);
return 0;
}
@@ -1046,7 +1046,7 @@ static int simpledrm_probe(struct platform_device *pdev)
static void simpledrm_remove(struct platform_device *pdev)
{
struct simpledrm_device *sdev = platform_get_drvdata(pdev);
- struct drm_device *dev = &sdev->dev;
+ struct drm_device *dev = &sdev->sysfb.dev;
drm_dev_unplug(dev);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 05/18] drm/sysfb: Add struct drm_sysfb_device
2025-03-19 7:45 ` [PATCH 05/18] drm/sysfb: Add struct drm_sysfb_device Thomas Zimmermann
@ 2025-03-23 10:39 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-23 10:39 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Add struct drm_sysfb_device that stores the system display's hardware
> settings. Further helpers for the mode-setting pipeline will use these
> fields. Convert ofdrm and simpledrm by embedding the sysfb device in
> their device structs.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Nice patch, this makes total sense in hindsight.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 06/18] drm/sysfb: Provide single mode-init helper
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (4 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 05/18] drm/sysfb: Add struct drm_sysfb_device Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-23 10:41 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 07/18] drm/sysfb: Merge mode-config functions Thomas Zimmermann
` (12 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Merge the mode-init functions of ofdrm and simpledrm to the new helper
drm_sysfb_mode(). Also implement the DPI defaults there. Replace the
code in each driver with the shared helper.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 24 ++++++++++++++++++++++++
drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 5 +++++
drivers/gpu/drm/sysfb/ofdrm.c | 17 +----------------
drivers/gpu/drm/sysfb/simpledrm.c | 23 +----------------------
4 files changed, 31 insertions(+), 38 deletions(-)
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
index c083d21fd9ca..6deeac81a41d 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
@@ -6,3 +6,27 @@
MODULE_DESCRIPTION("Helpers for DRM sysfb drivers");
MODULE_LICENSE("GPL");
+
+struct drm_display_mode drm_sysfb_mode(unsigned int width,
+ unsigned int height,
+ unsigned int width_mm,
+ unsigned int height_mm)
+{
+ /*
+ * Assume a monitor resolution of 96 dpi to
+ * get a somewhat reasonable screen size.
+ */
+ if (!width_mm)
+ width_mm = DRM_MODE_RES_MM(width, 96ul);
+ if (!height_mm)
+ height_mm = DRM_MODE_RES_MM(height, 96ul);
+
+ {
+ const struct drm_display_mode mode = {
+ DRM_MODE_INIT(60, width, height, width_mm, height_mm)
+ };
+
+ return mode;
+ }
+}
+EXPORT_SYMBOL(drm_sysfb_mode);
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
index 8f05eee7f49e..8b4cc4af702b 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -11,6 +11,11 @@
struct drm_format_info;
+struct drm_display_mode drm_sysfb_mode(unsigned int width,
+ unsigned int height,
+ unsigned int width_mm,
+ unsigned int height_mm);
+
/*
* Device
*/
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index d42704facb45..7df6901157fb 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -1070,21 +1070,6 @@ static const struct ofdrm_device_funcs ofdrm_qemu_device_funcs = {
.cmap_write = ofdrm_qemu_cmap_write,
};
-static struct drm_display_mode ofdrm_mode(unsigned int width, unsigned int height)
-{
- /*
- * Assume a monitor resolution of 96 dpi to
- * get a somewhat reasonable screen size.
- */
- const struct drm_display_mode mode = {
- DRM_MODE_INIT(60, width, height,
- DRM_MODE_RES_MM(width, 96ul),
- DRM_MODE_RES_MM(height, 96ul))
- };
-
- return mode;
-}
-
static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
struct platform_device *pdev)
{
@@ -1251,7 +1236,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
*/
iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
- sysfb->fb_mode = ofdrm_mode(width, height);
+ sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
sysfb->fb_format = format;
sysfb->fb_pitch = linebytes;
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index f258d8cdb6b6..149df6941b6c 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -756,18 +756,6 @@ static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = {
* Init / Cleanup
*/
-static struct drm_display_mode simpledrm_mode(unsigned int width,
- unsigned int height,
- unsigned int width_mm,
- unsigned int height_mm)
-{
- const struct drm_display_mode mode = {
- DRM_MODE_INIT(60, width, height, width_mm, height_mm)
- };
-
- return mode;
-}
-
static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
struct platform_device *pdev)
{
@@ -855,16 +843,7 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
return ERR_PTR(-EINVAL);
}
- /*
- * Assume a monitor resolution of 96 dpi if physical dimensions
- * are not specified to get a somewhat reasonable screen size.
- */
- if (!width_mm)
- width_mm = DRM_MODE_RES_MM(width, 96ul);
- if (!height_mm)
- height_mm = DRM_MODE_RES_MM(height, 96ul);
-
- sysfb->fb_mode = simpledrm_mode(width, height, width_mm, height_mm);
+ sysfb->fb_mode = drm_sysfb_mode(width, height, width_mm, height_mm);
sysfb->fb_format = format;
sysfb->fb_pitch = stride;
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 06/18] drm/sysfb: Provide single mode-init helper
2025-03-19 7:45 ` [PATCH 06/18] drm/sysfb: Provide single mode-init helper Thomas Zimmermann
@ 2025-03-23 10:41 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-23 10:41 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Merge the mode-init functions of ofdrm and simpledrm to the new helper
> drm_sysfb_mode(). Also implement the DPI defaults there. Replace the
> code in each driver with the shared helper.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 07/18] drm/sysfb: Merge mode-config functions
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (5 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 06/18] drm/sysfb: Provide single mode-init helper Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-23 10:47 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 08/18] drm/sysfb: Merge connector functions Thomas Zimmermann
` (11 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Provide initializer to set struct drm_mode_config_funcs. Convert
ofdrm and simpledrm.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 9 +++++++++
drivers/gpu/drm/sysfb/ofdrm.c | 4 +---
drivers/gpu/drm/sysfb/simpledrm.c | 4 +---
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
index 8b4cc4af702b..cf80b291014a 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -37,4 +37,13 @@ static inline struct drm_sysfb_device *to_drm_sysfb_device(struct drm_device *de
return container_of(dev, struct drm_sysfb_device, dev);
}
+/*
+ * Mode config
+ */
+
+#define DRM_SYSFB_MODE_CONFIG_FUNCS \
+ .fb_create = drm_gem_fb_create_with_dirty, \
+ .atomic_check = drm_atomic_helper_check, \
+ .atomic_commit = drm_atomic_helper_commit
+
#endif
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index 7df6901157fb..470b93f0f791 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -1018,9 +1018,7 @@ static const struct drm_connector_funcs ofdrm_connector_funcs = {
};
static const struct drm_mode_config_funcs ofdrm_mode_config_funcs = {
- .fb_create = drm_gem_fb_create_with_dirty,
- .atomic_check = drm_atomic_helper_check,
- .atomic_commit = drm_atomic_helper_commit,
+ DRM_SYSFB_MODE_CONFIG_FUNCS,
};
/*
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index 149df6941b6c..0cee8e1b2108 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -747,9 +747,7 @@ static const struct drm_connector_funcs simpledrm_connector_funcs = {
};
static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = {
- .fb_create = drm_gem_fb_create_with_dirty,
- .atomic_check = drm_atomic_helper_check,
- .atomic_commit = drm_atomic_helper_commit,
+ DRM_SYSFB_MODE_CONFIG_FUNCS,
};
/*
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* [PATCH 08/18] drm/sysfb: Merge connector functions
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (6 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 07/18] drm/sysfb: Merge mode-config functions Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-23 10:57 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 09/18] drm/sysfb: Maintain CRTC state in struct drm_sysfb_crtc_state Thomas Zimmermann
` (10 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Merge the connector functions of ofdrm and simpledrm. Replace the
code in each driver with the shared helpers. Set up callbacks with
initializer macros.
No effective code changes. The sysfb connector only returns the
preconfigured display mode.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 14 ++++++++++++++
drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 15 +++++++++++++++
drivers/gpu/drm/sysfb/ofdrm.c | 14 ++------------
drivers/gpu/drm/sysfb/simpledrm.c | 14 ++------------
4 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
index 6deeac81a41d..355e025c7c62 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
@@ -2,6 +2,8 @@
#include <linux/module.h>
+#include <drm/drm_probe_helper.h>
+
#include "drm_sysfb_helper.h"
MODULE_DESCRIPTION("Helpers for DRM sysfb drivers");
@@ -30,3 +32,15 @@ struct drm_display_mode drm_sysfb_mode(unsigned int width,
}
}
EXPORT_SYMBOL(drm_sysfb_mode);
+
+/*
+ * Connector
+ */
+
+int drm_sysfb_connector_helper_get_modes(struct drm_connector *connector)
+{
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
+
+ return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
+}
+EXPORT_SYMBOL(drm_sysfb_connector_helper_get_modes);
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
index cf80b291014a..7e3fe9fa5cff 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -37,6 +37,21 @@ static inline struct drm_sysfb_device *to_drm_sysfb_device(struct drm_device *de
return container_of(dev, struct drm_sysfb_device, dev);
}
+/*
+ * Connector
+ */
+
+int drm_sysfb_connector_helper_get_modes(struct drm_connector *connector);
+
+#define DRM_SYSFB_CONNECTOR_HELPER_FUNCS \
+ .get_modes = drm_sysfb_connector_helper_get_modes
+
+#define DRM_SYSFB_CONNECTOR_FUNCS \
+ .reset = drm_atomic_helper_connector_reset, \
+ .fill_modes = drm_helper_probe_single_connector_modes, \
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, \
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state
+
/*
* Mode config
*/
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index 470b93f0f791..85db7441d1bf 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -998,23 +998,13 @@ static const struct drm_encoder_funcs ofdrm_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-static int ofdrm_connector_helper_get_modes(struct drm_connector *connector)
-{
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
-
- return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
-}
-
static const struct drm_connector_helper_funcs ofdrm_connector_helper_funcs = {
- .get_modes = ofdrm_connector_helper_get_modes,
+ DRM_SYSFB_CONNECTOR_HELPER_FUNCS,
};
static const struct drm_connector_funcs ofdrm_connector_funcs = {
- .reset = drm_atomic_helper_connector_reset,
- .fill_modes = drm_helper_probe_single_connector_modes,
+ DRM_SYSFB_CONNECTOR_FUNCS,
.destroy = drm_connector_cleanup,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_mode_config_funcs ofdrm_mode_config_funcs = {
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index 0cee8e1b2108..6d76d125d126 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -727,23 +727,13 @@ static const struct drm_encoder_funcs simpledrm_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-static int simpledrm_connector_helper_get_modes(struct drm_connector *connector)
-{
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
-
- return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
-}
-
static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = {
- .get_modes = simpledrm_connector_helper_get_modes,
+ DRM_SYSFB_CONNECTOR_HELPER_FUNCS,
};
static const struct drm_connector_funcs simpledrm_connector_funcs = {
- .reset = drm_atomic_helper_connector_reset,
- .fill_modes = drm_helper_probe_single_connector_modes,
+ DRM_SYSFB_CONNECTOR_FUNCS,
.destroy = drm_connector_cleanup,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = {
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 08/18] drm/sysfb: Merge connector functions
2025-03-19 7:45 ` [PATCH 08/18] drm/sysfb: Merge connector functions Thomas Zimmermann
@ 2025-03-23 10:57 ` Javier Martinez Canillas
2025-03-24 7:37 ` Thomas Zimmermann
0 siblings, 1 reply; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-23 10:57 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Merge the connector functions of ofdrm and simpledrm. Replace the
> code in each driver with the shared helpers. Set up callbacks with
> initializer macros.
>
> No effective code changes. The sysfb connector only returns the
> preconfigured display mode.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
...
> +#define DRM_SYSFB_CONNECTOR_FUNCS \
> + .reset = drm_atomic_helper_connector_reset, \
> + .fill_modes = drm_helper_probe_single_connector_modes, \
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, \
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state
> +
> /*
...
> static const struct drm_connector_funcs ofdrm_connector_funcs = {
> - .reset = drm_atomic_helper_connector_reset,
> - .fill_modes = drm_helper_probe_single_connector_modes,
> + DRM_SYSFB_CONNECTOR_FUNCS,
> .destroy = drm_connector_cleanup,
Why not include the .destroy callback in DRM_SYSFB_CONNECTOR_FUNCS ?
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 08/18] drm/sysfb: Merge connector functions
2025-03-23 10:57 ` Javier Martinez Canillas
@ 2025-03-24 7:37 ` Thomas Zimmermann
2025-03-24 8:53 ` Javier Martinez Canillas
0 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-24 7:37 UTC (permalink / raw)
To: Javier Martinez Canillas, simona, airlied, maarten.lankhorst,
mripard
Cc: dri-devel
Hi Javier
Am 23.03.25 um 11:57 schrieb Javier Martinez Canillas:
> Thomas Zimmermann <tzimmermann@suse.de> writes:
>
>> Merge the connector functions of ofdrm and simpledrm. Replace the
>> code in each driver with the shared helpers. Set up callbacks with
>> initializer macros.
>>
>> No effective code changes. The sysfb connector only returns the
>> preconfigured display mode.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> ---
> ...
>
>> +#define DRM_SYSFB_CONNECTOR_FUNCS \
>> + .reset = drm_atomic_helper_connector_reset, \
>> + .fill_modes = drm_helper_probe_single_connector_modes, \
>> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, \
>> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state
>> +
>> /*
> ...
>
>> static const struct drm_connector_funcs ofdrm_connector_funcs = {
>> - .reset = drm_atomic_helper_connector_reset,
>> - .fill_modes = drm_helper_probe_single_connector_modes,
>> + DRM_SYSFB_CONNECTOR_FUNCS,
>> .destroy = drm_connector_cleanup,
> Why not include the .destroy callback in DRM_SYSFB_CONNECTOR_FUNCS ?
These sysfb helpers provide functionality to operate on the output
(damage handling, etc).
The destroy callback depends on the way the mode-setting pipeline is
organized. The driver controls this. It might wants to allocated the
connector separately or use a container structure (e.g., struct
ofdrm_connector) that needs separate cleanup. Hence the driver has to
control the destroy callback. That argument goes for all the other
elements of the pipeline.
Best regards
Thomas
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 08/18] drm/sysfb: Merge connector functions
2025-03-24 7:37 ` Thomas Zimmermann
@ 2025-03-24 8:53 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-24 8:53 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard; +Cc: dri-devel
Thomas Zimmermann <tzimmermann@suse.de> writes:
Hello Thomas,
> Hi Javier
>
> Am 23.03.25 um 11:57 schrieb Javier Martinez Canillas:
>> Thomas Zimmermann <tzimmermann@suse.de> writes:
>>
>>> Merge the connector functions of ofdrm and simpledrm. Replace the
>>> code in each driver with the shared helpers. Set up callbacks with
>>> initializer macros.
>>>
>>> No effective code changes. The sysfb connector only returns the
>>> preconfigured display mode.
>>>
>>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>>> ---
>> ...
>>
>>> +#define DRM_SYSFB_CONNECTOR_FUNCS \
>>> + .reset = drm_atomic_helper_connector_reset, \
>>> + .fill_modes = drm_helper_probe_single_connector_modes, \
>>> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, \
>>> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state
>>> +
>>> /*
>> ...
>>
>>> static const struct drm_connector_funcs ofdrm_connector_funcs = {
>>> - .reset = drm_atomic_helper_connector_reset,
>>> - .fill_modes = drm_helper_probe_single_connector_modes,
>>> + DRM_SYSFB_CONNECTOR_FUNCS,
>>> .destroy = drm_connector_cleanup,
>> Why not include the .destroy callback in DRM_SYSFB_CONNECTOR_FUNCS ?
>
> These sysfb helpers provide functionality to operate on the output
> (damage handling, etc).
>
> The destroy callback depends on the way the mode-setting pipeline is
> organized. The driver controls this. It might wants to allocated the
> connector separately or use a container structure (e.g., struct
> ofdrm_connector) that needs separate cleanup. Hence the driver has to
> control the destroy callback. That argument goes for all the other
> elements of the pipeline.
>
Thanks for the explanation. Makes sense.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 09/18] drm/sysfb: Maintain CRTC state in struct drm_sysfb_crtc_state
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (7 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 08/18] drm/sysfb: Merge connector functions Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-31 8:08 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 10/18] drm/sysfb: Merge CRTC functions Thomas Zimmermann
` (9 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Move ofdrm's struct ofdrm_crtc_state plus functions to sysfb
helpers and rename everything to drm_sysfb_crtc_state.
The sysfb CRTC state is a regular CRTC state with information on
the primary plane's color format, as required for color management.
Helpers for sysfb planes will later set this up automatically.
In ofdrm and simpledrm, replace existing code with the new helpers.
Ofdrm continues to use the CRTC state for color management. This
has no effect on simpledrm.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 59 ++++++++++++++++++
drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 29 +++++++++
drivers/gpu/drm/sysfb/ofdrm.c | 76 ++----------------------
drivers/gpu/drm/sysfb/simpledrm.c | 6 +-
4 files changed, 95 insertions(+), 75 deletions(-)
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
index 355e025c7c62..368061b6f514 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
@@ -1,7 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/export.h>
+#include <linux/slab.h>
#include <linux/module.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "drm_sysfb_helper.h"
@@ -33,6 +37,61 @@ struct drm_display_mode drm_sysfb_mode(unsigned int width,
}
EXPORT_SYMBOL(drm_sysfb_mode);
+/*
+ * CRTC
+ */
+
+static void drm_sysfb_crtc_state_destroy(struct drm_sysfb_crtc_state *sysfb_crtc_state)
+{
+ __drm_atomic_helper_crtc_destroy_state(&sysfb_crtc_state->base);
+
+ kfree(sysfb_crtc_state);
+}
+
+void drm_sysfb_crtc_reset(struct drm_crtc *crtc)
+{
+ struct drm_sysfb_crtc_state *sysfb_crtc_state;
+
+ if (crtc->state)
+ drm_sysfb_crtc_state_destroy(to_drm_sysfb_crtc_state(crtc->state));
+
+ sysfb_crtc_state = kzalloc(sizeof(*sysfb_crtc_state), GFP_KERNEL);
+ if (sysfb_crtc_state)
+ __drm_atomic_helper_crtc_reset(crtc, &sysfb_crtc_state->base);
+ else
+ __drm_atomic_helper_crtc_reset(crtc, NULL);
+}
+EXPORT_SYMBOL(drm_sysfb_crtc_reset);
+
+struct drm_crtc_state *drm_sysfb_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct drm_sysfb_crtc_state *new_sysfb_crtc_state;
+ struct drm_sysfb_crtc_state *sysfb_crtc_state;
+
+ if (drm_WARN_ON(dev, !crtc_state))
+ return NULL;
+
+ new_sysfb_crtc_state = kzalloc(sizeof(*new_sysfb_crtc_state), GFP_KERNEL);
+ if (!new_sysfb_crtc_state)
+ return NULL;
+
+ sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state);
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &new_sysfb_crtc_state->base);
+ new_sysfb_crtc_state->format = sysfb_crtc_state->format;
+
+ return &new_sysfb_crtc_state->base;
+}
+EXPORT_SYMBOL(drm_sysfb_crtc_atomic_duplicate_state);
+
+void drm_sysfb_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
+{
+ drm_sysfb_crtc_state_destroy(to_drm_sysfb_crtc_state(crtc_state));
+}
+EXPORT_SYMBOL(drm_sysfb_crtc_atomic_destroy_state);
+
/*
* Connector
*/
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
index 7e3fe9fa5cff..91da27405a46 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -6,6 +6,7 @@
#include <linux/container_of.h>
#include <linux/iosys-map.h>
+#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_modes.h>
@@ -37,6 +38,34 @@ static inline struct drm_sysfb_device *to_drm_sysfb_device(struct drm_device *de
return container_of(dev, struct drm_sysfb_device, dev);
}
+/*
+ * CRTC
+ */
+
+struct drm_sysfb_crtc_state {
+ struct drm_crtc_state base;
+
+ /* Primary-plane format; required for color mgmt. */
+ const struct drm_format_info *format;
+};
+
+static inline struct drm_sysfb_crtc_state *
+to_drm_sysfb_crtc_state(struct drm_crtc_state *base)
+{
+ return container_of(base, struct drm_sysfb_crtc_state, base);
+}
+
+void drm_sysfb_crtc_reset(struct drm_crtc *crtc);
+struct drm_crtc_state *drm_sysfb_crtc_atomic_duplicate_state(struct drm_crtc *crtc);
+void drm_sysfb_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state);
+
+#define DRM_SYSFB_CRTC_FUNCS \
+ .reset = drm_sysfb_crtc_reset, \
+ .set_config = drm_atomic_helper_set_config, \
+ .page_flip = drm_atomic_helper_page_flip, \
+ .atomic_duplicate_state = drm_sysfb_crtc_atomic_duplicate_state, \
+ .atomic_destroy_state = drm_sysfb_crtc_atomic_destroy_state
+
/*
* Connector
*/
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index 85db7441d1bf..faaf35ba17f3 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -725,24 +725,6 @@ static void ofdrm_device_set_gamma(struct ofdrm_device *odev,
* Modesetting
*/
-struct ofdrm_crtc_state {
- struct drm_crtc_state base;
-
- /* Primary-plane format; required for color mgmt. */
- const struct drm_format_info *format;
-};
-
-static struct ofdrm_crtc_state *to_ofdrm_crtc_state(struct drm_crtc_state *base)
-{
- return container_of(base, struct ofdrm_crtc_state, base);
-}
-
-static void ofdrm_crtc_state_destroy(struct ofdrm_crtc_state *ofdrm_crtc_state)
-{
- __drm_atomic_helper_crtc_destroy_state(&ofdrm_crtc_state->base);
- kfree(ofdrm_crtc_state);
-}
-
static const uint64_t ofdrm_primary_plane_format_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
@@ -759,7 +741,7 @@ static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
struct drm_framebuffer *new_fb = new_plane_state->fb;
struct drm_crtc *new_crtc = new_plane_state->crtc;
struct drm_crtc_state *new_crtc_state = NULL;
- struct ofdrm_crtc_state *new_ofdrm_crtc_state;
+ struct drm_sysfb_crtc_state *new_sysfb_crtc_state;
int ret;
if (new_crtc)
@@ -786,8 +768,8 @@ static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
- new_ofdrm_crtc_state = to_ofdrm_crtc_state(new_crtc_state);
- new_ofdrm_crtc_state->format = new_fb->format;
+ new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state);
+ new_sysfb_crtc_state->format = new_fb->format;
return 0;
}
@@ -920,10 +902,10 @@ static void ofdrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_ato
{
struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev);
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
- struct ofdrm_crtc_state *ofdrm_crtc_state = to_ofdrm_crtc_state(crtc_state);
+ struct drm_sysfb_crtc_state *sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state);
if (crtc_state->enable && crtc_state->color_mgmt_changed) {
- const struct drm_format_info *format = ofdrm_crtc_state->format;
+ const struct drm_format_info *format = sysfb_crtc_state->format;
if (crtc_state->gamma_lut)
ofdrm_device_set_gamma(odev, format, crtc_state->gamma_lut->data);
@@ -943,55 +925,9 @@ static const struct drm_crtc_helper_funcs ofdrm_crtc_helper_funcs = {
.atomic_flush = ofdrm_crtc_helper_atomic_flush,
};
-static void ofdrm_crtc_reset(struct drm_crtc *crtc)
-{
- struct ofdrm_crtc_state *ofdrm_crtc_state =
- kzalloc(sizeof(*ofdrm_crtc_state), GFP_KERNEL);
-
- if (crtc->state)
- ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc->state));
-
- if (ofdrm_crtc_state)
- __drm_atomic_helper_crtc_reset(crtc, &ofdrm_crtc_state->base);
- else
- __drm_atomic_helper_crtc_reset(crtc, NULL);
-}
-
-static struct drm_crtc_state *ofdrm_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_crtc_state *crtc_state = crtc->state;
- struct ofdrm_crtc_state *new_ofdrm_crtc_state;
- struct ofdrm_crtc_state *ofdrm_crtc_state;
-
- if (drm_WARN_ON(dev, !crtc_state))
- return NULL;
-
- new_ofdrm_crtc_state = kzalloc(sizeof(*new_ofdrm_crtc_state), GFP_KERNEL);
- if (!new_ofdrm_crtc_state)
- return NULL;
-
- ofdrm_crtc_state = to_ofdrm_crtc_state(crtc_state);
-
- __drm_atomic_helper_crtc_duplicate_state(crtc, &new_ofdrm_crtc_state->base);
- new_ofdrm_crtc_state->format = ofdrm_crtc_state->format;
-
- return &new_ofdrm_crtc_state->base;
-}
-
-static void ofdrm_crtc_atomic_destroy_state(struct drm_crtc *crtc,
- struct drm_crtc_state *crtc_state)
-{
- ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc_state));
-}
-
static const struct drm_crtc_funcs ofdrm_crtc_funcs = {
- .reset = ofdrm_crtc_reset,
+ DRM_SYSFB_CRTC_FUNCS,
.destroy = drm_crtc_cleanup,
- .set_config = drm_atomic_helper_set_config,
- .page_flip = drm_atomic_helper_page_flip,
- .atomic_duplicate_state = ofdrm_crtc_atomic_duplicate_state,
- .atomic_destroy_state = ofdrm_crtc_atomic_destroy_state,
};
static const struct drm_encoder_funcs ofdrm_encoder_funcs = {
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index 6d76d125d126..986177e4a0f0 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -715,12 +715,8 @@ static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = {
};
static const struct drm_crtc_funcs simpledrm_crtc_funcs = {
- .reset = drm_atomic_helper_crtc_reset,
+ DRM_SYSFB_CRTC_FUNCS,
.destroy = drm_crtc_cleanup,
- .set_config = drm_atomic_helper_set_config,
- .page_flip = drm_atomic_helper_page_flip,
- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
};
static const struct drm_encoder_funcs simpledrm_encoder_funcs = {
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 09/18] drm/sysfb: Maintain CRTC state in struct drm_sysfb_crtc_state
2025-03-19 7:45 ` [PATCH 09/18] drm/sysfb: Maintain CRTC state in struct drm_sysfb_crtc_state Thomas Zimmermann
@ 2025-03-31 8:08 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-31 8:08 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Move ofdrm's struct ofdrm_crtc_state plus functions to sysfb
> helpers and rename everything to drm_sysfb_crtc_state.
>
> The sysfb CRTC state is a regular CRTC state with information on
> the primary plane's color format, as required for color management.
> Helpers for sysfb planes will later set this up automatically.
>
> In ofdrm and simpledrm, replace existing code with the new helpers.
> Ofdrm continues to use the CRTC state for color management. This
> has no effect on simpledrm.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 10/18] drm/sysfb: Merge CRTC functions
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (8 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 09/18] drm/sysfb: Maintain CRTC state in struct drm_sysfb_crtc_state Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-31 9:00 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 11/18] drm/sysfb: Merge primary-plane functions Thomas Zimmermann
` (8 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Merge the CRTC functions of ofdrm and simpledrm. Replace the code
in each driver with the shared helpers. Set up callbacks with
initializer macros.
Ofdrm supports a gamma LUT, while simpledrm does not. So far ofdrm's
LUT size has been hard-coded in the driver CRTC's atomic_check helper.
Now pass the size of the LUT to the sysfb device. Ofdrm's custom
atomic_flush is still required to apply changes to the LUT. Simpledrm
passes a LUT size of 0, which disables the gamma LUT.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 40 ++++++++++++++++++
drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 9 ++++
drivers/gpu/drm/sysfb/ofdrm.c | 53 ++++--------------------
drivers/gpu/drm/sysfb/simpledrm.c | 17 +-------
4 files changed, 57 insertions(+), 62 deletions(-)
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
index 368061b6f514..ed9139f56e59 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
@@ -4,6 +4,8 @@
#include <linux/slab.h>
#include <linux/module.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -48,6 +50,44 @@ static void drm_sysfb_crtc_state_destroy(struct drm_sysfb_crtc_state *sysfb_crtc
kfree(sysfb_crtc_state);
}
+enum drm_mode_status drm_sysfb_crtc_helper_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
+{
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(crtc->dev);
+
+ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sysfb->fb_mode);
+}
+EXPORT_SYMBOL(drm_sysfb_crtc_helper_mode_valid);
+
+int drm_sysfb_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ int ret;
+
+ if (!new_crtc_state->enable)
+ return 0;
+
+ ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
+ if (ret)
+ return ret;
+
+ if (new_crtc_state->color_mgmt_changed) {
+ const size_t gamma_lut_length =
+ sysfb->fb_gamma_lut_size * sizeof(struct drm_color_lut);
+ const struct drm_property_blob *gamma_lut = new_crtc_state->gamma_lut;
+
+ if (gamma_lut && (gamma_lut->length != gamma_lut_length)) {
+ drm_dbg(dev, "Incorrect gamma_lut length %zu\n", gamma_lut->length);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_sysfb_crtc_helper_atomic_check);
+
void drm_sysfb_crtc_reset(struct drm_crtc *crtc)
{
struct drm_sysfb_crtc_state *sysfb_crtc_state;
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
index 91da27405a46..c8e5ac6b9b63 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -28,6 +28,7 @@ struct drm_sysfb_device {
struct drm_display_mode fb_mode;
const struct drm_format_info *fb_format;
unsigned int fb_pitch;
+ unsigned int fb_gamma_lut_size;
/* hardware-framebuffer kernel address */
struct iosys_map fb_addr;
@@ -55,6 +56,14 @@ to_drm_sysfb_crtc_state(struct drm_crtc_state *base)
return container_of(base, struct drm_sysfb_crtc_state, base);
}
+enum drm_mode_status drm_sysfb_crtc_helper_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode);
+int drm_sysfb_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state);
+
+#define DRM_SYSFB_CRTC_HELPER_FUNCS \
+ .mode_valid = drm_sysfb_crtc_helper_mode_valid, \
+ .atomic_check = drm_sysfb_crtc_helper_atomic_check
+
void drm_sysfb_crtc_reset(struct drm_crtc *crtc);
struct drm_crtc_state *drm_sysfb_crtc_atomic_duplicate_state(struct drm_crtc *crtc);
void drm_sysfb_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index faaf35ba17f3..29dbb69dd7ac 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -862,42 +862,6 @@ static const struct drm_plane_funcs ofdrm_primary_plane_funcs = {
DRM_GEM_SHADOW_PLANE_FUNCS,
};
-static enum drm_mode_status ofdrm_crtc_helper_mode_valid(struct drm_crtc *crtc,
- const struct drm_display_mode *mode)
-{
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(crtc->dev);
-
- return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sysfb->fb_mode);
-}
-
-static int ofdrm_crtc_helper_atomic_check(struct drm_crtc *crtc,
- struct drm_atomic_state *new_state)
-{
- static const size_t gamma_lut_length = OFDRM_GAMMA_LUT_SIZE * sizeof(struct drm_color_lut);
-
- struct drm_device *dev = crtc->dev;
- struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
- int ret;
-
- if (!new_crtc_state->enable)
- return 0;
-
- ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
- if (ret)
- return ret;
-
- if (new_crtc_state->color_mgmt_changed) {
- struct drm_property_blob *gamma_lut = new_crtc_state->gamma_lut;
-
- if (gamma_lut && (gamma_lut->length != gamma_lut_length)) {
- drm_dbg(dev, "Incorrect gamma_lut length %zu\n", gamma_lut->length);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
static void ofdrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state)
{
struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev);
@@ -914,14 +878,8 @@ static void ofdrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_ato
}
}
-/*
- * The CRTC is always enabled. Screen updates are performed by
- * the primary plane's atomic_update function. Disabling clears
- * the screen in the primary plane's atomic_disable function.
- */
static const struct drm_crtc_helper_funcs ofdrm_crtc_helper_funcs = {
- .mode_valid = ofdrm_crtc_helper_mode_valid,
- .atomic_check = ofdrm_crtc_helper_atomic_check,
+ DRM_SYSFB_CRTC_HELPER_FUNCS,
.atomic_flush = ofdrm_crtc_helper_atomic_flush,
};
@@ -1163,6 +1121,8 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
sysfb->fb_format = format;
sysfb->fb_pitch = linebytes;
+ if (odev->cmap_base)
+ sysfb->fb_gamma_lut_size = OFDRM_GAMMA_LUT_SIZE;
drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sysfb->fb_mode));
drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n",
@@ -1211,9 +1171,10 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
return ERR_PTR(ret);
drm_crtc_helper_add(crtc, &ofdrm_crtc_helper_funcs);
- if (odev->cmap_base) {
- drm_mode_crtc_set_gamma_size(crtc, OFDRM_GAMMA_LUT_SIZE);
- drm_crtc_enable_color_mgmt(crtc, 0, false, OFDRM_GAMMA_LUT_SIZE);
+ if (sysfb->fb_gamma_lut_size) {
+ ret = drm_mode_crtc_set_gamma_size(crtc, sysfb->fb_gamma_lut_size);
+ if (!ret)
+ drm_crtc_enable_color_mgmt(crtc, 0, false, sysfb->fb_gamma_lut_size);
}
/* Encoder */
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index 986177e4a0f0..9616e67ea42c 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -14,7 +14,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_connector.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
@@ -696,22 +695,8 @@ static const struct drm_plane_funcs simpledrm_primary_plane_funcs = {
DRM_GEM_SHADOW_PLANE_FUNCS,
};
-static enum drm_mode_status simpledrm_crtc_helper_mode_valid(struct drm_crtc *crtc,
- const struct drm_display_mode *mode)
-{
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(crtc->dev);
-
- return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sysfb->fb_mode);
-}
-
-/*
- * The CRTC is always enabled. Screen updates are performed by
- * the primary plane's atomic_update function. Disabling clears
- * the screen in the primary plane's atomic_disable function.
- */
static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = {
- .mode_valid = simpledrm_crtc_helper_mode_valid,
- .atomic_check = drm_crtc_helper_atomic_check,
+ DRM_SYSFB_CRTC_HELPER_FUNCS,
};
static const struct drm_crtc_funcs simpledrm_crtc_funcs = {
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 10/18] drm/sysfb: Merge CRTC functions
2025-03-19 7:45 ` [PATCH 10/18] drm/sysfb: Merge CRTC functions Thomas Zimmermann
@ 2025-03-31 9:00 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-31 9:00 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Merge the CRTC functions of ofdrm and simpledrm. Replace the code
> in each driver with the shared helpers. Set up callbacks with
> initializer macros.
>
> Ofdrm supports a gamma LUT, while simpledrm does not. So far ofdrm's
> LUT size has been hard-coded in the driver CRTC's atomic_check helper.
> Now pass the size of the LUT to the sysfb device. Ofdrm's custom
> atomic_flush is still required to apply changes to the LUT. Simpledrm
> passes a LUT size of 0, which disables the gamma LUT.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 11/18] drm/sysfb: Merge primary-plane functions
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (9 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 10/18] drm/sysfb: Merge CRTC functions Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-31 9:12 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support Thomas Zimmermann
` (7 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Merge the primary plane code of ofdrm and simpledrm. Replace the
plane implementation in each driver with the shared helpers. Set
up driver callbacks and format modifiers with initializer macros.
The plane code in ofdrm and simpledrm is very similar. Ofdrm has a
more sophisticated implementation of atomic_disable, which clears
individual scanlines. The code in simpledrm clears the whole buffer
at once. Take the ofdrm version.
Simpledrm supports get_scanout_buffer. Import it into the shared
helpers, which makes it available in ofdrm.
The supported formats are all native formats plus an optional enulated
XRGB8888 if that's not already a native format. Provide an initializer
macro that computes the size of the formats array.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 145 +++++++++++++++++++++++
drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 32 +++++
drivers/gpu/drm/sysfb/ofdrm.c | 134 +--------------------
drivers/gpu/drm/sysfb/simpledrm.c | 126 +-------------------
4 files changed, 187 insertions(+), 250 deletions(-)
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
index ed9139f56e59..b48e06b25305 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
@@ -7,6 +7,13 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_panic.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -39,6 +46,144 @@ struct drm_display_mode drm_sysfb_mode(unsigned int width,
}
EXPORT_SYMBOL(drm_sysfb_mode);
+/*
+ * Plane
+ */
+
+int drm_sysfb_plane_helper_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *new_state)
+{
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
+ struct drm_shadow_plane_state *new_shadow_plane_state =
+ to_drm_shadow_plane_state(new_plane_state);
+ struct drm_framebuffer *new_fb = new_plane_state->fb;
+ struct drm_crtc *new_crtc = new_plane_state->crtc;
+ struct drm_crtc_state *new_crtc_state = NULL;
+ struct drm_sysfb_crtc_state *new_sysfb_crtc_state;
+ int ret;
+
+ if (new_crtc)
+ new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
+
+ ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, false);
+ if (ret)
+ return ret;
+ else if (!new_plane_state->visible)
+ return 0;
+
+ if (new_fb->format != sysfb->fb_format) {
+ void *buf;
+
+ /* format conversion necessary; reserve buffer */
+ buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state,
+ sysfb->fb_pitch, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ }
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
+
+ new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state);
+ new_sysfb_crtc_state->format = new_fb->format;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_check);
+
+void drm_sysfb_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_framebuffer *fb = plane_state->fb;
+ unsigned int dst_pitch = sysfb->fb_pitch;
+ const struct drm_format_info *dst_format = sysfb->fb_format;
+ struct drm_atomic_helper_damage_iter iter;
+ struct drm_rect damage;
+ int ret, idx;
+
+ ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
+ if (ret)
+ return;
+
+ if (!drm_dev_enter(dev, &idx))
+ goto out_drm_gem_fb_end_cpu_access;
+
+ drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+ drm_atomic_for_each_plane_damage(&iter, &damage) {
+ struct iosys_map dst = sysfb->fb_addr;
+ struct drm_rect dst_clip = plane_state->dst;
+
+ if (!drm_rect_intersect(&dst_clip, &damage))
+ continue;
+
+ iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip));
+ drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb,
+ &damage, &shadow_plane_state->fmtcnv_state);
+ }
+
+ drm_dev_exit(idx);
+out_drm_gem_fb_end_cpu_access:
+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+}
+EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_update);
+
+void drm_sysfb_plane_helper_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
+ struct iosys_map dst = sysfb->fb_addr;
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
+ void __iomem *dst_vmap = dst.vaddr_iomem; /* TODO: Use mapping abstraction */
+ unsigned int dst_pitch = sysfb->fb_pitch;
+ const struct drm_format_info *dst_format = sysfb->fb_format;
+ struct drm_rect dst_clip;
+ unsigned long lines, linepixels, i;
+ int idx;
+
+ drm_rect_init(&dst_clip,
+ plane_state->src_x >> 16, plane_state->src_y >> 16,
+ plane_state->src_w >> 16, plane_state->src_h >> 16);
+
+ lines = drm_rect_height(&dst_clip);
+ linepixels = drm_rect_width(&dst_clip);
+
+ if (!drm_dev_enter(dev, &idx))
+ return;
+
+ /* Clear buffer to black if disabled */
+ dst_vmap += drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip);
+ for (i = 0; i < lines; ++i) {
+ memset_io(dst_vmap, 0, linepixels * dst_format->cpp[0]);
+ dst_vmap += dst_pitch;
+ }
+
+ drm_dev_exit(idx);
+}
+EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_disable);
+
+int drm_sysfb_plane_helper_get_scanout_buffer(struct drm_plane *plane,
+ struct drm_scanout_buffer *sb)
+{
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
+
+ sb->width = sysfb->fb_mode.hdisplay;
+ sb->height = sysfb->fb_mode.vdisplay;
+ sb->format = sysfb->fb_format;
+ sb->pitch[0] = sysfb->fb_pitch;
+ sb->map[0] = sysfb->fb_addr;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_sysfb_plane_helper_get_scanout_buffer);
+
/*
* CRTC
*/
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
index c8e5ac6b9b63..45e396bf74b7 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -39,6 +39,38 @@ static inline struct drm_sysfb_device *to_drm_sysfb_device(struct drm_device *de
return container_of(dev, struct drm_sysfb_device, dev);
}
+/*
+ * Plane
+ */
+
+int drm_sysfb_plane_helper_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *new_state);
+void drm_sysfb_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *state);
+void drm_sysfb_plane_helper_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *state);
+int drm_sysfb_plane_helper_get_scanout_buffer(struct drm_plane *plane,
+ struct drm_scanout_buffer *sb);
+
+#define DRM_SYSFB_PLANE_NFORMATS(_num_native) \
+ ((_num_native) + 1)
+
+#define DRM_SYSFB_PLANE_FORMAT_MODIFIERS \
+ DRM_FORMAT_MOD_LINEAR, \
+ DRM_FORMAT_MOD_INVALID
+
+#define DRM_SYSFB_PLANE_HELPER_FUNCS \
+ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, \
+ .atomic_check = drm_sysfb_plane_helper_atomic_check, \
+ .atomic_update = drm_sysfb_plane_helper_atomic_update, \
+ .atomic_disable = drm_sysfb_plane_helper_atomic_disable, \
+ .get_scanout_buffer = drm_sysfb_plane_helper_get_scanout_buffer
+
+#define DRM_SYSFB_PLANE_FUNCS \
+ .update_plane = drm_atomic_helper_update_plane, \
+ .disable_plane = drm_atomic_helper_disable_plane, \
+ DRM_GEM_SHADOW_PLANE_FUNCS
+
/*
* CRTC
*/
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index 29dbb69dd7ac..71e661ba9329 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -299,7 +299,7 @@ struct ofdrm_device {
void __iomem *cmap_base;
/* modesetting */
- uint32_t formats[8];
+ u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
struct drm_plane primary_plane;
struct drm_crtc crtc;
struct drm_encoder encoder;
@@ -725,141 +725,17 @@ static void ofdrm_device_set_gamma(struct ofdrm_device *odev,
* Modesetting
*/
-static const uint64_t ofdrm_primary_plane_format_modifiers[] = {
- DRM_FORMAT_MOD_LINEAR,
- DRM_FORMAT_MOD_INVALID
+static const u64 ofdrm_primary_plane_format_modifiers[] = {
+ DRM_SYSFB_PLANE_FORMAT_MODIFIERS,
};
-static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
- struct drm_atomic_state *new_state)
-{
- struct drm_device *dev = plane->dev;
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
- struct drm_shadow_plane_state *new_shadow_plane_state =
- to_drm_shadow_plane_state(new_plane_state);
- struct drm_framebuffer *new_fb = new_plane_state->fb;
- struct drm_crtc *new_crtc = new_plane_state->crtc;
- struct drm_crtc_state *new_crtc_state = NULL;
- struct drm_sysfb_crtc_state *new_sysfb_crtc_state;
- int ret;
-
- if (new_crtc)
- new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
-
- ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- false, false);
- if (ret)
- return ret;
- else if (!new_plane_state->visible)
- return 0;
-
- if (new_fb->format != sysfb->fb_format) {
- void *buf;
-
- /* format conversion necessary; reserve buffer */
- buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state,
- sysfb->fb_pitch, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- }
-
- new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
-
- new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state);
- new_sysfb_crtc_state->format = new_fb->format;
-
- return 0;
-}
-
-static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_device *dev = plane->dev;
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
- struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
- struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
- struct drm_framebuffer *fb = plane_state->fb;
- unsigned int dst_pitch = sysfb->fb_pitch;
- const struct drm_format_info *dst_format = sysfb->fb_format;
- struct drm_atomic_helper_damage_iter iter;
- struct drm_rect damage;
- int ret, idx;
-
- ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
- if (ret)
- return;
-
- if (!drm_dev_enter(dev, &idx))
- goto out_drm_gem_fb_end_cpu_access;
-
- drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
- drm_atomic_for_each_plane_damage(&iter, &damage) {
- struct iosys_map dst = sysfb->fb_addr;
- struct drm_rect dst_clip = plane_state->dst;
-
- if (!drm_rect_intersect(&dst_clip, &damage))
- continue;
-
- iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip));
- drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb,
- &damage, &shadow_plane_state->fmtcnv_state);
- }
-
- drm_dev_exit(idx);
-out_drm_gem_fb_end_cpu_access:
- drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
-}
-
-static void ofdrm_primary_plane_helper_atomic_disable(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_device *dev = plane->dev;
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
- struct iosys_map dst = sysfb->fb_addr;
- struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
- void __iomem *dst_vmap = dst.vaddr_iomem; /* TODO: Use mapping abstraction */
- unsigned int dst_pitch = sysfb->fb_pitch;
- const struct drm_format_info *dst_format = sysfb->fb_format;
- struct drm_rect dst_clip;
- unsigned long lines, linepixels, i;
- int idx;
-
- drm_rect_init(&dst_clip,
- plane_state->src_x >> 16, plane_state->src_y >> 16,
- plane_state->src_w >> 16, plane_state->src_h >> 16);
-
- lines = drm_rect_height(&dst_clip);
- linepixels = drm_rect_width(&dst_clip);
-
- if (!drm_dev_enter(dev, &idx))
- return;
-
- /* Clear buffer to black if disabled */
- dst_vmap += drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip);
- for (i = 0; i < lines; ++i) {
- memset_io(dst_vmap, 0, linepixels * dst_format->cpp[0]);
- dst_vmap += dst_pitch;
- }
-
- drm_dev_exit(idx);
-}
-
static const struct drm_plane_helper_funcs ofdrm_primary_plane_helper_funcs = {
- DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
- .atomic_check = ofdrm_primary_plane_helper_atomic_check,
- .atomic_update = ofdrm_primary_plane_helper_atomic_update,
- .atomic_disable = ofdrm_primary_plane_helper_atomic_disable,
+ DRM_SYSFB_PLANE_HELPER_FUNCS,
};
static const struct drm_plane_funcs ofdrm_primary_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
+ DRM_SYSFB_PLANE_FUNCS,
.destroy = drm_plane_cleanup,
- DRM_GEM_SHADOW_PLANE_FUNCS,
};
static void ofdrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state)
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index 9616e67ea42c..cfb1fe07704d 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -25,7 +25,6 @@
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper_vtables.h>
-#include <drm/drm_panic.h>
#include <drm/drm_probe_helper.h>
#include "drm_sysfb_helper.h"
@@ -238,7 +237,7 @@ struct simpledrm_device {
#endif
/* modesetting */
- uint32_t formats[8];
+ u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
struct drm_plane primary_plane;
struct drm_crtc crtc;
struct drm_encoder encoder;
@@ -567,132 +566,17 @@ static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev)
* Modesetting
*/
-static const uint64_t simpledrm_primary_plane_format_modifiers[] = {
- DRM_FORMAT_MOD_LINEAR,
- DRM_FORMAT_MOD_INVALID
+static const u64 simpledrm_primary_plane_format_modifiers[] = {
+ DRM_SYSFB_PLANE_FORMAT_MODIFIERS,
};
-static int simpledrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
- struct drm_shadow_plane_state *new_shadow_plane_state =
- to_drm_shadow_plane_state(new_plane_state);
- struct drm_framebuffer *new_fb = new_plane_state->fb;
- struct drm_crtc *new_crtc = new_plane_state->crtc;
- struct drm_crtc_state *new_crtc_state = NULL;
- struct drm_device *dev = plane->dev;
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
- int ret;
-
- if (new_crtc)
- new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
-
- ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- false, false);
- if (ret)
- return ret;
- else if (!new_plane_state->visible)
- return 0;
-
- if (new_fb->format != sysfb->fb_format) {
- void *buf;
-
- /* format conversion necessary; reserve buffer */
- buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state,
- sysfb->fb_pitch, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
- struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
- struct drm_framebuffer *fb = plane_state->fb;
- struct drm_device *dev = plane->dev;
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
- struct drm_atomic_helper_damage_iter iter;
- struct drm_rect damage;
- int ret, idx;
-
- ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
- if (ret)
- return;
-
- if (!drm_dev_enter(dev, &idx))
- goto out_drm_gem_fb_end_cpu_access;
-
- drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
- drm_atomic_for_each_plane_damage(&iter, &damage) {
- struct drm_rect dst_clip = plane_state->dst;
- struct iosys_map dst = sysfb->fb_addr;
-
- if (!drm_rect_intersect(&dst_clip, &damage))
- continue;
-
- iosys_map_incr(&dst, drm_fb_clip_offset(sysfb->fb_pitch, sysfb->fb_format,
- &dst_clip));
- drm_fb_blit(&dst, &sysfb->fb_pitch, sysfb->fb_format->format,
- shadow_plane_state->data,
- fb, &damage, &shadow_plane_state->fmtcnv_state);
- }
-
- drm_dev_exit(idx);
-out_drm_gem_fb_end_cpu_access:
- drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
-}
-
-static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plane,
- struct drm_atomic_state *state)
-{
- struct drm_device *dev = plane->dev;
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
- int idx;
-
- if (!drm_dev_enter(dev, &idx))
- return;
-
- /* Clear screen to black if disabled */
- iosys_map_memset(&sysfb->fb_addr, 0, 0, sysfb->fb_pitch * sysfb->fb_mode.vdisplay);
-
- drm_dev_exit(idx);
-}
-
-static int simpledrm_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane,
- struct drm_scanout_buffer *sb)
-{
- struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
-
- sb->width = sysfb->fb_mode.hdisplay;
- sb->height = sysfb->fb_mode.vdisplay;
- sb->format = sysfb->fb_format;
- sb->pitch[0] = sysfb->fb_pitch;
- sb->map[0] = sysfb->fb_addr;
-
- return 0;
-}
-
static const struct drm_plane_helper_funcs simpledrm_primary_plane_helper_funcs = {
- DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
- .atomic_check = simpledrm_primary_plane_helper_atomic_check,
- .atomic_update = simpledrm_primary_plane_helper_atomic_update,
- .atomic_disable = simpledrm_primary_plane_helper_atomic_disable,
- .get_scanout_buffer = simpledrm_primary_plane_helper_get_scanout_buffer,
+ DRM_SYSFB_PLANE_HELPER_FUNCS,
};
static const struct drm_plane_funcs simpledrm_primary_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
+ DRM_SYSFB_PLANE_FUNCS,
.destroy = drm_plane_cleanup,
- DRM_GEM_SHADOW_PLANE_FUNCS,
};
static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = {
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 11/18] drm/sysfb: Merge primary-plane functions
2025-03-19 7:45 ` [PATCH 11/18] drm/sysfb: Merge primary-plane functions Thomas Zimmermann
@ 2025-03-31 9:12 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-31 9:12 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Merge the primary plane code of ofdrm and simpledrm. Replace the
> plane implementation in each driver with the shared helpers. Set
> up driver callbacks and format modifiers with initializer macros.
>
> The plane code in ofdrm and simpledrm is very similar. Ofdrm has a
> more sophisticated implementation of atomic_disable, which clears
> individual scanlines. The code in simpledrm clears the whole buffer
> at once. Take the ofdrm version.
>
> Simpledrm supports get_scanout_buffer. Import it into the shared
> helpers, which makes it available in ofdrm.
>
> The supported formats are all native formats plus an optional enulated
> XRGB8888 if that's not already a native format. Provide an initializer
> macro that computes the size of the formats array.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (10 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 11/18] drm/sysfb: Merge primary-plane functions Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-20 12:50 ` Jani Nikula
2025-03-31 9:15 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 13/18] firmware: sysfb: Move bpp-depth calculation into screen_info helper Thomas Zimmermann
` (6 subsequent siblings)
18 siblings, 2 replies; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Add EDID support to sysfb connector helpers. Read the EDID property
from the OF node in ofdrm. Without EDID, this does nothing.
Some systems with OF display, such as 32-bit PPC Macintoshs, provide
the system display's EDID data as node property in their DT. Exporting
this information allows compositors to implement correct DPI and
meaningful color management.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 29 ++++++++++++++++++++++++
drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 2 ++
drivers/gpu/drm/sysfb/ofdrm.c | 20 ++++++++++++++++
3 files changed, 51 insertions(+)
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
index b48e06b25305..cb65c618f8d3 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
@@ -9,6 +9,7 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
@@ -281,10 +282,38 @@ EXPORT_SYMBOL(drm_sysfb_crtc_atomic_destroy_state);
* Connector
*/
+static int drm_sysfb_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
+{
+ const u8 *edid = data;
+ size_t off = block * EDID_LENGTH;
+ size_t end = off + len;
+
+ if (!edid)
+ return -1;
+ if (end > EDID_LENGTH)
+ return -1;
+ memcpy(buf, &edid[off], len);
+
+ return 0;
+}
+
int drm_sysfb_connector_helper_get_modes(struct drm_connector *connector)
{
struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
+ const struct drm_edid *drm_edid;
+
+ if (sysfb->edid) {
+ drm_edid = drm_edid_read_custom(connector, drm_sysfb_get_edid_block,
+ (void *)sysfb->edid);
+ if (drm_edid) {
+ drm_edid_connector_update(connector, drm_edid);
+ drm_edid_free(drm_edid);
+ } else {
+ drm_edid_connector_update(connector, NULL);
+ }
+ }
+ /* Return the fixed mode even with EDID */
return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
}
EXPORT_SYMBOL(drm_sysfb_connector_helper_get_modes);
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
index 45e396bf74b7..3684bd0ef085 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -24,6 +24,8 @@ struct drm_display_mode drm_sysfb_mode(unsigned int width,
struct drm_sysfb_device {
struct drm_device dev;
+ const u8 *edid; /* can be NULL */
+
/* hardware settings */
struct drm_display_mode fb_mode;
const struct drm_format_info *fb_format;
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index 71e661ba9329..86c1a0c80ceb 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -12,6 +12,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
+#include <drm/drm_edid.h>
#include <drm/drm_fbdev_shmem.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_framebuffer.h>
@@ -227,6 +228,16 @@ static u64 display_get_address_of(struct drm_device *dev, struct device_node *of
return address;
}
+static const u8 *display_get_edid_of(struct drm_device *dev, struct device_node *of_node,
+ u8 buf[EDID_LENGTH])
+{
+ int ret = of_property_read_u8_array(of_node, "EDID", buf, EDID_LENGTH);
+
+ if (ret)
+ return NULL;
+ return buf;
+}
+
static bool is_avivo(u32 vendor, u32 device)
{
/* This will match most R5xx */
@@ -298,6 +309,8 @@ struct ofdrm_device {
/* colormap */
void __iomem *cmap_base;
+ u8 edid[EDID_LENGTH];
+
/* modesetting */
u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
struct drm_plane primary_plane;
@@ -840,6 +853,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
int width, height, depth, linebytes;
const struct drm_format_info *format;
u64 address;
+ const u8 *edid;
resource_size_t fb_size, fb_base, fb_pgbase, fb_pgsize;
struct resource *res, *mem;
void __iomem *screen_base;
@@ -989,6 +1003,9 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
}
}
+ /* EDID is optional */
+ edid = display_get_edid_of(dev, of_node, odev->edid);
+
/*
* Firmware framebuffer
*/
@@ -999,6 +1016,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
sysfb->fb_pitch = linebytes;
if (odev->cmap_base)
sysfb->fb_gamma_lut_size = OFDRM_GAMMA_LUT_SIZE;
+ sysfb->edid = edid;
drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sysfb->fb_mode));
drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n",
@@ -1072,6 +1090,8 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
drm_connector_set_panel_orientation_with_quirk(connector,
DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
width, height);
+ if (edid)
+ drm_connector_attach_edid_property(connector);
ret = drm_connector_attach_encoder(connector, encoder);
if (ret)
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support
2025-03-19 7:45 ` [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support Thomas Zimmermann
@ 2025-03-20 12:50 ` Jani Nikula
2025-03-20 13:08 ` Thomas Zimmermann
2025-03-31 9:15 ` Javier Martinez Canillas
1 sibling, 1 reply; 47+ messages in thread
From: Jani Nikula @ 2025-03-20 12:50 UTC (permalink / raw)
To: Thomas Zimmermann, javierm, simona, airlied, maarten.lankhorst,
mripard
Cc: dri-devel, Thomas Zimmermann
On Wed, 19 Mar 2025, Thomas Zimmermann <tzimmermann@suse.de> wrote:
> Add EDID support to sysfb connector helpers. Read the EDID property
> from the OF node in ofdrm. Without EDID, this does nothing.
>
> Some systems with OF display, such as 32-bit PPC Macintoshs, provide
> the system display's EDID data as node property in their DT. Exporting
> this information allows compositors to implement correct DPI and
> meaningful color management.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 29 ++++++++++++++++++++++++
> drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 2 ++
> drivers/gpu/drm/sysfb/ofdrm.c | 20 ++++++++++++++++
> 3 files changed, 51 insertions(+)
>
> diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
> index b48e06b25305..cb65c618f8d3 100644
> --- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
> +++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
> @@ -9,6 +9,7 @@
> #include <drm/drm_atomic_state_helper.h>
> #include <drm/drm_damage_helper.h>
> #include <drm/drm_drv.h>
> +#include <drm/drm_edid.h>
> #include <drm/drm_fourcc.h>
> #include <drm/drm_framebuffer.h>
> #include <drm/drm_gem_atomic_helper.h>
> @@ -281,10 +282,38 @@ EXPORT_SYMBOL(drm_sysfb_crtc_atomic_destroy_state);
> * Connector
> */
>
> +static int drm_sysfb_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
> +{
> + const u8 *edid = data;
> + size_t off = block * EDID_LENGTH;
> + size_t end = off + len;
> +
> + if (!edid)
> + return -1;
> + if (end > EDID_LENGTH)
> + return -1;
Nitpick, I guess -1 is used elsewhere, but I think I'd prefer actual
error codes even if they're not currently propagated. It's just cleaner.
> + memcpy(buf, &edid[off], len);
> +
> + return 0;
> +}
> +
> int drm_sysfb_connector_helper_get_modes(struct drm_connector *connector)
> {
> struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
> + const struct drm_edid *drm_edid;
> +
> + if (sysfb->edid) {
> + drm_edid = drm_edid_read_custom(connector, drm_sysfb_get_edid_block,
> + (void *)sysfb->edid);
Nitpick, the (void *) cast is superfluous.
> + if (drm_edid) {
> + drm_edid_connector_update(connector, drm_edid);
> + drm_edid_free(drm_edid);
> + } else {
> + drm_edid_connector_update(connector, NULL);
> + }
Nitpick, the above could just be
drm_edid_connector_update(connector, drm_edid);
drm_edid_free(drm_edid);
without the if.
Despite the nitpicks, overall LGTM.
BR,
Jani.
> + }
>
> + /* Return the fixed mode even with EDID */
> return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
> }
> EXPORT_SYMBOL(drm_sysfb_connector_helper_get_modes);
> diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
> index 45e396bf74b7..3684bd0ef085 100644
> --- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
> +++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
> @@ -24,6 +24,8 @@ struct drm_display_mode drm_sysfb_mode(unsigned int width,
> struct drm_sysfb_device {
> struct drm_device dev;
>
> + const u8 *edid; /* can be NULL */
> +
> /* hardware settings */
> struct drm_display_mode fb_mode;
> const struct drm_format_info *fb_format;
> diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
> index 71e661ba9329..86c1a0c80ceb 100644
> --- a/drivers/gpu/drm/sysfb/ofdrm.c
> +++ b/drivers/gpu/drm/sysfb/ofdrm.c
> @@ -12,6 +12,7 @@
> #include <drm/drm_damage_helper.h>
> #include <drm/drm_device.h>
> #include <drm/drm_drv.h>
> +#include <drm/drm_edid.h>
> #include <drm/drm_fbdev_shmem.h>
> #include <drm/drm_format_helper.h>
> #include <drm/drm_framebuffer.h>
> @@ -227,6 +228,16 @@ static u64 display_get_address_of(struct drm_device *dev, struct device_node *of
> return address;
> }
>
> +static const u8 *display_get_edid_of(struct drm_device *dev, struct device_node *of_node,
> + u8 buf[EDID_LENGTH])
> +{
> + int ret = of_property_read_u8_array(of_node, "EDID", buf, EDID_LENGTH);
> +
> + if (ret)
> + return NULL;
> + return buf;
> +}
> +
> static bool is_avivo(u32 vendor, u32 device)
> {
> /* This will match most R5xx */
> @@ -298,6 +309,8 @@ struct ofdrm_device {
> /* colormap */
> void __iomem *cmap_base;
>
> + u8 edid[EDID_LENGTH];
> +
> /* modesetting */
> u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
> struct drm_plane primary_plane;
> @@ -840,6 +853,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
> int width, height, depth, linebytes;
> const struct drm_format_info *format;
> u64 address;
> + const u8 *edid;
> resource_size_t fb_size, fb_base, fb_pgbase, fb_pgsize;
> struct resource *res, *mem;
> void __iomem *screen_base;
> @@ -989,6 +1003,9 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
> }
> }
>
> + /* EDID is optional */
> + edid = display_get_edid_of(dev, of_node, odev->edid);
> +
> /*
> * Firmware framebuffer
> */
> @@ -999,6 +1016,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
> sysfb->fb_pitch = linebytes;
> if (odev->cmap_base)
> sysfb->fb_gamma_lut_size = OFDRM_GAMMA_LUT_SIZE;
> + sysfb->edid = edid;
>
> drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sysfb->fb_mode));
> drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n",
> @@ -1072,6 +1090,8 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
> drm_connector_set_panel_orientation_with_quirk(connector,
> DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
> width, height);
> + if (edid)
> + drm_connector_attach_edid_property(connector);
>
> ret = drm_connector_attach_encoder(connector, encoder);
> if (ret)
--
Jani Nikula, Intel
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support
2025-03-20 12:50 ` Jani Nikula
@ 2025-03-20 13:08 ` Thomas Zimmermann
2025-03-31 9:26 ` Maxime Ripard
0 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-20 13:08 UTC (permalink / raw)
To: Jani Nikula, javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel
Hi
Am 20.03.25 um 13:50 schrieb Jani Nikula:
> On Wed, 19 Mar 2025, Thomas Zimmermann <tzimmermann@suse.de> wrote:
>> Add EDID support to sysfb connector helpers. Read the EDID property
>> from the OF node in ofdrm. Without EDID, this does nothing.
>>
>> Some systems with OF display, such as 32-bit PPC Macintoshs, provide
>> the system display's EDID data as node property in their DT. Exporting
>> this information allows compositors to implement correct DPI and
>> meaningful color management.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> ---
>> drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 29 ++++++++++++++++++++++++
>> drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 2 ++
>> drivers/gpu/drm/sysfb/ofdrm.c | 20 ++++++++++++++++
>> 3 files changed, 51 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
>> index b48e06b25305..cb65c618f8d3 100644
>> --- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
>> +++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.c
>> @@ -9,6 +9,7 @@
>> #include <drm/drm_atomic_state_helper.h>
>> #include <drm/drm_damage_helper.h>
>> #include <drm/drm_drv.h>
>> +#include <drm/drm_edid.h>
>> #include <drm/drm_fourcc.h>
>> #include <drm/drm_framebuffer.h>
>> #include <drm/drm_gem_atomic_helper.h>
>> @@ -281,10 +282,38 @@ EXPORT_SYMBOL(drm_sysfb_crtc_atomic_destroy_state);
>> * Connector
>> */
>>
>> +static int drm_sysfb_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
>> +{
>> + const u8 *edid = data;
>> + size_t off = block * EDID_LENGTH;
>> + size_t end = off + len;
>> +
>> + if (!edid)
>> + return -1;
>> + if (end > EDID_LENGTH)
>> + return -1;
> Nitpick, I guess -1 is used elsewhere, but I think I'd prefer actual
> error codes even if they're not currently propagated. It's just cleaner.
Sure. Somehow I was under the impression that errno codes wouldn't be
welcome here.
>
>> + memcpy(buf, &edid[off], len);
>> +
>> + return 0;
>> +}
>> +
>> int drm_sysfb_connector_helper_get_modes(struct drm_connector *connector)
>> {
>> struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
>> + const struct drm_edid *drm_edid;
>> +
>> + if (sysfb->edid) {
>> + drm_edid = drm_edid_read_custom(connector, drm_sysfb_get_edid_block,
>> + (void *)sysfb->edid);
> Nitpick, the (void *) cast is superfluous.
This is a const cast.
>
>> + if (drm_edid) {
>> + drm_edid_connector_update(connector, drm_edid);
>> + drm_edid_free(drm_edid);
>> + } else {
>> + drm_edid_connector_update(connector, NULL);
>> + }
> Nitpick, the above could just be
>
> drm_edid_connector_update(connector, drm_edid);
> drm_edid_free(drm_edid);
>
> without the if.
Make sense.
>
>
> Despite the nitpicks, overall LGTM.
Thanks for reviewing.
Since I have your attention and you're knowledgeable wrt EDID: byte 20
of the EDID header indicates the type of output (analog, HDMI, DP, etc).
I intent to use this for setting the connector type to something better
then UNKNOWN. Does that make sense?
Best regards
Thomas
>
> BR,
> Jani.
>
>
>> + }
>>
>> + /* Return the fixed mode even with EDID */
>> return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
>> }
>> EXPORT_SYMBOL(drm_sysfb_connector_helper_get_modes);
>> diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
>> index 45e396bf74b7..3684bd0ef085 100644
>> --- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
>> +++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
>> @@ -24,6 +24,8 @@ struct drm_display_mode drm_sysfb_mode(unsigned int width,
>> struct drm_sysfb_device {
>> struct drm_device dev;
>>
>> + const u8 *edid; /* can be NULL */
>> +
>> /* hardware settings */
>> struct drm_display_mode fb_mode;
>> const struct drm_format_info *fb_format;
>> diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
>> index 71e661ba9329..86c1a0c80ceb 100644
>> --- a/drivers/gpu/drm/sysfb/ofdrm.c
>> +++ b/drivers/gpu/drm/sysfb/ofdrm.c
>> @@ -12,6 +12,7 @@
>> #include <drm/drm_damage_helper.h>
>> #include <drm/drm_device.h>
>> #include <drm/drm_drv.h>
>> +#include <drm/drm_edid.h>
>> #include <drm/drm_fbdev_shmem.h>
>> #include <drm/drm_format_helper.h>
>> #include <drm/drm_framebuffer.h>
>> @@ -227,6 +228,16 @@ static u64 display_get_address_of(struct drm_device *dev, struct device_node *of
>> return address;
>> }
>>
>> +static const u8 *display_get_edid_of(struct drm_device *dev, struct device_node *of_node,
>> + u8 buf[EDID_LENGTH])
>> +{
>> + int ret = of_property_read_u8_array(of_node, "EDID", buf, EDID_LENGTH);
>> +
>> + if (ret)
>> + return NULL;
>> + return buf;
>> +}
>> +
>> static bool is_avivo(u32 vendor, u32 device)
>> {
>> /* This will match most R5xx */
>> @@ -298,6 +309,8 @@ struct ofdrm_device {
>> /* colormap */
>> void __iomem *cmap_base;
>>
>> + u8 edid[EDID_LENGTH];
>> +
>> /* modesetting */
>> u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
>> struct drm_plane primary_plane;
>> @@ -840,6 +853,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
>> int width, height, depth, linebytes;
>> const struct drm_format_info *format;
>> u64 address;
>> + const u8 *edid;
>> resource_size_t fb_size, fb_base, fb_pgbase, fb_pgsize;
>> struct resource *res, *mem;
>> void __iomem *screen_base;
>> @@ -989,6 +1003,9 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
>> }
>> }
>>
>> + /* EDID is optional */
>> + edid = display_get_edid_of(dev, of_node, odev->edid);
>> +
>> /*
>> * Firmware framebuffer
>> */
>> @@ -999,6 +1016,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
>> sysfb->fb_pitch = linebytes;
>> if (odev->cmap_base)
>> sysfb->fb_gamma_lut_size = OFDRM_GAMMA_LUT_SIZE;
>> + sysfb->edid = edid;
>>
>> drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sysfb->fb_mode));
>> drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n",
>> @@ -1072,6 +1090,8 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
>> drm_connector_set_panel_orientation_with_quirk(connector,
>> DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
>> width, height);
>> + if (edid)
>> + drm_connector_attach_edid_property(connector);
>>
>> ret = drm_connector_attach_encoder(connector, encoder);
>> if (ret)
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support
2025-03-20 13:08 ` Thomas Zimmermann
@ 2025-03-31 9:26 ` Maxime Ripard
2025-03-31 9:32 ` Thomas Zimmermann
0 siblings, 1 reply; 47+ messages in thread
From: Maxime Ripard @ 2025-03-31 9:26 UTC (permalink / raw)
To: Thomas Zimmermann
Cc: Jani Nikula, javierm, simona, airlied, maarten.lankhorst,
dri-devel
[-- Attachment #1: Type: text/plain, Size: 1147 bytes --]
On Thu, Mar 20, 2025 at 02:08:56PM +0100, Thomas Zimmermann wrote:
> > Despite the nitpicks, overall LGTM.
>
> Thanks for reviewing.
>
> Since I have your attention and you're knowledgeable wrt EDID: byte 20 of
> the EDID header indicates the type of output (analog, HDMI, DP, etc). I
> intent to use this for setting the connector type to something better then
> UNKNOWN. Does that make sense?
I don't think it would work:
- EDID doesn't indicate the kind of KMS output (ie, source) but the
type of sink. Ie, what the monitor is capable of dealing with, not
what the connector can emit. If we have (passive or active) bridges
in between, it does mean that we can have an analog sink connected
to a digital connector.
- Since it depends on the sink, it can change over time, ie you plug
an analog monitor, remove it, and plug a digital one. That would
mean changing the connector type (and thus name exposed to
userspace) at runtime, for the same driver.
- Since it depends on the sink, it assumes the sink vendor didn't
botch the EDID. This one is a pretty big if :)
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support
2025-03-31 9:26 ` Maxime Ripard
@ 2025-03-31 9:32 ` Thomas Zimmermann
0 siblings, 0 replies; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-31 9:32 UTC (permalink / raw)
To: Maxime Ripard
Cc: Jani Nikula, javierm, simona, airlied, maarten.lankhorst,
dri-devel
Hi
Am 31.03.25 um 11:26 schrieb Maxime Ripard:
> On Thu, Mar 20, 2025 at 02:08:56PM +0100, Thomas Zimmermann wrote:
>>> Despite the nitpicks, overall LGTM.
>> Thanks for reviewing.
>>
>> Since I have your attention and you're knowledgeable wrt EDID: byte 20 of
>> the EDID header indicates the type of output (analog, HDMI, DP, etc). I
>> intent to use this for setting the connector type to something better then
>> UNKNOWN. Does that make sense?
> I don't think it would work:
>
> - EDID doesn't indicate the kind of KMS output (ie, source) but the
> type of sink. Ie, what the monitor is capable of dealing with, not
> what the connector can emit. If we have (passive or active) bridges
> in between, it does mean that we can have an analog sink connected
> to a digital connector.
>
> - Since it depends on the sink, it can change over time, ie you plug
> an analog monitor, remove it, and plug a digital one. That would
> mean changing the connector type (and thus name exposed to
> userspace) at runtime, for the same driver.
>
> - Since it depends on the sink, it assumes the sink vendor didn't
> botch the EDID. This one is a pretty big if :)
I see. I'd really just want this for these sysfb outputs that come from
the firmware. They should not change much at runtime. Right now, the
connector is always UNKNOWN and giving some type would indicate to the
user which display is in use. But it's not really so important.
Best regards
Thomas
>
> Maxime
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support
2025-03-19 7:45 ` [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support Thomas Zimmermann
2025-03-20 12:50 ` Jani Nikula
@ 2025-03-31 9:15 ` Javier Martinez Canillas
1 sibling, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-31 9:15 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Add EDID support to sysfb connector helpers. Read the EDID property
> from the OF node in ofdrm. Without EDID, this does nothing.
>
> Some systems with OF display, such as 32-bit PPC Macintoshs, provide
> the system display's EDID data as node property in their DT. Exporting
> this information allows compositors to implement correct DPI and
> meaningful color management.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 13/18] firmware: sysfb: Move bpp-depth calculation into screen_info helper
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (11 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 12/18] drm/sysfb: ofdrm: Add EDID support Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-31 9:24 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 14/18] drm/sysfb: Add efidrm for EFI displays Thomas Zimmermann
` (5 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Move the calculation of the bits per pixels for screen_info into a
helper function. This will make it available to other callers besides
the firmware code.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/firmware/sysfb_simplefb.c | 31 +------------------------
drivers/video/screen_info_generic.c | 36 +++++++++++++++++++++++++++++
include/linux/screen_info.h | 2 ++
3 files changed, 39 insertions(+), 30 deletions(-)
diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c
index 75a186bf8f8e..592d8a644619 100644
--- a/drivers/firmware/sysfb_simplefb.c
+++ b/drivers/firmware/sysfb_simplefb.c
@@ -35,36 +35,7 @@ __init bool sysfb_parse_mode(const struct screen_info *si,
if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
return false;
- /*
- * The meaning of depth and bpp for direct-color formats is
- * inconsistent:
- *
- * - DRM format info specifies depth as the number of color
- * bits; including alpha, but not including filler bits.
- * - Linux' EFI platform code computes lfb_depth from the
- * individual color channels, including the reserved bits.
- * - VBE 1.1 defines lfb_depth for XRGB1555 as 16, but later
- * versions use 15.
- * - On the kernel command line, 'bpp' of 32 is usually
- * XRGB8888 including the filler bits, but 15 is XRGB1555
- * not including the filler bit.
- *
- * It's not easily possible to fix this in struct screen_info,
- * as this could break UAPI. The best solution is to compute
- * bits_per_pixel from the color bits, reserved bits and
- * reported lfb_depth, whichever is highest. In the loop below,
- * ignore simplefb formats with alpha bits, as EFI and VESA
- * don't specify alpha channels.
- */
- if (si->lfb_depth > 8) {
- bits_per_pixel = max(max3(si->red_size + si->red_pos,
- si->green_size + si->green_pos,
- si->blue_size + si->blue_pos),
- si->rsvd_size + si->rsvd_pos);
- bits_per_pixel = max_t(u32, bits_per_pixel, si->lfb_depth);
- } else {
- bits_per_pixel = si->lfb_depth;
- }
+ bits_per_pixel = __screen_info_lfb_bits_per_pixel(si);
for (i = 0; i < ARRAY_SIZE(formats); ++i) {
const struct simplefb_format *f = &formats[i];
diff --git a/drivers/video/screen_info_generic.c b/drivers/video/screen_info_generic.c
index 64117c6367ab..900e9386eceb 100644
--- a/drivers/video/screen_info_generic.c
+++ b/drivers/video/screen_info_generic.c
@@ -144,3 +144,39 @@ ssize_t screen_info_resources(const struct screen_info *si, struct resource *r,
return pos - r;
}
EXPORT_SYMBOL(screen_info_resources);
+
+/*
+ * The meaning of depth and bpp for direct-color formats is
+ * inconsistent:
+ *
+ * - DRM format info specifies depth as the number of color
+ * bits; including alpha, but not including filler bits.
+ * - Linux' EFI platform code computes lfb_depth from the
+ * individual color channels, including the reserved bits.
+ * - VBE 1.1 defines lfb_depth for XRGB1555 as 16, but later
+ * versions use 15.
+ * - On the kernel command line, 'bpp' of 32 is usually
+ * XRGB8888 including the filler bits, but 15 is XRGB1555
+ * not including the filler bit.
+ *
+ * It is not easily possible to fix this in struct screen_info,
+ * as this could break UAPI. The best solution is to compute
+ * bits_per_pixel from the color bits, reserved bits and
+ * reported lfb_depth, whichever is highest.
+ */
+
+u32 __screen_info_lfb_bits_per_pixel(const struct screen_info *si)
+{
+ u32 bits_per_pixel = si->lfb_depth;
+
+ if (bits_per_pixel > 8) {
+ bits_per_pixel = max(max3(si->red_size + si->red_pos,
+ si->green_size + si->green_pos,
+ si->blue_size + si->blue_pos),
+ si->rsvd_size + si->rsvd_pos);
+ bits_per_pixel = max_t(u32, bits_per_pixel, si->lfb_depth);
+ }
+
+ return bits_per_pixel;
+}
+EXPORT_SYMBOL(__screen_info_lfb_bits_per_pixel);
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index 6a4a3cec4638..ab3cffbb58b7 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -128,6 +128,8 @@ static inline unsigned int screen_info_video_type(const struct screen_info *si)
ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, size_t num);
+u32 __screen_info_lfb_bits_per_pixel(const struct screen_info *si);
+
#if defined(CONFIG_PCI)
void screen_info_apply_fixups(void);
struct pci_dev *screen_info_pci_dev(const struct screen_info *si);
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* [PATCH 14/18] drm/sysfb: Add efidrm for EFI displays
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (12 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 13/18] firmware: sysfb: Move bpp-depth calculation into screen_info helper Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-31 9:35 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 15/18] drm/sysfb: efidrm: Add EDID support Thomas Zimmermann
` (4 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Add support for screen_info setups with VIDEO_TYPE_EFI. Provide the
minimum functionality of reading modes, updating and clearing the display.
There is existing support for these displays provided by simpledrm with
CONFIG_SYSFB_SIMPLEFB=y. Using efidrm over simpledrm will allows for the
mapping of video memory with correct caching. Simpledrm always assumes WC
caching, while fully cached memory is possible with efidrm. Efidrm will
also allow for the use of additional functionality provided by EFI, such
as EDID information.
In addition to efidrm, add struct pixel_format plus initializer macros.
The type and macros describe pixel formats in a generic way on order to
find the DRM format from the screen_info settings. Similar existing code
in SIMPLEFB_FORMATS and fbdev is not really what is needed in efidrm,
but SIMPLEFB_FORMATS can later be converted to struct pixel_format.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/Kconfig | 16 ++
drivers/gpu/drm/sysfb/Makefile | 1 +
drivers/gpu/drm/sysfb/efidrm.c | 487 +++++++++++++++++++++++++++++++++
include/video/pixel_format.h | 41 +++
4 files changed, 545 insertions(+)
create mode 100644 drivers/gpu/drm/sysfb/efidrm.c
create mode 100644 include/video/pixel_format.h
diff --git a/drivers/gpu/drm/sysfb/Kconfig b/drivers/gpu/drm/sysfb/Kconfig
index 87094da417f6..3ffd8da1224c 100644
--- a/drivers/gpu/drm/sysfb/Kconfig
+++ b/drivers/gpu/drm/sysfb/Kconfig
@@ -7,6 +7,22 @@ config DRM_SYSFB_HELPER
tristate
depends on DRM
+config DRM_EFIDRM
+ tristate "EFI framebuffer driver"
+ depends on DRM && MMU
+ select APERTURE_HELPERS
+ select DRM_CLIENT_SELECTION
+ select DRM_GEM_SHMEM_HELPER
+ select DRM_KMS_HELPER
+ select DRM_SYSFB_HELPER
+ select SYSFB
+ help
+ DRM driver for EFI framebuffers.
+
+ This driver assumes that the display hardware has been initialized
+ by the firmware or bootloader before the kernel boots. Scanout
+ buffer, size, and display format must be provided via EFI interfaces.
+
config DRM_OFDRM
tristate "Open Firmware display driver"
depends on DRM && MMU && OF && (PPC || COMPILE_TEST)
diff --git a/drivers/gpu/drm/sysfb/Makefile b/drivers/gpu/drm/sysfb/Makefile
index f1e8700c3e35..2f96f52842e6 100644
--- a/drivers/gpu/drm/sysfb/Makefile
+++ b/drivers/gpu/drm/sysfb/Makefile
@@ -2,5 +2,6 @@
obj-$(CONFIG_DRM_SYSFB_HELPER) += drm_sysfb_helper.o
+obj-$(CONFIG_DRM_EFIDRM) += efidrm.o
obj-$(CONFIG_DRM_OFDRM) += ofdrm.o
obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o
diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c
new file mode 100644
index 000000000000..5c1876e34a04
--- /dev/null
+++ b/drivers/gpu/drm/sysfb/efidrm.c
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/aperture.h>
+#include <linux/efi.h>
+#include <linux/limits.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+
+#include <drm/clients/drm_client_setup.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_shmem.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
+
+#include <video/pixel_format.h>
+
+#include "drm_sysfb_helper.h"
+
+#define DRIVER_NAME "efidrm"
+#define DRIVER_DESC "DRM driver for EFI platform devices"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+
+static int efidrm_get_validated_int(struct drm_device *dev, const char *name,
+ u64 value, u32 max)
+{
+ if (max > INT_MAX)
+ max = INT_MAX;
+ if (value > max) {
+ drm_err(dev, "%s of %llu exceeds maximum of %u\n", name, value, max);
+ return -EINVAL;
+ }
+ return value;
+}
+
+static int efidrm_get_validated_int0(struct drm_device *dev, const char *name,
+ u64 value, u32 max)
+{
+ if (!value) {
+ drm_err(dev, "%s of 0 not allowed\n", name);
+ return -EINVAL;
+ }
+ return efidrm_get_validated_int(dev, name, value, max);
+}
+
+static s64 efidrm_get_validated_size0(struct drm_device *dev, const char *name,
+ u64 value, u64 max)
+{
+ if (!value) {
+ drm_err(dev, "%s of 0 not allowed\n", name);
+ return -EINVAL;
+ } else if (value > max) {
+ drm_err(dev, "%s of %llu exceeds maximum of %llu\n", name, value, max);
+ return -EINVAL;
+ }
+ return value;
+}
+
+static int efidrm_get_width_si(struct drm_device *dev, const struct screen_info *si)
+{
+ return efidrm_get_validated_int0(dev, "width", si->lfb_width, U16_MAX);
+}
+
+static int efidrm_get_height_si(struct drm_device *dev, const struct screen_info *si)
+{
+ return efidrm_get_validated_int0(dev, "height", si->lfb_height, U16_MAX);
+}
+
+static struct resource *efidrm_get_memory_si(struct drm_device *dev,
+ const struct screen_info *si,
+ struct resource *res)
+{
+ ssize_t num;
+
+ num = screen_info_resources(si, res, 1);
+ if (!num) {
+ drm_err(dev, "memory resource not found\n");
+ return NULL;
+ }
+
+ return res;
+}
+
+static int efidrm_get_stride_si(struct drm_device *dev, const struct screen_info *si,
+ const struct drm_format_info *format,
+ unsigned int width, unsigned int height, u64 size)
+{
+ u64 lfb_linelength = si->lfb_linelength;
+
+ if (!lfb_linelength)
+ lfb_linelength = drm_format_info_min_pitch(format, 0, width);
+
+ return efidrm_get_validated_int0(dev, "stride", lfb_linelength, div64_u64(size, height));
+}
+
+static u64 efidrm_get_visible_size_si(struct drm_device *dev, const struct screen_info *si,
+ unsigned int height, unsigned int stride, u64 size)
+{
+ u64 vsize = PAGE_ALIGN(height * stride);
+
+ return efidrm_get_validated_size0(dev, "visible size", vsize, size);
+}
+
+static const struct drm_format_info *efidrm_get_format_si(struct drm_device *dev,
+ const struct screen_info *si)
+{
+ static const struct {
+ struct pixel_format pixel;
+ u32 fourcc;
+ } efi_formats[] = {
+ { PIXEL_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555, },
+ { PIXEL_FORMAT_RGB565, DRM_FORMAT_RGB565, },
+ { PIXEL_FORMAT_RGB888, DRM_FORMAT_RGB888, },
+ { PIXEL_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, },
+ { PIXEL_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888, },
+ { PIXEL_FORMAT_XRGB2101010, DRM_FORMAT_XRGB2101010, },
+ };
+ const struct drm_format_info *format = NULL;
+ u32 bits_per_pixel;
+ size_t i;
+
+ bits_per_pixel = __screen_info_lfb_bits_per_pixel(si);
+
+ for (i = 0; i < ARRAY_SIZE(efi_formats); ++i) {
+ const struct pixel_format *f = &efi_formats[i].pixel;
+
+ if (bits_per_pixel == f->bits_per_pixel &&
+ si->red_size == f->red.length &&
+ si->red_pos == f->red.offset &&
+ si->green_size == f->green.length &&
+ si->green_pos == f->green.offset &&
+ si->blue_size == f->blue.length &&
+ si->blue_pos == f->blue.offset) {
+ format = drm_format_info(efi_formats[i].fourcc);
+ break;
+ }
+ }
+
+ if (!format)
+ return ERR_PTR(-EINVAL);
+ if (format->is_color_indexed)
+ return ERR_PTR(-EINVAL);
+
+ return format;
+}
+
+static u64 efidrm_get_mem_flags(struct drm_device *dev, resource_size_t start,
+ resource_size_t len)
+{
+ u64 attribute = EFI_MEMORY_UC | EFI_MEMORY_WC |
+ EFI_MEMORY_WT | EFI_MEMORY_WB;
+ u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
+ resource_size_t end = start + len;
+ efi_memory_desc_t md;
+ u64 md_end;
+
+ if (!efi_enabled(EFI_MEMMAP) || efi_mem_desc_lookup(start, &md))
+ goto out;
+
+ md_end = md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT);
+ if (end > md_end)
+ goto out;
+
+ attribute &= md.attribute;
+ if (attribute) {
+ mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB;
+ mem_flags &= attribute;
+ }
+
+out:
+ return mem_flags;
+}
+
+/*
+ * EFI device
+ */
+
+struct efidrm_device {
+ struct drm_sysfb_device sysfb;
+
+ /* modesetting */
+ u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
+ struct drm_plane primary_plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+};
+
+/*
+ * Modesetting
+ */
+
+static const u64 efidrm_primary_plane_format_modifiers[] = {
+ DRM_SYSFB_PLANE_FORMAT_MODIFIERS,
+};
+
+static const struct drm_plane_helper_funcs efidrm_primary_plane_helper_funcs = {
+ DRM_SYSFB_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs efidrm_primary_plane_funcs = {
+ DRM_SYSFB_PLANE_FUNCS,
+ .destroy = drm_plane_cleanup,
+};
+
+static const struct drm_crtc_helper_funcs efidrm_crtc_helper_funcs = {
+ DRM_SYSFB_CRTC_HELPER_FUNCS,
+};
+
+static const struct drm_crtc_funcs efidrm_crtc_funcs = {
+ DRM_SYSFB_CRTC_FUNCS,
+ .destroy = drm_crtc_cleanup,
+};
+
+static const struct drm_encoder_funcs efidrm_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static const struct drm_connector_helper_funcs efidrm_connector_helper_funcs = {
+ DRM_SYSFB_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs efidrm_connector_funcs = {
+ DRM_SYSFB_CONNECTOR_FUNCS,
+ .destroy = drm_connector_cleanup,
+};
+
+static const struct drm_mode_config_funcs efidrm_mode_config_funcs = {
+ DRM_SYSFB_MODE_CONFIG_FUNCS,
+};
+
+/*
+ * Init / Cleanup
+ */
+
+static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
+ struct platform_device *pdev)
+{
+ const struct screen_info *si;
+ const struct drm_format_info *format;
+ int width, height, stride;
+ u64 vsize, mem_flags;
+ struct resource resbuf;
+ struct resource *res;
+ struct efidrm_device *efi;
+ struct drm_sysfb_device *sysfb;
+ struct drm_device *dev;
+ struct resource *mem = NULL;
+ void __iomem *screen_base;
+ struct drm_plane *primary_plane;
+ struct drm_crtc *crtc;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ unsigned long max_width, max_height;
+ size_t nformats;
+ int ret;
+
+ si = dev_get_platdata(&pdev->dev);
+ if (!si)
+ return ERR_PTR(-ENODEV);
+ if (screen_info_video_type(si) != VIDEO_TYPE_EFI)
+ return ERR_PTR(-ENODEV);
+
+ /*
+ * EFI DRM driver
+ */
+
+ efi = devm_drm_dev_alloc(&pdev->dev, drv, struct efidrm_device, sysfb.dev);
+ if (IS_ERR(efi))
+ return ERR_CAST(efi);
+ sysfb = &efi->sysfb;
+ dev = &sysfb->dev;
+ platform_set_drvdata(pdev, dev);
+
+ /*
+ * Hardware settings
+ */
+
+ format = efidrm_get_format_si(dev, si);
+ if (IS_ERR(format))
+ return ERR_CAST(format);
+ width = efidrm_get_width_si(dev, si);
+ if (width < 0)
+ return ERR_PTR(width);
+ height = efidrm_get_height_si(dev, si);
+ if (height < 0)
+ return ERR_PTR(height);
+ res = efidrm_get_memory_si(dev, si, &resbuf);
+ if (!res)
+ return ERR_PTR(-EINVAL);
+ stride = efidrm_get_stride_si(dev, si, format, width, height, resource_size(res));
+ if (stride < 0)
+ return ERR_PTR(stride);
+ vsize = efidrm_get_visible_size_si(dev, si, height, stride, resource_size(res));
+ if (!vsize)
+ return ERR_PTR(-EINVAL);
+
+ drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n",
+ &format->format, width, height, stride);
+
+ sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
+ sysfb->fb_format = format;
+ sysfb->fb_pitch = stride;
+
+ /*
+ * Memory management
+ */
+
+ ret = devm_aperture_acquire_for_platform_device(pdev, res->start, vsize);
+ if (ret) {
+ drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret);
+ return ERR_PTR(ret);
+ }
+
+ drm_dbg(dev, "using I/O memory framebuffer at %pr\n", res);
+
+ mem = devm_request_mem_region(&pdev->dev, res->start, vsize, drv->name);
+ if (!mem) {
+ /*
+ * We cannot make this fatal. Sometimes this comes from magic
+ * spaces our resource handlers simply don't know about. Use
+ * the I/O-memory resource as-is and try to map that instead.
+ */
+ drm_warn(dev, "could not acquire memory region %pr\n", res);
+ mem = res;
+ }
+
+ mem_flags = efidrm_get_mem_flags(dev, res->start, vsize);
+
+ if (mem_flags & EFI_MEMORY_WC)
+ screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem));
+ else if (mem_flags & EFI_MEMORY_UC)
+ screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+ else if (mem_flags & EFI_MEMORY_WT)
+ screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem),
+ MEMREMAP_WT);
+ else if (mem_flags & EFI_MEMORY_WB)
+ screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem),
+ MEMREMAP_WB);
+ if (!screen_base)
+ return ERR_PTR(-ENOMEM);
+ iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
+
+ /*
+ * Modesetting
+ */
+
+ ret = drmm_mode_config_init(dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH);
+ max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT);
+
+ dev->mode_config.min_width = width;
+ dev->mode_config.max_width = max_width;
+ dev->mode_config.min_height = height;
+ dev->mode_config.max_height = max_height;
+ dev->mode_config.preferred_depth = format->depth;
+ dev->mode_config.funcs = &efidrm_mode_config_funcs;
+
+ /* Primary plane */
+
+ nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
+ efi->formats, ARRAY_SIZE(efi->formats));
+
+ primary_plane = &efi->primary_plane;
+ ret = drm_universal_plane_init(dev, primary_plane, 0, &efidrm_primary_plane_funcs,
+ efi->formats, nformats,
+ efidrm_primary_plane_format_modifiers,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_plane_helper_add(primary_plane, &efidrm_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ /* CRTC */
+
+ crtc = &efi->crtc;
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &efidrm_crtc_funcs, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_crtc_helper_add(crtc, &efidrm_crtc_helper_funcs);
+
+ /* Encoder */
+
+ encoder = &efi->encoder;
+ ret = drm_encoder_init(dev, encoder, &efidrm_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+ /* Connector */
+
+ connector = &efi->connector;
+ ret = drm_connector_init(dev, connector, &efidrm_connector_funcs,
+ DRM_MODE_CONNECTOR_Unknown);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_connector_helper_add(connector, &efidrm_connector_helper_funcs);
+ drm_connector_set_panel_orientation_with_quirk(connector,
+ DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
+ width, height);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
+ return efi;
+}
+
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_FOPS(efidrm_fops);
+
+static struct drm_driver efidrm_driver = {
+ DRM_GEM_SHMEM_DRIVER_OPS,
+ DRM_FBDEV_SHMEM_DRIVER_OPS,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
+ .fops = &efidrm_fops,
+};
+
+/*
+ * Platform driver
+ */
+
+static int efidrm_probe(struct platform_device *pdev)
+{
+ struct efidrm_device *efi;
+ struct drm_sysfb_device *sysfb;
+ struct drm_device *dev;
+ int ret;
+
+ efi = efidrm_device_create(&efidrm_driver, pdev);
+ if (IS_ERR(efi))
+ return PTR_ERR(efi);
+ sysfb = &efi->sysfb;
+ dev = &sysfb->dev;
+
+ ret = drm_dev_register(dev, 0);
+ if (ret)
+ return ret;
+
+ drm_client_setup(dev, sysfb->fb_format);
+
+ return 0;
+}
+
+static void efidrm_remove(struct platform_device *pdev)
+{
+ struct drm_device *dev = platform_get_drvdata(pdev);
+
+ drm_dev_unplug(dev);
+}
+
+static struct platform_driver efidrm_platform_driver = {
+ .driver = {
+ .name = "efi-framebuffer",
+ },
+ .probe = efidrm_probe,
+ .remove = efidrm_remove,
+};
+
+module_platform_driver(efidrm_platform_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/include/video/pixel_format.h b/include/video/pixel_format.h
new file mode 100644
index 000000000000..b5104b2a3a13
--- /dev/null
+++ b/include/video/pixel_format.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef VIDEO_PIXEL_FORMAT_H
+#define VIDEO_PIXEL_FORMAT_H
+
+struct pixel_format {
+ unsigned char bits_per_pixel;
+ bool indexed;
+ union {
+ struct {
+ struct {
+ unsigned char offset;
+ unsigned char length;
+ } alpha, red, green, blue;
+ };
+ struct {
+ unsigned char offset;
+ unsigned char length;
+ } index;
+ };
+};
+
+#define PIXEL_FORMAT_XRGB1555 \
+ { 16, false, { .alpha = {0, 0}, .red = {10, 5}, .green = {5, 5}, .blue = {0, 5} } }
+
+#define PIXEL_FORMAT_RGB565 \
+ { 16, false, { .alpha = {0, 0}, .red = {11, 5}, .green = {5, 6}, .blue = {0, 5} } }
+
+#define PIXEL_FORMAT_RGB888 \
+ { 24, false, { .alpha = {0, 0}, .red = {16, 8}, .green = {8, 8}, .blue = {0, 8} } }
+
+#define PIXEL_FORMAT_XRGB8888 \
+ { 32, false, { .alpha = {0, 0}, .red = {16, 8}, .green = {8, 8}, .blue = {0, 8} } }
+
+#define PIXEL_FORMAT_XBGR8888 \
+ { 32, false, { .alpha = {0, 0}, .red = {0, 8}, .green = {8, 8}, .blue = {16, 8} } }
+
+#define PIXEL_FORMAT_XRGB2101010 \
+ { 32, false, { .alpha = {0, 0}, .red = {20, 10}, .green = {10, 10}, .blue = {0, 10} } }
+
+#endif
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 14/18] drm/sysfb: Add efidrm for EFI displays
2025-03-19 7:45 ` [PATCH 14/18] drm/sysfb: Add efidrm for EFI displays Thomas Zimmermann
@ 2025-03-31 9:35 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-31 9:35 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Add support for screen_info setups with VIDEO_TYPE_EFI. Provide the
> minimum functionality of reading modes, updating and clearing the display.
>
> There is existing support for these displays provided by simpledrm with
> CONFIG_SYSFB_SIMPLEFB=y. Using efidrm over simpledrm will allows for the
> mapping of video memory with correct caching. Simpledrm always assumes WC
> caching, while fully cached memory is possible with efidrm. Efidrm will
> also allow for the use of additional functionality provided by EFI, such
> as EDID information.
>
> In addition to efidrm, add struct pixel_format plus initializer macros.
> The type and macros describe pixel formats in a generic way on order to
> find the DRM format from the screen_info settings. Similar existing code
> in SIMPLEFB_FORMATS and fbdev is not really what is needed in efidrm,
> but SIMPLEFB_FORMATS can later be converted to struct pixel_format.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 15/18] drm/sysfb: efidrm: Add EDID support
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (13 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 14/18] drm/sysfb: Add efidrm for EFI displays Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-31 9:37 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 16/18] drm/sysfb: Add vesadrm for VESA displays Thomas Zimmermann
` (3 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Enable the connector's EDID property if edid_info contains valid
data. Exports the EDID via sysfs for user-space compositors.
EDID information is not always available. Depending on the system
and kernel configuration, it is either provided by the boot loader
or read by the kernel during early boot stages.
As of now, there's only one EFI display, so that EDID data always
belongs to this output. This might change if there's ever more than
one EFI display in the system.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/efidrm.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c
index 5c1876e34a04..af90064a4c04 100644
--- a/drivers/gpu/drm/sysfb/efidrm.c
+++ b/drivers/gpu/drm/sysfb/efidrm.c
@@ -13,6 +13,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
+#include <drm/drm_edid.h>
#include <drm/drm_fbdev_shmem.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
@@ -22,6 +23,7 @@
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
+#include <video/edid.h>
#include <video/pixel_format.h>
#include "drm_sysfb_helper.h"
@@ -308,6 +310,10 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n",
&format->format, width, height, stride);
+#ifdef CONFIG_X86
+ if (drm_edid_header_is_valid(edid_info.dummy) == 8)
+ sysfb->edid = edid_info.dummy;
+#endif
sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
sysfb->fb_format = format;
sysfb->fb_pitch = stride;
@@ -413,6 +419,8 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
drm_connector_set_panel_orientation_with_quirk(connector,
DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
width, height);
+ if (sysfb->edid)
+ drm_connector_attach_edid_property(connector);
ret = drm_connector_attach_encoder(connector, encoder);
if (ret)
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 15/18] drm/sysfb: efidrm: Add EDID support
2025-03-19 7:45 ` [PATCH 15/18] drm/sysfb: efidrm: Add EDID support Thomas Zimmermann
@ 2025-03-31 9:37 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-31 9:37 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Enable the connector's EDID property if edid_info contains valid
> data. Exports the EDID via sysfs for user-space compositors.
>
> EDID information is not always available. Depending on the system
> and kernel configuration, it is either provided by the boot loader
> or read by the kernel during early boot stages.
>
> As of now, there's only one EFI display, so that EDID data always
> belongs to this output. This might change if there's ever more than
> one EFI display in the system.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 16/18] drm/sysfb: Add vesadrm for VESA displays
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (14 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 15/18] drm/sysfb: efidrm: Add EDID support Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-31 9:42 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 17/18] drm/sysfb: vesadrm: Add EDID support Thomas Zimmermann
` (2 subsequent siblings)
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Add support for screen_info setups with VIDEO_TYPE_VLFB. Provide the
minimum functionality of reading modes, updating and clearing the display.
There is existing support for these displays provided by simpledrm with
CONFIG_SYSFB_SIMPLEFB=y. Using vesadrm over simpledrm will allow for the
use of additional functionality provided by VESA, such as EDID information,
gamma correction and palette modes. This enhances the user experience and
adds support for more display configuratons.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/Kconfig | 16 ++
drivers/gpu/drm/sysfb/Makefile | 1 +
drivers/gpu/drm/sysfb/vesadrm.c | 448 ++++++++++++++++++++++++++++++++
3 files changed, 465 insertions(+)
create mode 100644 drivers/gpu/drm/sysfb/vesadrm.c
diff --git a/drivers/gpu/drm/sysfb/Kconfig b/drivers/gpu/drm/sysfb/Kconfig
index 3ffd8da1224c..008c33eab99a 100644
--- a/drivers/gpu/drm/sysfb/Kconfig
+++ b/drivers/gpu/drm/sysfb/Kconfig
@@ -57,4 +57,20 @@ config DRM_SIMPLEDRM
On x86 BIOS or UEFI systems, you should also select SYSFB_SIMPLEFB
to use UEFI and VESA framebuffers.
+config DRM_VESADRM
+ tristate "VESA framebuffer driver"
+ depends on DRM && MMU
+ select APERTURE_HELPERS
+ select DRM_CLIENT_SELECTION
+ select DRM_GEM_SHMEM_HELPER
+ select DRM_KMS_HELPER
+ select DRM_SYSFB_HELPER
+ select SYSFB
+ help
+ DRM driver for VESA framebuffers.
+
+ This driver assumes that the display hardware has been initialized
+ by the firmware or bootloader before the kernel boots. Scanout
+ buffer, size, and display format must be provided via VBE interfaces.
+
endmenu
diff --git a/drivers/gpu/drm/sysfb/Makefile b/drivers/gpu/drm/sysfb/Makefile
index 2f96f52842e6..0d2518c97163 100644
--- a/drivers/gpu/drm/sysfb/Makefile
+++ b/drivers/gpu/drm/sysfb/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_DRM_SYSFB_HELPER) += drm_sysfb_helper.o
obj-$(CONFIG_DRM_EFIDRM) += efidrm.o
obj-$(CONFIG_DRM_OFDRM) += ofdrm.o
obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o
+obj-$(CONFIG_DRM_VESADRM) += vesadrm.o
diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c
new file mode 100644
index 000000000000..8a963057ffec
--- /dev/null
+++ b/drivers/gpu/drm/sysfb/vesadrm.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/aperture.h>
+#include <linux/ioport.h>
+#include <linux/limits.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+
+#include <drm/clients/drm_client_setup.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_shmem.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
+
+#include <video/pixel_format.h>
+
+#include "drm_sysfb_helper.h"
+
+#define DRIVER_NAME "vesadrm"
+#define DRIVER_DESC "DRM driver for VESA platform devices"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+
+static int vesadrm_get_validated_int(struct drm_device *dev, const char *name,
+ u64 value, u32 max)
+{
+ if (max > INT_MAX)
+ max = INT_MAX;
+ if (value > max) {
+ drm_err(dev, "%s of %llu exceeds maximum of %u\n", name, value, max);
+ return -EINVAL;
+ }
+ return value;
+}
+
+static int vesadrm_get_validated_int0(struct drm_device *dev, const char *name,
+ u64 value, u32 max)
+{
+ if (!value) {
+ drm_err(dev, "%s of 0 not allowed\n", name);
+ return -EINVAL;
+ }
+ return vesadrm_get_validated_int(dev, name, value, max);
+}
+
+static s64 vesadrm_get_validated_size0(struct drm_device *dev, const char *name,
+ u64 value, u64 max)
+{
+ if (!value) {
+ drm_err(dev, "vesadrm: %s of 0 not allowed\n", name);
+ return -EINVAL;
+ } else if (value > max) {
+ drm_err(dev, "vesadrm: %s of %llu exceeds maximum of %llu\n", name, value, max);
+ return -EINVAL;
+ }
+ return value;
+}
+
+static int vesadrm_get_width_si(struct drm_device *dev, const struct screen_info *si)
+{
+ return vesadrm_get_validated_int0(dev, "width", si->lfb_width, U16_MAX);
+}
+
+static int vesadrm_get_height_si(struct drm_device *dev, const struct screen_info *si)
+{
+ return vesadrm_get_validated_int0(dev, "height", si->lfb_height, U16_MAX);
+}
+
+static struct resource *vesadrm_get_memory_si(struct drm_device *dev,
+ const struct screen_info *si,
+ struct resource *res)
+{
+ ssize_t num;
+
+ num = screen_info_resources(si, res, 1);
+ if (!num) {
+ drm_err(dev, "vesadrm: memory resource not found\n");
+ return NULL;
+ }
+
+ return res;
+}
+
+static int vesadrm_get_stride_si(struct drm_device *dev, const struct screen_info *si,
+ const struct drm_format_info *format,
+ unsigned int width, unsigned int height, u64 size)
+{
+ u64 lfb_linelength = si->lfb_linelength;
+
+ if (!lfb_linelength)
+ lfb_linelength = drm_format_info_min_pitch(format, 0, width);
+
+ return vesadrm_get_validated_int0(dev, "stride", lfb_linelength, div64_u64(size, height));
+}
+
+static u64 vesadrm_get_visible_size_si(struct drm_device *dev, const struct screen_info *si,
+ unsigned int height, unsigned int stride, u64 size)
+{
+ u64 vsize = PAGE_ALIGN(height * stride);
+
+ return vesadrm_get_validated_size0(dev, "visible size", vsize, size);
+}
+
+static const struct drm_format_info *vesadrm_get_format_si(struct drm_device *dev,
+ const struct screen_info *si)
+{
+ static const struct {
+ struct pixel_format pixel;
+ u32 fourcc;
+ } vesa_formats[] = {
+ { PIXEL_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555, },
+ { PIXEL_FORMAT_RGB565, DRM_FORMAT_RGB565, },
+ { PIXEL_FORMAT_RGB888, DRM_FORMAT_RGB888, },
+ { PIXEL_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, },
+ { PIXEL_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888, },
+ };
+ const struct drm_format_info *format = NULL;
+ u32 bits_per_pixel;
+ size_t i;
+
+ bits_per_pixel = __screen_info_lfb_bits_per_pixel(si);
+
+ for (i = 0; i < ARRAY_SIZE(vesa_formats); ++i) {
+ const struct pixel_format *f = &vesa_formats[i].pixel;
+
+ if (bits_per_pixel == f->bits_per_pixel &&
+ si->red_size == f->red.length &&
+ si->red_pos == f->red.offset &&
+ si->green_size == f->green.length &&
+ si->green_pos == f->green.offset &&
+ si->blue_size == f->blue.length &&
+ si->blue_pos == f->blue.offset) {
+ format = drm_format_info(vesa_formats[i].fourcc);
+ break;
+ }
+ }
+
+ if (!format)
+ return ERR_PTR(-EINVAL);
+ if (format->is_color_indexed)
+ return ERR_PTR(-EINVAL);
+
+ return format;
+}
+
+/*
+ * VESA device
+ */
+
+struct vesadrm_device {
+ struct drm_sysfb_device sysfb;
+
+ /* modesetting */
+ u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
+ struct drm_plane primary_plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+};
+
+/*
+ * Modesetting
+ */
+
+static const u64 vesadrm_primary_plane_format_modifiers[] = {
+ DRM_SYSFB_PLANE_FORMAT_MODIFIERS,
+};
+
+static const struct drm_plane_helper_funcs vesadrm_primary_plane_helper_funcs = {
+ DRM_SYSFB_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs vesadrm_primary_plane_funcs = {
+ DRM_SYSFB_PLANE_FUNCS,
+ .destroy = drm_plane_cleanup,
+};
+
+static const struct drm_crtc_helper_funcs vesadrm_crtc_helper_funcs = {
+ DRM_SYSFB_CRTC_HELPER_FUNCS,
+};
+
+static const struct drm_crtc_funcs vesadrm_crtc_funcs = {
+ DRM_SYSFB_CRTC_FUNCS,
+ .destroy = drm_crtc_cleanup,
+};
+
+static const struct drm_encoder_funcs vesadrm_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static const struct drm_connector_helper_funcs vesadrm_connector_helper_funcs = {
+ DRM_SYSFB_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs vesadrm_connector_funcs = {
+ DRM_SYSFB_CONNECTOR_FUNCS,
+ .destroy = drm_connector_cleanup,
+};
+
+static const struct drm_mode_config_funcs vesadrm_mode_config_funcs = {
+ DRM_SYSFB_MODE_CONFIG_FUNCS,
+};
+
+/*
+ * Init / Cleanup
+ */
+
+static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
+ struct platform_device *pdev)
+{
+ const struct screen_info *si;
+ const struct drm_format_info *format;
+ int width, height, stride;
+ u64 vsize;
+ struct resource resbuf;
+ struct resource *res;
+ struct vesadrm_device *vesa;
+ struct drm_sysfb_device *sysfb;
+ struct drm_device *dev;
+ struct resource *mem = NULL;
+ void __iomem *screen_base;
+ struct drm_plane *primary_plane;
+ struct drm_crtc *crtc;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ unsigned long max_width, max_height;
+ size_t nformats;
+ int ret;
+
+ si = dev_get_platdata(&pdev->dev);
+ if (!si)
+ return ERR_PTR(-ENODEV);
+ if (screen_info_video_type(si) != VIDEO_TYPE_VLFB)
+ return ERR_PTR(-ENODEV);
+
+ /*
+ * VESA DRM driver
+ */
+
+ vesa = devm_drm_dev_alloc(&pdev->dev, drv, struct vesadrm_device, sysfb.dev);
+ if (IS_ERR(vesa))
+ return ERR_CAST(vesa);
+ sysfb = &vesa->sysfb;
+ dev = &sysfb->dev;
+ platform_set_drvdata(pdev, dev);
+
+ /*
+ * Hardware settings
+ */
+
+ format = vesadrm_get_format_si(dev, si);
+ if (IS_ERR(format))
+ return ERR_CAST(format);
+ width = vesadrm_get_width_si(dev, si);
+ if (width < 0)
+ return ERR_PTR(width);
+ height = vesadrm_get_height_si(dev, si);
+ if (height < 0)
+ return ERR_PTR(height);
+ res = vesadrm_get_memory_si(dev, si, &resbuf);
+ if (!res)
+ return ERR_PTR(-EINVAL);
+ stride = vesadrm_get_stride_si(dev, si, format, width, height, resource_size(res));
+ if (stride < 0)
+ return ERR_PTR(stride);
+ vsize = vesadrm_get_visible_size_si(dev, si, height, stride, resource_size(res));
+ if (!vsize)
+ return ERR_PTR(-EINVAL);
+
+ drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n",
+ &format->format, width, height, stride);
+
+ sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
+ sysfb->fb_format = format;
+ sysfb->fb_pitch = stride;
+
+ /*
+ * Memory management
+ */
+
+ ret = devm_aperture_acquire_for_platform_device(pdev, res->start, vsize);
+ if (ret) {
+ drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret);
+ return ERR_PTR(ret);
+ }
+
+ drm_dbg(dev, "using I/O memory framebuffer at %pr\n", res);
+
+ mem = devm_request_mem_region(&pdev->dev, res->start, vsize, drv->name);
+ if (!mem) {
+ /*
+ * We cannot make this fatal. Sometimes this comes from magic
+ * spaces our resource handlers simply don't know about. Use
+ * the I/O-memory resource as-is and try to map that instead.
+ */
+ drm_warn(dev, "could not acquire memory region %pr\n", res);
+ mem = res;
+ }
+
+ screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem));
+ if (!screen_base)
+ return ERR_PTR(-ENOMEM);
+ iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
+
+ /*
+ * Modesetting
+ */
+
+ ret = drmm_mode_config_init(dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH);
+ max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT);
+
+ dev->mode_config.min_width = width;
+ dev->mode_config.max_width = max_width;
+ dev->mode_config.min_height = height;
+ dev->mode_config.max_height = max_height;
+ dev->mode_config.preferred_depth = format->depth;
+ dev->mode_config.funcs = &vesadrm_mode_config_funcs;
+
+ /* Primary plane */
+
+ nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
+ vesa->formats, ARRAY_SIZE(vesa->formats));
+
+ primary_plane = &vesa->primary_plane;
+ ret = drm_universal_plane_init(dev, primary_plane, 0, &vesadrm_primary_plane_funcs,
+ vesa->formats, nformats,
+ vesadrm_primary_plane_format_modifiers,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_plane_helper_add(primary_plane, &vesadrm_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ /* CRTC */
+
+ crtc = &vesa->crtc;
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &vesadrm_crtc_funcs, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_crtc_helper_add(crtc, &vesadrm_crtc_helper_funcs);
+
+ /* Encoder */
+
+ encoder = &vesa->encoder;
+ ret = drm_encoder_init(dev, encoder, &vesadrm_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+ /* Connector */
+
+ connector = &vesa->connector;
+ ret = drm_connector_init(dev, connector, &vesadrm_connector_funcs,
+ DRM_MODE_CONNECTOR_Unknown);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_connector_helper_add(connector, &vesadrm_connector_helper_funcs);
+ drm_connector_set_panel_orientation_with_quirk(connector,
+ DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
+ width, height);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
+ return vesa;
+}
+
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_FOPS(vesadrm_fops);
+
+static struct drm_driver vesadrm_driver = {
+ DRM_GEM_SHMEM_DRIVER_OPS,
+ DRM_FBDEV_SHMEM_DRIVER_OPS,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
+ .fops = &vesadrm_fops,
+};
+
+/*
+ * Platform driver
+ */
+
+static int vesadrm_probe(struct platform_device *pdev)
+{
+ struct vesadrm_device *vesa;
+ struct drm_sysfb_device *sysfb;
+ struct drm_device *dev;
+ int ret;
+
+ vesa = vesadrm_device_create(&vesadrm_driver, pdev);
+ if (IS_ERR(vesa))
+ return PTR_ERR(vesa);
+ sysfb = &vesa->sysfb;
+ dev = &sysfb->dev;
+
+ ret = drm_dev_register(dev, 0);
+ if (ret)
+ return ret;
+
+ drm_client_setup(dev, sysfb->fb_format);
+
+ return 0;
+}
+
+static void vesadrm_remove(struct platform_device *pdev)
+{
+ struct drm_device *dev = platform_get_drvdata(pdev);
+
+ drm_dev_unplug(dev);
+}
+
+static struct platform_driver vesadrm_platform_driver = {
+ .driver = {
+ .name = "vesa-framebuffer",
+ },
+ .probe = vesadrm_probe,
+ .remove = vesadrm_remove,
+};
+
+module_platform_driver(vesadrm_platform_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 16/18] drm/sysfb: Add vesadrm for VESA displays
2025-03-19 7:45 ` [PATCH 16/18] drm/sysfb: Add vesadrm for VESA displays Thomas Zimmermann
@ 2025-03-31 9:42 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-31 9:42 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Add support for screen_info setups with VIDEO_TYPE_VLFB. Provide the
> minimum functionality of reading modes, updating and clearing the display.
>
> There is existing support for these displays provided by simpledrm with
> CONFIG_SYSFB_SIMPLEFB=y. Using vesadrm over simpledrm will allow for the
> use of additional functionality provided by VESA, such as EDID information,
> gamma correction and palette modes. This enhances the user experience and
> adds support for more display configuratons.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 17/18] drm/sysfb: vesadrm: Add EDID support
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (15 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 16/18] drm/sysfb: Add vesadrm for VESA displays Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-31 9:44 ` Javier Martinez Canillas
2025-03-19 7:45 ` [PATCH 18/18] drm/sysfb: vesadrm: Add gamma correction Thomas Zimmermann
2025-03-19 12:50 ` [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm nerdopolis
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Enable the connector's EDID property if edid_info contains valid
data. Exports the EDID via sysfs for user-space compositors.
EDID information is not always available. Depending on the system
and kernel configuration, it is either provided by the boot loader
or read by the kernel during early boot stages.
There's only one VESA display, so EDID data always belongs to this
output.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/vesadrm.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c
index 8a963057ffec..07f59880ce0f 100644
--- a/drivers/gpu/drm/sysfb/vesadrm.c
+++ b/drivers/gpu/drm/sysfb/vesadrm.c
@@ -13,6 +13,7 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
+#include <drm/drm_edid.h>
#include <drm/drm_fbdev_shmem.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
@@ -22,6 +23,7 @@
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
+#include <video/edid.h>
#include <video/pixel_format.h>
#include "drm_sysfb_helper.h"
@@ -280,6 +282,10 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n",
&format->format, width, height, stride);
+#ifdef CONFIG_X86
+ if (drm_edid_header_is_valid(edid_info.dummy) == 8)
+ sysfb->edid = edid_info.dummy;
+#endif
sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
sysfb->fb_format = format;
sysfb->fb_pitch = stride;
@@ -374,6 +380,8 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
drm_connector_set_panel_orientation_with_quirk(connector,
DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
width, height);
+ if (sysfb->edid)
+ drm_connector_attach_edid_property(connector);
ret = drm_connector_attach_encoder(connector, encoder);
if (ret)
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 17/18] drm/sysfb: vesadrm: Add EDID support
2025-03-19 7:45 ` [PATCH 17/18] drm/sysfb: vesadrm: Add EDID support Thomas Zimmermann
@ 2025-03-31 9:44 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-31 9:44 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Enable the connector's EDID property if edid_info contains valid
> data. Exports the EDID via sysfs for user-space compositors.
>
> EDID information is not always available. Depending on the system
> and kernel configuration, it is either provided by the boot loader
> or read by the kernel during early boot stages.
>
> There's only one VESA display, so EDID data always belongs to this
> output.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH 18/18] drm/sysfb: vesadrm: Add gamma correction
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (16 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 17/18] drm/sysfb: vesadrm: Add EDID support Thomas Zimmermann
@ 2025-03-19 7:45 ` Thomas Zimmermann
2025-03-31 9:47 ` Javier Martinez Canillas
2025-03-19 12:50 ` [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm nerdopolis
18 siblings, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 7:45 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Add palette support and export GAMMA properties via sysfs. User-space
compositors can use this interface for programming gamma ramps or night
mode.
Vesadrm supports palette updates via VGA DAC registers or VESA palette
calls. Up to 256 palette entries are available. Userspace always supplies
gamma ramps of 256 entries. If the native color format does not match
this because pixel component have less then 8 bits, vesadrm interpolates
among the palette entries.
The code uses CamelCase style in a few places to match the VESA manuals.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/sysfb/vesadrm.c | 204 ++++++++++++++++++++++++++++++++
include/linux/screen_info.h | 7 ++
2 files changed, 211 insertions(+)
diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c
index 07f59880ce0f..20cf867ad500 100644
--- a/drivers/gpu/drm/sysfb/vesadrm.c
+++ b/drivers/gpu/drm/sysfb/vesadrm.c
@@ -25,6 +25,7 @@
#include <video/edid.h>
#include <video/pixel_format.h>
+#include <video/vga.h>
#include "drm_sysfb_helper.h"
@@ -33,6 +34,8 @@
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
+#define VESADRM_GAMMA_LUT_SIZE 256
+
static int vesadrm_get_validated_int(struct drm_device *dev, const char *name,
u64 value, u32 max)
{
@@ -162,6 +165,14 @@ static const struct drm_format_info *vesadrm_get_format_si(struct drm_device *de
struct vesadrm_device {
struct drm_sysfb_device sysfb;
+ /* VESA Protected Mode interface */
+ struct {
+ const u8 *PrimaryPalette;
+ } pmi;
+
+ void (*cmap_write)(struct vesadrm_device *vesa, unsigned int index,
+ u16 red, u16 green, u16 blue);
+
/* modesetting */
u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
struct drm_plane primary_plane;
@@ -170,6 +181,151 @@ struct vesadrm_device {
struct drm_connector connector;
};
+static struct vesadrm_device *to_vesadrm_device(struct drm_device *dev)
+{
+ return container_of(to_drm_sysfb_device(dev), struct vesadrm_device, sysfb);
+}
+
+/*
+ * Palette
+ */
+
+static void vesadrm_vga_cmap_write(struct vesadrm_device *vesa, unsigned int index,
+ u16 red, u16 green, u16 blue)
+{
+ u8 i8, r8, g8, b8;
+
+ if (index > 255)
+ return;
+
+ i8 = index;
+ r8 = red >> 8;
+ g8 = green >> 8;
+ b8 = blue >> 8;
+
+ outb_p(i8, VGA_PEL_IW);
+ outb_p(r8, VGA_PEL_D);
+ outb_p(g8, VGA_PEL_D);
+ outb_p(b8, VGA_PEL_D);
+}
+
+#ifdef __i386__
+static void vesadrm_pmi_cmap_write(struct vesadrm_device *vesa, unsigned int index,
+ u16 red, u16 green, u16 blue)
+{
+ u32 i32 = index;
+ struct {
+ u8 b8;
+ u8 g8;
+ u8 r8;
+ u8 x8;
+ } PaletteEntry = {
+ blue >> 8,
+ green >> 8,
+ red >> 8,
+ 0x00,
+ };
+
+ if (index > 255)
+ return;
+
+ __asm__ __volatile__(
+ "call *(%%esi)"
+ : /* no return value */
+ : "a" (0x4f09),
+ "b" (0),
+ "c" (1),
+ "d" (i32),
+ "D" (&PaletteEntry),
+ "S" (&vesa->pmi.PrimaryPalette));
+}
+#endif
+
+static void vesadrm_set_gamma_linear(struct vesadrm_device *vesa,
+ const struct drm_format_info *format)
+{
+ struct drm_device *dev = &vesa->sysfb.dev;
+ size_t i;
+ u16 r16, g16, b16;
+
+ switch (format->format) {
+ case DRM_FORMAT_XRGB1555:
+ for (i = 0; i < 32; ++i) {
+ r16 = i * 8 + i / 4;
+ r16 |= (r16 << 8) | r16;
+ vesa->cmap_write(vesa, i, r16, r16, r16);
+ }
+ break;
+ case DRM_FORMAT_RGB565:
+ for (i = 0; i < 32; ++i) {
+ r16 = i * 8 + i / 4;
+ r16 |= (r16 << 8) | r16;
+ g16 = i * 4 + i / 16;
+ g16 |= (g16 << 8) | g16;
+ b16 = r16;
+ vesa->cmap_write(vesa, i, r16, g16, b16);
+ }
+ for (i = 32; i < 64; ++i) {
+ g16 = i * 4 + i / 16;
+ g16 |= (g16 << 8) | g16;
+ vesa->cmap_write(vesa, i, 0, g16, 0);
+ }
+ break;
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_BGRX8888:
+ for (i = 0; i < 256; ++i) {
+ r16 = (i << 8) | i;
+ vesa->cmap_write(vesa, i, r16, r16, r16);
+ }
+ break;
+ default:
+ drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n",
+ &format->format);
+ break;
+ }
+}
+
+static void vesadrm_set_gamma_lut(struct vesadrm_device *vesa,
+ const struct drm_format_info *format,
+ struct drm_color_lut *lut)
+{
+ struct drm_device *dev = &vesa->sysfb.dev;
+ size_t i;
+ u16 r16, g16, b16;
+
+ switch (format->format) {
+ case DRM_FORMAT_XRGB1555:
+ for (i = 0; i < 32; ++i) {
+ r16 = lut[i * 8 + i / 4].red;
+ g16 = lut[i * 8 + i / 4].green;
+ b16 = lut[i * 8 + i / 4].blue;
+ vesa->cmap_write(vesa, i, r16, g16, b16);
+ }
+ break;
+ case DRM_FORMAT_RGB565:
+ for (i = 0; i < 32; ++i) {
+ r16 = lut[i * 8 + i / 4].red;
+ g16 = lut[i * 4 + i / 16].green;
+ b16 = lut[i * 8 + i / 4].blue;
+ vesa->cmap_write(vesa, i, r16, g16, b16);
+ }
+ for (i = 32; i < 64; ++i)
+ vesa->cmap_write(vesa, i, 0, lut[i * 4 + i / 16].green, 0);
+ break;
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_BGRX8888:
+ for (i = 0; i < 256; ++i)
+ vesa->cmap_write(vesa, i, lut[i].red, lut[i].green, lut[i].blue);
+ break;
+ default:
+ drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n",
+ &format->format);
+ break;
+ }
+}
+
/*
* Modesetting
*/
@@ -187,8 +343,36 @@ static const struct drm_plane_funcs vesadrm_primary_plane_funcs = {
.destroy = drm_plane_cleanup,
};
+static void vesadrm_crtc_helper_atomic_flush(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
+ struct vesadrm_device *vesa = to_vesadrm_device(dev);
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ struct drm_sysfb_crtc_state *sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state);
+
+ /*
+ * The gamma LUT has to be reloaded after changing the primary
+ * plane's color format.
+ */
+ if (crtc_state->enable && crtc_state->color_mgmt_changed) {
+ if (sysfb_crtc_state->format == sysfb->fb_format) {
+ if (crtc_state->gamma_lut)
+ vesadrm_set_gamma_lut(vesa,
+ sysfb_crtc_state->format,
+ crtc_state->gamma_lut->data);
+ else
+ vesadrm_set_gamma_linear(vesa, sysfb_crtc_state->format);
+ } else {
+ vesadrm_set_gamma_linear(vesa, sysfb_crtc_state->format);
+ }
+ }
+}
+
static const struct drm_crtc_helper_funcs vesadrm_crtc_helper_funcs = {
DRM_SYSFB_CRTC_HELPER_FUNCS,
+ .atomic_flush = vesadrm_crtc_helper_atomic_flush,
};
static const struct drm_crtc_funcs vesadrm_crtc_funcs = {
@@ -282,6 +466,18 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n",
&format->format, width, height, stride);
+ if (!__screen_info_vbe_mode_nonvga(si)) {
+ vesa->cmap_write = vesadrm_vga_cmap_write;
+#ifdef __i386__
+ } else {
+ phys_addr_t pmi_base = __screen_info_vesapm_info_base(si);
+ const u16 *pmi_addr = phys_to_virt(pmi_base);
+
+ vesa->pmi.PrimaryPalette = (u8 *)pmi_addr + pmi_addr[2];
+ vesa->cmap_write = vesadrm_pmi_cmap_write;
+#endif
+ }
+
#ifdef CONFIG_X86
if (drm_edid_header_is_valid(edid_info.dummy) == 8)
sysfb->edid = edid_info.dummy;
@@ -289,6 +485,8 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
sysfb->fb_format = format;
sysfb->fb_pitch = stride;
+ if (vesa->cmap_write)
+ sysfb->fb_gamma_lut_size = VESADRM_GAMMA_LUT_SIZE;
/*
* Memory management
@@ -360,6 +558,12 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
return ERR_PTR(ret);
drm_crtc_helper_add(crtc, &vesadrm_crtc_helper_funcs);
+ if (sysfb->fb_gamma_lut_size) {
+ ret = drm_mode_crtc_set_gamma_size(crtc, sysfb->fb_gamma_lut_size);
+ if (!ret)
+ drm_crtc_enable_color_mgmt(crtc, 0, false, sysfb->fb_gamma_lut_size);
+ }
+
/* Encoder */
encoder = &vesa->encoder;
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index ab3cffbb58b7..923d68e07679 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -126,6 +126,13 @@ static inline unsigned int screen_info_video_type(const struct screen_info *si)
return VIDEO_TYPE_CGA;
}
+static inline u32 __screen_info_vesapm_info_base(const struct screen_info *si)
+{
+ if (si->vesapm_seg < 0xc000)
+ return 0;
+ return (si->vesapm_seg << 4) + si->vesapm_off;
+}
+
ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, size_t num);
u32 __screen_info_lfb_bits_per_pixel(const struct screen_info *si);
--
2.48.1
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH 18/18] drm/sysfb: vesadrm: Add gamma correction
2025-03-19 7:45 ` [PATCH 18/18] drm/sysfb: vesadrm: Add gamma correction Thomas Zimmermann
@ 2025-03-31 9:47 ` Javier Martinez Canillas
0 siblings, 0 replies; 47+ messages in thread
From: Javier Martinez Canillas @ 2025-03-31 9:47 UTC (permalink / raw)
To: Thomas Zimmermann, simona, airlied, maarten.lankhorst, mripard
Cc: dri-devel, Thomas Zimmermann
Thomas Zimmermann <tzimmermann@suse.de> writes:
> Add palette support and export GAMMA properties via sysfs. User-space
> compositors can use this interface for programming gamma ramps or night
> mode.
>
> Vesadrm supports palette updates via VGA DAC registers or VESA palette
> calls. Up to 256 palette entries are available. Userspace always supplies
> gamma ramps of 256 entries. If the native color format does not match
> this because pixel component have less then 8 bits, vesadrm interpolates
> among the palette entries.
>
> The code uses CamelCase style in a few places to match the VESA manuals.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
--
Best regards,
Javier Martinez Canillas
Core Platforms
Red Hat
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm
2025-03-19 7:44 [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm Thomas Zimmermann
` (17 preceding siblings ...)
2025-03-19 7:45 ` [PATCH 18/18] drm/sysfb: vesadrm: Add gamma correction Thomas Zimmermann
@ 2025-03-19 12:50 ` nerdopolis
2025-03-19 12:59 ` Thomas Zimmermann
2025-03-31 13:39 ` Thomas Zimmermann
18 siblings, 2 replies; 47+ messages in thread
From: nerdopolis @ 2025-03-19 12:50 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard, dri-devel
Cc: Thomas Zimmermann
On Wednesday, March 19, 2025 3:44:59 AM EDT Thomas Zimmermann wrote:
> This series simplifies the existing ofdrm and simepldrm drivers,
> and adds new drivers for EFI- and VESA-based framebuffers. Existing
> drivers for system framebuffers, ofdrm and simpledrm, share much of
> their mode-setting pipeline. The major difference between the two
> drivers is in how they retrieve the framebuffer from the systems.
> Hence, it makes sense to share some of the pipeline implementation.
> With the shared helpers in place, we can then add dedicated drivers
> for EFI and VESA easily.
>
> Patches 1 to 3 clean up obsolete artifacts from ofdrm and simpledrm.
>
> Patch 4 moves both drivers from tiny/ into their own subdirectory
> sysfb/. The name aligns with the naming in drivers/firmware/sysfb.c
> to signal the connection. It's the firmware code that creates most
> of the system-framebuffer devices that these drivers operate on. The
> patch also adds a separate menu in Kconfig.
>
> Patches 5 to 11 unify the mode-setting pipeline between ofdrm and
> simpledrm. Either both drivers already use the same implementation
> or they can easily do so. There've been previous attempts to unify
> some of the drivers' code, but with little success. This time the
> helpers will be shared among 4 drivers, so it's already much more
> successful than before.
>
> Patch 12 adds EDID support to ofdrm. The EDID data can be found in
> some Macintosh's DeviceTree next to the framebuffer configuration.
> EDID support will be useful for EFI and VESA as well.
>
> Patch 13 adds another helper for screen_info that will be required
> by EFI and VESA drivers.
>
> Patch 14 and 15 add efidrm, a DRM driver that operates on EFI-provided
> framebuffers. It uses the shared sysfb helpers. The immediate benefit
> over simpledrm is the support for EFI's various types of memory caching
> on the framebuffer. Simpledrm only supported WriteCombine caching.
> There's also EDID support if the kernel's edid_info has been initialized.
> This feature needs to be implemented in the kernel's efistub library.
>
> Patches 16 to 18 add vesadrm, a DRM driver that operates in VESA-
> provided framebuffers. It is very much like efidrm, but tailored
> towards VESA features. It has EDID support and there's a patch at [1]
> for grub to provide the data as part of the kernel's boot parameters.
> Vesadrm also supports gamma ramps. Together with EDID, this allows
> for gamma correction and night mode. Gnome already does that.
>
> Future directions: Efidrm requires EDID data that has to be provided
> by the efistub library. There is an EFI call to do so. Vesadrm currently
> requires a discrete color mode. Support for palette modes can be added
> later. There's still a bit of code duplication among palette handling.
> We have more drivers that use similar code for palette LUTs, such as
> ast and mgag200. We should try to provide generic palette helpers for
> all these drivers.
>
> This series has been tested on various devices that require the provided
> drivers.
>
> [1] https://build.opensuse.org/projects/home:tdz:branches:Base:System/packages/grub2/files/grub2-provide-edid.patch?expand=1
>
> Thomas Zimmermann (18):
> drm/ofdrm: Remove struct ofdrm_device.pdev
> drm/ofdrm: Open-code drm_simple_encoder_init()
> drm/simpledrm: Remove struct simpledrm_device.nformats
> drm: Move sysfb drivers into separate subdirectory
> drm/sysfb: Add struct drm_sysfb_device
> drm/sysfb: Provide single mode-init helper
> drm/sysfb: Merge mode-config functions
> drm/sysfb: Merge connector functions
> drm/sysfb: Maintain CRTC state in struct drm_sysfb_crtc_state
> drm/sysfb: Merge CRTC functions
> drm/sysfb: Merge primary-plane functions
> drm/sysfb: ofdrm: Add EDID support
> firmware: sysfb: Move bpp-depth calculation into screen_info helper
> drm/sysfb: Add efidrm for EFI displays
> drm/sysfb: efidrm: Add EDID support
> drm/sysfb: Add vesadrm for VESA displays
> drm/sysfb: vesadrm: Add EDID support
> drm/sysfb: vesadrm: Add gamma correction
>
> MAINTAINERS | 3 +-
> drivers/firmware/sysfb_simplefb.c | 31 +-
> drivers/gpu/drm/Kconfig | 2 +
> drivers/gpu/drm/Makefile | 1 +
> drivers/gpu/drm/sysfb/Kconfig | 76 +++
> drivers/gpu/drm/sysfb/Makefile | 8 +
> drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 319 ++++++++++
> drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 136 ++++
> drivers/gpu/drm/sysfb/efidrm.c | 495 +++++++++++++++
> drivers/gpu/drm/{tiny => sysfb}/ofdrm.c | 364 ++---------
> drivers/gpu/drm/{tiny => sysfb}/simpledrm.c | 237 +------
> drivers/gpu/drm/sysfb/vesadrm.c | 660 ++++++++++++++++++++
> drivers/gpu/drm/tiny/Kconfig | 32 -
> drivers/gpu/drm/tiny/Makefile | 2 -
> drivers/video/screen_info_generic.c | 36 ++
> include/linux/screen_info.h | 9 +
> include/video/pixel_format.h | 41 ++
> 17 files changed, 1885 insertions(+), 567 deletions(-)
> create mode 100644 drivers/gpu/drm/sysfb/Kconfig
> create mode 100644 drivers/gpu/drm/sysfb/Makefile
> create mode 100644 drivers/gpu/drm/sysfb/drm_sysfb_helper.c
> create mode 100644 drivers/gpu/drm/sysfb/drm_sysfb_helper.h
> create mode 100644 drivers/gpu/drm/sysfb/efidrm.c
> rename drivers/gpu/drm/{tiny => sysfb}/ofdrm.c (75%)
> rename drivers/gpu/drm/{tiny => sysfb}/simpledrm.c (76%)
> create mode 100644 drivers/gpu/drm/sysfb/vesadrm.c
> create mode 100644 include/video/pixel_format.h
>
>
FYI When this gets merged,
https://gitlab.freedesktop.org/xorg/xserver/-/blob/master/hw/xfree86/common/xf86platformBus.c?ref_type=heads#L589
might need to be updated to add exceptions for vesadrm and efidrm like there
is for simpledrm.
I am willing to open a merge request, but freedesktop is readonly for now
during their migration.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm
2025-03-19 12:50 ` [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm nerdopolis
@ 2025-03-19 12:59 ` Thomas Zimmermann
2025-03-31 13:39 ` Thomas Zimmermann
1 sibling, 0 replies; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-19 12:59 UTC (permalink / raw)
To: nerdopolis, javierm, simona, airlied, maarten.lankhorst, mripard,
dri-devel
Hi
Am 19.03.25 um 13:50 schrieb nerdopolis:
> On Wednesday, March 19, 2025 3:44:59 AM EDT Thomas Zimmermann wrote:
>> This series simplifies the existing ofdrm and simepldrm drivers,
>> and adds new drivers for EFI- and VESA-based framebuffers. Existing
>> drivers for system framebuffers, ofdrm and simpledrm, share much of
>> their mode-setting pipeline. The major difference between the two
>> drivers is in how they retrieve the framebuffer from the systems.
>> Hence, it makes sense to share some of the pipeline implementation.
>> With the shared helpers in place, we can then add dedicated drivers
>> for EFI and VESA easily.
>>
>> Patches 1 to 3 clean up obsolete artifacts from ofdrm and simpledrm.
>>
>> Patch 4 moves both drivers from tiny/ into their own subdirectory
>> sysfb/. The name aligns with the naming in drivers/firmware/sysfb.c
>> to signal the connection. It's the firmware code that creates most
>> of the system-framebuffer devices that these drivers operate on. The
>> patch also adds a separate menu in Kconfig.
>>
>> Patches 5 to 11 unify the mode-setting pipeline between ofdrm and
>> simpledrm. Either both drivers already use the same implementation
>> or they can easily do so. There've been previous attempts to unify
>> some of the drivers' code, but with little success. This time the
>> helpers will be shared among 4 drivers, so it's already much more
>> successful than before.
>>
>> Patch 12 adds EDID support to ofdrm. The EDID data can be found in
>> some Macintosh's DeviceTree next to the framebuffer configuration.
>> EDID support will be useful for EFI and VESA as well.
>>
>> Patch 13 adds another helper for screen_info that will be required
>> by EFI and VESA drivers.
>>
>> Patch 14 and 15 add efidrm, a DRM driver that operates on EFI-provided
>> framebuffers. It uses the shared sysfb helpers. The immediate benefit
>> over simpledrm is the support for EFI's various types of memory caching
>> on the framebuffer. Simpledrm only supported WriteCombine caching.
>> There's also EDID support if the kernel's edid_info has been initialized.
>> This feature needs to be implemented in the kernel's efistub library.
>>
>> Patches 16 to 18 add vesadrm, a DRM driver that operates in VESA-
>> provided framebuffers. It is very much like efidrm, but tailored
>> towards VESA features. It has EDID support and there's a patch at [1]
>> for grub to provide the data as part of the kernel's boot parameters.
>> Vesadrm also supports gamma ramps. Together with EDID, this allows
>> for gamma correction and night mode. Gnome already does that.
>>
>> Future directions: Efidrm requires EDID data that has to be provided
>> by the efistub library. There is an EFI call to do so. Vesadrm currently
>> requires a discrete color mode. Support for palette modes can be added
>> later. There's still a bit of code duplication among palette handling.
>> We have more drivers that use similar code for palette LUTs, such as
>> ast and mgag200. We should try to provide generic palette helpers for
>> all these drivers.
>>
>> This series has been tested on various devices that require the provided
>> drivers.
>>
>> [1] https://build.opensuse.org/projects/home:tdz:branches:Base:System/packages/grub2/files/grub2-provide-edid.patch?expand=1
>>
>> Thomas Zimmermann (18):
>> drm/ofdrm: Remove struct ofdrm_device.pdev
>> drm/ofdrm: Open-code drm_simple_encoder_init()
>> drm/simpledrm: Remove struct simpledrm_device.nformats
>> drm: Move sysfb drivers into separate subdirectory
>> drm/sysfb: Add struct drm_sysfb_device
>> drm/sysfb: Provide single mode-init helper
>> drm/sysfb: Merge mode-config functions
>> drm/sysfb: Merge connector functions
>> drm/sysfb: Maintain CRTC state in struct drm_sysfb_crtc_state
>> drm/sysfb: Merge CRTC functions
>> drm/sysfb: Merge primary-plane functions
>> drm/sysfb: ofdrm: Add EDID support
>> firmware: sysfb: Move bpp-depth calculation into screen_info helper
>> drm/sysfb: Add efidrm for EFI displays
>> drm/sysfb: efidrm: Add EDID support
>> drm/sysfb: Add vesadrm for VESA displays
>> drm/sysfb: vesadrm: Add EDID support
>> drm/sysfb: vesadrm: Add gamma correction
>>
>> MAINTAINERS | 3 +-
>> drivers/firmware/sysfb_simplefb.c | 31 +-
>> drivers/gpu/drm/Kconfig | 2 +
>> drivers/gpu/drm/Makefile | 1 +
>> drivers/gpu/drm/sysfb/Kconfig | 76 +++
>> drivers/gpu/drm/sysfb/Makefile | 8 +
>> drivers/gpu/drm/sysfb/drm_sysfb_helper.c | 319 ++++++++++
>> drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 136 ++++
>> drivers/gpu/drm/sysfb/efidrm.c | 495 +++++++++++++++
>> drivers/gpu/drm/{tiny => sysfb}/ofdrm.c | 364 ++---------
>> drivers/gpu/drm/{tiny => sysfb}/simpledrm.c | 237 +------
>> drivers/gpu/drm/sysfb/vesadrm.c | 660 ++++++++++++++++++++
>> drivers/gpu/drm/tiny/Kconfig | 32 -
>> drivers/gpu/drm/tiny/Makefile | 2 -
>> drivers/video/screen_info_generic.c | 36 ++
>> include/linux/screen_info.h | 9 +
>> include/video/pixel_format.h | 41 ++
>> 17 files changed, 1885 insertions(+), 567 deletions(-)
>> create mode 100644 drivers/gpu/drm/sysfb/Kconfig
>> create mode 100644 drivers/gpu/drm/sysfb/Makefile
>> create mode 100644 drivers/gpu/drm/sysfb/drm_sysfb_helper.c
>> create mode 100644 drivers/gpu/drm/sysfb/drm_sysfb_helper.h
>> create mode 100644 drivers/gpu/drm/sysfb/efidrm.c
>> rename drivers/gpu/drm/{tiny => sysfb}/ofdrm.c (75%)
>> rename drivers/gpu/drm/{tiny => sysfb}/simpledrm.c (76%)
>> create mode 100644 drivers/gpu/drm/sysfb/vesadrm.c
>> create mode 100644 include/video/pixel_format.h
>>
>>
> FYI When this gets merged,
> https://gitlab.freedesktop.org/xorg/xserver/-/blob/master/hw/xfree86/common/xf86platformBus.c?ref_type=heads#L589
> might need to be updated to add exceptions for vesadrm and efidrm like there
> is for simpledrm.
Yeah, we need a workaround for each of these drivers unfortunately.
> I am willing to open a merge request, but freedesktop is readonly for now
> during their migration.
No worries, I'll provide the patches.
Best regards
Thomas
>
>
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm
2025-03-19 12:50 ` [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm nerdopolis
2025-03-19 12:59 ` Thomas Zimmermann
@ 2025-03-31 13:39 ` Thomas Zimmermann
2025-04-02 2:44 ` nerdopolis
1 sibling, 1 reply; 47+ messages in thread
From: Thomas Zimmermann @ 2025-03-31 13:39 UTC (permalink / raw)
To: nerdopolis, javierm, simona, airlied, maarten.lankhorst, mripard,
dri-devel
Hi
Am 19.03.25 um 13:50 schrieb nerdopolis:
[...]
> FYI When this gets merged,
> https://gitlab.freedesktop.org/xorg/xserver/-/blob/master/hw/xfree86/common/xf86platformBus.c?ref_type=heads#L589
> might need to be updated to add exceptions for vesadrm and efidrm like there
> is for simpledrm.
> I am willing to open a merge request, but freedesktop is readonly for now
> during their migration.
I've sent out an MR with this update.
Best regards
Thomas
>
>
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH 00/18] drm: Provide helpers for system framebuffers and add efidrm/vesadrm
2025-03-31 13:39 ` Thomas Zimmermann
@ 2025-04-02 2:44 ` nerdopolis
0 siblings, 0 replies; 47+ messages in thread
From: nerdopolis @ 2025-04-02 2:44 UTC (permalink / raw)
To: javierm, simona, airlied, maarten.lankhorst, mripard, dri-devel,
Thomas Zimmermann
On Monday, March 31, 2025 9:39:26 AM EDT Thomas Zimmermann wrote:
> Hi
>
> Am 19.03.25 um 13:50 schrieb nerdopolis:
> [...]
> > FYI When this gets merged,
> > https://gitlab.freedesktop.org/xorg/xserver/-/blob/master/hw/xfree86/common/xf86platformBus.c?ref_type=heads#L589
> > might need to be updated to add exceptions for vesadrm and efidrm like there
> > is for simpledrm.
> > I am willing to open a merge request, but freedesktop is readonly for now
> > during their migration.
>
> I've sent out an MR with this update.
>
> Best regards
> Thomas
>
Sweet thanks, Yeah I noticed you were the one that added in those other two
drivers as well in the workaround list, but only after I sent that message.
I should have checked the commit log. Sorry about the unneeded reminder, as
you were obviously already aware that it needs those workarounds
> >
> >
> >
>
>
^ permalink raw reply [flat|nested] 47+ messages in thread