blob: e9f4d86f21aaf093c2569e67b640bd5d916c8ed6 [file] [log] [blame]
/*
* Copyright (C) 2015 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/busfreq-imx.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/psci.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/genalloc.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/suspend.h>
#include <asm/cacheflush.h>
#include <asm/fncpy.h>
#include <asm/mach/map.h>
#include <asm/proc-fns.h>
#include <asm/suspend.h>
#include <asm/tlb.h>
#include <uapi/linux/psci.h>
#include "common.h"
#include "hardware.h"
#include "cpuidle.h"
#define MX7_SUSPEND_OCRAM_SIZE 0x1000
#define MX7_MAX_DDRC_NUM 32
#define MX7_MAX_DDRC_PHY_NUM 16
#define MX7_SUSPEND_IRAM_ADDR_OFFSET 0
#define READ_DATA_FROM_HARDWARE 0
#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
#define MAX_IOMUXC_GPR 23
#define MAX_UART_IO 4
#define MAX_CCM_LPCG 167
#define MAX_GPT 3
#define MAX_GPIO_ROW 7
#define MAX_GPIO_COL 8
#define UART_RX_IO 0x128
#define UART_RX_PAD 0x398
#define UART_TX_IO 0x12c
#define UART_TX_PAD 0x39c
#define GPT_CR 0x0
#define GPT_PR 0x4
#define GPT_IR 0xc
#define CCM_LPCG_START 0x4040
#define CCM_LPCG_STEP 0x10
#define CCM_EIM_LPCG 0x4160
#define CCM_PXP_LPCG 0x44c0
#define CCM_PCIE_LPCG 0x4600
#define BM_CCM_ROOT_POST_PODF 0x3f
#define BM_CCM_ROOT_PRE_PODF 0x70000
#define BM_CCM_ROOT_MUX 0x7000000
#define BM_CCM_ROOT_ENABLE 0x10000000
#define BM_SYS_COUNTER_CNTCR_FCR1 0x200
#define BM_SYS_COUNTER_CNTCR_FCR0 0x100
#define PFD_A_OFFSET 0xc0
#define PFD_B_OFFSET 0xd0
#define PLL_ARM_OFFSET 0x60
#define PLL_DDR_OFFSET 0x70
#define PLL_DDR_SS_OFFSET 0x80
#define PLL_DDR_NUM_OFFSET 0x90
#define PLL_DDR_DENOM_OFFSET 0xa0
#define PLL_480_OFFSET 0xb0
#define PLL_ENET_OFFSET 0xe0
#define PLL_AUDIO_OFFSET 0xf0
#define PLL_AUDIO_SS_OFFSET 0x100
#define PLL_AUDIO_NUM_OFFSET 0x110
#define PLL_AUDIO_DENOM_OFFSET 0x120
#define PLL_VIDEO_OFFSET 0x130
#define PLL_VIDEO_SS_OFFSET 0x140
#define PLL_VIDEO_NUM_OFFSET 0x150
#define PLL_VIDEO_DENOM_OFFSET 0x160
#define REG_SET 0x4
#define REG_CLR 0x8
#define GPIO_DR 0x0
#define GPIO_GDIR 0x4
#define GPIO_ICR1 0xc
#define GPIO_ICR2 0x10
#define GPIO_IMR 0x14
#define GPIO_EDGE 0x1c
#define M4RCR 0x0C
#define M4_SP_OFF 0x00
#define M4_PC_OFF 0x04
#define M4_RCR_HALT 0xAB
#define M4_RCR_GO 0xAA
#define M4_OCRAMS_RESERVED_SIZE 0xc
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 unsigned int ocram_size;
static unsigned int *lpm_ocram_saved_in_ddr;
static void __iomem *lpm_ocram_base;
static unsigned int *lpm_m4tcm_saved_in_ddr;
static void __iomem *lpm_m4tcm_base;
static void __iomem *m4_bootrom_base;
static unsigned int lpm_ocram_size;
static void __iomem *ccm_base;
static void __iomem *lpsr_base;
static void __iomem *console_base;
static void __iomem *suspend_ocram_base;
static void __iomem *iomuxc_base;
static void __iomem *gpt1_base;
static void __iomem *system_counter_ctrl_base;
static void __iomem *system_counter_cmp_base;
static void __iomem *gpio1_base;
static void (*imx7_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
struct imx7_cpu_pm_info *pm_info;
static bool lpsr_enabled;
static u32 iomuxc_gpr[MAX_IOMUXC_GPR];
static u32 uart1_io[MAX_UART_IO];
static u32 ccm_lpcg[MAX_CCM_LPCG];
static u32 ccm_root[][2] = {
{0x8000, 0}, {0x8080, 0}, {0x8100, 0}, {0x8800, 0},
{0x8880, 0}, {0x8900, 0}, {0x8980, 0}, {0x9000, 0},
{0x9800, 0}, {0x9880, 0}, {0xa000, 0}, {0xa080, 0},
{0xa100, 0}, {0xa180, 0}, {0xa200, 0}, {0xa280, 0},
{0xa300, 0}, {0xa380, 0}, {0xa400, 0}, {0xa480, 0},
{0xa500, 0}, {0xa580, 0}, {0xa600, 0}, {0xa680, 0},
{0xa700, 0}, {0xa780, 0}, {0xa800, 0}, {0xa880, 0},
{0xa900, 0}, {0xa980, 0}, {0xaa00, 0}, {0xaa80, 0},
{0xab00, 0}, {0xab80, 0}, {0xac00, 0}, {0xac80, 0},
{0xad00, 0}, {0xad80, 0}, {0xae00, 0}, {0xae80, 0},
{0xaf00, 0}, {0xaf80, 0}, {0xb000, 0}, {0xb080, 0},
{0xb100, 0}, {0xb180, 0}, {0xb200, 0}, {0xb280, 0},
{0xb300, 0}, {0xb380, 0}, {0xb400, 0}, {0xb480, 0},
{0xb500, 0}, {0xb580, 0}, {0xb600, 0}, {0xb680, 0},
{0xb700, 0}, {0xb780, 0}, {0xb800, 0}, {0xb880, 0},
{0xb900, 0}, {0xb980, 0}, {0xba00, 0}, {0xba80, 0},
{0xbb00, 0}, {0xbb80, 0}, {0xbc00, 0}, {0xbc80, 0},
{0xbd00, 0}, {0xbd80, 0}, {0xbe00, 0},
};
static u32 pfd_a, pfd_b;
static u32 pll[15];
static u32 gpt1_regs[MAX_GPT];
static u32 sys_ctrl_reg, sys_cmp_reg;
static u32 gpio_reg[MAX_GPIO_ROW][MAX_GPIO_COL];
/*
* suspend ocram space layout:
* ======================== high address ======================
* .
* .
* .
* ^
* ^
* ^
* imx7_suspend code
* PM_INFO structure(imx7_cpu_pm_info)
* ======================== low address =======================
*/
struct imx7_pm_base {
phys_addr_t pbase;
void __iomem *vbase;
};
struct imx7_pm_socdata {
u32 ddr_type;
const char *ddrc_compat;
const char *src_compat;
const char *iomuxc_compat;
const char *gpc_compat;
const u32 ddrc_num;
const u32 (*ddrc_offset)[2];
const u32 ddrc_phy_num;
const u32 (*ddrc_phy_offset)[2];
};
static const u32 imx7d_ddrc_lpddr3_setting[][2] __initconst = {
{ 0x0, READ_DATA_FROM_HARDWARE },
{ 0x1a0, READ_DATA_FROM_HARDWARE },
{ 0x1a4, READ_DATA_FROM_HARDWARE },
{ 0x1a8, READ_DATA_FROM_HARDWARE },
{ 0x64, READ_DATA_FROM_HARDWARE },
{ 0xd0, READ_DATA_FROM_HARDWARE },
{ 0xdc, READ_DATA_FROM_HARDWARE },
{ 0xe0, READ_DATA_FROM_HARDWARE },
{ 0xe4, READ_DATA_FROM_HARDWARE },
{ 0xf4, READ_DATA_FROM_HARDWARE },
{ 0x100, READ_DATA_FROM_HARDWARE },
{ 0x104, READ_DATA_FROM_HARDWARE },
{ 0x108, READ_DATA_FROM_HARDWARE },
{ 0x10c, READ_DATA_FROM_HARDWARE },
{ 0x110, READ_DATA_FROM_HARDWARE },
{ 0x114, READ_DATA_FROM_HARDWARE },
{ 0x118, READ_DATA_FROM_HARDWARE },
{ 0x120, READ_DATA_FROM_HARDWARE },
{ 0x11c, READ_DATA_FROM_HARDWARE },
{ 0x180, READ_DATA_FROM_HARDWARE },
{ 0x184, READ_DATA_FROM_HARDWARE },
{ 0x190, READ_DATA_FROM_HARDWARE },
{ 0x194, READ_DATA_FROM_HARDWARE },
{ 0x200, READ_DATA_FROM_HARDWARE },
{ 0x204, READ_DATA_FROM_HARDWARE },
{ 0x210, READ_DATA_FROM_HARDWARE },
{ 0x214, READ_DATA_FROM_HARDWARE },
{ 0x218, READ_DATA_FROM_HARDWARE },
{ 0x240, READ_DATA_FROM_HARDWARE },
{ 0x244, READ_DATA_FROM_HARDWARE },
};
static const u32 imx7d_ddrc_phy_lpddr3_setting[][2] __initconst = {
{ 0x0, READ_DATA_FROM_HARDWARE },
{ 0x4, READ_DATA_FROM_HARDWARE },
{ 0x8, READ_DATA_FROM_HARDWARE },
{ 0x10, READ_DATA_FROM_HARDWARE },
{ 0xb0, READ_DATA_FROM_HARDWARE },
{ 0x1c, READ_DATA_FROM_HARDWARE },
{ 0x9c, READ_DATA_FROM_HARDWARE },
{ 0x7c, READ_DATA_FROM_HARDWARE },
{ 0x80, READ_DATA_FROM_HARDWARE },
{ 0x84, READ_DATA_FROM_HARDWARE },
{ 0x88, READ_DATA_FROM_HARDWARE },
{ 0x6c, READ_DATA_FROM_HARDWARE },
{ 0x20, READ_DATA_FROM_HARDWARE },
{ 0x30, READ_DATA_FROM_HARDWARE },
{ 0x50, 0x01000008 },
{ 0x50, 0x00000008 },
{ 0xc0, 0x0e487304 },
{ 0xc0, 0x0e4c7304 },
{ 0xc0, 0x0e4c7306 },
{ 0xc0, 0x0e487304 },
};
static const u32 imx7d_ddrc_ddr3_setting[][2] __initconst = {
{ 0x0, READ_DATA_FROM_HARDWARE },
{ 0x1a0, READ_DATA_FROM_HARDWARE },
{ 0x1a4, READ_DATA_FROM_HARDWARE },
{ 0x1a8, READ_DATA_FROM_HARDWARE },
{ 0x64, READ_DATA_FROM_HARDWARE },
{ 0x490, READ_DATA_FROM_HARDWARE },
{ 0xd0, READ_DATA_FROM_HARDWARE },
{ 0xd4, READ_DATA_FROM_HARDWARE },
{ 0xdc, READ_DATA_FROM_HARDWARE },
{ 0xe0, READ_DATA_FROM_HARDWARE },
{ 0xe4, READ_DATA_FROM_HARDWARE },
{ 0xf4, READ_DATA_FROM_HARDWARE },
{ 0x100, READ_DATA_FROM_HARDWARE },
{ 0x104, READ_DATA_FROM_HARDWARE },
{ 0x108, READ_DATA_FROM_HARDWARE },
{ 0x10c, READ_DATA_FROM_HARDWARE },
{ 0x110, READ_DATA_FROM_HARDWARE },
{ 0x114, READ_DATA_FROM_HARDWARE },
{ 0x120, READ_DATA_FROM_HARDWARE },
{ 0x180, READ_DATA_FROM_HARDWARE },
{ 0x190, READ_DATA_FROM_HARDWARE },
{ 0x194, READ_DATA_FROM_HARDWARE },
{ 0x200, READ_DATA_FROM_HARDWARE },
{ 0x204, READ_DATA_FROM_HARDWARE },
{ 0x210, READ_DATA_FROM_HARDWARE },
{ 0x214, READ_DATA_FROM_HARDWARE },
{ 0x218, READ_DATA_FROM_HARDWARE },
{ 0x240, READ_DATA_FROM_HARDWARE },
{ 0x244, READ_DATA_FROM_HARDWARE },
};
static const u32 imx7d_ddrc_phy_ddr3_setting[][2] __initconst = {
{ 0x0, READ_DATA_FROM_HARDWARE },
{ 0x4, READ_DATA_FROM_HARDWARE },
{ 0x10, READ_DATA_FROM_HARDWARE },
{ 0xb0, READ_DATA_FROM_HARDWARE },
{ 0x9c, READ_DATA_FROM_HARDWARE },
{ 0x7c, READ_DATA_FROM_HARDWARE },
{ 0x80, READ_DATA_FROM_HARDWARE },
{ 0x84, READ_DATA_FROM_HARDWARE },
{ 0x88, READ_DATA_FROM_HARDWARE },
{ 0x6c, READ_DATA_FROM_HARDWARE },
{ 0x20, READ_DATA_FROM_HARDWARE },
{ 0x30, READ_DATA_FROM_HARDWARE },
{ 0x50, 0x01000010 },
{ 0x50, 0x00000010 },
{ 0xc0, 0x0e407304 },
{ 0xc0, 0x0e447304 },
{ 0xc0, 0x0e447306 },
{ 0xc0, 0x0e407304 },
};
static const struct imx7_pm_socdata imx7d_pm_data_lpddr3 __initconst = {
.ddrc_compat = "fsl,imx7d-ddrc",
.src_compat = "fsl,imx7d-src",
.iomuxc_compat = "fsl,imx7d-iomuxc",
.gpc_compat = "fsl,imx7d-gpc",
.ddrc_num = ARRAY_SIZE(imx7d_ddrc_lpddr3_setting),
.ddrc_offset = imx7d_ddrc_lpddr3_setting,
.ddrc_phy_num = ARRAY_SIZE(imx7d_ddrc_phy_lpddr3_setting),
.ddrc_phy_offset = imx7d_ddrc_phy_lpddr3_setting,
};
static const struct imx7_pm_socdata imx7d_pm_data_ddr3 __initconst = {
.ddrc_compat = "fsl,imx7d-ddrc",
.src_compat = "fsl,imx7d-src",
.iomuxc_compat = "fsl,imx7d-iomuxc",
.gpc_compat = "fsl,imx7d-gpc",
.ddrc_num = ARRAY_SIZE(imx7d_ddrc_ddr3_setting),
.ddrc_offset = imx7d_ddrc_ddr3_setting,
.ddrc_phy_num = ARRAY_SIZE(imx7d_ddrc_phy_ddr3_setting),
.ddrc_phy_offset = imx7d_ddrc_phy_ddr3_setting,
};
/*
* This structure is for passing necessary data for low level ocram
* suspend code(arch/arm/mach-imx/suspend-imx7.S), if this struct
* definition is changed, the offset definition in
* arch/arm/mach-imx/suspend-imx7.S must be also changed accordingly,
* otherwise, the suspend to ocram function will be broken!
*/
struct imx7_cpu_pm_info {
u32 m4_reserve0;
u32 m4_reserve1;
u32 m4_reserve2;
phys_addr_t pbase; /* The physical address of pm_info. */
phys_addr_t resume_addr; /* The physical resume address for asm code */
u32 ddr_type;
u32 pm_info_size; /* Size of pm_info. */
struct imx7_pm_base ddrc_base;
struct imx7_pm_base ddrc_phy_base;
struct imx7_pm_base src_base;
struct imx7_pm_base iomuxc_gpr_base;
struct imx7_pm_base ccm_base;
struct imx7_pm_base gpc_base;
struct imx7_pm_base snvs_base;
struct imx7_pm_base anatop_base;
struct imx7_pm_base lpsr_base;
struct imx7_pm_base gic_base;
u32 ttbr1; /* Store TTBR1 */
u32 ddrc_num; /* Number of DDRC which need saved/restored. */
u32 ddrc_val[MX7_MAX_DDRC_NUM][2]; /* To save offset and value */
u32 ddrc_phy_num; /* Number of DDRC which need saved/restored. */
u32 ddrc_phy_val[MX7_MAX_DDRC_NUM][2]; /* To save offset and value */
} __aligned(8);
static struct map_desc imx7_pm_io_desc[] __initdata = {
imx_map_entry(MX7D, AIPS1, MT_DEVICE),
imx_map_entry(MX7D, AIPS2, MT_DEVICE),
imx_map_entry(MX7D, AIPS3, MT_DEVICE),
};
static const char * const low_power_ocram_match[] __initconst = {
"fsl,lpm-sram",
NULL
};
static void imx7_gpio_save(void)
{
u32 i;
for (i = 0; i < 7; i++) {
gpio_reg[i][0] = readl_relaxed(gpio1_base +
(i << 16) + GPIO_DR);
gpio_reg[i][1] = readl_relaxed(gpio1_base +
(i << 16) + GPIO_GDIR);
gpio_reg[i][3] = readl_relaxed(gpio1_base +
(i << 16) + GPIO_ICR1);
gpio_reg[i][4] = readl_relaxed(gpio1_base +
(i << 16) + GPIO_ICR2);
gpio_reg[i][5] = readl_relaxed(gpio1_base +
(i << 16) + GPIO_IMR);
gpio_reg[i][7] = readl_relaxed(gpio1_base +
(i << 16) + GPIO_EDGE);
}
}
static void imx7_gpio_restore(void)
{
u32 i, val;
for (i = 0; i < 7; i++) {
writel_relaxed(gpio_reg[i][1], gpio1_base +
(i << 16) + GPIO_GDIR);
writel_relaxed(gpio_reg[i][3], gpio1_base +
(i << 16) + GPIO_ICR1);
writel_relaxed(gpio_reg[i][4], gpio1_base +
(i << 16) + GPIO_ICR2);
writel_relaxed(gpio_reg[i][5], gpio1_base +
(i << 16) + GPIO_IMR);
writel_relaxed(gpio_reg[i][7], gpio1_base +
(i << 16) + GPIO_EDGE);
/* only restore output gpio value */
val = readl_relaxed(gpio1_base + (i << 16) + GPIO_DR) |
(gpio_reg[i][0] & gpio_reg[i][1]);
writel_relaxed(val, gpio1_base + (i << 16) + GPIO_DR);
}
}
static void imx7_ccm_save(void)
{
u32 i;
for (i = 0; i < MAX_CCM_LPCG; i++)
ccm_lpcg[i] = readl_relaxed(pm_info->ccm_base.vbase +
i * CCM_LPCG_STEP + CCM_LPCG_START);
pfd_a = readl_relaxed(pm_info->anatop_base.vbase + PFD_A_OFFSET);
pfd_b = readl_relaxed(pm_info->anatop_base.vbase + PFD_B_OFFSET);
pll[0] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_ARM_OFFSET);
pll[1] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_DDR_OFFSET);
pll[2] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_DDR_SS_OFFSET);
pll[3] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_DDR_NUM_OFFSET);
pll[4] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_DDR_DENOM_OFFSET);
pll[5] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_480_OFFSET);
pll[6] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_ENET_OFFSET);
pll[7] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_AUDIO_OFFSET);
pll[8] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_AUDIO_SS_OFFSET);
pll[9] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_AUDIO_NUM_OFFSET);
pll[10] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_AUDIO_DENOM_OFFSET);
pll[11] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_VIDEO_OFFSET);
pll[12] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_VIDEO_SS_OFFSET);
pll[13] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_VIDEO_NUM_OFFSET);
pll[14] = readl_relaxed(pm_info->anatop_base.vbase +
PLL_VIDEO_DENOM_OFFSET);
/* enable all PLLs/PFDs for saving CCM root */
writel_relaxed(0x1c000070, pm_info->anatop_base.vbase +
PLL_480_OFFSET + 0x8);
writel_relaxed(0x80808080, pm_info->anatop_base.vbase +
PFD_A_OFFSET + 0x8);
writel_relaxed(0x80808080, pm_info->anatop_base.vbase +
PFD_B_OFFSET + 0x8);
writel_relaxed(0x1fc0, pm_info->anatop_base.vbase +
PLL_ENET_OFFSET + 0x4);
writel_relaxed(0x12000, pm_info->anatop_base.vbase +
PLL_AUDIO_OFFSET);
writel_relaxed(0x12000, pm_info->anatop_base.vbase +
PLL_VIDEO_OFFSET);
for (i = 0; i < sizeof(ccm_root) / 8; i++)
ccm_root[i][1] = readl_relaxed(
pm_info->ccm_base.vbase + ccm_root[i][0]);
}
static void imx7_ccm_restore(void)
{
u32 i, val;
/* enable all PLLs/PFDs for restoring CCM root */
writel_relaxed(0x1c000070, pm_info->anatop_base.vbase +
PLL_480_OFFSET + REG_CLR);
writel_relaxed(0x80808080, pm_info->anatop_base.vbase +
PFD_A_OFFSET + REG_CLR);
writel_relaxed(0x80808080, pm_info->anatop_base.vbase +
PFD_B_OFFSET + REG_CLR);
writel_relaxed(0x1fc0, pm_info->anatop_base.vbase +
PLL_ENET_OFFSET + REG_SET);
writel_relaxed(0x12000, pm_info->anatop_base.vbase +
PLL_AUDIO_OFFSET);
writel_relaxed(0x12000, pm_info->anatop_base.vbase +
PLL_VIDEO_OFFSET);
for (i = 0; i < sizeof(ccm_root) / 8; i++) {
val = readl_relaxed(pm_info->ccm_base.vbase + ccm_root[i][0]);
/* restore post podf */
val &= ~BM_CCM_ROOT_POST_PODF;
val |= ccm_root[i][1] & BM_CCM_ROOT_POST_PODF;
writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]);
/* resotre pre podf */
val &= ~BM_CCM_ROOT_PRE_PODF;
val |= ccm_root[i][1] & BM_CCM_ROOT_PRE_PODF;
writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]);
/* restore mux */
val &= ~BM_CCM_ROOT_MUX;
val |= ccm_root[i][1] & BM_CCM_ROOT_MUX;
writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]);
/* restore enable */
val &= ~BM_CCM_ROOT_ENABLE;
val |= ccm_root[i][1] & BM_CCM_ROOT_ENABLE;
writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]);
}
/* restore PLLs */
writel_relaxed(pll[0], pm_info->anatop_base.vbase +
PLL_ARM_OFFSET);
writel_relaxed(pll[1], pm_info->anatop_base.vbase +
PLL_DDR_OFFSET);
writel_relaxed(pll[2], pm_info->anatop_base.vbase +
PLL_DDR_SS_OFFSET);
writel_relaxed(pll[3], pm_info->anatop_base.vbase +
PLL_DDR_NUM_OFFSET);
writel_relaxed(pll[4], pm_info->anatop_base.vbase +
PLL_DDR_DENOM_OFFSET);
writel_relaxed(pll[5], pm_info->anatop_base.vbase +
PLL_480_OFFSET);
writel_relaxed(pll[6], pm_info->anatop_base.vbase +
PLL_ENET_OFFSET);
writel_relaxed(pll[7], pm_info->anatop_base.vbase +
PLL_AUDIO_OFFSET);
writel_relaxed(pll[8], pm_info->anatop_base.vbase +
PLL_AUDIO_SS_OFFSET);
writel_relaxed(pll[9], pm_info->anatop_base.vbase +
PLL_AUDIO_NUM_OFFSET);
writel_relaxed(pll[10], pm_info->anatop_base.vbase +
PLL_AUDIO_DENOM_OFFSET);
writel_relaxed(pll[11], pm_info->anatop_base.vbase +
PLL_VIDEO_OFFSET);
writel_relaxed(pll[12], pm_info->anatop_base.vbase +
PLL_VIDEO_SS_OFFSET);
writel_relaxed(pll[13], pm_info->anatop_base.vbase +
PLL_VIDEO_NUM_OFFSET);
writel_relaxed(pll[14], pm_info->anatop_base.vbase +
PLL_VIDEO_DENOM_OFFSET);
for (i = 0; i < MAX_CCM_LPCG; i++)
writel_relaxed(ccm_lpcg[i], pm_info->ccm_base.vbase +
i * CCM_LPCG_STEP + CCM_LPCG_START);
/* restore PFDs */
writel_relaxed(pfd_a & 0x80808080,
pm_info->anatop_base.vbase + PFD_A_OFFSET + REG_SET);
writel_relaxed(pfd_a, pm_info->anatop_base.vbase + PFD_A_OFFSET);
writel_relaxed(pfd_b & 0x80808080,
pm_info->anatop_base.vbase + PFD_B_OFFSET + REG_SET);
writel_relaxed(pfd_b, pm_info->anatop_base.vbase + PFD_B_OFFSET);
}
static void imx7_sys_counter_save(void)
{
sys_ctrl_reg = readl_relaxed(system_counter_ctrl_base);
sys_cmp_reg = readl_relaxed(system_counter_cmp_base);
}
static void imx7_sys_counter_restore(void)
{
writel_relaxed(sys_ctrl_reg, system_counter_ctrl_base);
writel_relaxed(sys_cmp_reg, system_counter_cmp_base);
}
static void imx7_gpt_save(void)
{
gpt1_regs[0] = readl_relaxed(gpt1_base + GPT_CR);
gpt1_regs[1] = readl_relaxed(gpt1_base + GPT_PR);
gpt1_regs[2] = readl_relaxed(gpt1_base + GPT_IR);
}
static void imx7_gpt_restore(void)
{
writel_relaxed(gpt1_regs[0], gpt1_base + GPT_CR);
writel_relaxed(gpt1_regs[1], gpt1_base + GPT_PR);
writel_relaxed(gpt1_regs[2], gpt1_base + GPT_IR);
}
static void imx7_iomuxc_gpr_save(void)
{
u32 i;
for (i = 0; i < MAX_IOMUXC_GPR; i++)
iomuxc_gpr[i] = readl_relaxed(
pm_info->iomuxc_gpr_base.vbase + i * 4);
}
static void imx7_iomuxc_gpr_restore(void)
{
u32 i;
for (i = 0; i < MAX_IOMUXC_GPR; i++)
writel_relaxed(iomuxc_gpr[i],
pm_info->iomuxc_gpr_base.vbase + i * 4);
}
static void imx7_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_UTS);
}
static void imx7_console_io_save(void)
{
/* save uart1 io, driver resume is too late */
uart1_io[0] = readl_relaxed(iomuxc_base + UART_RX_IO);
uart1_io[1] = readl_relaxed(iomuxc_base + UART_RX_PAD);
uart1_io[2] = readl_relaxed(iomuxc_base + UART_TX_IO);
uart1_io[3] = readl_relaxed(iomuxc_base + UART_TX_PAD);
}
static void imx7_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_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 void imx7_console_io_restore(void)
{
/* restore uart1 io */
writel_relaxed(uart1_io[0], iomuxc_base + UART_RX_IO);
writel_relaxed(uart1_io[1], iomuxc_base + UART_RX_PAD);
writel_relaxed(uart1_io[2], iomuxc_base + UART_TX_IO);
writel_relaxed(uart1_io[3], iomuxc_base + UART_TX_PAD);
}
#define MX7D_SUSPEND_POWERDWN_PARAM \
((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
(1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
(PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
#define MX7D_SUSPEND_STANDBY_PARAM \
((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
(1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
(PSCI_POWER_STATE_TYPE_STANDBY << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
static int imx7_suspend_finish(unsigned long val)
{
u32 state;
if (val == 0)
state = MX7D_SUSPEND_POWERDWN_PARAM;
else
state = MX7D_SUSPEND_STANDBY_PARAM;
if (psci_ops.cpu_suspend) {
return psci_ops.cpu_suspend(state, __pa(cpu_resume));
}
if (!imx7_suspend_in_ocram_fn) {
cpu_do_idle();
} else {
/*
* call low level suspend function in ocram,
* as we need to float DDR IO.
*/
local_flush_tlb_all();
imx7_suspend_in_ocram_fn(suspend_ocram_base);
}
return 0;
}
static void imx7_pm_set_lpsr_resume_addr(unsigned long addr)
{
writel_relaxed(addr, pm_info->lpsr_base.vbase);
}
static int imx7_pm_is_resume_from_lpsr(void)
{
return readl_relaxed(lpsr_base);
}
static int imx7_pm_enter(suspend_state_t state)
{
unsigned int console_saved_reg[10] = {0};
u32 val;
if (!iram_tlb_base_addr) {
pr_warn("No IRAM/OCRAM memory allocated for suspend/resume \
code. Please ensure device tree has an entry for \
fsl,lpm-sram.\n");
return -EINVAL;
}
/*
* arm_arch_timer driver requires system counter to be
* a clock source with CLOCK_SOURCE_SUSPEND_NONSTOP flag
* set, which means hardware system counter needs to keep
* running during suspend, as the base clock for system
* counter is 24MHz which will be disabled in STOP mode,
* so we need to switch system counter's clock to alternate
* (lower) clock, it is based on 32K, from block guide, there
* is no special flow needs to be followed, system counter
* hardware will handle the clock transition.
*/
val = readl_relaxed(system_counter_ctrl_base);
val &= ~BM_SYS_COUNTER_CNTCR_FCR0;
val |= BM_SYS_COUNTER_CNTCR_FCR1;
writel_relaxed(val, system_counter_ctrl_base);
switch (state) {
case PM_SUSPEND_STANDBY:
imx_anatop_pre_suspend();
imx_gpcv2_pre_suspend(false);
/* Zzz ... */
if (psci_ops.cpu_suspend)
cpu_suspend(1, imx7_suspend_finish);
else
imx7_suspend_in_ocram_fn(suspend_ocram_base);
imx_anatop_post_resume();
imx_gpcv2_post_resume();
break;
case PM_SUSPEND_MEM:
imx_anatop_pre_suspend();
imx_gpcv2_pre_suspend(true);
if (imx_gpcv2_is_mf_mix_off()) {
/*
* per design requirement, EXSC for PCIe/EIM/PXP
* will need clock to recover RDC setting on
* resume, so enable PCIe/EIM LPCG for RDC
* recovery when M/F mix off
*/
writel_relaxed(0x3, pm_info->ccm_base.vbase +
CCM_EIM_LPCG);
writel_relaxed(0x3, pm_info->ccm_base.vbase +
CCM_PXP_LPCG);
writel_relaxed(0x3, pm_info->ccm_base.vbase +
CCM_PCIE_LPCG);
/* stop m4 if mix will also be shutdown */
if (imx_src_is_m4_enabled() && imx_mu_is_m4_in_stop()) {
writel(M4_RCR_HALT,
pm_info->src_base.vbase + M4RCR);
imx_gpcv2_enable_wakeup_for_m4();
}
imx7_console_save(console_saved_reg);
memcpy(ocram_saved_in_ddr, ocram_base, ocram_size);
if (lpsr_enabled) {
imx7_pm_set_lpsr_resume_addr(pm_info->resume_addr);
imx7_console_io_save();
memcpy(lpm_ocram_saved_in_ddr, lpm_ocram_base,
lpm_ocram_size);
imx7_iomuxc_gpr_save();
imx7_ccm_save();
imx7_gpt_save();
imx7_sys_counter_save();
imx7_gpio_save();
}
}
/* Zzz ... */
cpu_suspend(0, imx7_suspend_finish);
if (imx7_pm_is_resume_from_lpsr()) {
imx7_console_io_restore();
memcpy(lpm_ocram_base, lpm_ocram_saved_in_ddr,
lpm_ocram_size);
imx7_iomuxc_gpr_restore();
imx7_ccm_restore();
imx7_gpt_restore();
imx7_sys_counter_restore();
imx7_gpio_restore();
imx7d_enable_rcosc();
}
if (imx_gpcv2_is_mf_mix_off() ||
imx7_pm_is_resume_from_lpsr()) {
writel_relaxed(0x0, pm_info->ccm_base.vbase +
CCM_EIM_LPCG);
writel_relaxed(0x0, pm_info->ccm_base.vbase +
CCM_PXP_LPCG);
writel_relaxed(0x0, pm_info->ccm_base.vbase +
CCM_PCIE_LPCG);
memcpy(ocram_base, ocram_saved_in_ddr, ocram_size);
imx7_console_restore(console_saved_reg);
if (imx_src_is_m4_enabled() && imx_mu_is_m4_in_stop()) {
imx_gpcv2_disable_wakeup_for_m4();
/* restore M4 image */
memcpy(lpm_m4tcm_base,
lpm_m4tcm_saved_in_ddr, SZ_32K);
/* kick m4 to enable */
writel(M4_RCR_GO,
pm_info->src_base.vbase + M4RCR);
/* offset high bus count for m4 image */
request_bus_freq(BUS_FREQ_HIGH);
/* restore M4 to run mode */
imx_mu_set_m4_run_mode();
/* gpc wakeup */
}
}
/* clear LPSR resume address */
imx7_pm_set_lpsr_resume_addr(0);
imx_anatop_post_resume();
imx_gpcv2_post_resume();
break;
default:
return -EINVAL;
}
/* restore system counter's clock to base clock */
val = readl_relaxed(system_counter_ctrl_base);
val &= ~BM_SYS_COUNTER_CNTCR_FCR1;
val |= BM_SYS_COUNTER_CNTCR_FCR0;
writel_relaxed(val, system_counter_ctrl_base);
return 0;
}
static int imx7_pm_valid(suspend_state_t state)
{
return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM;
}
static const struct platform_suspend_ops imx7_pm_ops = {
.enter = imx7_pm_enter,
.valid = imx7_pm_valid,
};
void __init imx7_pm_set_ccm_base(void __iomem *base)
{
ccm_base = base;
}
static struct map_desc iram_tlb_io_desc __initdata = {
/* .virtual and .pfn are run-time assigned */
.length = SZ_1M,
.type = MT_MEMORY_RWX_NONCACHED,
};
static int __init imx7_dt_find_lpsram(unsigned long node, const char *uname,
int depth, void *data)
{
unsigned long lpram_addr;
const __be32 *prop = of_get_flat_dt_prop(node, "reg", NULL);
if (of_flat_dt_match(node, low_power_ocram_match)) {
if (!prop)
return -EINVAL;
lpram_addr = be32_to_cpup(prop);
/* We need to create a 1M page table entry. */
iram_tlb_io_desc.virtual = IMX_IO_P2V(lpram_addr & 0xFFF00000);
iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & 0xFFF00000);
iram_tlb_phys_addr = lpram_addr;
iram_tlb_base_addr = IMX_IO_P2V(lpram_addr);
iotable_init(&iram_tlb_io_desc, 1);
}
return 0;
}
void __init imx7_pm_map_io(void)
{
unsigned long i, j;
iotable_init(imx7_pm_io_desc, ARRAY_SIZE(imx7_pm_io_desc));
/*
* Get the address of IRAM or OCRAM to be used by the low
* power code from the device tree.
*/
WARN_ON(of_scan_flat_dt(imx7_dt_find_lpsram, NULL));
/* Return if no IRAM space is allocated for suspend/resume code. */
if (!iram_tlb_base_addr) {
pr_warn("No valid ocram available for suspend/resume!\n");
return;
}
/* TODO: Handle M4 in TEE? */
/* Set all entries to 0 except first 3 words reserved for M4. */
memset((void *)(iram_tlb_base_addr + M4_OCRAMS_RESERVED_SIZE),
0, MX7_IRAM_TLB_SIZE - M4_OCRAMS_RESERVED_SIZE);
/*
* Make sure the IRAM virtual address has a mapping in the IRAM
* page table.
*
* Only use the top 12 bits [31-20] when storing the physical
* address in the page table as only these bits are required
* for 1M mapping.
*/
j = ((iram_tlb_base_addr >> 20) << 2) / 4;
*((unsigned long *)iram_tlb_base_addr + j) =
(iram_tlb_phys_addr & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M;
/*
* Make sure the AIPS1 virtual address has a mapping in the
* IRAM page table.
*/
for (i = 0; i < 4; i++) {
j = ((IMX_IO_P2V(MX7D_AIPS1_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4;
*((unsigned long *)iram_tlb_base_addr + j) =
((MX7D_AIPS1_BASE_ADDR + i * 0x100000) & 0xFFF00000) |
TT_ATTRIB_NON_CACHEABLE_1M;
}
/*
* Make sure the AIPS2 virtual address has a mapping in the
* IRAM page table.
*/
for (i = 0; i < 4; i++) {
j = ((IMX_IO_P2V(MX7D_AIPS2_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4;
*((unsigned long *)iram_tlb_base_addr + j) =
((MX7D_AIPS2_BASE_ADDR + i * 0x100000) & 0xFFF00000) |
TT_ATTRIB_NON_CACHEABLE_1M;
}
/*
* Make sure the AIPS3 virtual address has a mapping
* in the IRAM page table.
*/
for (i = 0; i < 4; i++) {
j = ((IMX_IO_P2V(MX7D_AIPS3_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4;
*((unsigned long *)iram_tlb_base_addr + j) =
((MX7D_AIPS3_BASE_ADDR + i * 0x100000) & 0xFFF00000) |
TT_ATTRIB_NON_CACHEABLE_1M;
}
/*
* Make sure the GIC virtual address has a mapping in the
* IRAM page table.
*/
j = ((IMX_IO_P2V(MX7D_GIC_BASE_ADDR) >> 20) << 2) / 4;
*((unsigned long *)iram_tlb_base_addr + j) =
(MX7D_GIC_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M;
}
static int __init imx7_suspend_init(const struct imx7_pm_socdata *socdata)
{
struct device_node *node;
int i, ret = 0;
const u32 (*ddrc_offset_array)[2];
const u32 (*ddrc_phy_offset_array)[2];
unsigned long iram_paddr;
suspend_set_ops(&imx7_pm_ops);
if (!socdata) {
pr_warn("%s: invalid argument!\n", __func__);
return -EINVAL;
}
/*
* 16KB is allocated for IRAM TLB, but only up 8k is for kernel TLB,
* The lower 8K is not used, so use the lower 8K for IRAM code and
* pm_info.
*
*/
iram_paddr = iram_tlb_phys_addr + MX7_SUSPEND_IRAM_ADDR_OFFSET;
/* Make sure iram_paddr is 8 byte aligned. */
if ((uintptr_t)(iram_paddr) & (FNCPY_ALIGN - 1))
iram_paddr += FNCPY_ALIGN - iram_paddr % (FNCPY_ALIGN);
/* Get the virtual address of the suspend code. */
suspend_ocram_base = (void *)IMX_IO_P2V(iram_paddr);
if (psci_ops.cpu_suspend) {
pm_info = kmalloc(sizeof(*pm_info), GFP_KERNEL);
if (!pm_info)
return -ENOMEM;
} else {
pm_info = suspend_ocram_base;
}
/* pbase points to iram_paddr. */
pm_info->pbase = iram_paddr;
pm_info->resume_addr = virt_to_phys(ca7_cpu_resume);
pm_info->pm_info_size = sizeof(*pm_info);
/*
* ccm physical address is not used by asm code currently,
* so get ccm virtual address directly, as we already have
* it from ccm driver.
*/
pm_info->ccm_base.pbase = MX7D_CCM_BASE_ADDR;
pm_info->ccm_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_CCM_BASE_ADDR);
pm_info->ddrc_base.pbase = MX7D_DDRC_BASE_ADDR;
pm_info->ddrc_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_DDRC_BASE_ADDR);
pm_info->ddrc_phy_base.pbase = MX7D_DDRC_PHY_BASE_ADDR;
pm_info->ddrc_phy_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR);
pm_info->src_base.pbase = MX7D_SRC_BASE_ADDR;
pm_info->src_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_SRC_BASE_ADDR);
pm_info->iomuxc_gpr_base.pbase = MX7D_IOMUXC_GPR_BASE_ADDR;
pm_info->iomuxc_gpr_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR);
pm_info->gpc_base.pbase = MX7D_GPC_BASE_ADDR;
pm_info->gpc_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_GPC_BASE_ADDR);
pm_info->anatop_base.pbase = MX7D_ANATOP_BASE_ADDR;
pm_info->anatop_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR);
pm_info->snvs_base.pbase = MX7D_SNVS_BASE_ADDR;
pm_info->snvs_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_SNVS_BASE_ADDR);
pm_info->lpsr_base.pbase = MX7D_LPSR_BASE_ADDR;
lpsr_base = pm_info->lpsr_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_LPSR_BASE_ADDR);
pm_info->gic_base.pbase = MX7D_GIC_BASE_ADDR;
pm_info->gic_base.vbase = (void __iomem *)
IMX_IO_P2V(MX7D_GIC_BASE_ADDR);
pm_info->ddrc_num = socdata->ddrc_num;
ddrc_offset_array = socdata->ddrc_offset;
pm_info->ddrc_phy_num = socdata->ddrc_phy_num;
ddrc_phy_offset_array = socdata->ddrc_phy_offset;
/* initialize DDRC settings */
for (i = 0; i < pm_info->ddrc_num; i++) {
pm_info->ddrc_val[i][0] = ddrc_offset_array[i][0];
if (ddrc_offset_array[i][1] == READ_DATA_FROM_HARDWARE)
pm_info->ddrc_val[i][1] =
readl_relaxed(pm_info->ddrc_base.vbase +
ddrc_offset_array[i][0]);
else
pm_info->ddrc_val[i][1] = ddrc_offset_array[i][1];
if (pm_info->ddrc_val[i][0] == 0xd0)
pm_info->ddrc_val[i][1] |= 0xc0000000;
}
/* initialize DDRC PHY settings */
for (i = 0; i < pm_info->ddrc_phy_num; i++) {
pm_info->ddrc_phy_val[i][0] =
ddrc_phy_offset_array[i][0];
if (ddrc_phy_offset_array[i][1] == READ_DATA_FROM_HARDWARE)
pm_info->ddrc_phy_val[i][1] =
readl_relaxed(pm_info->ddrc_phy_base.vbase +
ddrc_phy_offset_array[i][0]);
else
pm_info->ddrc_phy_val[i][1] =
ddrc_phy_offset_array[i][1];
}
if (psci_ops.cpu_suspend)
goto put_node;
imx7_suspend_in_ocram_fn = fncpy(
suspend_ocram_base + sizeof(*pm_info),
&imx7_suspend,
MX7_SUSPEND_OCRAM_SIZE - sizeof(*pm_info));
goto put_node;
put_node:
of_node_put(node);
return ret;
}
static void __init imx7_pm_common_init(const struct imx7_pm_socdata
*socdata)
{
int ret;
struct regmap *gpr;
if (IS_ENABLED(CONFIG_SUSPEND)) {
ret = imx7_suspend_init(socdata);
if (ret)
pr_warn("%s: No DDR LPM support with suspend %d!\n",
__func__, ret);
}
/*
* Force IOMUXC irq pending, so that the interrupt to GPC can be
* used to deassert dsm_request signal when the signal gets
* asserted unexpectedly.
*/
gpr = syscon_regmap_lookup_by_compatible("fsl,imx7d-iomuxc-gpr");
if (!IS_ERR(gpr))
regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_IRQ_MASK,
IMX7D_GPR1_IRQ_MASK);
}
void __init imx7d_pm_init(void)
{
struct device_node *np;
struct resource res;
if (imx_src_is_m4_enabled()) {
/* map the 32K of M4 TCM */
np = of_find_node_by_path(
"/tcml@007f8000");
if (np)
lpm_m4tcm_base = of_iomap(np, 0);
WARN_ON(!lpm_m4tcm_base);
/* map the m4 bootrom from dtb */
np = of_find_node_by_path(
"/soc/sram@00180000");
if (np)
m4_bootrom_base = of_iomap(np, 0);
WARN_ON(!m4_bootrom_base);
lpm_m4tcm_saved_in_ddr = kzalloc(SZ_32K, GFP_KERNEL);
WARN_ON(!lpm_m4tcm_saved_in_ddr);
/* save M4 Image to DDR */
memcpy(lpm_m4tcm_saved_in_ddr, lpm_m4tcm_base, SZ_32K);
}
np = of_find_compatible_node(NULL, NULL, "fsl,lpm-sram");
if (of_get_property(np, "fsl,enable-lpsr", NULL))
lpsr_enabled = true;
if (psci_ops.cpu_suspend)
lpsr_enabled = false;
if (lpsr_enabled) {
pr_info("LPSR mode enabled, DSM will go into LPSR mode!\n");
lpm_ocram_base = of_iomap(np, 0);
WARN_ON(!lpm_ocram_base);
WARN_ON(of_address_to_resource(np, 0, &res));
lpm_ocram_size = resource_size(&res);
lpm_ocram_saved_in_ddr = kzalloc(lpm_ocram_size, GFP_KERNEL);
WARN_ON(!lpm_ocram_saved_in_ddr);
np = of_find_node_by_path(
"/soc/aips-bus@30000000/iomuxc@30330000");
if (np)
iomuxc_base = of_iomap(np, 0);
WARN_ON(!iomuxc_base);
np = of_find_node_by_path(
"/soc/aips-bus@30000000/gpt@302d0000");
if (np)
gpt1_base = of_iomap(np, 0);
WARN_ON(!gpt1_base);
np = of_find_node_by_path(
"/soc/aips-bus@30400000/system-counter-cmp@306b0000");
if (np)
system_counter_cmp_base = of_iomap(np, 0);
WARN_ON(!system_counter_cmp_base);
np = of_find_node_by_path(
"/soc/aips-bus@30000000/gpio@30200000");
if (np)
gpio1_base = of_iomap(np, 0);
WARN_ON(!gpio1_base);
}
np = of_find_node_by_path(
"/soc/aips-bus@30400000/system-counter-ctrl@306c0000");
if (np)
system_counter_ctrl_base = of_iomap(np, 0);
WARN_ON(!system_counter_ctrl_base);
if (imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_LPDDR3
|| imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
imx7_pm_common_init(&imx7d_pm_data_lpddr3);
else if (imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_DDR3)
imx7_pm_common_init(&imx7d_pm_data_ddr3);
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@30800000/serial@30860000");
if (np)
console_base = of_iomap(np, 0);
/* clear LPSR resume address first */
imx7_pm_set_lpsr_resume_addr(0);
}