diff --git a/drivers/gpu/host1x-nvhost/Makefile b/drivers/gpu/host1x-nvhost/Makefile index 9cab78f0..919e05fc 100644 --- a/drivers/gpu/host1x-nvhost/Makefile +++ b/drivers/gpu/host1x-nvhost/Makefile @@ -6,6 +6,6 @@ ccflags-y += -DCONFIG_TEGRA_HOST1X ccflags-y += -Werror -host1x-nvhost-objs = nvhost.o falcon.o +host1x-nvhost-objs = nvhost.o obj-m += host1x-nvhost.o diff --git a/drivers/gpu/host1x-nvhost/falcon.c b/drivers/gpu/host1x-nvhost/falcon.c deleted file mode 100644 index 7a1a8dfe..00000000 --- a/drivers/gpu/host1x-nvhost/falcon.c +++ /dev/null @@ -1,213 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015-2023, NVIDIA Corporation. All rights reserved. - */ - -#include -#include -#include -#include -#include - -#include "falcon.h" - -enum falcon_memory { - FALCON_MEMORY_IMEM, - FALCON_MEMORY_DATA, -}; - -static void falcon_writel(struct falcon *falcon, u32 value, u32 offset) -{ - writel(value, falcon->regs + offset); -} - -int falcon_wait_idle(struct falcon *falcon) -{ - u32 value; - - return readl_poll_timeout(falcon->regs + FALCON_IDLESTATE, value, - (value == 0), 10, 100000); -} - -static int falcon_dma_wait_idle(struct falcon *falcon) -{ - u32 value; - - return readl_poll_timeout(falcon->regs + FALCON_DMATRFCMD, value, - (value & FALCON_DMATRFCMD_IDLE), 10, 100000); -} - -static int falcon_copy_chunk(struct falcon *falcon, - phys_addr_t base, - unsigned long offset, - enum falcon_memory target) -{ - u32 cmd = FALCON_DMATRFCMD_SIZE_256B; - - if (target == FALCON_MEMORY_IMEM) - cmd |= FALCON_DMATRFCMD_IMEM; - - falcon_writel(falcon, offset, FALCON_DMATRFMOFFS); - falcon_writel(falcon, base, FALCON_DMATRFFBOFFS); - falcon_writel(falcon, cmd, FALCON_DMATRFCMD); - - return falcon_dma_wait_idle(falcon); -} - -static void falcon_copy_firmware_image(struct falcon *falcon, - const struct firmware *firmware) -{ - u32 *virt = falcon->firmware.virt; - size_t i; - - /* copy the whole thing taking into account endianness */ - for (i = 0; i < firmware->size / sizeof(u32); i++) - virt[i] = le32_to_cpu(((__le32 *)firmware->data)[i]); -} - -static int falcon_parse_firmware_image(struct falcon *falcon) -{ - struct falcon_fw_bin_header_v1 *bin = (void *)falcon->firmware.virt; - struct falcon_fw_os_header_v1 *os; - - /* endian problems would show up right here */ - if (bin->magic != PCI_VENDOR_ID_NVIDIA && bin->magic != 0x10fe) { - dev_err(falcon->dev, "incorrect firmware magic\n"); - return -EINVAL; - } - - /* currently only version 1 is supported */ - if (bin->version != 1) { - dev_err(falcon->dev, "unsupported firmware version\n"); - return -EINVAL; - } - - /* check that the firmware size is consistent */ - if (bin->size > falcon->firmware.size) { - dev_err(falcon->dev, "firmware image size inconsistency\n"); - return -EINVAL; - } - - os = falcon->firmware.virt + bin->os_header_offset; - - falcon->firmware.bin_data.size = bin->os_size; - falcon->firmware.bin_data.offset = bin->os_data_offset; - falcon->firmware.code.offset = os->code_offset; - falcon->firmware.code.size = os->code_size; - falcon->firmware.data.offset = os->data_offset; - falcon->firmware.data.size = os->data_size; - - return 0; -} - -int falcon_read_firmware(struct falcon *falcon, const char *name) -{ - int err, retry_count=10; - -retry_request: - /* request_firmware prints error if it fails */ - err = request_firmware_direct(&falcon->firmware.firmware, name, falcon->dev); - if (err == -EINTR && retry_count) { - retry_count--; - goto retry_request; - } - - if (err < 0) - return err; - - falcon->firmware.size = falcon->firmware.firmware->size; - - return 0; -} - -int falcon_load_firmware(struct falcon *falcon) -{ - const struct firmware *firmware = falcon->firmware.firmware; - int err; - - /* copy firmware image into local area. this also ensures endianness */ - falcon_copy_firmware_image(falcon, firmware); - - /* parse the image data */ - err = falcon_parse_firmware_image(falcon); - if (err < 0) { - dev_err(falcon->dev, "failed to parse firmware image\n"); - return err; - } - - release_firmware(firmware); - falcon->firmware.firmware = NULL; - - return 0; -} - -int falcon_init(struct falcon *falcon) -{ - falcon->firmware.virt = NULL; - - return 0; -} - -void falcon_exit(struct falcon *falcon) -{ - if (falcon->firmware.firmware) - release_firmware(falcon->firmware.firmware); -} - -int falcon_boot(struct falcon *falcon) -{ - unsigned long offset; - u32 value; - int err; - - if (!falcon->firmware.virt) - return -EINVAL; - - err = readl_poll_timeout(falcon->regs + FALCON_DMACTL, value, - (value & (FALCON_DMACTL_IMEM_SCRUBBING | - FALCON_DMACTL_DMEM_SCRUBBING)) == 0, - 10, 10000); - if (err < 0) - return err; - - falcon_writel(falcon, 0, FALCON_DMACTL); - - /* setup the address of the binary data so Falcon can access it later */ - falcon_writel(falcon, (falcon->firmware.iova + - falcon->firmware.bin_data.offset) >> 8, - FALCON_DMATRFBASE); - - /* copy the data segment into Falcon internal memory */ - for (offset = 0; offset < falcon->firmware.data.size; offset += 256) - falcon_copy_chunk(falcon, - falcon->firmware.data.offset + offset, - offset, FALCON_MEMORY_DATA); - - /* copy the code segment into Falcon internal memory */ - for (offset = 0; offset < falcon->firmware.code.size; offset += 256) - falcon_copy_chunk(falcon, falcon->firmware.code.offset + offset, - offset, FALCON_MEMORY_IMEM); - - /* enable interface */ - falcon_writel(falcon, FALCON_ITFEN_MTHDEN | - FALCON_ITFEN_CTXEN, - FALCON_ITFEN); - - /* boot falcon */ - falcon_writel(falcon, 0x00000000, FALCON_BOOTVEC); - falcon_writel(falcon, FALCON_CPUCTL_STARTCPU, FALCON_CPUCTL); - - err = falcon_wait_idle(falcon); - if (err < 0) { - dev_err(falcon->dev, "Falcon boot failed due to timeout\n"); - return err; - } - - return 0; -} - -void falcon_execute_method(struct falcon *falcon, u32 method, u32 data) -{ - falcon_writel(falcon, method >> 2, FALCON_UCLASS_METHOD_OFFSET); - falcon_writel(falcon, data, FALCON_UCLASS_METHOD_DATA); -} diff --git a/drivers/gpu/host1x-nvhost/falcon.h b/drivers/gpu/host1x-nvhost/falcon.h deleted file mode 100644 index 3c4a039a..00000000 --- a/drivers/gpu/host1x-nvhost/falcon.h +++ /dev/null @@ -1,114 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015-2022, NVIDIA Corporation. All rights reserved. - */ - -#ifndef _FALCON_H_ -#define _FALCON_H_ - -#include - -#define FALCON_UCLASS_METHOD_OFFSET 0x00000040 - -#define FALCON_UCLASS_METHOD_DATA 0x00000044 - -#define FALCON_IRQMSET 0x00001010 -#define FALCON_IRQMSET_WDTMR (1 << 1) -#define FALCON_IRQMSET_HALT (1 << 4) -#define FALCON_IRQMSET_EXTERR (1 << 5) -#define FALCON_IRQMSET_SWGEN0 (1 << 6) -#define FALCON_IRQMSET_SWGEN1 (1 << 7) -#define FALCON_IRQMSET_EXT(v) (((v) & 0xff) << 8) - -#define FALCON_IRQDEST 0x0000101c -#define FALCON_IRQDEST_HALT (1 << 4) -#define FALCON_IRQDEST_EXTERR (1 << 5) -#define FALCON_IRQDEST_SWGEN0 (1 << 6) -#define FALCON_IRQDEST_SWGEN1 (1 << 7) -#define FALCON_IRQDEST_EXT(v) (((v) & 0xff) << 8) - -#define FALCON_ITFEN 0x00001048 -#define FALCON_ITFEN_CTXEN (1 << 0) -#define FALCON_ITFEN_MTHDEN (1 << 1) - -#define FALCON_IDLESTATE 0x0000104c - -#define FALCON_CPUCTL 0x00001100 -#define FALCON_CPUCTL_STARTCPU (1 << 1) - -#define FALCON_BOOTVEC 0x00001104 - -#define FALCON_DMACTL 0x0000110c -#define FALCON_DMACTL_DMEM_SCRUBBING (1 << 1) -#define FALCON_DMACTL_IMEM_SCRUBBING (1 << 2) - -#define FALCON_DMATRFBASE 0x00001110 - -#define FALCON_DMATRFMOFFS 0x00001114 - -#define FALCON_DMATRFCMD 0x00001118 -#define FALCON_DMATRFCMD_IDLE (1 << 1) -#define FALCON_DMATRFCMD_IMEM (1 << 4) -#define FALCON_DMATRFCMD_SIZE_256B (6 << 8) - -#define FALCON_DMATRFFBOFFS 0x0000111c - -struct falcon_fw_bin_header_v1 { - u32 magic; /* 0x10de */ - u32 version; /* version of bin format (1) */ - u32 size; /* entire image size including this header */ - u32 os_header_offset; - u32 os_data_offset; - u32 os_size; -}; - -struct falcon_fw_os_app_v1 { - u32 offset; - u32 size; -}; - -struct falcon_fw_os_header_v1 { - u32 code_offset; - u32 code_size; - u32 data_offset; - u32 data_size; -}; - -struct falcon_firmware_section { - unsigned long offset; - size_t size; -}; - -struct falcon_firmware { - /* Firmware after it is read but not loaded */ - const struct firmware *firmware; - - /* Raw firmware data */ - dma_addr_t iova; - dma_addr_t phys; - void *virt; - size_t size; - - /* Parsed firmware information */ - struct falcon_firmware_section bin_data; - struct falcon_firmware_section data; - struct falcon_firmware_section code; -}; - -struct falcon { - /* Set by falcon client */ - struct device *dev; - void __iomem *regs; - - struct falcon_firmware firmware; -}; - -int falcon_init(struct falcon *falcon); -void falcon_exit(struct falcon *falcon); -int falcon_read_firmware(struct falcon *falcon, const char *firmware_name); -int falcon_load_firmware(struct falcon *falcon); -int falcon_boot(struct falcon *falcon); -void falcon_execute_method(struct falcon *falcon, u32 method, u32 data); -int falcon_wait_idle(struct falcon *falcon); - -#endif /* _FALCON_H_ */ diff --git a/drivers/gpu/host1x-nvhost/nvhost.c b/drivers/gpu/host1x-nvhost/nvhost.c index e3bf506d..b2729055 100644 --- a/drivers/gpu/host1x-nvhost/nvhost.c +++ b/drivers/gpu/host1x-nvhost/nvhost.c @@ -20,8 +20,7 @@ #include #include #include - -#include "falcon.h" +#include #define TEGRA194_SYNCPT_PAGE_SIZE 0x1000 #define TEGRA194_SYNCPT_SHIM_BASE 0x60000000 @@ -39,6 +38,35 @@ #define NVHOST_NUM_CDEV 1 +struct falcon_firmware_section { + unsigned long offset; + size_t size; +}; + +struct falcon_firmware { + /* Firmware after it is read but not loaded */ + const struct firmware *firmware; + + /* Raw firmware data */ + dma_addr_t iova; + dma_addr_t phys; + void *virt; + size_t size; + + /* Parsed firmware information */ + struct falcon_firmware_section bin_data; + struct falcon_firmware_section data; + struct falcon_firmware_section code; +}; + +struct falcon { + /* Set by falcon client */ + struct device *dev; + void __iomem *regs; + + struct falcon_firmware firmware; +}; + struct nvhost_syncpt_interface { dma_addr_t base; size_t size; @@ -551,166 +579,6 @@ dma_addr_t nvhost_syncpt_address(struct platform_device *pdev, u32 id) } EXPORT_SYMBOL(nvhost_syncpt_address); -static irqreturn_t flcn_isr(int irq, void *dev_id) -{ - struct platform_device *pdev = (struct platform_device *)(dev_id); - struct nvhost_device_data *pdata = nvhost_get_devdata(pdev); - - if (pdata->flcn_isr) - pdata->flcn_isr(pdev); - - return IRQ_HANDLED; -} - -int flcn_intr_init(struct platform_device *pdev) -{ - struct nvhost_device_data *pdata = nvhost_get_devdata(pdev); - int ret = 0; - - pdata->irq = platform_get_irq(pdev, 0); - if (pdata->irq < 0) { - dev_err(&pdev->dev, "failed to get IRQ\n"); - return -ENXIO; - } - - ret = devm_request_irq(&pdev->dev, pdata->irq, flcn_isr, 0, - dev_name(&pdev->dev), pdev); - if (ret) { - dev_err(&pdev->dev, "failed to request irq. err %d\n", ret); - return ret; - } - - /* keep irq disabled */ - disable_irq(pdata->irq); - - return 0; -} -EXPORT_SYMBOL(flcn_intr_init); - -int flcn_reload_fw(struct platform_device *pdev) -{ - /* TODO: Used by debugfs */ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(flcn_reload_fw); - -static int nvhost_flcn_init(struct platform_device *pdev, - struct nvhost_device_data *pdata) -{ - struct falcon *falcon; - - falcon = devm_kzalloc(&pdev->dev, sizeof(*falcon), GFP_KERNEL); - if (!falcon) - return -ENOMEM; - - falcon->dev = &pdev->dev; - falcon->regs = pdata->aperture[0]; - - falcon_init(falcon); - - pdata->falcon_data = falcon; - - return 0; -} - -int nvhost_flcn_prepare_poweroff(struct platform_device *pdev) -{ - struct nvhost_device_data *pdata = platform_get_drvdata(pdev); - - if (pdata->flcn_isr) - disable_irq(pdata->irq); - - return 0; -} -EXPORT_SYMBOL(nvhost_flcn_prepare_poweroff); - -static int nvhost_flcn_load_firmware(struct platform_device *pdev, - struct falcon *falcon, - char *firmware_name) -{ - dma_addr_t iova; - size_t size; - void *virt; - int err; - - if (falcon->firmware.virt) - return 0; - - err = falcon_read_firmware(falcon, firmware_name); - if (err < 0) - return err; - - size = falcon->firmware.size; - virt = dma_alloc_coherent(&pdev->dev, size, &iova, GFP_KERNEL); - if (!virt) - return -ENOMEM; - - falcon->firmware.virt = virt; - falcon->firmware.iova = iova; - - err = falcon_load_firmware(falcon); - if (err < 0) - goto cleanup; - - return 0; - -cleanup: - dma_free_coherent(&pdev->dev, size, virt, iova); - - return err; -} - -int nvhost_flcn_finalize_poweron(struct platform_device *pdev) -{ - struct nvhost_device_data *pdata = platform_get_drvdata(pdev); -#ifdef CONFIG_IOMMU_API - struct iommu_fwspec *spec = dev_iommu_fwspec_get(&pdev->dev); -#endif - struct falcon *falcon; - int err; - u32 value; - - if (!pdata->falcon_data) { - err = nvhost_flcn_init(pdev, pdata); - if (err < 0) - return -ENOMEM; - } - - falcon = pdata->falcon_data; - - err = nvhost_flcn_load_firmware(pdev, falcon, pdata->firmware_name); - if (err < 0) - return err; - -#ifdef CONFIG_IOMMU_API - if (spec) { - host1x_writel(pdev, pdata->transcfg_addr, pdata->transcfg_val); - - if (spec->num_ids > 0) { - value = spec->ids[0] & 0xffff; - host1x_writel(pdev, THI_STREAMID0, value); - host1x_writel(pdev, THI_STREAMID1, value); - } - } -#endif - - err = falcon_boot(falcon); - if (err < 0) - return err; - - err = falcon_wait_idle(falcon); - if (err < 0) { - dev_err(&pdev->dev, "falcon boot timed out\n"); - return err; - } - - if (pdata->flcn_isr) - enable_irq(pdata->irq); - - return 0; -} -EXPORT_SYMBOL(nvhost_flcn_finalize_poweron); - struct nvhost_host1x_cb { struct dma_fence_cb cb; struct work_struct work; @@ -782,6 +650,12 @@ int nvhost_intr_register_notifier(struct platform_device *pdev, } EXPORT_SYMBOL(nvhost_intr_register_notifier); +static void falcon_exit(struct falcon *falcon) +{ + if (falcon->firmware.firmware) + release_firmware(falcon->firmware.firmware); +} + void nvhost_module_deinit(struct platform_device *pdev) { struct nvhost_device_data *pdata = platform_get_drvdata(pdev); diff --git a/include/linux/nvhost.h b/include/linux/nvhost.h index 8054cca3..03f06864 100644 --- a/include/linux/nvhost.h +++ b/include/linux/nvhost.h @@ -178,11 +178,6 @@ struct nvhost_device_data *nvhost_get_devdata(struct platform_device *pdev) return (struct nvhost_device_data *)platform_get_drvdata(pdev); } -int flcn_intr_init(struct platform_device *pdev); -int flcn_reload_fw(struct platform_device *pdev); -int nvhost_flcn_prepare_poweroff(struct platform_device *pdev); -int nvhost_flcn_finalize_poweron(struct platform_device *dev); - /* public api to return platform_device ptr to the default host1x instance */ struct platform_device *nvhost_get_default_device(void); struct platform_device *nvhost_get_host1x_device(int instance);