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 #include <engine/falcon.h> 23 24 #include <subdev/timer.h> 25 26 void 27 nvkm_falcon_intr(struct nvkm_subdev *subdev) 28 { 29 struct nvkm_falcon *falcon = (void *)subdev; 30 u32 dispatch = nv_ro32(falcon, 0x01c); 31 u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16); 32 33 if (intr & 0x00000010) { 34 nvkm_debug(subdev, "ucode halted\n"); 35 nv_wo32(falcon, 0x004, 0x00000010); 36 intr &= ~0x00000010; 37 } 38 39 if (intr) { 40 nvkm_error(subdev, "intr %08x\n", intr); 41 nv_wo32(falcon, 0x004, intr); 42 } 43 } 44 45 u32 46 _nvkm_falcon_rd32(struct nvkm_object *object, u64 addr) 47 { 48 struct nvkm_falcon *falcon = (void *)object; 49 return nvkm_rd32(falcon->engine.subdev.device, falcon->addr + addr); 50 } 51 52 void 53 _nvkm_falcon_wr32(struct nvkm_object *object, u64 addr, u32 data) 54 { 55 struct nvkm_falcon *falcon = (void *)object; 56 nvkm_wr32(falcon->engine.subdev.device, falcon->addr + addr, data); 57 } 58 59 static void * 60 vmemdup(const void *src, size_t len) 61 { 62 void *p = vmalloc(len); 63 64 if (p) 65 memcpy(p, src, len); 66 return p; 67 } 68 69 int 70 _nvkm_falcon_init(struct nvkm_object *object) 71 { 72 struct nvkm_falcon *falcon = (void *)object; 73 struct nvkm_subdev *subdev = &falcon->engine.subdev; 74 struct nvkm_device *device = subdev->device; 75 const struct firmware *fw; 76 char name[32] = "internal"; 77 int ret, i; 78 u32 caps; 79 80 /* enable engine, and determine its capabilities */ 81 ret = nvkm_engine_init(&falcon->engine); 82 if (ret) 83 return ret; 84 85 if (device->chipset < 0xa3 || 86 device->chipset == 0xaa || device->chipset == 0xac) { 87 falcon->version = 0; 88 falcon->secret = (falcon->addr == 0x087000) ? 1 : 0; 89 } else { 90 caps = nv_ro32(falcon, 0x12c); 91 falcon->version = (caps & 0x0000000f); 92 falcon->secret = (caps & 0x00000030) >> 4; 93 } 94 95 caps = nv_ro32(falcon, 0x108); 96 falcon->code.limit = (caps & 0x000001ff) << 8; 97 falcon->data.limit = (caps & 0x0003fe00) >> 1; 98 99 nvkm_debug(subdev, "falcon version: %d\n", falcon->version); 100 nvkm_debug(subdev, "secret level: %d\n", falcon->secret); 101 nvkm_debug(subdev, "code limit: %d\n", falcon->code.limit); 102 nvkm_debug(subdev, "data limit: %d\n", falcon->data.limit); 103 104 /* wait for 'uc halted' to be signalled before continuing */ 105 if (falcon->secret && falcon->version < 4) { 106 if (!falcon->version) { 107 nvkm_msec(device, 2000, 108 if (nv_ro32(falcon, 0x008) & 0x00000010) 109 break; 110 ); 111 } else { 112 nvkm_msec(device, 2000, 113 if (!(nv_ro32(falcon, 0x180) & 0x80000000)) 114 break; 115 ); 116 } 117 nv_wo32(falcon, 0x004, 0x00000010); 118 } 119 120 /* disable all interrupts */ 121 nv_wo32(falcon, 0x014, 0xffffffff); 122 123 /* no default ucode provided by the engine implementation, try and 124 * locate a "self-bootstrapping" firmware image for the engine 125 */ 126 if (!falcon->code.data) { 127 snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x", 128 device->chipset, falcon->addr >> 12); 129 130 ret = request_firmware(&fw, name, nv_device_base(device)); 131 if (ret == 0) { 132 falcon->code.data = vmemdup(fw->data, fw->size); 133 falcon->code.size = fw->size; 134 falcon->data.data = NULL; 135 falcon->data.size = 0; 136 release_firmware(fw); 137 } 138 139 falcon->external = true; 140 } 141 142 /* next step is to try and load "static code/data segment" firmware 143 * images for the engine 144 */ 145 if (!falcon->code.data) { 146 snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd", 147 device->chipset, falcon->addr >> 12); 148 149 ret = request_firmware(&fw, name, nv_device_base(device)); 150 if (ret) { 151 nvkm_error(subdev, "unable to load firmware data\n"); 152 return ret; 153 } 154 155 falcon->data.data = vmemdup(fw->data, fw->size); 156 falcon->data.size = fw->size; 157 release_firmware(fw); 158 if (!falcon->data.data) 159 return -ENOMEM; 160 161 snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc", 162 device->chipset, falcon->addr >> 12); 163 164 ret = request_firmware(&fw, name, nv_device_base(device)); 165 if (ret) { 166 nvkm_error(subdev, "unable to load firmware code\n"); 167 return ret; 168 } 169 170 falcon->code.data = vmemdup(fw->data, fw->size); 171 falcon->code.size = fw->size; 172 release_firmware(fw); 173 if (!falcon->code.data) 174 return -ENOMEM; 175 } 176 177 nvkm_debug(subdev, "firmware: %s (%s)\n", name, falcon->data.data ? 178 "static code/data segments" : "self-bootstrapping"); 179 180 /* ensure any "self-bootstrapping" firmware image is in vram */ 181 if (!falcon->data.data && !falcon->core) { 182 ret = nvkm_gpuobj_new(object->parent, NULL, falcon->code.size, 183 256, 0, &falcon->core); 184 if (ret) { 185 nvkm_error(subdev, "core allocation failed, %d\n", ret); 186 return ret; 187 } 188 189 for (i = 0; i < falcon->code.size; i += 4) 190 nv_wo32(falcon->core, i, falcon->code.data[i / 4]); 191 } 192 193 /* upload firmware bootloader (or the full code segments) */ 194 if (falcon->core) { 195 if (device->card_type < NV_C0) 196 nv_wo32(falcon, 0x618, 0x04000000); 197 else 198 nv_wo32(falcon, 0x618, 0x00000114); 199 nv_wo32(falcon, 0x11c, 0); 200 nv_wo32(falcon, 0x110, falcon->core->addr >> 8); 201 nv_wo32(falcon, 0x114, 0); 202 nv_wo32(falcon, 0x118, 0x00006610); 203 } else { 204 if (falcon->code.size > falcon->code.limit || 205 falcon->data.size > falcon->data.limit) { 206 nvkm_error(subdev, "ucode exceeds falcon limit(s)\n"); 207 return -EINVAL; 208 } 209 210 if (falcon->version < 3) { 211 nv_wo32(falcon, 0xff8, 0x00100000); 212 for (i = 0; i < falcon->code.size / 4; i++) 213 nv_wo32(falcon, 0xff4, falcon->code.data[i]); 214 } else { 215 nv_wo32(falcon, 0x180, 0x01000000); 216 for (i = 0; i < falcon->code.size / 4; i++) { 217 if ((i & 0x3f) == 0) 218 nv_wo32(falcon, 0x188, i >> 6); 219 nv_wo32(falcon, 0x184, falcon->code.data[i]); 220 } 221 } 222 } 223 224 /* upload data segment (if necessary), zeroing the remainder */ 225 if (falcon->version < 3) { 226 nv_wo32(falcon, 0xff8, 0x00000000); 227 for (i = 0; !falcon->core && i < falcon->data.size / 4; i++) 228 nv_wo32(falcon, 0xff4, falcon->data.data[i]); 229 for (; i < falcon->data.limit; i += 4) 230 nv_wo32(falcon, 0xff4, 0x00000000); 231 } else { 232 nv_wo32(falcon, 0x1c0, 0x01000000); 233 for (i = 0; !falcon->core && i < falcon->data.size / 4; i++) 234 nv_wo32(falcon, 0x1c4, falcon->data.data[i]); 235 for (; i < falcon->data.limit / 4; i++) 236 nv_wo32(falcon, 0x1c4, 0x00000000); 237 } 238 239 /* start it running */ 240 nv_wo32(falcon, 0x10c, 0x00000001); /* BLOCK_ON_FIFO */ 241 nv_wo32(falcon, 0x104, 0x00000000); /* ENTRY */ 242 nv_wo32(falcon, 0x100, 0x00000002); /* TRIGGER */ 243 nv_wo32(falcon, 0x048, 0x00000003); /* FIFO | CHSW */ 244 return 0; 245 } 246 247 int 248 _nvkm_falcon_fini(struct nvkm_object *object, bool suspend) 249 { 250 struct nvkm_falcon *falcon = (void *)object; 251 252 if (!suspend) { 253 nvkm_gpuobj_ref(NULL, &falcon->core); 254 if (falcon->external) { 255 vfree(falcon->data.data); 256 vfree(falcon->code.data); 257 falcon->code.data = NULL; 258 } 259 } 260 261 nv_mo32(falcon, 0x048, 0x00000003, 0x00000000); 262 nv_wo32(falcon, 0x014, 0xffffffff); 263 264 return nvkm_engine_fini(&falcon->engine, suspend); 265 } 266 267 int 268 nvkm_falcon_create_(struct nvkm_object *parent, struct nvkm_object *engine, 269 struct nvkm_oclass *oclass, u32 addr, bool enable, 270 const char *iname, const char *fname, 271 int length, void **pobject) 272 { 273 struct nvkm_falcon *falcon; 274 int ret; 275 276 ret = nvkm_engine_create_(parent, engine, oclass, enable, iname, 277 fname, length, pobject); 278 falcon = *pobject; 279 if (ret) 280 return ret; 281 282 falcon->addr = addr; 283 return 0; 284 } 285