summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Lauss <mano@roarinelk.homelinux.net>2008-12-21 11:26:26 +0300
committerRalf Baechle <ralf@linux-mips.org>2009-01-11 12:57:27 +0300
commitac15dad061d351281b0bafbae1ecdd84e601435a (patch)
treedc5536f68f14e3a07f3af1105cfc23a2c317f21f
parent564365b0fc3395ed55501ef25705664888cebdbc (diff)
downloadlinux-ac15dad061d351281b0bafbae1ecdd84e601435a.tar.xz
MIPS: Alchemy: dbdma suspend/resume support.
Implement suspend/resume for DBDMA controller and its channels. Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/alchemy/common/dbdma.c65
-rw-r--r--arch/mips/alchemy/common/power.c11
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h5
3 files changed, 81 insertions, 0 deletions
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
index 601ee9180ee4..3ab6d80d150d 100644
--- a/arch/mips/alchemy/common/dbdma.c
+++ b/arch/mips/alchemy/common/dbdma.c
@@ -174,6 +174,11 @@ static dbdev_tab_t dbdev_tab[] = {
#define DBDEV_TAB_SIZE ARRAY_SIZE(dbdev_tab)
+#ifdef CONFIG_PM
+static u32 au1xxx_dbdma_pm_regs[NUM_DBDMA_CHANS + 1][8];
+#endif
+
+
static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS];
static dbdev_tab_t *find_dbdev_id(u32 id)
@@ -975,4 +980,64 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)
return nbytes;
}
+#ifdef CONFIG_PM
+void au1xxx_dbdma_suspend(void)
+{
+ int i;
+ u32 addr;
+
+ addr = DDMA_GLOBAL_BASE;
+ au1xxx_dbdma_pm_regs[0][0] = au_readl(addr + 0x00);
+ au1xxx_dbdma_pm_regs[0][1] = au_readl(addr + 0x04);
+ au1xxx_dbdma_pm_regs[0][2] = au_readl(addr + 0x08);
+ au1xxx_dbdma_pm_regs[0][3] = au_readl(addr + 0x0c);
+
+ /* save channel configurations */
+ for (i = 1, addr = DDMA_CHANNEL_BASE; i < NUM_DBDMA_CHANS; i++) {
+ au1xxx_dbdma_pm_regs[i][0] = au_readl(addr + 0x00);
+ au1xxx_dbdma_pm_regs[i][1] = au_readl(addr + 0x04);
+ au1xxx_dbdma_pm_regs[i][2] = au_readl(addr + 0x08);
+ au1xxx_dbdma_pm_regs[i][3] = au_readl(addr + 0x0c);
+ au1xxx_dbdma_pm_regs[i][4] = au_readl(addr + 0x10);
+ au1xxx_dbdma_pm_regs[i][5] = au_readl(addr + 0x14);
+ au1xxx_dbdma_pm_regs[i][6] = au_readl(addr + 0x18);
+
+ /* halt channel */
+ au_writel(au1xxx_dbdma_pm_regs[i][0] & ~1, addr + 0x00);
+ au_sync();
+ while (!(au_readl(addr + 0x14) & 1))
+ au_sync();
+
+ addr += 0x100; /* next channel base */
+ }
+ /* disable channel interrupts */
+ au_writel(0, DDMA_GLOBAL_BASE + 0x0c);
+ au_sync();
+}
+
+void au1xxx_dbdma_resume(void)
+{
+ int i;
+ u32 addr;
+
+ addr = DDMA_GLOBAL_BASE;
+ au_writel(au1xxx_dbdma_pm_regs[0][0], addr + 0x00);
+ au_writel(au1xxx_dbdma_pm_regs[0][1], addr + 0x04);
+ au_writel(au1xxx_dbdma_pm_regs[0][2], addr + 0x08);
+ au_writel(au1xxx_dbdma_pm_regs[0][3], addr + 0x0c);
+
+ /* restore channel configurations */
+ for (i = 1, addr = DDMA_CHANNEL_BASE; i < NUM_DBDMA_CHANS; i++) {
+ au_writel(au1xxx_dbdma_pm_regs[i][0], addr + 0x00);
+ au_writel(au1xxx_dbdma_pm_regs[i][1], addr + 0x04);
+ au_writel(au1xxx_dbdma_pm_regs[i][2], addr + 0x08);
+ au_writel(au1xxx_dbdma_pm_regs[i][3], addr + 0x0c);
+ au_writel(au1xxx_dbdma_pm_regs[i][4], addr + 0x10);
+ au_writel(au1xxx_dbdma_pm_regs[i][5], addr + 0x14);
+ au_writel(au1xxx_dbdma_pm_regs[i][6], addr + 0x18);
+ au_sync();
+ addr += 0x100; /* next channel base */
+ }
+}
+#endif /* CONFIG_PM */
#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c
index f08312b10d04..f58e151b38d4 100644
--- a/arch/mips/alchemy/common/power.c
+++ b/arch/mips/alchemy/common/power.c
@@ -36,6 +36,9 @@
#include <asm/uaccess.h>
#include <asm/mach-au1x00/au1000.h>
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#endif
#ifdef CONFIG_PM
@@ -156,6 +159,10 @@ static void save_core_regs(void)
sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3);
sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3);
sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3);
+
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+ au1xxx_dbdma_suspend();
+#endif
}
static void restore_core_regs(void)
@@ -221,6 +228,10 @@ static void restore_core_regs(void)
}
restore_au1xxx_intctl();
+
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+ au1xxx_dbdma_resume();
+#endif
}
unsigned long suspend_mode;
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
index 44a67bf05dc1..06f68f43800a 100644
--- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
@@ -357,6 +357,11 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr);
u32 au1xxx_ddma_add_device(dbdev_tab_t *dev);
extern void au1xxx_ddma_del_device(u32 devid);
void *au1xxx_ddma_get_nextptr_virt(au1x_ddma_desc_t *dp);
+#ifdef CONFIG_PM
+void au1xxx_dbdma_suspend(void);
+void au1xxx_dbdma_resume(void);
+#endif
+
/*
* Some compatibilty macros -- needed to make changes to API