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