| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * 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 | 4 | */ |
|---|
| 8 | 5 | |
|---|
| 9 | 6 | #include <linux/platform_device.h> |
|---|
| .. | .. |
|---|
| 61 | 58 | static void falcon_copy_firmware_image(struct falcon *falcon, |
|---|
| 62 | 59 | const struct firmware *firmware) |
|---|
| 63 | 60 | { |
|---|
| 64 | | - u32 *firmware_vaddr = falcon->firmware.vaddr; |
|---|
| 65 | | - dma_addr_t daddr; |
|---|
| 61 | + u32 *virt = falcon->firmware.virt; |
|---|
| 66 | 62 | size_t i; |
|---|
| 67 | | - int err; |
|---|
| 68 | 63 | |
|---|
| 69 | 64 | /* copy the whole thing taking into account endianness */ |
|---|
| 70 | 65 | 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); |
|---|
| 66 | + virt[i] = le32_to_cpu(((u32 *)firmware->data)[i]); |
|---|
| 85 | 67 | } |
|---|
| 86 | 68 | |
|---|
| 87 | 69 | static int falcon_parse_firmware_image(struct falcon *falcon) |
|---|
| 88 | 70 | { |
|---|
| 89 | | - struct falcon_fw_bin_header_v1 *bin = (void *)falcon->firmware.vaddr; |
|---|
| 71 | + struct falcon_fw_bin_header_v1 *bin = (void *)falcon->firmware.virt; |
|---|
| 90 | 72 | struct falcon_fw_os_header_v1 *os; |
|---|
| 91 | 73 | |
|---|
| 92 | 74 | /* endian problems would show up right here */ |
|---|
| .. | .. |
|---|
| 107 | 89 | return -EINVAL; |
|---|
| 108 | 90 | } |
|---|
| 109 | 91 | |
|---|
| 110 | | - os = falcon->firmware.vaddr + bin->os_header_offset; |
|---|
| 92 | + os = falcon->firmware.virt + bin->os_header_offset; |
|---|
| 111 | 93 | |
|---|
| 112 | 94 | falcon->firmware.bin_data.size = bin->os_size; |
|---|
| 113 | 95 | falcon->firmware.bin_data.offset = bin->os_data_offset; |
|---|
| .. | .. |
|---|
| 128 | 110 | if (err < 0) |
|---|
| 129 | 111 | return err; |
|---|
| 130 | 112 | |
|---|
| 113 | + falcon->firmware.size = falcon->firmware.firmware->size; |
|---|
| 114 | + |
|---|
| 131 | 115 | return 0; |
|---|
| 132 | 116 | } |
|---|
| 133 | 117 | |
|---|
| .. | .. |
|---|
| 136 | 120 | const struct firmware *firmware = falcon->firmware.firmware; |
|---|
| 137 | 121 | int err; |
|---|
| 138 | 122 | |
|---|
| 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 (!falcon->firmware.vaddr) { |
|---|
| 145 | | - dev_err(falcon->dev, "dma memory mapping failed\n"); |
|---|
| 146 | | - return -ENOMEM; |
|---|
| 147 | | - } |
|---|
| 148 | | - |
|---|
| 149 | 123 | /* copy firmware image into local area. this also ensures endianness */ |
|---|
| 150 | 124 | falcon_copy_firmware_image(falcon, firmware); |
|---|
| 151 | 125 | |
|---|
| .. | .. |
|---|
| 153 | 127 | err = falcon_parse_firmware_image(falcon); |
|---|
| 154 | 128 | if (err < 0) { |
|---|
| 155 | 129 | dev_err(falcon->dev, "failed to parse firmware image\n"); |
|---|
| 156 | | - goto err_setup_firmware_image; |
|---|
| 130 | + return err; |
|---|
| 157 | 131 | } |
|---|
| 158 | 132 | |
|---|
| 159 | 133 | release_firmware(firmware); |
|---|
| 160 | 134 | falcon->firmware.firmware = NULL; |
|---|
| 161 | 135 | |
|---|
| 162 | 136 | 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 | 137 | } |
|---|
| 170 | 138 | |
|---|
| 171 | 139 | int falcon_init(struct falcon *falcon) |
|---|
| 172 | 140 | { |
|---|
| 173 | | - /* check mandatory ops */ |
|---|
| 174 | | - if (!falcon->ops || !falcon->ops->alloc || !falcon->ops->free) |
|---|
| 175 | | - return -EINVAL; |
|---|
| 176 | | - |
|---|
| 177 | | - falcon->firmware.vaddr = NULL; |
|---|
| 141 | + falcon->firmware.virt = NULL; |
|---|
| 178 | 142 | |
|---|
| 179 | 143 | return 0; |
|---|
| 180 | 144 | } |
|---|
| 181 | 145 | |
|---|
| 182 | 146 | void falcon_exit(struct falcon *falcon) |
|---|
| 183 | 147 | { |
|---|
| 184 | | - if (falcon->firmware.firmware) { |
|---|
| 148 | + if (falcon->firmware.firmware) |
|---|
| 185 | 149 | 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 | 150 | } |
|---|
| 196 | 151 | |
|---|
| 197 | 152 | int falcon_boot(struct falcon *falcon) |
|---|
| 198 | 153 | { |
|---|
| 199 | 154 | unsigned long offset; |
|---|
| 155 | + u32 value; |
|---|
| 200 | 156 | int err; |
|---|
| 201 | 157 | |
|---|
| 202 | | - if (!falcon->firmware.vaddr) |
|---|
| 158 | + if (!falcon->firmware.virt) |
|---|
| 203 | 159 | return -EINVAL; |
|---|
| 160 | + |
|---|
| 161 | + err = readl_poll_timeout(falcon->regs + FALCON_DMACTL, value, |
|---|
| 162 | + (value & (FALCON_DMACTL_IMEM_SCRUBBING | |
|---|
| 163 | + FALCON_DMACTL_DMEM_SCRUBBING)) == 0, |
|---|
| 164 | + 10, 10000); |
|---|
| 165 | + if (err < 0) |
|---|
| 166 | + return err; |
|---|
| 204 | 167 | |
|---|
| 205 | 168 | falcon_writel(falcon, 0, FALCON_DMACTL); |
|---|
| 206 | 169 | |
|---|
| 207 | 170 | /* setup the address of the binary data so Falcon can access it later */ |
|---|
| 208 | | - falcon_writel(falcon, (falcon->firmware.paddr + |
|---|
| 171 | + falcon_writel(falcon, (falcon->firmware.iova + |
|---|
| 209 | 172 | falcon->firmware.bin_data.offset) >> 8, |
|---|
| 210 | 173 | FALCON_DMATRFBASE); |
|---|
| 211 | 174 | |
|---|