1/* 2 * Copyright 2011 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 */ 24 25#include "drmP.h" 26#include "nouveau_drv.h" 27#include "nouveau_ramht.h" 28 29struct nv31_mpeg_engine { 30 struct nouveau_exec_engine base; 31 atomic_t refcount; 32}; 33 34 35static int 36nv31_mpeg_context_new(struct nouveau_channel *chan, int engine) 37{ 38 struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); 39 40 if (!atomic_add_unless(&pmpeg->refcount, 1, 1)) 41 return -EBUSY; 42 43 chan->engctx[engine] = (void *)0xdeadcafe; 44 return 0; 45} 46 47static void 48nv31_mpeg_context_del(struct nouveau_channel *chan, int engine) 49{ 50 struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); 51 atomic_dec(&pmpeg->refcount); 52 chan->engctx[engine] = NULL; 53} 54 55static int 56nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) 57{ 58 struct drm_device *dev = chan->dev; 59 struct drm_nouveau_private *dev_priv = dev->dev_private; 60 struct nouveau_gpuobj *ctx = NULL; 61 unsigned long flags; 62 int ret; 63 64 NV_DEBUG(dev, "ch%d\n", chan->id); 65 66 ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | 67 NVOBJ_FLAG_ZERO_FREE, &ctx); 68 if (ret) 69 return ret; 70 71 nv_wo32(ctx, 0x78, 0x02001ec1); 72 73 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 74 nv_mask(dev, 0x002500, 0x00000001, 0x00000000); 75 if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) 76 nv_wr32(dev, 0x00330c, ctx->pinst >> 4); 77 nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4); 78 nv_mask(dev, 0x002500, 0x00000001, 0x00000001); 79 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 80 81 chan->engctx[engine] = ctx; 82 return 0; 83} 84 85static void 86nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) 87{ 88 struct drm_nouveau_private *dev_priv = chan->dev->dev_private; 89 struct nouveau_gpuobj *ctx = chan->engctx[engine]; 90 struct drm_device *dev = chan->dev; 91 unsigned long flags; 92 u32 inst = 0x80000000 | (ctx->pinst >> 4); 93 94 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 95 nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); 96 if (nv_rd32(dev, 0x00b318) == inst) 97 nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); 98 nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); 99 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 100 101 nouveau_gpuobj_ref(NULL, &ctx); 102 chan->engctx[engine] = NULL; 103} 104 105static int 106nv31_mpeg_object_new(struct nouveau_channel *chan, int engine, 107 u32 handle, u16 class) 108{ 109 struct drm_device *dev = chan->dev; 110 struct nouveau_gpuobj *obj = NULL; 111 int ret; 112 113 ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | 114 NVOBJ_FLAG_ZERO_FREE, &obj); 115 if (ret) 116 return ret; 117 obj->engine = 2; 118 obj->class = class; 119 120 nv_wo32(obj, 0x00, class); 121 122 ret = nouveau_ramht_insert(chan, handle, obj); 123 nouveau_gpuobj_ref(NULL, &obj); 124 return ret; 125} 126 127static int 128nv31_mpeg_init(struct drm_device *dev, int engine) 129{ 130 struct drm_nouveau_private *dev_priv = dev->dev_private; 131 struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); 132 int i; 133 134 /* VPE init */ 135 nv_mask(dev, 0x000200, 0x00000002, 0x00000000); 136 nv_mask(dev, 0x000200, 0x00000002, 0x00000002); 137 nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ 138 nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ 139 140 for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) 141 pmpeg->base.set_tile_region(dev, i); 142 143 /* PMPEG init */ 144 nv_wr32(dev, 0x00b32c, 0x00000000); 145 nv_wr32(dev, 0x00b314, 0x00000100); 146 nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031); 147 nv_wr32(dev, 0x00b300, 0x02001ec1); 148 nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); 149 150 nv_wr32(dev, 0x00b100, 0xffffffff); 151 nv_wr32(dev, 0x00b140, 0xffffffff); 152 153 if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { 154 NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); 155 return -EBUSY; 156 } 157 158 return 0; 159} 160 161static int 162nv31_mpeg_fini(struct drm_device *dev, int engine, bool suspend) 163{ 164 /*XXX: context save? */ 165 nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); 166 nv_wr32(dev, 0x00b140, 0x00000000); 167 return 0; 168} 169 170static int 171nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) 172{ 173 struct drm_device *dev = chan->dev; 174 u32 inst = data << 4; 175 u32 dma0 = nv_ri32(dev, inst + 0); 176 u32 dma1 = nv_ri32(dev, inst + 4); 177 u32 dma2 = nv_ri32(dev, inst + 8); 178 u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); 179 u32 size = dma1 + 1; 180 181 /* only allow linear DMA objects */ 182 if (!(dma0 & 0x00002000)) 183 return -EINVAL; 184 185 if (mthd == 0x0190) { 186 /* DMA_CMD */ 187 nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); 188 nv_wr32(dev, 0x00b334, base); 189 nv_wr32(dev, 0x00b324, size); 190 } else 191 if (mthd == 0x01a0) { 192 /* DMA_DATA */ 193 nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); 194 nv_wr32(dev, 0x00b360, base); 195 nv_wr32(dev, 0x00b364, size); 196 } else { 197 /* DMA_IMAGE, VRAM only */ 198 if (dma0 & 0x000c0000) 199 return -EINVAL; 200 201 nv_wr32(dev, 0x00b370, base); 202 nv_wr32(dev, 0x00b374, size); 203 } 204 205 return 0; 206} 207 208static int 209nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst) 210{ 211 struct drm_nouveau_private *dev_priv = dev->dev_private; 212 struct nouveau_gpuobj *ctx; 213 unsigned long flags; 214 int i; 215 216 /* hardcode drm channel id on nv3x, so swmthd lookup works */ 217 if (dev_priv->card_type < NV_40) 218 return 0; 219 220 spin_lock_irqsave(&dev_priv->channels.lock, flags); 221 for (i = 0; i < dev_priv->engine.fifo.channels; i++) { 222 if (!dev_priv->channels.ptr[i]) 223 continue; 224 225 ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; 226 if (ctx && ctx->pinst == inst) 227 break; 228 } 229 spin_unlock_irqrestore(&dev_priv->channels.lock, flags); 230 return i; 231} 232 233static void 234nv31_vpe_set_tile_region(struct drm_device *dev, int i) 235{ 236 struct drm_nouveau_private *dev_priv = dev->dev_private; 237 struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; 238 239 nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); 240 nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); 241 nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); 242} 243 244static void 245nv31_mpeg_isr(struct drm_device *dev) 246{ 247 u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; 248 u32 chid = nv31_mpeg_isr_chid(dev, inst); 249 u32 stat = nv_rd32(dev, 0x00b100); 250 u32 type = nv_rd32(dev, 0x00b230); 251 u32 mthd = nv_rd32(dev, 0x00b234); 252 u32 data = nv_rd32(dev, 0x00b238); 253 u32 show = stat; 254 255 if (stat & 0x01000000) { 256 /* happens on initial binding of the object */ 257 if (type == 0x00000020 && mthd == 0x0000) { 258 nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); 259 show &= ~0x01000000; 260 } 261 262 if (type == 0x00000010) { 263 if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) 264 show &= ~0x01000000; 265 } 266 } 267 268 nv_wr32(dev, 0x00b100, stat); 269 nv_wr32(dev, 0x00b230, 0x00000001); 270 271 if (show && nouveau_ratelimit()) { 272 NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", 273 chid, inst, stat, type, mthd, data); 274 } 275} 276 277static void 278nv31_vpe_isr(struct drm_device *dev) 279{ 280 if (nv_rd32(dev, 0x00b100)) 281 nv31_mpeg_isr(dev); 282 283 if (nv_rd32(dev, 0x00b800)) { 284 u32 stat = nv_rd32(dev, 0x00b800); 285 NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); 286 nv_wr32(dev, 0xb800, stat); 287 } 288} 289 290static void 291nv31_mpeg_destroy(struct drm_device *dev, int engine) 292{ 293 struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); 294 295 nouveau_irq_unregister(dev, 0); 296 297 NVOBJ_ENGINE_DEL(dev, MPEG); 298 kfree(pmpeg); 299} 300 301int 302nv31_mpeg_create(struct drm_device *dev) 303{ 304 struct drm_nouveau_private *dev_priv = dev->dev_private; 305 struct nv31_mpeg_engine *pmpeg; 306 307 pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); 308 if (!pmpeg) 309 return -ENOMEM; 310 atomic_set(&pmpeg->refcount, 0); 311 312 pmpeg->base.destroy = nv31_mpeg_destroy; 313 pmpeg->base.init = nv31_mpeg_init; 314 pmpeg->base.fini = nv31_mpeg_fini; 315 if (dev_priv->card_type < NV_40) { 316 pmpeg->base.context_new = nv31_mpeg_context_new; 317 pmpeg->base.context_del = nv31_mpeg_context_del; 318 } else { 319 pmpeg->base.context_new = nv40_mpeg_context_new; 320 pmpeg->base.context_del = nv40_mpeg_context_del; 321 } 322 pmpeg->base.object_new = nv31_mpeg_object_new; 323 324 /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between 325 * all VPE engines, for this driver's purposes the PMPEG engine 326 * will be treated as the "master" and handle the global VPE 327 * bits too 328 */ 329 pmpeg->base.set_tile_region = nv31_vpe_set_tile_region; 330 nouveau_irq_register(dev, 0, nv31_vpe_isr); 331 332 NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); 333 NVOBJ_CLASS(dev, 0x3174, MPEG); 334 NVOBJ_MTHD (dev, 0x3174, 0x0190, nv31_mpeg_mthd_dma); 335 NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv31_mpeg_mthd_dma); 336 NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv31_mpeg_mthd_dma); 337 338#if 0 339 NVOBJ_ENGINE_ADD(dev, ME, &pme->base); 340 NVOBJ_CLASS(dev, 0x4075, ME); 341#endif 342 return 0; 343 344} 345