ARM: OMAP2+: Prepare for irqs.h removal
[deliverable/linux.git] / arch / arm / mach-omap2 / omap_l3_noc.c
CommitLineData
2722e56d 1/*
ed0e3520 2 * OMAP4XXX L3 Interconnect error handling driver
3 *
4 * Copyright (C) 2011 Texas Corporation
5 * Santosh Shilimkar <santosh.shilimkar@ti.com>
6 * Sricharan <r.sricharan@ti.com>
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,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 */
d4fc7eb5 23#include <linux/module.h>
2722e56d
SS
24#include <linux/init.h>
25#include <linux/io.h>
26#include <linux/platform_device.h>
27#include <linux/interrupt.h>
28#include <linux/kernel.h>
29#include <linux/slab.h>
30
7d7e1eba
TL
31#include <plat/hardware.h>
32
2722e56d
SS
33#include "omap_l3_noc.h"
34
35/*
36 * Interrupt Handler for L3 error detection.
37 * 1) Identify the L3 clockdomain partition to which the error belongs to.
38 * 2) Identify the slave where the error information is logged
39 * 3) Print the logged information.
40 * 4) Add dump stack to provide kernel trace.
41 *
42 * Two Types of errors :
43 * 1) Custom errors in L3 :
44 * Target like DMM/FW/EMIF generates SRESP=ERR error
45 * 2) Standard L3 error:
46 * - Unsupported CMD.
47 * L3 tries to access target while it is idle
48 * - OCP disconnect.
49 * - Address hole error:
50 * If DSS/ISS/FDIF/USBHOSTFS access a target where they
51 * do not have connectivity, the error is logged in
52 * their default target which is DMM2.
53 *
54 * On High Secure devices, firewall errors are possible and those
55 * can be trapped as well. But the trapping is implemented as part
56 * secure software and hence need not be implemented here.
57 */
58static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
59{
60
ed0e3520 61 struct omap4_l3 *l3 = _l3;
551a9fa9 62 int inttype, i, k;
2722e56d 63 int err_src = 0;
551a9fa9 64 u32 std_err_main, err_reg, clear, masterid;
6616aac6 65 void __iomem *base, *l3_targ_base;
551a9fa9 66 char *target_name, *master_name = "UN IDENTIFIED";
2722e56d
SS
67
68 /* Get the Type of interrupt */
35f7b961 69 inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
2722e56d
SS
70
71 for (i = 0; i < L3_MODULES; i++) {
72 /*
73 * Read the regerr register of the clock domain
74 * to determine the source
75 */
6616aac6 76 base = l3->l3_base[i];
77 err_reg = __raw_readl(base + l3_flagmux[i] +
342fd144 78 + L3_FLAGMUX_REGERR0 + (inttype << 3));
2722e56d
SS
79
80 /* Get the corresponding error and analyse */
81 if (err_reg) {
82 /* Identify the source from control status register */
342fd144 83 err_src = __ffs(err_reg);
2722e56d 84
2722e56d 85 /* Read the stderrlog_main_source from clk domain */
342fd144 86 l3_targ_base = base + *(l3_targ[i] + err_src);
6616aac6 87 std_err_main = __raw_readl(l3_targ_base +
342fd144 88 L3_TARG_STDERRLOG_MAIN);
551a9fa9 89 masterid = __raw_readl(l3_targ_base +
90 L3_TARG_STDERRLOG_MSTADDR);
2722e56d 91
35f7b961 92 switch (std_err_main & CUSTOM_ERROR) {
2722e56d 93 case STANDARD_ERROR:
551a9fa9 94 target_name =
342fd144 95 l3_targ_inst_name[i][err_src];
551a9fa9 96 WARN(true, "L3 standard error: TARGET:%s at address 0x%x\n",
97 target_name,
6616aac6 98 __raw_readl(l3_targ_base +
342fd144 99 L3_TARG_STDERRLOG_SLVOFSLSB));
2722e56d
SS
100 /* clear the std error log*/
101 clear = std_err_main | CLEAR_STDERR_LOG;
342fd144
TP
102 writel(clear, l3_targ_base +
103 L3_TARG_STDERRLOG_MAIN);
2722e56d
SS
104 break;
105
106 case CUSTOM_ERROR:
551a9fa9 107 target_name =
342fd144 108 l3_targ_inst_name[i][err_src];
551a9fa9 109 for (k = 0; k < NUM_OF_L3_MASTERS; k++) {
110 if (masterid == l3_masters[k].id)
111 master_name =
112 l3_masters[k].name;
113 }
114 WARN(true, "L3 custom error: MASTER:%s TARGET:%s\n",
115 master_name, target_name);
2722e56d
SS
116 /* clear the std error log*/
117 clear = std_err_main | CLEAR_STDERR_LOG;
342fd144
TP
118 writel(clear, l3_targ_base +
119 L3_TARG_STDERRLOG_MAIN);
2722e56d
SS
120 break;
121
122 default:
123 /* Nothing to be handled here as of now */
124 break;
125 }
126 /* Error found so break the for loop */
127 break;
128 }
129 }
130 return IRQ_HANDLED;
131}
132
d039c5b9 133static int __devinit omap4_l3_probe(struct platform_device *pdev)
2722e56d 134{
ed0e3520 135 static struct omap4_l3 *l3;
342fd144 136 struct resource *res;
c1df2dcc 137 int ret;
2722e56d
SS
138
139 l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
140 if (!l3)
7529b703 141 return -ENOMEM;
2722e56d
SS
142
143 platform_set_drvdata(pdev, l3);
144 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
145 if (!res) {
146 dev_err(&pdev->dev, "couldn't find resource 0\n");
147 ret = -ENODEV;
7529b703 148 goto err0;
2722e56d
SS
149 }
150
151 l3->l3_base[0] = ioremap(res->start, resource_size(res));
35f7b961 152 if (!l3->l3_base[0]) {
2722e56d
SS
153 dev_err(&pdev->dev, "ioremap failed\n");
154 ret = -ENOMEM;
7529b703 155 goto err0;
2722e56d
SS
156 }
157
158 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
159 if (!res) {
160 dev_err(&pdev->dev, "couldn't find resource 1\n");
161 ret = -ENODEV;
7529b703 162 goto err1;
2722e56d
SS
163 }
164
165 l3->l3_base[1] = ioremap(res->start, resource_size(res));
35f7b961 166 if (!l3->l3_base[1]) {
2722e56d
SS
167 dev_err(&pdev->dev, "ioremap failed\n");
168 ret = -ENOMEM;
7529b703 169 goto err1;
2722e56d
SS
170 }
171
172 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
173 if (!res) {
174 dev_err(&pdev->dev, "couldn't find resource 2\n");
175 ret = -ENODEV;
7529b703 176 goto err2;
2722e56d
SS
177 }
178
179 l3->l3_base[2] = ioremap(res->start, resource_size(res));
35f7b961 180 if (!l3->l3_base[2]) {
2722e56d
SS
181 dev_err(&pdev->dev, "ioremap failed\n");
182 ret = -ENOMEM;
7529b703 183 goto err2;
2722e56d
SS
184 }
185
186 /*
187 * Setup interrupt Handlers
188 */
c1df2dcc
TP
189 l3->debug_irq = platform_get_irq(pdev, 0);
190 ret = request_irq(l3->debug_irq,
2722e56d
SS
191 l3_interrupt_handler,
192 IRQF_DISABLED, "l3-dbg-irq", l3);
193 if (ret) {
194 pr_crit("L3: request_irq failed to register for 0x%x\n",
7d7e1eba 195 9 + OMAP44XX_IRQ_GIC_START);
7529b703 196 goto err3;
2722e56d 197 }
2722e56d 198
c1df2dcc
TP
199 l3->app_irq = platform_get_irq(pdev, 1);
200 ret = request_irq(l3->app_irq,
2722e56d
SS
201 l3_interrupt_handler,
202 IRQF_DISABLED, "l3-app-irq", l3);
203 if (ret) {
204 pr_crit("L3: request_irq failed to register for 0x%x\n",
7d7e1eba 205 10 + OMAP44XX_IRQ_GIC_START);
7529b703 206 goto err4;
2722e56d 207 }
2722e56d 208
7529b703 209 return 0;
210
2722e56d 211err4:
7529b703 212 free_irq(l3->debug_irq, l3);
2722e56d 213err3:
7529b703 214 iounmap(l3->l3_base[2]);
2722e56d 215err2:
7529b703 216 iounmap(l3->l3_base[1]);
2722e56d 217err1:
7529b703 218 iounmap(l3->l3_base[0]);
2722e56d 219err0:
7529b703 220 kfree(l3);
2722e56d
SS
221 return ret;
222}
223
d039c5b9 224static int __devexit omap4_l3_remove(struct platform_device *pdev)
2722e56d 225{
ed0e3520 226 struct omap4_l3 *l3 = platform_get_drvdata(pdev);
2722e56d
SS
227
228 free_irq(l3->app_irq, l3);
229 free_irq(l3->debug_irq, l3);
230 iounmap(l3->l3_base[0]);
231 iounmap(l3->l3_base[1]);
232 iounmap(l3->l3_base[2]);
233 kfree(l3);
234
235 return 0;
236}
237
d039c5b9
BC
238#if defined(CONFIG_OF)
239static const struct of_device_id l3_noc_match[] = {
240 {.compatible = "ti,omap4-l3-noc", },
241 {},
8770b07c 242};
d039c5b9
BC
243MODULE_DEVICE_TABLE(of, l3_noc_match);
244#else
245#define l3_noc_match NULL
246#endif
247
2722e56d 248static struct platform_driver omap4_l3_driver = {
d039c5b9
BC
249 .probe = omap4_l3_probe,
250 .remove = __devexit_p(omap4_l3_remove),
251 .driver = {
252 .name = "omap_l3_noc",
253 .owner = THIS_MODULE,
254 .of_match_table = l3_noc_match,
2722e56d
SS
255 },
256};
257
258static int __init omap4_l3_init(void)
259{
d039c5b9 260 return platform_driver_register(&omap4_l3_driver);
2722e56d
SS
261}
262postcore_initcall_sync(omap4_l3_init);
263
264static void __exit omap4_l3_exit(void)
265{
266 platform_driver_unregister(&omap4_l3_driver);
267}
268module_exit(omap4_l3_exit);
This page took 0.105209 seconds and 5 git commands to generate.