1c39f472eSBen Skeggs /*
2c39f472eSBen Skeggs  * Copyright 2012 Red Hat Inc.
3c39f472eSBen Skeggs  *
4c39f472eSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5c39f472eSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6c39f472eSBen Skeggs  * to deal in the Software without restriction, including without limitation
7c39f472eSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c39f472eSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9c39f472eSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10c39f472eSBen Skeggs  *
11c39f472eSBen Skeggs  * The above copyright notice and this permission notice shall be included in
12c39f472eSBen Skeggs  * all copies or substantial portions of the Software.
13c39f472eSBen Skeggs  *
14c39f472eSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c39f472eSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c39f472eSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17c39f472eSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c39f472eSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c39f472eSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c39f472eSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21c39f472eSBen Skeggs  *
22c39f472eSBen Skeggs  * Authors: Ben Skeggs
23c39f472eSBen Skeggs  */
24639c308eSBen Skeggs #include "nv50.h"
25d36a99d2SBen Skeggs #include "ram.h"
26c39f472eSBen Skeggs 
27c39f472eSBen Skeggs #include <core/client.h>
28639c308eSBen Skeggs #include <core/enum.h>
29344c2d42SBen Skeggs #include <engine/fifo.h>
30c39f472eSBen Skeggs 
3103c8952fSBen Skeggs static int
nv50_fb_ram_new(struct nvkm_fb * base,struct nvkm_ram ** pram)3203c8952fSBen Skeggs nv50_fb_ram_new(struct nvkm_fb *base, struct nvkm_ram **pram)
3303c8952fSBen Skeggs {
3403c8952fSBen Skeggs 	struct nv50_fb *fb = nv50_fb(base);
3503c8952fSBen Skeggs 	return fb->func->ram_new(&fb->base, pram);
3603c8952fSBen Skeggs }
3703c8952fSBen Skeggs 
38639c308eSBen Skeggs static const struct nvkm_enum vm_dispatch_subclients[] = {
39344c2d42SBen Skeggs 	{ 0x00000000, "GRCTX" },
40344c2d42SBen Skeggs 	{ 0x00000001, "NOTIFY" },
41344c2d42SBen Skeggs 	{ 0x00000002, "QUERY" },
42344c2d42SBen Skeggs 	{ 0x00000003, "COND" },
43344c2d42SBen Skeggs 	{ 0x00000004, "M2M_IN" },
44344c2d42SBen Skeggs 	{ 0x00000005, "M2M_OUT" },
45344c2d42SBen Skeggs 	{ 0x00000006, "M2M_NOTIFY" },
46c39f472eSBen Skeggs 	{}
47c39f472eSBen Skeggs };
48c39f472eSBen Skeggs 
49639c308eSBen Skeggs static const struct nvkm_enum vm_ccache_subclients[] = {
50344c2d42SBen Skeggs 	{ 0x00000000, "CB" },
51344c2d42SBen Skeggs 	{ 0x00000001, "TIC" },
52344c2d42SBen Skeggs 	{ 0x00000002, "TSC" },
53c39f472eSBen Skeggs 	{}
54c39f472eSBen Skeggs };
55c39f472eSBen Skeggs 
56639c308eSBen Skeggs static const struct nvkm_enum vm_prop_subclients[] = {
57344c2d42SBen Skeggs 	{ 0x00000000, "RT0" },
58344c2d42SBen Skeggs 	{ 0x00000001, "RT1" },
59344c2d42SBen Skeggs 	{ 0x00000002, "RT2" },
60344c2d42SBen Skeggs 	{ 0x00000003, "RT3" },
61344c2d42SBen Skeggs 	{ 0x00000004, "RT4" },
62344c2d42SBen Skeggs 	{ 0x00000005, "RT5" },
63344c2d42SBen Skeggs 	{ 0x00000006, "RT6" },
64344c2d42SBen Skeggs 	{ 0x00000007, "RT7" },
65344c2d42SBen Skeggs 	{ 0x00000008, "ZETA" },
66344c2d42SBen Skeggs 	{ 0x00000009, "LOCAL" },
67344c2d42SBen Skeggs 	{ 0x0000000a, "GLOBAL" },
68344c2d42SBen Skeggs 	{ 0x0000000b, "STACK" },
69344c2d42SBen Skeggs 	{ 0x0000000c, "DST2D" },
70c39f472eSBen Skeggs 	{}
71c39f472eSBen Skeggs };
72c39f472eSBen Skeggs 
73639c308eSBen Skeggs static const struct nvkm_enum vm_pfifo_subclients[] = {
74344c2d42SBen Skeggs 	{ 0x00000000, "PUSHBUF" },
75344c2d42SBen Skeggs 	{ 0x00000001, "SEMAPHORE" },
76c39f472eSBen Skeggs 	{}
77c39f472eSBen Skeggs };
78c39f472eSBen Skeggs 
79639c308eSBen Skeggs static const struct nvkm_enum vm_bar_subclients[] = {
80344c2d42SBen Skeggs 	{ 0x00000000, "FB" },
81344c2d42SBen Skeggs 	{ 0x00000001, "IN" },
82c39f472eSBen Skeggs 	{}
83c39f472eSBen Skeggs };
84c39f472eSBen Skeggs 
85639c308eSBen Skeggs static const struct nvkm_enum vm_client[] = {
86344c2d42SBen Skeggs 	{ 0x00000000, "STRMOUT" },
87c39f472eSBen Skeggs 	{ 0x00000003, "DISPATCH", vm_dispatch_subclients },
88344c2d42SBen Skeggs 	{ 0x00000004, "PFIFO_WRITE" },
89c39f472eSBen Skeggs 	{ 0x00000005, "CCACHE", vm_ccache_subclients },
90344c2d42SBen Skeggs 	{ 0x00000006, "PMSPPP" },
91344c2d42SBen Skeggs 	{ 0x00000007, "CLIPID" },
92344c2d42SBen Skeggs 	{ 0x00000008, "PFIFO_READ" },
93344c2d42SBen Skeggs 	{ 0x00000009, "VFETCH" },
94344c2d42SBen Skeggs 	{ 0x0000000a, "TEXTURE" },
95c39f472eSBen Skeggs 	{ 0x0000000b, "PROP", vm_prop_subclients },
96344c2d42SBen Skeggs 	{ 0x0000000c, "PVP" },
97344c2d42SBen Skeggs 	{ 0x0000000d, "PBSP" },
98344c2d42SBen Skeggs 	{ 0x0000000e, "PCRYPT" },
99344c2d42SBen Skeggs 	{ 0x0000000f, "PCOUNTER" },
100344c2d42SBen Skeggs 	{ 0x00000011, "PDAEMON" },
101c39f472eSBen Skeggs 	{}
102c39f472eSBen Skeggs };
103c39f472eSBen Skeggs 
104639c308eSBen Skeggs static const struct nvkm_enum vm_engine[] = {
105344c2d42SBen Skeggs 	{ 0x00000000, "PGRAPH" },
106344c2d42SBen Skeggs 	{ 0x00000001, "PVP" },
107344c2d42SBen Skeggs 	{ 0x00000004, "PEEPHOLE" },
108344c2d42SBen Skeggs 	{ 0x00000005, "PFIFO", vm_pfifo_subclients },
109c39f472eSBen Skeggs 	{ 0x00000006, "BAR", vm_bar_subclients },
110344c2d42SBen Skeggs 	{ 0x00000008, "PMSPPP" },
111344c2d42SBen Skeggs 	{ 0x00000008, "PMPEG" },
112344c2d42SBen Skeggs 	{ 0x00000009, "PBSP" },
113344c2d42SBen Skeggs 	{ 0x0000000a, "PCRYPT" },
114344c2d42SBen Skeggs 	{ 0x0000000b, "PCOUNTER" },
115344c2d42SBen Skeggs 	{ 0x0000000c, "SEMAPHORE_BG" },
116344c2d42SBen Skeggs 	{ 0x0000000d, "PCE0" },
117bac34ed6SBen Skeggs 	{ 0x0000000e, "PMU" },
118c39f472eSBen Skeggs 	{}
119c39f472eSBen Skeggs };
120c39f472eSBen Skeggs 
121639c308eSBen Skeggs static const struct nvkm_enum vm_fault[] = {
122344c2d42SBen Skeggs 	{ 0x00000000, "PT_NOT_PRESENT" },
123344c2d42SBen Skeggs 	{ 0x00000001, "PT_TOO_SHORT" },
124344c2d42SBen Skeggs 	{ 0x00000002, "PAGE_NOT_PRESENT" },
125344c2d42SBen Skeggs 	{ 0x00000003, "PAGE_SYSTEM_ONLY" },
126344c2d42SBen Skeggs 	{ 0x00000004, "PAGE_READ_ONLY" },
127344c2d42SBen Skeggs 	{ 0x00000006, "NULL_DMAOBJ" },
128344c2d42SBen Skeggs 	{ 0x00000007, "WRONG_MEMTYPE" },
129344c2d42SBen Skeggs 	{ 0x0000000b, "VRAM_LIMIT" },
130344c2d42SBen Skeggs 	{ 0x0000000f, "DMAOBJ_LIMIT" },
131c39f472eSBen Skeggs 	{}
132c39f472eSBen Skeggs };
133c39f472eSBen Skeggs 
134c39f472eSBen Skeggs static void
nv50_fb_intr(struct nvkm_fb * base)13503c8952fSBen Skeggs nv50_fb_intr(struct nvkm_fb *base)
136c39f472eSBen Skeggs {
13703c8952fSBen Skeggs 	struct nv50_fb *fb = nv50_fb(base);
13803c8952fSBen Skeggs 	struct nvkm_subdev *subdev = &fb->base.subdev;
13903c8952fSBen Skeggs 	struct nvkm_device *device = subdev->device;
140c358f538SBen Skeggs 	struct nvkm_chan *chan;
1413ecd329bSBen Skeggs 	const struct nvkm_enum *en, *re, *cl, *sc;
142344c2d42SBen Skeggs 	u32 trap[6], idx, inst;
143c39f472eSBen Skeggs 	u8 st0, st1, st2, st3;
144344c2d42SBen Skeggs 	unsigned long flags;
145c39f472eSBen Skeggs 	int i;
146c39f472eSBen Skeggs 
1476758745bSBen Skeggs 	idx = nvkm_rd32(device, 0x100c90);
148c39f472eSBen Skeggs 	if (!(idx & 0x80000000))
149c39f472eSBen Skeggs 		return;
150c39f472eSBen Skeggs 	idx &= 0x00ffffff;
151c39f472eSBen Skeggs 
152c39f472eSBen Skeggs 	for (i = 0; i < 6; i++) {
1536758745bSBen Skeggs 		nvkm_wr32(device, 0x100c90, idx | i << 24);
1546758745bSBen Skeggs 		trap[i] = nvkm_rd32(device, 0x100c94);
155c39f472eSBen Skeggs 	}
1566758745bSBen Skeggs 	nvkm_wr32(device, 0x100c90, idx | 0x80000000);
157c39f472eSBen Skeggs 
158c39f472eSBen Skeggs 	/* decode status bits into something more useful */
159c39f472eSBen Skeggs 	if (device->chipset  < 0xa3 ||
160c39f472eSBen Skeggs 	    device->chipset == 0xaa || device->chipset == 0xac) {
161c39f472eSBen Skeggs 		st0 = (trap[0] & 0x0000000f) >> 0;
162c39f472eSBen Skeggs 		st1 = (trap[0] & 0x000000f0) >> 4;
163c39f472eSBen Skeggs 		st2 = (trap[0] & 0x00000f00) >> 8;
164c39f472eSBen Skeggs 		st3 = (trap[0] & 0x0000f000) >> 12;
165c39f472eSBen Skeggs 	} else {
166c39f472eSBen Skeggs 		st0 = (trap[0] & 0x000000ff) >> 0;
167c39f472eSBen Skeggs 		st1 = (trap[0] & 0x0000ff00) >> 8;
168c39f472eSBen Skeggs 		st2 = (trap[0] & 0x00ff0000) >> 16;
169c39f472eSBen Skeggs 		st3 = (trap[0] & 0xff000000) >> 24;
170c39f472eSBen Skeggs 	}
171344c2d42SBen Skeggs 	inst = ((trap[2] << 16) | trap[1]) << 12;
172c39f472eSBen Skeggs 
173639c308eSBen Skeggs 	en = nvkm_enum_find(vm_engine, st0);
1743ecd329bSBen Skeggs 	re = nvkm_enum_find(vm_fault , st1);
1753ecd329bSBen Skeggs 	cl = nvkm_enum_find(vm_client, st2);
1763ecd329bSBen Skeggs 	if      (cl && cl->data) sc = nvkm_enum_find(cl->data, st3);
1773ecd329bSBen Skeggs 	else if (en && en->data) sc = nvkm_enum_find(en->data, st3);
1783ecd329bSBen Skeggs 	else                     sc = NULL;
1793ecd329bSBen Skeggs 
180c358f538SBen Skeggs 	chan = nvkm_chan_get_inst(&device->fifo->engine, inst, &flags);
1818f0649b5SBen Skeggs 	nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel %d [%08x %s] "
1828f0649b5SBen Skeggs 			   "engine %02x [%s] client %02x [%s] "
1833ecd329bSBen Skeggs 			   "subclient %02x [%s] reason %08x [%s]\n",
184c39f472eSBen Skeggs 		   (trap[5] & 0x00000100) ? "read" : "write",
1858f0649b5SBen Skeggs 		   trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff,
186c358f538SBen Skeggs 		   chan ? chan->id : -1, inst,
187c358f538SBen Skeggs 		   chan ? chan->name : "unknown",
1888f0649b5SBen Skeggs 		   st0, en ? en->name : "",
1893ecd329bSBen Skeggs 		   st2, cl ? cl->name : "", st3, sc ? sc->name : "",
1903ecd329bSBen Skeggs 		   st1, re ? re->name : "");
191c358f538SBen Skeggs 	nvkm_chan_put(&chan, flags);
192c39f472eSBen Skeggs }
193c39f472eSBen Skeggs 
19403c8952fSBen Skeggs static void
nv50_fb_init(struct nvkm_fb * base)19503c8952fSBen Skeggs nv50_fb_init(struct nvkm_fb *base)
196c39f472eSBen Skeggs {
19703c8952fSBen Skeggs 	struct nv50_fb *fb = nv50_fb(base);
19803c8952fSBen Skeggs 	struct nvkm_device *device = fb->base.subdev.device;
199c39f472eSBen Skeggs 
20003c8952fSBen Skeggs 	/* This is needed to get meaningful information from 100c90
20103c8952fSBen Skeggs 	 * on traps. No idea what these values mean exactly. */
20203c8952fSBen Skeggs 	nvkm_wr32(device, 0x100c90, fb->func->trap);
20303c8952fSBen Skeggs }
20403c8952fSBen Skeggs 
205af793b8cSBen Skeggs static u32
nv50_fb_tags(struct nvkm_fb * base)206af793b8cSBen Skeggs nv50_fb_tags(struct nvkm_fb *base)
207af793b8cSBen Skeggs {
208af793b8cSBen Skeggs 	struct nv50_fb *fb = nv50_fb(base);
209af793b8cSBen Skeggs 	if (fb->func->tags)
210af793b8cSBen Skeggs 		return fb->func->tags(&fb->base);
211af793b8cSBen Skeggs 	return 0;
212af793b8cSBen Skeggs }
213af793b8cSBen Skeggs 
214*5728d064SBen Skeggs static void
nv50_fb_sysmem_flush_page_init(struct nvkm_fb * fb)215*5728d064SBen Skeggs nv50_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
216*5728d064SBen Skeggs {
217*5728d064SBen Skeggs 	nvkm_wr32(fb->subdev.device, 0x100c08, fb->sysmem.flush_page_addr >> 8);
218*5728d064SBen Skeggs }
219*5728d064SBen Skeggs 
22003c8952fSBen Skeggs static void *
nv50_fb_dtor(struct nvkm_fb * base)22103c8952fSBen Skeggs nv50_fb_dtor(struct nvkm_fb *base)
22203c8952fSBen Skeggs {
22303c8952fSBen Skeggs 	struct nv50_fb *fb = nv50_fb(base);
22403c8952fSBen Skeggs 
22503c8952fSBen Skeggs 	return fb;
22603c8952fSBen Skeggs }
22703c8952fSBen Skeggs 
22803c8952fSBen Skeggs static const struct nvkm_fb_func
22903c8952fSBen Skeggs nv50_fb_ = {
23003c8952fSBen Skeggs 	.dtor = nv50_fb_dtor,
231af793b8cSBen Skeggs 	.tags = nv50_fb_tags,
23203c8952fSBen Skeggs 	.init = nv50_fb_init,
23303c8952fSBen Skeggs 	.intr = nv50_fb_intr,
234*5728d064SBen Skeggs 	.sysmem.flush_page_init = nv50_fb_sysmem_flush_page_init,
23503c8952fSBen Skeggs 	.ram_new = nv50_fb_ram_new,
23603c8952fSBen Skeggs };
23703c8952fSBen Skeggs 
23803c8952fSBen Skeggs int
nv50_fb_new_(const struct nv50_fb_func * func,struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_fb ** pfb)23903c8952fSBen Skeggs nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device,
240b7a9369aSBen Skeggs 	     enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
24103c8952fSBen Skeggs {
24203c8952fSBen Skeggs 	struct nv50_fb *fb;
24303c8952fSBen Skeggs 
24403c8952fSBen Skeggs 	if (!(fb = kzalloc(sizeof(*fb), GFP_KERNEL)))
24503c8952fSBen Skeggs 		return -ENOMEM;
246b7a9369aSBen Skeggs 	nvkm_fb_ctor(&nv50_fb_, device, type, inst, &fb->base);
24703c8952fSBen Skeggs 	fb->func = func;
24803c8952fSBen Skeggs 	*pfb = &fb->base;
249c39f472eSBen Skeggs 	return 0;
250c39f472eSBen Skeggs }
251c39f472eSBen Skeggs 
25203c8952fSBen Skeggs static const struct nv50_fb_func
25303c8952fSBen Skeggs nv50_fb = {
25403c8952fSBen Skeggs 	.ram_new = nv50_ram_new,
255af793b8cSBen Skeggs 	.tags = nv20_fb_tags,
25603c8952fSBen Skeggs 	.trap = 0x000707ff,
25703c8952fSBen Skeggs };
258c39f472eSBen Skeggs 
259c39f472eSBen Skeggs int
nv50_fb_new(struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_fb ** pfb)260b7a9369aSBen Skeggs nv50_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
261c39f472eSBen Skeggs {
262b7a9369aSBen Skeggs 	return nv50_fb_new_(&nv50_fb, device, type, inst, pfb);
263c39f472eSBen Skeggs }
264