Lines Matching +full:e +full:- +full:ddc
2 * vga_switcheroo.c - Support for laptop with dual GPU using one set of outputs
33 #include <linux/apple-gmux.h>
65 * while others can switch just the DDC lines. (To allow EDID probing
71 * handler to control the power state of the discrete GPU, its ->switchto
72 * callback is a no-op for obvious reasons. The discrete GPU is often equipped
86 * a client may alternatively request that the DDC lines are temporarily
88 * only the DDC lines and not the entire output avoids unnecessary
93 * struct vga_switcheroo_client - registered client
105 * interface is a no-op so as not to interfere with runtime pm
131 * struct vgasr_priv - vga_switcheroo private data
143 * (in particular while DDC lines are temporarily switched)
144 * @old_ddc_owner: client to which DDC lines will be switched back on unlock
166 #define client_is_audio(c) ((c)->id & ID_BIT_AUDIO)
168 #define client_id(c) ((c)->id & ~ID_BIT_AUDIO)
192 if (vgasr_priv.handler->init) in vga_switcheroo_enable()
193 vgasr_priv.handler->init(); in vga_switcheroo_enable()
200 ret = vgasr_priv.handler->get_client_id(client->pdev); in vga_switcheroo_enable()
204 client->id = ret; in vga_switcheroo_enable()
212 ret = vgasr_priv.handler->get_client_id(client->vga_dev); in vga_switcheroo_enable()
216 client->id = ret | ID_BIT_AUDIO; in vga_switcheroo_enable()
217 if (client->ops->gpu_bound) in vga_switcheroo_enable()
218 client->ops->gpu_bound(client->pdev, ret); in vga_switcheroo_enable()
226 * vga_switcheroo_register_handler() - register handler
233 * Return: 0 on success, -EINVAL if a handler was already registered.
242 return -EINVAL; in vga_switcheroo_register_handler()
257 * vga_switcheroo_unregister_handler() - unregister handler
278 * vga_switcheroo_handler_flags() - obtain handler flags
302 return -ENOMEM; in register_client()
304 client->pwr_state = VGA_SWITCHEROO_ON; in register_client()
305 client->pdev = pdev; in register_client()
306 client->ops = ops; in register_client()
307 client->id = id; in register_client()
308 client->active = active; in register_client()
309 client->driver_power_control = driver_power_control; in register_client()
310 client->vga_dev = vga_dev; in register_client()
313 list_add_tail(&client->list, &vgasr_priv.clients); in register_client()
326 * vga_switcheroo_register_client - register vga client
337 * Return: 0 on success, -ENOMEM on memory allocation error.
350 * vga_switcheroo_register_audio_client - register audio client
359 * Return: 0 on success, -ENOMEM on memory allocation error, -EINVAL on getting
377 id = vgasr_priv.handler->get_client_id(vga_dev); in vga_switcheroo_register_audio_client()
380 return -EINVAL; in vga_switcheroo_register_audio_client()
383 if (ops->gpu_bound) in vga_switcheroo_register_audio_client()
384 ops->gpu_bound(pdev, id); in vga_switcheroo_register_audio_client()
399 if (client->pdev == pdev) in find_client_from_pci()
411 if (client->id == client_id) in find_client_from_id()
422 if (client->active) in find_active_client()
428 * vga_switcheroo_client_probe_defer() - whether to defer probing a given client
432 * client. Drivers shall invoke this early on in their ->probe callback
433 * and return %-EPROBE_DEFER if it evaluates to %true. Thou shalt not
440 if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { in vga_switcheroo_client_probe_defer()
442 * apple-gmux is needed on pre-retina MacBook Pro in vga_switcheroo_client_probe_defer()
457 if (client->driver_power_control) in vga_switcheroo_pwr_state()
458 if (pm_runtime_enabled(&client->pdev->dev) && in vga_switcheroo_pwr_state()
459 pm_runtime_active(&client->pdev->dev)) in vga_switcheroo_pwr_state()
464 return client->pwr_state; in vga_switcheroo_pwr_state()
468 * vga_switcheroo_get_client_state() - obtain power state of a given client
493 * vga_switcheroo_unregister_client() - unregister client
506 vgasr_priv.registered_clients--; in vga_switcheroo_unregister_client()
507 list_del(&client->list); in vga_switcheroo_unregister_client()
520 * vga_switcheroo_client_fb_set() - set framebuffer of a given client
535 client->fb_info = info; in vga_switcheroo_client_fb_set()
541 * vga_switcheroo_lock_ddc() - temporarily switch DDC lines to a given client
544 * Temporarily switch DDC lines to the client identified by @pdev
546 * This allows the inactive client to probe EDID. The DDC lines must
550 * Return: Previous DDC owner on success or a negative int on error.
551 * Specifically, %-ENODEV if no handler has registered or if the handler
552 * does not support switching the DDC lines. Also, a negative value
557 * which will be %NULL if DDC switching failed.
564 if (!vgasr_priv.handler || !vgasr_priv.handler->switch_ddc) { in vga_switcheroo_lock_ddc()
565 vgasr_priv.old_ddc_owner = -ENODEV; in vga_switcheroo_lock_ddc()
566 return -ENODEV; in vga_switcheroo_lock_ddc()
569 id = vgasr_priv.handler->get_client_id(pdev); in vga_switcheroo_lock_ddc()
570 vgasr_priv.old_ddc_owner = vgasr_priv.handler->switch_ddc(id); in vga_switcheroo_lock_ddc()
576 * vga_switcheroo_unlock_ddc() - switch DDC lines back to previous owner
579 * Switch DDC lines back to the previous owner after calling
583 * Return: Previous DDC owner on success (i.e. the client identifier of @pdev)
585 * Specifically, %-ENODEV if no handler has registered or if the handler
586 * does not support switching the DDC lines. Also, a negative value
589 * first is not allowed and will result in %-EINVAL.
597 return -EINVAL; in vga_switcheroo_unlock_ddc()
600 id = vgasr_priv.handler->get_client_id(pdev); in vga_switcheroo_unlock_ddc()
602 ret = vgasr_priv.handler->switch_ddc( in vga_switcheroo_unlock_ddc()
623 * Prerequisite is that no user space processes (e.g. Xorg, alsactl)
632 * * MIGD: Mux-only switch to the integrated graphics device.
637 * * MDIS: Mux-only switch to the discrete graphics device.
640 * the ON and OFF commands are a no-op (see next section).
656 client_is_vga(client) ? "" : "-Audio", in vga_switcheroo_show()
657 client->active ? '+' : ' ', in vga_switcheroo_show()
658 client->driver_power_control ? "Dyn" : "", in vga_switcheroo_show()
660 pci_name(client->pdev)); in vga_switcheroo_show()
674 if (client->driver_power_control) in vga_switchon()
676 if (vgasr_priv.handler->power_state) in vga_switchon()
677 vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON); in vga_switchon()
679 client->ops->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON); in vga_switchon()
680 client->pwr_state = VGA_SWITCHEROO_ON; in vga_switchon()
686 if (client->driver_power_control) in vga_switchoff()
689 client->ops->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF); in vga_switchoff()
690 if (vgasr_priv.handler->power_state) in vga_switchoff()
691 vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF); in vga_switchoff()
692 client->pwr_state = VGA_SWITCHEROO_OFF; in vga_switchoff()
703 client->ops->set_gpu_state(client->pdev, state); in set_audio_state()
718 vga_set_default_device(new_client->pdev); in vga_switchto_stage1()
732 active->active = false; in vga_switchto_stage2()
735 if (!active->driver_power_control) in vga_switchto_stage2()
736 set_audio_state(active->id, VGA_SWITCHEROO_OFF); in vga_switchto_stage2()
738 if (new_client->fb_info) in vga_switchto_stage2()
739 fbcon_remap_all(new_client->fb_info); in vga_switchto_stage2()
742 ret = vgasr_priv.handler->switchto(new_client->id); in vga_switchto_stage2()
747 if (new_client->ops->reprobe) in vga_switchto_stage2()
748 new_client->ops->reprobe(new_client->pdev); in vga_switchto_stage2()
754 if (!new_client->driver_power_control) in vga_switchto_stage2()
755 set_audio_state(new_client->id, VGA_SWITCHEROO_ON); in vga_switchto_stage2()
757 new_client->active = true; in vga_switchto_stage2()
766 if (!client->ops->can_switch(client->pdev)) { in check_can_switch()
767 pr_err("client %x refused switch\n", client->id); in check_can_switch()
789 return -EFAULT; in vga_switcheroo_debugfs_write()
794 cnt = -EINVAL; in vga_switcheroo_debugfs_write()
801 if (client->active || client_is_audio(client)) in vga_switcheroo_debugfs_write()
803 if (client->driver_power_control) in vga_switcheroo_debugfs_write()
805 set_audio_state(client->id, VGA_SWITCHEROO_OFF); in vga_switcheroo_debugfs_write()
806 if (client->pwr_state == VGA_SWITCHEROO_ON) in vga_switcheroo_debugfs_write()
814 if (client->active || client_is_audio(client)) in vga_switcheroo_debugfs_write()
816 if (client->driver_power_control) in vga_switcheroo_debugfs_write()
818 if (client->pwr_state == VGA_SWITCHEROO_OFF) in vga_switcheroo_debugfs_write()
820 set_audio_state(client->id, VGA_SWITCHEROO_ON); in vga_switcheroo_debugfs_write()
825 /* request a delayed switch - test can we switch now */ in vga_switcheroo_debugfs_write()
861 ret = vgasr_priv.handler->switchto(client_id); in vga_switcheroo_debugfs_write()
866 if (client->active) in vga_switcheroo_debugfs_write()
869 /* okay we want a switch - test if devices are willing to switch */ in vga_switcheroo_debugfs_write()
885 pr_info("setting delayed switch to client %d\n", client->id); in vga_switcheroo_debugfs_write()
910 debugfs_remove_recursive(priv->debugfs_root); in vga_switcheroo_debugfs_fini()
911 priv->debugfs_root = NULL; in vga_switcheroo_debugfs_fini()
917 if (priv->debugfs_root) in vga_switcheroo_debugfs_init()
920 priv->debugfs_root = debugfs_create_dir("vgaswitcheroo", NULL); in vga_switcheroo_debugfs_init()
922 debugfs_create_file("switch", 0644, priv->debugfs_root, NULL, in vga_switcheroo_debugfs_init()
927 * vga_switcheroo_process_delayed_switch() - helper for delayed switching
931 * Return: 0 on success. -EINVAL if no delayed switch is pending, if the client
939 int err = -EINVAL; in vga_switcheroo_process_delayed_switch()
971 * the ON and OFF commands become a no-op for the discrete GPU.
999 if (!vgasr_priv.handler->power_state) in vga_switcheroo_power_switch()
1006 if (!client->driver_power_control) in vga_switcheroo_power_switch()
1009 vgasr_priv.handler->power_state(client->id, state); in vga_switcheroo_power_switch()
1018 ret = dev->bus->pm->runtime_suspend(dev); in vga_switcheroo_runtime_suspend()
1022 if (vgasr_priv.handler->switchto) { in vga_switcheroo_runtime_suspend()
1024 vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD); in vga_switcheroo_runtime_suspend()
1027 pci_bus_set_current_state(pdev->bus, PCI_D3cold); in vga_switcheroo_runtime_suspend()
1040 pci_resume_bus(pdev->bus); in vga_switcheroo_runtime_resume()
1041 return dev->bus->pm->runtime_resume(dev); in vga_switcheroo_runtime_resume()
1045 * vga_switcheroo_init_domain_pm_ops() - helper for driver power control
1060 if (dev->bus && dev->bus->pm) { in vga_switcheroo_init_domain_pm_ops()
1061 domain->ops = *dev->bus->pm; in vga_switcheroo_init_domain_pm_ops()
1062 domain->ops.runtime_suspend = vga_switcheroo_runtime_suspend; in vga_switcheroo_init_domain_pm_ops()
1063 domain->ops.runtime_resume = vga_switcheroo_runtime_resume; in vga_switcheroo_init_domain_pm_ops()
1069 return -EINVAL; in vga_switcheroo_init_domain_pm_ops()