blob: f53c6a748200ff605086e51e71b80adc1ecb1822 [file] [log] [blame]
Ben Skeggs6ee73862009-12-11 19:24:15 +10001/*
2 * Copyright 2005 Stephane Marchesin
3 * Copyright 2008 Stuart Bennett
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26#include <linux/swab.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090027#include <linux/slab.h>
Ben Skeggs6ee73862009-12-11 19:24:15 +100028#include "drmP.h"
29#include "drm.h"
30#include "drm_sarea.h"
31#include "drm_crtc_helper.h"
32#include <linux/vgaarb.h>
Dave Airlie6a9ee8a2010-02-01 15:38:10 +100033#include <linux/vga_switcheroo.h>
Ben Skeggs6ee73862009-12-11 19:24:15 +100034
35#include "nouveau_drv.h"
Ben Skeggs94580292012-07-06 12:14:00 +100036#include <nouveau_drm.h>
Dave Airlie38651672010-03-30 05:34:13 +000037#include "nouveau_fbcon.h"
Ben Skeggs02a841d2012-07-04 23:44:54 +100038#include <core/ramht.h>
Ben Skeggs330c5982010-09-16 15:39:49 +100039#include "nouveau_pm.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +100040#include "nv50_display.h"
Ben Skeggs02a841d2012-07-04 23:44:54 +100041#include <engine/fifo.h>
Ben Skeggs5e120f62012-04-30 13:55:29 +100042#include "nouveau_fence.h"
Ben Skeggs20abd162012-04-30 11:33:43 -050043#include "nouveau_software.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +100044
Ben Skeggs6ee73862009-12-11 19:24:15 +100045static void nouveau_stub_takedown(struct drm_device *dev) {}
Ben Skeggsee2e0132010-07-26 09:28:25 +100046static int nouveau_stub_init(struct drm_device *dev) { return 0; }
Ben Skeggs6ee73862009-12-11 19:24:15 +100047
48static int nouveau_init_engine_ptrs(struct drm_device *dev)
49{
50 struct drm_nouveau_private *dev_priv = dev->dev_private;
51 struct nouveau_engine *engine = &dev_priv->engine;
52
53 switch (dev_priv->chipset & 0xf0) {
54 case 0x00:
Francisco Jerezc88c2e02010-07-24 17:37:33 +020055 engine->display.early_init = nv04_display_early_init;
56 engine->display.late_takedown = nv04_display_late_takedown;
57 engine->display.create = nv04_display_create;
Francisco Jerezc88c2e02010-07-24 17:37:33 +020058 engine->display.destroy = nv04_display_destroy;
Ben Skeggs2a44e492011-11-09 11:36:33 +100059 engine->display.init = nv04_display_init;
60 engine->display.fini = nv04_display_fini;
Ben Skeggs36f13172011-10-27 10:24:12 +100061 engine->pm.clocks_get = nv04_pm_clocks_get;
62 engine->pm.clocks_pre = nv04_pm_clocks_pre;
63 engine->pm.clocks_set = nv04_pm_clocks_set;
Ben Skeggs6ee73862009-12-11 19:24:15 +100064 break;
65 case 0x10:
Francisco Jerezc88c2e02010-07-24 17:37:33 +020066 engine->display.early_init = nv04_display_early_init;
67 engine->display.late_takedown = nv04_display_late_takedown;
68 engine->display.create = nv04_display_create;
Francisco Jerezc88c2e02010-07-24 17:37:33 +020069 engine->display.destroy = nv04_display_destroy;
Ben Skeggs2a44e492011-11-09 11:36:33 +100070 engine->display.init = nv04_display_init;
71 engine->display.fini = nv04_display_fini;
Ben Skeggs36f13172011-10-27 10:24:12 +100072 engine->pm.clocks_get = nv04_pm_clocks_get;
73 engine->pm.clocks_pre = nv04_pm_clocks_pre;
74 engine->pm.clocks_set = nv04_pm_clocks_set;
Ben Skeggs6ee73862009-12-11 19:24:15 +100075 break;
76 case 0x20:
Francisco Jerezc88c2e02010-07-24 17:37:33 +020077 engine->display.early_init = nv04_display_early_init;
78 engine->display.late_takedown = nv04_display_late_takedown;
79 engine->display.create = nv04_display_create;
Francisco Jerezc88c2e02010-07-24 17:37:33 +020080 engine->display.destroy = nv04_display_destroy;
Ben Skeggs2a44e492011-11-09 11:36:33 +100081 engine->display.init = nv04_display_init;
82 engine->display.fini = nv04_display_fini;
Ben Skeggs36f13172011-10-27 10:24:12 +100083 engine->pm.clocks_get = nv04_pm_clocks_get;
84 engine->pm.clocks_pre = nv04_pm_clocks_pre;
85 engine->pm.clocks_set = nv04_pm_clocks_set;
Ben Skeggs6ee73862009-12-11 19:24:15 +100086 break;
87 case 0x30:
Francisco Jerezc88c2e02010-07-24 17:37:33 +020088 engine->display.early_init = nv04_display_early_init;
89 engine->display.late_takedown = nv04_display_late_takedown;
90 engine->display.create = nv04_display_create;
Francisco Jerezc88c2e02010-07-24 17:37:33 +020091 engine->display.destroy = nv04_display_destroy;
Ben Skeggs2a44e492011-11-09 11:36:33 +100092 engine->display.init = nv04_display_init;
93 engine->display.fini = nv04_display_fini;
Ben Skeggs36f13172011-10-27 10:24:12 +100094 engine->pm.clocks_get = nv04_pm_clocks_get;
95 engine->pm.clocks_pre = nv04_pm_clocks_pre;
96 engine->pm.clocks_set = nv04_pm_clocks_set;
Ben Skeggs442b6262010-09-16 16:25:26 +100097 engine->pm.voltage_get = nouveau_voltage_gpio_get;
98 engine->pm.voltage_set = nouveau_voltage_gpio_set;
Ben Skeggs6ee73862009-12-11 19:24:15 +100099 break;
100 case 0x40:
101 case 0x60:
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200102 engine->display.early_init = nv04_display_early_init;
103 engine->display.late_takedown = nv04_display_late_takedown;
104 engine->display.create = nv04_display_create;
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200105 engine->display.destroy = nv04_display_destroy;
Ben Skeggs2a44e492011-11-09 11:36:33 +1000106 engine->display.init = nv04_display_init;
107 engine->display.fini = nv04_display_fini;
Ben Skeggs1262a202011-07-18 15:15:34 +1000108 engine->pm.clocks_get = nv40_pm_clocks_get;
109 engine->pm.clocks_pre = nv40_pm_clocks_pre;
110 engine->pm.clocks_set = nv40_pm_clocks_set;
Ben Skeggs442b6262010-09-16 16:25:26 +1000111 engine->pm.voltage_get = nouveau_voltage_gpio_get;
112 engine->pm.voltage_set = nouveau_voltage_gpio_set;
Francisco Jerez8155cac2010-09-23 20:58:38 +0200113 engine->pm.temp_get = nv40_temp_get;
Ben Skeggs69346182011-09-17 02:11:39 +1000114 engine->pm.pwm_get = nv40_pm_pwm_get;
115 engine->pm.pwm_set = nv40_pm_pwm_set;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000116 break;
117 case 0x50:
118 case 0x80: /* gotta love NVIDIA's consistency.. */
119 case 0x90:
Ben Skeggsd9f61c22011-07-04 13:25:17 +1000120 case 0xa0:
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200121 engine->display.early_init = nv50_display_early_init;
122 engine->display.late_takedown = nv50_display_late_takedown;
123 engine->display.create = nv50_display_create;
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200124 engine->display.destroy = nv50_display_destroy;
Ben Skeggs2a44e492011-11-09 11:36:33 +1000125 engine->display.init = nv50_display_init;
126 engine->display.fini = nv50_display_fini;
Ben Skeggsfade7ad2010-09-27 11:18:14 +1000127 switch (dev_priv->chipset) {
Ben Skeggsbd2e5972010-10-19 20:06:01 +1000128 case 0x84:
129 case 0x86:
130 case 0x92:
131 case 0x94:
132 case 0x96:
133 case 0x98:
134 case 0xa0:
Ben Skeggs5f801982010-10-22 08:44:09 +1000135 case 0xaa:
136 case 0xac:
Ben Skeggsbd2e5972010-10-19 20:06:01 +1000137 case 0x50:
Ben Skeggsf3fbaf32011-10-26 09:11:02 +1000138 engine->pm.clocks_get = nv50_pm_clocks_get;
139 engine->pm.clocks_pre = nv50_pm_clocks_pre;
140 engine->pm.clocks_set = nv50_pm_clocks_set;
Ben Skeggsfade7ad2010-09-27 11:18:14 +1000141 break;
Ben Skeggsbd2e5972010-10-19 20:06:01 +1000142 default:
Ben Skeggsca94a712011-06-17 15:38:48 +1000143 engine->pm.clocks_get = nva3_pm_clocks_get;
144 engine->pm.clocks_pre = nva3_pm_clocks_pre;
145 engine->pm.clocks_set = nva3_pm_clocks_set;
Ben Skeggsbd2e5972010-10-19 20:06:01 +1000146 break;
Ben Skeggsfade7ad2010-09-27 11:18:14 +1000147 }
Ben Skeggs02c30ca2010-09-16 16:17:35 +1000148 engine->pm.voltage_get = nouveau_voltage_gpio_get;
149 engine->pm.voltage_set = nouveau_voltage_gpio_set;
Francisco Jerez8155cac2010-09-23 20:58:38 +0200150 if (dev_priv->chipset >= 0x84)
151 engine->pm.temp_get = nv84_temp_get;
152 else
153 engine->pm.temp_get = nv40_temp_get;
Ben Skeggs5a4267a2011-09-17 02:01:24 +1000154 engine->pm.pwm_get = nv50_pm_pwm_get;
155 engine->pm.pwm_set = nv50_pm_pwm_set;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000156 break;
Ben Skeggsd9f61c22011-07-04 13:25:17 +1000157 case 0xc0:
Ben Skeggs4b223ee2010-08-03 10:00:56 +1000158 engine->display.early_init = nv50_display_early_init;
159 engine->display.late_takedown = nv50_display_late_takedown;
160 engine->display.create = nv50_display_create;
Ben Skeggs4b223ee2010-08-03 10:00:56 +1000161 engine->display.destroy = nv50_display_destroy;
Ben Skeggs2a44e492011-11-09 11:36:33 +1000162 engine->display.init = nv50_display_init;
163 engine->display.fini = nv50_display_fini;
Martin Peres74cfad12011-05-12 22:40:47 +0200164 engine->pm.temp_get = nv84_temp_get;
Ben Skeggs354d0782011-06-19 01:44:36 +1000165 engine->pm.clocks_get = nvc0_pm_clocks_get;
Ben Skeggs045da4e2011-10-29 00:22:49 +1000166 engine->pm.clocks_pre = nvc0_pm_clocks_pre;
167 engine->pm.clocks_set = nvc0_pm_clocks_set;
Ben Skeggs3c71c232011-06-09 17:34:02 +1000168 engine->pm.voltage_get = nouveau_voltage_gpio_get;
Ben Skeggsda1dc4c2011-06-10 12:07:09 +1000169 engine->pm.voltage_set = nouveau_voltage_gpio_set;
Ben Skeggs5a4267a2011-09-17 02:01:24 +1000170 engine->pm.pwm_get = nv50_pm_pwm_get;
171 engine->pm.pwm_set = nv50_pm_pwm_set;
Ben Skeggs4b223ee2010-08-03 10:00:56 +1000172 break;
Ben Skeggsd9f61c22011-07-04 13:25:17 +1000173 case 0xd0:
Ben Skeggsd9f61c22011-07-04 13:25:17 +1000174 engine->display.early_init = nouveau_stub_init;
175 engine->display.late_takedown = nouveau_stub_takedown;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000176 engine->display.create = nvd0_display_create;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000177 engine->display.destroy = nvd0_display_destroy;
Ben Skeggs2a44e492011-11-09 11:36:33 +1000178 engine->display.init = nvd0_display_init;
179 engine->display.fini = nvd0_display_fini;
Martin Peres61091832011-10-22 01:40:40 +0200180 engine->pm.temp_get = nv84_temp_get;
Ben Skeggs4784e4a2011-07-04 14:06:07 +1000181 engine->pm.clocks_get = nvc0_pm_clocks_get;
Ben Skeggs045da4e2011-10-29 00:22:49 +1000182 engine->pm.clocks_pre = nvc0_pm_clocks_pre;
183 engine->pm.clocks_set = nvc0_pm_clocks_set;
Ben Skeggs4784e4a2011-07-04 14:06:07 +1000184 engine->pm.voltage_get = nouveau_voltage_gpio_get;
185 engine->pm.voltage_set = nouveau_voltage_gpio_set;
Ben Skeggsd9f61c22011-07-04 13:25:17 +1000186 break;
Ben Skeggs68455a42012-03-04 14:47:55 +1000187 case 0xe0:
Ben Skeggs68455a42012-03-04 14:47:55 +1000188 engine->display.early_init = nouveau_stub_init;
189 engine->display.late_takedown = nouveau_stub_takedown;
190 engine->display.create = nvd0_display_create;
191 engine->display.destroy = nvd0_display_destroy;
192 engine->display.init = nvd0_display_init;
193 engine->display.fini = nvd0_display_fini;
Ben Skeggs68455a42012-03-04 14:47:55 +1000194 break;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000195 default:
196 NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
197 return 1;
198 }
199
Ben Skeggs03bc9672011-07-04 13:14:05 +1000200 /* headless mode */
201 if (nouveau_modeset == 2) {
202 engine->display.early_init = nouveau_stub_init;
203 engine->display.late_takedown = nouveau_stub_takedown;
204 engine->display.create = nouveau_stub_init;
205 engine->display.init = nouveau_stub_init;
206 engine->display.destroy = nouveau_stub_takedown;
207 }
208
Ben Skeggs6ee73862009-12-11 19:24:15 +1000209 return 0;
210}
211
212static unsigned int
213nouveau_vga_set_decode(void *priv, bool state)
214{
Marcin Kościelnicki9967b942010-02-08 00:20:17 +0000215 struct drm_device *dev = priv;
216 struct drm_nouveau_private *dev_priv = dev->dev_private;
217
218 if (dev_priv->chipset >= 0x40)
219 nv_wr32(dev, 0x88054, state);
220 else
221 nv_wr32(dev, 0x1854, state);
222
Ben Skeggs6ee73862009-12-11 19:24:15 +1000223 if (state)
224 return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
225 VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
226 else
227 return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
228}
229
Dave Airlie6a9ee8a2010-02-01 15:38:10 +1000230static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
231 enum vga_switcheroo_state state)
232{
Dave Airliefbf81762010-06-01 09:09:06 +1000233 struct drm_device *dev = pci_get_drvdata(pdev);
Dave Airlie6a9ee8a2010-02-01 15:38:10 +1000234 pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
235 if (state == VGA_SWITCHEROO_ON) {
236 printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
Dave Airlie5bcf7192010-12-07 09:20:40 +1000237 dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
Dave Airlie6a9ee8a2010-02-01 15:38:10 +1000238 nouveau_pci_resume(pdev);
Dave Airliefbf81762010-06-01 09:09:06 +1000239 drm_kms_helper_poll_enable(dev);
Dave Airlie5bcf7192010-12-07 09:20:40 +1000240 dev->switch_power_state = DRM_SWITCH_POWER_ON;
Dave Airlie6a9ee8a2010-02-01 15:38:10 +1000241 } else {
242 printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
Dave Airlie5bcf7192010-12-07 09:20:40 +1000243 dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
Dave Airliefbf81762010-06-01 09:09:06 +1000244 drm_kms_helper_poll_disable(dev);
Peter Lekensteynd0992302011-12-17 12:54:04 +0100245 nouveau_switcheroo_optimus_dsm();
Dave Airlie6a9ee8a2010-02-01 15:38:10 +1000246 nouveau_pci_suspend(pdev, pmm);
Dave Airlie5bcf7192010-12-07 09:20:40 +1000247 dev->switch_power_state = DRM_SWITCH_POWER_OFF;
Dave Airlie6a9ee8a2010-02-01 15:38:10 +1000248 }
249}
250
Dave Airlie8d608aa2010-12-07 08:57:57 +1000251static void nouveau_switcheroo_reprobe(struct pci_dev *pdev)
252{
253 struct drm_device *dev = pci_get_drvdata(pdev);
254 nouveau_fbcon_output_poll_changed(dev);
255}
256
Dave Airlie6a9ee8a2010-02-01 15:38:10 +1000257static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev)
258{
259 struct drm_device *dev = pci_get_drvdata(pdev);
260 bool can_switch;
261
262 spin_lock(&dev->count_lock);
263 can_switch = (dev->open_count == 0);
264 spin_unlock(&dev->count_lock);
265 return can_switch;
266}
267
Ben Skeggs48aca132012-03-18 00:40:41 +1000268static void
269nouveau_card_channel_fini(struct drm_device *dev)
270{
271 struct drm_nouveau_private *dev_priv = dev->dev_private;
272
Ben Skeggs3863c9b2012-07-14 19:09:17 +1000273 if (dev_priv->channel) {
Ben Skeggs48aca132012-03-18 00:40:41 +1000274 nouveau_channel_put_unlocked(&dev_priv->channel);
Ben Skeggs3863c9b2012-07-14 19:09:17 +1000275 nouveau_vm_ref(NULL, &dev_priv->chan_vm, NULL);
276 }
Ben Skeggs48aca132012-03-18 00:40:41 +1000277}
278
279static int
280nouveau_card_channel_init(struct drm_device *dev)
281{
282 struct drm_nouveau_private *dev_priv = dev->dev_private;
283 struct nouveau_channel *chan;
Ben Skeggsd1b167e2012-05-04 14:01:52 +1000284 int ret;
Ben Skeggs48aca132012-03-18 00:40:41 +1000285
Ben Skeggs3863c9b2012-07-14 19:09:17 +1000286 ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x1000, &dev_priv->chan_vm);
287 if (ret)
288 return ret;
289
Ben Skeggs48aca132012-03-18 00:40:41 +1000290 ret = nouveau_channel_alloc(dev, &chan, NULL, NvDmaFB, NvDmaTT);
291 dev_priv->channel = chan;
292 if (ret)
293 return ret;
Ben Skeggs48aca132012-03-18 00:40:41 +1000294 mutex_unlock(&dev_priv->channel->mutex);
295
Ben Skeggsd1b167e2012-05-04 14:01:52 +1000296 nouveau_bo_move_init(chan);
297 return 0;
Ben Skeggs48aca132012-03-18 00:40:41 +1000298}
299
Takashi Iwai26ec6852012-05-11 07:51:17 +0200300static const struct vga_switcheroo_client_ops nouveau_switcheroo_ops = {
301 .set_gpu_state = nouveau_switcheroo_set_state,
302 .reprobe = nouveau_switcheroo_reprobe,
303 .can_switch = nouveau_switcheroo_can_switch,
304};
305
Ben Skeggs6ee73862009-12-11 19:24:15 +1000306int
307nouveau_card_init(struct drm_device *dev)
308{
309 struct drm_nouveau_private *dev_priv = dev->dev_private;
310 struct nouveau_engine *engine;
Ben Skeggseea55c82011-04-18 08:57:51 +1000311 int ret, e = 0;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000312
Ben Skeggs6ee73862009-12-11 19:24:15 +1000313 vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
Takashi Iwai26ec6852012-05-11 07:51:17 +0200314 vga_switcheroo_register_client(dev->pdev, &nouveau_switcheroo_ops);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000315
316 /* Initialise internal driver API hooks */
317 ret = nouveau_init_engine_ptrs(dev);
318 if (ret)
Marcin Kościelnickic5804be2009-12-14 20:58:39 +0000319 goto out;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000320 engine = &dev_priv->engine;
Ben Skeggscff5c132010-10-06 16:16:59 +1000321 spin_lock_init(&dev_priv->channels.lock);
Francisco Jereza5cf68b2010-10-24 16:14:41 +0200322 spin_lock_init(&dev_priv->tile.lock);
Maarten Maathuisff9e5272010-02-01 20:58:27 +0100323 spin_lock_init(&dev_priv->context_switch_lock);
Ben Skeggs04eb34a2011-04-06 13:28:35 +1000324 spin_lock_init(&dev_priv->vm_lock);
Ben Skeggs3863c9b2012-07-14 19:09:17 +1000325 INIT_LIST_HEAD(&dev_priv->classes);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000326
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200327 /* Make the CRTCs and I2C buses accessible */
328 ret = engine->display.early_init(dev);
329 if (ret)
330 goto out;
331
Ben Skeggs6ee73862009-12-11 19:24:15 +1000332 /* Parse BIOS tables / Run init tables if card not POSTed */
Ben Skeggscd0b0722010-06-01 15:56:22 +1000333 ret = nouveau_bios_init(dev);
334 if (ret)
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200335 goto out_display_early;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000336
Ben Skeggs4c5df492011-10-28 10:59:45 +1000337 /* workaround an odd issue on nvc1 by disabling the device's
338 * nosnoop capability. hopefully won't cause issues until a
339 * better fix is found - assuming there is one...
340 */
341 if (dev_priv->chipset == 0xc1) {
342 nv_mask(dev, 0x00088080, 0x00000800, 0x00000000);
343 }
344
Ben Skeggs24f246a2011-06-10 13:36:08 +1000345 ret = nouveau_mem_vram_init(dev);
Ben Skeggsfbd28952010-09-01 15:24:34 +1000346 if (ret)
Ben Skeggs3863c9b2012-07-14 19:09:17 +1000347 goto out_bios;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000348
Ben Skeggs24f246a2011-06-10 13:36:08 +1000349 ret = nouveau_mem_gart_init(dev);
350 if (ret)
351 goto out_ttmvram;
352
Ben Skeggsaba99a82011-05-25 14:48:50 +1000353 if (!dev_priv->noaccel) {
Ben Skeggs18b54c42011-05-25 15:22:33 +1000354 switch (dev_priv->card_type) {
355 case NV_04:
Ben Skeggsc420b2d2012-05-01 20:48:08 +1000356 nv04_fifo_create(dev);
357 break;
358 case NV_10:
359 case NV_20:
360 case NV_30:
361 if (dev_priv->chipset < 0x17)
362 nv10_fifo_create(dev);
363 else
364 nv17_fifo_create(dev);
365 break;
366 case NV_40:
367 nv40_fifo_create(dev);
368 break;
369 case NV_50:
370 if (dev_priv->chipset == 0x50)
371 nv50_fifo_create(dev);
372 else
373 nv84_fifo_create(dev);
374 break;
375 case NV_C0:
376 case NV_D0:
377 nvc0_fifo_create(dev);
378 break;
379 case NV_E0:
380 nve0_fifo_create(dev);
381 break;
382 default:
383 break;
384 }
385
386 switch (dev_priv->card_type) {
387 case NV_04:
Ben Skeggs5e120f62012-04-30 13:55:29 +1000388 nv04_fence_create(dev);
389 break;
390 case NV_10:
391 case NV_20:
392 case NV_30:
393 case NV_40:
394 case NV_50:
395 if (dev_priv->chipset < 0x84)
396 nv10_fence_create(dev);
397 else
398 nv84_fence_create(dev);
399 break;
400 case NV_C0:
401 case NV_D0:
402 case NV_E0:
403 nvc0_fence_create(dev);
404 break;
405 default:
406 break;
407 }
408
409 switch (dev_priv->card_type) {
410 case NV_04:
Ben Skeggs20abd162012-04-30 11:33:43 -0500411 case NV_10:
412 case NV_20:
413 case NV_30:
414 case NV_40:
415 nv04_software_create(dev);
416 break;
417 case NV_50:
418 nv50_software_create(dev);
419 break;
420 case NV_C0:
421 case NV_D0:
422 case NV_E0:
423 nvc0_software_create(dev);
424 break;
425 default:
426 break;
427 }
428
429 switch (dev_priv->card_type) {
430 case NV_04:
Ben Skeggs18b54c42011-05-25 15:22:33 +1000431 nv04_graph_create(dev);
432 break;
433 case NV_10:
434 nv10_graph_create(dev);
435 break;
436 case NV_20:
437 case NV_30:
438 nv20_graph_create(dev);
439 break;
440 case NV_40:
441 nv40_graph_create(dev);
442 break;
443 case NV_50:
444 nv50_graph_create(dev);
445 break;
446 case NV_C0:
Ben Skeggs06784092011-07-11 15:57:54 +1000447 case NV_D0:
Ben Skeggs18b54c42011-05-25 15:22:33 +1000448 nvc0_graph_create(dev);
449 break;
Ben Skeggsab394542012-03-13 13:05:13 +1000450 case NV_E0:
451 nve0_graph_create(dev);
452 break;
Ben Skeggs18b54c42011-05-25 15:22:33 +1000453 default:
Ben Skeggs7ff54412011-03-18 10:25:59 +1000454 break;
455 }
Ben Skeggs7ff54412011-03-18 10:25:59 +1000456
Ben Skeggs18b54c42011-05-25 15:22:33 +1000457 switch (dev_priv->chipset) {
458 case 0x84:
459 case 0x86:
460 case 0x92:
461 case 0x94:
462 case 0x96:
463 case 0xa0:
464 nv84_crypt_create(dev);
465 break;
Ben Skeggs8f27c542011-08-11 14:58:06 +1000466 case 0x98:
467 case 0xaa:
468 case 0xac:
469 nv98_crypt_create(dev);
470 break;
Ben Skeggs18b54c42011-05-25 15:22:33 +1000471 }
Ben Skeggsa02ccc72011-04-04 16:08:24 +1000472
Ben Skeggs18b54c42011-05-25 15:22:33 +1000473 switch (dev_priv->card_type) {
474 case NV_50:
475 switch (dev_priv->chipset) {
476 case 0xa3:
477 case 0xa5:
478 case 0xa8:
Ben Skeggs18b54c42011-05-25 15:22:33 +1000479 nva3_copy_create(dev);
480 break;
481 }
482 break;
483 case NV_C0:
Ben Skeggs14f04582012-08-27 16:22:49 +1000484 if (!(nv_rd32(dev, 0x022500) & 0x00000200))
485 nvc0_copy_create(dev, 1);
Ben Skeggs0c75f332012-05-04 17:16:46 +1000486 case NV_D0:
Ben Skeggs14f04582012-08-27 16:22:49 +1000487 if (!(nv_rd32(dev, 0x022500) & 0x00000100))
488 nvc0_copy_create(dev, 0);
Ben Skeggs18b54c42011-05-25 15:22:33 +1000489 break;
490 default:
491 break;
492 }
493
Ben Skeggs8f27c542011-08-11 14:58:06 +1000494 if (dev_priv->chipset >= 0xa3 || dev_priv->chipset == 0x98) {
495 nv84_bsp_create(dev);
496 nv84_vp_create(dev);
497 nv98_ppp_create(dev);
498 } else
499 if (dev_priv->chipset >= 0x84) {
500 nv50_mpeg_create(dev);
501 nv84_bsp_create(dev);
502 nv84_vp_create(dev);
503 } else
504 if (dev_priv->chipset >= 0x50) {
505 nv50_mpeg_create(dev);
506 } else
Ben Skeggs52d07332011-06-23 16:44:05 +1000507 if (dev_priv->card_type == NV_40 ||
508 dev_priv->chipset == 0x31 ||
509 dev_priv->chipset == 0x34 ||
Ben Skeggs8f27c542011-08-11 14:58:06 +1000510 dev_priv->chipset == 0x36) {
Ben Skeggs323dcac2011-06-23 16:21:21 +1000511 nv31_mpeg_create(dev);
Ben Skeggs8f27c542011-08-11 14:58:06 +1000512 }
Ben Skeggs18b54c42011-05-25 15:22:33 +1000513
Ben Skeggs6dfdd7a2011-03-31 15:40:43 +1000514 for (e = 0; e < NVOBJ_ENGINE_NR; e++) {
515 if (dev_priv->eng[e]) {
516 ret = dev_priv->eng[e]->init(dev, e);
517 if (ret)
518 goto out_engine;
519 }
520 }
Marcin Kościelnickia32ed692010-01-26 14:00:42 +0000521 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000522
Ben Skeggs1575b362011-07-04 11:55:39 +1000523 ret = nouveau_irq_init(dev);
524 if (ret)
Ben Skeggsc420b2d2012-05-01 20:48:08 +1000525 goto out_engine;
Ben Skeggs1575b362011-07-04 11:55:39 +1000526
Ben Skeggs27d50302011-10-06 12:46:40 +1000527 ret = nouveau_display_create(dev);
Ben Skeggse88efe02010-07-09 10:56:08 +1000528 if (ret)
Ben Skeggs1575b362011-07-04 11:55:39 +1000529 goto out_irq;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000530
Ben Skeggs10b461e2011-08-02 19:29:37 +1000531 nouveau_backlight_init(dev);
Ben Skeggs7d3a7662012-02-01 15:17:07 +1000532 nouveau_pm_init(dev);
Ben Skeggs10b461e2011-08-02 19:29:37 +1000533
Ben Skeggsc61205b2012-03-23 09:10:22 +1000534 if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
Ben Skeggs48aca132012-03-18 00:40:41 +1000535 ret = nouveau_card_channel_init(dev);
Francisco Jerez0c6c1c22010-09-22 00:58:54 +0200536 if (ret)
Ben Skeggs5e120f62012-04-30 13:55:29 +1000537 goto out_pm;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000538 }
539
Ben Skeggs1575b362011-07-04 11:55:39 +1000540 if (dev->mode_config.num_crtc) {
Ben Skeggsf62b27d2011-11-09 15:18:47 +1000541 ret = nouveau_display_init(dev);
Ben Skeggs1575b362011-07-04 11:55:39 +1000542 if (ret)
543 goto out_chan;
544
545 nouveau_fbcon_init(dev);
Ben Skeggs1575b362011-07-04 11:55:39 +1000546 }
547
Ben Skeggs6ee73862009-12-11 19:24:15 +1000548 return 0;
Marcin Kościelnickic5804be2009-12-14 20:58:39 +0000549
Ben Skeggs1575b362011-07-04 11:55:39 +1000550out_chan:
Ben Skeggs48aca132012-03-18 00:40:41 +1000551 nouveau_card_channel_fini(dev);
Ben Skeggs7d3a7662012-02-01 15:17:07 +1000552out_pm:
553 nouveau_pm_fini(dev);
Ben Skeggs10b461e2011-08-02 19:29:37 +1000554 nouveau_backlight_exit(dev);
Ben Skeggs27d50302011-10-06 12:46:40 +1000555 nouveau_display_destroy(dev);
Marcin Kościelnickic5804be2009-12-14 20:58:39 +0000556out_irq:
Ben Skeggs35fa2f22010-10-21 14:07:03 +1000557 nouveau_irq_fini(dev);
Ben Skeggs6dfdd7a2011-03-31 15:40:43 +1000558out_engine:
Ben Skeggsaba99a82011-05-25 14:48:50 +1000559 if (!dev_priv->noaccel) {
Ben Skeggs6dfdd7a2011-03-31 15:40:43 +1000560 for (e = e - 1; e >= 0; e--) {
Ben Skeggs2703c212011-04-01 09:50:18 +1000561 if (!dev_priv->eng[e])
562 continue;
Ben Skeggs6c320fe2011-07-20 11:22:33 +1000563 dev_priv->eng[e]->fini(dev, e, false);
Ben Skeggs2703c212011-04-01 09:50:18 +1000564 dev_priv->eng[e]->destroy(dev,e );
Ben Skeggs6dfdd7a2011-03-31 15:40:43 +1000565 }
566 }
Ben Skeggsfbd28952010-09-01 15:24:34 +1000567 nouveau_mem_gart_fini(dev);
Ben Skeggs24f246a2011-06-10 13:36:08 +1000568out_ttmvram:
569 nouveau_mem_vram_fini(dev);
Marcin Kościelnickic5804be2009-12-14 20:58:39 +0000570out_bios:
571 nouveau_bios_takedown(dev);
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200572out_display_early:
573 engine->display.late_takedown(dev);
Marcin Kościelnickic5804be2009-12-14 20:58:39 +0000574out:
Andreas Heider5c5ed6e2012-05-21 00:14:51 +0100575 vga_switcheroo_unregister_client(dev->pdev);
Marcin Kościelnickic5804be2009-12-14 20:58:39 +0000576 vga_client_register(dev->pdev, NULL, NULL, NULL);
577 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000578}
579
580static void nouveau_card_takedown(struct drm_device *dev)
581{
582 struct drm_nouveau_private *dev_priv = dev->dev_private;
583 struct nouveau_engine *engine = &dev_priv->engine;
Ben Skeggs6dfdd7a2011-03-31 15:40:43 +1000584 int e;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000585
Ben Skeggs1575b362011-07-04 11:55:39 +1000586 if (dev->mode_config.num_crtc) {
Ben Skeggs1575b362011-07-04 11:55:39 +1000587 nouveau_fbcon_fini(dev);
Ben Skeggsf62b27d2011-11-09 15:18:47 +1000588 nouveau_display_fini(dev);
Ben Skeggs1575b362011-07-04 11:55:39 +1000589 }
Ben Skeggs06b75e32011-06-08 18:29:12 +1000590
Ben Skeggs48aca132012-03-18 00:40:41 +1000591 nouveau_card_channel_fini(dev);
Ben Skeggs7d3a7662012-02-01 15:17:07 +1000592 nouveau_pm_fini(dev);
Ben Skeggs10b461e2011-08-02 19:29:37 +1000593 nouveau_backlight_exit(dev);
Ben Skeggs27d50302011-10-06 12:46:40 +1000594 nouveau_display_destroy(dev);
Ben Skeggs06b75e32011-06-08 18:29:12 +1000595
Ben Skeggsaba99a82011-05-25 14:48:50 +1000596 if (!dev_priv->noaccel) {
Ben Skeggs6dfdd7a2011-03-31 15:40:43 +1000597 for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
598 if (dev_priv->eng[e]) {
Ben Skeggs6c320fe2011-07-20 11:22:33 +1000599 dev_priv->eng[e]->fini(dev, e, false);
Ben Skeggs6dfdd7a2011-03-31 15:40:43 +1000600 dev_priv->eng[e]->destroy(dev,e );
601 }
602 }
Ben Skeggsb6d3d872010-06-07 15:38:27 +1000603 }
Ben Skeggsb6d3d872010-06-07 15:38:27 +1000604
Jimmy Rentz97666102011-04-17 16:15:09 -0400605 if (dev_priv->vga_ram) {
606 nouveau_bo_unpin(dev_priv->vga_ram);
607 nouveau_bo_ref(NULL, &dev_priv->vga_ram);
608 }
609
Ben Skeggsb6d3d872010-06-07 15:38:27 +1000610 mutex_lock(&dev->struct_mutex);
611 ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
612 ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
613 mutex_unlock(&dev->struct_mutex);
Ben Skeggsfbd28952010-09-01 15:24:34 +1000614 nouveau_mem_gart_fini(dev);
Ben Skeggs24f246a2011-06-10 13:36:08 +1000615 nouveau_mem_vram_fini(dev);
Ben Skeggsb6d3d872010-06-07 15:38:27 +1000616
Ben Skeggsb6d3d872010-06-07 15:38:27 +1000617 nouveau_bios_takedown(dev);
Ben Skeggs668b6c02011-12-15 10:43:03 +1000618 engine->display.late_takedown(dev);
619
620 nouveau_irq_fini(dev);
Ben Skeggsb6d3d872010-06-07 15:38:27 +1000621
Andreas Heider5c5ed6e2012-05-21 00:14:51 +0100622 vga_switcheroo_unregister_client(dev->pdev);
Ben Skeggsb6d3d872010-06-07 15:38:27 +1000623 vga_client_register(dev->pdev, NULL, NULL, NULL);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000624}
625
Ben Skeggs3f0a68d2011-05-31 11:11:28 +1000626int
627nouveau_open(struct drm_device *dev, struct drm_file *file_priv)
628{
Ben Skeggsfe32b162011-06-03 10:07:08 +1000629 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs3f0a68d2011-05-31 11:11:28 +1000630 struct nouveau_fpriv *fpriv;
Ben Skeggse41f26e2011-06-07 15:35:37 +1000631 int ret;
Ben Skeggs3f0a68d2011-05-31 11:11:28 +1000632
633 fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
634 if (unlikely(!fpriv))
635 return -ENOMEM;
636
637 spin_lock_init(&fpriv->lock);
Ben Skeggse8a863c2011-06-01 19:18:48 +1000638 INIT_LIST_HEAD(&fpriv->channels);
639
Ben Skeggse41f26e2011-06-07 15:35:37 +1000640 if (dev_priv->card_type == NV_50) {
641 ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL,
642 &fpriv->vm);
643 if (ret) {
644 kfree(fpriv);
645 return ret;
646 }
647 } else
648 if (dev_priv->card_type >= NV_C0) {
Ben Skeggs5de80372011-06-08 18:17:41 +1000649 ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL,
650 &fpriv->vm);
651 if (ret) {
652 kfree(fpriv);
653 return ret;
654 }
Ben Skeggse41f26e2011-06-07 15:35:37 +1000655 }
Ben Skeggsfe32b162011-06-03 10:07:08 +1000656
Ben Skeggs3f0a68d2011-05-31 11:11:28 +1000657 file_priv->driver_priv = fpriv;
658 return 0;
659}
660
Ben Skeggs6ee73862009-12-11 19:24:15 +1000661/* here a client dies, release the stuff that was allocated for its
662 * file_priv */
663void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv)
664{
665 nouveau_channel_cleanup(dev, file_priv);
666}
667
Ben Skeggs3f0a68d2011-05-31 11:11:28 +1000668void
669nouveau_postclose(struct drm_device *dev, struct drm_file *file_priv)
670{
671 struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
Ben Skeggsfe32b162011-06-03 10:07:08 +1000672 nouveau_vm_ref(NULL, &fpriv->vm, NULL);
Ben Skeggs3f0a68d2011-05-31 11:11:28 +1000673 kfree(fpriv);
674}
675
Ben Skeggs6ee73862009-12-11 19:24:15 +1000676/* first module load, setup the mmio/fb mapping */
677/* KMS: we need mmio at load time, not when the first drm client opens. */
678int nouveau_firstopen(struct drm_device *dev)
679{
680 return 0;
681}
682
683/* if we have an OF card, copy vbios to RAMIN */
684static void nouveau_OF_copy_vbios_to_ramin(struct drm_device *dev)
685{
686#if defined(__powerpc__)
687 int size, i;
688 const uint32_t *bios;
689 struct device_node *dn = pci_device_to_OF_node(dev->pdev);
690 if (!dn) {
691 NV_INFO(dev, "Unable to get the OF node\n");
692 return;
693 }
694
695 bios = of_get_property(dn, "NVDA,BMP", &size);
696 if (bios) {
697 for (i = 0; i < size; i += 4)
698 nv_wi32(dev, i, bios[i/4]);
699 NV_INFO(dev, "OF bios successfully copied (%d bytes)\n", size);
700 } else {
701 NV_INFO(dev, "Unable to get the OF bios\n");
702 }
703#endif
704}
705
Marcin Slusarz06415c52010-05-16 17:29:56 +0200706static struct apertures_struct *nouveau_get_apertures(struct drm_device *dev)
707{
708 struct pci_dev *pdev = dev->pdev;
709 struct apertures_struct *aper = alloc_apertures(3);
710 if (!aper)
711 return NULL;
712
713 aper->ranges[0].base = pci_resource_start(pdev, 1);
714 aper->ranges[0].size = pci_resource_len(pdev, 1);
715 aper->count = 1;
716
717 if (pci_resource_len(pdev, 2)) {
718 aper->ranges[aper->count].base = pci_resource_start(pdev, 2);
719 aper->ranges[aper->count].size = pci_resource_len(pdev, 2);
720 aper->count++;
721 }
722
723 if (pci_resource_len(pdev, 3)) {
724 aper->ranges[aper->count].base = pci_resource_start(pdev, 3);
725 aper->ranges[aper->count].size = pci_resource_len(pdev, 3);
726 aper->count++;
727 }
728
729 return aper;
730}
731
732static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
733{
734 struct drm_nouveau_private *dev_priv = dev->dev_private;
Marcin Slusarz3b9676e2010-05-16 17:33:09 +0200735 bool primary = false;
Marcin Slusarz06415c52010-05-16 17:29:56 +0200736 dev_priv->apertures = nouveau_get_apertures(dev);
737 if (!dev_priv->apertures)
738 return -ENOMEM;
739
Marcin Slusarz3b9676e2010-05-16 17:33:09 +0200740#ifdef CONFIG_X86
741 primary = dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
742#endif
Emil Velikovf2129492011-03-19 23:31:52 +0000743
Marcin Slusarz3b9676e2010-05-16 17:33:09 +0200744 remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb", primary);
Marcin Slusarz06415c52010-05-16 17:29:56 +0200745 return 0;
746}
747
Ben Skeggs94580292012-07-06 12:14:00 +1000748void *
749nouveau_newpriv(struct drm_device *dev)
750{
751 struct drm_nouveau_private *dev_priv = dev->dev_private;
752 return dev_priv->newpriv;
753}
754
Ben Skeggs6ee73862009-12-11 19:24:15 +1000755int nouveau_load(struct drm_device *dev, unsigned long flags)
756{
757 struct drm_nouveau_private *dev_priv;
Ben Skeggs2f5394c2012-03-12 15:55:43 +1000758 uint32_t reg0 = ~0, strap;
Ben Skeggscd0b0722010-06-01 15:56:22 +1000759 int ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000760
761 dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
Dan Carpentera0d069e2010-07-30 17:04:32 +0200762 if (!dev_priv) {
763 ret = -ENOMEM;
764 goto err_out;
765 }
Ben Skeggs94580292012-07-06 12:14:00 +1000766 dev_priv->newpriv = dev->dev_private;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000767 dev->dev_private = dev_priv;
768 dev_priv->dev = dev;
769
770 dev_priv->flags = flags & NOUVEAU_FLAGS;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000771
772 NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
773 dev->pci_vendor, dev->pci_device, dev->pdev->class);
774
Ben Skeggs586c55f2012-07-09 14:14:48 +1000775 /* determine chipset and derive architecture from it */
776 reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
777 if ((reg0 & 0x0f000000) > 0) {
778 dev_priv->chipset = (reg0 & 0xff00000) >> 20;
779 switch (dev_priv->chipset & 0xf0) {
780 case 0x10:
781 case 0x20:
782 case 0x30:
783 dev_priv->card_type = dev_priv->chipset & 0xf0;
784 break;
785 case 0x40:
786 case 0x60:
787 dev_priv->card_type = NV_40;
788 break;
789 case 0x50:
790 case 0x80:
791 case 0x90:
792 case 0xa0:
793 dev_priv->card_type = NV_50;
794 break;
795 case 0xc0:
796 dev_priv->card_type = NV_C0;
797 break;
798 case 0xd0:
799 dev_priv->card_type = NV_D0;
800 break;
801 case 0xe0:
802 dev_priv->card_type = NV_E0;
803 break;
804 default:
805 break;
Ben Skeggs2f5394c2012-03-12 15:55:43 +1000806 }
Ben Skeggs586c55f2012-07-09 14:14:48 +1000807 } else
808 if ((reg0 & 0xff00fff0) == 0x20004000) {
809 if (reg0 & 0x00f00000)
810 dev_priv->chipset = 0x05;
811 else
812 dev_priv->chipset = 0x04;
813 dev_priv->card_type = NV_04;
Ben Skeggs2f5394c2012-03-12 15:55:43 +1000814 }
815
816 if (!dev_priv->card_type) {
817 NV_ERROR(dev, "unsupported chipset 0x%08x\n", reg0);
818 ret = -EINVAL;
819 goto err_priv;
820 }
821
Ben Skeggs42eddbd2012-05-09 20:17:07 +1000822 NV_INFO(dev, "Detected an NV%02x generation card (0x%08x)\n",
Ben Skeggs2f5394c2012-03-12 15:55:43 +1000823 dev_priv->card_type, reg0);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000824
Ben Skeggsf2cbe462011-07-21 15:39:06 +1000825 /* determine frequency of timing crystal */
826 strap = nv_rd32(dev, 0x101000);
827 if ( dev_priv->chipset < 0x17 ||
828 (dev_priv->chipset >= 0x20 && dev_priv->chipset <= 0x25))
829 strap &= 0x00000040;
830 else
831 strap &= 0x00400040;
832
833 switch (strap) {
834 case 0x00000000: dev_priv->crystal = 13500; break;
835 case 0x00000040: dev_priv->crystal = 14318; break;
836 case 0x00400000: dev_priv->crystal = 27000; break;
837 case 0x00400040: dev_priv->crystal = 25000; break;
838 }
839
840 NV_DEBUG(dev, "crystal freq: %dKHz\n", dev_priv->crystal);
841
Ben Skeggsaba99a82011-05-25 14:48:50 +1000842 /* Determine whether we'll attempt acceleration or not, some
843 * cards are disabled by default here due to them being known
844 * non-functional, or never been tested due to lack of hw.
845 */
846 dev_priv->noaccel = !!nouveau_noaccel;
847 if (nouveau_noaccel == -1) {
848 switch (dev_priv->chipset) {
Ben Skeggs06784092011-07-11 15:57:54 +1000849 case 0xd9: /* known broken */
Ben Skeggsab394542012-03-13 13:05:13 +1000850 case 0xe4: /* needs binary driver firmware */
851 case 0xe7: /* needs binary driver firmware */
Ben Skeggsad830d22011-05-27 16:18:10 +1000852 NV_INFO(dev, "acceleration disabled by default, pass "
853 "noaccel=0 to force enable\n");
Ben Skeggsaba99a82011-05-25 14:48:50 +1000854 dev_priv->noaccel = true;
855 break;
856 default:
857 dev_priv->noaccel = false;
858 break;
859 }
860 }
861
Ben Skeggscd0b0722010-06-01 15:56:22 +1000862 ret = nouveau_remove_conflicting_drivers(dev);
863 if (ret)
Ben Skeggs586c55f2012-07-09 14:14:48 +1000864 goto err_priv;
Marcin Slusarz06415c52010-05-16 17:29:56 +0200865
Ben Skeggs6ee73862009-12-11 19:24:15 +1000866 nouveau_OF_copy_vbios_to_ramin(dev);
867
868 /* Special flags */
869 if (dev->pci_device == 0x01a0)
870 dev_priv->flags |= NV_NFORCE;
871 else if (dev->pci_device == 0x01f0)
872 dev_priv->flags |= NV_NFORCE2;
873
874 /* For kernel modesetting, init card now and bring up fbcon */
Ben Skeggscd0b0722010-06-01 15:56:22 +1000875 ret = nouveau_card_init(dev);
876 if (ret)
Ben Skeggs3863c9b2012-07-14 19:09:17 +1000877 goto err_priv;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000878
879 return 0;
Dan Carpentera0d069e2010-07-30 17:04:32 +0200880
Dan Carpentera0d069e2010-07-30 17:04:32 +0200881err_priv:
Ben Skeggs94580292012-07-06 12:14:00 +1000882 dev->dev_private = dev_priv->newpriv;
Dan Carpentera0d069e2010-07-30 17:04:32 +0200883 kfree(dev_priv);
Dan Carpentera0d069e2010-07-30 17:04:32 +0200884err_out:
885 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000886}
887
Ben Skeggs6ee73862009-12-11 19:24:15 +1000888void nouveau_lastclose(struct drm_device *dev)
889{
Dave Airlie5ccb3772010-12-07 13:56:26 +1000890 vga_switcheroo_process_delayed_switch();
Ben Skeggs6ee73862009-12-11 19:24:15 +1000891}
892
893int nouveau_unload(struct drm_device *dev)
894{
895 struct drm_nouveau_private *dev_priv = dev->dev_private;
896
Ben Skeggscd0b0722010-06-01 15:56:22 +1000897 nouveau_card_takedown(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000898
Ben Skeggs94580292012-07-06 12:14:00 +1000899 dev->dev_private = dev_priv->newpriv;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000900 kfree(dev_priv);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000901 return 0;
902}
903
Ben Skeggs6ee73862009-12-11 19:24:15 +1000904/* Waits for PGRAPH to go completely idle */
905bool nouveau_wait_for_idle(struct drm_device *dev)
906{
Francisco Jerez0541324a2010-10-18 16:15:15 +0200907 struct drm_nouveau_private *dev_priv = dev->dev_private;
908 uint32_t mask = ~0;
909
910 if (dev_priv->card_type == NV_40)
911 mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
912
913 if (!nv_wait(dev, NV04_PGRAPH_STATUS, mask, 0)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000914 NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n",
915 nv_rd32(dev, NV04_PGRAPH_STATUS));
916 return false;
917 }
918
919 return true;
920}
921