aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c146
1 files changed, 101 insertions, 45 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
index 723dcbde2ac2..57719f675eec 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
@@ -26,6 +26,7 @@
26 26
27#include <core/client.h> 27#include <core/client.h>
28#include <core/notify.h> 28#include <core/notify.h>
29#include <core/oproxy.h>
29#include <core/ramht.h> 30#include <core/ramht.h>
30#include <engine/dma.h> 31#include <engine/dma.h>
31 32
@@ -65,7 +66,7 @@ nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c,
65void 66void
66nv50_disp_chan_mthd(struct nv50_disp_chan *chan, int debug) 67nv50_disp_chan_mthd(struct nv50_disp_chan *chan, int debug)
67{ 68{
68 struct nv50_disp *disp = chan->root->disp; 69 struct nv50_disp *disp = chan->disp;
69 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 70 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
70 const struct nv50_disp_chan_mthd *mthd = chan->mthd; 71 const struct nv50_disp_chan_mthd *mthd = chan->mthd;
71 const struct nv50_disp_mthd_list *list; 72 const struct nv50_disp_mthd_list *list;
@@ -154,13 +155,29 @@ nv50_disp_chan_uevent = {
154 .fini = nv50_disp_chan_uevent_fini, 155 .fini = nv50_disp_chan_uevent_fini,
155}; 156};
156 157
158u64
159nv50_disp_chan_user(struct nv50_disp_chan *chan, u64 *psize)
160{
161 *psize = 0x1000;
162 return 0x640000 + (chan->chid.user * 0x1000);
163}
164
165void
166nv50_disp_chan_intr(struct nv50_disp_chan *chan, bool en)
167{
168 struct nvkm_device *device = chan->disp->base.engine.subdev.device;
169 const u64 mask = 0x00010001 << chan->chid.user;
170 const u64 data = en ? 0x00010000 : 0x00000000;
171 nvkm_mask(device, 0x610028, mask, data);
172}
173
157static int 174static int
158nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data) 175nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data)
159{ 176{
160 struct nv50_disp_chan *chan = nv50_disp_chan(object); 177 struct nv50_disp_chan *chan = nv50_disp_chan(object);
161 struct nv50_disp *disp = chan->root->disp; 178 struct nvkm_device *device = chan->disp->base.engine.subdev.device;
162 struct nvkm_device *device = disp->base.engine.subdev.device; 179 u64 size, base = chan->func->user(chan, &size);
163 *data = nvkm_rd32(device, 0x640000 + (chan->chid.user * 0x1000) + addr); 180 *data = nvkm_rd32(device, base + addr);
164 return 0; 181 return 0;
165} 182}
166 183
@@ -168,9 +185,9 @@ static int
168nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) 185nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data)
169{ 186{
170 struct nv50_disp_chan *chan = nv50_disp_chan(object); 187 struct nv50_disp_chan *chan = nv50_disp_chan(object);
171 struct nv50_disp *disp = chan->root->disp; 188 struct nvkm_device *device = chan->disp->base.engine.subdev.device;
172 struct nvkm_device *device = disp->base.engine.subdev.device; 189 u64 size, base = chan->func->user(chan, &size);
173 nvkm_wr32(device, 0x640000 + (chan->chid.user * 0x1000) + addr, data); 190 nvkm_wr32(device, base + addr, data);
174 return 0; 191 return 0;
175} 192}
176 193
@@ -179,7 +196,7 @@ nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type,
179 struct nvkm_event **pevent) 196 struct nvkm_event **pevent)
180{ 197{
181 struct nv50_disp_chan *chan = nv50_disp_chan(object); 198 struct nv50_disp_chan *chan = nv50_disp_chan(object);
182 struct nv50_disp *disp = chan->root->disp; 199 struct nv50_disp *disp = chan->disp;
183 switch (type) { 200 switch (type) {
184 case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: 201 case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
185 *pevent = &disp->uevent; 202 *pevent = &disp->uevent;
@@ -195,34 +212,83 @@ nv50_disp_chan_map(struct nvkm_object *object, void *argv, u32 argc,
195 enum nvkm_object_map *type, u64 *addr, u64 *size) 212 enum nvkm_object_map *type, u64 *addr, u64 *size)
196{ 213{
197 struct nv50_disp_chan *chan = nv50_disp_chan(object); 214 struct nv50_disp_chan *chan = nv50_disp_chan(object);
198 struct nv50_disp *disp = chan->root->disp; 215 struct nvkm_device *device = chan->disp->base.engine.subdev.device;
199 struct nvkm_device *device = disp->base.engine.subdev.device; 216 const u64 base = device->func->resource_addr(device, 0);
200 *type = NVKM_OBJECT_MAP_IO; 217 *type = NVKM_OBJECT_MAP_IO;
201 *addr = device->func->resource_addr(device, 0) + 218 *addr = base + chan->func->user(chan, size);
202 0x640000 + (chan->chid.user * 0x1000);
203 *size = 0x001000;
204 return 0; 219 return 0;
205} 220}
206 221
222struct nv50_disp_chan_object {
223 struct nvkm_oproxy oproxy;
224 struct nv50_disp *disp;
225 int hash;
226};
227
228static void
229nv50_disp_chan_child_del_(struct nvkm_oproxy *base)
230{
231 struct nv50_disp_chan_object *object =
232 container_of(base, typeof(*object), oproxy);
233 nvkm_ramht_remove(object->disp->ramht, object->hash);
234}
235
236static const struct nvkm_oproxy_func
237nv50_disp_chan_child_func_ = {
238 .dtor[0] = nv50_disp_chan_child_del_,
239};
240
207static int 241static int
208nv50_disp_chan_child_new(const struct nvkm_oclass *oclass, 242nv50_disp_chan_child_new(const struct nvkm_oclass *oclass,
209 void *data, u32 size, struct nvkm_object **pobject) 243 void *argv, u32 argc, struct nvkm_object **pobject)
210{ 244{
211 struct nv50_disp_chan *chan = nv50_disp_chan(oclass->parent); 245 struct nv50_disp_chan *chan = nv50_disp_chan(oclass->parent);
212 return chan->func->child_new(chan, oclass, data, size, pobject); 246 struct nv50_disp *disp = chan->disp;
247 struct nvkm_device *device = disp->base.engine.subdev.device;
248 const struct nvkm_device_oclass *sclass = oclass->priv;
249 struct nv50_disp_chan_object *object;
250 int ret;
251
252 if (!(object = kzalloc(sizeof(*object), GFP_KERNEL)))
253 return -ENOMEM;
254 nvkm_oproxy_ctor(&nv50_disp_chan_child_func_, oclass, &object->oproxy);
255 object->disp = disp;
256 *pobject = &object->oproxy.base;
257
258 ret = sclass->ctor(device, oclass, argv, argc, &object->oproxy.object);
259 if (ret)
260 return ret;
261
262 object->hash = chan->func->bind(chan, object->oproxy.object,
263 oclass->handle);
264 if (object->hash < 0)
265 return object->hash;
266
267 return 0;
213} 268}
214 269
215static int 270static int
216nv50_disp_chan_child_get(struct nvkm_object *object, int index, 271nv50_disp_chan_child_get(struct nvkm_object *object, int index,
217 struct nvkm_oclass *oclass) 272 struct nvkm_oclass *sclass)
218{ 273{
219 struct nv50_disp_chan *chan = nv50_disp_chan(object); 274 struct nv50_disp_chan *chan = nv50_disp_chan(object);
220 if (chan->func->child_get) { 275 struct nvkm_device *device = chan->disp->base.engine.subdev.device;
221 int ret = chan->func->child_get(chan, index, oclass); 276 const struct nvkm_device_oclass *oclass = NULL;
222 if (ret == 0) 277
223 oclass->ctor = nv50_disp_chan_child_new; 278 if (chan->func->bind)
224 return ret; 279 sclass->engine = nvkm_device_engine(device, NVKM_ENGINE_DMAOBJ);
280 else
281 sclass->engine = NULL;
282
283 if (sclass->engine && sclass->engine->func->base.sclass) {
284 sclass->engine->func->base.sclass(sclass, index, &oclass);
285 if (oclass) {
286 sclass->ctor = nv50_disp_chan_child_new,
287 sclass->priv = oclass;
288 return 0;
289 }
225 } 290 }
291
226 return -EINVAL; 292 return -EINVAL;
227} 293}
228 294
@@ -231,6 +297,7 @@ nv50_disp_chan_fini(struct nvkm_object *object, bool suspend)
231{ 297{
232 struct nv50_disp_chan *chan = nv50_disp_chan(object); 298 struct nv50_disp_chan *chan = nv50_disp_chan(object);
233 chan->func->fini(chan); 299 chan->func->fini(chan);
300 chan->func->intr(chan, false);
234 return 0; 301 return 0;
235} 302}
236 303
@@ -238,6 +305,7 @@ static int
238nv50_disp_chan_init(struct nvkm_object *object) 305nv50_disp_chan_init(struct nvkm_object *object)
239{ 306{
240 struct nv50_disp_chan *chan = nv50_disp_chan(object); 307 struct nv50_disp_chan *chan = nv50_disp_chan(object);
308 chan->func->intr(chan, true);
241 return chan->func->init(chan); 309 return chan->func->init(chan);
242} 310}
243 311
@@ -245,10 +313,11 @@ static void *
245nv50_disp_chan_dtor(struct nvkm_object *object) 313nv50_disp_chan_dtor(struct nvkm_object *object)
246{ 314{
247 struct nv50_disp_chan *chan = nv50_disp_chan(object); 315 struct nv50_disp_chan *chan = nv50_disp_chan(object);
248 struct nv50_disp *disp = chan->root->disp; 316 struct nv50_disp *disp = chan->disp;
249 if (chan->chid.user >= 0) 317 if (chan->chid.user >= 0)
250 disp->chan[chan->chid.user] = NULL; 318 disp->chan[chan->chid.user] = NULL;
251 return chan->func->dtor ? chan->func->dtor(chan) : chan; 319 nvkm_memory_unref(&chan->memory);
320 return chan;
252} 321}
253 322
254static const struct nvkm_object_func 323static const struct nvkm_object_func
@@ -264,18 +333,22 @@ nv50_disp_chan = {
264}; 333};
265 334
266int 335int
267nv50_disp_chan_ctor(const struct nv50_disp_chan_func *func, 336nv50_disp_chan_new_(const struct nv50_disp_chan_func *func,
268 const struct nv50_disp_chan_mthd *mthd, 337 const struct nv50_disp_chan_mthd *mthd,
269 struct nv50_disp_root *root, int ctrl, int user, int head, 338 struct nv50_disp *disp, int ctrl, int user, int head,
270 const struct nvkm_oclass *oclass, 339 const struct nvkm_oclass *oclass,
271 struct nv50_disp_chan *chan) 340 struct nvkm_object **pobject)
272{ 341{
273 struct nv50_disp *disp = root->disp; 342 struct nv50_disp_chan *chan;
343
344 if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
345 return -ENOMEM;
346 *pobject = &chan->object;
274 347
275 nvkm_object_ctor(&nv50_disp_chan, oclass, &chan->object); 348 nvkm_object_ctor(&nv50_disp_chan, oclass, &chan->object);
276 chan->func = func; 349 chan->func = func;
277 chan->mthd = mthd; 350 chan->mthd = mthd;
278 chan->root = root; 351 chan->disp = disp;
279 chan->chid.ctrl = ctrl; 352 chan->chid.ctrl = ctrl;
280 chan->chid.user = user; 353 chan->chid.user = user;
281 chan->head = head; 354 chan->head = head;
@@ -287,20 +360,3 @@ nv50_disp_chan_ctor(const struct nv50_disp_chan_func *func,
287 disp->chan[chan->chid.user] = chan; 360 disp->chan[chan->chid.user] = chan;
288 return 0; 361 return 0;
289} 362}
290
291int
292nv50_disp_chan_new_(const struct nv50_disp_chan_func *func,
293 const struct nv50_disp_chan_mthd *mthd,
294 struct nv50_disp_root *root, int ctrl, int user, int head,
295 const struct nvkm_oclass *oclass,
296 struct nvkm_object **pobject)
297{
298 struct nv50_disp_chan *chan;
299
300 if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
301 return -ENOMEM;
302 *pobject = &chan->object;
303
304 return nv50_disp_chan_ctor(func, mthd, root, ctrl, user,
305 head, oclass, chan);
306}