Add support for VIC on Tegra264. The Tegra264 VIC uses a RISC-V based Falcon microcontroller instead of the traditional Falcon previously, and has the TRANSCFG register in a different place.
The .version field is set to 0x264 rather than 0x26 to allow distinguishing between different VIC capabilities between minor version variations of some chips. Signed-off-by: Mikko Perttunen <[email protected]> --- drivers/gpu/drm/tegra/drm.c | 1 + drivers/gpu/drm/tegra/vic.c | 95 +++++++++++++++++++++++++++++++++------------ drivers/gpu/drm/tegra/vic.h | 9 ++--- 3 files changed, 76 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 1dcef4e7d104..28245bf5ba5f 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1396,6 +1396,7 @@ static const struct of_device_id host1x_drm_subdevs[] = { { .compatible = "nvidia,tegra194-nvdec", }, { .compatible = "nvidia,tegra234-vic", }, { .compatible = "nvidia,tegra234-nvdec", }, + { .compatible = "nvidia,tegra264-vic", }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 332c9b563d3f..46c7e00de347 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -8,6 +8,7 @@ #include <linux/dma-mapping.h> #include <linux/host1x.h> #include <linux/iommu.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -20,10 +21,16 @@ #include "falcon.h" #include "vic.h" +#define VIC_FALCON_DEBUGINFO 0x1094 +#define VIC_DEBUGINFO_DUMMY 0xabcd1234 +#define VIC_DEBUGINFO_CLEAR 0x0 + struct vic_config { const char *firmware; unsigned int version; bool supports_sid; + bool has_riscv; + unsigned int transcfg_offset; }; struct vic { @@ -54,8 +61,8 @@ static void vic_writel(struct vic *vic, u32 value, unsigned int offset) static int vic_boot(struct vic *vic) { - u32 fce_ucode_size, fce_bin_data_offset, stream_id; - void *hdr; + u32 stream_id; + u32 val; int err = 0; if (vic->config->supports_sid && tegra_dev_iommu_get_stream_id(vic->dev, &stream_id)) { @@ -63,7 +70,7 @@ static int vic_boot(struct vic *vic) value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) | TRANSCFG_ATT(0, TRANSCFG_SID_HW); - vic_writel(vic, value, VIC_TFBIF_TRANSCFG); + vic_writel(vic, value, vic->config->transcfg_offset); /* * STREAMID0 is used for input/output buffers. Initialize it to SID_VIC in case @@ -85,31 +92,50 @@ static int vic_boot(struct vic *vic) CG_WAKEUP_DLY_CNT(4), NV_PVIC_MISC_PRI_VIC_CG); + if (vic->config->has_riscv) { + /* Write a known pattern into DEBUGINFO register */ + vic_writel(vic, VIC_DEBUGINFO_DUMMY, VIC_FALCON_DEBUGINFO); + } + err = falcon_boot(&vic->falcon); if (err < 0) return err; - hdr = vic->falcon.firmware.virt; - fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET); - - /* Old VIC firmware needs kernel help with setting up FCE microcode. */ - if (fce_bin_data_offset != 0x0 && fce_bin_data_offset != 0xa5a5a5a5) { - hdr = vic->falcon.firmware.virt + - *(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET); - fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET); - - falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE, - fce_ucode_size); - falcon_execute_method( - &vic->falcon, VIC_SET_FCE_UCODE_OFFSET, - (vic->falcon.firmware.iova + fce_bin_data_offset) >> 8); - } + if (vic->config->has_riscv) { + /* Check VIC has reached a proper initialized state */ + err = readl_poll_timeout(vic->regs + VIC_FALCON_DEBUGINFO, val, + val == VIC_DEBUGINFO_CLEAR, + 1000, 2000000); + if (err) { + dev_err(vic->dev, "VIC not initialized, timeout, val=0x%x\n", val); + return err; + } + } else { + u32 fce_ucode_size, fce_bin_data_offset; + void *hdr; + + hdr = vic->falcon.firmware.virt; + fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET); + + /* Old VIC firmware needs kernel help with setting up FCE microcode. */ + if (fce_bin_data_offset != 0x0 && fce_bin_data_offset != 0xa5a5a5a5) { + hdr = vic->falcon.firmware.virt + + *(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET); + fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET); + + falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE, + fce_ucode_size); + falcon_execute_method( + &vic->falcon, VIC_SET_FCE_UCODE_OFFSET, + (vic->falcon.firmware.iova + fce_bin_data_offset) >> 8); + } - err = falcon_wait_idle(&vic->falcon); - if (err < 0) { - dev_err(vic->dev, - "failed to set application ID and FCE base\n"); - return err; + err = falcon_wait_idle(&vic->falcon); + if (err < 0) { + dev_err(vic->dev, + "failed to set application ID and FCE base\n"); + return err; + } } return 0; @@ -277,6 +303,8 @@ static int vic_load_firmware(struct vic *vic) if (!vic->config->supports_sid) { vic->can_use_context = false; + } else if (vic->config->has_riscv) { + vic->can_use_context = true; } else if (fce_bin_data_offset != 0x0 && fce_bin_data_offset != 0xa5a5a5a5) { /* * Firmware will access FCE through STREAMID0, so context @@ -302,7 +330,6 @@ static int vic_load_firmware(struct vic *vic) return err; } - static int __maybe_unused vic_runtime_resume(struct device *dev) { struct vic *vic = dev_get_drvdata(dev); @@ -417,6 +444,7 @@ static const struct vic_config vic_t186_config = { .firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE, .version = 0x18, .supports_sid = true, + .transcfg_offset = 0x2044, }; #define NVIDIA_TEGRA_194_VIC_FIRMWARE "nvidia/tegra194/vic.bin" @@ -425,6 +453,7 @@ static const struct vic_config vic_t194_config = { .firmware = NVIDIA_TEGRA_194_VIC_FIRMWARE, .version = 0x19, .supports_sid = true, + .transcfg_offset = 0x2044, }; #define NVIDIA_TEGRA_234_VIC_FIRMWARE "nvidia/tegra234/vic.bin" @@ -433,6 +462,18 @@ static const struct vic_config vic_t234_config = { .firmware = NVIDIA_TEGRA_234_VIC_FIRMWARE, .version = 0x23, .supports_sid = true, + .transcfg_offset = 0x2044, +}; + +#define NVIDIA_TEGRA_264_VIC_FIRMWARE "nvidia/tegra264/vic.bin" +#define NVIDIA_TEGRA_264_VIC_DESC "nvidia/tegra264/vic.bin.desc" + +static const struct vic_config vic_t264_config = { + .firmware = NVIDIA_TEGRA_264_VIC_FIRMWARE, + .version = 0x264, + .supports_sid = true, + .has_riscv = true, + .transcfg_offset = 0x2244, }; static const struct of_device_id tegra_vic_of_match[] = { @@ -441,6 +482,7 @@ static const struct of_device_id tegra_vic_of_match[] = { { .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config }, { .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config }, { .compatible = "nvidia,tegra234-vic", .data = &vic_t234_config }, + { .compatible = "nvidia,tegra264-vic", .data = &vic_t264_config }, { }, }; MODULE_DEVICE_TABLE(of, tegra_vic_of_match); @@ -495,6 +537,7 @@ static int vic_probe(struct platform_device *pdev) vic->falcon.dev = dev; vic->falcon.regs = vic->regs; + vic->falcon.riscv = vic->config->has_riscv; err = falcon_init(&vic->falcon); if (err < 0) @@ -571,3 +614,7 @@ MODULE_FIRMWARE(NVIDIA_TEGRA_194_VIC_FIRMWARE); #if IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) MODULE_FIRMWARE(NVIDIA_TEGRA_234_VIC_FIRMWARE); #endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA_264_SOC) +MODULE_FIRMWARE(NVIDIA_TEGRA_264_VIC_FIRMWARE); +MODULE_FIRMWARE(NVIDIA_TEGRA_264_VIC_DESC); +#endif diff --git a/drivers/gpu/drm/tegra/vic.h b/drivers/gpu/drm/tegra/vic.h index acf35aac948b..e525a06daaba 100644 --- a/drivers/gpu/drm/tegra/vic.h +++ b/drivers/gpu/drm/tegra/vic.h @@ -21,11 +21,10 @@ #define CG_IDLE_CG_EN (1 << 6) #define CG_WAKEUP_DLY_CNT(val) ((val & 0xf) << 16) -#define VIC_TFBIF_TRANSCFG 0x00002044 -#define TRANSCFG_ATT(i, v) (((v) & 0x3) << (i * 4)) -#define TRANSCFG_SID_HW 0 -#define TRANSCFG_SID_PHY 1 -#define TRANSCFG_SID_FALCON 2 +#define TRANSCFG_ATT(i, v) (((v) & 0x3) << (i * 4)) +#define TRANSCFG_SID_HW 0 +#define TRANSCFG_SID_PHY 1 +#define TRANSCFG_SID_FALCON 2 /* Firmware offsets */ -- 2.53.0
