]>
Commit | Line | Data |
---|---|---|
a02ccc7f | 1 | /* |
ebb945a9 | 2 | * Copyright 2012 Red Hat Inc. |
a02ccc7f BS |
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 | */ | |
e7c29683 | 24 | #include "nv31.h" |
a02ccc7f | 25 | |
93260d3c | 26 | #include <core/client.h> |
13de7f46 | 27 | #include <core/gpuobj.h> |
ebb945a9 BS |
28 | #include <subdev/fb.h> |
29 | #include <subdev/timer.h> | |
218f978d BS |
30 | #include <engine/fifo.h> |
31 | ||
32 | #include <nvif/class.h> | |
a02ccc7f | 33 | |
ebb945a9 BS |
34 | /******************************************************************************* |
35 | * MPEG object classes | |
36 | ******************************************************************************/ | |
a02ccc7f BS |
37 | |
38 | static int | |
218f978d BS |
39 | nv31_mpeg_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, |
40 | int align, struct nvkm_gpuobj **pgpuobj) | |
a02ccc7f | 41 | { |
218f978d BS |
42 | int ret = nvkm_gpuobj_new(object->engine->subdev.device, 16, align, |
43 | false, parent, pgpuobj); | |
44 | if (ret == 0) { | |
45 | nvkm_kmap(*pgpuobj); | |
68f3f702 | 46 | nvkm_wo32(*pgpuobj, 0x00, object->oclass); |
218f978d BS |
47 | nvkm_wo32(*pgpuobj, 0x04, 0x00000000); |
48 | nvkm_wo32(*pgpuobj, 0x08, 0x00000000); | |
49 | nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); | |
50 | nvkm_done(*pgpuobj); | |
51 | } | |
52 | return ret; | |
53 | } | |
a02ccc7f | 54 | |
218f978d BS |
55 | const struct nvkm_object_func |
56 | nv31_mpeg_object = { | |
57 | .bind = nv31_mpeg_object_bind, | |
58 | }; | |
a02ccc7f | 59 | |
218f978d BS |
60 | /******************************************************************************* |
61 | * PMPEG context | |
62 | ******************************************************************************/ | |
63 | ||
64 | static void * | |
65 | nv31_mpeg_chan_dtor(struct nvkm_object *object) | |
66 | { | |
67 | struct nv31_mpeg_chan *chan = nv31_mpeg_chan(object); | |
68 | struct nv31_mpeg *mpeg = chan->mpeg; | |
69 | unsigned long flags; | |
70 | ||
7624fc01 | 71 | spin_lock_irqsave(&mpeg->engine.lock, flags); |
218f978d BS |
72 | if (mpeg->chan == chan) |
73 | mpeg->chan = NULL; | |
7624fc01 | 74 | spin_unlock_irqrestore(&mpeg->engine.lock, flags); |
218f978d BS |
75 | return chan; |
76 | } | |
77 | ||
78 | static const struct nvkm_object_func | |
79 | nv31_mpeg_chan = { | |
80 | .dtor = nv31_mpeg_chan_dtor, | |
81 | }; | |
82 | ||
83 | int | |
84 | nv31_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, | |
85 | const struct nvkm_oclass *oclass, | |
86 | struct nvkm_object **pobject) | |
87 | { | |
88 | struct nv31_mpeg *mpeg = nv31_mpeg(oclass->engine); | |
89 | struct nv31_mpeg_chan *chan; | |
90 | unsigned long flags; | |
91 | int ret = -EBUSY; | |
92 | ||
93 | if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) | |
94 | return -ENOMEM; | |
95 | nvkm_object_ctor(&nv31_mpeg_chan, oclass, &chan->object); | |
96 | chan->mpeg = mpeg; | |
97 | chan->fifo = fifoch; | |
98 | *pobject = &chan->object; | |
99 | ||
7624fc01 | 100 | spin_lock_irqsave(&mpeg->engine.lock, flags); |
218f978d BS |
101 | if (!mpeg->chan) { |
102 | mpeg->chan = chan; | |
103 | ret = 0; | |
104 | } | |
7624fc01 | 105 | spin_unlock_irqrestore(&mpeg->engine.lock, flags); |
218f978d BS |
106 | return ret; |
107 | } | |
108 | ||
109 | /******************************************************************************* | |
110 | * PMPEG engine/subdev functions | |
111 | ******************************************************************************/ | |
112 | ||
113 | void | |
7624fc01 | 114 | nv31_mpeg_tile(struct nvkm_engine *engine, int i, struct nvkm_fb_tile *tile) |
218f978d | 115 | { |
7624fc01 BS |
116 | struct nv31_mpeg *mpeg = nv31_mpeg(engine); |
117 | struct nvkm_device *device = mpeg->engine.subdev.device; | |
218f978d BS |
118 | |
119 | nvkm_wr32(device, 0x00b008 + (i * 0x10), tile->pitch); | |
120 | nvkm_wr32(device, 0x00b004 + (i * 0x10), tile->limit); | |
121 | nvkm_wr32(device, 0x00b000 + (i * 0x10), tile->addr); | |
a02ccc7f BS |
122 | } |
123 | ||
590801c1 BS |
124 | static bool |
125 | nv31_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) | |
a02ccc7f | 126 | { |
590801c1 BS |
127 | u32 inst = data << 4; |
128 | u32 dma0 = nvkm_rd32(device, 0x700000 + inst); | |
129 | u32 dma1 = nvkm_rd32(device, 0x700004 + inst); | |
130 | u32 dma2 = nvkm_rd32(device, 0x700008 + inst); | |
a02ccc7f BS |
131 | u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); |
132 | u32 size = dma1 + 1; | |
133 | ||
134 | /* only allow linear DMA objects */ | |
135 | if (!(dma0 & 0x00002000)) | |
590801c1 | 136 | return false; |
a02ccc7f BS |
137 | |
138 | if (mthd == 0x0190) { | |
139 | /* DMA_CMD */ | |
590801c1 BS |
140 | nvkm_mask(device, 0x00b300, 0x00010000, |
141 | (dma0 & 0x00030000) ? 0x00010000 : 0); | |
636e37aa BS |
142 | nvkm_wr32(device, 0x00b334, base); |
143 | nvkm_wr32(device, 0x00b324, size); | |
a02ccc7f BS |
144 | } else |
145 | if (mthd == 0x01a0) { | |
146 | /* DMA_DATA */ | |
590801c1 BS |
147 | nvkm_mask(device, 0x00b300, 0x00020000, |
148 | (dma0 & 0x00030000) ? 0x00020000 : 0); | |
636e37aa BS |
149 | nvkm_wr32(device, 0x00b360, base); |
150 | nvkm_wr32(device, 0x00b364, size); | |
a02ccc7f BS |
151 | } else { |
152 | /* DMA_IMAGE, VRAM only */ | |
be0dd4dd | 153 | if (dma0 & 0x00030000) |
590801c1 | 154 | return false; |
a02ccc7f | 155 | |
636e37aa BS |
156 | nvkm_wr32(device, 0x00b370, base); |
157 | nvkm_wr32(device, 0x00b374, size); | |
a02ccc7f BS |
158 | } |
159 | ||
590801c1 BS |
160 | return true; |
161 | } | |
162 | ||
163 | static bool | |
164 | nv31_mpeg_mthd(struct nv31_mpeg *mpeg, u32 mthd, u32 data) | |
165 | { | |
7624fc01 | 166 | struct nvkm_device *device = mpeg->engine.subdev.device; |
590801c1 BS |
167 | switch (mthd) { |
168 | case 0x190: | |
169 | case 0x1a0: | |
170 | case 0x1b0: | |
7624fc01 | 171 | return mpeg->func->mthd_dma(device, mthd, data); |
590801c1 BS |
172 | default: |
173 | break; | |
174 | } | |
175 | return false; | |
a02ccc7f BS |
176 | } |
177 | ||
7624fc01 BS |
178 | static void |
179 | nv31_mpeg_intr(struct nvkm_engine *engine) | |
ebb945a9 | 180 | { |
7624fc01 BS |
181 | struct nv31_mpeg *mpeg = nv31_mpeg(engine); |
182 | struct nvkm_subdev *subdev = &mpeg->engine.subdev; | |
183 | struct nvkm_device *device = subdev->device; | |
636e37aa BS |
184 | u32 stat = nvkm_rd32(device, 0x00b100); |
185 | u32 type = nvkm_rd32(device, 0x00b230); | |
186 | u32 mthd = nvkm_rd32(device, 0x00b234); | |
187 | u32 data = nvkm_rd32(device, 0x00b238); | |
a02ccc7f | 188 | u32 show = stat; |
ab403ac9 | 189 | unsigned long flags; |
72a14827 | 190 | |
7624fc01 | 191 | spin_lock_irqsave(&mpeg->engine.lock, flags); |
a02ccc7f BS |
192 | |
193 | if (stat & 0x01000000) { | |
194 | /* happens on initial binding of the object */ | |
72a14827 | 195 | if (type == 0x00000020 && mthd == 0x0000) { |
636e37aa | 196 | nvkm_mask(device, 0x00b308, 0x00000000, 0x00000000); |
a02ccc7f BS |
197 | show &= ~0x01000000; |
198 | } | |
199 | ||
590801c1 | 200 | if (type == 0x00000010) { |
a79a67de | 201 | if (nv31_mpeg_mthd(mpeg, mthd, data)) |
a02ccc7f BS |
202 | show &= ~0x01000000; |
203 | } | |
204 | } | |
205 | ||
636e37aa BS |
206 | nvkm_wr32(device, 0x00b100, stat); |
207 | nvkm_wr32(device, 0x00b230, 0x00000001); | |
a02ccc7f | 208 | |
ebb945a9 | 209 | if (show) { |
b835c09b | 210 | nvkm_error(subdev, "ch %d [%s] %08x %08x %08x %08x\n", |
590801c1 | 211 | mpeg->chan ? mpeg->chan->fifo->chid : -1, |
218f978d | 212 | mpeg->chan ? mpeg->chan->object.client->name : |
8f0649b5 | 213 | "unknown", stat, type, mthd, data); |
a02ccc7f | 214 | } |
72a14827 | 215 | |
7624fc01 | 216 | spin_unlock_irqrestore(&mpeg->engine.lock, flags); |
a02ccc7f BS |
217 | } |
218 | ||
ebb945a9 | 219 | int |
7624fc01 | 220 | nv31_mpeg_init(struct nvkm_engine *mpeg) |
a02ccc7f | 221 | { |
7624fc01 | 222 | struct nvkm_subdev *subdev = &mpeg->subdev; |
b835c09b | 223 | struct nvkm_device *device = subdev->device; |
a02ccc7f | 224 | |
ebb945a9 | 225 | /* VPE init */ |
636e37aa BS |
226 | nvkm_wr32(device, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ |
227 | nvkm_wr32(device, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ | |
a02ccc7f | 228 | |
ebb945a9 | 229 | /* PMPEG init */ |
636e37aa BS |
230 | nvkm_wr32(device, 0x00b32c, 0x00000000); |
231 | nvkm_wr32(device, 0x00b314, 0x00000100); | |
232 | nvkm_wr32(device, 0x00b220, 0x00000031); | |
233 | nvkm_wr32(device, 0x00b300, 0x02001ec1); | |
234 | nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); | |
ebb945a9 | 235 | |
636e37aa BS |
236 | nvkm_wr32(device, 0x00b100, 0xffffffff); |
237 | nvkm_wr32(device, 0x00b140, 0xffffffff); | |
ebb945a9 | 238 | |
37eabb03 BS |
239 | if (nvkm_msec(device, 2000, |
240 | if (!(nvkm_rd32(device, 0x00b200) & 0x00000001)) | |
241 | break; | |
242 | ) < 0) { | |
b835c09b BS |
243 | nvkm_error(subdev, "timeout %08x\n", |
244 | nvkm_rd32(device, 0x00b200)); | |
ebb945a9 | 245 | return -EBUSY; |
52d07331 | 246 | } |
a02ccc7f | 247 | |
ebb945a9 | 248 | return 0; |
a02ccc7f | 249 | } |
ebb945a9 | 250 | |
7624fc01 BS |
251 | static void * |
252 | nv31_mpeg_dtor(struct nvkm_engine *engine) | |
253 | { | |
254 | return nv31_mpeg(engine); | |
255 | } | |
256 | ||
257 | static const struct nvkm_engine_func | |
258 | nv31_mpeg_ = { | |
259 | .dtor = nv31_mpeg_dtor, | |
260 | .init = nv31_mpeg_init, | |
261 | .intr = nv31_mpeg_intr, | |
262 | .tile = nv31_mpeg_tile, | |
263 | .fifo.cclass = nv31_mpeg_chan_new, | |
264 | .sclass = { | |
265 | { -1, -1, NV31_MPEG, &nv31_mpeg_object }, | |
266 | {} | |
267 | } | |
ebb945a9 | 268 | }; |
7624fc01 BS |
269 | |
270 | int | |
271 | nv31_mpeg_new_(const struct nv31_mpeg_func *func, struct nvkm_device *device, | |
272 | int index, struct nvkm_engine **pmpeg) | |
273 | { | |
274 | struct nv31_mpeg *mpeg; | |
275 | ||
276 | if (!(mpeg = kzalloc(sizeof(*mpeg), GFP_KERNEL))) | |
277 | return -ENOMEM; | |
278 | mpeg->func = func; | |
279 | *pmpeg = &mpeg->engine; | |
280 | ||
56d06fa2 | 281 | return nvkm_engine_ctor(&nv31_mpeg_, device, index, |
7624fc01 BS |
282 | true, &mpeg->engine); |
283 | } | |
284 | ||
285 | static const struct nv31_mpeg_func | |
286 | nv31_mpeg = { | |
287 | .mthd_dma = nv31_mpeg_mthd_dma, | |
288 | }; | |
289 | ||
290 | int | |
291 | nv31_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) | |
292 | { | |
293 | return nv31_mpeg_new_(&nv31_mpeg, device, index, pmpeg); | |
294 | } |