Hans de Goede | acc962c | 2018-10-18 17:03:32 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: MIT |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (C) 2013-2017 Oracle Corporation |
| 4 | * This file is based on ast_drv.c |
| 5 | * Copyright 2012 Red Hat Inc. |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 6 | * Authors: Dave Airlie <airlied@redhat.com> |
| 7 | * Michael Thayer <michael.thayer@oracle.com, |
| 8 | * Hans de Goede <hdegoede@redhat.com> |
| 9 | */ |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 10 | #include <linux/console.h> |
Sam Ravnborg | 96bae04 | 2019-01-26 13:25:23 +0100 | [diff] [blame] | 11 | #include <linux/module.h> |
| 12 | #include <linux/pci.h> |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 13 | #include <linux/vt_kern.h> |
| 14 | |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 15 | #include <drm/drm_crtc_helper.h> |
Sam Ravnborg | 96bae04 | 2019-01-26 13:25:23 +0100 | [diff] [blame] | 16 | #include <drm/drm_drv.h> |
| 17 | #include <drm/drm_file.h> |
| 18 | #include <drm/drm_ioctl.h> |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 19 | |
| 20 | #include "vbox_drv.h" |
| 21 | |
Colin Ian King | cb67fa1 | 2017-07-19 10:36:16 +0100 | [diff] [blame] | 22 | static int vbox_modeset = -1; |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 23 | |
| 24 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); |
| 25 | module_param_named(modeset, vbox_modeset, int, 0400); |
| 26 | |
| 27 | static struct drm_driver driver; |
| 28 | |
| 29 | static const struct pci_device_id pciidlist[] = { |
Hans de Goede | 650d4aa | 2018-10-22 16:57:46 +0200 | [diff] [blame] | 30 | { PCI_DEVICE(0x80ee, 0xbeef) }, |
| 31 | { } |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 32 | }; |
| 33 | MODULE_DEVICE_TABLE(pci, pciidlist); |
| 34 | |
Nishka Dasgupta | 596cb85 | 2019-08-13 11:55:48 +0530 | [diff] [blame] | 35 | static const struct drm_fb_helper_funcs vbox_fb_helper_funcs = { |
Hans de Goede | e2c3860 | 2018-09-29 14:18:25 +0200 | [diff] [blame] | 36 | .fb_probe = vboxfb_create, |
| 37 | }; |
| 38 | |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 39 | static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 40 | { |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 41 | struct vbox_private *vbox; |
Fabio Rafael da Rosa | 1daddbc | 2018-06-03 23:24:45 -0300 | [diff] [blame] | 42 | int ret = 0; |
| 43 | |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 44 | if (!vbox_check_supported(VBE_DISPI_ID_HGSMI)) |
| 45 | return -ENODEV; |
| 46 | |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 47 | vbox = kzalloc(sizeof(*vbox), GFP_KERNEL); |
| 48 | if (!vbox) |
| 49 | return -ENOMEM; |
| 50 | |
| 51 | ret = drm_dev_init(&vbox->ddev, &driver, &pdev->dev); |
| 52 | if (ret) { |
| 53 | kfree(vbox); |
| 54 | return ret; |
| 55 | } |
| 56 | |
| 57 | vbox->ddev.pdev = pdev; |
| 58 | vbox->ddev.dev_private = vbox; |
| 59 | pci_set_drvdata(pdev, vbox); |
| 60 | mutex_init(&vbox->hw_mutex); |
Hans de Goede | 1ebafd15 | 2018-09-10 20:30:38 +0200 | [diff] [blame] | 61 | |
| 62 | ret = pci_enable_device(pdev); |
| 63 | if (ret) |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 64 | goto err_dev_put; |
Hans de Goede | 1ebafd15 | 2018-09-10 20:30:38 +0200 | [diff] [blame] | 65 | |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 66 | ret = vbox_hw_init(vbox); |
Fabio Rafael da Rosa | 1daddbc | 2018-06-03 23:24:45 -0300 | [diff] [blame] | 67 | if (ret) |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 68 | goto err_pci_disable; |
| 69 | |
| 70 | ret = vbox_mm_init(vbox); |
| 71 | if (ret) |
| 72 | goto err_hw_fini; |
| 73 | |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 74 | ret = vbox_mode_init(vbox); |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 75 | if (ret) |
| 76 | goto err_mm_fini; |
| 77 | |
| 78 | ret = vbox_irq_init(vbox); |
| 79 | if (ret) |
| 80 | goto err_mode_fini; |
| 81 | |
Hans de Goede | e2c3860 | 2018-09-29 14:18:25 +0200 | [diff] [blame] | 82 | ret = drm_fb_helper_fbdev_setup(&vbox->ddev, &vbox->fb_helper, |
| 83 | &vbox_fb_helper_funcs, 32, |
| 84 | vbox->num_crtcs); |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 85 | if (ret) |
| 86 | goto err_irq_fini; |
Fabio Rafael da Rosa | 1daddbc | 2018-06-03 23:24:45 -0300 | [diff] [blame] | 87 | |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 88 | ret = drm_dev_register(&vbox->ddev, 0); |
Fabio Rafael da Rosa | 1daddbc | 2018-06-03 23:24:45 -0300 | [diff] [blame] | 89 | if (ret) |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 90 | goto err_fbdev_fini; |
Fabio Rafael da Rosa | 1daddbc | 2018-06-03 23:24:45 -0300 | [diff] [blame] | 91 | |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 92 | return 0; |
Fabio Rafael da Rosa | 1daddbc | 2018-06-03 23:24:45 -0300 | [diff] [blame] | 93 | |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 94 | err_fbdev_fini: |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 95 | vbox_fbdev_fini(vbox); |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 96 | err_irq_fini: |
| 97 | vbox_irq_fini(vbox); |
| 98 | err_mode_fini: |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 99 | vbox_mode_fini(vbox); |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 100 | err_mm_fini: |
| 101 | vbox_mm_fini(vbox); |
| 102 | err_hw_fini: |
| 103 | vbox_hw_fini(vbox); |
| 104 | err_pci_disable: |
Hans de Goede | 1ebafd15 | 2018-09-10 20:30:38 +0200 | [diff] [blame] | 105 | pci_disable_device(pdev); |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 106 | err_dev_put: |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 107 | drm_dev_put(&vbox->ddev); |
Fabio Rafael da Rosa | 1daddbc | 2018-06-03 23:24:45 -0300 | [diff] [blame] | 108 | return ret; |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | static void vbox_pci_remove(struct pci_dev *pdev) |
| 112 | { |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 113 | struct vbox_private *vbox = pci_get_drvdata(pdev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 114 | |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 115 | drm_dev_unregister(&vbox->ddev); |
| 116 | vbox_fbdev_fini(vbox); |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 117 | vbox_irq_fini(vbox); |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 118 | vbox_mode_fini(vbox); |
Hans de Goede | d467090 | 2018-09-18 19:44:29 +0200 | [diff] [blame] | 119 | vbox_mm_fini(vbox); |
| 120 | vbox_hw_fini(vbox); |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 121 | drm_dev_put(&vbox->ddev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 122 | } |
| 123 | |
Hans de Goede | 35a703d | 2018-10-22 16:57:47 +0200 | [diff] [blame] | 124 | #ifdef CONFIG_PM_SLEEP |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 125 | static int vbox_pm_suspend(struct device *dev) |
| 126 | { |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 127 | struct vbox_private *vbox = dev_get_drvdata(dev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 128 | int error; |
| 129 | |
Hans de Goede | 438340a | 2018-09-29 14:18:19 +0200 | [diff] [blame] | 130 | error = drm_mode_config_helper_suspend(&vbox->ddev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 131 | if (error) |
| 132 | return error; |
| 133 | |
Hans de Goede | 438340a | 2018-09-29 14:18:19 +0200 | [diff] [blame] | 134 | pci_save_state(vbox->ddev.pdev); |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 135 | pci_disable_device(vbox->ddev.pdev); |
| 136 | pci_set_power_state(vbox->ddev.pdev, PCI_D3hot); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 137 | |
| 138 | return 0; |
| 139 | } |
| 140 | |
| 141 | static int vbox_pm_resume(struct device *dev) |
| 142 | { |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 143 | struct vbox_private *vbox = dev_get_drvdata(dev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 144 | |
Hans de Goede | 3498ea8 | 2018-09-18 19:44:31 +0200 | [diff] [blame] | 145 | if (pci_enable_device(vbox->ddev.pdev)) |
| 146 | return -EIO; |
| 147 | |
Hans de Goede | 438340a | 2018-09-29 14:18:19 +0200 | [diff] [blame] | 148 | return drm_mode_config_helper_resume(&vbox->ddev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | static int vbox_pm_freeze(struct device *dev) |
| 152 | { |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 153 | struct vbox_private *vbox = dev_get_drvdata(dev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 154 | |
Hans de Goede | 438340a | 2018-09-29 14:18:19 +0200 | [diff] [blame] | 155 | return drm_mode_config_helper_suspend(&vbox->ddev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 156 | } |
| 157 | |
| 158 | static int vbox_pm_thaw(struct device *dev) |
| 159 | { |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 160 | struct vbox_private *vbox = dev_get_drvdata(dev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 161 | |
Hans de Goede | 438340a | 2018-09-29 14:18:19 +0200 | [diff] [blame] | 162 | return drm_mode_config_helper_resume(&vbox->ddev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | static int vbox_pm_poweroff(struct device *dev) |
| 166 | { |
Hans de Goede | 0164889 | 2018-09-18 19:44:30 +0200 | [diff] [blame] | 167 | struct vbox_private *vbox = dev_get_drvdata(dev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 168 | |
Hans de Goede | 438340a | 2018-09-29 14:18:19 +0200 | [diff] [blame] | 169 | return drm_mode_config_helper_suspend(&vbox->ddev); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | static const struct dev_pm_ops vbox_pm_ops = { |
| 173 | .suspend = vbox_pm_suspend, |
| 174 | .resume = vbox_pm_resume, |
| 175 | .freeze = vbox_pm_freeze, |
| 176 | .thaw = vbox_pm_thaw, |
| 177 | .poweroff = vbox_pm_poweroff, |
| 178 | .restore = vbox_pm_resume, |
| 179 | }; |
Hans de Goede | 35a703d | 2018-10-22 16:57:47 +0200 | [diff] [blame] | 180 | #endif |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 181 | |
| 182 | static struct pci_driver vbox_pci_driver = { |
| 183 | .name = DRIVER_NAME, |
| 184 | .id_table = pciidlist, |
| 185 | .probe = vbox_pci_probe, |
| 186 | .remove = vbox_pci_remove, |
Hans de Goede | 35a703d | 2018-10-22 16:57:47 +0200 | [diff] [blame] | 187 | #ifdef CONFIG_PM_SLEEP |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 188 | .driver.pm = &vbox_pm_ops, |
Hans de Goede | 35a703d | 2018-10-22 16:57:47 +0200 | [diff] [blame] | 189 | #endif |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 190 | }; |
| 191 | |
| 192 | static const struct file_operations vbox_fops = { |
| 193 | .owner = THIS_MODULE, |
Thomas Zimmermann | 94065bf | 2019-05-08 10:26:28 +0200 | [diff] [blame] | 194 | DRM_VRAM_MM_FILE_OPERATIONS |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 195 | }; |
| 196 | |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 197 | static struct drm_driver driver = { |
| 198 | .driver_features = |
Daniel Vetter | 0424fda | 2019-06-17 17:39:24 +0200 | [diff] [blame] | 199 | DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 200 | |
Hans de Goede | e2c3860 | 2018-09-29 14:18:25 +0200 | [diff] [blame] | 201 | .lastclose = drm_fb_helper_lastclose, |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 202 | |
| 203 | .fops = &vbox_fops, |
| 204 | .irq_handler = vbox_irq_handler, |
| 205 | .name = DRIVER_NAME, |
| 206 | .desc = DRIVER_DESC, |
| 207 | .date = DRIVER_DATE, |
| 208 | .major = DRIVER_MAJOR, |
| 209 | .minor = DRIVER_MINOR, |
| 210 | .patchlevel = DRIVER_PATCHLEVEL, |
| 211 | |
Thomas Zimmermann | 94065bf | 2019-05-08 10:26:28 +0200 | [diff] [blame] | 212 | DRM_GEM_VRAM_DRIVER, |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 213 | }; |
| 214 | |
| 215 | static int __init vbox_init(void) |
| 216 | { |
| 217 | #ifdef CONFIG_VGA_CONSOLE |
| 218 | if (vgacon_text_force() && vbox_modeset == -1) |
| 219 | return -EINVAL; |
| 220 | #endif |
| 221 | |
| 222 | if (vbox_modeset == 0) |
| 223 | return -EINVAL; |
| 224 | |
Stephen Rothwell | e6742e1 | 2017-07-19 11:46:57 +1000 | [diff] [blame] | 225 | return pci_register_driver(&vbox_pci_driver); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 226 | } |
| 227 | |
| 228 | static void __exit vbox_exit(void) |
| 229 | { |
Stephen Rothwell | e6742e1 | 2017-07-19 11:46:57 +1000 | [diff] [blame] | 230 | pci_unregister_driver(&vbox_pci_driver); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 231 | } |
| 232 | |
| 233 | module_init(vbox_init); |
| 234 | module_exit(vbox_exit); |
| 235 | |
| 236 | MODULE_AUTHOR("Oracle Corporation"); |
Hans de Goede | e46b06e1 | 2018-10-22 16:57:48 +0200 | [diff] [blame] | 237 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); |
Hans de Goede | dd55d44 | 2017-07-06 16:06:01 +0200 | [diff] [blame] | 238 | MODULE_DESCRIPTION(DRIVER_DESC); |
| 239 | MODULE_LICENSE("GPL and additional rights"); |