ARM: at91: PM: add cpu idle support for sama7g5
authorClaudiu Beznea <claudiu.beznea@microchip.com>
Thu, 13 Jan 2022 14:48:54 +0000 (16:48 +0200)
committerNicolas Ferre <nicolas.ferre@microchip.com>
Fri, 25 Feb 2022 11:36:25 +0000 (12:36 +0100)
Add CPU idle support for SAMA7G5. Support will make use of PMC_CPU_RATIO
register to divide the CPU clock by 16 before switching it to idle and
use automatic self-refresh option of DDR controller.

Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Acked-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Link: https://lore.kernel.org/r/20220113144900.906370-5-claudiu.beznea@microchip.com
arch/arm/mach-at91/pm.c
include/linux/clk/at91_pmc.h
include/soc/at91/sama7-ddr.h

index dd6f4ce3f7660979868a72b7ad961b84fef1b6d7..0fd609e26615a42dbbd8926c2b86a7df8bd27c03 100644 (file)
@@ -605,6 +605,30 @@ static void at91sam9_sdram_standby(void)
                at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
 }
 
+static void sama7g5_standby(void)
+{
+       int pwrtmg, ratio;
+
+       pwrtmg = readl(soc_pm.data.ramc[0] + UDDRC_PWRCTL);
+       ratio = readl(soc_pm.data.pmc + AT91_PMC_RATIO);
+
+       /*
+        * Place RAM into self-refresh after a maximum idle clocks. The maximum
+        * idle clocks is configured by bootloader in
+        * UDDRC_PWRMGT.SELFREF_TO_X32.
+        */
+       writel(pwrtmg | UDDRC_PWRCTL_SELFREF_EN,
+              soc_pm.data.ramc[0] + UDDRC_PWRCTL);
+       /* Divide CPU clock by 16. */
+       writel(ratio & ~AT91_PMC_RATIO_RATIO, soc_pm.data.pmc + AT91_PMC_RATIO);
+
+       cpu_do_idle();
+
+       /* Restore previous configuration. */
+       writel(ratio, soc_pm.data.pmc + AT91_PMC_RATIO);
+       writel(pwrtmg, soc_pm.data.ramc[0] + UDDRC_PWRCTL);
+}
+
 struct ramc_info {
        void (*idle)(void);
        unsigned int memctrl;
@@ -615,6 +639,7 @@ static const struct ramc_info ramc_infos[] __initconst = {
        { .idle = at91sam9_sdram_standby, .memctrl = AT91_MEMCTRL_SDRAMC},
        { .idle = at91_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
        { .idle = sama5d3_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
+       { .idle = sama7g5_standby, },
 };
 
 static const struct of_device_id ramc_ids[] __initconst = {
@@ -622,7 +647,7 @@ static const struct of_device_id ramc_ids[] __initconst = {
        { .compatible = "atmel,at91sam9260-sdramc", .data = &ramc_infos[1] },
        { .compatible = "atmel,at91sam9g45-ddramc", .data = &ramc_infos[2] },
        { .compatible = "atmel,sama5d3-ddramc", .data = &ramc_infos[3] },
-       { .compatible = "microchip,sama7g5-uddrc", },
+       { .compatible = "microchip,sama7g5-uddrc", .data = &ramc_infos[4], },
        { /*sentinel*/ }
 };
 
index ccb3f034bfa93c0a5c2d4bdd6faea0042248141f..3484309b59bf1855244b97d7b89863fe4539d273 100644 (file)
 #define                AT91_PMC_MAINRDY        (1      << 16)          /* Main Clock Ready */
 
 #define        AT91_CKGR_PLLAR         0x28                    /* PLL A Register */
+
+#define        AT91_PMC_RATIO          0x2c                    /* Processor clock ratio register [SAMA7G5 only] */
+#define                AT91_PMC_RATIO_RATIO    (0xf)           /* CPU clock ratio. */
+
 #define        AT91_CKGR_PLLBR         0x2c                    /* PLL B Register */
 #define                AT91_PMC_DIV            (0xff  <<  0)           /* Divider */
 #define                AT91_PMC_PLLCOUNT       (0x3f  <<  8)           /* PLL Counter */
index fee1b11bddcaa54d9ffee770998831dc7ffed614..9e17247474fa92db82521d76f8a73c57d254de78 100644 (file)
@@ -53,6 +53,7 @@
 #define                UDDRC_STAT_OPMODE_MSK           (0x7 << 0)      /* Operating mode mask */
 
 #define UDDRC_PWRCTL                           (0x30)          /* UDDRC Low Power Control Register */
+#define                UDDRC_PWRCTL_SELFREF_EN         (1 << 0)        /* Automatic self-refresh */
 #define                UDDRC_PWRCTL_SELFREF_SW         (1 << 5)        /* Software self-refresh */
 
 #define UDDRC_DFIMISC                          (0x1B0)         /* UDDRC DFI Miscellaneous Control Register */