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/unpack.h>
35 gf100_fifo_gpfifo_engine_addr(struct nvkm_engine
*engine
)
37 switch (engine
->subdev
.index
) {
38 case NVKM_ENGINE_SW
: return 0;
39 case NVKM_ENGINE_GR
: return 0x0210;
40 case NVKM_ENGINE_CE0
: return 0x0230;
41 case NVKM_ENGINE_CE1
: return 0x0240;
42 case NVKM_ENGINE_MSPDEC
: return 0x0250;
43 case NVKM_ENGINE_MSPPP
: return 0x0260;
44 case NVKM_ENGINE_MSVLD
: return 0x0270;
52 gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan
*base
,
53 struct nvkm_engine
*engine
, bool suspend
)
55 const u32 offset
= gf100_fifo_gpfifo_engine_addr(engine
);
56 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
57 struct nvkm_subdev
*subdev
= &chan
->fifo
->base
.engine
.subdev
;
58 struct nvkm_device
*device
= subdev
->device
;
59 struct nvkm_gpuobj
*inst
= chan
->base
.inst
;
62 nvkm_wr32(device
, 0x002634, chan
->base
.chid
);
63 if (nvkm_msec(device
, 2000,
64 if (nvkm_rd32(device
, 0x002634) == chan
->base
.chid
)
67 nvkm_error(subdev
, "channel %d [%s] kick timeout\n",
68 chan
->base
.chid
, chan
->base
.object
.client
->name
);
76 nvkm_wo32(inst
, offset
+ 0x00, 0x00000000);
77 nvkm_wo32(inst
, offset
+ 0x04, 0x00000000);
85 gf100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan
*base
,
86 struct nvkm_engine
*engine
)
88 const u32 offset
= gf100_fifo_gpfifo_engine_addr(engine
);
89 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
90 struct nvkm_gpuobj
*inst
= chan
->base
.inst
;
93 u64 addr
= chan
->engn
[engine
->subdev
.index
].vma
.offset
;
95 nvkm_wo32(inst
, offset
+ 0x00, lower_32_bits(addr
) | 4);
96 nvkm_wo32(inst
, offset
+ 0x04, upper_32_bits(addr
));
104 gf100_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan
*base
,
105 struct nvkm_engine
*engine
)
107 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
108 nvkm_gpuobj_unmap(&chan
->engn
[engine
->subdev
.index
].vma
);
109 nvkm_gpuobj_del(&chan
->engn
[engine
->subdev
.index
].inst
);
113 gf100_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan
*base
,
114 struct nvkm_engine
*engine
,
115 struct nvkm_object
*object
)
117 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
118 int engn
= engine
->subdev
.index
;
121 if (!gf100_fifo_gpfifo_engine_addr(engine
))
124 ret
= nvkm_object_bind(object
, NULL
, 0, &chan
->engn
[engn
].inst
);
128 return nvkm_gpuobj_map(chan
->engn
[engn
].inst
, chan
->vm
,
129 NV_MEM_ACCESS_RW
, &chan
->engn
[engn
].vma
);
133 gf100_fifo_gpfifo_fini(struct nvkm_fifo_chan
*base
)
135 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
136 struct gf100_fifo
*fifo
= chan
->fifo
;
137 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
138 u32 coff
= chan
->base
.chid
* 8;
140 if (!list_empty(&chan
->head
) && !chan
->killed
) {
141 list_del_init(&chan
->head
);
142 nvkm_mask(device
, 0x003004 + coff
, 0x00000001, 0x00000000);
143 gf100_fifo_runlist_update(fifo
);
146 gf100_fifo_intr_engine(fifo
);
148 nvkm_wr32(device
, 0x003000 + coff
, 0x00000000);
152 gf100_fifo_gpfifo_init(struct nvkm_fifo_chan
*base
)
154 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
155 struct gf100_fifo
*fifo
= chan
->fifo
;
156 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
157 u32 addr
= chan
->base
.inst
->addr
>> 12;
158 u32 coff
= chan
->base
.chid
* 8;
160 nvkm_wr32(device
, 0x003000 + coff
, 0xc0000000 | addr
);
162 if (list_empty(&chan
->head
) && !chan
->killed
) {
163 list_add_tail(&chan
->head
, &fifo
->chan
);
164 nvkm_wr32(device
, 0x003004 + coff
, 0x001f0001);
165 gf100_fifo_runlist_update(fifo
);
170 gf100_fifo_gpfifo_dtor(struct nvkm_fifo_chan
*base
)
172 struct gf100_fifo_chan
*chan
= gf100_fifo_chan(base
);
173 nvkm_vm_ref(NULL
, &chan
->vm
, chan
->pgd
);
174 nvkm_gpuobj_del(&chan
->pgd
);
178 static const struct nvkm_fifo_chan_func
179 gf100_fifo_gpfifo_func
= {
180 .dtor
= gf100_fifo_gpfifo_dtor
,
181 .init
= gf100_fifo_gpfifo_init
,
182 .fini
= gf100_fifo_gpfifo_fini
,
183 .ntfy
= g84_fifo_chan_ntfy
,
184 .engine_ctor
= gf100_fifo_gpfifo_engine_ctor
,
185 .engine_dtor
= gf100_fifo_gpfifo_engine_dtor
,
186 .engine_init
= gf100_fifo_gpfifo_engine_init
,
187 .engine_fini
= gf100_fifo_gpfifo_engine_fini
,
191 gf100_fifo_gpfifo_new(struct nvkm_fifo
*base
, const struct nvkm_oclass
*oclass
,
192 void *data
, u32 size
, struct nvkm_object
**pobject
)
195 struct fermi_channel_gpfifo_v0 v0
;
197 struct gf100_fifo
*fifo
= gf100_fifo(base
);
198 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
199 struct nvkm_object
*parent
= oclass
->parent
;
200 struct gf100_fifo_chan
*chan
;
201 u64 usermem
, ioffset
, ilength
;
204 nvif_ioctl(parent
, "create channel gpfifo size %d\n", size
);
205 if (nvif_unpack(args
->v0
, 0, 0, false)) {
206 nvif_ioctl(parent
, "create channel gpfifo vers %d vm %llx "
207 "ioffset %016llx ilength %08x\n",
208 args
->v0
.version
, args
->v0
.vm
, args
->v0
.ioffset
,
213 /* allocate channel */
214 if (!(chan
= kzalloc(sizeof(*chan
), GFP_KERNEL
)))
216 *pobject
= &chan
->base
.object
;
218 INIT_LIST_HEAD(&chan
->head
);
220 ret
= nvkm_fifo_chan_ctor(&gf100_fifo_gpfifo_func
, &fifo
->base
,
221 0x1000, 0x1000, true, args
->v0
.vm
, 0,
222 (1ULL << NVKM_ENGINE_CE0
) |
223 (1ULL << NVKM_ENGINE_CE1
) |
224 (1ULL << NVKM_ENGINE_GR
) |
225 (1ULL << NVKM_ENGINE_MSPDEC
) |
226 (1ULL << NVKM_ENGINE_MSPPP
) |
227 (1ULL << NVKM_ENGINE_MSVLD
) |
228 (1ULL << NVKM_ENGINE_SW
),
229 1, fifo
->user
.bar
.offset
, 0x1000,
230 oclass
, &chan
->base
);
234 args
->v0
.chid
= chan
->base
.chid
;
237 ret
= nvkm_gpuobj_new(device
, 0x10000, 0x1000, false, NULL
, &chan
->pgd
);
241 nvkm_kmap(chan
->base
.inst
);
242 nvkm_wo32(chan
->base
.inst
, 0x0200, lower_32_bits(chan
->pgd
->addr
));
243 nvkm_wo32(chan
->base
.inst
, 0x0204, upper_32_bits(chan
->pgd
->addr
));
244 nvkm_wo32(chan
->base
.inst
, 0x0208, 0xffffffff);
245 nvkm_wo32(chan
->base
.inst
, 0x020c, 0x000000ff);
246 nvkm_done(chan
->base
.inst
);
248 ret
= nvkm_vm_ref(chan
->base
.vm
, &chan
->vm
, chan
->pgd
);
252 /* clear channel control registers */
254 usermem
= chan
->base
.chid
* 0x1000;
255 ioffset
= args
->v0
.ioffset
;
256 ilength
= order_base_2(args
->v0
.ilength
/ 8);
258 nvkm_kmap(fifo
->user
.mem
);
259 for (i
= 0; i
< 0x1000; i
+= 4)
260 nvkm_wo32(fifo
->user
.mem
, usermem
+ i
, 0x00000000);
261 nvkm_done(fifo
->user
.mem
);
262 usermem
= nvkm_memory_addr(fifo
->user
.mem
) + usermem
;
265 nvkm_kmap(chan
->base
.inst
);
266 nvkm_wo32(chan
->base
.inst
, 0x08, lower_32_bits(usermem
));
267 nvkm_wo32(chan
->base
.inst
, 0x0c, upper_32_bits(usermem
));
268 nvkm_wo32(chan
->base
.inst
, 0x10, 0x0000face);
269 nvkm_wo32(chan
->base
.inst
, 0x30, 0xfffff902);
270 nvkm_wo32(chan
->base
.inst
, 0x48, lower_32_bits(ioffset
));
271 nvkm_wo32(chan
->base
.inst
, 0x4c, upper_32_bits(ioffset
) |
273 nvkm_wo32(chan
->base
.inst
, 0x54, 0x00000002);
274 nvkm_wo32(chan
->base
.inst
, 0x84, 0x20400000);
275 nvkm_wo32(chan
->base
.inst
, 0x94, 0x30000001);
276 nvkm_wo32(chan
->base
.inst
, 0x9c, 0x00000100);
277 nvkm_wo32(chan
->base
.inst
, 0xa4, 0x1f1f1f1f);
278 nvkm_wo32(chan
->base
.inst
, 0xa8, 0x1f1f1f1f);
279 nvkm_wo32(chan
->base
.inst
, 0xac, 0x0000001f);
280 nvkm_wo32(chan
->base
.inst
, 0xb8, 0xf8000000);
281 nvkm_wo32(chan
->base
.inst
, 0xf8, 0x10003080); /* 0x002310 */
282 nvkm_wo32(chan
->base
.inst
, 0xfc, 0x10000010); /* 0x002350 */
283 nvkm_done(chan
->base
.inst
);
287 const struct nvkm_fifo_chan_oclass
288 gf100_fifo_gpfifo_oclass
= {
289 .base
.oclass
= FERMI_CHANNEL_GPFIFO
,
292 .ctor
= gf100_fifo_gpfifo_new
,