1 /* 2 * Copyright (c) 2015, NVIDIA Corporation. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/platform_device.h> 10 #include <linux/dma-mapping.h> 11 #include <linux/firmware.h> 12 #include <linux/pci_ids.h> 13 #include <linux/iopoll.h> 14 15 #include "falcon.h" 16 #include "drm.h" 17 18 enum falcon_memory { 19 FALCON_MEMORY_IMEM, 20 FALCON_MEMORY_DATA, 21 }; 22 23 static void falcon_writel(struct falcon *falcon, u32 value, u32 offset) 24 { 25 writel(value, falcon->regs + offset); 26 } 27 28 int falcon_wait_idle(struct falcon *falcon) 29 { 30 u32 value; 31 32 return readl_poll_timeout(falcon->regs + FALCON_IDLESTATE, value, 33 (value == 0), 10, 100000); 34 } 35 36 static int falcon_dma_wait_idle(struct falcon *falcon) 37 { 38 u32 value; 39 40 return readl_poll_timeout(falcon->regs + FALCON_DMATRFCMD, value, 41 (value & FALCON_DMATRFCMD_IDLE), 10, 100000); 42 } 43 44 static int falcon_copy_chunk(struct falcon *falcon, 45 phys_addr_t base, 46 unsigned long offset, 47 enum falcon_memory target) 48 { 49 u32 cmd = FALCON_DMATRFCMD_SIZE_256B; 50 51 if (target == FALCON_MEMORY_IMEM) 52 cmd |= FALCON_DMATRFCMD_IMEM; 53 54 falcon_writel(falcon, offset, FALCON_DMATRFMOFFS); 55 falcon_writel(falcon, base, FALCON_DMATRFFBOFFS); 56 falcon_writel(falcon, cmd, FALCON_DMATRFCMD); 57 58 return falcon_dma_wait_idle(falcon); 59 } 60 61 static void falcon_copy_firmware_image(struct falcon *falcon, 62 const struct firmware *firmware) 63 { 64 u32 *firmware_vaddr = falcon->firmware.vaddr; 65 dma_addr_t daddr; 66 size_t i; 67 int err; 68 69 /* copy the whole thing taking into account endianness */ 70 for (i = 0; i < firmware->size / sizeof(u32); i++) 71 firmware_vaddr[i] = le32_to_cpu(((u32 *)firmware->data)[i]); 72 73 /* ensure that caches are flushed and falcon can see the firmware */ 74 daddr = dma_map_single(falcon->dev, firmware_vaddr, 75 falcon->firmware.size, DMA_TO_DEVICE); 76 err = dma_mapping_error(falcon->dev, daddr); 77 if (err) { 78 dev_err(falcon->dev, "failed to map firmware: %d\n", err); 79 return; 80 } 81 dma_sync_single_for_device(falcon->dev, daddr, 82 falcon->firmware.size, DMA_TO_DEVICE); 83 dma_unmap_single(falcon->dev, daddr, falcon->firmware.size, 84 DMA_TO_DEVICE); 85 } 86 87 static int falcon_parse_firmware_image(struct falcon *falcon) 88 { 89 struct falcon_fw_bin_header_v1 *bin = (void *)falcon->firmware.vaddr; 90 struct falcon_fw_os_header_v1 *os; 91 92 /* endian problems would show up right here */ 93 if (bin->magic != PCI_VENDOR_ID_NVIDIA) { 94 dev_err(falcon->dev, "incorrect firmware magic\n"); 95 return -EINVAL; 96 } 97 98 /* currently only version 1 is supported */ 99 if (bin->version != 1) { 100 dev_err(falcon->dev, "unsupported firmware version\n"); 101 return -EINVAL; 102 } 103 104 /* check that the firmware size is consistent */ 105 if (bin->size > falcon->firmware.size) { 106 dev_err(falcon->dev, "firmware image size inconsistency\n"); 107 return -EINVAL; 108 } 109 110 os = falcon->firmware.vaddr + bin->os_header_offset; 111 112 falcon->firmware.bin_data.size = bin->os_size; 113 falcon->firmware.bin_data.offset = bin->os_data_offset; 114 falcon->firmware.code.offset = os->code_offset; 115 falcon->firmware.code.size = os->code_size; 116 falcon->firmware.data.offset = os->data_offset; 117 falcon->firmware.data.size = os->data_size; 118 119 return 0; 120 } 121 122 int falcon_read_firmware(struct falcon *falcon, const char *name) 123 { 124 int err; 125 126 /* request_firmware prints error if it fails */ 127 err = request_firmware(&falcon->firmware.firmware, name, falcon->dev); 128 if (err < 0) 129 return err; 130 131 return 0; 132 } 133 134 int falcon_load_firmware(struct falcon *falcon) 135 { 136 const struct firmware *firmware = falcon->firmware.firmware; 137 int err; 138 139 falcon->firmware.size = firmware->size; 140 141 /* allocate iova space for the firmware */ 142 falcon->firmware.vaddr = falcon->ops->alloc(falcon, firmware->size, 143 &falcon->firmware.paddr); 144 if (IS_ERR(falcon->firmware.vaddr)) { 145 dev_err(falcon->dev, "DMA memory mapping failed\n"); 146 return PTR_ERR(falcon->firmware.vaddr); 147 } 148 149 /* copy firmware image into local area. this also ensures endianness */ 150 falcon_copy_firmware_image(falcon, firmware); 151 152 /* parse the image data */ 153 err = falcon_parse_firmware_image(falcon); 154 if (err < 0) { 155 dev_err(falcon->dev, "failed to parse firmware image\n"); 156 goto err_setup_firmware_image; 157 } 158 159 release_firmware(firmware); 160 falcon->firmware.firmware = NULL; 161 162 return 0; 163 164 err_setup_firmware_image: 165 falcon->ops->free(falcon, falcon->firmware.size, 166 falcon->firmware.paddr, falcon->firmware.vaddr); 167 168 return err; 169 } 170 171 int falcon_init(struct falcon *falcon) 172 { 173 /* check mandatory ops */ 174 if (!falcon->ops || !falcon->ops->alloc || !falcon->ops->free) 175 return -EINVAL; 176 177 falcon->firmware.vaddr = NULL; 178 179 return 0; 180 } 181 182 void falcon_exit(struct falcon *falcon) 183 { 184 if (falcon->firmware.firmware) { 185 release_firmware(falcon->firmware.firmware); 186 falcon->firmware.firmware = NULL; 187 } 188 189 if (falcon->firmware.vaddr) { 190 falcon->ops->free(falcon, falcon->firmware.size, 191 falcon->firmware.paddr, 192 falcon->firmware.vaddr); 193 falcon->firmware.vaddr = NULL; 194 } 195 } 196 197 int falcon_boot(struct falcon *falcon) 198 { 199 unsigned long offset; 200 u32 value; 201 int err; 202 203 if (!falcon->firmware.vaddr) 204 return -EINVAL; 205 206 err = readl_poll_timeout(falcon->regs + FALCON_DMACTL, value, 207 (value & (FALCON_DMACTL_IMEM_SCRUBBING | 208 FALCON_DMACTL_DMEM_SCRUBBING)) == 0, 209 10, 10000); 210 if (err < 0) 211 return err; 212 213 falcon_writel(falcon, 0, FALCON_DMACTL); 214 215 /* setup the address of the binary data so Falcon can access it later */ 216 falcon_writel(falcon, (falcon->firmware.paddr + 217 falcon->firmware.bin_data.offset) >> 8, 218 FALCON_DMATRFBASE); 219 220 /* copy the data segment into Falcon internal memory */ 221 for (offset = 0; offset < falcon->firmware.data.size; offset += 256) 222 falcon_copy_chunk(falcon, 223 falcon->firmware.data.offset + offset, 224 offset, FALCON_MEMORY_DATA); 225 226 /* copy the first code segment into Falcon internal memory */ 227 falcon_copy_chunk(falcon, falcon->firmware.code.offset, 228 0, FALCON_MEMORY_IMEM); 229 230 /* setup falcon interrupts */ 231 falcon_writel(falcon, FALCON_IRQMSET_EXT(0xff) | 232 FALCON_IRQMSET_SWGEN1 | 233 FALCON_IRQMSET_SWGEN0 | 234 FALCON_IRQMSET_EXTERR | 235 FALCON_IRQMSET_HALT | 236 FALCON_IRQMSET_WDTMR, 237 FALCON_IRQMSET); 238 falcon_writel(falcon, FALCON_IRQDEST_EXT(0xff) | 239 FALCON_IRQDEST_SWGEN1 | 240 FALCON_IRQDEST_SWGEN0 | 241 FALCON_IRQDEST_EXTERR | 242 FALCON_IRQDEST_HALT, 243 FALCON_IRQDEST); 244 245 /* enable interface */ 246 falcon_writel(falcon, FALCON_ITFEN_MTHDEN | 247 FALCON_ITFEN_CTXEN, 248 FALCON_ITFEN); 249 250 /* boot falcon */ 251 falcon_writel(falcon, 0x00000000, FALCON_BOOTVEC); 252 falcon_writel(falcon, FALCON_CPUCTL_STARTCPU, FALCON_CPUCTL); 253 254 err = falcon_wait_idle(falcon); 255 if (err < 0) { 256 dev_err(falcon->dev, "Falcon boot failed due to timeout\n"); 257 return err; 258 } 259 260 return 0; 261 } 262 263 void falcon_execute_method(struct falcon *falcon, u32 method, u32 data) 264 { 265 falcon_writel(falcon, method >> 2, FALCON_UCLASS_METHOD_OFFSET); 266 falcon_writel(falcon, data, FALCON_UCLASS_METHOD_DATA); 267 } 268