xref: /openbmc/linux/drivers/gpu/host1x/dev.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
275471687STerje Bergstrom /*
375471687STerje Bergstrom  * Tegra host1x driver
475471687STerje Bergstrom  *
575471687STerje Bergstrom  * Copyright (c) 2010-2013, NVIDIA Corporation.
675471687STerje Bergstrom  */
775471687STerje Bergstrom 
875471687STerje Bergstrom #include <linux/clk.h>
96b6776e2SDmitry Osipenko #include <linux/delay.h>
10097452e6SAlexandre Courbot #include <linux/dma-mapping.h>
117e7d432cSThierry Reding #include <linux/io.h>
127e7d432cSThierry Reding #include <linux/list.h>
137e7d432cSThierry Reding #include <linux/module.h>
147e7d432cSThierry Reding #include <linux/of.h>
15*573cbf48SRob Herring #include <linux/of_platform.h>
16*573cbf48SRob Herring #include <linux/platform_device.h>
176b6776e2SDmitry Osipenko #include <linux/pm_runtime.h>
187e7d432cSThierry Reding #include <linux/slab.h>
1975471687STerje Bergstrom 
206b6776e2SDmitry Osipenko #include <soc/tegra/common.h>
216b6776e2SDmitry Osipenko 
2275471687STerje Bergstrom #define CREATE_TRACE_POINTS
2375471687STerje Bergstrom #include <trace/events/host1x.h>
24404bfb78SMikko Perttunen #undef CREATE_TRACE_POINTS
2575471687STerje Bergstrom 
26d5185965SDmitry Osipenko #if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
27d5185965SDmitry Osipenko #include <asm/dma-iommu.h>
28d5185965SDmitry Osipenko #endif
29d5185965SDmitry Osipenko 
30776dc384SThierry Reding #include "bus.h"
316579324aSTerje Bergstrom #include "channel.h"
328aa5bcb6SMikko Perttunen #include "context.h"
336236451dSTerje Bergstrom #include "debug.h"
347e7d432cSThierry Reding #include "dev.h"
357e7d432cSThierry Reding #include "intr.h"
367e7d432cSThierry Reding 
3775471687STerje Bergstrom #include "hw/host1x01.h"
385407f31bSThierry Reding #include "hw/host1x02.h"
39e6fff4aaSThierry Reding #include "hw/host1x04.h"
40a134789aSThierry Reding #include "hw/host1x05.h"
41f1b53c4eSMikko Perttunen #include "hw/host1x06.h"
42ac1bdbf2SThierry Reding #include "hw/host1x07.h"
439abdd497SMikko Perttunen #include "hw/host1x08.h"
44f1b53c4eSMikko Perttunen 
host1x_common_writel(struct host1x * host1x,u32 v,u32 r)4597dea367SMikko Perttunen void host1x_common_writel(struct host1x *host1x, u32 v, u32 r)
4697dea367SMikko Perttunen {
4797dea367SMikko Perttunen 	writel(v, host1x->common_regs + r);
4897dea367SMikko Perttunen }
4997dea367SMikko Perttunen 
host1x_hypervisor_writel(struct host1x * host1x,u32 v,u32 r)50f1b53c4eSMikko Perttunen void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r)
51f1b53c4eSMikko Perttunen {
52f1b53c4eSMikko Perttunen 	writel(v, host1x->hv_regs + r);
53f1b53c4eSMikko Perttunen }
54f1b53c4eSMikko Perttunen 
host1x_hypervisor_readl(struct host1x * host1x,u32 r)55f1b53c4eSMikko Perttunen u32 host1x_hypervisor_readl(struct host1x *host1x, u32 r)
56f1b53c4eSMikko Perttunen {
57f1b53c4eSMikko Perttunen 	return readl(host1x->hv_regs + r);
58f1b53c4eSMikko Perttunen }
5975471687STerje Bergstrom 
host1x_sync_writel(struct host1x * host1x,u32 v,u32 r)6075471687STerje Bergstrom void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
6175471687STerje Bergstrom {
6275471687STerje Bergstrom 	void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
6375471687STerje Bergstrom 
6475471687STerje Bergstrom 	writel(v, sync_regs + r);
6575471687STerje Bergstrom }
6675471687STerje Bergstrom 
host1x_sync_readl(struct host1x * host1x,u32 r)6775471687STerje Bergstrom u32 host1x_sync_readl(struct host1x *host1x, u32 r)
6875471687STerje Bergstrom {
6975471687STerje Bergstrom 	void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
7075471687STerje Bergstrom 
7175471687STerje Bergstrom 	return readl(sync_regs + r);
7275471687STerje Bergstrom }
7375471687STerje Bergstrom 
host1x_ch_writel(struct host1x_channel * ch,u32 v,u32 r)746579324aSTerje Bergstrom void host1x_ch_writel(struct host1x_channel *ch, u32 v, u32 r)
756579324aSTerje Bergstrom {
766579324aSTerje Bergstrom 	writel(v, ch->regs + r);
776579324aSTerje Bergstrom }
786579324aSTerje Bergstrom 
host1x_ch_readl(struct host1x_channel * ch,u32 r)796579324aSTerje Bergstrom u32 host1x_ch_readl(struct host1x_channel *ch, u32 r)
806579324aSTerje Bergstrom {
816579324aSTerje Bergstrom 	return readl(ch->regs + r);
826579324aSTerje Bergstrom }
836579324aSTerje Bergstrom 
8475471687STerje Bergstrom static const struct host1x_info host1x01_info = {
8575471687STerje Bergstrom 	.nb_channels = 8,
8675471687STerje Bergstrom 	.nb_pts = 32,
8775471687STerje Bergstrom 	.nb_mlocks = 16,
8875471687STerje Bergstrom 	.nb_bases = 8,
8975471687STerje Bergstrom 	.init = host1x01_init,
9075471687STerje Bergstrom 	.sync_offset = 0x3000,
91097452e6SAlexandre Courbot 	.dma_mask = DMA_BIT_MASK(32),
9206867a36SThierry Reding 	.has_wide_gather = false,
938f45f507SThierry Reding 	.has_hypervisor = false,
948f45f507SThierry Reding 	.num_sid_entries = 0,
958f45f507SThierry Reding 	.sid_table = NULL,
96f5ba33fbSMikko Perttunen 	.reserve_vblank_syncpts = true,
9775471687STerje Bergstrom };
9875471687STerje Bergstrom 
995407f31bSThierry Reding static const struct host1x_info host1x02_info = {
1005407f31bSThierry Reding 	.nb_channels = 9,
1015407f31bSThierry Reding 	.nb_pts = 32,
1025407f31bSThierry Reding 	.nb_mlocks = 16,
1035407f31bSThierry Reding 	.nb_bases = 12,
1045407f31bSThierry Reding 	.init = host1x02_init,
1055407f31bSThierry Reding 	.sync_offset = 0x3000,
106097452e6SAlexandre Courbot 	.dma_mask = DMA_BIT_MASK(32),
10706867a36SThierry Reding 	.has_wide_gather = false,
1088f45f507SThierry Reding 	.has_hypervisor = false,
1098f45f507SThierry Reding 	.num_sid_entries = 0,
1108f45f507SThierry Reding 	.sid_table = NULL,
111f5ba33fbSMikko Perttunen 	.reserve_vblank_syncpts = true,
1125407f31bSThierry Reding };
1135407f31bSThierry Reding 
114e6fff4aaSThierry Reding static const struct host1x_info host1x04_info = {
115e6fff4aaSThierry Reding 	.nb_channels = 12,
116e6fff4aaSThierry Reding 	.nb_pts = 192,
117e6fff4aaSThierry Reding 	.nb_mlocks = 16,
118e6fff4aaSThierry Reding 	.nb_bases = 64,
119e6fff4aaSThierry Reding 	.init = host1x04_init,
120e6fff4aaSThierry Reding 	.sync_offset = 0x2100,
121097452e6SAlexandre Courbot 	.dma_mask = DMA_BIT_MASK(34),
12206867a36SThierry Reding 	.has_wide_gather = false,
1238f45f507SThierry Reding 	.has_hypervisor = false,
1248f45f507SThierry Reding 	.num_sid_entries = 0,
1258f45f507SThierry Reding 	.sid_table = NULL,
126f5ba33fbSMikko Perttunen 	.reserve_vblank_syncpts = false,
127e6fff4aaSThierry Reding };
128e6fff4aaSThierry Reding 
129a134789aSThierry Reding static const struct host1x_info host1x05_info = {
130a134789aSThierry Reding 	.nb_channels = 14,
131a134789aSThierry Reding 	.nb_pts = 192,
132a134789aSThierry Reding 	.nb_mlocks = 16,
133a134789aSThierry Reding 	.nb_bases = 64,
134a134789aSThierry Reding 	.init = host1x05_init,
135a134789aSThierry Reding 	.sync_offset = 0x2100,
136097452e6SAlexandre Courbot 	.dma_mask = DMA_BIT_MASK(34),
13706867a36SThierry Reding 	.has_wide_gather = false,
1388f45f507SThierry Reding 	.has_hypervisor = false,
1398f45f507SThierry Reding 	.num_sid_entries = 0,
1408f45f507SThierry Reding 	.sid_table = NULL,
141f5ba33fbSMikko Perttunen 	.reserve_vblank_syncpts = false,
142a134789aSThierry Reding };
143a134789aSThierry Reding 
1446841482bSThierry Reding static const struct host1x_sid_entry tegra186_sid_table[] = {
1456841482bSThierry Reding 	{
1466841482bSThierry Reding 		/* VIC */
1476841482bSThierry Reding 		.base = 0x1af0,
1486841482bSThierry Reding 		.offset = 0x30,
1496841482bSThierry Reding 		.limit = 0x34
1506841482bSThierry Reding 	},
15146f226c9SMikko Perttunen 	{
15246f226c9SMikko Perttunen 		/* NVDEC */
15346f226c9SMikko Perttunen 		.base = 0x1b00,
15446f226c9SMikko Perttunen 		.offset = 0x30,
15546f226c9SMikko Perttunen 		.limit = 0x34
15646f226c9SMikko Perttunen 	},
1576841482bSThierry Reding };
1586841482bSThierry Reding 
159f1b53c4eSMikko Perttunen static const struct host1x_info host1x06_info = {
160f1b53c4eSMikko Perttunen 	.nb_channels = 63,
161f1b53c4eSMikko Perttunen 	.nb_pts = 576,
162f1b53c4eSMikko Perttunen 	.nb_mlocks = 24,
163f1b53c4eSMikko Perttunen 	.nb_bases = 16,
164f1b53c4eSMikko Perttunen 	.init = host1x06_init,
165f1b53c4eSMikko Perttunen 	.sync_offset = 0x0,
1668de896ebSThierry Reding 	.dma_mask = DMA_BIT_MASK(40),
16706867a36SThierry Reding 	.has_wide_gather = true,
168f1b53c4eSMikko Perttunen 	.has_hypervisor = true,
1696841482bSThierry Reding 	.num_sid_entries = ARRAY_SIZE(tegra186_sid_table),
1706841482bSThierry Reding 	.sid_table = tegra186_sid_table,
171f5ba33fbSMikko Perttunen 	.reserve_vblank_syncpts = false,
1726841482bSThierry Reding };
1736841482bSThierry Reding 
1746841482bSThierry Reding static const struct host1x_sid_entry tegra194_sid_table[] = {
1756841482bSThierry Reding 	{
1766841482bSThierry Reding 		/* VIC */
1776841482bSThierry Reding 		.base = 0x1af0,
1786841482bSThierry Reding 		.offset = 0x30,
1796841482bSThierry Reding 		.limit = 0x34
1806841482bSThierry Reding 	},
18146f226c9SMikko Perttunen 	{
18246f226c9SMikko Perttunen 		/* NVDEC */
18346f226c9SMikko Perttunen 		.base = 0x1b00,
18446f226c9SMikko Perttunen 		.offset = 0x30,
18546f226c9SMikko Perttunen 		.limit = 0x34
18646f226c9SMikko Perttunen 	},
18746f226c9SMikko Perttunen 	{
18846f226c9SMikko Perttunen 		/* NVDEC1 */
18946f226c9SMikko Perttunen 		.base = 0x1bc0,
19046f226c9SMikko Perttunen 		.offset = 0x30,
19146f226c9SMikko Perttunen 		.limit = 0x34
19246f226c9SMikko Perttunen 	},
193f1b53c4eSMikko Perttunen };
194f1b53c4eSMikko Perttunen 
195ac1bdbf2SThierry Reding static const struct host1x_info host1x07_info = {
196ac1bdbf2SThierry Reding 	.nb_channels = 63,
197ac1bdbf2SThierry Reding 	.nb_pts = 704,
198ac1bdbf2SThierry Reding 	.nb_mlocks = 32,
199ac1bdbf2SThierry Reding 	.nb_bases = 0,
200ac1bdbf2SThierry Reding 	.init = host1x07_init,
201ac1bdbf2SThierry Reding 	.sync_offset = 0x0,
202ac1bdbf2SThierry Reding 	.dma_mask = DMA_BIT_MASK(40),
20306867a36SThierry Reding 	.has_wide_gather = true,
204ac1bdbf2SThierry Reding 	.has_hypervisor = true,
2056841482bSThierry Reding 	.num_sid_entries = ARRAY_SIZE(tegra194_sid_table),
2066841482bSThierry Reding 	.sid_table = tegra194_sid_table,
207f5ba33fbSMikko Perttunen 	.reserve_vblank_syncpts = false,
208ac1bdbf2SThierry Reding };
209ac1bdbf2SThierry Reding 
2109abdd497SMikko Perttunen /*
2119abdd497SMikko Perttunen  * Tegra234 has two stream ID protection tables, one for setting stream IDs
2129abdd497SMikko Perttunen  * through the channel path via SETSTREAMID, and one for setting them via
2139abdd497SMikko Perttunen  * MMIO. We program each engine's data stream ID in the channel path table
2149abdd497SMikko Perttunen  * and firmware stream ID in the MMIO path table.
2159abdd497SMikko Perttunen  */
2169abdd497SMikko Perttunen static const struct host1x_sid_entry tegra234_sid_table[] = {
2179abdd497SMikko Perttunen 	{
2189abdd497SMikko Perttunen 		/* VIC channel */
2199abdd497SMikko Perttunen 		.base = 0x17b8,
2209abdd497SMikko Perttunen 		.offset = 0x30,
2219abdd497SMikko Perttunen 		.limit = 0x30
2229abdd497SMikko Perttunen 	},
2239abdd497SMikko Perttunen 	{
2249abdd497SMikko Perttunen 		/* VIC MMIO */
2259abdd497SMikko Perttunen 		.base = 0x1688,
2269abdd497SMikko Perttunen 		.offset = 0x34,
2279abdd497SMikko Perttunen 		.limit = 0x34
2289abdd497SMikko Perttunen 	},
22997b93b7aSMikko Perttunen 	{
23097b93b7aSMikko Perttunen 		/* NVDEC channel */
23197b93b7aSMikko Perttunen 		.base = 0x17c8,
23297b93b7aSMikko Perttunen 		.offset = 0x30,
23397b93b7aSMikko Perttunen 		.limit = 0x30,
23497b93b7aSMikko Perttunen 	},
23597b93b7aSMikko Perttunen 	{
23697b93b7aSMikko Perttunen 		/* NVDEC MMIO */
23797b93b7aSMikko Perttunen 		.base = 0x1698,
23897b93b7aSMikko Perttunen 		.offset = 0x34,
23997b93b7aSMikko Perttunen 		.limit = 0x34,
24097b93b7aSMikko Perttunen 	},
2419abdd497SMikko Perttunen };
2429abdd497SMikko Perttunen 
2439abdd497SMikko Perttunen static const struct host1x_info host1x08_info = {
2449abdd497SMikko Perttunen 	.nb_channels = 63,
2459abdd497SMikko Perttunen 	.nb_pts = 1024,
2469abdd497SMikko Perttunen 	.nb_mlocks = 24,
2479abdd497SMikko Perttunen 	.nb_bases = 0,
2489abdd497SMikko Perttunen 	.init = host1x08_init,
2499abdd497SMikko Perttunen 	.sync_offset = 0x0,
2509abdd497SMikko Perttunen 	.dma_mask = DMA_BIT_MASK(40),
2519abdd497SMikko Perttunen 	.has_wide_gather = true,
2529abdd497SMikko Perttunen 	.has_hypervisor = true,
2539abdd497SMikko Perttunen 	.has_common = true,
2549abdd497SMikko Perttunen 	.num_sid_entries = ARRAY_SIZE(tegra234_sid_table),
2559abdd497SMikko Perttunen 	.sid_table = tegra234_sid_table,
2569abdd497SMikko Perttunen 	.streamid_vm_table = { 0x1004, 128 },
2579abdd497SMikko Perttunen 	.classid_vm_table = { 0x1404, 25 },
2589abdd497SMikko Perttunen 	.mmio_vm_table = { 0x1504, 25 },
2599abdd497SMikko Perttunen 	.reserve_vblank_syncpts = false,
2609abdd497SMikko Perttunen };
2619abdd497SMikko Perttunen 
2626df633d0SThierry Reding static const struct of_device_id host1x_of_match[] = {
2639abdd497SMikko Perttunen 	{ .compatible = "nvidia,tegra234-host1x", .data = &host1x08_info, },
264ac1bdbf2SThierry Reding 	{ .compatible = "nvidia,tegra194-host1x", .data = &host1x07_info, },
265f1b53c4eSMikko Perttunen 	{ .compatible = "nvidia,tegra186-host1x", .data = &host1x06_info, },
266a134789aSThierry Reding 	{ .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, },
267e6fff4aaSThierry Reding 	{ .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, },
2685407f31bSThierry Reding 	{ .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, },
26975471687STerje Bergstrom 	{ .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, },
27075471687STerje Bergstrom 	{ .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, },
27175471687STerje Bergstrom 	{ },
27275471687STerje Bergstrom };
27375471687STerje Bergstrom MODULE_DEVICE_TABLE(of, host1x_of_match);
27475471687STerje Bergstrom 
host1x_setup_virtualization_tables(struct host1x * host)275939179faSMikko Perttunen static void host1x_setup_virtualization_tables(struct host1x *host)
2766841482bSThierry Reding {
2776841482bSThierry Reding 	const struct host1x_info *info = host->info;
2786841482bSThierry Reding 	unsigned int i;
2796841482bSThierry Reding 
2806b6776e2SDmitry Osipenko 	if (!info->has_hypervisor)
2816b6776e2SDmitry Osipenko 		return;
2826b6776e2SDmitry Osipenko 
2836841482bSThierry Reding 	for (i = 0; i < info->num_sid_entries; i++) {
2846841482bSThierry Reding 		const struct host1x_sid_entry *entry = &info->sid_table[i];
2856841482bSThierry Reding 
2866841482bSThierry Reding 		host1x_hypervisor_writel(host, entry->offset, entry->base);
2876841482bSThierry Reding 		host1x_hypervisor_writel(host, entry->limit, entry->base + 4);
2886841482bSThierry Reding 	}
289939179faSMikko Perttunen 
290939179faSMikko Perttunen 	for (i = 0; i < info->streamid_vm_table.count; i++) {
291939179faSMikko Perttunen 		/* Allow access to all stream IDs to all VMs. */
292939179faSMikko Perttunen 		host1x_hypervisor_writel(host, 0xff, info->streamid_vm_table.base + 4 * i);
293939179faSMikko Perttunen 	}
294939179faSMikko Perttunen 
295939179faSMikko Perttunen 	for (i = 0; i < info->classid_vm_table.count; i++) {
296939179faSMikko Perttunen 		/* Allow access to all classes to all VMs. */
297939179faSMikko Perttunen 		host1x_hypervisor_writel(host, 0xff, info->classid_vm_table.base + 4 * i);
298939179faSMikko Perttunen 	}
299939179faSMikko Perttunen 
300939179faSMikko Perttunen 	for (i = 0; i < info->mmio_vm_table.count; i++) {
301939179faSMikko Perttunen 		/* Use VM1 (that's us) as originator VMID for engine MMIO accesses. */
302939179faSMikko Perttunen 		host1x_hypervisor_writel(host, 0x1, info->mmio_vm_table.base + 4 * i);
303939179faSMikko Perttunen 	}
3046841482bSThierry Reding }
3056841482bSThierry Reding 
host1x_wants_iommu(struct host1x * host1x)3064010e729SThierry Reding static bool host1x_wants_iommu(struct host1x *host1x)
3074010e729SThierry Reding {
308c2418f91SRobin Murphy 	/* Our IOMMU usage policy doesn't currently play well with GART */
309c2418f91SRobin Murphy 	if (of_machine_is_compatible("nvidia,tegra20"))
310c2418f91SRobin Murphy 		return false;
311c2418f91SRobin Murphy 
3124010e729SThierry Reding 	/*
3134010e729SThierry Reding 	 * If we support addressing a maximum of 32 bits of physical memory
3144010e729SThierry Reding 	 * and if the host1x firewall is enabled, there's no need to enable
3154010e729SThierry Reding 	 * IOMMU support. This can happen for example on Tegra20, Tegra30
3164010e729SThierry Reding 	 * and Tegra114.
3174010e729SThierry Reding 	 *
3184010e729SThierry Reding 	 * Tegra124 and later can address up to 34 bits of physical memory and
3194010e729SThierry Reding 	 * many platforms come equipped with more than 2 GiB of system memory,
3204010e729SThierry Reding 	 * which requires crossing the 4 GiB boundary. But there's a catch: on
3214010e729SThierry Reding 	 * SoCs before Tegra186 (i.e. Tegra124 and Tegra210), the host1x can
3224010e729SThierry Reding 	 * only address up to 32 bits of memory in GATHER opcodes, which means
3234010e729SThierry Reding 	 * that command buffers need to either be in the first 2 GiB of system
3244010e729SThierry Reding 	 * memory (which could quickly lead to memory exhaustion), or command
3254010e729SThierry Reding 	 * buffers need to be treated differently from other buffers (which is
3264010e729SThierry Reding 	 * not possible with the current ABI).
3274010e729SThierry Reding 	 *
3284010e729SThierry Reding 	 * A third option is to use the IOMMU in these cases to make sure all
3294010e729SThierry Reding 	 * buffers will be mapped into a 32-bit IOVA space that host1x can
3304010e729SThierry Reding 	 * address. This allows all of the system memory to be used and works
3314010e729SThierry Reding 	 * within the limitations of the host1x on these SoCs.
3324010e729SThierry Reding 	 *
3334010e729SThierry Reding 	 * In summary, default to enable IOMMU on Tegra124 and later. For any
3344010e729SThierry Reding 	 * of the earlier SoCs, only use the IOMMU for additional safety when
3354010e729SThierry Reding 	 * the host1x firewall is disabled.
3364010e729SThierry Reding 	 */
3374010e729SThierry Reding 	if (host1x->info->dma_mask <= DMA_BIT_MASK(32)) {
3384010e729SThierry Reding 		if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
3394010e729SThierry Reding 			return false;
3404010e729SThierry Reding 	}
3414010e729SThierry Reding 
3424010e729SThierry Reding 	return true;
3434010e729SThierry Reding }
3444010e729SThierry Reding 
host1x_iommu_attach(struct host1x * host)34506867a36SThierry Reding static struct iommu_domain *host1x_iommu_attach(struct host1x *host)
34606867a36SThierry Reding {
34706867a36SThierry Reding 	struct iommu_domain *domain = iommu_get_domain_for_dev(host->dev);
34806867a36SThierry Reding 	int err;
34906867a36SThierry Reding 
350d5185965SDmitry Osipenko #if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
351d5185965SDmitry Osipenko 	if (host->dev->archdata.mapping) {
352d5185965SDmitry Osipenko 		struct dma_iommu_mapping *mapping =
353d5185965SDmitry Osipenko 				to_dma_iommu_mapping(host->dev);
354d5185965SDmitry Osipenko 		arm_iommu_detach_device(host->dev);
355d5185965SDmitry Osipenko 		arm_iommu_release_mapping(mapping);
356d5185965SDmitry Osipenko 
357d5185965SDmitry Osipenko 		domain = iommu_get_domain_for_dev(host->dev);
358d5185965SDmitry Osipenko 	}
359d5185965SDmitry Osipenko #endif
360d5185965SDmitry Osipenko 
36106867a36SThierry Reding 	/*
3624010e729SThierry Reding 	 * We may not always want to enable IOMMU support (for example if the
3634010e729SThierry Reding 	 * host1x firewall is already enabled and we don't support addressing
3644010e729SThierry Reding 	 * more than 32 bits of physical memory), so check for that first.
3654010e729SThierry Reding 	 *
3664010e729SThierry Reding 	 * Similarly, if host1x is already attached to an IOMMU (via the DMA
3674010e729SThierry Reding 	 * API), don't try to attach again.
36806867a36SThierry Reding 	 */
3694010e729SThierry Reding 	if (!host1x_wants_iommu(host) || domain)
37006867a36SThierry Reding 		return domain;
37106867a36SThierry Reding 
37206867a36SThierry Reding 	host->group = iommu_group_get(host->dev);
37306867a36SThierry Reding 	if (host->group) {
37406867a36SThierry Reding 		struct iommu_domain_geometry *geometry;
37506867a36SThierry Reding 		dma_addr_t start, end;
37606867a36SThierry Reding 		unsigned long order;
37706867a36SThierry Reding 
37806867a36SThierry Reding 		err = iova_cache_get();
37906867a36SThierry Reding 		if (err < 0)
38006867a36SThierry Reding 			goto put_group;
38106867a36SThierry Reding 
38206867a36SThierry Reding 		host->domain = iommu_domain_alloc(&platform_bus_type);
38306867a36SThierry Reding 		if (!host->domain) {
38406867a36SThierry Reding 			err = -ENOMEM;
38506867a36SThierry Reding 			goto put_cache;
38606867a36SThierry Reding 		}
38706867a36SThierry Reding 
38806867a36SThierry Reding 		err = iommu_attach_group(host->domain, host->group);
38906867a36SThierry Reding 		if (err) {
39006867a36SThierry Reding 			if (err == -ENODEV)
39106867a36SThierry Reding 				err = 0;
39206867a36SThierry Reding 
39306867a36SThierry Reding 			goto free_domain;
39406867a36SThierry Reding 		}
39506867a36SThierry Reding 
39606867a36SThierry Reding 		geometry = &host->domain->geometry;
39706867a36SThierry Reding 		start = geometry->aperture_start & host->info->dma_mask;
39806867a36SThierry Reding 		end = geometry->aperture_end & host->info->dma_mask;
39906867a36SThierry Reding 
40006867a36SThierry Reding 		order = __ffs(host->domain->pgsize_bitmap);
40106867a36SThierry Reding 		init_iova_domain(&host->iova, 1UL << order, start >> order);
40206867a36SThierry Reding 		host->iova_end = end;
40306867a36SThierry Reding 
40406867a36SThierry Reding 		domain = host->domain;
40506867a36SThierry Reding 	}
40606867a36SThierry Reding 
40706867a36SThierry Reding 	return domain;
40806867a36SThierry Reding 
40906867a36SThierry Reding free_domain:
41006867a36SThierry Reding 	iommu_domain_free(host->domain);
41106867a36SThierry Reding 	host->domain = NULL;
41206867a36SThierry Reding put_cache:
41306867a36SThierry Reding 	iova_cache_put();
41406867a36SThierry Reding put_group:
41506867a36SThierry Reding 	iommu_group_put(host->group);
41606867a36SThierry Reding 	host->group = NULL;
41706867a36SThierry Reding 
41806867a36SThierry Reding 	return ERR_PTR(err);
41906867a36SThierry Reding }
42006867a36SThierry Reding 
host1x_iommu_init(struct host1x * host)42106867a36SThierry Reding static int host1x_iommu_init(struct host1x *host)
42206867a36SThierry Reding {
42306867a36SThierry Reding 	u64 mask = host->info->dma_mask;
42406867a36SThierry Reding 	struct iommu_domain *domain;
42506867a36SThierry Reding 	int err;
42606867a36SThierry Reding 
42706867a36SThierry Reding 	domain = host1x_iommu_attach(host);
42806867a36SThierry Reding 	if (IS_ERR(domain)) {
42906867a36SThierry Reding 		err = PTR_ERR(domain);
43006867a36SThierry Reding 		dev_err(host->dev, "failed to attach to IOMMU: %d\n", err);
43106867a36SThierry Reding 		return err;
43206867a36SThierry Reding 	}
43306867a36SThierry Reding 
43406867a36SThierry Reding 	/*
43506867a36SThierry Reding 	 * If we're not behind an IOMMU make sure we don't get push buffers
43606867a36SThierry Reding 	 * that are allocated outside of the range addressable by the GATHER
43706867a36SThierry Reding 	 * opcode.
43806867a36SThierry Reding 	 *
43906867a36SThierry Reding 	 * Newer generations of Tegra (Tegra186 and later) support a wide
44006867a36SThierry Reding 	 * variant of the GATHER opcode that allows addressing more bits.
44106867a36SThierry Reding 	 */
44206867a36SThierry Reding 	if (!domain && !host->info->has_wide_gather)
44306867a36SThierry Reding 		mask = DMA_BIT_MASK(32);
44406867a36SThierry Reding 
44506867a36SThierry Reding 	err = dma_coerce_mask_and_coherent(host->dev, mask);
44606867a36SThierry Reding 	if (err < 0) {
44706867a36SThierry Reding 		dev_err(host->dev, "failed to set DMA mask: %d\n", err);
44806867a36SThierry Reding 		return err;
44906867a36SThierry Reding 	}
45006867a36SThierry Reding 
45106867a36SThierry Reding 	return 0;
45206867a36SThierry Reding }
45306867a36SThierry Reding 
host1x_iommu_exit(struct host1x * host)45406867a36SThierry Reding static void host1x_iommu_exit(struct host1x *host)
45506867a36SThierry Reding {
45606867a36SThierry Reding 	if (host->domain) {
45706867a36SThierry Reding 		put_iova_domain(&host->iova);
45806867a36SThierry Reding 		iommu_detach_group(host->domain, host->group);
45906867a36SThierry Reding 
46006867a36SThierry Reding 		iommu_domain_free(host->domain);
46106867a36SThierry Reding 		host->domain = NULL;
46206867a36SThierry Reding 
46306867a36SThierry Reding 		iova_cache_put();
46406867a36SThierry Reding 
46506867a36SThierry Reding 		iommu_group_put(host->group);
46606867a36SThierry Reding 		host->group = NULL;
46706867a36SThierry Reding 	}
46806867a36SThierry Reding }
46906867a36SThierry Reding 
host1x_get_resets(struct host1x * host)4706b6776e2SDmitry Osipenko static int host1x_get_resets(struct host1x *host)
4716b6776e2SDmitry Osipenko {
4726b6776e2SDmitry Osipenko 	int err;
4736b6776e2SDmitry Osipenko 
4746b6776e2SDmitry Osipenko 	host->resets[0].id = "mc";
4756b6776e2SDmitry Osipenko 	host->resets[1].id = "host1x";
4766b6776e2SDmitry Osipenko 	host->nresets = ARRAY_SIZE(host->resets);
4776b6776e2SDmitry Osipenko 
4786b6776e2SDmitry Osipenko 	err = devm_reset_control_bulk_get_optional_exclusive_released(
4796b6776e2SDmitry Osipenko 				host->dev, host->nresets, host->resets);
4806b6776e2SDmitry Osipenko 	if (err) {
4816b6776e2SDmitry Osipenko 		dev_err(host->dev, "failed to get reset: %d\n", err);
4826b6776e2SDmitry Osipenko 		return err;
4836b6776e2SDmitry Osipenko 	}
4846b6776e2SDmitry Osipenko 
4856b6776e2SDmitry Osipenko 	return 0;
4866b6776e2SDmitry Osipenko }
4876b6776e2SDmitry Osipenko 
host1x_probe(struct platform_device * pdev)48875471687STerje Bergstrom static int host1x_probe(struct platform_device *pdev)
48975471687STerje Bergstrom {
49075471687STerje Bergstrom 	struct host1x *host;
49175471687STerje Bergstrom 	int err;
49275471687STerje Bergstrom 
4936a341fdfSThierry Reding 	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
4946a341fdfSThierry Reding 	if (!host)
4956a341fdfSThierry Reding 		return -ENOMEM;
49675471687STerje Bergstrom 
4976a341fdfSThierry Reding 	host->info = of_device_get_match_data(&pdev->dev);
49875471687STerje Bergstrom 
499f1b53c4eSMikko Perttunen 	if (host->info->has_hypervisor) {
50097dea367SMikko Perttunen 		host->regs = devm_platform_ioremap_resource_byname(pdev, "vm");
50197dea367SMikko Perttunen 		if (IS_ERR(host->regs))
50297dea367SMikko Perttunen 			return PTR_ERR(host->regs);
503f1b53c4eSMikko Perttunen 
50497dea367SMikko Perttunen 		host->hv_regs = devm_platform_ioremap_resource_byname(pdev, "hypervisor");
50597dea367SMikko Perttunen 		if (IS_ERR(host->hv_regs))
50697dea367SMikko Perttunen 			return PTR_ERR(host->hv_regs);
50797dea367SMikko Perttunen 
50897dea367SMikko Perttunen 		if (host->info->has_common) {
50997dea367SMikko Perttunen 			host->common_regs = devm_platform_ioremap_resource_byname(pdev, "common");
51097dea367SMikko Perttunen 			if (IS_ERR(host->common_regs))
51197dea367SMikko Perttunen 				return PTR_ERR(host->common_regs);
512f1b53c4eSMikko Perttunen 		}
513f1b53c4eSMikko Perttunen 	} else {
51497dea367SMikko Perttunen 		host->regs = devm_platform_ioremap_resource(pdev, 0);
51597dea367SMikko Perttunen 		if (IS_ERR(host->regs))
51697dea367SMikko Perttunen 			return PTR_ERR(host->regs);
517f1b53c4eSMikko Perttunen 	}
51875471687STerje Bergstrom 
519625d4ffbSMikko Perttunen 	host->syncpt_irq = platform_get_irq(pdev, 0);
5207d31677bSArnd Bergmann 	if (host->syncpt_irq < 0)
5217d31677bSArnd Bergmann 		return host->syncpt_irq;
52275471687STerje Bergstrom 
523776dc384SThierry Reding 	mutex_init(&host->devices_lock);
524776dc384SThierry Reding 	INIT_LIST_HEAD(&host->devices);
525776dc384SThierry Reding 	INIT_LIST_HEAD(&host->list);
52675471687STerje Bergstrom 	host->dev = &pdev->dev;
52775471687STerje Bergstrom 
52875471687STerje Bergstrom 	/* set common host1x device data */
52975471687STerje Bergstrom 	platform_set_drvdata(pdev, host);
53075471687STerje Bergstrom 
531d98914ebSThierry Reding 	host->dev->dma_parms = &host->dma_parms;
532d98914ebSThierry Reding 	dma_set_max_seg_size(host->dev, UINT_MAX);
533d98914ebSThierry Reding 
53475471687STerje Bergstrom 	if (host->info->init) {
53575471687STerje Bergstrom 		err = host->info->init(host);
53675471687STerje Bergstrom 		if (err)
53775471687STerje Bergstrom 			return err;
53875471687STerje Bergstrom 	}
53975471687STerje Bergstrom 
54075471687STerje Bergstrom 	host->clk = devm_clk_get(&pdev->dev, NULL);
54175471687STerje Bergstrom 	if (IS_ERR(host->clk)) {
54275471687STerje Bergstrom 		err = PTR_ERR(host->clk);
5434bb923e8SThierry Reding 
5444bb923e8SThierry Reding 		if (err != -EPROBE_DEFER)
5454bb923e8SThierry Reding 			dev_err(&pdev->dev, "failed to get clock: %d\n", err);
5464bb923e8SThierry Reding 
54775471687STerje Bergstrom 		return err;
54875471687STerje Bergstrom 	}
54975471687STerje Bergstrom 
5506b6776e2SDmitry Osipenko 	err = host1x_get_resets(host);
5516b6776e2SDmitry Osipenko 	if (err)
552b386c6b7SThierry Reding 		return err;
553af1cbfb9SThierry Reding 
554e5d5db1aSChristophe JAILLET 	host1x_bo_cache_init(&host->cache);
555e5d5db1aSChristophe JAILLET 
55606867a36SThierry Reding 	err = host1x_iommu_init(host);
55706867a36SThierry Reding 	if (err < 0) {
55806867a36SThierry Reding 		dev_err(&pdev->dev, "failed to setup IOMMU: %d\n", err);
559e5d5db1aSChristophe JAILLET 		goto destroy_cache;
56041c3068cSThierry Reding 	}
561404bfb78SMikko Perttunen 
5628474b025SMikko Perttunen 	err = host1x_channel_list_init(&host->channel_list,
5638474b025SMikko Perttunen 				       host->info->nb_channels);
5646579324aSTerje Bergstrom 	if (err) {
5656579324aSTerje Bergstrom 		dev_err(&pdev->dev, "failed to initialize channel list\n");
56606867a36SThierry Reding 		goto iommu_exit;
5676579324aSTerje Bergstrom 	}
5686579324aSTerje Bergstrom 
5698aa5bcb6SMikko Perttunen 	err = host1x_memory_context_list_init(host);
5708aa5bcb6SMikko Perttunen 	if (err) {
5718aa5bcb6SMikko Perttunen 		dev_err(&pdev->dev, "failed to initialize context list\n");
5728aa5bcb6SMikko Perttunen 		goto free_channels;
5738aa5bcb6SMikko Perttunen 	}
5748aa5bcb6SMikko Perttunen 
57575471687STerje Bergstrom 	err = host1x_syncpt_init(host);
57675471687STerje Bergstrom 	if (err) {
57775471687STerje Bergstrom 		dev_err(&pdev->dev, "failed to initialize syncpts\n");
5788aa5bcb6SMikko Perttunen 		goto free_contexts;
57975471687STerje Bergstrom 	}
58075471687STerje Bergstrom 
581625d4ffbSMikko Perttunen 	err = host1x_intr_init(host);
5827ede0b0bSTerje Bergstrom 	if (err) {
5837ede0b0bSTerje Bergstrom 		dev_err(&pdev->dev, "failed to initialize interrupts\n");
58406867a36SThierry Reding 		goto deinit_syncpt;
5857ede0b0bSTerje Bergstrom 	}
5867ede0b0bSTerje Bergstrom 
5876b6776e2SDmitry Osipenko 	pm_runtime_enable(&pdev->dev);
5886236451dSTerje Bergstrom 
5896b6776e2SDmitry Osipenko 	err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
5906b6776e2SDmitry Osipenko 	if (err)
5916b6776e2SDmitry Osipenko 		goto pm_disable;
5926b6776e2SDmitry Osipenko 
5936b6776e2SDmitry Osipenko 	/* the driver's code isn't ready yet for the dynamic RPM */
5946b6776e2SDmitry Osipenko 	err = pm_runtime_resume_and_get(&pdev->dev);
5956b6776e2SDmitry Osipenko 	if (err)
5966b6776e2SDmitry Osipenko 		goto pm_disable;
5976b6776e2SDmitry Osipenko 
5986b6776e2SDmitry Osipenko 	host1x_debug_init(host);
5996841482bSThierry Reding 
600776dc384SThierry Reding 	err = host1x_register(host);
601776dc384SThierry Reding 	if (err < 0)
602109be8b2SChristophe JAILLET 		goto deinit_debugfs;
603692e6d7bSTerje Bergstrom 
604ca2030d5SThierry Reding 	err = devm_of_platform_populate(&pdev->dev);
605ca2030d5SThierry Reding 	if (err < 0)
606ca2030d5SThierry Reding 		goto unregister;
607ca2030d5SThierry Reding 
60875471687STerje Bergstrom 	return 0;
6097ede0b0bSTerje Bergstrom 
610ca2030d5SThierry Reding unregister:
611ca2030d5SThierry Reding 	host1x_unregister(host);
612109be8b2SChristophe JAILLET deinit_debugfs:
613109be8b2SChristophe JAILLET 	host1x_debug_deinit(host);
6146b6776e2SDmitry Osipenko 
6156b6776e2SDmitry Osipenko 	pm_runtime_put_sync_suspend(&pdev->dev);
6166b6776e2SDmitry Osipenko pm_disable:
6176b6776e2SDmitry Osipenko 	pm_runtime_disable(&pdev->dev);
6186b6776e2SDmitry Osipenko 
619776dc384SThierry Reding 	host1x_intr_deinit(host);
62006867a36SThierry Reding deinit_syncpt:
6217ede0b0bSTerje Bergstrom 	host1x_syncpt_deinit(host);
6228aa5bcb6SMikko Perttunen free_contexts:
6238aa5bcb6SMikko Perttunen 	host1x_memory_context_list_free(&host->context_list);
62406867a36SThierry Reding free_channels:
6258474b025SMikko Perttunen 	host1x_channel_list_free(&host->channel_list);
62606867a36SThierry Reding iommu_exit:
62706867a36SThierry Reding 	host1x_iommu_exit(host);
628e5d5db1aSChristophe JAILLET destroy_cache:
629e5d5db1aSChristophe JAILLET 	host1x_bo_cache_destroy(&host->cache);
630404bfb78SMikko Perttunen 
6317ede0b0bSTerje Bergstrom 	return err;
63275471687STerje Bergstrom }
63375471687STerje Bergstrom 
host1x_remove(struct platform_device * pdev)634452e7f0cSThierry Reding static int host1x_remove(struct platform_device *pdev)
63575471687STerje Bergstrom {
63675471687STerje Bergstrom 	struct host1x *host = platform_get_drvdata(pdev);
63775471687STerje Bergstrom 
638776dc384SThierry Reding 	host1x_unregister(host);
63944156eeeSThierry Reding 	host1x_debug_deinit(host);
6406b6776e2SDmitry Osipenko 
6416b6776e2SDmitry Osipenko 	pm_runtime_force_suspend(&pdev->dev);
6426b6776e2SDmitry Osipenko 
6437ede0b0bSTerje Bergstrom 	host1x_intr_deinit(host);
64475471687STerje Bergstrom 	host1x_syncpt_deinit(host);
6458aa5bcb6SMikko Perttunen 	host1x_memory_context_list_free(&host->context_list);
646025c6643SChristophe JAILLET 	host1x_channel_list_free(&host->channel_list);
64706867a36SThierry Reding 	host1x_iommu_exit(host);
6481f39b1dfSThierry Reding 	host1x_bo_cache_destroy(&host->cache);
649404bfb78SMikko Perttunen 
65075471687STerje Bergstrom 	return 0;
65175471687STerje Bergstrom }
65275471687STerje Bergstrom 
host1x_runtime_suspend(struct device * dev)6536b6776e2SDmitry Osipenko static int __maybe_unused host1x_runtime_suspend(struct device *dev)
6546b6776e2SDmitry Osipenko {
6556b6776e2SDmitry Osipenko 	struct host1x *host = dev_get_drvdata(dev);
6566b6776e2SDmitry Osipenko 	int err;
6576b6776e2SDmitry Osipenko 
6586b6776e2SDmitry Osipenko 	host1x_intr_stop(host);
6596b6776e2SDmitry Osipenko 	host1x_syncpt_save(host);
6606b6776e2SDmitry Osipenko 
6616b6776e2SDmitry Osipenko 	err = reset_control_bulk_assert(host->nresets, host->resets);
6626b6776e2SDmitry Osipenko 	if (err) {
6636b6776e2SDmitry Osipenko 		dev_err(dev, "failed to assert reset: %d\n", err);
6646b6776e2SDmitry Osipenko 		goto resume_host1x;
6656b6776e2SDmitry Osipenko 	}
6666b6776e2SDmitry Osipenko 
6676b6776e2SDmitry Osipenko 	usleep_range(1000, 2000);
6686b6776e2SDmitry Osipenko 
6696b6776e2SDmitry Osipenko 	clk_disable_unprepare(host->clk);
6706b6776e2SDmitry Osipenko 	reset_control_bulk_release(host->nresets, host->resets);
6716b6776e2SDmitry Osipenko 
6726b6776e2SDmitry Osipenko 	return 0;
6736b6776e2SDmitry Osipenko 
6746b6776e2SDmitry Osipenko resume_host1x:
675939179faSMikko Perttunen 	host1x_setup_virtualization_tables(host);
6766b6776e2SDmitry Osipenko 	host1x_syncpt_restore(host);
6776b6776e2SDmitry Osipenko 	host1x_intr_start(host);
6786b6776e2SDmitry Osipenko 
6796b6776e2SDmitry Osipenko 	return err;
6806b6776e2SDmitry Osipenko }
6816b6776e2SDmitry Osipenko 
host1x_runtime_resume(struct device * dev)6826b6776e2SDmitry Osipenko static int __maybe_unused host1x_runtime_resume(struct device *dev)
6836b6776e2SDmitry Osipenko {
6846b6776e2SDmitry Osipenko 	struct host1x *host = dev_get_drvdata(dev);
6856b6776e2SDmitry Osipenko 	int err;
6866b6776e2SDmitry Osipenko 
6876b6776e2SDmitry Osipenko 	err = reset_control_bulk_acquire(host->nresets, host->resets);
6886b6776e2SDmitry Osipenko 	if (err) {
6896b6776e2SDmitry Osipenko 		dev_err(dev, "failed to acquire reset: %d\n", err);
6906b6776e2SDmitry Osipenko 		return err;
6916b6776e2SDmitry Osipenko 	}
6926b6776e2SDmitry Osipenko 
6936b6776e2SDmitry Osipenko 	err = clk_prepare_enable(host->clk);
6946b6776e2SDmitry Osipenko 	if (err) {
6956b6776e2SDmitry Osipenko 		dev_err(dev, "failed to enable clock: %d\n", err);
6966b6776e2SDmitry Osipenko 		goto release_reset;
6976b6776e2SDmitry Osipenko 	}
6986b6776e2SDmitry Osipenko 
6996b6776e2SDmitry Osipenko 	err = reset_control_bulk_deassert(host->nresets, host->resets);
7006b6776e2SDmitry Osipenko 	if (err < 0) {
7016b6776e2SDmitry Osipenko 		dev_err(dev, "failed to deassert reset: %d\n", err);
7026b6776e2SDmitry Osipenko 		goto disable_clk;
7036b6776e2SDmitry Osipenko 	}
7046b6776e2SDmitry Osipenko 
705939179faSMikko Perttunen 	host1x_setup_virtualization_tables(host);
7066b6776e2SDmitry Osipenko 	host1x_syncpt_restore(host);
7076b6776e2SDmitry Osipenko 	host1x_intr_start(host);
7086b6776e2SDmitry Osipenko 
7096b6776e2SDmitry Osipenko 	return 0;
7106b6776e2SDmitry Osipenko 
7116b6776e2SDmitry Osipenko disable_clk:
7126b6776e2SDmitry Osipenko 	clk_disable_unprepare(host->clk);
7136b6776e2SDmitry Osipenko release_reset:
7146b6776e2SDmitry Osipenko 	reset_control_bulk_release(host->nresets, host->resets);
7156b6776e2SDmitry Osipenko 
7166b6776e2SDmitry Osipenko 	return err;
7176b6776e2SDmitry Osipenko }
7186b6776e2SDmitry Osipenko 
7196b6776e2SDmitry Osipenko static const struct dev_pm_ops host1x_pm_ops = {
7206b6776e2SDmitry Osipenko 	SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume,
7216b6776e2SDmitry Osipenko 			   NULL)
7226b6776e2SDmitry Osipenko 	/* TODO: add system suspend-resume once driver will be ready for that */
7236b6776e2SDmitry Osipenko };
7246b6776e2SDmitry Osipenko 
725692e6d7bSTerje Bergstrom static struct platform_driver tegra_host1x_driver = {
72675471687STerje Bergstrom 	.driver = {
72775471687STerje Bergstrom 		.name = "tegra-host1x",
72875471687STerje Bergstrom 		.of_match_table = host1x_of_match,
7296b6776e2SDmitry Osipenko 		.pm = &host1x_pm_ops,
73075471687STerje Bergstrom 	},
731452e7f0cSThierry Reding 	.probe = host1x_probe,
732452e7f0cSThierry Reding 	.remove = host1x_remove,
73375471687STerje Bergstrom };
73475471687STerje Bergstrom 
73528fae81fSThierry Reding static struct platform_driver * const drivers[] = {
73628fae81fSThierry Reding 	&tegra_host1x_driver,
73728fae81fSThierry Reding 	&tegra_mipi_driver,
73828fae81fSThierry Reding };
73928fae81fSThierry Reding 
tegra_host1x_init(void)740692e6d7bSTerje Bergstrom static int __init tegra_host1x_init(void)
741692e6d7bSTerje Bergstrom {
742692e6d7bSTerje Bergstrom 	int err;
74375471687STerje Bergstrom 
744f4c5cf88SThierry Reding 	err = bus_register(&host1x_bus_type);
745692e6d7bSTerje Bergstrom 	if (err < 0)
746692e6d7bSTerje Bergstrom 		return err;
747692e6d7bSTerje Bergstrom 
74828fae81fSThierry Reding 	err = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
7494de6a2d6SThierry Reding 	if (err < 0)
750f4c5cf88SThierry Reding 		bus_unregister(&host1x_bus_type);
75128fae81fSThierry Reding 
7524de6a2d6SThierry Reding 	return err;
753692e6d7bSTerje Bergstrom }
754692e6d7bSTerje Bergstrom module_init(tegra_host1x_init);
755692e6d7bSTerje Bergstrom 
tegra_host1x_exit(void)756692e6d7bSTerje Bergstrom static void __exit tegra_host1x_exit(void)
757692e6d7bSTerje Bergstrom {
75828fae81fSThierry Reding 	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
759f4c5cf88SThierry Reding 	bus_unregister(&host1x_bus_type);
760692e6d7bSTerje Bergstrom }
761692e6d7bSTerje Bergstrom module_exit(tegra_host1x_exit);
762692e6d7bSTerje Bergstrom 
763501be6c1SThierry Reding /**
764501be6c1SThierry Reding  * host1x_get_dma_mask() - query the supported DMA mask for host1x
765501be6c1SThierry Reding  * @host1x: host1x instance
766501be6c1SThierry Reding  *
767501be6c1SThierry Reding  * Note that this returns the supported DMA mask for host1x, which can be
768501be6c1SThierry Reding  * different from the applicable DMA mask under certain circumstances.
769501be6c1SThierry Reding  */
host1x_get_dma_mask(struct host1x * host1x)770501be6c1SThierry Reding u64 host1x_get_dma_mask(struct host1x *host1x)
771501be6c1SThierry Reding {
772501be6c1SThierry Reding 	return host1x->info->dma_mask;
773501be6c1SThierry Reding }
774501be6c1SThierry Reding EXPORT_SYMBOL(host1x_get_dma_mask);
775501be6c1SThierry Reding 
776692e6d7bSTerje Bergstrom MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
77775471687STerje Bergstrom MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>");
77875471687STerje Bergstrom MODULE_DESCRIPTION("Host1x driver for Tegra products");
77975471687STerje Bergstrom MODULE_LICENSE("GPL");
780