aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/common-t2.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/common-t2.c')
-rw-r--r--arch/arm/mach-tegra/common-t2.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/common-t2.c b/arch/arm/mach-tegra/common-t2.c
new file mode 100644
index 00000000000..6f9b177892c
--- /dev/null
+++ b/arch/arm/mach-tegra/common-t2.c
@@ -0,0 +1,192 @@
1/*
2 * arch/arm/mach-tegra/common-t2.c
3 *
4 * Tegra 2 SoC-specific initialization (memory controller, etc.)
5 *
6 * Copyright (c) 2009-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#define MC_INT_STATUS 0x0
32#define MC_INT_MASK 0x4
33#define MC_INT_DECERR_EMEM_OTHERS (1<<6)
34#define MC_INT_INVALID_GART_PAGE (1<<7)
35#define MC_INT_SECURITY_VIOLATION (1<<8)
36
37#define MC_GART_ERROR_STATUS 0x30
38#define MC_GART_ERROR_ADDRESS 0x34
39
40#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
41#define MC_DECERR_EMEM_OTHERS_ADDRESS 0x5c
42
43#define MC_SECURITY_VIOLATION_STATUS 0x74
44#define MC_SECURITY_VIOLATION_ADDRESS 0x78
45
46struct mc_client {
47 bool write;
48 const char *name;
49};
50
51#define client(_name,_write) \
52 { \
53 .write = _write, \
54 .name = _name, \
55 }
56
57static const struct mc_client mc_clients[] = {
58 client("display0_wina", false), client("display1_wina", false),
59 client("display0_winb", false), client("display1_winb", false),
60 client("display0_winc", false), client("display1_winc", false),
61 client("display0_winb_vfilter", false),
62 client("display1_winb_vfilter", false),
63 client("epp", false), client("gr2d_pat", false),
64 client("gr2d_src", false), client("mpe_unified", false),
65 client("vi_chroma_filter", false), client("cop", false),
66 client("display0_cursor", false), client("display1_cursor", false),
67 client("gr3d_fdc", false), client("gr2d_dst", false),
68 client("host1x_dma", false), client("host1x_generic", false),
69 client("gr3d_idx", false), client("cpu_uncached", false),
70 client("mpe_intrapred", false), client("mpe_mpea", false),
71 client("mpe_mpec", false), client("ahb_dma", false),
72 client("ahb_slave", false), client("gr3d_tex", false),
73 client("vde_bsev", false), client("vde_mbe", false),
74 client("vde_mce", false), client("vde_tpe", false),
75 client("epp_u", true), client("epp_v", true),
76 client("epp_y", true), client("mpe_unified", true),
77 client("vi_sb", true), client("vi_u", true),
78 client("vi_v", true), client("vi_y", true),
79 client("gr2d_dst", true), client("gr3d_fdc", true),
80 client("host1x", true), client("isp", true),
81 client("cpu_uncached", true), client("mpe_mpec", true),
82 client("ahb_dma", true), client("ahb_slave", true),
83 client("avp_bsev", true), client("avp_mbe", true),
84 client("avp_tpm", true),
85};
86
87static DEFINE_SPINLOCK(mc_lock);
88static unsigned long error_count = 0;
89#define MAX_PRINTS 5
90
91static void unthrottle_prints(struct work_struct *work)
92{
93 unsigned long flags;
94
95 spin_lock_irqsave(&mc_lock, flags);
96 error_count = 0;
97 spin_unlock_irqrestore(&mc_lock, flags);
98}
99
100static DECLARE_DELAYED_WORK(unthrottle_prints_work, unthrottle_prints);
101
102static irqreturn_t tegra_mc_error_isr(int irq, void *data)
103{
104 void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
105 unsigned long count;
106 u32 stat;
107
108 stat = readl(mc + MC_INT_STATUS);
109 stat &= (MC_INT_SECURITY_VIOLATION |
110 MC_INT_INVALID_GART_PAGE |
111 MC_INT_DECERR_EMEM_OTHERS);
112
113 __cancel_delayed_work(&unthrottle_prints_work);
114
115 spin_lock(&mc_lock);
116 count = ++error_count;
117 spin_unlock(&mc_lock);
118
119 if (count >= MAX_PRINTS) {
120 if (count == MAX_PRINTS)
121 pr_err("Too many MC errors; throttling prints\n");
122 schedule_delayed_work(&unthrottle_prints_work, HZ/2);
123 goto out;
124 }
125
126 if (stat & MC_INT_DECERR_EMEM_OTHERS) {
127 const struct mc_client *client = NULL;
128 u32 addr, req;
129
130 req = readl(mc + MC_DECERR_EMEM_OTHERS_STATUS);
131 addr = readl(mc + MC_DECERR_EMEM_OTHERS_ADDRESS);
132 req &= 0x3f;
133 if (req < ARRAY_SIZE(mc_clients))
134 client = &mc_clients[req];
135
136 pr_err("MC_DECERR: %p %s (%s)\n", (void*)addr,
137 (client) ? client->name : "unknown",
138 (client && client->write) ? "write" : "read");
139 }
140
141 if (stat & MC_INT_INVALID_GART_PAGE) {
142 const struct mc_client *client = NULL;
143 u32 addr, req;
144
145 req = readl(mc + MC_GART_ERROR_STATUS);
146 addr = readl(mc + MC_GART_ERROR_ADDRESS);
147 req = (req >> 1) & 0x3f;
148
149 if (req < ARRAY_SIZE(mc_clients))
150 client = &mc_clients[req];
151
152 pr_err("MC_GART_ERR: %p %s (%s)\n", (void*)addr,
153 (client) ? client->name : "unknown",
154 (client && client->write) ? "write" : "read");
155 }
156
157 if (stat & MC_INT_SECURITY_VIOLATION) {
158 const struct mc_client *client = NULL;
159 const char *type = NULL;
160 u32 addr, req;
161
162 req = readl(mc + MC_SECURITY_VIOLATION_STATUS);
163 addr = readl(mc + MC_SECURITY_VIOLATION_ADDRESS);
164
165 type = (req & (1<<30)) ? "carveout" : "trustzone";
166
167 req &= 0x3f;
168 if (req < ARRAY_SIZE(mc_clients))
169 client = &mc_clients[req];
170
171 pr_err("MC_SECURITY_ERR (%s): %p %s (%s)\n", type, (void*)addr,
172 (client) ? client->name : "unknown",
173 (client && client->write) ? "write" : "read");
174 }
175out:
176 writel(stat, mc + MC_INT_STATUS);
177 return IRQ_HANDLED;
178}
179
180void __init tegra_mc_init(void)
181{
182 if (request_irq(INT_MC_GENERAL, tegra_mc_error_isr, 0,
183 "mc_status", NULL)) {
184 pr_err("%s: unable to register MC error interrupt\n", __func__);
185 } else {
186 void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
187 u32 reg = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
188 MC_INT_DECERR_EMEM_OTHERS;
189 writel(reg, mc + MC_INT_MASK);
190 }
191}
192arch_initcall(tegra_mc_init);