Commit 156d7d41 authored by Lukas Wunner's avatar Lukas Wunner Committed by Daniel Vetter

vga_switcheroo: Add handler flags infrastructure

Allow handlers to declare their capabilities and allow clients to
obtain that information. So far we have these use cases:

* If the handler is able to switch DDC separately, clients need to
  probe EDID with drm_get_edid_switcheroo(). We should allow them
  to detect a capable handler to ensure this function only gets
  called when needed.

* Likewise if the handler is unable to switch AUX separately, the active
  client needs to communicate link training parameters to the inactive
  client, which 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). Clients need a way to recognize such a situation.

The flags for the radeon_atpx_handler and amdgpu_atpx_handler are
initially set to 0, this can later on be amended with
  handler_flags |= VGA_SWITCHEROO_CAN_SWITCH_DDC;
when a ->switch_ddc callback is added.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115Tested-by: default avatarLukas Wunner <lukas@wunner.de>
    [MBP  9,1 2012  intel IVB + nvidia GK107  pre-retina  15"]
Signed-off-by: default avatarLukas Wunner <lukas@wunner.de>
Reviewed-by: default avatarDarren Hart <dvhart@linux.intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/2b0d93ed6e511ca09e95e45e0b35627f330fabce.1452525860.git.lukas@wunner.de
parent e87a52b3
...@@ -3422,6 +3422,7 @@ int num_ioctls;</synopsis> ...@@ -3422,6 +3422,7 @@ int num_ioctls;</synopsis>
</sect1> </sect1>
<sect1> <sect1>
<title>Public constants</title> <title>Public constants</title>
!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_client_id
!Finclude/linux/vga_switcheroo.h vga_switcheroo_state !Finclude/linux/vga_switcheroo.h vga_switcheroo_state
</sect1> </sect1>
......
...@@ -552,13 +552,14 @@ static bool amdgpu_atpx_detect(void) ...@@ -552,13 +552,14 @@ static bool amdgpu_atpx_detect(void)
void amdgpu_register_atpx_handler(void) void amdgpu_register_atpx_handler(void)
{ {
bool r; bool r;
enum vga_switcheroo_handler_flags_t handler_flags = 0;
/* detect if we have any ATPX + 2 VGA in the system */ /* detect if we have any ATPX + 2 VGA in the system */
r = amdgpu_atpx_detect(); r = amdgpu_atpx_detect();
if (!r) if (!r)
return; return;
vga_switcheroo_register_handler(&amdgpu_atpx_handler); vga_switcheroo_register_handler(&amdgpu_atpx_handler, handler_flags);
} }
/** /**
......
...@@ -314,7 +314,7 @@ void nouveau_register_dsm_handler(void) ...@@ -314,7 +314,7 @@ void nouveau_register_dsm_handler(void)
if (!r) if (!r)
return; 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 */ /* Must be called for Optimus models before the card can be turned off */
......
...@@ -551,13 +551,14 @@ static bool radeon_atpx_detect(void) ...@@ -551,13 +551,14 @@ static bool radeon_atpx_detect(void)
void radeon_register_atpx_handler(void) void radeon_register_atpx_handler(void)
{ {
bool r; bool r;
enum vga_switcheroo_handler_flags_t handler_flags = 0;
/* detect if we have any ATPX + 2 VGA in the system */ /* detect if we have any ATPX + 2 VGA in the system */
r = radeon_atpx_detect(); r = radeon_atpx_detect();
if (!r) if (!r)
return; return;
vga_switcheroo_register_handler(&radeon_atpx_handler); vga_switcheroo_register_handler(&radeon_atpx_handler, handler_flags);
} }
/** /**
......
...@@ -126,6 +126,7 @@ static DEFINE_MUTEX(vgasr_mutex); ...@@ -126,6 +126,7 @@ static DEFINE_MUTEX(vgasr_mutex);
* (counting only vga clients, not audio clients) * (counting only vga clients, not audio clients)
* @clients: list of registered clients * @clients: list of registered clients
* @handler: registered handler * @handler: registered handler
* @handler_flags: flags of registered handler
* *
* vga_switcheroo private data. Currently only one vga_switcheroo instance * vga_switcheroo private data. Currently only one vga_switcheroo instance
* per system is supported. * per system is supported.
...@@ -142,6 +143,7 @@ struct vgasr_priv { ...@@ -142,6 +143,7 @@ struct vgasr_priv {
struct list_head clients; struct list_head clients;
const struct vga_switcheroo_handler *handler; const struct vga_switcheroo_handler *handler;
enum vga_switcheroo_handler_flags_t handler_flags;
}; };
#define ID_BIT_AUDIO 0x100 #define ID_BIT_AUDIO 0x100
...@@ -190,13 +192,15 @@ static void vga_switcheroo_enable(void) ...@@ -190,13 +192,15 @@ static void vga_switcheroo_enable(void)
/** /**
* vga_switcheroo_register_handler() - register handler * vga_switcheroo_register_handler() - register handler
* @handler: handler callbacks * @handler: handler callbacks
* @handler_flags: handler flags
* *
* Register handler. Enable vga_switcheroo if two vga clients have already * Register handler. Enable vga_switcheroo if two vga clients have already
* registered. * registered.
* *
* Return: 0 on success, -EINVAL if a handler was 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); mutex_lock(&vgasr_mutex);
if (vgasr_priv.handler) { if (vgasr_priv.handler) {
...@@ -205,6 +209,7 @@ int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler ...@@ -205,6 +209,7 @@ int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler
} }
vgasr_priv.handler = handler; vgasr_priv.handler = handler;
vgasr_priv.handler_flags = handler_flags;
if (vga_switcheroo_ready()) { if (vga_switcheroo_ready()) {
pr_info("enabled\n"); pr_info("enabled\n");
vga_switcheroo_enable(); vga_switcheroo_enable();
...@@ -222,6 +227,7 @@ EXPORT_SYMBOL(vga_switcheroo_register_handler); ...@@ -222,6 +227,7 @@ EXPORT_SYMBOL(vga_switcheroo_register_handler);
void vga_switcheroo_unregister_handler(void) void vga_switcheroo_unregister_handler(void)
{ {
mutex_lock(&vgasr_mutex); mutex_lock(&vgasr_mutex);
vgasr_priv.handler_flags = 0;
vgasr_priv.handler = NULL; vgasr_priv.handler = NULL;
if (vgasr_priv.active) { if (vgasr_priv.active) {
pr_info("disabled\n"); pr_info("disabled\n");
...@@ -232,6 +238,20 @@ void vga_switcheroo_unregister_handler(void) ...@@ -232,6 +238,20 @@ void vga_switcheroo_unregister_handler(void)
} }
EXPORT_SYMBOL(vga_switcheroo_unregister_handler); 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, static int register_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops, const struct vga_switcheroo_client_ops *ops,
enum vga_switcheroo_client_id id, bool active, enum vga_switcheroo_client_id id, bool active,
......
...@@ -705,7 +705,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) ...@@ -705,7 +705,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
init_completion(&gmux_data->powerchange_done); init_completion(&gmux_data->powerchange_done);
gmux_enable_interrupts(gmux_data); gmux_enable_interrupts(gmux_data);
if (vga_switcheroo_register_handler(&gmux_handler)) { if (vga_switcheroo_register_handler(&gmux_handler, 0)) {
ret = -ENODEV; ret = -ENODEV;
goto err_register_handler; goto err_register_handler;
} }
......
...@@ -35,6 +35,26 @@ ...@@ -35,6 +35,26 @@
struct pci_dev; 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 * enum vga_switcheroo_state - client power state
* @VGA_SWITCHEROO_OFF: off * @VGA_SWITCHEROO_OFF: off
...@@ -132,8 +152,10 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev, ...@@ -132,8 +152,10 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
void vga_switcheroo_client_fb_set(struct pci_dev *dev, void vga_switcheroo_client_fb_set(struct pci_dev *dev,
struct fb_info *info); 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); void vga_switcheroo_unregister_handler(void);
enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void);
int vga_switcheroo_process_delayed_switch(void); int vga_switcheroo_process_delayed_switch(void);
...@@ -150,11 +172,13 @@ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {} ...@@ -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, static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; } 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 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, static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops, const struct vga_switcheroo_client_ops *ops,
enum vga_switcheroo_client_id id) { return 0; } enum vga_switcheroo_client_id id) { return 0; }
static inline void vga_switcheroo_unregister_handler(void) {} 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 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; } static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment