This is a fix for pm code with regard to the DSP.
In the current code we have a problem that DSP won't
re-enabled after suspend if DSP is just turned on
(with idle request) from McBSP driver but not used
by DSP Gateway.
I moved DSP related code from pm.c to dsp_common.c.
With this patch DSP will be resumed to the original state
after suspend, whichever state (reset / idling for
McBSP / running with DSP Gateway) DSP was in.
Signed-off-by: Toshihiro Kobayashi <Toshihiro.Kobayashi@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/mm.h>
+#include <asm/io.h>
#include <asm/tlbflush.h>
#include <asm/irq.h>
#include <asm/arch/dsp.h>
dsp_idle();
}
+static unsigned short save_dsp_idlect2;
+
+/*
+ * note: if we are in pm_suspend / pm_resume function,
+ * we are out of clk_use() management.
+ */
+void omap_dsp_pm_suspend(void)
+{
+ unsigned short save_arm_idlect2;
+
+ /* Reset DSP */
+ __dsp_reset();
+
+ clk_disable(dsp_ck_handle);
+
+ /* Stop any DSP domain clocks */
+ save_arm_idlect2 = omap_readw(ARM_IDLECT2); // api_ck is in ARM_IDLECT2
+ clk_enable(api_ck_handle);
+ save_dsp_idlect2 = __raw_readw(DSP_IDLECT2);
+ __raw_writew(0, DSP_IDLECT2);
+ omap_writew(save_arm_idlect2, ARM_IDLECT2);
+}
+
+void omap_dsp_pm_resume(void)
+{
+ unsigned short save_arm_idlect2;
+
+ /* Restore DSP domain clocks */
+ save_arm_idlect2 = omap_readw(ARM_IDLECT2); // api_ck is in ARM_IDLECT2
+ clk_enable(api_ck_handle);
+ __raw_writew(save_dsp_idlect2, DSP_IDLECT2);
+ omap_writew(save_arm_idlect2, ARM_IDLECT2);
+
+ /* Run DSP, if it was running */
+ if (dsp_runstat != RUNSTAT_RESET)
+ __dsp_run();
+}
static int init_done;
static int __init omap_dsp_init(void)
arch_initcall(omap_dsp_init);
+EXPORT_SYMBOL(omap_dsp_pm_suspend);
+EXPORT_SYMBOL(omap_dsp_pm_resume);
EXPORT_SYMBOL(omap_dsp_request_idle);
#ifdef CONFIG_OMAP_DSP_MODULE
return -ERESTARTSYS;
if (!dsp_is_ready()) {
- printk(KERN_WARNING
- "omapdsp: DSP is not ready. suspend failed.\n");
ret = -EINVAL;
goto up_out;
}
}
udelay(100);
- dsp_reset();
cfgstat = CFG_SUSPEND;
up_out:
up(&ioctl_sem);
return 0;
cfgstat = CFG_READY;
- dsp_run();
return 0;
}
break;
case OMAP_DSP_IOCTL_SUSPEND:
- ret = dsp_suspend();
+ if ((ret = dsp_suspend()) < 0)
+ break;
+ dsp_reset();
break;
case OMAP_DSP_IOCTL_RESUME:
- ret = dsp_resume();
+ if ((ret = dsp_resume()) < 0)
+ break;
+ dsp_run();
break;
case OMAP_DSP_IOCTL_REGMEMR:
#include <asm/arch/pm.h>
#include <asm/arch/mux.h>
#include <asm/arch/tps65010.h>
+#include <asm/arch/dsp_common.h>
#include "clock.h"
{
unsigned long arg0 = 0, arg1 = 0;
int (*func_ptr)(unsigned short, unsigned short) = NULL;
- unsigned short save_dsp_idlect2;
printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
* Step 4: OMAP DSP Shutdown
*/
- /* Set DSP_RST = 1 and DSP_EN = 0, put DSP block into reset */
- omap_writel((omap_readl(ARM_RSTCT1) | DSP_RST) & ~DSP_ENABLE,
- ARM_RSTCT1);
-
- /* Set DSP boot mode to DSP-IDLE, DSP_BOOT_MODE = 0x2 */
- omap_writel(DSP_IDLE_MODE, MPUI_DSP_BOOT_CONFIG);
-
- /* Set EN_DSPCK = 0, stop DSP block clock */
- omap_writel(omap_readl(ARM_CKCTL) & ~DSP_CLOCK_ENABLE, ARM_CKCTL);
-
- /* Stop any DSP domain clocks */
- omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
- save_dsp_idlect2 = __raw_readw(DSP_IDLECT2);
- __raw_writew(0, DSP_IDLECT2);
+ omap_dsp_pm_suspend();
/*
* Step 5: Wakeup Event Setup
*/
/* Restore DSP clocks */
- omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
- __raw_writew(save_dsp_idlect2, DSP_IDLECT2);
- ARM_RESTORE(ARM_IDLECT2);
+ omap_dsp_pm_resume();
/*
* Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
#ifndef ASM_ARCH_DSP_COMMON_H
#define ASM_ARCH_DSP_COMMON_H
+void omap_dsp_pm_suspend(void);
+void omap_dsp_pm_resume(void);
void omap_dsp_request_idle(void);
#endif /* ASM_ARCH_DSP_COMMON_H */