18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 188c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 198c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 208c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci#include "priv.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <subdev/mc.h> 258c2ecf20Sopenharmony_ci#include <subdev/top.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_civoid 288c2ecf20Sopenharmony_cinvkm_falcon_load_imem(struct nvkm_falcon *falcon, void *data, u32 start, 298c2ecf20Sopenharmony_ci u32 size, u16 tag, u8 port, bool secure) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci if (secure && !falcon->secret) { 328c2ecf20Sopenharmony_ci nvkm_warn(falcon->user, 338c2ecf20Sopenharmony_ci "writing with secure tag on a non-secure falcon!\n"); 348c2ecf20Sopenharmony_ci return; 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci falcon->func->load_imem(falcon, data, start, size, tag, port, 388c2ecf20Sopenharmony_ci secure); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_civoid 428c2ecf20Sopenharmony_cinvkm_falcon_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start, 438c2ecf20Sopenharmony_ci u32 size, u8 port) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci mutex_lock(&falcon->dmem_mutex); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci falcon->func->load_dmem(falcon, data, start, size, port); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci mutex_unlock(&falcon->dmem_mutex); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_civoid 538c2ecf20Sopenharmony_cinvkm_falcon_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size, u8 port, 548c2ecf20Sopenharmony_ci void *data) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci mutex_lock(&falcon->dmem_mutex); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci falcon->func->read_dmem(falcon, start, size, port, data); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci mutex_unlock(&falcon->dmem_mutex); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_civoid 648c2ecf20Sopenharmony_cinvkm_falcon_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *inst) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci if (!falcon->func->bind_context) { 678c2ecf20Sopenharmony_ci nvkm_error(falcon->user, 688c2ecf20Sopenharmony_ci "Context binding not supported on this falcon!\n"); 698c2ecf20Sopenharmony_ci return; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci falcon->func->bind_context(falcon, inst); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_civoid 768c2ecf20Sopenharmony_cinvkm_falcon_set_start_addr(struct nvkm_falcon *falcon, u32 start_addr) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci falcon->func->set_start_addr(falcon, start_addr); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_civoid 828c2ecf20Sopenharmony_cinvkm_falcon_start(struct nvkm_falcon *falcon) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci falcon->func->start(falcon); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ciint 888c2ecf20Sopenharmony_cinvkm_falcon_enable(struct nvkm_falcon *falcon) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct nvkm_device *device = falcon->owner->device; 918c2ecf20Sopenharmony_ci enum nvkm_devidx id = falcon->owner->index; 928c2ecf20Sopenharmony_ci int ret; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci nvkm_mc_enable(device, id); 958c2ecf20Sopenharmony_ci ret = falcon->func->enable(falcon); 968c2ecf20Sopenharmony_ci if (ret) { 978c2ecf20Sopenharmony_ci nvkm_mc_disable(device, id); 988c2ecf20Sopenharmony_ci return ret; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_civoid 1058c2ecf20Sopenharmony_cinvkm_falcon_disable(struct nvkm_falcon *falcon) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct nvkm_device *device = falcon->owner->device; 1088c2ecf20Sopenharmony_ci enum nvkm_devidx id = falcon->owner->index; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* already disabled, return or wait_idle will timeout */ 1118c2ecf20Sopenharmony_ci if (!nvkm_mc_enabled(device, id)) 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci falcon->func->disable(falcon); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci nvkm_mc_disable(device, id); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ciint 1208c2ecf20Sopenharmony_cinvkm_falcon_reset(struct nvkm_falcon *falcon) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci if (!falcon->func->reset) { 1238c2ecf20Sopenharmony_ci nvkm_falcon_disable(falcon); 1248c2ecf20Sopenharmony_ci return nvkm_falcon_enable(falcon); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return falcon->func->reset(falcon); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ciint 1318c2ecf20Sopenharmony_cinvkm_falcon_wait_for_halt(struct nvkm_falcon *falcon, u32 ms) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci return falcon->func->wait_for_halt(falcon, ms); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciint 1378c2ecf20Sopenharmony_cinvkm_falcon_clear_interrupt(struct nvkm_falcon *falcon, u32 mask) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci return falcon->func->clear_interrupt(falcon, mask); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int 1438c2ecf20Sopenharmony_cinvkm_falcon_oneinit(struct nvkm_falcon *falcon) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci const struct nvkm_falcon_func *func = falcon->func; 1468c2ecf20Sopenharmony_ci const struct nvkm_subdev *subdev = falcon->owner; 1478c2ecf20Sopenharmony_ci u32 reg; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (!falcon->addr) { 1508c2ecf20Sopenharmony_ci falcon->addr = nvkm_top_addr(subdev->device, subdev->index); 1518c2ecf20Sopenharmony_ci if (WARN_ON(!falcon->addr)) 1528c2ecf20Sopenharmony_ci return -ENODEV; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci reg = nvkm_falcon_rd32(falcon, 0x12c); 1568c2ecf20Sopenharmony_ci falcon->version = reg & 0xf; 1578c2ecf20Sopenharmony_ci falcon->secret = (reg >> 4) & 0x3; 1588c2ecf20Sopenharmony_ci falcon->code.ports = (reg >> 8) & 0xf; 1598c2ecf20Sopenharmony_ci falcon->data.ports = (reg >> 12) & 0xf; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci reg = nvkm_falcon_rd32(falcon, 0x108); 1628c2ecf20Sopenharmony_ci falcon->code.limit = (reg & 0x1ff) << 8; 1638c2ecf20Sopenharmony_ci falcon->data.limit = (reg & 0x3fe00) >> 1; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (func->debug) { 1668c2ecf20Sopenharmony_ci u32 val = nvkm_falcon_rd32(falcon, func->debug); 1678c2ecf20Sopenharmony_ci falcon->debug = (val >> 20) & 0x1; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_civoid 1748c2ecf20Sopenharmony_cinvkm_falcon_put(struct nvkm_falcon *falcon, const struct nvkm_subdev *user) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci if (unlikely(!falcon)) 1778c2ecf20Sopenharmony_ci return; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci mutex_lock(&falcon->mutex); 1808c2ecf20Sopenharmony_ci if (falcon->user == user) { 1818c2ecf20Sopenharmony_ci nvkm_debug(falcon->user, "released %s falcon\n", falcon->name); 1828c2ecf20Sopenharmony_ci falcon->user = NULL; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci mutex_unlock(&falcon->mutex); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ciint 1888c2ecf20Sopenharmony_cinvkm_falcon_get(struct nvkm_falcon *falcon, const struct nvkm_subdev *user) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci int ret = 0; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci mutex_lock(&falcon->mutex); 1938c2ecf20Sopenharmony_ci if (falcon->user) { 1948c2ecf20Sopenharmony_ci nvkm_error(user, "%s falcon already acquired by %s!\n", 1958c2ecf20Sopenharmony_ci falcon->name, nvkm_subdev_name[falcon->user->index]); 1968c2ecf20Sopenharmony_ci mutex_unlock(&falcon->mutex); 1978c2ecf20Sopenharmony_ci return -EBUSY; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci nvkm_debug(user, "acquired %s falcon\n", falcon->name); 2018c2ecf20Sopenharmony_ci if (!falcon->oneinit) 2028c2ecf20Sopenharmony_ci ret = nvkm_falcon_oneinit(falcon); 2038c2ecf20Sopenharmony_ci falcon->user = user; 2048c2ecf20Sopenharmony_ci mutex_unlock(&falcon->mutex); 2058c2ecf20Sopenharmony_ci return ret; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_civoid 2098c2ecf20Sopenharmony_cinvkm_falcon_dtor(struct nvkm_falcon *falcon) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ciint 2148c2ecf20Sopenharmony_cinvkm_falcon_ctor(const struct nvkm_falcon_func *func, 2158c2ecf20Sopenharmony_ci struct nvkm_subdev *subdev, const char *name, u32 addr, 2168c2ecf20Sopenharmony_ci struct nvkm_falcon *falcon) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci falcon->func = func; 2198c2ecf20Sopenharmony_ci falcon->owner = subdev; 2208c2ecf20Sopenharmony_ci falcon->name = name; 2218c2ecf20Sopenharmony_ci falcon->addr = addr; 2228c2ecf20Sopenharmony_ci mutex_init(&falcon->mutex); 2238c2ecf20Sopenharmony_ci mutex_init(&falcon->dmem_mutex); 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_civoid 2288c2ecf20Sopenharmony_cinvkm_falcon_del(struct nvkm_falcon **pfalcon) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci if (*pfalcon) { 2318c2ecf20Sopenharmony_ci nvkm_falcon_dtor(*pfalcon); 2328c2ecf20Sopenharmony_ci kfree(*pfalcon); 2338c2ecf20Sopenharmony_ci *pfalcon = NULL; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci} 236