* [PATCH 01/10] drm/edid: Include <linux/fb.h>
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 02/10] drm/client: Add acquire_outputs callback; implement for fbdev emulation Thomas Zimmermann
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
We currently get <linux/fb.h> via <linux/vga_switcheroo.h>. Include it
explicitly.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/drm_edid.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 07970e5b5f65..86ae2d8d4de2 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -32,6 +32,7 @@
#include <linux/byteorder/generic.h>
#include <linux/cec.h>
#include <linux/export.h>
+#include <linux/fb.h> /* for KHZ2PICOS() */
#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 02/10] drm/client: Add acquire_outputs callback; implement for fbdev emulation
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 01/10] drm/edid: Include <linux/fb.h> Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 03/10] vga_switcheroo: Add pre_switch callback to client ops Thomas Zimmermann
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
Add the callback acquire_outputs to drm_client_funcs to inform an internal
DRM client that vga-switcheroo is about to switch the physical outputs to
the client's device. Allows the client to prepare its internal state for
the upcoming switch.
Wire up the DRM client helpers to invoke the helper for a device's
clients.
Implement acquire_outputs for fbdev emulation. Invoke fb_switch_outputs(),
which remaps framebuffers to virtual terminals in fbcon. Currently this
is still being done by vga-switcheroo. With more DRM clients becoming
available, vga-switcheroo needs to become client agonostic.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/clients/drm_fbdev_client.c | 23 +++++++++++++++-------
drivers/gpu/drm/drm_client_event.c | 18 +++++++++++++++++
include/drm/drm_client.h | 14 +++++++++++++
include/drm/drm_client_event.h | 3 +++
4 files changed, 51 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/clients/drm_fbdev_client.c b/drivers/gpu/drm/clients/drm_fbdev_client.c
index 91d196a397cf..827f32668714 100644
--- a/drivers/gpu/drm/clients/drm_fbdev_client.c
+++ b/drivers/gpu/drm/clients/drm_fbdev_client.c
@@ -47,6 +47,14 @@ static int drm_fbdev_client_restore(struct drm_client_dev *client, bool force)
return 0;
}
+static void drm_fbdev_client_acquire_outputs(struct drm_client_dev *client)
+{
+ struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+
+ if (fb_helper->info)
+ fb_switch_outputs(fb_helper->info);
+}
+
static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
{
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
@@ -95,13 +103,14 @@ static int drm_fbdev_client_resume(struct drm_client_dev *client)
}
static const struct drm_client_funcs drm_fbdev_client_funcs = {
- .owner = THIS_MODULE,
- .free = drm_fbdev_client_free,
- .unregister = drm_fbdev_client_unregister,
- .restore = drm_fbdev_client_restore,
- .hotplug = drm_fbdev_client_hotplug,
- .suspend = drm_fbdev_client_suspend,
- .resume = drm_fbdev_client_resume,
+ .owner = THIS_MODULE,
+ .free = drm_fbdev_client_free,
+ .unregister = drm_fbdev_client_unregister,
+ .restore = drm_fbdev_client_restore,
+ .acquire_outputs = drm_fbdev_client_acquire_outputs,
+ .hotplug = drm_fbdev_client_hotplug,
+ .suspend = drm_fbdev_client_suspend,
+ .resume = drm_fbdev_client_resume,
};
/**
diff --git a/drivers/gpu/drm/drm_client_event.c b/drivers/gpu/drm/drm_client_event.c
index 7b3e362f7926..f0af584da23c 100644
--- a/drivers/gpu/drm/drm_client_event.c
+++ b/drivers/gpu/drm/drm_client_event.c
@@ -123,6 +123,24 @@ void drm_client_dev_restore(struct drm_device *dev, bool force)
mutex_unlock(&dev->clientlist_mutex);
}
+void drm_client_dev_acquire_outputs(struct drm_device *dev)
+{
+ struct drm_client_dev *client;
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return;
+
+ mutex_lock(&dev->clientlist_mutex);
+ list_for_each_entry(client, &dev->clientlist, list) {
+ if (!client->funcs || !client->funcs->acquire_outputs)
+ continue;
+
+ client->funcs->acquire_outputs(client);
+ }
+ mutex_unlock(&dev->clientlist_mutex);
+}
+EXPORT_SYMBOL(drm_client_dev_acquire_outputs);
+
static int drm_client_suspend(struct drm_client_dev *client)
{
struct drm_device *dev = client->dev;
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 49a21f3dcb36..10a0cae3e48f 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -66,6 +66,20 @@ struct drm_client_funcs {
*/
int (*restore)(struct drm_client_dev *client, bool force);
+ /**
+ * @acquire_outputs:
+ *
+ * Called by vga-switcheroo. Informs the client that the outputs will
+ * be switched to its device. When @acquire_outputs runs, the outputs
+ * have not been switched yet. The client should only prepare the software
+ * state. After the switch happened, the client might get a hotplug
+ * event to update the hardware state.
+ *
+ * This callback exists for remapping framebuffers to virtual terminals
+ * in fbcon.
+ */
+ void (*acquire_outputs)(struct drm_client_dev *client);
+
/**
* @hotplug:
*
diff --git a/include/drm/drm_client_event.h b/include/drm/drm_client_event.h
index 79369c755bc9..c93f404bae1d 100644
--- a/include/drm/drm_client_event.h
+++ b/include/drm/drm_client_event.h
@@ -11,6 +11,7 @@ struct drm_device;
void drm_client_dev_unregister(struct drm_device *dev);
void drm_client_dev_hotplug(struct drm_device *dev);
void drm_client_dev_restore(struct drm_device *dev, bool force);
+void drm_client_dev_acquire_outputs(struct drm_device *dev);
void drm_client_dev_suspend(struct drm_device *dev);
void drm_client_dev_resume(struct drm_device *dev);
#else
@@ -20,6 +21,8 @@ static inline void drm_client_dev_hotplug(struct drm_device *dev)
{ }
static inline void drm_client_dev_restore(struct drm_device *dev, bool force)
{ }
+static inline void drm_client_dev_acquire_outputs(struct drm_device *dev)
+{ }
static inline void drm_client_dev_suspend(struct drm_device *dev)
{ }
static inline void drm_client_dev_resume(struct drm_device *dev)
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 03/10] vga_switcheroo: Add pre_switch callback to client ops
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 01/10] drm/edid: Include <linux/fb.h> Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 02/10] drm/client: Add acquire_outputs callback; implement for fbdev emulation Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 04/10] vga_switcheroo: Add post_switch " Thomas Zimmermann
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
Add pre_switch to struct vga_switcheroo_client_ops to inform the
switcheroo client about upcoming switches of the outputs.
This callback is intended to replace the hard-coded call to fbdev's
fb_switch_outputs(). With DRM supporting more clients than just fbdev
emulation, something more flexible is required.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/vga/vga_switcheroo.c | 4 +++-
include/linux/vga_switcheroo.h | 12 +++++++++---
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 22cf52b78b75..bdf1e56ae891 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -733,8 +733,10 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (!active->driver_power_control)
set_audio_state(active->id, VGA_SWITCHEROO_OFF);
+ if (new_client->ops->pre_switch)
+ new_client->ops->pre_switch(new_client->pdev);
#if defined(CONFIG_FB)
- if (new_client->fb_info)
+ else if (new_client->fb_info)
fb_switch_outputs(new_client->fb_info);
#endif
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 7e6ac0114d55..d2ce30d8b6f7 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -127,23 +127,29 @@ struct vga_switcheroo_handler {
* @set_gpu_state: do the equivalent of suspend/resume for the card.
* Mandatory. This should not cut power to the discrete GPU,
* which is the job of the handler
+ * @gpu_bound: Optional. Called before switching the outputs to the device.
* @reprobe: poll outputs.
* Optional. This gets called after waking the GPU and switching
* the outputs to it
* @can_switch: check if the device is in a position to switch now.
* Mandatory. The client should return false if a user space process
* has one of its device files open
+ * @pre_switch: prepare switch
+ * Optional. This gets called before switching the outputs to the
+ * GPU. Allows drivers to prepare for the switch.
* @gpu_bound: notify the client id to audio client when the GPU is bound.
*
* Client callbacks. A client can be either a GPU or an audio device on a GPU.
- * The @set_gpu_state and @can_switch methods are mandatory, @reprobe may be
- * set to NULL. For audio clients, the @reprobe member is bogus.
- * OTOH, @gpu_bound is only for audio clients, and not used for GPU clients.
+ * The @set_gpu_state and @can_switch methods are mandatory, @pre_switch and
+ * @reprobe may be set to NULL. For audio clients, the @pre_switch and
+ * @reprobe members are bogus. OTOH, @gpu_bound is only for audio clients,
+ * and not used for GPU clients.
*/
struct vga_switcheroo_client_ops {
void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state);
void (*reprobe)(struct pci_dev *dev);
bool (*can_switch)(struct pci_dev *dev);
+ void (*pre_switch)(struct pci_dev *dev);
void (*gpu_bound)(struct pci_dev *dev, enum vga_switcheroo_client_id);
};
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 04/10] vga_switcheroo: Add post_switch callback to client ops
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
` (2 preceding siblings ...)
2026-07-07 13:38 ` [PATCH 03/10] vga_switcheroo: Add pre_switch callback to client ops Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 05/10] drm/amdgpu: Implement struct vga_switcheroo_client_ops.pre_switch Thomas Zimmermann
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
Add post_switch to struct vga_switcheroo_client_ops to inform the
switcheroo client about a completed switch of the output.
This callback is intended to replace the reprobe client op. It is a
rename of reprobe for consistency with pre_switch.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/vga/vga_switcheroo.c | 4 +++-
include/linux/vga_switcheroo.h | 12 +++++++-----
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index bdf1e56ae891..7b0af4a8aa7d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -746,7 +746,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (ret)
return ret;
- if (new_client->ops->reprobe)
+ if (new_client->ops->post_switch)
+ new_client->ops->post_switch(new_client->pdev);
+ else if (new_client->ops->reprobe)
new_client->ops->reprobe(new_client->pdev);
if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON)
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index d2ce30d8b6f7..38047fe6ea60 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -128,21 +128,22 @@ struct vga_switcheroo_handler {
* Mandatory. This should not cut power to the discrete GPU,
* which is the job of the handler
* @gpu_bound: Optional. Called before switching the outputs to the device.
- * @reprobe: poll outputs.
- * Optional. This gets called after waking the GPU and switching
- * the outputs to it
+ * @reprobe: deprecated
* @can_switch: check if the device is in a position to switch now.
* Mandatory. The client should return false if a user space process
* has one of its device files open
* @pre_switch: prepare switch
* Optional. This gets called before switching the outputs to the
* GPU. Allows drivers to prepare for the switch.
+ * @post_switch: completes switch
+ * Optional. This gets called after waking the GPU and switching
+ * the outputs to it. Allows drivers to poll the switched outputs.
* @gpu_bound: notify the client id to audio client when the GPU is bound.
*
* Client callbacks. A client can be either a GPU or an audio device on a GPU.
* The @set_gpu_state and @can_switch methods are mandatory, @pre_switch and
- * @reprobe may be set to NULL. For audio clients, the @pre_switch and
- * @reprobe members are bogus. OTOH, @gpu_bound is only for audio clients,
+ * @post_switch may be set to NULL. For audio clients, the @pre_switch and
+ * @post_switch members are bogus. OTOH, @gpu_bound is only for audio clients,
* and not used for GPU clients.
*/
struct vga_switcheroo_client_ops {
@@ -150,6 +151,7 @@ struct vga_switcheroo_client_ops {
void (*reprobe)(struct pci_dev *dev);
bool (*can_switch)(struct pci_dev *dev);
void (*pre_switch)(struct pci_dev *dev);
+ void (*post_switch)(struct pci_dev *dev);
void (*gpu_bound)(struct pci_dev *dev, enum vga_switcheroo_client_id);
};
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 05/10] drm/amdgpu: Implement struct vga_switcheroo_client_ops.pre_switch
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
` (3 preceding siblings ...)
2026-07-07 13:38 ` [PATCH 04/10] vga_switcheroo: Add post_switch " Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 06/10] drm/i915: Implement vga_switcheroo_client_ops.pre_switch Thomas Zimmermann
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
Call drm_client_dev_acquire_outputs() from vga_switcheroo's pre_switch
callback. Pushes fbcon updates from vga_switcheroo into DRM's fbdev
emulation.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 78c96c7102e4..87a59a79a019 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1699,10 +1699,18 @@ static bool amdgpu_switcheroo_can_switch(struct pci_dev *pdev)
return atomic_read(&dev->open_count) == 0;
}
+static void amdgpu_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ drm_client_dev_acquire_outputs(dev);
+}
+
static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = {
.set_gpu_state = amdgpu_switcheroo_set_state,
.reprobe = NULL,
.can_switch = amdgpu_switcheroo_can_switch,
+ .pre_switch = amdgpu_switcheroo_pre_switch,
};
/**
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 06/10] drm/i915: Implement vga_switcheroo_client_ops.pre_switch
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
` (4 preceding siblings ...)
2026-07-07 13:38 ` [PATCH 05/10] drm/amdgpu: Implement struct vga_switcheroo_client_ops.pre_switch Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 07/10] drm/nouveau: " Thomas Zimmermann
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
Call drm_client_dev_acquire_outputs() from vga_switcheroo's pre_switch
callback. Pushes fbcon updates from vga_switcheroo into DRM's fbdev
emulation.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/i915/i915_switcheroo.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_switcheroo.c b/drivers/gpu/drm/i915/i915_switcheroo.c
index 7e0791024282..6b306ece0556 100644
--- a/drivers/gpu/drm/i915/i915_switcheroo.c
+++ b/drivers/gpu/drm/i915/i915_switcheroo.c
@@ -5,6 +5,7 @@
#include <linux/vga_switcheroo.h>
+#include <drm/drm_client_event.h>
#include <drm/drm_print.h>
#include "display/intel_display_device.h"
@@ -58,10 +59,19 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
atomic_read(&i915->drm.open_count) == 0;
}
+static void i915_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+ struct drm_i915_private *i915 = pdev_to_i915(pdev);
+
+ if (i915 && intel_display_device_present(i915->display))
+ drm_client_dev_acquire_outputs(&i915->drm);
+}
+
static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
.set_gpu_state = i915_switcheroo_set_state,
.reprobe = NULL,
.can_switch = i915_switcheroo_can_switch,
+ .pre_switch = i915_switcheroo_pre_switch,
};
int i915_switcheroo_register(struct drm_i915_private *i915)
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 07/10] drm/nouveau: Implement vga_switcheroo_client_ops.pre_switch
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
` (5 preceding siblings ...)
2026-07-07 13:38 ` [PATCH 06/10] drm/i915: Implement vga_switcheroo_client_ops.pre_switch Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 08/10] drm/nouveau: Implement vga_switcheroo_client_ops.post_switch Thomas Zimmermann
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
Call drm_client_dev_acquire_outputs() from vga_switcheroo's pre_switch
callback. Pushes fbcon updates from vga_switcheroo into DRM's fbdev
emulation.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/nouveau/nouveau_vga.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
index a6c375a24154..2d2d08be8fbe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -76,11 +76,20 @@ nouveau_switcheroo_can_switch(struct pci_dev *pdev)
return atomic_read(&drm->dev->open_count) == 0;
}
+static void
+nouveau_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+ struct nouveau_drm *drm = pci_get_drvdata(pdev);
+
+ drm_client_dev_acquire_outputs(drm->dev);
+}
+
static const struct vga_switcheroo_client_ops
nouveau_switcheroo_ops = {
.set_gpu_state = nouveau_switcheroo_set_state,
.reprobe = nouveau_switcheroo_reprobe,
.can_switch = nouveau_switcheroo_can_switch,
+ .pre_switch = nouveau_switcheroo_pre_switch,
};
void
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 08/10] drm/nouveau: Implement vga_switcheroo_client_ops.post_switch
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
` (6 preceding siblings ...)
2026-07-07 13:38 ` [PATCH 07/10] drm/nouveau: " Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 09/10] drm/radeon: Implement struct vga_switcheroo_client_ops.pre_switch Thomas Zimmermann
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
An output's attached display might have changed while a DRM client's
device did not have the output switched to it.
The nouveau_switcheroo_reprobe() callback sends a hotplug notice to
DRM's internal clients, wo that they can reconfigure their display
output if necessary.
As post_switch callback replaces reprobe in vga_switcheroo, update
nouveau accordingly. No functional changes.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/nouveau/nouveau_vga.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
index 2d2d08be8fbe..29a801124e56 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -54,15 +54,6 @@ nouveau_switcheroo_set_state(struct pci_dev *pdev,
}
}
-static void
-nouveau_switcheroo_reprobe(struct pci_dev *pdev)
-{
- struct nouveau_drm *drm = pci_get_drvdata(pdev);
- struct drm_device *dev = drm->dev;
-
- drm_client_dev_hotplug(dev);
-}
-
static bool
nouveau_switcheroo_can_switch(struct pci_dev *pdev)
{
@@ -84,12 +75,20 @@ nouveau_switcheroo_pre_switch(struct pci_dev *pdev)
drm_client_dev_acquire_outputs(drm->dev);
}
+static void
+nouveau_switcheroo_post_switch(struct pci_dev *pdev)
+{
+ struct nouveau_drm *drm = pci_get_drvdata(pdev);
+
+ drm_client_dev_hotplug(drm->dev);
+}
+
static const struct vga_switcheroo_client_ops
nouveau_switcheroo_ops = {
.set_gpu_state = nouveau_switcheroo_set_state,
- .reprobe = nouveau_switcheroo_reprobe,
.can_switch = nouveau_switcheroo_can_switch,
.pre_switch = nouveau_switcheroo_pre_switch,
+ .post_switch = nouveau_switcheroo_post_switch,
};
void
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 09/10] drm/radeon: Implement struct vga_switcheroo_client_ops.pre_switch
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
` (7 preceding siblings ...)
2026-07-07 13:38 ` [PATCH 08/10] drm/nouveau: Implement vga_switcheroo_client_ops.post_switch Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-07 13:38 ` [PATCH 10/10] vga-switcheroo: Remove unused interfaces Thomas Zimmermann
2026-07-08 21:56 ` [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients lyude
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
Call drm_client_dev_acquire_outputs() from vga_switcheroo's pre_switch
callback. Pushes fbcon updates from vga_switcheroo into DRM's fbdev
emulation.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/radeon/radeon_device.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 705c012fcf9e..8697a9eb5d13 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1258,10 +1258,18 @@ static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)
return atomic_read(&dev->open_count) == 0;
}
+static void radeon_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ drm_client_dev_acquire_outputs(dev);
+}
+
static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
.set_gpu_state = radeon_switcheroo_set_state,
.reprobe = NULL,
.can_switch = radeon_switcheroo_can_switch,
+ .pre_switch = radeon_switcheroo_pre_switch,
};
/**
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 10/10] vga-switcheroo: Remove unused interfaces
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
` (8 preceding siblings ...)
2026-07-07 13:38 ` [PATCH 09/10] drm/radeon: Implement struct vga_switcheroo_client_ops.pre_switch Thomas Zimmermann
@ 2026-07-07 13:38 ` Thomas Zimmermann
2026-07-08 21:56 ` [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients lyude
10 siblings, 0 replies; 12+ messages in thread
From: Thomas Zimmermann @ 2026-07-07 13:38 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
Remove all unused interfaces that used to implement the functionality
of pre_switch and post_switch.
For pre_switch, drop calls to vga_switcheroo_client_fb_set() from
fbcon. Each client that implements pre_switch holds references to
its resources; either fbcon's fb_info or something else. Also remove
vga_switcheroo_client_fb_set(). This further allows for removing all
symbols and data structures that refer to fbdev; such as fb_info and
fb_switch_outputs().
For post_switch, remove the reprobe callback from the client ops.
Nouveau, the only driver that implemented the interface, now uses
post_switch.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 1 -
drivers/gpu/drm/i915/i915_switcheroo.c | 1 -
drivers/gpu/drm/radeon/radeon_device.c | 1 -
drivers/gpu/vga/vga_switcheroo.c | 37 +++-------------------
drivers/video/fbdev/core/fbcon.c | 8 -----
include/linux/vga_switcheroo.h | 12 +++----
6 files changed, 9 insertions(+), 51 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 87a59a79a019..5bb1567d512d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1708,7 +1708,6 @@ static void amdgpu_switcheroo_pre_switch(struct pci_dev *pdev)
static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = {
.set_gpu_state = amdgpu_switcheroo_set_state,
- .reprobe = NULL,
.can_switch = amdgpu_switcheroo_can_switch,
.pre_switch = amdgpu_switcheroo_pre_switch,
};
diff --git a/drivers/gpu/drm/i915/i915_switcheroo.c b/drivers/gpu/drm/i915/i915_switcheroo.c
index 6b306ece0556..d97057722fde 100644
--- a/drivers/gpu/drm/i915/i915_switcheroo.c
+++ b/drivers/gpu/drm/i915/i915_switcheroo.c
@@ -69,7 +69,6 @@ static void i915_switcheroo_pre_switch(struct pci_dev *pdev)
static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
.set_gpu_state = i915_switcheroo_set_state,
- .reprobe = NULL,
.can_switch = i915_switcheroo_can_switch,
.pre_switch = i915_switcheroo_pre_switch,
};
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 8697a9eb5d13..9523240110a6 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1267,7 +1267,6 @@ static void radeon_switcheroo_pre_switch(struct pci_dev *pdev)
static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
.set_gpu_state = radeon_switcheroo_set_state,
- .reprobe = NULL,
.can_switch = radeon_switcheroo_can_switch,
.pre_switch = radeon_switcheroo_pre_switch,
};
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 7b0af4a8aa7d..9431d83b38a9 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -32,9 +32,9 @@
#include <linux/apple-gmux.h>
#include <linux/debugfs.h>
-#include <linux/fb.h>
+#include <linux/export.h>
#include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
@@ -90,7 +90,6 @@
/**
* struct vga_switcheroo_client - registered client
* @pdev: client pci device
- * @fb_info: framebuffer to which console is remapped on switching
* @pwr_state: current power state if manual power control is used.
* For driver power control, call vga_switcheroo_pwr_state().
* @ops: client callbacks
@@ -105,12 +104,11 @@
* @vga_dev: pci device, indicate which GPU is bound to current audio client
*
* Registered client. A client can be either a GPU or an audio device on a GPU.
- * For audio clients, the @fb_info and @active members are bogus. For GPU
- * clients, the @vga_dev is bogus.
+ * For audio clients, the @active member is bogus. For GPU clients, the @vga_dev
+ * is bogus.
*/
struct vga_switcheroo_client {
struct pci_dev *pdev;
- struct fb_info *fb_info;
enum vga_switcheroo_state pwr_state;
const struct vga_switcheroo_client_ops *ops;
enum vga_switcheroo_client_id id;
@@ -514,27 +512,6 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev)
}
EXPORT_SYMBOL(vga_switcheroo_unregister_client);
-/**
- * vga_switcheroo_client_fb_set() - set framebuffer of a given client
- * @pdev: client pci device
- * @info: framebuffer
- *
- * Set framebuffer of a given client. The console will be remapped to this
- * on switching.
- */
-void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
- struct fb_info *info)
-{
- struct vga_switcheroo_client *client;
-
- mutex_lock(&vgasr_mutex);
- client = find_client_from_pci(&vgasr_priv.clients, pdev);
- if (client)
- client->fb_info = info;
- mutex_unlock(&vgasr_mutex);
-}
-EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
-
/**
* vga_switcheroo_lock_ddc() - temporarily switch DDC lines to a given client
* @pdev: client pci device
@@ -735,10 +712,6 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (new_client->ops->pre_switch)
new_client->ops->pre_switch(new_client->pdev);
-#if defined(CONFIG_FB)
- else if (new_client->fb_info)
- fb_switch_outputs(new_client->fb_info);
-#endif
mutex_lock(&vgasr_priv.mux_hw_lock);
ret = vgasr_priv.handler->switchto(new_client->id);
@@ -748,8 +721,6 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (new_client->ops->post_switch)
new_client->ops->post_switch(new_client->pdev);
- else if (new_client->ops->reprobe)
- new_client->ops->reprobe(new_client->pdev);
if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON)
vga_switchoff(active);
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 9f5c4c101581..974c7dcf5251 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -78,7 +78,6 @@
#include <linux/interrupt.h>
#include <linux/crc32.h> /* For counting font checksums */
#include <linux/uaccess.h>
-#include <linux/vga_switcheroo.h>
#include <asm/irq.h>
#include "fbcon.h"
@@ -2851,9 +2850,6 @@ void fbcon_fb_unregistered(struct fb_info *info)
console_lock();
- if (info->device && dev_is_pci(info->device))
- vga_switcheroo_client_fb_set(to_pci_dev(info->device), NULL);
-
fbcon_registered_fb[info->node] = NULL;
fbcon_num_registered_fb--;
@@ -2987,10 +2983,6 @@ static int do_fb_registered(struct fb_info *info)
}
}
- /* Set the fb info for vga_switcheroo clients. Does nothing otherwise. */
- if (info->device && dev_is_pci(info->device))
- vga_switcheroo_client_fb_set(to_pci_dev(info->device), info);
-
return ret;
}
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 38047fe6ea60..e0198cffb4d6 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -31,8 +31,12 @@
#ifndef _LINUX_VGA_SWITCHEROO_H_
#define _LINUX_VGA_SWITCHEROO_H_
-#include <linux/fb.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+struct device;
+struct dev_pm_domain;
+struct fb_info;
struct pci_dev;
/**
@@ -128,7 +132,6 @@ struct vga_switcheroo_handler {
* Mandatory. This should not cut power to the discrete GPU,
* which is the job of the handler
* @gpu_bound: Optional. Called before switching the outputs to the device.
- * @reprobe: deprecated
* @can_switch: check if the device is in a position to switch now.
* Mandatory. The client should return false if a user space process
* has one of its device files open
@@ -148,7 +151,6 @@ struct vga_switcheroo_handler {
*/
struct vga_switcheroo_client_ops {
void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state);
- void (*reprobe)(struct pci_dev *dev);
bool (*can_switch)(struct pci_dev *dev);
void (*pre_switch)(struct pci_dev *dev);
void (*post_switch)(struct pci_dev *dev);
@@ -164,9 +166,6 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
struct pci_dev *vga_dev);
-void vga_switcheroo_client_fb_set(struct pci_dev *dev,
- struct fb_info *info);
-
int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler,
enum vga_switcheroo_handler_flags_t handler_flags);
void vga_switcheroo_unregister_handler(void);
@@ -186,7 +185,6 @@ void vga_switcheroo_fini_domain_pm_ops(struct device *dev);
static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; }
-static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {}
static inline int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler,
enum vga_switcheroo_handler_flags_t handler_flags) { return 0; }
static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients
2026-07-07 13:38 [PATCH 00/10] vga_switcheroo, drm: Push fbcon handling into DRM clients Thomas Zimmermann
` (9 preceding siblings ...)
2026-07-07 13:38 ` [PATCH 10/10] vga-switcheroo: Remove unused interfaces Thomas Zimmermann
@ 2026-07-08 21:56 ` lyude
10 siblings, 0 replies; 12+ messages in thread
From: lyude @ 2026-07-08 21:56 UTC (permalink / raw)
To: Thomas Zimmermann, lukas, jfalempe, alexander.deucher,
christian.koenig, airlied, simona, maarten.lankhorst, mripard,
jani.nikula, joonas.lahtinen, rodrigo.vivi, tursulin, dakr,
deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews
For both nouveau patches:
Reviewed-by: Lyude Paul <lyude@redhat.com>
On Tue, 2026-07-07 at 15:38 +0200, Thomas Zimmermann wrote:
> Vga_switcheroo currently invokes fb_switch_outputs() to inform fbcon
> about switching of the physical outputs among framebuffer devices.
> But
> new DRM clients to not use fbdev/fbcon and might require their own
> vga_switcheroo support. Let's strictly separate them from each other.
>
> Remove fbdev/fbcon from vga_switcheroo. Introduce a pre_switch
> callback
> for vga_switcheroo clients to do the fbcon update. Allows for
> removing
> all direct interactions between vga_switcheroo and fbdev/fbcon.
>
> Also replace the existing reprobe hook with post_switch for symetry.
>
> At the same time, push the fbcon update into DRM's client for fbdev
> emulation. Do this with the new DRM client callback acquire_outputs,
> so that other clients can have their own handling of vga_switcheroo.
>
> There are only four drivers that support vga_switcheroo: amdgpu,
> radeon, i915 and nouveau. Update each of them with the new callbacks.
> When vga_switcheroo now invokes pre_switch, each DRM driver forwards
> to aquire_outputs and lets the DRM clients handle the new outputs.
>
> Tested with radeon on a notebook with Radeon HD 4225 and HD 5430.
>
> Thomas Zimmermann (10):
> drm/edid: Include <linux/fb.h>
> drm/client: Add acquire_outputs callback; implement for fbdev
> emulation
> vga_switcheroo: Add pre_switch callback to client ops
> vga_switcheroo: Add post_switch callback to client ops
> drm/amdgpu: Implement struct vga_switcheroo_client_ops.pre_switch
> drm/i915: Implement vga_switcheroo_client_ops.pre_switch
> drm/nouveau: Implement vga_switcheroo_client_ops.pre_switch
> drm/nouveau: Implement vga_switcheroo_client_ops.post_switch
> drm/radeon: Implement struct vga_switcheroo_client_ops.pre_switch
> vga-switcheroo: Remove unused interfaces
>
> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 9 ++++-
> drivers/gpu/drm/clients/drm_fbdev_client.c | 23 ++++++++----
> drivers/gpu/drm/drm_client_event.c | 18 ++++++++++
> drivers/gpu/drm/drm_edid.c | 1 +
> drivers/gpu/drm/i915/i915_switcheroo.c | 11 +++++-
> drivers/gpu/drm/nouveau/nouveau_vga.c | 28 +++++++++------
> drivers/gpu/drm/radeon/radeon_device.c | 9 ++++-
> drivers/gpu/vga/vga_switcheroo.c | 41 +++++---------------
> --
> drivers/video/fbdev/core/fbcon.c | 8 -----
> include/drm/drm_client.h | 14 ++++++++
> include/drm/drm_client_event.h | 3 ++
> include/linux/vga_switcheroo.h | 30 +++++++++-------
> 12 files changed, 122 insertions(+), 73 deletions(-)
>
>
> base-commit: cd8abe2554ec7eba16c1d48ab508732bf93534eb
^ permalink raw reply [flat|nested] 12+ messages in thread