2 * Copyright 2012 Red Hat Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
24 #include "changf100.h"
26 #include <core/client.h>
27 #include <core/gpuobj.h>
28 #include <subdev/fb.h>
29 #include <subdev/timer.h>
31 #include <nvif/class.h>
32 #include <nvif/cl906f.h>
33 #include <nvif/unpack.h>
36 gf100_fifo_chan_ntfy(struct nvkm_fifo_chan
*chan
, u32 type
,
37 struct nvkm_event
**pevent
)
40 case NV906F_V0_NTFY_NON_STALL_INTERRUPT
:
41 *pevent
= &chan
->fifo
->uevent
;
43 case NV906F_V0_NTFY_KILLED
:
44 *pevent
= &chan
->fifo
->kevent
;
53 gf100_fifo_gpfifo_engine_addr(struct nvkm_engine
*engine
)
55 switch (engine
->subdev
.index
) {
56 case NVKM_ENGINE_SW
: return 0;
57 case NVKM_ENGINE_GR
: return 0x0210;
58 case NVKM_ENGINE_CE0
: return 0x0230;
59 case NVKM_ENGINE_CE1
: return 0x0240;
60 case NVKM_ENGINE_MSPDEC
: return 0x0250;
61 case NVKM_ENGINE_MSPPP
: return 0x0260;
62 case NVKM_ENGINE_MSVLD
: return 0x0270;
70 gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan
*base
,
71 struct nvkm_engine
*engine
, bool suspend
)
73 const u32 offset
= gf100_fifo_gpfifo_engine_addr(engine
);
74 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
75 struct nvkm_subdev
*subdev
= &chan
->fifo
->base
.engine
.subdev
;
76 struct nvkm_device
*device
= subdev
->device
;
77 struct nvkm_gpuobj
*inst
= chan
->base
.inst
;
80 mutex_lock(&subdev
->mutex
);
81 nvkm_wr32(device
, 0x002634, chan
->base
.chid
);
82 if (nvkm_msec(device
, 2000,
83 if (nvkm_rd32(device
, 0x002634) == chan
->base
.chid
)
86 nvkm_error(subdev
, "channel %d [%s] kick timeout\n",
87 chan
->base
.chid
, chan
->base
.object
.client
->name
);
90 mutex_unlock(&subdev
->mutex
);
97 nvkm_wo32(inst
, offset
+ 0x00, 0x00000000);
98 nvkm_wo32(inst
, offset
+ 0x04, 0x00000000);
106 gf100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan
*base
,
107 struct nvkm_engine
*engine
)
109 const u32 offset
= gf100_fifo_gpfifo_engine_addr(engine
);
110 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
111 struct nvkm_gpuobj
*inst
= chan
->base
.inst
;
114 u64 addr
= chan
->engn
[engine
->subdev
.index
].vma
->addr
;
116 nvkm_wo32(inst
, offset
+ 0x00, lower_32_bits(addr
) | 4);
117 nvkm_wo32(inst
, offset
+ 0x04, upper_32_bits(addr
));
125 gf100_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan
*base
,
126 struct nvkm_engine
*engine
)
128 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
129 nvkm_vmm_put(chan
->base
.vmm
, &chan
->engn
[engine
->subdev
.index
].vma
);
130 nvkm_gpuobj_del(&chan
->engn
[engine
->subdev
.index
].inst
);
134 gf100_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan
*base
,
135 struct nvkm_engine
*engine
,
136 struct nvkm_object
*object
)
138 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
139 int engn
= engine
->subdev
.index
;
142 if (!gf100_fifo_gpfifo_engine_addr(engine
))
145 ret
= nvkm_object_bind(object
, NULL
, 0, &chan
->engn
[engn
].inst
);
149 ret
= nvkm_vmm_get(chan
->base
.vmm
, 12, chan
->engn
[engn
].inst
->size
,
150 &chan
->engn
[engn
].vma
);
154 return nvkm_memory_map(chan
->engn
[engn
].inst
, 0, chan
->base
.vmm
,
155 chan
->engn
[engn
].vma
, NULL
, 0);
159 gf100_fifo_gpfifo_fini(struct nvkm_fifo_chan
*base
)
161 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
162 struct gf100_fifo
*fifo
= chan
->fifo
;
163 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
164 u32 coff
= chan
->base
.chid
* 8;
166 if (!list_empty(&chan
->head
) && !chan
->killed
) {
167 gf100_fifo_runlist_remove(fifo
, chan
);
168 nvkm_mask(device
, 0x003004 + coff
, 0x00000001, 0x00000000);
169 gf100_fifo_runlist_commit(fifo
);
172 gf100_fifo_intr_engine(fifo
);
174 nvkm_wr32(device
, 0x003000 + coff
, 0x00000000);
178 gf100_fifo_gpfifo_init(struct nvkm_fifo_chan
*base
)
180 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
181 struct gf100_fifo
*fifo
= chan
->fifo
;
182 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
183 u32 addr
= chan
->base
.inst
->addr
>> 12;
184 u32 coff
= chan
->base
.chid
* 8;
186 nvkm_wr32(device
, 0x003000 + coff
, 0xc0000000 | addr
);
188 if (list_empty(&chan
->head
) && !chan
->killed
) {
189 gf100_fifo_runlist_insert(fifo
, chan
);
190 nvkm_wr32(device
, 0x003004 + coff
, 0x001f0001);
191 gf100_fifo_runlist_commit(fifo
);
196 gf100_fifo_gpfifo_dtor(struct nvkm_fifo_chan
*base
)
198 return gf100_fifo_chan(base
);
201 static const struct nvkm_fifo_chan_func
202 gf100_fifo_gpfifo_func
= {
203 .dtor
= gf100_fifo_gpfifo_dtor
,
204 .init
= gf100_fifo_gpfifo_init
,
205 .fini
= gf100_fifo_gpfifo_fini
,
206 .ntfy
= gf100_fifo_chan_ntfy
,
207 .engine_ctor
= gf100_fifo_gpfifo_engine_ctor
,
208 .engine_dtor
= gf100_fifo_gpfifo_engine_dtor
,
209 .engine_init
= gf100_fifo_gpfifo_engine_init
,
210 .engine_fini
= gf100_fifo_gpfifo_engine_fini
,
214 gf100_fifo_gpfifo_new(struct nvkm_fifo
*base
, const struct nvkm_oclass
*oclass
,
215 void *data
, u32 size
, struct nvkm_object
**pobject
)
218 struct fermi_channel_gpfifo_v0 v0
;
220 struct gf100_fifo
*fifo
= gf100_fifo(base
);
221 struct nvkm_object
*parent
= oclass
->parent
;
222 struct gf100_fifo_chan
*chan
;
223 u64 usermem
, ioffset
, ilength
;
224 int ret
= -ENOSYS
, i
;
226 nvif_ioctl(parent
, "create channel gpfifo size %d\n", size
);
227 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
228 nvif_ioctl(parent
, "create channel gpfifo vers %d vmm %llx "
229 "ioffset %016llx ilength %08x\n",
230 args
->v0
.version
, args
->v0
.vmm
, args
->v0
.ioffset
,
237 /* allocate channel */
238 if (!(chan
= kzalloc(sizeof(*chan
), GFP_KERNEL
)))
240 *pobject
= &chan
->base
.object
;
242 INIT_LIST_HEAD(&chan
->head
);
244 ret
= nvkm_fifo_chan_ctor(&gf100_fifo_gpfifo_func
, &fifo
->base
,
245 0x1000, 0x1000, true, args
->v0
.vmm
, 0,
246 (1ULL << NVKM_ENGINE_CE0
) |
247 (1ULL << NVKM_ENGINE_CE1
) |
248 (1ULL << NVKM_ENGINE_GR
) |
249 (1ULL << NVKM_ENGINE_MSPDEC
) |
250 (1ULL << NVKM_ENGINE_MSPPP
) |
251 (1ULL << NVKM_ENGINE_MSVLD
) |
252 (1ULL << NVKM_ENGINE_SW
),
253 1, fifo
->user
.bar
->addr
, 0x1000,
254 oclass
, &chan
->base
);
258 args
->v0
.chid
= chan
->base
.chid
;
260 /* clear channel control registers */
262 usermem
= chan
->base
.chid
* 0x1000;
263 ioffset
= args
->v0
.ioffset
;
264 ilength
= order_base_2(args
->v0
.ilength
/ 8);
266 nvkm_kmap(fifo
->user
.mem
);
267 for (i
= 0; i
< 0x1000; i
+= 4)
268 nvkm_wo32(fifo
->user
.mem
, usermem
+ i
, 0x00000000);
269 nvkm_done(fifo
->user
.mem
);
270 usermem
= nvkm_memory_addr(fifo
->user
.mem
) + usermem
;
273 nvkm_kmap(chan
->base
.inst
);
274 nvkm_wo32(chan
->base
.inst
, 0x08, lower_32_bits(usermem
));
275 nvkm_wo32(chan
->base
.inst
, 0x0c, upper_32_bits(usermem
));
276 nvkm_wo32(chan
->base
.inst
, 0x10, 0x0000face);
277 nvkm_wo32(chan
->base
.inst
, 0x30, 0xfffff902);
278 nvkm_wo32(chan
->base
.inst
, 0x48, lower_32_bits(ioffset
));
279 nvkm_wo32(chan
->base
.inst
, 0x4c, upper_32_bits(ioffset
) |
281 nvkm_wo32(chan
->base
.inst
, 0x54, 0x00000002);
282 nvkm_wo32(chan
->base
.inst
, 0x84, 0x20400000);
283 nvkm_wo32(chan
->base
.inst
, 0x94, 0x30000001);
284 nvkm_wo32(chan
->base
.inst
, 0x9c, 0x00000100);
285 nvkm_wo32(chan
->base
.inst
, 0xa4, 0x1f1f1f1f);
286 nvkm_wo32(chan
->base
.inst
, 0xa8, 0x1f1f1f1f);
287 nvkm_wo32(chan
->base
.inst
, 0xac, 0x0000001f);
288 nvkm_wo32(chan
->base
.inst
, 0xb8, 0xf8000000);
289 nvkm_wo32(chan
->base
.inst
, 0xf8, 0x10003080); /* 0x002310 */
290 nvkm_wo32(chan
->base
.inst
, 0xfc, 0x10000010); /* 0x002350 */
291 nvkm_done(chan
->base
.inst
);
295 const struct nvkm_fifo_chan_oclass
296 gf100_fifo_gpfifo_oclass
= {
297 .base
.oclass
= FERMI_CHANNEL_GPFIFO
,
300 .ctor
= gf100_fifo_gpfifo_new
,