diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl index 49c97913c5ae..d6579d8c1341 100644 --- a/Documentation/DocBook/gpu.tmpl +++ b/Documentation/DocBook/gpu.tmpl @@ -3422,6 +3422,7 @@ int num_ioctls; Public constants +!Finclude/linux/vga_switcheroo.h vga_switcheroo_handler_flags_t !Finclude/linux/vga_switcheroo.h vga_switcheroo_client_id !Finclude/linux/vga_switcheroo.h vga_switcheroo_state diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index 3c895863fcf5..fa948dcbdd5d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -552,13 +552,14 @@ static bool amdgpu_atpx_detect(void) void amdgpu_register_atpx_handler(void) { bool r; + enum vga_switcheroo_handler_flags_t handler_flags = 0; /* detect if we have any ATPX + 2 VGA in the system */ r = amdgpu_atpx_detect(); if (!r) return; - vga_switcheroo_register_handler(&amdgpu_atpx_handler); + vga_switcheroo_register_handler(&amdgpu_atpx_handler, handler_flags); } /** diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index d5e6938cc6bc..cdf522770cfa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -314,7 +314,7 @@ void nouveau_register_dsm_handler(void) if (!r) return; - vga_switcheroo_register_handler(&nouveau_dsm_handler); + vga_switcheroo_register_handler(&nouveau_dsm_handler, 0); } /* Must be called for Optimus models before the card can be turned off */ diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index c4b4f298a283..56482e35d43e 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -551,13 +551,14 @@ static bool radeon_atpx_detect(void) void radeon_register_atpx_handler(void) { bool r; + enum vga_switcheroo_handler_flags_t handler_flags = 0; /* detect if we have any ATPX + 2 VGA in the system */ r = radeon_atpx_detect(); if (!r) return; - vga_switcheroo_register_handler(&radeon_atpx_handler); + vga_switcheroo_register_handler(&radeon_atpx_handler, handler_flags); } /** diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 665ab9fd0e01..e89f6ad5d83e 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -126,6 +126,7 @@ static DEFINE_MUTEX(vgasr_mutex); * (counting only vga clients, not audio clients) * @clients: list of registered clients * @handler: registered handler + * @handler_flags: flags of registered handler * * vga_switcheroo private data. Currently only one vga_switcheroo instance * per system is supported. @@ -142,6 +143,7 @@ struct vgasr_priv { struct list_head clients; const struct vga_switcheroo_handler *handler; + enum vga_switcheroo_handler_flags_t handler_flags; }; #define ID_BIT_AUDIO 0x100 @@ -190,13 +192,15 @@ static void vga_switcheroo_enable(void) /** * vga_switcheroo_register_handler() - register handler * @handler: handler callbacks + * @handler_flags: handler flags * * Register handler. Enable vga_switcheroo if two vga clients have already * registered. * * Return: 0 on success, -EINVAL if a handler was already registered. */ -int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler) +int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler, + enum vga_switcheroo_handler_flags_t handler_flags) { mutex_lock(&vgasr_mutex); if (vgasr_priv.handler) { @@ -205,6 +209,7 @@ int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler } vgasr_priv.handler = handler; + vgasr_priv.handler_flags = handler_flags; if (vga_switcheroo_ready()) { pr_info("enabled\n"); vga_switcheroo_enable(); @@ -222,6 +227,7 @@ EXPORT_SYMBOL(vga_switcheroo_register_handler); void vga_switcheroo_unregister_handler(void) { mutex_lock(&vgasr_mutex); + vgasr_priv.handler_flags = 0; vgasr_priv.handler = NULL; if (vgasr_priv.active) { pr_info("disabled\n"); @@ -232,6 +238,20 @@ void vga_switcheroo_unregister_handler(void) } EXPORT_SYMBOL(vga_switcheroo_unregister_handler); +/** + * vga_switcheroo_handler_flags() - obtain handler flags + * + * Helper for clients to obtain the handler flags bitmask. + * + * Return: Handler flags. A value of 0 means that no handler is registered + * or that the handler has no special capabilities. + */ +enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void) +{ + return vgasr_priv.handler_flags; +} +EXPORT_SYMBOL(vga_switcheroo_handler_flags); + static int register_client(struct pci_dev *pdev, const struct vga_switcheroo_client_ops *ops, enum vga_switcheroo_client_id id, bool active, diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index f236250ac106..c401d4936b65 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -705,7 +705,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) init_completion(&gmux_data->powerchange_done); gmux_enable_interrupts(gmux_data); - if (vga_switcheroo_register_handler(&gmux_handler)) { + if (vga_switcheroo_register_handler(&gmux_handler, 0)) { ret = -ENODEV; goto err_register_handler; } diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h index 69e1d4a1f1b3..a745f4f0f729 100644 --- a/include/linux/vga_switcheroo.h +++ b/include/linux/vga_switcheroo.h @@ -35,6 +35,26 @@ struct pci_dev; +/** + * enum vga_switcheroo_handler_flags_t - handler flags bitmask + * @VGA_SWITCHEROO_CAN_SWITCH_DDC: whether the handler is able to switch the + * DDC lines separately. This signals to clients that they should call + * drm_get_edid_switcheroo() to probe the EDID + * @VGA_SWITCHEROO_NEEDS_EDP_CONFIG: whether the handler is unable to switch + * the AUX channel separately. This signals to clients that the active + * GPU needs to train the link and communicate the link parameters to the + * inactive GPU (mediated by vga_switcheroo). The inactive GPU may then + * skip the AUX handshake and set up its output with these pre-calibrated + * values (DisplayPort specification v1.1a, section 2.5.3.3) + * + * Handler flags bitmask. Used by handlers to declare their capabilities upon + * registering with vga_switcheroo. + */ +enum vga_switcheroo_handler_flags_t { + VGA_SWITCHEROO_CAN_SWITCH_DDC = (1 << 0), + VGA_SWITCHEROO_NEEDS_EDP_CONFIG = (1 << 1), +}; + /** * enum vga_switcheroo_state - client power state * @VGA_SWITCHEROO_OFF: off @@ -132,8 +152,10 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev, 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); +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); +enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void); int vga_switcheroo_process_delayed_switch(void); @@ -150,11 +172,13 @@ 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) { return 0; } +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, const struct vga_switcheroo_client_ops *ops, enum vga_switcheroo_client_id id) { return 0; } static inline void vga_switcheroo_unregister_handler(void) {} +static inline enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void) { return 0; } static inline int vga_switcheroo_process_delayed_switch(void) { return 0; } static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }