Hi Marek

On 2/21/22 21:56, Marek Vasut wrote:
> Implement PSCI system suspend and placement of DRAM into SSR while the
> CPUs are in suspend. This saves non-trivial amount of power in suspend,
> on 2x W632GU6NB-15 ~710mW.
> 
> Signed-off-by: Marek Vasut <ma...@denx.de>
> Cc: Patrick Delaunay <patrick.delau...@foss.st.com>
> Cc: Patrice Chotard <patrice.chot...@foss.st.com>
> ---
> V2: - Lowercase all the hex values
>     - Sort bit macros in descending order
>     - Use GENMASK even though it seems to only obfuscate the macros
>     - Rename SYSCFG_CMPCR_MPUEN to SYSCFG_CMPENR_MPUEN
>     - Use ARM CP15 timer in secure_udelay() and secure_waitbits()
>     - Restore DDRC PWRCTL after return from SSR
>     - Call ISB/DSB before WFI
>     - Test on STM32MP157C DK2, saves ~420mW here per USB-C power meter
> ---
>  arch/arm/mach-stm32mp/include/mach/stm32.h |   3 +
>  arch/arm/mach-stm32mp/psci.c               | 527 ++++++++++++++++++++-
>  2 files changed, 519 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h 
> b/arch/arm/mach-stm32mp/include/mach/stm32.h
> index c11a9903f20..47e88fc3dcd 100644
> --- a/arch/arm/mach-stm32mp/include/mach/stm32.h
> +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h
> @@ -16,8 +16,11 @@
>   */
>  #define STM32_RCC_BASE                       0x50000000
>  #define STM32_PWR_BASE                       0x50001000
> +#define STM32_SYSCFG_BASE            0x50020000
>  #define STM32_DBGMCU_BASE            0x50081000
>  #define STM32_FMC2_BASE                      0x58002000
> +#define STM32_DDRCTRL_BASE           0x5A003000
> +#define STM32_DDRPHYC_BASE           0x5A004000
>  #define STM32_TZC_BASE                       0x5C006000
>  #define STM32_ETZPC_BASE             0x5C007000
>  #define STM32_STGEN_BASE             0x5C008000
> diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c
> index 155aa79cd5e..86c160987a9 100644
> --- a/arch/arm/mach-stm32mp/psci.c
> +++ b/arch/arm/mach-stm32mp/psci.c
> @@ -11,19 +11,152 @@
>  #include <asm/io.h>
>  #include <asm/psci.h>
>  #include <asm/secure.h>
> +#include <hang.h>
>  #include <linux/bitops.h>
>  
> -#define BOOT_API_A7_CORE0_MAGIC_NUMBER       0xCA7FACE0
> -#define BOOT_API_A7_CORE1_MAGIC_NUMBER       0xCA7FACE1
> -
> -#define MPIDR_AFF0                   GENMASK(7, 0)
> -
> -#define RCC_MP_GRSTCSETR             (STM32_RCC_BASE + 0x0404)
> -#define RCC_MP_GRSTCSETR_MPUP1RST    BIT(5)
> -#define RCC_MP_GRSTCSETR_MPUP0RST    BIT(4)
> -#define RCC_MP_GRSTCSETR_MPSYSRST    BIT(0)
> -
> -#define STM32MP1_PSCI_NR_CPUS                2
> +/* PWR */
> +#define PWR_CR3                                      0x0c
> +#define PWR_MPUCR                            0x10
> +
> +#define PWR_CR3_DDRSREN                              BIT(10)
> +#define PWR_CR3_DDRRETEN                     BIT(12)
> +
> +#define PWR_MPUCR_PDDS                               BIT(0)
> +#define PWR_MPUCR_CSTDBYDIS                  BIT(3)
> +#define PWR_MPUCR_CSSF                               BIT(9)
> +
> +/* RCC */
> +#define RCC_DDRITFCR                         0xd8
> +
> +#define RCC_DDRITFCR_DDRC1EN                 BIT(0)
> +#define RCC_DDRITFCR_DDRC1LPEN                       BIT(1)
> +#define RCC_DDRITFCR_DDRC2EN                 BIT(2)
> +#define RCC_DDRITFCR_DDRC2LPEN                       BIT(3)
> +#define RCC_DDRITFCR_DDRPHYCEN                       BIT(4)
> +#define RCC_DDRITFCR_DDRPHYCLPEN             BIT(5)
> +#define RCC_DDRITFCR_DDRCAPBEN                       BIT(6)
> +#define RCC_DDRITFCR_DDRCAPBLPEN             BIT(7)
> +#define RCC_DDRITFCR_AXIDCGEN                        BIT(8)
> +#define RCC_DDRITFCR_DDRPHYCAPBEN            BIT(9)
> +#define RCC_DDRITFCR_DDRPHYCAPBLPEN          BIT(10)
> +#define RCC_DDRITFCR_DDRCKMOD_MASK           GENMASK(22, 20)
> +#define RCC_DDRITFCR_GSKPCTRL                        BIT(24)
> +
> +#define RCC_MP_SREQSETR                              0x104
> +#define RCC_MP_SREQCLRR                              0x108
> +
> +#define RCC_MP_CIER                          0x414
> +#define RCC_MP_CIFR                          0x418
> +#define RCC_MP_CIFR_WKUPF                    BIT(20)
> +
> +/* SYSCFG */
> +#define SYSCFG_CMPCR                         0x20
> +#define SYSCFG_CMPCR_SW_CTRL                 BIT(2)
> +#define SYSCFG_CMPENSETR                     0x24
> +#define SYSCFG_CMPENCLRR                     0x28
> +#define SYSCFG_CMPENR_MPUEN                  BIT(0)
> +
> +/* DDR Controller registers offsets */
> +#define DDRCTRL_STAT                         0x004
> +#define DDRCTRL_PWRCTL                               0x030
> +#define DDRCTRL_PWRTMG                               0x034
> +#define DDRCTRL_HWLPCTL                              0x038
> +#define DDRCTRL_DFIMISC                              0x1b0
> +#define DDRCTRL_SWCTL                                0x320
> +#define DDRCTRL_SWSTAT                               0x324
> +#define DDRCTRL_PSTAT                                0x3fc
> +#define DDRCTRL_PCTRL_0                              0x490
> +#define DDRCTRL_PCTRL_1                              0x540
> +
> +/* DDR Controller Register fields */
> +#define DDRCTRL_STAT_OPERATING_MODE_MASK     GENMASK(2, 0)
> +#define DDRCTRL_STAT_OPERATING_MODE_NORMAL   0x1
> +#define DDRCTRL_STAT_OPERATING_MODE_SR               0x3
> +#define DDRCTRL_STAT_SELFREF_TYPE_MASK               GENMASK(5, 4)
> +#define DDRCTRL_STAT_SELFREF_TYPE_ASR                (0x3 << 4)
> +#define DDRCTRL_STAT_SELFREF_TYPE_SR         (0x2 << 4)
> +
> +#define DDRCTRL_PWRCTL_SELFREF_EN            BIT(0)
> +#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE       BIT(3)
> +#define DDRCTRL_PWRCTL_SELFREF_SW            BIT(5)
> +
> +#define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK   GENMASK(23, 16)
> +#define DDRCTRL_PWRTMG_SELFREF_TO_X32_0              BIT(16)
> +
> +#define DDRCTRL_HWLPCTL_HW_LP_EN             BIT(0)
> +
> +#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0)
> +
> +#define DDRCTRL_SWCTL_SW_DONE                        BIT(0)
> +
> +#define DDRCTRL_SWSTAT_SW_DONE_ACK           BIT(0)
> +
> +#define DDRCTRL_PSTAT_RD_PORT_BUSY_0         BIT(0)
> +#define DDRCTRL_PSTAT_RD_PORT_BUSY_1         BIT(1)
> +#define DDRCTRL_PSTAT_WR_PORT_BUSY_0         BIT(16)
> +#define DDRCTRL_PSTAT_WR_PORT_BUSY_1         BIT(17)
> +
> +#define DDRCTRL_PCTRL_N_PORT_EN                      BIT(0)
> +
> +/* DDR PHY registers offsets */
> +#define DDRPHYC_PIR                          0x004
> +#define DDRPHYC_PGSR                         0x00c
> +#define DDRPHYC_ACDLLCR                              0x014
> +#define DDRPHYC_ACIOCR                               0x024
> +#define DDRPHYC_DXCCR                                0x028
> +#define DDRPHYC_DSGCR                                0x02c
> +#define DDRPHYC_ZQ0CR0                               0x180
> +#define DDRPHYC_DX0DLLCR                     0x1cc
> +#define DDRPHYC_DX1DLLCR                     0x20c
> +#define DDRPHYC_DX2DLLCR                     0x24c
> +#define DDRPHYC_DX3DLLCR                     0x28c
> +
> +/* DDR PHY Register fields */
> +#define DDRPHYC_PIR_INIT                     BIT(0)
> +#define DDRPHYC_PIR_DLLSRST                  BIT(1)
> +#define DDRPHYC_PIR_DLLLOCK                  BIT(2)
> +#define DDRPHYC_PIR_ITMSRST                  BIT(4)
> +
> +#define DDRPHYC_PGSR_IDONE                   BIT(0)
> +
> +#define DDRPHYC_ACDLLCR_DLLSRST                      BIT(30)
> +#define DDRPHYC_ACDLLCR_DLLDIS                       BIT(31)
> +
> +#define DDRPHYC_ACIOCR_ACOE                  BIT(1)
> +#define DDRPHYC_ACIOCR_ACPDD                 BIT(3)
> +#define DDRPHYC_ACIOCR_ACPDR                 BIT(4)
> +#define DDRPHYC_ACIOCR_CKPDD_MASK            GENMASK(10, 8)
> +#define DDRPHYC_ACIOCR_CKPDD_0                       BIT(8)
> +#define DDRPHYC_ACIOCR_CKPDR_MASK            GENMASK(13, 11)
> +#define DDRPHYC_ACIOCR_CKPDR_0                       BIT(11)
> +#define DDRPHYC_ACIOCR_CSPDD_MASK            GENMASK(20, 18)
> +#define DDRPHYC_ACIOCR_CSPDD_0                       BIT(18)
> +
> +#define DDRPHYC_DXCCR_DXPDD                  BIT(2)
> +#define DDRPHYC_DXCCR_DXPDR                  BIT(3)
> +
> +#define DDRPHYC_DSGCR_CKEPDD_MASK            GENMASK(19, 16)
> +#define DDRPHYC_DSGCR_CKEPDD_0                       BIT(16)
> +#define DDRPHYC_DSGCR_ODTPDD_MASK            GENMASK(23, 20)
> +#define DDRPHYC_DSGCR_ODTPDD_0                       BIT(20)
> +#define DDRPHYC_DSGCR_NL2PD                  BIT(24)
> +#define DDRPHYC_DSGCR_CKOE                   BIT(28)
> +
> +#define DDRPHYC_ZQ0CRN_ZQPD                  BIT(31)
> +
> +#define DDRPHYC_DXNDLLCR_DLLDIS                      BIT(31)
> +
> +#define BOOT_API_A7_CORE0_MAGIC_NUMBER               0xca7face0
> +#define BOOT_API_A7_CORE1_MAGIC_NUMBER               0xca7face1
> +
> +#define MPIDR_AFF0                           GENMASK(7, 0)
> +
> +#define RCC_MP_GRSTCSETR                     (STM32_RCC_BASE + 0x0404)
> +#define RCC_MP_GRSTCSETR_MPSYSRST            BIT(0)
> +#define RCC_MP_GRSTCSETR_MPUP0RST            BIT(4)
> +#define RCC_MP_GRSTCSETR_MPUP1RST            BIT(5)
> +
> +#define STM32MP1_PSCI_NR_CPUS                        2
>  #if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS
>  #error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS"
>  #endif
> @@ -98,6 +231,7 @@ s32 __secure psci_features(u32 function_id, u32 psci_fid)
>       case ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
>       case ARM_PSCI_0_2_FN_SYSTEM_OFF:
>       case ARM_PSCI_0_2_FN_SYSTEM_RESET:
> +     case ARM_PSCI_1_0_FN_SYSTEM_SUSPEND:
>               return 0x0;
>       }
>       return ARM_PSCI_RET_NI;
> @@ -222,3 +356,374 @@ void __secure psci_system_off(void)
>       while (1)
>               wfi();
>  }
> +
> +static void __secure secure_udelay(unsigned int delay)
> +{
> +     u32 freq = cp15_read_cntfrq() / 1000000;
> +     u64 start, end;
> +
> +     delay *= freq;
> +
> +     asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (start));
> +     for (;;) {
> +             asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (end));
> +             if ((end - start) > delay)
> +                     break;
> +     }
> +}
> +
> +static int __secure secure_waitbits(u32 reg, u32 mask, u32 val)
> +{
> +     u32 freq = cp15_read_cntfrq() / 1000000;
> +     u32 delay = 500 * freq; /* 500 us */
> +     u64 start, end;
> +     u32 tmp;
> +
> +     asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (start));
> +     for (;;) {
> +             tmp = readl(reg);
> +             tmp &= mask;
> +             if ((tmp & val) == val)
> +                     return 0;
> +             asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (end));
> +             if ((end - start) > delay)
> +                     return -ETIMEDOUT;
> +     }
> +}
> +
> +static void __secure ddr_sr_mode_ssr(u32 *saved_pwrctl)
> +{
> +     setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR,
> +                  RCC_DDRITFCR_DDRC1LPEN | RCC_DDRITFCR_DDRC1EN |
> +                  RCC_DDRITFCR_DDRC2LPEN | RCC_DDRITFCR_DDRC2EN |
> +                  RCC_DDRITFCR_DDRCAPBLPEN | RCC_DDRITFCR_DDRPHYCAPBLPEN |
> +                  RCC_DDRITFCR_DDRCAPBEN | RCC_DDRITFCR_DDRPHYCAPBEN |
> +                  RCC_DDRITFCR_DDRPHYCEN);
> +
> +     clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR,
> +                  RCC_DDRITFCR_AXIDCGEN | RCC_DDRITFCR_DDRCKMOD_MASK);
> +
> +     /* Disable HW LP interface of uMCTL2 */
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_HWLPCTL,
> +                  DDRCTRL_HWLPCTL_HW_LP_EN);
> +
> +     /* Configure Automatic LP modes of uMCTL2 */
> +     clrsetbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRTMG,
> +                     DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK,
> +                     DDRCTRL_PWRTMG_SELFREF_TO_X32_0);
> +
> +     /* Save PWRCTL register to restart ASR after suspend (if applicable) */
> +     *saved_pwrctl = readl(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL);
> +
> +     /*
> +      * Disable Clock disable with LP modes
> +      * (used in RUN mode for LPDDR2 with specific timing).
> +      */
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL,
> +                  DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE);
> +
> +     /* Disable automatic Self-Refresh mode */
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL,
> +                  DDRCTRL_PWRCTL_SELFREF_EN);
> +}
> +
> +static void __secure ddr_sr_mode_restore(u32 saved_pwrctl)
> +{
> +     saved_pwrctl &= DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE |
> +                     DDRCTRL_PWRCTL_SELFREF_EN;
> +
> +     /* Restore ASR mode in case it was enabled before suspend. */
> +     setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, saved_pwrctl);
> +}
> +
> +static int __secure ddr_sw_self_refresh_in(void)
> +{
> +     int ret;
> +
> +     clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
> +
> +     /* Blocks AXI ports from taking anymore transactions */
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0,
> +                  DDRCTRL_PCTRL_N_PORT_EN);
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1,
> +                  DDRCTRL_PCTRL_N_PORT_EN);
> +
> +     /*
> +      * Waits unit all AXI ports are idle
> +      * Poll PSTAT.rd_port_busy_n = 0
> +      * Poll PSTAT.wr_port_busy_n = 0
> +      */
> +     ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_PSTAT,
> +                           DDRCTRL_PSTAT_RD_PORT_BUSY_0 |
> +                           DDRCTRL_PSTAT_RD_PORT_BUSY_1 |
> +                           DDRCTRL_PSTAT_WR_PORT_BUSY_0 |
> +                           DDRCTRL_PSTAT_WR_PORT_BUSY_1, 0);
> +     if (ret)
> +             goto pstat_failed;
> +
> +     /* SW Self-Refresh entry */
> +     setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, 
> DDRCTRL_PWRCTL_SELFREF_SW);
> +
> +     /*
> +      * Wait operating mode change in self-refresh mode
> +      * with STAT.operating_mode[1:0]==11.
> +      * Ensure transition to self-refresh was due to software
> +      * by checking also that STAT.selfref_type[1:0]=2.
> +      */
> +     ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_STAT,
> +                           DDRCTRL_STAT_OPERATING_MODE_MASK |
> +                           DDRCTRL_STAT_SELFREF_TYPE_MASK,
> +                           DDRCTRL_STAT_OPERATING_MODE_SR |
> +                           DDRCTRL_STAT_SELFREF_TYPE_SR);
> +     if (ret)
> +             goto selfref_sw_failed;
> +
> +     /* IOs powering down (PUBL registers) */
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD);
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDR);
> +
> +     clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR,
> +                     DDRPHYC_ACIOCR_CKPDD_MASK,
> +                     DDRPHYC_ACIOCR_CKPDD_0);
> +
> +     clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR,
> +                     DDRPHYC_ACIOCR_CKPDR_MASK,
> +                     DDRPHYC_ACIOCR_CKPDR_0);
> +
> +     clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR,
> +                     DDRPHYC_ACIOCR_CSPDD_MASK,
> +                     DDRPHYC_ACIOCR_CSPDD_0);
> +
> +     /* Disable command/address output driver */
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE);
> +
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD);
> +
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR);
> +
> +     clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR,
> +                     DDRPHYC_DSGCR_ODTPDD_MASK,
> +                     DDRPHYC_DSGCR_ODTPDD_0);
> +
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD);
> +
> +     clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR,
> +                     DDRPHYC_DSGCR_CKEPDD_MASK,
> +                     DDRPHYC_DSGCR_CKEPDD_0);
> +
> +     /* Disable PZQ cell (PUBL register) */
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD);
> +
> +     /* Set latch */
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE);
> +
> +     /* Additional delay to avoid early latch */
> +     secure_udelay(10);
> +
> +     /* Activate sw retention in PWRCTRL */
> +     setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRRETEN);
> +
> +     /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */
> +     setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
> +
> +     /* Disable all DLLs: GLITCH window */
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, 
> DDRPHYC_ACDLLCR_DLLDIS);
> +
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX0DLLCR, 
> DDRPHYC_DXNDLLCR_DLLDIS);
> +
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX1DLLCR, 
> DDRPHYC_DXNDLLCR_DLLDIS);
> +
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX2DLLCR, 
> DDRPHYC_DXNDLLCR_DLLDIS);
> +
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX3DLLCR, 
> DDRPHYC_DXNDLLCR_DLLDIS);
> +
> +     /* Switch controller clocks (uMCTL2/PUBL) to DLL output clock */
> +     clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
> +
> +     /* Deactivate all DDR clocks */
> +     clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR,
> +                  RCC_DDRITFCR_DDRC1EN | RCC_DDRITFCR_DDRC2EN |
> +                  RCC_DDRITFCR_DDRCAPBEN | RCC_DDRITFCR_DDRPHYCAPBEN);
> +
> +     return 0;
> +
> +selfref_sw_failed:
> +     /* This bit should be cleared to restore DDR in its previous state */
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL,
> +                  DDRCTRL_PWRCTL_SELFREF_SW);
> +
> +pstat_failed:
> +     setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0,
> +                  DDRCTRL_PCTRL_N_PORT_EN);
> +     setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1,
> +                  DDRCTRL_PCTRL_N_PORT_EN);
> +
> +     return -EINVAL;
> +};
> +
> +static void __secure ddr_sw_self_refresh_exit(void)
> +{
> +     int ret;
> +
> +     /* Enable all clocks */
> +     setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR,
> +                  RCC_DDRITFCR_DDRC1EN | RCC_DDRITFCR_DDRC2EN |
> +                  RCC_DDRITFCR_DDRPHYCEN | RCC_DDRITFCR_DDRPHYCAPBEN |
> +                  RCC_DDRITFCR_DDRCAPBEN);
> +
> +     /* Handshake */
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
> +
> +     /* Mask dfi_init_complete_en */
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_DFIMISC,
> +                  DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
> +
> +     /* Ack */
> +     setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
> +     ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_SWSTAT,
> +                           DDRCTRL_SWSTAT_SW_DONE_ACK,
> +                           DDRCTRL_SWSTAT_SW_DONE_ACK);
> +     if (ret)
> +             hang();
> +
> +     /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */
> +     setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
> +
> +     /* Enable all DLLs: GLITCH window */
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR,
> +                  DDRPHYC_ACDLLCR_DLLDIS);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX0DLLCR, 
> DDRPHYC_DXNDLLCR_DLLDIS);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX1DLLCR, 
> DDRPHYC_DXNDLLCR_DLLDIS);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX2DLLCR, 
> DDRPHYC_DXNDLLCR_DLLDIS);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX3DLLCR, 
> DDRPHYC_DXNDLLCR_DLLDIS);
> +
> +     /* Additional delay to avoid early DLL clock switch */
> +     secure_udelay(50);
> +
> +     /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */
> +     clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, 
> DDRPHYC_ACDLLCR_DLLSRST);
> +
> +     secure_udelay(10);
> +
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, 
> DDRPHYC_ACDLLCR_DLLSRST);
> +
> +     /* PHY partial init: (DLL lock and ITM reset) */
> +     writel(DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK |
> +            DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_INIT,
> +            STM32_DDRPHYC_BASE + DDRPHYC_PIR);
> +
> +     /* Need to wait at least 10 clock cycles before accessing PGSR */
> +     secure_udelay(1);
> +
> +     /* Pool end of init */
> +     ret = secure_waitbits(STM32_DDRPHYC_BASE + DDRPHYC_PGSR,
> +                           DDRPHYC_PGSR_IDONE, DDRPHYC_PGSR_IDONE);
> +     if (ret)
> +             hang();
> +
> +     /* Handshake */
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
> +
> +     /* Unmask dfi_init_complete_en to uMCTL2 */
> +     setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_DFIMISC, 
> DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
> +
> +     /* Ack */
> +     setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
> +     ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_SWSTAT,
> +                           DDRCTRL_SWSTAT_SW_DONE_ACK,
> +                           DDRCTRL_SWSTAT_SW_DONE_ACK);
> +     if (ret)
> +             hang();
> +
> +     /* Deactivate sw retention in PWR */
> +     clrbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRRETEN);
> +
> +     /* Enable PZQ cell (PUBL register) */
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD);
> +
> +     /* Enable pad drivers */
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD);
> +
> +     /* Enable command/address output driver */
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, 
> DDRPHYC_ACIOCR_CKPDD_MASK);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, 
> DDRPHYC_ACIOCR_CSPDD_MASK);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR);
> +
> +     /* Release latch */
> +     setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, 
> DDRPHYC_DSGCR_ODTPDD_MASK);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD);
> +
> +     clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, 
> DDRPHYC_DSGCR_CKEPDD_MASK);
> +
> +     /* Remove selfrefresh */
> +     clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, 
> DDRCTRL_PWRCTL_SELFREF_SW);
> +
> +     /* Wait operating_mode == normal */
> +     ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_STAT,
> +                           DDRCTRL_STAT_OPERATING_MODE_MASK,
> +                           DDRCTRL_STAT_OPERATING_MODE_NORMAL);
> +     if (ret)
> +             hang();
> +
> +     /* AXI ports are no longer blocked from taking transactions */
> +     setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0, 
> DDRCTRL_PCTRL_N_PORT_EN);
> +     setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1, 
> DDRCTRL_PCTRL_N_PORT_EN);
> +
> +     setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
> +}
> +
> +void __secure psci_system_suspend(u32 __always_unused function_id,
> +                               u32 ep, u32 context_id)
> +{
> +     u32 saved_pwrctl, reg;
> +
> +     /* Disable IO compensation */
> +
> +     /* Place current APSRC/ANSRC into RAPSRC/RANSRC */
> +     reg = readl(STM32_SYSCFG_BASE + SYSCFG_CMPCR);
> +     reg >>= 8;
> +     reg &= 0xff << 16;
> +     reg |= SYSCFG_CMPCR_SW_CTRL;
> +     writel(reg, STM32_SYSCFG_BASE + SYSCFG_CMPCR);
> +     writel(SYSCFG_CMPENR_MPUEN, STM32_SYSCFG_BASE + SYSCFG_CMPENCLRR);
> +
> +     writel(RCC_MP_CIFR_WKUPF, STM32_RCC_BASE + RCC_MP_CIFR);
> +     setbits_le32(STM32_RCC_BASE + RCC_MP_CIER, RCC_MP_CIFR_WKUPF);
> +
> +     setbits_le32(STM32_PWR_BASE + PWR_MPUCR,
> +                  PWR_MPUCR_CSSF | PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_PDDS);
> +
> +     psci_v7_flush_dcache_all();
> +     ddr_sr_mode_ssr(&saved_pwrctl);
> +     ddr_sw_self_refresh_in();
> +     setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRSREN);
> +     writel(0x3, STM32_RCC_BASE + RCC_MP_SREQSETR);
> +
> +     /* Zzz, enter stop mode */
> +     asm volatile(
> +             "isb\n"
> +             "dsb\n"
> +             "wfi\n");
> +
> +     writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR);
> +     ddr_sw_self_refresh_exit();
> +     ddr_sr_mode_restore(saved_pwrctl);
> +
> +     writel(SYSCFG_CMPENR_MPUEN, STM32_SYSCFG_BASE + SYSCFG_CMPENSETR);
> +     clrbits_le32(STM32_SYSCFG_BASE + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
> +}
Reviewed-by: Patrice Chotard <patrice.chot...@foss.st.com>

Thanks 
Patrice

Reply via email to