ARM: at91: pm: add self-refresh support for sama7g5
authorClaudiu Beznea <claudiu.beznea@microchip.com>
Thu, 15 Apr 2021 10:49:58 +0000 (13:49 +0300)
committerNicolas Ferre <nicolas.ferre@microchip.com>
Mon, 19 Jul 2021 12:32:12 +0000 (14:32 +0200)
Add self-refresh support for SAMA7G5.

Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Link: https://lore.kernel.org/r/20210415105010.569620-13-claudiu.beznea@microchip.com
arch/arm/mach-at91/pm.h
arch/arm/mach-at91/pm_data-offsets.c
arch/arm/mach-at91/pm_suspend.S

index bfb260b..6664740 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mfd/syscon/atmel-mc.h>
 #include <soc/at91/at91sam9_ddrsdr.h>
 #include <soc/at91/at91sam9_sdramc.h>
+#include <soc/at91/sama7-ddr.h>
 
 #define AT91_MEMCTRL_MC                0
 #define AT91_MEMCTRL_SDRAMC    1
@@ -27,6 +28,7 @@
 struct at91_pm_data {
        void __iomem *pmc;
        void __iomem *ramc[2];
+       void __iomem *ramc_phy;
        unsigned long uhp_udp_mask;
        unsigned int memctrl;
        unsigned int mode;
index 82089ff..40bd4e8 100644 (file)
@@ -8,6 +8,8 @@ int main(void)
        DEFINE(PM_DATA_PMC,             offsetof(struct at91_pm_data, pmc));
        DEFINE(PM_DATA_RAMC0,           offsetof(struct at91_pm_data, ramc[0]));
        DEFINE(PM_DATA_RAMC1,           offsetof(struct at91_pm_data, ramc[1]));
+       DEFINE(PM_DATA_RAMC_PHY,        offsetof(struct at91_pm_data,
+                                                ramc_phy));
        DEFINE(PM_DATA_MEMCTRL, offsetof(struct at91_pm_data, memctrl));
        DEFINE(PM_DATA_MODE,            offsetof(struct at91_pm_data, mode));
        DEFINE(PM_DATA_SHDWC,           offsetof(struct at91_pm_data, shdwc));
index 7669b32..8441812 100644 (file)
@@ -87,6 +87,200 @@ tmp3        .req    r6
 
        .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_PWRCTRL_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
+
+       /* Put DDR PHY's DLL in bypass mode for non-backup modes. */
+       cmp     r7, #AT91_PM_BACKUP
+       beq     sr_ena_3
+       ldr     tmp1, [r3, #DDR3PHY_PIR]
+       orr     tmp1, tmp1, #DDR3PHY_PIR_DLLBYP
+       str     tmp1, [r3, #DDR3PHY_PIR]
+
+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, tmp1, #DDR3PHY_ACIORC_ACPDD
+       orr     tmp1, tmp1, #DDR3PHY_ACIOCR_CKPDD_CK0
+       orr     tmp1, tmp1, #DDR3PHY_ACIOCR_CSPDD_CS0
+       str     tmp1, [r3, #DDR3PHY_ACIOCR]
+
+       /* Power down ODT. */
+       ldr     tmp1, [r3, #DDR3PHY_DSGCR]
+       orr     tmp1, tmp1, #DDR3PHY_DSGCR_ODTPDD_ODT0
+       str     tmp1, [r3, #DDR3PHY_DSGCR]
+.endm
+
+/**
+ * Disable self-refresh
+ *
+ * Side effects: overwrites r2, r3, tmp1, tmp2, tmp3
+ */
+.macro at91_sramc_self_refresh_dis
+       ldr     r2, .sramc_base
+       ldr     r3, .sramc_phy_base
+
+       /* Power up DDR PHY data receivers. */
+       ldr     tmp1, [r3, #DDR3PHY_DXCCR]
+       bic     tmp1, tmp1, #DDR3PHY_DXCCR_DXPDR
+       str     tmp1, [r3, #DDR3PHY_DXCCR]
+
+       /* Power up the output of CK and CS pins. */
+       ldr     tmp1, [r3, #DDR3PHY_ACIOCR]
+       bic     tmp1, tmp1, #DDR3PHY_ACIORC_ACPDD
+       bic     tmp1, tmp1, #DDR3PHY_ACIOCR_CKPDD_CK0
+       bic     tmp1, tmp1, #DDR3PHY_ACIOCR_CSPDD_CS0
+       str     tmp1, [r3, #DDR3PHY_ACIOCR]
+
+       /* Power up ODT. */
+       ldr     tmp1, [r3, #DDR3PHY_DSGCR]
+       bic     tmp1, tmp1, #DDR3PHY_DSGCR_ODTPDD_ODT0
+       str     tmp1, [r3, #DDR3PHY_DSGCR]
+
+       /* Take DDR PHY's DLL out of bypass mode. */
+       ldr     tmp1, [r3, #DDR3PHY_PIR]
+       bic     tmp1, tmp1, #DDR3PHY_PIR_DLLBYP
+       str     tmp1, [r3, #DDR3PHY_PIR]
+
+       /* Enable quasi-dynamic programming. */
+       mov     tmp1, #0
+       str     tmp1, [r2, #UDDRC_SWCTRL]
+
+       /* De-assert SDRAM initialization. */
+       ldr     tmp1, [r2, #UDDRC_DFIMISC]
+       bic     tmp1, tmp1, #UDDRC_DFIMISC_DFI_INIT_COMPLETE_EN
+       str     tmp1, [r2, #UDDRC_DFIMISC]
+
+       /* Quasi-dynamic programming done. */
+       mov     tmp1, #UDDRC_SWCTRL_SW_DONE
+       str     tmp1, [r2, #UDDRC_SWCTRL]
+
+sr_dis_1:
+       ldr     tmp1, [r2, #UDDRC_SWSTAT]
+       tst     tmp1, #UDDRC_SWSTAT_SW_DONE_ACK
+       beq     sr_dis_1
+
+       /* DLL soft-reset + DLL lock wait + ITM reset */
+       mov     tmp1, #(DDR3PHY_PIR_INIT | DDR3PHY_PIR_DLLSRST | \
+                       DDR3PHY_PIR_DLLLOCK | DDR3PHY_PIR_ITMSRST)
+       str     tmp1, [r3, #DDR3PHY_PIR]
+
+sr_dis_4:
+       /* Wait for it. */
+       ldr     tmp1, [r3, #DDR3PHY_PGSR]
+       tst     tmp1, #DDR3PHY_PGSR_IDONE
+       beq     sr_dis_4
+
+       /* Enable quasi-dynamic programming. */
+       mov     tmp1, #0
+       str     tmp1, [r2, #UDDRC_SWCTRL]
+
+       /* Assert PHY init complete enable signal. */
+       ldr     tmp1, [r2, #UDDRC_DFIMISC]
+       orr     tmp1, tmp1, #UDDRC_DFIMISC_DFI_INIT_COMPLETE_EN
+       str     tmp1, [r2, #UDDRC_DFIMISC]
+
+       /* Programming is done. Set sw_done. */
+       mov     tmp1, #UDDRC_SWCTRL_SW_DONE
+       str     tmp1, [r2, #UDDRC_SWCTRL]
+
+sr_dis_5:
+       /* Wait for it. */
+       ldr     tmp1, [r2, #UDDRC_SWSTAT]
+       tst     tmp1, #UDDRC_SWSTAT_SW_DONE_ACK
+       beq     sr_dis_5
+
+       /* Trigger self-refresh exit. */
+       ldr     tmp1, [r2, #UDDRC_PWRCTL]
+       bic     tmp1, tmp1, #UDDRC_PWRCTRL_SELFREF_SW
+       str     tmp1, [r2, #UDDRC_PWRCTL]
+
+sr_dis_6:
+       /* Wait for self-refresh exit done. */
+       ldr     tmp1, [r2, #UDDRC_STAT]
+       bic     tmp1, tmp1, #~UDDRC_STAT_OPMODE_MSK
+       cmp     tmp1, #UDDRC_STAT_OPMODE_NORMAL
+       bne     sr_dis_6
+
+       /* Enable all AXI ports. */
+       ldr     tmp1, [r2, #UDDRC_PCTRL_0]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_0]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_1]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_1]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_2]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_2]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_3]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_3]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_4]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_4]
+
+       dsb
+.endm
+#else
 /**
  * Enable self-refresh
  *
@@ -228,6 +422,7 @@ sdramc_exit_sf:
 
 sr_dis_exit:
 .endm
+#endif
 
 .macro at91_pm_ulp0_mode
        ldr     pmc, .pmc_base
@@ -668,6 +863,8 @@ ENTRY(at91_pm_suspend_in_sram)
        str     tmp1, .sramc_base
        ldr     tmp1, [r0, #PM_DATA_RAMC1]
        str     tmp1, .sramc1_base
+       ldr     tmp1, [r0, #PM_DATA_RAMC_PHY]
+       str     tmp1, .sramc_phy_base
        ldr     tmp1, [r0, #PM_DATA_MEMCTRL]
        str     tmp1, .memtype
        ldr     tmp1, [r0, #PM_DATA_MODE]
@@ -721,6 +918,8 @@ ENDPROC(at91_pm_suspend_in_sram)
        .word 0
 .sramc1_base:
        .word 0
+.sramc_phy_base:
+       .word 0
 .shdwc:
        .word 0
 .sfrbu: