xref: /linux/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c (revision a940daa52167e9db8ecce82213813b735a9d9f23)
1c39f472eSBen Skeggs /*
2c39f472eSBen Skeggs  * Copyright 2012 Red Hat Inc.
3c39f472eSBen Skeggs  *
4c39f472eSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5c39f472eSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6c39f472eSBen Skeggs  * to deal in the Software without restriction, including without limitation
7c39f472eSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c39f472eSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9c39f472eSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10c39f472eSBen Skeggs  *
11c39f472eSBen Skeggs  * The above copyright notice and this permission notice shall be included in
12c39f472eSBen Skeggs  * all copies or substantial portions of the Software.
13c39f472eSBen Skeggs  *
14c39f472eSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c39f472eSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c39f472eSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17c39f472eSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c39f472eSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c39f472eSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c39f472eSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21c39f472eSBen Skeggs  *
22c39f472eSBen Skeggs  * Authors: Ben Skeggs
23c39f472eSBen Skeggs  */
247624fc01SBen Skeggs #define nv44_mpeg(p) container_of((p), struct nv44_mpeg, engine)
25218f978dSBen Skeggs #include "priv.h"
26c39f472eSBen Skeggs 
27e7c29683SBen Skeggs #include <core/client.h>
2813de7f46SBen Skeggs #include <core/gpuobj.h>
29e7c29683SBen Skeggs #include <engine/fifo.h>
30e7c29683SBen Skeggs 
31218f978dSBen Skeggs #include <nvif/class.h>
32218f978dSBen Skeggs 
33590801c1SBen Skeggs struct nv44_mpeg {
347624fc01SBen Skeggs 	struct nvkm_engine engine;
35590801c1SBen Skeggs 	struct list_head chan;
36590801c1SBen Skeggs };
37590801c1SBen Skeggs 
38c39f472eSBen Skeggs /*******************************************************************************
39c39f472eSBen Skeggs  * PMPEG context
40c39f472eSBen Skeggs  ******************************************************************************/
41218f978dSBen Skeggs #define nv44_mpeg_chan(p) container_of((p), struct nv44_mpeg_chan, object)
42c39f472eSBen Skeggs 
43218f978dSBen Skeggs struct nv44_mpeg_chan {
44218f978dSBen Skeggs 	struct nvkm_object object;
45218f978dSBen Skeggs 	struct nv44_mpeg *mpeg;
46*c546656fSBen Skeggs 	struct nvkm_chan *fifo;
47218f978dSBen Skeggs 	struct list_head head;
48218f978dSBen Skeggs 	u32 inst;
49218f978dSBen Skeggs };
50590801c1SBen Skeggs 
51c39f472eSBen Skeggs static int
nv44_mpeg_chan_bind(struct nvkm_object * object,struct nvkm_gpuobj * parent,int align,struct nvkm_gpuobj ** pgpuobj)52218f978dSBen Skeggs nv44_mpeg_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent,
53218f978dSBen Skeggs 		    int align, struct nvkm_gpuobj **pgpuobj)
54c39f472eSBen Skeggs {
55218f978dSBen Skeggs 	struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object);
56218f978dSBen Skeggs 	int ret = nvkm_gpuobj_new(chan->object.engine->subdev.device, 264 * 4,
57218f978dSBen Skeggs 				  align, true, parent, pgpuobj);
58218f978dSBen Skeggs 	if (ret == 0) {
59218f978dSBen Skeggs 		chan->inst = (*pgpuobj)->addr;
60218f978dSBen Skeggs 		nvkm_kmap(*pgpuobj);
61218f978dSBen Skeggs 		nvkm_wo32(*pgpuobj, 0x78, 0x02001ec1);
62218f978dSBen Skeggs 		nvkm_done(*pgpuobj);
63218f978dSBen Skeggs 	}
64c39f472eSBen Skeggs 	return ret;
65c39f472eSBen Skeggs }
66c39f472eSBen Skeggs 
67c39f472eSBen Skeggs static int
nv44_mpeg_chan_fini(struct nvkm_object * object,bool suspend)68218f978dSBen Skeggs nv44_mpeg_chan_fini(struct nvkm_object *object, bool suspend)
69c39f472eSBen Skeggs {
70c39f472eSBen Skeggs 
71218f978dSBen Skeggs 	struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object);
72218f978dSBen Skeggs 	struct nv44_mpeg *mpeg = chan->mpeg;
737624fc01SBen Skeggs 	struct nvkm_device *device = mpeg->engine.subdev.device;
74218f978dSBen Skeggs 	u32 inst = 0x80000000 | (chan->inst >> 4);
75c39f472eSBen Skeggs 
76636e37aaSBen Skeggs 	nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000000);
77636e37aaSBen Skeggs 	if (nvkm_rd32(device, 0x00b318) == inst)
78636e37aaSBen Skeggs 		nvkm_mask(device, 0x00b318, 0x80000000, 0x00000000);
79636e37aaSBen Skeggs 	nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001);
80c39f472eSBen Skeggs 	return 0;
81c39f472eSBen Skeggs }
82c39f472eSBen Skeggs 
83218f978dSBen Skeggs static void *
nv44_mpeg_chan_dtor(struct nvkm_object * object)84218f978dSBen Skeggs nv44_mpeg_chan_dtor(struct nvkm_object *object)
85218f978dSBen Skeggs {
86218f978dSBen Skeggs 	struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object);
87218f978dSBen Skeggs 	struct nv44_mpeg *mpeg = chan->mpeg;
88218f978dSBen Skeggs 	unsigned long flags;
897624fc01SBen Skeggs 	spin_lock_irqsave(&mpeg->engine.lock, flags);
90218f978dSBen Skeggs 	list_del(&chan->head);
917624fc01SBen Skeggs 	spin_unlock_irqrestore(&mpeg->engine.lock, flags);
92218f978dSBen Skeggs 	return chan;
93218f978dSBen Skeggs }
94218f978dSBen Skeggs 
95218f978dSBen Skeggs static const struct nvkm_object_func
96218f978dSBen Skeggs nv44_mpeg_chan = {
97218f978dSBen Skeggs 	.dtor = nv44_mpeg_chan_dtor,
98218f978dSBen Skeggs 	.fini = nv44_mpeg_chan_fini,
99218f978dSBen Skeggs 	.bind = nv44_mpeg_chan_bind,
100c39f472eSBen Skeggs };
101c39f472eSBen Skeggs 
102218f978dSBen Skeggs static int
nv44_mpeg_chan_new(struct nvkm_chan * fifoch,const struct nvkm_oclass * oclass,struct nvkm_object ** pobject)103*c546656fSBen Skeggs nv44_mpeg_chan_new(struct nvkm_chan *fifoch, const struct nvkm_oclass *oclass,
104218f978dSBen Skeggs 		   struct nvkm_object **pobject)
105218f978dSBen Skeggs {
106218f978dSBen Skeggs 	struct nv44_mpeg *mpeg = nv44_mpeg(oclass->engine);
107218f978dSBen Skeggs 	struct nv44_mpeg_chan *chan;
108218f978dSBen Skeggs 	unsigned long flags;
109218f978dSBen Skeggs 
110218f978dSBen Skeggs 	if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
111218f978dSBen Skeggs 		return -ENOMEM;
112218f978dSBen Skeggs 	nvkm_object_ctor(&nv44_mpeg_chan, oclass, &chan->object);
113218f978dSBen Skeggs 	chan->mpeg = mpeg;
114218f978dSBen Skeggs 	chan->fifo = fifoch;
115218f978dSBen Skeggs 	*pobject = &chan->object;
116218f978dSBen Skeggs 
1177624fc01SBen Skeggs 	spin_lock_irqsave(&mpeg->engine.lock, flags);
118218f978dSBen Skeggs 	list_add(&chan->head, &mpeg->chan);
1197624fc01SBen Skeggs 	spin_unlock_irqrestore(&mpeg->engine.lock, flags);
120218f978dSBen Skeggs 	return 0;
121218f978dSBen Skeggs }
122218f978dSBen Skeggs 
123c39f472eSBen Skeggs /*******************************************************************************
124c39f472eSBen Skeggs  * PMPEG engine/subdev functions
125c39f472eSBen Skeggs  ******************************************************************************/
126c39f472eSBen Skeggs 
127590801c1SBen Skeggs static bool
nv44_mpeg_mthd(struct nvkm_device * device,u32 mthd,u32 data)128590801c1SBen Skeggs nv44_mpeg_mthd(struct nvkm_device *device, u32 mthd, u32 data)
129590801c1SBen Skeggs {
130590801c1SBen Skeggs 	switch (mthd) {
131590801c1SBen Skeggs 	case 0x190:
132590801c1SBen Skeggs 	case 0x1a0:
133590801c1SBen Skeggs 	case 0x1b0:
134590801c1SBen Skeggs 		return nv40_mpeg_mthd_dma(device, mthd, data);
135590801c1SBen Skeggs 	default:
136590801c1SBen Skeggs 		break;
137590801c1SBen Skeggs 	}
138590801c1SBen Skeggs 	return false;
139590801c1SBen Skeggs }
140590801c1SBen Skeggs 
141c39f472eSBen Skeggs static void
nv44_mpeg_intr(struct nvkm_engine * engine)1427624fc01SBen Skeggs nv44_mpeg_intr(struct nvkm_engine *engine)
143c39f472eSBen Skeggs {
1447624fc01SBen Skeggs 	struct nv44_mpeg *mpeg = nv44_mpeg(engine);
1457624fc01SBen Skeggs 	struct nvkm_subdev *subdev = &mpeg->engine.subdev;
1467624fc01SBen Skeggs 	struct nvkm_device *device = subdev->device;
147590801c1SBen Skeggs 	struct nv44_mpeg_chan *temp, *chan = NULL;
148590801c1SBen Skeggs 	unsigned long flags;
149636e37aaSBen Skeggs 	u32 inst = nvkm_rd32(device, 0x00b318) & 0x000fffff;
150636e37aaSBen Skeggs 	u32 stat = nvkm_rd32(device, 0x00b100);
151636e37aaSBen Skeggs 	u32 type = nvkm_rd32(device, 0x00b230);
152636e37aaSBen Skeggs 	u32 mthd = nvkm_rd32(device, 0x00b234);
153636e37aaSBen Skeggs 	u32 data = nvkm_rd32(device, 0x00b238);
154c39f472eSBen Skeggs 	u32 show = stat;
155c39f472eSBen Skeggs 
1567624fc01SBen Skeggs 	spin_lock_irqsave(&mpeg->engine.lock, flags);
157590801c1SBen Skeggs 	list_for_each_entry(temp, &mpeg->chan, head) {
158590801c1SBen Skeggs 		if (temp->inst >> 4 == inst) {
159590801c1SBen Skeggs 			chan = temp;
160590801c1SBen Skeggs 			list_del(&chan->head);
161590801c1SBen Skeggs 			list_add(&chan->head, &mpeg->chan);
162590801c1SBen Skeggs 			break;
163590801c1SBen Skeggs 		}
164590801c1SBen Skeggs 	}
165c39f472eSBen Skeggs 
166c39f472eSBen Skeggs 	if (stat & 0x01000000) {
167c39f472eSBen Skeggs 		/* happens on initial binding of the object */
168c39f472eSBen Skeggs 		if (type == 0x00000020 && mthd == 0x0000) {
169636e37aaSBen Skeggs 			nvkm_mask(device, 0x00b308, 0x00000000, 0x00000000);
170c39f472eSBen Skeggs 			show &= ~0x01000000;
171c39f472eSBen Skeggs 		}
172c39f472eSBen Skeggs 
173c39f472eSBen Skeggs 		if (type == 0x00000010) {
17483bce9c2SIlia Mirkin 			if (nv44_mpeg_mthd(subdev->device, mthd, data))
175c39f472eSBen Skeggs 				show &= ~0x01000000;
176c39f472eSBen Skeggs 		}
177c39f472eSBen Skeggs 	}
178c39f472eSBen Skeggs 
179636e37aaSBen Skeggs 	nvkm_wr32(device, 0x00b100, stat);
180636e37aaSBen Skeggs 	nvkm_wr32(device, 0x00b230, 0x00000001);
181c39f472eSBen Skeggs 
182c39f472eSBen Skeggs 	if (show) {
183590801c1SBen Skeggs 		nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n",
184c358f538SBen Skeggs 			   chan ? chan->fifo->id : -1, inst << 4,
185c358f538SBen Skeggs 			   chan ? chan->fifo->name : "unknown",
186590801c1SBen Skeggs 			   stat, type, mthd, data);
187c39f472eSBen Skeggs 	}
188c39f472eSBen Skeggs 
1897624fc01SBen Skeggs 	spin_unlock_irqrestore(&mpeg->engine.lock, flags);
190c39f472eSBen Skeggs }
191c39f472eSBen Skeggs 
192218f978dSBen Skeggs static const struct nvkm_engine_func
193218f978dSBen Skeggs nv44_mpeg = {
1947624fc01SBen Skeggs 	.init = nv31_mpeg_init,
1957624fc01SBen Skeggs 	.intr = nv44_mpeg_intr,
1967624fc01SBen Skeggs 	.tile = nv31_mpeg_tile,
197218f978dSBen Skeggs 	.fifo.cclass = nv44_mpeg_chan_new,
198218f978dSBen Skeggs 	.sclass = {
199218f978dSBen Skeggs 		{ -1, -1, NV31_MPEG, &nv31_mpeg_object },
200218f978dSBen Skeggs 		{}
201218f978dSBen Skeggs 	}
202218f978dSBen Skeggs };
203218f978dSBen Skeggs 
2047624fc01SBen Skeggs int
nv44_mpeg_new(struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_engine ** pmpeg)205e5e95a76SBen Skeggs nv44_mpeg_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
206e5e95a76SBen Skeggs 	      struct nvkm_engine **pmpeg)
207c39f472eSBen Skeggs {
208590801c1SBen Skeggs 	struct nv44_mpeg *mpeg;
209c39f472eSBen Skeggs 
2107624fc01SBen Skeggs 	if (!(mpeg = kzalloc(sizeof(*mpeg), GFP_KERNEL)))
2117624fc01SBen Skeggs 		return -ENOMEM;
212590801c1SBen Skeggs 	INIT_LIST_HEAD(&mpeg->chan);
2137624fc01SBen Skeggs 	*pmpeg = &mpeg->engine;
214590801c1SBen Skeggs 
215e5e95a76SBen Skeggs 	return nvkm_engine_ctor(&nv44_mpeg, device, type, inst, true, &mpeg->engine);
216c39f472eSBen Skeggs }
217