162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2011-2014 Freescale Semiconductor, Inc.
462306a36Sopenharmony_ci * Copyright 2011 Linaro Ltd.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/clk/imx.h>
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/irq.h>
1262306a36Sopenharmony_ci#include <linux/genalloc.h>
1362306a36Sopenharmony_ci#include <linux/irqchip/arm-gic.h>
1462306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1562306a36Sopenharmony_ci#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/of_address.h>
1862306a36Sopenharmony_ci#include <linux/of_platform.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <linux/regmap.h>
2162306a36Sopenharmony_ci#include <linux/suspend.h>
2262306a36Sopenharmony_ci#include <asm/cacheflush.h>
2362306a36Sopenharmony_ci#include <asm/fncpy.h>
2462306a36Sopenharmony_ci#include <asm/proc-fns.h>
2562306a36Sopenharmony_ci#include <asm/suspend.h>
2662306a36Sopenharmony_ci#include <asm/tlb.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "common.h"
2962306a36Sopenharmony_ci#include "hardware.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define CCR				0x0
3262306a36Sopenharmony_ci#define BM_CCR_WB_COUNT			(0x7 << 16)
3362306a36Sopenharmony_ci#define BM_CCR_RBC_BYPASS_COUNT		(0x3f << 21)
3462306a36Sopenharmony_ci#define BM_CCR_RBC_EN			(0x1 << 27)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define CLPCR				0x54
3762306a36Sopenharmony_ci#define BP_CLPCR_LPM			0
3862306a36Sopenharmony_ci#define BM_CLPCR_LPM			(0x3 << 0)
3962306a36Sopenharmony_ci#define BM_CLPCR_BYPASS_PMIC_READY	(0x1 << 2)
4062306a36Sopenharmony_ci#define BM_CLPCR_ARM_CLK_DIS_ON_LPM	(0x1 << 5)
4162306a36Sopenharmony_ci#define BM_CLPCR_SBYOS			(0x1 << 6)
4262306a36Sopenharmony_ci#define BM_CLPCR_DIS_REF_OSC		(0x1 << 7)
4362306a36Sopenharmony_ci#define BM_CLPCR_VSTBY			(0x1 << 8)
4462306a36Sopenharmony_ci#define BP_CLPCR_STBY_COUNT		9
4562306a36Sopenharmony_ci#define BM_CLPCR_STBY_COUNT		(0x3 << 9)
4662306a36Sopenharmony_ci#define BM_CLPCR_COSC_PWRDOWN		(0x1 << 11)
4762306a36Sopenharmony_ci#define BM_CLPCR_WB_PER_AT_LPM		(0x1 << 16)
4862306a36Sopenharmony_ci#define BM_CLPCR_WB_CORE_AT_LPM		(0x1 << 17)
4962306a36Sopenharmony_ci#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS	(0x1 << 19)
5062306a36Sopenharmony_ci#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS	(0x1 << 21)
5162306a36Sopenharmony_ci#define BM_CLPCR_MASK_CORE0_WFI		(0x1 << 22)
5262306a36Sopenharmony_ci#define BM_CLPCR_MASK_CORE1_WFI		(0x1 << 23)
5362306a36Sopenharmony_ci#define BM_CLPCR_MASK_CORE2_WFI		(0x1 << 24)
5462306a36Sopenharmony_ci#define BM_CLPCR_MASK_CORE3_WFI		(0x1 << 25)
5562306a36Sopenharmony_ci#define BM_CLPCR_MASK_SCU_IDLE		(0x1 << 26)
5662306a36Sopenharmony_ci#define BM_CLPCR_MASK_L2CC_IDLE		(0x1 << 27)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define CGPR				0x64
5962306a36Sopenharmony_ci#define BM_CGPR_INT_MEM_CLK_LPM		(0x1 << 17)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define MX6Q_SUSPEND_OCRAM_SIZE		0x1000
6262306a36Sopenharmony_ci#define MX6_MAX_MMDC_IO_NUM		33
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void __iomem *ccm_base;
6562306a36Sopenharmony_cistatic void __iomem *suspend_ocram_base;
6662306a36Sopenharmony_cistatic void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*
6962306a36Sopenharmony_ci * suspend ocram space layout:
7062306a36Sopenharmony_ci * ======================== high address ======================
7162306a36Sopenharmony_ci *                              .
7262306a36Sopenharmony_ci *                              .
7362306a36Sopenharmony_ci *                              .
7462306a36Sopenharmony_ci *                              ^
7562306a36Sopenharmony_ci *                              ^
7662306a36Sopenharmony_ci *                              ^
7762306a36Sopenharmony_ci *                      imx6_suspend code
7862306a36Sopenharmony_ci *              PM_INFO structure(imx6_cpu_pm_info)
7962306a36Sopenharmony_ci * ======================== low address =======================
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistruct imx6_pm_base {
8362306a36Sopenharmony_ci	phys_addr_t pbase;
8462306a36Sopenharmony_ci	void __iomem *vbase;
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistruct imx6_pm_socdata {
8862306a36Sopenharmony_ci	u32 ddr_type;
8962306a36Sopenharmony_ci	const char *mmdc_compat;
9062306a36Sopenharmony_ci	const char *src_compat;
9162306a36Sopenharmony_ci	const char *iomuxc_compat;
9262306a36Sopenharmony_ci	const char *gpc_compat;
9362306a36Sopenharmony_ci	const char *pl310_compat;
9462306a36Sopenharmony_ci	const u32 mmdc_io_num;
9562306a36Sopenharmony_ci	const u32 *mmdc_io_offset;
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic const u32 imx6q_mmdc_io_offset[] __initconst = {
9962306a36Sopenharmony_ci	0x5ac, 0x5b4, 0x528, 0x520, /* DQM0 ~ DQM3 */
10062306a36Sopenharmony_ci	0x514, 0x510, 0x5bc, 0x5c4, /* DQM4 ~ DQM7 */
10162306a36Sopenharmony_ci	0x56c, 0x578, 0x588, 0x594, /* CAS, RAS, SDCLK_0, SDCLK_1 */
10262306a36Sopenharmony_ci	0x5a8, 0x5b0, 0x524, 0x51c, /* SDQS0 ~ SDQS3 */
10362306a36Sopenharmony_ci	0x518, 0x50c, 0x5b8, 0x5c0, /* SDQS4 ~ SDQS7 */
10462306a36Sopenharmony_ci	0x784, 0x788, 0x794, 0x79c, /* GPR_B0DS ~ GPR_B3DS */
10562306a36Sopenharmony_ci	0x7a0, 0x7a4, 0x7a8, 0x748, /* GPR_B4DS ~ GPR_B7DS */
10662306a36Sopenharmony_ci	0x59c, 0x5a0, 0x750, 0x774, /* SODT0, SODT1, MODE_CTL, MODE */
10762306a36Sopenharmony_ci	0x74c,			    /* GPR_ADDS */
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic const u32 imx6dl_mmdc_io_offset[] __initconst = {
11162306a36Sopenharmony_ci	0x470, 0x474, 0x478, 0x47c, /* DQM0 ~ DQM3 */
11262306a36Sopenharmony_ci	0x480, 0x484, 0x488, 0x48c, /* DQM4 ~ DQM7 */
11362306a36Sopenharmony_ci	0x464, 0x490, 0x4ac, 0x4b0, /* CAS, RAS, SDCLK_0, SDCLK_1 */
11462306a36Sopenharmony_ci	0x4bc, 0x4c0, 0x4c4, 0x4c8, /* DRAM_SDQS0 ~ DRAM_SDQS3 */
11562306a36Sopenharmony_ci	0x4cc, 0x4d0, 0x4d4, 0x4d8, /* DRAM_SDQS4 ~ DRAM_SDQS7 */
11662306a36Sopenharmony_ci	0x764, 0x770, 0x778, 0x77c, /* GPR_B0DS ~ GPR_B3DS */
11762306a36Sopenharmony_ci	0x780, 0x784, 0x78c, 0x748, /* GPR_B4DS ~ GPR_B7DS */
11862306a36Sopenharmony_ci	0x4b4, 0x4b8, 0x750, 0x760, /* SODT0, SODT1, MODE_CTL, MODE */
11962306a36Sopenharmony_ci	0x74c,			    /* GPR_ADDS */
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const u32 imx6sl_mmdc_io_offset[] __initconst = {
12362306a36Sopenharmony_ci	0x30c, 0x310, 0x314, 0x318, /* DQM0 ~ DQM3 */
12462306a36Sopenharmony_ci	0x5c4, 0x5cc, 0x5d4, 0x5d8, /* GPR_B0DS ~ GPR_B3DS */
12562306a36Sopenharmony_ci	0x300, 0x31c, 0x338, 0x5ac, /* CAS, RAS, SDCLK_0, GPR_ADDS */
12662306a36Sopenharmony_ci	0x33c, 0x340, 0x5b0, 0x5c0, /* SODT0, SODT1, MODE_CTL, MODE */
12762306a36Sopenharmony_ci	0x330, 0x334, 0x320,        /* SDCKE0, SDCKE1, RESET */
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic const u32 imx6sll_mmdc_io_offset[] __initconst = {
13162306a36Sopenharmony_ci	0x294, 0x298, 0x29c, 0x2a0, /* DQM0 ~ DQM3 */
13262306a36Sopenharmony_ci	0x544, 0x54c, 0x554, 0x558, /* GPR_B0DS ~ GPR_B3DS */
13362306a36Sopenharmony_ci	0x530, 0x540, 0x2ac, 0x52c, /* MODE_CTL, MODE, SDCLK_0, GPR_ADDDS */
13462306a36Sopenharmony_ci	0x2a4, 0x2a8,		    /* SDCKE0, SDCKE1*/
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic const u32 imx6sx_mmdc_io_offset[] __initconst = {
13862306a36Sopenharmony_ci	0x2ec, 0x2f0, 0x2f4, 0x2f8, /* DQM0 ~ DQM3 */
13962306a36Sopenharmony_ci	0x60c, 0x610, 0x61c, 0x620, /* GPR_B0DS ~ GPR_B3DS */
14062306a36Sopenharmony_ci	0x300, 0x2fc, 0x32c, 0x5f4, /* CAS, RAS, SDCLK_0, GPR_ADDS */
14162306a36Sopenharmony_ci	0x310, 0x314, 0x5f8, 0x608, /* SODT0, SODT1, MODE_CTL, MODE */
14262306a36Sopenharmony_ci	0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic const u32 imx6ul_mmdc_io_offset[] __initconst = {
14662306a36Sopenharmony_ci	0x244, 0x248, 0x24c, 0x250, /* DQM0, DQM1, RAS, CAS */
14762306a36Sopenharmony_ci	0x27c, 0x498, 0x4a4, 0x490, /* SDCLK0, GPR_B0DS-B1DS, GPR_ADDS */
14862306a36Sopenharmony_ci	0x280, 0x284, 0x260, 0x264, /* SDQS0~1, SODT0, SODT1 */
14962306a36Sopenharmony_ci	0x494, 0x4b0,	            /* MODE_CTL, MODE, */
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic const struct imx6_pm_socdata imx6q_pm_data __initconst = {
15362306a36Sopenharmony_ci	.mmdc_compat = "fsl,imx6q-mmdc",
15462306a36Sopenharmony_ci	.src_compat = "fsl,imx6q-src",
15562306a36Sopenharmony_ci	.iomuxc_compat = "fsl,imx6q-iomuxc",
15662306a36Sopenharmony_ci	.gpc_compat = "fsl,imx6q-gpc",
15762306a36Sopenharmony_ci	.pl310_compat = "arm,pl310-cache",
15862306a36Sopenharmony_ci	.mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset),
15962306a36Sopenharmony_ci	.mmdc_io_offset = imx6q_mmdc_io_offset,
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
16362306a36Sopenharmony_ci	.mmdc_compat = "fsl,imx6q-mmdc",
16462306a36Sopenharmony_ci	.src_compat = "fsl,imx6q-src",
16562306a36Sopenharmony_ci	.iomuxc_compat = "fsl,imx6dl-iomuxc",
16662306a36Sopenharmony_ci	.gpc_compat = "fsl,imx6q-gpc",
16762306a36Sopenharmony_ci	.pl310_compat = "arm,pl310-cache",
16862306a36Sopenharmony_ci	.mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset),
16962306a36Sopenharmony_ci	.mmdc_io_offset = imx6dl_mmdc_io_offset,
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
17362306a36Sopenharmony_ci	.mmdc_compat = "fsl,imx6sl-mmdc",
17462306a36Sopenharmony_ci	.src_compat = "fsl,imx6sl-src",
17562306a36Sopenharmony_ci	.iomuxc_compat = "fsl,imx6sl-iomuxc",
17662306a36Sopenharmony_ci	.gpc_compat = "fsl,imx6sl-gpc",
17762306a36Sopenharmony_ci	.pl310_compat = "arm,pl310-cache",
17862306a36Sopenharmony_ci	.mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset),
17962306a36Sopenharmony_ci	.mmdc_io_offset = imx6sl_mmdc_io_offset,
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic const struct imx6_pm_socdata imx6sll_pm_data __initconst = {
18362306a36Sopenharmony_ci	.mmdc_compat = "fsl,imx6sll-mmdc",
18462306a36Sopenharmony_ci	.src_compat = "fsl,imx6sll-src",
18562306a36Sopenharmony_ci	.iomuxc_compat = "fsl,imx6sll-iomuxc",
18662306a36Sopenharmony_ci	.gpc_compat = "fsl,imx6sll-gpc",
18762306a36Sopenharmony_ci	.pl310_compat = "arm,pl310-cache",
18862306a36Sopenharmony_ci	.mmdc_io_num = ARRAY_SIZE(imx6sll_mmdc_io_offset),
18962306a36Sopenharmony_ci	.mmdc_io_offset = imx6sll_mmdc_io_offset,
19062306a36Sopenharmony_ci};
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
19362306a36Sopenharmony_ci	.mmdc_compat = "fsl,imx6sx-mmdc",
19462306a36Sopenharmony_ci	.src_compat = "fsl,imx6sx-src",
19562306a36Sopenharmony_ci	.iomuxc_compat = "fsl,imx6sx-iomuxc",
19662306a36Sopenharmony_ci	.gpc_compat = "fsl,imx6sx-gpc",
19762306a36Sopenharmony_ci	.pl310_compat = "arm,pl310-cache",
19862306a36Sopenharmony_ci	.mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset),
19962306a36Sopenharmony_ci	.mmdc_io_offset = imx6sx_mmdc_io_offset,
20062306a36Sopenharmony_ci};
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic const struct imx6_pm_socdata imx6ul_pm_data __initconst = {
20362306a36Sopenharmony_ci	.mmdc_compat = "fsl,imx6ul-mmdc",
20462306a36Sopenharmony_ci	.src_compat = "fsl,imx6ul-src",
20562306a36Sopenharmony_ci	.iomuxc_compat = "fsl,imx6ul-iomuxc",
20662306a36Sopenharmony_ci	.gpc_compat = "fsl,imx6ul-gpc",
20762306a36Sopenharmony_ci	.pl310_compat = NULL,
20862306a36Sopenharmony_ci	.mmdc_io_num = ARRAY_SIZE(imx6ul_mmdc_io_offset),
20962306a36Sopenharmony_ci	.mmdc_io_offset = imx6ul_mmdc_io_offset,
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/*
21362306a36Sopenharmony_ci * This structure is for passing necessary data for low level ocram
21462306a36Sopenharmony_ci * suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct
21562306a36Sopenharmony_ci * definition is changed, the offset definition in
21662306a36Sopenharmony_ci * arch/arm/mach-imx/suspend-imx6.S must be also changed accordingly,
21762306a36Sopenharmony_ci * otherwise, the suspend to ocram function will be broken!
21862306a36Sopenharmony_ci */
21962306a36Sopenharmony_cistruct imx6_cpu_pm_info {
22062306a36Sopenharmony_ci	phys_addr_t pbase; /* The physical address of pm_info. */
22162306a36Sopenharmony_ci	phys_addr_t resume_addr; /* The physical resume address for asm code */
22262306a36Sopenharmony_ci	u32 ddr_type;
22362306a36Sopenharmony_ci	u32 pm_info_size; /* Size of pm_info. */
22462306a36Sopenharmony_ci	struct imx6_pm_base mmdc_base;
22562306a36Sopenharmony_ci	struct imx6_pm_base src_base;
22662306a36Sopenharmony_ci	struct imx6_pm_base iomuxc_base;
22762306a36Sopenharmony_ci	struct imx6_pm_base ccm_base;
22862306a36Sopenharmony_ci	struct imx6_pm_base gpc_base;
22962306a36Sopenharmony_ci	struct imx6_pm_base l2_base;
23062306a36Sopenharmony_ci	u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */
23162306a36Sopenharmony_ci	u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */
23262306a36Sopenharmony_ci} __aligned(8);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_civoid imx6_set_int_mem_clk_lpm(bool enable)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	u32 val = readl_relaxed(ccm_base + CGPR);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	val &= ~BM_CGPR_INT_MEM_CLK_LPM;
23962306a36Sopenharmony_ci	if (enable)
24062306a36Sopenharmony_ci		val |= BM_CGPR_INT_MEM_CLK_LPM;
24162306a36Sopenharmony_ci	writel_relaxed(val, ccm_base + CGPR);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_civoid imx6_enable_rbc(bool enable)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	u32 val;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/*
24962306a36Sopenharmony_ci	 * need to mask all interrupts in GPC before
25062306a36Sopenharmony_ci	 * operating RBC configurations
25162306a36Sopenharmony_ci	 */
25262306a36Sopenharmony_ci	imx_gpc_mask_all();
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* configure RBC enable bit */
25562306a36Sopenharmony_ci	val = readl_relaxed(ccm_base + CCR);
25662306a36Sopenharmony_ci	val &= ~BM_CCR_RBC_EN;
25762306a36Sopenharmony_ci	val |= enable ? BM_CCR_RBC_EN : 0;
25862306a36Sopenharmony_ci	writel_relaxed(val, ccm_base + CCR);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/* configure RBC count */
26162306a36Sopenharmony_ci	val = readl_relaxed(ccm_base + CCR);
26262306a36Sopenharmony_ci	val &= ~BM_CCR_RBC_BYPASS_COUNT;
26362306a36Sopenharmony_ci	val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0;
26462306a36Sopenharmony_ci	writel(val, ccm_base + CCR);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/*
26762306a36Sopenharmony_ci	 * need to delay at least 2 cycles of CKIL(32K)
26862306a36Sopenharmony_ci	 * due to hardware design requirement, which is
26962306a36Sopenharmony_ci	 * ~61us, here we use 65us for safe
27062306a36Sopenharmony_ci	 */
27162306a36Sopenharmony_ci	udelay(65);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* restore GPC interrupt mask settings */
27462306a36Sopenharmony_ci	imx_gpc_restore_all();
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void imx6q_enable_wb(bool enable)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	u32 val;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/* configure well bias enable bit */
28262306a36Sopenharmony_ci	val = readl_relaxed(ccm_base + CLPCR);
28362306a36Sopenharmony_ci	val &= ~BM_CLPCR_WB_PER_AT_LPM;
28462306a36Sopenharmony_ci	val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0;
28562306a36Sopenharmony_ci	writel_relaxed(val, ccm_base + CLPCR);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* configure well bias count */
28862306a36Sopenharmony_ci	val = readl_relaxed(ccm_base + CCR);
28962306a36Sopenharmony_ci	val &= ~BM_CCR_WB_COUNT;
29062306a36Sopenharmony_ci	val |= enable ? BM_CCR_WB_COUNT : 0;
29162306a36Sopenharmony_ci	writel_relaxed(val, ccm_base + CCR);
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ciint imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	u32 val = readl_relaxed(ccm_base + CLPCR);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	val &= ~BM_CLPCR_LPM;
29962306a36Sopenharmony_ci	switch (mode) {
30062306a36Sopenharmony_ci	case WAIT_CLOCKED:
30162306a36Sopenharmony_ci		break;
30262306a36Sopenharmony_ci	case WAIT_UNCLOCKED:
30362306a36Sopenharmony_ci		val |= 0x1 << BP_CLPCR_LPM;
30462306a36Sopenharmony_ci		val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM;
30562306a36Sopenharmony_ci		break;
30662306a36Sopenharmony_ci	case STOP_POWER_ON:
30762306a36Sopenharmony_ci		val |= 0x2 << BP_CLPCR_LPM;
30862306a36Sopenharmony_ci		val &= ~BM_CLPCR_VSTBY;
30962306a36Sopenharmony_ci		val &= ~BM_CLPCR_SBYOS;
31062306a36Sopenharmony_ci		if (cpu_is_imx6sl())
31162306a36Sopenharmony_ci			val |= BM_CLPCR_BYPASS_PMIC_READY;
31262306a36Sopenharmony_ci		if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul() ||
31362306a36Sopenharmony_ci		    cpu_is_imx6ull() || cpu_is_imx6sll() || cpu_is_imx6ulz())
31462306a36Sopenharmony_ci			val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
31562306a36Sopenharmony_ci		else
31662306a36Sopenharmony_ci			val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
31762306a36Sopenharmony_ci		break;
31862306a36Sopenharmony_ci	case WAIT_UNCLOCKED_POWER_OFF:
31962306a36Sopenharmony_ci		val |= 0x1 << BP_CLPCR_LPM;
32062306a36Sopenharmony_ci		val &= ~BM_CLPCR_VSTBY;
32162306a36Sopenharmony_ci		val &= ~BM_CLPCR_SBYOS;
32262306a36Sopenharmony_ci		break;
32362306a36Sopenharmony_ci	case STOP_POWER_OFF:
32462306a36Sopenharmony_ci		val |= 0x2 << BP_CLPCR_LPM;
32562306a36Sopenharmony_ci		val |= 0x3 << BP_CLPCR_STBY_COUNT;
32662306a36Sopenharmony_ci		val |= BM_CLPCR_VSTBY;
32762306a36Sopenharmony_ci		val |= BM_CLPCR_SBYOS;
32862306a36Sopenharmony_ci		if (cpu_is_imx6sl() || cpu_is_imx6sx())
32962306a36Sopenharmony_ci			val |= BM_CLPCR_BYPASS_PMIC_READY;
33062306a36Sopenharmony_ci		if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul() ||
33162306a36Sopenharmony_ci		    cpu_is_imx6ull() || cpu_is_imx6sll() || cpu_is_imx6ulz())
33262306a36Sopenharmony_ci			val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
33362306a36Sopenharmony_ci		else
33462306a36Sopenharmony_ci			val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
33562306a36Sopenharmony_ci		break;
33662306a36Sopenharmony_ci	default:
33762306a36Sopenharmony_ci		return -EINVAL;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/*
34162306a36Sopenharmony_ci	 * ERR007265: CCM: When improper low-power sequence is used,
34262306a36Sopenharmony_ci	 * the SoC enters low power mode before the ARM core executes WFI.
34362306a36Sopenharmony_ci	 *
34462306a36Sopenharmony_ci	 * Software workaround:
34562306a36Sopenharmony_ci	 * 1) Software should trigger IRQ #32 (IOMUX) to be always pending
34662306a36Sopenharmony_ci	 *    by setting IOMUX_GPR1_GINT.
34762306a36Sopenharmony_ci	 * 2) Software should then unmask IRQ #32 in GPC before setting CCM
34862306a36Sopenharmony_ci	 *    Low-Power mode.
34962306a36Sopenharmony_ci	 * 3) Software should mask IRQ #32 right after CCM Low-Power mode
35062306a36Sopenharmony_ci	 *    is set (set bits 0-1 of CCM_CLPCR).
35162306a36Sopenharmony_ci	 *
35262306a36Sopenharmony_ci	 * Note that IRQ #32 is GIC SPI #0.
35362306a36Sopenharmony_ci	 */
35462306a36Sopenharmony_ci	if (mode != WAIT_CLOCKED)
35562306a36Sopenharmony_ci		imx_gpc_hwirq_unmask(0);
35662306a36Sopenharmony_ci	writel_relaxed(val, ccm_base + CLPCR);
35762306a36Sopenharmony_ci	if (mode != WAIT_CLOCKED)
35862306a36Sopenharmony_ci		imx_gpc_hwirq_mask(0);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return 0;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic int imx6q_suspend_finish(unsigned long val)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	if (!imx6_suspend_in_ocram_fn) {
36662306a36Sopenharmony_ci		cpu_do_idle();
36762306a36Sopenharmony_ci	} else {
36862306a36Sopenharmony_ci		/*
36962306a36Sopenharmony_ci		 * call low level suspend function in ocram,
37062306a36Sopenharmony_ci		 * as we need to float DDR IO.
37162306a36Sopenharmony_ci		 */
37262306a36Sopenharmony_ci		local_flush_tlb_all();
37362306a36Sopenharmony_ci		/* check if need to flush internal L2 cache */
37462306a36Sopenharmony_ci		if (!((struct imx6_cpu_pm_info *)
37562306a36Sopenharmony_ci			suspend_ocram_base)->l2_base.vbase)
37662306a36Sopenharmony_ci			flush_cache_all();
37762306a36Sopenharmony_ci		imx6_suspend_in_ocram_fn(suspend_ocram_base);
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return 0;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic int imx6q_pm_enter(suspend_state_t state)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	switch (state) {
38662306a36Sopenharmony_ci	case PM_SUSPEND_STANDBY:
38762306a36Sopenharmony_ci		imx6_set_lpm(STOP_POWER_ON);
38862306a36Sopenharmony_ci		imx6_set_int_mem_clk_lpm(true);
38962306a36Sopenharmony_ci		imx_gpc_pre_suspend(false);
39062306a36Sopenharmony_ci		if (cpu_is_imx6sl())
39162306a36Sopenharmony_ci			imx6sl_set_wait_clk(true);
39262306a36Sopenharmony_ci		/* Zzz ... */
39362306a36Sopenharmony_ci		cpu_do_idle();
39462306a36Sopenharmony_ci		if (cpu_is_imx6sl())
39562306a36Sopenharmony_ci			imx6sl_set_wait_clk(false);
39662306a36Sopenharmony_ci		imx_gpc_post_resume();
39762306a36Sopenharmony_ci		imx6_set_lpm(WAIT_CLOCKED);
39862306a36Sopenharmony_ci		break;
39962306a36Sopenharmony_ci	case PM_SUSPEND_MEM:
40062306a36Sopenharmony_ci		imx6_set_lpm(STOP_POWER_OFF);
40162306a36Sopenharmony_ci		imx6_set_int_mem_clk_lpm(false);
40262306a36Sopenharmony_ci		imx6q_enable_wb(true);
40362306a36Sopenharmony_ci		/*
40462306a36Sopenharmony_ci		 * For suspend into ocram, asm code already take care of
40562306a36Sopenharmony_ci		 * RBC setting, so we do NOT need to do that here.
40662306a36Sopenharmony_ci		 */
40762306a36Sopenharmony_ci		if (!imx6_suspend_in_ocram_fn)
40862306a36Sopenharmony_ci			imx6_enable_rbc(true);
40962306a36Sopenharmony_ci		imx_gpc_pre_suspend(true);
41062306a36Sopenharmony_ci		imx_anatop_pre_suspend();
41162306a36Sopenharmony_ci		/* Zzz ... */
41262306a36Sopenharmony_ci		cpu_suspend(0, imx6q_suspend_finish);
41362306a36Sopenharmony_ci		if (cpu_is_imx6q() || cpu_is_imx6dl())
41462306a36Sopenharmony_ci			imx_smp_prepare();
41562306a36Sopenharmony_ci		imx_anatop_post_resume();
41662306a36Sopenharmony_ci		imx_gpc_post_resume();
41762306a36Sopenharmony_ci		imx6_enable_rbc(false);
41862306a36Sopenharmony_ci		imx6q_enable_wb(false);
41962306a36Sopenharmony_ci		imx6_set_int_mem_clk_lpm(true);
42062306a36Sopenharmony_ci		imx6_set_lpm(WAIT_CLOCKED);
42162306a36Sopenharmony_ci		break;
42262306a36Sopenharmony_ci	default:
42362306a36Sopenharmony_ci		return -EINVAL;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	return 0;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic int imx6q_pm_valid(suspend_state_t state)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	return (state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic const struct platform_suspend_ops imx6q_pm_ops = {
43562306a36Sopenharmony_ci	.enter = imx6q_pm_enter,
43662306a36Sopenharmony_ci	.valid = imx6q_pm_valid,
43762306a36Sopenharmony_ci};
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic int __init imx6_pm_get_base(struct imx6_pm_base *base,
44062306a36Sopenharmony_ci				const char *compat)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct device_node *node;
44362306a36Sopenharmony_ci	struct resource res;
44462306a36Sopenharmony_ci	int ret = 0;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	node = of_find_compatible_node(NULL, NULL, compat);
44762306a36Sopenharmony_ci	if (!node)
44862306a36Sopenharmony_ci		return -ENODEV;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	ret = of_address_to_resource(node, 0, &res);
45162306a36Sopenharmony_ci	if (ret)
45262306a36Sopenharmony_ci		goto put_node;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	base->pbase = res.start;
45562306a36Sopenharmony_ci	base->vbase = ioremap(res.start, resource_size(&res));
45662306a36Sopenharmony_ci	if (!base->vbase)
45762306a36Sopenharmony_ci		ret = -ENOMEM;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ciput_node:
46062306a36Sopenharmony_ci	of_node_put(node);
46162306a36Sopenharmony_ci	return ret;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	phys_addr_t ocram_pbase;
46762306a36Sopenharmony_ci	struct device_node *node;
46862306a36Sopenharmony_ci	struct platform_device *pdev;
46962306a36Sopenharmony_ci	struct imx6_cpu_pm_info *pm_info;
47062306a36Sopenharmony_ci	struct gen_pool *ocram_pool;
47162306a36Sopenharmony_ci	unsigned long ocram_base;
47262306a36Sopenharmony_ci	int i, ret = 0;
47362306a36Sopenharmony_ci	const u32 *mmdc_offset_array;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	suspend_set_ops(&imx6q_pm_ops);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (!socdata) {
47862306a36Sopenharmony_ci		pr_warn("%s: invalid argument!\n", __func__);
47962306a36Sopenharmony_ci		return -EINVAL;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	node = of_find_compatible_node(NULL, NULL, "mmio-sram");
48362306a36Sopenharmony_ci	if (!node) {
48462306a36Sopenharmony_ci		pr_warn("%s: failed to find ocram node!\n", __func__);
48562306a36Sopenharmony_ci		return -ENODEV;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	pdev = of_find_device_by_node(node);
48962306a36Sopenharmony_ci	if (!pdev) {
49062306a36Sopenharmony_ci		pr_warn("%s: failed to find ocram device!\n", __func__);
49162306a36Sopenharmony_ci		ret = -ENODEV;
49262306a36Sopenharmony_ci		goto put_node;
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	ocram_pool = gen_pool_get(&pdev->dev, NULL);
49662306a36Sopenharmony_ci	if (!ocram_pool) {
49762306a36Sopenharmony_ci		pr_warn("%s: ocram pool unavailable!\n", __func__);
49862306a36Sopenharmony_ci		ret = -ENODEV;
49962306a36Sopenharmony_ci		goto put_device;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	ocram_base = gen_pool_alloc(ocram_pool, MX6Q_SUSPEND_OCRAM_SIZE);
50362306a36Sopenharmony_ci	if (!ocram_base) {
50462306a36Sopenharmony_ci		pr_warn("%s: unable to alloc ocram!\n", __func__);
50562306a36Sopenharmony_ci		ret = -ENOMEM;
50662306a36Sopenharmony_ci		goto put_device;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
51262306a36Sopenharmony_ci		MX6Q_SUSPEND_OCRAM_SIZE, false);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	memset(suspend_ocram_base, 0, sizeof(*pm_info));
51562306a36Sopenharmony_ci	pm_info = suspend_ocram_base;
51662306a36Sopenharmony_ci	pm_info->pbase = ocram_pbase;
51762306a36Sopenharmony_ci	pm_info->resume_addr = __pa_symbol(v7_cpu_resume);
51862306a36Sopenharmony_ci	pm_info->pm_info_size = sizeof(*pm_info);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/*
52162306a36Sopenharmony_ci	 * ccm physical address is not used by asm code currently,
52262306a36Sopenharmony_ci	 * so get ccm virtual address directly.
52362306a36Sopenharmony_ci	 */
52462306a36Sopenharmony_ci	pm_info->ccm_base.vbase = ccm_base;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	ret = imx6_pm_get_base(&pm_info->mmdc_base, socdata->mmdc_compat);
52762306a36Sopenharmony_ci	if (ret) {
52862306a36Sopenharmony_ci		pr_warn("%s: failed to get mmdc base %d!\n", __func__, ret);
52962306a36Sopenharmony_ci		goto put_device;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	ret = imx6_pm_get_base(&pm_info->src_base, socdata->src_compat);
53362306a36Sopenharmony_ci	if (ret) {
53462306a36Sopenharmony_ci		pr_warn("%s: failed to get src base %d!\n", __func__, ret);
53562306a36Sopenharmony_ci		goto src_map_failed;
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	ret = imx6_pm_get_base(&pm_info->iomuxc_base, socdata->iomuxc_compat);
53962306a36Sopenharmony_ci	if (ret) {
54062306a36Sopenharmony_ci		pr_warn("%s: failed to get iomuxc base %d!\n", __func__, ret);
54162306a36Sopenharmony_ci		goto iomuxc_map_failed;
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	ret = imx6_pm_get_base(&pm_info->gpc_base, socdata->gpc_compat);
54562306a36Sopenharmony_ci	if (ret) {
54662306a36Sopenharmony_ci		pr_warn("%s: failed to get gpc base %d!\n", __func__, ret);
54762306a36Sopenharmony_ci		goto gpc_map_failed;
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (socdata->pl310_compat) {
55162306a36Sopenharmony_ci		ret = imx6_pm_get_base(&pm_info->l2_base, socdata->pl310_compat);
55262306a36Sopenharmony_ci		if (ret) {
55362306a36Sopenharmony_ci			pr_warn("%s: failed to get pl310-cache base %d!\n",
55462306a36Sopenharmony_ci				__func__, ret);
55562306a36Sopenharmony_ci			goto pl310_cache_map_failed;
55662306a36Sopenharmony_ci		}
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	pm_info->ddr_type = imx_mmdc_get_ddr_type();
56062306a36Sopenharmony_ci	pm_info->mmdc_io_num = socdata->mmdc_io_num;
56162306a36Sopenharmony_ci	mmdc_offset_array = socdata->mmdc_io_offset;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	for (i = 0; i < pm_info->mmdc_io_num; i++) {
56462306a36Sopenharmony_ci		pm_info->mmdc_io_val[i][0] =
56562306a36Sopenharmony_ci			mmdc_offset_array[i];
56662306a36Sopenharmony_ci		pm_info->mmdc_io_val[i][1] =
56762306a36Sopenharmony_ci			readl_relaxed(pm_info->iomuxc_base.vbase +
56862306a36Sopenharmony_ci			mmdc_offset_array[i]);
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	imx6_suspend_in_ocram_fn = fncpy(
57262306a36Sopenharmony_ci		suspend_ocram_base + sizeof(*pm_info),
57362306a36Sopenharmony_ci		&imx6_suspend,
57462306a36Sopenharmony_ci		MX6Q_SUSPEND_OCRAM_SIZE - sizeof(*pm_info));
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	__arm_iomem_set_ro(suspend_ocram_base, MX6Q_SUSPEND_OCRAM_SIZE);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	goto put_device;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cipl310_cache_map_failed:
58162306a36Sopenharmony_ci	iounmap(pm_info->gpc_base.vbase);
58262306a36Sopenharmony_cigpc_map_failed:
58362306a36Sopenharmony_ci	iounmap(pm_info->iomuxc_base.vbase);
58462306a36Sopenharmony_ciiomuxc_map_failed:
58562306a36Sopenharmony_ci	iounmap(pm_info->src_base.vbase);
58662306a36Sopenharmony_cisrc_map_failed:
58762306a36Sopenharmony_ci	iounmap(pm_info->mmdc_base.vbase);
58862306a36Sopenharmony_ciput_device:
58962306a36Sopenharmony_ci	put_device(&pdev->dev);
59062306a36Sopenharmony_ciput_node:
59162306a36Sopenharmony_ci	of_node_put(node);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	return ret;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic void __init imx6_pm_common_init(const struct imx6_pm_socdata
59762306a36Sopenharmony_ci					*socdata)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	struct regmap *gpr;
60062306a36Sopenharmony_ci	int ret;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	WARN_ON(!ccm_base);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_SUSPEND)) {
60562306a36Sopenharmony_ci		ret = imx6q_suspend_init(socdata);
60662306a36Sopenharmony_ci		if (ret)
60762306a36Sopenharmony_ci			pr_warn("%s: No DDR LPM support with suspend %d!\n",
60862306a36Sopenharmony_ci				__func__, ret);
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/*
61262306a36Sopenharmony_ci	 * This is for SW workaround step #1 of ERR007265, see comments
61362306a36Sopenharmony_ci	 * in imx6_set_lpm for details of this errata.
61462306a36Sopenharmony_ci	 * Force IOMUXC irq pending, so that the interrupt to GPC can be
61562306a36Sopenharmony_ci	 * used to deassert dsm_request signal when the signal gets
61662306a36Sopenharmony_ci	 * asserted unexpectedly.
61762306a36Sopenharmony_ci	 */
61862306a36Sopenharmony_ci	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
61962306a36Sopenharmony_ci	if (!IS_ERR(gpr))
62062306a36Sopenharmony_ci		regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT,
62162306a36Sopenharmony_ci				   IMX6Q_GPR1_GINT);
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic void imx6_pm_stby_poweroff(void)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	gic_cpu_if_down(0);
62762306a36Sopenharmony_ci	imx6_set_lpm(STOP_POWER_OFF);
62862306a36Sopenharmony_ci	imx6q_suspend_finish(0);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	mdelay(1000);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	pr_emerg("Unable to poweroff system\n");
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic int imx6_pm_stby_poweroff_probe(void)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	if (pm_power_off) {
63862306a36Sopenharmony_ci		pr_warn("%s: pm_power_off already claimed  %p %ps!\n",
63962306a36Sopenharmony_ci			__func__, pm_power_off, pm_power_off);
64062306a36Sopenharmony_ci		return -EBUSY;
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	pm_power_off = imx6_pm_stby_poweroff;
64462306a36Sopenharmony_ci	return 0;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_civoid __init imx6_pm_ccm_init(const char *ccm_compat)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	struct device_node *np;
65062306a36Sopenharmony_ci	u32 val;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, ccm_compat);
65362306a36Sopenharmony_ci	ccm_base = of_iomap(np, 0);
65462306a36Sopenharmony_ci	BUG_ON(!ccm_base);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/*
65762306a36Sopenharmony_ci	 * Initialize CCM_CLPCR_LPM into RUN mode to avoid ARM core
65862306a36Sopenharmony_ci	 * clock being shut down unexpectedly by WAIT mode.
65962306a36Sopenharmony_ci	 */
66062306a36Sopenharmony_ci	val = readl_relaxed(ccm_base + CLPCR);
66162306a36Sopenharmony_ci	val &= ~BM_CLPCR_LPM;
66262306a36Sopenharmony_ci	writel_relaxed(val, ccm_base + CLPCR);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (of_property_read_bool(np, "fsl,pmic-stby-poweroff"))
66562306a36Sopenharmony_ci		imx6_pm_stby_poweroff_probe();
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	of_node_put(np);
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_civoid __init imx6q_pm_init(void)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	imx6_pm_common_init(&imx6q_pm_data);
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_civoid __init imx6dl_pm_init(void)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	imx6_pm_common_init(&imx6dl_pm_data);
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_civoid __init imx6sl_pm_init(void)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	struct regmap *gpr;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (cpu_is_imx6sl()) {
68562306a36Sopenharmony_ci		imx6_pm_common_init(&imx6sl_pm_data);
68662306a36Sopenharmony_ci	} else {
68762306a36Sopenharmony_ci		imx6_pm_common_init(&imx6sll_pm_data);
68862306a36Sopenharmony_ci		gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
68962306a36Sopenharmony_ci		if (!IS_ERR(gpr))
69062306a36Sopenharmony_ci			regmap_update_bits(gpr, IOMUXC_GPR5,
69162306a36Sopenharmony_ci				IMX6SLL_GPR5_AFCG_X_BYPASS_MASK, 0);
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_civoid __init imx6sx_pm_init(void)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	imx6_pm_common_init(&imx6sx_pm_data);
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_civoid __init imx6ul_pm_init(void)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	imx6_pm_common_init(&imx6ul_pm_data);
70362306a36Sopenharmony_ci}
704