blob: c7d8e2902c6c5f7e42e361b72e7a834f5c33d671 [file] [log] [blame]
Ben Skeggs9274f4a2012-07-06 07:36:43 +10001/*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
Ben Skeggs97190472015-01-14 15:35:00 +100024#include "priv.h"
25#include "acpi.h"
Ben Skeggs9274f4a2012-07-06 07:36:43 +100026
Ben Skeggs97190472015-01-14 15:35:00 +100027#include <core/notify.h>
Ben Skeggsa1bfb292015-08-20 14:54:15 +100028#include <core/option.h>
Ben Skeggsd01c3092014-08-10 04:10:21 +100029
Ben Skeggsa1bfb292015-08-20 14:54:15 +100030#include <subdev/bios.h>
Ben Skeggs9274f4a2012-07-06 07:36:43 +100031
32static DEFINE_MUTEX(nv_devices_mutex);
33static LIST_HEAD(nv_devices);
34
Ben Skeggs7974dd12015-08-20 14:54:17 +100035static struct nvkm_device *
36nvkm_device_find_locked(u64 handle)
Ben Skeggs9274f4a2012-07-06 07:36:43 +100037{
Ben Skeggs7974dd12015-08-20 14:54:17 +100038 struct nvkm_device *device;
Ben Skeggs9274f4a2012-07-06 07:36:43 +100039 list_for_each_entry(device, &nv_devices, head) {
Ben Skeggs7974dd12015-08-20 14:54:17 +100040 if (device->handle == handle)
41 return device;
Ben Skeggs9274f4a2012-07-06 07:36:43 +100042 }
Ben Skeggs7974dd12015-08-20 14:54:17 +100043 return NULL;
44}
45
46struct nvkm_device *
47nvkm_device_find(u64 handle)
48{
49 struct nvkm_device *device;
50 mutex_lock(&nv_devices_mutex);
51 device = nvkm_device_find_locked(handle);
Ben Skeggs9274f4a2012-07-06 07:36:43 +100052 mutex_unlock(&nv_devices_mutex);
Ben Skeggs7974dd12015-08-20 14:54:17 +100053 return device;
Ben Skeggs9274f4a2012-07-06 07:36:43 +100054}
55
Ben Skeggs803c1782014-08-10 04:10:21 +100056int
Ben Skeggs97190472015-01-14 15:35:00 +100057nvkm_device_list(u64 *name, int size)
Ben Skeggs803c1782014-08-10 04:10:21 +100058{
Ben Skeggs97190472015-01-14 15:35:00 +100059 struct nvkm_device *device;
Ben Skeggs803c1782014-08-10 04:10:21 +100060 int nr = 0;
61 mutex_lock(&nv_devices_mutex);
62 list_for_each_entry(device, &nv_devices, head) {
63 if (nr++ < size)
64 name[nr - 1] = device->handle;
65 }
66 mutex_unlock(&nv_devices_mutex);
67 return nr;
68}
69
Ben Skeggsa1e88732015-08-20 14:54:15 +100070#include <core/parent.h>
Ben Skeggs7974dd12015-08-20 14:54:17 +100071#include <core/client.h>
Ben Skeggsa1e88732015-08-20 14:54:15 +100072
Ben Skeggs97190472015-01-14 15:35:00 +100073struct nvkm_device *
Ben Skeggsa38f37a2014-12-05 11:20:19 +100074nv_device(void *obj)
75{
Ben Skeggs97190472015-01-14 15:35:00 +100076 struct nvkm_object *device = nv_object(obj);
Ben Skeggsa1e88732015-08-20 14:54:15 +100077
Ben Skeggs8000fb22014-12-05 12:21:34 +100078 if (device->engine == NULL) {
Ben Skeggsa1e88732015-08-20 14:54:15 +100079 while (device && device->parent) {
Ben Skeggs7974dd12015-08-20 14:54:17 +100080 if (!nv_iclass(device, NV_SUBDEV_CLASS) &&
81 device->parent == &nvkm_client(device)->namedb.parent.object) {
Ben Skeggsa1e88732015-08-20 14:54:15 +100082 struct {
83 struct nvkm_parent base;
84 struct nvkm_device *device;
85 } *udevice = (void *)device;
86 return udevice->device;
87 }
Ben Skeggs8000fb22014-12-05 12:21:34 +100088 device = device->parent;
Ben Skeggsa1e88732015-08-20 14:54:15 +100089 }
Ben Skeggs8000fb22014-12-05 12:21:34 +100090 } else {
Ben Skeggsec0e5542014-12-05 12:37:19 +100091 device = &nv_object(obj)->engine->subdev.object;
Ben Skeggs490d5952014-12-05 11:26:23 +100092 if (device && device->parent)
93 device = device->parent;
Ben Skeggsa38f37a2014-12-05 11:20:19 +100094 }
Ben Skeggs490d5952014-12-05 11:26:23 +100095#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
Ben Skeggs53003942015-08-20 14:54:13 +100096 BUG_ON(!device);
Ben Skeggsa38f37a2014-12-05 11:20:19 +100097#endif
Ben Skeggsa38f37a2014-12-05 11:20:19 +100098 return (void *)device;
99}
100
Ben Skeggs066a5d02013-04-25 11:35:18 +1000101static int
Ben Skeggs97190472015-01-14 15:35:00 +1000102nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size,
103 struct nvkm_notify *notify)
Ben Skeggs79ca2772014-08-10 04:10:20 +1000104{
105 if (!WARN_ON(size != 0)) {
106 notify->size = 0;
107 notify->types = 1;
108 notify->index = 0;
109 return 0;
110 }
111 return -EINVAL;
112}
113
114static const struct nvkm_event_func
Ben Skeggs97190472015-01-14 15:35:00 +1000115nvkm_device_event_func = {
116 .ctor = nvkm_device_event_ctor,
Ben Skeggs79ca2772014-08-10 04:10:20 +1000117};
118
Ben Skeggsa1e88732015-08-20 14:54:15 +1000119int
120nvkm_device_fini(struct nvkm_device *device, bool suspend)
Ben Skeggs066a5d02013-04-25 11:35:18 +1000121{
Ben Skeggs97190472015-01-14 15:35:00 +1000122 struct nvkm_object *subdev;
Ben Skeggs10caad32013-04-25 11:43:54 +1000123 int ret, i;
124
125 for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
126 if ((subdev = device->subdev[i])) {
127 if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
Ben Skeggs97190472015-01-14 15:35:00 +1000128 ret = nvkm_object_dec(subdev, suspend);
Ben Skeggs10caad32013-04-25 11:43:54 +1000129 if (ret && suspend)
130 goto fail;
131 }
132 }
133 }
134
Ben Skeggsed76a872014-06-13 12:42:21 +1000135 ret = nvkm_acpi_fini(device, suspend);
Ben Skeggs7974dd12015-08-20 14:54:17 +1000136
137 if (device->func->fini)
138 device->func->fini(device, suspend);
Ben Skeggs10caad32013-04-25 11:43:54 +1000139fail:
140 for (; ret && i < NVDEV_SUBDEV_NR; i++) {
141 if ((subdev = device->subdev[i])) {
142 if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
Ben Skeggs97190472015-01-14 15:35:00 +1000143 ret = nvkm_object_inc(subdev);
Ben Skeggs10caad32013-04-25 11:43:54 +1000144 if (ret) {
145 /* XXX */
146 }
147 }
148 }
149 }
150
151 return ret;
Ben Skeggs066a5d02013-04-25 11:35:18 +1000152}
153
Ben Skeggsa1e88732015-08-20 14:54:15 +1000154int
Ben Skeggs7974dd12015-08-20 14:54:17 +1000155nvkm_device_preinit(struct nvkm_device *device)
156{
157 int ret;
158 s64 time;
159
160 nvdev_trace(device, "preinit running...\n");
161 time = ktime_to_us(ktime_get());
162
163 if (device->func->preinit) {
164 ret = device->func->preinit(device);
165 if (ret)
166 goto fail;
167 }
168
169 time = ktime_to_us(ktime_get()) - time;
170 nvdev_trace(device, "preinit completed in %lldus\n", time);
171 return 0;
172
173fail:
174 nvdev_error(device, "preinit failed with %d\n", ret);
175 return ret;
176}
177
178int
Ben Skeggsa1e88732015-08-20 14:54:15 +1000179nvkm_device_init(struct nvkm_device *device)
Ben Skeggs066a5d02013-04-25 11:35:18 +1000180{
Ben Skeggs97190472015-01-14 15:35:00 +1000181 struct nvkm_object *subdev;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000182 int ret, i = 0, c;
Ben Skeggsed76a872014-06-13 12:42:21 +1000183
Ben Skeggs7974dd12015-08-20 14:54:17 +1000184 ret = nvkm_device_preinit(device);
185 if (ret)
186 return ret;
187
Ben Skeggsed76a872014-06-13 12:42:21 +1000188 ret = nvkm_acpi_init(device);
189 if (ret)
190 goto fail;
Ben Skeggs10caad32013-04-25 11:43:54 +1000191
Ben Skeggsa1e88732015-08-20 14:54:15 +1000192 for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) {
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000193#define _(s,m) case s: if (device->oclass[s] && !device->subdev[s]) { \
Ben Skeggsaa358882015-08-20 14:54:16 +1000194 ret = nvkm_object_old(nv_object(device), NULL, \
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000195 device->oclass[s], NULL, (s), \
196 (struct nvkm_object **)&device->m); \
197 if (ret == -ENODEV) { \
198 device->oclass[s] = NULL; \
199 continue; \
200 } \
201 if (ret) \
202 goto fail; \
203 device->subdev[s] = (struct nvkm_object *)device->m; \
204} break
205 switch (i) {
206 _(NVDEV_SUBDEV_BAR , bar);
207 _(NVDEV_SUBDEV_VBIOS , bios);
208 _(NVDEV_SUBDEV_BUS , bus);
209 _(NVDEV_SUBDEV_CLK , clk);
210 _(NVDEV_SUBDEV_DEVINIT, devinit);
211 _(NVDEV_SUBDEV_FB , fb);
212 _(NVDEV_SUBDEV_FUSE , fuse);
213 _(NVDEV_SUBDEV_GPIO , gpio);
214 _(NVDEV_SUBDEV_I2C , i2c);
215 _(NVDEV_SUBDEV_IBUS , ibus);
216 _(NVDEV_SUBDEV_INSTMEM, imem);
217 _(NVDEV_SUBDEV_LTC , ltc);
218 _(NVDEV_SUBDEV_MC , mc);
219 _(NVDEV_SUBDEV_MMU , mmu);
220 _(NVDEV_SUBDEV_MXM , mxm);
221 _(NVDEV_SUBDEV_PMU , pmu);
222 _(NVDEV_SUBDEV_THERM , therm);
223 _(NVDEV_SUBDEV_TIMER , timer);
224 _(NVDEV_SUBDEV_VOLT , volt);
225 _(NVDEV_ENGINE_BSP , bsp);
226 _(NVDEV_ENGINE_CE0 , ce[0]);
227 _(NVDEV_ENGINE_CE1 , ce[1]);
228 _(NVDEV_ENGINE_CE2 , ce[2]);
229 _(NVDEV_ENGINE_CIPHER , cipher);
230 _(NVDEV_ENGINE_DISP , disp);
231 _(NVDEV_ENGINE_DMAOBJ , dma);
232 _(NVDEV_ENGINE_FIFO , fifo);
233 _(NVDEV_ENGINE_GR , gr);
234 _(NVDEV_ENGINE_IFB , ifb);
235 _(NVDEV_ENGINE_ME , me);
236 _(NVDEV_ENGINE_MPEG , mpeg);
237 _(NVDEV_ENGINE_MSENC , msenc);
238 _(NVDEV_ENGINE_MSPDEC , mspdec);
239 _(NVDEV_ENGINE_MSPPP , msppp);
240 _(NVDEV_ENGINE_MSVLD , msvld);
241 _(NVDEV_ENGINE_PM , pm);
242 _(NVDEV_ENGINE_SEC , sec);
243 _(NVDEV_ENGINE_SW , sw);
244 _(NVDEV_ENGINE_VIC , vic);
245 _(NVDEV_ENGINE_VP , vp);
246 default:
247 WARN_ON(1);
248 continue;
249 }
250#undef _
251
252 /* note: can't init *any* subdevs until devinit has been run
253 * due to not knowing exactly what the vbios init tables will
254 * mess with. devinit also can't be run until all of its
255 * dependencies have been created.
256 *
257 * this code delays init of any subdev until all of devinit's
258 * dependencies have been created, and then initialises each
259 * subdev in turn as they're created.
260 */
261 while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
262 struct nvkm_object *subdev = device->subdev[c++];
263 if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
Ben Skeggs97190472015-01-14 15:35:00 +1000264 ret = nvkm_object_inc(subdev);
Ben Skeggs10caad32013-04-25 11:43:54 +1000265 if (ret)
266 goto fail;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000267 } else
268 if (subdev) {
Ben Skeggs97190472015-01-14 15:35:00 +1000269 nvkm_subdev_reset(subdev);
Ben Skeggs10caad32013-04-25 11:43:54 +1000270 }
271 }
272 }
273
274 ret = 0;
275fail:
276 for (--i; ret && i >= 0; i--) {
277 if ((subdev = device->subdev[i])) {
278 if (!nv_iclass(subdev, NV_ENGINE_CLASS))
Ben Skeggs97190472015-01-14 15:35:00 +1000279 nvkm_object_dec(subdev, false);
Ben Skeggs10caad32013-04-25 11:43:54 +1000280 }
281 }
282
Ben Skeggsed76a872014-06-13 12:42:21 +1000283 if (ret)
284 nvkm_acpi_fini(device, false);
Ben Skeggs10caad32013-04-25 11:43:54 +1000285 return ret;
Ben Skeggs066a5d02013-04-25 11:35:18 +1000286}
287
Alexandre Courbot420b9462014-02-17 15:17:26 +0900288resource_size_t
Ben Skeggs97190472015-01-14 15:35:00 +1000289nv_device_resource_start(struct nvkm_device *device, unsigned int bar)
Alexandre Courbot420b9462014-02-17 15:17:26 +0900290{
291 if (nv_device_is_pci(device)) {
292 return pci_resource_start(device->pdev, bar);
293 } else {
294 struct resource *res;
295 res = platform_get_resource(device->platformdev,
296 IORESOURCE_MEM, bar);
297 if (!res)
298 return 0;
299 return res->start;
300 }
301}
302
303resource_size_t
Ben Skeggs97190472015-01-14 15:35:00 +1000304nv_device_resource_len(struct nvkm_device *device, unsigned int bar)
Alexandre Courbot420b9462014-02-17 15:17:26 +0900305{
306 if (nv_device_is_pci(device)) {
307 return pci_resource_len(device->pdev, bar);
308 } else {
309 struct resource *res;
310 res = platform_get_resource(device->platformdev,
311 IORESOURCE_MEM, bar);
312 if (!res)
313 return 0;
314 return resource_size(res);
315 }
316}
317
Alexandre Courbot420b9462014-02-17 15:17:26 +0900318int
Ben Skeggs97190472015-01-14 15:35:00 +1000319nv_device_get_irq(struct nvkm_device *device, bool stall)
Alexandre Courbot420b9462014-02-17 15:17:26 +0900320{
321 if (nv_device_is_pci(device)) {
322 return device->pdev->irq;
323 } else {
324 return platform_get_irq_byname(device->platformdev,
325 stall ? "stall" : "nonstall");
326 }
327}
328
Ben Skeggse781dc82015-08-20 14:54:15 +1000329void
330nvkm_device_del(struct nvkm_device **pdevice)
331{
332 struct nvkm_device *device = *pdevice;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000333 int i;
Ben Skeggse781dc82015-08-20 14:54:15 +1000334 if (device) {
Ben Skeggse781dc82015-08-20 14:54:15 +1000335 mutex_lock(&nv_devices_mutex);
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000336 for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--)
337 nvkm_object_ref(NULL, &device->subdev[i]);
338
339 nvkm_event_fini(&device->event);
Ben Skeggse781dc82015-08-20 14:54:15 +1000340
341 if (device->pri)
342 iounmap(device->pri);
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000343 list_del(&device->head);
Ben Skeggs7974dd12015-08-20 14:54:17 +1000344
345 if (device->func->dtor)
346 *pdevice = device->func->dtor(device);
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000347 mutex_unlock(&nv_devices_mutex);
Ben Skeggse781dc82015-08-20 14:54:15 +1000348
Ben Skeggs7974dd12015-08-20 14:54:17 +1000349 kfree(*pdevice);
Ben Skeggse781dc82015-08-20 14:54:15 +1000350 *pdevice = NULL;
351 }
352}
353
Ben Skeggs7974dd12015-08-20 14:54:17 +1000354static const struct nvkm_engine_func
355nvkm_device_func = {
356};
357
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000358int
Ben Skeggs7974dd12015-08-20 14:54:17 +1000359nvkm_device_ctor(const struct nvkm_device_func *func,
360 const struct nvkm_device_quirk *quirk,
361 void *dev, enum nv_bus_type type, u64 handle,
362 const char *name, const char *cfg, const char *dbg,
363 bool detect, bool mmio, u64 subdev_mask,
364 struct nvkm_device *device)
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000365{
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000366 u64 mmio_base, mmio_size;
367 u32 boot0, strap;
368 void __iomem *map;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000369 int ret = -EEXIST;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000370 int i;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000371
372 mutex_lock(&nv_devices_mutex);
Ben Skeggs7974dd12015-08-20 14:54:17 +1000373 if (nvkm_device_find_locked(handle))
374 goto done;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000375
Ben Skeggs7974dd12015-08-20 14:54:17 +1000376 ret = nvkm_engine_ctor(&nvkm_device_func, device, 0, 0,
377 true, &device->engine);
378 device->engine.subdev.object.parent = NULL;
379 device->func = func;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000380 if (ret)
381 goto done;
382
Ben Skeggs7974dd12015-08-20 14:54:17 +1000383 device->quirk = quirk;
Alexandre Courbot420b9462014-02-17 15:17:26 +0900384 switch (type) {
Ben Skeggs97190472015-01-14 15:35:00 +1000385 case NVKM_BUS_PCI:
Alexandre Courbot420b9462014-02-17 15:17:26 +0900386 device->pdev = dev;
Ben Skeggs6d0d40e2015-08-20 14:54:06 +1000387 device->dev = &device->pdev->dev;
Alexandre Courbot420b9462014-02-17 15:17:26 +0900388 break;
Ben Skeggs97190472015-01-14 15:35:00 +1000389 case NVKM_BUS_PLATFORM:
Alexandre Courbot420b9462014-02-17 15:17:26 +0900390 device->platformdev = dev;
Ben Skeggs6d0d40e2015-08-20 14:54:06 +1000391 device->dev = &device->platformdev->dev;
Alexandre Courbot420b9462014-02-17 15:17:26 +0900392 break;
393 }
Ben Skeggs7974dd12015-08-20 14:54:17 +1000394 device->handle = handle;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000395 device->cfgopt = cfg;
396 device->dbgopt = dbg;
Ben Skeggs7974dd12015-08-20 14:54:17 +1000397 device->name = name;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000398
Ben Skeggs0d5dd3f2015-08-20 14:54:05 +1000399 list_add_tail(&device->head, &nv_devices);
Ben Skeggsed76a872014-06-13 12:42:21 +1000400
Ben Skeggs97190472015-01-14 15:35:00 +1000401 ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event);
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000402 if (ret)
403 goto done;
404
405 mmio_base = nv_device_resource_start(device, 0);
406 mmio_size = nv_device_resource_len(device, 0);
407
408 /* identify the chipset, and determine classes of subdev/engines */
409 if (detect) {
410 map = ioremap(mmio_base, 0x102000);
411 if (ret = -ENOMEM, map == NULL)
412 goto done;
413
414 /* switch mmio to cpu's native endianness */
415#ifndef __BIG_ENDIAN
416 if (ioread32_native(map + 0x000004) != 0x00000000) {
417#else
418 if (ioread32_native(map + 0x000004) == 0x00000000) {
419#endif
420 iowrite32_native(0x01000001, map + 0x000004);
421 ioread32_native(map);
422 }
423
424 /* read boot0 and strapping information */
425 boot0 = ioread32_native(map + 0x000000);
426 strap = ioread32_native(map + 0x101000);
427 iounmap(map);
428
429 /* determine chipset and derive architecture from it */
430 if ((boot0 & 0x1f000000) > 0) {
431 device->chipset = (boot0 & 0x1ff00000) >> 20;
432 device->chiprev = (boot0 & 0x000000ff);
433 switch (device->chipset & 0x1f0) {
434 case 0x010: {
435 if (0x461 & (1 << (device->chipset & 0xf)))
436 device->card_type = NV_10;
437 else
438 device->card_type = NV_11;
439 device->chiprev = 0x00;
440 break;
441 }
442 case 0x020: device->card_type = NV_20; break;
443 case 0x030: device->card_type = NV_30; break;
444 case 0x040:
445 case 0x060: device->card_type = NV_40; break;
446 case 0x050:
447 case 0x080:
448 case 0x090:
449 case 0x0a0: device->card_type = NV_50; break;
450 case 0x0c0:
451 case 0x0d0: device->card_type = NV_C0; break;
452 case 0x0e0:
453 case 0x0f0:
454 case 0x100: device->card_type = NV_E0; break;
455 case 0x110:
456 case 0x120: device->card_type = GM100; break;
457 default:
458 break;
459 }
460 } else
461 if ((boot0 & 0xff00fff0) == 0x20004000) {
462 if (boot0 & 0x00f00000)
463 device->chipset = 0x05;
464 else
465 device->chipset = 0x04;
466 device->card_type = NV_04;
467 }
468
469 switch (device->card_type) {
470 case NV_04: ret = nv04_identify(device); break;
471 case NV_10:
472 case NV_11: ret = nv10_identify(device); break;
473 case NV_20: ret = nv20_identify(device); break;
474 case NV_30: ret = nv30_identify(device); break;
475 case NV_40: ret = nv40_identify(device); break;
476 case NV_50: ret = nv50_identify(device); break;
477 case NV_C0: ret = gf100_identify(device); break;
478 case NV_E0: ret = gk104_identify(device); break;
479 case GM100: ret = gm100_identify(device); break;
480 default:
481 ret = -EINVAL;
482 break;
483 }
484
485 if (ret) {
486 nvdev_error(device, "unknown chipset (%08x)\n", boot0);
487 goto done;
488 }
489
490 nvdev_info(device, "NVIDIA %s (%08x)\n", device->cname, boot0);
491
492 /* determine frequency of timing crystal */
493 if ( device->card_type <= NV_10 || device->chipset < 0x17 ||
494 (device->chipset >= 0x20 && device->chipset < 0x25))
495 strap &= 0x00000040;
496 else
497 strap &= 0x00400040;
498
499 switch (strap) {
500 case 0x00000000: device->crystal = 13500; break;
501 case 0x00000040: device->crystal = 14318; break;
502 case 0x00400000: device->crystal = 27000; break;
503 case 0x00400040: device->crystal = 25000; break;
504 }
505 } else {
506 device->cname = "NULL";
507 device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass;
508 }
509
510 if (mmio) {
511 device->pri = ioremap(mmio_base, mmio_size);
512 if (!device->pri) {
513 nvdev_error(device, "unable to map PRI\n");
514 return -ENOMEM;
515 }
516 }
517
518 /* disable subdevs that aren't required (used by tools) */
519 for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
520 if (!(subdev_mask & (1ULL << i)))
521 device->oclass[i] = NULL;
522 }
523
Ben Skeggsa1e88732015-08-20 14:54:15 +1000524 atomic_set(&device->engine.subdev.object.usecount, 2);
525 mutex_init(&device->mutex);
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000526done:
527 mutex_unlock(&nv_devices_mutex);
528 return ret;
529}