2
* OMAP4XXX L3 Interconnect error handling driver
4
* Copyright (C) 2011 Texas Corporation
5
* Santosh Shilimkar <santosh.shilimkar@ti.com>
6
* Sricharan <r.sricharan@ti.com>
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.
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.
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
2
* OMAP4XXX L3 Interconnect error handling driver
4
* Copyright (C) 2011 Texas Corporation
5
* Santosh Shilimkar <santosh.shilimkar@ti.com>
6
* Sricharan <r.sricharan@ti.com>
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.
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.
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
23
#include <linux/module.h>
23
24
#include <linux/init.h>
24
25
#include <linux/io.h>
25
26
#include <linux/platform_device.h>
55
56
static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
58
struct omap4_l3 *l3 = _l3;
59
struct omap4_l3 *l3 = _l3;
61
u32 std_err_main_addr, std_err_main, err_reg;
62
u32 base, slave_addr, clear;
62
u32 std_err_main, err_reg, clear, masterid;
63
void __iomem *base, *l3_targ_base;
64
char *target_name, *master_name = "UN IDENTIFIED";
65
66
/* Get the Type of interrupt */
66
67
inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
70
71
* Read the regerr register of the clock domain
71
72
* to determine the source
73
base = (u32)l3->l3_base[i];
74
err_reg = readl(base + l3_flagmux[i] + (inttype << 3));
74
base = l3->l3_base[i];
75
err_reg = __raw_readl(base + l3_flagmux[i] +
76
+ L3_FLAGMUX_REGERR0 + (inttype << 3));
76
78
/* Get the corresponding error and analyse */
78
80
/* Identify the source from control status register */
79
for (j = 0; !(err_reg & (1 << j)); j++)
81
err_src = __ffs(err_reg);
83
83
/* Read the stderrlog_main_source from clk domain */
84
std_err_main_addr = base + *(l3_targ[i] + err_src);
85
std_err_main = readl(std_err_main_addr);
84
l3_targ_base = base + *(l3_targ[i] + err_src);
85
std_err_main = __raw_readl(l3_targ_base +
86
L3_TARG_STDERRLOG_MAIN);
87
masterid = __raw_readl(l3_targ_base +
88
L3_TARG_STDERRLOG_MSTADDR);
87
90
switch (std_err_main & CUSTOM_ERROR) {
88
91
case STANDARD_ERROR:
90
l3_targ_stderrlog_main_name[i][err_src];
92
slave_addr = std_err_main_addr +
93
L3_SLAVE_ADDRESS_OFFSET;
94
WARN(true, "L3 standard error: SOURCE:%s at address 0x%x\n",
95
source_name, readl(slave_addr));
93
l3_targ_inst_name[i][err_src];
94
WARN(true, "L3 standard error: TARGET:%s at address 0x%x\n",
96
__raw_readl(l3_targ_base +
97
L3_TARG_STDERRLOG_SLVOFSLSB));
96
98
/* clear the std error log*/
97
99
clear = std_err_main | CLEAR_STDERR_LOG;
98
writel(clear, std_err_main_addr);
100
writel(clear, l3_targ_base +
101
L3_TARG_STDERRLOG_MAIN);
101
104
case CUSTOM_ERROR:
103
l3_targ_stderrlog_main_name[i][err_src];
105
WARN(true, "CUSTOM SRESP error with SOURCE:%s\n",
106
l3_targ_inst_name[i][err_src];
107
for (k = 0; k < NUM_OF_L3_MASTERS; k++) {
108
if (masterid == l3_masters[k].id)
112
WARN(true, "L3 custom error: MASTER:%s TARGET:%s\n",
113
master_name, target_name);
107
114
/* clear the std error log*/
108
115
clear = std_err_main | CLEAR_STDERR_LOG;
109
writel(clear, std_err_main_addr);
116
writel(clear, l3_targ_base +
117
L3_TARG_STDERRLOG_MAIN);
178
185
* Setup interrupt Handlers
180
irq = platform_get_irq(pdev, 0);
181
ret = request_irq(irq,
187
l3->debug_irq = platform_get_irq(pdev, 0);
188
ret = request_irq(l3->debug_irq,
182
189
l3_interrupt_handler,
183
190
IRQF_DISABLED, "l3-dbg-irq", l3);
185
192
pr_crit("L3: request_irq failed to register for 0x%x\n",
186
OMAP44XX_IRQ_L3_DBG);
193
OMAP44XX_IRQ_L3_DBG);
191
irq = platform_get_irq(pdev, 1);
192
ret = request_irq(irq,
197
l3->app_irq = platform_get_irq(pdev, 1);
198
ret = request_irq(l3->app_irq,
193
199
l3_interrupt_handler,
194
200
IRQF_DISABLED, "l3-app-irq", l3);
196
202
pr_crit("L3: request_irq failed to register for 0x%x\n",
197
OMAP44XX_IRQ_L3_APP);
203
OMAP44XX_IRQ_L3_APP);
217
static int __exit omap4_l3_remove(struct platform_device *pdev)
222
static int __devexit omap4_l3_remove(struct platform_device *pdev)
219
struct omap4_l3 *l3 = platform_get_drvdata(pdev);
224
struct omap4_l3 *l3 = platform_get_drvdata(pdev);
221
226
free_irq(l3->app_irq, l3);
222
227
free_irq(l3->debug_irq, l3);
236
#if defined(CONFIG_OF)
237
static const struct of_device_id l3_noc_match[] = {
238
{.compatible = "ti,omap4-l3-noc", },
241
MODULE_DEVICE_TABLE(of, l3_noc_match);
243
#define l3_noc_match NULL
231
246
static struct platform_driver omap4_l3_driver = {
232
.remove = __exit_p(omap4_l3_remove),
247
.probe = omap4_l3_probe,
248
.remove = __devexit_p(omap4_l3_remove),
234
.name = "omap_l3_noc",
250
.name = "omap_l3_noc",
251
.owner = THIS_MODULE,
252
.of_match_table = l3_noc_match,
238
256
static int __init omap4_l3_init(void)
240
return platform_driver_probe(&omap4_l3_driver, omap4_l3_probe);
258
return platform_driver_register(&omap4_l3_driver);
242
260
postcore_initcall_sync(omap4_l3_init);