aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus/omap_l3_noc.c
diff options
context:
space:
mode:
authorKeerthy <j-keerthy@ti.com>2014-11-10 13:19:47 -0500
committerTony Lindgren <tony@atomide.com>2014-11-12 10:16:05 -0500
commit61b43d4e919e8fa5e10c77ee32ba328da07e0264 (patch)
treea336de40a967ef33390a20431b16caea142f0119 /drivers/bus/omap_l3_noc.c
parent126e31faa12c0d40c3b603adb9ac6d72dd424860 (diff)
bus: omap_l3_noc: Add resume hook to restore context
On certain SoCs such as AM437x SoC, L3_noc error registers are maintained in power domain such as per domain which looses context as part of low power state such as RTC+DDR mode. On these platforms when we mask interrupts which we cannot handle, the source of these interrupts still remain on resume, however, the flag mux registers now contain their reset value (unmasked) - this breaks the system with infinite interrupts since we do not these interrupts to take place ever again. To handle this: restore the masking of interrupts which we have already recorded in the system as ones we cannot handle. Fixes: 2100b595b7 ("bus: omap_l3_noc: ignore masked out unclearable targets") Acked-by: Nishanth Menon <nm@ti.com> Signed-off-by: Keerthy <j-keerthy@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'drivers/bus/omap_l3_noc.c')
-rw-r--r--drivers/bus/omap_l3_noc.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c
index 531ae591783b..b5eac29d8f6e 100644
--- a/drivers/bus/omap_l3_noc.c
+++ b/drivers/bus/omap_l3_noc.c
@@ -296,11 +296,66 @@ static int omap_l3_probe(struct platform_device *pdev)
296 return ret; 296 return ret;
297} 297}
298 298
299#ifdef CONFIG_PM
300
301/**
302 * l3_resume_noirq() - resume function for l3_noc
303 * @dev: pointer to l3_noc device structure
304 *
305 * We only have the resume handler only since we
306 * have already maintained the delta register
307 * configuration as part of configuring the system
308 */
309static int l3_resume_noirq(struct device *dev)
310{
311 struct omap_l3 *l3 = dev_get_drvdata(dev);
312 int i;
313 struct l3_flagmux_data *flag_mux;
314 void __iomem *base, *mask_regx = NULL;
315 u32 mask_val;
316
317 for (i = 0; i < l3->num_modules; i++) {
318 base = l3->l3_base[i];
319 flag_mux = l3->l3_flagmux[i];
320 if (!flag_mux->mask_app_bits && !flag_mux->mask_dbg_bits)
321 continue;
322
323 mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
324 (L3_APPLICATION_ERROR << 3);
325 mask_val = readl_relaxed(mask_regx);
326 mask_val &= ~(flag_mux->mask_app_bits);
327
328 writel_relaxed(mask_val, mask_regx);
329 mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
330 (L3_DEBUG_ERROR << 3);
331 mask_val = readl_relaxed(mask_regx);
332 mask_val &= ~(flag_mux->mask_dbg_bits);
333
334 writel_relaxed(mask_val, mask_regx);
335 }
336
337 /* Dummy read to force OCP barrier */
338 if (mask_regx)
339 (void)readl(mask_regx);
340
341 return 0;
342}
343
344static const struct dev_pm_ops l3_dev_pm_ops = {
345 .resume_noirq = l3_resume_noirq,
346};
347
348#define L3_DEV_PM_OPS (&l3_dev_pm_ops)
349#else
350#define L3_DEV_PM_OPS NULL
351#endif
352
299static struct platform_driver omap_l3_driver = { 353static struct platform_driver omap_l3_driver = {
300 .probe = omap_l3_probe, 354 .probe = omap_l3_probe,
301 .driver = { 355 .driver = {
302 .name = "omap_l3_noc", 356 .name = "omap_l3_noc",
303 .owner = THIS_MODULE, 357 .owner = THIS_MODULE,
358 .pm = L3_DEV_PM_OPS,
304 .of_match_table = of_match_ptr(l3_noc_match), 359 .of_match_table = of_match_ptr(l3_noc_match),
305 }, 360 },
306}; 361};