From 69eeab4d855778c5d466b225430e975abddef683 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Thu, 20 Aug 2015 21:50:07 +0800 Subject: [PATCH] MLK-11389-03 ARM: imx: enable M/F mix support on imx6sx Enable the M/F funtion support on i.MX6SX. The M4 M/F off support is not added at present, will be enabled after the M4 funtion is ready. Signed-off-by: Bai Ping --- arch/arm/mach-imx/common.h | 1 + arch/arm/mach-imx/gpc.c | 6 +- arch/arm/mach-imx/pm-imx6.c | 155 +++++++++++++++++++++++++++++++++++- 3 files changed, 156 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 3247493e912c..4a46191677b8 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -98,6 +98,7 @@ void imx7_pm_map_io(void); void imx_src_init(void); void imx_gpc_pre_suspend(bool arm_power_off); void imx_gpc_post_resume(void); +unsigned int imx_gpc_is_mf_mix_off(void); void imx_gpcv2_pre_suspend(bool arm_power_off); void imx_gpcv2_post_resume(void); void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn); diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 32dd028f124a..2a420d6414cc 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -100,7 +100,7 @@ void imx_gpc_pre_suspend(bool arm_power_off) int i; /* power down the mega-fast power domain */ - if (cpu_is_imx6ul() && arm_power_off) + if ((cpu_is_imx6sx() || cpu_is_imx6ul()) && arm_power_off) imx_gpc_mf_mix_off(); /* Tell GPC to power off ARM core when suspend */ @@ -121,7 +121,7 @@ void imx_gpc_post_resume(void) /* Keep ARM core powered on for other low-power modes */ imx_gpc_set_arm_power_in_lpm(false); /* Keep M/F mix powered on for other low-power modes */ - if (cpu_is_imx6ul()) + if (cpu_is_imx6sx() || cpu_is_imx6ul()) writel_relaxed(0x0, gpc_base + GPC_PGC_MF_PDN); for (i = 0; i < IMR_NUM; i++) @@ -301,7 +301,7 @@ static int __init imx_gpc_init(struct device_node *node, writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4); /* Read supported wakeup source in M/F domain */ - if (cpu_is_imx6ul()) { + if (cpu_is_imx6sx() || cpu_is_imx6ul()) { of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 0, &gpc_mf_irqs[0]); of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 1, diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index 6b10b62c8809..165d31ce97ad 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -62,17 +63,45 @@ #define CGPR 0x64 #define BM_CGPR_INT_MEM_CLK_LPM (0x1 << 17) +#define CCGR4 0x78 +#define CCGR6 0x80 #define MX6Q_SUSPEND_OCRAM_SIZE 0x1000 #define MX6_MAX_MMDC_IO_NUM 33 #define MX6_MAX_MMDC_NUM 34 +#define ROMC_ROMPATCH0D 0xf0 +#define ROMC_ROMPATCHCNTL 0xf4 +#define ROMC_ROMPATCHENL 0xfc +#define ROMC_ROMPATCH0A 0x100 +#define BM_ROMPATCHCNTL_0D (0x1 << 0) +#define BM_ROMPATCHCNTL_DIS (0x1 << 29) +#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 + extern unsigned long iram_tlb_base_addr; extern 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; static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase); +struct regmap *romcp; /* * suspend ocram space layout: @@ -146,6 +175,16 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = { 0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */ }; +static const u32 imx6sx_mmdc_offset[] __initconst = { + 0x800, 0x80c, 0x810, 0x83c, + 0x840, 0x848, 0x850, 0x81c, + 0x820, 0x824, 0x828, 0x8b8, + 0x004, 0x008, 0x00c, 0x010, + 0x014, 0x018, 0x01c, 0x02c, + 0x030, 0x040, 0x000, 0x01c, + 0x020, 0x818, 0x01c, +}; + static const u32 imx6ul_mmdc_io_offset[] __initconst = { 0x244, 0x248, 0x24c, 0x250, /* DQM0, DQM1, RAS, CAS */ 0x27c, 0x498, 0x4a4, 0x490, /* SDCLK0, GPR_B0DS-B1DS, GPR_ADDS */ @@ -207,8 +246,8 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { .pl310_compat = "arm,pl310-cache", .mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset), .mmdc_io_offset = imx6sx_mmdc_io_offset, - .mmdc_num = 0, - .mmdc_offset = NULL, + .mmdc_num = ARRAY_SIZE(imx6sx_mmdc_offset), + .mmdc_offset = imx6sx_mmdc_offset, }; static const struct imx6_pm_socdata imx6ul_pm_data __initconst = { @@ -446,8 +485,47 @@ 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}; + static unsigned int ccm_ccgr4, ccm_ccgr6; + switch (state) { case PM_SUSPEND_STANDBY: imx6_set_lpm(STOP_POWER_ON); @@ -474,8 +552,36 @@ static int imx6q_pm_enter(suspend_state_t state) imx6_enable_rbc(true); imx_gpc_pre_suspend(true); imx_anatop_pre_suspend(); + if (cpu_is_imx6sx() && imx_gpc_is_mf_mix_off()) { + ccm_ccgr4 = readl_relaxed(ccm_base + CCGR4); + ccm_ccgr6 = readl_relaxed(ccm_base + CCGR6); + /* + * i.MX6SX RDC needs PCIe and eim clk to be enabled + * if Mega/Fast off, it is better to check cpu type + * and whether Mega/Fast is off in this suspend flow, + * but we need to add cpu type check for 3 places which + * will increase code size, so here we just do it + * for all cases, as when STOP mode is entered, CCM + * hardware will gate all clocks, so it will NOT impact + * any function or power. + */ + writel_relaxed(ccm_ccgr4 | (0x3 << 0), ccm_base + + CCGR4); + writel_relaxed(ccm_ccgr6 | (0x3 << 10), ccm_base + + CCGR6); + 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()) { + writel_relaxed(ccm_ccgr4, ccm_base + CCGR4); + writel_relaxed(ccm_ccgr6, ccm_base + CCGR6); + 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(); @@ -690,7 +796,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) } /* need to overwrite the value for some mmdc registers */ - if (cpu_is_imx6ul()) { + if (cpu_is_imx6sx() || cpu_is_imx6ul()) { pm_info->mmdc_val[20][1] = (pm_info->mmdc_val[20][1] & 0xffff0000) | 0x0202; pm_info->mmdc_val[23][1] = 0x8033; @@ -772,7 +878,50 @@ void __init imx6sl_pm_init(void) void __init imx6sx_pm_init(void) { + struct device_node *np; + struct resource res; + imx6_pm_common_init(&imx6sx_pm_data); + + if (imx_get_soc_revision() < IMX_CHIP_REVISION_1_2) { + /* + * As there is a 16K OCRAM(start from 0x8f8000) + * dedicated for low power function on i.MX6SX, + * but ROM did NOT do the ocram address change + * accordingly, so we need to add a data patch + * to workaround this issue, otherwise, system + * will fail to resume from DSM mode. TO1.2 fixes + * this issue. + */ + romcp = syscon_regmap_lookup_by_compatible( + "fsl,imx6sx-romcp"); + if (IS_ERR(romcp)) { + pr_err("failed to find fsl,imx6sx-romcp regmap\n"); + return; + } + regmap_write(romcp, ROMC_ROMPATCH0D, iram_tlb_phys_addr); + regmap_update_bits(romcp, ROMC_ROMPATCHCNTL, + BM_ROMPATCHCNTL_0D, BM_ROMPATCHCNTL_0D); + regmap_update_bits(romcp, ROMC_ROMPATCHENL, + BM_ROMPATCHENL_0D, BM_ROMPATCHENL_0D); + regmap_write(romcp, ROMC_ROMPATCH0A, + ROM_ADDR_FOR_INTERNAL_RAM_BASE); + regmap_update_bits(romcp, ROMC_ROMPATCHCNTL, + BM_ROMPATCHCNTL_DIS, ~BM_ROMPATCHCNTL_DIS); + } + + np = of_find_compatible_node(NULL, NULL, "fsl,mega-fast-sram"); + ocram_base = of_iomap(np, 0); + WARN_ON(!ocram_base); + WARN_ON(of_address_to_resource(np, 0, &res)); + 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); } void __init imx6ul_pm_init(void) -- 2.17.1