1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright (C) 2013-2017 Oracle Corporation 4 * This file is based on ast_drv.c 5 * Copyright 2012 Red Hat Inc. 6 * Authors: Dave Airlie <airlied@redhat.com> 7 * Michael Thayer <michael.thayer@oracle.com, 8 * Hans de Goede <hdegoede@redhat.com> 9 */ 10 #include <linux/module.h> 11 #include <linux/pci.h> 12 #include <linux/vt_kern.h> 13 14 #include <drm/drm_aperture.h> 15 #include <drm/drm_atomic_helper.h> 16 #include <drm/drm_client_setup.h> 17 #include <drm/drm_drv.h> 18 #include <drm/drm_fbdev_ttm.h> 19 #include <drm/drm_file.h> 20 #include <drm/drm_ioctl.h> 21 #include <drm/drm_managed.h> 22 #include <drm/drm_modeset_helper.h> 23 #include <drm/drm_module.h> 24 25 #include "vbox_drv.h" 26 27 static int vbox_modeset = -1; 28 29 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); 30 module_param_named(modeset, vbox_modeset, int, 0400); 31 32 static const struct drm_driver driver; 33 34 static const struct pci_device_id pciidlist[] = { 35 { PCI_DEVICE(0x80ee, 0xbeef) }, 36 { } 37 }; 38 MODULE_DEVICE_TABLE(pci, pciidlist); 39 40 static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 41 { 42 struct vbox_private *vbox; 43 int ret = 0; 44 45 if (!vbox_check_supported(VBE_DISPI_ID_HGSMI)) 46 return -ENODEV; 47 48 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver); 49 if (ret) 50 return ret; 51 52 vbox = devm_drm_dev_alloc(&pdev->dev, &driver, 53 struct vbox_private, ddev); 54 if (IS_ERR(vbox)) 55 return PTR_ERR(vbox); 56 57 pci_set_drvdata(pdev, vbox); 58 mutex_init(&vbox->hw_mutex); 59 60 ret = pcim_enable_device(pdev); 61 if (ret) 62 return ret; 63 64 ret = vbox_hw_init(vbox); 65 if (ret) 66 return ret; 67 68 ret = vbox_mm_init(vbox); 69 if (ret) 70 goto err_hw_fini; 71 72 ret = vbox_mode_init(vbox); 73 if (ret) 74 goto err_hw_fini; 75 76 ret = vbox_irq_init(vbox); 77 if (ret) 78 goto err_mode_fini; 79 80 ret = drm_dev_register(&vbox->ddev, 0); 81 if (ret) 82 goto err_irq_fini; 83 84 drm_client_setup(&vbox->ddev, NULL); 85 86 return 0; 87 88 err_irq_fini: 89 vbox_irq_fini(vbox); 90 err_mode_fini: 91 vbox_mode_fini(vbox); 92 err_hw_fini: 93 vbox_hw_fini(vbox); 94 return ret; 95 } 96 97 static void vbox_pci_remove(struct pci_dev *pdev) 98 { 99 struct vbox_private *vbox = pci_get_drvdata(pdev); 100 101 drm_dev_unregister(&vbox->ddev); 102 drm_atomic_helper_shutdown(&vbox->ddev); 103 vbox_irq_fini(vbox); 104 vbox_mode_fini(vbox); 105 vbox_hw_fini(vbox); 106 } 107 108 static void vbox_pci_shutdown(struct pci_dev *pdev) 109 { 110 struct vbox_private *vbox = pci_get_drvdata(pdev); 111 112 drm_atomic_helper_shutdown(&vbox->ddev); 113 } 114 115 static int vbox_pm_suspend(struct device *dev) 116 { 117 struct vbox_private *vbox = dev_get_drvdata(dev); 118 struct pci_dev *pdev = to_pci_dev(dev); 119 int error; 120 121 error = drm_mode_config_helper_suspend(&vbox->ddev); 122 if (error) 123 return error; 124 125 pci_save_state(pdev); 126 pci_disable_device(pdev); 127 pci_set_power_state(pdev, PCI_D3hot); 128 129 return 0; 130 } 131 132 static int vbox_pm_resume(struct device *dev) 133 { 134 struct vbox_private *vbox = dev_get_drvdata(dev); 135 struct pci_dev *pdev = to_pci_dev(dev); 136 137 if (pci_enable_device(pdev)) 138 return -EIO; 139 140 return drm_mode_config_helper_resume(&vbox->ddev); 141 } 142 143 static int vbox_pm_freeze(struct device *dev) 144 { 145 struct vbox_private *vbox = dev_get_drvdata(dev); 146 147 return drm_mode_config_helper_suspend(&vbox->ddev); 148 } 149 150 static int vbox_pm_thaw(struct device *dev) 151 { 152 struct vbox_private *vbox = dev_get_drvdata(dev); 153 154 return drm_mode_config_helper_resume(&vbox->ddev); 155 } 156 157 static int vbox_pm_poweroff(struct device *dev) 158 { 159 struct vbox_private *vbox = dev_get_drvdata(dev); 160 161 return drm_mode_config_helper_suspend(&vbox->ddev); 162 } 163 164 static const struct dev_pm_ops vbox_pm_ops = { 165 .suspend = vbox_pm_suspend, 166 .resume = vbox_pm_resume, 167 .freeze = vbox_pm_freeze, 168 .thaw = vbox_pm_thaw, 169 .poweroff = vbox_pm_poweroff, 170 .restore = vbox_pm_resume, 171 }; 172 173 static struct pci_driver vbox_pci_driver = { 174 .name = DRIVER_NAME, 175 .id_table = pciidlist, 176 .probe = vbox_pci_probe, 177 .remove = vbox_pci_remove, 178 .shutdown = vbox_pci_shutdown, 179 .driver.pm = pm_sleep_ptr(&vbox_pm_ops), 180 }; 181 182 DEFINE_DRM_GEM_FOPS(vbox_fops); 183 184 static const struct drm_driver driver = { 185 .driver_features = 186 DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_CURSOR_HOTSPOT, 187 188 .fops = &vbox_fops, 189 .name = DRIVER_NAME, 190 .desc = DRIVER_DESC, 191 .date = DRIVER_DATE, 192 .major = DRIVER_MAJOR, 193 .minor = DRIVER_MINOR, 194 .patchlevel = DRIVER_PATCHLEVEL, 195 196 DRM_GEM_VRAM_DRIVER, 197 DRM_FBDEV_TTM_DRIVER_OPS, 198 }; 199 200 drm_module_pci_driver_if_modeset(vbox_pci_driver, vbox_modeset); 201 202 MODULE_AUTHOR("Oracle Corporation"); 203 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 204 MODULE_DESCRIPTION(DRIVER_DESC); 205 MODULE_LICENSE("GPL and additional rights"); 206