Commit 81c6d806 authored by Tony Lindgren's avatar Tony Lindgren

Merge branch 'for-v3.17/cm-prm-cleanup' of...

Merge branch 'for-v3.17/cm-prm-cleanup' of https://github.com/t-kristo/linux-pm into omap-for-v3.17/soc
parents 6bf58859 ba12c242
...@@ -44,8 +44,7 @@ struct omap3_scratchpad { ...@@ -44,8 +44,7 @@ struct omap3_scratchpad {
}; };
struct omap3_scratchpad_prcm_block { struct omap3_scratchpad_prcm_block {
u32 prm_clksrc_ctrl; u32 prm_contents[2];
u32 prm_clksel;
u32 cm_contents[11]; u32 cm_contents[11];
u32 prcm_block_size; u32 prcm_block_size;
}; };
...@@ -282,13 +281,9 @@ void omap3_clear_scratchpad_contents(void) ...@@ -282,13 +281,9 @@ void omap3_clear_scratchpad_contents(void)
void __iomem *v_addr; void __iomem *v_addr;
u32 offset = 0; u32 offset = 0;
v_addr = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD_ROM); v_addr = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD_ROM);
if (omap2_prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) & if (omap3xxx_prm_clear_global_cold_reset()) {
OMAP3430_GLOBAL_COLD_RST_MASK) {
for ( ; offset <= max_offset; offset += 0x4) for ( ; offset <= max_offset; offset += 0x4)
writel_relaxed(0x0, (v_addr + offset)); writel_relaxed(0x0, (v_addr + offset));
omap2_prm_set_mod_reg_bits(OMAP3430_GLOBAL_COLD_RST_MASK,
OMAP3430_GR_MOD,
OMAP3_PRM_RSTST_OFFSET);
} }
} }
...@@ -331,13 +326,7 @@ void omap3_save_scratchpad_contents(void) ...@@ -331,13 +326,7 @@ void omap3_save_scratchpad_contents(void)
scratchpad_contents.sdrc_block_offset = 0x64; scratchpad_contents.sdrc_block_offset = 0x64;
/* Populate the PRCM block contents */ /* Populate the PRCM block contents */
prcm_block_contents.prm_clksrc_ctrl = omap3_prm_save_scratchpad_contents(prcm_block_contents.prm_contents);
omap2_prm_read_mod_reg(OMAP3430_GR_MOD,
OMAP3_PRM_CLKSRC_CTRL_OFFSET);
prcm_block_contents.prm_clksel =
omap2_prm_read_mod_reg(OMAP3430_CCR_MOD,
OMAP3_PRM_CLKSEL_OFFSET);
omap3_cm_save_scratchpad_contents(prcm_block_contents.cm_contents); omap3_cm_save_scratchpad_contents(prcm_block_contents.cm_contents);
prcm_block_contents.prcm_block_size = 0x0; prcm_block_contents.prcm_block_size = 0x0;
...@@ -575,9 +564,50 @@ int omap3_ctrl_save_padconf(void) ...@@ -575,9 +564,50 @@ int omap3_ctrl_save_padconf(void)
* Sets the bootmode for IVA2 to idle. This is needed by the PM code to * Sets the bootmode for IVA2 to idle. This is needed by the PM code to
* force disable IVA2 so that it does not prevent any low-power states. * force disable IVA2 so that it does not prevent any low-power states.
*/ */
void omap3_ctrl_set_iva_bootmode_idle(void) static void __init omap3_ctrl_set_iva_bootmode_idle(void)
{ {
omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE, omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
OMAP343X_CONTROL_IVA2_BOOTMOD); OMAP343X_CONTROL_IVA2_BOOTMOD);
} }
/**
* omap3_ctrl_setup_d2d_padconf - setup stacked modem pads for idle
*
* Sets up the pads controlling the stacked modem in such way that the
* device can enter idle.
*/
static void __init omap3_ctrl_setup_d2d_padconf(void)
{
u16 mask, padconf;
/*
* In a stand alone OMAP3430 where there is not a stacked
* modem for the D2D Idle Ack and D2D MStandby must be pulled
* high. S CONTROL_PADCONF_SAD2D_IDLEACK and
* CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up.
*/
mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
padconf |= mask;
omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
padconf |= mask;
omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
}
/**
* omap3_ctrl_init - does static initializations for control module
*
* Initializes system control module. This sets up the sysconfig autoidle,
* and sets up modem and iva2 so that they can be idled properly.
*/
void __init omap3_ctrl_init(void)
{
omap_ctrl_writel(OMAP3430_AUTOIDLE_MASK, OMAP2_CONTROL_SYSCONFIG);
omap3_ctrl_set_iva_bootmode_idle();
omap3_ctrl_setup_d2d_padconf();
}
#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */ #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
...@@ -455,7 +455,7 @@ extern void omap_ctrl_write_dsp_boot_addr(u32 bootaddr); ...@@ -455,7 +455,7 @@ extern void omap_ctrl_write_dsp_boot_addr(u32 bootaddr);
extern void omap_ctrl_write_dsp_boot_mode(u8 bootmode); extern void omap_ctrl_write_dsp_boot_mode(u8 bootmode);
extern void omap3630_ctrl_disable_rta(void); extern void omap3630_ctrl_disable_rta(void);
extern int omap3_ctrl_save_padconf(void); extern int omap3_ctrl_save_padconf(void);
extern void omap3_ctrl_set_iva_bootmode_idle(void); void omap3_ctrl_init(void);
extern void omap2_set_globals_control(void __iomem *ctrl, extern void omap2_set_globals_control(void __iomem *ctrl,
void __iomem *ctrl_pad); void __iomem *ctrl_pad);
#else #else
......
...@@ -75,9 +75,9 @@ static int omap2_enter_full_retention(void) ...@@ -75,9 +75,9 @@ static int omap2_enter_full_retention(void)
/* Clear old wake-up events */ /* Clear old wake-up events */
/* REVISIT: These write to reserved bits? */ /* REVISIT: These write to reserved bits? */
omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1); omap2xxx_prm_clear_mod_irqs(CORE_MOD, PM_WKST1, ~0);
omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); omap2xxx_prm_clear_mod_irqs(CORE_MOD, OMAP24XX_PM_WKST2, ~0);
omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); omap2xxx_prm_clear_mod_irqs(WKUP_MOD, PM_WKST, ~0);
pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET); pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
...@@ -104,23 +104,18 @@ static int omap2_enter_full_retention(void) ...@@ -104,23 +104,18 @@ static int omap2_enter_full_retention(void)
clk_enable(osc_ck); clk_enable(osc_ck);
/* clear CORE wake-up events */ /* clear CORE wake-up events */
omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1); omap2xxx_prm_clear_mod_irqs(CORE_MOD, PM_WKST1, ~0);
omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); omap2xxx_prm_clear_mod_irqs(CORE_MOD, OMAP24XX_PM_WKST2, ~0);
/* wakeup domain events - bit 1: GPT1, bit5 GPIO */ /* wakeup domain events - bit 1: GPT1, bit5 GPIO */
omap2_prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST); omap2xxx_prm_clear_mod_irqs(WKUP_MOD, PM_WKST, 0x4 | 0x1);
/* MPU domain wake events */ /* MPU domain wake events */
l = omap2_prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); omap2xxx_prm_clear_mod_irqs(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET,
if (l & 0x01) 0x1);
omap2_prm_write_mod_reg(0x01, OCP_MOD,
OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
if (l & 0x20)
omap2_prm_write_mod_reg(0x20, OCP_MOD,
OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
/* Mask future PRCM-to-MPU interrupts */ omap2xxx_prm_clear_mod_irqs(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET,
omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); 0x20);
pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON); pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON);
...@@ -148,9 +143,9 @@ static void omap2_enter_mpu_retention(void) ...@@ -148,9 +143,9 @@ static void omap2_enter_mpu_retention(void)
* it is in retention mode. */ * it is in retention mode. */
if (omap2_allow_mpu_retention()) { if (omap2_allow_mpu_retention()) {
/* REVISIT: These write to reserved bits? */ /* REVISIT: These write to reserved bits? */
omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1); omap2xxx_prm_clear_mod_irqs(CORE_MOD, PM_WKST1, ~0);
omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); omap2xxx_prm_clear_mod_irqs(CORE_MOD, OMAP24XX_PM_WKST2, ~0);
omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); omap2xxx_prm_clear_mod_irqs(WKUP_MOD, PM_WKST, ~0);
/* Try to enter MPU retention */ /* Try to enter MPU retention */
pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
......
...@@ -133,60 +133,13 @@ static void omap3_save_secure_ram_context(void) ...@@ -133,60 +133,13 @@ static void omap3_save_secure_ram_context(void)
} }
} }
/*
* 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 ignore_bits)
{
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 = 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) static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
{ {
int c; int c;
c = prcm_clear_mod_irqs(WKUP_MOD, 1, c = omap3xxx_prm_clear_mod_irqs(WKUP_MOD, 1,
~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK)); ~(OMAP3430_ST_IO_MASK |
OMAP3430_ST_IO_CHAIN_MASK));
return c ? IRQ_HANDLED : IRQ_NONE; return c ? IRQ_HANDLED : IRQ_NONE;
} }
...@@ -200,13 +153,14 @@ static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused) ...@@ -200,13 +153,14 @@ static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
* these are handled in a separate handler to avoid acking * these are handled in a separate handler to avoid acking
* IO events before parsing in mux code * IO events before parsing in mux code
*/ */
c = prcm_clear_mod_irqs(WKUP_MOD, 1, c = omap3xxx_prm_clear_mod_irqs(WKUP_MOD, 1,
OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK); OMAP3430_ST_IO_MASK |
c += prcm_clear_mod_irqs(CORE_MOD, 1, 0); OMAP3430_ST_IO_CHAIN_MASK);
c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0); c += omap3xxx_prm_clear_mod_irqs(CORE_MOD, 1, 0);
c += omap3xxx_prm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0);
if (omap_rev() > OMAP3430_REV_ES1_0) { if (omap_rev() > OMAP3430_REV_ES1_0) {
c += prcm_clear_mod_irqs(CORE_MOD, 3, 0); c += omap3xxx_prm_clear_mod_irqs(CORE_MOD, 3, 0);
c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0); c += omap3xxx_prm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0);
} }
return c ? IRQ_HANDLED : IRQ_NONE; return c ? IRQ_HANDLED : IRQ_NONE;
...@@ -399,159 +353,11 @@ static int omap3_pm_suspend(void) ...@@ -399,159 +353,11 @@ static int omap3_pm_suspend(void)
#define omap3_pm_suspend NULL #define omap3_pm_suspend NULL
#endif /* CONFIG_SUSPEND */ #endif /* CONFIG_SUSPEND */
/**
* omap3_iva_idle(): ensure IVA is in idle so it can be put into
* retention
*
* In cases where IVA2 is activated by bootcode, it may prevent
* full-chip retention or off-mode because it is not idle. This
* function forces the IVA2 into idle state so it can go
* into retention/off and thus allow full-chip retention/off.
*
**/
static void __init omap3_iva_idle(void)
{
/* ensure IVA2 clock is disabled */
omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
/* if no clock activity, nothing else to do */
if (!(omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
OMAP3430_CLKACTIVITY_IVA2_MASK))
return;
/* Reset IVA2 */
omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK |
OMAP3430_RST2_IVA2_MASK |
OMAP3430_RST3_IVA2_MASK,
OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
/* Enable IVA2 clock */
omap2_cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK,
OMAP3430_IVA2_MOD, CM_FCLKEN);
/* Set IVA2 boot mode to 'idle' */
omap3_ctrl_set_iva_bootmode_idle();
/* Un-reset IVA2 */
omap2_prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
/* Disable IVA2 clock */
omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
/* Reset IVA2 */
omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK |
OMAP3430_RST2_IVA2_MASK |
OMAP3430_RST3_IVA2_MASK,
OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
}
static void __init omap3_d2d_idle(void)
{
u16 mask, padconf;
/* In a stand alone OMAP3430 where there is not a stacked
* modem for the D2D Idle Ack and D2D MStandby must be pulled
* high. S CONTROL_PADCONF_SAD2D_IDLEACK and
* CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
padconf |= mask;
omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
padconf |= mask;
omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
/* reset modem */
omap2_prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON_MASK |
OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST_MASK,
CORE_MOD, OMAP2_RM_RSTCTRL);
omap2_prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL);
}
static void __init prcm_setup_regs(void) static void __init prcm_setup_regs(void)
{ {
u32 omap3630_en_uart4_mask = cpu_is_omap3630() ? omap3_ctrl_init();
OMAP3630_EN_UART4_MASK : 0;
u32 omap3630_grpsel_uart4_mask = cpu_is_omap3630() ?
OMAP3630_GRPSEL_UART4_MASK : 0;
/* XXX This should be handled by hwmod code or SCM init code */
omap_ctrl_writel(OMAP3430_AUTOIDLE_MASK, OMAP2_CONTROL_SYSCONFIG);
/*
* Enable control of expternal oscillator through
* sys_clkreq. In the long run clock framework should
* take care of this.
*/
omap2_prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
1 << OMAP_AUTOEXTCLKMODE_SHIFT,
OMAP3430_GR_MOD,
OMAP3_PRM_CLKSRC_CTRL_OFFSET);
/* setup wakup source */
omap2_prm_write_mod_reg(OMAP3430_EN_IO_MASK | OMAP3430_EN_GPIO1_MASK |
OMAP3430_EN_GPT1_MASK | OMAP3430_EN_GPT12_MASK,
WKUP_MOD, PM_WKEN);
/* No need to write EN_IO, that is always enabled */
omap2_prm_write_mod_reg(OMAP3430_GRPSEL_GPIO1_MASK |
OMAP3430_GRPSEL_GPT1_MASK |
OMAP3430_GRPSEL_GPT12_MASK,
WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
/* Enable PM_WKEN to support DSS LPR */
omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK,
OMAP3430_DSS_MOD, PM_WKEN);
/* Enable wakeups in PER */
omap2_prm_write_mod_reg(omap3630_en_uart4_mask |
OMAP3430_EN_GPIO2_MASK | OMAP3430_EN_GPIO3_MASK |
OMAP3430_EN_GPIO4_MASK | OMAP3430_EN_GPIO5_MASK |
OMAP3430_EN_GPIO6_MASK | OMAP3430_EN_UART3_MASK |
OMAP3430_EN_MCBSP2_MASK | OMAP3430_EN_MCBSP3_MASK |
OMAP3430_EN_MCBSP4_MASK,
OMAP3430_PER_MOD, PM_WKEN);
/* and allow them to wake up MPU */
omap2_prm_write_mod_reg(omap3630_grpsel_uart4_mask |
OMAP3430_GRPSEL_GPIO2_MASK |
OMAP3430_GRPSEL_GPIO3_MASK |
OMAP3430_GRPSEL_GPIO4_MASK |
OMAP3430_GRPSEL_GPIO5_MASK |
OMAP3430_GRPSEL_GPIO6_MASK |
OMAP3430_GRPSEL_UART3_MASK |
OMAP3430_GRPSEL_MCBSP2_MASK |
OMAP3430_GRPSEL_MCBSP3_MASK |
OMAP3430_GRPSEL_MCBSP4_MASK,
OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL);
/* Don't attach IVA interrupts */
if (omap3_has_iva()) {
omap2_prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
omap2_prm_write_mod_reg(0, OMAP3430_PER_MOD,
OMAP3430_PM_IVAGRPSEL);
}
/* Clear any pending 'reset' flags */
omap2_prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, OMAP2_RM_RSTST);
/* Clear any pending PRCM interrupts */
omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
/*
* We need to idle iva2_pwrdm even on am3703 with no iva2.
*/
omap3_iva_idle();
omap3_d2d_idle(); omap3_prm_init_pm(cpu_is_omap3630(), omap3_has_iva());
} }
void omap3_pm_off_mode_enable(int enable) void omap3_pm_off_mode_enable(int enable)
......
...@@ -114,6 +114,24 @@ void omap2xxx_prm_dpll_reset(void) ...@@ -114,6 +114,24 @@ void omap2xxx_prm_dpll_reset(void)
omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL); omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL);
} }
/**
* omap2xxx_prm_clear_mod_irqs - clear wakeup status bits for a module
* @module: PRM module to clear wakeups from
* @regs: register offset to clear
* @wkst_mask: wakeup status mask to clear
*
* Clears wakeup status bits for a given module, so that the device can
* re-enter idle.
*/
void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask)
{
u32 wkst;
wkst = omap2_prm_read_mod_reg(module, regs);
wkst &= wkst_mask;
omap2_prm_write_mod_reg(wkst, module, regs);
}
int omap2xxx_clkdm_sleep(struct clockdomain *clkdm) int omap2xxx_clkdm_sleep(struct clockdomain *clkdm)
{ {
omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
......
...@@ -125,6 +125,7 @@ extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm); ...@@ -125,6 +125,7 @@ extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm);
extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm); extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm);
extern void omap2xxx_prm_dpll_reset(void); extern void omap2xxx_prm_dpll_reset(void);
void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask);
extern int __init omap2xxx_prm_init(void); extern int __init omap2xxx_prm_init(void);
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include "prm2xxx_3xxx.h" #include "prm2xxx_3xxx.h"
#include "cm2xxx_3xxx.h" #include "cm2xxx_3xxx.h"
#include "prm-regbits-34xx.h" #include "prm-regbits-34xx.h"
#include "cm3xxx.h"
#include "cm-regbits-34xx.h"
static const struct omap_prcm_irq omap3_prcm_irqs[] = { static const struct omap_prcm_irq omap3_prcm_irqs[] = {
OMAP_PRCM_IRQ("wkup", 0, 0), OMAP_PRCM_IRQ("wkup", 0, 0),
...@@ -205,6 +207,167 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask) ...@@ -205,6 +207,167 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
OMAP3_PRM_IRQENABLE_MPU_OFFSET); OMAP3_PRM_IRQENABLE_MPU_OFFSET);
} }
/**
* omap3xxx_prm_clear_mod_irqs - clear wake-up events from PRCM interrupt
* @module: PRM module to clear wakeups from
* @regs: register set to clear, 1 or 3
* @ignore_bits: wakeup status bits to ignore
*
* 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.
*/
int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
{
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 = 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;
}
/**
* omap3_prm_reset_modem - toggle reset signal for modem
*
* Toggles the reset signal to modem IP block. Required to allow
* OMAP3430 without stacked modem to idle properly.
*/
void __init omap3_prm_reset_modem(void)
{
omap2_prm_write_mod_reg(
OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON_MASK |
OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST_MASK,
CORE_MOD, OMAP2_RM_RSTCTRL);
omap2_prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL);
}
/**
* omap3_prm_init_pm - initialize PM related registers for PRM
* @has_uart4: SoC has UART4
* @has_iva: SoC has IVA
*
* Initializes PRM registers for PM use. Called from PM init.
*/
void __init omap3_prm_init_pm(bool has_uart4, bool has_iva)
{
u32 en_uart4_mask;
u32 grpsel_uart4_mask;
/*
* Enable control of expternal oscillator through
* sys_clkreq. In the long run clock framework should
* take care of this.
*/
omap2_prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
1 << OMAP_AUTOEXTCLKMODE_SHIFT,
OMAP3430_GR_MOD,
OMAP3_PRM_CLKSRC_CTRL_OFFSET);
/* setup wakup source */
omap2_prm_write_mod_reg(OMAP3430_EN_IO_MASK | OMAP3430_EN_GPIO1_MASK |
OMAP3430_EN_GPT1_MASK | OMAP3430_EN_GPT12_MASK,
WKUP_MOD, PM_WKEN);
/* No need to write EN_IO, that is always enabled */
omap2_prm_write_mod_reg(OMAP3430_GRPSEL_GPIO1_MASK |
OMAP3430_GRPSEL_GPT1_MASK |
OMAP3430_GRPSEL_GPT12_MASK,
WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
/* Enable PM_WKEN to support DSS LPR */
omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK,
OMAP3430_DSS_MOD, PM_WKEN);
if (has_uart4) {
en_uart4_mask = OMAP3630_EN_UART4_MASK;
grpsel_uart4_mask = OMAP3630_GRPSEL_UART4_MASK;
}
/* Enable wakeups in PER */
omap2_prm_write_mod_reg(en_uart4_mask |
OMAP3430_EN_GPIO2_MASK |
OMAP3430_EN_GPIO3_MASK |
OMAP3430_EN_GPIO4_MASK |
OMAP3430_EN_GPIO5_MASK |
OMAP3430_EN_GPIO6_MASK |
OMAP3430_EN_UART3_MASK |
OMAP3430_EN_MCBSP2_MASK |
OMAP3430_EN_MCBSP3_MASK |
OMAP3430_EN_MCBSP4_MASK,
OMAP3430_PER_MOD, PM_WKEN);
/* and allow them to wake up MPU */
omap2_prm_write_mod_reg(grpsel_uart4_mask |
OMAP3430_GRPSEL_GPIO2_MASK |
OMAP3430_GRPSEL_GPIO3_MASK |
OMAP3430_GRPSEL_GPIO4_MASK |
OMAP3430_GRPSEL_GPIO5_MASK |
OMAP3430_GRPSEL_GPIO6_MASK |
OMAP3430_GRPSEL_UART3_MASK |
OMAP3430_GRPSEL_MCBSP2_MASK |
OMAP3430_GRPSEL_MCBSP3_MASK |
OMAP3430_GRPSEL_MCBSP4_MASK,
OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL);
/* Don't attach IVA interrupts */
if (has_iva) {
omap2_prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
omap2_prm_write_mod_reg(0, OMAP3430_PER_MOD,
OMAP3430_PM_IVAGRPSEL);
}
/* Clear any pending 'reset' flags */
omap2_prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, OMAP2_RM_RSTST);
omap2_prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD,
OMAP2_RM_RSTST);
/* Clear any pending PRCM interrupts */
omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
/* We need to idle iva2_pwrdm even on am3703 with no iva2. */
omap3xxx_prm_iva_idle();
omap3_prm_reset_modem();
}
/** /**
* omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain * omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
* *
...@@ -276,6 +439,76 @@ static u32 omap3xxx_prm_read_reset_sources(void) ...@@ -276,6 +439,76 @@ static u32 omap3xxx_prm_read_reset_sources(void)
return r; return r;
} }
/**
* omap3xxx_prm_iva_idle - ensure IVA is in idle so it can be put into retention
*
* In cases where IVA2 is activated by bootcode, it may prevent
* full-chip retention or off-mode because it is not idle. This
* function forces the IVA2 into idle state so it can go
* into retention/off and thus allow full-chip retention/off.
*/
void omap3xxx_prm_iva_idle(void)
{
/* ensure IVA2 clock is disabled */
omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
/* if no clock activity, nothing else to do */
if (!(omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
OMAP3430_CLKACTIVITY_IVA2_MASK))
return;
/* Reset IVA2 */
omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK |
OMAP3430_RST2_IVA2_MASK |
OMAP3430_RST3_IVA2_MASK,
OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
/* Enable IVA2 clock */
omap2_cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK,
OMAP3430_IVA2_MOD, CM_FCLKEN);
/* Un-reset IVA2 */
omap2_prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
/* Disable IVA2 clock */
omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
/* Reset IVA2 */
omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK |
OMAP3430_RST2_IVA2_MASK |
OMAP3430_RST3_IVA2_MASK,
OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
}
/**
* omap3xxx_prm_clear_global_cold_reset - checks the global cold reset status
* and clears it if asserted
*
* Checks if cold-reset has occurred and clears the status bit if yes. Returns
* 1 if cold-reset has occurred, 0 otherwise.
*/
int omap3xxx_prm_clear_global_cold_reset(void)
{
if (omap2_prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) &
OMAP3430_GLOBAL_COLD_RST_MASK) {
omap2_prm_set_mod_reg_bits(OMAP3430_GLOBAL_COLD_RST_MASK,
OMAP3430_GR_MOD,
OMAP3_PRM_RSTST_OFFSET);
return 1;
}
return 0;
}
void omap3_prm_save_scratchpad_contents(u32 *ptr)
{
*ptr++ = omap2_prm_read_mod_reg(OMAP3430_GR_MOD,
OMAP3_PRM_CLKSRC_CTRL_OFFSET);
*ptr++ = omap2_prm_read_mod_reg(OMAP3430_GR_MOD,
OMAP3_PRM_CLKSEL_OFFSET);
}
/* Powerdomain low-level functions */ /* Powerdomain low-level functions */
static int omap3_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) static int omap3_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
......
...@@ -162,6 +162,12 @@ extern void omap3xxx_prm_dpll3_reset(void); ...@@ -162,6 +162,12 @@ extern void omap3xxx_prm_dpll3_reset(void);
extern int __init omap3xxx_prm_init(void); extern int __init omap3xxx_prm_init(void);
extern u32 omap3xxx_prm_get_reset_sources(void); extern u32 omap3xxx_prm_get_reset_sources(void);
int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits);
void omap3xxx_prm_iva_idle(void);
void omap3_prm_reset_modem(void);
int omap3xxx_prm_clear_global_cold_reset(void);
void omap3_prm_save_scratchpad_contents(u32 *ptr);
void omap3_prm_init_pm(bool has_uart4, bool has_iva);
#endif /* __ASSEMBLER */ #endif /* __ASSEMBLER */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment