18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2012 Red Hat Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci#include <engine/falcon.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <core/gpuobj.h> 258c2ecf20Sopenharmony_ci#include <subdev/mc.h> 268c2ecf20Sopenharmony_ci#include <subdev/timer.h> 278c2ecf20Sopenharmony_ci#include <engine/fifo.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int 308c2ecf20Sopenharmony_cinvkm_falcon_oclass_get(struct nvkm_oclass *oclass, int index) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct nvkm_falcon *falcon = nvkm_falcon(oclass->engine); 338c2ecf20Sopenharmony_ci int c = 0; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci while (falcon->func->sclass[c].oclass) { 368c2ecf20Sopenharmony_ci if (c++ == index) { 378c2ecf20Sopenharmony_ci oclass->base = falcon->func->sclass[index]; 388c2ecf20Sopenharmony_ci return index; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return c; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int 468c2ecf20Sopenharmony_cinvkm_falcon_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, 478c2ecf20Sopenharmony_ci int align, struct nvkm_gpuobj **pgpuobj) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci return nvkm_gpuobj_new(object->engine->subdev.device, 256, 508c2ecf20Sopenharmony_ci align, true, parent, pgpuobj); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic const struct nvkm_object_func 548c2ecf20Sopenharmony_cinvkm_falcon_cclass = { 558c2ecf20Sopenharmony_ci .bind = nvkm_falcon_cclass_bind, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void 598c2ecf20Sopenharmony_cinvkm_falcon_intr(struct nvkm_engine *engine) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct nvkm_falcon *falcon = nvkm_falcon(engine); 628c2ecf20Sopenharmony_ci struct nvkm_subdev *subdev = &falcon->engine.subdev; 638c2ecf20Sopenharmony_ci struct nvkm_device *device = subdev->device; 648c2ecf20Sopenharmony_ci const u32 base = falcon->addr; 658c2ecf20Sopenharmony_ci u32 dest = nvkm_rd32(device, base + 0x01c); 668c2ecf20Sopenharmony_ci u32 intr = nvkm_rd32(device, base + 0x008) & dest & ~(dest >> 16); 678c2ecf20Sopenharmony_ci u32 inst = nvkm_rd32(device, base + 0x050) & 0x3fffffff; 688c2ecf20Sopenharmony_ci struct nvkm_fifo_chan *chan; 698c2ecf20Sopenharmony_ci unsigned long flags; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (intr & 0x00000040) { 748c2ecf20Sopenharmony_ci if (falcon->func->intr) { 758c2ecf20Sopenharmony_ci falcon->func->intr(falcon, chan); 768c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x004, 0x00000040); 778c2ecf20Sopenharmony_ci intr &= ~0x00000040; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (intr & 0x00000010) { 828c2ecf20Sopenharmony_ci nvkm_debug(subdev, "ucode halted\n"); 838c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x004, 0x00000010); 848c2ecf20Sopenharmony_ci intr &= ~0x00000010; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (intr) { 888c2ecf20Sopenharmony_ci nvkm_error(subdev, "intr %08x\n", intr); 898c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x004, intr); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci nvkm_fifo_chan_put(device->fifo, flags, &chan); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int 968c2ecf20Sopenharmony_cinvkm_falcon_fini(struct nvkm_engine *engine, bool suspend) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct nvkm_falcon *falcon = nvkm_falcon(engine); 998c2ecf20Sopenharmony_ci struct nvkm_device *device = falcon->engine.subdev.device; 1008c2ecf20Sopenharmony_ci const u32 base = falcon->addr; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (!suspend) { 1038c2ecf20Sopenharmony_ci nvkm_memory_unref(&falcon->core); 1048c2ecf20Sopenharmony_ci if (falcon->external) { 1058c2ecf20Sopenharmony_ci vfree(falcon->data.data); 1068c2ecf20Sopenharmony_ci vfree(falcon->code.data); 1078c2ecf20Sopenharmony_ci falcon->code.data = NULL; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (nvkm_mc_enabled(device, engine->subdev.index)) { 1128c2ecf20Sopenharmony_ci nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000); 1138c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x014, 0xffffffff); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void * 1198c2ecf20Sopenharmony_civmemdup(const void *src, size_t len) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci void *p = vmalloc(len); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (p) 1248c2ecf20Sopenharmony_ci memcpy(p, src, len); 1258c2ecf20Sopenharmony_ci return p; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int 1298c2ecf20Sopenharmony_cinvkm_falcon_oneinit(struct nvkm_engine *engine) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct nvkm_falcon *falcon = nvkm_falcon(engine); 1328c2ecf20Sopenharmony_ci struct nvkm_subdev *subdev = &falcon->engine.subdev; 1338c2ecf20Sopenharmony_ci struct nvkm_device *device = subdev->device; 1348c2ecf20Sopenharmony_ci const u32 base = falcon->addr; 1358c2ecf20Sopenharmony_ci u32 caps; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* determine falcon capabilities */ 1388c2ecf20Sopenharmony_ci if (device->chipset < 0xa3 || 1398c2ecf20Sopenharmony_ci device->chipset == 0xaa || device->chipset == 0xac) { 1408c2ecf20Sopenharmony_ci falcon->version = 0; 1418c2ecf20Sopenharmony_ci falcon->secret = (falcon->addr == 0x087000) ? 1 : 0; 1428c2ecf20Sopenharmony_ci } else { 1438c2ecf20Sopenharmony_ci caps = nvkm_rd32(device, base + 0x12c); 1448c2ecf20Sopenharmony_ci falcon->version = (caps & 0x0000000f); 1458c2ecf20Sopenharmony_ci falcon->secret = (caps & 0x00000030) >> 4; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci caps = nvkm_rd32(device, base + 0x108); 1498c2ecf20Sopenharmony_ci falcon->code.limit = (caps & 0x000001ff) << 8; 1508c2ecf20Sopenharmony_ci falcon->data.limit = (caps & 0x0003fe00) >> 1; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci nvkm_debug(subdev, "falcon version: %d\n", falcon->version); 1538c2ecf20Sopenharmony_ci nvkm_debug(subdev, "secret level: %d\n", falcon->secret); 1548c2ecf20Sopenharmony_ci nvkm_debug(subdev, "code limit: %d\n", falcon->code.limit); 1558c2ecf20Sopenharmony_ci nvkm_debug(subdev, "data limit: %d\n", falcon->data.limit); 1568c2ecf20Sopenharmony_ci return 0; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic int 1608c2ecf20Sopenharmony_cinvkm_falcon_init(struct nvkm_engine *engine) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct nvkm_falcon *falcon = nvkm_falcon(engine); 1638c2ecf20Sopenharmony_ci struct nvkm_subdev *subdev = &falcon->engine.subdev; 1648c2ecf20Sopenharmony_ci struct nvkm_device *device = subdev->device; 1658c2ecf20Sopenharmony_ci const struct firmware *fw; 1668c2ecf20Sopenharmony_ci char name[32] = "internal"; 1678c2ecf20Sopenharmony_ci const u32 base = falcon->addr; 1688c2ecf20Sopenharmony_ci int ret, i; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* wait for 'uc halted' to be signalled before continuing */ 1718c2ecf20Sopenharmony_ci if (falcon->secret && falcon->version < 4) { 1728c2ecf20Sopenharmony_ci if (!falcon->version) { 1738c2ecf20Sopenharmony_ci nvkm_msec(device, 2000, 1748c2ecf20Sopenharmony_ci if (nvkm_rd32(device, base + 0x008) & 0x00000010) 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci ); 1778c2ecf20Sopenharmony_ci } else { 1788c2ecf20Sopenharmony_ci nvkm_msec(device, 2000, 1798c2ecf20Sopenharmony_ci if (!(nvkm_rd32(device, base + 0x180) & 0x80000000)) 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci ); 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x004, 0x00000010); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* disable all interrupts */ 1878c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x014, 0xffffffff); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* no default ucode provided by the engine implementation, try and 1908c2ecf20Sopenharmony_ci * locate a "self-bootstrapping" firmware image for the engine 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci if (!falcon->code.data) { 1938c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x", 1948c2ecf20Sopenharmony_ci device->chipset, falcon->addr >> 12); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci ret = request_firmware(&fw, name, device->dev); 1978c2ecf20Sopenharmony_ci if (ret == 0) { 1988c2ecf20Sopenharmony_ci falcon->code.data = vmemdup(fw->data, fw->size); 1998c2ecf20Sopenharmony_ci falcon->code.size = fw->size; 2008c2ecf20Sopenharmony_ci falcon->data.data = NULL; 2018c2ecf20Sopenharmony_ci falcon->data.size = 0; 2028c2ecf20Sopenharmony_ci release_firmware(fw); 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci falcon->external = true; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* next step is to try and load "static code/data segment" firmware 2098c2ecf20Sopenharmony_ci * images for the engine 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci if (!falcon->code.data) { 2128c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd", 2138c2ecf20Sopenharmony_ci device->chipset, falcon->addr >> 12); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ret = request_firmware(&fw, name, device->dev); 2168c2ecf20Sopenharmony_ci if (ret) { 2178c2ecf20Sopenharmony_ci nvkm_error(subdev, "unable to load firmware data\n"); 2188c2ecf20Sopenharmony_ci return -ENODEV; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci falcon->data.data = vmemdup(fw->data, fw->size); 2228c2ecf20Sopenharmony_ci falcon->data.size = fw->size; 2238c2ecf20Sopenharmony_ci release_firmware(fw); 2248c2ecf20Sopenharmony_ci if (!falcon->data.data) 2258c2ecf20Sopenharmony_ci return -ENOMEM; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc", 2288c2ecf20Sopenharmony_ci device->chipset, falcon->addr >> 12); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci ret = request_firmware(&fw, name, device->dev); 2318c2ecf20Sopenharmony_ci if (ret) { 2328c2ecf20Sopenharmony_ci nvkm_error(subdev, "unable to load firmware code\n"); 2338c2ecf20Sopenharmony_ci return -ENODEV; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci falcon->code.data = vmemdup(fw->data, fw->size); 2378c2ecf20Sopenharmony_ci falcon->code.size = fw->size; 2388c2ecf20Sopenharmony_ci release_firmware(fw); 2398c2ecf20Sopenharmony_ci if (!falcon->code.data) 2408c2ecf20Sopenharmony_ci return -ENOMEM; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci nvkm_debug(subdev, "firmware: %s (%s)\n", name, falcon->data.data ? 2448c2ecf20Sopenharmony_ci "static code/data segments" : "self-bootstrapping"); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* ensure any "self-bootstrapping" firmware image is in vram */ 2478c2ecf20Sopenharmony_ci if (!falcon->data.data && !falcon->core) { 2488c2ecf20Sopenharmony_ci ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 2498c2ecf20Sopenharmony_ci falcon->code.size, 256, false, 2508c2ecf20Sopenharmony_ci &falcon->core); 2518c2ecf20Sopenharmony_ci if (ret) { 2528c2ecf20Sopenharmony_ci nvkm_error(subdev, "core allocation failed, %d\n", ret); 2538c2ecf20Sopenharmony_ci return ret; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci nvkm_kmap(falcon->core); 2578c2ecf20Sopenharmony_ci for (i = 0; i < falcon->code.size; i += 4) 2588c2ecf20Sopenharmony_ci nvkm_wo32(falcon->core, i, falcon->code.data[i / 4]); 2598c2ecf20Sopenharmony_ci nvkm_done(falcon->core); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* upload firmware bootloader (or the full code segments) */ 2638c2ecf20Sopenharmony_ci if (falcon->core) { 2648c2ecf20Sopenharmony_ci u64 addr = nvkm_memory_addr(falcon->core); 2658c2ecf20Sopenharmony_ci if (device->card_type < NV_C0) 2668c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x618, 0x04000000); 2678c2ecf20Sopenharmony_ci else 2688c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x618, 0x00000114); 2698c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x11c, 0); 2708c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x110, addr >> 8); 2718c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x114, 0); 2728c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x118, 0x00006610); 2738c2ecf20Sopenharmony_ci } else { 2748c2ecf20Sopenharmony_ci if (falcon->code.size > falcon->code.limit || 2758c2ecf20Sopenharmony_ci falcon->data.size > falcon->data.limit) { 2768c2ecf20Sopenharmony_ci nvkm_error(subdev, "ucode exceeds falcon limit(s)\n"); 2778c2ecf20Sopenharmony_ci return -EINVAL; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (falcon->version < 3) { 2818c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0xff8, 0x00100000); 2828c2ecf20Sopenharmony_ci for (i = 0; i < falcon->code.size / 4; i++) 2838c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0xff4, falcon->code.data[i]); 2848c2ecf20Sopenharmony_ci } else { 2858c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x180, 0x01000000); 2868c2ecf20Sopenharmony_ci for (i = 0; i < falcon->code.size / 4; i++) { 2878c2ecf20Sopenharmony_ci if ((i & 0x3f) == 0) 2888c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x188, i >> 6); 2898c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x184, falcon->code.data[i]); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* upload data segment (if necessary), zeroing the remainder */ 2958c2ecf20Sopenharmony_ci if (falcon->version < 3) { 2968c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0xff8, 0x00000000); 2978c2ecf20Sopenharmony_ci for (i = 0; !falcon->core && i < falcon->data.size / 4; i++) 2988c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0xff4, falcon->data.data[i]); 2998c2ecf20Sopenharmony_ci for (; i < falcon->data.limit; i += 4) 3008c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0xff4, 0x00000000); 3018c2ecf20Sopenharmony_ci } else { 3028c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x1c0, 0x01000000); 3038c2ecf20Sopenharmony_ci for (i = 0; !falcon->core && i < falcon->data.size / 4; i++) 3048c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x1c4, falcon->data.data[i]); 3058c2ecf20Sopenharmony_ci for (; i < falcon->data.limit / 4; i++) 3068c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x1c4, 0x00000000); 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* start it running */ 3108c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x10c, 0x00000001); /* BLOCK_ON_FIFO */ 3118c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x104, 0x00000000); /* ENTRY */ 3128c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x100, 0x00000002); /* TRIGGER */ 3138c2ecf20Sopenharmony_ci nvkm_wr32(device, base + 0x048, 0x00000003); /* FIFO | CHSW */ 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (falcon->func->init) 3168c2ecf20Sopenharmony_ci falcon->func->init(falcon); 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void * 3218c2ecf20Sopenharmony_cinvkm_falcon_dtor(struct nvkm_engine *engine) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci return nvkm_falcon(engine); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic const struct nvkm_engine_func 3278c2ecf20Sopenharmony_cinvkm_falcon = { 3288c2ecf20Sopenharmony_ci .dtor = nvkm_falcon_dtor, 3298c2ecf20Sopenharmony_ci .oneinit = nvkm_falcon_oneinit, 3308c2ecf20Sopenharmony_ci .init = nvkm_falcon_init, 3318c2ecf20Sopenharmony_ci .fini = nvkm_falcon_fini, 3328c2ecf20Sopenharmony_ci .intr = nvkm_falcon_intr, 3338c2ecf20Sopenharmony_ci .fifo.sclass = nvkm_falcon_oclass_get, 3348c2ecf20Sopenharmony_ci .cclass = &nvkm_falcon_cclass, 3358c2ecf20Sopenharmony_ci}; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ciint 3388c2ecf20Sopenharmony_cinvkm_falcon_new_(const struct nvkm_falcon_func *func, 3398c2ecf20Sopenharmony_ci struct nvkm_device *device, int index, bool enable, 3408c2ecf20Sopenharmony_ci u32 addr, struct nvkm_engine **pengine) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct nvkm_falcon *falcon; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (!(falcon = kzalloc(sizeof(*falcon), GFP_KERNEL))) 3458c2ecf20Sopenharmony_ci return -ENOMEM; 3468c2ecf20Sopenharmony_ci falcon->func = func; 3478c2ecf20Sopenharmony_ci falcon->addr = addr; 3488c2ecf20Sopenharmony_ci falcon->code.data = func->code.data; 3498c2ecf20Sopenharmony_ci falcon->code.size = func->code.size; 3508c2ecf20Sopenharmony_ci falcon->data.data = func->data.data; 3518c2ecf20Sopenharmony_ci falcon->data.size = func->data.size; 3528c2ecf20Sopenharmony_ci *pengine = &falcon->engine; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return nvkm_engine_ctor(&nvkm_falcon, device, index, 3558c2ecf20Sopenharmony_ci enable, &falcon->engine); 3568c2ecf20Sopenharmony_ci} 357