1131abc56SHans de Goede // SPDX-License-Identifier: MIT
2131abc56SHans de Goede /*
3131abc56SHans de Goede * Copyright (C) 2013-2017 Oracle Corporation
4131abc56SHans de Goede * This file is based on ast_drv.c
5131abc56SHans de Goede * Copyright 2012 Red Hat Inc.
6131abc56SHans de Goede * Authors: Dave Airlie <airlied@redhat.com>
7131abc56SHans de Goede * Michael Thayer <michael.thayer@oracle.com,
8131abc56SHans de Goede * Hans de Goede <hdegoede@redhat.com>
9131abc56SHans de Goede */
10131abc56SHans de Goede #include <linux/module.h>
11131abc56SHans de Goede #include <linux/pci.h>
12131abc56SHans de Goede #include <linux/vt_kern.h>
13131abc56SHans de Goede
146848c291SThomas Zimmermann #include <drm/drm_aperture.h>
1569f03be1SDouglas Anderson #include <drm/drm_atomic_helper.h>
16131abc56SHans de Goede #include <drm/drm_drv.h>
178ab59da2SThomas Zimmermann #include <drm/drm_fbdev_generic.h>
18131abc56SHans de Goede #include <drm/drm_file.h>
19131abc56SHans de Goede #include <drm/drm_ioctl.h>
20780e41edSDaniel Vetter #include <drm/drm_managed.h>
21ad2a3befSThomas Zimmermann #include <drm/drm_modeset_helper.h>
22ccecfd01SThomas Zimmermann #include <drm/drm_module.h>
23131abc56SHans de Goede
24131abc56SHans de Goede #include "vbox_drv.h"
25131abc56SHans de Goede
26131abc56SHans de Goede static int vbox_modeset = -1;
27131abc56SHans de Goede
28131abc56SHans de Goede MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
29131abc56SHans de Goede module_param_named(modeset, vbox_modeset, int, 0400);
30131abc56SHans de Goede
3170a59dd8SDaniel Vetter static const struct drm_driver driver;
32131abc56SHans de Goede
33131abc56SHans de Goede static const struct pci_device_id pciidlist[] = {
34131abc56SHans de Goede { PCI_DEVICE(0x80ee, 0xbeef) },
35131abc56SHans de Goede { }
36131abc56SHans de Goede };
37131abc56SHans de Goede MODULE_DEVICE_TABLE(pci, pciidlist);
38131abc56SHans de Goede
vbox_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)39131abc56SHans de Goede static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
40131abc56SHans de Goede {
41131abc56SHans de Goede struct vbox_private *vbox;
42131abc56SHans de Goede int ret = 0;
43131abc56SHans de Goede
44131abc56SHans de Goede if (!vbox_check_supported(VBE_DISPI_ID_HGSMI))
45131abc56SHans de Goede return -ENODEV;
46131abc56SHans de Goede
4797c9bfe3SThomas Zimmermann ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver);
48a65a97b4SHans de Goede if (ret)
49a65a97b4SHans de Goede return ret;
50a65a97b4SHans de Goede
5135b24eedSDaniel Vetter vbox = devm_drm_dev_alloc(&pdev->dev, &driver,
5235b24eedSDaniel Vetter struct vbox_private, ddev);
5335b24eedSDaniel Vetter if (IS_ERR(vbox))
5435b24eedSDaniel Vetter return PTR_ERR(vbox);
55131abc56SHans de Goede
56131abc56SHans de Goede pci_set_drvdata(pdev, vbox);
57131abc56SHans de Goede mutex_init(&vbox->hw_mutex);
58131abc56SHans de Goede
598558de40SDaniel Vetter ret = pcim_enable_device(pdev);
60131abc56SHans de Goede if (ret)
6135b24eedSDaniel Vetter return ret;
62131abc56SHans de Goede
63131abc56SHans de Goede ret = vbox_hw_init(vbox);
64131abc56SHans de Goede if (ret)
658558de40SDaniel Vetter return ret;
66131abc56SHans de Goede
67131abc56SHans de Goede ret = vbox_mm_init(vbox);
68131abc56SHans de Goede if (ret)
69131abc56SHans de Goede goto err_hw_fini;
70131abc56SHans de Goede
71131abc56SHans de Goede ret = vbox_mode_init(vbox);
72131abc56SHans de Goede if (ret)
73c6dc899eSThomas Zimmermann goto err_hw_fini;
74131abc56SHans de Goede
75131abc56SHans de Goede ret = vbox_irq_init(vbox);
76131abc56SHans de Goede if (ret)
77131abc56SHans de Goede goto err_mode_fini;
78131abc56SHans de Goede
79131abc56SHans de Goede ret = drm_dev_register(&vbox->ddev, 0);
80131abc56SHans de Goede if (ret)
812695eae1SThomas Zimmermann goto err_irq_fini;
82131abc56SHans de Goede
833662cd19SThomas Zimmermann drm_fbdev_generic_setup(&vbox->ddev, 32);
843662cd19SThomas Zimmermann
85131abc56SHans de Goede return 0;
86131abc56SHans de Goede
87131abc56SHans de Goede err_irq_fini:
88131abc56SHans de Goede vbox_irq_fini(vbox);
89131abc56SHans de Goede err_mode_fini:
90131abc56SHans de Goede vbox_mode_fini(vbox);
91131abc56SHans de Goede err_hw_fini:
92131abc56SHans de Goede vbox_hw_fini(vbox);
93131abc56SHans de Goede return ret;
94131abc56SHans de Goede }
95131abc56SHans de Goede
vbox_pci_remove(struct pci_dev * pdev)96131abc56SHans de Goede static void vbox_pci_remove(struct pci_dev *pdev)
97131abc56SHans de Goede {
98131abc56SHans de Goede struct vbox_private *vbox = pci_get_drvdata(pdev);
99131abc56SHans de Goede
100131abc56SHans de Goede drm_dev_unregister(&vbox->ddev);
10169f03be1SDouglas Anderson drm_atomic_helper_shutdown(&vbox->ddev);
102131abc56SHans de Goede vbox_irq_fini(vbox);
103131abc56SHans de Goede vbox_mode_fini(vbox);
104131abc56SHans de Goede vbox_hw_fini(vbox);
105131abc56SHans de Goede }
106131abc56SHans de Goede
vbox_pci_shutdown(struct pci_dev * pdev)10769f03be1SDouglas Anderson static void vbox_pci_shutdown(struct pci_dev *pdev)
10869f03be1SDouglas Anderson {
10969f03be1SDouglas Anderson struct vbox_private *vbox = pci_get_drvdata(pdev);
11069f03be1SDouglas Anderson
11169f03be1SDouglas Anderson drm_atomic_helper_shutdown(&vbox->ddev);
11269f03be1SDouglas Anderson }
11369f03be1SDouglas Anderson
vbox_pm_suspend(struct device * dev)114131abc56SHans de Goede static int vbox_pm_suspend(struct device *dev)
115131abc56SHans de Goede {
116131abc56SHans de Goede struct vbox_private *vbox = dev_get_drvdata(dev);
11756492fe9SThomas Zimmermann struct pci_dev *pdev = to_pci_dev(dev);
118131abc56SHans de Goede int error;
119131abc56SHans de Goede
120131abc56SHans de Goede error = drm_mode_config_helper_suspend(&vbox->ddev);
121131abc56SHans de Goede if (error)
122131abc56SHans de Goede return error;
123131abc56SHans de Goede
12456492fe9SThomas Zimmermann pci_save_state(pdev);
12556492fe9SThomas Zimmermann pci_disable_device(pdev);
12656492fe9SThomas Zimmermann pci_set_power_state(pdev, PCI_D3hot);
127131abc56SHans de Goede
128131abc56SHans de Goede return 0;
129131abc56SHans de Goede }
130131abc56SHans de Goede
vbox_pm_resume(struct device * dev)131131abc56SHans de Goede static int vbox_pm_resume(struct device *dev)
132131abc56SHans de Goede {
133131abc56SHans de Goede struct vbox_private *vbox = dev_get_drvdata(dev);
13456492fe9SThomas Zimmermann struct pci_dev *pdev = to_pci_dev(dev);
135131abc56SHans de Goede
13656492fe9SThomas Zimmermann if (pci_enable_device(pdev))
137131abc56SHans de Goede return -EIO;
138131abc56SHans de Goede
139131abc56SHans de Goede return drm_mode_config_helper_resume(&vbox->ddev);
140131abc56SHans de Goede }
141131abc56SHans de Goede
vbox_pm_freeze(struct device * dev)142131abc56SHans de Goede static int vbox_pm_freeze(struct device *dev)
143131abc56SHans de Goede {
144131abc56SHans de Goede struct vbox_private *vbox = dev_get_drvdata(dev);
145131abc56SHans de Goede
146131abc56SHans de Goede return drm_mode_config_helper_suspend(&vbox->ddev);
147131abc56SHans de Goede }
148131abc56SHans de Goede
vbox_pm_thaw(struct device * dev)149131abc56SHans de Goede static int vbox_pm_thaw(struct device *dev)
150131abc56SHans de Goede {
151131abc56SHans de Goede struct vbox_private *vbox = dev_get_drvdata(dev);
152131abc56SHans de Goede
153131abc56SHans de Goede return drm_mode_config_helper_resume(&vbox->ddev);
154131abc56SHans de Goede }
155131abc56SHans de Goede
vbox_pm_poweroff(struct device * dev)156131abc56SHans de Goede static int vbox_pm_poweroff(struct device *dev)
157131abc56SHans de Goede {
158131abc56SHans de Goede struct vbox_private *vbox = dev_get_drvdata(dev);
159131abc56SHans de Goede
160131abc56SHans de Goede return drm_mode_config_helper_suspend(&vbox->ddev);
161131abc56SHans de Goede }
162131abc56SHans de Goede
163131abc56SHans de Goede static const struct dev_pm_ops vbox_pm_ops = {
164131abc56SHans de Goede .suspend = vbox_pm_suspend,
165131abc56SHans de Goede .resume = vbox_pm_resume,
166131abc56SHans de Goede .freeze = vbox_pm_freeze,
167131abc56SHans de Goede .thaw = vbox_pm_thaw,
168131abc56SHans de Goede .poweroff = vbox_pm_poweroff,
169131abc56SHans de Goede .restore = vbox_pm_resume,
170131abc56SHans de Goede };
171131abc56SHans de Goede
172131abc56SHans de Goede static struct pci_driver vbox_pci_driver = {
173131abc56SHans de Goede .name = DRIVER_NAME,
174131abc56SHans de Goede .id_table = pciidlist,
175131abc56SHans de Goede .probe = vbox_pci_probe,
176131abc56SHans de Goede .remove = vbox_pci_remove,
17769f03be1SDouglas Anderson .shutdown = vbox_pci_shutdown,
17866284ff9SPaul Cercueil .driver.pm = pm_sleep_ptr(&vbox_pm_ops),
179131abc56SHans de Goede };
180131abc56SHans de Goede
18102f64b2dSGerd Hoffmann DEFINE_DRM_GEM_FOPS(vbox_fops);
182131abc56SHans de Goede
18370a59dd8SDaniel Vetter static const struct drm_driver driver = {
184131abc56SHans de Goede .driver_features =
185*87b3b45cSZack Rusin DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_CURSOR_HOTSPOT,
186131abc56SHans de Goede
187131abc56SHans de Goede .fops = &vbox_fops,
188131abc56SHans de Goede .name = DRIVER_NAME,
189131abc56SHans de Goede .desc = DRIVER_DESC,
190131abc56SHans de Goede .date = DRIVER_DATE,
191131abc56SHans de Goede .major = DRIVER_MAJOR,
192131abc56SHans de Goede .minor = DRIVER_MINOR,
193131abc56SHans de Goede .patchlevel = DRIVER_PATCHLEVEL,
194131abc56SHans de Goede
19594065bf5SThomas Zimmermann DRM_GEM_VRAM_DRIVER,
196131abc56SHans de Goede };
197131abc56SHans de Goede
198ccecfd01SThomas Zimmermann drm_module_pci_driver_if_modeset(vbox_pci_driver, vbox_modeset);
199131abc56SHans de Goede
200131abc56SHans de Goede MODULE_AUTHOR("Oracle Corporation");
201131abc56SHans de Goede MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
202131abc56SHans de Goede MODULE_DESCRIPTION(DRIVER_DESC);
203131abc56SHans de Goede MODULE_LICENSE("GPL and additional rights");
204