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