summaryrefslogtreecommitdiff
path: root/drivers/gpu/host1x/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/host1x/dev.c')
-rw-r--r--drivers/gpu/host1x/dev.c124
1 files changed, 90 insertions, 34 deletions
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 80c685ab3e30..0cd3f97e7e49 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -28,6 +28,7 @@
#include "bus.h"
#include "channel.h"
+#include "context.h"
#include "debug.h"
#include "dev.h"
#include "intr.h"
@@ -38,6 +39,12 @@
#include "hw/host1x05.h"
#include "hw/host1x06.h"
#include "hw/host1x07.h"
+#include "hw/host1x08.h"
+
+void host1x_common_writel(struct host1x *host1x, u32 v, u32 r)
+{
+ writel(v, host1x->common_regs + r);
+}
void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r)
{
@@ -199,7 +206,48 @@ static const struct host1x_info host1x07_info = {
.reserve_vblank_syncpts = false,
};
+/*
+ * Tegra234 has two stream ID protection tables, one for setting stream IDs
+ * through the channel path via SETSTREAMID, and one for setting them via
+ * MMIO. We program each engine's data stream ID in the channel path table
+ * and firmware stream ID in the MMIO path table.
+ */
+static const struct host1x_sid_entry tegra234_sid_table[] = {
+ {
+ /* VIC channel */
+ .base = 0x17b8,
+ .offset = 0x30,
+ .limit = 0x30
+ },
+ {
+ /* VIC MMIO */
+ .base = 0x1688,
+ .offset = 0x34,
+ .limit = 0x34
+ },
+};
+
+static const struct host1x_info host1x08_info = {
+ .nb_channels = 63,
+ .nb_pts = 1024,
+ .nb_mlocks = 24,
+ .nb_bases = 0,
+ .init = host1x08_init,
+ .sync_offset = 0x0,
+ .dma_mask = DMA_BIT_MASK(40),
+ .has_wide_gather = true,
+ .has_hypervisor = true,
+ .has_common = true,
+ .num_sid_entries = ARRAY_SIZE(tegra234_sid_table),
+ .sid_table = tegra234_sid_table,
+ .streamid_vm_table = { 0x1004, 128 },
+ .classid_vm_table = { 0x1404, 25 },
+ .mmio_vm_table = { 0x1504, 25 },
+ .reserve_vblank_syncpts = false,
+};
+
static const struct of_device_id host1x_of_match[] = {
+ { .compatible = "nvidia,tegra234-host1x", .data = &host1x08_info, },
{ .compatible = "nvidia,tegra194-host1x", .data = &host1x07_info, },
{ .compatible = "nvidia,tegra186-host1x", .data = &host1x06_info, },
{ .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, },
@@ -211,7 +259,7 @@ static const struct of_device_id host1x_of_match[] = {
};
MODULE_DEVICE_TABLE(of, host1x_of_match);
-static void host1x_setup_sid_table(struct host1x *host)
+static void host1x_setup_virtualization_tables(struct host1x *host)
{
const struct host1x_info *info = host->info;
unsigned int i;
@@ -225,6 +273,21 @@ static void host1x_setup_sid_table(struct host1x *host)
host1x_hypervisor_writel(host, entry->offset, entry->base);
host1x_hypervisor_writel(host, entry->limit, entry->base + 4);
}
+
+ for (i = 0; i < info->streamid_vm_table.count; i++) {
+ /* Allow access to all stream IDs to all VMs. */
+ host1x_hypervisor_writel(host, 0xff, info->streamid_vm_table.base + 4 * i);
+ }
+
+ for (i = 0; i < info->classid_vm_table.count; i++) {
+ /* Allow access to all classes to all VMs. */
+ host1x_hypervisor_writel(host, 0xff, info->classid_vm_table.base + 4 * i);
+ }
+
+ for (i = 0; i < info->mmio_vm_table.count; i++) {
+ /* Use VM1 (that's us) as originator VMID for engine MMIO accesses. */
+ host1x_hypervisor_writel(host, 0x1, info->mmio_vm_table.base + 4 * i);
+ }
}
static bool host1x_wants_iommu(struct host1x *host1x)
@@ -402,16 +465,12 @@ static int host1x_get_resets(struct host1x *host)
return err;
}
- if (WARN_ON(!host->resets[1].rstc))
- return -ENOENT;
-
return 0;
}
static int host1x_probe(struct platform_device *pdev)
{
struct host1x *host;
- struct resource *regs, *hv_regs = NULL;
int syncpt_irq;
int err;
@@ -422,25 +481,23 @@ static int host1x_probe(struct platform_device *pdev)
host->info = of_device_get_match_data(&pdev->dev);
if (host->info->has_hypervisor) {
- regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vm");
- if (!regs) {
- dev_err(&pdev->dev, "failed to get vm registers\n");
- return -ENXIO;
- }
+ host->regs = devm_platform_ioremap_resource_byname(pdev, "vm");
+ if (IS_ERR(host->regs))
+ return PTR_ERR(host->regs);
+
+ host->hv_regs = devm_platform_ioremap_resource_byname(pdev, "hypervisor");
+ if (IS_ERR(host->hv_regs))
+ return PTR_ERR(host->hv_regs);
- hv_regs = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "hypervisor");
- if (!hv_regs) {
- dev_err(&pdev->dev,
- "failed to get hypervisor registers\n");
- return -ENXIO;
+ if (host->info->has_common) {
+ host->common_regs = devm_platform_ioremap_resource_byname(pdev, "common");
+ if (IS_ERR(host->common_regs))
+ return PTR_ERR(host->common_regs);
}
} else {
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
- dev_err(&pdev->dev, "failed to get registers\n");
- return -ENXIO;
- }
+ host->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(host->regs))
+ return PTR_ERR(host->regs);
}
syncpt_irq = platform_get_irq(pdev, 0);
@@ -455,16 +512,6 @@ static int host1x_probe(struct platform_device *pdev)
/* set common host1x device data */
platform_set_drvdata(pdev, host);
- host->regs = devm_ioremap_resource(&pdev->dev, regs);
- if (IS_ERR(host->regs))
- return PTR_ERR(host->regs);
-
- if (host->info->has_hypervisor) {
- host->hv_regs = devm_ioremap_resource(&pdev->dev, hv_regs);
- if (IS_ERR(host->hv_regs))
- return PTR_ERR(host->hv_regs);
- }
-
host->dev->dma_parms = &host->dma_parms;
dma_set_max_seg_size(host->dev, UINT_MAX);
@@ -503,10 +550,16 @@ static int host1x_probe(struct platform_device *pdev)
goto iommu_exit;
}
+ err = host1x_memory_context_list_init(host);
+ if (err) {
+ dev_err(&pdev->dev, "failed to initialize context list\n");
+ goto free_channels;
+ }
+
err = host1x_syncpt_init(host);
if (err) {
dev_err(&pdev->dev, "failed to initialize syncpts\n");
- goto free_channels;
+ goto free_contexts;
}
err = host1x_intr_init(host, syncpt_irq);
@@ -550,6 +603,8 @@ pm_disable:
host1x_intr_deinit(host);
deinit_syncpt:
host1x_syncpt_deinit(host);
+free_contexts:
+ host1x_memory_context_list_free(&host->context_list);
free_channels:
host1x_channel_list_free(&host->channel_list);
iommu_exit:
@@ -571,6 +626,7 @@ static int host1x_remove(struct platform_device *pdev)
host1x_intr_deinit(host);
host1x_syncpt_deinit(host);
+ host1x_memory_context_list_free(&host->context_list);
host1x_channel_list_free(&host->channel_list);
host1x_iommu_exit(host);
host1x_bo_cache_destroy(&host->cache);
@@ -600,7 +656,7 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev)
return 0;
resume_host1x:
- host1x_setup_sid_table(host);
+ host1x_setup_virtualization_tables(host);
host1x_syncpt_restore(host);
host1x_intr_start(host);
@@ -630,7 +686,7 @@ static int __maybe_unused host1x_runtime_resume(struct device *dev)
goto disable_clk;
}
- host1x_setup_sid_table(host);
+ host1x_setup_virtualization_tables(host);
host1x_syncpt_restore(host);
host1x_intr_start(host);