1/* $NetBSD: nouveau_nvkm_engine_mpeg_nv44.c,v 1.3 2021/12/18 23:45:36 riastradh Exp $ */ 2 3/* 4 * Copyright 2012 Red Hat Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: Ben Skeggs 25 */ 26#include <sys/cdefs.h> 27__KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_engine_mpeg_nv44.c,v 1.3 2021/12/18 23:45:36 riastradh Exp $"); 28 29#define nv44_mpeg(p) container_of((p), struct nv44_mpeg, engine) 30#include "priv.h" 31 32#include <core/client.h> 33#include <core/gpuobj.h> 34#include <engine/fifo.h> 35 36#include <nvif/class.h> 37 38struct nv44_mpeg { 39 struct nvkm_engine engine; 40 struct list_head chan; 41}; 42 43/******************************************************************************* 44 * PMPEG context 45 ******************************************************************************/ 46#define nv44_mpeg_chan(p) container_of((p), struct nv44_mpeg_chan, object) 47 48struct nv44_mpeg_chan { 49 struct nvkm_object object; 50 struct nv44_mpeg *mpeg; 51 struct nvkm_fifo_chan *fifo; 52 struct list_head head; 53 u32 inst; 54}; 55 56static int 57nv44_mpeg_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, 58 int align, struct nvkm_gpuobj **pgpuobj) 59{ 60 struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); 61 int ret = nvkm_gpuobj_new(chan->object.engine->subdev.device, 264 * 4, 62 align, true, parent, pgpuobj); 63 if (ret == 0) { 64 chan->inst = (*pgpuobj)->addr; 65 nvkm_kmap(*pgpuobj); 66 nvkm_wo32(*pgpuobj, 0x78, 0x02001ec1); 67 nvkm_done(*pgpuobj); 68 } 69 return ret; 70} 71 72static int 73nv44_mpeg_chan_fini(struct nvkm_object *object, bool suspend) 74{ 75 76 struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); 77 struct nv44_mpeg *mpeg = chan->mpeg; 78 struct nvkm_device *device = mpeg->engine.subdev.device; 79 u32 inst = 0x80000000 | (chan->inst >> 4); 80 81 nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000000); 82 if (nvkm_rd32(device, 0x00b318) == inst) 83 nvkm_mask(device, 0x00b318, 0x80000000, 0x00000000); 84 nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); 85 return 0; 86} 87 88static void * 89nv44_mpeg_chan_dtor(struct nvkm_object *object) 90{ 91 struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); 92 struct nv44_mpeg *mpeg = chan->mpeg; 93 unsigned long flags; 94 spin_lock_irqsave(&mpeg->engine.lock, flags); 95 list_del(&chan->head); 96 spin_unlock_irqrestore(&mpeg->engine.lock, flags); 97 return chan; 98} 99 100static const struct nvkm_object_func 101nv44_mpeg_chan = { 102 .dtor = nv44_mpeg_chan_dtor, 103 .fini = nv44_mpeg_chan_fini, 104 .bind = nv44_mpeg_chan_bind, 105}; 106 107static int 108nv44_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, 109 const struct nvkm_oclass *oclass, 110 struct nvkm_object **pobject) 111{ 112 struct nv44_mpeg *mpeg = nv44_mpeg(oclass->engine); 113 struct nv44_mpeg_chan *chan; 114 unsigned long flags; 115 116 if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) 117 return -ENOMEM; 118 nvkm_object_ctor(&nv44_mpeg_chan, oclass, &chan->object); 119 chan->mpeg = mpeg; 120 chan->fifo = fifoch; 121 *pobject = &chan->object; 122 123 spin_lock_irqsave(&mpeg->engine.lock, flags); 124 list_add(&chan->head, &mpeg->chan); 125 spin_unlock_irqrestore(&mpeg->engine.lock, flags); 126 return 0; 127} 128 129/******************************************************************************* 130 * PMPEG engine/subdev functions 131 ******************************************************************************/ 132 133static bool 134nv44_mpeg_mthd(struct nvkm_device *device, u32 mthd, u32 data) 135{ 136 switch (mthd) { 137 case 0x190: 138 case 0x1a0: 139 case 0x1b0: 140 return nv40_mpeg_mthd_dma(device, mthd, data); 141 default: 142 break; 143 } 144 return false; 145} 146 147static void 148nv44_mpeg_intr(struct nvkm_engine *engine) 149{ 150 struct nv44_mpeg *mpeg = nv44_mpeg(engine); 151 struct nvkm_subdev *subdev = &mpeg->engine.subdev; 152 struct nvkm_device *device = subdev->device; 153 struct nv44_mpeg_chan *temp, *chan = NULL; 154 unsigned long flags; 155 u32 inst = nvkm_rd32(device, 0x00b318) & 0x000fffff; 156 u32 stat = nvkm_rd32(device, 0x00b100); 157 u32 type = nvkm_rd32(device, 0x00b230); 158 u32 mthd = nvkm_rd32(device, 0x00b234); 159 u32 data = nvkm_rd32(device, 0x00b238); 160 u32 show = stat; 161 162 spin_lock_irqsave(&mpeg->engine.lock, flags); 163 list_for_each_entry(temp, &mpeg->chan, head) { 164 if (temp->inst >> 4 == inst) { 165 chan = temp; 166 list_del(&chan->head); 167 list_add(&chan->head, &mpeg->chan); 168 break; 169 } 170 } 171 172 if (stat & 0x01000000) { 173 /* happens on initial binding of the object */ 174 if (type == 0x00000020 && mthd == 0x0000) { 175 nvkm_mask(device, 0x00b308, 0x00000000, 0x00000000); 176 show &= ~0x01000000; 177 } 178 179 if (type == 0x00000010) { 180 if (nv44_mpeg_mthd(subdev->device, mthd, data)) 181 show &= ~0x01000000; 182 } 183 } 184 185 nvkm_wr32(device, 0x00b100, stat); 186 nvkm_wr32(device, 0x00b230, 0x00000001); 187 188 if (show) { 189 nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n", 190 chan ? chan->fifo->chid : -1, inst << 4, 191 chan ? chan->object.client->name : "unknown", 192 stat, type, mthd, data); 193 } 194 195 spin_unlock_irqrestore(&mpeg->engine.lock, flags); 196} 197 198static const struct nvkm_engine_func 199nv44_mpeg = { 200 .init = nv31_mpeg_init, 201 .intr = nv44_mpeg_intr, 202 .tile = nv31_mpeg_tile, 203 .fifo.cclass = nv44_mpeg_chan_new, 204 .sclass = { 205 { -1, -1, NV31_MPEG, &nv31_mpeg_object }, 206 {} 207 } 208}; 209 210int 211nv44_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) 212{ 213 struct nv44_mpeg *mpeg; 214 215 if (!(mpeg = kzalloc(sizeof(*mpeg), GFP_KERNEL))) 216 return -ENOMEM; 217 INIT_LIST_HEAD(&mpeg->chan); 218 *pmpeg = &mpeg->engine; 219 220 return nvkm_engine_ctor(&nv44_mpeg, device, index, true, &mpeg->engine); 221} 222