1/* 2 * Copyright 2012 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#include "channv50.h" 25 26#include <core/client.h> 27#include <core/ramht.h> 28#include <subdev/mmu.h> 29#include <subdev/timer.h> 30 31#include <nvif/class.h> 32 33int 34g84_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type, 35 struct nvkm_event **pevent) 36{ 37 switch (type) { 38 case G82_CHANNEL_DMA_V0_NTFY_UEVENT: 39 *pevent = &chan->fifo->uevent; 40 return 0; 41 default: 42 break; 43 } 44 return -EINVAL; 45} 46 47static int 48g84_fifo_chan_engine(struct nvkm_engine *engine) 49{ 50 switch (engine->subdev.index) { 51 case NVKM_ENGINE_GR : return 0; 52 case NVKM_ENGINE_MPEG : 53 case NVKM_ENGINE_MSPPP : return 1; 54 case NVKM_ENGINE_CE0 : return 2; 55 case NVKM_ENGINE_VP : 56 case NVKM_ENGINE_MSPDEC: return 3; 57 case NVKM_ENGINE_CIPHER: 58 case NVKM_ENGINE_SEC : return 4; 59 case NVKM_ENGINE_BSP : 60 case NVKM_ENGINE_MSVLD : return 5; 61 default: 62 WARN_ON(1); 63 return 0; 64 } 65} 66 67static int 68g84_fifo_chan_engine_addr(struct nvkm_engine *engine) 69{ 70 switch (engine->subdev.index) { 71 case NVKM_ENGINE_DMAOBJ: 72 case NVKM_ENGINE_SW : return -1; 73 case NVKM_ENGINE_GR : return 0x0020; 74 case NVKM_ENGINE_VP : 75 case NVKM_ENGINE_MSPDEC: return 0x0040; 76 case NVKM_ENGINE_MPEG : 77 case NVKM_ENGINE_MSPPP : return 0x0060; 78 case NVKM_ENGINE_BSP : 79 case NVKM_ENGINE_MSVLD : return 0x0080; 80 case NVKM_ENGINE_CIPHER: 81 case NVKM_ENGINE_SEC : return 0x00a0; 82 case NVKM_ENGINE_CE0 : return 0x00c0; 83 default: 84 WARN_ON(1); 85 return -1; 86 } 87} 88 89static int 90g84_fifo_chan_engine_fini(struct nvkm_fifo_chan *base, 91 struct nvkm_engine *engine, bool suspend) 92{ 93 struct nv50_fifo_chan *chan = nv50_fifo_chan(base); 94 struct nv50_fifo *fifo = chan->fifo; 95 struct nvkm_subdev *subdev = &fifo->base.engine.subdev; 96 struct nvkm_device *device = subdev->device; 97 u32 engn, save; 98 int offset; 99 bool done; 100 101 offset = g84_fifo_chan_engine_addr(engine); 102 if (offset < 0) 103 return 0; 104 105 engn = g84_fifo_chan_engine(engine); 106 save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn); 107 nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12); 108 done = nvkm_msec(device, 2000, 109 if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) 110 break; 111 ) >= 0; 112 nvkm_wr32(device, 0x002520, save); 113 if (!done) { 114 nvkm_error(subdev, "channel %d [%s] unload timeout\n", 115 chan->base.chid, chan->base.object.client->name); 116 if (suspend) 117 return -EBUSY; 118 } 119 120 nvkm_kmap(chan->eng); 121 nvkm_wo32(chan->eng, offset + 0x00, 0x00000000); 122 nvkm_wo32(chan->eng, offset + 0x04, 0x00000000); 123 nvkm_wo32(chan->eng, offset + 0x08, 0x00000000); 124 nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000); 125 nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); 126 nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); 127 nvkm_done(chan->eng); 128 return 0; 129} 130 131 132int 133g84_fifo_chan_engine_init(struct nvkm_fifo_chan *base, 134 struct nvkm_engine *engine) 135{ 136 struct nv50_fifo_chan *chan = nv50_fifo_chan(base); 137 struct nvkm_gpuobj *engn = chan->engn[engine->subdev.index]; 138 u64 limit, start; 139 int offset; 140 141 offset = g84_fifo_chan_engine_addr(engine); 142 if (offset < 0) 143 return 0; 144 limit = engn->addr + engn->size - 1; 145 start = engn->addr; 146 147 nvkm_kmap(chan->eng); 148 nvkm_wo32(chan->eng, offset + 0x00, 0x00190000); 149 nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit)); 150 nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start)); 151 nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 | 152 upper_32_bits(start)); 153 nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); 154 nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); 155 nvkm_done(chan->eng); 156 return 0; 157} 158 159static int 160g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, 161 struct nvkm_engine *engine, 162 struct nvkm_object *object) 163{ 164 struct nv50_fifo_chan *chan = nv50_fifo_chan(base); 165 int engn = engine->subdev.index; 166 167 if (g84_fifo_chan_engine_addr(engine) < 0) 168 return 0; 169 170 return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); 171} 172 173int 174g84_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, 175 struct nvkm_object *object) 176{ 177 struct nv50_fifo_chan *chan = nv50_fifo_chan(base); 178 u32 handle = object->handle; 179 u32 context; 180 181 switch (object->engine->subdev.index) { 182 case NVKM_ENGINE_DMAOBJ: 183 case NVKM_ENGINE_SW : context = 0x00000000; break; 184 case NVKM_ENGINE_GR : context = 0x00100000; break; 185 case NVKM_ENGINE_MPEG : 186 case NVKM_ENGINE_MSPPP : context = 0x00200000; break; 187 case NVKM_ENGINE_ME : 188 case NVKM_ENGINE_CE0 : context = 0x00300000; break; 189 case NVKM_ENGINE_VP : 190 case NVKM_ENGINE_MSPDEC: context = 0x00400000; break; 191 case NVKM_ENGINE_CIPHER: 192 case NVKM_ENGINE_SEC : 193 case NVKM_ENGINE_VIC : context = 0x00500000; break; 194 case NVKM_ENGINE_BSP : 195 case NVKM_ENGINE_MSVLD : context = 0x00600000; break; 196 default: 197 WARN_ON(1); 198 return -EINVAL; 199 } 200 201 return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context); 202} 203 204static void 205g84_fifo_chan_init(struct nvkm_fifo_chan *base) 206{ 207 struct nv50_fifo_chan *chan = nv50_fifo_chan(base); 208 struct nv50_fifo *fifo = chan->fifo; 209 struct nvkm_device *device = fifo->base.engine.subdev.device; 210 u64 addr = chan->ramfc->addr >> 8; 211 u32 chid = chan->base.chid; 212 213 nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr); 214 nv50_fifo_runlist_update(fifo); 215} 216 217static const struct nvkm_fifo_chan_func 218g84_fifo_chan_func = { 219 .dtor = nv50_fifo_chan_dtor, 220 .init = g84_fifo_chan_init, 221 .fini = nv50_fifo_chan_fini, 222 .ntfy = g84_fifo_chan_ntfy, 223 .engine_ctor = g84_fifo_chan_engine_ctor, 224 .engine_dtor = nv50_fifo_chan_engine_dtor, 225 .engine_init = g84_fifo_chan_engine_init, 226 .engine_fini = g84_fifo_chan_engine_fini, 227 .object_ctor = g84_fifo_chan_object_ctor, 228 .object_dtor = nv50_fifo_chan_object_dtor, 229}; 230 231int 232g84_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vm, u64 push, 233 const struct nvkm_oclass *oclass, 234 struct nv50_fifo_chan *chan) 235{ 236 struct nvkm_device *device = fifo->base.engine.subdev.device; 237 int ret; 238 239 ret = nvkm_fifo_chan_ctor(&g84_fifo_chan_func, &fifo->base, 240 0x10000, 0x1000, false, vm, push, 241 (1ULL << NVKM_ENGINE_BSP) | 242 (1ULL << NVKM_ENGINE_CE0) | 243 (1ULL << NVKM_ENGINE_CIPHER) | 244 (1ULL << NVKM_ENGINE_DMAOBJ) | 245 (1ULL << NVKM_ENGINE_GR) | 246 (1ULL << NVKM_ENGINE_ME) | 247 (1ULL << NVKM_ENGINE_MPEG) | 248 (1ULL << NVKM_ENGINE_MSPDEC) | 249 (1ULL << NVKM_ENGINE_MSPPP) | 250 (1ULL << NVKM_ENGINE_MSVLD) | 251 (1ULL << NVKM_ENGINE_SEC) | 252 (1ULL << NVKM_ENGINE_SW) | 253 (1ULL << NVKM_ENGINE_VIC) | 254 (1ULL << NVKM_ENGINE_VP), 255 0, 0xc00000, 0x2000, oclass, &chan->base); 256 chan->fifo = fifo; 257 if (ret) 258 return ret; 259 260 ret = nvkm_gpuobj_new(device, 0x0200, 0, true, chan->base.inst, 261 &chan->eng); 262 if (ret) 263 return ret; 264 265 ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst, 266 &chan->pgd); 267 if (ret) 268 return ret; 269 270 ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, chan->base.inst, 271 &chan->cache); 272 if (ret) 273 return ret; 274 275 ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, chan->base.inst, 276 &chan->ramfc); 277 if (ret) 278 return ret; 279 280 ret = nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht); 281 if (ret) 282 return ret; 283 284 return nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd); 285} 286