1 /* $NetBSD: nouveau_nvkm_engine_fifo_chang84.c,v 1.4 2021/12/18 23:45:35 riastradh Exp $ */
2
3 /*
4 * Copyright 2012 Red Hat Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: Ben Skeggs
25 */
26 #include <sys/cdefs.h>
27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_engine_fifo_chang84.c,v 1.4 2021/12/18 23:45:35 riastradh Exp $");
28
29 #include "channv50.h"
30
31 #include <core/client.h>
32 #include <core/ramht.h>
33 #include <subdev/mmu.h>
34 #include <subdev/timer.h>
35
36 #include <nvif/cl826e.h>
37
38 static int
g84_fifo_chan_ntfy(struct nvkm_fifo_chan * chan,u32 type,struct nvkm_event ** pevent)39 g84_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type,
40 struct nvkm_event **pevent)
41 {
42 switch (type) {
43 case NV826E_V0_NTFY_NON_STALL_INTERRUPT:
44 *pevent = &chan->fifo->uevent;
45 return 0;
46 default:
47 break;
48 }
49 return -EINVAL;
50 }
51
52 static int
g84_fifo_chan_engine(struct nvkm_engine * engine)53 g84_fifo_chan_engine(struct nvkm_engine *engine)
54 {
55 switch (engine->subdev.index) {
56 case NVKM_ENGINE_GR : return 0;
57 case NVKM_ENGINE_MPEG :
58 case NVKM_ENGINE_MSPPP : return 1;
59 case NVKM_ENGINE_CE0 : return 2;
60 case NVKM_ENGINE_VP :
61 case NVKM_ENGINE_MSPDEC: return 3;
62 case NVKM_ENGINE_CIPHER:
63 case NVKM_ENGINE_SEC : return 4;
64 case NVKM_ENGINE_BSP :
65 case NVKM_ENGINE_MSVLD : return 5;
66 default:
67 WARN_ON(1);
68 return 0;
69 }
70 }
71
72 static int
g84_fifo_chan_engine_addr(struct nvkm_engine * engine)73 g84_fifo_chan_engine_addr(struct nvkm_engine *engine)
74 {
75 switch (engine->subdev.index) {
76 case NVKM_ENGINE_DMAOBJ:
77 case NVKM_ENGINE_SW : return -1;
78 case NVKM_ENGINE_GR : return 0x0020;
79 case NVKM_ENGINE_VP :
80 case NVKM_ENGINE_MSPDEC: return 0x0040;
81 case NVKM_ENGINE_MPEG :
82 case NVKM_ENGINE_MSPPP : return 0x0060;
83 case NVKM_ENGINE_BSP :
84 case NVKM_ENGINE_MSVLD : return 0x0080;
85 case NVKM_ENGINE_CIPHER:
86 case NVKM_ENGINE_SEC : return 0x00a0;
87 case NVKM_ENGINE_CE0 : return 0x00c0;
88 default:
89 WARN_ON(1);
90 return -1;
91 }
92 }
93
94 static int
g84_fifo_chan_engine_fini(struct nvkm_fifo_chan * base,struct nvkm_engine * engine,bool suspend)95 g84_fifo_chan_engine_fini(struct nvkm_fifo_chan *base,
96 struct nvkm_engine *engine, bool suspend)
97 {
98 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
99 struct nv50_fifo *fifo = chan->fifo;
100 struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
101 struct nvkm_device *device = subdev->device;
102 u32 engn, save;
103 int offset;
104 bool done;
105
106 offset = g84_fifo_chan_engine_addr(engine);
107 if (offset < 0)
108 return 0;
109
110 engn = g84_fifo_chan_engine(engine);
111 save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn);
112 nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12);
113 done = nvkm_msec(device, 2000,
114 if (nvkm_rd32(device, 0x0032fc) != 0xffffffff)
115 break;
116 ) >= 0;
117 nvkm_wr32(device, 0x002520, save);
118 if (!done) {
119 nvkm_error(subdev, "channel %d [%s] unload timeout\n",
120 chan->base.chid, chan->base.object.client->name);
121 if (suspend)
122 return -EBUSY;
123 }
124
125 nvkm_kmap(chan->eng);
126 nvkm_wo32(chan->eng, offset + 0x00, 0x00000000);
127 nvkm_wo32(chan->eng, offset + 0x04, 0x00000000);
128 nvkm_wo32(chan->eng, offset + 0x08, 0x00000000);
129 nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000);
130 nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
131 nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
132 nvkm_done(chan->eng);
133 return 0;
134 }
135
136
137 static int
g84_fifo_chan_engine_init(struct nvkm_fifo_chan * base,struct nvkm_engine * engine)138 g84_fifo_chan_engine_init(struct nvkm_fifo_chan *base,
139 struct nvkm_engine *engine)
140 {
141 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
142 struct nvkm_gpuobj *engn = chan->engn[engine->subdev.index];
143 u64 limit, start;
144 int offset;
145
146 offset = g84_fifo_chan_engine_addr(engine);
147 if (offset < 0)
148 return 0;
149 limit = engn->addr + engn->size - 1;
150 start = engn->addr;
151
152 nvkm_kmap(chan->eng);
153 nvkm_wo32(chan->eng, offset + 0x00, 0x00190000);
154 nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit));
155 nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start));
156 nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 |
157 upper_32_bits(start));
158 nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
159 nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
160 nvkm_done(chan->eng);
161 return 0;
162 }
163
164 static int
g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan * base,struct nvkm_engine * engine,struct nvkm_object * object)165 g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base,
166 struct nvkm_engine *engine,
167 struct nvkm_object *object)
168 {
169 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
170 int engn = engine->subdev.index;
171
172 if (g84_fifo_chan_engine_addr(engine) < 0)
173 return 0;
174
175 return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]);
176 }
177
178 static int
g84_fifo_chan_object_ctor(struct nvkm_fifo_chan * base,struct nvkm_object * object)179 g84_fifo_chan_object_ctor(struct nvkm_fifo_chan *base,
180 struct nvkm_object *object)
181 {
182 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
183 u32 handle = object->handle;
184 u32 context;
185
186 switch (object->engine->subdev.index) {
187 case NVKM_ENGINE_DMAOBJ:
188 case NVKM_ENGINE_SW : context = 0x00000000; break;
189 case NVKM_ENGINE_GR : context = 0x00100000; break;
190 case NVKM_ENGINE_MPEG :
191 case NVKM_ENGINE_MSPPP : context = 0x00200000; break;
192 case NVKM_ENGINE_ME :
193 case NVKM_ENGINE_CE0 : context = 0x00300000; break;
194 case NVKM_ENGINE_VP :
195 case NVKM_ENGINE_MSPDEC: context = 0x00400000; break;
196 case NVKM_ENGINE_CIPHER:
197 case NVKM_ENGINE_SEC :
198 case NVKM_ENGINE_VIC : context = 0x00500000; break;
199 case NVKM_ENGINE_BSP :
200 case NVKM_ENGINE_MSVLD : context = 0x00600000; break;
201 default:
202 WARN_ON(1);
203 return -EINVAL;
204 }
205
206 return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context);
207 }
208
209 static void
g84_fifo_chan_init(struct nvkm_fifo_chan * base)210 g84_fifo_chan_init(struct nvkm_fifo_chan *base)
211 {
212 struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
213 struct nv50_fifo *fifo = chan->fifo;
214 struct nvkm_device *device = fifo->base.engine.subdev.device;
215 u64 addr = chan->ramfc->addr >> 8;
216 u32 chid = chan->base.chid;
217
218 nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr);
219 nv50_fifo_runlist_update(fifo);
220 }
221
222 static const struct nvkm_fifo_chan_func
223 g84_fifo_chan_func = {
224 .dtor = nv50_fifo_chan_dtor,
225 .init = g84_fifo_chan_init,
226 .fini = nv50_fifo_chan_fini,
227 .ntfy = g84_fifo_chan_ntfy,
228 .engine_ctor = g84_fifo_chan_engine_ctor,
229 .engine_dtor = nv50_fifo_chan_engine_dtor,
230 .engine_init = g84_fifo_chan_engine_init,
231 .engine_fini = g84_fifo_chan_engine_fini,
232 .object_ctor = g84_fifo_chan_object_ctor,
233 .object_dtor = nv50_fifo_chan_object_dtor,
234 };
235
236 int
g84_fifo_chan_ctor(struct nv50_fifo * fifo,u64 vmm,u64 push,const struct nvkm_oclass * oclass,struct nv50_fifo_chan * chan)237 g84_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vmm, u64 push,
238 const struct nvkm_oclass *oclass,
239 struct nv50_fifo_chan *chan)
240 {
241 struct nvkm_device *device = fifo->base.engine.subdev.device;
242 int ret;
243
244 if (!vmm)
245 return -EINVAL;
246
247 ret = nvkm_fifo_chan_ctor(&g84_fifo_chan_func, &fifo->base,
248 0x10000, 0x1000, false, vmm, push,
249 (1ULL << NVKM_ENGINE_BSP) |
250 (1ULL << NVKM_ENGINE_CE0) |
251 (1ULL << NVKM_ENGINE_CIPHER) |
252 (1ULL << NVKM_ENGINE_DMAOBJ) |
253 (1ULL << NVKM_ENGINE_GR) |
254 (1ULL << NVKM_ENGINE_ME) |
255 (1ULL << NVKM_ENGINE_MPEG) |
256 (1ULL << NVKM_ENGINE_MSPDEC) |
257 (1ULL << NVKM_ENGINE_MSPPP) |
258 (1ULL << NVKM_ENGINE_MSVLD) |
259 (1ULL << NVKM_ENGINE_SEC) |
260 (1ULL << NVKM_ENGINE_SW) |
261 (1ULL << NVKM_ENGINE_VIC) |
262 (1ULL << NVKM_ENGINE_VP),
263 0, 0xc00000, 0x2000, oclass, &chan->base);
264 chan->fifo = fifo;
265 if (ret)
266 return ret;
267
268 ret = nvkm_gpuobj_new(device, 0x0200, 0, true, chan->base.inst,
269 &chan->eng);
270 if (ret)
271 return ret;
272
273 ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst,
274 &chan->pgd);
275 if (ret)
276 return ret;
277
278 ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, chan->base.inst,
279 &chan->cache);
280 if (ret)
281 return ret;
282
283 ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, chan->base.inst,
284 &chan->ramfc);
285 if (ret)
286 return ret;
287
288 return nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht);
289 }
290