Commit | Line | Data |
---|---|---|
5fa75430 IM |
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 | */ | |
7624fc01 | 24 | #define nv44_mpeg(p) container_of((p), struct nv44_mpeg, engine) |
218f978d | 25 | #include "priv.h" |
5fa75430 | 26 | |
5fa75430 | 27 | #include <core/client.h> |
13de7f46 | 28 | #include <core/gpuobj.h> |
5fa75430 | 29 | #include <engine/fifo.h> |
5fa75430 | 30 | |
218f978d BS |
31 | #include <nvif/class.h> |
32 | ||
590801c1 | 33 | struct nv44_mpeg { |
7624fc01 | 34 | struct nvkm_engine engine; |
590801c1 BS |
35 | struct list_head chan; |
36 | }; | |
37 | ||
218f978d BS |
38 | /******************************************************************************* |
39 | * PMPEG context | |
40 | ******************************************************************************/ | |
41 | #define nv44_mpeg_chan(p) container_of((p), struct nv44_mpeg_chan, object) | |
42 | ||
5fa75430 | 43 | struct nv44_mpeg_chan { |
218f978d BS |
44 | struct nvkm_object object; |
45 | struct nv44_mpeg *mpeg; | |
590801c1 | 46 | struct nvkm_fifo_chan *fifo; |
590801c1 | 47 | struct list_head head; |
218f978d | 48 | u32 inst; |
5fa75430 IM |
49 | }; |
50 | ||
218f978d BS |
51 | static int |
52 | nv44_mpeg_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, | |
53 | int align, struct nvkm_gpuobj **pgpuobj) | |
54 | { | |
55 | struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); | |
56 | int ret = nvkm_gpuobj_new(chan->object.engine->subdev.device, 264 * 4, | |
57 | align, true, parent, pgpuobj); | |
58 | if (ret == 0) { | |
59 | chan->inst = (*pgpuobj)->addr; | |
60 | nvkm_kmap(*pgpuobj); | |
61 | nvkm_wo32(*pgpuobj, 0x78, 0x02001ec1); | |
62 | nvkm_done(*pgpuobj); | |
63 | } | |
64 | return ret; | |
65 | } | |
590801c1 | 66 | |
218f978d BS |
67 | static int |
68 | nv44_mpeg_chan_fini(struct nvkm_object *object, bool suspend) | |
69 | { | |
5fa75430 | 70 | |
218f978d BS |
71 | struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); |
72 | struct nv44_mpeg *mpeg = chan->mpeg; | |
7624fc01 | 73 | struct nvkm_device *device = mpeg->engine.subdev.device; |
218f978d BS |
74 | u32 inst = 0x80000000 | (chan->inst >> 4); |
75 | ||
76 | nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000000); | |
77 | if (nvkm_rd32(device, 0x00b318) == inst) | |
78 | nvkm_mask(device, 0x00b318, 0x80000000, 0x00000000); | |
79 | nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); | |
80 | return 0; | |
81 | } | |
82 | ||
83 | static void * | |
84 | nv44_mpeg_chan_dtor(struct nvkm_object *object) | |
590801c1 | 85 | { |
218f978d BS |
86 | struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); |
87 | struct nv44_mpeg *mpeg = chan->mpeg; | |
590801c1 | 88 | unsigned long flags; |
7624fc01 | 89 | spin_lock_irqsave(&mpeg->engine.lock, flags); |
590801c1 | 90 | list_del(&chan->head); |
7624fc01 | 91 | spin_unlock_irqrestore(&mpeg->engine.lock, flags); |
218f978d | 92 | return chan; |
590801c1 BS |
93 | } |
94 | ||
218f978d BS |
95 | static const struct nvkm_object_func |
96 | nv44_mpeg_chan = { | |
97 | .dtor = nv44_mpeg_chan_dtor, | |
98 | .fini = nv44_mpeg_chan_fini, | |
99 | .bind = nv44_mpeg_chan_bind, | |
100 | }; | |
101 | ||
5fa75430 | 102 | static int |
218f978d BS |
103 | nv44_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, |
104 | const struct nvkm_oclass *oclass, | |
105 | struct nvkm_object **pobject) | |
5fa75430 | 106 | { |
218f978d | 107 | struct nv44_mpeg *mpeg = nv44_mpeg(oclass->engine); |
5fa75430 | 108 | struct nv44_mpeg_chan *chan; |
590801c1 | 109 | unsigned long flags; |
5fa75430 | 110 | |
218f978d BS |
111 | if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) |
112 | return -ENOMEM; | |
113 | nvkm_object_ctor(&nv44_mpeg_chan, oclass, &chan->object); | |
114 | chan->mpeg = mpeg; | |
115 | chan->fifo = fifoch; | |
116 | *pobject = &chan->object; | |
5fa75430 | 117 | |
7624fc01 | 118 | spin_lock_irqsave(&mpeg->engine.lock, flags); |
590801c1 | 119 | list_add(&chan->head, &mpeg->chan); |
7624fc01 | 120 | spin_unlock_irqrestore(&mpeg->engine.lock, flags); |
5fa75430 IM |
121 | return 0; |
122 | } | |
123 | ||
5fa75430 IM |
124 | /******************************************************************************* |
125 | * PMPEG engine/subdev functions | |
126 | ******************************************************************************/ | |
127 | ||
590801c1 BS |
128 | static bool |
129 | nv44_mpeg_mthd(struct nvkm_device *device, u32 mthd, u32 data) | |
130 | { | |
131 | switch (mthd) { | |
132 | case 0x190: | |
133 | case 0x1a0: | |
134 | case 0x1b0: | |
135 | return nv40_mpeg_mthd_dma(device, mthd, data); | |
136 | default: | |
137 | break; | |
138 | } | |
139 | return false; | |
140 | } | |
141 | ||
5fa75430 | 142 | static void |
7624fc01 | 143 | nv44_mpeg_intr(struct nvkm_engine *engine) |
5fa75430 | 144 | { |
7624fc01 BS |
145 | struct nv44_mpeg *mpeg = nv44_mpeg(engine); |
146 | struct nvkm_subdev *subdev = &mpeg->engine.subdev; | |
147 | struct nvkm_device *device = subdev->device; | |
590801c1 | 148 | struct nv44_mpeg_chan *temp, *chan = NULL; |
590801c1 | 149 | unsigned long flags; |
636e37aa BS |
150 | u32 inst = nvkm_rd32(device, 0x00b318) & 0x000fffff; |
151 | u32 stat = nvkm_rd32(device, 0x00b100); | |
152 | u32 type = nvkm_rd32(device, 0x00b230); | |
153 | u32 mthd = nvkm_rd32(device, 0x00b234); | |
154 | u32 data = nvkm_rd32(device, 0x00b238); | |
5fa75430 | 155 | u32 show = stat; |
590801c1 | 156 | |
7624fc01 | 157 | spin_lock_irqsave(&mpeg->engine.lock, flags); |
590801c1 BS |
158 | list_for_each_entry(temp, &mpeg->chan, head) { |
159 | if (temp->inst >> 4 == inst) { | |
160 | chan = temp; | |
590801c1 BS |
161 | list_del(&chan->head); |
162 | list_add(&chan->head, &mpeg->chan); | |
163 | break; | |
164 | } | |
165 | } | |
5fa75430 IM |
166 | |
167 | if (stat & 0x01000000) { | |
168 | /* happens on initial binding of the object */ | |
169 | if (type == 0x00000020 && mthd == 0x0000) { | |
636e37aa | 170 | nvkm_mask(device, 0x00b308, 0x00000000, 0x00000000); |
5fa75430 IM |
171 | show &= ~0x01000000; |
172 | } | |
173 | ||
174 | if (type == 0x00000010) { | |
590801c1 | 175 | if (!nv44_mpeg_mthd(subdev->device, mthd, data)) |
5fa75430 | 176 | show &= ~0x01000000; |
5fa75430 IM |
177 | } |
178 | } | |
179 | ||
636e37aa BS |
180 | nvkm_wr32(device, 0x00b100, stat); |
181 | nvkm_wr32(device, 0x00b230, 0x00000001); | |
5fa75430 IM |
182 | |
183 | if (show) { | |
590801c1 | 184 | nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n", |
8f0649b5 | 185 | chan ? chan->fifo->chid : -1, inst << 4, |
218f978d | 186 | chan ? chan->object.client->name : "unknown", |
590801c1 | 187 | stat, type, mthd, data); |
5fa75430 IM |
188 | } |
189 | ||
7624fc01 | 190 | spin_unlock_irqrestore(&mpeg->engine.lock, flags); |
5fa75430 IM |
191 | } |
192 | ||
218f978d BS |
193 | static const struct nvkm_engine_func |
194 | nv44_mpeg = { | |
7624fc01 BS |
195 | .init = nv31_mpeg_init, |
196 | .intr = nv44_mpeg_intr, | |
197 | .tile = nv31_mpeg_tile, | |
218f978d BS |
198 | .fifo.cclass = nv44_mpeg_chan_new, |
199 | .sclass = { | |
200 | { -1, -1, NV31_MPEG, &nv31_mpeg_object }, | |
201 | {} | |
202 | } | |
203 | }; | |
204 | ||
7624fc01 BS |
205 | int |
206 | nv44_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) | |
5fa75430 | 207 | { |
590801c1 | 208 | struct nv44_mpeg *mpeg; |
5fa75430 | 209 | |
7624fc01 BS |
210 | if (!(mpeg = kzalloc(sizeof(*mpeg), GFP_KERNEL))) |
211 | return -ENOMEM; | |
590801c1 | 212 | INIT_LIST_HEAD(&mpeg->chan); |
7624fc01 | 213 | *pmpeg = &mpeg->engine; |
590801c1 | 214 | |
56d06fa2 | 215 | return nvkm_engine_ctor(&nv44_mpeg, device, index, true, &mpeg->engine); |
5fa75430 | 216 | } |