aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_drv.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2009-12-11 04:24:15 -0500
committerDave Airlie <airlied@redhat.com>2009-12-11 06:29:34 -0500
commit6ee738610f41b59733f63718f0bdbcba7d3a3f12 (patch)
treeeccb9f07671998c50a1bc606a54cd6f82ba43e0a /drivers/gpu/drm/nouveau/nouveau_drv.c
parentd1ede145cea25c5b6d2ebb19b167af14e374bb45 (diff)
drm/nouveau: Add DRM driver for NVIDIA GPUs
This adds a drm/kms staging non-API stable driver for GPUs from NVIDIA. This driver is a KMS-based driver and requires a compatible nouveau userspace libdrm and nouveau X.org driver. This driver requires firmware files not available in this kernel tree, interested parties can find them via the nouveau project git archive. This driver is reverse engineered, and is in no way supported by nVidia. Support for nearly the complete range of nvidia hw from nv04->g80 (nv50) is available, and the kms driver should support driving nearly all output types (displayport is under development still) along with supporting suspend/resume. This work is all from the upstream nouveau project found at nouveau.freedesktop.org. The original authors list from nouveau git tree is: Anssi Hannula <anssi.hannula@iki.fi> Ben Skeggs <bskeggs@redhat.com> Francisco Jerez <currojerez@riseup.net> Maarten Maathuis <madman2003@gmail.com> Marcin Koƛcielnicki <koriakin@0x04.net> Matthew Garrett <mjg@redhat.com> Matt Parnell <mparnell@gmail.com> Patrice Mandin <patmandin@gmail.com> Pekka Paalanen <pq@iki.fi> Xavier Chantry <shiningxc@gmail.com> along with project founder Stephane Marchesin <marchesin@icps.u-strasbg.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_drv.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
new file mode 100644
index 000000000000..35249c35118f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -0,0 +1,405 @@
1/*
2 * Copyright 2005 Stephane Marchesin.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <linux/console.h>
26
27#include "drmP.h"
28#include "drm.h"
29#include "drm_crtc_helper.h"
30#include "nouveau_drv.h"
31#include "nouveau_hw.h"
32#include "nouveau_fb.h"
33#include "nouveau_fbcon.h"
34#include "nv50_display.h"
35
36#include "drm_pciids.h"
37
38MODULE_PARM_DESC(noagp, "Disable AGP");
39int nouveau_noagp;
40module_param_named(noagp, nouveau_noagp, int, 0400);
41
42MODULE_PARM_DESC(modeset, "Enable kernel modesetting");
43static int nouveau_modeset = -1; /* kms */
44module_param_named(modeset, nouveau_modeset, int, 0400);
45
46MODULE_PARM_DESC(vbios, "Override default VBIOS location");
47char *nouveau_vbios;
48module_param_named(vbios, nouveau_vbios, charp, 0400);
49
50MODULE_PARM_DESC(vram_pushbuf, "Force DMA push buffers to be in VRAM");
51int nouveau_vram_pushbuf;
52module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
53
54MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM");
55int nouveau_vram_notify;
56module_param_named(vram_notify, nouveau_vram_notify, int, 0400);
57
58MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)");
59int nouveau_duallink = 1;
60module_param_named(duallink, nouveau_duallink, int, 0400);
61
62MODULE_PARM_DESC(uscript_lvds, "LVDS output script table ID (>=GeForce 8)");
63int nouveau_uscript_lvds = -1;
64module_param_named(uscript_lvds, nouveau_uscript_lvds, int, 0400);
65
66MODULE_PARM_DESC(uscript_tmds, "TMDS output script table ID (>=GeForce 8)");
67int nouveau_uscript_tmds = -1;
68module_param_named(uscript_tmds, nouveau_uscript_tmds, int, 0400);
69
70MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
71 "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n"
72 "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n"
73 "\t\tDefault: PAL\n"
74 "\t\t*NOTE* Ignored for cards with external TV encoders.");
75char *nouveau_tv_norm;
76module_param_named(tv_norm, nouveau_tv_norm, charp, 0400);
77
78MODULE_PARM_DESC(reg_debug, "Register access debug bitmask:\n"
79 "\t\t0x1 mc, 0x2 video, 0x4 fb, 0x8 extdev,\n"
80 "\t\t0x10 crtc, 0x20 ramdac, 0x40 vgacrtc, 0x80 rmvio,\n"
81 "\t\t0x100 vgaattr, 0x200 EVO (G80+). ");
82int nouveau_reg_debug;
83module_param_named(reg_debug, nouveau_reg_debug, int, 0600);
84
85int nouveau_fbpercrtc;
86#if 0
87module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400);
88#endif
89
90static struct pci_device_id pciidlist[] = {
91 {
92 PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
93 .class = PCI_BASE_CLASS_DISPLAY << 16,
94 .class_mask = 0xff << 16,
95 },
96 {
97 PCI_DEVICE(PCI_VENDOR_ID_NVIDIA_SGS, PCI_ANY_ID),
98 .class = PCI_BASE_CLASS_DISPLAY << 16,
99 .class_mask = 0xff << 16,
100 },
101 {}
102};
103
104MODULE_DEVICE_TABLE(pci, pciidlist);
105
106static struct drm_driver driver;
107
108static int __devinit
109nouveau_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
110{
111 return drm_get_dev(pdev, ent, &driver);
112}
113
114static void
115nouveau_pci_remove(struct pci_dev *pdev)
116{
117 struct drm_device *dev = pci_get_drvdata(pdev);
118
119 drm_put_dev(dev);
120}
121
122static int
123nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
124{
125 struct drm_device *dev = pci_get_drvdata(pdev);
126 struct drm_nouveau_private *dev_priv = dev->dev_private;
127 struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
128 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
129 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
130 struct nouveau_channel *chan;
131 struct drm_crtc *crtc;
132 uint32_t fbdev_flags;
133 int ret, i;
134
135 if (!drm_core_check_feature(dev, DRIVER_MODESET))
136 return -ENODEV;
137
138 if (pm_state.event == PM_EVENT_PRETHAW)
139 return 0;
140
141 fbdev_flags = dev_priv->fbdev_info->flags;
142 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
143
144 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
145 struct nouveau_framebuffer *nouveau_fb;
146
147 nouveau_fb = nouveau_framebuffer(crtc->fb);
148 if (!nouveau_fb || !nouveau_fb->nvbo)
149 continue;
150
151 nouveau_bo_unpin(nouveau_fb->nvbo);
152 }
153
154 NV_INFO(dev, "Evicting buffers...\n");
155 ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
156
157 NV_INFO(dev, "Idling channels...\n");
158 for (i = 0; i < pfifo->channels; i++) {
159 struct nouveau_fence *fence = NULL;
160
161 chan = dev_priv->fifos[i];
162 if (!chan || (dev_priv->card_type >= NV_50 &&
163 chan == dev_priv->fifos[0]))
164 continue;
165
166 ret = nouveau_fence_new(chan, &fence, true);
167 if (ret == 0) {
168 ret = nouveau_fence_wait(fence, NULL, false, false);
169 nouveau_fence_unref((void *)&fence);
170 }
171
172 if (ret) {
173 NV_ERROR(dev, "Failed to idle channel %d for suspend\n",
174 chan->id);
175 }
176 }
177
178 pgraph->fifo_access(dev, false);
179 nouveau_wait_for_idle(dev);
180 pfifo->reassign(dev, false);
181 pfifo->disable(dev);
182 pfifo->unload_context(dev);
183 pgraph->unload_context(dev);
184
185 NV_INFO(dev, "Suspending GPU objects...\n");
186 ret = nouveau_gpuobj_suspend(dev);
187 if (ret) {
188 NV_ERROR(dev, "... failed: %d\n", ret);
189 goto out_abort;
190 }
191
192 ret = pinstmem->suspend(dev);
193 if (ret) {
194 NV_ERROR(dev, "... failed: %d\n", ret);
195 nouveau_gpuobj_suspend_cleanup(dev);
196 goto out_abort;
197 }
198
199 NV_INFO(dev, "And we're gone!\n");
200 pci_save_state(pdev);
201 if (pm_state.event == PM_EVENT_SUSPEND) {
202 pci_disable_device(pdev);
203 pci_set_power_state(pdev, PCI_D3hot);
204 }
205
206 acquire_console_sem();
207 fb_set_suspend(dev_priv->fbdev_info, 1);
208 release_console_sem();
209 dev_priv->fbdev_info->flags = fbdev_flags;
210 return 0;
211
212out_abort:
213 NV_INFO(dev, "Re-enabling acceleration..\n");
214 pfifo->enable(dev);
215 pfifo->reassign(dev, true);
216 pgraph->fifo_access(dev, true);
217 return ret;
218}
219
220static int
221nouveau_pci_resume(struct pci_dev *pdev)
222{
223 struct drm_device *dev = pci_get_drvdata(pdev);
224 struct drm_nouveau_private *dev_priv = dev->dev_private;
225 struct nouveau_engine *engine = &dev_priv->engine;
226 struct drm_crtc *crtc;
227 uint32_t fbdev_flags;
228 int ret, i;
229
230 if (!drm_core_check_feature(dev, DRIVER_MODESET))
231 return -ENODEV;
232
233 fbdev_flags = dev_priv->fbdev_info->flags;
234 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
235
236 NV_INFO(dev, "We're back, enabling device...\n");
237 pci_set_power_state(pdev, PCI_D0);
238 pci_restore_state(pdev);
239 if (pci_enable_device(pdev))
240 return -1;
241 pci_set_master(dev->pdev);
242
243 NV_INFO(dev, "POSTing device...\n");
244 ret = nouveau_run_vbios_init(dev);
245 if (ret)
246 return ret;
247
248 if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
249 ret = nouveau_mem_init_agp(dev);
250 if (ret) {
251 NV_ERROR(dev, "error reinitialising AGP: %d\n", ret);
252 return ret;
253 }
254 }
255
256 NV_INFO(dev, "Reinitialising engines...\n");
257 engine->instmem.resume(dev);
258 engine->mc.init(dev);
259 engine->timer.init(dev);
260 engine->fb.init(dev);
261 engine->graph.init(dev);
262 engine->fifo.init(dev);
263
264 NV_INFO(dev, "Restoring GPU objects...\n");
265 nouveau_gpuobj_resume(dev);
266
267 nouveau_irq_postinstall(dev);
268
269 /* Re-write SKIPS, they'll have been lost over the suspend */
270 if (nouveau_vram_pushbuf) {
271 struct nouveau_channel *chan;
272 int j;
273
274 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
275 chan = dev_priv->fifos[i];
276 if (!chan)
277 continue;
278
279 for (j = 0; j < NOUVEAU_DMA_SKIPS; j++)
280 nouveau_bo_wr32(chan->pushbuf_bo, i, 0);
281 }
282 }
283
284 NV_INFO(dev, "Restoring mode...\n");
285 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
286 struct nouveau_framebuffer *nouveau_fb;
287
288 nouveau_fb = nouveau_framebuffer(crtc->fb);
289 if (!nouveau_fb || !nouveau_fb->nvbo)
290 continue;
291
292 nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
293 }
294
295 if (dev_priv->card_type < NV_50) {
296 nv04_display_restore(dev);
297 NVLockVgaCrtcs(dev, false);
298 } else
299 nv50_display_init(dev);
300
301 /* Force CLUT to get re-loaded during modeset */
302 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
303 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
304
305 nv_crtc->lut.depth = 0;
306 }
307
308 acquire_console_sem();
309 fb_set_suspend(dev_priv->fbdev_info, 0);
310 release_console_sem();
311
312 nouveau_fbcon_zfill(dev);
313
314 drm_helper_resume_force_mode(dev);
315 dev_priv->fbdev_info->flags = fbdev_flags;
316 return 0;
317}
318
319static struct drm_driver driver = {
320 .driver_features =
321 DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
322 DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
323 .load = nouveau_load,
324 .firstopen = nouveau_firstopen,
325 .lastclose = nouveau_lastclose,
326 .unload = nouveau_unload,
327 .preclose = nouveau_preclose,
328#if defined(CONFIG_DRM_NOUVEAU_DEBUG)
329 .debugfs_init = nouveau_debugfs_init,
330 .debugfs_cleanup = nouveau_debugfs_takedown,
331#endif
332 .irq_preinstall = nouveau_irq_preinstall,
333 .irq_postinstall = nouveau_irq_postinstall,
334 .irq_uninstall = nouveau_irq_uninstall,
335 .irq_handler = nouveau_irq_handler,
336 .reclaim_buffers = drm_core_reclaim_buffers,
337 .get_map_ofs = drm_core_get_map_ofs,
338 .get_reg_ofs = drm_core_get_reg_ofs,
339 .ioctls = nouveau_ioctls,
340 .fops = {
341 .owner = THIS_MODULE,
342 .open = drm_open,
343 .release = drm_release,
344 .ioctl = drm_ioctl,
345 .mmap = nouveau_ttm_mmap,
346 .poll = drm_poll,
347 .fasync = drm_fasync,
348#if defined(CONFIG_COMPAT)
349 .compat_ioctl = nouveau_compat_ioctl,
350#endif
351 },
352 .pci_driver = {
353 .name = DRIVER_NAME,
354 .id_table = pciidlist,
355 .probe = nouveau_pci_probe,
356 .remove = nouveau_pci_remove,
357 .suspend = nouveau_pci_suspend,
358 .resume = nouveau_pci_resume
359 },
360
361 .gem_init_object = nouveau_gem_object_new,
362 .gem_free_object = nouveau_gem_object_del,
363
364 .name = DRIVER_NAME,
365 .desc = DRIVER_DESC,
366#ifdef GIT_REVISION
367 .date = GIT_REVISION,
368#else
369 .date = DRIVER_DATE,
370#endif
371 .major = DRIVER_MAJOR,
372 .minor = DRIVER_MINOR,
373 .patchlevel = DRIVER_PATCHLEVEL,
374};
375
376static int __init nouveau_init(void)
377{
378 driver.num_ioctls = nouveau_max_ioctl;
379
380 if (nouveau_modeset == -1) {
381#ifdef CONFIG_VGA_CONSOLE
382 if (vgacon_text_force())
383 nouveau_modeset = 0;
384 else
385#endif
386 nouveau_modeset = 1;
387 }
388
389 if (nouveau_modeset == 1)
390 driver.driver_features |= DRIVER_MODESET;
391
392 return drm_init(&driver);
393}
394
395static void __exit nouveau_exit(void)
396{
397 drm_exit(&driver);
398}
399
400module_init(nouveau_init);
401module_exit(nouveau_exit);
402
403MODULE_AUTHOR(DRIVER_AUTHOR);
404MODULE_DESCRIPTION(DRIVER_DESC);
405MODULE_LICENSE("GPL and additional rights");