Commit 397ee6685dbe3d1dd7b002bcf6231d969080ab0c

Authored by Keerthy
Committed by Greg Kroah-Hartman
1 parent fa036ea44c

bus: omap_l3_noc: Add resume hook to restore context

commit 61b43d4e919e8fa5e10c77ee32ba328da07e0264 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 1 changed file with 55 additions and 0 deletions Side-by-side Diff

drivers/bus/omap_l3_noc.c
... ... @@ -296,11 +296,66 @@
296 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 + */
  309 +static 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 +
  344 +static 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 +
299 353 static struct platform_driver omap_l3_driver = {
300 354 .probe = omap_l3_probe,
301 355 .driver = {
302 356 .name = "omap_l3_noc",
303 357 .owner = THIS_MODULE,
  358 + .pm = L3_DEV_PM_OPS,
304 359 .of_match_table = of_match_ptr(l3_noc_match),
305 360 },
306 361 };