aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-04-16 03:24:44 -0400
committerThierry Reding <treding@nvidia.com>2014-12-04 10:11:47 -0500
commit8918465163171322c77a19d5258a95f56d89d2e4 (patch)
tree4d818b6d61af15bffc6c60316c7b5d64efb01bde /drivers
parent4bc567dd60a1cfa9abd8484cff2de31cdf51649d (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/Kconfig12
-rw-r--r--drivers/iommu/tegra-smmu.c1610
-rw-r--r--drivers/memory/Kconfig12
-rw-r--r--drivers/memory/Makefile3
-rw-r--r--drivers/memory/tegra/Kconfig7
-rw-r--r--drivers/memory/tegra/Makefile7
-rw-r--r--drivers/memory/tegra/mc.c301
-rw-r--r--drivers/memory/tegra/mc.h40
-rw-r--r--drivers/memory/tegra/tegra114.c948
-rw-r--r--drivers/memory/tegra/tegra124.c995
-rw-r--r--drivers/memory/tegra/tegra30.c970
-rw-r--r--drivers/memory/tegra30-mc.c378
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
165config TEGRA_IOMMU_SMMU 165config 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
175config EXYNOS_IOMMU 175config 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> 20struct tegra_smmu {
42#include <asm/cacheflush.h> 21 void __iomem *regs;
43 22 struct device *dev;
44enum 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 */
92enum {
93 _MC = 0,
94};
95 26
96enum { 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
241static 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/* 33struct tegra_smmu_as {
262 * Per client for address space 34 struct iommu_domain *domain;
263 */ 35 struct tegra_smmu *smmu;
264struct 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/* 43static inline void smmu_writel(struct tegra_smmu *smmu, u32 value,
272 * Per address space 44 unsigned long offset)
273 */ 45{
274struct 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
288struct smmu_debugfs_info { 49static 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 */
297struct 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
327static 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)
332static 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
347static 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
356static 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) 128static inline void smmu_flush_ptc(struct tegra_smmu *smmu, struct page *page,
384 129 unsigned long offset)
385static 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
416err_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
426static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on) 154static 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/* 159static 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 */
443static 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
458static int smmu_setup_regs(struct smmu_device *smmu) 169static 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
489static void flush_ptc_and_tlb(struct smmu_device *smmu, 180static 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
508static 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
525static void free_pdir(struct smmu_as *as) 191static 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/* 196static 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 */
551static 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 215static void tegra_smmu_free_asid(struct tegra_smmu *smmu, unsigned int id)
599static 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
615static inline void put_signature(struct smmu_as *as, 222static 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/* 227static int tegra_smmu_domain_init(struct iommu_domain *domain)
622 * Caller must not hold as->lock
623 */
624static 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
677err_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
686static void __smmu_iommu_unmap(struct smmu_as *as, dma_addr_t iova) 272static 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
706static void __smmu_iommu_map_pfn(struct smmu_as *as, dma_addr_t iova, 282static const struct tegra_smmu_swgroup *
707 unsigned long pfn) 283tegra_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
728static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova, 298static 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
746static 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
760static phys_addr_t smmu_iommu_iova_to_phys(struct iommu_domain *domain, 326static 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
783static 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
788static int smmu_iommu_attach_dev(struct iommu_domain *domain, 354static 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
838err_client: 381 return 0;
839 smmu_client_disable_hwgrp(client);
840 spin_unlock(&as->client_lock);
841err_hwgrp:
842 devm_kfree(smmu->dev, client);
843 return err;
844} 382}
845 383
846static void smmu_iommu_detach_dev(struct iommu_domain *domain, 384static 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));
867out:
868 spin_unlock(&as->client_lock);
869} 392}
870 393
871static int smmu_iommu_domain_init(struct iommu_domain *domain) 394static 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
896found: 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); 429static 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
919static void smmu_iommu_domain_destroy(struct iommu_domain *domain) 454static 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
950static 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 */
964static const char * const smmu_debugfs_mc[] = { "mc", };
965static const char * const smmu_debugfs_cache[] = { "tlb", "ptc", };
966 497
967static ssize_t smmu_debugfs_stats_write(struct file *file, 498static 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
1033static int smmu_debugfs_stats_show(struct seq_file *s, void *v) 524static 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
1056static int smmu_debugfs_stats_open(struct inode *inode, struct file *file) 548static 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
1061static 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
1069static 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
1075static void smmu_debugfs_create(struct smmu_device *smmu) 572static 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
1121err_out: 583 return PFN_PHYS(pfn);
1122 smmu_debugfs_delete(smmu);
1123} 584}
1124 585
1125static int tegra_smmu_suspend(struct device *dev) 586static 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
1136static int tegra_smmu_resume(struct device *dev) 602static 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
1148static int tegra_smmu_probe(struct platform_device *pdev) 629static 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) 634static 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)) 650static 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; 665struct 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
1243static 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
1258static 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
1263static 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};
1267MODULE_DEVICE_TABLE(of, tegra_smmu_of_match);
1268
1269static 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
1280static 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
1285static 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
1290subsys_initcall(tegra_smmu_init); 727 err = bus_set_iommu(&platform_bus_type, &tegra_smmu_ops);
1291module_exit(tegra_smmu_exit); 728 if (err < 0)
729 return ERR_PTR(err);
1292 730
1293MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30"); 731 return smmu;
1294MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); 732}
1295MODULE_ALIAS("platform:tegra-smmu");
1296MODULE_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
64config 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
74config FSL_CORENET_CF 64config 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
78source "drivers/memory/tegra/Kconfig"
79
88endif 80endif
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
12obj-$(CONFIG_FSL_IFC) += fsl_ifc.o 12obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
13obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o 13obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
14obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o 14obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
15obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o 15
16obj-$(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 @@
1config 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 @@
1tegra-mc-y := mc.o
2
3tegra-mc-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30.o
4tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o
5tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o
6
7obj-$(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
51static 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};
63MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
64
65static 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
94static 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
106static 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
113static 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
209static 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
283static 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
293static int tegra_mc_init(void)
294{
295 return platform_driver_register(&tegra_mc_driver);
296}
297arch_initcall(tegra_mc_init);
298
299MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
300MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver");
301MODULE_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
17static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
18{
19 return readl(mc->regs + offset);
20}
21
22static 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
29extern const struct tegra_mc_soc tegra30_mc_soc;
30#endif
31
32#ifdef CONFIG_ARCH_TEGRA_114_SOC
33extern const struct tegra_mc_soc tegra114_mc_soc;
34#endif
35
36#ifdef CONFIG_ARCH_TEGRA_124_SOC
37extern 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
18static 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
898static 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
917static 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
927static const struct tegra_smmu_ops tegra114_smmu_ops = {
928 .flush_dcache = tegra114_flush_dcache,
929};
930
931static 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
942const 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
18static 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
936static 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
963static 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
973static const struct tegra_smmu_ops tegra124_smmu_ops = {
974 .flush_dcache = tegra124_flush_dcache,
975};
976
977static 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
988const 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
18static 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
920static 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
939static 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
949static const struct tegra_smmu_ops tegra30_smmu_ops = {
950 .flush_dcache = tegra30_flush_dcache,
951};
952
953static 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
964const 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
87struct tegra30_mc {
88 void __iomem *regs[NUM_MC_REG_BANKS];
89 struct device *dev;
90 u32 ctx[0];
91};
92
93static 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
109static 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
121static 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
190static 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
247static 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
272static 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
282static 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
297static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
298 tegra30_mc_suspend,
299 tegra30_mc_resume, NULL);
300
301static const struct of_device_id tegra30_mc_of_match[] = {
302 { .compatible = "nvidia,tegra30-mc", },
303 {},
304};
305
306static 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
325static 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
364static 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};
373module_platform_driver(tegra30_mc_driver);
374
375MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
376MODULE_DESCRIPTION("Tegra30 MC driver");
377MODULE_LICENSE("GPL v2");
378MODULE_ALIAS("platform:" DRV_NAME);