diff --git a/drivers/video/tegra/host/nvdla/nvdla.c b/drivers/video/tegra/host/nvdla/nvdla.c index 35ff8bc4..af91a4b8 100644 --- a/drivers/video/tegra/host/nvdla/nvdla.c +++ b/drivers/video/tegra/host/nvdla/nvdla.c @@ -621,6 +621,11 @@ int nvhost_nvdla_finalize_poweron(struct platform_device *pdev) } nvdla_dev->is_gos_enabled = true; + if (nvdla_dev->quirks & NVDLA_QUIRK_T194_A01_WAR) { + host1x_writel(pdev, + NVDLA_MCIF_CFG_OUTSTANDING_CNT_0_OFFSET, 0xff); + nvdla_dbg_info(pdev, "enabled T194-A01 WAR"); + } return 0; fail_to_alloc_trace: diff --git a/drivers/video/tegra/host/nvdla/nvdla.h b/drivers/video/tegra/host/nvdla/nvdla.h index 06d19008..4f30dc81 100644 --- a/drivers/video/tegra/host/nvdla/nvdla.h +++ b/drivers/video/tegra/host/nvdla/nvdla.h @@ -47,6 +47,12 @@ */ #define MAX_GRID_SIZE SZ_256 +/** + * DLA MCIF (Matrix Convolution Image Filter) outstanding AXI transactions + * count register offset + */ +#define NVDLA_MCIF_CFG_OUTSTANDING_CNT_0_OFFSET 0x00005014 /* RW-4R */ + /** * Method ID and Method data THI registers */ @@ -114,6 +120,11 @@ #define MAX_CMD_SIZE SZ_256 #define NVDLA_CMD_OFFSET(index) (MAX_CMD_SIZE * index) +/* + * Tegra/DLA Hardware version specific Quirks + */ +#define NVDLA_QUIRK_T194_A01_WAR BIT(0) + /** * data structure to keep command memory * @@ -183,6 +194,7 @@ enum nvdla_submit_mode { * @en_fw_gcov flag to enable firmware gcov * @gcov_dump_pa physical address of fw gcov buffer * @gcov_dump_va virtual address of fw gcovbuffer + * @quirks Tegra/DLA Hardware version specific settings */ struct nvdla_device { struct platform_device *pdev; @@ -206,6 +218,7 @@ struct nvdla_device { u32 en_fw_gcov; dma_addr_t gcov_dump_pa; u32 *gcov_dump_va; + u32 quirks; }; /** diff --git a/drivers/video/tegra/host/nvdla/nvdla_debug.c b/drivers/video/tegra/host/nvdla/nvdla_debug.c index 06ebd351..621ea7bf 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_debug.c +++ b/drivers/video/tegra/host/nvdla/nvdla_debug.c @@ -24,6 +24,8 @@ #include "flcn/hw_flcn.h" #include "dla_os_interface.h" #include +#include +#include #include "nvdla/nvdla.h" #include "nvdla_debug.h" @@ -518,6 +520,46 @@ static ssize_t debug_dla_fw_reload_set(struct file *file, return count; } +static ssize_t debug_dla_fw_a01_war_set(struct file *file, + const char __user *buffer, size_t count, loff_t *off) +{ + int err; + struct seq_file *p = file->private_data; + struct nvdla_device *nvdla_dev; + struct platform_device *pdev; + long val; + + if (!p) + return -EFAULT; + + nvdla_dev = (struct nvdla_device *)p->private; + if (!nvdla_dev) + return -EFAULT; + + pdev = nvdla_dev->pdev; + if (!pdev) + return -EFAULT; + + err = kstrtol_from_user(buffer, count, 10, &val); + if (err < 0) + return err; + + if (val < 0) /* "0" to disable WAR, positive value to enable WAR */ + return count; + + + if ((tegra_get_chipid() == TEGRA_CHIPID_TEGRA19) && + (tegra_chip_get_revision() == TEGRA194_REVISION_A01)) + if (val) + nvdla_dev->quirks |= (NVDLA_QUIRK_T194_A01_WAR); + else + nvdla_dev->quirks &= (~NVDLA_QUIRK_T194_A01_WAR); + else + nvdla_dbg_info(pdev, "This WAR is valid only for T194-A01."); + + return count; +} + static int nvdla_fw_ver_tag_show(struct seq_file *s, void *unused) { struct nvdla_device *nvdla_dev; @@ -561,11 +603,31 @@ static int debug_dla_fw_reload_show(struct seq_file *s, void *data) return 0; } +static int debug_dla_fw_a01_war_show(struct seq_file *s, void *data) +{ + struct nvdla_device *nvdla_dev; + + if (!s) + return -EFAULT; + + nvdla_dev = (struct nvdla_device *)s->private; + if (!nvdla_dev) + return -EFAULT; + + seq_printf(s, "%x\n", nvdla_dev->quirks); + return 0; +} + static int debug_dla_fw_reload_open(struct inode *inode, struct file *file) { return single_open(file, debug_dla_fw_reload_show, inode->i_private); } +static int debug_dla_fw_a01_war_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_dla_fw_a01_war_show, inode->i_private); +} + static const struct file_operations debug_dla_enable_trace_fops = { .open = debug_dla_enable_trace_open, .read = seq_read, @@ -626,6 +688,14 @@ static const struct file_operations nvdla_fw_reload_fops = { .write = debug_dla_fw_reload_set, }; +static const struct file_operations nvdla_a01_war_fops = { + .open = debug_dla_fw_a01_war_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = debug_dla_fw_a01_war_set, +}; + static void dla_fw_debugfs_init(struct platform_device *pdev) { struct dentry *fw_dir, *fw_trace, *events, *fw_gcov; @@ -652,6 +722,10 @@ static void dla_fw_debugfs_init(struct platform_device *pdev) nvdla_dev, &nvdla_fw_reload_fops)) goto trace_failed; + if (!debugfs_create_file("a01_war", 0600, fw_dir, + nvdla_dev, &nvdla_a01_war_fops)) + goto trace_failed; + fw_trace = debugfs_create_dir("trace", fw_dir); if (!fw_trace) goto trace_failed;