ARM: tegra: pcie: Remove dock detect variable
[linux-3.10.git] / arch / arm / mach-tegra / common-t2.c
1 /*
2  * arch/arm/mach-tegra/common-t2.c
3  *
4  * Tegra 2 SoC-specific initialization (memory controller, etc.)
5  *
6  * Copyright (c) 2009-2012 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
46 struct 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
57 static 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
87 static DEFINE_SPINLOCK(mc_lock);
88 static unsigned long error_count = 0;
89 #define MAX_PRINTS 5
90
91 static 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
100 static DECLARE_DELAYED_WORK(unthrottle_prints_work, unthrottle_prints);
101
102 static 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         }
175 out:
176         writel(stat, mc + MC_INT_STATUS);
177         return IRQ_HANDLED;
178 }
179
180 static int __init tegra20_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                 return -EINVAL;
186         } else {
187                 void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
188                 u32 reg = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
189                         MC_INT_DECERR_EMEM_OTHERS;
190                 writel(reg, mc + MC_INT_MASK);
191         }
192
193         return 0;
194 }
195 arch_initcall(tegra20_mc_init);