|
@@ -153,3 +153,143 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
|
|
|
int c = 0;
|
|
|
|
|
|
wkst = omap2_prm_read_mod_reg(module, wkst_off);
|
|
|
+ wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
|
|
|
+ wkst &= ~ignore_bits;
|
|
|
+ if (wkst) {
|
|
|
+ iclk = omap2_cm_read_mod_reg(module, iclk_off);
|
|
|
+ fclk = omap2_cm_read_mod_reg(module, fclk_off);
|
|
|
+ while (wkst) {
|
|
|
+ clken = wkst;
|
|
|
+ omap2_cm_set_mod_reg_bits(clken, module, iclk_off);
|
|
|
+ /*
|
|
|
+ * For USBHOST, we don't know whether HOST1 or
|
|
|
+ * HOST2 woke us up, so enable both f-clocks
|
|
|
+ */
|
|
|
+ if (module == OMAP3430ES2_USBHOST_MOD)
|
|
|
+ clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT;
|
|
|
+ omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
|
|
|
+ omap2_prm_write_mod_reg(wkst, module, wkst_off);
|
|
|
+ wkst = omap2_prm_read_mod_reg(module, wkst_off);
|
|
|
+ wkst &= ~ignore_bits;
|
|
|
+ c++;
|
|
|
+ }
|
|
|
+ omap2_cm_write_mod_reg(iclk, module, iclk_off);
|
|
|
+ omap2_cm_write_mod_reg(fclk, module, fclk_off);
|
|
|
+ }
|
|
|
+
|
|
|
+ return c;
|
|
|
+}
|
|
|
+
|
|
|
+static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
|
|
|
+{
|
|
|
+ int c;
|
|
|
+
|
|
|
+ c = prcm_clear_mod_irqs(WKUP_MOD, 1,
|
|
|
+ ~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
|
|
|
+
|
|
|
+ return c ? IRQ_HANDLED : IRQ_NONE;
|
|
|
+}
|
|
|
+
|
|
|
+static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
|
|
|
+{
|
|
|
+ int c;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Clear all except ST_IO and ST_IO_CHAIN for wkup module,
|
|
|
+ * these are handled in a separate handler to avoid acking
|
|
|
+ * IO events before parsing in mux code
|
|
|
+ */
|
|
|
+ c = prcm_clear_mod_irqs(WKUP_MOD, 1,
|
|
|
+ OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK);
|
|
|
+ c += prcm_clear_mod_irqs(CORE_MOD, 1, 0);
|
|
|
+ c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0);
|
|
|
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
|
|
|
+ c += prcm_clear_mod_irqs(CORE_MOD, 3, 0);
|
|
|
+ c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ return c ? IRQ_HANDLED : IRQ_NONE;
|
|
|
+}
|
|
|
+
|
|
|
+static void omap34xx_save_context(u32 *save)
|
|
|
+{
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ /* Read Auxiliary Control Register */
|
|
|
+ asm("mrc p15, 0, %0, c1, c0, 1" : "=r" (val));
|
|
|
+ *save++ = 1;
|
|
|
+ *save++ = val;
|
|
|
+
|
|
|
+ /* Read L2 AUX ctrl register */
|
|
|
+ asm("mrc p15, 1, %0, c9, c0, 2" : "=r" (val));
|
|
|
+ *save++ = 1;
|
|
|
+ *save++ = val;
|
|
|
+}
|
|
|
+
|
|
|
+static int omap34xx_do_sram_idle(unsigned long save_state)
|
|
|
+{
|
|
|
+ omap34xx_cpu_suspend(save_state);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void omap_sram_idle(void)
|
|
|
+{
|
|
|
+ /* Variable to tell what needs to be saved and restored
|
|
|
+ * in omap_sram_idle*/
|
|
|
+ /* save_state = 0 => Nothing to save and restored */
|
|
|
+ /* save_state = 1 => Only L1 and logic lost */
|
|
|
+ /* save_state = 2 => Only L2 lost */
|
|
|
+ /* save_state = 3 => L1, L2 and logic lost */
|
|
|
+ int save_state = 0;
|
|
|
+ int mpu_next_state = PWRDM_POWER_ON;
|
|
|
+ int per_next_state = PWRDM_POWER_ON;
|
|
|
+ int core_next_state = PWRDM_POWER_ON;
|
|
|
+ int per_going_off;
|
|
|
+ int core_prev_state;
|
|
|
+ u32 sdrc_pwr = 0;
|
|
|
+
|
|
|
+ mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
|
|
|
+ switch (mpu_next_state) {
|
|
|
+ case PWRDM_POWER_ON:
|
|
|
+ case PWRDM_POWER_RET:
|
|
|
+ /* No need to save context */
|
|
|
+ save_state = 0;
|
|
|
+ break;
|
|
|
+ case PWRDM_POWER_OFF:
|
|
|
+ save_state = 3;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /* Invalid state */
|
|
|
+ pr_err("Invalid mpu state in sram_idle\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* NEON control */
|
|
|
+ if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
|
|
|
+ pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state);
|
|
|
+
|
|
|
+ /* Enable IO-PAD and IO-CHAIN wakeups */
|
|
|
+ per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
|
|
|
+ core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
|
|
|
+
|
|
|
+ pwrdm_pre_transition(NULL);
|
|
|
+
|
|
|
+ /* PER */
|
|
|
+ if (per_next_state < PWRDM_POWER_ON) {
|
|
|
+ per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
|
|
|
+ omap2_gpio_prepare_for_idle(per_going_off);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* CORE */
|
|
|
+ if (core_next_state < PWRDM_POWER_ON) {
|
|
|
+ if (core_next_state == PWRDM_POWER_OFF) {
|
|
|
+ omap3_core_save_context();
|
|
|
+ omap3_cm_save_context();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ omap3_intc_prepare_idle();
|
|
|
+
|
|
|
+ /*
|
|
|
+ * On EMU/HS devices ROM code restores a SRDC value
|
|
|
+ * from scratchpad which has automatic self refresh on timeout
|