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