/* SPDX-License-Identifier: GPL-2.0-only */
/*
* arch/arm/mach-at91/pm_slow_clock.S
*
* Copyright (C) 2006 Savin Zlobec
*
* AT91SAM9 support:
* Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee>
*/
#include <linux/linkage.h>
#include <linux/clk/at91_pmc.h>
#include "pm.h"
#include "pm_data-offsets.h"
#ifdef CONFIG_CPU_V7
.arch armv7-a
#endif
#define SRAMC_SELF_FRESH_ACTIVE 0x01
#define SRAMC_SELF_FRESH_EXIT 0x00
pmc .req r0
tmp1 .req r4
tmp2 .req r5
tmp3 .req r6
/*
* Wait until master clock is ready (after switching master clock source)
*
* @r_mckid: register holding master clock identifier
*
* Side effects: overwrites r7, r8
*/
.macro wait_mckrdy r_mckid
#ifdef CONFIG_SOC_SAMA7
cmp \r_mckid, #0
beq 1f
mov r7, #AT91_PMC_MCKXRDY
b 2f
#endif
1: mov r7, #AT91_PMC_MCKRDY
2: ldr r8, [pmc, #AT91_PMC_SR]
and r8, r7
cmp r8, r7
bne 2b
.endm
/*
* Wait until master oscillator has stabilized.
*
* Side effects: overwrites r7
*/
.macro wait_moscrdy
1: ldr r7, [pmc, #AT91_PMC_SR]
tst r7, #AT91_PMC_MOSCS
beq 1b
.endm
/*
* Wait for main oscillator selection is done
*
* Side effects: overwrites r7
*/
.macro wait_moscsels
1: ldr r7, [pmc, #AT91_PMC_SR]
tst r7, #AT91_PMC_MOSCSELS
beq 1b
.endm
/*
* Put the processor to enter the idle state
*
* Side effects: overwrites r7
*/
.macro at91_cpu_idle
#if defined(CONFIG_CPU_V7)
mov r7, #AT91_PMC_PCK
str r7, [pmc, #AT91_PMC_SCDR]
dsb
wfi @ Wait For Interrupt
#else
mcr p15, 0, tmp1, c7, c0, 4
#endif
.endm
/**
* Set state for 2.5V low power regulator
* @ena: 0 - disable regulator
* 1 - enable regulator
*
* Side effects: overwrites r7, r8, r9, r10
*/
.macro at91_2_5V_reg_set_low_power ena
#ifdef CONFIG_SOC_SAMA7
ldr r7, .sfrbu
mov r8, #\ena
ldr r9, [r7, #AT91_SFRBU_25LDOCR]
orr r9, r9, #AT91_SFRBU_25LDOCR_LP
cmp r8, #1
beq lp_done_\ena
bic r9, r9, #AT91_SFRBU_25LDOCR_LP
lp_done_\ena:
ldr r10, =AT91_SFRBU_25LDOCR_LDOANAKEY
orr r9, r9, r10
str r9, [r7, #AT91_SFRBU_25LDOCR]
#endif
.endm
.macro at91_backup_set_lpm reg
#ifdef CONFIG_SOC_SAMA7
orr \reg, \reg, #0x200000
#endif
.endm
.text
.arm
#ifdef CONFIG_SOC_SAMA7
/**
* Enable self-refresh
*
* Side effects: overwrites r2, r3, tmp1, tmp2, tmp3, r7
*/
.macro at91_sramc_self_refresh_ena
ldr r2, .sramc_base
ldr r3, .sramc_phy_base
ldr r7, .pm_mode
dsb
/* Disable all AXI ports. */
ldr tmp1, [r2, #UDDRC_PCTRL_0]
bic tmp1, tmp1, #0x1
str tmp1, [r2, #UDDRC_PCTRL_0]
ldr tmp1, [r2, #UDDRC_PCTRL_1]
bic tmp1, tmp1, #0x1
str tmp1, [r2, #UDDRC_PCTRL_1]
ldr tmp1, [r2, #UDDRC_PCTRL_2]
bic tmp1, tmp1, #0x1
str tmp1, [r2, #UDDRC_PCTRL_2]
ldr tmp1, [r2, #UDDRC_PCTRL_3]
bic tmp1, tmp1, #0x1
str tmp1, [r2, #UDDRC_PCTRL_3]
ldr tmp1, [r2, #UDDRC_PCTRL_4]
bic tmp1, tmp1, #0x1
str tmp1, [r2, #UDDRC_PCTRL_4]
sr_ena_1:
/* Wait for all ports to disable. */
ldr tmp1, [r2, #UDDRC_PSTAT]
ldr tmp2, =UDDRC_PSTAT_ALL_PORTS
tst tmp1, tmp2
bne sr_ena_1
/* Switch to self-refresh. */
ldr tmp1, [r2, #UDDRC_PWRCTL]
orr tmp1, tmp1, #UDDRC_PWRCTL_SELFREF_SW
str tmp1, [r2, #UDDRC_PWRCTL]
sr_ena_2:
/* Wait for self-refresh enter. */
ldr tmp1, [r2, #UDDRC_STAT]
bic tmp1, tmp1, #~UDDRC_STAT_SELFREF_TYPE_MSK
cmp tmp1, #UDDRC_STAT_SELFREF_TYPE_SW
bne sr_ena_2
/* Disable DX DLLs for non-backup modes. */
cmp r7, #AT91_PM_BACKUP
beq sr_ena_3
/* Do not soft reset the AC DLL. */
ldr tmp1, [r3, DDR3PHY_ACDLLCR]
bic tmp1, tmp1, DDR3PHY_ACDLLCR_DLLSRST
str tmp1, [r3, DDR3PHY_ACDLLCR]
/* Disable DX DLLs. */
ldr tmp1, [r3, #DDR3PHY_DX0DLLCR]
orr tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
str tmp1, [r3, #DDR3PHY_DX0DLLCR]
ldr tmp1, [r3, #DDR3PHY_DX1DLLCR]
orr tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
str tmp1, [r3, #DDR3PHY_DX1DLLCR]
sr_ena_3:
/* Power down DDR PHY data receivers. */
ldr tmp1, [r3, #DDR3PHY_DXCCR]
orr tmp1, tmp1, #DDR3PHY_DXCCR_DXPDR
str tmp1, [r3, #DDR3PHY_DXCCR]
/* Power down ADDR/CMD IO. */
ldr tmp1, [r3, #DDR3PHY_ACIOCR]
orr tmp1,