xref: /openbmc/linux/drivers/gpu/drm/vboxvideo/vbox_drv.c (revision 7d7ae873b5e0f46d19e5dc818d1a7809e4b7cc81)
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