blob: 1e4935f33842b07e46cf45a4251611eddcf4f103 [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 Skeggs9274f4a2012-07-06 07:36:43 +100027#include <core/client.h>
Ben Skeggs9274f4a2012-07-06 07:36:43 +100028#include <core/option.h>
Ben Skeggs97190472015-01-14 15:35:00 +100029#include <core/notify.h>
30#include <core/parent.h>
Ben Skeggsddbb55a2014-11-18 10:51:19 +100031#include <subdev/bios.h>
Ben Skeggsd01c3092014-08-10 04:10:21 +100032#include <subdev/fb.h>
33#include <subdev/instmem.h>
34
Ben Skeggs97190472015-01-14 15:35:00 +100035#include <nvif/class.h>
36#include <nvif/unpack.h>
Ben Skeggs9274f4a2012-07-06 07:36:43 +100037
38static DEFINE_MUTEX(nv_devices_mutex);
39static LIST_HEAD(nv_devices);
40
Ben Skeggs97190472015-01-14 15:35:00 +100041struct nvkm_device *
42nvkm_device_find(u64 name)
Ben Skeggs9274f4a2012-07-06 07:36:43 +100043{
Ben Skeggs97190472015-01-14 15:35:00 +100044 struct nvkm_device *device, *match = NULL;
Ben Skeggs9274f4a2012-07-06 07:36:43 +100045 mutex_lock(&nv_devices_mutex);
46 list_for_each_entry(device, &nv_devices, head) {
47 if (device->handle == name) {
48 match = device;
49 break;
50 }
51 }
52 mutex_unlock(&nv_devices_mutex);
53 return match;
54}
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 Skeggs9274f4a2012-07-06 07:36:43 +100070/******************************************************************************
Ben Skeggs97190472015-01-14 15:35:00 +100071 * nvkm_devobj (0x0080): class implementation
Ben Skeggs9274f4a2012-07-06 07:36:43 +100072 *****************************************************************************/
Ben Skeggsd01c3092014-08-10 04:10:21 +100073
Ben Skeggs97190472015-01-14 15:35:00 +100074struct nvkm_devobj {
75 struct nvkm_parent base;
Ben Skeggs9274f4a2012-07-06 07:36:43 +100076};
77
Ben Skeggsd01c3092014-08-10 04:10:21 +100078static int
Ben Skeggs97190472015-01-14 15:35:00 +100079nvkm_devobj_info(struct nvkm_object *object, void *data, u32 size)
Ben Skeggsd01c3092014-08-10 04:10:21 +100080{
Ben Skeggs97190472015-01-14 15:35:00 +100081 struct nvkm_device *device = nv_device(object);
Ben Skeggsb1e45532015-08-20 14:54:06 +100082 struct nvkm_fb *fb = nvkm_fb(device);
Ben Skeggs97190472015-01-14 15:35:00 +100083 struct nvkm_instmem *imem = nvkm_instmem(device);
Ben Skeggsd01c3092014-08-10 04:10:21 +100084 union {
85 struct nv_device_info_v0 v0;
86 } *args = data;
87 int ret;
88
Ben Skeggs53003942015-08-20 14:54:13 +100089 nvif_ioctl(object, "device info size %d\n", size);
Ben Skeggsd01c3092014-08-10 04:10:21 +100090 if (nvif_unpack(args->v0, 0, 0, false)) {
Ben Skeggs53003942015-08-20 14:54:13 +100091 nvif_ioctl(object, "device info vers %d\n", args->v0.version);
Ben Skeggsd01c3092014-08-10 04:10:21 +100092 } else
93 return ret;
94
95 switch (device->chipset) {
96 case 0x01a:
97 case 0x01f:
98 case 0x04c:
99 case 0x04e:
100 case 0x063:
101 case 0x067:
102 case 0x068:
103 case 0x0aa:
104 case 0x0ac:
105 case 0x0af:
106 args->v0.platform = NV_DEVICE_INFO_V0_IGP;
107 break;
108 default:
109 if (device->pdev) {
110 if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP))
111 args->v0.platform = NV_DEVICE_INFO_V0_AGP;
112 else
113 if (pci_is_pcie(device->pdev))
114 args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
115 else
116 args->v0.platform = NV_DEVICE_INFO_V0_PCI;
117 } else {
118 args->v0.platform = NV_DEVICE_INFO_V0_SOC;
119 }
120 break;
121 }
122
123 switch (device->card_type) {
124 case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
125 case NV_10:
126 case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
127 case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
128 case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
129 case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
130 case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
Ben Skeggs9c210f32014-08-10 04:10:21 +1000131 case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
Ben Skeggsd01c3092014-08-10 04:10:21 +1000132 case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
133 case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
134 default:
135 args->v0.family = 0;
136 break;
137 }
138
139 args->v0.chipset = device->chipset;
Ben Skeggs37047912014-11-17 22:56:37 +1000140 args->v0.revision = device->chiprev;
Ben Skeggsb1e45532015-08-20 14:54:06 +1000141 if (fb && fb->ram)
142 args->v0.ram_size = args->v0.ram_user = fb->ram->size;
Alexandre Courboteaecf032015-02-20 18:22:59 +0900143 else
144 args->v0.ram_size = args->v0.ram_user = 0;
145 if (imem && args->v0.ram_size > 0)
146 args->v0.ram_user = args->v0.ram_user - imem->reserved;
147
Ben Skeggsd01c3092014-08-10 04:10:21 +1000148 return 0;
149}
150
151static int
Ben Skeggs97190472015-01-14 15:35:00 +1000152nvkm_devobj_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
Ben Skeggsd01c3092014-08-10 04:10:21 +1000153{
154 switch (mthd) {
155 case NV_DEVICE_V0_INFO:
Ben Skeggs97190472015-01-14 15:35:00 +1000156 return nvkm_devobj_info(object, data, size);
Ben Skeggsd01c3092014-08-10 04:10:21 +1000157 default:
158 break;
159 }
160 return -EINVAL;
161}
162
163static u8
Ben Skeggs97190472015-01-14 15:35:00 +1000164nvkm_devobj_rd08(struct nvkm_object *object, u64 addr)
Ben Skeggsd01c3092014-08-10 04:10:21 +1000165{
Ben Skeggsf9793bb2015-08-20 14:54:10 +1000166 return nvkm_rd08(object->engine->subdev.device, addr);
Ben Skeggsd01c3092014-08-10 04:10:21 +1000167}
168
169static u16
Ben Skeggs97190472015-01-14 15:35:00 +1000170nvkm_devobj_rd16(struct nvkm_object *object, u64 addr)
Ben Skeggsd01c3092014-08-10 04:10:21 +1000171{
Ben Skeggsf9793bb2015-08-20 14:54:10 +1000172 return nvkm_rd16(object->engine->subdev.device, addr);
Ben Skeggsd01c3092014-08-10 04:10:21 +1000173}
174
175static u32
Ben Skeggs97190472015-01-14 15:35:00 +1000176nvkm_devobj_rd32(struct nvkm_object *object, u64 addr)
Ben Skeggsd01c3092014-08-10 04:10:21 +1000177{
Ben Skeggsf9793bb2015-08-20 14:54:10 +1000178 return nvkm_rd32(object->engine->subdev.device, addr);
Ben Skeggsd01c3092014-08-10 04:10:21 +1000179}
180
181static void
Ben Skeggs97190472015-01-14 15:35:00 +1000182nvkm_devobj_wr08(struct nvkm_object *object, u64 addr, u8 data)
Ben Skeggsd01c3092014-08-10 04:10:21 +1000183{
Ben Skeggsf9793bb2015-08-20 14:54:10 +1000184 nvkm_wr08(object->engine->subdev.device, addr, data);
Ben Skeggsd01c3092014-08-10 04:10:21 +1000185}
186
187static void
Ben Skeggs97190472015-01-14 15:35:00 +1000188nvkm_devobj_wr16(struct nvkm_object *object, u64 addr, u16 data)
Ben Skeggsd01c3092014-08-10 04:10:21 +1000189{
Ben Skeggsf9793bb2015-08-20 14:54:10 +1000190 nvkm_wr16(object->engine->subdev.device, addr, data);
Ben Skeggsd01c3092014-08-10 04:10:21 +1000191}
192
193static void
Ben Skeggs97190472015-01-14 15:35:00 +1000194nvkm_devobj_wr32(struct nvkm_object *object, u64 addr, u32 data)
Ben Skeggsd01c3092014-08-10 04:10:21 +1000195{
Ben Skeggsf9793bb2015-08-20 14:54:10 +1000196 nvkm_wr32(object->engine->subdev.device, addr, data);
Ben Skeggsd01c3092014-08-10 04:10:21 +1000197}
198
Ben Skeggs586491e2014-08-10 04:10:24 +1000199static int
Ben Skeggs97190472015-01-14 15:35:00 +1000200nvkm_devobj_map(struct nvkm_object *object, u64 *addr, u32 *size)
Ben Skeggs586491e2014-08-10 04:10:24 +1000201{
Ben Skeggs97190472015-01-14 15:35:00 +1000202 struct nvkm_device *device = nv_device(object);
Ben Skeggs586491e2014-08-10 04:10:24 +1000203 *addr = nv_device_resource_start(device, 0);
204 *size = nv_device_resource_len(device, 0);
205 return 0;
206}
207
Ben Skeggs97190472015-01-14 15:35:00 +1000208static struct nvkm_oclass
209nvkm_devobj_oclass_super = {
Ben Skeggs586491e2014-08-10 04:10:24 +1000210 .handle = NV_DEVICE,
Ben Skeggs97190472015-01-14 15:35:00 +1000211 .ofuncs = &(struct nvkm_ofuncs) {
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000212 .dtor = _nvkm_parent_dtor,
Ben Skeggs97190472015-01-14 15:35:00 +1000213 .init = _nvkm_parent_init,
214 .fini = _nvkm_parent_fini,
215 .mthd = nvkm_devobj_mthd,
216 .map = nvkm_devobj_map,
217 .rd08 = nvkm_devobj_rd08,
218 .rd16 = nvkm_devobj_rd16,
219 .rd32 = nvkm_devobj_rd32,
220 .wr08 = nvkm_devobj_wr08,
221 .wr16 = nvkm_devobj_wr16,
222 .wr32 = nvkm_devobj_wr32,
Ben Skeggs586491e2014-08-10 04:10:24 +1000223 }
224};
225
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000226static int
Ben Skeggs97190472015-01-14 15:35:00 +1000227nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
228 struct nvkm_oclass *oclass, void *data, u32 size,
229 struct nvkm_object **pobject)
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000230{
Ben Skeggs586491e2014-08-10 04:10:24 +1000231 union {
232 struct nv_device_v0 v0;
233 } *args = data;
Ben Skeggs97190472015-01-14 15:35:00 +1000234 struct nvkm_client *client = nv_client(parent);
235 struct nvkm_device *device;
236 struct nvkm_devobj *devobj;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000237 int ret;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000238
Ben Skeggs53003942015-08-20 14:54:13 +1000239 nvif_ioctl(parent, "create device size %d\n", size);
Ben Skeggs586491e2014-08-10 04:10:24 +1000240 if (nvif_unpack(args->v0, 0, 0, false)) {
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000241 nvif_ioctl(parent, "create device v%d device %016llx\n",
242 args->v0.version, args->v0.device);
Ben Skeggs586491e2014-08-10 04:10:24 +1000243 } else
244 return ret;
245
246 /* give priviledged clients register access */
247 if (client->super)
Ben Skeggs97190472015-01-14 15:35:00 +1000248 oclass = &nvkm_devobj_oclass_super;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000249
250 /* find the device subdev that matches what the client requested */
Ben Skeggs76ecea52015-08-20 14:54:15 +1000251 device = client->device;
Ben Skeggs586491e2014-08-10 04:10:24 +1000252 if (args->v0.device != ~0) {
Ben Skeggs97190472015-01-14 15:35:00 +1000253 device = nvkm_device_find(args->v0.device);
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000254 if (!device)
255 return -ENODEV;
256 }
257
Ben Skeggs97190472015-01-14 15:35:00 +1000258 ret = nvkm_parent_create(parent, nv_object(device), oclass, 0,
259 nvkm_control_oclass,
260 (1ULL << NVDEV_ENGINE_DMAOBJ) |
261 (1ULL << NVDEV_ENGINE_FIFO) |
262 (1ULL << NVDEV_ENGINE_DISP) |
263 (1ULL << NVDEV_ENGINE_PM), &devobj);
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000264 *pobject = nv_object(devobj);
265 if (ret)
266 return ret;
267
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000268 return 0;
269}
270
Ben Skeggs97190472015-01-14 15:35:00 +1000271static struct nvkm_ofuncs
272nvkm_devobj_ofuncs = {
273 .ctor = nvkm_devobj_ctor,
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000274 .dtor = _nvkm_parent_dtor,
Ben Skeggs97190472015-01-14 15:35:00 +1000275 .init = _nvkm_parent_init,
276 .fini = _nvkm_parent_fini,
277 .mthd = nvkm_devobj_mthd,
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000278};
279
280/******************************************************************************
Ben Skeggs97190472015-01-14 15:35:00 +1000281 * nvkm_device: engine functions
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000282 *****************************************************************************/
Ben Skeggs79ca2772014-08-10 04:10:20 +1000283
Ben Skeggs97190472015-01-14 15:35:00 +1000284struct nvkm_device *
Ben Skeggsa38f37a2014-12-05 11:20:19 +1000285nv_device(void *obj)
286{
Ben Skeggs97190472015-01-14 15:35:00 +1000287 struct nvkm_object *device = nv_object(obj);
Ben Skeggs8000fb22014-12-05 12:21:34 +1000288 if (device->engine == NULL) {
289 while (device && device->parent)
290 device = device->parent;
291 } else {
Ben Skeggsec0e5542014-12-05 12:37:19 +1000292 device = &nv_object(obj)->engine->subdev.object;
Ben Skeggs490d5952014-12-05 11:26:23 +1000293 if (device && device->parent)
294 device = device->parent;
Ben Skeggsa38f37a2014-12-05 11:20:19 +1000295 }
Ben Skeggs490d5952014-12-05 11:26:23 +1000296#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
Ben Skeggs53003942015-08-20 14:54:13 +1000297 BUG_ON(!device);
Ben Skeggsa38f37a2014-12-05 11:20:19 +1000298#endif
Ben Skeggsa38f37a2014-12-05 11:20:19 +1000299 return (void *)device;
300}
301
Ben Skeggs97190472015-01-14 15:35:00 +1000302static struct nvkm_oclass
303nvkm_device_sclass[] = {
304 { 0x0080, &nvkm_devobj_ofuncs },
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000305 {}
306};
307
Ben Skeggs066a5d02013-04-25 11:35:18 +1000308static int
Ben Skeggs97190472015-01-14 15:35:00 +1000309nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size,
310 struct nvkm_notify *notify)
Ben Skeggs79ca2772014-08-10 04:10:20 +1000311{
312 if (!WARN_ON(size != 0)) {
313 notify->size = 0;
314 notify->types = 1;
315 notify->index = 0;
316 return 0;
317 }
318 return -EINVAL;
319}
320
321static const struct nvkm_event_func
Ben Skeggs97190472015-01-14 15:35:00 +1000322nvkm_device_event_func = {
323 .ctor = nvkm_device_event_ctor,
Ben Skeggs79ca2772014-08-10 04:10:20 +1000324};
325
326static int
Ben Skeggs97190472015-01-14 15:35:00 +1000327nvkm_device_fini(struct nvkm_object *object, bool suspend)
Ben Skeggs066a5d02013-04-25 11:35:18 +1000328{
Ben Skeggs97190472015-01-14 15:35:00 +1000329 struct nvkm_device *device = (void *)object;
330 struct nvkm_object *subdev;
Ben Skeggs10caad32013-04-25 11:43:54 +1000331 int ret, i;
332
333 for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
334 if ((subdev = device->subdev[i])) {
335 if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
Ben Skeggs97190472015-01-14 15:35:00 +1000336 ret = nvkm_object_dec(subdev, suspend);
Ben Skeggs10caad32013-04-25 11:43:54 +1000337 if (ret && suspend)
338 goto fail;
339 }
340 }
341 }
342
Ben Skeggsed76a872014-06-13 12:42:21 +1000343 ret = nvkm_acpi_fini(device, suspend);
Ben Skeggs10caad32013-04-25 11:43:54 +1000344fail:
345 for (; ret && i < NVDEV_SUBDEV_NR; i++) {
346 if ((subdev = device->subdev[i])) {
347 if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
Ben Skeggs97190472015-01-14 15:35:00 +1000348 ret = nvkm_object_inc(subdev);
Ben Skeggs10caad32013-04-25 11:43:54 +1000349 if (ret) {
350 /* XXX */
351 }
352 }
353 }
354 }
355
356 return ret;
Ben Skeggs066a5d02013-04-25 11:35:18 +1000357}
358
359static int
Ben Skeggs97190472015-01-14 15:35:00 +1000360nvkm_device_init(struct nvkm_object *object)
Ben Skeggs066a5d02013-04-25 11:35:18 +1000361{
Ben Skeggs97190472015-01-14 15:35:00 +1000362 struct nvkm_device *device = (void *)object;
363 struct nvkm_object *subdev;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000364 int ret, i = 0, c;
Ben Skeggsed76a872014-06-13 12:42:21 +1000365
366 ret = nvkm_acpi_init(device);
367 if (ret)
368 goto fail;
Ben Skeggs10caad32013-04-25 11:43:54 +1000369
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000370 for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) {
371#define _(s,m) case s: if (device->oclass[s] && !device->subdev[s]) { \
372 ret = nvkm_object_ctor(nv_object(device), NULL, \
373 device->oclass[s], NULL, (s), \
374 (struct nvkm_object **)&device->m); \
375 if (ret == -ENODEV) { \
376 device->oclass[s] = NULL; \
377 continue; \
378 } \
379 if (ret) \
380 goto fail; \
381 device->subdev[s] = (struct nvkm_object *)device->m; \
382} break
383 switch (i) {
384 _(NVDEV_SUBDEV_BAR , bar);
385 _(NVDEV_SUBDEV_VBIOS , bios);
386 _(NVDEV_SUBDEV_BUS , bus);
387 _(NVDEV_SUBDEV_CLK , clk);
388 _(NVDEV_SUBDEV_DEVINIT, devinit);
389 _(NVDEV_SUBDEV_FB , fb);
390 _(NVDEV_SUBDEV_FUSE , fuse);
391 _(NVDEV_SUBDEV_GPIO , gpio);
392 _(NVDEV_SUBDEV_I2C , i2c);
393 _(NVDEV_SUBDEV_IBUS , ibus);
394 _(NVDEV_SUBDEV_INSTMEM, imem);
395 _(NVDEV_SUBDEV_LTC , ltc);
396 _(NVDEV_SUBDEV_MC , mc);
397 _(NVDEV_SUBDEV_MMU , mmu);
398 _(NVDEV_SUBDEV_MXM , mxm);
399 _(NVDEV_SUBDEV_PMU , pmu);
400 _(NVDEV_SUBDEV_THERM , therm);
401 _(NVDEV_SUBDEV_TIMER , timer);
402 _(NVDEV_SUBDEV_VOLT , volt);
403 _(NVDEV_ENGINE_BSP , bsp);
404 _(NVDEV_ENGINE_CE0 , ce[0]);
405 _(NVDEV_ENGINE_CE1 , ce[1]);
406 _(NVDEV_ENGINE_CE2 , ce[2]);
407 _(NVDEV_ENGINE_CIPHER , cipher);
408 _(NVDEV_ENGINE_DISP , disp);
409 _(NVDEV_ENGINE_DMAOBJ , dma);
410 _(NVDEV_ENGINE_FIFO , fifo);
411 _(NVDEV_ENGINE_GR , gr);
412 _(NVDEV_ENGINE_IFB , ifb);
413 _(NVDEV_ENGINE_ME , me);
414 _(NVDEV_ENGINE_MPEG , mpeg);
415 _(NVDEV_ENGINE_MSENC , msenc);
416 _(NVDEV_ENGINE_MSPDEC , mspdec);
417 _(NVDEV_ENGINE_MSPPP , msppp);
418 _(NVDEV_ENGINE_MSVLD , msvld);
419 _(NVDEV_ENGINE_PM , pm);
420 _(NVDEV_ENGINE_SEC , sec);
421 _(NVDEV_ENGINE_SW , sw);
422 _(NVDEV_ENGINE_VIC , vic);
423 _(NVDEV_ENGINE_VP , vp);
424 default:
425 WARN_ON(1);
426 continue;
427 }
428#undef _
429
430 /* note: can't init *any* subdevs until devinit has been run
431 * due to not knowing exactly what the vbios init tables will
432 * mess with. devinit also can't be run until all of its
433 * dependencies have been created.
434 *
435 * this code delays init of any subdev until all of devinit's
436 * dependencies have been created, and then initialises each
437 * subdev in turn as they're created.
438 */
439 while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
440 struct nvkm_object *subdev = device->subdev[c++];
441 if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
Ben Skeggs97190472015-01-14 15:35:00 +1000442 ret = nvkm_object_inc(subdev);
Ben Skeggs10caad32013-04-25 11:43:54 +1000443 if (ret)
444 goto fail;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000445 } else
446 if (subdev) {
Ben Skeggs97190472015-01-14 15:35:00 +1000447 nvkm_subdev_reset(subdev);
Ben Skeggs10caad32013-04-25 11:43:54 +1000448 }
449 }
450 }
451
452 ret = 0;
453fail:
454 for (--i; ret && i >= 0; i--) {
455 if ((subdev = device->subdev[i])) {
456 if (!nv_iclass(subdev, NV_ENGINE_CLASS))
Ben Skeggs97190472015-01-14 15:35:00 +1000457 nvkm_object_dec(subdev, false);
Ben Skeggs10caad32013-04-25 11:43:54 +1000458 }
459 }
460
Ben Skeggsed76a872014-06-13 12:42:21 +1000461 if (ret)
462 nvkm_acpi_fini(device, false);
Ben Skeggs10caad32013-04-25 11:43:54 +1000463 return ret;
Ben Skeggs066a5d02013-04-25 11:35:18 +1000464}
465
Alexandre Courbot420b9462014-02-17 15:17:26 +0900466resource_size_t
Ben Skeggs97190472015-01-14 15:35:00 +1000467nv_device_resource_start(struct nvkm_device *device, unsigned int bar)
Alexandre Courbot420b9462014-02-17 15:17:26 +0900468{
469 if (nv_device_is_pci(device)) {
470 return pci_resource_start(device->pdev, bar);
471 } else {
472 struct resource *res;
473 res = platform_get_resource(device->platformdev,
474 IORESOURCE_MEM, bar);
475 if (!res)
476 return 0;
477 return res->start;
478 }
479}
480
481resource_size_t
Ben Skeggs97190472015-01-14 15:35:00 +1000482nv_device_resource_len(struct nvkm_device *device, unsigned int bar)
Alexandre Courbot420b9462014-02-17 15:17:26 +0900483{
484 if (nv_device_is_pci(device)) {
485 return pci_resource_len(device->pdev, bar);
486 } else {
487 struct resource *res;
488 res = platform_get_resource(device->platformdev,
489 IORESOURCE_MEM, bar);
490 if (!res)
491 return 0;
492 return resource_size(res);
493 }
494}
495
Alexandre Courbot420b9462014-02-17 15:17:26 +0900496int
Ben Skeggs97190472015-01-14 15:35:00 +1000497nv_device_get_irq(struct nvkm_device *device, bool stall)
Alexandre Courbot420b9462014-02-17 15:17:26 +0900498{
499 if (nv_device_is_pci(device)) {
500 return device->pdev->irq;
501 } else {
502 return platform_get_irq_byname(device->platformdev,
503 stall ? "stall" : "nonstall");
504 }
505}
506
Ben Skeggs97190472015-01-14 15:35:00 +1000507static struct nvkm_oclass
508nvkm_device_oclass = {
Ben Skeggsdded35d2013-04-25 17:23:43 +1000509 .handle = NV_ENGINE(DEVICE, 0x00),
Ben Skeggs97190472015-01-14 15:35:00 +1000510 .ofuncs = &(struct nvkm_ofuncs) {
Ben Skeggs97190472015-01-14 15:35:00 +1000511 .init = nvkm_device_init,
512 .fini = nvkm_device_fini,
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000513 },
514};
515
Ben Skeggse781dc82015-08-20 14:54:15 +1000516void
517nvkm_device_del(struct nvkm_device **pdevice)
518{
519 struct nvkm_device *device = *pdevice;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000520 int i;
Ben Skeggse781dc82015-08-20 14:54:15 +1000521 if (device) {
Ben Skeggse781dc82015-08-20 14:54:15 +1000522 mutex_lock(&nv_devices_mutex);
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000523 for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--)
524 nvkm_object_ref(NULL, &device->subdev[i]);
525
526 nvkm_event_fini(&device->event);
Ben Skeggse781dc82015-08-20 14:54:15 +1000527
528 if (device->pri)
529 iounmap(device->pri);
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000530 list_del(&device->head);
531 mutex_unlock(&nv_devices_mutex);
Ben Skeggse781dc82015-08-20 14:54:15 +1000532
533 nvkm_engine_destroy(&device->engine);
534 *pdevice = NULL;
535 }
536}
537
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000538int
Ben Skeggse781dc82015-08-20 14:54:15 +1000539nvkm_device_new(void *dev, enum nv_bus_type type, u64 name,
540 const char *sname, const char *cfg, const char *dbg,
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000541 bool detect, bool mmio, u64 subdev_mask,
Ben Skeggse781dc82015-08-20 14:54:15 +1000542 struct nvkm_device **pdevice)
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000543{
Ben Skeggs97190472015-01-14 15:35:00 +1000544 struct nvkm_device *device;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000545 u64 mmio_base, mmio_size;
546 u32 boot0, strap;
547 void __iomem *map;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000548 int ret = -EEXIST;
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000549 int i;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000550
551 mutex_lock(&nv_devices_mutex);
552 list_for_each_entry(device, &nv_devices, head) {
553 if (device->handle == name)
554 goto done;
555 }
556
Ben Skeggse781dc82015-08-20 14:54:15 +1000557 ret = nvkm_engine_create(NULL, NULL, &nvkm_device_oclass, true,
558 "DEVICE", "device", &device);
559 *pdevice = device;
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000560 if (ret)
561 goto done;
562
Alexandre Courbot420b9462014-02-17 15:17:26 +0900563 switch (type) {
Ben Skeggs97190472015-01-14 15:35:00 +1000564 case NVKM_BUS_PCI:
Alexandre Courbot420b9462014-02-17 15:17:26 +0900565 device->pdev = dev;
Ben Skeggs6d0d40e2015-08-20 14:54:06 +1000566 device->dev = &device->pdev->dev;
Alexandre Courbot420b9462014-02-17 15:17:26 +0900567 break;
Ben Skeggs97190472015-01-14 15:35:00 +1000568 case NVKM_BUS_PLATFORM:
Alexandre Courbot420b9462014-02-17 15:17:26 +0900569 device->platformdev = dev;
Ben Skeggs6d0d40e2015-08-20 14:54:06 +1000570 device->dev = &device->platformdev->dev;
Alexandre Courbot420b9462014-02-17 15:17:26 +0900571 break;
572 }
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000573 device->handle = name;
574 device->cfgopt = cfg;
575 device->dbgopt = dbg;
576 device->name = sname;
577
Ben Skeggs97190472015-01-14 15:35:00 +1000578 nv_subdev(device)->debug = nvkm_dbgopt(device->dbgopt, "DEVICE");
579 nv_engine(device)->sclass = nvkm_device_sclass;
Ben Skeggs0d5dd3f2015-08-20 14:54:05 +1000580 list_add_tail(&device->head, &nv_devices);
Ben Skeggsed76a872014-06-13 12:42:21 +1000581
Ben Skeggs97190472015-01-14 15:35:00 +1000582 ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event);
Ben Skeggs0ac9d212015-08-20 14:54:15 +1000583 if (ret)
584 goto done;
585
586 mmio_base = nv_device_resource_start(device, 0);
587 mmio_size = nv_device_resource_len(device, 0);
588
589 /* identify the chipset, and determine classes of subdev/engines */
590 if (detect) {
591 map = ioremap(mmio_base, 0x102000);
592 if (ret = -ENOMEM, map == NULL)
593 goto done;
594
595 /* switch mmio to cpu's native endianness */
596#ifndef __BIG_ENDIAN
597 if (ioread32_native(map + 0x000004) != 0x00000000) {
598#else
599 if (ioread32_native(map + 0x000004) == 0x00000000) {
600#endif
601 iowrite32_native(0x01000001, map + 0x000004);
602 ioread32_native(map);
603 }
604
605 /* read boot0 and strapping information */
606 boot0 = ioread32_native(map + 0x000000);
607 strap = ioread32_native(map + 0x101000);
608 iounmap(map);
609
610 /* determine chipset and derive architecture from it */
611 if ((boot0 & 0x1f000000) > 0) {
612 device->chipset = (boot0 & 0x1ff00000) >> 20;
613 device->chiprev = (boot0 & 0x000000ff);
614 switch (device->chipset & 0x1f0) {
615 case 0x010: {
616 if (0x461 & (1 << (device->chipset & 0xf)))
617 device->card_type = NV_10;
618 else
619 device->card_type = NV_11;
620 device->chiprev = 0x00;
621 break;
622 }
623 case 0x020: device->card_type = NV_20; break;
624 case 0x030: device->card_type = NV_30; break;
625 case 0x040:
626 case 0x060: device->card_type = NV_40; break;
627 case 0x050:
628 case 0x080:
629 case 0x090:
630 case 0x0a0: device->card_type = NV_50; break;
631 case 0x0c0:
632 case 0x0d0: device->card_type = NV_C0; break;
633 case 0x0e0:
634 case 0x0f0:
635 case 0x100: device->card_type = NV_E0; break;
636 case 0x110:
637 case 0x120: device->card_type = GM100; break;
638 default:
639 break;
640 }
641 } else
642 if ((boot0 & 0xff00fff0) == 0x20004000) {
643 if (boot0 & 0x00f00000)
644 device->chipset = 0x05;
645 else
646 device->chipset = 0x04;
647 device->card_type = NV_04;
648 }
649
650 switch (device->card_type) {
651 case NV_04: ret = nv04_identify(device); break;
652 case NV_10:
653 case NV_11: ret = nv10_identify(device); break;
654 case NV_20: ret = nv20_identify(device); break;
655 case NV_30: ret = nv30_identify(device); break;
656 case NV_40: ret = nv40_identify(device); break;
657 case NV_50: ret = nv50_identify(device); break;
658 case NV_C0: ret = gf100_identify(device); break;
659 case NV_E0: ret = gk104_identify(device); break;
660 case GM100: ret = gm100_identify(device); break;
661 default:
662 ret = -EINVAL;
663 break;
664 }
665
666 if (ret) {
667 nvdev_error(device, "unknown chipset (%08x)\n", boot0);
668 goto done;
669 }
670
671 nvdev_info(device, "NVIDIA %s (%08x)\n", device->cname, boot0);
672
673 /* determine frequency of timing crystal */
674 if ( device->card_type <= NV_10 || device->chipset < 0x17 ||
675 (device->chipset >= 0x20 && device->chipset < 0x25))
676 strap &= 0x00000040;
677 else
678 strap &= 0x00400040;
679
680 switch (strap) {
681 case 0x00000000: device->crystal = 13500; break;
682 case 0x00000040: device->crystal = 14318; break;
683 case 0x00400000: device->crystal = 27000; break;
684 case 0x00400040: device->crystal = 25000; break;
685 }
686 } else {
687 device->cname = "NULL";
688 device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass;
689 }
690
691 if (mmio) {
692 device->pri = ioremap(mmio_base, mmio_size);
693 if (!device->pri) {
694 nvdev_error(device, "unable to map PRI\n");
695 return -ENOMEM;
696 }
697 }
698
699 /* disable subdevs that aren't required (used by tools) */
700 for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
701 if (!(subdev_mask & (1ULL << i)))
702 device->oclass[i] = NULL;
703 }
704
Ben Skeggs9274f4a2012-07-06 07:36:43 +1000705done:
706 mutex_unlock(&nv_devices_mutex);
707 return ret;
708}