diff options
Diffstat (limited to 'arch/arm/mach-imx/pm-imx6.c')
-rw-r--r-- | arch/arm/mach-imx/pm-imx6.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index 5d0a7c3f6114..8fd1f7188725 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -757,10 +757,12 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode) static int imx6q_suspend_finish(unsigned long val) { +#if defined(CONFIG_ARM_PSCI_FW) if (psci_ops.cpu_suspend) { return psci_ops.cpu_suspend(MX6Q_SUSPEND_PARAM, __pa(cpu_resume)); } +#endif if (!imx6_suspend_in_ocram_fn) { cpu_do_idle(); @@ -1086,11 +1088,13 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) return -EINVAL; } +#if defined(CONFIG_ARM_PSCI_FW) if (psci_ops.cpu_suspend) { /* TODO: seems not needed */ /* of_node_put(node); */ return ret; } +#endif /* * 16KB is allocated for IRAM TLB, but only up 8k is for kernel TLB, @@ -1272,6 +1276,28 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata IMX6Q_GPR1_GINT); } +static void imx6_pm_stby_poweroff(void) +{ + imx6_set_lpm(STOP_POWER_OFF); + imx6q_suspend_finish(0); + + mdelay(1000); + + pr_emerg("Unable to poweroff system\n"); +} + +static int imx6_pm_stby_poweroff_probe(void) +{ + if (pm_power_off) { + pr_warn("%s: pm_power_off already claimed %p %pf!\n", + __func__, pm_power_off, pm_power_off); + return -EBUSY; + } + + pm_power_off = imx6_pm_stby_poweroff; + return 0; +} + void __init imx6_pm_ccm_init(const char *ccm_compat) { struct device_node *np; @@ -1288,6 +1314,37 @@ void __init imx6_pm_ccm_init(const char *ccm_compat) val = readl_relaxed(ccm_base + CLPCR); val &= ~BM_CLPCR_LPM; writel_relaxed(val, ccm_base + CLPCR); + + if (of_property_read_bool(np, "fsl,pmic-stby-poweroff")) + imx6_pm_stby_poweroff_probe(); +} + +void imx6_stop_mode_poweroff(void) +{ + /* compare with imx6q_set_lpm */ + u32 val = readl_relaxed(ccm_base + CLPCR); + + val &= ~BM_CLPCR_LPM; + /* + * mask all but the currently running processor, + * otherwise we will not enter stop mode + */ + val |= smp_processor_id() != 0 ? BM_CLPCR_MASK_CORE0_WFI : 0; + val |= smp_processor_id() != 1 ? BM_CLPCR_MASK_CORE1_WFI : 0; + val |= smp_processor_id() != 2 ? BM_CLPCR_MASK_CORE2_WFI : 0; + val |= smp_processor_id() != 3 ? BM_CLPCR_MASK_CORE3_WFI : 0; + val |= BM_CLPCR_MASK_SCU_IDLE; + val |= 0x2 << BP_CLPCR_LPM; + val |= 0x3 << BP_CLPCR_STBY_COUNT; + val |= BM_CLPCR_VSTBY; + val |= BM_CLPCR_SBYOS; + val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + + imx_gpc_hwirq_unmask(0); + writel_relaxed(val, ccm_base + CLPCR); + imx_gpc_hwirq_mask(0); + imx_gpc_mask_all(); + cpu_do_idle(); } void __init imx6q_pm_init(void) @@ -1296,11 +1353,30 @@ void __init imx6q_pm_init(void) imx6_pm_common_init(&imx6q_lpddr2_pm_data); else imx6_pm_common_init(&imx6q_pm_data); +#ifndef CONFIG_POWER_RESET_GPIO + /* + * if no specific power off function in board file, power off system by + * stop mode + */ + if (!pm_power_off) + if (of_machine_is_compatible("toradex,apalis_imx6q")) + pm_power_off = imx6_stop_mode_poweroff; +#endif } void __init imx6dl_pm_init(void) { imx6_pm_common_init(&imx6dl_pm_data); + +#ifndef CONFIG_POWER_RESET_GPIO + /* + * if no specific power off function in board file, power off system by + * stop mode + */ + if (!pm_power_off) + if (of_machine_is_compatible("toradex,colibri_imx6dl")) + pm_power_off = imx6_stop_mode_poweroff; +#endif } void __init imx6sl_pm_init(void) |