From ec03f18cc222bb7bec074ce7845c157d1c5195f6 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 19 Jul 2021 11:03:17 +0300 Subject: [PATCH 01/26] clk: at91: add register definition for sama7g5's master clock Add register definitions for SAMA7G5's master clock. These would be also used by architecture specific power saving code. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210719080317.1045832-3-claudiu.beznea@microchip.com --- include/linux/clk/at91_pmc.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index a4f82e836a7c..ccb3f034bfa9 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -137,6 +137,32 @@ #define AT91_PMC_PLLADIV2_ON (1 << 12) #define AT91_PMC_H32MXDIV BIT(24) +#define AT91_PMC_MCR_V2 0x30 /* Master Clock Register [SAMA7G5 only] */ +#define AT91_PMC_MCR_V2_ID_MSK (0xF) +#define AT91_PMC_MCR_V2_ID(_id) ((_id) & AT91_PMC_MCR_V2_ID_MSK) +#define AT91_PMC_MCR_V2_CMD (1 << 7) +#define AT91_PMC_MCR_V2_DIV (7 << 8) +#define AT91_PMC_MCR_V2_DIV1 (0 << 8) +#define AT91_PMC_MCR_V2_DIV2 (1 << 8) +#define AT91_PMC_MCR_V2_DIV4 (2 << 8) +#define AT91_PMC_MCR_V2_DIV8 (3 << 8) +#define AT91_PMC_MCR_V2_DIV16 (4 << 8) +#define AT91_PMC_MCR_V2_DIV32 (5 << 8) +#define AT91_PMC_MCR_V2_DIV64 (6 << 8) +#define AT91_PMC_MCR_V2_DIV3 (7 << 8) +#define AT91_PMC_MCR_V2_CSS (0x1F << 16) +#define AT91_PMC_MCR_V2_CSS_MD_SLCK (0 << 16) +#define AT91_PMC_MCR_V2_CSS_TD_SLCK (1 << 16) +#define AT91_PMC_MCR_V2_CSS_MAINCK (2 << 16) +#define AT91_PMC_MCR_V2_CSS_MCK0 (3 << 16) +#define AT91_PMC_MCR_V2_CSS_SYSPLL (5 << 16) +#define AT91_PMC_MCR_V2_CSS_DDRPLL (6 << 16) +#define AT91_PMC_MCR_V2_CSS_IMGPLL (7 << 16) +#define AT91_PMC_MCR_V2_CSS_BAUDPLL (8 << 16) +#define AT91_PMC_MCR_V2_CSS_AUDIOPLL (9 << 16) +#define AT91_PMC_MCR_V2_CSS_ETHPLL (10 << 16) +#define AT91_PMC_MCR_V2_EN (1 << 28) + #define AT91_PMC_XTALF 0x34 /* Main XTAL Frequency Register [SAMA7G5 only] */ #define AT91_PMC_USB 0x38 /* USB Clock Register [some SAM9 only] */ From 56bc29659182a9d4b58d8364420f5a9c59d709e8 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Fri, 9 Apr 2021 14:31:15 +0300 Subject: [PATCH 02/26] ARM: at91: add new SoC sama7g5 Add new SoC from at91 family : sama7g5 Signed-off-by: Eugen Hristev [claudiu.beznea@microchip.com: Select PLL, generic clock and UTMI support, add PM configs] Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210409113116.482199-1-eugen.hristev@microchip.com Link: https://lore.kernel.org/r/20210719080317.1045832-2-claudiu.beznea@microchip.com --- arch/arm/mach-at91/Kconfig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index ccd7e80ce943..b09bb2279f7f 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -57,6 +57,16 @@ config SOC_SAMA5D4 help Select this if you are using one of Microchip's SAMA5D4 family SoC. +config SOC_SAMA7G5 + bool "SAMA7G5 family" + depends on ARCH_MULTI_V7 + select HAVE_AT91_GENERATED_CLK + select HAVE_AT91_SAM9X60_PLL + select HAVE_AT91_UTMI + select SOC_SAMA7 + help + Select this if you are using one of Microchip's SAMA7G5 family SoC. + config SOC_AT91RM9200 bool "AT91RM9200" depends on ARCH_MULTI_V4T @@ -191,4 +201,12 @@ config SOC_SAMA5 config ATMEL_PM bool +config SOC_SAMA7 + bool + select ARM_GIC + select ATMEL_PM if PM + select ATMEL_SDRAMC + select MEMORY + select SOC_SAM_V7 + select SRAM if PM endif From 577cb67ad98b2b76985336ae204c145228362e2a Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Fri, 9 Apr 2021 14:31:16 +0300 Subject: [PATCH 03/26] ARM: at91: debug: add sama7g5 low level debug uart Add sama7g5 SoC debug uart on Flexcom3. This is the UART that the ROM bootloader uses. Signed-off-by: Eugen Hristev Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210409113116.482199-2-eugen.hristev@microchip.com --- arch/arm/Kconfig.debug | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 1c4384db223d..98436702e0c7 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -193,6 +193,14 @@ choice their output to the USART1 port on SAMV7 based machines. + config DEBUG_AT91_SAMA7G5_FLEXCOM3 + bool "Kernel low-level debugging on SAMA7G5 FLEXCOM3" + select DEBUG_AT91_UART + depends on SOC_SAMA7G5 + help + Say Y here if you want kernel low-level debugging support + on the FLEXCOM3 port of SAMA7G5. + config DEBUG_BCM2835 bool "Kernel low-level debugging on BCM2835 PL011 UART" depends on ARCH_BCM2835 && ARCH_MULTI_V6 @@ -1668,6 +1676,7 @@ config DEBUG_UART_PHYS default 0xd4017000 if DEBUG_MMP_UART2 default 0xd4018000 if DEBUG_MMP_UART3 default 0xe0000000 if DEBUG_SPEAR13XX + default 0xe1824200 if DEBUG_AT91_SAMA7G5_FLEXCOM3 default 0xe4007000 if DEBUG_HIP04_UART default 0xe6c40000 if DEBUG_RMOBILE_SCIFA0 default 0xe6c50000 if DEBUG_RMOBILE_SCIFA1 @@ -1729,6 +1738,7 @@ config DEBUG_UART_VIRT default 0xc8821000 if DEBUG_RV1108_UART1 default 0xc8912000 if DEBUG_RV1108_UART0 default 0xe0010fe0 if ARCH_RPC + default 0xe0824200 if DEBUG_AT91_SAMA7G5_FLEXCOM3 default 0xf0010000 if DEBUG_ASM9260_UART default 0xf0100000 if DEBUG_DIGICOLOR_UA0 default 0xf01fb000 if DEBUG_NOMADIK_UART From f19dd1df9e71da7e76b2c43cf640507be24bca72 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:47 +0300 Subject: [PATCH 04/26] ARM: at91: pm: move pm_bu to soc_pm data structure Move pm_bu to soc_pm data structure. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-2-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 90dcdfe3b3d0..e13ceef7ac9a 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -27,10 +27,25 @@ #include "generic.h" #include "pm.h" +/** + * struct at91_pm_bu - AT91 power management backup unit data structure + * @suspended: true if suspended to backup mode + * @reserved: reserved + * @canary: canary data for memory checking after exit from backup mode + * @resume: resume API + */ +struct at91_pm_bu { + int suspended; + unsigned long reserved; + phys_addr_t canary; + phys_addr_t resume; +}; + struct at91_soc_pm { int (*config_shdwc_ws)(void __iomem *shdwc, u32 *mode, u32 *polarity); int (*config_pmc_ws)(void __iomem *pmc, u32 mode, u32 polarity); const struct of_device_id *ws_ids; + struct at91_pm_bu *bu; struct at91_pm_data data; }; @@ -71,13 +86,6 @@ static int at91_pm_valid_state(suspend_state_t state) static int canary = 0xA5A5A5A5; -static struct at91_pm_bu { - int suspended; - unsigned long reserved; - phys_addr_t canary; - phys_addr_t resume; -} *pm_bu; - struct wakeup_source_info { unsigned int pmc_fsmr_bit; unsigned int shdwc_mr_bit; @@ -288,7 +296,7 @@ static int at91_suspend_finish(unsigned long val) static void at91_pm_suspend(suspend_state_t state) { if (soc_pm.data.mode == AT91_PM_BACKUP) { - pm_bu->suspended = 1; + soc_pm.bu->suspended = 1; cpu_suspend(0, at91_suspend_finish); @@ -657,16 +665,16 @@ static int __init at91_pm_backup_init(void) goto securam_fail; } - pm_bu = (void *)gen_pool_alloc(sram_pool, sizeof(struct at91_pm_bu)); - if (!pm_bu) { + soc_pm.bu = (void *)gen_pool_alloc(sram_pool, sizeof(struct at91_pm_bu)); + if (!soc_pm.bu) { pr_warn("%s: unable to alloc securam!\n", __func__); ret = -ENOMEM; goto securam_fail; } - pm_bu->suspended = 0; - pm_bu->canary = __pa_symbol(&canary); - pm_bu->resume = __pa_symbol(cpu_resume); + soc_pm.bu->suspended = 0; + soc_pm.bu->canary = __pa_symbol(&canary); + soc_pm.bu->resume = __pa_symbol(cpu_resume); return 0; From fe4c09e56852ceb4f4e07ba42e1750b4f5188d76 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:48 +0300 Subject: [PATCH 05/26] ARM: at91: pm: move the setup of soc_pm.bu->suspended Move the setup of soc_pm.bu->suspended in platform_suspend::begin function so that the PMC code in charge with clocks suspend/resume to differentiate b/w standard PM mode and backup mode. Signed-off-by: Claudiu Beznea Reviewed-by: Alexandre Belloni Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-3-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index e13ceef7ac9a..3742a1fb76db 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -214,6 +214,8 @@ static int at91_sam9x60_config_pmc_ws(void __iomem *pmc, u32 mode, u32 polarity) */ static int at91_pm_begin(suspend_state_t state) { + int ret; + switch (state) { case PM_SUSPEND_MEM: soc_pm.data.mode = soc_pm.data.suspend_mode; @@ -227,7 +229,16 @@ static int at91_pm_begin(suspend_state_t state) soc_pm.data.mode = -1; } - return at91_pm_config_ws(soc_pm.data.mode, true); + ret = at91_pm_config_ws(soc_pm.data.mode, true); + if (ret) + return ret; + + if (soc_pm.data.mode == AT91_PM_BACKUP) + soc_pm.bu->suspended = 1; + else if (soc_pm.bu) + soc_pm.bu->suspended = 0; + + return 0; } /* @@ -296,8 +307,6 @@ static int at91_suspend_finish(unsigned long val) static void at91_pm_suspend(suspend_state_t state) { if (soc_pm.data.mode == AT91_PM_BACKUP) { - soc_pm.bu->suspended = 1; - cpu_suspend(0, at91_suspend_finish); /* The SRAM is lost between suspend cycles */ From 0a7a2443c7a41ae06f0c2a1387072e07d1338d1d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:49 +0300 Subject: [PATCH 06/26] ARM: at91: pm: document at91_soc_pm structure Document at91_soc_pm structure. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-4-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 3742a1fb76db..3029351ec78e 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -41,6 +41,14 @@ struct at91_pm_bu { phys_addr_t resume; }; +/** + * struct at91_soc_pm - AT91 SoC power management data structure + * @config_shdwc_ws: wakeup sources configuration function for SHDWC + * @config_pmc_ws: wakeup srouces configuration function for PMC + * @ws_ids: wakup sources of_device_id array + * @data: PM data to be used on last phase of suspend + * @bu: backup unit mapped data (for backup mode) + */ struct at91_soc_pm { int (*config_shdwc_ws)(void __iomem *shdwc, u32 *mode, u32 *polarity); int (*config_pmc_ws)(void __iomem *pmc, u32 mode, u32 polarity); From 404956f47c3c6fe300dfc9458ea9c3248d174850 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:50 +0300 Subject: [PATCH 07/26] ARM: at91: pm: check for different controllers in at91_pm_modes_init() at91_pm_modes_init() checks for proper nodes in device tree and maps them accordingly. Up to SAMA7G5 all AT91 SoCs had the same mapping b/w power saving modes and different controllers needed in the final/first steps of suspend/resume. SAMA7G5 is not aligned with the old SoCs thus the code is adapted for this. This patch prepares the field for next commits. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-5-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 147 +++++++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 54 deletions(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 3029351ec78e..5a6ce1d88971 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -57,6 +57,18 @@ struct at91_soc_pm { struct at91_pm_data data; }; +/** + * enum at91_pm_iomaps: IOs that needs to be mapped for different PM modes + * @AT91_PM_IOMAP_SHDWC: SHDWC controller + * @AT91_PM_IOMAP_SFRBU: SFRBU controller + */ +enum at91_pm_iomaps { + AT91_PM_IOMAP_SHDWC, + AT91_PM_IOMAP_SFRBU, +}; + +#define AT91_PM_IOMAP(name) BIT(AT91_PM_IOMAP_##name) + static struct at91_soc_pm soc_pm = { .data = { .standby_mode = AT91_PM_STANDBY, @@ -656,24 +668,15 @@ static int __init at91_pm_backup_init(void) if (!at91_is_pm_mode_active(AT91_PM_BACKUP)) return 0; - np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-sfrbu"); - if (!np) { - pr_warn("%s: failed to find sfrbu!\n", __func__); - return ret; - } - - soc_pm.data.sfrbu = of_iomap(np, 0); - of_node_put(np); - np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-securam"); if (!np) - goto securam_fail_no_ref_dev; + return ret; pdev = of_find_device_by_node(np); of_node_put(np); if (!pdev) { pr_warn("%s: failed to find securam device!\n", __func__); - goto securam_fail_no_ref_dev; + return ret; } sram_pool = gen_pool_get(&pdev->dev, NULL); @@ -697,64 +700,92 @@ static int __init at91_pm_backup_init(void) securam_fail: put_device(&pdev->dev); -securam_fail_no_ref_dev: - iounmap(soc_pm.data.sfrbu); - soc_pm.data.sfrbu = NULL; return ret; } -static void __init at91_pm_use_default_mode(int pm_mode) -{ - if (pm_mode != AT91_PM_ULP1 && pm_mode != AT91_PM_BACKUP) - return; - - if (soc_pm.data.standby_mode == pm_mode) - soc_pm.data.standby_mode = AT91_PM_ULP0; - if (soc_pm.data.suspend_mode == pm_mode) - soc_pm.data.suspend_mode = AT91_PM_ULP0; -} - static const struct of_device_id atmel_shdwc_ids[] = { { .compatible = "atmel,sama5d2-shdwc" }, { .compatible = "microchip,sam9x60-shdwc" }, { /* sentinel. */ } }; -static void __init at91_pm_modes_init(void) +static void __init at91_pm_modes_init(const u32 *maps, int len) { struct device_node *np; - int ret; - - if (!at91_is_pm_mode_active(AT91_PM_BACKUP) && - !at91_is_pm_mode_active(AT91_PM_ULP1)) - return; - - np = of_find_matching_node(NULL, atmel_shdwc_ids); - if (!np) { - pr_warn("%s: failed to find shdwc!\n", __func__); - goto ulp1_default; - } - - soc_pm.data.shdwc = of_iomap(np, 0); - of_node_put(np); + int ret, mode; ret = at91_pm_backup_init(); if (ret) { - if (!at91_is_pm_mode_active(AT91_PM_ULP1)) - goto unmap; - else - goto backup_default; + if (soc_pm.data.standby_mode == AT91_PM_BACKUP) + soc_pm.data.standby_mode = AT91_PM_ULP0; + if (soc_pm.data.suspend_mode == AT91_PM_BACKUP) + soc_pm.data.suspend_mode = AT91_PM_ULP0; + } + + if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SHDWC) || + maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SHDWC)) { + np = of_find_matching_node(NULL, atmel_shdwc_ids); + if (!np) { + pr_warn("%s: failed to find shdwc!\n", __func__); + + /* Use ULP0 if it doesn't needs SHDWC.*/ + if (!(maps[AT91_PM_ULP0] & AT91_PM_IOMAP(SHDWC))) + mode = AT91_PM_ULP0; + else + mode = AT91_PM_STANDBY; + + if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SHDWC)) + soc_pm.data.standby_mode = mode; + if (maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SHDWC)) + soc_pm.data.suspend_mode = mode; + } else { + soc_pm.data.shdwc = of_iomap(np, 0); + of_node_put(np); + } + } + + if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SFRBU) || + maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SFRBU)) { + np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-sfrbu"); + if (!np) { + pr_warn("%s: failed to find sfrbu!\n", __func__); + + /* + * Use ULP0 if it doesn't need SHDWC or if SHDWC + * was already located. + */ + if (!(maps[AT91_PM_ULP0] & AT91_PM_IOMAP(SHDWC)) || + soc_pm.data.shdwc) + mode = AT91_PM_ULP0; + else + mode = AT91_PM_STANDBY; + + if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SFRBU)) + soc_pm.data.standby_mode = mode; + if (maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SFRBU)) + soc_pm.data.suspend_mode = mode; + } else { + soc_pm.data.sfrbu = of_iomap(np, 0); + of_node_put(np); + } + } + + /* Unmap all unnecessary. */ + if (soc_pm.data.shdwc && + !(maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SHDWC) || + maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SHDWC))) { + iounmap(soc_pm.data.shdwc); + soc_pm.data.shdwc = NULL; + } + + if (soc_pm.data.sfrbu && + !(maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SFRBU) || + maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SFRBU))) { + iounmap(soc_pm.data.sfrbu); + soc_pm.data.sfrbu = NULL; } return; - -unmap: - iounmap(soc_pm.data.shdwc); - soc_pm.data.shdwc = NULL; -ulp1_default: - at91_pm_use_default_mode(AT91_PM_ULP1); -backup_default: - at91_pm_use_default_mode(AT91_PM_BACKUP); } struct pmc_info { @@ -917,12 +948,15 @@ void __init sam9x60_pm_init(void) static const int modes[] __initconst = { AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1, }; + static const int iomaps[] __initconst = { + [AT91_PM_ULP1] = AT91_PM_IOMAP(SHDWC), + }; if (!IS_ENABLED(CONFIG_SOC_SAM9X60)) return; at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); - at91_pm_modes_init(); + at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps)); at91_dt_ramc(); at91_pm_init(NULL); @@ -967,12 +1001,17 @@ void __init sama5d2_pm_init(void) AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1, AT91_PM_BACKUP, }; + static const u32 iomaps[] __initconst = { + [AT91_PM_ULP1] = AT91_PM_IOMAP(SHDWC), + [AT91_PM_BACKUP] = AT91_PM_IOMAP(SHDWC) | + AT91_PM_IOMAP(SFRBU), + }; if (!IS_ENABLED(CONFIG_SOC_SAMA5D2)) return; at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); - at91_pm_modes_init(); + at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps)); at91_dt_ramc(); at91_pm_init(NULL); From 629ba8ee03a5b0536d53f0e67092e3dba884a576 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:51 +0300 Subject: [PATCH 08/26] ARM: at91: pm: do not initialize pdev There is no need to initialize pdev. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-6-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 5a6ce1d88971..65e13769cf50 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -659,7 +659,7 @@ static int __init at91_pm_backup_init(void) { struct gen_pool *sram_pool; struct device_node *np; - struct platform_device *pdev = NULL; + struct platform_device *pdev; int ret = -ENODEV; if (!IS_ENABLED(CONFIG_SOC_SAMA5D2)) From 29cdf077a9ef238e608eb1243cdcc9e47592ad02 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:52 +0300 Subject: [PATCH 09/26] ARM: at91: pm: use r7 instead of tmp1 Use r7 instead of tmp1 in macros. This prepares the filed for next commits. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-7-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm_suspend.S | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index b683c2caa40b..3d20c9880fee 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -31,30 +31,36 @@ tmp3 .req r6 /* * Wait until master oscillator has stabilized. + * + * Side effects: overwrites r7 */ .macro wait_moscrdy -1: ldr tmp1, [pmc, #AT91_PMC_SR] - tst tmp1, #AT91_PMC_MOSCS +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 tmp1, [pmc, #AT91_PMC_SR] - tst tmp1, #AT91_PMC_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 tmp1, #AT91_PMC_PCK - str tmp1, [pmc, #AT91_PMC_SCDR] + mov r7, #AT91_PMC_PCK + str r7, [pmc, #AT91_PMC_SCDR] dsb From 87e1b30c29b9ae41cfbf6cda42f970b529bfcfb9 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:53 +0300 Subject: [PATCH 10/26] ARM: at91: pm: avoid push and pop on stack while memory is in self-refersh For the previous AT91 RAM controller and self-refresh procedure this had no side effects. However, for SAMA7G5 the self-refresh procedure doesn't allow this anymore as the RAM controller ports are closed before switching it to self-refresh. This commits prepares the code for the following ones adding self-refresh and PM support for SAMA7G5. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-8-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm_suspend.S | 399 +++++++++++++++++--------------- 1 file changed, 206 insertions(+), 193 deletions(-) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 3d20c9880fee..960ad29cce51 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -75,98 +75,147 @@ tmp3 .req r6 .arm -/* - * void at91_suspend_sram_fn(struct at91_pm_data*) - * @input param: - * @r0: base address of struct at91_pm_data +/** + * Enable self-refresh + * + * register usage: + * @r1: memory type + * @r2: base address of the sram controller + * @r3: temporary */ -/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */ - .align 3 -ENTRY(at91_pm_suspend_in_sram) - /* Save registers on stack */ - stmfd sp!, {r4 - r12, lr} +.macro at91_sramc_self_refresh_ena + ldr r1, .memtype + ldr r2, .sramc_base - /* Drain write buffer */ - mov tmp1, #0 - mcr p15, 0, tmp1, c7, c10, 4 + cmp r1, #AT91_MEMCTRL_MC + bne sr_ena_ddrc_sf - ldr tmp1, [r0, #PM_DATA_PMC] - str tmp1, .pmc_base - ldr tmp1, [r0, #PM_DATA_RAMC0] - str tmp1, .sramc_base - ldr tmp1, [r0, #PM_DATA_RAMC1] - str tmp1, .sramc1_base - ldr tmp1, [r0, #PM_DATA_MEMCTRL] - str tmp1, .memtype - ldr tmp1, [r0, #PM_DATA_MODE] - str tmp1, .pm_mode - ldr tmp1, [r0, #PM_DATA_PMC_MCKR_OFFSET] - str tmp1, .mckr_offset - ldr tmp1, [r0, #PM_DATA_PMC_VERSION] - str tmp1, .pmc_version - /* Both ldrne below are here to preload their address in the TLB */ - ldr tmp1, [r0, #PM_DATA_SHDWC] - str tmp1, .shdwc - cmp tmp1, #0 - ldrne tmp2, [tmp1, #0] - ldr tmp1, [r0, #PM_DATA_SFRBU] - str tmp1, .sfrbu - cmp tmp1, #0 - ldrne tmp2, [tmp1, #0x10] + /* Active SDRAM self-refresh mode */ + mov r3, #1 + str r3, [r2, #AT91_MC_SDRAMC_SRR] + b sr_ena_exit - /* Active the self-refresh mode */ - mov r0, #SRAMC_SELF_FRESH_ACTIVE - bl at91_sramc_self_refresh +sr_ena_ddrc_sf: + cmp r1, #AT91_MEMCTRL_DDRSDR + bne sr_ena_sdramc_sf - ldr r0, .pm_mode - cmp r0, #AT91_PM_STANDBY - beq standby - cmp r0, #AT91_PM_BACKUP - beq backup_mode + /* + * DDR Memory controller + */ - bl at91_ulp_mode - b exit_suspend + /* LPDDR1 --> force DDR2 mode during self-refresh */ + ldr r3, [r2, #AT91_DDRSDRC_MDR] + str r3, .saved_sam9_mdr + bic r3, r3, #~AT91_DDRSDRC_MD + cmp r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR + ldreq r3, [r2, #AT91_DDRSDRC_MDR] + biceq r3, r3, #AT91_DDRSDRC_MD + orreq r3, r3, #AT91_DDRSDRC_MD_DDR2 + streq r3, [r2, #AT91_DDRSDRC_MDR] -standby: - /* Wait for interrupt */ - ldr pmc, .pmc_base - at91_cpu_idle - b exit_suspend + /* Active DDRC self-refresh mode */ + ldr r3, [r2, #AT91_DDRSDRC_LPR] + str r3, .saved_sam9_lpr + bic r3, r3, #AT91_DDRSDRC_LPCB + orr r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH + str r3, [r2, #AT91_DDRSDRC_LPR] -backup_mode: - bl at91_backup_mode - b exit_suspend + /* If using the 2nd ddr controller */ + ldr r2, .sramc1_base + cmp r2, #0 + beq sr_ena_no_2nd_ddrc -exit_suspend: - /* Exit the self-refresh mode */ - mov r0, #SRAMC_SELF_FRESH_EXIT - bl at91_sramc_self_refresh + ldr r3, [r2, #AT91_DDRSDRC_MDR] + str r3, .saved_sam9_mdr1 + bic r3, r3, #~AT91_DDRSDRC_MD + cmp r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR + ldreq r3, [r2, #AT91_DDRSDRC_MDR] + biceq r3, r3, #AT91_DDRSDRC_MD + orreq r3, r3, #AT91_DDRSDRC_MD_DDR2 + streq r3, [r2, #AT91_DDRSDRC_MDR] - /* Restore registers, and return */ - ldmfd sp!, {r4 - r12, pc} -ENDPROC(at91_pm_suspend_in_sram) + /* Active DDRC self-refresh mode */ + ldr r3, [r2, #AT91_DDRSDRC_LPR] + str r3, .saved_sam9_lpr1 + bic r3, r3, #AT91_DDRSDRC_LPCB + orr r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH + str r3, [r2, #AT91_DDRSDRC_LPR] -ENTRY(at91_backup_mode) - /* Switch the master clock source to slow clock. */ - ldr pmc, .pmc_base - ldr tmp2, .mckr_offset - ldr tmp1, [pmc, tmp2] - bic tmp1, tmp1, #AT91_PMC_CSS - str tmp1, [pmc, tmp2] +sr_ena_no_2nd_ddrc: + b sr_ena_exit - wait_mckrdy + /* + * SDRAMC Memory controller + */ +sr_ena_sdramc_sf: + /* Active SDRAMC self-refresh mode */ + ldr r3, [r2, #AT91_SDRAMC_LPR] + str r3, .saved_sam9_lpr + bic r3, r3, #AT91_SDRAMC_LPCB + orr r3, r3, #AT91_SDRAMC_LPCB_SELF_REFRESH + str r3, [r2, #AT91_SDRAMC_LPR] - /*BUMEN*/ - ldr r0, .sfrbu - mov tmp1, #0x1 - str tmp1, [r0, #0x10] + ldr r3, .saved_sam9_lpr + str r3, [r2, #AT91_SDRAMC_LPR] - /* Shutdown */ - ldr r0, .shdwc - mov tmp1, #0xA5000000 - add tmp1, tmp1, #0x1 - str tmp1, [r0, #0] -ENDPROC(at91_backup_mode) +sr_ena_exit: +.endm + +/** + * Disable self-refresh + * + * register usage: + * @r1: memory type + * @r2: base address of the sram controller + * @r3: temporary + */ +.macro at91_sramc_self_refresh_dis + ldr r1, .memtype + ldr r2, .sramc_base + + cmp r1, #AT91_MEMCTRL_MC + bne sr_dis_ddrc_exit_sf + + /* + * at91rm9200 Memory controller + */ + + /* + * For exiting the self-refresh mode, do nothing, + * automatically exit the self-refresh mode. + */ + b sr_dis_exit + +sr_dis_ddrc_exit_sf: + cmp r1, #AT91_MEMCTRL_DDRSDR + bne sdramc_exit_sf + + /* DDR Memory controller */ + + /* Restore MDR in case of LPDDR1 */ + ldr r3, .saved_sam9_mdr + str r3, [r2, #AT91_DDRSDRC_MDR] + /* Restore LPR on AT91 with DDRAM */ + ldr r3, .saved_sam9_lpr + str r3, [r2, #AT91_DDRSDRC_LPR] + + /* If using the 2nd ddr controller */ + ldr r2, .sramc1_base + cmp r2, #0 + ldrne r3, .saved_sam9_mdr1 + strne r3, [r2, #AT91_DDRSDRC_MDR] + ldrne r3, .saved_sam9_lpr1 + strne r3, [r2, #AT91_DDRSDRC_LPR] + + b sr_dis_exit + +sdramc_exit_sf: + /* SDRAMC Memory controller */ + ldr r3, .saved_sam9_lpr + str r3, [r2, #AT91_SDRAMC_LPR] + +sr_dis_exit: +.endm .macro at91_pm_ulp0_mode ldr pmc, .pmc_base @@ -503,7 +552,7 @@ ENDPROC(at91_backup_mode) 2: .endm -ENTRY(at91_ulp_mode) +.macro at91_ulp_mode ldr pmc, .pmc_base ldr tmp2, .mckr_offset ldr tmp3, .pm_mode @@ -552,133 +601,97 @@ ulp_exit: wait_mckrdy - mov pc, lr -ENDPROC(at91_ulp_mode) +.endm + +.macro at91_backup_mode + /* Switch the master clock source to slow clock. */ + ldr pmc, .pmc_base + ldr tmp2, .mckr_offset + ldr tmp1, [pmc, tmp2] + bic tmp1, tmp1, #AT91_PMC_CSS + str tmp1, [pmc, tmp2] + + wait_mckrdy + + /*BUMEN*/ + ldr r0, .sfrbu + mov tmp1, #0x1 + str tmp1, [r0, #0x10] + + /* Shutdown */ + ldr r0, .shdwc + mov tmp1, #0xA5000000 + add tmp1, tmp1, #0x1 + str tmp1, [r0, #0] +.endm /* - * void at91_sramc_self_refresh(unsigned int is_active) - * + * void at91_suspend_sram_fn(struct at91_pm_data*) * @input param: - * @r0: 1 - active self-refresh mode - * 0 - exit self-refresh mode - * register usage: - * @r1: memory type - * @r2: base address of the sram controller + * @r0: base address of struct at91_pm_data */ +/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */ + .align 3 +ENTRY(at91_pm_suspend_in_sram) + /* Save registers on stack */ + stmfd sp!, {r4 - r12, lr} -ENTRY(at91_sramc_self_refresh) - ldr r1, .memtype - ldr r2, .sramc_base + /* Drain write buffer */ + mov tmp1, #0 + mcr p15, 0, tmp1, c7, c10, 4 - cmp r1, #AT91_MEMCTRL_MC - bne ddrc_sf + ldr tmp1, [r0, #PM_DATA_PMC] + str tmp1, .pmc_base + ldr tmp1, [r0, #PM_DATA_RAMC0] + str tmp1, .sramc_base + ldr tmp1, [r0, #PM_DATA_RAMC1] + str tmp1, .sramc1_base + ldr tmp1, [r0, #PM_DATA_MEMCTRL] + str tmp1, .memtype + ldr tmp1, [r0, #PM_DATA_MODE] + str tmp1, .pm_mode + ldr tmp1, [r0, #PM_DATA_PMC_MCKR_OFFSET] + str tmp1, .mckr_offset + ldr tmp1, [r0, #PM_DATA_PMC_VERSION] + str tmp1, .pmc_version + /* Both ldrne below are here to preload their address in the TLB */ + ldr tmp1, [r0, #PM_DATA_SHDWC] + str tmp1, .shdwc + cmp tmp1, #0 + ldrne tmp2, [tmp1, #0] + ldr tmp1, [r0, #PM_DATA_SFRBU] + str tmp1, .sfrbu + cmp tmp1, #0 + ldrne tmp2, [tmp1, #0x10] - /* - * at91rm9200 Memory controller - */ + /* Active the self-refresh mode */ + at91_sramc_self_refresh_ena - /* - * For exiting the self-refresh mode, do nothing, - * automatically exit the self-refresh mode. - */ - tst r0, #SRAMC_SELF_FRESH_ACTIVE - beq exit_sramc_sf + ldr r0, .pm_mode + cmp r0, #AT91_PM_STANDBY + beq standby + cmp r0, #AT91_PM_BACKUP + beq backup_mode - /* Active SDRAM self-refresh mode */ - mov r3, #1 - str r3, [r2, #AT91_MC_SDRAMC_SRR] - b exit_sramc_sf + at91_ulp_mode + b exit_suspend -ddrc_sf: - cmp r1, #AT91_MEMCTRL_DDRSDR - bne sdramc_sf +standby: + /* Wait for interrupt */ + ldr pmc, .pmc_base + at91_cpu_idle + b exit_suspend - /* - * DDR Memory controller - */ - tst r0, #SRAMC_SELF_FRESH_ACTIVE - beq ddrc_exit_sf +backup_mode: + at91_backup_mode - /* LPDDR1 --> force DDR2 mode during self-refresh */ - ldr r3, [r2, #AT91_DDRSDRC_MDR] - str r3, .saved_sam9_mdr - bic r3, r3, #~AT91_DDRSDRC_MD - cmp r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR - ldreq r3, [r2, #AT91_DDRSDRC_MDR] - biceq r3, r3, #AT91_DDRSDRC_MD - orreq r3, r3, #AT91_DDRSDRC_MD_DDR2 - streq r3, [r2, #AT91_DDRSDRC_MDR] +exit_suspend: + /* Exit the self-refresh mode */ + at91_sramc_self_refresh_dis - /* Active DDRC self-refresh mode */ - ldr r3, [r2, #AT91_DDRSDRC_LPR] - str r3, .saved_sam9_lpr - bic r3, r3, #AT91_DDRSDRC_LPCB - orr r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH - str r3, [r2, #AT91_DDRSDRC_LPR] - - /* If using the 2nd ddr controller */ - ldr r2, .sramc1_base - cmp r2, #0 - beq no_2nd_ddrc - - ldr r3, [r2, #AT91_DDRSDRC_MDR] - str r3, .saved_sam9_mdr1 - bic r3, r3, #~AT91_DDRSDRC_MD - cmp r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR - ldreq r3, [r2, #AT91_DDRSDRC_MDR] - biceq r3, r3, #AT91_DDRSDRC_MD - orreq r3, r3, #AT91_DDRSDRC_MD_DDR2 - streq r3, [r2, #AT91_DDRSDRC_MDR] - - /* Active DDRC self-refresh mode */ - ldr r3, [r2, #AT91_DDRSDRC_LPR] - str r3, .saved_sam9_lpr1 - bic r3, r3, #AT91_DDRSDRC_LPCB - orr r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH - str r3, [r2, #AT91_DDRSDRC_LPR] - -no_2nd_ddrc: - b exit_sramc_sf - -ddrc_exit_sf: - /* Restore MDR in case of LPDDR1 */ - ldr r3, .saved_sam9_mdr - str r3, [r2, #AT91_DDRSDRC_MDR] - /* Restore LPR on AT91 with DDRAM */ - ldr r3, .saved_sam9_lpr - str r3, [r2, #AT91_DDRSDRC_LPR] - - /* If using the 2nd ddr controller */ - ldr r2, .sramc1_base - cmp r2, #0 - ldrne r3, .saved_sam9_mdr1 - strne r3, [r2, #AT91_DDRSDRC_MDR] - ldrne r3, .saved_sam9_lpr1 - strne r3, [r2, #AT91_DDRSDRC_LPR] - - b exit_sramc_sf - - /* - * SDRAMC Memory controller - */ -sdramc_sf: - tst r0, #SRAMC_SELF_FRESH_ACTIVE - beq sdramc_exit_sf - - /* Active SDRAMC self-refresh mode */ - ldr r3, [r2, #AT91_SDRAMC_LPR] - str r3, .saved_sam9_lpr - bic r3, r3, #AT91_SDRAMC_LPCB - orr r3, r3, #AT91_SDRAMC_LPCB_SELF_REFRESH - str r3, [r2, #AT91_SDRAMC_LPR] - -sdramc_exit_sf: - ldr r3, .saved_sam9_lpr - str r3, [r2, #AT91_SDRAMC_LPR] - -exit_sramc_sf: - mov pc, lr -ENDPROC(at91_sramc_self_refresh) + /* Restore registers, and return */ + ldmfd sp!, {r4 - r12, pc} +ENDPROC(at91_pm_suspend_in_sram) .pmc_base: .word 0 From e3821ed4767000fa49b40be50de2344e2204bcd6 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:54 +0300 Subject: [PATCH 11/26] ARM: at91: pm: s/CONFIG_SOC_SAM9X60/CONFIG_HAVE_AT91_SAM9X60_PLL/g Replace CONFIG_SOC_SAM9X60 with CONFIG_HAVE_AT91_SAM9X60_PLL as the SAM9X60's PLL is also present on SAMA7G5. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-9-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm_suspend.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 960ad29cce51..1f63bbfad728 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -422,7 +422,7 @@ sr_dis_exit: cmp tmp1, #AT91_PMC_V1 beq 1f -#ifdef CONFIG_SOC_SAM9X60 +#ifdef CONFIG_HAVE_AT91_SAM9X60_PLL /* Save PLLA settings. */ ldr tmp2, [pmc, #AT91_PMC_PLL_UPDT] bic tmp2, tmp2, #AT91_PMC_PLL_UPDT_ID @@ -489,7 +489,7 @@ sr_dis_exit: cmp tmp3, #AT91_PMC_V1 beq 4f -#ifdef CONFIG_SOC_SAM9X60 +#ifdef CONFIG_HAVE_AT91_SAM9X60_PLL /* step 1. */ ldr tmp1, [pmc, #AT91_PMC_PLL_UPDT] bic tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID From 15126bb61b12ed1ddf006367bd6029dce7409532 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:55 +0300 Subject: [PATCH 12/26] ARM: at91: pm: add support for waiting MCK1..4 SAMA7G5 has 5 master clocks 0..4. MCK0 is controlled differently than MCK 1..4. MCK 1..4 should also be saved/restored in the last phase of suspend/resume. Thus, adapt wait_mckrdy to support also MCK1..4. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-10-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm_suspend.S | 48 ++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 1f63bbfad728..7669b32d5257 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -22,11 +22,23 @@ 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 -1: ldr tmp1, [pmc, #AT91_PMC_SR] - tst tmp1, #AT91_PMC_MCKRDY - beq 1b + .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 /* @@ -231,7 +243,9 @@ sr_dis_exit: bic tmp1, tmp1, #AT91_PMC_PRES orr tmp1, tmp1, #AT91_PMC_PRES_64 str tmp1, [pmc, tmp3] - wait_mckrdy + + mov tmp3, #0 + wait_mckrdy tmp3 b 1f 0: @@ -267,10 +281,13 @@ sr_dis_exit: bne 5f /* Set lowest prescaler for fast resume. */ + ldr tmp3, .mckr_offset ldr tmp1, [pmc, tmp3] bic tmp1, tmp1, #AT91_PMC_PRES str tmp1, [pmc, tmp3] - wait_mckrdy + + mov tmp3, #0 + wait_mckrdy tmp3 b 6f 5: /* Restore RC oscillator state */ @@ -307,6 +324,7 @@ sr_dis_exit: .macro at91_pm_ulp1_mode ldr pmc, .pmc_base ldr tmp2, .mckr_offset + mov tmp3, #0 /* Save RC oscillator state and check if it is enabled. */ ldr tmp1, [pmc, #AT91_PMC_SR] @@ -348,7 +366,7 @@ sr_dis_exit: orr tmp1, tmp1, #AT91_PMC_CSS_MAIN str tmp1, [pmc, tmp2] - wait_mckrdy + wait_mckrdy tmp3 /* Enter the ULP1 mode by set WAITMODE bit in CKGR_MOR */ ldr tmp1, [pmc, #AT91_CKGR_MOR] @@ -361,7 +379,7 @@ sr_dis_exit: nop nop - wait_mckrdy + wait_mckrdy tmp3 /* Enable the crystal oscillator */ ldr tmp1, [pmc, #AT91_CKGR_MOR] @@ -377,7 +395,7 @@ sr_dis_exit: bic tmp1, tmp1, #AT91_PMC_CSS str tmp1, [pmc, tmp2] - wait_mckrdy + wait_mckrdy tmp3 /* Switch main clock source to crystal oscillator */ ldr tmp1, [pmc, #AT91_CKGR_MOR] @@ -394,7 +412,7 @@ sr_dis_exit: orr tmp1, tmp1, #AT91_PMC_CSS_MAIN str tmp1, [pmc, tmp2] - wait_mckrdy + wait_mckrdy tmp3 /* Restore RC oscillator state */ ldr tmp1, .saved_osc_status @@ -573,10 +591,12 @@ sr_dis_exit: save_mck: str tmp1, [pmc, tmp2] - wait_mckrdy + mov tmp3, #0 + wait_mckrdy tmp3 at91_plla_disable + ldr tmp3, .pm_mode cmp tmp3, #AT91_PM_ULP1 beq ulp1_mode @@ -599,7 +619,8 @@ ulp_exit: ldr tmp2, .saved_mckr str tmp2, [pmc, tmp1] - wait_mckrdy + mov tmp3, #0 + wait_mckrdy tmp3 .endm @@ -611,7 +632,8 @@ ulp_exit: bic tmp1, tmp1, #AT91_PMC_CSS str tmp1, [pmc, tmp2] - wait_mckrdy + mov tmp3, #0 + wait_mckrdy tmp3 /*BUMEN*/ ldr r0, .sfrbu From 96abf16861508b92b1b44c564115c2be1f2b4966 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:56 +0300 Subject: [PATCH 13/26] ARM: at91: sfrbu: add sfrbu registers definitions for sama7g5 Add SFRBU registers definitions for SAMA7G5. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-11-claudiu.beznea@microchip.com --- include/soc/at91/sama7-sfrbu.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 include/soc/at91/sama7-sfrbu.h diff --git a/include/soc/at91/sama7-sfrbu.h b/include/soc/at91/sama7-sfrbu.h new file mode 100644 index 000000000000..76b740810d34 --- /dev/null +++ b/include/soc/at91/sama7-sfrbu.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Microchip SAMA7 SFRBU registers offsets and bit definitions. + * + * Copyright (C) [2020] Microchip Technology Inc. and its subsidiaries + * + * Author: Claudu Beznea + */ + +#ifndef __SAMA7_SFRBU_H__ +#define __SAMA7_SFRBU_H__ + +#ifdef CONFIG_SOC_SAMA7 + +#define AT91_SFRBU_PSWBU (0x00) /* SFRBU Power Switch BU Control Register */ +#define AT91_SFRBU_PSWBU_PSWKEY (0x4BD20C << 8) /* Specific value mandatory to allow writing of other register bits */ +#define AT91_SFRBU_PSWBU_STATE (1 << 2) /* Power switch BU state */ +#define AT91_SFRBU_PSWBU_SOFTSWITCH (1 << 1) /* Power switch BU source selection */ +#define AT91_SFRBU_PSWBU_CTRL (1 << 0) /* Power switch BU control */ + +#define AT91_SFRBU_25LDOCR (0x0C) /* SFRBU 2.5V LDO Control Register */ +#define AT91_SFRBU_25LDOCR_LDOANAKEY (0x3B6E18 << 8) /* Specific value mandatory to allow writing of other register bits. */ +#define AT91_SFRBU_25LDOCR_STATE (1 << 3) /* LDOANA Switch On/Off Control */ +#define AT91_SFRBU_25LDOCR_LP (1 << 2) /* LDOANA Low-Power Mode Control */ +#define AT91_SFRBU_PD_VALUE_MSK (0x3) +#define AT91_SFRBU_25LDOCR_PD_VALUE(v) ((v) & AT91_SFRBU_PD_VALUE_MSK) /* LDOANA Pull-down value */ + +#define AT91_FRBU_DDRPWR (0x10) /* SFRBU DDR Power Control Register */ +#define AT91_FRBU_DDRPWR_STATE (1 << 0) /* DDR Power Mode State */ + +#endif /* CONFIG_SOC_SAMA7 */ + +#endif /* __SAMA7_SFRBU_H__ */ + From d8c7983f31ac9ac75fc0138070349b360ab876fa Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:57 +0300 Subject: [PATCH 14/26] ARM: at91: ddr: add registers definitions for sama7g5's ddr Add registers and bits definitions for SAMA7G5's UDDRC and DDR3PHY. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-12-claudiu.beznea@microchip.com --- include/soc/at91/sama7-ddr.h | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 include/soc/at91/sama7-ddr.h diff --git a/include/soc/at91/sama7-ddr.h b/include/soc/at91/sama7-ddr.h new file mode 100644 index 000000000000..f6542584ca13 --- /dev/null +++ b/include/soc/at91/sama7-ddr.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Microchip SAMA7 UDDR Controller and DDR3 PHY Controller registers offsets + * and bit definitions. + * + * Copyright (C) [2020] Microchip Technology Inc. and its subsidiaries + * + * Author: Claudu Beznea + */ + +#ifndef __SAMA7_DDR_H__ +#define __SAMA7_DDR_H__ + +#ifdef CONFIG_SOC_SAMA7 + +/* DDR3PHY */ +#define DDR3PHY_PIR (0x04) /* DDR3PHY PHY Initialization Register */ +#define DDR3PHY_PIR_DLLBYP (1 << 17) /* DLL Bypass */ +#define DDR3PHY_PIR_ITMSRST (1 << 4) /* Interface Timing Module Soft Reset */ +#define DDR3PHY_PIR_DLLLOCK (1 << 2) /* DLL Lock */ +#define DDR3PHY_PIR_DLLSRST (1 << 1) /* DLL Soft Rest */ +#define DDR3PHY_PIR_INIT (1 << 0) /* Initialization Trigger */ + +#define DDR3PHY_PGCR (0x08) /* DDR3PHY PHY General Configuration Register */ +#define DDR3PHY_PGCR_CKDV1 (1 << 13) /* CK# Disable Value */ +#define DDR3PHY_PGCR_CKDV0 (1 << 12) /* CK Disable Value */ + +#define DDR3PHY_PGSR (0x0C) /* DDR3PHY PHY General Status Register */ +#define DDR3PHY_PGSR_IDONE (1 << 0) /* Initialization Done */ + +#define DDR3PHY_ACIOCR (0x24) /* DDR3PHY AC I/O Configuration Register */ +#define DDR3PHY_ACIOCR_CSPDD_CS0 (1 << 18) /* CS#[0] Power Down Driver */ +#define DDR3PHY_ACIOCR_CKPDD_CK0 (1 << 8) /* CK[0] Power Down Driver */ +#define DDR3PHY_ACIORC_ACPDD (1 << 3) /* AC Power Down Driver */ + +#define DDR3PHY_DXCCR (0x28) /* DDR3PHY DATX8 Common Configuration Register */ +#define DDR3PHY_DXCCR_DXPDR (1 << 3) /* Data Power Down Receiver */ + +#define DDR3PHY_DSGCR (0x2C) /* DDR3PHY DDR System General Configuration Register */ +#define DDR3PHY_DSGCR_ODTPDD_ODT0 (1 << 20) /* ODT[0] Power Down Driver */ + +#define DDR3PHY_ZQ0SR0 (0x188) /* ZQ status register 0 */ + +/* UDDRC */ +#define UDDRC_STAT (0x04) /* UDDRC Operating Mode Status Register */ +#define UDDRC_STAT_SELFREF_TYPE_DIS (0x0 << 4) /* SDRAM is not in Self-refresh */ +#define UDDRC_STAT_SELFREF_TYPE_PHY (0x1 << 4) /* SDRAM is in Self-refresh, which was caused by PHY Master Request */ +#define UDDRC_STAT_SELFREF_TYPE_SW (0x2 << 4) /* SDRAM is in Self-refresh, which was not caused solely under Automatic Self-refresh control */ +#define UDDRC_STAT_SELFREF_TYPE_AUTO (0x3 << 4) /* SDRAM is in Self-refresh, which was caused by Automatic Self-refresh only */ +#define UDDRC_STAT_SELFREF_TYPE_MSK (0x3 << 4) /* Self-refresh type mask */ +#define UDDRC_STAT_OPMODE_INIT (0x0 << 0) /* Init */ +#define UDDRC_STAT_OPMODE_NORMAL (0x1 << 0) /* Normal */ +#define UDDRC_STAT_OPMODE_PWRDOWN (0x2 << 0) /* Power-down */ +#define UDDRC_STAT_OPMODE_SELF_REFRESH (0x3 << 0) /* Self-refresh */ +#define UDDRC_STAT_OPMODE_MSK (0x7 << 0) /* Operating mode mask */ + +#define UDDRC_PWRCTL (0x30) /* UDDRC Low Power Control Register */ +#define UDDRC_PWRCTRL_SELFREF_SW (1 << 5) /* Software self-refresh */ + +#define UDDRC_DFIMISC (0x1B0) /* UDDRC DFI Miscellaneous Control Register */ +#define UDDRC_DFIMISC_DFI_INIT_COMPLETE_EN (1 << 0) /* PHY initialization complete enable signal */ + +#define UDDRC_SWCTRL (0x320) /* UDDRC Software Register Programming Control Enable */ +#define UDDRC_SWCTRL_SW_DONE (1 << 0) /* Enable quasi-dynamic register programming outside reset */ + +#define UDDRC_SWSTAT (0x324) /* UDDRC Software Register Programming Control Status */ +#define UDDRC_SWSTAT_SW_DONE_ACK (1 << 0) /* Register programming done */ + +#define UDDRC_PSTAT (0x3FC) /* UDDRC Port Status Register */ +#define UDDRC_PSTAT_ALL_PORTS (0x1F001F) /* Read + writes outstanding transactions on all ports */ + +#define UDDRC_PCTRL_0 (0x490) /* UDDRC Port 0 Control Register */ +#define UDDRC_PCTRL_1 (0x540) /* UDDRC Port 1 Control Register */ +#define UDDRC_PCTRL_2 (0x5F0) /* UDDRC Port 2 Control Register */ +#define UDDRC_PCTRL_3 (0x6A0) /* UDDRC Port 3 Control Register */ +#define UDDRC_PCTRL_4 (0x750) /* UDDRC Port 4 Control Register */ + +#endif /* CONFIG_SOC_SAMA7 */ + +#endif /* __SAMA7_DDR_H__ */ From f0bbf17958e84e2fdc0a4487c85472025c7ed04a Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:58 +0300 Subject: [PATCH 15/26] ARM: at91: pm: add self-refresh support for sama7g5 Add self-refresh support for SAMA7G5. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-13-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.h | 2 + arch/arm/mach-at91/pm_data-offsets.c | 2 + arch/arm/mach-at91/pm_suspend.S | 199 +++++++++++++++++++++++++++ 3 files changed, 203 insertions(+) diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index bfb260be371e..666474088d55 100644 --- a/arch/arm/mach-at91/pm.h +++ b/arch/arm/mach-at91/pm.h @@ -12,6 +12,7 @@ #include #include #include +#include #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; diff --git a/arch/arm/mach-at91/pm_data-offsets.c b/arch/arm/mach-at91/pm_data-offsets.c index 82089ff258c0..40bd4e8fe40a 100644 --- a/arch/arm/mach-at91/pm_data-offsets.c +++ b/arch/arm/mach-at91/pm_data-offsets.c @@ -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)); diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 7669b32d5257..84418120ba67 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -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: From 28eb1d40fe57fd03657f01fdaf2cce115cba3b7d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:49:59 +0300 Subject: [PATCH 16/26] ARM: at91: pm: add support for MCK1..4 save/restore for ulp modes Add support for MCK1..4 save restore for ULP modes. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-14-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm_suspend.S | 126 ++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 84418120ba67..8b0b8619ee8a 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -765,7 +765,122 @@ sr_dis_exit: 2: .endm +/** + * at91_mckx_ps_enable: save MCK1..4 settings and switch it to main clock + * + * Side effects: overwrites tmp1, tmp2 + */ +.macro at91_mckx_ps_enable +#ifdef CONFIG_SOC_SAMA7 + ldr pmc, .pmc_base + + /* There are 4 MCKs we need to handle: MCK1..4 */ + mov tmp1, #1 +e_loop: cmp tmp1, #5 + beq e_done + + /* Write MCK ID to retrieve the settings. */ + str tmp1, [pmc, #AT91_PMC_MCR_V2] + ldr tmp2, [pmc, #AT91_PMC_MCR_V2] + +e_save_mck1: + cmp tmp1, #1 + bne e_save_mck2 + str tmp2, .saved_mck1 + b e_ps + +e_save_mck2: + cmp tmp1, #2 + bne e_save_mck3 + str tmp2, .saved_mck2 + b e_ps + +e_save_mck3: + cmp tmp1, #3 + bne e_save_mck4 + str tmp2, .saved_mck3 + b e_ps + +e_save_mck4: + str tmp2, .saved_mck4 + +e_ps: + /* Use CSS=MAINCK and DIV=1. */ + bic tmp2, tmp2, #AT91_PMC_MCR_V2_CSS + bic tmp2, tmp2, #AT91_PMC_MCR_V2_DIV + orr tmp2, tmp2, #AT91_PMC_MCR_V2_CSS_MAINCK + orr tmp2, tmp2, #AT91_PMC_MCR_V2_DIV1 + str tmp2, [pmc, #AT91_PMC_MCR_V2] + + wait_mckrdy tmp1 + + add tmp1, tmp1, #1 + b e_loop + +e_done: +#endif +.endm + +/** + * at91_mckx_ps_restore: restore MCK1..4 settings + * + * Side effects: overwrites tmp1, tmp2 + */ +.macro at91_mckx_ps_restore +#ifdef CONFIG_SOC_SAMA7 + ldr pmc, .pmc_base + + /* There are 4 MCKs we need to handle: MCK1..4 */ + mov tmp1, #1 +r_loop: cmp tmp1, #5 + beq r_done + +r_save_mck1: + cmp tmp1, #1 + bne r_save_mck2 + ldr tmp2, .saved_mck1 + b r_ps + +r_save_mck2: + cmp tmp1, #2 + bne r_save_mck3 + ldr tmp2, .saved_mck2 + b r_ps + +r_save_mck3: + cmp tmp1, #3 + bne r_save_mck4 + ldr tmp2, .saved_mck3 + b r_ps + +r_save_mck4: + ldr tmp2, .saved_mck4 + +r_ps: + /* Write MCK ID to retrieve the settings. */ + str tmp1, [pmc, #AT91_PMC_MCR_V2] + ldr tmp3, [pmc, #AT91_PMC_MCR_V2] + + /* We need to restore CSS and DIV. */ + bic tmp3, tmp3, #AT91_PMC_MCR_V2_CSS + bic tmp3, tmp3, #AT91_PMC_MCR_V2_DIV + orr tmp3, tmp3, tmp2 + bic tmp3, tmp3, #AT91_PMC_MCR_V2_ID_MSK + orr tmp3, tmp3, tmp1 + orr tmp3, tmp3, #AT91_PMC_MCR_V2_CMD + str tmp2, [pmc, #AT91_PMC_MCR_V2] + + wait_mckrdy tmp1 + + add tmp1, tmp1, #1 + b r_loop +r_done: +#endif +.endm + .macro at91_ulp_mode + at91_mckx_ps_enable + ldr pmc, .pmc_base ldr tmp2, .mckr_offset ldr tmp3, .pm_mode @@ -817,6 +932,7 @@ ulp_exit: mov tmp3, #0 wait_mckrdy tmp3 + at91_mckx_ps_restore .endm .macro at91_backup_mode @@ -946,6 +1062,16 @@ ENDPROC(at91_pm_suspend_in_sram) .word 0 .saved_osc_status: .word 0 +#ifdef CONFIG_SOC_SAMA7 +.saved_mck1: + .word 0 +.saved_mck2: + .word 0 +.saved_mck3: + .word 0 +.saved_mck4: + .word 0 +#endif ENTRY(at91_pm_suspend_in_sram_sz) .word .-at91_pm_suspend_in_sram From 475be50fc149ae11822433e8cb511493bb0e5c1d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:50:00 +0300 Subject: [PATCH 17/26] ARM: at91: pm: add support for 2.5V LDO regulator control Add support to disable/enable 2.5V LDO regulator when entering/exiting any ULP mode. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-15-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.h | 1 + arch/arm/mach-at91/pm_suspend.S | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index 666474088d55..53bdc9000e44 100644 --- a/arch/arm/mach-at91/pm.h +++ b/arch/arm/mach-at91/pm.h @@ -13,6 +13,7 @@ #include #include #include +#include #define AT91_MEMCTRL_MC 0 #define AT91_MEMCTRL_SDRAMC 1 diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 8b0b8619ee8a..9c9e08fd8300 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -83,6 +83,29 @@ tmp3 .req r6 .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 + .text .arm @@ -906,6 +929,9 @@ save_mck: at91_plla_disable + /* Enable low power mode for 2.5V regulator. */ + at91_2_5V_reg_set_low_power 1 + ldr tmp3, .pm_mode cmp tmp3, #AT91_PM_ULP1 beq ulp1_mode @@ -918,6 +944,9 @@ ulp1_mode: b ulp_exit ulp_exit: + /* Disable low power mode for 2.5V regulator. */ + at91_2_5V_reg_set_low_power 0 + ldr pmc, .pmc_base at91_plla_enable From 5b0bef872c1d131c4a4b2abdd825d4d5f548a1a1 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:50:01 +0300 Subject: [PATCH 18/26] ARM: at91: pm: wait for ddr power mode off Wait for DDR power mode off before shutting down the core. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-16-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm_suspend.S | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 9c9e08fd8300..7396e18dd7e5 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -980,6 +980,11 @@ ulp_exit: mov tmp1, #0x1 str tmp1, [r0, #0x10] + /* Wait for it. */ +1: ldr tmp1, [r0, #0x10] + tst tmp1, #0x1 + beq 1b + /* Shutdown */ ldr r0, .shdwc mov tmp1, #0xA5000000 From 2c26cb4d6944edf0a65a4b1fdeacdcc816261739 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:50:03 +0300 Subject: [PATCH 19/26] ARM: at91: pm: add sama7g5 ddr controller Add SAMA7G5 DDR controller to the list of DDR controller compatibles. At the moment there is no standby support. Adapt the code for this. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-18-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 65e13769cf50..5dc942a2012d 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -548,6 +548,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", }, { /*sentinel*/ } }; @@ -565,9 +566,11 @@ static __init void at91_dt_ramc(void) panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx); ramc = of_id->data; - if (!standby) - standby = ramc->idle; - soc_pm.data.memctrl = ramc->memctrl; + if (ramc) { + if (!standby) + standby = ramc->idle; + soc_pm.data.memctrl = ramc->memctrl; + } idx++; } From 892e1f4a3ae58c1cd376d952d45dca6f20dc712c Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:50:04 +0300 Subject: [PATCH 20/26] ARM: at91: pm: add sama7g5 ddr phy controller SAMA7G5 self-refresh procedure accesses also the DDR PHY registers. Adapt the code so that the at91_dt_ramc() to look also for DDR PHYs, in case it is mandatory. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-19-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 5dc942a2012d..4dec7216a80e 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -552,7 +552,12 @@ static const struct of_device_id ramc_ids[] __initconst = { { /*sentinel*/ } }; -static __init void at91_dt_ramc(void) +static const struct of_device_id ramc_phy_ids[] __initconst = { + { .compatible = "microchip,sama7g5-ddr3phy", }, + { /* Sentinel. */ }, +}; + +static __init void at91_dt_ramc(bool phy_mandatory) { struct device_node *np; const struct of_device_id *of_id; @@ -578,6 +583,16 @@ static __init void at91_dt_ramc(void) if (!idx) panic(pr_fmt("unable to find compatible ram controller node in dtb\n")); + /* Lookup for DDR PHY node, if any. */ + for_each_matching_node_and_match(np, ramc_phy_ids, &of_id) { + soc_pm.data.ramc_phy = of_iomap(np, 0); + if (!soc_pm.data.ramc_phy) + panic(pr_fmt("unable to map ramc phy cpu registers\n")); + } + + if (phy_mandatory && !soc_pm.data.ramc_phy) + panic(pr_fmt("DDR PHY is mandatory!\n")); + if (!standby) { pr_warn("ramc no standby function available\n"); return; @@ -936,7 +951,7 @@ void __init at91rm9200_pm_init(void) soc_pm.data.standby_mode = AT91_PM_STANDBY; soc_pm.data.suspend_mode = AT91_PM_ULP0; - at91_dt_ramc(); + at91_dt_ramc(false); /* * AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. @@ -960,7 +975,7 @@ void __init sam9x60_pm_init(void) at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps)); - at91_dt_ramc(); + at91_dt_ramc(false); at91_pm_init(NULL); soc_pm.ws_ids = sam9x60_ws_ids; @@ -980,7 +995,7 @@ void __init at91sam9_pm_init(void) soc_pm.data.standby_mode = AT91_PM_STANDBY; soc_pm.data.suspend_mode = AT91_PM_ULP0; - at91_dt_ramc(); + at91_dt_ramc(false); at91_pm_init(at91sam9_idle); } @@ -994,7 +1009,7 @@ void __init sama5_pm_init(void) return; at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); - at91_dt_ramc(); + at91_dt_ramc(false); at91_pm_init(NULL); } @@ -1015,7 +1030,7 @@ void __init sama5d2_pm_init(void) at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps)); - at91_dt_ramc(); + at91_dt_ramc(false); at91_pm_init(NULL); soc_pm.ws_ids = sama5d2_ws_ids; From d2d4716d83840f279c979053fc0d0f966153b601 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:50:05 +0300 Subject: [PATCH 21/26] ARM: at91: pm: save ddr phy calibration data to securam The resuming from backup mode is done with the help of bootloader. The bootloader reconfigure the DDR controller and DDR PHY controller. To speed-up the resuming process save the PHY calibration data into SECURAM before suspending (securam is powered on backup mode). This data will be later used by bootloader in DDR PHY reconfiguration process. Also, in the process or recalibration the first 8 words of the memory may get corrupted. To solve this, these 8 words are saved in the securam and restored by bootloader in the process of PHY configuration. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-20-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 60 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 4dec7216a80e..91b4014d2e10 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -27,18 +28,23 @@ #include "generic.h" #include "pm.h" +#define BACKUP_DDR_PHY_CALIBRATION (9) + /** * struct at91_pm_bu - AT91 power management backup unit data structure * @suspended: true if suspended to backup mode * @reserved: reserved * @canary: canary data for memory checking after exit from backup mode * @resume: resume API + * @ddr_phy_calibration: DDR PHY calibration data: ZQ0CR0, first 8 words + * of the memory */ struct at91_pm_bu { int suspended; unsigned long reserved; phys_addr_t canary; phys_addr_t resume; + unsigned long ddr_phy_calibration[BACKUP_DDR_PHY_CALIBRATION]; }; /** @@ -48,6 +54,7 @@ struct at91_pm_bu { * @ws_ids: wakup sources of_device_id array * @data: PM data to be used on last phase of suspend * @bu: backup unit mapped data (for backup mode) + * @memcs: memory chip select */ struct at91_soc_pm { int (*config_shdwc_ws)(void __iomem *shdwc, u32 *mode, u32 *polarity); @@ -55,6 +62,7 @@ struct at91_soc_pm { const struct of_device_id *ws_ids; struct at91_pm_bu *bu; struct at91_pm_data data; + void *memcs; }; /** @@ -316,6 +324,19 @@ extern u32 at91_pm_suspend_in_sram_sz; static int at91_suspend_finish(unsigned long val) { + int i; + + if (soc_pm.data.mode == AT91_PM_BACKUP && soc_pm.data.ramc_phy) { + /* + * The 1st 8 words of memory might get corrupted in the process + * of DDR PHY recalibration; it is saved here in securam and it + * will be restored later, after recalibration, by bootloader + */ + for (i = 1; i < BACKUP_DDR_PHY_CALIBRATION; i++) + soc_pm.bu->ddr_phy_calibration[i] = + *((unsigned int *)soc_pm.memcs + (i - 1)); + } + flush_cache_all(); outer_disable(); @@ -673,12 +694,40 @@ static bool __init at91_is_pm_mode_active(int pm_mode) soc_pm.data.suspend_mode == pm_mode); } +static int __init at91_pm_backup_scan_memcs(unsigned long node, + const char *uname, int depth, + void *data) +{ + const char *type; + const __be32 *reg; + int *located = data; + int size; + + /* Memory node already located. */ + if (*located) + return 0; + + type = of_get_flat_dt_prop(node, "device_type", NULL); + + /* We are scanning "memory" nodes only. */ + if (!type || strcmp(type, "memory")) + return 0; + + reg = of_get_flat_dt_prop(node, "reg", &size); + if (reg) { + soc_pm.memcs = __va((phys_addr_t)be32_to_cpu(*reg)); + *located = 1; + } + + return 0; +} + static int __init at91_pm_backup_init(void) { struct gen_pool *sram_pool; struct device_node *np; struct platform_device *pdev; - int ret = -ENODEV; + int ret = -ENODEV, located = 0; if (!IS_ENABLED(CONFIG_SOC_SAMA5D2)) return -EPERM; @@ -713,6 +762,15 @@ static int __init at91_pm_backup_init(void) soc_pm.bu->suspended = 0; soc_pm.bu->canary = __pa_symbol(&canary); soc_pm.bu->resume = __pa_symbol(cpu_resume); + if (soc_pm.data.ramc_phy) { + of_scan_flat_dt(at91_pm_backup_scan_memcs, &located); + if (!located) + goto securam_fail; + + /* DDR3PHY_ZQ0SR0 */ + soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy + + 0x188); + } return 0; From f205adb60898ed72c3aa5aedac22f74a1d293734 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:50:06 +0300 Subject: [PATCH 22/26] ARM: at91: pm: add backup mode support for SAMA7G5 Adapt at91_pm_backup_init() to work for SAMA7G5. Also, set the LPM pin to shutdown controller. This will signal to PMIC that it needs to switch to the state corresponding to backup mode. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-21-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 3 ++- arch/arm/mach-at91/pm_suspend.S | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 91b4014d2e10..fcb20272d65d 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -729,7 +729,8 @@ static int __init at91_pm_backup_init(void) struct platform_device *pdev; int ret = -ENODEV, located = 0; - if (!IS_ENABLED(CONFIG_SOC_SAMA5D2)) + if (!IS_ENABLED(CONFIG_SOC_SAMA5D2) && + !IS_ENABLED(CONFIG_SOC_SAMA7G5)) return -EPERM; if (!at91_is_pm_mode_active(AT91_PM_BACKUP)) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 7396e18dd7e5..cbd61a3bcab1 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -106,6 +106,12 @@ lp_done_\ena: #endif .endm + .macro at91_backup_set_lpm reg +#ifdef CONFIG_SOC_SAMA7 + orr \reg, \reg, #0x200000 +#endif + .endm + .text .arm @@ -989,6 +995,7 @@ ulp_exit: ldr r0, .shdwc mov tmp1, #0xA5000000 add tmp1, tmp1, #0x1 + at91_backup_set_lpm tmp1 str tmp1, [r0, #0] .endm From ccdbdf33bdc074bbf33e8c3182189d8524a7039f Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:50:07 +0300 Subject: [PATCH 23/26] ARM: at91: pm: add sama7g5's pmc Add SAMA7G5's PMC to compatible list. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-22-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index fcb20272d65d..f4e66a7c7d18 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -897,6 +897,11 @@ static const struct pmc_info pmc_infos[] __initconst = { .mckr = 0x28, .version = AT91_PMC_V2, }, + { + .mckr = 0x28, + .version = AT91_PMC_V2, + }, + }; static const struct of_device_id atmel_pmc_ids[] __initconst = { @@ -912,6 +917,7 @@ static const struct of_device_id atmel_pmc_ids[] __initconst = { { .compatible = "atmel,sama5d4-pmc", .data = &pmc_infos[1] }, { .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] }, { .compatible = "microchip,sam9x60-pmc", .data = &pmc_infos[4] }, + { .compatible = "microchip,sama7g5-pmc", .data = &pmc_infos[5] }, { /* sentinel */ }, }; From 9d464cc5ac018975b9151ac8d2b68b1b033a3268 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 15 Apr 2021 13:50:08 +0300 Subject: [PATCH 24/26] ARM: at91: sama7: introduce sama7 SoC family Introduce new family of SoCs, sama7, and first SoC, sama7g5. Signed-off-by: Eugen Hristev [claudiu.beznea@microchip.com: keep only the sama7_dt] Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-23-claudiu.beznea@microchip.com --- arch/arm/mach-at91/Makefile | 1 + arch/arm/mach-at91/sama7.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 arch/arm/mach-at91/sama7.c diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index f565490f1b70..522b680b6446 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9.o obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o obj-$(CONFIG_SOC_SAMA5) += sama5.o +obj-$(CONFIG_SOC_SAMA7) += sama7.o obj-$(CONFIG_SOC_SAMV7) += samv7.o # Power Management diff --git a/arch/arm/mach-at91/sama7.c b/arch/arm/mach-at91/sama7.c new file mode 100644 index 000000000000..19d7bcbc97f1 --- /dev/null +++ b/arch/arm/mach-at91/sama7.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Setup code for SAMA7 + * + * Copyright (C) 2021 Microchip Technology, Inc. and its subsidiaries + * + */ + +#include +#include + +#include +#include + +#include "generic.h" + +static void __init sama7_dt_device_init(void) +{ + of_platform_default_populate(NULL, NULL, NULL); +} + +static const char *const sama7_dt_board_compat[] __initconst = { + "microchip,sama7", + NULL +}; + +DT_MACHINE_START(sama7_dt, "Microchip SAMA7") + /* Maintainer: Microchip */ + .init_machine = sama7_dt_device_init, + .dt_compat = sama7_dt_board_compat, +MACHINE_END + From 6501330f9f5e45a00622dee69a4a005d5943172d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:50:09 +0300 Subject: [PATCH 25/26] ARM: at91: pm: add pm support for SAMA7G5 Add support for SAMA7G5 power management modes: standby, ulp0, ulp1, backup. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-24-claudiu.beznea@microchip.com --- arch/arm/mach-at91/generic.h | 2 ++ arch/arm/mach-at91/pm.c | 37 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-at91/sama7.c | 1 + 3 files changed, 40 insertions(+) diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 0a4cdcb4985b..0c3960a8b3eb 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -14,12 +14,14 @@ extern void __init at91sam9_pm_init(void); extern void __init sam9x60_pm_init(void); extern void __init sama5_pm_init(void); extern void __init sama5d2_pm_init(void); +extern void __init sama7_pm_init(void); #else static inline void __init at91rm9200_pm_init(void) { } static inline void __init at91sam9_pm_init(void) { } static inline void __init sam9x60_pm_init(void) { } static inline void __init sama5_pm_init(void) { } static inline void __init sama5d2_pm_init(void) { } +static inline void __init sama7_pm_init(void) { } #endif #endif /* _AT91_GENERIC_H */ diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index f4e66a7c7d18..24d5fd06d487 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -152,6 +152,17 @@ static const struct of_device_id sam9x60_ws_ids[] = { { /* sentinel */ } }; +static const struct of_device_id sama7g5_ws_ids[] = { + { .compatible = "atmel,at91sam9x5-rtc", .data = &ws_info[1] }, + { .compatible = "microchip,sama7g5-ohci", .data = &ws_info[2] }, + { .compatible = "usb-ohci", .data = &ws_info[2] }, + { .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] }, + { .compatible = "usb-ehci", .data = &ws_info[2] }, + { .compatible = "microchip,sama7g5-sdhci", .data = &ws_info[3] }, + { .compatible = "atmel,at91sam9260-rtt", .data = &ws_info[4] }, + { /* sentinel */ } +}; + static int at91_pm_config_ws(unsigned int pm_mode, bool set) { const struct wakeup_source_info *wsi; @@ -1103,6 +1114,32 @@ void __init sama5d2_pm_init(void) soc_pm.config_pmc_ws = at91_sama5d2_config_pmc_ws; } +void __init sama7_pm_init(void) +{ + static const int modes[] __initconst = { + AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP1, AT91_PM_BACKUP, + }; + static const u32 iomaps[] __initconst = { + [AT91_PM_ULP0] = AT91_PM_IOMAP(SFRBU), + [AT91_PM_ULP1] = AT91_PM_IOMAP(SFRBU) | + AT91_PM_IOMAP(SHDWC), + [AT91_PM_BACKUP] = AT91_PM_IOMAP(SFRBU) | + AT91_PM_IOMAP(SHDWC), + }; + + if (!IS_ENABLED(CONFIG_SOC_SAMA7)) + return; + + at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); + + at91_dt_ramc(true); + at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps)); + at91_pm_init(NULL); + + soc_pm.ws_ids = sama7g5_ws_ids; + soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws; +} + static int __init at91_pm_modes_select(char *str) { char *s; diff --git a/arch/arm/mach-at91/sama7.c b/arch/arm/mach-at91/sama7.c index 19d7bcbc97f1..bd43733ede18 100644 --- a/arch/arm/mach-at91/sama7.c +++ b/arch/arm/mach-at91/sama7.c @@ -17,6 +17,7 @@ static void __init sama7_dt_device_init(void) { of_platform_default_populate(NULL, NULL, NULL); + sama7_pm_init(); } static const char *const sama7_dt_board_compat[] __initconst = { From ad9bc2e35cf575644064284943aefdde426644cc Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 15 Apr 2021 13:50:10 +0300 Subject: [PATCH 26/26] ARM: at91: pm: add sama7g5 shdwc Add SAMA7G5 SHDWC. Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20210415105010.569620-25-claudiu.beznea@microchip.com --- arch/arm/mach-at91/pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 24d5fd06d487..d6cfe7c4bb00 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -794,6 +794,7 @@ securam_fail: static const struct of_device_id atmel_shdwc_ids[] = { { .compatible = "atmel,sama5d2-shdwc" }, { .compatible = "microchip,sam9x60-shdwc" }, + { .compatible = "microchip,sama7g5-shdwc" }, { /* sentinel. */ } };