xref: /optee_os/core/drivers/atmel_shdwc_a32.S (revision 58200af7b323cb4f89ca930649ec1bef72a1964e)
1*58200af7SClément Léger/* SPDX-License-Identifier: BSD-2-Clause */
2*58200af7SClément Léger/*
3*58200af7SClément Léger * Copyright (c) 2015 Atmel Corporation,
4*58200af7SClément Léger *                    Nicolas Ferre <nicolas.ferre@atmel.com>
5*58200af7SClément Léger * Copyright (c) 2021, Microchip
6*58200af7SClément Léger */
7*58200af7SClément Léger
8*58200af7SClément Léger
9*58200af7SClément Léger#include <arm.h>
10*58200af7SClément Léger#include <arm32_macros.S>
11*58200af7SClément Léger#include <asm.S>
12*58200af7SClément Léger#include <drivers/atmel_shdwc.h>
13*58200af7SClément Léger#include <drivers/sam/at91_ddr.h>
14*58200af7SClément Léger
15*58200af7SClément Léger#include "at91_pmc.h"
16*58200af7SClément Léger
17*58200af7SClément Léger/*
18*58200af7SClément Léger * Code size of shutdown assembly must fit in a single Cortex-A5 cache
19*58200af7SClément Léger * line which is 8 words long (32 bytes) since SDRAM might be disabled and thus
20*58200af7SClément Léger * not accessible to fetch code or data from it.
21*58200af7SClément Léger */
22*58200af7SClément Léger.macro check_fit_in_cacheline since
23*58200af7SClément Léger	.if (. - \since) > 32
24*58200af7SClément Léger		.error "Shutdown assembly code exceeds cache line size"
25*58200af7SClément Léger	.endif
26*58200af7SClément Léger.endm
27*58200af7SClément Léger
28*58200af7SClément Léger/**
29*58200af7SClément Léger * Shutdown the CPU
30*58200af7SClément Léger *
31*58200af7SClément Léger * This function is in assembly to be sure the code fits in a single cache line.
32*58200af7SClément Léger * We are going to power down the SDRAM and thus we can't fetch code from it
33*58200af7SClément Léger * once powered down.
34*58200af7SClément Léger *
35*58200af7SClément Léger * r0 = mpddrc_base
36*58200af7SClément Léger * r1 = shdwc_base
37*58200af7SClément Léger * r2 = pmc_base
38*58200af7SClément Léger */
39*58200af7SClément LégerFUNC __atmel_shdwc_shutdown , :
40*58200af7SClément Léger
41*58200af7SClément Léger	mov_imm r3, AT91_DDRSDRC_LPDDR2_PWOFF
42*58200af7SClément Léger	mov_imm r4, (AT91_SHDW_KEY | AT91_SHDW_SHDW)
43*58200af7SClément Léger
44*58200af7SClément Léger	/*
45*58200af7SClément Léger	 * Read values from both shutdown controller and PMC to ensure the
46*58200af7SClément Léger	 * translations will be in the TLB.
47*58200af7SClément Léger	 */
48*58200af7SClément Léger	ldr	r6, [r1, #AT91_SHDW_CR]
49*58200af7SClément Léger	ldr	r6, [r2, #AT91_PMC_MCKR]
50*58200af7SClément Léger
51*58200af7SClément Léger	/* Power down SDRAM0 if mpddrc_base is set */
52*58200af7SClément Léger	tst	r0, #0
53*58200af7SClément Léger	beq	1f
54*58200af7SClément Léger
55*58200af7SClément Léger/* Align to cache line to ensure the rest of code fits in a single line */
56*58200af7SClément Léger.balign 32
57*58200af7SClément Léger__atmel_shdwc_shutdown_sdram_disabled:
58*58200af7SClément Léger	str	r3, [r0, #AT91_DDRSDRC_LPR]
59*58200af7SClément Léger
60*58200af7SClément Léger	/* Switch the master clock source to slow clock. */
61*58200af7SClément Léger1:
62*58200af7SClément Léger	ldr	r6, [r2, #AT91_PMC_MCKR]
63*58200af7SClément Léger	bic	r6, r6, #AT91_PMC_CSS
64*58200af7SClément Léger	str	r6, [r2, #AT91_PMC_MCKR]
65*58200af7SClément Léger
66*58200af7SClément Léger	/* Wait for clock switch. */
67*58200af7SClément Léger2:
68*58200af7SClément Léger	ldr	r6, [r2, #AT91_PMC_SR]
69*58200af7SClément Léger	tst	r6, #AT91_PMC_MCKRDY
70*58200af7SClément Léger	beq	2b
71*58200af7SClément Léger
72*58200af7SClément Léger	/* Shutdown CPU */
73*58200af7SClément Léger	str	r4, [r1, #AT91_SHDW_CR]
74*58200af7SClément Léger
75*58200af7SClément Léger	check_fit_in_cacheline __atmel_shdwc_shutdown_sdram_disabled
76*58200af7SClément Léger
77*58200af7SClément Léger	/* We should never reach this since we shut down the CPU */
78*58200af7SClément Léger	b	.
79*58200af7SClément LégerEND_FUNC __atmel_shdwc_shutdown
80