Add support for loading and booting RISC-V firmwares on Falcons with RISC-V hardware. The flow is mostly the same as for traditional Falcons, with a few different registers and different firmware layout.
Signed-off-by: Mikko Perttunen <[email protected]> --- drivers/gpu/drm/tegra/falcon.c | 66 +++++++++++++++++++++++++++++++++++------- drivers/gpu/drm/tegra/falcon.h | 23 +++++++++++++++ 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/tegra/falcon.c b/drivers/gpu/drm/tegra/falcon.c index 17f616bbcb45..1172356b6af3 100644 --- a/drivers/gpu/drm/tegra/falcon.c +++ b/drivers/gpu/drm/tegra/falcon.c @@ -26,8 +26,12 @@ int falcon_wait_idle(struct falcon *falcon) { u32 value; - return readl_poll_timeout(falcon->regs + FALCON_IDLESTATE, value, - (value == 0), 10, 100000); + if (falcon->riscv) + return readl_poll_timeout(falcon->regs + RISCV_CPUCTL, value, + (value & RISCV_CPUCTL_ACTIVE_STAT_ACTIVE), 10, 100000); + else + return readl_poll_timeout(falcon->regs + FALCON_IDLESTATE, value, + (value == 0), 10, 100000); } static int falcon_dma_wait_not_full(struct falcon *falcon) @@ -122,6 +126,17 @@ static int falcon_parse_firmware_image(struct falcon *falcon) return 0; } +static void falcon_parse_firmware_desc(struct falcon *falcon) +{ + struct falcon_fw_riscv_desc *desc = + (struct falcon_fw_riscv_desc *)falcon->firmware.desc_firmware->data; + + falcon->firmware.code.offset = desc->code_offset; + falcon->firmware.code.size = desc->code_size; + falcon->firmware.data.offset = desc->data_offset; + falcon->firmware.data.size = desc->data_size; +} + int falcon_read_firmware(struct falcon *falcon, const char *name) { int err; @@ -133,7 +148,23 @@ int falcon_read_firmware(struct falcon *falcon, const char *name) falcon->firmware.size = falcon->firmware.firmware->size; + if (falcon->riscv) { + /* Load separate descriptor */ + char desc_name[128]; + + scnprintf(desc_name, sizeof(desc_name), "%s.desc", name); + err = request_firmware(&falcon->firmware.desc_firmware, desc_name, falcon->dev); + if (err < 0) + goto release_firmware; + } + return 0; + +release_firmware: + release_firmware(falcon->firmware.firmware); + falcon->firmware.firmware = NULL; + + return err; } int falcon_load_firmware(struct falcon *falcon) @@ -144,16 +175,22 @@ int falcon_load_firmware(struct falcon *falcon) /* 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; + if (falcon->riscv) { + falcon_parse_firmware_desc(falcon); + } else { + 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; + release_firmware(falcon->firmware.desc_firmware); + falcon->firmware.desc_firmware = NULL; + return 0; } @@ -168,6 +205,9 @@ void falcon_exit(struct falcon *falcon) { if (falcon->firmware.firmware) release_firmware(falcon->firmware.firmware); + + if (falcon->firmware.desc_firmware) + release_firmware(falcon->firmware.desc_firmware); } int falcon_boot(struct falcon *falcon) @@ -229,9 +269,15 @@ int falcon_boot(struct falcon *falcon) FALCON_ITFEN_CTXEN, FALCON_ITFEN); - /* boot falcon */ - falcon_writel(falcon, 0x00000000, FALCON_BOOTVEC); - falcon_writel(falcon, FALCON_CPUCTL_STARTCPU, FALCON_CPUCTL); + if (falcon->riscv) { + falcon_writel(falcon, RISCV_BCR_CTRL_CORE_SELECT_RISCV, RISCV_BCR_CTRL); + falcon_writel(falcon, 0x0, RISCV_BOOT_VECTOR_HI); + falcon_writel(falcon, 0x100000, RISCV_BOOT_VECTOR_LO); + falcon_writel(falcon, RISCV_CPUCTL_STARTCPU, RISCV_CPUCTL); + } else { + falcon_writel(falcon, 0x00000000, FALCON_BOOTVEC); + falcon_writel(falcon, FALCON_CPUCTL_STARTCPU, FALCON_CPUCTL); + } err = falcon_wait_idle(falcon); if (err < 0) { diff --git a/drivers/gpu/drm/tegra/falcon.h b/drivers/gpu/drm/tegra/falcon.h index 902bb7e4fd0f..37a17c6136b3 100644 --- a/drivers/gpu/drm/tegra/falcon.h +++ b/drivers/gpu/drm/tegra/falcon.h @@ -55,6 +55,16 @@ #define FALCON_DMATRFFBOFFS 0x0000111c +#define RISCV_BOOT_VECTOR_LO 0x00001780 +#define RISCV_BOOT_VECTOR_HI 0x00001784 + +#define RISCV_CPUCTL 0x00001788 +#define RISCV_CPUCTL_STARTCPU (1 << 0) +#define RISCV_CPUCTL_ACTIVE_STAT_ACTIVE (1 << 7) + +#define RISCV_BCR_CTRL 0x00001a68 +#define RISCV_BCR_CTRL_CORE_SELECT_RISCV (1 << 4) + struct falcon_fw_bin_header_v1 { u32 magic; /* 0x10de */ u32 version; /* version of bin format (1) */ @@ -76,6 +86,14 @@ struct falcon_fw_os_header_v1 { u32 data_size; }; +struct falcon_fw_riscv_desc { + u32 reserved[74]; + u32 data_offset; + u32 data_size; + u32 code_offset; + u32 code_size; +}; + struct falcon_firmware_section { unsigned long offset; size_t size; @@ -84,6 +102,8 @@ struct falcon_firmware_section { struct falcon_firmware { /* Firmware after it is read but not loaded */ const struct firmware *firmware; + /* RISC-V firmware descriptor */ + const struct firmware *desc_firmware; /* Raw firmware data */ dma_addr_t iova; @@ -102,6 +122,9 @@ struct falcon { struct device *dev; void __iomem *regs; + /* Peregrine falcon, external boot */ + bool riscv; + struct falcon_firmware firmware; }; -- 2.53.0
