root/drivers/gpu/drm/tegra/falcon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. falcon_writel
  2. falcon_wait_idle
  3. falcon_dma_wait_idle
  4. falcon_copy_chunk
  5. falcon_copy_firmware_image
  6. falcon_parse_firmware_image
  7. falcon_read_firmware
  8. falcon_load_firmware
  9. falcon_init
  10. falcon_exit
  11. falcon_boot
  12. falcon_execute_method

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

/* [<][>][^][v][top][bottom][index][help] */