PageRenderTime 29ms CodeModel.GetById 16ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/arm/mach-omap2/omap_l3_smx.c

https://github.com/AICP/kernel_asus_grouper
C | 299 lines | 219 code | 35 blank | 45 comment | 12 complexity | 6be15314443d29edf0c38cbb12a95c94 MD5 | raw file
  1 /*
  2  * OMAP3XXX L3 Interconnect Driver
  3  *
  4  * Copyright (C) 2011 Texas Corporation
  5  *	Felipe Balbi <balbi@ti.com>
  6  *	Santosh Shilimkar <santosh.shilimkar@ti.com>
  7  *	Sricharan <r.sricharan@ti.com>
  8  *
  9  * This program is free software; you can redistribute it and/or modify
 10  * it under the terms of the GNU General Public License as published by
 11  * the Free Software Foundation; either version 2 of the License, or
 12  * (at your option) any later version.
 13  *
 14  * This program is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17  * GNU General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU General Public License
 20  * along with this program; if not, write to the Free Software
 21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 22  * USA
 23  */
 24
 25#include <linux/kernel.h>
 26#include <linux/slab.h>
 27#include <linux/platform_device.h>
 28#include <linux/interrupt.h>
 29#include <linux/io.h>
 30#include "omap_l3_smx.h"
 31
 32static inline u64 omap3_l3_readll(void __iomem *base, u16 reg)
 33{
 34	return __raw_readll(base + reg);
 35}
 36
 37static inline void omap3_l3_writell(void __iomem *base, u16 reg, u64 value)
 38{
 39	__raw_writell(value, base + reg);
 40}
 41
 42static inline enum omap3_l3_code omap3_l3_decode_error_code(u64 error)
 43{
 44	return (error & 0x0f000000) >> L3_ERROR_LOG_CODE;
 45}
 46
 47static inline u32 omap3_l3_decode_addr(u64 error_addr)
 48{
 49	return error_addr & 0xffffffff;
 50}
 51
 52static inline unsigned omap3_l3_decode_cmd(u64 error)
 53{
 54	return (error & 0x07) >> L3_ERROR_LOG_CMD;
 55}
 56
 57static inline enum omap3_l3_initiator_id omap3_l3_decode_initid(u64 error)
 58{
 59	return (error & 0xff00) >> L3_ERROR_LOG_INITID;
 60}
 61
 62static inline unsigned omap3_l3_decode_req_info(u64 error)
 63{
 64	return (error >> 32) & 0xffff;
 65}
 66
 67static char *omap3_l3_code_string(u8 code)
 68{
 69	switch (code) {
 70	case OMAP_L3_CODE_NOERROR:
 71		return "No Error";
 72	case OMAP_L3_CODE_UNSUP_CMD:
 73		return "Unsupported Command";
 74	case OMAP_L3_CODE_ADDR_HOLE:
 75		return "Address Hole";
 76	case OMAP_L3_CODE_PROTECT_VIOLATION:
 77		return "Protection Violation";
 78	case OMAP_L3_CODE_IN_BAND_ERR:
 79		return "In-band Error";
 80	case OMAP_L3_CODE_REQ_TOUT_NOT_ACCEPT:
 81		return "Request Timeout Not Accepted";
 82	case OMAP_L3_CODE_REQ_TOUT_NO_RESP:
 83		return "Request Timeout, no response";
 84	default:
 85		return "UNKNOWN error";
 86	}
 87}
 88
 89static char *omap3_l3_initiator_string(u8 initid)
 90{
 91	switch (initid) {
 92	case OMAP_L3_LCD:
 93		return "LCD";
 94	case OMAP_L3_SAD2D:
 95		return "SAD2D";
 96	case OMAP_L3_IA_MPU_SS_1:
 97	case OMAP_L3_IA_MPU_SS_2:
 98	case OMAP_L3_IA_MPU_SS_3:
 99	case OMAP_L3_IA_MPU_SS_4:
100	case OMAP_L3_IA_MPU_SS_5:
101		return "MPU";
102	case OMAP_L3_IA_IVA_SS_1:
103	case OMAP_L3_IA_IVA_SS_2:
104	case OMAP_L3_IA_IVA_SS_3:
105		return "IVA_SS";
106	case OMAP_L3_IA_IVA_SS_DMA_1:
107	case OMAP_L3_IA_IVA_SS_DMA_2:
108	case OMAP_L3_IA_IVA_SS_DMA_3:
109	case OMAP_L3_IA_IVA_SS_DMA_4:
110	case OMAP_L3_IA_IVA_SS_DMA_5:
111	case OMAP_L3_IA_IVA_SS_DMA_6:
112		return "IVA_SS_DMA";
113	case OMAP_L3_IA_SGX:
114		return "SGX";
115	case OMAP_L3_IA_CAM_1:
116	case OMAP_L3_IA_CAM_2:
117	case OMAP_L3_IA_CAM_3:
118		return "CAM";
119	case OMAP_L3_IA_DAP:
120		return "DAP";
121	case OMAP_L3_SDMA_WR_1:
122	case OMAP_L3_SDMA_WR_2:
123		return "SDMA_WR";
124	case OMAP_L3_SDMA_RD_1:
125	case OMAP_L3_SDMA_RD_2:
126	case OMAP_L3_SDMA_RD_3:
127	case OMAP_L3_SDMA_RD_4:
128		return "SDMA_RD";
129	case OMAP_L3_USBOTG:
130		return "USB_OTG";
131	case OMAP_L3_USBHOST:
132		return "USB_HOST";
133	default:
134		return "UNKNOWN Initiator";
135	}
136}
137
138/**
139 * omap3_l3_block_irq - handles a register block's irq
140 * @l3: struct omap3_l3 *
141 * @base: register block base address
142 * @error: L3_ERROR_LOG register of our block
143 *
144 * Called in hard-irq context. Caller should take care of locking
145 *
146 * OMAP36xx TRM gives, on page 2001, Figure 9-10, the Typical Error
147 * Analysis Sequence, we are following that sequence here, please
148 * refer to that Figure for more information on the subject.
149 */
150static irqreturn_t omap3_l3_block_irq(struct omap3_l3 *l3,
151					u64 error, int error_addr)
152{
153	u8                      code = omap3_l3_decode_error_code(error);
154	u8                      initid = omap3_l3_decode_initid(error);
155	u8                      multi = error & L3_ERROR_LOG_MULTI;
156	u32			address = omap3_l3_decode_addr(error_addr);
157
158	WARN(true, "%s seen by %s %s at address %x\n",
159				 omap3_l3_code_string(code),
160			  omap3_l3_initiator_string(initid),
161			     multi ? "Multiple Errors" : "",
162						   address);
163
164	return IRQ_HANDLED;
165}
166
167static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
168{
169	struct omap3_l3         *l3 = _l3;
170	u64                     status, clear;
171	u64                     error;
172	u64			error_addr;
173	u64			err_source = 0;
174	void			__iomem *base;
175	int			int_type;
176	irqreturn_t             ret = IRQ_NONE;
177
178	int_type = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
179	if (!int_type) {
180		status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_0);
181		/*
182		 * if we have a timeout error, there's nothing we can
183		 * do besides rebooting the board. So let's BUG on any
184		 * of such errors and handle the others. timeout error
185		 * is severe and not expected to occur.
186		 */
187		BUG_ON(status & L3_STATUS_0_TIMEOUT_MASK);
188	} else {
189		status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_1);
190		/* No timeout error for debug sources */
191	}
192
193	/* identify the error source */
194	for (err_source = 0; !(status & (1 << err_source)); err_source++)
195									;
196
197	base = l3->rt + *(omap3_l3_bases[int_type] + err_source);
198	error = omap3_l3_readll(base, L3_ERROR_LOG);
199	if (error) {
200		error_addr = omap3_l3_readll(base, L3_ERROR_LOG_ADDR);
201
202		ret |= omap3_l3_block_irq(l3, error, error_addr);
203	}
204
205	/* Clear the status register */
206	clear = (L3_AGENT_STATUS_CLEAR_IA << int_type) |
207		L3_AGENT_STATUS_CLEAR_TA;
208	omap3_l3_writell(base, L3_AGENT_STATUS, clear);
209
210	/* clear the error log register */
211	omap3_l3_writell(base, L3_ERROR_LOG, error);
212
213	return ret;
214}
215
216static int __init omap3_l3_probe(struct platform_device *pdev)
217{
218	struct omap3_l3         *l3;
219	struct resource         *res;
220	int                     ret;
221
222	l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
223	if (!l3)
224		return -ENOMEM;
225
226	platform_set_drvdata(pdev, l3);
227
228	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
229	if (!res) {
230		dev_err(&pdev->dev, "couldn't find resource\n");
231		ret = -ENODEV;
232		goto err0;
233	}
234	l3->rt = ioremap(res->start, resource_size(res));
235	if (!l3->rt) {
236		dev_err(&pdev->dev, "ioremap failed\n");
237		ret = -ENOMEM;
238		goto err0;
239	}
240
241	l3->debug_irq = platform_get_irq(pdev, 0);
242	ret = request_irq(l3->debug_irq, omap3_l3_app_irq,
243		IRQF_DISABLED | IRQF_TRIGGER_RISING,
244		"l3-debug-irq", l3);
245	if (ret) {
246		dev_err(&pdev->dev, "couldn't request debug irq\n");
247		goto err1;
248	}
249
250	l3->app_irq = platform_get_irq(pdev, 1);
251	ret = request_irq(l3->app_irq, omap3_l3_app_irq,
252		IRQF_DISABLED | IRQF_TRIGGER_RISING,
253		"l3-app-irq", l3);
254	if (ret) {
255		dev_err(&pdev->dev, "couldn't request app irq\n");
256		goto err2;
257	}
258
259	return 0;
260
261err2:
262	free_irq(l3->debug_irq, l3);
263err1:
264	iounmap(l3->rt);
265err0:
266	kfree(l3);
267	return ret;
268}
269
270static int __exit omap3_l3_remove(struct platform_device *pdev)
271{
272	struct omap3_l3         *l3 = platform_get_drvdata(pdev);
273
274	free_irq(l3->app_irq, l3);
275	free_irq(l3->debug_irq, l3);
276	iounmap(l3->rt);
277	kfree(l3);
278
279	return 0;
280}
281
282static struct platform_driver omap3_l3_driver = {
283	.remove         = __exit_p(omap3_l3_remove),
284	.driver         = {
285	.name   = "omap_l3_smx",
286	},
287};
288
289static int __init omap3_l3_init(void)
290{
291	return platform_driver_probe(&omap3_l3_driver, omap3_l3_probe);
292}
293postcore_initcall_sync(omap3_l3_init);
294
295static void __exit omap3_l3_exit(void)
296{
297	platform_driver_unregister(&omap3_l3_driver);
298}
299module_exit(omap3_l3_exit);