support for platform devices
[deliverable/linux.git] / drivers / gpu / drm / nouveau / core / subdev / fb / nv50.c
CommitLineData
861d2107
BS
1/*
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 */
24
93260d3c 25#include <core/client.h>
861d2107 26#include <core/enum.h>
93260d3c
MS
27#include <core/engctx.h>
28#include <core/object.h>
861d2107 29
861d2107 30#include <subdev/bios.h>
304424e1 31
9ca3037e 32#include "nv50.h"
20f63afe 33
dceef5d8
BS
34int
35nv50_fb_memtype[0x80] = {
861d2107
BS
36 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
38 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
41 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2,
43 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0
44};
45
20cdeaf9 46bool
861d2107 47nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype)
8f7286f8 48{
dceef5d8 49 return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
861d2107
BS
50}
51
e6626254 52static const struct nouveau_enum vm_dispatch_subclients[] = {
312d1d5f
BS
53 { 0x00000000, "GRCTX", NULL },
54 { 0x00000001, "NOTIFY", NULL },
55 { 0x00000002, "QUERY", NULL },
56 { 0x00000003, "COND", NULL },
57 { 0x00000004, "M2M_IN", NULL },
58 { 0x00000005, "M2M_OUT", NULL },
59 { 0x00000006, "M2M_NOTIFY", NULL },
60 {}
61};
62
e6626254 63static const struct nouveau_enum vm_ccache_subclients[] = {
312d1d5f
BS
64 { 0x00000000, "CB", NULL },
65 { 0x00000001, "TIC", NULL },
66 { 0x00000002, "TSC", NULL },
67 {}
68};
69
e6626254 70static const struct nouveau_enum vm_prop_subclients[] = {
312d1d5f
BS
71 { 0x00000000, "RT0", NULL },
72 { 0x00000001, "RT1", NULL },
73 { 0x00000002, "RT2", NULL },
74 { 0x00000003, "RT3", NULL },
75 { 0x00000004, "RT4", NULL },
76 { 0x00000005, "RT5", NULL },
77 { 0x00000006, "RT6", NULL },
78 { 0x00000007, "RT7", NULL },
79 { 0x00000008, "ZETA", NULL },
80 { 0x00000009, "LOCAL", NULL },
81 { 0x0000000a, "GLOBAL", NULL },
82 { 0x0000000b, "STACK", NULL },
83 { 0x0000000c, "DST2D", NULL },
84 {}
85};
86
e6626254 87static const struct nouveau_enum vm_pfifo_subclients[] = {
312d1d5f
BS
88 { 0x00000000, "PUSHBUF", NULL },
89 { 0x00000001, "SEMAPHORE", NULL },
90 {}
91};
92
e6626254 93static const struct nouveau_enum vm_bar_subclients[] = {
312d1d5f
BS
94 { 0x00000000, "FB", NULL },
95 { 0x00000001, "IN", NULL },
96 {}
97};
98
e6626254 99static const struct nouveau_enum vm_client[] = {
312d1d5f
BS
100 { 0x00000000, "STRMOUT", NULL },
101 { 0x00000003, "DISPATCH", vm_dispatch_subclients },
102 { 0x00000004, "PFIFO_WRITE", NULL },
103 { 0x00000005, "CCACHE", vm_ccache_subclients },
104 { 0x00000006, "PPPP", NULL },
105 { 0x00000007, "CLIPID", NULL },
106 { 0x00000008, "PFIFO_READ", NULL },
107 { 0x00000009, "VFETCH", NULL },
108 { 0x0000000a, "TEXTURE", NULL },
109 { 0x0000000b, "PROP", vm_prop_subclients },
110 { 0x0000000c, "PVP", NULL },
111 { 0x0000000d, "PBSP", NULL },
112 { 0x0000000e, "PCRYPT", NULL },
113 { 0x0000000f, "PCOUNTER", NULL },
114 { 0x00000011, "PDAEMON", NULL },
115 {}
116};
117
e6626254 118static const struct nouveau_enum vm_engine[] = {
93260d3c
MS
119 { 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR },
120 { 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP },
312d1d5f 121 { 0x00000004, "PEEPHOLE", NULL },
93260d3c 122 { 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO },
312d1d5f 123 { 0x00000006, "BAR", vm_bar_subclients },
93260d3c
MS
124 { 0x00000008, "PPPP", NULL, NVDEV_ENGINE_PPP },
125 { 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG },
126 { 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP },
127 { 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CRYPT },
312d1d5f
BS
128 { 0x0000000b, "PCOUNTER", NULL },
129 { 0x0000000c, "SEMAPHORE_BG", NULL },
93260d3c 130 { 0x0000000d, "PCOPY", NULL, NVDEV_ENGINE_COPY0 },
312d1d5f
BS
131 { 0x0000000e, "PDAEMON", NULL },
132 {}
133};
134
e6626254 135static const struct nouveau_enum vm_fault[] = {
312d1d5f
BS
136 { 0x00000000, "PT_NOT_PRESENT", NULL },
137 { 0x00000001, "PT_TOO_SHORT", NULL },
138 { 0x00000002, "PAGE_NOT_PRESENT", NULL },
139 { 0x00000003, "PAGE_SYSTEM_ONLY", NULL },
140 { 0x00000004, "PAGE_READ_ONLY", NULL },
141 { 0x00000006, "NULL_DMAOBJ", NULL },
142 { 0x00000007, "WRONG_MEMTYPE", NULL },
143 { 0x0000000b, "VRAM_LIMIT", NULL },
144 { 0x0000000f, "DMAOBJ_LIMIT", NULL },
145 {}
146};
147
874309a5
BS
148static void
149nv50_fb_intr(struct nouveau_subdev *subdev)
d96773e7 150{
874309a5 151 struct nouveau_device *device = nv_device(subdev);
93260d3c 152 struct nouveau_engine *engine;
874309a5 153 struct nv50_fb_priv *priv = (void *)subdev;
312d1d5f 154 const struct nouveau_enum *en, *cl;
93260d3c 155 struct nouveau_object *engctx = NULL;
861d2107 156 u32 trap[6], idx, chan;
312d1d5f 157 u8 st0, st1, st2, st3;
861d2107 158 int i;
d96773e7 159
861d2107 160 idx = nv_rd32(priv, 0x100c90);
d96773e7
BS
161 if (!(idx & 0x80000000))
162 return;
163 idx &= 0x00ffffff;
164
165 for (i = 0; i < 6; i++) {
861d2107
BS
166 nv_wr32(priv, 0x100c90, idx | i << 24);
167 trap[i] = nv_rd32(priv, 0x100c94);
d96773e7 168 }
861d2107 169 nv_wr32(priv, 0x100c90, idx | 0x80000000);
d96773e7 170
312d1d5f 171 /* decode status bits into something more useful */
861d2107
BS
172 if (device->chipset < 0xa3 ||
173 device->chipset == 0xaa || device->chipset == 0xac) {
312d1d5f
BS
174 st0 = (trap[0] & 0x0000000f) >> 0;
175 st1 = (trap[0] & 0x000000f0) >> 4;
176 st2 = (trap[0] & 0x00000f00) >> 8;
177 st3 = (trap[0] & 0x0000f000) >> 12;
178 } else {
179 st0 = (trap[0] & 0x000000ff) >> 0;
180 st1 = (trap[0] & 0x0000ff00) >> 8;
181 st2 = (trap[0] & 0x00ff0000) >> 16;
182 st3 = (trap[0] & 0xff000000) >> 24;
183 }
861d2107 184 chan = (trap[2] << 16) | trap[1];
312d1d5f 185
93260d3c
MS
186 en = nouveau_enum_find(vm_engine, st0);
187
188 if (en && en->data2) {
189 const struct nouveau_enum *orig_en = en;
190 while (en->name && en->value == st0 && en->data2) {
191 engine = nouveau_engine(subdev, en->data2);
192 if (engine) {
193 engctx = nouveau_engctx_get(engine, chan);
194 if (engctx)
195 break;
196 }
197 en++;
198 }
199 if (!engctx)
200 en = orig_en;
201 }
202
203 nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ",
861d2107 204 (trap[5] & 0x00000100) ? "read" : "write",
93260d3c
MS
205 trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan,
206 nouveau_client_name(engctx));
207
208 nouveau_engctx_put(engctx);
312d1d5f 209
312d1d5f 210 if (en)
f533da10 211 pr_cont("%s/", en->name);
312d1d5f 212 else
f533da10 213 pr_cont("%02x/", st0);
312d1d5f
BS
214
215 cl = nouveau_enum_find(vm_client, st2);
216 if (cl)
f533da10 217 pr_cont("%s/", cl->name);
312d1d5f 218 else
f533da10 219 pr_cont("%02x/", st2);
312d1d5f
BS
220
221 if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3);
222 else if (en && en->data) cl = nouveau_enum_find(en->data, st3);
223 else cl = NULL;
224 if (cl)
f533da10 225 pr_cont("%s", cl->name);
312d1d5f 226 else
f533da10 227 pr_cont("%02x", st3);
312d1d5f 228
f533da10 229 pr_cont(" reason: ");
312d1d5f
BS
230 en = nouveau_enum_find(vm_fault, st1);
231 if (en)
f533da10 232 pr_cont("%s\n", en->name);
312d1d5f 233 else
f533da10 234 pr_cont("0x%08x\n", st1);
d96773e7 235}
874309a5 236
9ca3037e 237int
874309a5
BS
238nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
239 struct nouveau_oclass *oclass, void *data, u32 size,
240 struct nouveau_object **pobject)
241{
242 struct nouveau_device *device = nv_device(parent);
243 struct nv50_fb_priv *priv;
244 int ret;
245
8613e731 246 ret = nouveau_fb_create(parent, engine, oclass, &priv);
874309a5
BS
247 *pobject = nv_object(priv);
248 if (ret)
249 return ret;
250
251 priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
252 if (priv->r100c08_page) {
420b9469
AC
253 priv->r100c08 = nv_device_map_page(device, priv->r100c08_page);
254 if (!priv->r100c08)
874309a5
BS
255 nv_warn(priv, "failed 0x100c08 page map\n");
256 } else {
257 nv_warn(priv, "failed 0x100c08 page alloc\n");
258 }
259
874309a5 260 nv_subdev(priv)->intr = nv50_fb_intr;
dceef5d8 261 return 0;
874309a5
BS
262}
263
9ca3037e 264void
874309a5
BS
265nv50_fb_dtor(struct nouveau_object *object)
266{
267 struct nouveau_device *device = nv_device(object);
268 struct nv50_fb_priv *priv = (void *)object;
269
270 if (priv->r100c08_page) {
420b9469 271 nv_device_unmap_page(device, priv->r100c08);
874309a5
BS
272 __free_page(priv->r100c08_page);
273 }
274
275 nouveau_fb_destroy(&priv->base);
276}
277
9ca3037e 278int
874309a5
BS
279nv50_fb_init(struct nouveau_object *object)
280{
9ca3037e 281 struct nv50_fb_impl *impl = (void *)object->oclass;
874309a5
BS
282 struct nv50_fb_priv *priv = (void *)object;
283 int ret;
284
285 ret = nouveau_fb_init(&priv->base);
286 if (ret)
287 return ret;
288
289 /* Not a clue what this is exactly. Without pointing it at a
290 * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
291 * cause IOMMU "read from address 0" errors (rh#561267)
292 */
293 nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
294
295 /* This is needed to get meaningful information from 100c90
296 * on traps. No idea what these values mean exactly. */
9ca3037e 297 nv_wr32(priv, 0x100c90, impl->trap);
874309a5
BS
298 return 0;
299}
300
1e9fc30e 301struct nouveau_oclass *
9ca3037e 302nv50_fb_oclass = &(struct nv50_fb_impl) {
8613e731
BS
303 .base.base.handle = NV_SUBDEV(FB, 0x50),
304 .base.base.ofuncs = &(struct nouveau_ofuncs) {
874309a5
BS
305 .ctor = nv50_fb_ctor,
306 .dtor = nv50_fb_dtor,
307 .init = nv50_fb_init,
308 .fini = _nouveau_fb_fini,
309 },
20cdeaf9 310 .base.memtype = nv50_fb_memtype_valid,
8613e731 311 .base.ram = &nv50_ram_oclass,
9ca3037e 312 .trap = 0x000707ff,
8613e731 313}.base.base;
This page took 0.268181 seconds and 5 git commands to generate.