Home | History | Annotate | Line # | Download | only in i915
      1  1.1  riastrad /*	$NetBSD: i915_switcheroo.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad // SPDX-License-Identifier: MIT
      4  1.1  riastrad /*
      5  1.1  riastrad  * Copyright  2019 Intel Corporation
      6  1.1  riastrad  */
      7  1.1  riastrad 
      8  1.1  riastrad #include <sys/cdefs.h>
      9  1.1  riastrad __KERNEL_RCSID(0, "$NetBSD: i915_switcheroo.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $");
     10  1.1  riastrad 
     11  1.1  riastrad #include <linux/vga_switcheroo.h>
     12  1.1  riastrad 
     13  1.1  riastrad #include "i915_drv.h"
     14  1.1  riastrad #include "i915_switcheroo.h"
     15  1.1  riastrad 
     16  1.1  riastrad static void i915_switcheroo_set_state(struct pci_dev *pdev,
     17  1.1  riastrad 				      enum vga_switcheroo_state state)
     18  1.1  riastrad {
     19  1.1  riastrad 	struct drm_i915_private *i915 = pdev_to_i915(pdev);
     20  1.1  riastrad 	pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
     21  1.1  riastrad 
     22  1.1  riastrad 	if (!i915) {
     23  1.1  riastrad 		dev_err(&pdev->dev, "DRM not initialized, aborting switch.\n");
     24  1.1  riastrad 		return;
     25  1.1  riastrad 	}
     26  1.1  riastrad 
     27  1.1  riastrad 	if (state == VGA_SWITCHEROO_ON) {
     28  1.1  riastrad 		pr_info("switched on\n");
     29  1.1  riastrad 		i915->drm.switch_power_state = DRM_SWITCH_POWER_CHANGING;
     30  1.1  riastrad 		/* i915 resume handler doesn't set to D0 */
     31  1.1  riastrad 		pci_set_power_state(pdev, PCI_D0);
     32  1.1  riastrad 		i915_resume_switcheroo(i915);
     33  1.1  riastrad 		i915->drm.switch_power_state = DRM_SWITCH_POWER_ON;
     34  1.1  riastrad 	} else {
     35  1.1  riastrad 		pr_info("switched off\n");
     36  1.1  riastrad 		i915->drm.switch_power_state = DRM_SWITCH_POWER_CHANGING;
     37  1.1  riastrad 		i915_suspend_switcheroo(i915, pmm);
     38  1.1  riastrad 		i915->drm.switch_power_state = DRM_SWITCH_POWER_OFF;
     39  1.1  riastrad 	}
     40  1.1  riastrad }
     41  1.1  riastrad 
     42  1.1  riastrad static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
     43  1.1  riastrad {
     44  1.1  riastrad 	struct drm_i915_private *i915 = pdev_to_i915(pdev);
     45  1.1  riastrad 
     46  1.1  riastrad 	/*
     47  1.1  riastrad 	 * FIXME: open_count is protected by drm_global_mutex but that would lead to
     48  1.1  riastrad 	 * locking inversion with the driver load path. And the access here is
     49  1.1  riastrad 	 * completely racy anyway. So don't bother with locking for now.
     50  1.1  riastrad 	 */
     51  1.1  riastrad 	return i915 && i915->drm.open_count == 0;
     52  1.1  riastrad }
     53  1.1  riastrad 
     54  1.1  riastrad static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
     55  1.1  riastrad 	.set_gpu_state = i915_switcheroo_set_state,
     56  1.1  riastrad 	.reprobe = NULL,
     57  1.1  riastrad 	.can_switch = i915_switcheroo_can_switch,
     58  1.1  riastrad };
     59  1.1  riastrad 
     60  1.1  riastrad int i915_switcheroo_register(struct drm_i915_private *i915)
     61  1.1  riastrad {
     62  1.1  riastrad 	struct pci_dev *pdev = i915->drm.pdev;
     63  1.1  riastrad 
     64  1.1  riastrad 	return vga_switcheroo_register_client(pdev, &i915_switcheroo_ops, false);
     65  1.1  riastrad }
     66  1.1  riastrad 
     67  1.1  riastrad void i915_switcheroo_unregister(struct drm_i915_private *i915)
     68  1.1  riastrad {
     69  1.1  riastrad 	struct pci_dev *pdev = i915->drm.pdev;
     70  1.1  riastrad 
     71  1.1  riastrad 	vga_switcheroo_unregister_client(pdev);
     72  1.1  riastrad }
     73