static void omap2_iommu_disable(struct omap_iommu *obj) { struct omap_hwmod *oh; u32 l; oh = omap_hwmod_lookup(obj->name); if (!oh) return; /* * IPU and DSP iommus are not directly connected to the processor * instead they are behind a shared MMU. Therefore in the case of * a mmu fault and the mmu fault was not handled, even if the processor * is under reset, the shared MMU will try to translation the address * again causing that the status flag cannot be clear and therefore * as soon as the clkdm wants to go to idle the clkdm will be stuck * in transition state. The only way to reset the shared MMU is doing * a hardreset of the L2 iommu which shared the reset line with the * shared MMU. That way we can clean the status bit and turn off * the iommu without any issue. */ if (!strcmp(obj->name, "ipu") || !strcmp(obj->name, "dsp")) { omap_hwmod_assert_hardreset(oh, oh->rst_lines->name); omap_hwmod_deassert_hardreset(oh, oh->rst_lines->name); goto out; } l = iommu_read_reg(obj, MMU_IRQSTATUS); iommu_write_reg(obj, l, MMU_IRQSTATUS); l = iommu_read_reg(obj, MMU_CNTL); l &= ~MMU_CNTL_MASK; iommu_write_reg(obj, l, MMU_CNTL); out: clkdm_allow_idle(oh->clkdm); dev_dbg(obj->dev, "%s is shutting down\n", obj->name); }
/** * omap_device_assert_hardreset - set a device's hardreset line * @pdev: struct platform_device * to reset * @name: const char * name of the reset line * * Set the hardreset line identified by @name on the IP blocks * associated with the hwmods backing the platform_device @pdev. All * of the hwmods associated with @pdev must have the same hardreset * line linked to them for this to work. Passes along the return value * of omap_hwmod_assert_hardreset() in the event of any failure, or * returns 0 upon success. */ int omap_device_assert_hardreset(struct platform_device *pdev, const char *name) { struct omap_device *od = to_omap_device(pdev); int ret = 0; int i; for (i = 0; i < od->hwmods_cnt; i++) { ret = omap_hwmod_assert_hardreset(od->hwmods[i], name); if (ret) break; } return ret; }