#define DGO_GPR3 0x60
#define DGO_GPR4 0x64
+#define ADDR_1M_MASK 0xFFF00000
+
static void __iomem *smc1_base;
static void __iomem *pmc0_base;
static void __iomem *pmc1_base;
static void __iomem *wdog1_base;
static void __iomem *wdog2_base;
static void __iomem *suspend_ocram_base;
-static void (*imx7ulp_suspend_in_ocram_fn)(void __iomem *sram_vbase);
+static void (*imx7ulp_suspend_in_ocram_fn)(void __iomem *sram_base);
static u32 tpm5_regs[4];
static u32 lpuart4_regs[4];
0x608, 0x60c, 0x610, 0x614,
};
+static u32 ptc1;
+
extern unsigned long iram_tlb_base_addr;
extern unsigned long iram_tlb_phys_addr;
* PM_INFO structure(imx7ulp_cpu_pm_info)
* ======================== low address =======================
*/
-
-struct imx7ulp_pm_base {
- phys_addr_t pbase;
- void __iomem *vbase;
-};
-
struct imx7ulp_pm_socdata {
u32 ddr_type;
const char *mmdc_compat;
phys_addr_t pbase; /* The physical address of pm_info. */
phys_addr_t resume_addr; /* The physical resume address for asm code */
u32 pm_info_size; /* Size of pm_info. */
- struct imx7ulp_pm_base sim_base;
- struct imx7ulp_pm_base scg1_base;
- struct imx7ulp_pm_base mmdc_base;
- struct imx7ulp_pm_base mmdc_io_base;
+ void __iomem *sim_base;
+ void __iomem *scg1_base;
+ void __iomem *mmdc_base;
+ void __iomem *gpio_base;
+ void __iomem *mmdc_io_base;
+ void __iomem *smc1_base;
u32 scg1[16];
u32 ttbr1; /* Store TTBR1 */
u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */
} __aligned(8);
static struct imx7ulp_cpu_pm_info *pm_info;
+static void __iomem *aips1_base;
+static void __iomem *aips2_base;
+static void __iomem *aips3_base;
+static void __iomem *aips4_base;
+static void __iomem *aips5_base;
static const char * const low_power_ocram_match[] __initconst = {
"fsl,lpm-sram",
NULL
};
-static struct map_desc imx7ulp_pm_io_desc[] __initdata = {
- imx_map_entry(MX7ULP, AIPS1, MT_DEVICE),
- imx_map_entry(MX7ULP, AIPS2, MT_DEVICE),
- imx_map_entry(MX7ULP, AIPS3, MT_DEVICE),
-};
-
static void imx7ulp_scg1_save(void)
{
int i;
writel_relaxed(pcc2_regs[i][1], pcc2_base + pcc2_regs[i][0]);
}
+static inline void imx7ulp_iomuxc_save(void)
+{
+ ptc1 = readl_relaxed(iomuxc1_base + 0x4);
+}
+
+static inline void imx7ulp_iomuxc_restore(void)
+{
+ writel_relaxed(ptc1, iomuxc1_base + 0x4);
+}
+
static void imx7ulp_lpuart_save(void)
{
lpuart4_regs[0] = readl_relaxed(lpuart4_base + LPUART_BAUD);
static void imx7ulp_set_dgo(u32 val)
{
- writel_relaxed(val, pm_info->sim_base.vbase + DGO_GPR3);
- writel_relaxed(val, pm_info->sim_base.vbase + DGO_GPR4);
+ writel_relaxed(val, pm_info->sim_base + DGO_GPR3);
+ writel_relaxed(val, pm_info->sim_base + DGO_GPR4);
}
int imx7ulp_set_lpm(enum imx7ulp_cpu_pwr_mode mode)
imx7ulp_pcc3_save();
imx7ulp_tpm_save();
imx7ulp_lpuart_save();
+ imx7ulp_iomuxc_save();
imx7ulp_set_lpm(VLLS);
/* Zzz ... */
cpu_suspend(0, imx7ulp_suspend_finish);
+ imx7ulp_disable_wdog();
imx7ulp_pcc2_restore();
imx7ulp_pcc3_restore();
imx7ulp_lpuart_restore();
- imx7ulp_disable_wdog();
imx7ulp_set_dgo(0);
imx7ulp_tpm_restore();
+ imx7ulp_iomuxc_restore();
imx7ulp_set_lpm(RUN);
break;
default:
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_io_desc.virtual =
+ IMX_IO_P2V(lpram_addr & ADDR_1M_MASK);
+ iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & ADDR_1M_MASK);
iram_tlb_phys_addr = lpram_addr;
iram_tlb_base_addr = IMX_IO_P2V(lpram_addr);
iotable_init(&iram_tlb_io_desc, 1);
void __init imx7ulp_pm_map_io(void)
{
- unsigned long i, j;
-
- iotable_init(imx7ulp_pm_io_desc, ARRAY_SIZE(imx7ulp_pm_io_desc));
/*
* Get the address of IRAM or OCRAM to be used by the low
* power code from the device tree.
/* Set all entries to 0 except first 3 words reserved for M4. */
memset((void *)iram_tlb_base_addr, 0, MX7ULP_IRAM_TLB_SIZE);
+}
+
+void __init imx7ulp_pm_common_init(const struct imx7ulp_pm_socdata
+ *socdata)
+{
+ struct device_node *np;
+ unsigned long sram_paddr;
+ const u32 *mmdc_offset_array;
+ const u32 *mmdc_io_offset_array;
+ unsigned long i, j;
+ int ret;
/*
* Make sure the IRAM virtual address has a mapping in the IRAM
*/
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;
-
+ (iram_tlb_phys_addr & ADDR_1M_MASK) |
+ TT_ATTRIB_NON_CACHEABLE_1M;
/*
* Make sure the AIPS1 virtual address has a mapping in the
* IRAM page table.
*/
- j = ((IMX_IO_P2V(MX7ULP_AIPS1_BASE_ADDR) >> 20) << 2) / 4;
+ aips1_base = ioremap(MX7ULP_AIPS1_BASE_ADDR, SZ_1M);
+ j = (((u32)aips1_base >> 20) << 2) / 4;
*((unsigned long *)iram_tlb_base_addr + j) =
- ((MX7ULP_AIPS1_BASE_ADDR) & 0xFFF00000) |
+ ((MX7ULP_AIPS1_BASE_ADDR) & ADDR_1M_MASK) |
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(MX7ULP_AIPS2_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4;
- *((unsigned long *)iram_tlb_base_addr + j) =
- ((MX7ULP_AIPS2_BASE_ADDR + i * 0x100000) & 0xFFF00000) |
- TT_ATTRIB_NON_CACHEABLE_1M;
- }
+ aips2_base = ioremap(MX7ULP_AIPS2_BASE_ADDR, SZ_1M);
+ j = (((u32)aips2_base >> 20) << 2) / 4;
+ *((unsigned long *)iram_tlb_base_addr + j) =
+ ((MX7ULP_AIPS2_BASE_ADDR) & ADDR_1M_MASK) |
+ TT_ATTRIB_NON_CACHEABLE_1M;
/*
* Make sure the AIPS3 virtual address has a mapping in the
* IRAM page table.
*/
- j = ((IMX_IO_P2V(MX7ULP_AIPS3_BASE_ADDR) >> 20) << 2) / 4;
+ aips3_base = ioremap(MX7ULP_AIPS3_BASE_ADDR, SZ_1M);
+ j = (((u32)aips3_base >> 20) << 2) / 4;
*((unsigned long *)iram_tlb_base_addr + j) =
- ((MX7ULP_AIPS3_BASE_ADDR) & 0xFFF00000) |
+ ((MX7ULP_AIPS3_BASE_ADDR) & ADDR_1M_MASK) |
+ TT_ATTRIB_NON_CACHEABLE_1M;
+ /*
+ * Make sure the AIPS4 virtual address has a mapping in the
+ * IRAM page table.
+ */
+ aips4_base = ioremap(MX7ULP_AIPS4_BASE_ADDR, SZ_1M);
+ j = (((u32)aips4_base >> 20) << 2) / 4;
+ *((unsigned long *)iram_tlb_base_addr + j) =
+ ((MX7ULP_AIPS4_BASE_ADDR) & ADDR_1M_MASK) |
+ TT_ATTRIB_NON_CACHEABLE_1M;
+ /*
+ * Make sure the AIPS5 virtual address has a mapping in the
+ * IRAM page table.
+ */
+ aips5_base = ioremap(MX7ULP_AIPS5_BASE_ADDR, SZ_1M);
+ j = (((u32)aips5_base >> 20) << 2) / 4;
+ *((unsigned long *)iram_tlb_base_addr + j) =
+ ((MX7ULP_AIPS5_BASE_ADDR) & ADDR_1M_MASK) |
TT_ATTRIB_NON_CACHEABLE_1M;
-}
-
-void __init imx7ulp_pm_common_init(const struct imx7ulp_pm_socdata
- *socdata)
-{
- struct device_node *np;
- unsigned long sram_paddr;
- const u32 *mmdc_offset_array;
- const u32 *mmdc_io_offset_array;
- int i, ret;
np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-smc1");
smc1_base = of_iomap(np, 0);
pm_info->resume_addr = virt_to_phys(imx7ulp_cpu_resume);
pm_info->pm_info_size = sizeof(*pm_info);
- pm_info->sim_base.pbase = MX7ULP_SIM_BASE_ADDR;
- pm_info->sim_base.vbase = (void __iomem *)
- IMX_IO_P2V(MX7ULP_SIM_BASE_ADDR);
-
- pm_info->scg1_base.pbase = MX7ULP_SCG1_BASE_ADDR;
- pm_info->scg1_base.vbase = (void __iomem *)
- IMX_IO_P2V(MX7ULP_SCG1_BASE_ADDR);
-
- pm_info->mmdc_base.pbase = MX7ULP_MMDC_BASE_ADDR;
- pm_info->mmdc_base.vbase = (void __iomem *)
- IMX_IO_P2V(MX7ULP_MMDC_BASE_ADDR);
-
- pm_info->mmdc_io_base.pbase = MX7ULP_MMDC_IO_BASE_ADDR;
- pm_info->mmdc_io_base.vbase = (void __iomem *)
- IMX_IO_P2V(MX7ULP_MMDC_IO_BASE_ADDR);
+ pm_info->gpio_base = aips1_base +
+ (MX7ULP_GPIOC_BASE_ADDR & ~ADDR_1M_MASK);
+ pm_info->scg1_base = aips2_base +
+ (MX7ULP_SCG1_BASE_ADDR & ~ADDR_1M_MASK);
+ pm_info->smc1_base = aips3_base +
+ (MX7ULP_SMC1_BASE_ADDR & ~ADDR_1M_MASK);
+ pm_info->mmdc_base = aips4_base +
+ (MX7ULP_MMDC_BASE_ADDR & ~ADDR_1M_MASK);
+ pm_info->mmdc_io_base = aips4_base +
+ (MX7ULP_MMDC_IO_BASE_ADDR & ~ADDR_1M_MASK);
+ pm_info->sim_base = aips5_base +
+ (MX7ULP_SIM_BASE_ADDR & ~ADDR_1M_MASK);
pm_info->mmdc_io_num = socdata->mmdc_io_num;
mmdc_io_offset_array = socdata->mmdc_io_offset;
pm_info->mmdc_io_val[i][0] =
mmdc_io_offset_array[i];
pm_info->mmdc_io_val[i][1] =
- readl_relaxed(pm_info->mmdc_io_base.vbase +
+ readl_relaxed(pm_info->mmdc_io_base +
mmdc_io_offset_array[i]);
}
#define PM_INFO_PBASE_OFFSET 0xc
#define PM_INFO_RESUME_ADDR_OFFSET 0x10
#define PM_INFO_PM_INFO_SIZE_OFFSET 0x14
-#define PM_INFO_PM_INFO_SIM_PBASE_OFFSET 0x18
-#define PM_INFO_PM_INFO_SIM_VBASE_OFFSET 0x1c
-#define PM_INFO_PM_INFO_SCG1_PBASE_OFFSET 0x20
-#define PM_INFO_PM_INFO_SCG1_VBASE_OFFSET 0x24
-#define PM_INFO_PM_INFO_MMDC_PBASE_OFFSET 0x28
-#define PM_INFO_PM_INFO_MMDC_VBASE_OFFSET 0x2c
-#define PM_INFO_PM_INFO_MMDC_IO_PBASE_OFFSET 0x30
-#define PM_INFO_PM_INFO_MMDC_IO_VBASE_OFFSET 0x34
-#define PM_INFO_PM_INFO_SCG1_VAL_OFFSET 0x38
-#define PM_INFO_MX7ULP_TTBR1_V_OFFSET 0x78
-#define PM_INFO_MMDC_IO_NUM_OFFSET 0x7c
-#define PM_INFO_MMDC_IO_VAL_OFFSET 0x80
+#define PM_INFO_PM_INFO_SIM_VBASE_OFFSET 0x18
+#define PM_INFO_PM_INFO_SCG1_VBASE_OFFSET 0x1c
+#define PM_INFO_PM_INFO_MMDC_VBASE_OFFSET 0x20
+#define PM_INFO_PM_INFO_GPIOC_VBASE_OFFSET 0x24
+#define PM_INFO_PM_INFO_MMDC_IO_VBASE_OFFSET 0x28
+#define PM_INFO_PM_INFO_SMC1_VBASE_OFFSET 0x2c
+#define PM_INFO_PM_INFO_SCG1_VAL_OFFSET 0x30
+#define PM_INFO_MX7ULP_TTBR1_V_OFFSET 0x70
+#define PM_INFO_MMDC_IO_NUM_OFFSET 0x74
+#define PM_INFO_MMDC_IO_VAL_OFFSET 0x78
/* below offsets depends on MX7ULP_MAX_MMDC_IO_NUM(36) definition */
-#define PM_INFO_MMDC_NUM_OFFSET 0x1a0
-#define PM_INFO_MMDC_VAL_OFFSET 0x1a4
+#define PM_INFO_MMDC_NUM_OFFSET 0x198
+#define PM_INFO_MMDC_VAL_OFFSET 0x19c
#define DGO_GPR3 0x60
#define DGO_GPR4 0x64
#define PMC1_CTRL 0x24
+#define GPIO_PDOR 0x0
+#define GPIO_PDDR 0x14
+
+#define PMCTRL 0x10
+
.align 3
.macro store_ttbr1
.macro restore_mmdc_settings
- ldr r10, [r0, #PM_INFO_PM_INFO_MMDC_IO_PBASE_OFFSET]
- ldr r11, [r0, #PM_INFO_PM_INFO_MMDC_PBASE_OFFSET]
+ ldr r10, =MX7ULP_MMDC_IO_BASE_ADDR
+ ldr r11, =MX7ULP_MMDC_BASE_ADDR
/* resume mmdc iomuxc settings */
ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
ands r7, r7, #(1 << 24)
beq poll_dvfs_set
+ ldr r10, [r0, #PM_INFO_PM_INFO_SMC1_VBASE_OFFSET]
+ ldr r7, [r10, #PMCTRL]
+ and r7, r7, #0x7
+ cmp r7, #0x4
+ bne wfi
+
+ /* turn off NVCC_DRAM_SW - PTC1 */
+ ldr r10, [r0, #PM_INFO_PM_INFO_GPIOC_VBASE_OFFSET]
+ ldr r7, [r10, #GPIO_PDDR]
+ orr r7, #(1 << 1)
+ str r7, [r10, #GPIO_PDDR]
+ ldr r7, [r10, #GPIO_PDOR]
+ orr r7, #(1 << 1)
+ str r7, [r10, #GPIO_PDOR]
+
+wfi:
/* Zzz, enter stop mode */
wfi
nop
nop
nop
+ ldr r10, [r0, #PM_INFO_PM_INFO_SMC1_VBASE_OFFSET]
+ ldr r7, [r10, #PMCTRL]
+ and r7, r7, #0x7
+ cmp r7, #0x4
+ bne skip_gpio
+
+ /* turn on NVCC_DRAM_SW - PTC1 */
+ ldr r10, [r0, #PM_INFO_PM_INFO_GPIOC_VBASE_OFFSET]
+ ldr r7, [r10, #GPIO_PDOR]
+ bic r7, #(1 << 1)
+ str r7, [r10, #GPIO_PDOR]
+
+ /* gpioc needs 400us to ramp up, here use ~800us */
+ ldr r7, =50000
+wait_gpio_up_vlps:
+ subs r7, #0x1
+ bne wait_gpio_up_vlps
+
+skip_gpio:
/* clear core0's entry and parameter */
ldr r10, [r0, #PM_INFO_PM_INFO_SIM_VBASE_OFFSET]
mov r7, #0x0
/* enable mmdc clock in pcc3 */
ldr r11, =MX7ULP_PCC3_BASE_ADDR
ldr r7, [r11, #0xac]
- orr r7, r7, #0x40000000
+ orr r7, r7, #(1 << 30)
str r7, [r11, #0xac]
- restore_mmdc_settings
+ /* enable GPIO clock in pcc2 */
+ ldr r11, =MX7ULP_PCC2_BASE_ADDR
+ ldr r7, [r11, #0x3c]
+ orr r7, r7, #(1 << 30)
+ str r7, [r11, #0x3c]
+
+ /* enable PTC1 IOMUXC */
+ ldr r11, =MX7ULP_IOMUXC1_BASE_ADDR
+ ldr r7, =0x20100
+ str r7, [r11, #0x4]
+
+ /* output PTC1 to 0 */
+ ldr r11, =MX7ULP_GPIOC_BASE_ADDR
+ ldr r7, [r11, #GPIO_PDDR]
+ orr r7, #(1 << 1)
+ str r7, [r11, #GPIO_PDDR]
+ ldr r7, [r11, #GPIO_PDOR]
+ bic r7, #(1 << 1)
+ str r7, [r11, #GPIO_PDOR]
+
+ /* gpioc needs 400us to ramp up, here use ~800us */
+ ldr r7, =50000
+wait_gpio_up_vlls:
+ subs r7, #0x1
+ bne wait_gpio_up_vlls
+ restore_mmdc_settings
mov pc, lr
ENDPROC(imx7ulp_suspend)