diff options
author | Claudiu Beznea <claudiu.beznea@microchip.com> | 2022-01-13 17:48:54 +0300 |
---|---|---|
committer | Nicolas Ferre <nicolas.ferre@microchip.com> | 2022-02-25 14:36:25 +0300 |
commit | 9584e7263e9ebcd94b184dc3efc847355a624220 (patch) | |
tree | 9c1c07f2a65d6329d072f7fcfe0965b865f282d6 | |
parent | 9a0775c9cd3d89d1fe957a137131681a33f5736b (diff) | |
download | linux-9584e7263e9ebcd94b184dc3efc847355a624220.tar.xz |
ARM: at91: PM: add cpu idle support for sama7g5
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
-rw-r--r-- | arch/arm/mach-at91/pm.c | 27 | ||||
-rw-r--r-- | include/linux/clk/at91_pmc.h | 4 | ||||
-rw-r--r-- | include/soc/at91/sama7-ddr.h | 1 |
3 files changed, 31 insertions, 1 deletions
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index dd6f4ce3f766..0fd609e26615 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -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*/ } }; diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index ccb3f034bfa9..3484309b59bf 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -78,6 +78,10 @@ #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 */ diff --git a/include/soc/at91/sama7-ddr.h b/include/soc/at91/sama7-ddr.h index fee1b11bddca..9e17247474fa 100644 --- a/include/soc/at91/sama7-ddr.h +++ b/include/soc/at91/sama7-ddr.h @@ -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 */ |