/* * PRCM Interrupt Handler Helper Function * * The purpose of this function is to clear any wake-up events latched * in the PRCM PM_WKST_x registers. It is possible that a wake-up event * may occur whilst attempting to clear a PM_WKST_x register and thus * set another bit in this register. A while loop is used to ensure * that any peripheral wake-up events occurring while attempting to * clear the PM_WKST_x are detected and cleared. */ static int prcm_clear_mod_irqs(s16 module, u8 regs) { u32 wkst, fclk, iclk, clken; u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1; u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1; u16 grpsel_off = (regs == 3) ? OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL; int c = 0; wkst = prm_read_mod_reg(module, wkst_off); wkst &= prm_read_mod_reg(module, grpsel_off); if (wkst) { iclk = cm_read_mod_reg(module, iclk_off); fclk = cm_read_mod_reg(module, fclk_off); while (wkst) { clken = wkst; 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; cm_set_mod_reg_bits(clken, module, fclk_off); prm_write_mod_reg(wkst, module, wkst_off); wkst = prm_read_mod_reg(module, wkst_off); c++; } cm_write_mod_reg(iclk, module, iclk_off); cm_write_mod_reg(fclk, module, fclk_off); } return c; }
u32 omap_prcm_get_reset_sources(void) { /* XXX This presumably needs modification for 34XX */ if (cpu_is_omap24xx() || cpu_is_omap34xx()) return prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST) & 0x7f; if (cpu_is_omap44xx()) return prm_read_mod_reg(WKUP_MOD, OMAP4_RM_RSTST) & 0x7f; return -EIO; }
int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) { u32 c = 0; /* * REVISIT: pwrdm_wait_transition() may be better implemented * via a callback and a periodic timer check -- how long do we expect * powerdomain transitions to take? */ /* XXX Is this udelay() value meaningful? */ while ((prm_read_mod_reg(pwrdm->prcm_offs, OMAP4_PM_PWSTST) & OMAP_INTRANSITION_MASK) && (c++ < PWRDM_TRANSITION_BAILOUT)) udelay(1); if (c > PWRDM_TRANSITION_BAILOUT) { printk(KERN_ERR "powerdomain: waited too long for " "powerdomain %s to complete transition\n", pwrdm->name); return -EAGAIN; } pr_debug("powerdomain: completed transition in %d loops\n", c); return 0; }
static void serial_console_sleep(int enable) { if (console_iclk == NULL || console_fclk == NULL) return; if (enable) { BUG_ON(serial_console_clock_disabled); if (clk_get_usecount(console_fclk) == 0) return; if ((int) serial_console_next_disable - (int) omap2_read_32k_sync_counter() >= 0) return; serial_wait_tx(); clk_disable(console_iclk); clk_disable(console_fclk); serial_console_clock_disabled = 1; } else { int serial_wakeup = 0; u32 l; switch (serial_console_uart) { case 1: l = prm_read_mod_reg(CORE_MOD, PM_WKST1); if (l & OMAP24XX_ST_UART1) serial_wakeup = 1; break; case 2: l = prm_read_mod_reg(CORE_MOD, PM_WKST1); if (l & OMAP24XX_ST_UART2) serial_wakeup = 1; break; case 3: l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKST2); if (l & OMAP24XX_ST_UART3) serial_wakeup = 1; break; } if (serial_wakeup) serial_console_kick(); if (!serial_console_clock_disabled) return; clk_enable(console_iclk); clk_enable(console_fclk); serial_console_clock_disabled = 0; } }
static void pm_init_serial_console(void) { const struct omap_serial_console_config *conf; char name[16]; u32 l; conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE, struct omap_serial_console_config); if (conf == NULL) return; if (conf->console_uart > 3 || conf->console_uart < 1) return; serial_console_uart = conf->console_uart; sprintf(name, "uart%d_fck", conf->console_uart); console_fclk = clk_get(NULL, name); if (IS_ERR(console_fclk)) console_fclk = NULL; name[6] = 'i'; console_iclk = clk_get(NULL, name); if (IS_ERR(console_fclk)) console_iclk = NULL; if (console_fclk == NULL || console_iclk == NULL) { serial_console_uart = 0; return; } switch (serial_console_uart) { case 1: l = prm_read_mod_reg(CORE_MOD, PM_WKEN1); l |= OMAP24XX_ST_UART1; prm_write_mod_reg(l, CORE_MOD, PM_WKEN1); break; case 2: l = prm_read_mod_reg(CORE_MOD, PM_WKEN1); l |= OMAP24XX_ST_UART2; prm_write_mod_reg(l, CORE_MOD, PM_WKEN1); break; case 3: l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKEN2); l |= OMAP24XX_ST_UART3; prm_write_mod_reg(l, CORE_MOD, OMAP24XX_PM_WKEN2); break; } }
/* Read a PRM register, AND it, and shift the result down to bit 0 */ u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask) { u32 v; v = prm_read_mod_reg(domain, idx); v &= mask; v >>= __ffs(mask); return v; }
/* * PRCM Interrupt Handler * * The PRM_IRQSTATUS_MPU register indicates if there are any pending * interrupts from the PRCM for the MPU. These bits must be cleared in * order to clear the PRCM interrupt. The PRCM interrupt handler is * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU * register indicates that a wake-up event is pending for the MPU and * this bit can only be cleared if the all the wake-up events latched * in the various PM_WKST_x registers have been cleared. The interrupt * handler is implemented using a do-while loop so that if a wake-up * event occurred during the processing of the prcm interrupt handler * (setting a bit in the corresponding PM_WKST_x register and thus * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register) * this would be handled. */ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) { u32 irqenable_mpu, irqstatus_mpu; int c = 0; int ct = 0; irqenable_mpu = prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); irqstatus_mpu = prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); irqstatus_mpu &= irqenable_mpu; do { if (irqstatus_mpu & (OMAP3430_WKUP_ST_MASK | OMAP3430_IO_ST_MASK)) { c = _prcm_int_handle_wakeup(); ct++; /* * Is the MPU PRCM interrupt handler racing with the * IVA2 PRCM interrupt handler ? */ WARN(!c && (ct == 1), "prcm: WARNING: PRCM indicated " "MPU wakeup but no wakeup sources are " "marked\n"); } else { /* XXX we need to expand our PRCM interrupt handler */ WARN(1, "prcm: WARNING: PRCM interrupt received, but " "no code to handle it (%08x)\n", irqstatus_mpu); } prm_write_mod_reg(irqstatus_mpu, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); irqstatus_mpu = prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); irqstatus_mpu &= irqenable_mpu; } while (irqstatus_mpu); return IRQ_HANDLED; }
/* Read-modify-write a register in a PRM module. Caller must lock */ u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx) { u32 v; v = prm_read_mod_reg(module, idx); v &= ~mask; v |= bits; prm_write_mod_reg(v, module, idx); return v; }
static u32 omap2_get_sysclkdiv(void) { u32 div; div = prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET); div &= OMAP_SYSCLKDIV_MASK; div >>= OMAP_SYSCLKDIV_SHIFT; return div; }
int omap4_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) { u32 reg; prm_rmw_mod_reg_bits(OMAP4430_LASTPOWERSTATEENTERED_MASK, 0x3 << OMAP4430_LASTPOWERSTATEENTERED_SHIFT, pwrdm->prcm_offs, OMAP4_PM_PWSTST); reg = prm_read_mod_reg(pwrdm->prcm_offs, pwrdm->context_offset); prm_write_mod_reg(reg, pwrdm->prcm_offs, pwrdm->context_offset); return 0; }
static void omap3_enable_io_chain(void) { int timeout = 0; if (omap_rev() >= OMAP3430_REV_ES3_1) { prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, PM_WKEN); /* Do a readback to assure write has been done */ prm_read_mod_reg(WKUP_MOD, PM_WKEN); while (!(prm_read_mod_reg(WKUP_MOD, PM_WKST) & OMAP3430_ST_IO_CHAIN_MASK)) { timeout++; if (timeout > 1000) { printk(KERN_ERR "Wake up daisy chain " "activation failed.\n"); return; } } } }
/** * _omap2xxx_clk_commit - commit clock parent/rate changes in hardware * @clk: struct clk * * * If @clk has the DELAYED_APP flag set, meaning that parent/rate changes * don't take effect until the VALID_CONFIG bit is written, write the * VALID_CONFIG bit and wait for the write to complete. No return value. */ static void _omap2xxx_clk_commit(struct clk *clk) { if (!cpu_is_omap24xx()) return; if (!(clk->flags & DELAYED_APP)) return; prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET); /* OCP barrier */ prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET); }
static int prcm_wakeup_event_control ( u32 reg_bit, u8 operation ) { volatile u32 prcm_val=0; prcm_val = prm_read_mod_reg( WKUP_MOD, PM_WKEN1 ); if ( operation ) prcm_val = prcm_val | reg_bit; else prcm_val = prcm_val & ~reg_bit; prm_write_mod_reg( prcm_val, WKUP_MOD, PM_WKEN1 ); return 0; }
/* * Clears the scratchpad contents in case of cold boot- * called during bootup */ void omap3_clear_scratchpad_contents(void) { u32 max_offset = OMAP343X_SCRATCHPAD_ROM_OFFSET; u32 *v_addr; u32 offset = 0; v_addr = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD_ROM); if (prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) & OMAP3430_GLOBAL_COLD_RST) { for ( ; offset <= max_offset; offset += 0x4) __raw_writel(0x0, (v_addr + offset)); prm_set_mod_reg_bits(OMAP3430_GLOBAL_COLD_RST, OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET); } }
static void iommu_disable(struct iommu *obj) { u32 reg; if (!obj) return; if (cpu_is_omap44xx() && !strcmp(obj->name, "ducati")) { reg = prm_read_mod_reg(OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTCTRL_OFFSET); prm_write_mod_reg((reg | RM_M3_RST1ST | RM_M3_RST2ST), OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTCTRL_OFFSET); } if (cpu_is_omap44xx() && !strcmp(obj->name, "tesla")) { reg = prm_read_mod_reg(OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTCTRL_OFFSET); prm_write_mod_reg((reg | RM_TESLA_RST1ST), OMAP4430_PRM_CORE_MOD, OMAP4_RM_TESLA_RSTCTRL_OFFSET); } if (!cpu_is_omap44xx()) clk_enable(obj->clk); arch_iommu->disable(obj); if (!cpu_is_omap44xx()) clk_disable(obj->clk); if (cpu_is_omap44xx() && !strcmp(obj->name, "ducati")) { pr_info("iommu_disable: Ducati Assert RST1, RST2 and RST3\n"); reg = prm_read_mod_reg(OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTCTRL_OFFSET); prm_write_mod_reg((reg | RM_M3_MPU_ALL_RESETS), OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTCTRL_OFFSET); pr_info("iommu_disable: Ducati Reset Status RSTST = 0x%x\n", prm_read_mod_reg(OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTST_OFFSET)); } if (cpu_is_omap44xx() && !strcmp(obj->name, "tesla")) { pr_info("iommu_disable: Tesla Assert DSP RST1 and RST2\n"); reg = prm_read_mod_reg(OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTCTRL_OFFSET); prm_write_mod_reg((reg | RM_TESLA_ALL_RESETS), OMAP4430_PRM_CORE_MOD, OMAP4_RM_TESLA_RSTCTRL_OFFSET); pr_info("iommu_disable: Tesla Reset Status RSTST = 0x%x\n", prm_read_mod_reg(OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTST_OFFSET)); } }
static int omap2_pm_suspend(void) { u32 wken_wkup, mir1; wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN); prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN); /* Mask GPT1 */ mir1 = omap_readl(0x480fe0a4); omap_writel(1 << 5, 0x480fe0ac); omap2_enter_full_retention(); omap_writel(mir1, 0x480fe0a4); prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN); return 0; }
/* Read-modify-write a register in a PRM module. Caller must lock */ u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx) { u32 v; /* CHIRON CPU0/1 domains are not part of PRM */ if (cpu_is_omap44xx() && ((module == OMAP4430_CHIRONSS_CHIRONSS_CPU0_MOD) || (module == OMAP4430_CHIRONSS_CHIRONSS_CPU1_MOD))) v = chiron_read_mod_reg(module, idx); else v = prm_read_mod_reg(module, idx); v &= ~mask; v |= bits; if (cpu_is_omap44xx() && ((module == OMAP4430_CHIRONSS_CHIRONSS_CPU0_MOD) || (module == OMAP4430_CHIRONSS_CHIRONSS_CPU1_MOD))) chiron_write_mod_reg(v, module, idx); else prm_write_mod_reg(v, module, idx); return v; }
static void omap2_enter_full_retention(void) { u32 l; struct timespec ts_preidle, ts_postidle, ts_idle; /* There is 1 reference hold for all children of the oscillator * clock, the following will remove it. If no one else uses the * oscillator itself it will be disabled if/when we enter retention * mode. */ clk_disable(osc_ck); /* Clear old wake-up events */ /* REVISIT: These write to reserved bits? */ prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1); prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); /* * Set MPU powerdomain's next power state to RETENTION; * preserve logic state during retention */ pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); /* Workaround to kill USB */ l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL; omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0); omap2_gpio_prepare_for_idle(PWRDM_POWER_RET); if (omap2_pm_debug) { omap2_pm_dump(0, 0, 0); getnstimeofday(&ts_preidle); } /* One last check for pending IRQs to avoid extra latency due * to sleeping unnecessarily. */ if (omap_irq_pending()) goto no_sleep; omap_uart_prepare_idle(0); omap_uart_prepare_idle(1); omap_uart_prepare_idle(2); /* Jump to SRAM suspend code */ omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL), OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL), OMAP_SDRC_REGADDR(SDRC_POWER)); no_sleep: omap_uart_resume_idle(2); omap_uart_resume_idle(1); omap_uart_resume_idle(0); if (omap2_pm_debug) { unsigned long long tmp; getnstimeofday(&ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC; omap2_pm_dump(0, 1, tmp); } omap2_gpio_resume_after_idle(); clk_enable(osc_ck); /* clear CORE wake-up events */ prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1); prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); /* wakeup domain events - bit 1: GPT1, bit5 GPIO */ prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST); /* MPU domain wake events */ l = prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET); if (l & 0x01) prm_write_mod_reg(0x01, OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET); if (l & 0x20) prm_write_mod_reg(0x20, OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET); /* Mask future PRCM-to-MPU interrupts */ prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET); }
int __init omap2_pm_init(void) { u32 l; printk(KERN_INFO "Power Management for OMAP2 initializing\n"); l = prm_read_mod_reg(OCP_MOD, OMAP24XX_PRM_REVISION_OFFSET); printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f); /* Look up important powerdomains, clockdomains */ mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); if (!mpu_pwrdm) pr_err("PM: mpu_pwrdm not found\n"); core_pwrdm = pwrdm_lookup("core_pwrdm"); if (!core_pwrdm) pr_err("PM: core_pwrdm not found\n"); dsp_clkdm = clkdm_lookup("dsp_clkdm"); if (!dsp_clkdm) pr_err("PM: mpu_clkdm not found\n"); gfx_clkdm = clkdm_lookup("gfx_clkdm"); if (!gfx_clkdm) pr_err("PM: gfx_clkdm not found\n"); osc_ck = clk_get(NULL, "osc_ck"); if (IS_ERR(osc_ck)) { printk(KERN_ERR "could not get osc_ck\n"); return -ENODEV; } if (cpu_is_omap242x()) { emul_ck = clk_get(NULL, "emul_ck"); if (IS_ERR(emul_ck)) { printk(KERN_ERR "could not get emul_ck\n"); clk_put(osc_ck); return -ENODEV; } } prcm_setup_regs(); /* Hack to prevent MPU retention when STI console is enabled. */ { const struct omap_sti_console_config *sti; sti = omap_get_config(OMAP_TAG_STI_CONSOLE, struct omap_sti_console_config); if (sti != NULL && sti->enable) sti_console_enabled = 1; } /* * We copy the assembler sleep/wakeup routines to SRAM. * These routines need to be in SRAM as that's the only * memory the MPU can see when it wakes up. */ if (cpu_is_omap24xx()) { omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, omap24xx_idle_loop_suspend_sz); omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, omap24xx_cpu_suspend_sz); } suspend_set_ops(&omap_pm_ops); pm_idle = omap2_pm_idle; return 0; }
void omap3_prcm_save_context(void) { prcm_context.control_padconf_sys_nirq = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_SYSNIRQ); prcm_context.iva2_cm_clksel1 = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL1); prcm_context.iva2_cm_clksel2 = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL2); prcm_context.cm_sysconfig = __raw_readl(OMAP3430_CM_SYSCONFIG); prcm_context.sgx_cm_clksel = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSEL); prcm_context.dss_cm_clksel = cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSEL); prcm_context.cam_cm_clksel = cm_read_mod_reg(OMAP3430_CAM_MOD, CM_CLKSEL); prcm_context.per_cm_clksel = cm_read_mod_reg(OMAP3430_PER_MOD, CM_CLKSEL); prcm_context.emu_cm_clksel = cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSEL1); prcm_context.emu_cm_clkstctrl = cm_read_mod_reg(OMAP3430_EMU_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.pll_cm_autoidle2 = cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2); prcm_context.pll_cm_clksel4 = cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL4); prcm_context.pll_cm_clksel5 = cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL5); prcm_context.pll_cm_clken2 = cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKEN2); prcm_context.cm_polctrl = __raw_readl(OMAP3430_CM_POLCTRL); prcm_context.iva2_cm_fclken = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_FCLKEN); prcm_context.iva2_cm_clken_pll = cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL); prcm_context.core_cm_fclken1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); prcm_context.core_cm_fclken3 = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3); prcm_context.sgx_cm_fclken = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_FCLKEN); prcm_context.wkup_cm_fclken = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN); prcm_context.dss_cm_fclken = cm_read_mod_reg(OMAP3430_DSS_MOD, CM_FCLKEN); prcm_context.cam_cm_fclken = cm_read_mod_reg(OMAP3430_CAM_MOD, CM_FCLKEN); prcm_context.per_cm_fclken = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN); prcm_context.usbhost_cm_fclken = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN); prcm_context.core_cm_iclken1 = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1); prcm_context.core_cm_iclken2 = cm_read_mod_reg(CORE_MOD, CM_ICLKEN2); prcm_context.core_cm_iclken3 = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3); prcm_context.sgx_cm_iclken = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_ICLKEN); prcm_context.wkup_cm_iclken = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN); prcm_context.dss_cm_iclken = cm_read_mod_reg(OMAP3430_DSS_MOD, CM_ICLKEN); prcm_context.cam_cm_iclken = cm_read_mod_reg(OMAP3430_CAM_MOD, CM_ICLKEN); prcm_context.per_cm_iclken = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN); prcm_context.usbhost_cm_iclken = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN); prcm_context.iva2_cm_autiidle2 = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_AUTOIDLE2); prcm_context.mpu_cm_autoidle2 = cm_read_mod_reg(MPU_MOD, CM_AUTOIDLE2); prcm_context.iva2_cm_clkstctrl = cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.mpu_cm_clkstctrl = cm_read_mod_reg(MPU_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.core_cm_clkstctrl = cm_read_mod_reg(CORE_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.sgx_cm_clkstctrl = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.dss_cm_clkstctrl = cm_read_mod_reg(OMAP3430_DSS_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.cam_cm_clkstctrl = cm_read_mod_reg(OMAP3430_CAM_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.per_cm_clkstctrl = cm_read_mod_reg(OMAP3430_PER_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.neon_cm_clkstctrl = cm_read_mod_reg(OMAP3430_NEON_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.usbhost_cm_clkstctrl = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.core_cm_autoidle1 = cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE1); prcm_context.core_cm_autoidle2 = cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE2); prcm_context.core_cm_autoidle3 = cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE3); prcm_context.wkup_cm_autoidle = cm_read_mod_reg(WKUP_MOD, CM_AUTOIDLE); prcm_context.dss_cm_autoidle = cm_read_mod_reg(OMAP3430_DSS_MOD, CM_AUTOIDLE); prcm_context.cam_cm_autoidle = cm_read_mod_reg(OMAP3430_CAM_MOD, CM_AUTOIDLE); prcm_context.per_cm_autoidle = cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE); prcm_context.usbhost_cm_autoidle = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE); prcm_context.sgx_cm_sleepdep = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.dss_cm_sleepdep = cm_read_mod_reg(OMAP3430_DSS_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.cam_cm_sleepdep = cm_read_mod_reg(OMAP3430_CAM_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.per_cm_sleepdep = cm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.usbhost_cm_sleepdep = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.cm_clkout_ctrl = cm_read_mod_reg(OMAP3430_CCR_MOD, OMAP3_CM_CLKOUT_CTRL_OFFSET); prcm_context.prm_clkout_ctrl = prm_read_mod_reg(OMAP3430_CCR_MOD, OMAP3_PRM_CLKOUT_CTRL_OFFSET); prcm_context.sgx_pm_wkdep = prm_read_mod_reg(OMAP3430ES2_SGX_MOD, PM_WKDEP); prcm_context.dss_pm_wkdep = prm_read_mod_reg(OMAP3430_DSS_MOD, PM_WKDEP); prcm_context.cam_pm_wkdep = prm_read_mod_reg(OMAP3430_CAM_MOD, PM_WKDEP); prcm_context.per_pm_wkdep = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKDEP); prcm_context.neon_pm_wkdep = prm_read_mod_reg(OMAP3430_NEON_MOD, PM_WKDEP); prcm_context.usbhost_pm_wkdep = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKDEP); prcm_context.core_pm_mpugrpsel1 = prm_read_mod_reg(CORE_MOD, OMAP3430_PM_MPUGRPSEL1); prcm_context.iva2_pm_ivagrpsel1 = prm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_PM_IVAGRPSEL1); prcm_context.core_pm_mpugrpsel3 = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_MPUGRPSEL3); prcm_context.core_pm_ivagrpsel3 = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); prcm_context.wkup_pm_mpugrpsel = prm_read_mod_reg(WKUP_MOD, OMAP3430_PM_MPUGRPSEL); prcm_context.wkup_pm_ivagrpsel = prm_read_mod_reg(WKUP_MOD, OMAP3430_PM_IVAGRPSEL); prcm_context.per_pm_mpugrpsel = prm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL); prcm_context.per_pm_ivagrpsel = prm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); prcm_context.wkup_pm_wken = prm_read_mod_reg(WKUP_MOD, PM_WKEN); return; }
static int iommu_enable(struct iommu *obj) { int err; u32 reg; if (!obj) return -EINVAL; if (cpu_is_omap44xx() && !strcmp(obj->name, "ducati")) { /* Check that releasing resets would indeed be effective */ reg = prm_read_mod_reg(OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTCTRL_OFFSET); pr_info("iommu_enable: OMAP4_RM_DUCATI_RSTCTRL_OFFSET = 0x%x", reg); if ((reg & RM_M3_MPU_ALL_RESETS) != RM_M3_MPU_ALL_RESETS) { pr_info("iommu_enable: Ducati Resets in not proper " "state!\n"); pr_info("iommu_enable: Ducati Asserting RST1, RST2, " "and RST3...\n"); prm_write_mod_reg(RM_M3_MPU_ALL_RESETS, OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTCTRL_OFFSET); while (prm_read_mod_reg(OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTCTRL_OFFSET) != RM_M3_MPU_ALL_RESETS); } /* De-assert RST3, and clear the Reset status */ pr_info("iommu_enable: De-assert Ducati RST3\n"); reg = prm_read_mod_reg(OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTCTRL_OFFSET); pr_info("iommu_enable: Ducati RSTCTRL = 0x%x\n", reg); prm_write_mod_reg(RM_M3_REL_RST3_MASK, OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTCTRL_OFFSET); while (!(prm_read_mod_reg(OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTST_OFFSET) & RM_M3_RST3ST)); pr_info("iommu_enable: Ducati RST3 released!"); prm_write_mod_reg(RM_M3_RST3ST, OMAP4430_PRM_CORE_MOD, OMAP4_RM_DUCATI_RSTST_OFFSET); pr_info("iommu_enable: Ducati %s %d\n", __func__, __LINE__); } if (cpu_is_omap44xx() && !strcmp(obj->name, "tesla")) { /* Check that releasing resets would indeed be effective */ reg = prm_read_mod_reg(OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTCTRL_OFFSET); pr_info("iommu_enable: OMAP4_RM_TESLA_RSTCTRL_OFFSET = 0x%x", reg); if ((reg & RM_TESLA_ALL_RESETS) != RM_TESLA_ALL_RESETS) { pr_info("iommu_enable: Tesla Resets in not proper " "state!\n"); pr_info("iommu_enable: Tesla Assert RST1 and RST2.n"); prm_write_mod_reg(RM_TESLA_ALL_RESETS, OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTCTRL_OFFSET); while (prm_read_mod_reg(OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTCTRL_OFFSET) != RM_TESLA_ALL_RESETS); } /* De-assert RST2, and clear the Reset status */ pr_info("iommu_enable: De-assert Tesla RST2\n"); reg = prm_read_mod_reg(OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTCTRL_OFFSET); pr_info("iommu_enable: Tesla RSTCTRL = 0x%x\n", reg); prm_write_mod_reg(RM_TESLA_REL_RST2_MASK, OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTCTRL_OFFSET); while (!(prm_read_mod_reg(OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTST_OFFSET) & RM_TESLA_RST2ST)); pr_info("iommu_enable: Tesla RST2 released!"); prm_write_mod_reg(RM_TESLA_RST2ST, OMAP4430_PRM_TESLA_MOD, OMAP4_RM_TESLA_RSTST_OFFSET); pr_info("iommu_enable: Tesla %s %d\n", __func__, __LINE__); } if (!cpu_is_omap44xx()) clk_enable(obj->clk); err = arch_iommu->enable(obj); if (!cpu_is_omap44xx()) clk_disable(obj->clk); return err; }
u32 omap_prcm_get_reset_sources(void) { /* XXX This presumably needs modification for 34XX */ return prm_read_mod_reg(WKUP_MOD, RM_RSTST) & 0x7f; }
/* Populate the scratchpad structure with restore structure */ void omap3_save_scratchpad_contents(void) { void __iomem *scratchpad_address; u32 arm_context_addr; struct omap3_scratchpad scratchpad_contents; struct omap3_scratchpad_prcm_block prcm_block_contents; struct omap3_scratchpad_sdrc_block sdrc_block_contents; /* Populate the Scratchpad contents */ scratchpad_contents.boot_config_ptr = 0x0; if (cpu_is_omap3630()) scratchpad_contents.public_restore_ptr = virt_to_phys(get_omap3630_restore_pointer()); else if (omap_rev() != OMAP3430_REV_ES3_0 && omap_rev() != OMAP3430_REV_ES3_1) scratchpad_contents.public_restore_ptr = virt_to_phys(get_restore_pointer()); else scratchpad_contents.public_restore_ptr = virt_to_phys(get_es3_restore_pointer()); if (omap_type() == OMAP2_DEVICE_TYPE_GP) scratchpad_contents.secure_ram_restore_ptr = 0x0; else scratchpad_contents.secure_ram_restore_ptr = (u32) __pa(omap3_secure_ram_storage); scratchpad_contents.sdrc_module_semaphore = 0x0; scratchpad_contents.prcm_block_offset = 0x2C; scratchpad_contents.sdrc_block_offset = 0x64; /* Populate the PRCM block contents */ prcm_block_contents.prm_clksrc_ctrl = prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_CLKSRC_CTRL_OFFSET); prcm_block_contents.prm_clksel = prm_read_mod_reg(OMAP3430_CCR_MOD, OMAP3_PRM_CLKSEL_OFFSET); prcm_block_contents.cm_clksel_core = cm_read_mod_reg(CORE_MOD, CM_CLKSEL); prcm_block_contents.cm_clksel_wkup = cm_read_mod_reg(WKUP_MOD, CM_CLKSEL); prcm_block_contents.cm_clken_pll = cm_read_mod_reg(PLL_MOD, CM_CLKEN); prcm_block_contents.cm_autoidle_pll = cm_read_mod_reg(PLL_MOD, OMAP3430_CM_AUTOIDLE_PLL); prcm_block_contents.cm_clksel1_pll = cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL1_PLL); prcm_block_contents.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL2_PLL); prcm_block_contents.cm_clksel3_pll = cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL3); prcm_block_contents.cm_clken_pll_mpu = cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKEN_PLL); prcm_block_contents.cm_autoidle_pll_mpu = cm_read_mod_reg(MPU_MOD, OMAP3430_CM_AUTOIDLE_PLL); prcm_block_contents.cm_clksel1_pll_mpu = cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL); prcm_block_contents.cm_clksel2_pll_mpu = cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKSEL2_PLL); prcm_block_contents.prcm_block_size = 0x0; /* Populate the SDRC block contents */ sdrc_block_contents.sysconfig = (sdrc_read_reg(SDRC_SYSCONFIG) & 0xFFFF); sdrc_block_contents.cs_cfg = (sdrc_read_reg(SDRC_CS_CFG) & 0xFFFF); sdrc_block_contents.sharing = (sdrc_read_reg(SDRC_SHARING) & 0xFFFF); sdrc_block_contents.err_type = (sdrc_read_reg(SDRC_ERR_TYPE) & 0xFFFF); sdrc_block_contents.dll_a_ctrl = sdrc_read_reg(SDRC_DLLA_CTRL); sdrc_block_contents.dll_b_ctrl = 0x0; /* * Due to a OMAP3 errata (1.142), on EMU/HS devices SRDC should * be programed to issue automatic self refresh on timeout * of AUTO_CNT = 1 prior to any transition to OFF mode. */ if ((omap_type() != OMAP2_DEVICE_TYPE_GP) && (omap_rev() >= OMAP3430_REV_ES3_0)) sdrc_block_contents.power = (sdrc_read_reg(SDRC_POWER) & ~(SDRC_POWER_AUTOCOUNT_MASK| SDRC_POWER_CLKCTRL_MASK)) | (1 << SDRC_POWER_AUTOCOUNT_SHIFT) | SDRC_SELF_REFRESH_ON_AUTOCOUNT; else sdrc_block_contents.power = sdrc_read_reg(SDRC_POWER); sdrc_block_contents.cs_0 = 0x0; sdrc_block_contents.mcfg_0 = sdrc_read_reg(SDRC_MCFG_0); sdrc_block_contents.mr_0 = (sdrc_read_reg(SDRC_MR_0) & 0xFFFF); sdrc_block_contents.emr_1_0 = 0x0; sdrc_block_contents.emr_2_0 = 0x0; sdrc_block_contents.emr_3_0 = 0x0; sdrc_block_contents.actim_ctrla_0 = sdrc_read_reg(SDRC_ACTIM_CTRL_A_0); sdrc_block_contents.actim_ctrlb_0 = sdrc_read_reg(SDRC_ACTIM_CTRL_B_0); sdrc_block_contents.rfr_ctrl_0 = sdrc_read_reg(SDRC_RFR_CTRL_0); sdrc_block_contents.cs_1 = 0x0; sdrc_block_contents.mcfg_1 = sdrc_read_reg(SDRC_MCFG_1); sdrc_block_contents.mr_1 = sdrc_read_reg(SDRC_MR_1) & 0xFFFF; sdrc_block_contents.emr_1_1 = 0x0; sdrc_block_contents.emr_2_1 = 0x0; sdrc_block_contents.emr_3_1 = 0x0; sdrc_block_contents.actim_ctrla_1 = sdrc_read_reg(SDRC_ACTIM_CTRL_A_1); sdrc_block_contents.actim_ctrlb_1 = sdrc_read_reg(SDRC_ACTIM_CTRL_B_1); sdrc_block_contents.rfr_ctrl_1 = sdrc_read_reg(SDRC_RFR_CTRL_1); sdrc_block_contents.dcdl_1_ctrl = 0x0; sdrc_block_contents.dcdl_2_ctrl = 0x0; sdrc_block_contents.flags = 0x0; sdrc_block_contents.block_size = 0x0; arm_context_addr = virt_to_phys(omap3_arm_context); /* Copy all the contents to the scratchpad location */ scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD); memcpy_toio(scratchpad_address, &scratchpad_contents, sizeof(scratchpad_contents)); /* Scratchpad contents being 32 bits, a divide by 4 done here */ memcpy_toio(scratchpad_address + scratchpad_contents.prcm_block_offset, &prcm_block_contents, sizeof(prcm_block_contents)); memcpy_toio(scratchpad_address + scratchpad_contents.sdrc_block_offset, &sdrc_block_contents, sizeof(sdrc_block_contents)); /* * Copies the address of the location in SDRAM where ARM * registers get saved during a MPU OFF transition. */ memcpy_toio(scratchpad_address + scratchpad_contents.sdrc_block_offset + sizeof(sdrc_block_contents), &arm_context_addr, 4); }
static u32 omap3_voltage_read_reg(u16 mod, u8 offset) { return prm_read_mod_reg(mod, offset); }