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