|
@@ -670,3 +670,116 @@ int __init omap3_pm_init(void)
|
|
|
|
|
|
/* XXX prcm_setup_regs needs to be before enabling hw
|
|
/* XXX prcm_setup_regs needs to be before enabling hw
|
|
* supervised mode for powerdomains */
|
|
* supervised mode for powerdomains */
|
|
|
|
+ prcm_setup_regs();
|
|
|
|
+
|
|
|
|
+ ret = request_irq(omap_prcm_event_to_irq("wkup"),
|
|
|
|
+ _prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL);
|
|
|
|
+
|
|
|
|
+ if (ret) {
|
|
|
|
+ pr_err("pm: Failed to request pm_wkup irq\n");
|
|
|
|
+ goto err1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* IO interrupt is shared with mux code */
|
|
|
|
+ ret = request_irq(omap_prcm_event_to_irq("io"),
|
|
|
|
+ _prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io",
|
|
|
|
+ omap3_pm_init);
|
|
|
|
+ enable_irq(omap_prcm_event_to_irq("io"));
|
|
|
|
+
|
|
|
|
+ if (ret) {
|
|
|
|
+ pr_err("pm: Failed to request pm_io irq\n");
|
|
|
|
+ goto err2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = pwrdm_for_each(pwrdms_setup, NULL);
|
|
|
|
+ if (ret) {
|
|
|
|
+ pr_err("Failed to setup powerdomains\n");
|
|
|
|
+ goto err3;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
|
|
|
|
+
|
|
|
|
+ mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
|
|
|
|
+ if (mpu_pwrdm == NULL) {
|
|
|
|
+ pr_err("Failed to get mpu_pwrdm\n");
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto err3;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ neon_pwrdm = pwrdm_lookup("neon_pwrdm");
|
|
|
|
+ per_pwrdm = pwrdm_lookup("per_pwrdm");
|
|
|
|
+ core_pwrdm = pwrdm_lookup("core_pwrdm");
|
|
|
|
+
|
|
|
|
+ neon_clkdm = clkdm_lookup("neon_clkdm");
|
|
|
|
+ mpu_clkdm = clkdm_lookup("mpu_clkdm");
|
|
|
|
+ per_clkdm = clkdm_lookup("per_clkdm");
|
|
|
|
+ wkup_clkdm = clkdm_lookup("wkup_clkdm");
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_SUSPEND
|
|
|
|
+ omap_pm_suspend = omap3_pm_suspend;
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ arm_pm_idle = omap3_pm_idle;
|
|
|
|
+ omap3_idle_init();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * RTA is disabled during initialization as per erratum i608
|
|
|
|
+ * it is safer to disable RTA by the bootloader, but we would like
|
|
|
|
+ * to be doubly sure here and prevent any mishaps.
|
|
|
|
+ */
|
|
|
|
+ if (IS_PM34XX_ERRATUM(PM_RTA_ERRATUM_i608))
|
|
|
|
+ omap3630_ctrl_disable_rta();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * The UART3/4 FIFO and the sidetone memory in McBSP2/3 are
|
|
|
|
+ * not correctly reset when the PER powerdomain comes back
|
|
|
|
+ * from OFF or OSWR when the CORE powerdomain is kept active.
|
|
|
|
+ * See OMAP36xx Erratum i582 "PER Domain reset issue after
|
|
|
|
+ * Domain-OFF/OSWR Wakeup". This wakeup dependency is not a
|
|
|
|
+ * complete workaround. The kernel must also prevent the PER
|
|
|
|
+ * powerdomain from going to OSWR/OFF while the CORE
|
|
|
|
+ * powerdomain is not going to OSWR/OFF. And if PER last
|
|
|
|
+ * power state was off while CORE last power state was ON, the
|
|
|
|
+ * UART3/4 and McBSP2/3 SIDETONE devices need to run a
|
|
|
|
+ * self-test using their loopback tests; if that fails, those
|
|
|
|
+ * devices are unusable until the PER/CORE can complete a transition
|
|
|
|
+ * from ON to OSWR/OFF and then back to ON.
|
|
|
|
+ *
|
|
|
|
+ * XXX Technically this workaround is only needed if off-mode
|
|
|
|
+ * or OSWR is enabled.
|
|
|
|
+ */
|
|
|
|
+ if (IS_PM34XX_ERRATUM(PM_PER_MEMORIES_ERRATUM_i582))
|
|
|
|
+ clkdm_add_wkdep(per_clkdm, wkup_clkdm);
|
|
|
|
+
|
|
|
|
+ clkdm_add_wkdep(neon_clkdm, mpu_clkdm);
|
|
|
|
+ if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
|
|
|
|
+ omap3_secure_ram_storage =
|
|
|
|
+ kmalloc(0x803F, GFP_KERNEL);
|
|
|
|
+ if (!omap3_secure_ram_storage)
|
|
|
|
+ pr_err("Memory allocation failed when allocating for secure sram context\n");
|
|
|
|
+
|
|
|
|
+ local_irq_disable();
|
|
|
|
+ local_fiq_disable();
|
|
|
|
+
|
|
|
|
+ omap_dma_global_context_save();
|
|
|
|
+ omap3_save_secure_ram_context();
|
|
|
|
+ omap_dma_global_context_restore();
|
|
|
|
+
|
|
|
|
+ local_irq_enable();
|
|
|
|
+ local_fiq_enable();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ omap3_save_scratchpad_contents();
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+err3:
|
|
|
|
+ list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
|
|
|
|
+ list_del(&pwrst->node);
|
|
|
|
+ kfree(pwrst);
|
|
|
|
+ }
|
|
|
|
+ free_irq(omap_prcm_event_to_irq("io"), omap3_pm_init);
|
|
|
|
+err2:
|
|
|
|
+ free_irq(omap_prcm_event_to_irq("wkup"), NULL);
|
|
|
|
+err1:
|
|
|
|
+ return ret;
|
|
|
|
+}
|