cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

suspend-imx6.S (7911B)


      1/* SPDX-License-Identifier: GPL-2.0-or-later */
      2/*
      3 * Copyright 2014 Freescale Semiconductor, Inc.
      4 */
      5
      6#include <linux/linkage.h>
      7#include <asm/assembler.h>
      8#include <asm/asm-offsets.h>
      9#include <asm/hardware/cache-l2x0.h>
     10#include "hardware.h"
     11
     12/*
     13 * ==================== low level suspend ====================
     14 *
     15 * Better to follow below rules to use ARM registers:
     16 * r0: pm_info structure address;
     17 * r1 ~ r4: for saving pm_info members;
     18 * r5 ~ r10: free registers;
     19 * r11: io base address.
     20 *
     21 * suspend ocram space layout:
     22 * ======================== high address ======================
     23 *                              .
     24 *                              .
     25 *                              .
     26 *                              ^
     27 *                              ^
     28 *                              ^
     29 *                      imx6_suspend code
     30 *              PM_INFO structure(imx6_cpu_pm_info)
     31 * ======================== low address =======================
     32 */
     33
     34/*
     35 * Below offsets are based on struct imx6_cpu_pm_info
     36 * which defined in arch/arm/mach-imx/pm-imx6q.c, this
     37 * structure contains necessary pm info for low level
     38 * suspend related code.
     39 */
     40#define PM_INFO_PBASE_OFFSET			0x0
     41#define PM_INFO_RESUME_ADDR_OFFSET		0x4
     42#define PM_INFO_DDR_TYPE_OFFSET			0x8
     43#define PM_INFO_PM_INFO_SIZE_OFFSET		0xC
     44#define PM_INFO_MX6Q_MMDC_P_OFFSET		0x10
     45#define PM_INFO_MX6Q_MMDC_V_OFFSET		0x14
     46#define PM_INFO_MX6Q_SRC_P_OFFSET		0x18
     47#define PM_INFO_MX6Q_SRC_V_OFFSET		0x1C
     48#define PM_INFO_MX6Q_IOMUXC_P_OFFSET		0x20
     49#define PM_INFO_MX6Q_IOMUXC_V_OFFSET		0x24
     50#define PM_INFO_MX6Q_CCM_P_OFFSET		0x28
     51#define PM_INFO_MX6Q_CCM_V_OFFSET		0x2C
     52#define PM_INFO_MX6Q_GPC_P_OFFSET		0x30
     53#define PM_INFO_MX6Q_GPC_V_OFFSET		0x34
     54#define PM_INFO_MX6Q_L2_P_OFFSET		0x38
     55#define PM_INFO_MX6Q_L2_V_OFFSET		0x3C
     56#define PM_INFO_MMDC_IO_NUM_OFFSET		0x40
     57#define PM_INFO_MMDC_IO_VAL_OFFSET		0x44
     58
     59#define MX6Q_SRC_GPR1	0x20
     60#define MX6Q_SRC_GPR2	0x24
     61#define MX6Q_MMDC_MAPSR	0x404
     62#define MX6Q_MMDC_MPDGCTRL0	0x83c
     63#define MX6Q_GPC_IMR1	0x08
     64#define MX6Q_GPC_IMR2	0x0c
     65#define MX6Q_GPC_IMR3	0x10
     66#define MX6Q_GPC_IMR4	0x14
     67#define MX6Q_CCM_CCR	0x0
     68
     69	.align 3
     70	.arm
     71
     72	.macro  sync_l2_cache
     73
     74	/* sync L2 cache to drain L2's buffers to DRAM. */
     75#ifdef CONFIG_CACHE_L2X0
     76	ldr	r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
     77	teq	r11, #0
     78	beq	6f
     79	mov	r6, #0x0
     80	str	r6, [r11, #L2X0_CACHE_SYNC]
     811:
     82	ldr	r6, [r11, #L2X0_CACHE_SYNC]
     83	ands	r6, r6, #0x1
     84	bne	1b
     856:
     86#endif
     87
     88	.endm
     89
     90	.macro	resume_mmdc
     91
     92	/* restore MMDC IO */
     93	cmp	r5, #0x0
     94	ldreq	r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
     95	ldrne	r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
     96
     97	ldr	r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
     98	ldr	r7, =PM_INFO_MMDC_IO_VAL_OFFSET
     99	add	r7, r7, r0
    1001:
    101	ldr	r8, [r7], #0x4
    102	ldr	r9, [r7], #0x4
    103	str	r9, [r11, r8]
    104	subs	r6, r6, #0x1
    105	bne	1b
    106
    107	cmp	r5, #0x0
    108	ldreq	r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
    109	ldrne	r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
    110
    111	cmp	r3, #IMX_DDR_TYPE_LPDDR2
    112	bne	4f
    113
    114	/* reset read FIFO, RST_RD_FIFO */
    115	ldr	r7, =MX6Q_MMDC_MPDGCTRL0
    116	ldr	r6, [r11, r7]
    117	orr     r6, r6, #(1 << 31)
    118	str	r6, [r11, r7]
    1192:
    120	ldr	r6, [r11, r7]
    121	ands	r6, r6, #(1 << 31)
    122	bne	2b
    123
    124	/* reset FIFO a second time */
    125	ldr	r6, [r11, r7]
    126	orr     r6, r6, #(1 << 31)
    127	str	r6, [r11, r7]
    1283:
    129	ldr	r6, [r11, r7]
    130	ands	r6, r6, #(1 << 31)
    131	bne	3b
    1324:
    133	/* let DDR out of self-refresh */
    134	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
    135	bic	r7, r7, #(1 << 21)
    136	str	r7, [r11, #MX6Q_MMDC_MAPSR]
    1375:
    138	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
    139	ands	r7, r7, #(1 << 25)
    140	bne	5b
    141
    142	/* enable DDR auto power saving */
    143	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
    144	bic	r7, r7, #0x1
    145	str	r7, [r11, #MX6Q_MMDC_MAPSR]
    146
    147	.endm
    148
    149ENTRY(imx6_suspend)
    150	ldr	r1, [r0, #PM_INFO_PBASE_OFFSET]
    151	ldr	r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
    152	ldr	r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
    153	ldr	r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
    154
    155	/*
    156	 * counting the resume address in iram
    157	 * to set it in SRC register.
    158	 */
    159	ldr	r6, =imx6_suspend
    160	ldr	r7, =resume
    161	sub	r7, r7, r6
    162	add	r8, r1, r4
    163	add	r9, r8, r7
    164
    165	/*
    166	 * make sure TLB contain the addr we want,
    167	 * as we will access them after MMDC IO floated.
    168	 */
    169
    170	ldr	r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
    171	ldr	r6, [r11, #0x0]
    172	ldr	r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
    173	ldr	r6, [r11, #0x0]
    174	ldr	r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
    175	ldr	r6, [r11, #0x0]
    176
    177	/* use r11 to store the IO address */
    178	ldr	r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]
    179	/* store physical resume addr and pm_info address. */
    180	str	r9, [r11, #MX6Q_SRC_GPR1]
    181	str	r1, [r11, #MX6Q_SRC_GPR2]
    182
    183	/* need to sync L2 cache before DSM. */
    184	sync_l2_cache
    185
    186	ldr	r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
    187	/*
    188	 * put DDR explicitly into self-refresh and
    189	 * disable automatic power savings.
    190	 */
    191	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
    192	orr	r7, r7, #0x1
    193	str	r7, [r11, #MX6Q_MMDC_MAPSR]
    194
    195	/* make the DDR explicitly enter self-refresh. */
    196	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
    197	orr	r7, r7, #(1 << 21)
    198	str	r7, [r11, #MX6Q_MMDC_MAPSR]
    199
    200poll_dvfs_set:
    201	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
    202	ands	r7, r7, #(1 << 25)
    203	beq	poll_dvfs_set
    204
    205	ldr	r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
    206	ldr	r6, =0x0
    207	ldr	r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
    208	ldr	r8, =PM_INFO_MMDC_IO_VAL_OFFSET
    209	add	r8, r8, r0
    210	/* LPDDR2's last 3 IOs need special setting */
    211	cmp	r3, #IMX_DDR_TYPE_LPDDR2
    212	subeq	r7, r7, #0x3
    213set_mmdc_io_lpm:
    214	ldr	r9, [r8], #0x8
    215	str	r6, [r11, r9]
    216	subs	r7, r7, #0x1
    217	bne	set_mmdc_io_lpm
    218
    219	cmp 	r3, #IMX_DDR_TYPE_LPDDR2
    220	bne	set_mmdc_io_lpm_done
    221	ldr	r6, =0x1000
    222	ldr	r9, [r8], #0x8
    223	str	r6, [r11, r9]
    224	ldr	r9, [r8], #0x8
    225	str	r6, [r11, r9]
    226	ldr	r6, =0x80000
    227	ldr	r9, [r8]
    228	str	r6, [r11, r9]
    229set_mmdc_io_lpm_done:
    230
    231	/*
    232	 * mask all GPC interrupts before
    233	 * enabling the RBC counters to
    234	 * avoid the counter starting too
    235	 * early if an interupt is already
    236	 * pending.
    237	 */
    238	ldr	r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
    239	ldr	r6, [r11, #MX6Q_GPC_IMR1]
    240	ldr	r7, [r11, #MX6Q_GPC_IMR2]
    241	ldr	r8, [r11, #MX6Q_GPC_IMR3]
    242	ldr	r9, [r11, #MX6Q_GPC_IMR4]
    243
    244	ldr	r10, =0xffffffff
    245	str	r10, [r11, #MX6Q_GPC_IMR1]
    246	str	r10, [r11, #MX6Q_GPC_IMR2]
    247	str	r10, [r11, #MX6Q_GPC_IMR3]
    248	str	r10, [r11, #MX6Q_GPC_IMR4]
    249
    250	/*
    251	 * enable the RBC bypass counter here
    252	 * to hold off the interrupts. RBC counter
    253	 * = 32 (1ms), Minimum RBC delay should be
    254	 * 400us for the analog LDOs to power down.
    255	 */
    256	ldr	r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
    257	ldr	r10, [r11, #MX6Q_CCM_CCR]
    258	bic	r10, r10, #(0x3f << 21)
    259	orr	r10, r10, #(0x20 << 21)
    260	str	r10, [r11, #MX6Q_CCM_CCR]
    261
    262	/* enable the counter. */
    263	ldr	r10, [r11, #MX6Q_CCM_CCR]
    264	orr	r10, r10, #(0x1 << 27)
    265	str	r10, [r11, #MX6Q_CCM_CCR]
    266
    267	/* unmask all the GPC interrupts. */
    268	ldr	r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
    269	str	r6, [r11, #MX6Q_GPC_IMR1]
    270	str	r7, [r11, #MX6Q_GPC_IMR2]
    271	str	r8, [r11, #MX6Q_GPC_IMR3]
    272	str	r9, [r11, #MX6Q_GPC_IMR4]
    273
    274	/*
    275	 * now delay for a short while (3usec)
    276	 * ARM is at 1GHz at this point
    277	 * so a short loop should be enough.
    278	 * this delay is required to ensure that
    279	 * the RBC counter can start counting in
    280	 * case an interrupt is already pending
    281	 * or in case an interrupt arrives just
    282	 * as ARM is about to assert DSM_request.
    283	 */
    284	ldr	r6, =2000
    285rbc_loop:
    286	subs	r6, r6, #0x1
    287	bne	rbc_loop
    288
    289	/* Zzz, enter stop mode */
    290	wfi
    291	nop
    292	nop
    293	nop
    294	nop
    295
    296	/*
    297	 * run to here means there is pending
    298	 * wakeup source, system should auto
    299	 * resume, we need to restore MMDC IO first
    300	 */
    301	mov	r5, #0x0
    302	resume_mmdc
    303
    304	/* return to suspend finish */
    305	ret	lr
    306
    307resume:
    308	/* invalidate L1 I-cache first */
    309	mov     r6, #0x0
    310	mcr     p15, 0, r6, c7, c5, 0
    311	mcr     p15, 0, r6, c7, c5, 6
    312	/* enable the Icache and branch prediction */
    313	mov     r6, #0x1800
    314	mcr     p15, 0, r6, c1, c0, 0
    315	isb
    316
    317	/* get physical resume address from pm_info. */
    318	ldr	lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
    319	/* clear core0's entry and parameter */
    320	ldr	r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET]
    321	mov	r7, #0x0
    322	str	r7, [r11, #MX6Q_SRC_GPR1]
    323	str	r7, [r11, #MX6Q_SRC_GPR2]
    324
    325	ldr	r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
    326	mov	r5, #0x1
    327	resume_mmdc
    328
    329	ret	lr
    330ENDPROC(imx6_suspend)