diff options
author | Thierry Reding <treding@nvidia.com> | 2014-04-16 03:24:44 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-12-04 10:11:47 -0500 |
commit | 8918465163171322c77a19d5258a95f56d89d2e4 (patch) | |
tree | 4d818b6d61af15bffc6c60316c7b5d64efb01bde /drivers | |
parent | 4bc567dd60a1cfa9abd8484cff2de31cdf51649d (diff) |
memory: Add NVIDIA Tegra memory controller support
The memory controller on NVIDIA Tegra exposes various knobs that can be
used to tune the behaviour of the clients attached to it.
Currently this driver sets up the latency allowance registers to the HW
defaults. Eventually an API should be exported by this driver (via a
custom API or a generic subsystem) to allow clients to register latency
requirements.
This driver also registers an IOMMU (SMMU) that's implemented by the
memory controller. It is supported on Tegra30, Tegra114 and Tegra124
currently. Tegra20 has a GART instead.
The Tegra SMMU operates on memory clients and SWGROUPs. A memory client
is a unidirectional, special-purpose DMA master. A SWGROUP represents a
set of memory clients that form a logical functional unit corresponding
to a single device. Typically a device has two clients: one client for
read transactions and one client for write transactions, but there are
also devices that have only read clients, but many of them (such as the
display controllers).
Because there is no 1:1 relationship between memory clients and devices
the driver keeps a table of memory clients and the SWGROUPs that they
belong to per SoC. Note that this is an exception and due to the fact
that the SMMU is tightly integrated with the rest of the Tegra SoC. The
use of these tables is discouraged in drivers for generic IOMMU devices
such as the ARM SMMU because the same IOMMU could be used in any number
of SoCs and keeping such tables for each SoC would not scale.
Acked-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/iommu/Kconfig | 12 | ||||
-rw-r--r-- | drivers/iommu/tegra-smmu.c | 1610 | ||||
-rw-r--r-- | drivers/memory/Kconfig | 12 | ||||
-rw-r--r-- | drivers/memory/Makefile | 3 | ||||
-rw-r--r-- | drivers/memory/tegra/Kconfig | 7 | ||||
-rw-r--r-- | drivers/memory/tegra/Makefile | 7 | ||||
-rw-r--r-- | drivers/memory/tegra/mc.c | 301 | ||||
-rw-r--r-- | drivers/memory/tegra/mc.h | 40 | ||||
-rw-r--r-- | drivers/memory/tegra/tegra114.c | 948 | ||||
-rw-r--r-- | drivers/memory/tegra/tegra124.c | 995 | ||||
-rw-r--r-- | drivers/memory/tegra/tegra30.c | 970 | ||||
-rw-r--r-- | drivers/memory/tegra30-mc.c | 378 |
12 files changed, 3801 insertions, 1482 deletions
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index dd5112265cc9..6dbfbc209491 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig | |||
@@ -163,14 +163,14 @@ config TEGRA_IOMMU_GART | |||
163 | hardware included on Tegra SoCs. | 163 | hardware included on Tegra SoCs. |
164 | 164 | ||
165 | config TEGRA_IOMMU_SMMU | 165 | config TEGRA_IOMMU_SMMU |
166 | bool "Tegra SMMU IOMMU Support" | 166 | bool "NVIDIA Tegra SMMU Support" |
167 | depends on ARCH_TEGRA && TEGRA_AHB | 167 | depends on ARCH_TEGRA |
168 | depends on TEGRA_AHB | ||
169 | depends on TEGRA_MC | ||
168 | select IOMMU_API | 170 | select IOMMU_API |
169 | help | 171 | help |
170 | Enables support for remapping discontiguous physical memory | 172 | This driver supports the IOMMU hardware (SMMU) found on NVIDIA Tegra |
171 | shared with the operating system into contiguous I/O virtual | 173 | SoCs (Tegra30 up to Tegra124). |
172 | space through the SMMU (System Memory Management Unit) | ||
173 | hardware included on Tegra SoCs. | ||
174 | 174 | ||
175 | config EXYNOS_IOMMU | 175 | config EXYNOS_IOMMU |
176 | bool "Exynos IOMMU Support" | 176 | bool "Exynos IOMMU Support" |
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 73e845a66925..6e134c7c227f 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c | |||
@@ -1,1296 +1,732 @@ | |||
1 | /* | 1 | /* |
2 | * IOMMU API for SMMU in Tegra30 | 2 | * Copyright (C) 2011-2014 NVIDIA CORPORATION. All rights reserved. |
3 | * | 3 | * |
4 | * Copyright (c) 2011-2013, NVIDIA CORPORATION. All rights reserved. | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * published by the Free Software Foundation. |
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | 7 | */ |
19 | 8 | ||
20 | #define pr_fmt(fmt) "%s(): " fmt, __func__ | ||
21 | |||
22 | #include <linux/err.h> | 9 | #include <linux/err.h> |
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/vmalloc.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/pagemap.h> | ||
30 | #include <linux/device.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/iommu.h> | 10 | #include <linux/iommu.h> |
33 | #include <linux/io.h> | 11 | #include <linux/kernel.h> |
34 | #include <linux/of.h> | 12 | #include <linux/of.h> |
35 | #include <linux/of_iommu.h> | 13 | #include <linux/of_device.h> |
36 | #include <linux/debugfs.h> | 14 | #include <linux/platform_device.h> |
37 | #include <linux/seq_file.h> | 15 | #include <linux/slab.h> |
38 | 16 | ||
39 | #include <soc/tegra/ahb.h> | 17 | #include <soc/tegra/ahb.h> |
18 | #include <soc/tegra/mc.h> | ||
40 | 19 | ||
41 | #include <asm/page.h> | 20 | struct tegra_smmu { |
42 | #include <asm/cacheflush.h> | 21 | void __iomem *regs; |
43 | 22 | struct device *dev; | |
44 | enum smmu_hwgrp { | ||
45 | HWGRP_AFI, | ||
46 | HWGRP_AVPC, | ||
47 | HWGRP_DC, | ||
48 | HWGRP_DCB, | ||
49 | HWGRP_EPP, | ||
50 | HWGRP_G2, | ||
51 | HWGRP_HC, | ||
52 | HWGRP_HDA, | ||
53 | HWGRP_ISP, | ||
54 | HWGRP_MPE, | ||
55 | HWGRP_NV, | ||
56 | HWGRP_NV2, | ||
57 | HWGRP_PPCS, | ||
58 | HWGRP_SATA, | ||
59 | HWGRP_VDE, | ||
60 | HWGRP_VI, | ||
61 | |||
62 | HWGRP_COUNT, | ||
63 | |||
64 | HWGRP_END = ~0, | ||
65 | }; | ||
66 | 23 | ||
67 | #define HWG_AFI (1 << HWGRP_AFI) | 24 | struct tegra_mc *mc; |
68 | #define HWG_AVPC (1 << HWGRP_AVPC) | 25 | const struct tegra_smmu_soc *soc; |
69 | #define HWG_DC (1 << HWGRP_DC) | ||
70 | #define HWG_DCB (1 << HWGRP_DCB) | ||
71 | #define HWG_EPP (1 << HWGRP_EPP) | ||
72 | #define HWG_G2 (1 << HWGRP_G2) | ||
73 | #define HWG_HC (1 << HWGRP_HC) | ||
74 | #define HWG_HDA (1 << HWGRP_HDA) | ||
75 | #define HWG_ISP (1 << HWGRP_ISP) | ||
76 | #define HWG_MPE (1 << HWGRP_MPE) | ||
77 | #define HWG_NV (1 << HWGRP_NV) | ||
78 | #define HWG_NV2 (1 << HWGRP_NV2) | ||
79 | #define HWG_PPCS (1 << HWGRP_PPCS) | ||
80 | #define HWG_SATA (1 << HWGRP_SATA) | ||
81 | #define HWG_VDE (1 << HWGRP_VDE) | ||
82 | #define HWG_VI (1 << HWGRP_VI) | ||
83 | |||
84 | /* bitmap of the page sizes currently supported */ | ||
85 | #define SMMU_IOMMU_PGSIZES (SZ_4K) | ||
86 | |||
87 | #define SMMU_CONFIG 0x10 | ||
88 | #define SMMU_CONFIG_DISABLE 0 | ||
89 | #define SMMU_CONFIG_ENABLE 1 | ||
90 | |||
91 | /* REVISIT: To support multiple MCs */ | ||
92 | enum { | ||
93 | _MC = 0, | ||
94 | }; | ||
95 | 26 | ||
96 | enum { | 27 | unsigned long *asids; |
97 | _TLB = 0, | 28 | struct mutex lock; |
98 | _PTC, | ||
99 | }; | ||
100 | 29 | ||
101 | #define SMMU_CACHE_CONFIG_BASE 0x14 | 30 | struct list_head list; |
102 | #define __SMMU_CACHE_CONFIG(mc, cache) (SMMU_CACHE_CONFIG_BASE + 4 * cache) | ||
103 | #define SMMU_CACHE_CONFIG(cache) __SMMU_CACHE_CONFIG(_MC, cache) | ||
104 | |||
105 | #define SMMU_CACHE_CONFIG_STATS_SHIFT 31 | ||
106 | #define SMMU_CACHE_CONFIG_STATS_ENABLE (1 << SMMU_CACHE_CONFIG_STATS_SHIFT) | ||
107 | #define SMMU_CACHE_CONFIG_STATS_TEST_SHIFT 30 | ||
108 | #define SMMU_CACHE_CONFIG_STATS_TEST (1 << SMMU_CACHE_CONFIG_STATS_TEST_SHIFT) | ||
109 | |||
110 | #define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE (1 << 29) | ||
111 | #define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE 0x10 | ||
112 | #define SMMU_TLB_CONFIG_RESET_VAL 0x20000010 | ||
113 | |||
114 | #define SMMU_PTC_CONFIG_CACHE__ENABLE (1 << 29) | ||
115 | #define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN 0x3f | ||
116 | #define SMMU_PTC_CONFIG_RESET_VAL 0x2000003f | ||
117 | |||
118 | #define SMMU_PTB_ASID 0x1c | ||
119 | #define SMMU_PTB_ASID_CURRENT_SHIFT 0 | ||
120 | |||
121 | #define SMMU_PTB_DATA 0x20 | ||
122 | #define SMMU_PTB_DATA_RESET_VAL 0 | ||
123 | #define SMMU_PTB_DATA_ASID_NONSECURE_SHIFT 29 | ||
124 | #define SMMU_PTB_DATA_ASID_WRITABLE_SHIFT 30 | ||
125 | #define SMMU_PTB_DATA_ASID_READABLE_SHIFT 31 | ||
126 | |||
127 | #define SMMU_TLB_FLUSH 0x30 | ||
128 | #define SMMU_TLB_FLUSH_VA_MATCH_ALL 0 | ||
129 | #define SMMU_TLB_FLUSH_VA_MATCH_SECTION 2 | ||
130 | #define SMMU_TLB_FLUSH_VA_MATCH_GROUP 3 | ||
131 | #define SMMU_TLB_FLUSH_ASID_SHIFT 29 | ||
132 | #define SMMU_TLB_FLUSH_ASID_MATCH_DISABLE 0 | ||
133 | #define SMMU_TLB_FLUSH_ASID_MATCH_ENABLE 1 | ||
134 | #define SMMU_TLB_FLUSH_ASID_MATCH_SHIFT 31 | ||
135 | |||
136 | #define SMMU_PTC_FLUSH 0x34 | ||
137 | #define SMMU_PTC_FLUSH_TYPE_ALL 0 | ||
138 | #define SMMU_PTC_FLUSH_TYPE_ADR 1 | ||
139 | #define SMMU_PTC_FLUSH_ADR_SHIFT 4 | ||
140 | |||
141 | #define SMMU_ASID_SECURITY 0x38 | ||
142 | |||
143 | #define SMMU_STATS_CACHE_COUNT_BASE 0x1f0 | ||
144 | |||
145 | #define SMMU_STATS_CACHE_COUNT(mc, cache, hitmiss) \ | ||
146 | (SMMU_STATS_CACHE_COUNT_BASE + 8 * cache + 4 * hitmiss) | ||
147 | |||
148 | #define SMMU_TRANSLATION_ENABLE_0 0x228 | ||
149 | #define SMMU_TRANSLATION_ENABLE_1 0x22c | ||
150 | #define SMMU_TRANSLATION_ENABLE_2 0x230 | ||
151 | |||
152 | #define SMMU_AFI_ASID 0x238 /* PCIE */ | ||
153 | #define SMMU_AVPC_ASID 0x23c /* AVP */ | ||
154 | #define SMMU_DC_ASID 0x240 /* Display controller */ | ||
155 | #define SMMU_DCB_ASID 0x244 /* Display controller B */ | ||
156 | #define SMMU_EPP_ASID 0x248 /* Encoder pre-processor */ | ||
157 | #define SMMU_G2_ASID 0x24c /* 2D engine */ | ||
158 | #define SMMU_HC_ASID 0x250 /* Host1x */ | ||
159 | #define SMMU_HDA_ASID 0x254 /* High-def audio */ | ||
160 | #define SMMU_ISP_ASID 0x258 /* Image signal processor */ | ||
161 | #define SMMU_MPE_ASID 0x264 /* MPEG encoder */ | ||
162 | #define SMMU_NV_ASID 0x268 /* (3D) */ | ||
163 | #define SMMU_NV2_ASID 0x26c /* (3D) */ | ||
164 | #define SMMU_PPCS_ASID 0x270 /* AHB */ | ||
165 | #define SMMU_SATA_ASID 0x278 /* SATA */ | ||
166 | #define SMMU_VDE_ASID 0x27c /* Video decoder */ | ||
167 | #define SMMU_VI_ASID 0x280 /* Video input */ | ||
168 | |||
169 | #define SMMU_PDE_NEXT_SHIFT 28 | ||
170 | |||
171 | #define SMMU_TLB_FLUSH_VA_SECTION__MASK 0xffc00000 | ||
172 | #define SMMU_TLB_FLUSH_VA_SECTION__SHIFT 12 /* right shift */ | ||
173 | #define SMMU_TLB_FLUSH_VA_GROUP__MASK 0xffffc000 | ||
174 | #define SMMU_TLB_FLUSH_VA_GROUP__SHIFT 12 /* right shift */ | ||
175 | #define SMMU_TLB_FLUSH_VA(iova, which) \ | ||
176 | ((((iova) & SMMU_TLB_FLUSH_VA_##which##__MASK) >> \ | ||
177 | SMMU_TLB_FLUSH_VA_##which##__SHIFT) | \ | ||
178 | SMMU_TLB_FLUSH_VA_MATCH_##which) | ||
179 | #define SMMU_PTB_ASID_CUR(n) \ | ||
180 | ((n) << SMMU_PTB_ASID_CURRENT_SHIFT) | ||
181 | #define SMMU_TLB_FLUSH_ASID_MATCH_disable \ | ||
182 | (SMMU_TLB_FLUSH_ASID_MATCH_DISABLE << \ | ||
183 | SMMU_TLB_FLUSH_ASID_MATCH_SHIFT) | ||
184 | #define SMMU_TLB_FLUSH_ASID_MATCH__ENABLE \ | ||
185 | (SMMU_TLB_FLUSH_ASID_MATCH_ENABLE << \ | ||
186 | SMMU_TLB_FLUSH_ASID_MATCH_SHIFT) | ||
187 | |||
188 | #define SMMU_PAGE_SHIFT 12 | ||
189 | #define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT) | ||
190 | #define SMMU_PAGE_MASK ((1 << SMMU_PAGE_SHIFT) - 1) | ||
191 | |||
192 | #define SMMU_PDIR_COUNT 1024 | ||
193 | #define SMMU_PDIR_SIZE (sizeof(unsigned long) * SMMU_PDIR_COUNT) | ||
194 | #define SMMU_PTBL_COUNT 1024 | ||
195 | #define SMMU_PTBL_SIZE (sizeof(unsigned long) * SMMU_PTBL_COUNT) | ||
196 | #define SMMU_PDIR_SHIFT 12 | ||
197 | #define SMMU_PDE_SHIFT 12 | ||
198 | #define SMMU_PTE_SHIFT 12 | ||
199 | #define SMMU_PFN_MASK 0x000fffff | ||
200 | |||
201 | #define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12) | ||
202 | #define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22) | ||
203 | #define SMMU_PDN_TO_ADDR(pdn) ((pdn) << 22) | ||
204 | |||
205 | #define _READABLE (1 << SMMU_PTB_DATA_ASID_READABLE_SHIFT) | ||
206 | #define _WRITABLE (1 << SMMU_PTB_DATA_ASID_WRITABLE_SHIFT) | ||
207 | #define _NONSECURE (1 << SMMU_PTB_DATA_ASID_NONSECURE_SHIFT) | ||
208 | #define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT) | ||
209 | #define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE) | ||
210 | |||
211 | #define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE) | ||
212 | |||
213 | #define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE) | ||
214 | #define _PDE_ATTR_N (_PDE_ATTR | _PDE_NEXT) | ||
215 | #define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR) | ||
216 | |||
217 | #define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE) | ||
218 | #define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR) | ||
219 | |||
220 | #define SMMU_MK_PDIR(page, attr) \ | ||
221 | ((page_to_phys(page) >> SMMU_PDIR_SHIFT) | (attr)) | ||
222 | #define SMMU_MK_PDE(page, attr) \ | ||
223 | (unsigned long)((page_to_phys(page) >> SMMU_PDE_SHIFT) | (attr)) | ||
224 | #define SMMU_EX_PTBL_PAGE(pde) \ | ||
225 | pfn_to_page((unsigned long)(pde) & SMMU_PFN_MASK) | ||
226 | #define SMMU_PFN_TO_PTE(pfn, attr) (unsigned long)((pfn) | (attr)) | ||
227 | |||
228 | #define SMMU_ASID_ENABLE(asid) ((asid) | (1 << 31)) | ||
229 | #define SMMU_ASID_DISABLE 0 | ||
230 | #define SMMU_ASID_ASID(n) ((n) & ~SMMU_ASID_ENABLE(0)) | ||
231 | |||
232 | #define NUM_SMMU_REG_BANKS 3 | ||
233 | |||
234 | #define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1) | ||
235 | #define smmu_client_disable_hwgrp(c) smmu_client_set_hwgrp(c, 0, 0) | ||
236 | #define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1) | ||
237 | #define __smmu_client_disable_hwgrp(c) __smmu_client_set_hwgrp(c, 0, 0) | ||
238 | |||
239 | #define HWGRP_INIT(client) [HWGRP_##client] = SMMU_##client##_ASID | ||
240 | |||
241 | static const u32 smmu_hwgrp_asid_reg[] = { | ||
242 | HWGRP_INIT(AFI), | ||
243 | HWGRP_INIT(AVPC), | ||
244 | HWGRP_INIT(DC), | ||
245 | HWGRP_INIT(DCB), | ||
246 | HWGRP_INIT(EPP), | ||
247 | HWGRP_INIT(G2), | ||
248 | HWGRP_INIT(HC), | ||
249 | HWGRP_INIT(HDA), | ||
250 | HWGRP_INIT(ISP), | ||
251 | HWGRP_INIT(MPE), | ||
252 | HWGRP_INIT(NV), | ||
253 | HWGRP_INIT(NV2), | ||
254 | HWGRP_INIT(PPCS), | ||
255 | HWGRP_INIT(SATA), | ||
256 | HWGRP_INIT(VDE), | ||
257 | HWGRP_INIT(VI), | ||
258 | }; | 31 | }; |
259 | #define HWGRP_ASID_REG(x) (smmu_hwgrp_asid_reg[x]) | ||
260 | 32 | ||
261 | /* | 33 | struct tegra_smmu_as { |
262 | * Per client for address space | 34 | struct iommu_domain *domain; |
263 | */ | 35 | struct tegra_smmu *smmu; |
264 | struct smmu_client { | 36 | unsigned int use_count; |
265 | struct device *dev; | 37 | struct page *count; |
266 | struct list_head list; | 38 | struct page *pd; |
267 | struct smmu_as *as; | 39 | unsigned id; |
268 | u32 hwgrp; | 40 | u32 attr; |
269 | }; | 41 | }; |
270 | 42 | ||
271 | /* | 43 | static inline void smmu_writel(struct tegra_smmu *smmu, u32 value, |
272 | * Per address space | 44 | unsigned long offset) |
273 | */ | 45 | { |
274 | struct smmu_as { | 46 | writel(value, smmu->regs + offset); |
275 | struct smmu_device *smmu; /* back pointer to container */ | 47 | } |
276 | unsigned int asid; | ||
277 | spinlock_t lock; /* for pagetable */ | ||
278 | struct page *pdir_page; | ||
279 | unsigned long pdir_attr; | ||
280 | unsigned long pde_attr; | ||
281 | unsigned long pte_attr; | ||
282 | unsigned int *pte_count; | ||
283 | |||
284 | struct list_head client; | ||
285 | spinlock_t client_lock; /* for client list */ | ||
286 | }; | ||
287 | 48 | ||
288 | struct smmu_debugfs_info { | 49 | static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset) |
289 | struct smmu_device *smmu; | 50 | { |
290 | int mc; | 51 | return readl(smmu->regs + offset); |
291 | int cache; | 52 | } |
292 | }; | ||
293 | 53 | ||
294 | /* | 54 | #define SMMU_CONFIG 0x010 |
295 | * Per SMMU device - IOMMU device | 55 | #define SMMU_CONFIG_ENABLE (1 << 0) |
296 | */ | ||
297 | struct smmu_device { | ||
298 | void __iomem *regbase; /* register offset base */ | ||
299 | void __iomem **regs; /* register block start address array */ | ||
300 | void __iomem **rege; /* register block end address array */ | ||
301 | int nregs; /* number of register blocks */ | ||
302 | |||
303 | unsigned long iovmm_base; /* remappable base address */ | ||
304 | unsigned long page_count; /* total remappable size */ | ||
305 | spinlock_t lock; | ||
306 | char *name; | ||
307 | struct device *dev; | ||
308 | struct page *avp_vector_page; /* dummy page shared by all AS's */ | ||
309 | 56 | ||
310 | /* | 57 | #define SMMU_TLB_CONFIG 0x14 |
311 | * Register image savers for suspend/resume | 58 | #define SMMU_TLB_CONFIG_HIT_UNDER_MISS (1 << 29) |
312 | */ | 59 | #define SMMU_TLB_CONFIG_ROUND_ROBIN_ARBITRATION (1 << 28) |
313 | unsigned long translation_enable_0; | 60 | #define SMMU_TLB_CONFIG_ACTIVE_LINES(x) ((x) & 0x3f) |
314 | unsigned long translation_enable_1; | ||
315 | unsigned long translation_enable_2; | ||
316 | unsigned long asid_security; | ||
317 | 61 | ||
318 | struct dentry *debugfs_root; | 62 | #define SMMU_PTC_CONFIG 0x18 |
319 | struct smmu_debugfs_info *debugfs_info; | 63 | #define SMMU_PTC_CONFIG_ENABLE (1 << 29) |
64 | #define SMMU_PTC_CONFIG_REQ_LIMIT(x) (((x) & 0x0f) << 24) | ||
65 | #define SMMU_PTC_CONFIG_INDEX_MAP(x) ((x) & 0x3f) | ||
320 | 66 | ||
321 | struct device_node *ahb; | 67 | #define SMMU_PTB_ASID 0x01c |
68 | #define SMMU_PTB_ASID_VALUE(x) ((x) & 0x7f) | ||
322 | 69 | ||
323 | int num_as; | 70 | #define SMMU_PTB_DATA 0x020 |
324 | struct smmu_as as[0]; /* Run-time allocated array */ | 71 | #define SMMU_PTB_DATA_VALUE(page, attr) (page_to_phys(page) >> 12 | (attr)) |
325 | }; | ||
326 | 72 | ||
327 | static struct smmu_device *smmu_handle; /* unique for a system */ | 73 | #define SMMU_MK_PDE(page, attr) (page_to_phys(page) >> SMMU_PTE_SHIFT | (attr)) |
328 | 74 | ||
329 | /* | 75 | #define SMMU_TLB_FLUSH 0x030 |
330 | * SMMU register accessors | 76 | #define SMMU_TLB_FLUSH_VA_MATCH_ALL (0 << 0) |
331 | */ | 77 | #define SMMU_TLB_FLUSH_VA_MATCH_SECTION (2 << 0) |
332 | static bool inline smmu_valid_reg(struct smmu_device *smmu, | 78 | #define SMMU_TLB_FLUSH_VA_MATCH_GROUP (3 << 0) |
333 | void __iomem *addr) | 79 | #define SMMU_TLB_FLUSH_ASID(x) (((x) & 0x7f) << 24) |
334 | { | 80 | #define SMMU_TLB_FLUSH_VA_SECTION(addr) ((((addr) & 0xffc00000) >> 12) | \ |
335 | int i; | 81 | SMMU_TLB_FLUSH_VA_MATCH_SECTION) |
82 | #define SMMU_TLB_FLUSH_VA_GROUP(addr) ((((addr) & 0xffffc000) >> 12) | \ | ||
83 | SMMU_TLB_FLUSH_VA_MATCH_GROUP) | ||
84 | #define SMMU_TLB_FLUSH_ASID_MATCH (1 << 31) | ||
336 | 85 | ||
337 | for (i = 0; i < smmu->nregs; i++) { | 86 | #define SMMU_PTC_FLUSH 0x034 |
338 | if (addr < smmu->regs[i]) | 87 | #define SMMU_PTC_FLUSH_TYPE_ALL (0 << 0) |
339 | break; | 88 | #define SMMU_PTC_FLUSH_TYPE_ADR (1 << 0) |
340 | if (addr <= smmu->rege[i]) | ||
341 | return true; | ||
342 | } | ||
343 | 89 | ||
344 | return false; | 90 | #define SMMU_PTC_FLUSH_HI 0x9b8 |
345 | } | 91 | #define SMMU_PTC_FLUSH_HI_MASK 0x3 |
346 | 92 | ||
347 | static inline u32 smmu_read(struct smmu_device *smmu, size_t offs) | 93 | /* per-SWGROUP SMMU_*_ASID register */ |
348 | { | 94 | #define SMMU_ASID_ENABLE (1 << 31) |
349 | void __iomem *addr = smmu->regbase + offs; | 95 | #define SMMU_ASID_MASK 0x7f |
96 | #define SMMU_ASID_VALUE(x) ((x) & SMMU_ASID_MASK) | ||
350 | 97 | ||
351 | BUG_ON(!smmu_valid_reg(smmu, addr)); | 98 | /* page table definitions */ |
99 | #define SMMU_NUM_PDE 1024 | ||
100 | #define SMMU_NUM_PTE 1024 | ||
352 | 101 | ||
353 | return readl(addr); | 102 | #define SMMU_SIZE_PD (SMMU_NUM_PDE * 4) |
354 | } | 103 | #define SMMU_SIZE_PT (SMMU_NUM_PTE * 4) |
355 | 104 | ||
356 | static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) | 105 | #define SMMU_PDE_SHIFT 22 |
357 | { | 106 | #define SMMU_PTE_SHIFT 12 |
358 | void __iomem *addr = smmu->regbase + offs; | ||
359 | 107 | ||
360 | BUG_ON(!smmu_valid_reg(smmu, addr)); | 108 | #define SMMU_PFN_MASK 0x000fffff |
361 | 109 | ||
362 | writel(val, addr); | 110 | #define SMMU_PD_READABLE (1 << 31) |
363 | } | 111 | #define SMMU_PD_WRITABLE (1 << 30) |
112 | #define SMMU_PD_NONSECURE (1 << 29) | ||
364 | 113 | ||
365 | #define VA_PAGE_TO_PA(va, page) \ | 114 | #define SMMU_PDE_READABLE (1 << 31) |
366 | (page_to_phys(page) + ((unsigned long)(va) & ~PAGE_MASK)) | 115 | #define SMMU_PDE_WRITABLE (1 << 30) |
116 | #define SMMU_PDE_NONSECURE (1 << 29) | ||
117 | #define SMMU_PDE_NEXT (1 << 28) | ||
367 | 118 | ||
368 | #define FLUSH_CPU_DCACHE(va, page, size) \ | 119 | #define SMMU_PTE_READABLE (1 << 31) |
369 | do { \ | 120 | #define SMMU_PTE_WRITABLE (1 << 30) |
370 | unsigned long _pa_ = VA_PAGE_TO_PA(va, page); \ | 121 | #define SMMU_PTE_NONSECURE (1 << 29) |
371 | __cpuc_flush_dcache_area((void *)(va), (size_t)(size)); \ | ||
372 | outer_flush_range(_pa_, _pa_+(size_t)(size)); \ | ||
373 | } while (0) | ||
374 | 122 | ||
375 | /* | 123 | #define SMMU_PDE_ATTR (SMMU_PDE_READABLE | SMMU_PDE_WRITABLE | \ |
376 | * Any interaction between any block on PPSB and a block on APB or AHB | 124 | SMMU_PDE_NONSECURE) |
377 | * must have these read-back barriers to ensure the APB/AHB bus | 125 | #define SMMU_PTE_ATTR (SMMU_PTE_READABLE | SMMU_PTE_WRITABLE | \ |
378 | * transaction is complete before initiating activity on the PPSB | 126 | SMMU_PTE_NONSECURE) |
379 | * block. | ||
380 | */ | ||
381 | #define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG) | ||
382 | 127 | ||
383 | #define smmu_client_hwgrp(c) (u32)((c)->dev->platform_data) | 128 | static inline void smmu_flush_ptc(struct tegra_smmu *smmu, struct page *page, |
384 | 129 | unsigned long offset) | |
385 | static int __smmu_client_set_hwgrp(struct smmu_client *c, | ||
386 | unsigned long map, int on) | ||
387 | { | 130 | { |
388 | int i; | 131 | phys_addr_t phys = page ? page_to_phys(page) : 0; |
389 | struct smmu_as *as = c->as; | 132 | u32 value; |
390 | u32 val, offs, mask = SMMU_ASID_ENABLE(as->asid); | 133 | |
391 | struct smmu_device *smmu = as->smmu; | 134 | if (page) { |
392 | 135 | offset &= ~(smmu->mc->soc->atom_size - 1); | |
393 | WARN_ON(!on && map); | 136 | |
394 | if (on && !map) | 137 | if (smmu->mc->soc->num_address_bits > 32) { |
395 | return -EINVAL; | 138 | #ifdef CONFIG_PHYS_ADDR_T_64BIT |
396 | if (!on) | 139 | value = (phys >> 32) & SMMU_PTC_FLUSH_HI_MASK; |
397 | map = smmu_client_hwgrp(c); | 140 | #else |
398 | 141 | value = 0; | |
399 | for_each_set_bit(i, &map, HWGRP_COUNT) { | 142 | #endif |
400 | offs = HWGRP_ASID_REG(i); | 143 | smmu_writel(smmu, value, SMMU_PTC_FLUSH_HI); |
401 | val = smmu_read(smmu, offs); | ||
402 | if (on) { | ||
403 | if (WARN_ON(val & mask)) | ||
404 | goto err_hw_busy; | ||
405 | val |= mask; | ||
406 | } else { | ||
407 | WARN_ON((val & mask) == mask); | ||
408 | val &= ~mask; | ||
409 | } | 144 | } |
410 | smmu_write(smmu, val, offs); | ||
411 | } | ||
412 | FLUSH_SMMU_REGS(smmu); | ||
413 | c->hwgrp = map; | ||
414 | return 0; | ||
415 | 145 | ||
416 | err_hw_busy: | 146 | value = (phys + offset) | SMMU_PTC_FLUSH_TYPE_ADR; |
417 | for_each_set_bit(i, &map, HWGRP_COUNT) { | 147 | } else { |
418 | offs = HWGRP_ASID_REG(i); | 148 | value = SMMU_PTC_FLUSH_TYPE_ALL; |
419 | val = smmu_read(smmu, offs); | ||
420 | val &= ~mask; | ||
421 | smmu_write(smmu, val, offs); | ||
422 | } | 149 | } |
423 | return -EBUSY; | 150 | |
151 | smmu_writel(smmu, value, SMMU_PTC_FLUSH); | ||
424 | } | 152 | } |
425 | 153 | ||
426 | static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on) | 154 | static inline void smmu_flush_tlb(struct tegra_smmu *smmu) |
427 | { | 155 | { |
428 | u32 val; | 156 | smmu_writel(smmu, SMMU_TLB_FLUSH_VA_MATCH_ALL, SMMU_TLB_FLUSH); |
429 | unsigned long flags; | ||
430 | struct smmu_as *as = c->as; | ||
431 | struct smmu_device *smmu = as->smmu; | ||
432 | |||
433 | spin_lock_irqsave(&smmu->lock, flags); | ||
434 | val = __smmu_client_set_hwgrp(c, map, on); | ||
435 | spin_unlock_irqrestore(&smmu->lock, flags); | ||
436 | return val; | ||
437 | } | 157 | } |
438 | 158 | ||
439 | /* | 159 | static inline void smmu_flush_tlb_asid(struct tegra_smmu *smmu, |
440 | * Flush all TLB entries and all PTC entries | 160 | unsigned long asid) |
441 | * Caller must lock smmu | ||
442 | */ | ||
443 | static void smmu_flush_regs(struct smmu_device *smmu, int enable) | ||
444 | { | 161 | { |
445 | u32 val; | 162 | u32 value; |
446 | |||
447 | smmu_write(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH); | ||
448 | FLUSH_SMMU_REGS(smmu); | ||
449 | val = SMMU_TLB_FLUSH_VA_MATCH_ALL | | ||
450 | SMMU_TLB_FLUSH_ASID_MATCH_disable; | ||
451 | smmu_write(smmu, val, SMMU_TLB_FLUSH); | ||
452 | 163 | ||
453 | if (enable) | 164 | value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) | |
454 | smmu_write(smmu, SMMU_CONFIG_ENABLE, SMMU_CONFIG); | 165 | SMMU_TLB_FLUSH_VA_MATCH_ALL; |
455 | FLUSH_SMMU_REGS(smmu); | 166 | smmu_writel(smmu, value, SMMU_TLB_FLUSH); |
456 | } | 167 | } |
457 | 168 | ||
458 | static int smmu_setup_regs(struct smmu_device *smmu) | 169 | static inline void smmu_flush_tlb_section(struct tegra_smmu *smmu, |
170 | unsigned long asid, | ||
171 | unsigned long iova) | ||
459 | { | 172 | { |
460 | int i; | 173 | u32 value; |
461 | u32 val; | ||
462 | 174 | ||
463 | for (i = 0; i < smmu->num_as; i++) { | 175 | value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) | |
464 | struct smmu_as *as = &smmu->as[i]; | 176 | SMMU_TLB_FLUSH_VA_SECTION(iova); |
465 | struct smmu_client *c; | 177 | smmu_writel(smmu, value, SMMU_TLB_FLUSH); |
466 | |||
467 | smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID); | ||
468 | val = as->pdir_page ? | ||
469 | SMMU_MK_PDIR(as->pdir_page, as->pdir_attr) : | ||
470 | SMMU_PTB_DATA_RESET_VAL; | ||
471 | smmu_write(smmu, val, SMMU_PTB_DATA); | ||
472 | |||
473 | list_for_each_entry(c, &as->client, list) | ||
474 | __smmu_client_set_hwgrp(c, c->hwgrp, 1); | ||
475 | } | ||
476 | |||
477 | smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0); | ||
478 | smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1); | ||
479 | smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2); | ||
480 | smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY); | ||
481 | smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_TLB)); | ||
482 | smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_PTC)); | ||
483 | |||
484 | smmu_flush_regs(smmu, 1); | ||
485 | |||
486 | return tegra_ahb_enable_smmu(smmu->ahb); | ||
487 | } | 178 | } |
488 | 179 | ||
489 | static void flush_ptc_and_tlb(struct smmu_device *smmu, | 180 | static inline void smmu_flush_tlb_group(struct tegra_smmu *smmu, |
490 | struct smmu_as *as, dma_addr_t iova, | 181 | unsigned long asid, |
491 | unsigned long *pte, struct page *page, int is_pde) | 182 | unsigned long iova) |
492 | { | 183 | { |
493 | u32 val; | 184 | u32 value; |
494 | unsigned long tlb_flush_va = is_pde | ||
495 | ? SMMU_TLB_FLUSH_VA(iova, SECTION) | ||
496 | : SMMU_TLB_FLUSH_VA(iova, GROUP); | ||
497 | |||
498 | val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page); | ||
499 | smmu_write(smmu, val, SMMU_PTC_FLUSH); | ||
500 | FLUSH_SMMU_REGS(smmu); | ||
501 | val = tlb_flush_va | | ||
502 | SMMU_TLB_FLUSH_ASID_MATCH__ENABLE | | ||
503 | (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT); | ||
504 | smmu_write(smmu, val, SMMU_TLB_FLUSH); | ||
505 | FLUSH_SMMU_REGS(smmu); | ||
506 | } | ||
507 | 185 | ||
508 | static void free_ptbl(struct smmu_as *as, dma_addr_t iova) | 186 | value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) | |
509 | { | 187 | SMMU_TLB_FLUSH_VA_GROUP(iova); |
510 | unsigned long pdn = SMMU_ADDR_TO_PDN(iova); | 188 | smmu_writel(smmu, value, SMMU_TLB_FLUSH); |
511 | unsigned long *pdir = (unsigned long *)page_address(as->pdir_page); | ||
512 | |||
513 | if (pdir[pdn] != _PDE_VACANT(pdn)) { | ||
514 | dev_dbg(as->smmu->dev, "pdn: %lx\n", pdn); | ||
515 | |||
516 | ClearPageReserved(SMMU_EX_PTBL_PAGE(pdir[pdn])); | ||
517 | __free_page(SMMU_EX_PTBL_PAGE(pdir[pdn])); | ||
518 | pdir[pdn] = _PDE_VACANT(pdn); | ||
519 | FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]); | ||
520 | flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn], | ||
521 | as->pdir_page, 1); | ||
522 | } | ||
523 | } | 189 | } |
524 | 190 | ||
525 | static void free_pdir(struct smmu_as *as) | 191 | static inline void smmu_flush(struct tegra_smmu *smmu) |
526 | { | 192 | { |
527 | unsigned addr; | 193 | smmu_readl(smmu, SMMU_CONFIG); |
528 | int count; | ||
529 | struct device *dev = as->smmu->dev; | ||
530 | |||
531 | if (!as->pdir_page) | ||
532 | return; | ||
533 | |||
534 | addr = as->smmu->iovmm_base; | ||
535 | count = as->smmu->page_count; | ||
536 | while (count-- > 0) { | ||
537 | free_ptbl(as, addr); | ||
538 | addr += SMMU_PAGE_SIZE * SMMU_PTBL_COUNT; | ||
539 | } | ||
540 | ClearPageReserved(as->pdir_page); | ||
541 | __free_page(as->pdir_page); | ||
542 | as->pdir_page = NULL; | ||
543 | devm_kfree(dev, as->pte_count); | ||
544 | as->pte_count = NULL; | ||
545 | } | 194 | } |
546 | 195 | ||
547 | /* | 196 | static int tegra_smmu_alloc_asid(struct tegra_smmu *smmu, unsigned int *idp) |
548 | * Maps PTBL for given iova and returns the PTE address | ||
549 | * Caller must unmap the mapped PTBL returned in *ptbl_page_p | ||
550 | */ | ||
551 | static unsigned long *locate_pte(struct smmu_as *as, | ||
552 | dma_addr_t iova, bool allocate, | ||
553 | struct page **ptbl_page_p, | ||
554 | unsigned int **count) | ||
555 | { | 197 | { |
556 | unsigned long ptn = SMMU_ADDR_TO_PFN(iova); | 198 | unsigned long id; |
557 | unsigned long pdn = SMMU_ADDR_TO_PDN(iova); | ||
558 | unsigned long *pdir = page_address(as->pdir_page); | ||
559 | unsigned long *ptbl; | ||
560 | |||
561 | if (pdir[pdn] != _PDE_VACANT(pdn)) { | ||
562 | /* Mapped entry table already exists */ | ||
563 | *ptbl_page_p = SMMU_EX_PTBL_PAGE(pdir[pdn]); | ||
564 | ptbl = page_address(*ptbl_page_p); | ||
565 | } else if (!allocate) { | ||
566 | return NULL; | ||
567 | } else { | ||
568 | int pn; | ||
569 | unsigned long addr = SMMU_PDN_TO_ADDR(pdn); | ||
570 | 199 | ||
571 | /* Vacant - allocate a new page table */ | 200 | mutex_lock(&smmu->lock); |
572 | dev_dbg(as->smmu->dev, "New PTBL pdn: %lx\n", pdn); | ||
573 | 201 | ||
574 | *ptbl_page_p = alloc_page(GFP_ATOMIC); | 202 | id = find_first_zero_bit(smmu->asids, smmu->soc->num_asids); |
575 | if (!*ptbl_page_p) { | 203 | if (id >= smmu->soc->num_asids) { |
576 | dev_err(as->smmu->dev, | 204 | mutex_unlock(&smmu->lock); |
577 | "failed to allocate smmu_device page table\n"); | 205 | return -ENOSPC; |
578 | return NULL; | ||
579 | } | ||
580 | SetPageReserved(*ptbl_page_p); | ||
581 | ptbl = (unsigned long *)page_address(*ptbl_page_p); | ||
582 | for (pn = 0; pn < SMMU_PTBL_COUNT; | ||
583 | pn++, addr += SMMU_PAGE_SIZE) { | ||
584 | ptbl[pn] = _PTE_VACANT(addr); | ||
585 | } | ||
586 | FLUSH_CPU_DCACHE(ptbl, *ptbl_page_p, SMMU_PTBL_SIZE); | ||
587 | pdir[pdn] = SMMU_MK_PDE(*ptbl_page_p, | ||
588 | as->pde_attr | _PDE_NEXT); | ||
589 | FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]); | ||
590 | flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn], | ||
591 | as->pdir_page, 1); | ||
592 | } | 206 | } |
593 | *count = &as->pte_count[pdn]; | ||
594 | 207 | ||
595 | return &ptbl[ptn % SMMU_PTBL_COUNT]; | 208 | set_bit(id, smmu->asids); |
209 | *idp = id; | ||
210 | |||
211 | mutex_unlock(&smmu->lock); | ||
212 | return 0; | ||
596 | } | 213 | } |
597 | 214 | ||
598 | #ifdef CONFIG_SMMU_SIG_DEBUG | 215 | static void tegra_smmu_free_asid(struct tegra_smmu *smmu, unsigned int id) |
599 | static void put_signature(struct smmu_as *as, | ||
600 | dma_addr_t iova, unsigned long pfn) | ||
601 | { | 216 | { |
602 | struct page *page; | 217 | mutex_lock(&smmu->lock); |
603 | unsigned long *vaddr; | 218 | clear_bit(id, smmu->asids); |
604 | 219 | mutex_unlock(&smmu->lock); | |
605 | page = pfn_to_page(pfn); | ||
606 | vaddr = page_address(page); | ||
607 | if (!vaddr) | ||
608 | return; | ||
609 | |||
610 | vaddr[0] = iova; | ||
611 | vaddr[1] = pfn << PAGE_SHIFT; | ||
612 | FLUSH_CPU_DCACHE(vaddr, page, sizeof(vaddr[0]) * 2); | ||
613 | } | 220 | } |
614 | #else | 221 | |
615 | static inline void put_signature(struct smmu_as *as, | 222 | static bool tegra_smmu_capable(enum iommu_cap cap) |
616 | unsigned long addr, unsigned long pfn) | ||
617 | { | 223 | { |
224 | return false; | ||
618 | } | 225 | } |
619 | #endif | ||
620 | 226 | ||
621 | /* | 227 | static int tegra_smmu_domain_init(struct iommu_domain *domain) |
622 | * Caller must not hold as->lock | ||
623 | */ | ||
624 | static int alloc_pdir(struct smmu_as *as) | ||
625 | { | 228 | { |
626 | unsigned long *pdir, flags; | 229 | struct tegra_smmu_as *as; |
627 | int pdn, err = 0; | 230 | unsigned int i; |
628 | u32 val; | 231 | uint32_t *pd; |
629 | struct smmu_device *smmu = as->smmu; | ||
630 | struct page *page; | ||
631 | unsigned int *cnt; | ||
632 | 232 | ||
633 | /* | 233 | as = kzalloc(sizeof(*as), GFP_KERNEL); |
634 | * do the allocation, then grab as->lock | 234 | if (!as) |
635 | */ | 235 | return -ENOMEM; |
636 | cnt = devm_kzalloc(smmu->dev, | ||
637 | sizeof(cnt[0]) * SMMU_PDIR_COUNT, | ||
638 | GFP_KERNEL); | ||
639 | page = alloc_page(GFP_KERNEL | __GFP_DMA); | ||
640 | 236 | ||
641 | spin_lock_irqsave(&as->lock, flags); | 237 | as->attr = SMMU_PD_READABLE | SMMU_PD_WRITABLE | SMMU_PD_NONSECURE; |
238 | as->domain = domain; | ||
642 | 239 | ||
643 | if (as->pdir_page) { | 240 | as->pd = alloc_page(GFP_KERNEL | __GFP_DMA); |
644 | /* We raced, free the redundant */ | 241 | if (!as->pd) { |
645 | err = -EAGAIN; | 242 | kfree(as); |
646 | goto err_out; | 243 | return -ENOMEM; |
647 | } | 244 | } |
648 | 245 | ||
649 | if (!page || !cnt) { | 246 | as->count = alloc_page(GFP_KERNEL); |
650 | dev_err(smmu->dev, "failed to allocate at %s\n", __func__); | 247 | if (!as->count) { |
651 | err = -ENOMEM; | 248 | __free_page(as->pd); |
652 | goto err_out; | 249 | kfree(as); |
250 | return -ENOMEM; | ||
653 | } | 251 | } |
654 | 252 | ||
655 | as->pdir_page = page; | 253 | /* clear PDEs */ |
656 | as->pte_count = cnt; | 254 | pd = page_address(as->pd); |
255 | SetPageReserved(as->pd); | ||
657 | 256 | ||
658 | SetPageReserved(as->pdir_page); | 257 | for (i = 0; i < SMMU_NUM_PDE; i++) |
659 | pdir = page_address(as->pdir_page); | 258 | pd[i] = 0; |
660 | 259 | ||
661 | for (pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++) | 260 | /* clear PDE usage counters */ |
662 | pdir[pdn] = _PDE_VACANT(pdn); | 261 | pd = page_address(as->count); |
663 | FLUSH_CPU_DCACHE(pdir, as->pdir_page, SMMU_PDIR_SIZE); | 262 | SetPageReserved(as->count); |
664 | val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pdir, as->pdir_page); | ||
665 | smmu_write(smmu, val, SMMU_PTC_FLUSH); | ||
666 | FLUSH_SMMU_REGS(as->smmu); | ||
667 | val = SMMU_TLB_FLUSH_VA_MATCH_ALL | | ||
668 | SMMU_TLB_FLUSH_ASID_MATCH__ENABLE | | ||
669 | (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT); | ||
670 | smmu_write(smmu, val, SMMU_TLB_FLUSH); | ||
671 | FLUSH_SMMU_REGS(as->smmu); | ||
672 | 263 | ||
673 | spin_unlock_irqrestore(&as->lock, flags); | 264 | for (i = 0; i < SMMU_NUM_PDE; i++) |
674 | 265 | pd[i] = 0; | |
675 | return 0; | ||
676 | 266 | ||
677 | err_out: | 267 | domain->priv = as; |
678 | spin_unlock_irqrestore(&as->lock, flags); | ||
679 | 268 | ||
680 | devm_kfree(smmu->dev, cnt); | 269 | return 0; |
681 | if (page) | ||
682 | __free_page(page); | ||
683 | return err; | ||
684 | } | 270 | } |
685 | 271 | ||
686 | static void __smmu_iommu_unmap(struct smmu_as *as, dma_addr_t iova) | 272 | static void tegra_smmu_domain_destroy(struct iommu_domain *domain) |
687 | { | 273 | { |
688 | unsigned long *pte; | 274 | struct tegra_smmu_as *as = domain->priv; |
689 | struct page *page; | ||
690 | unsigned int *count; | ||
691 | 275 | ||
692 | pte = locate_pte(as, iova, false, &page, &count); | 276 | /* TODO: free page directory and page tables */ |
693 | if (WARN_ON(!pte)) | 277 | ClearPageReserved(as->pd); |
694 | return; | ||
695 | 278 | ||
696 | if (WARN_ON(*pte == _PTE_VACANT(iova))) | 279 | kfree(as); |
697 | return; | ||
698 | |||
699 | *pte = _PTE_VACANT(iova); | ||
700 | FLUSH_CPU_DCACHE(pte, page, sizeof(*pte)); | ||
701 | flush_ptc_and_tlb(as->smmu, as, iova, pte, page, 0); | ||
702 | if (!--(*count)) | ||
703 | free_ptbl(as, iova); | ||
704 | } | 280 | } |
705 | 281 | ||
706 | static void __smmu_iommu_map_pfn(struct smmu_as *as, dma_addr_t iova, | 282 | static const struct tegra_smmu_swgroup * |
707 | unsigned long pfn) | 283 | tegra_smmu_find_swgroup(struct tegra_smmu *smmu, unsigned int swgroup) |
708 | { | 284 | { |
709 | struct smmu_device *smmu = as->smmu; | 285 | const struct tegra_smmu_swgroup *group = NULL; |
710 | unsigned long *pte; | 286 | unsigned int i; |
711 | unsigned int *count; | ||
712 | struct page *page; | ||
713 | 287 | ||
714 | pte = locate_pte(as, iova, true, &page, &count); | 288 | for (i = 0; i < smmu->soc->num_swgroups; i++) { |
715 | if (WARN_ON(!pte)) | 289 | if (smmu->soc->swgroups[i].swgroup == swgroup) { |
716 | return; | 290 | group = &smmu->soc->swgroups[i]; |
291 | break; | ||
292 | } | ||
293 | } | ||
717 | 294 | ||
718 | if (*pte == _PTE_VACANT(iova)) | 295 | return group; |
719 | (*count)++; | ||
720 | *pte = SMMU_PFN_TO_PTE(pfn, as->pte_attr); | ||
721 | if (unlikely((*pte == _PTE_VACANT(iova)))) | ||
722 | (*count)--; | ||
723 | FLUSH_CPU_DCACHE(pte, page, sizeof(*pte)); | ||
724 | flush_ptc_and_tlb(smmu, as, iova, pte, page, 0); | ||
725 | put_signature(as, iova, pfn); | ||
726 | } | 296 | } |
727 | 297 | ||
728 | static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova, | 298 | static void tegra_smmu_enable(struct tegra_smmu *smmu, unsigned int swgroup, |
729 | phys_addr_t pa, size_t bytes, int prot) | 299 | unsigned int asid) |
730 | { | 300 | { |
731 | struct smmu_as *as = domain->priv; | 301 | const struct tegra_smmu_swgroup *group; |
732 | unsigned long pfn = __phys_to_pfn(pa); | 302 | unsigned int i; |
733 | unsigned long flags; | 303 | u32 value; |
734 | 304 | ||
735 | dev_dbg(as->smmu->dev, "[%d] %08lx:%pa\n", as->asid, iova, &pa); | 305 | for (i = 0; i < smmu->soc->num_clients; i++) { |
306 | const struct tegra_mc_client *client = &smmu->soc->clients[i]; | ||
736 | 307 | ||
737 | if (!pfn_valid(pfn)) | 308 | if (client->swgroup != swgroup) |
738 | return -ENOMEM; | 309 | continue; |
739 | |||
740 | spin_lock_irqsave(&as->lock, flags); | ||
741 | __smmu_iommu_map_pfn(as, iova, pfn); | ||
742 | spin_unlock_irqrestore(&as->lock, flags); | ||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | static size_t smmu_iommu_unmap(struct iommu_domain *domain, unsigned long iova, | ||
747 | size_t bytes) | ||
748 | { | ||
749 | struct smmu_as *as = domain->priv; | ||
750 | unsigned long flags; | ||
751 | 310 | ||
752 | dev_dbg(as->smmu->dev, "[%d] %08lx\n", as->asid, iova); | 311 | value = smmu_readl(smmu, client->smmu.reg); |
312 | value |= BIT(client->smmu.bit); | ||
313 | smmu_writel(smmu, value, client->smmu.reg); | ||
314 | } | ||
753 | 315 | ||
754 | spin_lock_irqsave(&as->lock, flags); | 316 | group = tegra_smmu_find_swgroup(smmu, swgroup); |
755 | __smmu_iommu_unmap(as, iova); | 317 | if (group) { |
756 | spin_unlock_irqrestore(&as->lock, flags); | 318 | value = smmu_readl(smmu, group->reg); |
757 | return SMMU_PAGE_SIZE; | 319 | value &= ~SMMU_ASID_MASK; |
320 | value |= SMMU_ASID_VALUE(asid); | ||
321 | value |= SMMU_ASID_ENABLE; | ||
322 | smmu_writel(smmu, value, group->reg); | ||
323 | } | ||
758 | } | 324 | } |
759 | 325 | ||
760 | static phys_addr_t smmu_iommu_iova_to_phys(struct iommu_domain *domain, | 326 | static void tegra_smmu_disable(struct tegra_smmu *smmu, unsigned int swgroup, |
761 | dma_addr_t iova) | 327 | unsigned int asid) |
762 | { | 328 | { |
763 | struct smmu_as *as = domain->priv; | 329 | const struct tegra_smmu_swgroup *group; |
764 | unsigned long *pte; | 330 | unsigned int i; |
765 | unsigned int *count; | 331 | u32 value; |
766 | struct page *page; | ||
767 | unsigned long pfn; | ||
768 | unsigned long flags; | ||
769 | 332 | ||
770 | spin_lock_irqsave(&as->lock, flags); | 333 | group = tegra_smmu_find_swgroup(smmu, swgroup); |
334 | if (group) { | ||
335 | value = smmu_readl(smmu, group->reg); | ||
336 | value &= ~SMMU_ASID_MASK; | ||
337 | value |= SMMU_ASID_VALUE(asid); | ||
338 | value &= ~SMMU_ASID_ENABLE; | ||
339 | smmu_writel(smmu, value, group->reg); | ||
340 | } | ||
771 | 341 | ||
772 | pte = locate_pte(as, iova, true, &page, &count); | 342 | for (i = 0; i < smmu->soc->num_clients; i++) { |
773 | pfn = *pte & SMMU_PFN_MASK; | 343 | const struct tegra_mc_client *client = &smmu->soc->clients[i]; |
774 | WARN_ON(!pfn_valid(pfn)); | ||
775 | dev_dbg(as->smmu->dev, | ||
776 | "iova:%08llx pfn:%08lx asid:%d\n", (unsigned long long)iova, | ||
777 | pfn, as->asid); | ||
778 | 344 | ||
779 | spin_unlock_irqrestore(&as->lock, flags); | 345 | if (client->swgroup != swgroup) |
780 | return PFN_PHYS(pfn); | 346 | continue; |
781 | } | ||
782 | 347 | ||
783 | static bool smmu_iommu_capable(enum iommu_cap cap) | 348 | value = smmu_readl(smmu, client->smmu.reg); |
784 | { | 349 | value &= ~BIT(client->smmu.bit); |
785 | return false; | 350 | smmu_writel(smmu, value, client->smmu.reg); |
351 | } | ||
786 | } | 352 | } |
787 | 353 | ||
788 | static int smmu_iommu_attach_dev(struct iommu_domain *domain, | 354 | static int tegra_smmu_as_prepare(struct tegra_smmu *smmu, |
789 | struct device *dev) | 355 | struct tegra_smmu_as *as) |
790 | { | 356 | { |
791 | struct smmu_as *as = domain->priv; | 357 | u32 value; |
792 | struct smmu_device *smmu = as->smmu; | ||
793 | struct smmu_client *client, *c; | ||
794 | u32 map; | ||
795 | int err; | 358 | int err; |
796 | 359 | ||
797 | client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL); | 360 | if (as->use_count > 0) { |
798 | if (!client) | 361 | as->use_count++; |
799 | return -ENOMEM; | 362 | return 0; |
800 | client->dev = dev; | ||
801 | client->as = as; | ||
802 | map = (unsigned long)dev->platform_data; | ||
803 | if (!map) | ||
804 | return -EINVAL; | ||
805 | |||
806 | err = smmu_client_enable_hwgrp(client, map); | ||
807 | if (err) | ||
808 | goto err_hwgrp; | ||
809 | |||
810 | spin_lock(&as->client_lock); | ||
811 | list_for_each_entry(c, &as->client, list) { | ||
812 | if (c->dev == dev) { | ||
813 | dev_err(smmu->dev, | ||
814 | "%s is already attached\n", dev_name(c->dev)); | ||
815 | err = -EINVAL; | ||
816 | goto err_client; | ||
817 | } | ||
818 | } | 363 | } |
819 | list_add(&client->list, &as->client); | ||
820 | spin_unlock(&as->client_lock); | ||
821 | 364 | ||
822 | /* | 365 | err = tegra_smmu_alloc_asid(smmu, &as->id); |
823 | * Reserve "page zero" for AVP vectors using a common dummy | 366 | if (err < 0) |
824 | * page. | 367 | return err; |
825 | */ | ||
826 | if (map & HWG_AVPC) { | ||
827 | struct page *page; | ||
828 | 368 | ||
829 | page = as->smmu->avp_vector_page; | 369 | smmu->soc->ops->flush_dcache(as->pd, 0, SMMU_SIZE_PD); |
830 | __smmu_iommu_map_pfn(as, 0, page_to_pfn(page)); | 370 | smmu_flush_ptc(smmu, as->pd, 0); |
371 | smmu_flush_tlb_asid(smmu, as->id); | ||
831 | 372 | ||
832 | pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n"); | 373 | smmu_writel(smmu, as->id & 0x7f, SMMU_PTB_ASID); |
833 | } | 374 | value = SMMU_PTB_DATA_VALUE(as->pd, as->attr); |
375 | smmu_writel(smmu, value, SMMU_PTB_DATA); | ||
376 | smmu_flush(smmu); | ||
834 | 377 | ||
835 | dev_dbg(smmu->dev, "%s is attached\n", dev_name(dev)); | 378 | as->smmu = smmu; |
836 | return 0; | 379 | as->use_count++; |
837 | 380 | ||
838 | err_client: | 381 | return 0; |
839 | smmu_client_disable_hwgrp(client); | ||
840 | spin_unlock(&as->client_lock); | ||
841 | err_hwgrp: | ||
842 | devm_kfree(smmu->dev, client); | ||
843 | return err; | ||
844 | } | 382 | } |
845 | 383 | ||
846 | static void smmu_iommu_detach_dev(struct iommu_domain *domain, | 384 | static void tegra_smmu_as_unprepare(struct tegra_smmu *smmu, |
847 | struct device *dev) | 385 | struct tegra_smmu_as *as) |
848 | { | 386 | { |
849 | struct smmu_as *as = domain->priv; | 387 | if (--as->use_count > 0) |
850 | struct smmu_device *smmu = as->smmu; | 388 | return; |
851 | struct smmu_client *c; | 389 | |
852 | 390 | tegra_smmu_free_asid(smmu, as->id); | |
853 | spin_lock(&as->client_lock); | 391 | as->smmu = NULL; |
854 | |||
855 | list_for_each_entry(c, &as->client, list) { | ||
856 | if (c->dev == dev) { | ||
857 | smmu_client_disable_hwgrp(c); | ||
858 | list_del(&c->list); | ||
859 | devm_kfree(smmu->dev, c); | ||
860 | c->as = NULL; | ||
861 | dev_dbg(smmu->dev, | ||
862 | "%s is detached\n", dev_name(c->dev)); | ||
863 | goto out; | ||
864 | } | ||
865 | } | ||
866 | dev_err(smmu->dev, "Couldn't find %s\n", dev_name(dev)); | ||
867 | out: | ||
868 | spin_unlock(&as->client_lock); | ||
869 | } | 392 | } |
870 | 393 | ||
871 | static int smmu_iommu_domain_init(struct iommu_domain *domain) | 394 | static int tegra_smmu_attach_dev(struct iommu_domain *domain, |
395 | struct device *dev) | ||
872 | { | 396 | { |
873 | int i, err = -EAGAIN; | 397 | struct tegra_smmu *smmu = dev->archdata.iommu; |
874 | unsigned long flags; | 398 | struct tegra_smmu_as *as = domain->priv; |
875 | struct smmu_as *as; | 399 | struct device_node *np = dev->of_node; |
876 | struct smmu_device *smmu = smmu_handle; | 400 | struct of_phandle_args args; |
401 | unsigned int index = 0; | ||
402 | int err = 0; | ||
877 | 403 | ||
878 | /* Look for a free AS with lock held */ | 404 | while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells", index, |
879 | for (i = 0; i < smmu->num_as; i++) { | 405 | &args)) { |
880 | as = &smmu->as[i]; | 406 | unsigned int swgroup = args.args[0]; |
881 | 407 | ||
882 | if (as->pdir_page) | 408 | if (args.np != smmu->dev->of_node) { |
409 | of_node_put(args.np); | ||
883 | continue; | 410 | continue; |
411 | } | ||
884 | 412 | ||
885 | err = alloc_pdir(as); | 413 | of_node_put(args.np); |
886 | if (!err) | ||
887 | goto found; | ||
888 | 414 | ||
889 | if (err != -EAGAIN) | 415 | err = tegra_smmu_as_prepare(smmu, as); |
890 | break; | 416 | if (err < 0) |
417 | return err; | ||
418 | |||
419 | tegra_smmu_enable(smmu, swgroup, as->id); | ||
420 | index++; | ||
891 | } | 421 | } |
892 | if (i == smmu->num_as) | ||
893 | dev_err(smmu->dev, "no free AS\n"); | ||
894 | return err; | ||
895 | 422 | ||
896 | found: | 423 | if (index == 0) |
897 | spin_lock_irqsave(&smmu->lock, flags); | 424 | return -ENODEV; |
898 | 425 | ||
899 | /* Update PDIR register */ | 426 | return 0; |
900 | smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID); | 427 | } |
901 | smmu_write(smmu, | ||
902 | SMMU_MK_PDIR(as->pdir_page, as->pdir_attr), SMMU_PTB_DATA); | ||
903 | FLUSH_SMMU_REGS(smmu); | ||
904 | 428 | ||
905 | spin_unlock_irqrestore(&smmu->lock, flags); | 429 | static void tegra_smmu_detach_dev(struct iommu_domain *domain, struct device *dev) |
430 | { | ||
431 | struct tegra_smmu_as *as = domain->priv; | ||
432 | struct device_node *np = dev->of_node; | ||
433 | struct tegra_smmu *smmu = as->smmu; | ||
434 | struct of_phandle_args args; | ||
435 | unsigned int index = 0; | ||
906 | 436 | ||
907 | domain->priv = as; | 437 | while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells", index, |
438 | &args)) { | ||
439 | unsigned int swgroup = args.args[0]; | ||
908 | 440 | ||
909 | domain->geometry.aperture_start = smmu->iovmm_base; | 441 | if (args.np != smmu->dev->of_node) { |
910 | domain->geometry.aperture_end = smmu->iovmm_base + | 442 | of_node_put(args.np); |
911 | smmu->page_count * SMMU_PAGE_SIZE - 1; | 443 | continue; |
912 | domain->geometry.force_aperture = true; | 444 | } |
913 | 445 | ||
914 | dev_dbg(smmu->dev, "smmu_as@%p\n", as); | 446 | of_node_put(args.np); |
915 | 447 | ||
916 | return 0; | 448 | tegra_smmu_disable(smmu, swgroup, as->id); |
449 | tegra_smmu_as_unprepare(smmu, as); | ||
450 | index++; | ||
451 | } | ||
917 | } | 452 | } |
918 | 453 | ||
919 | static void smmu_iommu_domain_destroy(struct iommu_domain *domain) | 454 | static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova, |
455 | struct page **pagep) | ||
920 | { | 456 | { |
921 | struct smmu_as *as = domain->priv; | 457 | u32 *pd = page_address(as->pd), *pt, *count; |
922 | struct smmu_device *smmu = as->smmu; | 458 | u32 pde = (iova >> SMMU_PDE_SHIFT) & 0x3ff; |
923 | unsigned long flags; | 459 | u32 pte = (iova >> SMMU_PTE_SHIFT) & 0x3ff; |
460 | struct tegra_smmu *smmu = as->smmu; | ||
461 | struct page *page; | ||
462 | unsigned int i; | ||
463 | |||
464 | if (pd[pde] == 0) { | ||
465 | page = alloc_page(GFP_KERNEL | __GFP_DMA); | ||
466 | if (!page) | ||
467 | return NULL; | ||
924 | 468 | ||
925 | spin_lock_irqsave(&as->lock, flags); | 469 | pt = page_address(page); |
470 | SetPageReserved(page); | ||
926 | 471 | ||
927 | if (as->pdir_page) { | 472 | for (i = 0; i < SMMU_NUM_PTE; i++) |
928 | spin_lock(&smmu->lock); | 473 | pt[i] = 0; |
929 | smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID); | ||
930 | smmu_write(smmu, SMMU_PTB_DATA_RESET_VAL, SMMU_PTB_DATA); | ||
931 | FLUSH_SMMU_REGS(smmu); | ||
932 | spin_unlock(&smmu->lock); | ||
933 | 474 | ||
934 | free_pdir(as); | 475 | smmu->soc->ops->flush_dcache(page, 0, SMMU_SIZE_PT); |
935 | } | ||
936 | 476 | ||
937 | if (!list_empty(&as->client)) { | 477 | pd[pde] = SMMU_MK_PDE(page, SMMU_PDE_ATTR | SMMU_PDE_NEXT); |
938 | struct smmu_client *c; | ||
939 | 478 | ||
940 | list_for_each_entry(c, &as->client, list) | 479 | smmu->soc->ops->flush_dcache(as->pd, pde << 2, 4); |
941 | smmu_iommu_detach_dev(domain, c->dev); | 480 | smmu_flush_ptc(smmu, as->pd, pde << 2); |
481 | smmu_flush_tlb_section(smmu, as->id, iova); | ||
482 | smmu_flush(smmu); | ||
483 | } else { | ||
484 | page = pfn_to_page(pd[pde] & SMMU_PFN_MASK); | ||
485 | pt = page_address(page); | ||
942 | } | 486 | } |
943 | 487 | ||
944 | spin_unlock_irqrestore(&as->lock, flags); | 488 | *pagep = page; |
945 | 489 | ||
946 | domain->priv = NULL; | 490 | /* Keep track of entries in this page table. */ |
947 | dev_dbg(smmu->dev, "smmu_as@%p\n", as); | 491 | count = page_address(as->count); |
948 | } | 492 | if (pt[pte] == 0) |
493 | count[pde]++; | ||
949 | 494 | ||
950 | static const struct iommu_ops smmu_iommu_ops = { | 495 | return &pt[pte]; |
951 | .capable = smmu_iommu_capable, | 496 | } |
952 | .domain_init = smmu_iommu_domain_init, | ||
953 | .domain_destroy = smmu_iommu_domain_destroy, | ||
954 | .attach_dev = smmu_iommu_attach_dev, | ||
955 | .detach_dev = smmu_iommu_detach_dev, | ||
956 | .map = smmu_iommu_map, | ||
957 | .unmap = smmu_iommu_unmap, | ||
958 | .map_sg = default_iommu_map_sg, | ||
959 | .iova_to_phys = smmu_iommu_iova_to_phys, | ||
960 | .pgsize_bitmap = SMMU_IOMMU_PGSIZES, | ||
961 | }; | ||
962 | |||
963 | /* Should be in the order of enum */ | ||
964 | static const char * const smmu_debugfs_mc[] = { "mc", }; | ||
965 | static const char * const smmu_debugfs_cache[] = { "tlb", "ptc", }; | ||
966 | 497 | ||
967 | static ssize_t smmu_debugfs_stats_write(struct file *file, | 498 | static void as_put_pte(struct tegra_smmu_as *as, dma_addr_t iova) |
968 | const char __user *buffer, | ||
969 | size_t count, loff_t *pos) | ||
970 | { | 499 | { |
971 | struct smmu_debugfs_info *info; | 500 | u32 pde = (iova >> SMMU_PDE_SHIFT) & 0x3ff; |
972 | struct smmu_device *smmu; | 501 | u32 pte = (iova >> SMMU_PTE_SHIFT) & 0x3ff; |
973 | int i; | 502 | u32 *count = page_address(as->count); |
974 | enum { | 503 | u32 *pd = page_address(as->pd), *pt; |
975 | _OFF = 0, | 504 | struct page *page; |
976 | _ON, | ||
977 | _RESET, | ||
978 | }; | ||
979 | const char * const command[] = { | ||
980 | [_OFF] = "off", | ||
981 | [_ON] = "on", | ||
982 | [_RESET] = "reset", | ||
983 | }; | ||
984 | char str[] = "reset"; | ||
985 | u32 val; | ||
986 | size_t offs; | ||
987 | 505 | ||
988 | count = min_t(size_t, count, sizeof(str)); | 506 | page = pfn_to_page(pd[pde] & SMMU_PFN_MASK); |
989 | if (copy_from_user(str, buffer, count)) | 507 | pt = page_address(page); |
990 | return -EINVAL; | ||
991 | 508 | ||
992 | for (i = 0; i < ARRAY_SIZE(command); i++) | 509 | /* |
993 | if (strncmp(str, command[i], | 510 | * When no entries in this page table are used anymore, return the |
994 | strlen(command[i])) == 0) | 511 | * memory page to the system. |
995 | break; | 512 | */ |
513 | if (pt[pte] != 0) { | ||
514 | if (--count[pde] == 0) { | ||
515 | ClearPageReserved(page); | ||
516 | __free_page(page); | ||
517 | pd[pde] = 0; | ||
518 | } | ||
996 | 519 | ||
997 | if (i == ARRAY_SIZE(command)) | 520 | pt[pte] = 0; |
998 | return -EINVAL; | ||
999 | |||
1000 | info = file_inode(file)->i_private; | ||
1001 | smmu = info->smmu; | ||
1002 | |||
1003 | offs = SMMU_CACHE_CONFIG(info->cache); | ||
1004 | val = smmu_read(smmu, offs); | ||
1005 | switch (i) { | ||
1006 | case _OFF: | ||
1007 | val &= ~SMMU_CACHE_CONFIG_STATS_ENABLE; | ||
1008 | val &= ~SMMU_CACHE_CONFIG_STATS_TEST; | ||
1009 | smmu_write(smmu, val, offs); | ||
1010 | break; | ||
1011 | case _ON: | ||
1012 | val |= SMMU_CACHE_CONFIG_STATS_ENABLE; | ||
1013 | val &= ~SMMU_CACHE_CONFIG_STATS_TEST; | ||
1014 | smmu_write(smmu, val, offs); | ||
1015 | break; | ||
1016 | case _RESET: | ||
1017 | val |= SMMU_CACHE_CONFIG_STATS_TEST; | ||
1018 | smmu_write(smmu, val, offs); | ||
1019 | val &= ~SMMU_CACHE_CONFIG_STATS_TEST; | ||
1020 | smmu_write(smmu, val, offs); | ||
1021 | break; | ||
1022 | default: | ||
1023 | BUG(); | ||
1024 | break; | ||
1025 | } | 521 | } |
1026 | |||
1027 | dev_dbg(smmu->dev, "%s() %08x, %08x @%08x\n", __func__, | ||
1028 | val, smmu_read(smmu, offs), offs); | ||
1029 | |||
1030 | return count; | ||
1031 | } | 522 | } |
1032 | 523 | ||
1033 | static int smmu_debugfs_stats_show(struct seq_file *s, void *v) | 524 | static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova, |
525 | phys_addr_t paddr, size_t size, int prot) | ||
1034 | { | 526 | { |
1035 | struct smmu_debugfs_info *info = s->private; | 527 | struct tegra_smmu_as *as = domain->priv; |
1036 | struct smmu_device *smmu = info->smmu; | 528 | struct tegra_smmu *smmu = as->smmu; |
1037 | int i; | 529 | unsigned long offset; |
1038 | const char * const stats[] = { "hit", "miss", }; | 530 | struct page *page; |
531 | u32 *pte; | ||
1039 | 532 | ||
533 | pte = as_get_pte(as, iova, &page); | ||
534 | if (!pte) | ||
535 | return -ENOMEM; | ||
1040 | 536 | ||
1041 | for (i = 0; i < ARRAY_SIZE(stats); i++) { | 537 | *pte = __phys_to_pfn(paddr) | SMMU_PTE_ATTR; |
1042 | u32 val; | 538 | offset = offset_in_page(pte); |
1043 | size_t offs; | ||
1044 | 539 | ||
1045 | offs = SMMU_STATS_CACHE_COUNT(info->mc, info->cache, i); | 540 | smmu->soc->ops->flush_dcache(page, offset, 4); |
1046 | val = smmu_read(smmu, offs); | 541 | smmu_flush_ptc(smmu, page, offset); |
1047 | seq_printf(s, "%s:%08x ", stats[i], val); | 542 | smmu_flush_tlb_group(smmu, as->id, iova); |
543 | smmu_flush(smmu); | ||
1048 | 544 | ||
1049 | dev_dbg(smmu->dev, "%s() %s %08x @%08x\n", __func__, | ||
1050 | stats[i], val, offs); | ||
1051 | } | ||
1052 | seq_printf(s, "\n"); | ||
1053 | return 0; | 545 | return 0; |
1054 | } | 546 | } |
1055 | 547 | ||
1056 | static int smmu_debugfs_stats_open(struct inode *inode, struct file *file) | 548 | static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova, |
549 | size_t size) | ||
1057 | { | 550 | { |
1058 | return single_open(file, smmu_debugfs_stats_show, inode->i_private); | 551 | struct tegra_smmu_as *as = domain->priv; |
1059 | } | 552 | struct tegra_smmu *smmu = as->smmu; |
553 | unsigned long offset; | ||
554 | struct page *page; | ||
555 | u32 *pte; | ||
1060 | 556 | ||
1061 | static const struct file_operations smmu_debugfs_stats_fops = { | 557 | pte = as_get_pte(as, iova, &page); |
1062 | .open = smmu_debugfs_stats_open, | 558 | if (!pte) |
1063 | .read = seq_read, | 559 | return 0; |
1064 | .llseek = seq_lseek, | ||
1065 | .release = single_release, | ||
1066 | .write = smmu_debugfs_stats_write, | ||
1067 | }; | ||
1068 | 560 | ||
1069 | static void smmu_debugfs_delete(struct smmu_device *smmu) | 561 | offset = offset_in_page(pte); |
1070 | { | 562 | as_put_pte(as, iova); |
1071 | debugfs_remove_recursive(smmu->debugfs_root); | 563 | |
1072 | kfree(smmu->debugfs_info); | 564 | smmu->soc->ops->flush_dcache(page, offset, 4); |
565 | smmu_flush_ptc(smmu, page, offset); | ||
566 | smmu_flush_tlb_group(smmu, as->id, iova); | ||
567 | smmu_flush(smmu); | ||
568 | |||
569 | return size; | ||
1073 | } | 570 | } |
1074 | 571 | ||
1075 | static void smmu_debugfs_create(struct smmu_device *smmu) | 572 | static phys_addr_t tegra_smmu_iova_to_phys(struct iommu_domain *domain, |
573 | dma_addr_t iova) | ||
1076 | { | 574 | { |
1077 | int i; | 575 | struct tegra_smmu_as *as = domain->priv; |
1078 | size_t bytes; | 576 | struct page *page; |
1079 | struct dentry *root; | 577 | unsigned long pfn; |
1080 | 578 | u32 *pte; | |
1081 | bytes = ARRAY_SIZE(smmu_debugfs_mc) * ARRAY_SIZE(smmu_debugfs_cache) * | ||
1082 | sizeof(*smmu->debugfs_info); | ||
1083 | smmu->debugfs_info = kmalloc(bytes, GFP_KERNEL); | ||
1084 | if (!smmu->debugfs_info) | ||
1085 | return; | ||
1086 | |||
1087 | root = debugfs_create_dir(dev_name(smmu->dev), NULL); | ||
1088 | if (!root) | ||
1089 | goto err_out; | ||
1090 | smmu->debugfs_root = root; | ||
1091 | |||
1092 | for (i = 0; i < ARRAY_SIZE(smmu_debugfs_mc); i++) { | ||
1093 | int j; | ||
1094 | struct dentry *mc; | ||
1095 | |||
1096 | mc = debugfs_create_dir(smmu_debugfs_mc[i], root); | ||
1097 | if (!mc) | ||
1098 | goto err_out; | ||
1099 | |||
1100 | for (j = 0; j < ARRAY_SIZE(smmu_debugfs_cache); j++) { | ||
1101 | struct dentry *cache; | ||
1102 | struct smmu_debugfs_info *info; | ||
1103 | |||
1104 | info = smmu->debugfs_info; | ||
1105 | info += i * ARRAY_SIZE(smmu_debugfs_mc) + j; | ||
1106 | info->smmu = smmu; | ||
1107 | info->mc = i; | ||
1108 | info->cache = j; | ||
1109 | |||
1110 | cache = debugfs_create_file(smmu_debugfs_cache[j], | ||
1111 | S_IWUGO | S_IRUGO, mc, | ||
1112 | (void *)info, | ||
1113 | &smmu_debugfs_stats_fops); | ||
1114 | if (!cache) | ||
1115 | goto err_out; | ||
1116 | } | ||
1117 | } | ||
1118 | 579 | ||
1119 | return; | 580 | pte = as_get_pte(as, iova, &page); |
581 | pfn = *pte & SMMU_PFN_MASK; | ||
1120 | 582 | ||
1121 | err_out: | 583 | return PFN_PHYS(pfn); |
1122 | smmu_debugfs_delete(smmu); | ||
1123 | } | 584 | } |
1124 | 585 | ||
1125 | static int tegra_smmu_suspend(struct device *dev) | 586 | static struct tegra_smmu *tegra_smmu_find(struct device_node *np) |
1126 | { | 587 | { |
1127 | struct smmu_device *smmu = dev_get_drvdata(dev); | 588 | struct platform_device *pdev; |
589 | struct tegra_mc *mc; | ||
1128 | 590 | ||
1129 | smmu->translation_enable_0 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_0); | 591 | pdev = of_find_device_by_node(np); |
1130 | smmu->translation_enable_1 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_1); | 592 | if (!pdev) |
1131 | smmu->translation_enable_2 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_2); | 593 | return NULL; |
1132 | smmu->asid_security = smmu_read(smmu, SMMU_ASID_SECURITY); | 594 | |
1133 | return 0; | 595 | mc = platform_get_drvdata(pdev); |
596 | if (!mc) | ||
597 | return NULL; | ||
598 | |||
599 | return mc->smmu; | ||
1134 | } | 600 | } |
1135 | 601 | ||
1136 | static int tegra_smmu_resume(struct device *dev) | 602 | static int tegra_smmu_add_device(struct device *dev) |
1137 | { | 603 | { |
1138 | struct smmu_device *smmu = dev_get_drvdata(dev); | 604 | struct device_node *np = dev->of_node; |
1139 | unsigned long flags; | 605 | struct of_phandle_args args; |
1140 | int err; | 606 | unsigned int index = 0; |
1141 | 607 | ||
1142 | spin_lock_irqsave(&smmu->lock, flags); | 608 | while (of_parse_phandle_with_args(np, "iommus", "#iommu-cells", index, |
1143 | err = smmu_setup_regs(smmu); | 609 | &args) == 0) { |
1144 | spin_unlock_irqrestore(&smmu->lock, flags); | 610 | struct tegra_smmu *smmu; |
1145 | return err; | 611 | |
612 | smmu = tegra_smmu_find(args.np); | ||
613 | if (smmu) { | ||
614 | /* | ||
615 | * Only a single IOMMU master interface is currently | ||
616 | * supported by the Linux kernel, so abort after the | ||
617 | * first match. | ||
618 | */ | ||
619 | dev->archdata.iommu = smmu; | ||
620 | break; | ||
621 | } | ||
622 | |||
623 | index++; | ||
624 | } | ||
625 | |||
626 | return 0; | ||
1146 | } | 627 | } |
1147 | 628 | ||
1148 | static int tegra_smmu_probe(struct platform_device *pdev) | 629 | static void tegra_smmu_remove_device(struct device *dev) |
1149 | { | 630 | { |
1150 | struct smmu_device *smmu; | 631 | dev->archdata.iommu = NULL; |
1151 | struct device *dev = &pdev->dev; | 632 | } |
1152 | int i, asids, err = 0; | ||
1153 | dma_addr_t uninitialized_var(base); | ||
1154 | size_t bytes, uninitialized_var(size); | ||
1155 | 633 | ||
1156 | if (smmu_handle) | 634 | static const struct iommu_ops tegra_smmu_ops = { |
1157 | return -EIO; | 635 | .capable = tegra_smmu_capable, |
636 | .domain_init = tegra_smmu_domain_init, | ||
637 | .domain_destroy = tegra_smmu_domain_destroy, | ||
638 | .attach_dev = tegra_smmu_attach_dev, | ||
639 | .detach_dev = tegra_smmu_detach_dev, | ||
640 | .add_device = tegra_smmu_add_device, | ||
641 | .remove_device = tegra_smmu_remove_device, | ||
642 | .map = tegra_smmu_map, | ||
643 | .unmap = tegra_smmu_unmap, | ||
644 | .map_sg = default_iommu_map_sg, | ||
645 | .iova_to_phys = tegra_smmu_iova_to_phys, | ||
1158 | 646 | ||
1159 | BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT); | 647 | .pgsize_bitmap = SZ_4K, |
648 | }; | ||
1160 | 649 | ||
1161 | if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids)) | 650 | static void tegra_smmu_ahb_enable(void) |
1162 | return -ENODEV; | 651 | { |
652 | static const struct of_device_id ahb_match[] = { | ||
653 | { .compatible = "nvidia,tegra30-ahb", }, | ||
654 | { } | ||
655 | }; | ||
656 | struct device_node *ahb; | ||
1163 | 657 | ||
1164 | bytes = sizeof(*smmu) + asids * sizeof(*smmu->as); | 658 | ahb = of_find_matching_node(NULL, ahb_match); |
1165 | smmu = devm_kzalloc(dev, bytes, GFP_KERNEL); | 659 | if (ahb) { |
1166 | if (!smmu) { | 660 | tegra_ahb_enable_smmu(ahb); |
1167 | dev_err(dev, "failed to allocate smmu_device\n"); | 661 | of_node_put(ahb); |
1168 | return -ENOMEM; | ||
1169 | } | 662 | } |
663 | } | ||
1170 | 664 | ||
1171 | smmu->nregs = pdev->num_resources; | 665 | struct tegra_smmu *tegra_smmu_probe(struct device *dev, |
1172 | smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs), | 666 | const struct tegra_smmu_soc *soc, |
1173 | GFP_KERNEL); | 667 | struct tegra_mc *mc) |
1174 | smmu->rege = smmu->regs + smmu->nregs; | 668 | { |
1175 | if (!smmu->regs) | 669 | struct tegra_smmu *smmu; |
1176 | return -ENOMEM; | 670 | size_t size; |
1177 | for (i = 0; i < smmu->nregs; i++) { | 671 | u32 value; |
1178 | struct resource *res; | 672 | int err; |
1179 | |||
1180 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
1181 | smmu->regs[i] = devm_ioremap_resource(&pdev->dev, res); | ||
1182 | if (IS_ERR(smmu->regs[i])) | ||
1183 | return PTR_ERR(smmu->regs[i]); | ||
1184 | smmu->rege[i] = smmu->regs[i] + resource_size(res) - 1; | ||
1185 | } | ||
1186 | /* Same as "mc" 1st regiter block start address */ | ||
1187 | smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & PAGE_MASK); | ||
1188 | 673 | ||
1189 | err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size); | 674 | /* This can happen on Tegra20 which doesn't have an SMMU */ |
1190 | if (err) | 675 | if (!soc) |
1191 | return -ENODEV; | 676 | return NULL; |
1192 | 677 | ||
1193 | if (size & SMMU_PAGE_MASK) | 678 | smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); |
1194 | return -EINVAL; | 679 | if (!smmu) |
680 | return ERR_PTR(-ENOMEM); | ||
1195 | 681 | ||
1196 | size >>= SMMU_PAGE_SHIFT; | 682 | /* |
1197 | if (!size) | 683 | * This is a bit of a hack. Ideally we'd want to simply return this |
1198 | return -EINVAL; | 684 | * value. However the IOMMU registration process will attempt to add |
685 | * all devices to the IOMMU when bus_set_iommu() is called. In order | ||
686 | * not to rely on global variables to track the IOMMU instance, we | ||
687 | * set it here so that it can be looked up from the .add_device() | ||
688 | * callback via the IOMMU device's .drvdata field. | ||
689 | */ | ||
690 | mc->smmu = smmu; | ||
1199 | 691 | ||
1200 | smmu->ahb = of_parse_phandle(dev->of_node, "nvidia,ahb", 0); | 692 | size = BITS_TO_LONGS(soc->num_asids) * sizeof(long); |
1201 | if (!smmu->ahb) | ||
1202 | return -ENODEV; | ||
1203 | 693 | ||
1204 | smmu->dev = dev; | 694 | smmu->asids = devm_kzalloc(dev, size, GFP_KERNEL); |
1205 | smmu->num_as = asids; | 695 | if (!smmu->asids) |
1206 | smmu->iovmm_base = base; | 696 | return ERR_PTR(-ENOMEM); |
1207 | smmu->page_count = size; | ||
1208 | |||
1209 | smmu->translation_enable_0 = ~0; | ||
1210 | smmu->translation_enable_1 = ~0; | ||
1211 | smmu->translation_enable_2 = ~0; | ||
1212 | smmu->asid_security = 0; | ||
1213 | |||
1214 | for (i = 0; i < smmu->num_as; i++) { | ||
1215 | struct smmu_as *as = &smmu->as[i]; | ||
1216 | |||
1217 | as->smmu = smmu; | ||
1218 | as->asid = i; | ||
1219 | as->pdir_attr = _PDIR_ATTR; | ||
1220 | as->pde_attr = _PDE_ATTR; | ||
1221 | as->pte_attr = _PTE_ATTR; | ||
1222 | |||
1223 | spin_lock_init(&as->lock); | ||
1224 | spin_lock_init(&as->client_lock); | ||
1225 | INIT_LIST_HEAD(&as->client); | ||
1226 | } | ||
1227 | spin_lock_init(&smmu->lock); | ||
1228 | err = smmu_setup_regs(smmu); | ||
1229 | if (err) | ||
1230 | return err; | ||
1231 | platform_set_drvdata(pdev, smmu); | ||
1232 | 697 | ||
1233 | smmu->avp_vector_page = alloc_page(GFP_KERNEL); | 698 | mutex_init(&smmu->lock); |
1234 | if (!smmu->avp_vector_page) | ||
1235 | return -ENOMEM; | ||
1236 | 699 | ||
1237 | smmu_debugfs_create(smmu); | 700 | smmu->regs = mc->regs; |
1238 | smmu_handle = smmu; | 701 | smmu->soc = soc; |
1239 | bus_set_iommu(&platform_bus_type, &smmu_iommu_ops); | 702 | smmu->dev = dev; |
1240 | return 0; | 703 | smmu->mc = mc; |
1241 | } | ||
1242 | 704 | ||
1243 | static int tegra_smmu_remove(struct platform_device *pdev) | 705 | value = SMMU_PTC_CONFIG_ENABLE | SMMU_PTC_CONFIG_INDEX_MAP(0x3f); |
1244 | { | ||
1245 | struct smmu_device *smmu = platform_get_drvdata(pdev); | ||
1246 | int i; | ||
1247 | 706 | ||
1248 | smmu_debugfs_delete(smmu); | 707 | if (soc->supports_request_limit) |
708 | value |= SMMU_PTC_CONFIG_REQ_LIMIT(8); | ||
1249 | 709 | ||
1250 | smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG); | 710 | smmu_writel(smmu, value, SMMU_PTC_CONFIG); |
1251 | for (i = 0; i < smmu->num_as; i++) | ||
1252 | free_pdir(&smmu->as[i]); | ||
1253 | __free_page(smmu->avp_vector_page); | ||
1254 | smmu_handle = NULL; | ||
1255 | return 0; | ||
1256 | } | ||
1257 | 711 | ||
1258 | static const struct dev_pm_ops tegra_smmu_pm_ops = { | 712 | value = SMMU_TLB_CONFIG_HIT_UNDER_MISS | |
1259 | .suspend = tegra_smmu_suspend, | 713 | SMMU_TLB_CONFIG_ACTIVE_LINES(0x20); |
1260 | .resume = tegra_smmu_resume, | ||
1261 | }; | ||
1262 | 714 | ||
1263 | static const struct of_device_id tegra_smmu_of_match[] = { | 715 | if (soc->supports_round_robin_arbitration) |
1264 | { .compatible = "nvidia,tegra30-smmu", }, | 716 | value |= SMMU_TLB_CONFIG_ROUND_ROBIN_ARBITRATION; |
1265 | { }, | ||
1266 | }; | ||
1267 | MODULE_DEVICE_TABLE(of, tegra_smmu_of_match); | ||
1268 | |||
1269 | static struct platform_driver tegra_smmu_driver = { | ||
1270 | .probe = tegra_smmu_probe, | ||
1271 | .remove = tegra_smmu_remove, | ||
1272 | .driver = { | ||
1273 | .owner = THIS_MODULE, | ||
1274 | .name = "tegra-smmu", | ||
1275 | .pm = &tegra_smmu_pm_ops, | ||
1276 | .of_match_table = tegra_smmu_of_match, | ||
1277 | }, | ||
1278 | }; | ||
1279 | 717 | ||
1280 | static int tegra_smmu_init(void) | 718 | smmu_writel(smmu, value, SMMU_TLB_CONFIG); |
1281 | { | ||
1282 | return platform_driver_register(&tegra_smmu_driver); | ||
1283 | } | ||
1284 | 719 | ||
1285 | static void __exit tegra_smmu_exit(void) | 720 | smmu_flush_ptc(smmu, NULL, 0); |
1286 | { | 721 | smmu_flush_tlb(smmu); |
1287 | platform_driver_unregister(&tegra_smmu_driver); | 722 | smmu_writel(smmu, SMMU_CONFIG_ENABLE, SMMU_CONFIG); |
1288 | } | 723 | smmu_flush(smmu); |
724 | |||
725 | tegra_smmu_ahb_enable(); | ||
1289 | 726 | ||
1290 | subsys_initcall(tegra_smmu_init); | 727 | err = bus_set_iommu(&platform_bus_type, &tegra_smmu_ops); |
1291 | module_exit(tegra_smmu_exit); | 728 | if (err < 0) |
729 | return ERR_PTR(err); | ||
1292 | 730 | ||
1293 | MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30"); | 731 | return smmu; |
1294 | MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); | 732 | } |
1295 | MODULE_ALIAS("platform:tegra-smmu"); | ||
1296 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 6d91c27fd4c8..08bd4cfca2a4 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig | |||
@@ -61,16 +61,6 @@ config TEGRA20_MC | |||
61 | analysis, especially for IOMMU/GART(Graphics Address | 61 | analysis, especially for IOMMU/GART(Graphics Address |
62 | Relocation Table) module. | 62 | Relocation Table) module. |
63 | 63 | ||
64 | config TEGRA30_MC | ||
65 | bool "Tegra30 Memory Controller(MC) driver" | ||
66 | default y | ||
67 | depends on ARCH_TEGRA_3x_SOC | ||
68 | help | ||
69 | This driver is for the Memory Controller(MC) module available | ||
70 | in Tegra30 SoCs, mainly for a address translation fault | ||
71 | analysis, especially for IOMMU/SMMU(System Memory Management | ||
72 | Unit) module. | ||
73 | |||
74 | config FSL_CORENET_CF | 64 | config FSL_CORENET_CF |
75 | tristate "Freescale CoreNet Error Reporting" | 65 | tristate "Freescale CoreNet Error Reporting" |
76 | depends on FSL_SOC_BOOKE | 66 | depends on FSL_SOC_BOOKE |
@@ -85,4 +75,6 @@ config FSL_IFC | |||
85 | bool | 75 | bool |
86 | depends on FSL_SOC | 76 | depends on FSL_SOC |
87 | 77 | ||
78 | source "drivers/memory/tegra/Kconfig" | ||
79 | |||
88 | endif | 80 | endif |
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index c32d31981be3..ad98bb232623 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile | |||
@@ -12,4 +12,5 @@ obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o | |||
12 | obj-$(CONFIG_FSL_IFC) += fsl_ifc.o | 12 | obj-$(CONFIG_FSL_IFC) += fsl_ifc.o |
13 | obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o | 13 | obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o |
14 | obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o | 14 | obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o |
15 | obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o | 15 | |
16 | obj-$(CONFIG_TEGRA_MC) += tegra/ | ||
diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig new file mode 100644 index 000000000000..571087621827 --- /dev/null +++ b/drivers/memory/tegra/Kconfig | |||
@@ -0,0 +1,7 @@ | |||
1 | config TEGRA_MC | ||
2 | bool "NVIDIA Tegra Memory Controller support" | ||
3 | default y | ||
4 | depends on ARCH_TEGRA | ||
5 | help | ||
6 | This driver supports the Memory Controller (MC) hardware found on | ||
7 | NVIDIA Tegra SoCs. | ||
diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile new file mode 100644 index 000000000000..0d9f497b786c --- /dev/null +++ b/drivers/memory/tegra/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | tegra-mc-y := mc.o | ||
2 | |||
3 | tegra-mc-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30.o | ||
4 | tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o | ||
5 | tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o | ||
6 | |||
7 | obj-$(CONFIG_TEGRA_MC) += tegra-mc.o | ||
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c new file mode 100644 index 000000000000..fe3c44e7e1d1 --- /dev/null +++ b/drivers/memory/tegra/mc.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/of.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include "mc.h" | ||
18 | |||
19 | #define MC_INTSTATUS 0x000 | ||
20 | #define MC_INT_DECERR_MTS (1 << 16) | ||
21 | #define MC_INT_SECERR_SEC (1 << 13) | ||
22 | #define MC_INT_DECERR_VPR (1 << 12) | ||
23 | #define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) | ||
24 | #define MC_INT_INVALID_SMMU_PAGE (1 << 10) | ||
25 | #define MC_INT_ARBITRATION_EMEM (1 << 9) | ||
26 | #define MC_INT_SECURITY_VIOLATION (1 << 8) | ||
27 | #define MC_INT_DECERR_EMEM (1 << 6) | ||
28 | |||
29 | #define MC_INTMASK 0x004 | ||
30 | |||
31 | #define MC_ERR_STATUS 0x08 | ||
32 | #define MC_ERR_STATUS_TYPE_SHIFT 28 | ||
33 | #define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (6 << MC_ERR_STATUS_TYPE_SHIFT) | ||
34 | #define MC_ERR_STATUS_TYPE_MASK (0x7 << MC_ERR_STATUS_TYPE_SHIFT) | ||
35 | #define MC_ERR_STATUS_READABLE (1 << 27) | ||
36 | #define MC_ERR_STATUS_WRITABLE (1 << 26) | ||
37 | #define MC_ERR_STATUS_NONSECURE (1 << 25) | ||
38 | #define MC_ERR_STATUS_ADR_HI_SHIFT 20 | ||
39 | #define MC_ERR_STATUS_ADR_HI_MASK 0x3 | ||
40 | #define MC_ERR_STATUS_SECURITY (1 << 17) | ||
41 | #define MC_ERR_STATUS_RW (1 << 16) | ||
42 | #define MC_ERR_STATUS_CLIENT_MASK 0x7f | ||
43 | |||
44 | #define MC_ERR_ADR 0x0c | ||
45 | |||
46 | #define MC_EMEM_ARB_CFG 0x90 | ||
47 | #define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0) | ||
48 | #define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff | ||
49 | #define MC_EMEM_ARB_MISC0 0xd8 | ||
50 | |||
51 | static const struct of_device_id tegra_mc_of_match[] = { | ||
52 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
53 | { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc }, | ||
54 | #endif | ||
55 | #ifdef CONFIG_ARCH_TEGRA_114_SOC | ||
56 | { .compatible = "nvidia,tegra114-mc", .data = &tegra114_mc_soc }, | ||
57 | #endif | ||
58 | #ifdef CONFIG_ARCH_TEGRA_124_SOC | ||
59 | { .compatible = "nvidia,tegra124-mc", .data = &tegra124_mc_soc }, | ||
60 | #endif | ||
61 | { } | ||
62 | }; | ||
63 | MODULE_DEVICE_TABLE(of, tegra_mc_of_match); | ||
64 | |||
65 | static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) | ||
66 | { | ||
67 | unsigned long long tick; | ||
68 | unsigned int i; | ||
69 | u32 value; | ||
70 | |||
71 | /* compute the number of MC clock cycles per tick */ | ||
72 | tick = mc->tick * clk_get_rate(mc->clk); | ||
73 | do_div(tick, NSEC_PER_SEC); | ||
74 | |||
75 | value = readl(mc->regs + MC_EMEM_ARB_CFG); | ||
76 | value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; | ||
77 | value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); | ||
78 | writel(value, mc->regs + MC_EMEM_ARB_CFG); | ||
79 | |||
80 | /* write latency allowance defaults */ | ||
81 | for (i = 0; i < mc->soc->num_clients; i++) { | ||
82 | const struct tegra_mc_la *la = &mc->soc->clients[i].la; | ||
83 | u32 value; | ||
84 | |||
85 | value = readl(mc->regs + la->reg); | ||
86 | value &= ~(la->mask << la->shift); | ||
87 | value |= (la->def & la->mask) << la->shift; | ||
88 | writel(value, mc->regs + la->reg); | ||
89 | } | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static const char *const status_names[32] = { | ||
95 | [ 1] = "External interrupt", | ||
96 | [ 6] = "EMEM address decode error", | ||
97 | [ 8] = "Security violation", | ||
98 | [ 9] = "EMEM arbitration error", | ||
99 | [10] = "Page fault", | ||
100 | [11] = "Invalid APB ASID update", | ||
101 | [12] = "VPR violation", | ||
102 | [13] = "Secure carveout violation", | ||
103 | [16] = "MTS carveout violation", | ||
104 | }; | ||
105 | |||
106 | static const char *const error_names[8] = { | ||
107 | [2] = "EMEM decode error", | ||
108 | [3] = "TrustZone violation", | ||
109 | [4] = "Carveout violation", | ||
110 | [6] = "SMMU translation error", | ||
111 | }; | ||
112 | |||
113 | static irqreturn_t tegra_mc_irq(int irq, void *data) | ||
114 | { | ||
115 | struct tegra_mc *mc = data; | ||
116 | unsigned long status, mask; | ||
117 | unsigned int bit; | ||
118 | |||
119 | /* mask all interrupts to avoid flooding */ | ||
120 | status = mc_readl(mc, MC_INTSTATUS); | ||
121 | mask = mc_readl(mc, MC_INTMASK); | ||
122 | |||
123 | for_each_set_bit(bit, &status, 32) { | ||
124 | const char *error = status_names[bit] ?: "unknown"; | ||
125 | const char *client = "unknown", *desc; | ||
126 | const char *direction, *secure; | ||
127 | phys_addr_t addr = 0; | ||
128 | unsigned int i; | ||
129 | char perm[7]; | ||
130 | u8 id, type; | ||
131 | u32 value; | ||
132 | |||
133 | value = mc_readl(mc, MC_ERR_STATUS); | ||
134 | |||
135 | #ifdef CONFIG_PHYS_ADDR_T_64BIT | ||
136 | if (mc->soc->num_address_bits > 32) { | ||
137 | addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) & | ||
138 | MC_ERR_STATUS_ADR_HI_MASK); | ||
139 | addr <<= 32; | ||
140 | } | ||
141 | #endif | ||
142 | |||
143 | if (value & MC_ERR_STATUS_RW) | ||
144 | direction = "write"; | ||
145 | else | ||
146 | direction = "read"; | ||
147 | |||
148 | if (value & MC_ERR_STATUS_SECURITY) | ||
149 | secure = "secure "; | ||
150 | else | ||
151 | secure = ""; | ||
152 | |||
153 | id = value & MC_ERR_STATUS_CLIENT_MASK; | ||
154 | |||
155 | for (i = 0; i < mc->soc->num_clients; i++) { | ||
156 | if (mc->soc->clients[i].id == id) { | ||
157 | client = mc->soc->clients[i].name; | ||
158 | break; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | type = (value & MC_ERR_STATUS_TYPE_MASK) >> | ||
163 | MC_ERR_STATUS_TYPE_SHIFT; | ||
164 | desc = error_names[type]; | ||
165 | |||
166 | switch (value & MC_ERR_STATUS_TYPE_MASK) { | ||
167 | case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE: | ||
168 | perm[0] = ' '; | ||
169 | perm[1] = '['; | ||
170 | |||
171 | if (value & MC_ERR_STATUS_READABLE) | ||
172 | perm[2] = 'R'; | ||
173 | else | ||
174 | perm[2] = '-'; | ||
175 | |||
176 | if (value & MC_ERR_STATUS_WRITABLE) | ||
177 | perm[3] = 'W'; | ||
178 | else | ||
179 | perm[3] = '-'; | ||
180 | |||
181 | if (value & MC_ERR_STATUS_NONSECURE) | ||
182 | perm[4] = '-'; | ||
183 | else | ||
184 | perm[4] = 'S'; | ||
185 | |||
186 | perm[5] = ']'; | ||
187 | perm[6] = '\0'; | ||
188 | break; | ||
189 | |||
190 | default: | ||
191 | perm[0] = '\0'; | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | value = mc_readl(mc, MC_ERR_ADR); | ||
196 | addr |= value; | ||
197 | |||
198 | dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s%s)\n", | ||
199 | client, secure, direction, &addr, error, | ||
200 | desc, perm); | ||
201 | } | ||
202 | |||
203 | /* clear interrupts */ | ||
204 | mc_writel(mc, status, MC_INTSTATUS); | ||
205 | |||
206 | return IRQ_HANDLED; | ||
207 | } | ||
208 | |||
209 | static int tegra_mc_probe(struct platform_device *pdev) | ||
210 | { | ||
211 | const struct of_device_id *match; | ||
212 | struct resource *res; | ||
213 | struct tegra_mc *mc; | ||
214 | u32 value; | ||
215 | int err; | ||
216 | |||
217 | match = of_match_node(tegra_mc_of_match, pdev->dev.of_node); | ||
218 | if (!match) | ||
219 | return -ENODEV; | ||
220 | |||
221 | mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); | ||
222 | if (!mc) | ||
223 | return -ENOMEM; | ||
224 | |||
225 | platform_set_drvdata(pdev, mc); | ||
226 | mc->soc = match->data; | ||
227 | mc->dev = &pdev->dev; | ||
228 | |||
229 | /* length of MC tick in nanoseconds */ | ||
230 | mc->tick = 30; | ||
231 | |||
232 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
233 | mc->regs = devm_ioremap_resource(&pdev->dev, res); | ||
234 | if (IS_ERR(mc->regs)) | ||
235 | return PTR_ERR(mc->regs); | ||
236 | |||
237 | mc->clk = devm_clk_get(&pdev->dev, "mc"); | ||
238 | if (IS_ERR(mc->clk)) { | ||
239 | dev_err(&pdev->dev, "failed to get MC clock: %ld\n", | ||
240 | PTR_ERR(mc->clk)); | ||
241 | return PTR_ERR(mc->clk); | ||
242 | } | ||
243 | |||
244 | err = tegra_mc_setup_latency_allowance(mc); | ||
245 | if (err < 0) { | ||
246 | dev_err(&pdev->dev, "failed to setup latency allowance: %d\n", | ||
247 | err); | ||
248 | return err; | ||
249 | } | ||
250 | |||
251 | if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) { | ||
252 | mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); | ||
253 | if (IS_ERR(mc->smmu)) { | ||
254 | dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", | ||
255 | PTR_ERR(mc->smmu)); | ||
256 | return PTR_ERR(mc->smmu); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | mc->irq = platform_get_irq(pdev, 0); | ||
261 | if (mc->irq < 0) { | ||
262 | dev_err(&pdev->dev, "interrupt not specified\n"); | ||
263 | return mc->irq; | ||
264 | } | ||
265 | |||
266 | err = devm_request_irq(&pdev->dev, mc->irq, tegra_mc_irq, IRQF_SHARED, | ||
267 | dev_name(&pdev->dev), mc); | ||
268 | if (err < 0) { | ||
269 | dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, | ||
270 | err); | ||
271 | return err; | ||
272 | } | ||
273 | |||
274 | value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | | ||
275 | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | | ||
276 | MC_INT_ARBITRATION_EMEM | MC_INT_SECURITY_VIOLATION | | ||
277 | MC_INT_DECERR_EMEM; | ||
278 | mc_writel(mc, value, MC_INTMASK); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static struct platform_driver tegra_mc_driver = { | ||
284 | .driver = { | ||
285 | .name = "tegra-mc", | ||
286 | .of_match_table = tegra_mc_of_match, | ||
287 | .suppress_bind_attrs = true, | ||
288 | }, | ||
289 | .prevent_deferred_probe = true, | ||
290 | .probe = tegra_mc_probe, | ||
291 | }; | ||
292 | |||
293 | static int tegra_mc_init(void) | ||
294 | { | ||
295 | return platform_driver_register(&tegra_mc_driver); | ||
296 | } | ||
297 | arch_initcall(tegra_mc_init); | ||
298 | |||
299 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
300 | MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver"); | ||
301 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h new file mode 100644 index 000000000000..d5d21147fc77 --- /dev/null +++ b/drivers/memory/tegra/mc.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef MEMORY_TEGRA_MC_H | ||
10 | #define MEMORY_TEGRA_MC_H | ||
11 | |||
12 | #include <linux/io.h> | ||
13 | #include <linux/types.h> | ||
14 | |||
15 | #include <soc/tegra/mc.h> | ||
16 | |||
17 | static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) | ||
18 | { | ||
19 | return readl(mc->regs + offset); | ||
20 | } | ||
21 | |||
22 | static inline void mc_writel(struct tegra_mc *mc, u32 value, | ||
23 | unsigned long offset) | ||
24 | { | ||
25 | writel(value, mc->regs + offset); | ||
26 | } | ||
27 | |||
28 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
29 | extern const struct tegra_mc_soc tegra30_mc_soc; | ||
30 | #endif | ||
31 | |||
32 | #ifdef CONFIG_ARCH_TEGRA_114_SOC | ||
33 | extern const struct tegra_mc_soc tegra114_mc_soc; | ||
34 | #endif | ||
35 | |||
36 | #ifdef CONFIG_ARCH_TEGRA_124_SOC | ||
37 | extern const struct tegra_mc_soc tegra124_mc_soc; | ||
38 | #endif | ||
39 | |||
40 | #endif /* MEMORY_TEGRA_MC_H */ | ||
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c new file mode 100644 index 000000000000..511e9a25c151 --- /dev/null +++ b/drivers/memory/tegra/tegra114.c | |||
@@ -0,0 +1,948 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/of.h> | ||
10 | #include <linux/mm.h> | ||
11 | |||
12 | #include <asm/cacheflush.h> | ||
13 | |||
14 | #include <dt-bindings/memory/tegra114-mc.h> | ||
15 | |||
16 | #include "mc.h" | ||
17 | |||
18 | static const struct tegra_mc_client tegra114_mc_clients[] = { | ||
19 | { | ||
20 | .id = 0x00, | ||
21 | .name = "ptcr", | ||
22 | .swgroup = TEGRA_SWGROUP_PTC, | ||
23 | }, { | ||
24 | .id = 0x01, | ||
25 | .name = "display0a", | ||
26 | .swgroup = TEGRA_SWGROUP_DC, | ||
27 | .smmu = { | ||
28 | .reg = 0x228, | ||
29 | .bit = 1, | ||
30 | }, | ||
31 | .la = { | ||
32 | .reg = 0x2e8, | ||
33 | .shift = 0, | ||
34 | .mask = 0xff, | ||
35 | .def = 0x4e, | ||
36 | }, | ||
37 | }, { | ||
38 | .id = 0x02, | ||
39 | .name = "display0ab", | ||
40 | .swgroup = TEGRA_SWGROUP_DCB, | ||
41 | .smmu = { | ||
42 | .reg = 0x228, | ||
43 | .bit = 2, | ||
44 | }, | ||
45 | .la = { | ||
46 | .reg = 0x2f4, | ||
47 | .shift = 0, | ||
48 | .mask = 0xff, | ||
49 | .def = 0x4e, | ||
50 | }, | ||
51 | }, { | ||
52 | .id = 0x03, | ||
53 | .name = "display0b", | ||
54 | .swgroup = TEGRA_SWGROUP_DC, | ||
55 | .smmu = { | ||
56 | .reg = 0x228, | ||
57 | .bit = 3, | ||
58 | }, | ||
59 | .la = { | ||
60 | .reg = 0x2e8, | ||
61 | .shift = 16, | ||
62 | .mask = 0xff, | ||
63 | .def = 0x4e, | ||
64 | }, | ||
65 | }, { | ||
66 | .id = 0x04, | ||
67 | .name = "display0bb", | ||
68 | .swgroup = TEGRA_SWGROUP_DCB, | ||
69 | .smmu = { | ||
70 | .reg = 0x228, | ||
71 | .bit = 4, | ||
72 | }, | ||
73 | .la = { | ||
74 | .reg = 0x2f4, | ||
75 | .shift = 16, | ||
76 | .mask = 0xff, | ||
77 | .def = 0x4e, | ||
78 | }, | ||
79 | }, { | ||
80 | .id = 0x05, | ||
81 | .name = "display0c", | ||
82 | .swgroup = TEGRA_SWGROUP_DC, | ||
83 | .smmu = { | ||
84 | .reg = 0x228, | ||
85 | .bit = 5, | ||
86 | }, | ||
87 | .la = { | ||
88 | .reg = 0x2ec, | ||
89 | .shift = 0, | ||
90 | .mask = 0xff, | ||
91 | .def = 0x4e, | ||
92 | }, | ||
93 | }, { | ||
94 | .id = 0x06, | ||
95 | .name = "display0cb", | ||
96 | .swgroup = TEGRA_SWGROUP_DCB, | ||
97 | .smmu = { | ||
98 | .reg = 0x228, | ||
99 | .bit = 6, | ||
100 | }, | ||
101 | .la = { | ||
102 | .reg = 0x2f8, | ||
103 | .shift = 0, | ||
104 | .mask = 0xff, | ||
105 | .def = 0x4e, | ||
106 | }, | ||
107 | }, { | ||
108 | .id = 0x09, | ||
109 | .name = "eppup", | ||
110 | .swgroup = TEGRA_SWGROUP_EPP, | ||
111 | .smmu = { | ||
112 | .reg = 0x228, | ||
113 | .bit = 9, | ||
114 | }, | ||
115 | .la = { | ||
116 | .reg = 0x300, | ||
117 | .shift = 0, | ||
118 | .mask = 0xff, | ||
119 | .def = 0x33, | ||
120 | }, | ||
121 | }, { | ||
122 | .id = 0x0a, | ||
123 | .name = "g2pr", | ||
124 | .swgroup = TEGRA_SWGROUP_G2, | ||
125 | .smmu = { | ||
126 | .reg = 0x228, | ||
127 | .bit = 10, | ||
128 | }, | ||
129 | .la = { | ||
130 | .reg = 0x308, | ||
131 | .shift = 0, | ||
132 | .mask = 0xff, | ||
133 | .def = 0x09, | ||
134 | }, | ||
135 | }, { | ||
136 | .id = 0x0b, | ||
137 | .name = "g2sr", | ||
138 | .swgroup = TEGRA_SWGROUP_G2, | ||
139 | .smmu = { | ||
140 | .reg = 0x228, | ||
141 | .bit = 11, | ||
142 | }, | ||
143 | .la = { | ||
144 | .reg = 0x308, | ||
145 | .shift = 16, | ||
146 | .mask = 0xff, | ||
147 | .def = 0x09, | ||
148 | }, | ||
149 | }, { | ||
150 | .id = 0x0f, | ||
151 | .name = "avpcarm7r", | ||
152 | .swgroup = TEGRA_SWGROUP_AVPC, | ||
153 | .smmu = { | ||
154 | .reg = 0x228, | ||
155 | .bit = 15, | ||
156 | }, | ||
157 | .la = { | ||
158 | .reg = 0x2e4, | ||
159 | .shift = 0, | ||
160 | .mask = 0xff, | ||
161 | .def = 0x04, | ||
162 | }, | ||
163 | }, { | ||
164 | .id = 0x10, | ||
165 | .name = "displayhc", | ||
166 | .swgroup = TEGRA_SWGROUP_DC, | ||
167 | .smmu = { | ||
168 | .reg = 0x228, | ||
169 | .bit = 16, | ||
170 | }, | ||
171 | .la = { | ||
172 | .reg = 0x2f0, | ||
173 | .shift = 0, | ||
174 | .mask = 0xff, | ||
175 | .def = 0x68, | ||
176 | }, | ||
177 | }, { | ||
178 | .id = 0x11, | ||
179 | .name = "displayhcb", | ||
180 | .swgroup = TEGRA_SWGROUP_DCB, | ||
181 | .smmu = { | ||
182 | .reg = 0x228, | ||
183 | .bit = 17, | ||
184 | }, | ||
185 | .la = { | ||
186 | .reg = 0x2fc, | ||
187 | .shift = 0, | ||
188 | .mask = 0xff, | ||
189 | .def = 0x68, | ||
190 | }, | ||
191 | }, { | ||
192 | .id = 0x12, | ||
193 | .name = "fdcdrd", | ||
194 | .swgroup = TEGRA_SWGROUP_NV, | ||
195 | .smmu = { | ||
196 | .reg = 0x228, | ||
197 | .bit = 18, | ||
198 | }, | ||
199 | .la = { | ||
200 | .reg = 0x334, | ||
201 | .shift = 0, | ||
202 | .mask = 0xff, | ||
203 | .def = 0x0c, | ||
204 | }, | ||
205 | }, { | ||
206 | .id = 0x13, | ||
207 | .name = "fdcdrd2", | ||
208 | .swgroup = TEGRA_SWGROUP_NV, | ||
209 | .smmu = { | ||
210 | .reg = 0x228, | ||
211 | .bit = 19, | ||
212 | }, | ||
213 | .la = { | ||
214 | .reg = 0x33c, | ||
215 | .shift = 0, | ||
216 | .mask = 0xff, | ||
217 | .def = 0x0c, | ||
218 | }, | ||
219 | }, { | ||
220 | .id = 0x14, | ||
221 | .name = "g2dr", | ||
222 | .swgroup = TEGRA_SWGROUP_G2, | ||
223 | .smmu = { | ||
224 | .reg = 0x228, | ||
225 | .bit = 20, | ||
226 | }, | ||
227 | .la = { | ||
228 | .reg = 0x30c, | ||
229 | .shift = 0, | ||
230 | .mask = 0xff, | ||
231 | .def = 0x0a, | ||
232 | }, | ||
233 | }, { | ||
234 | .id = 0x15, | ||
235 | .name = "hdar", | ||
236 | .swgroup = TEGRA_SWGROUP_HDA, | ||
237 | .smmu = { | ||
238 | .reg = 0x228, | ||
239 | .bit = 21, | ||
240 | }, | ||
241 | .la = { | ||
242 | .reg = 0x318, | ||
243 | .shift = 0, | ||
244 | .mask = 0xff, | ||
245 | .def = 0xff, | ||
246 | }, | ||
247 | }, { | ||
248 | .id = 0x16, | ||
249 | .name = "host1xdmar", | ||
250 | .swgroup = TEGRA_SWGROUP_HC, | ||
251 | .smmu = { | ||
252 | .reg = 0x228, | ||
253 | .bit = 22, | ||
254 | }, | ||
255 | .la = { | ||
256 | .reg = 0x310, | ||
257 | .shift = 0, | ||
258 | .mask = 0xff, | ||
259 | .def = 0x10, | ||
260 | }, | ||
261 | }, { | ||
262 | .id = 0x17, | ||
263 | .name = "host1xr", | ||
264 | .swgroup = TEGRA_SWGROUP_HC, | ||
265 | .smmu = { | ||
266 | .reg = 0x228, | ||
267 | .bit = 23, | ||
268 | }, | ||
269 | .la = { | ||
270 | .reg = 0x310, | ||
271 | .shift = 16, | ||
272 | .mask = 0xff, | ||
273 | .def = 0xa5, | ||
274 | }, | ||
275 | }, { | ||
276 | .id = 0x18, | ||
277 | .name = "idxsrd", | ||
278 | .swgroup = TEGRA_SWGROUP_NV, | ||
279 | .smmu = { | ||
280 | .reg = 0x228, | ||
281 | .bit = 24, | ||
282 | }, | ||
283 | .la = { | ||
284 | .reg = 0x334, | ||
285 | .shift = 16, | ||
286 | .mask = 0xff, | ||
287 | .def = 0x0b, | ||
288 | }, | ||
289 | }, { | ||
290 | .id = 0x1c, | ||
291 | .name = "msencsrd", | ||
292 | .swgroup = TEGRA_SWGROUP_MSENC, | ||
293 | .smmu = { | ||
294 | .reg = 0x228, | ||
295 | .bit = 28, | ||
296 | }, | ||
297 | .la = { | ||
298 | .reg = 0x328, | ||
299 | .shift = 0, | ||
300 | .mask = 0xff, | ||
301 | .def = 0x80, | ||
302 | }, | ||
303 | }, { | ||
304 | .id = 0x1d, | ||
305 | .name = "ppcsahbdmar", | ||
306 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
307 | .smmu = { | ||
308 | .reg = 0x228, | ||
309 | .bit = 29, | ||
310 | }, | ||
311 | .la = { | ||
312 | .reg = 0x344, | ||
313 | .shift = 0, | ||
314 | .mask = 0xff, | ||
315 | .def = 0x50, | ||
316 | }, | ||
317 | }, { | ||
318 | .id = 0x1e, | ||
319 | .name = "ppcsahbslvr", | ||
320 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
321 | .smmu = { | ||
322 | .reg = 0x228, | ||
323 | .bit = 30, | ||
324 | }, | ||
325 | .la = { | ||
326 | .reg = 0x344, | ||
327 | .shift = 16, | ||
328 | .mask = 0xff, | ||
329 | .def = 0xe8, | ||
330 | }, | ||
331 | }, { | ||
332 | .id = 0x20, | ||
333 | .name = "texl2srd", | ||
334 | .swgroup = TEGRA_SWGROUP_NV, | ||
335 | .smmu = { | ||
336 | .reg = 0x22c, | ||
337 | .bit = 0, | ||
338 | }, | ||
339 | .la = { | ||
340 | .reg = 0x338, | ||
341 | .shift = 0, | ||
342 | .mask = 0xff, | ||
343 | .def = 0x0c, | ||
344 | }, | ||
345 | }, { | ||
346 | .id = 0x22, | ||
347 | .name = "vdebsevr", | ||
348 | .swgroup = TEGRA_SWGROUP_VDE, | ||
349 | .smmu = { | ||
350 | .reg = 0x22c, | ||
351 | .bit = 2, | ||
352 | }, | ||
353 | .la = { | ||
354 | .reg = 0x354, | ||
355 | .shift = 0, | ||
356 | .mask = 0xff, | ||
357 | .def = 0xff, | ||
358 | }, | ||
359 | }, { | ||
360 | .id = 0x23, | ||
361 | .name = "vdember", | ||
362 | .swgroup = TEGRA_SWGROUP_VDE, | ||
363 | .smmu = { | ||
364 | .reg = 0x22c, | ||
365 | .bit = 3, | ||
366 | }, | ||
367 | .la = { | ||
368 | .reg = 0x354, | ||
369 | .shift = 16, | ||
370 | .mask = 0xff, | ||
371 | .def = 0xff, | ||
372 | }, | ||
373 | }, { | ||
374 | .id = 0x24, | ||
375 | .name = "vdemcer", | ||
376 | .swgroup = TEGRA_SWGROUP_VDE, | ||
377 | .smmu = { | ||
378 | .reg = 0x22c, | ||
379 | .bit = 4, | ||
380 | }, | ||
381 | .la = { | ||
382 | .reg = 0x358, | ||
383 | .shift = 0, | ||
384 | .mask = 0xff, | ||
385 | .def = 0xb8, | ||
386 | }, | ||
387 | }, { | ||
388 | .id = 0x25, | ||
389 | .name = "vdetper", | ||
390 | .swgroup = TEGRA_SWGROUP_VDE, | ||
391 | .smmu = { | ||
392 | .reg = 0x22c, | ||
393 | .bit = 5, | ||
394 | }, | ||
395 | .la = { | ||
396 | .reg = 0x358, | ||
397 | .shift = 16, | ||
398 | .mask = 0xff, | ||
399 | .def = 0xee, | ||
400 | }, | ||
401 | }, { | ||
402 | .id = 0x26, | ||
403 | .name = "mpcorelpr", | ||
404 | .swgroup = TEGRA_SWGROUP_MPCORELP, | ||
405 | .la = { | ||
406 | .reg = 0x324, | ||
407 | .shift = 0, | ||
408 | .mask = 0xff, | ||
409 | .def = 0x04, | ||
410 | }, | ||
411 | }, { | ||
412 | .id = 0x27, | ||
413 | .name = "mpcorer", | ||
414 | .swgroup = TEGRA_SWGROUP_MPCORE, | ||
415 | .la = { | ||
416 | .reg = 0x320, | ||
417 | .shift = 0, | ||
418 | .mask = 0xff, | ||
419 | .def = 0x04, | ||
420 | }, | ||
421 | }, { | ||
422 | .id = 0x28, | ||
423 | .name = "eppu", | ||
424 | .swgroup = TEGRA_SWGROUP_EPP, | ||
425 | .smmu = { | ||
426 | .reg = 0x22c, | ||
427 | .bit = 8, | ||
428 | }, | ||
429 | .la = { | ||
430 | .reg = 0x300, | ||
431 | .shift = 16, | ||
432 | .mask = 0xff, | ||
433 | .def = 0x33, | ||
434 | }, | ||
435 | }, { | ||
436 | .id = 0x29, | ||
437 | .name = "eppv", | ||
438 | .swgroup = TEGRA_SWGROUP_EPP, | ||
439 | .smmu = { | ||
440 | .reg = 0x22c, | ||
441 | .bit = 9, | ||
442 | }, | ||
443 | .la = { | ||
444 | .reg = 0x304, | ||
445 | .shift = 0, | ||
446 | .mask = 0xff, | ||
447 | .def = 0x6c, | ||
448 | }, | ||
449 | }, { | ||
450 | .id = 0x2a, | ||
451 | .name = "eppy", | ||
452 | .swgroup = TEGRA_SWGROUP_EPP, | ||
453 | .smmu = { | ||
454 | .reg = 0x22c, | ||
455 | .bit = 10, | ||
456 | }, | ||
457 | .la = { | ||
458 | .reg = 0x304, | ||
459 | .shift = 16, | ||
460 | .mask = 0xff, | ||
461 | .def = 0x6c, | ||
462 | }, | ||
463 | }, { | ||
464 | .id = 0x2b, | ||
465 | .name = "msencswr", | ||
466 | .swgroup = TEGRA_SWGROUP_MSENC, | ||
467 | .smmu = { | ||
468 | .reg = 0x22c, | ||
469 | .bit = 11, | ||
470 | }, | ||
471 | .la = { | ||
472 | .reg = 0x328, | ||
473 | .shift = 16, | ||
474 | .mask = 0xff, | ||
475 | .def = 0x80, | ||
476 | }, | ||
477 | }, { | ||
478 | .id = 0x2c, | ||
479 | .name = "viwsb", | ||
480 | .swgroup = TEGRA_SWGROUP_VI, | ||
481 | .smmu = { | ||
482 | .reg = 0x22c, | ||
483 | .bit = 12, | ||
484 | }, | ||
485 | .la = { | ||
486 | .reg = 0x364, | ||
487 | .shift = 0, | ||
488 | .mask = 0xff, | ||
489 | .def = 0x47, | ||
490 | }, | ||
491 | }, { | ||
492 | .id = 0x2d, | ||
493 | .name = "viwu", | ||
494 | .swgroup = TEGRA_SWGROUP_VI, | ||
495 | .smmu = { | ||
496 | .reg = 0x22c, | ||
497 | .bit = 13, | ||
498 | }, | ||
499 | .la = { | ||
500 | .reg = 0x368, | ||
501 | .shift = 0, | ||
502 | .mask = 0xff, | ||
503 | .def = 0xff, | ||
504 | }, | ||
505 | }, { | ||
506 | .id = 0x2e, | ||
507 | .name = "viwv", | ||
508 | .swgroup = TEGRA_SWGROUP_VI, | ||
509 | .smmu = { | ||
510 | .reg = 0x22c, | ||
511 | .bit = 14, | ||
512 | }, | ||
513 | .la = { | ||
514 | .reg = 0x368, | ||
515 | .shift = 16, | ||
516 | .mask = 0xff, | ||
517 | .def = 0xff, | ||
518 | }, | ||
519 | }, { | ||
520 | .id = 0x2f, | ||
521 | .name = "viwy", | ||
522 | .swgroup = TEGRA_SWGROUP_VI, | ||
523 | .smmu = { | ||
524 | .reg = 0x22c, | ||
525 | .bit = 15, | ||
526 | }, | ||
527 | .la = { | ||
528 | .reg = 0x36c, | ||
529 | .shift = 0, | ||
530 | .mask = 0xff, | ||
531 | .def = 0x47, | ||
532 | }, | ||
533 | }, { | ||
534 | .id = 0x30, | ||
535 | .name = "g2dw", | ||
536 | .swgroup = TEGRA_SWGROUP_G2, | ||
537 | .smmu = { | ||
538 | .reg = 0x22c, | ||
539 | .bit = 16, | ||
540 | }, | ||
541 | .la = { | ||
542 | .reg = 0x30c, | ||
543 | .shift = 16, | ||
544 | .mask = 0xff, | ||
545 | .def = 0x9, | ||
546 | }, | ||
547 | }, { | ||
548 | .id = 0x32, | ||
549 | .name = "avpcarm7w", | ||
550 | .swgroup = TEGRA_SWGROUP_AVPC, | ||
551 | .smmu = { | ||
552 | .reg = 0x22c, | ||
553 | .bit = 18, | ||
554 | }, | ||
555 | .la = { | ||
556 | .reg = 0x2e4, | ||
557 | .shift = 16, | ||
558 | .mask = 0xff, | ||
559 | .def = 0x0e, | ||
560 | }, | ||
561 | }, { | ||
562 | .id = 0x33, | ||
563 | .name = "fdcdwr", | ||
564 | .swgroup = TEGRA_SWGROUP_NV, | ||
565 | .smmu = { | ||
566 | .reg = 0x22c, | ||
567 | .bit = 19, | ||
568 | }, | ||
569 | .la = { | ||
570 | .reg = 0x338, | ||
571 | .shift = 16, | ||
572 | .mask = 0xff, | ||
573 | .def = 0x10, | ||
574 | }, | ||
575 | }, { | ||
576 | .id = 0x34, | ||
577 | .name = "fdcwr2", | ||
578 | .swgroup = TEGRA_SWGROUP_NV, | ||
579 | .smmu = { | ||
580 | .reg = 0x22c, | ||
581 | .bit = 20, | ||
582 | }, | ||
583 | .la = { | ||
584 | .reg = 0x340, | ||
585 | .shift = 0, | ||
586 | .mask = 0xff, | ||
587 | .def = 0x10, | ||
588 | }, | ||
589 | }, { | ||
590 | .id = 0x35, | ||
591 | .name = "hdaw", | ||
592 | .swgroup = TEGRA_SWGROUP_HDA, | ||
593 | .smmu = { | ||
594 | .reg = 0x22c, | ||
595 | .bit = 21, | ||
596 | }, | ||
597 | .la = { | ||
598 | .reg = 0x318, | ||
599 | .shift = 16, | ||
600 | .mask = 0xff, | ||
601 | .def = 0xff, | ||
602 | }, | ||
603 | }, { | ||
604 | .id = 0x36, | ||
605 | .name = "host1xw", | ||
606 | .swgroup = TEGRA_SWGROUP_HC, | ||
607 | .smmu = { | ||
608 | .reg = 0x22c, | ||
609 | .bit = 22, | ||
610 | }, | ||
611 | .la = { | ||
612 | .reg = 0x314, | ||
613 | .shift = 0, | ||
614 | .mask = 0xff, | ||
615 | .def = 0x25, | ||
616 | }, | ||
617 | }, { | ||
618 | .id = 0x37, | ||
619 | .name = "ispw", | ||
620 | .swgroup = TEGRA_SWGROUP_ISP, | ||
621 | .smmu = { | ||
622 | .reg = 0x22c, | ||
623 | .bit = 23, | ||
624 | }, | ||
625 | .la = { | ||
626 | .reg = 0x31c, | ||
627 | .shift = 0, | ||
628 | .mask = 0xff, | ||
629 | .def = 0xff, | ||
630 | }, | ||
631 | }, { | ||
632 | .id = 0x38, | ||
633 | .name = "mpcorelpw", | ||
634 | .swgroup = TEGRA_SWGROUP_MPCORELP, | ||
635 | .la = { | ||
636 | .reg = 0x324, | ||
637 | .shift = 16, | ||
638 | .mask = 0xff, | ||
639 | .def = 0x80, | ||
640 | }, | ||
641 | }, { | ||
642 | .id = 0x39, | ||
643 | .name = "mpcorew", | ||
644 | .swgroup = TEGRA_SWGROUP_MPCORE, | ||
645 | .la = { | ||
646 | .reg = 0x320, | ||
647 | .shift = 16, | ||
648 | .mask = 0xff, | ||
649 | .def = 0x0e, | ||
650 | }, | ||
651 | }, { | ||
652 | .id = 0x3b, | ||
653 | .name = "ppcsahbdmaw", | ||
654 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
655 | .smmu = { | ||
656 | .reg = 0x22c, | ||
657 | .bit = 27, | ||
658 | }, | ||
659 | .la = { | ||
660 | .reg = 0x348, | ||
661 | .shift = 0, | ||
662 | .mask = 0xff, | ||
663 | .def = 0xa5, | ||
664 | }, | ||
665 | }, { | ||
666 | .id = 0x3c, | ||
667 | .name = "ppcsahbslvw", | ||
668 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
669 | .smmu = { | ||
670 | .reg = 0x22c, | ||
671 | .bit = 28, | ||
672 | }, | ||
673 | .la = { | ||
674 | .reg = 0x348, | ||
675 | .shift = 16, | ||
676 | .mask = 0xff, | ||
677 | .def = 0xe8, | ||
678 | }, | ||
679 | }, { | ||
680 | .id = 0x3e, | ||
681 | .name = "vdebsevw", | ||
682 | .swgroup = TEGRA_SWGROUP_VDE, | ||
683 | .smmu = { | ||
684 | .reg = 0x22c, | ||
685 | .bit = 30, | ||
686 | }, | ||
687 | .la = { | ||
688 | .reg = 0x35c, | ||
689 | .shift = 0, | ||
690 | .mask = 0xff, | ||
691 | .def = 0xff, | ||
692 | }, | ||
693 | }, { | ||
694 | .id = 0x3f, | ||
695 | .name = "vdedbgw", | ||
696 | .swgroup = TEGRA_SWGROUP_VDE, | ||
697 | .smmu = { | ||
698 | .reg = 0x22c, | ||
699 | .bit = 31, | ||
700 | }, | ||
701 | .la = { | ||
702 | .reg = 0x35c, | ||
703 | .shift = 16, | ||
704 | .mask = 0xff, | ||
705 | .def = 0xff, | ||
706 | }, | ||
707 | }, { | ||
708 | .id = 0x40, | ||
709 | .name = "vdembew", | ||
710 | .swgroup = TEGRA_SWGROUP_VDE, | ||
711 | .smmu = { | ||
712 | .reg = 0x230, | ||
713 | .bit = 0, | ||
714 | }, | ||
715 | .la = { | ||
716 | .reg = 0x360, | ||
717 | .shift = 0, | ||
718 | .mask = 0xff, | ||
719 | .def = 0x89, | ||
720 | }, | ||
721 | }, { | ||
722 | .id = 0x41, | ||
723 | .name = "vdetpmw", | ||
724 | .swgroup = TEGRA_SWGROUP_VDE, | ||
725 | .smmu = { | ||
726 | .reg = 0x230, | ||
727 | .bit = 1, | ||
728 | }, | ||
729 | .la = { | ||
730 | .reg = 0x360, | ||
731 | .shift = 16, | ||
732 | .mask = 0xff, | ||
733 | .def = 0x59, | ||
734 | }, | ||
735 | }, { | ||
736 | .id = 0x4a, | ||
737 | .name = "xusb_hostr", | ||
738 | .swgroup = TEGRA_SWGROUP_XUSB_HOST, | ||
739 | .smmu = { | ||
740 | .reg = 0x230, | ||
741 | .bit = 10, | ||
742 | }, | ||
743 | .la = { | ||
744 | .reg = 0x37c, | ||
745 | .shift = 0, | ||
746 | .mask = 0xff, | ||
747 | .def = 0xa5, | ||
748 | }, | ||
749 | }, { | ||
750 | .id = 0x4b, | ||
751 | .name = "xusb_hostw", | ||
752 | .swgroup = TEGRA_SWGROUP_XUSB_HOST, | ||
753 | .smmu = { | ||
754 | .reg = 0x230, | ||
755 | .bit = 11, | ||
756 | }, | ||
757 | .la = { | ||
758 | .reg = 0x37c, | ||
759 | .shift = 16, | ||
760 | .mask = 0xff, | ||
761 | .def = 0xa5, | ||
762 | }, | ||
763 | }, { | ||
764 | .id = 0x4c, | ||
765 | .name = "xusb_devr", | ||
766 | .swgroup = TEGRA_SWGROUP_XUSB_DEV, | ||
767 | .smmu = { | ||
768 | .reg = 0x230, | ||
769 | .bit = 12, | ||
770 | }, | ||
771 | .la = { | ||
772 | .reg = 0x380, | ||
773 | .shift = 0, | ||
774 | .mask = 0xff, | ||
775 | .def = 0xa5, | ||
776 | }, | ||
777 | }, { | ||
778 | .id = 0x4d, | ||
779 | .name = "xusb_devw", | ||
780 | .swgroup = TEGRA_SWGROUP_XUSB_DEV, | ||
781 | .smmu = { | ||
782 | .reg = 0x230, | ||
783 | .bit = 13, | ||
784 | }, | ||
785 | .la = { | ||
786 | .reg = 0x380, | ||
787 | .shift = 16, | ||
788 | .mask = 0xff, | ||
789 | .def = 0xa5, | ||
790 | }, | ||
791 | }, { | ||
792 | .id = 0x4e, | ||
793 | .name = "fdcdwr3", | ||
794 | .swgroup = TEGRA_SWGROUP_NV, | ||
795 | .smmu = { | ||
796 | .reg = 0x230, | ||
797 | .bit = 14, | ||
798 | }, | ||
799 | .la = { | ||
800 | .reg = 0x388, | ||
801 | .shift = 0, | ||
802 | .mask = 0xff, | ||
803 | .def = 0x10, | ||
804 | }, | ||
805 | }, { | ||
806 | .id = 0x4f, | ||
807 | .name = "fdcdrd3", | ||
808 | .swgroup = TEGRA_SWGROUP_NV, | ||
809 | .smmu = { | ||
810 | .reg = 0x230, | ||
811 | .bit = 15, | ||
812 | }, | ||
813 | .la = { | ||
814 | .reg = 0x384, | ||
815 | .shift = 0, | ||
816 | .mask = 0xff, | ||
817 | .def = 0x0c, | ||
818 | }, | ||
819 | }, { | ||
820 | .id = 0x50, | ||
821 | .name = "fdcwr4", | ||
822 | .swgroup = TEGRA_SWGROUP_NV, | ||
823 | .smmu = { | ||
824 | .reg = 0x230, | ||
825 | .bit = 16, | ||
826 | }, | ||
827 | .la = { | ||
828 | .reg = 0x388, | ||
829 | .shift = 16, | ||
830 | .mask = 0xff, | ||
831 | .def = 0x10, | ||
832 | }, | ||
833 | }, { | ||
834 | .id = 0x51, | ||
835 | .name = "fdcrd4", | ||
836 | .swgroup = TEGRA_SWGROUP_NV, | ||
837 | .smmu = { | ||
838 | .reg = 0x230, | ||
839 | .bit = 17, | ||
840 | }, | ||
841 | .la = { | ||
842 | .reg = 0x384, | ||
843 | .shift = 16, | ||
844 | .mask = 0xff, | ||
845 | .def = 0x0c, | ||
846 | }, | ||
847 | }, { | ||
848 | .id = 0x52, | ||
849 | .name = "emucifr", | ||
850 | .swgroup = TEGRA_SWGROUP_EMUCIF, | ||
851 | .la = { | ||
852 | .reg = 0x38c, | ||
853 | .shift = 0, | ||
854 | .mask = 0xff, | ||
855 | .def = 0x04, | ||
856 | }, | ||
857 | }, { | ||
858 | .id = 0x53, | ||
859 | .name = "emucifw", | ||
860 | .swgroup = TEGRA_SWGROUP_EMUCIF, | ||
861 | .la = { | ||
862 | .reg = 0x38c, | ||
863 | .shift = 16, | ||
864 | .mask = 0xff, | ||
865 | .def = 0x0e, | ||
866 | }, | ||
867 | }, { | ||
868 | .id = 0x54, | ||
869 | .name = "tsecsrd", | ||
870 | .swgroup = TEGRA_SWGROUP_TSEC, | ||
871 | .smmu = { | ||
872 | .reg = 0x230, | ||
873 | .bit = 20, | ||
874 | }, | ||
875 | .la = { | ||
876 | .reg = 0x390, | ||
877 | .shift = 0, | ||
878 | .mask = 0xff, | ||
879 | .def = 0x50, | ||
880 | }, | ||
881 | }, { | ||
882 | .id = 0x55, | ||
883 | .name = "tsecswr", | ||
884 | .swgroup = TEGRA_SWGROUP_TSEC, | ||
885 | .smmu = { | ||
886 | .reg = 0x230, | ||
887 | .bit = 21, | ||
888 | }, | ||
889 | .la = { | ||
890 | .reg = 0x390, | ||
891 | .shift = 16, | ||
892 | .mask = 0xff, | ||
893 | .def = 0x50, | ||
894 | }, | ||
895 | }, | ||
896 | }; | ||
897 | |||
898 | static const struct tegra_smmu_swgroup tegra114_swgroups[] = { | ||
899 | { .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 }, | ||
900 | { .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 }, | ||
901 | { .swgroup = TEGRA_SWGROUP_EPP, .reg = 0x248 }, | ||
902 | { .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c }, | ||
903 | { .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c }, | ||
904 | { .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268 }, | ||
905 | { .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 }, | ||
906 | { .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 }, | ||
907 | { .swgroup = TEGRA_SWGROUP_MSENC, .reg = 0x264 }, | ||
908 | { .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 }, | ||
909 | { .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c }, | ||
910 | { .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 }, | ||
911 | { .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 }, | ||
912 | { .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 }, | ||
913 | { .swgroup = TEGRA_SWGROUP_XUSB_DEV, .reg = 0x28c }, | ||
914 | { .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 }, | ||
915 | }; | ||
916 | |||
917 | static void tegra114_flush_dcache(struct page *page, unsigned long offset, | ||
918 | size_t size) | ||
919 | { | ||
920 | phys_addr_t phys = page_to_phys(page) + offset; | ||
921 | void *virt = page_address(page) + offset; | ||
922 | |||
923 | __cpuc_flush_dcache_area(virt, size); | ||
924 | outer_flush_range(phys, phys + size); | ||
925 | } | ||
926 | |||
927 | static const struct tegra_smmu_ops tegra114_smmu_ops = { | ||
928 | .flush_dcache = tegra114_flush_dcache, | ||
929 | }; | ||
930 | |||
931 | static const struct tegra_smmu_soc tegra114_smmu_soc = { | ||
932 | .clients = tegra114_mc_clients, | ||
933 | .num_clients = ARRAY_SIZE(tegra114_mc_clients), | ||
934 | .swgroups = tegra114_swgroups, | ||
935 | .num_swgroups = ARRAY_SIZE(tegra114_swgroups), | ||
936 | .supports_round_robin_arbitration = false, | ||
937 | .supports_request_limit = false, | ||
938 | .num_asids = 4, | ||
939 | .ops = &tegra114_smmu_ops, | ||
940 | }; | ||
941 | |||
942 | const struct tegra_mc_soc tegra114_mc_soc = { | ||
943 | .clients = tegra114_mc_clients, | ||
944 | .num_clients = ARRAY_SIZE(tegra114_mc_clients), | ||
945 | .num_address_bits = 32, | ||
946 | .atom_size = 32, | ||
947 | .smmu = &tegra114_smmu_soc, | ||
948 | }; | ||
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c new file mode 100644 index 000000000000..278d40b854c1 --- /dev/null +++ b/drivers/memory/tegra/tegra124.c | |||
@@ -0,0 +1,995 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/of.h> | ||
10 | #include <linux/mm.h> | ||
11 | |||
12 | #include <asm/cacheflush.h> | ||
13 | |||
14 | #include <dt-bindings/memory/tegra124-mc.h> | ||
15 | |||
16 | #include "mc.h" | ||
17 | |||
18 | static const struct tegra_mc_client tegra124_mc_clients[] = { | ||
19 | { | ||
20 | .id = 0x00, | ||
21 | .name = "ptcr", | ||
22 | .swgroup = TEGRA_SWGROUP_PTC, | ||
23 | }, { | ||
24 | .id = 0x01, | ||
25 | .name = "display0a", | ||
26 | .swgroup = TEGRA_SWGROUP_DC, | ||
27 | .smmu = { | ||
28 | .reg = 0x228, | ||
29 | .bit = 1, | ||
30 | }, | ||
31 | .la = { | ||
32 | .reg = 0x2e8, | ||
33 | .shift = 0, | ||
34 | .mask = 0xff, | ||
35 | .def = 0xc2, | ||
36 | }, | ||
37 | }, { | ||
38 | .id = 0x02, | ||
39 | .name = "display0ab", | ||
40 | .swgroup = TEGRA_SWGROUP_DCB, | ||
41 | .smmu = { | ||
42 | .reg = 0x228, | ||
43 | .bit = 2, | ||
44 | }, | ||
45 | .la = { | ||
46 | .reg = 0x2f4, | ||
47 | .shift = 0, | ||
48 | .mask = 0xff, | ||
49 | .def = 0xc6, | ||
50 | }, | ||
51 | }, { | ||
52 | .id = 0x03, | ||
53 | .name = "display0b", | ||
54 | .swgroup = TEGRA_SWGROUP_DC, | ||
55 | .smmu = { | ||
56 | .reg = 0x228, | ||
57 | .bit = 3, | ||
58 | }, | ||
59 | .la = { | ||
60 | .reg = 0x2e8, | ||
61 | .shift = 16, | ||
62 | .mask = 0xff, | ||
63 | .def = 0x50, | ||
64 | }, | ||
65 | }, { | ||
66 | .id = 0x04, | ||
67 | .name = "display0bb", | ||
68 | .swgroup = TEGRA_SWGROUP_DCB, | ||
69 | .smmu = { | ||
70 | .reg = 0x228, | ||
71 | .bit = 4, | ||
72 | }, | ||
73 | .la = { | ||
74 | .reg = 0x2f4, | ||
75 | .shift = 16, | ||
76 | .mask = 0xff, | ||
77 | .def = 0x50, | ||
78 | }, | ||
79 | }, { | ||
80 | .id = 0x05, | ||
81 | .name = "display0c", | ||
82 | .swgroup = TEGRA_SWGROUP_DC, | ||
83 | .smmu = { | ||
84 | .reg = 0x228, | ||
85 | .bit = 5, | ||
86 | }, | ||
87 | .la = { | ||
88 | .reg = 0x2ec, | ||
89 | .shift = 0, | ||
90 | .mask = 0xff, | ||
91 | .def = 0x50, | ||
92 | }, | ||
93 | }, { | ||
94 | .id = 0x06, | ||
95 | .name = "display0cb", | ||
96 | .swgroup = TEGRA_SWGROUP_DCB, | ||
97 | .smmu = { | ||
98 | .reg = 0x228, | ||
99 | .bit = 6, | ||
100 | }, | ||
101 | .la = { | ||
102 | .reg = 0x2f8, | ||
103 | .shift = 0, | ||
104 | .mask = 0xff, | ||
105 | .def = 0x50, | ||
106 | }, | ||
107 | }, { | ||
108 | .id = 0x0e, | ||
109 | .name = "afir", | ||
110 | .swgroup = TEGRA_SWGROUP_AFI, | ||
111 | .smmu = { | ||
112 | .reg = 0x228, | ||
113 | .bit = 14, | ||
114 | }, | ||
115 | .la = { | ||
116 | .reg = 0x2e0, | ||
117 | .shift = 0, | ||
118 | .mask = 0xff, | ||
119 | .def = 0x13, | ||
120 | }, | ||
121 | }, { | ||
122 | .id = 0x0f, | ||
123 | .name = "avpcarm7r", | ||
124 | .swgroup = TEGRA_SWGROUP_AVPC, | ||
125 | .smmu = { | ||
126 | .reg = 0x228, | ||
127 | .bit = 15, | ||
128 | }, | ||
129 | .la = { | ||
130 | .reg = 0x2e4, | ||
131 | .shift = 0, | ||
132 | .mask = 0xff, | ||
133 | .def = 0x04, | ||
134 | }, | ||
135 | }, { | ||
136 | .id = 0x10, | ||
137 | .name = "displayhc", | ||
138 | .swgroup = TEGRA_SWGROUP_DC, | ||
139 | .smmu = { | ||
140 | .reg = 0x228, | ||
141 | .bit = 16, | ||
142 | }, | ||
143 | .la = { | ||
144 | .reg = 0x2f0, | ||
145 | .shift = 0, | ||
146 | .mask = 0xff, | ||
147 | .def = 0x50, | ||
148 | }, | ||
149 | }, { | ||
150 | .id = 0x11, | ||
151 | .name = "displayhcb", | ||
152 | .swgroup = TEGRA_SWGROUP_DCB, | ||
153 | .smmu = { | ||
154 | .reg = 0x228, | ||
155 | .bit = 17, | ||
156 | }, | ||
157 | .la = { | ||
158 | .reg = 0x2fc, | ||
159 | .shift = 0, | ||
160 | .mask = 0xff, | ||
161 | .def = 0x50, | ||
162 | }, | ||
163 | }, { | ||
164 | .id = 0x15, | ||
165 | .name = "hdar", | ||
166 | .swgroup = TEGRA_SWGROUP_HDA, | ||
167 | .smmu = { | ||
168 | .reg = 0x228, | ||
169 | .bit = 21, | ||
170 | }, | ||
171 | .la = { | ||
172 | .reg = 0x318, | ||
173 | .shift = 0, | ||
174 | .mask = 0xff, | ||
175 | .def = 0x24, | ||
176 | }, | ||
177 | }, { | ||
178 | .id = 0x16, | ||
179 | .name = "host1xdmar", | ||
180 | .swgroup = TEGRA_SWGROUP_HC, | ||
181 | .smmu = { | ||
182 | .reg = 0x228, | ||
183 | .bit = 22, | ||
184 | }, | ||
185 | .la = { | ||
186 | .reg = 0x310, | ||
187 | .shift = 0, | ||
188 | .mask = 0xff, | ||
189 | .def = 0x1e, | ||
190 | }, | ||
191 | }, { | ||
192 | .id = 0x17, | ||
193 | .name = "host1xr", | ||
194 | .swgroup = TEGRA_SWGROUP_HC, | ||
195 | .smmu = { | ||
196 | .reg = 0x228, | ||
197 | .bit = 23, | ||
198 | }, | ||
199 | .la = { | ||
200 | .reg = 0x310, | ||
201 | .shift = 16, | ||
202 | .mask = 0xff, | ||
203 | .def = 0x50, | ||
204 | }, | ||
205 | }, { | ||
206 | .id = 0x1c, | ||
207 | .name = "msencsrd", | ||
208 | .swgroup = TEGRA_SWGROUP_MSENC, | ||
209 | .smmu = { | ||
210 | .reg = 0x228, | ||
211 | .bit = 28, | ||
212 | }, | ||
213 | .la = { | ||
214 | .reg = 0x328, | ||
215 | .shift = 0, | ||
216 | .mask = 0xff, | ||
217 | .def = 0x23, | ||
218 | }, | ||
219 | }, { | ||
220 | .id = 0x1d, | ||
221 | .name = "ppcsahbdmar", | ||
222 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
223 | .smmu = { | ||
224 | .reg = 0x228, | ||
225 | .bit = 29, | ||
226 | }, | ||
227 | .la = { | ||
228 | .reg = 0x344, | ||
229 | .shift = 0, | ||
230 | .mask = 0xff, | ||
231 | .def = 0x49, | ||
232 | }, | ||
233 | }, { | ||
234 | .id = 0x1e, | ||
235 | .name = "ppcsahbslvr", | ||
236 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
237 | .smmu = { | ||
238 | .reg = 0x228, | ||
239 | .bit = 30, | ||
240 | }, | ||
241 | .la = { | ||
242 | .reg = 0x344, | ||
243 | .shift = 16, | ||
244 | .mask = 0xff, | ||
245 | .def = 0x1a, | ||
246 | }, | ||
247 | }, { | ||
248 | .id = 0x1f, | ||
249 | .name = "satar", | ||
250 | .swgroup = TEGRA_SWGROUP_SATA, | ||
251 | .smmu = { | ||
252 | .reg = 0x228, | ||
253 | .bit = 31, | ||
254 | }, | ||
255 | .la = { | ||
256 | .reg = 0x350, | ||
257 | .shift = 0, | ||
258 | .mask = 0xff, | ||
259 | .def = 0x65, | ||
260 | }, | ||
261 | }, { | ||
262 | .id = 0x22, | ||
263 | .name = "vdebsevr", | ||
264 | .swgroup = TEGRA_SWGROUP_VDE, | ||
265 | .smmu = { | ||
266 | .reg = 0x22c, | ||
267 | .bit = 2, | ||
268 | }, | ||
269 | .la = { | ||
270 | .reg = 0x354, | ||
271 | .shift = 0, | ||
272 | .mask = 0xff, | ||
273 | .def = 0x4f, | ||
274 | }, | ||
275 | }, { | ||
276 | .id = 0x23, | ||
277 | .name = "vdember", | ||
278 | .swgroup = TEGRA_SWGROUP_VDE, | ||
279 | .smmu = { | ||
280 | .reg = 0x22c, | ||
281 | .bit = 3, | ||
282 | }, | ||
283 | .la = { | ||
284 | .reg = 0x354, | ||
285 | .shift = 16, | ||
286 | .mask = 0xff, | ||
287 | .def = 0x3d, | ||
288 | }, | ||
289 | }, { | ||
290 | .id = 0x24, | ||
291 | .name = "vdemcer", | ||
292 | .swgroup = TEGRA_SWGROUP_VDE, | ||
293 | .smmu = { | ||
294 | .reg = 0x22c, | ||
295 | .bit = 4, | ||
296 | }, | ||
297 | .la = { | ||
298 | .reg = 0x358, | ||
299 | .shift = 0, | ||
300 | .mask = 0xff, | ||
301 | .def = 0x66, | ||
302 | }, | ||
303 | }, { | ||
304 | .id = 0x25, | ||
305 | .name = "vdetper", | ||
306 | .swgroup = TEGRA_SWGROUP_VDE, | ||
307 | .smmu = { | ||
308 | .reg = 0x22c, | ||
309 | .bit = 5, | ||
310 | }, | ||
311 | .la = { | ||
312 | .reg = 0x358, | ||
313 | .shift = 16, | ||
314 | .mask = 0xff, | ||
315 | .def = 0xa5, | ||
316 | }, | ||
317 | }, { | ||
318 | .id = 0x26, | ||
319 | .name = "mpcorelpr", | ||
320 | .swgroup = TEGRA_SWGROUP_MPCORELP, | ||
321 | .la = { | ||
322 | .reg = 0x324, | ||
323 | .shift = 0, | ||
324 | .mask = 0xff, | ||
325 | .def = 0x04, | ||
326 | }, | ||
327 | }, { | ||
328 | .id = 0x27, | ||
329 | .name = "mpcorer", | ||
330 | .swgroup = TEGRA_SWGROUP_MPCORE, | ||
331 | .la = { | ||
332 | .reg = 0x320, | ||
333 | .shift = 0, | ||
334 | .mask = 0xff, | ||
335 | .def = 0x04, | ||
336 | }, | ||
337 | }, { | ||
338 | .id = 0x2b, | ||
339 | .name = "msencswr", | ||
340 | .swgroup = TEGRA_SWGROUP_MSENC, | ||
341 | .smmu = { | ||
342 | .reg = 0x22c, | ||
343 | .bit = 11, | ||
344 | }, | ||
345 | .la = { | ||
346 | .reg = 0x328, | ||
347 | .shift = 16, | ||
348 | .mask = 0xff, | ||
349 | .def = 0x80, | ||
350 | }, | ||
351 | }, { | ||
352 | .id = 0x31, | ||
353 | .name = "afiw", | ||
354 | .swgroup = TEGRA_SWGROUP_AFI, | ||
355 | .smmu = { | ||
356 | .reg = 0x22c, | ||
357 | .bit = 17, | ||
358 | }, | ||
359 | .la = { | ||
360 | .reg = 0x2e0, | ||
361 | .shift = 16, | ||
362 | .mask = 0xff, | ||
363 | .def = 0x80, | ||
364 | }, | ||
365 | }, { | ||
366 | .id = 0x32, | ||
367 | .name = "avpcarm7w", | ||
368 | .swgroup = TEGRA_SWGROUP_AVPC, | ||
369 | .smmu = { | ||
370 | .reg = 0x22c, | ||
371 | .bit = 18, | ||
372 | }, | ||
373 | .la = { | ||
374 | .reg = 0x2e4, | ||
375 | .shift = 16, | ||
376 | .mask = 0xff, | ||
377 | .def = 0x80, | ||
378 | }, | ||
379 | }, { | ||
380 | .id = 0x35, | ||
381 | .name = "hdaw", | ||
382 | .swgroup = TEGRA_SWGROUP_HDA, | ||
383 | .smmu = { | ||
384 | .reg = 0x22c, | ||
385 | .bit = 21, | ||
386 | }, | ||
387 | .la = { | ||
388 | .reg = 0x318, | ||
389 | .shift = 16, | ||
390 | .mask = 0xff, | ||
391 | .def = 0x80, | ||
392 | }, | ||
393 | }, { | ||
394 | .id = 0x36, | ||
395 | .name = "host1xw", | ||
396 | .swgroup = TEGRA_SWGROUP_HC, | ||
397 | .smmu = { | ||
398 | .reg = 0x22c, | ||
399 | .bit = 22, | ||
400 | }, | ||
401 | .la = { | ||
402 | .reg = 0x314, | ||
403 | .shift = 0, | ||
404 | .mask = 0xff, | ||
405 | .def = 0x80, | ||
406 | }, | ||
407 | }, { | ||
408 | .id = 0x38, | ||
409 | .name = "mpcorelpw", | ||
410 | .swgroup = TEGRA_SWGROUP_MPCORELP, | ||
411 | .la = { | ||
412 | .reg = 0x324, | ||
413 | .shift = 16, | ||
414 | .mask = 0xff, | ||
415 | .def = 0x80, | ||
416 | }, | ||
417 | }, { | ||
418 | .id = 0x39, | ||
419 | .name = "mpcorew", | ||
420 | .swgroup = TEGRA_SWGROUP_MPCORE, | ||
421 | .la = { | ||
422 | .reg = 0x320, | ||
423 | .shift = 16, | ||
424 | .mask = 0xff, | ||
425 | .def = 0x80, | ||
426 | }, | ||
427 | }, { | ||
428 | .id = 0x3b, | ||
429 | .name = "ppcsahbdmaw", | ||
430 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
431 | .smmu = { | ||
432 | .reg = 0x22c, | ||
433 | .bit = 27, | ||
434 | }, | ||
435 | .la = { | ||
436 | .reg = 0x348, | ||
437 | .shift = 0, | ||
438 | .mask = 0xff, | ||
439 | .def = 0x80, | ||
440 | }, | ||
441 | }, { | ||
442 | .id = 0x3c, | ||
443 | .name = "ppcsahbslvw", | ||
444 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
445 | .smmu = { | ||
446 | .reg = 0x22c, | ||
447 | .bit = 28, | ||
448 | }, | ||
449 | .la = { | ||
450 | .reg = 0x348, | ||
451 | .shift = 16, | ||
452 | .mask = 0xff, | ||
453 | .def = 0x80, | ||
454 | }, | ||
455 | }, { | ||
456 | .id = 0x3d, | ||
457 | .name = "sataw", | ||
458 | .swgroup = TEGRA_SWGROUP_SATA, | ||
459 | .smmu = { | ||
460 | .reg = 0x22c, | ||
461 | .bit = 29, | ||
462 | }, | ||
463 | .la = { | ||
464 | .reg = 0x350, | ||
465 | .shift = 16, | ||
466 | .mask = 0xff, | ||
467 | .def = 0x65, | ||
468 | }, | ||
469 | }, { | ||
470 | .id = 0x3e, | ||
471 | .name = "vdebsevw", | ||
472 | .swgroup = TEGRA_SWGROUP_VDE, | ||
473 | .smmu = { | ||
474 | .reg = 0x22c, | ||
475 | .bit = 30, | ||
476 | }, | ||
477 | .la = { | ||
478 | .reg = 0x35c, | ||
479 | .shift = 0, | ||
480 | .mask = 0xff, | ||
481 | .def = 0x80, | ||
482 | }, | ||
483 | }, { | ||
484 | .id = 0x3f, | ||
485 | .name = "vdedbgw", | ||
486 | .swgroup = TEGRA_SWGROUP_VDE, | ||
487 | .smmu = { | ||
488 | .reg = 0x22c, | ||
489 | .bit = 31, | ||
490 | }, | ||
491 | .la = { | ||
492 | .reg = 0x35c, | ||
493 | .shift = 16, | ||
494 | .mask = 0xff, | ||
495 | .def = 0x80, | ||
496 | }, | ||
497 | }, { | ||
498 | .id = 0x40, | ||
499 | .name = "vdembew", | ||
500 | .swgroup = TEGRA_SWGROUP_VDE, | ||
501 | .smmu = { | ||
502 | .reg = 0x230, | ||
503 | .bit = 0, | ||
504 | }, | ||
505 | .la = { | ||
506 | .reg = 0x360, | ||
507 | .shift = 0, | ||
508 | .mask = 0xff, | ||
509 | .def = 0x80, | ||
510 | }, | ||
511 | }, { | ||
512 | .id = 0x41, | ||
513 | .name = "vdetpmw", | ||
514 | .swgroup = TEGRA_SWGROUP_VDE, | ||
515 | .smmu = { | ||
516 | .reg = 0x230, | ||
517 | .bit = 1, | ||
518 | }, | ||
519 | .la = { | ||
520 | .reg = 0x360, | ||
521 | .shift = 16, | ||
522 | .mask = 0xff, | ||
523 | .def = 0x80, | ||
524 | }, | ||
525 | }, { | ||
526 | .id = 0x44, | ||
527 | .name = "ispra", | ||
528 | .swgroup = TEGRA_SWGROUP_ISP2, | ||
529 | .smmu = { | ||
530 | .reg = 0x230, | ||
531 | .bit = 4, | ||
532 | }, | ||
533 | .la = { | ||
534 | .reg = 0x370, | ||
535 | .shift = 0, | ||
536 | .mask = 0xff, | ||
537 | .def = 0x18, | ||
538 | }, | ||
539 | }, { | ||
540 | .id = 0x46, | ||
541 | .name = "ispwa", | ||
542 | .swgroup = TEGRA_SWGROUP_ISP2, | ||
543 | .smmu = { | ||
544 | .reg = 0x230, | ||
545 | .bit = 6, | ||
546 | }, | ||
547 | .la = { | ||
548 | .reg = 0x374, | ||
549 | .shift = 0, | ||
550 | .mask = 0xff, | ||
551 | .def = 0x80, | ||
552 | }, | ||
553 | }, { | ||
554 | .id = 0x47, | ||
555 | .name = "ispwb", | ||
556 | .swgroup = TEGRA_SWGROUP_ISP2, | ||
557 | .smmu = { | ||
558 | .reg = 0x230, | ||
559 | .bit = 7, | ||
560 | }, | ||
561 | .la = { | ||
562 | .reg = 0x374, | ||
563 | .shift = 16, | ||
564 | .mask = 0xff, | ||
565 | .def = 0x80, | ||
566 | }, | ||
567 | }, { | ||
568 | .id = 0x4a, | ||
569 | .name = "xusb_hostr", | ||
570 | .swgroup = TEGRA_SWGROUP_XUSB_HOST, | ||
571 | .smmu = { | ||
572 | .reg = 0x230, | ||
573 | .bit = 10, | ||
574 | }, | ||
575 | .la = { | ||
576 | .reg = 0x37c, | ||
577 | .shift = 0, | ||
578 | .mask = 0xff, | ||
579 | .def = 0x39, | ||
580 | }, | ||
581 | }, { | ||
582 | .id = 0x4b, | ||
583 | .name = "xusb_hostw", | ||
584 | .swgroup = TEGRA_SWGROUP_XUSB_HOST, | ||
585 | .smmu = { | ||
586 | .reg = 0x230, | ||
587 | .bit = 11, | ||
588 | }, | ||
589 | .la = { | ||
590 | .reg = 0x37c, | ||
591 | .shift = 16, | ||
592 | .mask = 0xff, | ||
593 | .def = 0x80, | ||
594 | }, | ||
595 | }, { | ||
596 | .id = 0x4c, | ||
597 | .name = "xusb_devr", | ||
598 | .swgroup = TEGRA_SWGROUP_XUSB_DEV, | ||
599 | .smmu = { | ||
600 | .reg = 0x230, | ||
601 | .bit = 12, | ||
602 | }, | ||
603 | .la = { | ||
604 | .reg = 0x380, | ||
605 | .shift = 0, | ||
606 | .mask = 0xff, | ||
607 | .def = 0x39, | ||
608 | }, | ||
609 | }, { | ||
610 | .id = 0x4d, | ||
611 | .name = "xusb_devw", | ||
612 | .swgroup = TEGRA_SWGROUP_XUSB_DEV, | ||
613 | .smmu = { | ||
614 | .reg = 0x230, | ||
615 | .bit = 13, | ||
616 | }, | ||
617 | .la = { | ||
618 | .reg = 0x380, | ||
619 | .shift = 16, | ||
620 | .mask = 0xff, | ||
621 | .def = 0x80, | ||
622 | }, | ||
623 | }, { | ||
624 | .id = 0x4e, | ||
625 | .name = "isprab", | ||
626 | .swgroup = TEGRA_SWGROUP_ISP2B, | ||
627 | .smmu = { | ||
628 | .reg = 0x230, | ||
629 | .bit = 14, | ||
630 | }, | ||
631 | .la = { | ||
632 | .reg = 0x384, | ||
633 | .shift = 0, | ||
634 | .mask = 0xff, | ||
635 | .def = 0x18, | ||
636 | }, | ||
637 | }, { | ||
638 | .id = 0x50, | ||
639 | .name = "ispwab", | ||
640 | .swgroup = TEGRA_SWGROUP_ISP2B, | ||
641 | .smmu = { | ||
642 | .reg = 0x230, | ||
643 | .bit = 16, | ||
644 | }, | ||
645 | .la = { | ||
646 | .reg = 0x388, | ||
647 | .shift = 0, | ||
648 | .mask = 0xff, | ||
649 | .def = 0x80, | ||
650 | }, | ||
651 | }, { | ||
652 | .id = 0x51, | ||
653 | .name = "ispwbb", | ||
654 | .swgroup = TEGRA_SWGROUP_ISP2B, | ||
655 | .smmu = { | ||
656 | .reg = 0x230, | ||
657 | .bit = 17, | ||
658 | }, | ||
659 | .la = { | ||
660 | .reg = 0x388, | ||
661 | .shift = 16, | ||
662 | .mask = 0xff, | ||
663 | .def = 0x80, | ||
664 | }, | ||
665 | }, { | ||
666 | .id = 0x54, | ||
667 | .name = "tsecsrd", | ||
668 | .swgroup = TEGRA_SWGROUP_TSEC, | ||
669 | .smmu = { | ||
670 | .reg = 0x230, | ||
671 | .bit = 20, | ||
672 | }, | ||
673 | .la = { | ||
674 | .reg = 0x390, | ||
675 | .shift = 0, | ||
676 | .mask = 0xff, | ||
677 | .def = 0x9b, | ||
678 | }, | ||
679 | }, { | ||
680 | .id = 0x55, | ||
681 | .name = "tsecswr", | ||
682 | .swgroup = TEGRA_SWGROUP_TSEC, | ||
683 | .smmu = { | ||
684 | .reg = 0x230, | ||
685 | .bit = 21, | ||
686 | }, | ||
687 | .la = { | ||
688 | .reg = 0x390, | ||
689 | .shift = 16, | ||
690 | .mask = 0xff, | ||
691 | .def = 0x80, | ||
692 | }, | ||
693 | }, { | ||
694 | .id = 0x56, | ||
695 | .name = "a9avpscr", | ||
696 | .swgroup = TEGRA_SWGROUP_A9AVP, | ||
697 | .smmu = { | ||
698 | .reg = 0x230, | ||
699 | .bit = 22, | ||
700 | }, | ||
701 | .la = { | ||
702 | .reg = 0x3a4, | ||
703 | .shift = 0, | ||
704 | .mask = 0xff, | ||
705 | .def = 0x04, | ||
706 | }, | ||
707 | }, { | ||
708 | .id = 0x57, | ||
709 | .name = "a9avpscw", | ||
710 | .swgroup = TEGRA_SWGROUP_A9AVP, | ||
711 | .smmu = { | ||
712 | .reg = 0x230, | ||
713 | .bit = 23, | ||
714 | }, | ||
715 | .la = { | ||
716 | .reg = 0x3a4, | ||
717 | .shift = 16, | ||
718 | .mask = 0xff, | ||
719 | .def = 0x80, | ||
720 | }, | ||
721 | }, { | ||
722 | .id = 0x58, | ||
723 | .name = "gpusrd", | ||
724 | .swgroup = TEGRA_SWGROUP_GPU, | ||
725 | .smmu = { | ||
726 | /* read-only */ | ||
727 | .reg = 0x230, | ||
728 | .bit = 24, | ||
729 | }, | ||
730 | .la = { | ||
731 | .reg = 0x3c8, | ||
732 | .shift = 0, | ||
733 | .mask = 0xff, | ||
734 | .def = 0x1a, | ||
735 | }, | ||
736 | }, { | ||
737 | .id = 0x59, | ||
738 | .name = "gpuswr", | ||
739 | .swgroup = TEGRA_SWGROUP_GPU, | ||
740 | .smmu = { | ||
741 | /* read-only */ | ||
742 | .reg = 0x230, | ||
743 | .bit = 25, | ||
744 | }, | ||
745 | .la = { | ||
746 | .reg = 0x3c8, | ||
747 | .shift = 16, | ||
748 | .mask = 0xff, | ||
749 | .def = 0x80, | ||
750 | }, | ||
751 | }, { | ||
752 | .id = 0x5a, | ||
753 | .name = "displayt", | ||
754 | .swgroup = TEGRA_SWGROUP_DC, | ||
755 | .smmu = { | ||
756 | .reg = 0x230, | ||
757 | .bit = 26, | ||
758 | }, | ||
759 | .la = { | ||
760 | .reg = 0x2f0, | ||
761 | .shift = 16, | ||
762 | .mask = 0xff, | ||
763 | .def = 0x50, | ||
764 | }, | ||
765 | }, { | ||
766 | .id = 0x60, | ||
767 | .name = "sdmmcra", | ||
768 | .swgroup = TEGRA_SWGROUP_SDMMC1A, | ||
769 | .smmu = { | ||
770 | .reg = 0x234, | ||
771 | .bit = 0, | ||
772 | }, | ||
773 | .la = { | ||
774 | .reg = 0x3b8, | ||
775 | .shift = 0, | ||
776 | .mask = 0xff, | ||
777 | .def = 0x49, | ||
778 | }, | ||
779 | }, { | ||
780 | .id = 0x61, | ||
781 | .name = "sdmmcraa", | ||
782 | .swgroup = TEGRA_SWGROUP_SDMMC2A, | ||
783 | .smmu = { | ||
784 | .reg = 0x234, | ||
785 | .bit = 1, | ||
786 | }, | ||
787 | .la = { | ||
788 | .reg = 0x3bc, | ||
789 | .shift = 0, | ||
790 | .mask = 0xff, | ||
791 | .def = 0x49, | ||
792 | }, | ||
793 | }, { | ||
794 | .id = 0x62, | ||
795 | .name = "sdmmcr", | ||
796 | .swgroup = TEGRA_SWGROUP_SDMMC3A, | ||
797 | .smmu = { | ||
798 | .reg = 0x234, | ||
799 | .bit = 2, | ||
800 | }, | ||
801 | .la = { | ||
802 | .reg = 0x3c0, | ||
803 | .shift = 0, | ||
804 | .mask = 0xff, | ||
805 | .def = 0x49, | ||
806 | }, | ||
807 | }, { | ||
808 | .id = 0x63, | ||
809 | .swgroup = TEGRA_SWGROUP_SDMMC4A, | ||
810 | .name = "sdmmcrab", | ||
811 | .smmu = { | ||
812 | .reg = 0x234, | ||
813 | .bit = 3, | ||
814 | }, | ||
815 | .la = { | ||
816 | .reg = 0x3c4, | ||
817 | .shift = 0, | ||
818 | .mask = 0xff, | ||
819 | .def = 0x49, | ||
820 | }, | ||
821 | }, { | ||
822 | .id = 0x64, | ||
823 | .name = "sdmmcwa", | ||
824 | .swgroup = TEGRA_SWGROUP_SDMMC1A, | ||
825 | .smmu = { | ||
826 | .reg = 0x234, | ||
827 | .bit = 4, | ||
828 | }, | ||
829 | .la = { | ||
830 | .reg = 0x3b8, | ||
831 | .shift = 16, | ||
832 | .mask = 0xff, | ||
833 | .def = 0x80, | ||
834 | }, | ||
835 | }, { | ||
836 | .id = 0x65, | ||
837 | .name = "sdmmcwaa", | ||
838 | .swgroup = TEGRA_SWGROUP_SDMMC2A, | ||
839 | .smmu = { | ||
840 | .reg = 0x234, | ||
841 | .bit = 5, | ||
842 | }, | ||
843 | .la = { | ||
844 | .reg = 0x3bc, | ||
845 | .shift = 16, | ||
846 | .mask = 0xff, | ||
847 | .def = 0x80, | ||
848 | }, | ||
849 | }, { | ||
850 | .id = 0x66, | ||
851 | .name = "sdmmcw", | ||
852 | .swgroup = TEGRA_SWGROUP_SDMMC3A, | ||
853 | .smmu = { | ||
854 | .reg = 0x234, | ||
855 | .bit = 6, | ||
856 | }, | ||
857 | .la = { | ||
858 | .reg = 0x3c0, | ||
859 | .shift = 16, | ||
860 | .mask = 0xff, | ||
861 | .def = 0x80, | ||
862 | }, | ||
863 | }, { | ||
864 | .id = 0x67, | ||
865 | .name = "sdmmcwab", | ||
866 | .swgroup = TEGRA_SWGROUP_SDMMC4A, | ||
867 | .smmu = { | ||
868 | .reg = 0x234, | ||
869 | .bit = 7, | ||
870 | }, | ||
871 | .la = { | ||
872 | .reg = 0x3c4, | ||
873 | .shift = 16, | ||
874 | .mask = 0xff, | ||
875 | .def = 0x80, | ||
876 | }, | ||
877 | }, { | ||
878 | .id = 0x6c, | ||
879 | .name = "vicsrd", | ||
880 | .swgroup = TEGRA_SWGROUP_VIC, | ||
881 | .smmu = { | ||
882 | .reg = 0x234, | ||
883 | .bit = 12, | ||
884 | }, | ||
885 | .la = { | ||
886 | .reg = 0x394, | ||
887 | .shift = 0, | ||
888 | .mask = 0xff, | ||
889 | .def = 0x1a, | ||
890 | }, | ||
891 | }, { | ||
892 | .id = 0x6d, | ||
893 | .name = "vicswr", | ||
894 | .swgroup = TEGRA_SWGROUP_VIC, | ||
895 | .smmu = { | ||
896 | .reg = 0x234, | ||
897 | .bit = 13, | ||
898 | }, | ||
899 | .la = { | ||
900 | .reg = 0x394, | ||
901 | .shift = 16, | ||
902 | .mask = 0xff, | ||
903 | .def = 0x80, | ||
904 | }, | ||
905 | }, { | ||
906 | .id = 0x72, | ||
907 | .name = "viw", | ||
908 | .swgroup = TEGRA_SWGROUP_VI, | ||
909 | .smmu = { | ||
910 | .reg = 0x234, | ||
911 | .bit = 18, | ||
912 | }, | ||
913 | .la = { | ||
914 | .reg = 0x398, | ||
915 | .shift = 0, | ||
916 | .mask = 0xff, | ||
917 | .def = 0x80, | ||
918 | }, | ||
919 | }, { | ||
920 | .id = 0x73, | ||
921 | .name = "displayd", | ||
922 | .swgroup = TEGRA_SWGROUP_DC, | ||
923 | .smmu = { | ||
924 | .reg = 0x234, | ||
925 | .bit = 19, | ||
926 | }, | ||
927 | .la = { | ||
928 | .reg = 0x3c8, | ||
929 | .shift = 0, | ||
930 | .mask = 0xff, | ||
931 | .def = 0x50, | ||
932 | }, | ||
933 | }, | ||
934 | }; | ||
935 | |||
936 | static const struct tegra_smmu_swgroup tegra124_swgroups[] = { | ||
937 | { .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 }, | ||
938 | { .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 }, | ||
939 | { .swgroup = TEGRA_SWGROUP_AFI, .reg = 0x238 }, | ||
940 | { .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c }, | ||
941 | { .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 }, | ||
942 | { .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 }, | ||
943 | { .swgroup = TEGRA_SWGROUP_MSENC, .reg = 0x264 }, | ||
944 | { .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 }, | ||
945 | { .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x274 }, | ||
946 | { .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c }, | ||
947 | { .swgroup = TEGRA_SWGROUP_ISP2, .reg = 0x258 }, | ||
948 | { .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 }, | ||
949 | { .swgroup = TEGRA_SWGROUP_XUSB_DEV, .reg = 0x28c }, | ||
950 | { .swgroup = TEGRA_SWGROUP_ISP2B, .reg = 0xaa4 }, | ||
951 | { .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 }, | ||
952 | { .swgroup = TEGRA_SWGROUP_A9AVP, .reg = 0x290 }, | ||
953 | { .swgroup = TEGRA_SWGROUP_GPU, .reg = 0xaac }, | ||
954 | { .swgroup = TEGRA_SWGROUP_SDMMC1A, .reg = 0xa94 }, | ||
955 | { .swgroup = TEGRA_SWGROUP_SDMMC2A, .reg = 0xa98 }, | ||
956 | { .swgroup = TEGRA_SWGROUP_SDMMC3A, .reg = 0xa9c }, | ||
957 | { .swgroup = TEGRA_SWGROUP_SDMMC4A, .reg = 0xaa0 }, | ||
958 | { .swgroup = TEGRA_SWGROUP_VIC, .reg = 0x284 }, | ||
959 | { .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 }, | ||
960 | }; | ||
961 | |||
962 | #ifdef CONFIG_ARCH_TEGRA_124_SOC | ||
963 | static void tegra124_flush_dcache(struct page *page, unsigned long offset, | ||
964 | size_t size) | ||
965 | { | ||
966 | phys_addr_t phys = page_to_phys(page) + offset; | ||
967 | void *virt = page_address(page) + offset; | ||
968 | |||
969 | __cpuc_flush_dcache_area(virt, size); | ||
970 | outer_flush_range(phys, phys + size); | ||
971 | } | ||
972 | |||
973 | static const struct tegra_smmu_ops tegra124_smmu_ops = { | ||
974 | .flush_dcache = tegra124_flush_dcache, | ||
975 | }; | ||
976 | |||
977 | static const struct tegra_smmu_soc tegra124_smmu_soc = { | ||
978 | .clients = tegra124_mc_clients, | ||
979 | .num_clients = ARRAY_SIZE(tegra124_mc_clients), | ||
980 | .swgroups = tegra124_swgroups, | ||
981 | .num_swgroups = ARRAY_SIZE(tegra124_swgroups), | ||
982 | .supports_round_robin_arbitration = true, | ||
983 | .supports_request_limit = true, | ||
984 | .num_asids = 128, | ||
985 | .ops = &tegra124_smmu_ops, | ||
986 | }; | ||
987 | |||
988 | const struct tegra_mc_soc tegra124_mc_soc = { | ||
989 | .clients = tegra124_mc_clients, | ||
990 | .num_clients = ARRAY_SIZE(tegra124_mc_clients), | ||
991 | .num_address_bits = 34, | ||
992 | .atom_size = 32, | ||
993 | .smmu = &tegra124_smmu_soc, | ||
994 | }; | ||
995 | #endif /* CONFIG_ARCH_TEGRA_124_SOC */ | ||
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c new file mode 100644 index 000000000000..71fe9376fe53 --- /dev/null +++ b/drivers/memory/tegra/tegra30.c | |||
@@ -0,0 +1,970 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/of.h> | ||
10 | #include <linux/mm.h> | ||
11 | |||
12 | #include <asm/cacheflush.h> | ||
13 | |||
14 | #include <dt-bindings/memory/tegra30-mc.h> | ||
15 | |||
16 | #include "mc.h" | ||
17 | |||
18 | static const struct tegra_mc_client tegra30_mc_clients[] = { | ||
19 | { | ||
20 | .id = 0x00, | ||
21 | .name = "ptcr", | ||
22 | .swgroup = TEGRA_SWGROUP_PTC, | ||
23 | }, { | ||
24 | .id = 0x01, | ||
25 | .name = "display0a", | ||
26 | .swgroup = TEGRA_SWGROUP_DC, | ||
27 | .smmu = { | ||
28 | .reg = 0x228, | ||
29 | .bit = 1, | ||
30 | }, | ||
31 | .la = { | ||
32 | .reg = 0x2e8, | ||
33 | .shift = 0, | ||
34 | .mask = 0xff, | ||
35 | .def = 0x4e, | ||
36 | }, | ||
37 | }, { | ||
38 | .id = 0x02, | ||
39 | .name = "display0ab", | ||
40 | .swgroup = TEGRA_SWGROUP_DCB, | ||
41 | .smmu = { | ||
42 | .reg = 0x228, | ||
43 | .bit = 2, | ||
44 | }, | ||
45 | .la = { | ||
46 | .reg = 0x2f4, | ||
47 | .shift = 0, | ||
48 | .mask = 0xff, | ||
49 | .def = 0x4e, | ||
50 | }, | ||
51 | }, { | ||
52 | .id = 0x03, | ||
53 | .name = "display0b", | ||
54 | .swgroup = TEGRA_SWGROUP_DC, | ||
55 | .smmu = { | ||
56 | .reg = 0x228, | ||
57 | .bit = 3, | ||
58 | }, | ||
59 | .la = { | ||
60 | .reg = 0x2e8, | ||
61 | .shift = 16, | ||
62 | .mask = 0xff, | ||
63 | .def = 0x4e, | ||
64 | }, | ||
65 | }, { | ||
66 | .id = 0x04, | ||
67 | .name = "display0bb", | ||
68 | .swgroup = TEGRA_SWGROUP_DCB, | ||
69 | .smmu = { | ||
70 | .reg = 0x228, | ||
71 | .bit = 4, | ||
72 | }, | ||
73 | .la = { | ||
74 | .reg = 0x2f4, | ||
75 | .shift = 16, | ||
76 | .mask = 0xff, | ||
77 | .def = 0x4e, | ||
78 | }, | ||
79 | }, { | ||
80 | .id = 0x05, | ||
81 | .name = "display0c", | ||
82 | .swgroup = TEGRA_SWGROUP_DC, | ||
83 | .smmu = { | ||
84 | .reg = 0x228, | ||
85 | .bit = 5, | ||
86 | }, | ||
87 | .la = { | ||
88 | .reg = 0x2ec, | ||
89 | .shift = 0, | ||
90 | .mask = 0xff, | ||
91 | .def = 0x4e, | ||
92 | }, | ||
93 | }, { | ||
94 | .id = 0x06, | ||
95 | .name = "display0cb", | ||
96 | .swgroup = TEGRA_SWGROUP_DCB, | ||
97 | .smmu = { | ||
98 | .reg = 0x228, | ||
99 | .bit = 6, | ||
100 | }, | ||
101 | .la = { | ||
102 | .reg = 0x2f8, | ||
103 | .shift = 0, | ||
104 | .mask = 0xff, | ||
105 | .def = 0x4e, | ||
106 | }, | ||
107 | }, { | ||
108 | .id = 0x07, | ||
109 | .name = "display1b", | ||
110 | .swgroup = TEGRA_SWGROUP_DC, | ||
111 | .smmu = { | ||
112 | .reg = 0x228, | ||
113 | .bit = 7, | ||
114 | }, | ||
115 | .la = { | ||
116 | .reg = 0x2ec, | ||
117 | .shift = 16, | ||
118 | .mask = 0xff, | ||
119 | .def = 0x4e, | ||
120 | }, | ||
121 | }, { | ||
122 | .id = 0x08, | ||
123 | .name = "display1bb", | ||
124 | .swgroup = TEGRA_SWGROUP_DCB, | ||
125 | .smmu = { | ||
126 | .reg = 0x228, | ||
127 | .bit = 8, | ||
128 | }, | ||
129 | .la = { | ||
130 | .reg = 0x2f8, | ||
131 | .shift = 16, | ||
132 | .mask = 0xff, | ||
133 | .def = 0x4e, | ||
134 | }, | ||
135 | }, { | ||
136 | .id = 0x09, | ||
137 | .name = "eppup", | ||
138 | .swgroup = TEGRA_SWGROUP_EPP, | ||
139 | .smmu = { | ||
140 | .reg = 0x228, | ||
141 | .bit = 9, | ||
142 | }, | ||
143 | .la = { | ||
144 | .reg = 0x300, | ||
145 | .shift = 0, | ||
146 | .mask = 0xff, | ||
147 | .def = 0x17, | ||
148 | }, | ||
149 | }, { | ||
150 | .id = 0x0a, | ||
151 | .name = "g2pr", | ||
152 | .swgroup = TEGRA_SWGROUP_G2, | ||
153 | .smmu = { | ||
154 | .reg = 0x228, | ||
155 | .bit = 10, | ||
156 | }, | ||
157 | .la = { | ||
158 | .reg = 0x308, | ||
159 | .shift = 0, | ||
160 | .mask = 0xff, | ||
161 | .def = 0x09, | ||
162 | }, | ||
163 | }, { | ||
164 | .id = 0x0b, | ||
165 | .name = "g2sr", | ||
166 | .swgroup = TEGRA_SWGROUP_G2, | ||
167 | .smmu = { | ||
168 | .reg = 0x228, | ||
169 | .bit = 11, | ||
170 | }, | ||
171 | .la = { | ||
172 | .reg = 0x308, | ||
173 | .shift = 16, | ||
174 | .mask = 0xff, | ||
175 | .def = 0x09, | ||
176 | }, | ||
177 | }, { | ||
178 | .id = 0x0c, | ||
179 | .name = "mpeunifbr", | ||
180 | .swgroup = TEGRA_SWGROUP_MPE, | ||
181 | .smmu = { | ||
182 | .reg = 0x228, | ||
183 | .bit = 12, | ||
184 | }, | ||
185 | .la = { | ||
186 | .reg = 0x328, | ||
187 | .shift = 0, | ||
188 | .mask = 0xff, | ||
189 | .def = 0x50, | ||
190 | }, | ||
191 | }, { | ||
192 | .id = 0x0d, | ||
193 | .name = "viruv", | ||
194 | .swgroup = TEGRA_SWGROUP_VI, | ||
195 | .smmu = { | ||
196 | .reg = 0x228, | ||
197 | .bit = 13, | ||
198 | }, | ||
199 | .la = { | ||
200 | .reg = 0x364, | ||
201 | .shift = 0, | ||
202 | .mask = 0xff, | ||
203 | .def = 0x2c, | ||
204 | }, | ||
205 | }, { | ||
206 | .id = 0x0e, | ||
207 | .name = "afir", | ||
208 | .swgroup = TEGRA_SWGROUP_AFI, | ||
209 | .smmu = { | ||
210 | .reg = 0x228, | ||
211 | .bit = 14, | ||
212 | }, | ||
213 | .la = { | ||
214 | .reg = 0x2e0, | ||
215 | .shift = 0, | ||
216 | .mask = 0xff, | ||
217 | .def = 0x10, | ||
218 | }, | ||
219 | }, { | ||
220 | .id = 0x0f, | ||
221 | .name = "avpcarm7r", | ||
222 | .swgroup = TEGRA_SWGROUP_AVPC, | ||
223 | .smmu = { | ||
224 | .reg = 0x228, | ||
225 | .bit = 15, | ||
226 | }, | ||
227 | .la = { | ||
228 | .reg = 0x2e4, | ||
229 | .shift = 0, | ||
230 | .mask = 0xff, | ||
231 | .def = 0x04, | ||
232 | }, | ||
233 | }, { | ||
234 | .id = 0x10, | ||
235 | .name = "displayhc", | ||
236 | .swgroup = TEGRA_SWGROUP_DC, | ||
237 | .smmu = { | ||
238 | .reg = 0x228, | ||
239 | .bit = 16, | ||
240 | }, | ||
241 | .la = { | ||
242 | .reg = 0x2f0, | ||
243 | .shift = 0, | ||
244 | .mask = 0xff, | ||
245 | .def = 0xff, | ||
246 | }, | ||
247 | }, { | ||
248 | .id = 0x11, | ||
249 | .name = "displayhcb", | ||
250 | .swgroup = TEGRA_SWGROUP_DCB, | ||
251 | .smmu = { | ||
252 | .reg = 0x228, | ||
253 | .bit = 17, | ||
254 | }, | ||
255 | .la = { | ||
256 | .reg = 0x2fc, | ||
257 | .shift = 0, | ||
258 | .mask = 0xff, | ||
259 | .def = 0xff, | ||
260 | }, | ||
261 | }, { | ||
262 | .id = 0x12, | ||
263 | .name = "fdcdrd", | ||
264 | .swgroup = TEGRA_SWGROUP_NV, | ||
265 | .smmu = { | ||
266 | .reg = 0x228, | ||
267 | .bit = 18, | ||
268 | }, | ||
269 | .la = { | ||
270 | .reg = 0x334, | ||
271 | .shift = 0, | ||
272 | .mask = 0xff, | ||
273 | .def = 0x0a, | ||
274 | }, | ||
275 | }, { | ||
276 | .id = 0x13, | ||
277 | .name = "fdcdrd2", | ||
278 | .swgroup = TEGRA_SWGROUP_NV2, | ||
279 | .smmu = { | ||
280 | .reg = 0x228, | ||
281 | .bit = 19, | ||
282 | }, | ||
283 | .la = { | ||
284 | .reg = 0x33c, | ||
285 | .shift = 0, | ||
286 | .mask = 0xff, | ||
287 | .def = 0x0a, | ||
288 | }, | ||
289 | }, { | ||
290 | .id = 0x14, | ||
291 | .name = "g2dr", | ||
292 | .swgroup = TEGRA_SWGROUP_G2, | ||
293 | .smmu = { | ||
294 | .reg = 0x228, | ||
295 | .bit = 20, | ||
296 | }, | ||
297 | .la = { | ||
298 | .reg = 0x30c, | ||
299 | .shift = 0, | ||
300 | .mask = 0xff, | ||
301 | .def = 0x0a, | ||
302 | }, | ||
303 | }, { | ||
304 | .id = 0x15, | ||
305 | .name = "hdar", | ||
306 | .swgroup = TEGRA_SWGROUP_HDA, | ||
307 | .smmu = { | ||
308 | .reg = 0x228, | ||
309 | .bit = 21, | ||
310 | }, | ||
311 | .la = { | ||
312 | .reg = 0x318, | ||
313 | .shift = 0, | ||
314 | .mask = 0xff, | ||
315 | .def = 0xff, | ||
316 | }, | ||
317 | }, { | ||
318 | .id = 0x16, | ||
319 | .name = "host1xdmar", | ||
320 | .swgroup = TEGRA_SWGROUP_HC, | ||
321 | .smmu = { | ||
322 | .reg = 0x228, | ||
323 | .bit = 22, | ||
324 | }, | ||
325 | .la = { | ||
326 | .reg = 0x310, | ||
327 | .shift = 0, | ||
328 | .mask = 0xff, | ||
329 | .def = 0x05, | ||
330 | }, | ||
331 | }, { | ||
332 | .id = 0x17, | ||
333 | .name = "host1xr", | ||
334 | .swgroup = TEGRA_SWGROUP_HC, | ||
335 | .smmu = { | ||
336 | .reg = 0x228, | ||
337 | .bit = 23, | ||
338 | }, | ||
339 | .la = { | ||
340 | .reg = 0x310, | ||
341 | .shift = 16, | ||
342 | .mask = 0xff, | ||
343 | .def = 0x50, | ||
344 | }, | ||
345 | }, { | ||
346 | .id = 0x18, | ||
347 | .name = "idxsrd", | ||
348 | .swgroup = TEGRA_SWGROUP_NV, | ||
349 | .smmu = { | ||
350 | .reg = 0x228, | ||
351 | .bit = 24, | ||
352 | }, | ||
353 | .la = { | ||
354 | .reg = 0x334, | ||
355 | .shift = 16, | ||
356 | .mask = 0xff, | ||
357 | .def = 0x13, | ||
358 | }, | ||
359 | }, { | ||
360 | .id = 0x19, | ||
361 | .name = "idxsrd2", | ||
362 | .swgroup = TEGRA_SWGROUP_NV2, | ||
363 | .smmu = { | ||
364 | .reg = 0x228, | ||
365 | .bit = 25, | ||
366 | }, | ||
367 | .la = { | ||
368 | .reg = 0x33c, | ||
369 | .shift = 16, | ||
370 | .mask = 0xff, | ||
371 | .def = 0x13, | ||
372 | }, | ||
373 | }, { | ||
374 | .id = 0x1a, | ||
375 | .name = "mpe_ipred", | ||
376 | .swgroup = TEGRA_SWGROUP_MPE, | ||
377 | .smmu = { | ||
378 | .reg = 0x228, | ||
379 | .bit = 26, | ||
380 | }, | ||
381 | .la = { | ||
382 | .reg = 0x328, | ||
383 | .shift = 16, | ||
384 | .mask = 0xff, | ||
385 | .def = 0x80, | ||
386 | }, | ||
387 | }, { | ||
388 | .id = 0x1b, | ||
389 | .name = "mpeamemrd", | ||
390 | .swgroup = TEGRA_SWGROUP_MPE, | ||
391 | .smmu = { | ||
392 | .reg = 0x228, | ||
393 | .bit = 27, | ||
394 | }, | ||
395 | .la = { | ||
396 | .reg = 0x32c, | ||
397 | .shift = 0, | ||
398 | .mask = 0xff, | ||
399 | .def = 0x42, | ||
400 | }, | ||
401 | }, { | ||
402 | .id = 0x1c, | ||
403 | .name = "mpecsrd", | ||
404 | .swgroup = TEGRA_SWGROUP_MPE, | ||
405 | .smmu = { | ||
406 | .reg = 0x228, | ||
407 | .bit = 28, | ||
408 | }, | ||
409 | .la = { | ||
410 | .reg = 0x32c, | ||
411 | .shift = 16, | ||
412 | .mask = 0xff, | ||
413 | .def = 0xff, | ||
414 | }, | ||
415 | }, { | ||
416 | .id = 0x1d, | ||
417 | .name = "ppcsahbdmar", | ||
418 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
419 | .smmu = { | ||
420 | .reg = 0x228, | ||
421 | .bit = 29, | ||
422 | }, | ||
423 | .la = { | ||
424 | .reg = 0x344, | ||
425 | .shift = 0, | ||
426 | .mask = 0xff, | ||
427 | .def = 0x10, | ||
428 | }, | ||
429 | }, { | ||
430 | .id = 0x1e, | ||
431 | .name = "ppcsahbslvr", | ||
432 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
433 | .smmu = { | ||
434 | .reg = 0x228, | ||
435 | .bit = 30, | ||
436 | }, | ||
437 | .la = { | ||
438 | .reg = 0x344, | ||
439 | .shift = 16, | ||
440 | .mask = 0xff, | ||
441 | .def = 0x12, | ||
442 | }, | ||
443 | }, { | ||
444 | .id = 0x1f, | ||
445 | .name = "satar", | ||
446 | .swgroup = TEGRA_SWGROUP_SATA, | ||
447 | .smmu = { | ||
448 | .reg = 0x228, | ||
449 | .bit = 31, | ||
450 | }, | ||
451 | .la = { | ||
452 | .reg = 0x350, | ||
453 | .shift = 0, | ||
454 | .mask = 0xff, | ||
455 | .def = 0x33, | ||
456 | }, | ||
457 | }, { | ||
458 | .id = 0x20, | ||
459 | .name = "texsrd", | ||
460 | .swgroup = TEGRA_SWGROUP_NV, | ||
461 | .smmu = { | ||
462 | .reg = 0x22c, | ||
463 | .bit = 0, | ||
464 | }, | ||
465 | .la = { | ||
466 | .reg = 0x338, | ||
467 | .shift = 0, | ||
468 | .mask = 0xff, | ||
469 | .def = 0x13, | ||
470 | }, | ||
471 | }, { | ||
472 | .id = 0x21, | ||
473 | .name = "texsrd2", | ||
474 | .swgroup = TEGRA_SWGROUP_NV2, | ||
475 | .smmu = { | ||
476 | .reg = 0x22c, | ||
477 | .bit = 1, | ||
478 | }, | ||
479 | .la = { | ||
480 | .reg = 0x340, | ||
481 | .shift = 0, | ||
482 | .mask = 0xff, | ||
483 | .def = 0x13, | ||
484 | }, | ||
485 | }, { | ||
486 | .id = 0x22, | ||
487 | .name = "vdebsevr", | ||
488 | .swgroup = TEGRA_SWGROUP_VDE, | ||
489 | .smmu = { | ||
490 | .reg = 0x22c, | ||
491 | .bit = 2, | ||
492 | }, | ||
493 | .la = { | ||
494 | .reg = 0x354, | ||
495 | .shift = 0, | ||
496 | .mask = 0xff, | ||
497 | .def = 0xff, | ||
498 | }, | ||
499 | }, { | ||
500 | .id = 0x23, | ||
501 | .name = "vdember", | ||
502 | .swgroup = TEGRA_SWGROUP_VDE, | ||
503 | .smmu = { | ||
504 | .reg = 0x22c, | ||
505 | .bit = 3, | ||
506 | }, | ||
507 | .la = { | ||
508 | .reg = 0x354, | ||
509 | .shift = 16, | ||
510 | .mask = 0xff, | ||
511 | .def = 0xd0, | ||
512 | }, | ||
513 | }, { | ||
514 | .id = 0x24, | ||
515 | .name = "vdemcer", | ||
516 | .swgroup = TEGRA_SWGROUP_VDE, | ||
517 | .smmu = { | ||
518 | .reg = 0x22c, | ||
519 | .bit = 4, | ||
520 | }, | ||
521 | .la = { | ||
522 | .reg = 0x358, | ||
523 | .shift = 0, | ||
524 | .mask = 0xff, | ||
525 | .def = 0x2a, | ||
526 | }, | ||
527 | }, { | ||
528 | .id = 0x25, | ||
529 | .name = "vdetper", | ||
530 | .swgroup = TEGRA_SWGROUP_VDE, | ||
531 | .smmu = { | ||
532 | .reg = 0x22c, | ||
533 | .bit = 5, | ||
534 | }, | ||
535 | .la = { | ||
536 | .reg = 0x358, | ||
537 | .shift = 16, | ||
538 | .mask = 0xff, | ||
539 | .def = 0x74, | ||
540 | }, | ||
541 | }, { | ||
542 | .id = 0x26, | ||
543 | .name = "mpcorelpr", | ||
544 | .swgroup = TEGRA_SWGROUP_MPCORELP, | ||
545 | .la = { | ||
546 | .reg = 0x324, | ||
547 | .shift = 0, | ||
548 | .mask = 0xff, | ||
549 | .def = 0x04, | ||
550 | }, | ||
551 | }, { | ||
552 | .id = 0x27, | ||
553 | .name = "mpcorer", | ||
554 | .swgroup = TEGRA_SWGROUP_MPCORE, | ||
555 | .la = { | ||
556 | .reg = 0x320, | ||
557 | .shift = 0, | ||
558 | .mask = 0xff, | ||
559 | .def = 0x04, | ||
560 | }, | ||
561 | }, { | ||
562 | .id = 0x28, | ||
563 | .name = "eppu", | ||
564 | .swgroup = TEGRA_SWGROUP_EPP, | ||
565 | .smmu = { | ||
566 | .reg = 0x22c, | ||
567 | .bit = 8, | ||
568 | }, | ||
569 | .la = { | ||
570 | .reg = 0x300, | ||
571 | .shift = 16, | ||
572 | .mask = 0xff, | ||
573 | .def = 0x6c, | ||
574 | }, | ||
575 | }, { | ||
576 | .id = 0x29, | ||
577 | .name = "eppv", | ||
578 | .swgroup = TEGRA_SWGROUP_EPP, | ||
579 | .smmu = { | ||
580 | .reg = 0x22c, | ||
581 | .bit = 9, | ||
582 | }, | ||
583 | .la = { | ||
584 | .reg = 0x304, | ||
585 | .shift = 0, | ||
586 | .mask = 0xff, | ||
587 | .def = 0x6c, | ||
588 | }, | ||
589 | }, { | ||
590 | .id = 0x2a, | ||
591 | .name = "eppy", | ||
592 | .swgroup = TEGRA_SWGROUP_EPP, | ||
593 | .smmu = { | ||
594 | .reg = 0x22c, | ||
595 | .bit = 10, | ||
596 | }, | ||
597 | .la = { | ||
598 | .reg = 0x304, | ||
599 | .shift = 16, | ||
600 | .mask = 0xff, | ||
601 | .def = 0x6c, | ||
602 | }, | ||
603 | }, { | ||
604 | .id = 0x2b, | ||
605 | .name = "mpeunifbw", | ||
606 | .swgroup = TEGRA_SWGROUP_MPE, | ||
607 | .smmu = { | ||
608 | .reg = 0x22c, | ||
609 | .bit = 11, | ||
610 | }, | ||
611 | .la = { | ||
612 | .reg = 0x330, | ||
613 | .shift = 0, | ||
614 | .mask = 0xff, | ||
615 | .def = 0x13, | ||
616 | }, | ||
617 | }, { | ||
618 | .id = 0x2c, | ||
619 | .name = "viwsb", | ||
620 | .swgroup = TEGRA_SWGROUP_VI, | ||
621 | .smmu = { | ||
622 | .reg = 0x22c, | ||
623 | .bit = 12, | ||
624 | }, | ||
625 | .la = { | ||
626 | .reg = 0x364, | ||
627 | .shift = 16, | ||
628 | .mask = 0xff, | ||
629 | .def = 0x12, | ||
630 | }, | ||
631 | }, { | ||
632 | .id = 0x2d, | ||
633 | .name = "viwu", | ||
634 | .swgroup = TEGRA_SWGROUP_VI, | ||
635 | .smmu = { | ||
636 | .reg = 0x22c, | ||
637 | .bit = 13, | ||
638 | }, | ||
639 | .la = { | ||
640 | .reg = 0x368, | ||
641 | .shift = 0, | ||
642 | .mask = 0xff, | ||
643 | .def = 0xb2, | ||
644 | }, | ||
645 | }, { | ||
646 | .id = 0x2e, | ||
647 | .name = "viwv", | ||
648 | .swgroup = TEGRA_SWGROUP_VI, | ||
649 | .smmu = { | ||
650 | .reg = 0x22c, | ||
651 | .bit = 14, | ||
652 | }, | ||
653 | .la = { | ||
654 | .reg = 0x368, | ||
655 | .shift = 16, | ||
656 | .mask = 0xff, | ||
657 | .def = 0xb2, | ||
658 | }, | ||
659 | }, { | ||
660 | .id = 0x2f, | ||
661 | .name = "viwy", | ||
662 | .swgroup = TEGRA_SWGROUP_VI, | ||
663 | .smmu = { | ||
664 | .reg = 0x22c, | ||
665 | .bit = 15, | ||
666 | }, | ||
667 | .la = { | ||
668 | .reg = 0x36c, | ||
669 | .shift = 0, | ||
670 | .mask = 0xff, | ||
671 | .def = 0x12, | ||
672 | }, | ||
673 | }, { | ||
674 | .id = 0x30, | ||
675 | .name = "g2dw", | ||
676 | .swgroup = TEGRA_SWGROUP_G2, | ||
677 | .smmu = { | ||
678 | .reg = 0x22c, | ||
679 | .bit = 16, | ||
680 | }, | ||
681 | .la = { | ||
682 | .reg = 0x30c, | ||
683 | .shift = 16, | ||
684 | .mask = 0xff, | ||
685 | .def = 0x9, | ||
686 | }, | ||
687 | }, { | ||
688 | .id = 0x31, | ||
689 | .name = "afiw", | ||
690 | .swgroup = TEGRA_SWGROUP_AFI, | ||
691 | .smmu = { | ||
692 | .reg = 0x22c, | ||
693 | .bit = 17, | ||
694 | }, | ||
695 | .la = { | ||
696 | .reg = 0x2e0, | ||
697 | .shift = 16, | ||
698 | .mask = 0xff, | ||
699 | .def = 0x0c, | ||
700 | }, | ||
701 | }, { | ||
702 | .id = 0x32, | ||
703 | .name = "avpcarm7w", | ||
704 | .swgroup = TEGRA_SWGROUP_AVPC, | ||
705 | .smmu = { | ||
706 | .reg = 0x22c, | ||
707 | .bit = 18, | ||
708 | }, | ||
709 | .la = { | ||
710 | .reg = 0x2e4, | ||
711 | .shift = 16, | ||
712 | .mask = 0xff, | ||
713 | .def = 0x0e, | ||
714 | }, | ||
715 | }, { | ||
716 | .id = 0x33, | ||
717 | .name = "fdcdwr", | ||
718 | .swgroup = TEGRA_SWGROUP_NV, | ||
719 | .smmu = { | ||
720 | .reg = 0x22c, | ||
721 | .bit = 19, | ||
722 | }, | ||
723 | .la = { | ||
724 | .reg = 0x338, | ||
725 | .shift = 16, | ||
726 | .mask = 0xff, | ||
727 | .def = 0x0a, | ||
728 | }, | ||
729 | }, { | ||
730 | .id = 0x34, | ||
731 | .name = "fdcwr2", | ||
732 | .swgroup = TEGRA_SWGROUP_NV2, | ||
733 | .smmu = { | ||
734 | .reg = 0x22c, | ||
735 | .bit = 20, | ||
736 | }, | ||
737 | .la = { | ||
738 | .reg = 0x340, | ||
739 | .shift = 16, | ||
740 | .mask = 0xff, | ||
741 | .def = 0x0a, | ||
742 | }, | ||
743 | }, { | ||
744 | .id = 0x35, | ||
745 | .name = "hdaw", | ||
746 | .swgroup = TEGRA_SWGROUP_HDA, | ||
747 | .smmu = { | ||
748 | .reg = 0x22c, | ||
749 | .bit = 21, | ||
750 | }, | ||
751 | .la = { | ||
752 | .reg = 0x318, | ||
753 | .shift = 16, | ||
754 | .mask = 0xff, | ||
755 | .def = 0xff, | ||
756 | }, | ||
757 | }, { | ||
758 | .id = 0x36, | ||
759 | .name = "host1xw", | ||
760 | .swgroup = TEGRA_SWGROUP_HC, | ||
761 | .smmu = { | ||
762 | .reg = 0x22c, | ||
763 | .bit = 22, | ||
764 | }, | ||
765 | .la = { | ||
766 | .reg = 0x314, | ||
767 | .shift = 0, | ||
768 | .mask = 0xff, | ||
769 | .def = 0x10, | ||
770 | }, | ||
771 | }, { | ||
772 | .id = 0x37, | ||
773 | .name = "ispw", | ||
774 | .swgroup = TEGRA_SWGROUP_ISP, | ||
775 | .smmu = { | ||
776 | .reg = 0x22c, | ||
777 | .bit = 23, | ||
778 | }, | ||
779 | .la = { | ||
780 | .reg = 0x31c, | ||
781 | .shift = 0, | ||
782 | .mask = 0xff, | ||
783 | .def = 0xff, | ||
784 | }, | ||
785 | }, { | ||
786 | .id = 0x38, | ||
787 | .name = "mpcorelpw", | ||
788 | .swgroup = TEGRA_SWGROUP_MPCORELP, | ||
789 | .la = { | ||
790 | .reg = 0x324, | ||
791 | .shift = 16, | ||
792 | .mask = 0xff, | ||
793 | .def = 0x0e, | ||
794 | }, | ||
795 | }, { | ||
796 | .id = 0x39, | ||
797 | .name = "mpcorew", | ||
798 | .swgroup = TEGRA_SWGROUP_MPCORE, | ||
799 | .la = { | ||
800 | .reg = 0x320, | ||
801 | .shift = 16, | ||
802 | .mask = 0xff, | ||
803 | .def = 0x0e, | ||
804 | }, | ||
805 | }, { | ||
806 | .id = 0x3a, | ||
807 | .name = "mpecswr", | ||
808 | .swgroup = TEGRA_SWGROUP_MPE, | ||
809 | .smmu = { | ||
810 | .reg = 0x22c, | ||
811 | .bit = 26, | ||
812 | }, | ||
813 | .la = { | ||
814 | .reg = 0x330, | ||
815 | .shift = 16, | ||
816 | .mask = 0xff, | ||
817 | .def = 0xff, | ||
818 | }, | ||
819 | }, { | ||
820 | .id = 0x3b, | ||
821 | .name = "ppcsahbdmaw", | ||
822 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
823 | .smmu = { | ||
824 | .reg = 0x22c, | ||
825 | .bit = 27, | ||
826 | }, | ||
827 | .la = { | ||
828 | .reg = 0x348, | ||
829 | .shift = 0, | ||
830 | .mask = 0xff, | ||
831 | .def = 0x10, | ||
832 | }, | ||
833 | }, { | ||
834 | .id = 0x3c, | ||
835 | .name = "ppcsahbslvw", | ||
836 | .swgroup = TEGRA_SWGROUP_PPCS, | ||
837 | .smmu = { | ||
838 | .reg = 0x22c, | ||
839 | .bit = 28, | ||
840 | }, | ||
841 | .la = { | ||
842 | .reg = 0x348, | ||
843 | .shift = 16, | ||
844 | .mask = 0xff, | ||
845 | .def = 0x06, | ||
846 | }, | ||
847 | }, { | ||
848 | .id = 0x3d, | ||
849 | .name = "sataw", | ||
850 | .swgroup = TEGRA_SWGROUP_SATA, | ||
851 | .smmu = { | ||
852 | .reg = 0x22c, | ||
853 | .bit = 29, | ||
854 | }, | ||
855 | .la = { | ||
856 | .reg = 0x350, | ||
857 | .shift = 16, | ||
858 | .mask = 0xff, | ||
859 | .def = 0x33, | ||
860 | }, | ||
861 | }, { | ||
862 | .id = 0x3e, | ||
863 | .name = "vdebsevw", | ||
864 | .swgroup = TEGRA_SWGROUP_VDE, | ||
865 | .smmu = { | ||
866 | .reg = 0x22c, | ||
867 | .bit = 30, | ||
868 | }, | ||
869 | .la = { | ||
870 | .reg = 0x35c, | ||
871 | .shift = 0, | ||
872 | .mask = 0xff, | ||
873 | .def = 0xff, | ||
874 | }, | ||
875 | }, { | ||
876 | .id = 0x3f, | ||
877 | .name = "vdedbgw", | ||
878 | .swgroup = TEGRA_SWGROUP_VDE, | ||
879 | .smmu = { | ||
880 | .reg = 0x22c, | ||
881 | .bit = 31, | ||
882 | }, | ||
883 | .la = { | ||
884 | .reg = 0x35c, | ||
885 | .shift = 16, | ||
886 | .mask = 0xff, | ||
887 | .def = 0xff, | ||
888 | }, | ||
889 | }, { | ||
890 | .id = 0x40, | ||
891 | .name = "vdembew", | ||
892 | .swgroup = TEGRA_SWGROUP_VDE, | ||
893 | .smmu = { | ||
894 | .reg = 0x230, | ||
895 | .bit = 0, | ||
896 | }, | ||
897 | .la = { | ||
898 | .reg = 0x360, | ||
899 | .shift = 0, | ||
900 | .mask = 0xff, | ||
901 | .def = 0x42, | ||
902 | }, | ||
903 | }, { | ||
904 | .id = 0x41, | ||
905 | .name = "vdetpmw", | ||
906 | .swgroup = TEGRA_SWGROUP_VDE, | ||
907 | .smmu = { | ||
908 | .reg = 0x230, | ||
909 | .bit = 1, | ||
910 | }, | ||
911 | .la = { | ||
912 | .reg = 0x360, | ||
913 | .shift = 16, | ||
914 | .mask = 0xff, | ||
915 | .def = 0x2a, | ||
916 | }, | ||
917 | }, | ||
918 | }; | ||
919 | |||
920 | static const struct tegra_smmu_swgroup tegra30_swgroups[] = { | ||
921 | { .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 }, | ||
922 | { .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 }, | ||
923 | { .swgroup = TEGRA_SWGROUP_EPP, .reg = 0x248 }, | ||
924 | { .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c }, | ||
925 | { .swgroup = TEGRA_SWGROUP_MPE, .reg = 0x264 }, | ||
926 | { .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 }, | ||
927 | { .swgroup = TEGRA_SWGROUP_AFI, .reg = 0x238 }, | ||
928 | { .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c }, | ||
929 | { .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268 }, | ||
930 | { .swgroup = TEGRA_SWGROUP_NV2, .reg = 0x26c }, | ||
931 | { .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 }, | ||
932 | { .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 }, | ||
933 | { .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 }, | ||
934 | { .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x278 }, | ||
935 | { .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c }, | ||
936 | { .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 }, | ||
937 | }; | ||
938 | |||
939 | static void tegra30_flush_dcache(struct page *page, unsigned long offset, | ||
940 | size_t size) | ||
941 | { | ||
942 | phys_addr_t phys = page_to_phys(page) + offset; | ||
943 | void *virt = page_address(page) + offset; | ||
944 | |||
945 | __cpuc_flush_dcache_area(virt, size); | ||
946 | outer_flush_range(phys, phys + size); | ||
947 | } | ||
948 | |||
949 | static const struct tegra_smmu_ops tegra30_smmu_ops = { | ||
950 | .flush_dcache = tegra30_flush_dcache, | ||
951 | }; | ||
952 | |||
953 | static const struct tegra_smmu_soc tegra30_smmu_soc = { | ||
954 | .clients = tegra30_mc_clients, | ||
955 | .num_clients = ARRAY_SIZE(tegra30_mc_clients), | ||
956 | .swgroups = tegra30_swgroups, | ||
957 | .num_swgroups = ARRAY_SIZE(tegra30_swgroups), | ||
958 | .supports_round_robin_arbitration = false, | ||
959 | .supports_request_limit = false, | ||
960 | .num_asids = 4, | ||
961 | .ops = &tegra30_smmu_ops, | ||
962 | }; | ||
963 | |||
964 | const struct tegra_mc_soc tegra30_mc_soc = { | ||
965 | .clients = tegra30_mc_clients, | ||
966 | .num_clients = ARRAY_SIZE(tegra30_mc_clients), | ||
967 | .num_address_bits = 32, | ||
968 | .atom_size = 16, | ||
969 | .smmu = &tegra30_smmu_soc, | ||
970 | }; | ||
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c deleted file mode 100644 index ef7934535fd1..000000000000 --- a/drivers/memory/tegra30-mc.c +++ /dev/null | |||
@@ -1,378 +0,0 @@ | |||
1 | /* | ||
2 | * Tegra30 Memory Controller | ||
3 | * | ||
4 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/err.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/ratelimit.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/io.h> | ||
27 | |||
28 | #define DRV_NAME "tegra30-mc" | ||
29 | |||
30 | #define MC_INTSTATUS 0x0 | ||
31 | #define MC_INTMASK 0x4 | ||
32 | |||
33 | #define MC_INT_ERR_SHIFT 6 | ||
34 | #define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT) | ||
35 | #define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT) | ||
36 | #define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2) | ||
37 | #define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3) | ||
38 | #define MC_INT_INVALID_SMMU_PAGE BIT(MC_INT_ERR_SHIFT + 4) | ||
39 | |||
40 | #define MC_ERR_STATUS 0x8 | ||
41 | #define MC_ERR_ADR 0xc | ||
42 | |||
43 | #define MC_ERR_TYPE_SHIFT 28 | ||
44 | #define MC_ERR_TYPE_MASK (7 << MC_ERR_TYPE_SHIFT) | ||
45 | #define MC_ERR_TYPE_DECERR_EMEM 2 | ||
46 | #define MC_ERR_TYPE_SECURITY_TRUSTZONE 3 | ||
47 | #define MC_ERR_TYPE_SECURITY_CARVEOUT 4 | ||
48 | #define MC_ERR_TYPE_INVALID_SMMU_PAGE 6 | ||
49 | |||
50 | #define MC_ERR_INVALID_SMMU_PAGE_SHIFT 25 | ||
51 | #define MC_ERR_INVALID_SMMU_PAGE_MASK (7 << MC_ERR_INVALID_SMMU_PAGE_SHIFT) | ||
52 | #define MC_ERR_RW_SHIFT 16 | ||
53 | #define MC_ERR_RW BIT(MC_ERR_RW_SHIFT) | ||
54 | #define MC_ERR_SECURITY BIT(MC_ERR_RW_SHIFT + 1) | ||
55 | |||
56 | #define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */ | ||
57 | |||
58 | #define MC_EMEM_ARB_CFG 0x90 | ||
59 | #define MC_EMEM_ARB_OUTSTANDING_REQ 0x94 | ||
60 | #define MC_EMEM_ARB_TIMING_RCD 0x98 | ||
61 | #define MC_EMEM_ARB_TIMING_RP 0x9c | ||
62 | #define MC_EMEM_ARB_TIMING_RC 0xa0 | ||
63 | #define MC_EMEM_ARB_TIMING_RAS 0xa4 | ||
64 | #define MC_EMEM_ARB_TIMING_FAW 0xa8 | ||
65 | #define MC_EMEM_ARB_TIMING_RRD 0xac | ||
66 | #define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0 | ||
67 | #define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4 | ||
68 | #define MC_EMEM_ARB_TIMING_R2R 0xb8 | ||
69 | #define MC_EMEM_ARB_TIMING_W2W 0xbc | ||
70 | #define MC_EMEM_ARB_TIMING_R2W 0xc0 | ||
71 | #define MC_EMEM_ARB_TIMING_W2R 0xc4 | ||
72 | |||
73 | #define MC_EMEM_ARB_DA_TURNS 0xd0 | ||
74 | #define MC_EMEM_ARB_DA_COVERS 0xd4 | ||
75 | #define MC_EMEM_ARB_MISC0 0xd8 | ||
76 | #define MC_EMEM_ARB_MISC1 0xdc | ||
77 | |||
78 | #define MC_EMEM_ARB_RING3_THROTTLE 0xe4 | ||
79 | #define MC_EMEM_ARB_OVERRIDE 0xe8 | ||
80 | |||
81 | #define MC_TIMING_CONTROL 0xfc | ||
82 | |||
83 | #define MC_CLIENT_ID_MASK 0x7f | ||
84 | |||
85 | #define NUM_MC_REG_BANKS 4 | ||
86 | |||
87 | struct tegra30_mc { | ||
88 | void __iomem *regs[NUM_MC_REG_BANKS]; | ||
89 | struct device *dev; | ||
90 | u32 ctx[0]; | ||
91 | }; | ||
92 | |||
93 | static inline u32 mc_readl(struct tegra30_mc *mc, u32 offs) | ||
94 | { | ||
95 | u32 val = 0; | ||
96 | |||
97 | if (offs < 0x10) | ||
98 | val = readl(mc->regs[0] + offs); | ||
99 | else if (offs < 0x1f0) | ||
100 | val = readl(mc->regs[1] + offs - 0x3c); | ||
101 | else if (offs < 0x228) | ||
102 | val = readl(mc->regs[2] + offs - 0x200); | ||
103 | else if (offs < 0x400) | ||
104 | val = readl(mc->regs[3] + offs - 0x284); | ||
105 | |||
106 | return val; | ||
107 | } | ||
108 | |||
109 | static inline void mc_writel(struct tegra30_mc *mc, u32 val, u32 offs) | ||
110 | { | ||
111 | if (offs < 0x10) | ||
112 | writel(val, mc->regs[0] + offs); | ||
113 | else if (offs < 0x1f0) | ||
114 | writel(val, mc->regs[1] + offs - 0x3c); | ||
115 | else if (offs < 0x228) | ||
116 | writel(val, mc->regs[2] + offs - 0x200); | ||
117 | else if (offs < 0x400) | ||
118 | writel(val, mc->regs[3] + offs - 0x284); | ||
119 | } | ||
120 | |||
121 | static const char * const tegra30_mc_client[] = { | ||
122 | "csr_ptcr", | ||
123 | "cbr_display0a", | ||
124 | "cbr_display0ab", | ||
125 | "cbr_display0b", | ||
126 | "cbr_display0bb", | ||
127 | "cbr_display0c", | ||
128 | "cbr_display0cb", | ||
129 | "cbr_display1b", | ||
130 | "cbr_display1bb", | ||
131 | "cbr_eppup", | ||
132 | "cbr_g2pr", | ||
133 | "cbr_g2sr", | ||
134 | "cbr_mpeunifbr", | ||
135 | "cbr_viruv", | ||
136 | "csr_afir", | ||
137 | "csr_avpcarm7r", | ||
138 | "csr_displayhc", | ||
139 | "csr_displayhcb", | ||
140 | "csr_fdcdrd", | ||
141 | "csr_fdcdrd2", | ||
142 | "csr_g2dr", | ||
143 | "csr_hdar", | ||
144 | "csr_host1xdmar", | ||
145 | "csr_host1xr", | ||
146 | "csr_idxsrd", | ||
147 | "csr_idxsrd2", | ||
148 | "csr_mpe_ipred", | ||
149 | "csr_mpeamemrd", | ||
150 | "csr_mpecsrd", | ||
151 | "csr_ppcsahbdmar", | ||
152 | "csr_ppcsahbslvr", | ||
153 | "csr_satar", | ||
154 | "csr_texsrd", | ||
155 | "csr_texsrd2", | ||
156 | "csr_vdebsevr", | ||
157 | "csr_vdember", | ||
158 | "csr_vdemcer", | ||
159 | "csr_vdetper", | ||
160 | "csr_mpcorelpr", | ||
161 | "csr_mpcorer", | ||
162 | "cbw_eppu", | ||
163 | "cbw_eppv", | ||
164 | "cbw_eppy", | ||
165 | "cbw_mpeunifbw", | ||
166 | "cbw_viwsb", | ||
167 | "cbw_viwu", | ||
168 | "cbw_viwv", | ||
169 | "cbw_viwy", | ||
170 | "ccw_g2dw", | ||
171 | "csw_afiw", | ||
172 | "csw_avpcarm7w", | ||
173 | "csw_fdcdwr", | ||
174 | "csw_fdcdwr2", | ||
175 | "csw_hdaw", | ||
176 | "csw_host1xw", | ||
177 | "csw_ispw", | ||
178 | "csw_mpcorelpw", | ||
179 | "csw_mpcorew", | ||
180 | "csw_mpecswr", | ||
181 | "csw_ppcsahbdmaw", | ||
182 | "csw_ppcsahbslvw", | ||
183 | "csw_sataw", | ||
184 | "csw_vdebsevw", | ||
185 | "csw_vdedbgw", | ||
186 | "csw_vdembew", | ||
187 | "csw_vdetpmw", | ||
188 | }; | ||
189 | |||
190 | static void tegra30_mc_decode(struct tegra30_mc *mc, int n) | ||
191 | { | ||
192 | u32 err, addr; | ||
193 | const char * const mc_int_err[] = { | ||
194 | "MC_DECERR", | ||
195 | "Unknown", | ||
196 | "MC_SECURITY_ERR", | ||
197 | "MC_ARBITRATION_EMEM", | ||
198 | "MC_SMMU_ERR", | ||
199 | }; | ||
200 | const char * const err_type[] = { | ||
201 | "Unknown", | ||
202 | "Unknown", | ||
203 | "DECERR_EMEM", | ||
204 | "SECURITY_TRUSTZONE", | ||
205 | "SECURITY_CARVEOUT", | ||
206 | "Unknown", | ||
207 | "INVALID_SMMU_PAGE", | ||
208 | "Unknown", | ||
209 | }; | ||
210 | char attr[6]; | ||
211 | int cid, perm, type, idx; | ||
212 | const char *client = "Unknown"; | ||
213 | |||
214 | idx = n - MC_INT_ERR_SHIFT; | ||
215 | if ((idx < 0) || (idx >= ARRAY_SIZE(mc_int_err)) || (idx == 1)) { | ||
216 | dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n", | ||
217 | BIT(n)); | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | err = mc_readl(mc, MC_ERR_STATUS); | ||
222 | |||
223 | type = (err & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT; | ||
224 | perm = (err & MC_ERR_INVALID_SMMU_PAGE_MASK) >> | ||
225 | MC_ERR_INVALID_SMMU_PAGE_SHIFT; | ||
226 | if (type == MC_ERR_TYPE_INVALID_SMMU_PAGE) | ||
227 | sprintf(attr, "%c-%c-%c", | ||
228 | (perm & BIT(2)) ? 'R' : '-', | ||
229 | (perm & BIT(1)) ? 'W' : '-', | ||
230 | (perm & BIT(0)) ? 'S' : '-'); | ||
231 | else | ||
232 | attr[0] = '\0'; | ||
233 | |||
234 | cid = err & MC_CLIENT_ID_MASK; | ||
235 | if (cid < ARRAY_SIZE(tegra30_mc_client)) | ||
236 | client = tegra30_mc_client[cid]; | ||
237 | |||
238 | addr = mc_readl(mc, MC_ERR_ADR); | ||
239 | |||
240 | dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s %s %s)\n", | ||
241 | mc_int_err[idx], err, addr, client, | ||
242 | (err & MC_ERR_SECURITY) ? "secure" : "non-secure", | ||
243 | (err & MC_ERR_RW) ? "write" : "read", | ||
244 | err_type[type], attr); | ||
245 | } | ||
246 | |||
247 | static const u32 tegra30_mc_ctx[] = { | ||
248 | MC_EMEM_ARB_CFG, | ||
249 | MC_EMEM_ARB_OUTSTANDING_REQ, | ||
250 | MC_EMEM_ARB_TIMING_RCD, | ||
251 | MC_EMEM_ARB_TIMING_RP, | ||
252 | MC_EMEM_ARB_TIMING_RC, | ||
253 | MC_EMEM_ARB_TIMING_RAS, | ||
254 | MC_EMEM_ARB_TIMING_FAW, | ||
255 | MC_EMEM_ARB_TIMING_RRD, | ||
256 | MC_EMEM_ARB_TIMING_RAP2PRE, | ||
257 | MC_EMEM_ARB_TIMING_WAP2PRE, | ||
258 | MC_EMEM_ARB_TIMING_R2R, | ||
259 | MC_EMEM_ARB_TIMING_W2W, | ||
260 | MC_EMEM_ARB_TIMING_R2W, | ||
261 | MC_EMEM_ARB_TIMING_W2R, | ||
262 | MC_EMEM_ARB_DA_TURNS, | ||
263 | MC_EMEM_ARB_DA_COVERS, | ||
264 | MC_EMEM_ARB_MISC0, | ||
265 | MC_EMEM_ARB_MISC1, | ||
266 | MC_EMEM_ARB_RING3_THROTTLE, | ||
267 | MC_EMEM_ARB_OVERRIDE, | ||
268 | MC_INTMASK, | ||
269 | }; | ||
270 | |||
271 | #ifdef CONFIG_PM | ||
272 | static int tegra30_mc_suspend(struct device *dev) | ||
273 | { | ||
274 | int i; | ||
275 | struct tegra30_mc *mc = dev_get_drvdata(dev); | ||
276 | |||
277 | for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++) | ||
278 | mc->ctx[i] = mc_readl(mc, tegra30_mc_ctx[i]); | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int tegra30_mc_resume(struct device *dev) | ||
283 | { | ||
284 | int i; | ||
285 | struct tegra30_mc *mc = dev_get_drvdata(dev); | ||
286 | |||
287 | for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++) | ||
288 | mc_writel(mc, mc->ctx[i], tegra30_mc_ctx[i]); | ||
289 | |||
290 | mc_writel(mc, 1, MC_TIMING_CONTROL); | ||
291 | /* Read-back to ensure that write reached */ | ||
292 | mc_readl(mc, MC_TIMING_CONTROL); | ||
293 | return 0; | ||
294 | } | ||
295 | #endif | ||
296 | |||
297 | static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm, | ||
298 | tegra30_mc_suspend, | ||
299 | tegra30_mc_resume, NULL); | ||
300 | |||
301 | static const struct of_device_id tegra30_mc_of_match[] = { | ||
302 | { .compatible = "nvidia,tegra30-mc", }, | ||
303 | {}, | ||
304 | }; | ||
305 | |||
306 | static irqreturn_t tegra30_mc_isr(int irq, void *data) | ||
307 | { | ||
308 | u32 stat, mask, bit; | ||
309 | struct tegra30_mc *mc = data; | ||
310 | |||
311 | stat = mc_readl(mc, MC_INTSTATUS); | ||
312 | mask = mc_readl(mc, MC_INTMASK); | ||
313 | mask &= stat; | ||
314 | if (!mask) | ||
315 | return IRQ_NONE; | ||
316 | while ((bit = ffs(mask)) != 0) { | ||
317 | tegra30_mc_decode(mc, bit - 1); | ||
318 | mask &= ~BIT(bit - 1); | ||
319 | } | ||
320 | |||
321 | mc_writel(mc, stat, MC_INTSTATUS); | ||
322 | return IRQ_HANDLED; | ||
323 | } | ||
324 | |||
325 | static int tegra30_mc_probe(struct platform_device *pdev) | ||
326 | { | ||
327 | struct resource *irq; | ||
328 | struct tegra30_mc *mc; | ||
329 | size_t bytes; | ||
330 | int err, i; | ||
331 | u32 intmask; | ||
332 | |||
333 | bytes = sizeof(*mc) + sizeof(u32) * ARRAY_SIZE(tegra30_mc_ctx); | ||
334 | mc = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL); | ||
335 | if (!mc) | ||
336 | return -ENOMEM; | ||
337 | mc->dev = &pdev->dev; | ||
338 | |||
339 | for (i = 0; i < ARRAY_SIZE(mc->regs); i++) { | ||
340 | struct resource *res; | ||
341 | |||
342 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
343 | mc->regs[i] = devm_ioremap_resource(&pdev->dev, res); | ||
344 | if (IS_ERR(mc->regs[i])) | ||
345 | return PTR_ERR(mc->regs[i]); | ||
346 | } | ||
347 | |||
348 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
349 | if (!irq) | ||
350 | return -ENODEV; | ||
351 | err = devm_request_irq(&pdev->dev, irq->start, tegra30_mc_isr, | ||
352 | IRQF_SHARED, dev_name(&pdev->dev), mc); | ||
353 | if (err) | ||
354 | return -ENODEV; | ||
355 | |||
356 | platform_set_drvdata(pdev, mc); | ||
357 | |||
358 | intmask = MC_INT_INVALID_SMMU_PAGE | | ||
359 | MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION; | ||
360 | mc_writel(mc, intmask, MC_INTMASK); | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static struct platform_driver tegra30_mc_driver = { | ||
365 | .probe = tegra30_mc_probe, | ||
366 | .driver = { | ||
367 | .name = DRV_NAME, | ||
368 | .owner = THIS_MODULE, | ||
369 | .of_match_table = tegra30_mc_of_match, | ||
370 | .pm = &tegra30_mc_pm, | ||
371 | }, | ||
372 | }; | ||
373 | module_platform_driver(tegra30_mc_driver); | ||
374 | |||
375 | MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); | ||
376 | MODULE_DESCRIPTION("Tegra30 MC driver"); | ||
377 | MODULE_LICENSE("GPL v2"); | ||
378 | MODULE_ALIAS("platform:" DRV_NAME); | ||