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

Reply via email to