xref: /openbmc/linux/drivers/gpu/drm/ast/ast_drv.c (revision 312fec1405dd546ddb3fa6387d54e78f604dd8f8)
1*312fec14SDave Airlie /*
2*312fec14SDave Airlie  * Copyright 2012 Red Hat Inc.
3*312fec14SDave Airlie  *
4*312fec14SDave Airlie  * Permission is hereby granted, free of charge, to any person obtaining a
5*312fec14SDave Airlie  * copy of this software and associated documentation files (the
6*312fec14SDave Airlie  * "Software"), to deal in the Software without restriction, including
7*312fec14SDave Airlie  * without limitation the rights to use, copy, modify, merge, publish,
8*312fec14SDave Airlie  * distribute, sub license, and/or sell copies of the Software, and to
9*312fec14SDave Airlie  * permit persons to whom the Software is furnished to do so, subject to
10*312fec14SDave Airlie  * the following conditions:
11*312fec14SDave Airlie  *
12*312fec14SDave Airlie  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13*312fec14SDave Airlie  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14*312fec14SDave Airlie  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
15*312fec14SDave Airlie  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
16*312fec14SDave Airlie  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
17*312fec14SDave Airlie  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18*312fec14SDave Airlie  * USE OR OTHER DEALINGS IN THE SOFTWARE.
19*312fec14SDave Airlie  *
20*312fec14SDave Airlie  * The above copyright notice and this permission notice (including the
21*312fec14SDave Airlie  * next paragraph) shall be included in all copies or substantial portions
22*312fec14SDave Airlie  * of the Software.
23*312fec14SDave Airlie  *
24*312fec14SDave Airlie  */
25*312fec14SDave Airlie /*
26*312fec14SDave Airlie  * Authors: Dave Airlie <airlied@redhat.com>
27*312fec14SDave Airlie  */
28*312fec14SDave Airlie #include <linux/module.h>
29*312fec14SDave Airlie #include <linux/console.h>
30*312fec14SDave Airlie 
31*312fec14SDave Airlie #include "drmP.h"
32*312fec14SDave Airlie #include "drm.h"
33*312fec14SDave Airlie #include "drm_crtc_helper.h"
34*312fec14SDave Airlie 
35*312fec14SDave Airlie #include "ast_drv.h"
36*312fec14SDave Airlie 
37*312fec14SDave Airlie int ast_modeset = -1;
38*312fec14SDave Airlie 
39*312fec14SDave Airlie MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
40*312fec14SDave Airlie module_param_named(modeset, ast_modeset, int, 0400);
41*312fec14SDave Airlie 
42*312fec14SDave Airlie #define PCI_VENDOR_ASPEED 0x1a03
43*312fec14SDave Airlie 
44*312fec14SDave Airlie static struct drm_driver driver;
45*312fec14SDave Airlie 
46*312fec14SDave Airlie #define AST_VGA_DEVICE(id, info) {		\
47*312fec14SDave Airlie 	.class = PCI_BASE_CLASS_DISPLAY << 16,	\
48*312fec14SDave Airlie 	.class_mask = 0xff0000,			\
49*312fec14SDave Airlie 	.vendor = PCI_VENDOR_ASPEED,			\
50*312fec14SDave Airlie 	.device = id,				\
51*312fec14SDave Airlie 	.subvendor = PCI_ANY_ID,		\
52*312fec14SDave Airlie 	.subdevice = PCI_ANY_ID,		\
53*312fec14SDave Airlie 	.driver_data = (unsigned long) info }
54*312fec14SDave Airlie 
55*312fec14SDave Airlie static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
56*312fec14SDave Airlie 	AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL),
57*312fec14SDave Airlie 	AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL),
58*312fec14SDave Airlie 	/*	AST_VGA_DEVICE(PCI_CHIP_AST1180, NULL), - don't bind to 1180 for now */
59*312fec14SDave Airlie 	{0, 0, 0},
60*312fec14SDave Airlie };
61*312fec14SDave Airlie 
62*312fec14SDave Airlie MODULE_DEVICE_TABLE(pci, pciidlist);
63*312fec14SDave Airlie 
64*312fec14SDave Airlie static int __devinit
65*312fec14SDave Airlie ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
66*312fec14SDave Airlie {
67*312fec14SDave Airlie 	return drm_get_pci_dev(pdev, ent, &driver);
68*312fec14SDave Airlie }
69*312fec14SDave Airlie 
70*312fec14SDave Airlie static void
71*312fec14SDave Airlie ast_pci_remove(struct pci_dev *pdev)
72*312fec14SDave Airlie {
73*312fec14SDave Airlie 	struct drm_device *dev = pci_get_drvdata(pdev);
74*312fec14SDave Airlie 
75*312fec14SDave Airlie 	drm_put_dev(dev);
76*312fec14SDave Airlie }
77*312fec14SDave Airlie 
78*312fec14SDave Airlie 
79*312fec14SDave Airlie 
80*312fec14SDave Airlie static int ast_drm_freeze(struct drm_device *dev)
81*312fec14SDave Airlie {
82*312fec14SDave Airlie 	drm_kms_helper_poll_disable(dev);
83*312fec14SDave Airlie 
84*312fec14SDave Airlie 	pci_save_state(dev->pdev);
85*312fec14SDave Airlie 
86*312fec14SDave Airlie 	console_lock();
87*312fec14SDave Airlie 	ast_fbdev_set_suspend(dev, 1);
88*312fec14SDave Airlie 	console_unlock();
89*312fec14SDave Airlie 	return 0;
90*312fec14SDave Airlie }
91*312fec14SDave Airlie 
92*312fec14SDave Airlie static int ast_drm_thaw(struct drm_device *dev)
93*312fec14SDave Airlie {
94*312fec14SDave Airlie 	int error = 0;
95*312fec14SDave Airlie 
96*312fec14SDave Airlie 	ast_post_gpu(dev);
97*312fec14SDave Airlie 
98*312fec14SDave Airlie 	drm_mode_config_reset(dev);
99*312fec14SDave Airlie 	mutex_lock(&dev->mode_config.mutex);
100*312fec14SDave Airlie 	drm_helper_resume_force_mode(dev);
101*312fec14SDave Airlie 	mutex_unlock(&dev->mode_config.mutex);
102*312fec14SDave Airlie 
103*312fec14SDave Airlie 	console_lock();
104*312fec14SDave Airlie 	ast_fbdev_set_suspend(dev, 0);
105*312fec14SDave Airlie 	console_unlock();
106*312fec14SDave Airlie 	return error;
107*312fec14SDave Airlie }
108*312fec14SDave Airlie 
109*312fec14SDave Airlie static int ast_drm_resume(struct drm_device *dev)
110*312fec14SDave Airlie {
111*312fec14SDave Airlie 	int ret;
112*312fec14SDave Airlie 
113*312fec14SDave Airlie 	if (pci_enable_device(dev->pdev))
114*312fec14SDave Airlie 		return -EIO;
115*312fec14SDave Airlie 
116*312fec14SDave Airlie 	ret = ast_drm_thaw(dev);
117*312fec14SDave Airlie 	if (ret)
118*312fec14SDave Airlie 		return ret;
119*312fec14SDave Airlie 
120*312fec14SDave Airlie 	drm_kms_helper_poll_enable(dev);
121*312fec14SDave Airlie 	return 0;
122*312fec14SDave Airlie }
123*312fec14SDave Airlie 
124*312fec14SDave Airlie static int ast_pm_suspend(struct device *dev)
125*312fec14SDave Airlie {
126*312fec14SDave Airlie 	struct pci_dev *pdev = to_pci_dev(dev);
127*312fec14SDave Airlie 	struct drm_device *ddev = pci_get_drvdata(pdev);
128*312fec14SDave Airlie 	int error;
129*312fec14SDave Airlie 
130*312fec14SDave Airlie 	error = ast_drm_freeze(ddev);
131*312fec14SDave Airlie 	if (error)
132*312fec14SDave Airlie 		return error;
133*312fec14SDave Airlie 
134*312fec14SDave Airlie 	pci_disable_device(pdev);
135*312fec14SDave Airlie 	pci_set_power_state(pdev, PCI_D3hot);
136*312fec14SDave Airlie 	return 0;
137*312fec14SDave Airlie }
138*312fec14SDave Airlie static int ast_pm_resume(struct device *dev)
139*312fec14SDave Airlie {
140*312fec14SDave Airlie 	struct pci_dev *pdev = to_pci_dev(dev);
141*312fec14SDave Airlie 	struct drm_device *ddev = pci_get_drvdata(pdev);
142*312fec14SDave Airlie 	return ast_drm_resume(ddev);
143*312fec14SDave Airlie }
144*312fec14SDave Airlie 
145*312fec14SDave Airlie static int ast_pm_freeze(struct device *dev)
146*312fec14SDave Airlie {
147*312fec14SDave Airlie 	struct pci_dev *pdev = to_pci_dev(dev);
148*312fec14SDave Airlie 	struct drm_device *ddev = pci_get_drvdata(pdev);
149*312fec14SDave Airlie 
150*312fec14SDave Airlie 	if (!ddev || !ddev->dev_private)
151*312fec14SDave Airlie 		return -ENODEV;
152*312fec14SDave Airlie 	return ast_drm_freeze(ddev);
153*312fec14SDave Airlie 
154*312fec14SDave Airlie }
155*312fec14SDave Airlie 
156*312fec14SDave Airlie static int ast_pm_thaw(struct device *dev)
157*312fec14SDave Airlie {
158*312fec14SDave Airlie 	struct pci_dev *pdev = to_pci_dev(dev);
159*312fec14SDave Airlie 	struct drm_device *ddev = pci_get_drvdata(pdev);
160*312fec14SDave Airlie 	return ast_drm_thaw(ddev);
161*312fec14SDave Airlie }
162*312fec14SDave Airlie 
163*312fec14SDave Airlie static int ast_pm_poweroff(struct device *dev)
164*312fec14SDave Airlie {
165*312fec14SDave Airlie 	struct pci_dev *pdev = to_pci_dev(dev);
166*312fec14SDave Airlie 	struct drm_device *ddev = pci_get_drvdata(pdev);
167*312fec14SDave Airlie 
168*312fec14SDave Airlie 	return ast_drm_freeze(ddev);
169*312fec14SDave Airlie }
170*312fec14SDave Airlie 
171*312fec14SDave Airlie static const struct dev_pm_ops ast_pm_ops = {
172*312fec14SDave Airlie 	.suspend = ast_pm_suspend,
173*312fec14SDave Airlie 	.resume = ast_pm_resume,
174*312fec14SDave Airlie 	.freeze = ast_pm_freeze,
175*312fec14SDave Airlie 	.thaw = ast_pm_thaw,
176*312fec14SDave Airlie 	.poweroff = ast_pm_poweroff,
177*312fec14SDave Airlie 	.restore = ast_pm_resume,
178*312fec14SDave Airlie };
179*312fec14SDave Airlie 
180*312fec14SDave Airlie static struct pci_driver ast_pci_driver = {
181*312fec14SDave Airlie 	.name = DRIVER_NAME,
182*312fec14SDave Airlie 	.id_table = pciidlist,
183*312fec14SDave Airlie 	.probe = ast_pci_probe,
184*312fec14SDave Airlie 	.remove = ast_pci_remove,
185*312fec14SDave Airlie 	.driver.pm = &ast_pm_ops,
186*312fec14SDave Airlie };
187*312fec14SDave Airlie 
188*312fec14SDave Airlie static const struct file_operations ast_fops = {
189*312fec14SDave Airlie 	.owner = THIS_MODULE,
190*312fec14SDave Airlie 	.open = drm_open,
191*312fec14SDave Airlie 	.release = drm_release,
192*312fec14SDave Airlie 	.unlocked_ioctl = drm_ioctl,
193*312fec14SDave Airlie 	.mmap = ast_mmap,
194*312fec14SDave Airlie 	.poll = drm_poll,
195*312fec14SDave Airlie 	.fasync = drm_fasync,
196*312fec14SDave Airlie 	.read = drm_read,
197*312fec14SDave Airlie };
198*312fec14SDave Airlie 
199*312fec14SDave Airlie static struct drm_driver driver = {
200*312fec14SDave Airlie 	.driver_features = DRIVER_USE_MTRR | DRIVER_MODESET | DRIVER_GEM,
201*312fec14SDave Airlie 	.dev_priv_size = 0,
202*312fec14SDave Airlie 
203*312fec14SDave Airlie 	.load = ast_driver_load,
204*312fec14SDave Airlie 	.unload = ast_driver_unload,
205*312fec14SDave Airlie 
206*312fec14SDave Airlie 	.fops = &ast_fops,
207*312fec14SDave Airlie 	.name = DRIVER_NAME,
208*312fec14SDave Airlie 	.desc = DRIVER_DESC,
209*312fec14SDave Airlie 	.date = DRIVER_DATE,
210*312fec14SDave Airlie 	.major = DRIVER_MAJOR,
211*312fec14SDave Airlie 	.minor = DRIVER_MINOR,
212*312fec14SDave Airlie 	.patchlevel = DRIVER_PATCHLEVEL,
213*312fec14SDave Airlie 
214*312fec14SDave Airlie 	.gem_init_object = ast_gem_init_object,
215*312fec14SDave Airlie 	.gem_free_object = ast_gem_free_object,
216*312fec14SDave Airlie 	.dumb_create = ast_dumb_create,
217*312fec14SDave Airlie 	.dumb_map_offset = ast_dumb_mmap_offset,
218*312fec14SDave Airlie 	.dumb_destroy = ast_dumb_destroy,
219*312fec14SDave Airlie 
220*312fec14SDave Airlie };
221*312fec14SDave Airlie 
222*312fec14SDave Airlie static int __init ast_init(void)
223*312fec14SDave Airlie {
224*312fec14SDave Airlie 	if (vgacon_text_force() && ast_modeset == -1)
225*312fec14SDave Airlie 		return -EINVAL;
226*312fec14SDave Airlie 
227*312fec14SDave Airlie 	if (ast_modeset == 0)
228*312fec14SDave Airlie 		return -EINVAL;
229*312fec14SDave Airlie 	return drm_pci_init(&driver, &ast_pci_driver);
230*312fec14SDave Airlie }
231*312fec14SDave Airlie static void __exit ast_exit(void)
232*312fec14SDave Airlie {
233*312fec14SDave Airlie 	drm_pci_exit(&driver, &ast_pci_driver);
234*312fec14SDave Airlie }
235*312fec14SDave Airlie 
236*312fec14SDave Airlie module_init(ast_init);
237*312fec14SDave Airlie module_exit(ast_exit);
238*312fec14SDave Airlie 
239*312fec14SDave Airlie MODULE_AUTHOR(DRIVER_AUTHOR);
240*312fec14SDave Airlie MODULE_DESCRIPTION(DRIVER_DESC);
241*312fec14SDave Airlie MODULE_LICENSE("GPL and additional rights");
242*312fec14SDave Airlie 
243