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>
15573cbf48SRob Herring #include <linux/of_platform.h>
16573cbf48SRob 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[] = {
1454e90b03aSMikko Perttunen { /* SE1 */ .base = 0x1ac8, .offset = 0x90, .limit = 0x90 },
1464e90b03aSMikko Perttunen { /* SE2 */ .base = 0x1ad0, .offset = 0x90, .limit = 0x90 },
1474e90b03aSMikko Perttunen { /* SE3 */ .base = 0x1ad8, .offset = 0x90, .limit = 0x90 },
1484e90b03aSMikko Perttunen { /* SE4 */ .base = 0x1ae0, .offset = 0x90, .limit = 0x90 },
1494e90b03aSMikko Perttunen { /* ISP */ .base = 0x1ae8, .offset = 0x50, .limit = 0x50 },
1504e90b03aSMikko Perttunen { /* VIC */ .base = 0x1af0, .offset = 0x30, .limit = 0x34 },
1514e90b03aSMikko Perttunen { /* NVENC */ .base = 0x1af8, .offset = 0x30, .limit = 0x34 },
1524e90b03aSMikko Perttunen { /* NVDEC */ .base = 0x1b00, .offset = 0x30, .limit = 0x34 },
1534e90b03aSMikko Perttunen { /* NVJPG */ .base = 0x1b08, .offset = 0x30, .limit = 0x34 },
1544e90b03aSMikko Perttunen { /* TSEC */ .base = 0x1b10, .offset = 0x30, .limit = 0x34 },
1554e90b03aSMikko Perttunen { /* TSECB */ .base = 0x1b18, .offset = 0x30, .limit = 0x34 },
1564e90b03aSMikko Perttunen { /* VI 0 */ .base = 0x1b80, .offset = 0x10000, .limit = 0x10000 },
1574e90b03aSMikko Perttunen { /* VI 1 */ .base = 0x1b88, .offset = 0x20000, .limit = 0x20000 },
1584e90b03aSMikko Perttunen { /* VI 2 */ .base = 0x1b90, .offset = 0x30000, .limit = 0x30000 },
1594e90b03aSMikko Perttunen { /* VI 3 */ .base = 0x1b98, .offset = 0x40000, .limit = 0x40000 },
1604e90b03aSMikko Perttunen { /* VI 4 */ .base = 0x1ba0, .offset = 0x50000, .limit = 0x50000 },
1614e90b03aSMikko Perttunen { /* VI 5 */ .base = 0x1ba8, .offset = 0x60000, .limit = 0x60000 },
1624e90b03aSMikko Perttunen { /* VI 6 */ .base = 0x1bb0, .offset = 0x70000, .limit = 0x70000 },
1634e90b03aSMikko Perttunen { /* VI 7 */ .base = 0x1bb8, .offset = 0x80000, .limit = 0x80000 },
1644e90b03aSMikko Perttunen { /* VI 8 */ .base = 0x1bc0, .offset = 0x90000, .limit = 0x90000 },
1654e90b03aSMikko Perttunen { /* VI 9 */ .base = 0x1bc8, .offset = 0xa0000, .limit = 0xa0000 },
1664e90b03aSMikko Perttunen { /* VI 10 */ .base = 0x1bd0, .offset = 0xb0000, .limit = 0xb0000 },
1674e90b03aSMikko Perttunen { /* VI 11 */ .base = 0x1bd8, .offset = 0xc0000, .limit = 0xc0000 },
1686841482bSThierry Reding };
1696841482bSThierry Reding
170f1b53c4eSMikko Perttunen static const struct host1x_info host1x06_info = {
171f1b53c4eSMikko Perttunen .nb_channels = 63,
172f1b53c4eSMikko Perttunen .nb_pts = 576,
173f1b53c4eSMikko Perttunen .nb_mlocks = 24,
174f1b53c4eSMikko Perttunen .nb_bases = 16,
175f1b53c4eSMikko Perttunen .init = host1x06_init,
176f1b53c4eSMikko Perttunen .sync_offset = 0x0,
1778de896ebSThierry Reding .dma_mask = DMA_BIT_MASK(40),
17806867a36SThierry Reding .has_wide_gather = true,
179f1b53c4eSMikko Perttunen .has_hypervisor = true,
1806841482bSThierry Reding .num_sid_entries = ARRAY_SIZE(tegra186_sid_table),
1816841482bSThierry Reding .sid_table = tegra186_sid_table,
182f5ba33fbSMikko Perttunen .reserve_vblank_syncpts = false,
1831fa8d07aSMikko Perttunen .skip_reset_assert = true,
1846841482bSThierry Reding };
1856841482bSThierry Reding
1866841482bSThierry Reding static const struct host1x_sid_entry tegra194_sid_table[] = {
1874e90b03aSMikko Perttunen { /* SE1 */ .base = 0x1ac8, .offset = 0x90, .limit = 0x90 },
1884e90b03aSMikko Perttunen { /* SE2 */ .base = 0x1ad0, .offset = 0x90, .limit = 0x90 },
1894e90b03aSMikko Perttunen { /* SE3 */ .base = 0x1ad8, .offset = 0x90, .limit = 0x90 },
1904e90b03aSMikko Perttunen { /* SE4 */ .base = 0x1ae0, .offset = 0x90, .limit = 0x90 },
1914e90b03aSMikko Perttunen { /* ISP */ .base = 0x1ae8, .offset = 0x800, .limit = 0x800 },
1924e90b03aSMikko Perttunen { /* VIC */ .base = 0x1af0, .offset = 0x30, .limit = 0x34 },
1934e90b03aSMikko Perttunen { /* NVENC */ .base = 0x1af8, .offset = 0x30, .limit = 0x34 },
1944e90b03aSMikko Perttunen { /* NVDEC */ .base = 0x1b00, .offset = 0x30, .limit = 0x34 },
1954e90b03aSMikko Perttunen { /* NVJPG */ .base = 0x1b08, .offset = 0x30, .limit = 0x34 },
1964e90b03aSMikko Perttunen { /* TSEC */ .base = 0x1b10, .offset = 0x30, .limit = 0x34 },
1974e90b03aSMikko Perttunen { /* TSECB */ .base = 0x1b18, .offset = 0x30, .limit = 0x34 },
1984e90b03aSMikko Perttunen { /* VI */ .base = 0x1b80, .offset = 0x800, .limit = 0x800 },
1994e90b03aSMikko Perttunen { /* VI_THI */ .base = 0x1b88, .offset = 0x30, .limit = 0x34 },
2004e90b03aSMikko Perttunen { /* ISP_THI */ .base = 0x1b90, .offset = 0x30, .limit = 0x34 },
2014e90b03aSMikko Perttunen { /* PVA0_CLUSTER */ .base = 0x1b98, .offset = 0x0, .limit = 0x0 },
2024e90b03aSMikko Perttunen { /* PVA0_CLUSTER */ .base = 0x1ba0, .offset = 0x0, .limit = 0x0 },
2034e90b03aSMikko Perttunen { /* NVDLA0 */ .base = 0x1ba8, .offset = 0x30, .limit = 0x34 },
2044e90b03aSMikko Perttunen { /* NVDLA1 */ .base = 0x1bb0, .offset = 0x30, .limit = 0x34 },
2054e90b03aSMikko Perttunen { /* NVENC1 */ .base = 0x1bb8, .offset = 0x30, .limit = 0x34 },
2064e90b03aSMikko Perttunen { /* NVDEC1 */ .base = 0x1bc0, .offset = 0x30, .limit = 0x34 },
207f1b53c4eSMikko Perttunen };
208f1b53c4eSMikko Perttunen
209ac1bdbf2SThierry Reding static const struct host1x_info host1x07_info = {
210ac1bdbf2SThierry Reding .nb_channels = 63,
211ac1bdbf2SThierry Reding .nb_pts = 704,
212ac1bdbf2SThierry Reding .nb_mlocks = 32,
213ac1bdbf2SThierry Reding .nb_bases = 0,
214ac1bdbf2SThierry Reding .init = host1x07_init,
215ac1bdbf2SThierry Reding .sync_offset = 0x0,
216ac1bdbf2SThierry Reding .dma_mask = DMA_BIT_MASK(40),
21706867a36SThierry Reding .has_wide_gather = true,
218ac1bdbf2SThierry Reding .has_hypervisor = true,
2196841482bSThierry Reding .num_sid_entries = ARRAY_SIZE(tegra194_sid_table),
2206841482bSThierry Reding .sid_table = tegra194_sid_table,
221f5ba33fbSMikko Perttunen .reserve_vblank_syncpts = false,
222ac1bdbf2SThierry Reding };
223ac1bdbf2SThierry Reding
2249abdd497SMikko Perttunen /*
2259abdd497SMikko Perttunen * Tegra234 has two stream ID protection tables, one for setting stream IDs
2269abdd497SMikko Perttunen * through the channel path via SETSTREAMID, and one for setting them via
2279abdd497SMikko Perttunen * MMIO. We program each engine's data stream ID in the channel path table
2289abdd497SMikko Perttunen * and firmware stream ID in the MMIO path table.
2299abdd497SMikko Perttunen */
2309abdd497SMikko Perttunen static const struct host1x_sid_entry tegra234_sid_table[] = {
2314e90b03aSMikko Perttunen { /* SE1 MMIO */ .base = 0x1650, .offset = 0x90, .limit = 0x90 },
2324e90b03aSMikko Perttunen { /* SE1 ch */ .base = 0x1730, .offset = 0x90, .limit = 0x90 },
2334e90b03aSMikko Perttunen { /* SE2 MMIO */ .base = 0x1658, .offset = 0x90, .limit = 0x90 },
2344e90b03aSMikko Perttunen { /* SE2 ch */ .base = 0x1738, .offset = 0x90, .limit = 0x90 },
2354e90b03aSMikko Perttunen { /* SE4 MMIO */ .base = 0x1660, .offset = 0x90, .limit = 0x90 },
2364e90b03aSMikko Perttunen { /* SE4 ch */ .base = 0x1740, .offset = 0x90, .limit = 0x90 },
2374e90b03aSMikko Perttunen { /* ISP MMIO */ .base = 0x1680, .offset = 0x800, .limit = 0x800 },
2384e90b03aSMikko Perttunen { /* VIC MMIO */ .base = 0x1688, .offset = 0x34, .limit = 0x34 },
2394e90b03aSMikko Perttunen { /* VIC ch */ .base = 0x17b8, .offset = 0x30, .limit = 0x30 },
2404e90b03aSMikko Perttunen { /* NVENC MMIO */ .base = 0x1690, .offset = 0x34, .limit = 0x34 },
2414e90b03aSMikko Perttunen { /* NVENC ch */ .base = 0x17c0, .offset = 0x30, .limit = 0x30 },
2424e90b03aSMikko Perttunen { /* NVDEC MMIO */ .base = 0x1698, .offset = 0x34, .limit = 0x34 },
2434e90b03aSMikko Perttunen { /* NVDEC ch */ .base = 0x17c8, .offset = 0x30, .limit = 0x30 },
2444e90b03aSMikko Perttunen { /* NVJPG MMIO */ .base = 0x16a0, .offset = 0x34, .limit = 0x34 },
2454e90b03aSMikko Perttunen { /* NVJPG ch */ .base = 0x17d0, .offset = 0x30, .limit = 0x30 },
2464e90b03aSMikko Perttunen { /* TSEC MMIO */ .base = 0x16a8, .offset = 0x30, .limit = 0x34 },
2474e90b03aSMikko Perttunen { /* NVJPG1 MMIO */ .base = 0x16b0, .offset = 0x34, .limit = 0x34 },
2484e90b03aSMikko Perttunen { /* NVJPG1 ch */ .base = 0x17a8, .offset = 0x30, .limit = 0x30 },
2494e90b03aSMikko Perttunen { /* VI MMIO */ .base = 0x16b8, .offset = 0x800, .limit = 0x800 },
2504e90b03aSMikko Perttunen { /* VI_THI MMIO */ .base = 0x16c0, .offset = 0x30, .limit = 0x34 },
2514e90b03aSMikko Perttunen { /* ISP_THI MMIO */ .base = 0x16c8, .offset = 0x30, .limit = 0x34 },
2524e90b03aSMikko Perttunen { /* NVDLA MMIO */ .base = 0x16d8, .offset = 0x30, .limit = 0x34 },
2534e90b03aSMikko Perttunen { /* NVDLA ch */ .base = 0x17e0, .offset = 0x30, .limit = 0x34 },
2544e90b03aSMikko Perttunen { /* NVDLA1 MMIO */ .base = 0x16e0, .offset = 0x30, .limit = 0x34 },
2554e90b03aSMikko Perttunen { /* NVDLA1 ch */ .base = 0x17e8, .offset = 0x30, .limit = 0x34 },
2564e90b03aSMikko Perttunen { /* OFA MMIO */ .base = 0x16e8, .offset = 0x34, .limit = 0x34 },
2574e90b03aSMikko Perttunen { /* OFA ch */ .base = 0x1768, .offset = 0x30, .limit = 0x30 },
2584e90b03aSMikko Perttunen { /* VI2 MMIO */ .base = 0x16f0, .offset = 0x800, .limit = 0x800 },
2594e90b03aSMikko Perttunen { /* VI2_THI MMIO */ .base = 0x16f8, .offset = 0x30, .limit = 0x34 },
2609abdd497SMikko Perttunen };
2619abdd497SMikko Perttunen
2629abdd497SMikko Perttunen static const struct host1x_info host1x08_info = {
2639abdd497SMikko Perttunen .nb_channels = 63,
2649abdd497SMikko Perttunen .nb_pts = 1024,
2659abdd497SMikko Perttunen .nb_mlocks = 24,
2669abdd497SMikko Perttunen .nb_bases = 0,
2679abdd497SMikko Perttunen .init = host1x08_init,
2689abdd497SMikko Perttunen .sync_offset = 0x0,
2699abdd497SMikko Perttunen .dma_mask = DMA_BIT_MASK(40),
2709abdd497SMikko Perttunen .has_wide_gather = true,
2719abdd497SMikko Perttunen .has_hypervisor = true,
2729abdd497SMikko Perttunen .has_common = true,
2739abdd497SMikko Perttunen .num_sid_entries = ARRAY_SIZE(tegra234_sid_table),
2749abdd497SMikko Perttunen .sid_table = tegra234_sid_table,
2759abdd497SMikko Perttunen .streamid_vm_table = { 0x1004, 128 },
2769abdd497SMikko Perttunen .classid_vm_table = { 0x1404, 25 },
2779abdd497SMikko Perttunen .mmio_vm_table = { 0x1504, 25 },
2789abdd497SMikko Perttunen .reserve_vblank_syncpts = false,
2799abdd497SMikko Perttunen };
2809abdd497SMikko Perttunen
2816df633d0SThierry Reding static const struct of_device_id host1x_of_match[] = {
2829abdd497SMikko Perttunen { .compatible = "nvidia,tegra234-host1x", .data = &host1x08_info, },
283ac1bdbf2SThierry Reding { .compatible = "nvidia,tegra194-host1x", .data = &host1x07_info, },
284f1b53c4eSMikko Perttunen { .compatible = "nvidia,tegra186-host1x", .data = &host1x06_info, },
285a134789aSThierry Reding { .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, },
286e6fff4aaSThierry Reding { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, },
2875407f31bSThierry Reding { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, },
28875471687STerje Bergstrom { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, },
28975471687STerje Bergstrom { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, },
29075471687STerje Bergstrom { },
29175471687STerje Bergstrom };
29275471687STerje Bergstrom MODULE_DEVICE_TABLE(of, host1x_of_match);
29375471687STerje Bergstrom
host1x_setup_virtualization_tables(struct host1x * host)294939179faSMikko Perttunen static void host1x_setup_virtualization_tables(struct host1x *host)
2956841482bSThierry Reding {
2966841482bSThierry Reding const struct host1x_info *info = host->info;
2976841482bSThierry Reding unsigned int i;
2986841482bSThierry Reding
2996b6776e2SDmitry Osipenko if (!info->has_hypervisor)
3006b6776e2SDmitry Osipenko return;
3016b6776e2SDmitry Osipenko
3026841482bSThierry Reding for (i = 0; i < info->num_sid_entries; i++) {
3036841482bSThierry Reding const struct host1x_sid_entry *entry = &info->sid_table[i];
3046841482bSThierry Reding
3056841482bSThierry Reding host1x_hypervisor_writel(host, entry->offset, entry->base);
3066841482bSThierry Reding host1x_hypervisor_writel(host, entry->limit, entry->base + 4);
3076841482bSThierry Reding }
308939179faSMikko Perttunen
309939179faSMikko Perttunen for (i = 0; i < info->streamid_vm_table.count; i++) {
310939179faSMikko Perttunen /* Allow access to all stream IDs to all VMs. */
311939179faSMikko Perttunen host1x_hypervisor_writel(host, 0xff, info->streamid_vm_table.base + 4 * i);
312939179faSMikko Perttunen }
313939179faSMikko Perttunen
314939179faSMikko Perttunen for (i = 0; i < info->classid_vm_table.count; i++) {
315939179faSMikko Perttunen /* Allow access to all classes to all VMs. */
316939179faSMikko Perttunen host1x_hypervisor_writel(host, 0xff, info->classid_vm_table.base + 4 * i);
317939179faSMikko Perttunen }
318939179faSMikko Perttunen
319939179faSMikko Perttunen for (i = 0; i < info->mmio_vm_table.count; i++) {
320939179faSMikko Perttunen /* Use VM1 (that's us) as originator VMID for engine MMIO accesses. */
321939179faSMikko Perttunen host1x_hypervisor_writel(host, 0x1, info->mmio_vm_table.base + 4 * i);
322939179faSMikko Perttunen }
3236841482bSThierry Reding }
3246841482bSThierry Reding
host1x_wants_iommu(struct host1x * host1x)3254010e729SThierry Reding static bool host1x_wants_iommu(struct host1x *host1x)
3264010e729SThierry Reding {
327c2418f91SRobin Murphy /* Our IOMMU usage policy doesn't currently play well with GART */
328c2418f91SRobin Murphy if (of_machine_is_compatible("nvidia,tegra20"))
329c2418f91SRobin Murphy return false;
330c2418f91SRobin Murphy
3314010e729SThierry Reding /*
3324010e729SThierry Reding * If we support addressing a maximum of 32 bits of physical memory
3334010e729SThierry Reding * and if the host1x firewall is enabled, there's no need to enable
3344010e729SThierry Reding * IOMMU support. This can happen for example on Tegra20, Tegra30
3354010e729SThierry Reding * and Tegra114.
3364010e729SThierry Reding *
3374010e729SThierry Reding * Tegra124 and later can address up to 34 bits of physical memory and
3384010e729SThierry Reding * many platforms come equipped with more than 2 GiB of system memory,
3394010e729SThierry Reding * which requires crossing the 4 GiB boundary. But there's a catch: on
3404010e729SThierry Reding * SoCs before Tegra186 (i.e. Tegra124 and Tegra210), the host1x can
3414010e729SThierry Reding * only address up to 32 bits of memory in GATHER opcodes, which means
3424010e729SThierry Reding * that command buffers need to either be in the first 2 GiB of system
3434010e729SThierry Reding * memory (which could quickly lead to memory exhaustion), or command
3444010e729SThierry Reding * buffers need to be treated differently from other buffers (which is
3454010e729SThierry Reding * not possible with the current ABI).
3464010e729SThierry Reding *
3474010e729SThierry Reding * A third option is to use the IOMMU in these cases to make sure all
3484010e729SThierry Reding * buffers will be mapped into a 32-bit IOVA space that host1x can
3494010e729SThierry Reding * address. This allows all of the system memory to be used and works
3504010e729SThierry Reding * within the limitations of the host1x on these SoCs.
3514010e729SThierry Reding *
3524010e729SThierry Reding * In summary, default to enable IOMMU on Tegra124 and later. For any
3534010e729SThierry Reding * of the earlier SoCs, only use the IOMMU for additional safety when
3544010e729SThierry Reding * the host1x firewall is disabled.
3554010e729SThierry Reding */
3564010e729SThierry Reding if (host1x->info->dma_mask <= DMA_BIT_MASK(32)) {
3574010e729SThierry Reding if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
3584010e729SThierry Reding return false;
3594010e729SThierry Reding }
3604010e729SThierry Reding
3614010e729SThierry Reding return true;
3624010e729SThierry Reding }
3634010e729SThierry Reding
364*cb83f4b9SJason Gunthorpe /*
365*cb83f4b9SJason Gunthorpe * Returns ERR_PTR on failure, NULL if the translation is IDENTITY, otherwise a
366*cb83f4b9SJason Gunthorpe * valid paging domain.
367*cb83f4b9SJason Gunthorpe */
host1x_iommu_attach(struct host1x * host)36806867a36SThierry Reding static struct iommu_domain *host1x_iommu_attach(struct host1x *host)
36906867a36SThierry Reding {
37006867a36SThierry Reding struct iommu_domain *domain = iommu_get_domain_for_dev(host->dev);
37106867a36SThierry Reding int err;
37206867a36SThierry Reding
373d5185965SDmitry Osipenko #if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
374d5185965SDmitry Osipenko if (host->dev->archdata.mapping) {
375d5185965SDmitry Osipenko struct dma_iommu_mapping *mapping =
376d5185965SDmitry Osipenko to_dma_iommu_mapping(host->dev);
377d5185965SDmitry Osipenko arm_iommu_detach_device(host->dev);
378d5185965SDmitry Osipenko arm_iommu_release_mapping(mapping);
379d5185965SDmitry Osipenko
380d5185965SDmitry Osipenko domain = iommu_get_domain_for_dev(host->dev);
381d5185965SDmitry Osipenko }
382d5185965SDmitry Osipenko #endif
383d5185965SDmitry Osipenko
38406867a36SThierry Reding /*
3854010e729SThierry Reding * We may not always want to enable IOMMU support (for example if the
3864010e729SThierry Reding * host1x firewall is already enabled and we don't support addressing
3874010e729SThierry Reding * more than 32 bits of physical memory), so check for that first.
3884010e729SThierry Reding *
3894010e729SThierry Reding * Similarly, if host1x is already attached to an IOMMU (via the DMA
3904010e729SThierry Reding * API), don't try to attach again.
39106867a36SThierry Reding */
392*cb83f4b9SJason Gunthorpe if (domain && domain->type == IOMMU_DOMAIN_IDENTITY)
393*cb83f4b9SJason Gunthorpe domain = NULL;
3944010e729SThierry Reding if (!host1x_wants_iommu(host) || domain)
39506867a36SThierry Reding return domain;
39606867a36SThierry Reding
39706867a36SThierry Reding host->group = iommu_group_get(host->dev);
39806867a36SThierry Reding if (host->group) {
39906867a36SThierry Reding struct iommu_domain_geometry *geometry;
40006867a36SThierry Reding dma_addr_t start, end;
40106867a36SThierry Reding unsigned long order;
40206867a36SThierry Reding
40306867a36SThierry Reding err = iova_cache_get();
40406867a36SThierry Reding if (err < 0)
40506867a36SThierry Reding goto put_group;
40606867a36SThierry Reding
4079719c7b8SLu Baolu host->domain = iommu_paging_domain_alloc(host->dev);
4089719c7b8SLu Baolu if (IS_ERR(host->domain)) {
4099719c7b8SLu Baolu err = PTR_ERR(host->domain);
4109719c7b8SLu Baolu host->domain = NULL;
41106867a36SThierry Reding goto put_cache;
41206867a36SThierry Reding }
41306867a36SThierry Reding
41406867a36SThierry Reding err = iommu_attach_group(host->domain, host->group);
41506867a36SThierry Reding if (err) {
41606867a36SThierry Reding if (err == -ENODEV)
41706867a36SThierry Reding err = 0;
41806867a36SThierry Reding
41906867a36SThierry Reding goto free_domain;
42006867a36SThierry Reding }
42106867a36SThierry Reding
42206867a36SThierry Reding geometry = &host->domain->geometry;
42306867a36SThierry Reding start = geometry->aperture_start & host->info->dma_mask;
42406867a36SThierry Reding end = geometry->aperture_end & host->info->dma_mask;
42506867a36SThierry Reding
42606867a36SThierry Reding order = __ffs(host->domain->pgsize_bitmap);
42706867a36SThierry Reding init_iova_domain(&host->iova, 1UL << order, start >> order);
42806867a36SThierry Reding host->iova_end = end;
42906867a36SThierry Reding
43006867a36SThierry Reding domain = host->domain;
43106867a36SThierry Reding }
43206867a36SThierry Reding
43306867a36SThierry Reding return domain;
43406867a36SThierry Reding
43506867a36SThierry Reding free_domain:
43606867a36SThierry Reding iommu_domain_free(host->domain);
43706867a36SThierry Reding host->domain = NULL;
43806867a36SThierry Reding put_cache:
43906867a36SThierry Reding iova_cache_put();
44006867a36SThierry Reding put_group:
44106867a36SThierry Reding iommu_group_put(host->group);
44206867a36SThierry Reding host->group = NULL;
44306867a36SThierry Reding
44406867a36SThierry Reding return ERR_PTR(err);
44506867a36SThierry Reding }
44606867a36SThierry Reding
host1x_iommu_init(struct host1x * host)44706867a36SThierry Reding static int host1x_iommu_init(struct host1x *host)
44806867a36SThierry Reding {
44906867a36SThierry Reding u64 mask = host->info->dma_mask;
45006867a36SThierry Reding struct iommu_domain *domain;
45106867a36SThierry Reding int err;
45206867a36SThierry Reding
45306867a36SThierry Reding domain = host1x_iommu_attach(host);
45406867a36SThierry Reding if (IS_ERR(domain)) {
45506867a36SThierry Reding err = PTR_ERR(domain);
45606867a36SThierry Reding dev_err(host->dev, "failed to attach to IOMMU: %d\n", err);
45706867a36SThierry Reding return err;
45806867a36SThierry Reding }
45906867a36SThierry Reding
46006867a36SThierry Reding /*
46106867a36SThierry Reding * If we're not behind an IOMMU make sure we don't get push buffers
46206867a36SThierry Reding * that are allocated outside of the range addressable by the GATHER
46306867a36SThierry Reding * opcode.
46406867a36SThierry Reding *
46506867a36SThierry Reding * Newer generations of Tegra (Tegra186 and later) support a wide
46606867a36SThierry Reding * variant of the GATHER opcode that allows addressing more bits.
46706867a36SThierry Reding */
46806867a36SThierry Reding if (!domain && !host->info->has_wide_gather)
46906867a36SThierry Reding mask = DMA_BIT_MASK(32);
47006867a36SThierry Reding
47106867a36SThierry Reding err = dma_coerce_mask_and_coherent(host->dev, mask);
47206867a36SThierry Reding if (err < 0) {
47306867a36SThierry Reding dev_err(host->dev, "failed to set DMA mask: %d\n", err);
47406867a36SThierry Reding return err;
47506867a36SThierry Reding }
47606867a36SThierry Reding
47706867a36SThierry Reding return 0;
47806867a36SThierry Reding }
47906867a36SThierry Reding
host1x_iommu_exit(struct host1x * host)48006867a36SThierry Reding static void host1x_iommu_exit(struct host1x *host)
48106867a36SThierry Reding {
48206867a36SThierry Reding if (host->domain) {
48306867a36SThierry Reding put_iova_domain(&host->iova);
48406867a36SThierry Reding iommu_detach_group(host->domain, host->group);
48506867a36SThierry Reding
48606867a36SThierry Reding iommu_domain_free(host->domain);
48706867a36SThierry Reding host->domain = NULL;
48806867a36SThierry Reding
48906867a36SThierry Reding iova_cache_put();
49006867a36SThierry Reding
49106867a36SThierry Reding iommu_group_put(host->group);
49206867a36SThierry Reding host->group = NULL;
49306867a36SThierry Reding }
49406867a36SThierry Reding }
49506867a36SThierry Reding
host1x_get_resets(struct host1x * host)4966b6776e2SDmitry Osipenko static int host1x_get_resets(struct host1x *host)
4976b6776e2SDmitry Osipenko {
4986b6776e2SDmitry Osipenko int err;
4996b6776e2SDmitry Osipenko
5006b6776e2SDmitry Osipenko host->resets[0].id = "mc";
5016b6776e2SDmitry Osipenko host->resets[1].id = "host1x";
5026b6776e2SDmitry Osipenko host->nresets = ARRAY_SIZE(host->resets);
5036b6776e2SDmitry Osipenko
5046b6776e2SDmitry Osipenko err = devm_reset_control_bulk_get_optional_exclusive_released(
5056b6776e2SDmitry Osipenko host->dev, host->nresets, host->resets);
5066b6776e2SDmitry Osipenko if (err) {
5076b6776e2SDmitry Osipenko dev_err(host->dev, "failed to get reset: %d\n", err);
5086b6776e2SDmitry Osipenko return err;
5096b6776e2SDmitry Osipenko }
5106b6776e2SDmitry Osipenko
5116b6776e2SDmitry Osipenko return 0;
5126b6776e2SDmitry Osipenko }
5136b6776e2SDmitry Osipenko
host1x_probe(struct platform_device * pdev)51475471687STerje Bergstrom static int host1x_probe(struct platform_device *pdev)
51575471687STerje Bergstrom {
51675471687STerje Bergstrom struct host1x *host;
517f017f1e9SMikko Perttunen int err, i;
51875471687STerje Bergstrom
5196a341fdfSThierry Reding host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
5206a341fdfSThierry Reding if (!host)
5216a341fdfSThierry Reding return -ENOMEM;
52275471687STerje Bergstrom
5236a341fdfSThierry Reding host->info = of_device_get_match_data(&pdev->dev);
52475471687STerje Bergstrom
525f1b53c4eSMikko Perttunen if (host->info->has_hypervisor) {
52697dea367SMikko Perttunen host->regs = devm_platform_ioremap_resource_byname(pdev, "vm");
52797dea367SMikko Perttunen if (IS_ERR(host->regs))
52897dea367SMikko Perttunen return PTR_ERR(host->regs);
529f1b53c4eSMikko Perttunen
53097dea367SMikko Perttunen host->hv_regs = devm_platform_ioremap_resource_byname(pdev, "hypervisor");
53197dea367SMikko Perttunen if (IS_ERR(host->hv_regs))
53297dea367SMikko Perttunen return PTR_ERR(host->hv_regs);
53397dea367SMikko Perttunen
53497dea367SMikko Perttunen if (host->info->has_common) {
53597dea367SMikko Perttunen host->common_regs = devm_platform_ioremap_resource_byname(pdev, "common");
53697dea367SMikko Perttunen if (IS_ERR(host->common_regs))
53797dea367SMikko Perttunen return PTR_ERR(host->common_regs);
538f1b53c4eSMikko Perttunen }
539f1b53c4eSMikko Perttunen } else {
54097dea367SMikko Perttunen host->regs = devm_platform_ioremap_resource(pdev, 0);
54197dea367SMikko Perttunen if (IS_ERR(host->regs))
54297dea367SMikko Perttunen return PTR_ERR(host->regs);
543f1b53c4eSMikko Perttunen }
54475471687STerje Bergstrom
545f017f1e9SMikko Perttunen for (i = 0; i < ARRAY_SIZE(host->syncpt_irqs); i++) {
546f017f1e9SMikko Perttunen char irq_name[] = "syncptX";
547f017f1e9SMikko Perttunen
548f017f1e9SMikko Perttunen sprintf(irq_name, "syncpt%d", i);
549f017f1e9SMikko Perttunen
550f017f1e9SMikko Perttunen err = platform_get_irq_byname_optional(pdev, irq_name);
551f017f1e9SMikko Perttunen if (err == -ENXIO)
552f017f1e9SMikko Perttunen break;
553f017f1e9SMikko Perttunen if (err < 0)
554f017f1e9SMikko Perttunen return err;
555f017f1e9SMikko Perttunen
556f017f1e9SMikko Perttunen host->syncpt_irqs[i] = err;
557f017f1e9SMikko Perttunen }
558f017f1e9SMikko Perttunen
559f017f1e9SMikko Perttunen host->num_syncpt_irqs = i;
560f017f1e9SMikko Perttunen
561f017f1e9SMikko Perttunen /* Device tree without irq names */
562f017f1e9SMikko Perttunen if (i == 0) {
563f017f1e9SMikko Perttunen host->syncpt_irqs[0] = platform_get_irq(pdev, 0);
564f017f1e9SMikko Perttunen if (host->syncpt_irqs[0] < 0)
565f017f1e9SMikko Perttunen return host->syncpt_irqs[0];
566f017f1e9SMikko Perttunen
567f017f1e9SMikko Perttunen host->num_syncpt_irqs = 1;
568f017f1e9SMikko Perttunen }
56975471687STerje Bergstrom
570776dc384SThierry Reding mutex_init(&host->devices_lock);
571776dc384SThierry Reding INIT_LIST_HEAD(&host->devices);
572776dc384SThierry Reding INIT_LIST_HEAD(&host->list);
57375471687STerje Bergstrom host->dev = &pdev->dev;
57475471687STerje Bergstrom
57575471687STerje Bergstrom /* set common host1x device data */
57675471687STerje Bergstrom platform_set_drvdata(pdev, host);
57775471687STerje Bergstrom
578d98914ebSThierry Reding host->dev->dma_parms = &host->dma_parms;
579d98914ebSThierry Reding dma_set_max_seg_size(host->dev, UINT_MAX);
580d98914ebSThierry Reding
58175471687STerje Bergstrom if (host->info->init) {
58275471687STerje Bergstrom err = host->info->init(host);
58375471687STerje Bergstrom if (err)
58475471687STerje Bergstrom return err;
58575471687STerje Bergstrom }
58675471687STerje Bergstrom
58775471687STerje Bergstrom host->clk = devm_clk_get(&pdev->dev, NULL);
58875471687STerje Bergstrom if (IS_ERR(host->clk)) {
58975471687STerje Bergstrom err = PTR_ERR(host->clk);
5904bb923e8SThierry Reding
5914bb923e8SThierry Reding if (err != -EPROBE_DEFER)
5924bb923e8SThierry Reding dev_err(&pdev->dev, "failed to get clock: %d\n", err);
5934bb923e8SThierry Reding
59475471687STerje Bergstrom return err;
59575471687STerje Bergstrom }
59675471687STerje Bergstrom
5976b6776e2SDmitry Osipenko err = host1x_get_resets(host);
5986b6776e2SDmitry Osipenko if (err)
599b386c6b7SThierry Reding return err;
600af1cbfb9SThierry Reding
601e5d5db1aSChristophe JAILLET host1x_bo_cache_init(&host->cache);
602e5d5db1aSChristophe JAILLET
60306867a36SThierry Reding err = host1x_iommu_init(host);
60406867a36SThierry Reding if (err < 0) {
60506867a36SThierry Reding dev_err(&pdev->dev, "failed to setup IOMMU: %d\n", err);
606e5d5db1aSChristophe JAILLET goto destroy_cache;
60741c3068cSThierry Reding }
608404bfb78SMikko Perttunen
6098474b025SMikko Perttunen err = host1x_channel_list_init(&host->channel_list,
6108474b025SMikko Perttunen host->info->nb_channels);
6116579324aSTerje Bergstrom if (err) {
6126579324aSTerje Bergstrom dev_err(&pdev->dev, "failed to initialize channel list\n");
61306867a36SThierry Reding goto iommu_exit;
6146579324aSTerje Bergstrom }
6156579324aSTerje Bergstrom
6168aa5bcb6SMikko Perttunen err = host1x_memory_context_list_init(host);
6178aa5bcb6SMikko Perttunen if (err) {
6188aa5bcb6SMikko Perttunen dev_err(&pdev->dev, "failed to initialize context list\n");
6198aa5bcb6SMikko Perttunen goto free_channels;
6208aa5bcb6SMikko Perttunen }
6218aa5bcb6SMikko Perttunen
62275471687STerje Bergstrom err = host1x_syncpt_init(host);
62375471687STerje Bergstrom if (err) {
62475471687STerje Bergstrom dev_err(&pdev->dev, "failed to initialize syncpts\n");
6258aa5bcb6SMikko Perttunen goto free_contexts;
62675471687STerje Bergstrom }
62775471687STerje Bergstrom
62802458fbfSRupinderjit Singh mutex_init(&host->intr_mutex);
62902458fbfSRupinderjit Singh
6306b6776e2SDmitry Osipenko pm_runtime_enable(&pdev->dev);
6316236451dSTerje Bergstrom
6326b6776e2SDmitry Osipenko err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
6336b6776e2SDmitry Osipenko if (err)
6346b6776e2SDmitry Osipenko goto pm_disable;
6356b6776e2SDmitry Osipenko
6366b6776e2SDmitry Osipenko /* the driver's code isn't ready yet for the dynamic RPM */
6376b6776e2SDmitry Osipenko err = pm_runtime_resume_and_get(&pdev->dev);
6386b6776e2SDmitry Osipenko if (err)
6396b6776e2SDmitry Osipenko goto pm_disable;
6406b6776e2SDmitry Osipenko
641dc56f842SJon Hunter err = host1x_intr_init(host);
642dc56f842SJon Hunter if (err) {
643dc56f842SJon Hunter dev_err(&pdev->dev, "failed to initialize interrupts\n");
644dc56f842SJon Hunter goto pm_put;
645dc56f842SJon Hunter }
646dc56f842SJon Hunter
6476b6776e2SDmitry Osipenko host1x_debug_init(host);
6486841482bSThierry Reding
649776dc384SThierry Reding err = host1x_register(host);
650776dc384SThierry Reding if (err < 0)
651109be8b2SChristophe JAILLET goto deinit_debugfs;
652692e6d7bSTerje Bergstrom
653ca2030d5SThierry Reding err = devm_of_platform_populate(&pdev->dev);
654ca2030d5SThierry Reding if (err < 0)
655ca2030d5SThierry Reding goto unregister;
656ca2030d5SThierry Reding
65775471687STerje Bergstrom return 0;
6587ede0b0bSTerje Bergstrom
659ca2030d5SThierry Reding unregister:
660ca2030d5SThierry Reding host1x_unregister(host);
661109be8b2SChristophe JAILLET deinit_debugfs:
662109be8b2SChristophe JAILLET host1x_debug_deinit(host);
663dc56f842SJon Hunter host1x_intr_deinit(host);
664dc56f842SJon Hunter pm_put:
6656b6776e2SDmitry Osipenko pm_runtime_put_sync_suspend(&pdev->dev);
6666b6776e2SDmitry Osipenko pm_disable:
6676b6776e2SDmitry Osipenko pm_runtime_disable(&pdev->dev);
6687ede0b0bSTerje Bergstrom host1x_syncpt_deinit(host);
6698aa5bcb6SMikko Perttunen free_contexts:
6708aa5bcb6SMikko Perttunen host1x_memory_context_list_free(&host->context_list);
67106867a36SThierry Reding free_channels:
6728474b025SMikko Perttunen host1x_channel_list_free(&host->channel_list);
67306867a36SThierry Reding iommu_exit:
67406867a36SThierry Reding host1x_iommu_exit(host);
675e5d5db1aSChristophe JAILLET destroy_cache:
676e5d5db1aSChristophe JAILLET host1x_bo_cache_destroy(&host->cache);
677404bfb78SMikko Perttunen
6787ede0b0bSTerje Bergstrom return err;
67975471687STerje Bergstrom }
68075471687STerje Bergstrom
host1x_remove(struct platform_device * pdev)68117e1b2dbSUwe Kleine-König static void host1x_remove(struct platform_device *pdev)
68275471687STerje Bergstrom {
68375471687STerje Bergstrom struct host1x *host = platform_get_drvdata(pdev);
68475471687STerje Bergstrom
685776dc384SThierry Reding host1x_unregister(host);
68644156eeeSThierry Reding host1x_debug_deinit(host);
6876b6776e2SDmitry Osipenko
6886b6776e2SDmitry Osipenko pm_runtime_force_suspend(&pdev->dev);
6896b6776e2SDmitry Osipenko
6907ede0b0bSTerje Bergstrom host1x_intr_deinit(host);
69175471687STerje Bergstrom host1x_syncpt_deinit(host);
6928aa5bcb6SMikko Perttunen host1x_memory_context_list_free(&host->context_list);
693025c6643SChristophe JAILLET host1x_channel_list_free(&host->channel_list);
69406867a36SThierry Reding host1x_iommu_exit(host);
6951f39b1dfSThierry Reding host1x_bo_cache_destroy(&host->cache);
69675471687STerje Bergstrom }
69775471687STerje Bergstrom
host1x_runtime_suspend(struct device * dev)6986b6776e2SDmitry Osipenko static int __maybe_unused host1x_runtime_suspend(struct device *dev)
6996b6776e2SDmitry Osipenko {
7006b6776e2SDmitry Osipenko struct host1x *host = dev_get_drvdata(dev);
7016b6776e2SDmitry Osipenko int err;
7026b6776e2SDmitry Osipenko
70387fafcd5SMikko Perttunen host1x_channel_stop_all(host);
7046b6776e2SDmitry Osipenko host1x_intr_stop(host);
7056b6776e2SDmitry Osipenko host1x_syncpt_save(host);
7066b6776e2SDmitry Osipenko
7071fa8d07aSMikko Perttunen if (!host->info->skip_reset_assert) {
7086b6776e2SDmitry Osipenko err = reset_control_bulk_assert(host->nresets, host->resets);
7096b6776e2SDmitry Osipenko if (err) {
7106b6776e2SDmitry Osipenko dev_err(dev, "failed to assert reset: %d\n", err);
7116b6776e2SDmitry Osipenko goto resume_host1x;
7126b6776e2SDmitry Osipenko }
7136b6776e2SDmitry Osipenko
7146b6776e2SDmitry Osipenko usleep_range(1000, 2000);
7151fa8d07aSMikko Perttunen }
7166b6776e2SDmitry Osipenko
7176b6776e2SDmitry Osipenko clk_disable_unprepare(host->clk);
7186b6776e2SDmitry Osipenko reset_control_bulk_release(host->nresets, host->resets);
7196b6776e2SDmitry Osipenko
7206b6776e2SDmitry Osipenko return 0;
7216b6776e2SDmitry Osipenko
7226b6776e2SDmitry Osipenko resume_host1x:
723939179faSMikko Perttunen host1x_setup_virtualization_tables(host);
7246b6776e2SDmitry Osipenko host1x_syncpt_restore(host);
7256b6776e2SDmitry Osipenko host1x_intr_start(host);
7266b6776e2SDmitry Osipenko
7276b6776e2SDmitry Osipenko return err;
7286b6776e2SDmitry Osipenko }
7296b6776e2SDmitry Osipenko
host1x_runtime_resume(struct device * dev)7306b6776e2SDmitry Osipenko static int __maybe_unused host1x_runtime_resume(struct device *dev)
7316b6776e2SDmitry Osipenko {
7326b6776e2SDmitry Osipenko struct host1x *host = dev_get_drvdata(dev);
7336b6776e2SDmitry Osipenko int err;
7346b6776e2SDmitry Osipenko
7356b6776e2SDmitry Osipenko err = reset_control_bulk_acquire(host->nresets, host->resets);
7366b6776e2SDmitry Osipenko if (err) {
7376b6776e2SDmitry Osipenko dev_err(dev, "failed to acquire reset: %d\n", err);
7386b6776e2SDmitry Osipenko return err;
7396b6776e2SDmitry Osipenko }
7406b6776e2SDmitry Osipenko
7416b6776e2SDmitry Osipenko err = clk_prepare_enable(host->clk);
7426b6776e2SDmitry Osipenko if (err) {
7436b6776e2SDmitry Osipenko dev_err(dev, "failed to enable clock: %d\n", err);
7446b6776e2SDmitry Osipenko goto release_reset;
7456b6776e2SDmitry Osipenko }
7466b6776e2SDmitry Osipenko
7476b6776e2SDmitry Osipenko err = reset_control_bulk_deassert(host->nresets, host->resets);
7486b6776e2SDmitry Osipenko if (err < 0) {
7496b6776e2SDmitry Osipenko dev_err(dev, "failed to deassert reset: %d\n", err);
7506b6776e2SDmitry Osipenko goto disable_clk;
7516b6776e2SDmitry Osipenko }
7526b6776e2SDmitry Osipenko
753939179faSMikko Perttunen host1x_setup_virtualization_tables(host);
7546b6776e2SDmitry Osipenko host1x_syncpt_restore(host);
7556b6776e2SDmitry Osipenko host1x_intr_start(host);
7566b6776e2SDmitry Osipenko
7576b6776e2SDmitry Osipenko return 0;
7586b6776e2SDmitry Osipenko
7596b6776e2SDmitry Osipenko disable_clk:
7606b6776e2SDmitry Osipenko clk_disable_unprepare(host->clk);
7616b6776e2SDmitry Osipenko release_reset:
7626b6776e2SDmitry Osipenko reset_control_bulk_release(host->nresets, host->resets);
7636b6776e2SDmitry Osipenko
7646b6776e2SDmitry Osipenko return err;
7656b6776e2SDmitry Osipenko }
7666b6776e2SDmitry Osipenko
7676b6776e2SDmitry Osipenko static const struct dev_pm_ops host1x_pm_ops = {
7686b6776e2SDmitry Osipenko SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume,
7696b6776e2SDmitry Osipenko NULL)
770b7c00cdfSMikko Perttunen SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
7716b6776e2SDmitry Osipenko };
7726b6776e2SDmitry Osipenko
773692e6d7bSTerje Bergstrom static struct platform_driver tegra_host1x_driver = {
77475471687STerje Bergstrom .driver = {
77575471687STerje Bergstrom .name = "tegra-host1x",
77675471687STerje Bergstrom .of_match_table = host1x_of_match,
7776b6776e2SDmitry Osipenko .pm = &host1x_pm_ops,
77875471687STerje Bergstrom },
779452e7f0cSThierry Reding .probe = host1x_probe,
780e70140baSLinus Torvalds .remove = host1x_remove,
78175471687STerje Bergstrom };
78275471687STerje Bergstrom
78328fae81fSThierry Reding static struct platform_driver * const drivers[] = {
78428fae81fSThierry Reding &tegra_host1x_driver,
78528fae81fSThierry Reding &tegra_mipi_driver,
78628fae81fSThierry Reding };
78728fae81fSThierry Reding
tegra_host1x_init(void)788692e6d7bSTerje Bergstrom static int __init tegra_host1x_init(void)
789692e6d7bSTerje Bergstrom {
790692e6d7bSTerje Bergstrom int err;
79175471687STerje Bergstrom
792f4c5cf88SThierry Reding err = bus_register(&host1x_bus_type);
793692e6d7bSTerje Bergstrom if (err < 0)
794692e6d7bSTerje Bergstrom return err;
795692e6d7bSTerje Bergstrom
79628fae81fSThierry Reding err = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
7974de6a2d6SThierry Reding if (err < 0)
798f4c5cf88SThierry Reding bus_unregister(&host1x_bus_type);
79928fae81fSThierry Reding
8004de6a2d6SThierry Reding return err;
801692e6d7bSTerje Bergstrom }
802692e6d7bSTerje Bergstrom module_init(tegra_host1x_init);
803692e6d7bSTerje Bergstrom
tegra_host1x_exit(void)804692e6d7bSTerje Bergstrom static void __exit tegra_host1x_exit(void)
805692e6d7bSTerje Bergstrom {
80628fae81fSThierry Reding platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
807f4c5cf88SThierry Reding bus_unregister(&host1x_bus_type);
808692e6d7bSTerje Bergstrom }
809692e6d7bSTerje Bergstrom module_exit(tegra_host1x_exit);
810692e6d7bSTerje Bergstrom
811501be6c1SThierry Reding /**
812501be6c1SThierry Reding * host1x_get_dma_mask() - query the supported DMA mask for host1x
813501be6c1SThierry Reding * @host1x: host1x instance
814501be6c1SThierry Reding *
815501be6c1SThierry Reding * Note that this returns the supported DMA mask for host1x, which can be
816501be6c1SThierry Reding * different from the applicable DMA mask under certain circumstances.
817501be6c1SThierry Reding */
host1x_get_dma_mask(struct host1x * host1x)818501be6c1SThierry Reding u64 host1x_get_dma_mask(struct host1x *host1x)
819501be6c1SThierry Reding {
820501be6c1SThierry Reding return host1x->info->dma_mask;
821501be6c1SThierry Reding }
822501be6c1SThierry Reding EXPORT_SYMBOL(host1x_get_dma_mask);
823501be6c1SThierry Reding
824692e6d7bSTerje Bergstrom MODULE_AUTHOR("Thierry Reding <[email protected]>");
82575471687STerje Bergstrom MODULE_AUTHOR("Terje Bergstrom <[email protected]>");
82675471687STerje Bergstrom MODULE_DESCRIPTION("Host1x driver for Tegra products");
82775471687STerje Bergstrom MODULE_LICENSE("GPL");
828