Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/nv40/vpe: add support for PMPEG

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

+321
+1
drivers/gpu/drm/nouveau/Makefile
··· 21 21 nv40_grctx.o nv50_grctx.o nvc0_grctx.o \ 22 22 nv84_crypt.o \ 23 23 nva3_copy.o nvc0_copy.o \ 24 + nv40_mpeg.o \ 24 25 nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ 25 26 nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ 26 27 nv50_cursor.o nv50_display.o \
+4
drivers/gpu/drm/nouveau/nouveau_drv.h
··· 153 153 #define NVOBJ_ENGINE_CRYPT 2 154 154 #define NVOBJ_ENGINE_COPY0 3 155 155 #define NVOBJ_ENGINE_COPY1 4 156 + #define NVOBJ_ENGINE_MPEG 5 156 157 #define NVOBJ_ENGINE_DISPLAY 15 157 158 #define NVOBJ_ENGINE_NR 16 158 159 ··· 1154 1153 1155 1154 /* nvc0_copy.c */ 1156 1155 extern int nvc0_copy_create(struct drm_device *dev, int engine); 1156 + 1157 + /* nv40_mpeg.c */ 1158 + extern int nv40_mpeg_create(struct drm_device *dev); 1157 1159 1158 1160 /* nv04_instmem.c */ 1159 1161 extern int nv04_instmem_init(struct drm_device *);
+3
drivers/gpu/drm/nouveau/nouveau_state.c
··· 617 617 break; 618 618 } 619 619 620 + if (dev_priv->card_type == NV_40) 621 + nv40_mpeg_create(dev); 622 + 620 623 if (!nouveau_noaccel) { 621 624 for (e = 0; e < NVOBJ_ENGINE_NR; e++) { 622 625 if (dev_priv->eng[e]) {
+2
drivers/gpu/drm/nouveau/nv40_fifo.c
··· 115 115 nv_wr32(dev, 0x32e8, nv_ri32(dev, fc + 68)); 116 116 nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76)); 117 117 nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80)); 118 + nv_wr32(dev, 0x330c, nv_ri32(dev, fc + 84)); 118 119 119 120 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); 120 121 nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); ··· 187 186 tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16); 188 187 nv_wi32(dev, fc + 72, tmp); 189 188 #endif 189 + nv_wi32(dev, fc + 84, nv_rd32(dev, 0x330c)); 190 190 191 191 nv40_fifo_do_load_context(dev, pfifo->channels - 1); 192 192 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
+311
drivers/gpu/drm/nouveau/nv40_mpeg.c
··· 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 + 29 + struct nv40_mpeg_engine { 30 + struct nouveau_exec_engine base; 31 + }; 32 + 33 + static int 34 + nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) 35 + { 36 + struct drm_device *dev = chan->dev; 37 + struct drm_nouveau_private *dev_priv = dev->dev_private; 38 + struct nouveau_gpuobj *ctx = NULL; 39 + unsigned long flags; 40 + int ret; 41 + 42 + NV_DEBUG(dev, "ch%d\n", chan->id); 43 + 44 + ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | 45 + NVOBJ_FLAG_ZERO_FREE, &ctx); 46 + if (ret) 47 + return ret; 48 + 49 + nv_wo32(ctx, 0x78, 0x02001ec1); 50 + 51 + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 52 + nv_mask(dev, 0x002500, 0x00000001, 0x00000000); 53 + if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) 54 + nv_wr32(dev, 0x00330c, ctx->pinst >> 4); 55 + nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4); 56 + nv_mask(dev, 0x002500, 0x00000001, 0x00000001); 57 + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 58 + 59 + chan->engctx[engine] = ctx; 60 + return 0; 61 + } 62 + 63 + static void 64 + nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) 65 + { 66 + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; 67 + struct nouveau_gpuobj *ctx = chan->engctx[engine]; 68 + struct drm_device *dev = chan->dev; 69 + unsigned long flags; 70 + u32 inst = 0x80000000 | (ctx->pinst >> 4); 71 + 72 + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 73 + nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); 74 + if (nv_rd32(dev, 0x00b318) == inst) 75 + nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); 76 + nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); 77 + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 78 + 79 + nouveau_gpuobj_ref(NULL, &ctx); 80 + chan->engctx[engine] = NULL; 81 + } 82 + 83 + static int 84 + nv40_mpeg_object_new(struct nouveau_channel *chan, int engine, 85 + u32 handle, u16 class) 86 + { 87 + struct drm_device *dev = chan->dev; 88 + struct nouveau_gpuobj *obj = NULL; 89 + int ret; 90 + 91 + ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | 92 + NVOBJ_FLAG_ZERO_FREE, &obj); 93 + if (ret) 94 + return ret; 95 + obj->engine = 2; 96 + obj->class = class; 97 + 98 + nv_wo32(obj, 0x00, class); 99 + 100 + ret = nouveau_ramht_insert(chan, handle, obj); 101 + nouveau_gpuobj_ref(NULL, &obj); 102 + return ret; 103 + } 104 + 105 + static int 106 + nv40_mpeg_init(struct drm_device *dev, int engine) 107 + { 108 + struct drm_nouveau_private *dev_priv = dev->dev_private; 109 + struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); 110 + int i; 111 + 112 + /* VPE init */ 113 + nv_mask(dev, 0x000200, 0x00000002, 0x00000000); 114 + nv_mask(dev, 0x000200, 0x00000002, 0x00000002); 115 + nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ 116 + nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ 117 + 118 + for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) 119 + pmpeg->base.set_tile_region(dev, i); 120 + 121 + /* PMPEG init */ 122 + nv_wr32(dev, 0x00b32c, 0x00000000); 123 + nv_wr32(dev, 0x00b314, 0x00000100); 124 + nv_wr32(dev, 0x00b220, 0x00000044); 125 + nv_wr32(dev, 0x00b300, 0x02001ec1); 126 + nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); 127 + 128 + nv_wr32(dev, 0x00b100, 0xffffffff); 129 + nv_wr32(dev, 0x00b140, 0xffffffff); 130 + 131 + if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { 132 + NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); 133 + return -EBUSY; 134 + } 135 + 136 + return 0; 137 + } 138 + 139 + static int 140 + nv40_mpeg_fini(struct drm_device *dev, int engine) 141 + { 142 + /*XXX: context save? */ 143 + nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); 144 + nv_wr32(dev, 0x00b140, 0x00000000); 145 + return 0; 146 + } 147 + 148 + static int 149 + nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) 150 + { 151 + struct drm_device *dev = chan->dev; 152 + u32 inst = data << 4; 153 + u32 dma0 = nv_ri32(dev, inst + 0); 154 + u32 dma1 = nv_ri32(dev, inst + 4); 155 + u32 dma2 = nv_ri32(dev, inst + 8); 156 + u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); 157 + u32 size = dma1 + 1; 158 + 159 + /* only allow linear DMA objects */ 160 + if (!(dma0 & 0x00002000)) 161 + return -EINVAL; 162 + 163 + if (mthd == 0x0190) { 164 + /* DMA_CMD */ 165 + nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); 166 + nv_wr32(dev, 0x00b334, base); 167 + nv_wr32(dev, 0x00b324, size); 168 + } else 169 + if (mthd == 0x01a0) { 170 + /* DMA_DATA */ 171 + nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); 172 + nv_wr32(dev, 0x00b360, base); 173 + nv_wr32(dev, 0x00b364, size); 174 + } else { 175 + /* DMA_IMAGE, VRAM only */ 176 + if (dma0 & 0x000c0000) 177 + return -EINVAL; 178 + 179 + nv_wr32(dev, 0x00b370, base); 180 + nv_wr32(dev, 0x00b374, size); 181 + } 182 + 183 + return 0; 184 + } 185 + 186 + static int 187 + nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst) 188 + { 189 + struct drm_nouveau_private *dev_priv = dev->dev_private; 190 + struct nouveau_gpuobj *ctx; 191 + unsigned long flags; 192 + int i; 193 + 194 + spin_lock_irqsave(&dev_priv->channels.lock, flags); 195 + for (i = 0; i < dev_priv->engine.fifo.channels; i++) { 196 + if (!dev_priv->channels.ptr[i]) 197 + continue; 198 + 199 + ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; 200 + if (ctx && ctx->pinst == inst) 201 + break; 202 + } 203 + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); 204 + return i; 205 + } 206 + 207 + static void 208 + nv40_vpe_set_tile_region(struct drm_device *dev, int i) 209 + { 210 + struct drm_nouveau_private *dev_priv = dev->dev_private; 211 + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; 212 + 213 + nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); 214 + nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); 215 + nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); 216 + } 217 + 218 + static void 219 + nv40_mpeg_isr(struct drm_device *dev) 220 + { 221 + u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; 222 + u32 chid = nv40_mpeg_isr_chid(dev, inst); 223 + u32 stat = nv_rd32(dev, 0x00b100); 224 + u32 type = nv_rd32(dev, 0x00b230); 225 + u32 mthd = nv_rd32(dev, 0x00b234); 226 + u32 data = nv_rd32(dev, 0x00b238); 227 + u32 show = stat; 228 + 229 + if (stat & 0x01000000) { 230 + /* happens on initial binding of the object */ 231 + if (type == 0x00000020 && mthd == 0x0000) { 232 + nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); 233 + show &= ~0x01000000; 234 + } 235 + 236 + if (type == 0x00000010) { 237 + if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) 238 + show &= ~0x01000000; 239 + } 240 + } 241 + 242 + nv_wr32(dev, 0x00b100, stat); 243 + nv_wr32(dev, 0x00b230, 0x00000001); 244 + 245 + if (show && nouveau_ratelimit()) { 246 + NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", 247 + chid, inst, stat, type, mthd, data); 248 + } 249 + } 250 + 251 + static void 252 + nv40_vpe_isr(struct drm_device *dev) 253 + { 254 + if (nv_rd32(dev, 0x00b100)) 255 + nv40_mpeg_isr(dev); 256 + 257 + if (nv_rd32(dev, 0x00b800)) { 258 + u32 stat = nv_rd32(dev, 0x00b800); 259 + NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); 260 + nv_wr32(dev, 0xb800, stat); 261 + } 262 + } 263 + 264 + static void 265 + nv40_mpeg_destroy(struct drm_device *dev, int engine) 266 + { 267 + struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); 268 + 269 + nouveau_irq_unregister(dev, 0); 270 + 271 + NVOBJ_ENGINE_DEL(dev, MPEG); 272 + kfree(pmpeg); 273 + } 274 + 275 + int 276 + nv40_mpeg_create(struct drm_device *dev) 277 + { 278 + struct nv40_mpeg_engine *pmpeg; 279 + 280 + pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); 281 + if (!pmpeg) 282 + return -ENOMEM; 283 + 284 + pmpeg->base.destroy = nv40_mpeg_destroy; 285 + pmpeg->base.init = nv40_mpeg_init; 286 + pmpeg->base.fini = nv40_mpeg_fini; 287 + pmpeg->base.context_new = nv40_mpeg_context_new; 288 + pmpeg->base.context_del = nv40_mpeg_context_del; 289 + pmpeg->base.object_new = nv40_mpeg_object_new; 290 + 291 + /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between 292 + * all VPE engines, for this driver's purposes the PMPEG engine 293 + * will be treated as the "master" and handle the global VPE 294 + * bits too 295 + */ 296 + pmpeg->base.set_tile_region = nv40_vpe_set_tile_region; 297 + nouveau_irq_register(dev, 0, nv40_vpe_isr); 298 + 299 + NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); 300 + NVOBJ_CLASS(dev, 0x3174, MPEG); 301 + NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma); 302 + NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma); 303 + NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma); 304 + 305 + #if 0 306 + NVOBJ_ENGINE_ADD(dev, ME, &pme->base); 307 + NVOBJ_CLASS(dev, 0x4075, ME); 308 + #endif 309 + return 0; 310 + 311 + }