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 #include "channv50.h"
25
26 #include <core/client.h>
27 #include <core/ramht.h>
28 #include <subdev/mmu.h>
29 #include <subdev/timer.h>
30
31 #include <nvif/cl826e.h>
32
33 static int
g84_fifo_chan_ntfy(struct nvkm_fifo_chan * chan,u32 type,struct nvkm_event ** pevent)34 g84_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type,
35 struct nvkm_event **pevent)
36 {
37 switch (type) {
38 case NV826E_V0_NTFY_NON_STALL_INTERRUPT:
39 *pevent = &chan->fifo->uevent;
40 return 0;
41 default:
42 break;
43 }
44 return -EINVAL;
45 }
46
47 static int
g84_fifo_chan_engine(struct nvkm_engine * engine)48 g84_fifo_chan_engine(struct nvkm_engine *engine)
49 {
50 switch (engine->subdev.index) {
51 case NVKM_ENGINE_GR : return 0;
52 case NVKM_ENGINE_MPEG :
53 case NVKM_ENGINE_MSPPP : return 1;
54 case NVKM_ENGINE_CE0 : return 2;
55 case NVKM_ENGINE_VP :
56 case NVKM_ENGINE_MSPDEC: return 3;
57 case NVKM_ENGINE_CIPHER:
58 case NVKM_ENGINE_SEC : return 4;
59 case NVKM_ENGINE_BSP :
60 case NVKM_ENGINE_MSVLD : return 5;
61 default:
62 WARN_ON(1);
63 return 0;
64 }
65 }
66
67 static int
g84_fifo_chan_engine_addr(struct nvkm_engine * engine)68 g84_fifo_chan_engine_addr(struct nvkm_engine *engine)
69 {
70 switch (engine->subdev.index) {
71 case NVKM_ENGINE_DMAOBJ:
72 case NVKM_ENGINE_SW : return -1;
73 case NVKM_ENGINE_GR : return 0x0020;
74 case NVKM_ENGINE_VP :
75 case NVKM_ENGINE_MSPDEC: return 0x0040;
76 case NVKM_ENGINE_MPEG :
77 case NVKM_ENGINE_MSPPP : return 0x0060;
78 case NVKM_ENGINE_BSP :
79 case NVKM_ENGINE_MSVLD : return 0x0080;
80 case NVKM_ENGINE_CIPHER:
81 case NVKM_ENGINE_SEC : return 0x00a0;
82 case NVKM_ENGINE_CE0 : return 0x00c0;
83 default:
84 WARN_ON(1);
85 return -1;
86 }
87 }
88
89 static int
g84_fifo_chan_engine_fini(struct nvkm_fifo_chan * base,struct nvkm_engine * engine,bool suspend)90 g84_fifo_chan_engine_fini(struct nvkm_fifo_chan *base,
91 struct nvkm_engine *engine, bool suspend)
92 {
93 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
94 struct nv50_fifo *fifo = chan->fifo;
95 struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
96 struct nvkm_device *device = subdev->device;
97 u32 engn, save;
98 int offset;
99 bool done;
100
101 offset = g84_fifo_chan_engine_addr(engine);
102 if (offset < 0)
103 return 0;
104
105 engn = g84_fifo_chan_engine(engine);
106 save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn);
107 nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12);
108 done = nvkm_msec(device, 2000,
109 if (nvkm_rd32(device, 0x0032fc) != 0xffffffff)
110 break;
111 ) >= 0;
112 nvkm_wr32(device, 0x002520, save);
113 if (!done) {
114 nvkm_error(subdev, "channel %d [%s] unload timeout\n",
115 chan->base.chid, chan->base.object.client->name);
116 if (suspend)
117 return -EBUSY;
118 }
119
120 nvkm_kmap(chan->eng);
121 nvkm_wo32(chan->eng, offset + 0x00, 0x00000000);
122 nvkm_wo32(chan->eng, offset + 0x04, 0x00000000);
123 nvkm_wo32(chan->eng, offset + 0x08, 0x00000000);
124 nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000);
125 nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
126 nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
127 nvkm_done(chan->eng);
128 return 0;
129 }
130
131
132 static int
g84_fifo_chan_engine_init(struct nvkm_fifo_chan * base,struct nvkm_engine * engine)133 g84_fifo_chan_engine_init(struct nvkm_fifo_chan *base,
134 struct nvkm_engine *engine)
135 {
136 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
137 struct nvkm_gpuobj *engn = chan->engn[engine->subdev.index];
138 u64 limit, start;
139 int offset;
140
141 offset = g84_fifo_chan_engine_addr(engine);
142 if (offset < 0)
143 return 0;
144 limit = engn->addr + engn->size - 1;
145 start = engn->addr;
146
147 nvkm_kmap(chan->eng);
148 nvkm_wo32(chan->eng, offset + 0x00, 0x00190000);
149 nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit));
150 nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start));
151 nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 |
152 upper_32_bits(start));
153 nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
154 nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
155 nvkm_done(chan->eng);
156 return 0;
157 }
158
159 static int
g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan * base,struct nvkm_engine * engine,struct nvkm_object * object)160 g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base,
161 struct nvkm_engine *engine,
162 struct nvkm_object *object)
163 {
164 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
165 int engn = engine->subdev.index;
166
167 if (g84_fifo_chan_engine_addr(engine) < 0)
168 return 0;
169
170 return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]);
171 }
172
173 static int
g84_fifo_chan_object_ctor(struct nvkm_fifo_chan * base,struct nvkm_object * object)174 g84_fifo_chan_object_ctor(struct nvkm_fifo_chan *base,
175 struct nvkm_object *object)
176 {
177 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
178 u32 handle = object->handle;
179 u32 context;
180
181 switch (object->engine->subdev.index) {
182 case NVKM_ENGINE_DMAOBJ:
183 case NVKM_ENGINE_SW : context = 0x00000000; break;
184 case NVKM_ENGINE_GR : context = 0x00100000; break;
185 case NVKM_ENGINE_MPEG :
186 case NVKM_ENGINE_MSPPP : context = 0x00200000; break;
187 case NVKM_ENGINE_ME :
188 case NVKM_ENGINE_CE0 : context = 0x00300000; break;
189 case NVKM_ENGINE_VP :
190 case NVKM_ENGINE_MSPDEC: context = 0x00400000; break;
191 case NVKM_ENGINE_CIPHER:
192 case NVKM_ENGINE_SEC :
193 case NVKM_ENGINE_VIC : context = 0x00500000; break;
194 case NVKM_ENGINE_BSP :
195 case NVKM_ENGINE_MSVLD : context = 0x00600000; break;
196 default:
197 WARN_ON(1);
198 return -EINVAL;
199 }
200
201 return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context);
202 }
203
204 static void
g84_fifo_chan_init(struct nvkm_fifo_chan * base)205 g84_fifo_chan_init(struct nvkm_fifo_chan *base)
206 {
207 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
208 struct nv50_fifo *fifo = chan->fifo;
209 struct nvkm_device *device = fifo->base.engine.subdev.device;
210 u64 addr = chan->ramfc->addr >> 8;
211 u32 chid = chan->base.chid;
212
213 nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr);
214 nv50_fifo_runlist_update(fifo);
215 }
216
217 static const struct nvkm_fifo_chan_func
218 g84_fifo_chan_func = {
219 .dtor = nv50_fifo_chan_dtor,
220 .init = g84_fifo_chan_init,
221 .fini = nv50_fifo_chan_fini,
222 .ntfy = g84_fifo_chan_ntfy,
223 .engine_ctor = g84_fifo_chan_engine_ctor,
224 .engine_dtor = nv50_fifo_chan_engine_dtor,
225 .engine_init = g84_fifo_chan_engine_init,
226 .engine_fini = g84_fifo_chan_engine_fini,
227 .object_ctor = g84_fifo_chan_object_ctor,
228 .object_dtor = nv50_fifo_chan_object_dtor,
229 };
230
231 int
g84_fifo_chan_ctor(struct nv50_fifo * fifo,u64 vmm,u64 push,const struct nvkm_oclass * oclass,struct nv50_fifo_chan * chan)232 g84_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vmm, u64 push,
233 const struct nvkm_oclass *oclass,
234 struct nv50_fifo_chan *chan)
235 {
236 struct nvkm_device *device = fifo->base.engine.subdev.device;
237 int ret;
238
239 if (!vmm)
240 return -EINVAL;
241
242 ret = nvkm_fifo_chan_ctor(&g84_fifo_chan_func, &fifo->base,
243 0x10000, 0x1000, false, vmm, push,
244 (1ULL << NVKM_ENGINE_BSP) |
245 (1ULL << NVKM_ENGINE_CE0) |
246 (1ULL << NVKM_ENGINE_CIPHER) |
247 (1ULL << NVKM_ENGINE_DMAOBJ) |
248 (1ULL << NVKM_ENGINE_GR) |
249 (1ULL << NVKM_ENGINE_ME) |
250 (1ULL << NVKM_ENGINE_MPEG) |
251 (1ULL << NVKM_ENGINE_MSPDEC) |
252 (1ULL << NVKM_ENGINE_MSPPP) |
253 (1ULL << NVKM_ENGINE_MSVLD) |
254 (1ULL << NVKM_ENGINE_SEC) |
255 (1ULL << NVKM_ENGINE_SW) |
256 (1ULL << NVKM_ENGINE_VIC) |
257 (1ULL << NVKM_ENGINE_VP),
258 0, 0xc00000, 0x2000, oclass, &chan->base);
259 chan->fifo = fifo;
260 if (ret)
261 return ret;
262
263 ret = nvkm_gpuobj_new(device, 0x0200, 0, true, chan->base.inst,
264 &chan->eng);
265 if (ret)
266 return ret;
267
268 ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst,
269 &chan->pgd);
270 if (ret)
271 return ret;
272
273 ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, chan->base.inst,
274 &chan->cache);
275 if (ret)
276 return ret;
277
278 ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, chan->base.inst,
279 &chan->ramfc);
280 if (ret)
281 return ret;
282
283 return nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht);
284 }
285