1 /* 2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 #include <core/device.h> 23 #include <core/firmware.h> 24 25 #include <subdev/fb.h> 26 #include <subdev/mmu.h> 27 28 int 29 nvkm_firmware_load_name(const struct nvkm_subdev *subdev, const char *base, 30 const char *name, int ver, const struct firmware **pfw) 31 { 32 char path[64]; 33 int ret; 34 35 snprintf(path, sizeof(path), "%s%s", base, name); 36 ret = nvkm_firmware_get(subdev, path, ver, pfw); 37 if (ret < 0) 38 return ret; 39 40 return 0; 41 } 42 43 int 44 nvkm_firmware_load_blob(const struct nvkm_subdev *subdev, const char *base, 45 const char *name, int ver, struct nvkm_blob *blob) 46 { 47 const struct firmware *fw; 48 int ret; 49 50 ret = nvkm_firmware_load_name(subdev, base, name, ver, &fw); 51 if (ret == 0) { 52 blob->data = kmemdup(fw->data, fw->size, GFP_KERNEL); 53 blob->size = fw->size; 54 nvkm_firmware_put(fw); 55 if (!blob->data) 56 return -ENOMEM; 57 } 58 59 return ret; 60 } 61 62 /** 63 * nvkm_firmware_get - load firmware from the official nvidia/chip/ directory 64 * @subdev: subdevice that will use that firmware 65 * @fwname: name of firmware file to load 66 * @ver: firmware version to load 67 * @fw: firmware structure to load to 68 * 69 * Use this function to load firmware files in the form nvidia/chip/fwname.bin. 70 * Firmware files released by NVIDIA will always follow this format. 71 */ 72 int 73 nvkm_firmware_get(const struct nvkm_subdev *subdev, const char *fwname, int ver, 74 const struct firmware **fw) 75 { 76 struct nvkm_device *device = subdev->device; 77 char f[64]; 78 char cname[16]; 79 int i; 80 81 /* Convert device name to lowercase */ 82 strncpy(cname, device->chip->name, sizeof(cname)); 83 cname[sizeof(cname) - 1] = '\0'; 84 i = strlen(cname); 85 while (i) { 86 --i; 87 cname[i] = tolower(cname[i]); 88 } 89 90 if (ver != 0) 91 snprintf(f, sizeof(f), "nvidia/%s/%s-%d.bin", cname, fwname, ver); 92 else 93 snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname); 94 95 if (!firmware_request_nowarn(fw, f, device->dev)) { 96 nvkm_debug(subdev, "firmware \"%s\" loaded - %zu byte(s)\n", 97 f, (*fw)->size); 98 return 0; 99 } 100 101 nvkm_debug(subdev, "firmware \"%s\" unavailable\n", f); 102 return -ENOENT; 103 } 104 105 /* 106 * nvkm_firmware_put - release firmware loaded with nvkm_firmware_get 107 */ 108 void 109 nvkm_firmware_put(const struct firmware *fw) 110 { 111 release_firmware(fw); 112 } 113 114 #define nvkm_firmware_mem(p) container_of((p), struct nvkm_firmware, mem.memory) 115 116 static int 117 nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm, 118 struct nvkm_vma *vma, void *argv, u32 argc) 119 { 120 struct nvkm_firmware *fw = nvkm_firmware_mem(memory); 121 struct nvkm_vmm_map map = { 122 .memory = &fw->mem.memory, 123 .offset = offset, 124 .sgl = &fw->mem.sgl, 125 }; 126 127 if (WARN_ON(fw->func->type != NVKM_FIRMWARE_IMG_DMA)) 128 return -ENOSYS; 129 130 return nvkm_vmm_map(vmm, vma, argv, argc, &map); 131 } 132 133 static u64 134 nvkm_firmware_mem_size(struct nvkm_memory *memory) 135 { 136 return sg_dma_len(&nvkm_firmware_mem(memory)->mem.sgl); 137 } 138 139 static u64 140 nvkm_firmware_mem_addr(struct nvkm_memory *memory) 141 { 142 return nvkm_firmware_mem(memory)->phys; 143 } 144 145 static u8 146 nvkm_firmware_mem_page(struct nvkm_memory *memory) 147 { 148 return PAGE_SHIFT; 149 } 150 151 static enum nvkm_memory_target 152 nvkm_firmware_mem_target(struct nvkm_memory *memory) 153 { 154 if (nvkm_firmware_mem(memory)->device->func->tegra) 155 return NVKM_MEM_TARGET_NCOH; 156 157 return NVKM_MEM_TARGET_HOST; 158 } 159 160 static void * 161 nvkm_firmware_mem_dtor(struct nvkm_memory *memory) 162 { 163 return NULL; 164 } 165 166 static const struct nvkm_memory_func 167 nvkm_firmware_mem = { 168 .dtor = nvkm_firmware_mem_dtor, 169 .target = nvkm_firmware_mem_target, 170 .page = nvkm_firmware_mem_page, 171 .addr = nvkm_firmware_mem_addr, 172 .size = nvkm_firmware_mem_size, 173 .map = nvkm_firmware_mem_map, 174 }; 175 176 void 177 nvkm_firmware_dtor(struct nvkm_firmware *fw) 178 { 179 struct nvkm_memory *memory = &fw->mem.memory; 180 181 if (!fw->img) 182 return; 183 184 switch (fw->func->type) { 185 case NVKM_FIRMWARE_IMG_RAM: 186 kfree(fw->img); 187 break; 188 case NVKM_FIRMWARE_IMG_DMA: 189 nvkm_memory_unref(&memory); 190 dma_free_coherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), fw->img, fw->phys); 191 break; 192 default: 193 WARN_ON(1); 194 break; 195 } 196 197 fw->img = NULL; 198 } 199 200 int 201 nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name, 202 struct nvkm_device *device, const void *src, int len, struct nvkm_firmware *fw) 203 { 204 fw->func = func; 205 fw->name = name; 206 fw->device = device; 207 fw->len = len; 208 209 switch (fw->func->type) { 210 case NVKM_FIRMWARE_IMG_RAM: 211 fw->img = kmemdup(src, fw->len, GFP_KERNEL); 212 break; 213 case NVKM_FIRMWARE_IMG_DMA: { 214 dma_addr_t addr; 215 216 len = ALIGN(fw->len, PAGE_SIZE); 217 218 fw->img = dma_alloc_coherent(fw->device->dev, len, &addr, GFP_KERNEL); 219 if (fw->img) { 220 memcpy(fw->img, src, fw->len); 221 fw->phys = addr; 222 } 223 224 sg_init_one(&fw->mem.sgl, fw->img, len); 225 sg_dma_address(&fw->mem.sgl) = fw->phys; 226 sg_dma_len(&fw->mem.sgl) = len; 227 } 228 break; 229 default: 230 WARN_ON(1); 231 return -EINVAL; 232 } 233 234 if (!fw->img) 235 return -ENOMEM; 236 237 nvkm_memory_ctor(&nvkm_firmware_mem, &fw->mem.memory); 238 return 0; 239 } 240