summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/pm-imx6.c
diff options
context:
space:
mode:
authorFugang Duan <b38611@freescale.com>2014-09-03 12:23:33 +0800
committerNitin Garg <nitin.garg@freescale.com>2015-04-14 14:01:07 -0500
commit45316168dc4b6f16c31f5f58ded259320c0e07f1 (patch)
tree948022f8b7dd3e6109a9439e48f1d099e751777a /arch/arm/mach-imx/pm-imx6.c
parent16e5f337d054380a137340585ff5dbd30fe99a38 (diff)
ENGR00329198-01 ARM: imx6sx: pm: support no_console_suspend with Mega/Fast mix
For imx6sx, with M/F mix off in DSM, during the window of SOC resume and UART driver resume, the UART1 hardware is NOT working. So, add uart1 registers save/restore during suspend/resume When no_console_suspend is enabled. Signed-off-by: Fugang Duan <B38611@freescale.com>
Diffstat (limited to 'arch/arm/mach-imx/pm-imx6.c')
-rw-r--r--arch/arm/mach-imx/pm-imx6.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index febc696b3919..4230f590561d 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -82,11 +82,24 @@
#define BM_ROMPATCHENL_0D (0x1 << 0)
#define ROM_ADDR_FOR_INTERNAL_RAM_BASE 0x10d7c
+#define UART_UCR1 0x80
+#define UART_UCR2 0x84
+#define UART_UCR3 0x88
+#define UART_UCR4 0x8c
+#define UART_UFCR 0x90
+#define UART_UESC 0x9c
+#define UART_UTIM 0xa0
+#define UART_UBIR 0xa4
+#define UART_UBMR 0xa8
+#define UART_UBRC 0xac
+#define UART_UTS 0xb4
+
unsigned long iram_tlb_base_addr;
unsigned long iram_tlb_phys_addr;
static unsigned int *ocram_saved_in_ddr;
static void __iomem *ocram_base;
+static void __iomem *console_base;
static unsigned int ocram_size;
static void __iomem *ccm_base;
static void __iomem *suspend_ocram_base;
@@ -411,8 +424,46 @@ static int imx6q_suspend_finish(unsigned long val)
return 0;
}
+static void imx6_console_save(unsigned int *regs)
+{
+ if (!console_base)
+ return;
+
+ regs[0] = readl_relaxed(console_base + UART_UCR1);
+ regs[1] = readl_relaxed(console_base + UART_UCR2);
+ regs[2] = readl_relaxed(console_base + UART_UCR3);
+ regs[3] = readl_relaxed(console_base + UART_UCR4);
+ regs[4] = readl_relaxed(console_base + UART_UFCR);
+ regs[5] = readl_relaxed(console_base + UART_UESC);
+ regs[6] = readl_relaxed(console_base + UART_UTIM);
+ regs[7] = readl_relaxed(console_base + UART_UBIR);
+ regs[8] = readl_relaxed(console_base + UART_UBMR);
+ regs[9] = readl_relaxed(console_base + UART_UBRC);
+ regs[10] = readl_relaxed(console_base + UART_UTS);
+}
+
+static void imx6_console_restore(unsigned int *regs)
+{
+ if (!console_base)
+ return;
+
+ writel_relaxed(regs[4], console_base + UART_UFCR);
+ writel_relaxed(regs[5], console_base + UART_UESC);
+ writel_relaxed(regs[6], console_base + UART_UTIM);
+ writel_relaxed(regs[7], console_base + UART_UBIR);
+ writel_relaxed(regs[8], console_base + UART_UBMR);
+ writel_relaxed(regs[9], console_base + UART_UBRC);
+ writel_relaxed(regs[10], console_base + UART_UTS);
+ writel_relaxed(regs[0], console_base + UART_UCR1);
+ writel_relaxed(regs[1] | 0x1, console_base + UART_UCR2);
+ writel_relaxed(regs[2], console_base + UART_UCR3);
+ writel_relaxed(regs[3], console_base + UART_UCR4);
+}
+
static int imx6q_pm_enter(suspend_state_t state)
{
+ unsigned int console_saved_reg[11] = {0};
+
if (!iram_tlb_base_addr) {
pr_warn("No IRAM/OCRAM memory allocated for suspend/resume \
code. Please ensure device tree has an entry for \
@@ -447,14 +498,18 @@ static int imx6q_pm_enter(suspend_state_t state)
imx_gpc_pre_suspend(true);
imx_anatop_pre_suspend();
imx_set_cpu_jump(0, v7_cpu_resume);
- if (cpu_is_imx6sx() && imx_gpc_is_mf_mix_off())
+ if (cpu_is_imx6sx() && imx_gpc_is_mf_mix_off()) {
memcpy(ocram_saved_in_ddr, ocram_base, ocram_size);
+ imx6_console_save(console_saved_reg);
+ }
/* Zzz ... */
cpu_suspend(0, imx6q_suspend_finish);
- if (cpu_is_imx6sx() && imx_gpc_is_mf_mix_off())
+ if (cpu_is_imx6sx() && imx_gpc_is_mf_mix_off()) {
memcpy(ocram_base, ocram_saved_in_ddr, ocram_size);
+ imx6_console_restore(console_saved_reg);
+ }
if (cpu_is_imx6q() || cpu_is_imx6dl())
imx_smp_prepare();
imx_anatop_post_resume();
@@ -800,4 +855,8 @@ void __init imx6sx_pm_init(void)
ocram_size = resource_size(&res);
ocram_saved_in_ddr = kzalloc(ocram_size, GFP_KERNEL);
WARN_ON(!ocram_saved_in_ddr);
+
+ np = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000");
+ if (np)
+ console_base = of_iomap(np, 0);
}