aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/common-t3.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /arch/arm/mach-tegra/common-t3.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'arch/arm/mach-tegra/common-t3.c')
-rw-r--r--arch/arm/mach-tegra/common-t3.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/common-t3.c b/arch/arm/mach-tegra/common-t3.c
new file mode 100644
index 00000000000..1a9bd755e28
--- /dev/null
+++ b/arch/arm/mach-tegra/common-t3.c
@@ -0,0 +1,268 @@
1/*
2 * arch/arm/mach-tegra/common-t3.c
3 *
4 * Tegra 3 SoC-specific initialization (memory controller, etc.)
5 *
6 * Copyright (c) 2010-2011, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#include <linux/kernel.h>
24#include <linux/io.h>
25#include <linux/interrupt.h>
26#include <linux/spinlock.h>
27
28#include <mach/iomap.h>
29#include <mach/irqs.h>
30
31#include "tegra3_emc.h"
32
33#define MC_INT_STATUS 0x0
34#define MC_INT_MASK 0x4
35#define MC_INT_DECERR_EMEM (1<<6)
36#define MC_INT_SECURITY_VIOLATION (1<<8)
37#define MC_INT_ARBITRATION_EMEM (1<<9)
38#define MC_INT_INVALID_SMMU_PAGE (1<<10)
39
40#define MC_ERROR_STATUS 0x8
41#define MC_ERROR_ADDRESS 0xC
42
43#define MC_TIMING_REG_NUM1 \
44 ((MC_EMEM_ARB_TIMING_W2R - MC_EMEM_ARB_CFG) / 4 + 1)
45#define MC_TIMING_REG_NUM2 \
46 ((MC_EMEM_ARB_MISC1 - MC_EMEM_ARB_DA_TURNS) / 4 + 1)
47
48struct mc_client {
49 const char *name;
50};
51
52#define client(_name) \
53 { \
54 .name = _name, \
55 }
56
57
58static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
59
60
61#ifdef CONFIG_PM_SLEEP
62static u32 mc_boot_timing[MC_TIMING_REG_NUM1 + MC_TIMING_REG_NUM2 + 4];
63
64static void tegra_mc_timing_save(void)
65{
66 u32 off;
67 u32 *ctx = mc_boot_timing;
68
69 for (off = MC_EMEM_ARB_CFG; off <= MC_EMEM_ARB_TIMING_W2R; off += 4)
70 *ctx++ = readl((u32)mc + off);
71
72 for (off = MC_EMEM_ARB_DA_TURNS; off <= MC_EMEM_ARB_MISC1; off += 4)
73 *ctx++ = readl((u32)mc + off);
74
75 *ctx++ = readl((u32)mc + MC_EMEM_ARB_RING3_THROTTLE);
76 *ctx++ = readl((u32)mc + MC_EMEM_ARB_OVERRIDE);
77 *ctx++ = readl((u32)mc + MC_RESERVED_RSV);
78
79 *ctx++ = readl((u32)mc + MC_INT_MASK);
80}
81
82void tegra_mc_timing_restore(void)
83{
84 u32 off;
85 u32 *ctx = mc_boot_timing;
86
87 for (off = MC_EMEM_ARB_CFG; off <= MC_EMEM_ARB_TIMING_W2R; off += 4)
88 __raw_writel(*ctx++, (u32)mc + off);
89
90 for (off = MC_EMEM_ARB_DA_TURNS; off <= MC_EMEM_ARB_MISC1; off += 4)
91 __raw_writel(*ctx++, (u32)mc + off);
92
93 __raw_writel(*ctx++, (u32)mc + MC_EMEM_ARB_RING3_THROTTLE);
94 __raw_writel(*ctx++, (u32)mc + MC_EMEM_ARB_OVERRIDE);
95 __raw_writel(*ctx++, (u32)mc + MC_RESERVED_RSV);
96
97 writel(*ctx++, (u32)mc + MC_INT_MASK);
98 off = readl((u32)mc + MC_INT_MASK);
99
100 writel(0x1, (u32)mc + MC_TIMING_CONTROL);
101 off = readl((u32)mc + MC_TIMING_CONTROL);
102}
103#else
104#define tegra_mc_timing_save()
105#endif
106
107
108static const struct mc_client mc_clients[] = {
109 client("ptc"),
110 client("display0_wina"), client("display1_wina"),
111 client("display0_winb"), client("display1_winb"),
112 client("display0_winc"), client("display1_winc"),
113 client("display0_winb_vfilter"),
114 client("display1_winb_vfilter"),
115 client("epp"), client("gr2d_pat"),
116 client("gr2d_src"), client("mpe_unified"),
117 client("vi_chroma_filter"), client("pcie"),
118 client("avp"),
119 client("display0_cursor"), client("display1_cursor"),
120 client("gr3d0_fdc"), client("gr3d1_fdc"),
121 client("gr2d_dst"), client("hda"),
122 client("host1x_dma"), client("host1x_generic"),
123 client("gr3d0_idx"), client("gr3d1_idx"),
124 client("mpe_intrapred"), client("mpe_mpea"),
125 client("mpe_mpec"), client("ahb_dma"),
126 client("ahb_slave"), client("sata"),
127 client("gr3d0_tex"), client("gr3d1_tex"),
128 client("vde_bsev"), client("vde_mbe"),
129 client("vde_mce"), client("vde_tpe"),
130 client("cpu_lp"), client("cpu"),
131 client("epp_u"), client("epp_v"),
132 client("epp_y"), client("mpe_unified"),
133 client("vi_sb"), client("vi_u"),
134 client("vi_v"), client("vi_y"),
135 client("gr2d_dst"), client("pcie"),
136 client("avp"), client("gr3d0_fdc"),
137 client("gr3d1_fdc"), client("hda"),
138 client("host1x"), client("isp"),
139 client("cpu_lp"), client("cpu"),
140 client("mpe_mpec"), client("ahb_dma"),
141 client("ahb_slave"), client("sata"),
142 client("vde_bsev"), client("vde_dbg"),
143 client("vde_mbe"), client("vde_tpm"),
144};
145
146static const char *smmu_page_attrib[] = {
147 "SMMU: nr-nw-s",
148 "SMMU: nr-nw-ns",
149 "SMMU: nr-wr-s",
150 "SMMU: nr-wr-ns",
151 "SMMU: rd-nw-s",
152 "SMMU: rd-nw-ns",
153 "SMMU: rd-wr-s",
154 "SMMU: rd-wr-ns"
155};
156
157static DEFINE_SPINLOCK(mc_lock);
158static unsigned long error_count = 0;
159#define MAX_PRINTS 5
160
161static void unthrottle_prints(struct work_struct *work)
162{
163 unsigned long flags;
164
165 spin_lock_irqsave(&mc_lock, flags);
166 error_count = 0;
167 spin_unlock_irqrestore(&mc_lock, flags);
168}
169
170static DECLARE_DELAYED_WORK(unthrottle_prints_work, unthrottle_prints);
171
172static irqreturn_t tegra_mc_error_isr(int irq, void *data)
173{
174 const struct mc_client *client = NULL;
175 const char *mc_err;
176 const char *mc_err_info;
177 unsigned long count;
178 u32 stat;
179 u32 addr;
180 u32 err;
181 u32 type;
182 u32 is_write;
183 u32 is_secure;
184 u32 client_id;
185
186 stat = readl(mc + MC_INT_STATUS);
187 stat &= (MC_INT_DECERR_EMEM |
188 MC_INT_SECURITY_VIOLATION |
189 MC_INT_INVALID_SMMU_PAGE);
190
191 __cancel_delayed_work(&unthrottle_prints_work);
192
193 spin_lock(&mc_lock);
194 count = ++error_count;
195 spin_unlock(&mc_lock);
196
197 if (count >= MAX_PRINTS) {
198 if (count == MAX_PRINTS)
199 pr_err("Too many MC errors; throttling prints\n");
200 schedule_delayed_work(&unthrottle_prints_work, HZ/2);
201 goto out;
202 }
203
204 err = readl(mc + MC_ERROR_STATUS);
205 addr = readl(mc + MC_ERROR_ADDRESS);
206 is_write = err & (1<<16);
207 is_secure = err & (1<<17);
208 type = (err >> 28) & 7;
209 client_id = err & 0x7f;
210 if (client_id < ARRAY_SIZE(mc_clients))
211 client = &mc_clients[client_id];
212
213 if (stat & MC_INT_DECERR_EMEM)
214 mc_err = "MC_DECERR";
215 else if (stat & MC_INT_SECURITY_VIOLATION)
216 mc_err = "MC_SECURITY_ERR";
217 else if (stat & MC_INT_INVALID_SMMU_PAGE)
218 mc_err = "MC_SMMU_ERR";
219 else
220 mc_err = "unknown";
221
222 mc_err_info = "";
223 if (type == 3) {
224 mc_err_info = "SECURITY_TRUSTZONE";
225 } else if (type == 4) {
226 mc_err_info = "SECURITY_CARVEOUT";
227 } else if (type == 6) {
228 u32 attrib = (err >> 25) & 7;
229 mc_err_info = smmu_page_attrib[attrib];
230 }
231
232 pr_err("%s (0x%08X): %p %s (%s %s %s)\n", mc_err, err, (void*)addr,
233 (client) ? client->name : "unknown",
234 (is_secure)? "secure" : "non-secure",
235 (is_write) ? "write" : "read",
236 mc_err_info);
237
238out:
239 writel(stat, mc + MC_INT_STATUS);
240 return IRQ_HANDLED;
241}
242
243int __init tegra_mc_init(void)
244{
245 u32 reg;
246 int ret = 0;
247
248 reg = 0x0F7F1010;
249 writel(reg, mc + MC_RESERVED_RSV);
250
251 reg = readl(mc + MC_EMEM_ARB_OVERRIDE);
252 reg |= 3;
253 writel(reg, mc + MC_EMEM_ARB_OVERRIDE);
254
255 if (request_irq(INT_MC_GENERAL, tegra_mc_error_isr, 0,
256 "mc_status", NULL)) {
257 pr_err("%s: unable to register MC error interrupt\n", __func__);
258 ret = -ENXIO;
259 } else {
260 reg = MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION |
261 MC_INT_INVALID_SMMU_PAGE;
262 writel(reg, mc + MC_INT_MASK);
263 }
264 tegra_mc_timing_save();
265
266 return ret;
267}
268arch_initcall(tegra_mc_init);