All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Zimmermann <tzimmermann@suse.de>
To: alexander.deucher@amd.com, christian.koenig@amd.com,
	Xinhui.Pan@amd.com, airlied@gmail.com, daniel@ffwll.ch,
	javierm@redhat.com
Cc: Thomas Zimmermann <tzimmermann@suse.de>,
	amd-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Subject: [PATCH 09/10] drm/radeon: Implement client-based fbdev emulation
Date: Thu, 16 Mar 2023 10:37:37 +0100	[thread overview]
Message-ID: <20230316093738.28866-10-tzimmermann@suse.de> (raw)
In-Reply-To: <20230316093738.28866-1-tzimmermann@suse.de>

Implement fbdev emulation on top of struct drm_client and its helpers.
Replaces ad-hoc interfaces for restoring and closing fbdev emulation with
per-client callbacks for hotplugging, restoring and unregistering.

A single function, radeon_fbdev_setup(), starts fbdev emulation after
the DRM device has been registered. Hence, fbdev acts like a regular
DRM client.

The setup call prepares the fbdev emulation and invokes connector
hotplugging. The first successful hotplug event initializes fbdev
emulation with a framebuffer, device file, etc.

Unregistering depends on the hotplug status. Fully initialized emulation
is cleaned up through drm_fb_helper_unregister_info() and fb_destroy.
For prepared-only setups, unregistering unprepares the emulation and
releases all resources. In both cases, fbdev emulation will be cleaned
up.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/radeon/radeon_display.c |   4 -
 drivers/gpu/drm/radeon/radeon_drv.c     |   3 +-
 drivers/gpu/drm/radeon/radeon_drv.h     |   1 -
 drivers/gpu/drm/radeon/radeon_fb.c      | 126 ++++++++++++++++--------
 drivers/gpu/drm/radeon/radeon_kms.c     |  18 ----
 drivers/gpu/drm/radeon/radeon_mode.h    |   3 +-
 6 files changed, 89 insertions(+), 66 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index f34a7f63261d..901e75ec70ff 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -34,7 +34,6 @@
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_framebuffer.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -1354,7 +1353,6 @@ radeon_user_framebuffer_create(struct drm_device *dev,
 
 static const struct drm_mode_config_funcs radeon_mode_funcs = {
 	.fb_create = radeon_user_framebuffer_create,
-	.output_poll_changed = drm_fb_helper_output_poll_changed,
 };
 
 static const struct drm_prop_enum_list radeon_tmds_pll_enum_list[] =
@@ -1642,7 +1640,6 @@ int radeon_modeset_init(struct radeon_device *rdev)
 	/* setup afmt */
 	radeon_afmt_init(rdev);
 
-	radeon_fbdev_init(rdev);
 	drm_kms_helper_poll_init(rdev->ddev);
 
 	/* do pm late init */
@@ -1657,7 +1654,6 @@ void radeon_modeset_fini(struct radeon_device *rdev)
 		drm_kms_helper_poll_fini(rdev->ddev);
 		radeon_hpd_fini(rdev);
 		drm_helper_force_disable_all(rdev->ddev);
-		radeon_fbdev_fini(rdev);
 		radeon_afmt_fini(rdev);
 		drm_mode_config_cleanup(rdev->ddev);
 		rdev->mode_info.mode_config_initialized = false;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 716ab85a376b..e4374814f0ef 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -341,6 +341,8 @@ static int radeon_pci_probe(struct pci_dev *pdev,
 	if (ret)
 		goto err_agp;
 
+	radeon_fbdev_setup(dev->dev_private);
+
 	return 0;
 
 err_agp:
@@ -595,7 +597,6 @@ static const struct drm_driver kms_driver = {
 	.load = radeon_driver_load_kms,
 	.open = radeon_driver_open_kms,
 	.postclose = radeon_driver_postclose_kms,
-	.lastclose = radeon_driver_lastclose_kms,
 	.unload = radeon_driver_unload_kms,
 	.ioctls = radeon_ioctls_kms,
 	.num_ioctls = ARRAY_SIZE(radeon_ioctls_kms),
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index ac7970919c4d..2ffe0975ee54 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -120,7 +120,6 @@ long radeon_drm_ioctl(struct file *filp,
 
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 void radeon_driver_unload_kms(struct drm_device *dev);
-void radeon_driver_lastclose_kms(struct drm_device *dev);
 int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv);
 void radeon_driver_postclose_kms(struct drm_device *dev,
 				 struct drm_file *file_priv);
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 2b629bb23be8..fe76e29910ef 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -24,19 +24,16 @@
  *     David Airlie
  */
 
-#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
-#include <linux/slab.h>
 #include <linux/vga_switcheroo.h>
 
-#include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_framebuffer.h>
 #include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/radeon_drm.h>
 
 #include "radeon.h"
 
@@ -179,14 +176,16 @@ static void radeon_fbdev_fb_destroy(struct fb_info *info)
 	struct drm_framebuffer *fb = fb_helper->fb;
 	struct drm_gem_object *gobj = drm_gem_fb_get_obj(fb, 0);
 
+	drm_fb_helper_fini(fb_helper);
+
 	drm_framebuffer_unregister_private(fb);
 	drm_framebuffer_cleanup(fb);
 	kfree(fb);
-	fb_helper->fb = NULL;
-
 	radeon_fbdev_destroy_pinned_object(gobj);
 
-	drm_fb_helper_fini(fb_helper);
+	drm_client_release(&fb_helper->client);
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
 }
 
 static const struct fb_ops radeon_fbdev_fb_ops = {
@@ -279,7 +278,6 @@ static int radeon_fbdev_fb_helper_fb_probe(struct drm_fb_helper *fb_helper,
 	DRM_INFO("fb depth is %d\n", fb->format->depth);
 	DRM_INFO("   pitch is %d\n", fb->pitches[0]);
 
-	vga_switcheroo_client_fb_set(rdev->pdev, info);
 	return 0;
 
 err_drm_framebuffer_unregister_private:
@@ -297,59 +295,107 @@ static const struct drm_fb_helper_funcs radeon_fbdev_fb_helper_funcs = {
 	.fb_probe = radeon_fbdev_fb_helper_fb_probe,
 };
 
-int radeon_fbdev_init(struct radeon_device *rdev)
+/*
+ * Fbdev client and struct drm_client_funcs
+ */
+
+static void radeon_fbdev_client_unregister(struct drm_client_dev *client)
 {
-	struct drm_fb_helper *fb_helper;
-	int bpp_sel = 32;
-	int ret;
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+	struct drm_device *dev = fb_helper->dev;
+	struct radeon_device *rdev = dev->dev_private;
+
+	if (fb_helper->info) {
+		vga_switcheroo_client_fb_set(rdev->pdev, NULL);
+		drm_fb_helper_unregister_info(fb_helper);
+	} else {
+		drm_client_release(&fb_helper->client);
+		drm_fb_helper_unprepare(fb_helper);
+		kfree(fb_helper);
+	}
+}
 
-	/* don't enable fbdev if no connectors */
-	if (list_empty(&rdev->ddev->mode_config.connector_list))
-		return 0;
+static int radeon_fbdev_client_restore(struct drm_client_dev *client)
+{
+	drm_fb_helper_lastclose(client->dev);
+	vga_switcheroo_process_delayed_switch();
 
-	/* select 8 bpp console on 8MB cards, or 16 bpp on RN50 or 32MB */
-	if (rdev->mc.real_vram_size <= (8*1024*1024))
-		bpp_sel = 8;
-	else if (ASIC_IS_RN50(rdev) ||
-		 rdev->mc.real_vram_size <= (32*1024*1024))
-		bpp_sel = 16;
+	return 0;
+}
 
-	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
-	if (!fb_helper)
-		return -ENOMEM;
+static int radeon_fbdev_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+	struct drm_device *dev = client->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	int ret;
 
-	drm_fb_helper_prepare(rdev->ddev, fb_helper, bpp_sel, &radeon_fbdev_fb_helper_funcs);
+	if (dev->fb_helper)
+		return drm_fb_helper_hotplug_event(dev->fb_helper);
 
-	ret = drm_fb_helper_init(rdev->ddev, fb_helper);
+	ret = drm_fb_helper_init(dev, fb_helper);
 	if (ret)
-		goto free;
+		goto err_drm_err;
 
-	/* disable all the possible outputs/crtcs before entering KMS mode */
-	drm_helper_disable_unused_functions(rdev->ddev);
+	if (!drm_drv_uses_atomic_modeset(dev))
+		drm_helper_disable_unused_functions(dev);
 
 	ret = drm_fb_helper_initial_config(fb_helper);
 	if (ret)
-		goto fini;
+		goto err_drm_fb_helper_fini;
+
+	vga_switcheroo_client_fb_set(rdev->pdev, fb_helper->info);
 
 	return 0;
 
-fini:
+err_drm_fb_helper_fini:
 	drm_fb_helper_fini(fb_helper);
-free:
-	drm_fb_helper_unprepare(fb_helper);
-	kfree(fb_helper);
+err_drm_err:
+	drm_err(dev, "Failed to setup radeon fbdev emulation (ret=%d)\n", ret);
 	return ret;
 }
 
-void radeon_fbdev_fini(struct radeon_device *rdev)
+static const struct drm_client_funcs radeon_fbdev_client_funcs = {
+	.owner		= THIS_MODULE,
+	.unregister	= radeon_fbdev_client_unregister,
+	.restore	= radeon_fbdev_client_restore,
+	.hotplug	= radeon_fbdev_client_hotplug,
+};
+
+void radeon_fbdev_setup(struct radeon_device *rdev)
 {
-	if (!rdev->ddev->fb_helper)
+	struct drm_fb_helper *fb_helper;
+	int bpp_sel = 32;
+	int ret;
+
+	if (rdev->mc.real_vram_size <= (8 * 1024 * 1024))
+		bpp_sel = 8;
+	else if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32 * 1024 * 1024))
+		bpp_sel = 16;
+
+	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
+	if (!fb_helper)
 		return;
+	drm_fb_helper_prepare(rdev->ddev, fb_helper, bpp_sel, &radeon_fbdev_fb_helper_funcs);
+
+	ret = drm_client_init(rdev->ddev, &fb_helper->client, "radeon-fbdev",
+			      &radeon_fbdev_client_funcs);
+	if (ret) {
+		drm_err(rdev->ddev, "Failed to register client: %d\n", ret);
+		goto err_drm_client_init;
+	}
 
-	drm_fb_helper_unregister_info(rdev->ddev->fb_helper);
-	drm_fb_helper_unprepare(rdev->ddev->fb_helper);
-	kfree(rdev->ddev->fb_helper);
-	rdev->ddev->fb_helper = NULL;
+	ret = radeon_fbdev_client_hotplug(&fb_helper->client);
+	if (ret)
+		drm_dbg_kms(rdev->ddev, "client hotplug ret=%d\n", ret);
+
+	drm_client_register(&fb_helper->client);
+
+	return;
+
+err_drm_client_init:
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
 }
 
 void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state)
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 965161b8565b..e0214cf1b43b 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -32,7 +32,6 @@
 #include <linux/uaccess.h>
 #include <linux/vga_switcheroo.h>
 
-#include <drm/drm_fb_helper.h>
 #include <drm/drm_file.h>
 #include <drm/drm_ioctl.h>
 #include <drm/radeon_drm.h>
@@ -622,23 +621,6 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 	return 0;
 }
 
-
-/*
- * Outdated mess for old drm with Xorg being in charge (void function now).
- */
-/**
- * radeon_driver_lastclose_kms - drm callback for last close
- *
- * @dev: drm dev pointer
- *
- * Switch vga_switcheroo state after last close (all asics).
- */
-void radeon_driver_lastclose_kms(struct drm_device *dev)
-{
-	drm_fb_helper_lastclose(dev);
-	vga_switcheroo_process_delayed_switch();
-}
-
 /**
  * radeon_driver_open_kms - drm callback for open
  *
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 64cf263ae646..d81f61e5a95c 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -939,8 +939,7 @@ void dce4_program_fmt(struct drm_encoder *encoder);
 void dce8_program_fmt(struct drm_encoder *encoder);
 
 /* fbdev layer */
-int radeon_fbdev_init(struct radeon_device *rdev);
-void radeon_fbdev_fini(struct radeon_device *rdev);
+void radeon_fbdev_setup(struct radeon_device *rdev);
 void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
 bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
 
-- 
2.39.2


  parent reply	other threads:[~2023-03-16  9:38 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-16  9:37 [PATCH 00/10] drm/radeon: Convert fbdev to DRM client Thomas Zimmermann
2023-03-16  9:37 ` [PATCH 01/10] drm/radeon: Move radeon_align_pitch() next to dumb-buffer helpers Thomas Zimmermann
2023-03-16  9:37 ` [PATCH 02/10] drm/radeon: Improve fbdev object-test helper Thomas Zimmermann
2023-03-16  9:37 ` [PATCH 03/10] drm/radeon: Remove struct radeon_fbdev Thomas Zimmermann
2023-03-16  9:37 ` [PATCH 04/10] drm/radeon: Remove test for !screen_base in fbdev probing Thomas Zimmermann
2023-03-16  9:37 ` [PATCH 05/10] drm/radeon: Move fbdev object helpers before struct fb_ops et al Thomas Zimmermann
2023-03-16  9:37 ` [PATCH 06/10] drm/radeon: Fix coding style in fbdev emulation Thomas Zimmermann
2023-03-16  9:37 ` [PATCH 07/10] drm/radeon: Move fbdev cleanup code into fb_destroy callback Thomas Zimmermann
2023-03-16  9:37 ` [PATCH 08/10] drm/radeon: Correctly clean up failed display probing Thomas Zimmermann
2023-03-16  9:37 ` Thomas Zimmermann [this message]
2023-03-16  9:37 ` [PATCH 10/10] drm/radeon: Only build fbdev if DRM_FBDEV_EMULATION is set Thomas Zimmermann
2023-03-17  8:53 ` [PATCH 00/10] drm/radeon: Convert fbdev to DRM client Christian König
2023-03-17  9:20   ` Thomas Zimmermann
2023-03-20 15:11     ` Christian König
2023-03-20 15:19       ` Thomas Zimmermann
2023-03-20 15:23         ` Alex Deucher
2023-03-20 15:23           ` Alex Deucher
2023-03-21  9:33           ` Thomas Zimmermann
2023-03-24 21:44             ` Alex Deucher
2023-03-27 22:39               ` Alex Deucher

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230316093738.28866-10-tzimmermann@suse.de \
    --to=tzimmermann@suse.de \
    --cc=Xinhui.Pan@amd.com \
    --cc=airlied@gmail.com \
    --cc=alexander.deucher@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=christian.koenig@amd.com \
    --cc=daniel@ffwll.ch \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=javierm@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.