Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2015, NVIDIA Corporation.
0004  */
0005 
0006 #include <linux/platform_device.h>
0007 #include <linux/dma-mapping.h>
0008 #include <linux/firmware.h>
0009 #include <linux/pci_ids.h>
0010 #include <linux/iopoll.h>
0011 
0012 #include "falcon.h"
0013 #include "drm.h"
0014 
0015 enum falcon_memory {
0016     FALCON_MEMORY_IMEM,
0017     FALCON_MEMORY_DATA,
0018 };
0019 
0020 static void falcon_writel(struct falcon *falcon, u32 value, u32 offset)
0021 {
0022     writel(value, falcon->regs + offset);
0023 }
0024 
0025 int falcon_wait_idle(struct falcon *falcon)
0026 {
0027     u32 value;
0028 
0029     return readl_poll_timeout(falcon->regs + FALCON_IDLESTATE, value,
0030                   (value == 0), 10, 100000);
0031 }
0032 
0033 static int falcon_dma_wait_idle(struct falcon *falcon)
0034 {
0035     u32 value;
0036 
0037     return readl_poll_timeout(falcon->regs + FALCON_DMATRFCMD, value,
0038                   (value & FALCON_DMATRFCMD_IDLE), 10, 100000);
0039 }
0040 
0041 static int falcon_copy_chunk(struct falcon *falcon,
0042                  phys_addr_t base,
0043                  unsigned long offset,
0044                  enum falcon_memory target)
0045 {
0046     u32 cmd = FALCON_DMATRFCMD_SIZE_256B;
0047 
0048     if (target == FALCON_MEMORY_IMEM)
0049         cmd |= FALCON_DMATRFCMD_IMEM;
0050 
0051     /*
0052      * Use second DMA context (i.e. the one for firmware). Strictly
0053      * speaking, at this point both DMA contexts point to the firmware
0054      * stream ID, but this register's value will be reused by the firmware
0055      * for later DMA transactions, so we need to use the correct value.
0056      */
0057     cmd |= FALCON_DMATRFCMD_DMACTX(1);
0058 
0059     falcon_writel(falcon, offset, FALCON_DMATRFMOFFS);
0060     falcon_writel(falcon, base, FALCON_DMATRFFBOFFS);
0061     falcon_writel(falcon, cmd, FALCON_DMATRFCMD);
0062 
0063     return falcon_dma_wait_idle(falcon);
0064 }
0065 
0066 static void falcon_copy_firmware_image(struct falcon *falcon,
0067                        const struct firmware *firmware)
0068 {
0069     u32 *virt = falcon->firmware.virt;
0070     size_t i;
0071 
0072     /* copy the whole thing taking into account endianness */
0073     for (i = 0; i < firmware->size / sizeof(u32); i++)
0074         virt[i] = le32_to_cpu(((__le32 *)firmware->data)[i]);
0075 }
0076 
0077 static int falcon_parse_firmware_image(struct falcon *falcon)
0078 {
0079     struct falcon_fw_bin_header_v1 *bin = (void *)falcon->firmware.virt;
0080     struct falcon_fw_os_header_v1 *os;
0081 
0082     /* endian problems would show up right here */
0083     if (bin->magic != PCI_VENDOR_ID_NVIDIA && bin->magic != 0x10fe) {
0084         dev_err(falcon->dev, "incorrect firmware magic\n");
0085         return -EINVAL;
0086     }
0087 
0088     /* currently only version 1 is supported */
0089     if (bin->version != 1) {
0090         dev_err(falcon->dev, "unsupported firmware version\n");
0091         return -EINVAL;
0092     }
0093 
0094     /* check that the firmware size is consistent */
0095     if (bin->size > falcon->firmware.size) {
0096         dev_err(falcon->dev, "firmware image size inconsistency\n");
0097         return -EINVAL;
0098     }
0099 
0100     os = falcon->firmware.virt + bin->os_header_offset;
0101 
0102     falcon->firmware.bin_data.size = bin->os_size;
0103     falcon->firmware.bin_data.offset = bin->os_data_offset;
0104     falcon->firmware.code.offset = os->code_offset;
0105     falcon->firmware.code.size = os->code_size;
0106     falcon->firmware.data.offset = os->data_offset;
0107     falcon->firmware.data.size = os->data_size;
0108 
0109     return 0;
0110 }
0111 
0112 int falcon_read_firmware(struct falcon *falcon, const char *name)
0113 {
0114     int err;
0115 
0116     /* request_firmware prints error if it fails */
0117     err = request_firmware(&falcon->firmware.firmware, name, falcon->dev);
0118     if (err < 0)
0119         return err;
0120 
0121     falcon->firmware.size = falcon->firmware.firmware->size;
0122 
0123     return 0;
0124 }
0125 
0126 int falcon_load_firmware(struct falcon *falcon)
0127 {
0128     const struct firmware *firmware = falcon->firmware.firmware;
0129     int err;
0130 
0131     /* copy firmware image into local area. this also ensures endianness */
0132     falcon_copy_firmware_image(falcon, firmware);
0133 
0134     /* parse the image data */
0135     err = falcon_parse_firmware_image(falcon);
0136     if (err < 0) {
0137         dev_err(falcon->dev, "failed to parse firmware image\n");
0138         return err;
0139     }
0140 
0141     release_firmware(firmware);
0142     falcon->firmware.firmware = NULL;
0143 
0144     return 0;
0145 }
0146 
0147 int falcon_init(struct falcon *falcon)
0148 {
0149     falcon->firmware.virt = NULL;
0150 
0151     return 0;
0152 }
0153 
0154 void falcon_exit(struct falcon *falcon)
0155 {
0156     if (falcon->firmware.firmware)
0157         release_firmware(falcon->firmware.firmware);
0158 }
0159 
0160 int falcon_boot(struct falcon *falcon)
0161 {
0162     unsigned long offset;
0163     u32 value;
0164     int err;
0165 
0166     if (!falcon->firmware.virt)
0167         return -EINVAL;
0168 
0169     err = readl_poll_timeout(falcon->regs + FALCON_DMACTL, value,
0170                  (value & (FALCON_DMACTL_IMEM_SCRUBBING |
0171                        FALCON_DMACTL_DMEM_SCRUBBING)) == 0,
0172                  10, 10000);
0173     if (err < 0)
0174         return err;
0175 
0176     falcon_writel(falcon, 0, FALCON_DMACTL);
0177 
0178     /* setup the address of the binary data so Falcon can access it later */
0179     falcon_writel(falcon, (falcon->firmware.iova +
0180                    falcon->firmware.bin_data.offset) >> 8,
0181               FALCON_DMATRFBASE);
0182 
0183     /* copy the data segment into Falcon internal memory */
0184     for (offset = 0; offset < falcon->firmware.data.size; offset += 256)
0185         falcon_copy_chunk(falcon,
0186                   falcon->firmware.data.offset + offset,
0187                   offset, FALCON_MEMORY_DATA);
0188 
0189     /* copy the code segment into Falcon internal memory */
0190     for (offset = 0; offset < falcon->firmware.code.size; offset += 256)
0191         falcon_copy_chunk(falcon, falcon->firmware.code.offset + offset,
0192                   offset, FALCON_MEMORY_IMEM);
0193 
0194     /* setup falcon interrupts */
0195     falcon_writel(falcon, FALCON_IRQMSET_EXT(0xff) |
0196                   FALCON_IRQMSET_SWGEN1 |
0197                   FALCON_IRQMSET_SWGEN0 |
0198                   FALCON_IRQMSET_EXTERR |
0199                   FALCON_IRQMSET_HALT |
0200                   FALCON_IRQMSET_WDTMR,
0201               FALCON_IRQMSET);
0202     falcon_writel(falcon, FALCON_IRQDEST_EXT(0xff) |
0203                   FALCON_IRQDEST_SWGEN1 |
0204                   FALCON_IRQDEST_SWGEN0 |
0205                   FALCON_IRQDEST_EXTERR |
0206                   FALCON_IRQDEST_HALT,
0207               FALCON_IRQDEST);
0208 
0209     /* enable interface */
0210     falcon_writel(falcon, FALCON_ITFEN_MTHDEN |
0211                   FALCON_ITFEN_CTXEN,
0212               FALCON_ITFEN);
0213 
0214     /* boot falcon */
0215     falcon_writel(falcon, 0x00000000, FALCON_BOOTVEC);
0216     falcon_writel(falcon, FALCON_CPUCTL_STARTCPU, FALCON_CPUCTL);
0217 
0218     err = falcon_wait_idle(falcon);
0219     if (err < 0) {
0220         dev_err(falcon->dev, "Falcon boot failed due to timeout\n");
0221         return err;
0222     }
0223 
0224     return 0;
0225 }
0226 
0227 void falcon_execute_method(struct falcon *falcon, u32 method, u32 data)
0228 {
0229     falcon_writel(falcon, method >> 2, FALCON_UCLASS_METHOD_OFFSET);
0230     falcon_writel(falcon, data, FALCON_UCLASS_METHOD_DATA);
0231 }