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