[PATCH v3 24/24] ARM: at91: pm: add sama7g5 shdwc
Add SAMA7G5 SHDWC. Signed-off-by: Claudiu Beznea --- 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 @@ static int __init at91_pm_backup_init(void) static const struct of_device_id atmel_shdwc_ids[] = { { .compatible = "atmel,sama5d2-shdwc" }, { .compatible = "microchip,sam9x60-shdwc" }, + { .compatible = "microchip,sama7g5-shdwc" }, { /* sentinel. */ } }; -- 2.25.1
[PATCH v3 22/24] ARM: at91: sama7: introduce sama7 SoC family
From: Eugen Hristev Introduce new family of SoCs, sama7, and first SoC, sama7g5. Signed-off-by: Eugen Hristev [claudiu.bez...@microchip.com: keep only the sama7_dt] Signed-off-by: Claudiu Beznea --- 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 ..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 + -- 2.25.1
[PATCH v3 23/24] ARM: at91: pm: add pm support for SAMA7G5
Add support for SAMA7G5 power management modes: standby, ulp0, ulp1, backup. Signed-off-by: Claudiu Beznea --- 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 = _info[1] }, + { .compatible = "microchip,sama7g5-ohci", .data = _info[2] }, + { .compatible = "usb-ohci", .data = _info[2] }, + { .compatible = "atmel,at91sam9g45-ehci", .data = _info[2] }, + { .compatible = "usb-ehci", .data = _info[2] }, + { .compatible = "microchip,sama7g5-sdhci", .data = _info[3] }, + { .compatible = "atmel,at91sam9260-rtt",.data = _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 = { -- 2.25.1
[PATCH v3 20/24] 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 --- 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, #0x20 +#endif + .endm + .text .arm @@ -989,6 +995,7 @@ ulp_exit: ldr r0, .shdwc mov tmp1, #0xA500 add tmp1, tmp1, #0x1 + at91_backup_set_lpm tmp1 str tmp1, [r0, #0] .endm -- 2.25.1
[PATCH v3 17/24] 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 --- 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 = _infos[1] }, { .compatible = "atmel,at91sam9g45-ddramc", .data = _infos[2] }, { .compatible = "atmel,sama5d3-ddramc", .data = _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++; } -- 2.25.1
[PATCH v3 19/24] 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 --- 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", ); + 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(); soc_pm.bu->resume = __pa_symbol(cpu_resume); + if (soc_pm.data.ramc_phy) { + of_scan_flat_dt(at91_pm_backup_scan_memcs, ); + if (!located) + goto securam_fail; + + /* DDR3PHY_ZQ0SR0 */ + soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy + + 0x188); + } return 0; -- 2.25.1
[PATCH v3 18/24] 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 --- 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, _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; -- 2.25.1
[PATCH v3 21/24] ARM: at91: pm: add sama7g5's pmc
Add SAMA7G5's PMC to compatible list. Signed-off-by: Claudiu Beznea --- 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 = _infos[1] }, { .compatible = "atmel,sama5d2-pmc", .data = _infos[1] }, { .compatible = "microchip,sam9x60-pmc", .data = _infos[4] }, + { .compatible = "microchip,sama7g5-pmc", .data = _infos[5] }, { /* sentinel */ }, }; -- 2.25.1
[PATCH v3 16/24] dt-bindings: atmel-sysreg: add bindings for sama7g5
Add RAM controller and RAM PHY controller DT bindings. Signed-off-by: Claudiu Beznea --- .../devicetree/bindings/arm/atmel-sysregs.txt | 14 +- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt index 807264a78edc..16eef600d599 100644 --- a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt +++ b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt @@ -45,7 +45,8 @@ RAMC SDRAM/DDR Controller required properties: "atmel,at91sam9260-sdramc", "atmel,at91sam9g45-ddramc", "atmel,sama5d3-ddramc", - "microchip,sam9x60-ddramc" + "microchip,sam9x60-ddramc", + "microchip,sama7g5-uddrc" - reg: Should contain registers location and length Examples: @@ -55,6 +56,17 @@ Examples: reg = <0xe800 0x200>; }; +RAMC PHY Controller required properties: +- compatible: Should be "microchip,sama7g5-ddr3phy", "syscon" +- reg: Should contain registers location and length + +Example: + + ddr3phy: ddr3phy@e3804000 { + compatible = "microchip,sama7g5-ddr3phy", "syscon"; + reg = <0xe3804000 0x1000>; +}; + SHDWC Shutdown Controller required properties: -- 2.25.1
[PATCH v3 15/24] 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 --- 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, #0xA500 -- 2.25.1
[PATCH v3 14/24] 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 --- 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_MC0 #define AT91_MEMCTRL_SDRAMC1 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 .reqr6 .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 -- 2.25.1
[PATCH v3 12/24] ARM: at91: pm: add self-refresh support for sama7g5
Add self-refresh support for SAMA7G5. Signed-off-by: Claudiu Beznea --- 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_MC0 #define AT91_MEMCTRL_SDRAMC1 @@ -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.reqr6 .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
[PATCH v3 11/24] 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 --- 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 ..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 */ +#defineDDR3PHY_PIR_DLLBYP (1 << 17) /* DLL Bypass */ +#defineDDR3PHY_PIR_ITMSRST (1 << 4)/* Interface Timing Module Soft Reset */ +#defineDDR3PHY_PIR_DLLLOCK (1 << 2)/* DLL Lock */ +#defineDDR3PHY_PIR_DLLSRST (1 << 1)/* DLL Soft Rest */ +#defineDDR3PHY_PIR_INIT(1 << 0)/* Initialization Trigger */ + +#define DDR3PHY_PGCR (0x08) /* DDR3PHY PHY General Configuration Register */ +#defineDDR3PHY_PGCR_CKDV1 (1 << 13) /* CK# Disable Value */ +#defineDDR3PHY_PGCR_CKDV0 (1 << 12) /* CK Disable Value */ + +#defineDDR3PHY_PGSR(0x0C) /* DDR3PHY PHY General Status Register */ +#defineDDR3PHY_PGSR_IDONE (1 << 0)/* Initialization Done */ + +#define DDR3PHY_ACIOCR (0x24) /* DDR3PHY AC I/O Configuration Register */ +#defineDDR3PHY_ACIOCR_CSPDD_CS0(1 << 18) /* CS#[0] Power Down Driver */ +#defineDDR3PHY_ACIOCR_CKPDD_CK0(1 << 8)/* CK[0] Power Down Driver */ +#defineDDR3PHY_ACIORC_ACPDD(1 << 3)/* AC Power Down Driver */ + +#define DDR3PHY_DXCCR (0x28) /* DDR3PHY DATX8 Common Configuration Register */ +#defineDDR3PHY_DXCCR_DXPDR (1 << 3)/* Data Power Down Receiver */ + +#define DDR3PHY_DSGCR (0x2C) /* DDR3PHY DDR System General Configuration Register */ +#defineDDR3PHY_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 */ +#defineUDDRC_STAT_SELFREF_TYPE_DIS (0x0 << 4) /* SDRAM is not in Self-refresh */ +#defineUDDRC_STAT_SELFREF_TYPE_PHY (0x1 << 4) /* SDRAM is in Self-refresh, which was caused by PHY Master Request */ +#defineUDDRC_STAT_SELFREF_TYPE_SW (0x2 << 4) /* SDRAM is in Self-refresh, which was not caused solely under Automatic Self-refresh control */ +#defineUDDRC_STAT_SELFREF_TYPE_AUTO(0x3 << 4) /* SDRAM is in Self-refresh, which was caused by Automatic Self-refresh only */ +#defineUDDRC_STAT_SELFREF_TYPE_MSK (0x3 << 4) /* Self-refresh type mask */ +#defineUDDRC_STAT_OPMODE_INIT (0x0 << 0) /* Init */ +#defineUDDRC_STAT_OPMODE_NORMAL(0x1 << 0) /* Normal */ +#defineUDDRC_STAT_OPMODE_PWRDOWN (0x2 << 0) /* Power-down */ +#defineUDDRC_STAT_OPMODE_SELF_REFRESH (0x3 << 0) /* Self-refresh */ +#defineUDDRC_STAT_OPMODE_MSK (0x7 << 0) /* Operating mode mask */ + +#define UDDRC_PWRCTL (0x30) /* UDDRC Low Power Control Register */ +#defineUDDRC_PWRCTRL_SELFREF_SW(1 << 5)/* Software self-refresh */ + +#define UDDRC_DFIMISC (0x1B0) /* UDDRC DFI Miscellaneous Control Register */ +#defineUDDRC_DFIMISC_DFI_INIT_COMPLETE_EN (1 << 0) /* PHY initialization complete enable signal */ + +#define UDDRC_SWCTRL (0x320) /* UDDRC Software Register Programming Control Enable */ +#defineUDDRC_SWCTRL_SW_DONE(1 << 0)/* Enable quasi-dynamic register programming outside reset */ + +#define UDDRC
[PATCH v3 13/24] 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 --- 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 -- 2.25.1
[PATCH v3 10/24] ARM: at91: sfrbu: add sfrbu registers definitions for sama7g5
Add SFRBU registers definitions for SAMA7G5. Signed-off-by: Claudiu Beznea --- 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 ..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 */ +#defineAT91_SFRBU_PSWBU_PSWKEY (0x4BD20C << 8) /* Specific value mandatory to allow writing of other register bits */ +#defineAT91_SFRBU_PSWBU_STATE (1 << 2)/* Power switch BU state */ +#defineAT91_SFRBU_PSWBU_SOFTSWITCH (1 << 1)/* Power switch BU source selection */ +#defineAT91_SFRBU_PSWBU_CTRL (1 << 0)/* Power switch BU control */ + +#define AT91_SFRBU_25LDOCR (0x0C) /* SFRBU 2.5V LDO Control Register */ +#defineAT91_SFRBU_25LDOCR_LDOANAKEY(0x3B6E18 << 8) /* Specific value mandatory to allow writing of other register bits. */ +#defineAT91_SFRBU_25LDOCR_STATE(1 << 3)/* LDOANA Switch On/Off Control */ +#defineAT91_SFRBU_25LDOCR_LP (1 << 2)/* LDOANA Low-Power Mode Control */ +#defineAT91_SFRBU_PD_VALUE_MSK (0x3) +#defineAT91_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 */ +#defineAT91_FRBU_DDRPWR_STATE (1 << 0)/* DDR Power Mode State */ + +#endif /* CONFIG_SOC_SAMA7 */ + +#endif /* __SAMA7_SFRBU_H__ */ + -- 2.25.1
[PATCH v3 09/24] 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 --- 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.reqr6 /* * 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 -- 2.25.1
[PATCH v3 08/24] 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 --- 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 -- 2.25.1
[PATCH v3 07/24] 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 --- arch/arm/mach-at91/pm_suspend.S | 397 +--- 1 file changed, 205 insertions(+), 192 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 .reqr6 .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 cl
[PATCH v3 06/24] 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 --- 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.reqr6 /* * 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 -- 2.25.1
[PATCH v3 02/24] 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 --- 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 */ -- 2.25.1
[PATCH v3 05/24] ARM: at91: pm: do not initialize pdev
There is no need to initialize pdev. Signed-off-by: Claudiu Beznea --- 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)) -- 2.25.1
[PATCH v3 04/24] 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 --- arch/arm/mach-at91/pm.c | 143 +--- 1 file changed, 91 insertions(+), 52 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(>dev, NULL); @@ -697,64 +700,92 @@ static int __init at91_pm_backup_init(void) securam_fail: put_device(>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; + int ret, mode; - if (!at91_is_pm_mode_active(AT91_PM_BACKUP) && - !at91_is_pm_mode_active(AT91_PM_ULP1)) - return; + ret = at91_pm_backup_init(); + if (ret) { + 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; + } - np = of_find_matching_node(NULL, atmel_shdwc_ids); - if (!np) { - pr_warn("%s: failed to find shdwc!\n", __func__); - goto ulp1_default; + 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); + } } - soc_pm.data.shdwc = of_iomap(np, 0); - of_node_put(np); + if (maps[soc_pm.data.standby_mode] & AT91_PM_IOM
[PATCH v3 03/24] ARM: at91: pm: document at91_soc_pm structure
Document at91_soc_pm structure. Signed-off-by: Claudiu Beznea --- 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); -- 2.25.1
[PATCH v3 01/24] ARM: at91: pm: move pm_bu to soc_pm data structure
Move pm_bu to soc_pm data structure. Signed-off-by: Claudiu Beznea --- 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(); - pm_bu->resume = __pa_symbol(cpu_resume); + soc_pm.bu->suspended = 0; + soc_pm.bu->canary = __pa_symbol(); + soc_pm.bu->resume = __pa_symbol(cpu_resume); return 0; -- 2.25.1
[PATCH v3 00/24] ARM: at91: pm: add support for sama7g5
Hi, This series adds PM support for SAMA7G5. The standby, ulp0, ulp1, and backup modes are supported. Thank you, Claudiu Beznea Changes in v3: - drop: status = "okay" in patch 16/24 Changes in v2: - keep only the generic sama7_dt in patch 22/24 and adapt patch 23/24 - collected tags Claudiu Beznea (23): ARM: at91: pm: move pm_bu to soc_pm data structure ARM: at91: pm: move the setup of soc_pm.bu->suspended ARM: at91: pm: document at91_soc_pm structure ARM: at91: pm: check for different controllers in at91_pm_modes_init() ARM: at91: pm: do not initialize pdev ARM: at91: pm: use r7 instead of tmp1 ARM: at91: pm: avoid push and pop on stack while memory is in self-refersh ARM: at91: pm: s/CONFIG_SOC_SAM9X60/CONFIG_HAVE_AT91_SAM9X60_PLL/g ARM: at91: pm: add support for waiting MCK1..4 ARM: at91: sfrbu: add sfrbu registers definitions for sama7g5 ARM: at91: ddr: add registers definitions for sama7g5's ddr ARM: at91: pm: add self-refresh support for sama7g5 ARM: at91: pm: add support for MCK1..4 save/restore for ulp modes ARM: at91: pm: add support for 2.5V LDO regulator control ARM: at91: pm: wait for ddr power mode off dt-bindings: atmel-sysreg: add bindings for sama7g5 ARM: at91: pm: add sama7g5 ddr controller ARM: at91: pm: add sama7g5 ddr phy controller ARM: at91: pm: save ddr phy calibration data to securam ARM: at91: pm: add backup mode support for SAMA7G5 ARM: at91: pm: add sama7g5's pmc ARM: at91: pm: add pm support for SAMA7G5 ARM: at91: pm: add sama7g5 shdwc Eugen Hristev (1): ARM: at91: sama7: introduce sama7 SoC family .../devicetree/bindings/arm/atmel-sysregs.txt | 14 +- arch/arm/mach-at91/Makefile | 1 + arch/arm/mach-at91/generic.h | 2 + arch/arm/mach-at91/pm.c | 343 ++-- arch/arm/mach-at91/pm.h | 3 + arch/arm/mach-at91/pm_data-offsets.c | 2 + arch/arm/mach-at91/pm_suspend.S | 827 +- arch/arm/mach-at91/sama7.c| 33 + include/soc/at91/sama7-ddr.h | 80 ++ include/soc/at91/sama7-sfrbu.h| 34 + 10 files changed, 1049 insertions(+), 290 deletions(-) create mode 100644 arch/arm/mach-at91/sama7.c create mode 100644 include/soc/at91/sama7-ddr.h create mode 100644 include/soc/at91/sama7-sfrbu.h -- 2.25.1
[PATCH] net: macb: fix the restore of cmp registers
Commit a14d273ba159 ("net: macb: restore cmp registers on resume path") introduces the restore of CMP registers on resume path. In case the IP doesn't support type 2 screeners (zero on DCFG8 register) the struct macb::rx_fs_list::list is not initialized and thus the list_for_each_entry(item, >rx_fs_list.list, list) loop introduced in commit a14d273ba159 ("net: macb: restore cmp registers on resume path") will access an uninitialized list leading to crash. Thus, initialize the struct macb::rx_fs_list::list without taking into account if the IP supports type 2 screeners or not. Fixes: a14d273ba159 ("net: macb: restore cmp registers on resume path") Signed-off-by: Claudiu Beznea --- drivers/net/ethernet/cadence/macb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index c36722541bc4..0db538d089b1 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -3926,6 +3926,7 @@ static int macb_init(struct platform_device *pdev) reg = gem_readl(bp, DCFG8); bp->max_tuples = min((GEM_BFEXT(SCR2CMP, reg) / 3), GEM_BFEXT(T2SCR, reg)); + INIT_LIST_HEAD(>rx_fs_list.list); if (bp->max_tuples > 0) { /* also needs one ethtype match to check IPv4 */ if (GEM_BFEXT(SCR2ETH, reg) > 0) { @@ -3938,7 +3939,6 @@ static int macb_init(struct platform_device *pdev) /* Filtering is supported in hw but don't enable it in kernel now */ dev->hw_features |= NETIF_F_NTUPLE; /* init Rx flow definitions */ - INIT_LIST_HEAD(>rx_fs_list.list); bp->rx_fs_list.count = 0; spin_lock_init(>rx_fs_lock); } else -- 2.25.1
[PATCH v2 24/24] ARM: at91: pm: add sama7g5 shdwc
Add SAMA7G5 SHDWC. Signed-off-by: Claudiu Beznea --- 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 @@ static int __init at91_pm_backup_init(void) static const struct of_device_id atmel_shdwc_ids[] = { { .compatible = "atmel,sama5d2-shdwc" }, { .compatible = "microchip,sam9x60-shdwc" }, + { .compatible = "microchip,sama7g5-shdwc" }, { /* sentinel. */ } }; -- 2.25.1
[PATCH v2 22/24] ARM: at91: sama7: introduce sama7 SoC family
From: Eugen Hristev Introduce new family of SoCs, sama7, and first SoC, sama7g5. Signed-off-by: Eugen Hristev [claudiu.bez...@microchip.com: keep only the sama7_dt] Signed-off-by: Claudiu Beznea --- 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 ..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 + -- 2.25.1
[PATCH v2 23/24] ARM: at91: pm: add pm support for SAMA7G5
Add support for SAMA7G5 power management modes: standby, ulp0, ulp1, backup. Signed-off-by: Claudiu Beznea --- 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 = _info[1] }, + { .compatible = "microchip,sama7g5-ohci", .data = _info[2] }, + { .compatible = "usb-ohci", .data = _info[2] }, + { .compatible = "atmel,at91sam9g45-ehci", .data = _info[2] }, + { .compatible = "usb-ehci", .data = _info[2] }, + { .compatible = "microchip,sama7g5-sdhci", .data = _info[3] }, + { .compatible = "atmel,at91sam9260-rtt",.data = _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 = { -- 2.25.1
[PATCH v2 21/24] ARM: at91: pm: add sama7g5's pmc
Add SAMA7G5's PMC to compatible list. Signed-off-by: Claudiu Beznea --- 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 = _infos[1] }, { .compatible = "atmel,sama5d2-pmc", .data = _infos[1] }, { .compatible = "microchip,sam9x60-pmc", .data = _infos[4] }, + { .compatible = "microchip,sama7g5-pmc", .data = _infos[5] }, { /* sentinel */ }, }; -- 2.25.1
[PATCH v2 20/24] 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 --- 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, #0x20 +#endif + .endm + .text .arm @@ -989,6 +995,7 @@ ulp_exit: ldr r0, .shdwc mov tmp1, #0xA500 add tmp1, tmp1, #0x1 + at91_backup_set_lpm tmp1 str tmp1, [r0, #0] .endm -- 2.25.1
[PATCH v2 19/24] 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 --- 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", ); + 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(); soc_pm.bu->resume = __pa_symbol(cpu_resume); + if (soc_pm.data.ramc_phy) { + of_scan_flat_dt(at91_pm_backup_scan_memcs, ); + if (!located) + goto securam_fail; + + /* DDR3PHY_ZQ0SR0 */ + soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy + + 0x188); + } return 0; -- 2.25.1
[PATCH v2 18/24] 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 --- 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, _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; -- 2.25.1
[PATCH v2 17/24] 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 --- 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 = _infos[1] }, { .compatible = "atmel,at91sam9g45-ddramc", .data = _infos[2] }, { .compatible = "atmel,sama5d3-ddramc", .data = _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++; } -- 2.25.1
[PATCH v2 16/24] dt-bindings: atmel-sysreg: add bindings for sama7g5
Add RAM controller and RAM PHY controller DT bindings. Signed-off-by: Claudiu Beznea --- .../devicetree/bindings/arm/atmel-sysregs.txt | 15 ++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt index 807264a78edc..7cd55a760d41 100644 --- a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt +++ b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt @@ -45,7 +45,8 @@ RAMC SDRAM/DDR Controller required properties: "atmel,at91sam9260-sdramc", "atmel,at91sam9g45-ddramc", "atmel,sama5d3-ddramc", - "microchip,sam9x60-ddramc" + "microchip,sam9x60-ddramc", + "microchip,sama7g5-uddrc" - reg: Should contain registers location and length Examples: @@ -55,6 +56,18 @@ Examples: reg = <0xe800 0x200>; }; +RAMC PHY Controller required properties: +- compatible: Should be "microchip,sama7g5-ddr3phy", "syscon" +- reg: Should contain registers location and length + +Example: + + ddr3phy: ddr3phy@e3804000 { + compatible = "microchip,sama7g5-ddr3phy", "syscon"; + reg = <0xe3804000 0x1000>; + status = "okay"; +}; + SHDWC Shutdown Controller required properties: -- 2.25.1
[PATCH v2 15/24] 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 --- 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, #0xA500 -- 2.25.1
[PATCH v2 14/24] 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 --- 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_MC0 #define AT91_MEMCTRL_SDRAMC1 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 .reqr6 .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 -- 2.25.1
[PATCH v2 13/24] 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 --- 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 -- 2.25.1
[PATCH v2 12/24] ARM: at91: pm: add self-refresh support for sama7g5
Add self-refresh support for SAMA7G5. Signed-off-by: Claudiu Beznea --- 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_MC0 #define AT91_MEMCTRL_SDRAMC1 @@ -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.reqr6 .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
[PATCH v2 11/24] 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 --- 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 ..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 */ +#defineDDR3PHY_PIR_DLLBYP (1 << 17) /* DLL Bypass */ +#defineDDR3PHY_PIR_ITMSRST (1 << 4)/* Interface Timing Module Soft Reset */ +#defineDDR3PHY_PIR_DLLLOCK (1 << 2)/* DLL Lock */ +#defineDDR3PHY_PIR_DLLSRST (1 << 1)/* DLL Soft Rest */ +#defineDDR3PHY_PIR_INIT(1 << 0)/* Initialization Trigger */ + +#define DDR3PHY_PGCR (0x08) /* DDR3PHY PHY General Configuration Register */ +#defineDDR3PHY_PGCR_CKDV1 (1 << 13) /* CK# Disable Value */ +#defineDDR3PHY_PGCR_CKDV0 (1 << 12) /* CK Disable Value */ + +#defineDDR3PHY_PGSR(0x0C) /* DDR3PHY PHY General Status Register */ +#defineDDR3PHY_PGSR_IDONE (1 << 0)/* Initialization Done */ + +#define DDR3PHY_ACIOCR (0x24) /* DDR3PHY AC I/O Configuration Register */ +#defineDDR3PHY_ACIOCR_CSPDD_CS0(1 << 18) /* CS#[0] Power Down Driver */ +#defineDDR3PHY_ACIOCR_CKPDD_CK0(1 << 8)/* CK[0] Power Down Driver */ +#defineDDR3PHY_ACIORC_ACPDD(1 << 3)/* AC Power Down Driver */ + +#define DDR3PHY_DXCCR (0x28) /* DDR3PHY DATX8 Common Configuration Register */ +#defineDDR3PHY_DXCCR_DXPDR (1 << 3)/* Data Power Down Receiver */ + +#define DDR3PHY_DSGCR (0x2C) /* DDR3PHY DDR System General Configuration Register */ +#defineDDR3PHY_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 */ +#defineUDDRC_STAT_SELFREF_TYPE_DIS (0x0 << 4) /* SDRAM is not in Self-refresh */ +#defineUDDRC_STAT_SELFREF_TYPE_PHY (0x1 << 4) /* SDRAM is in Self-refresh, which was caused by PHY Master Request */ +#defineUDDRC_STAT_SELFREF_TYPE_SW (0x2 << 4) /* SDRAM is in Self-refresh, which was not caused solely under Automatic Self-refresh control */ +#defineUDDRC_STAT_SELFREF_TYPE_AUTO(0x3 << 4) /* SDRAM is in Self-refresh, which was caused by Automatic Self-refresh only */ +#defineUDDRC_STAT_SELFREF_TYPE_MSK (0x3 << 4) /* Self-refresh type mask */ +#defineUDDRC_STAT_OPMODE_INIT (0x0 << 0) /* Init */ +#defineUDDRC_STAT_OPMODE_NORMAL(0x1 << 0) /* Normal */ +#defineUDDRC_STAT_OPMODE_PWRDOWN (0x2 << 0) /* Power-down */ +#defineUDDRC_STAT_OPMODE_SELF_REFRESH (0x3 << 0) /* Self-refresh */ +#defineUDDRC_STAT_OPMODE_MSK (0x7 << 0) /* Operating mode mask */ + +#define UDDRC_PWRCTL (0x30) /* UDDRC Low Power Control Register */ +#defineUDDRC_PWRCTRL_SELFREF_SW(1 << 5)/* Software self-refresh */ + +#define UDDRC_DFIMISC (0x1B0) /* UDDRC DFI Miscellaneous Control Register */ +#defineUDDRC_DFIMISC_DFI_INIT_COMPLETE_EN (1 << 0) /* PHY initialization complete enable signal */ + +#define UDDRC_SWCTRL (0x320) /* UDDRC Software Register Programming Control Enable */ +#defineUDDRC_SWCTRL_SW_DONE(1 << 0)/* Enable quasi-dynamic register programming outside reset */ + +#define UDDRC
[PATCH v2 08/24] 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 --- 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 -- 2.25.1
[PATCH v2 09/24] 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 --- 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.reqr6 /* * 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 -- 2.25.1
[PATCH v2 10/24] ARM: at91: sfrbu: add sfrbu registers definitions for sama7g5
Add SFRBU registers definitions for SAMA7G5. Signed-off-by: Claudiu Beznea --- 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 ..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 */ +#defineAT91_SFRBU_PSWBU_PSWKEY (0x4BD20C << 8) /* Specific value mandatory to allow writing of other register bits */ +#defineAT91_SFRBU_PSWBU_STATE (1 << 2)/* Power switch BU state */ +#defineAT91_SFRBU_PSWBU_SOFTSWITCH (1 << 1)/* Power switch BU source selection */ +#defineAT91_SFRBU_PSWBU_CTRL (1 << 0)/* Power switch BU control */ + +#define AT91_SFRBU_25LDOCR (0x0C) /* SFRBU 2.5V LDO Control Register */ +#defineAT91_SFRBU_25LDOCR_LDOANAKEY(0x3B6E18 << 8) /* Specific value mandatory to allow writing of other register bits. */ +#defineAT91_SFRBU_25LDOCR_STATE(1 << 3)/* LDOANA Switch On/Off Control */ +#defineAT91_SFRBU_25LDOCR_LP (1 << 2)/* LDOANA Low-Power Mode Control */ +#defineAT91_SFRBU_PD_VALUE_MSK (0x3) +#defineAT91_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 */ +#defineAT91_FRBU_DDRPWR_STATE (1 << 0)/* DDR Power Mode State */ + +#endif /* CONFIG_SOC_SAMA7 */ + +#endif /* __SAMA7_SFRBU_H__ */ + -- 2.25.1
[PATCH v2 07/24] 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 --- arch/arm/mach-at91/pm_suspend.S | 397 +--- 1 file changed, 205 insertions(+), 192 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 .reqr6 .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 cl
[PATCH v2 06/24] 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 --- 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.reqr6 /* * 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 -- 2.25.1
[PATCH v2 05/24] ARM: at91: pm: do not initialize pdev
There is no need to initialize pdev. Signed-off-by: Claudiu Beznea --- 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)) -- 2.25.1
[PATCH v2 04/24] 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 --- arch/arm/mach-at91/pm.c | 143 +--- 1 file changed, 91 insertions(+), 52 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(>dev, NULL); @@ -697,64 +700,92 @@ static int __init at91_pm_backup_init(void) securam_fail: put_device(>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; + int ret, mode; - if (!at91_is_pm_mode_active(AT91_PM_BACKUP) && - !at91_is_pm_mode_active(AT91_PM_ULP1)) - return; + ret = at91_pm_backup_init(); + if (ret) { + 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; + } - np = of_find_matching_node(NULL, atmel_shdwc_ids); - if (!np) { - pr_warn("%s: failed to find shdwc!\n", __func__); - goto ulp1_default; + 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); + } } - soc_pm.data.shdwc = of_iomap(np, 0); - of_node_put(np); + if (maps[soc_pm.data.standby_mode] & AT91_PM_IOM
[PATCH v2 03/24] ARM: at91: pm: document at91_soc_pm structure
Document at91_soc_pm structure. Signed-off-by: Claudiu Beznea --- 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); -- 2.25.1
[PATCH v2 02/24] 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 --- 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 */ -- 2.25.1
[PATCH v2 01/24] ARM: at91: pm: move pm_bu to soc_pm data structure
Move pm_bu to soc_pm data structure. Signed-off-by: Claudiu Beznea --- 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(); - pm_bu->resume = __pa_symbol(cpu_resume); + soc_pm.bu->suspended = 0; + soc_pm.bu->canary = __pa_symbol(); + soc_pm.bu->resume = __pa_symbol(cpu_resume); return 0; -- 2.25.1
[PATCH v2 00/24] ARM: at91: pm: add support for sama7g5
Hi, This series adds PM support for SAMA7G5. The standby, ulp0, ulp1, and backup modes are supported. Thank you, Claudiu Beznea Changes in v2: - keep only the generic sama7_dt in patch 22/24 and adapt patch 23/24 - collected tags Claudiu Beznea (23): ARM: at91: pm: move pm_bu to soc_pm data structure ARM: at91: pm: move the setup of soc_pm.bu->suspended ARM: at91: pm: document at91_soc_pm structure ARM: at91: pm: check for different controllers in at91_pm_modes_init() ARM: at91: pm: do not initialize pdev ARM: at91: pm: use r7 instead of tmp1 ARM: at91: pm: avoid push and pop on stack while memory is in self-refersh ARM: at91: pm: s/CONFIG_SOC_SAM9X60/CONFIG_HAVE_AT91_SAM9X60_PLL/g ARM: at91: pm: add support for waiting MCK1..4 ARM: at91: sfrbu: add sfrbu registers definitions for sama7g5 ARM: at91: ddr: add registers definitions for sama7g5's ddr ARM: at91: pm: add self-refresh support for sama7g5 ARM: at91: pm: add support for MCK1..4 save/restore for ulp modes ARM: at91: pm: add support for 2.5V LDO regulator control ARM: at91: pm: wait for ddr power mode off dt-bindings: atmel-sysreg: add bindings for sama7g5 ARM: at91: pm: add sama7g5 ddr controller ARM: at91: pm: add sama7g5 ddr phy controller ARM: at91: pm: save ddr phy calibration data to securam ARM: at91: pm: add backup mode support for SAMA7G5 ARM: at91: pm: add sama7g5's pmc ARM: at91: pm: add pm support for SAMA7G5 ARM: at91: pm: add sama7g5 shdwc Eugen Hristev (1): ARM: at91: sama7: introduce sama7 SoC family .../devicetree/bindings/arm/atmel-sysregs.txt | 15 +- arch/arm/mach-at91/Makefile | 1 + arch/arm/mach-at91/generic.h | 2 + arch/arm/mach-at91/pm.c | 343 ++-- arch/arm/mach-at91/pm.h | 3 + arch/arm/mach-at91/pm_data-offsets.c | 2 + arch/arm/mach-at91/pm_suspend.S | 827 +- arch/arm/mach-at91/sama7.c| 33 + include/soc/at91/sama7-ddr.h | 80 ++ include/soc/at91/sama7-sfrbu.h| 34 + 10 files changed, 1050 insertions(+), 290 deletions(-) create mode 100644 arch/arm/mach-at91/sama7.c create mode 100644 include/soc/at91/sama7-ddr.h create mode 100644 include/soc/at91/sama7-sfrbu.h -- 2.25.1
[PATCH] ARM: configs: at91_dt_defconfig: configs for sam9x60
Enable CONFIG_NO_HZ_IDLE and CONFIG_HIGH_RES_TIMERS=y to be used in conjunction with PIT64B present on SAM9X60. Signed-off-by: Claudiu Beznea --- arch/arm/configs/at91_dt_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 6403b064e8dc..bd749977b566 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -1,6 +1,8 @@ # CONFIG_LOCALVERSION_AUTO is not set # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -- 2.25.1
[PATCH] eeprom: at24: avoid adjusting offset for 24AA025E{48, 64}
Some EEPROMs could be used only for MAC storage. In this case the EEPROM areas where MACs resides could be modeled as NVMEM cells (directly via DT bindings) such that the already available networking infrastructure to read properly the MAC addresses (via of_get_mac_address()). Add "atmel,24mac02e4", "atmel,24mac02e4" compatible for the usage w/ 24AA025E{48, 64} type of EEPROMs and adapt the driver to not do offset adjustments. Signed-off-by: Claudiu Beznea --- Hi Bartosz, For the previously available compatibles the offset adjustment is done (probably for compatibility w/ old DT bindings?). In my scenario 24AA025E48 is used in setup with macb driver which is calling of_get_mac_address() to get the proper NVMEM cell in EEPROM where the MAC resides and read directly from there. We modeled the EEPROM and NVMEM cell in DT as follows: { // ... eeprom0: eeprom0@52 { compatible = "atmel,24mac02e4"; #address-cells = <1>; #size-cells = <0>; reg = <0x52>; pagesize = <16>; size = <256>; status = "okay"; eeprom0_eui48: eui48@fa { reg = <0xfa 0x6>; }; }; }; { // ... nvmem-cells = <_eui48>; nvmem-cell-names = "mac-address"; // ... }; Let me know if some other approach needs to be taken into account in at24 driver for this to work. Thank you, Claudiu Beznea drivers/misc/eeprom/at24.c | 69 ++ 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 926408b41270..ae2fbcb5e83d 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -123,17 +123,19 @@ MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)"); struct at24_chip_data { u32 byte_len; u8 flags; + u8 adjoff; void (*read_post)(unsigned int off, char *buf, size_t count); }; -#define AT24_CHIP_DATA(_name, _len, _flags)\ +#define AT24_CHIP_DATA(_name, _len, _flags, _adjoff) \ static const struct at24_chip_data _name = {\ - .byte_len = _len, .flags = _flags, \ + .byte_len = _len, .flags = _flags, .adjoff = _adjoff, \ } -#define AT24_CHIP_DATA_CB(_name, _len, _flags, _read_post) \ +#define AT24_CHIP_DATA_CB(_name, _len, _flags, _adjoff, _read_post)\ static const struct at24_chip_data _name = {\ .byte_len = _len, .flags = _flags, \ + .adjoff = _adjoff, \ .read_post = _read_post,\ } @@ -158,48 +160,52 @@ static void at24_read_post_vaio(unsigned int off, char *buf, size_t count) } /* needs 8 addresses as A0-A2 are ignored */ -AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR); +AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR, 0); /* old variants can't be handled with this generic entry! */ -AT24_CHIP_DATA(at24_data_24c01, 1024 / 8, 0); +AT24_CHIP_DATA(at24_data_24c01, 1024 / 8, 0, 0); AT24_CHIP_DATA(at24_data_24cs01, 16, - AT24_FLAG_SERIAL | AT24_FLAG_READONLY); -AT24_CHIP_DATA(at24_data_24c02, 2048 / 8, 0); + AT24_FLAG_SERIAL | AT24_FLAG_READONLY, 0); +AT24_CHIP_DATA(at24_data_24c02, 2048 / 8, 0, 0); AT24_CHIP_DATA(at24_data_24cs02, 16, - AT24_FLAG_SERIAL | AT24_FLAG_READONLY); + AT24_FLAG_SERIAL | AT24_FLAG_READONLY, 0); AT24_CHIP_DATA(at24_data_24mac402, 48 / 8, - AT24_FLAG_MAC | AT24_FLAG_READONLY); + AT24_FLAG_MAC | AT24_FLAG_READONLY, 1); AT24_CHIP_DATA(at24_data_24mac602, 64 / 8, - AT24_FLAG_MAC | AT24_FLAG_READONLY); + AT24_FLAG_MAC | AT24_FLAG_READONLY, 1); +AT24_CHIP_DATA(at24_data_24mac02e4, 48 / 8, + AT24_FLAG_MAC | AT24_FLAG_READONLY, 0); +AT24_CHIP_DATA(at24_data_24mac02e6, 64 / 8, + AT24_FLAG_MAC | AT24_FLAG_READONLY, 0); /* spd is a 24c02 in memory DIMMs */ AT24_CHIP_DATA(at24_data_spd, 2048 / 8, - AT24_FLAG_READONLY | AT24_FLAG_IRUGO); + AT24_FLAG_READONLY | AT24_FLAG_IRUGO, 0); /* 24c02_vaio is a 24c02 on some Sony laptops */ AT24_CHIP_DATA_CB(at24_data_24c02_vaio, 2048 / 8, - AT24_FLAG_READONLY | AT24_FLAG_IRUGO, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO, 0, at24_read_post_vaio); -AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0); +AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0, 0); AT24_CHIP_DATA(at24_data_24cs04, 16, - AT24_FLAG_SERIAL | AT24_FLAG_READONLY); + AT24_FLAG_SERIAL | AT24_FLAG_READONLY, 0); /* 24rf08 quirk is handled at i2c-core */ -AT24_CHIP_DATA(at24_data_24c08
[PATCH 1/1] net: macb: restore cmp registers on resume path
Restore CMP screener registers on resume path. Fixes: c1e85c6ce57ef ("net: macb: save/restore the remaining registers and features") Signed-off-by: Claudiu Beznea --- drivers/net/ethernet/cadence/macb_main.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index f56f3dbbc015..ffd56a23f8b0 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -3269,6 +3269,9 @@ static void gem_prog_cmp_regs(struct macb *bp, struct ethtool_rx_flow_spec *fs) bool cmp_b = false; bool cmp_c = false; + if (!macb_is_gem(bp)) + return; + tp4sp_v = &(fs->h_u.tcp_ip4_spec); tp4sp_m = &(fs->m_u.tcp_ip4_spec); @@ -3637,6 +3640,7 @@ static void macb_restore_features(struct macb *bp) { struct net_device *netdev = bp->dev; netdev_features_t features = netdev->features; + struct ethtool_rx_fs_item *item; /* TX checksum offload */ macb_set_txcsum_feature(bp, features); @@ -3645,6 +3649,9 @@ static void macb_restore_features(struct macb *bp) macb_set_rxcsum_feature(bp, features); /* RX Flow Filters */ + list_for_each_entry(item, >rx_fs_list.list, list) + gem_prog_cmp_regs(bp, >fs); + macb_set_rxflow_feature(bp, features); } -- 2.25.1
[PATCH v2 1/1] power: reset: at91-reset: use devm_of_iomap
Use devm_of_iomap() to map resources. This will avoid the necessity to track the mapped resources and free them on failure path or on remove. Reported-by: kernel test robot Reported-by: Dan Carpenter Suggested-by: Nicolas Ferre Signed-off-by: Claudiu Beznea --- Changes in v2: - use devm_of_iomap() - change commit description and title to match to the new approach - add Suggested-by tag drivers/power/reset/at91-reset.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 3ff9d93a5226..026649409135 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -192,7 +192,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) if (!reset) return -ENOMEM; - reset->rstc_base = of_iomap(pdev->dev.of_node, 0); + reset->rstc_base = devm_of_iomap(>dev, pdev->dev.of_node, 0, NULL); if (!reset->rstc_base) { dev_err(>dev, "Could not map reset controller address\n"); return -ENODEV; @@ -202,7 +202,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) /* we need to shutdown the ddr controller, so get ramc base */ for_each_matching_node_and_match(np, at91_ramc_of_match, ) { reset->ramc_lpr = (u32)match->data; - reset->ramc_base[idx] = of_iomap(np, 0); + reset->ramc_base[idx] = devm_of_iomap(>dev, np, 0, NULL); if (!reset->ramc_base[idx]) { dev_err(>dev, "Could not map ram controller address\n"); of_node_put(np); -- 2.25.1
[PATCH v2 6/6] clk: at91: clk-master: improve readability by using local variables
Improve readability in clk_sama7g5_master_set() by using local variables. Suggested-by: Nicolas Ferre Signed-off-by: Claudiu Beznea --- drivers/clk/at91/clk-master.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index 1b2962289629..76b2467b32dc 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -720,6 +720,8 @@ static void clk_sama7g5_master_set(struct clk_master *master, unsigned long flags; unsigned int val, cparent; unsigned int enable = status ? AT91_PMC_MCR_V2_EN : 0; + unsigned int parent = master->parent << PMC_MCR_CSS_SHIFT; + unsigned int div = master->div << MASTER_DIV_SHIFT; spin_lock_irqsave(master->lock, flags); @@ -729,9 +731,7 @@ static void clk_sama7g5_master_set(struct clk_master *master, regmap_update_bits(master->regmap, AT91_PMC_MCR_V2, enable | AT91_PMC_MCR_V2_CSS | AT91_PMC_MCR_V2_DIV | AT91_PMC_MCR_V2_CMD | AT91_PMC_MCR_V2_ID_MSK, - enable | (master->parent << PMC_MCR_CSS_SHIFT) | - (master->div << MASTER_DIV_SHIFT) | - AT91_PMC_MCR_V2_CMD | + enable | parent | div | AT91_PMC_MCR_V2_CMD | AT91_PMC_MCR_V2_ID(master->id)); cparent = (val & AT91_PMC_MCR_V2_CSS) >> PMC_MCR_CSS_SHIFT; -- 2.25.1
[PATCH v2 3/6] clk: at91: sama7g5: add securam's peripheral clock
Add SECURAM's peripheral clock. Signed-off-by: Claudiu Beznea Acked-by: Nicolas Ferre --- drivers/clk/at91/sama7g5.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 9e1ec48c4474..9c87b50abbae 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -377,6 +377,7 @@ static const struct { u8 id; } sama7g5_periphck[] = { { .n = "pioA_clk", .p = "mck0", .id = 11, }, + { .n = "securam_clk", .p = "mck0", .id = 18, }, { .n = "sfr_clk", .p = "mck1", .id = 19, }, { .n = "hsmc_clk", .p = "mck1", .id = 21, }, { .n = "xdmac0_clk",.p = "mck1", .id = 22, }, -- 2.25.1
[PATCH v2 2/6] clk: at91: pmc: execute suspend/resume only for backup mode
Before going to backup mode architecture specific PM code sets the first word in securam (and it will be cleared in a subsequent commit for the rest of power saving modes). Thus take this into account when suspending/resuming clocks. This will avoid executing unnecessary instructions when suspending to non backup modes. Since the clear of the 1st word in securam will be done in a subsequent commit the current commit will not broke the current behavior since up to this moment the suspend/resume were executed for all AT91 PM modes. The difference now is that the suspend/resume for clocks will be executed for the rest of AT91 PM modes just after the 1st enter/exit to/from backup mode. Also this commit changed the postcore_initcall() with subsys_initcall() to be able to execute of_find_compatible_node() since this was not available at the moment of postcore_initcall(). This should not alter the tcb_clksrc since the changes are related to clocks suspend/resume procedure that will be executed at the user space request, thus long ago after postcore_initcall(). Signed-off-by: Claudiu Beznea --- drivers/clk/at91/pmc.c | 48 ++ 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 77b57c9f5dcb..c226d33cd899 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -110,13 +112,35 @@ struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem, } #ifdef CONFIG_PM + +/* Address in SECURAM that say if we suspend to backup mode. */ +static void __iomem *at91_pmc_backup_suspend; + static int at91_pmc_suspend(void) { + unsigned int backup; + + if (!at91_pmc_backup_suspend) + return 0; + + backup = *(unsigned int *)at91_pmc_backup_suspend; + if (!backup) + return 0; + return clk_save_context(); } static void at91_pmc_resume(void) { + unsigned int backup; + + if (!at91_pmc_backup_suspend) + return; + + backup = *(unsigned int *)at91_pmc_backup_suspend; + if (!backup) + return; + clk_restore_context(); } @@ -125,24 +149,30 @@ static struct syscore_ops pmc_syscore_ops = { .resume = at91_pmc_resume, }; -static const struct of_device_id sama5d2_pmc_dt_ids[] = { - { .compatible = "atmel,sama5d2-pmc" }, - { /* sentinel */ } -}; - static int __init pmc_register_ops(void) { + struct platform_device *pdev; struct device_node *np; - np = of_find_matching_node(NULL, sama5d2_pmc_dt_ids); + np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-securam"); if (!np) - return 0; + return -ENODEV; + + pdev = of_find_device_by_node(np); of_node_put(np); + if (!pdev) + return -ENODEV; + + at91_pmc_backup_suspend = of_iomap(np, 0); + if (!at91_pmc_backup_suspend) { + pr_warn("%s(): unable to map securam\n", __func__); + return -ENOMEM; + } register_syscore_ops(_syscore_ops); return 0; } -/* This has to happen before arch_initcall because of the tcb_clksrc driver */ -postcore_initcall(pmc_register_ops); + +subsys_initcall(pmc_register_ops); #endif -- 2.25.1
[PATCH v2 4/6] clk: at91: clk-master: 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. With this, update also clk-master.c. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/clk-master.c | 50 --- include/linux/clk/at91_pmc.h | 26 ++ 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index 21e82111890d..736406528824 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -17,15 +17,7 @@ #define MASTER_DIV_SHIFT 8 #define MASTER_DIV_MASK0x7 -#define PMC_MCR0x30 -#define PMC_MCR_ID_MSK GENMASK(3, 0) -#define PMC_MCR_CMDBIT(7) -#define PMC_MCR_DIVGENMASK(10, 8) -#define PMC_MCR_CSSGENMASK(20, 16) #define PMC_MCR_CSS_SHIFT (16) -#define PMC_MCR_EN BIT(28) - -#define PMC_MCR_ID(x) ((x) & PMC_MCR_ID_MSK) #define MASTER_MAX_ID 4 @@ -682,20 +674,22 @@ static void clk_sama7g5_master_set(struct clk_master *master, { unsigned long flags; unsigned int val, cparent; - unsigned int enable = status ? PMC_MCR_EN : 0; + unsigned int enable = status ? AT91_PMC_MCR_V2_EN : 0; spin_lock_irqsave(master->lock, flags); - regmap_write(master->regmap, PMC_MCR, PMC_MCR_ID(master->id)); - regmap_read(master->regmap, PMC_MCR, ); - regmap_update_bits(master->regmap, PMC_MCR, - enable | PMC_MCR_CSS | PMC_MCR_DIV | - PMC_MCR_CMD | PMC_MCR_ID_MSK, + regmap_write(master->regmap, AT91_PMC_MCR_V2, +AT91_PMC_MCR_V2_ID(master->id)); + regmap_read(master->regmap, AT91_PMC_MCR_V2, ); + regmap_update_bits(master->regmap, AT91_PMC_MCR_V2, + enable | AT91_PMC_MCR_V2_CSS | AT91_PMC_MCR_V2_DIV | + AT91_PMC_MCR_V2_CMD | AT91_PMC_MCR_V2_ID_MSK, enable | (master->parent << PMC_MCR_CSS_SHIFT) | (master->div << MASTER_DIV_SHIFT) | - PMC_MCR_CMD | PMC_MCR_ID(master->id)); + AT91_PMC_MCR_V2_CMD | + AT91_PMC_MCR_V2_ID(master->id)); - cparent = (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT; + cparent = (val & AT91_PMC_MCR_V2_CSS) >> PMC_MCR_CSS_SHIFT; /* Wait here only if parent is being changed. */ while ((cparent != master->parent) && !clk_master_ready(master)) @@ -720,10 +714,12 @@ static void clk_sama7g5_master_disable(struct clk_hw *hw) spin_lock_irqsave(master->lock, flags); - regmap_write(master->regmap, PMC_MCR, master->id); - regmap_update_bits(master->regmap, PMC_MCR, - PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK, - PMC_MCR_CMD | PMC_MCR_ID(master->id)); + regmap_write(master->regmap, AT91_PMC_MCR_V2, master->id); + regmap_update_bits(master->regmap, AT91_PMC_MCR_V2, + AT91_PMC_MCR_V2_EN | AT91_PMC_MCR_V2_CMD | + AT91_PMC_MCR_V2_ID_MSK, + AT91_PMC_MCR_V2_CMD | + AT91_PMC_MCR_V2_ID(master->id)); spin_unlock_irqrestore(master->lock, flags); } @@ -736,12 +732,12 @@ static int clk_sama7g5_master_is_enabled(struct clk_hw *hw) spin_lock_irqsave(master->lock, flags); - regmap_write(master->regmap, PMC_MCR, master->id); - regmap_read(master->regmap, PMC_MCR, ); + regmap_write(master->regmap, AT91_PMC_MCR_V2, master->id); + regmap_read(master->regmap, AT91_PMC_MCR_V2, ); spin_unlock_irqrestore(master->lock, flags); - return !!(val & PMC_MCR_EN); + return !!(val & AT91_PMC_MCR_V2_EN); } static int clk_sama7g5_master_set_rate(struct clk_hw *hw, unsigned long rate, @@ -837,10 +833,10 @@ at91_clk_sama7g5_register_master(struct regmap *regmap, master->mux_table = mux_table; spin_lock_irqsave(master->lock, flags); - regmap_write(master->regmap, PMC_MCR, master->id); - regmap_read(master->regmap, PMC_MCR, ); - master->parent = (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT; - master->div = (val & PMC_MCR_DIV) >> MASTER_DIV_SHIFT; + regmap_write(master->regmap, AT91_PMC_MCR_V2, master->id); + regmap_read(master->regmap, AT91_PMC_MCR_V2, ); + master->parent = (val & AT91_PMC_MCR_V2_CSS) >> PMC_MCR_CSS_SHIFT; + master->div = (val & AT91_PMC_MCR_V2_DIV) >> MASTER_DIV_SHIFT; spin_unlock_irqrestore(master->lock, flags);
[PATCH v2 0/6] clk: at91: updates for power management and dvfs
Hi, This series addresses the power management for SAMA7G5 and also updates the master clock prescaller and master clock divider drivers to accommodate the requests at [1]. The power management part is implemented by adding save_context()/restore_context() on each clock driver (patch 1/6). Since the PM part is necessary only for backup mode (supported on SAMA5D2 and SAMA7G5) the pmc.c has been adapted to call the save_context()/restore_context() only on switches to/from backup mode (patch 2/6). Patch 3/6 adds the securam clock on SAMA7G5. This is necessary for backup mode of SAMA7G5. Patch 4/6 adds registers definitions for the new master clocks (MCK1..4) of SAMA7G5 and adapt the clk-master.c. The defines exported in include/linux/clk/at91_pmc.h will be also used by platform specific PM code. Patch 5/6 adpat the master clock divider and master clock prescaller to address the requests at [1]. Patch 6/6 clean up a bit the code in clk-master as suggested by Nicolas. Thank you, Claudiu Beznea [1] https://lore.kernel.org/lkml/20210105104426.4tmgc2l3vyicwedd@vireshk-i7/ Changes in v2: - addressed code review comments - collected tags Claudiu Beznea (6): clk: at91: re-factor clocks suspend/resume clk: at91: pmc: execute suspend/resume only for backup mode clk: at91: sama7g5: add securam's peripheral clock clk: at91: clk-master: add register definition for sama7g5's master clock clk: at91: clk-master: update for dvfs clk: at91: clk-master: improve readability by using local variables drivers/clk/at91/at91rm9200.c | 2 +- drivers/clk/at91/at91sam9260.c | 2 +- drivers/clk/at91/at91sam9g45.c | 2 +- drivers/clk/at91/at91sam9n12.c | 2 +- drivers/clk/at91/at91sam9rl.c | 2 +- drivers/clk/at91/at91sam9x5.c | 2 +- drivers/clk/at91/clk-generated.c| 46 +++- drivers/clk/at91/clk-main.c | 66 + drivers/clk/at91/clk-master.c | 396 +--- drivers/clk/at91/clk-peripheral.c | 40 ++- drivers/clk/at91/clk-pll.c | 37 +++ drivers/clk/at91/clk-programmable.c | 29 +- drivers/clk/at91/clk-sam9x60-pll.c | 68 - drivers/clk/at91/clk-system.c | 20 ++ drivers/clk/at91/clk-usb.c | 27 ++ drivers/clk/at91/clk-utmi.c | 47 +++- drivers/clk/at91/dt-compat.c| 2 +- drivers/clk/at91/pmc.c | 175 +++- drivers/clk/at91/pmc.h | 27 +- drivers/clk/at91/sam9x60.c | 2 +- drivers/clk/at91/sama5d2.c | 2 +- drivers/clk/at91/sama5d3.c | 2 +- drivers/clk/at91/sama5d4.c | 2 +- drivers/clk/at91/sama7g5.c | 3 +- include/linux/clk/at91_pmc.h| 26 ++ 25 files changed, 752 insertions(+), 277 deletions(-) -- 2.25.1
[PATCH v2 5/6] clk: at91: clk-master: update for dvfs
SAMA7G5 supports CPU DVFS. The hardware block diagram for the clock system generating CPU clock is as follows: ++ +-->|divider1|--> CPU clock | ++ ++ +--+ | ++ |CPU PLL |-->|prescaller|--+-->|divider0|--> MCK0 clock ++ +--+ ++ The divider1 is not implemented in software since the supported CPU frequencies could be directly retrieved from CPU PLL + prescaller. Every time the CPU clock needs to be changed the MCK0 should also be changed to avoid its over/under clocking and also to preserve its initial value (200MHz). MCK0 feeds IPs that are glitch free aware. The initial approach for implementing DVFS was to implement MCK0 and CPU clocks as 2 different Linux clocks, to pass these two clocks to CPUFreq driver and in CPUFreq driver to run clk_set_rate() on CPU and MCK clocks accordingly. E.g. if 1GHz speed was requested by CPUFreq subsystem the following were executed in CPUFreq driver: /* ... */ clk_set_rate(mck0, intermediary_freq_to_avoid_over_under_clocking); clk_set_rate(cpu, 10); clk_set_rate(mck0, initial_freq); / ... */ However, it has been proposed in [1] to use the generic cpufreq-dt driver and to overload the necessary clocks operations in the proper clock driver. To address this proposal the master clock prescaller registers a clock notifier that will update properly the master clock divider on PRE_RATE_CHANGE and POST_RATE_CHANGE events to avoid master clock divider over/under clocking and also to preserve its initial value (200MHz). [1] https://lore.kernel.org/lkml/1609842147-8161-1-git-send-email-claudiu.bez...@microchip.com/ Signed-off-by: Claudiu Beznea --- drivers/clk/at91/at91rm9200.c | 2 +- drivers/clk/at91/at91sam9260.c | 2 +- drivers/clk/at91/at91sam9g45.c | 2 +- drivers/clk/at91/at91sam9n12.c | 2 +- drivers/clk/at91/at91sam9rl.c | 2 +- drivers/clk/at91/at91sam9x5.c | 2 +- drivers/clk/at91/clk-master.c | 187 - drivers/clk/at91/dt-compat.c | 2 +- drivers/clk/at91/pmc.h | 3 +- drivers/clk/at91/sam9x60.c | 2 +- drivers/clk/at91/sama5d2.c | 2 +- drivers/clk/at91/sama5d3.c | 2 +- drivers/clk/at91/sama5d4.c | 2 +- drivers/clk/at91/sama7g5.c | 2 +- 14 files changed, 130 insertions(+), 84 deletions(-) diff --git a/drivers/clk/at91/at91rm9200.c b/drivers/clk/at91/at91rm9200.c index 428a6f4b9ebc..f8df6064d55d 100644 --- a/drivers/clk/at91/at91rm9200.c +++ b/drivers/clk/at91/at91rm9200.c @@ -144,7 +144,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np) _master_layout, _mck_characteristics, _mck_lock, CLK_SET_RATE_GATE, - INT_MIN); + INT_MIN, 0); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9260.c b/drivers/clk/at91/at91sam9260.c index b29843bea278..8db7bf141b45 100644 --- a/drivers/clk/at91/at91sam9260.c +++ b/drivers/clk/at91/at91sam9260.c @@ -420,7 +420,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np, _master_layout, data->mck_characteristics, _mck_lock, - CLK_SET_RATE_GATE, INT_MIN); + CLK_SET_RATE_GATE, INT_MIN, 0); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9g45.c b/drivers/clk/at91/at91sam9g45.c index 15da0dfe3ef2..c139169b2d40 100644 --- a/drivers/clk/at91/at91sam9g45.c +++ b/drivers/clk/at91/at91sam9g45.c @@ -155,7 +155,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np) _master_layout, _characteristics, _mck_lock, - CLK_SET_RATE_GATE, INT_MIN); + CLK_SET_RATE_GATE, INT_MIN, 0); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9n12.c b/drivers/clk/at91/at91sam9n12.c index 7fe435f4b46b..a4e46c4026d0 100644 --- a/drivers/clk/at91/at91sam9n12.c +++ b/drivers/clk/at91/at91sam9n12.c @@ -182,7 +182,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np) _master_layout, _characteristics, _mck_lock, - CLK_SET_RATE_GATE, INT_MIN); + CLK_SET_RAT
[PATCH v2 1/6] clk: at91: re-factor clocks suspend/resume
SAMA5D2 and SAMA7G5 have a special power saving mode (backup mode) where most of the SoC's components are powered off (including PMC). Resuming from this mode is done with the help of bootloader. Peripherals are not aware of the power saving mode thus most of them are disabling clocks in proper suspend API and re-enable them in resume API without taking into account the previously setup rate. Moreover some of the peripherals are acting as wakeup sources and are not disabling the clocks in this scenario, when suspending. Since backup mode cuts the power for peripherals, in resume part these clocks needs to be re-configured. The initial PMC suspend/resume code was designed with SAMA5D2's PMC in mind. SAMA7G's PMC is different (few new functionalities, different registers offsets, different offsets in registers for each functionalities). To address both SAMA5D2 and SAMA7G5 PMC add .save_context()/.resume_context() support to each clocks driver and call this from PMC driver. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/clk-generated.c| 46 +-- drivers/clk/at91/clk-main.c | 66 ++ drivers/clk/at91/clk-master.c | 183 ++-- drivers/clk/at91/clk-peripheral.c | 40 +- drivers/clk/at91/clk-pll.c | 37 ++ drivers/clk/at91/clk-programmable.c | 29 - drivers/clk/at91/clk-sam9x60-pll.c | 68 ++- drivers/clk/at91/clk-system.c | 20 +++ drivers/clk/at91/clk-usb.c | 27 drivers/clk/at91/clk-utmi.c | 47 ++- drivers/clk/at91/pmc.c | 149 ++ drivers/clk/at91/pmc.h | 24 ++-- 12 files changed, 556 insertions(+), 180 deletions(-) diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index b4fc8d71daf2..a3ff46e251c5 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -27,6 +27,7 @@ struct clk_generated { u32 id; u32 gckdiv; const struct clk_pcr_layout *layout; + struct at91_clk_pms pms; u8 parent_id; int chg_pid; }; @@ -34,25 +35,35 @@ struct clk_generated { #define to_clk_generated(hw) \ container_of(hw, struct clk_generated, hw) -static int clk_generated_enable(struct clk_hw *hw) +static int clk_generated_set(struct clk_generated *gck, int status) { - struct clk_generated *gck = to_clk_generated(hw); unsigned long flags; - - pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", -__func__, gck->gckdiv, gck->parent_id); + unsigned int enable = status ? AT91_PMC_PCR_GCKEN : 0; spin_lock_irqsave(gck->lock, flags); regmap_write(gck->regmap, gck->layout->offset, (gck->id & gck->layout->pid_mask)); regmap_update_bits(gck->regmap, gck->layout->offset, AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask | - gck->layout->cmd | AT91_PMC_PCR_GCKEN, + gck->layout->cmd | enable, field_prep(gck->layout->gckcss_mask, gck->parent_id) | gck->layout->cmd | FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) | - AT91_PMC_PCR_GCKEN); + enable); spin_unlock_irqrestore(gck->lock, flags); + + return 0; +} + +static int clk_generated_enable(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + + pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", +__func__, gck->gckdiv, gck->parent_id); + + clk_generated_set(gck, 1); + return 0; } @@ -239,6 +250,23 @@ static int clk_generated_set_rate(struct clk_hw *hw, return 0; } +static int clk_generated_save_context(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + + gck->pms.status = clk_generated_is_enabled(>hw); + + return 0; +} + +static void clk_generated_restore_context(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + + if (gck->pms.status) + clk_generated_set(gck, gck->pms.status); +} + static const struct clk_ops generated_ops = { .enable = clk_generated_enable, .disable = clk_generated_disable, @@ -248,6 +276,8 @@ static const struct clk_ops generated_ops = { .get_parent = clk_generated_get_parent, .set_parent = clk_generated_set_parent, .set_rate = clk_generated_set_rate, + .save_context = clk_generated_save_context, + .restore_context = clk_generated_restore_context, }; /** @@ -314,8 +344,6 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, if (ret) { kfree(gck); hw = ERR_PTR(ret); - }
[PATCH 21/24] ARM: at91: pm: add sama7g5's pmc
Add SAMA7G5's PMC to compatible list. Signed-off-by: Claudiu Beznea --- 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 = _infos[1] }, { .compatible = "atmel,sama5d2-pmc", .data = _infos[1] }, { .compatible = "microchip,sam9x60-pmc", .data = _infos[4] }, + { .compatible = "microchip,sama7g5-pmc", .data = _infos[5] }, { /* sentinel */ }, }; -- 2.25.1
[PATCH 19/24] 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 --- 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", ); + 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(); soc_pm.bu->resume = __pa_symbol(cpu_resume); + if (soc_pm.data.ramc_phy) { + of_scan_flat_dt(at91_pm_backup_scan_memcs, ); + if (!located) + goto securam_fail; + + /* DDR3PHY_ZQ0SR0 */ + soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy + + 0x188); + } return 0; -- 2.25.1
[PATCH 24/24] ARM: at91: pm: add sama7g5 shdwc
Add SAMA7G5 SHDWC. Signed-off-by: Claudiu Beznea --- 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 @@ static int __init at91_pm_backup_init(void) static const struct of_device_id atmel_shdwc_ids[] = { { .compatible = "atmel,sama5d2-shdwc" }, { .compatible = "microchip,sam9x60-shdwc" }, + { .compatible = "microchip,sama7g5-shdwc" }, { /* sentinel. */ } }; -- 2.25.1
[PATCH 23/24] ARM: at91: pm: add pm support for SAMA7G5
Add support for SAMA7G5 power management modes: standby, ulp0, ulp1, backup. Signed-off-by: Claudiu Beznea --- 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 = _info[1] }, + { .compatible = "microchip,sama7g5-ohci", .data = _info[2] }, + { .compatible = "usb-ohci", .data = _info[2] }, + { .compatible = "atmel,at91sam9g45-ehci", .data = _info[2] }, + { .compatible = "usb-ehci", .data = _info[2] }, + { .compatible = "microchip,sama7g5-sdhci", .data = _info[3] }, + { .compatible = "atmel,at91sam9260-rtt",.data = _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 e04cadb569ad..bcabe4d82080 100644 --- a/arch/arm/mach-at91/sama7.c +++ b/arch/arm/mach-at91/sama7.c @@ -17,6 +17,7 @@ static void __init sama7_common_init(void) { of_platform_default_populate(NULL, NULL, NULL); + sama7_pm_init(); } static void __init sama7_dt_device_init(void) -- 2.25.1
[PATCH 22/24] ARM: at91: sama7: introduce sama7 SoC family
From: Eugen Hristev Introduce new family of SoCs, sama7, and first SoC, sama7g5. Signed-off-by: Eugen Hristev Signed-off-by: Claudiu Beznea --- arch/arm/mach-at91/Makefile | 1 + arch/arm/mach-at91/sama7.c | 48 + 2 files changed, 49 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..6cc6624cddac 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_SOC_AT91SAM9) += at91sam9.o obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o obj-$(CONFIG_SOC_SAMA5)+= sama5.o obj-$(CONFIG_SOC_SAMV7)+= samv7.o +obj-$(CONFIG_SOC_SAMA7)+= sama7.o # Power Management obj-$(CONFIG_ATMEL_PM) += pm.o pm_suspend.o diff --git a/arch/arm/mach-at91/sama7.c b/arch/arm/mach-at91/sama7.c new file mode 100644 index ..e04cadb569ad --- /dev/null +++ b/arch/arm/mach-at91/sama7.c @@ -0,0 +1,48 @@ +// 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_common_init(void) +{ + of_platform_default_populate(NULL, NULL, NULL); +} + +static void __init sama7_dt_device_init(void) +{ + sama7_common_init(); +} + +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 + +static const char *const sama7g5_dt_board_compat[] __initconst = { + "microchip,sama7g5", + NULL +}; + +DT_MACHINE_START(sama7g5_dt, "Microchip SAMA7G5") + /* Maintainer: Microchip */ + .init_machine = sama7_dt_device_init, + .dt_compat = sama7g5_dt_board_compat, +MACHINE_END + -- 2.25.1
[PATCH 20/24] 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 --- 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, #0x20 +#endif + .endm + .text .arm @@ -989,6 +995,7 @@ ulp_exit: ldr r0, .shdwc mov tmp1, #0xA500 add tmp1, tmp1, #0x1 + at91_backup_set_lpm tmp1 str tmp1, [r0, #0] .endm -- 2.25.1
[PATCH 18/24] 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 --- 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, _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; -- 2.25.1
[PATCH 17/24] 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 --- 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 = _infos[1] }, { .compatible = "atmel,at91sam9g45-ddramc", .data = _infos[2] }, { .compatible = "atmel,sama5d3-ddramc", .data = _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++; } -- 2.25.1
[PATCH 14/24] 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 --- 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_MC0 #define AT91_MEMCTRL_SDRAMC1 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 .reqr6 .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 -- 2.25.1
[PATCH 16/24] dt-bindings: atmel-sysreg: add bindings for sama7g5
Add RAM controller and RAM PHY controller DT bindings. Signed-off-by: Claudiu Beznea --- .../devicetree/bindings/arm/atmel-sysregs.txt | 15 ++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt index 807264a78edc..7cd55a760d41 100644 --- a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt +++ b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt @@ -45,7 +45,8 @@ RAMC SDRAM/DDR Controller required properties: "atmel,at91sam9260-sdramc", "atmel,at91sam9g45-ddramc", "atmel,sama5d3-ddramc", - "microchip,sam9x60-ddramc" + "microchip,sam9x60-ddramc", + "microchip,sama7g5-uddrc" - reg: Should contain registers location and length Examples: @@ -55,6 +56,18 @@ Examples: reg = <0xe800 0x200>; }; +RAMC PHY Controller required properties: +- compatible: Should be "microchip,sama7g5-ddr3phy", "syscon" +- reg: Should contain registers location and length + +Example: + + ddr3phy: ddr3phy@e3804000 { + compatible = "microchip,sama7g5-ddr3phy", "syscon"; + reg = <0xe3804000 0x1000>; + status = "okay"; +}; + SHDWC Shutdown Controller required properties: -- 2.25.1
[PATCH 15/24] 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 --- 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, #0xA500 -- 2.25.1
[PATCH 02/24] 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 --- 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 */ -- 2.25.1
[PATCH 05/24] ARM: at91: pm: do not initialize pdev
There is no need to initialize pdev. Signed-off-by: Claudiu Beznea --- 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)) -- 2.25.1
[PATCH 04/24] 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 --- arch/arm/mach-at91/pm.c | 143 +--- 1 file changed, 91 insertions(+), 52 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(>dev, NULL); @@ -697,64 +700,92 @@ static int __init at91_pm_backup_init(void) securam_fail: put_device(>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; + int ret, mode; - if (!at91_is_pm_mode_active(AT91_PM_BACKUP) && - !at91_is_pm_mode_active(AT91_PM_ULP1)) - return; + ret = at91_pm_backup_init(); + if (ret) { + 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; + } - np = of_find_matching_node(NULL, atmel_shdwc_ids); - if (!np) { - pr_warn("%s: failed to find shdwc!\n", __func__); - goto ulp1_default; + 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); + } } - soc_pm.data.shdwc = of_iomap(np, 0); - of_node_put(np); + if (maps[soc_pm.data.standby_mode] & AT91_PM_IOM
[PATCH 01/24] ARM: at91: pm: move pm_bu to soc_pm data structure
Move pm_bu to soc_pm data structure. Signed-off-by: Claudiu Beznea --- 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(); - pm_bu->resume = __pa_symbol(cpu_resume); + soc_pm.bu->suspended = 0; + soc_pm.bu->canary = __pa_symbol(); + soc_pm.bu->resume = __pa_symbol(cpu_resume); return 0; -- 2.25.1
[PATCH 03/24] ARM: at91: pm: document at91_soc_pm structure
Document at91_soc_pm structure. Signed-off-by: Claudiu Beznea --- 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); -- 2.25.1
[PATCH 13/24] 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 --- 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 -- 2.25.1
[PATCH 10/24] ARM: at91: sfrbu: add sfrbu registers definitions for sama7g5
Add SFRBU registers definitions for SAMA7G5. Signed-off-by: Claudiu Beznea --- 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 ..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 */ +#defineAT91_SFRBU_PSWBU_PSWKEY (0x4BD20C << 8) /* Specific value mandatory to allow writing of other register bits */ +#defineAT91_SFRBU_PSWBU_STATE (1 << 2)/* Power switch BU state */ +#defineAT91_SFRBU_PSWBU_SOFTSWITCH (1 << 1)/* Power switch BU source selection */ +#defineAT91_SFRBU_PSWBU_CTRL (1 << 0)/* Power switch BU control */ + +#define AT91_SFRBU_25LDOCR (0x0C) /* SFRBU 2.5V LDO Control Register */ +#defineAT91_SFRBU_25LDOCR_LDOANAKEY(0x3B6E18 << 8) /* Specific value mandatory to allow writing of other register bits. */ +#defineAT91_SFRBU_25LDOCR_STATE(1 << 3)/* LDOANA Switch On/Off Control */ +#defineAT91_SFRBU_25LDOCR_LP (1 << 2)/* LDOANA Low-Power Mode Control */ +#defineAT91_SFRBU_PD_VALUE_MSK (0x3) +#defineAT91_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 */ +#defineAT91_FRBU_DDRPWR_STATE (1 << 0)/* DDR Power Mode State */ + +#endif /* CONFIG_SOC_SAMA7 */ + +#endif /* __SAMA7_SFRBU_H__ */ + -- 2.25.1
[PATCH 00/24] ARM: at91: pm: add support for sama7g5
Hi, This series adds PM support for SAMA7G5. The standby, ulp0, ulp1, and backup modes are supported. Thank you, Claudiu Beznea Claudiu Beznea (23): ARM: at91: pm: move pm_bu to soc_pm data structure ARM: at91: pm: move the setup of soc_pm.bu->suspended ARM: at91: pm: document at91_soc_pm structure ARM: at91: pm: check for different controllers in at91_pm_modes_init() ARM: at91: pm: do not initialize pdev ARM: at91: pm: use r7 instead of tmp1 ARM: at91: pm: avoid push and pop on stack while memory is in self-refersh ARM: at91: pm: s/CONFIG_SOC_SAM9X60/CONFIG_HAVE_AT91_SAM9X60_PLL/g ARM: at91: pm: add support for waiting MCK1..4 ARM: at91: sfrbu: add sfrbu registers definitions for sama7g5 ARM: at91: ddr: add registers definitions for sama7g5's ddr ARM: at91: pm: add self-refresh support for sama7g5 ARM: at91: pm: add support for MCK1..4 save/restore for ulp modes ARM: at91: pm: add support for 2.5V LDO regulator control ARM: at91: pm: wait for ddr power mode off dt-bindings: atmel-sysreg: add bindings for sama7g5 ARM: at91: pm: add sama7g5 ddr controller ARM: at91: pm: add sama7g5 ddr phy controller ARM: at91: pm: save ddr phy calibration data to securam ARM: at91: pm: add backup mode support for SAMA7G5 ARM: at91: pm: add sama7g5's pmc ARM: at91: pm: add pm support for SAMA7G5 ARM: at91: pm: add sama7g5 shdwc Eugen Hristev (1): ARM: at91: sama7: introduce sama7 SoC family .../devicetree/bindings/arm/atmel-sysregs.txt | 15 +- arch/arm/mach-at91/Makefile | 1 + arch/arm/mach-at91/generic.h | 2 + arch/arm/mach-at91/pm.c | 343 ++-- arch/arm/mach-at91/pm.h | 3 + arch/arm/mach-at91/pm_data-offsets.c | 2 + arch/arm/mach-at91/pm_suspend.S | 827 +- arch/arm/mach-at91/sama7.c| 49 ++ include/soc/at91/sama7-ddr.h | 80 ++ include/soc/at91/sama7-sfrbu.h| 34 + 10 files changed, 1066 insertions(+), 290 deletions(-) create mode 100644 arch/arm/mach-at91/sama7.c create mode 100644 include/soc/at91/sama7-ddr.h create mode 100644 include/soc/at91/sama7-sfrbu.h -- 2.25.1
[PATCH 12/24] ARM: at91: pm: add self-refresh support for sama7g5
Add self-refresh support for SAMA7G5. Signed-off-by: Claudiu Beznea --- 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_MC0 #define AT91_MEMCTRL_SDRAMC1 @@ -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.reqr6 .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
[PATCH 06/24] 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 --- 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.reqr6 /* * 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 -- 2.25.1
[PATCH 09/24] 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 --- 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.reqr6 /* * 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 -- 2.25.1
[PATCH 07/24] 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 --- arch/arm/mach-at91/pm_suspend.S | 397 +--- 1 file changed, 205 insertions(+), 192 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 .reqr6 .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 cl
[PATCH 11/24] 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 --- 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 ..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 */ +#defineDDR3PHY_PIR_DLLBYP (1 << 17) /* DLL Bypass */ +#defineDDR3PHY_PIR_ITMSRST (1 << 4)/* Interface Timing Module Soft Reset */ +#defineDDR3PHY_PIR_DLLLOCK (1 << 2)/* DLL Lock */ +#defineDDR3PHY_PIR_DLLSRST (1 << 1)/* DLL Soft Rest */ +#defineDDR3PHY_PIR_INIT(1 << 0)/* Initialization Trigger */ + +#define DDR3PHY_PGCR (0x08) /* DDR3PHY PHY General Configuration Register */ +#defineDDR3PHY_PGCR_CKDV1 (1 << 13) /* CK# Disable Value */ +#defineDDR3PHY_PGCR_CKDV0 (1 << 12) /* CK Disable Value */ + +#defineDDR3PHY_PGSR(0x0C) /* DDR3PHY PHY General Status Register */ +#defineDDR3PHY_PGSR_IDONE (1 << 0)/* Initialization Done */ + +#define DDR3PHY_ACIOCR (0x24) /* DDR3PHY AC I/O Configuration Register */ +#defineDDR3PHY_ACIOCR_CSPDD_CS0(1 << 18) /* CS#[0] Power Down Driver */ +#defineDDR3PHY_ACIOCR_CKPDD_CK0(1 << 8)/* CK[0] Power Down Driver */ +#defineDDR3PHY_ACIORC_ACPDD(1 << 3)/* AC Power Down Driver */ + +#define DDR3PHY_DXCCR (0x28) /* DDR3PHY DATX8 Common Configuration Register */ +#defineDDR3PHY_DXCCR_DXPDR (1 << 3)/* Data Power Down Receiver */ + +#define DDR3PHY_DSGCR (0x2C) /* DDR3PHY DDR System General Configuration Register */ +#defineDDR3PHY_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 */ +#defineUDDRC_STAT_SELFREF_TYPE_DIS (0x0 << 4) /* SDRAM is not in Self-refresh */ +#defineUDDRC_STAT_SELFREF_TYPE_PHY (0x1 << 4) /* SDRAM is in Self-refresh, which was caused by PHY Master Request */ +#defineUDDRC_STAT_SELFREF_TYPE_SW (0x2 << 4) /* SDRAM is in Self-refresh, which was not caused solely under Automatic Self-refresh control */ +#defineUDDRC_STAT_SELFREF_TYPE_AUTO(0x3 << 4) /* SDRAM is in Self-refresh, which was caused by Automatic Self-refresh only */ +#defineUDDRC_STAT_SELFREF_TYPE_MSK (0x3 << 4) /* Self-refresh type mask */ +#defineUDDRC_STAT_OPMODE_INIT (0x0 << 0) /* Init */ +#defineUDDRC_STAT_OPMODE_NORMAL(0x1 << 0) /* Normal */ +#defineUDDRC_STAT_OPMODE_PWRDOWN (0x2 << 0) /* Power-down */ +#defineUDDRC_STAT_OPMODE_SELF_REFRESH (0x3 << 0) /* Self-refresh */ +#defineUDDRC_STAT_OPMODE_MSK (0x7 << 0) /* Operating mode mask */ + +#define UDDRC_PWRCTL (0x30) /* UDDRC Low Power Control Register */ +#defineUDDRC_PWRCTRL_SELFREF_SW(1 << 5)/* Software self-refresh */ + +#define UDDRC_DFIMISC (0x1B0) /* UDDRC DFI Miscellaneous Control Register */ +#defineUDDRC_DFIMISC_DFI_INIT_COMPLETE_EN (1 << 0) /* PHY initialization complete enable signal */ + +#define UDDRC_SWCTRL (0x320) /* UDDRC Software Register Programming Control Enable */ +#defineUDDRC_SWCTRL_SW_DONE(1 << 0)/* Enable quasi-dynamic register programming outside reset */ + +#define UDDRC
[PATCH 08/24] 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 --- 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 -- 2.25.1
[RESEND PATCH 5/5] clk: at91: clk-master: update for dvfs
SAMA7G5 supports CPU DVFS. The hardware block diagram for the clock system generating CPU clock is as follows: ++ +-->|divider1|--> CPU clock | ++ ++ +--+ | ++ |CPU PLL |-->|prescaller|--+-->|divider0|--> MCK0 clock ++ +--+ ++ The divider1 is not implemented in software since the supported CPU frequencies could be directly retrieved from CPU PLL + prescaller. Every time the CPU clock needs to be changed the MCK0 should also be changed to avoid its over/under clocking and also to preserve its initial value (200MHz). MCK0 feeds IPs that are glitch free aware. The initial approach for implementing DVFS was to implement MCK0 and CPU clocks as 2 different Linux clocks, to pass these two clocks to CPUFreq driver and in CPUFreq driver to run clk_set_rate() on CPU and MCK clocks accordingly. E.g. if 1GHz speed was requested by CPUFreq subsystem the following were executed in CPUFreq driver: /* ... */ clk_set_rate(mck0, intermediary_freq_to_avoid_over_under_clocking); clk_set_rate(cpu, 10); clk_set_rate(mck0, initial_freq); / ... */ However, it has been proposed in [1] to use the generic cpufreq-dt driver and to overload the necessary clocks operations in the proper clock driver. To address this proposal the master clock prescaller registers a clock notifier that will update properly the master clock divider on PRE_RATE_CHANGE and POST_RATE_CHANGE events to avoid master clock divider over/under clocking and also to preserve its initial value (200MHz). [1] https://lore.kernel.org/lkml/1609842147-8161-1-git-send-email-claudiu.bez...@microchip.com/ Signed-off-by: Claudiu Beznea --- drivers/clk/at91/at91rm9200.c | 2 +- drivers/clk/at91/at91sam9260.c | 2 +- drivers/clk/at91/at91sam9g45.c | 2 +- drivers/clk/at91/at91sam9n12.c | 2 +- drivers/clk/at91/at91sam9rl.c | 2 +- drivers/clk/at91/at91sam9x5.c | 2 +- drivers/clk/at91/clk-master.c | 187 - drivers/clk/at91/dt-compat.c | 2 +- drivers/clk/at91/pmc.h | 3 +- drivers/clk/at91/sam9x60.c | 2 +- drivers/clk/at91/sama5d2.c | 2 +- drivers/clk/at91/sama5d3.c | 2 +- drivers/clk/at91/sama5d4.c | 2 +- drivers/clk/at91/sama7g5.c | 2 +- 14 files changed, 130 insertions(+), 84 deletions(-) diff --git a/drivers/clk/at91/at91rm9200.c b/drivers/clk/at91/at91rm9200.c index 0fad1009f315..749c0b1e9c3d 100644 --- a/drivers/clk/at91/at91rm9200.c +++ b/drivers/clk/at91/at91rm9200.c @@ -144,7 +144,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np) _master_layout, _mck_characteristics, _mck_lock, CLK_SET_RATE_GATE, - INT_MIN); + INT_MIN, 0); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9260.c b/drivers/clk/at91/at91sam9260.c index ceb5495f723a..c01d9455f6d4 100644 --- a/drivers/clk/at91/at91sam9260.c +++ b/drivers/clk/at91/at91sam9260.c @@ -420,7 +420,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np, _master_layout, data->mck_characteristics, _mck_lock, - CLK_SET_RATE_GATE, INT_MIN); + CLK_SET_RATE_GATE, INT_MIN, 0); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9g45.c b/drivers/clk/at91/at91sam9g45.c index 0214333dedd3..8364e7a06cfc 100644 --- a/drivers/clk/at91/at91sam9g45.c +++ b/drivers/clk/at91/at91sam9g45.c @@ -155,7 +155,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np) _master_layout, _characteristics, _mck_lock, - CLK_SET_RATE_GATE, INT_MIN); + CLK_SET_RATE_GATE, INT_MIN, 0); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/at91sam9n12.c b/drivers/clk/at91/at91sam9n12.c index f9db5316a7f1..ddcae243a4ea 100644 --- a/drivers/clk/at91/at91sam9n12.c +++ b/drivers/clk/at91/at91sam9n12.c @@ -182,7 +182,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np) _master_layout, _characteristics, _mck_lock, - CLK_SET_RATE_GATE, INT_MIN); + CLK_SET_RAT
[RESEND PATCH 3/5] clk: at91: sama7g5: add securam's peripheral clock
Add SECURAM's peripheral clock. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/sama7g5.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index a6e20b35960e..28e26fb90417 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -377,6 +377,7 @@ static const struct { u8 id; } sama7g5_periphck[] = { { .n = "pioA_clk", .p = "mck0", .id = 11, }, + { .n = "securam_clk", .p = "mck0", .id = 18, }, { .n = "sfr_clk", .p = "mck1", .id = 19, }, { .n = "hsmc_clk", .p = "mck1", .id = 21, }, { .n = "xdmac0_clk",.p = "mck1", .id = 22, }, -- 2.25.1
[RESEND PATCH 4/5] clk: at91: clk-master: 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. With this, update also clk-master.c. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/clk-master.c | 51 +-- include/linux/clk/at91_pmc.h | 26 ++ 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index 6f1fb2eb2a8d..a6a393bb1def 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -17,15 +17,7 @@ #define MASTER_DIV_SHIFT 8 #define MASTER_DIV_MASK0x7 -#define PMC_MCR0x30 -#define PMC_MCR_ID_MSK GENMASK(3, 0) -#define PMC_MCR_CMDBIT(7) -#define PMC_MCR_DIVGENMASK(10, 8) -#define PMC_MCR_CSSGENMASK(20, 16) #define PMC_MCR_CSS_SHIFT (16) -#define PMC_MCR_EN BIT(28) - -#define PMC_MCR_ID(x) ((x) & PMC_MCR_ID_MSK) #define MASTER_MAX_ID 4 @@ -685,17 +677,20 @@ static void clk_sama7g5_master_set(struct clk_master *master, spin_lock_irqsave(master->lock, flags); - regmap_write(master->regmap, PMC_MCR, PMC_MCR_ID(master->id)); - regmap_read(master->regmap, PMC_MCR, ); - regmap_update_bits(master->regmap, PMC_MCR, - (status ? PMC_MCR_EN : 0) | PMC_MCR_CSS | PMC_MCR_DIV | - PMC_MCR_CMD | PMC_MCR_ID_MSK, - (status ? PMC_MCR_EN : 0) | + regmap_write(master->regmap, AT91_PMC_MCR_V2, +AT91_PMC_MCR_V2_ID(master->id)); + regmap_read(master->regmap, AT91_PMC_MCR_V2, ); + regmap_update_bits(master->regmap, AT91_PMC_MCR_V2, + (status ? AT91_PMC_MCR_V2_EN : 0) | + AT91_PMC_MCR_V2_CSS | AT91_PMC_MCR_V2_DIV | + AT91_PMC_MCR_V2_CMD | AT91_PMC_MCR_V2_ID_MSK, + (status ? AT91_PMC_MCR_V2_EN : 0) | (master->parent << PMC_MCR_CSS_SHIFT) | (master->div << MASTER_DIV_SHIFT) | - PMC_MCR_CMD | PMC_MCR_ID(master->id)); + AT91_PMC_MCR_V2_CMD | + AT91_PMC_MCR_V2_ID(master->id)); - cparent = (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT; + cparent = (val & AT91_PMC_MCR_V2_CSS) >> PMC_MCR_CSS_SHIFT; /* Wait here only if parent is being changed. */ while ((cparent != master->parent) && !clk_master_ready(master)) @@ -720,10 +715,12 @@ static void clk_sama7g5_master_disable(struct clk_hw *hw) spin_lock_irqsave(master->lock, flags); - regmap_write(master->regmap, PMC_MCR, master->id); - regmap_update_bits(master->regmap, PMC_MCR, - PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK, - PMC_MCR_CMD | PMC_MCR_ID(master->id)); + regmap_write(master->regmap, AT91_PMC_MCR_V2, master->id); + regmap_update_bits(master->regmap, AT91_PMC_MCR_V2, + AT91_PMC_MCR_V2_EN | AT91_PMC_MCR_V2_CMD | + AT91_PMC_MCR_V2_ID_MSK, + AT91_PMC_MCR_V2_CMD | + AT91_PMC_MCR_V2_ID(master->id)); spin_unlock_irqrestore(master->lock, flags); } @@ -736,12 +733,12 @@ static int clk_sama7g5_master_is_enabled(struct clk_hw *hw) spin_lock_irqsave(master->lock, flags); - regmap_write(master->regmap, PMC_MCR, master->id); - regmap_read(master->regmap, PMC_MCR, ); + regmap_write(master->regmap, AT91_PMC_MCR_V2, master->id); + regmap_read(master->regmap, AT91_PMC_MCR_V2, ); spin_unlock_irqrestore(master->lock, flags); - return !!(val & PMC_MCR_EN); + return !!(val & AT91_PMC_MCR_V2_EN); } static int clk_sama7g5_master_set_rate(struct clk_hw *hw, unsigned long rate, @@ -837,10 +834,10 @@ at91_clk_sama7g5_register_master(struct regmap *regmap, master->mux_table = mux_table; spin_lock_irqsave(master->lock, flags); - regmap_write(master->regmap, PMC_MCR, master->id); - regmap_read(master->regmap, PMC_MCR, ); - master->parent = (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT; - master->div = (val & PMC_MCR_DIV) >> MASTER_DIV_SHIFT; + regmap_write(master->regmap, AT91_PMC_MCR_V2, master->id); + regmap_read(master->regmap, AT91_PMC_MCR_V2, ); + master->parent = (val & AT91_PMC_MCR_V2_CSS) >> PMC_MCR_CSS_SHIFT; + master->div = (val & AT91_PMC_MCR_V2_DIV) >> MASTER_DIV_SHIFT; spin_unlock_irqrestore(master->lock, flags);
[RESEND PATCH 2/5] clk: at91: pmc: execute suspend/resume only for backup mode
Before going to backup mode architecture specific PM code sets the first word in securam (and it will be cleared in a subsequent commit for the rest of power saving modes). Thus take this into account when suspending/resuming clocks. This will avoid executing unnecessary instructions when suspending to non backup modes. Since the clear of the 1st word in securam will be done in a subsequent commit the current commit will not broke the current behavior since up to this moment the suspend/resume were executed for all AT91 PM modes. The difference now is that the suspend/resume for clocks will be executed for the rest of AT91 PM modes just after the 1st enter/exit to/from backup mode. Also this commit changed the postcore_initcall() with subsys_initcall() to be able to execute of_find_compatible_node() since this was not available at the moment of postcore_initcall(). This should not alter the tcb_clksrc since the changes are related to clocks suspend/resume procedure that will be executed at the user space request, thus long ago after postcore_initcall(). Signed-off-by: Claudiu Beznea --- drivers/clk/at91/pmc.c | 48 ++ 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 77b57c9f5dcb..c226d33cd899 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -110,13 +112,35 @@ struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem, } #ifdef CONFIG_PM + +/* Address in SECURAM that say if we suspend to backup mode. */ +static void __iomem *at91_pmc_backup_suspend; + static int at91_pmc_suspend(void) { + unsigned int backup; + + if (!at91_pmc_backup_suspend) + return 0; + + backup = *(unsigned int *)at91_pmc_backup_suspend; + if (!backup) + return 0; + return clk_save_context(); } static void at91_pmc_resume(void) { + unsigned int backup; + + if (!at91_pmc_backup_suspend) + return; + + backup = *(unsigned int *)at91_pmc_backup_suspend; + if (!backup) + return; + clk_restore_context(); } @@ -125,24 +149,30 @@ static struct syscore_ops pmc_syscore_ops = { .resume = at91_pmc_resume, }; -static const struct of_device_id sama5d2_pmc_dt_ids[] = { - { .compatible = "atmel,sama5d2-pmc" }, - { /* sentinel */ } -}; - static int __init pmc_register_ops(void) { + struct platform_device *pdev; struct device_node *np; - np = of_find_matching_node(NULL, sama5d2_pmc_dt_ids); + np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-securam"); if (!np) - return 0; + return -ENODEV; + + pdev = of_find_device_by_node(np); of_node_put(np); + if (!pdev) + return -ENODEV; + + at91_pmc_backup_suspend = of_iomap(np, 0); + if (!at91_pmc_backup_suspend) { + pr_warn("%s(): unable to map securam\n", __func__); + return -ENOMEM; + } register_syscore_ops(_syscore_ops); return 0; } -/* This has to happen before arch_initcall because of the tcb_clksrc driver */ -postcore_initcall(pmc_register_ops); + +subsys_initcall(pmc_register_ops); #endif -- 2.25.1
[RESEND PATCH 1/5] clk: at91: re-factor clocks suspend/resume
SAMA5D2 and SAMA7G5 have a special power saving mode (backup mode) where most of the SoC's components are powered off (including PMC). Resuming from this mode is done with the help of bootloader. Peripherals are not aware of the power saving mode thus most of them are disabling clocks in proper suspend API and re-enable them in resume API without taking into account the previously setup rate. Moreover some of the peripherals are acting as wakeup sources and are not disabling the clocks in this scenario, when suspending. Since backup mode cuts the power for peripherals, in resume part these clocks needs to be re-configured. The initial PMC suspend/resume code was designed with SAMA5D2's PMC in mind. SAMA7G's PMC is different (few new functionalities, different registers offsets, different offsets in registers for each functionalities). To address both SAMA5D2 and SAMA7G5 PMC add .save_context()/.resume_context() support to each clocks driver and call this from PMC driver. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/clk-generated.c| 45 +-- drivers/clk/at91/clk-main.c | 66 ++ drivers/clk/at91/clk-master.c | 183 ++-- drivers/clk/at91/clk-peripheral.c | 38 +- drivers/clk/at91/clk-pll.c | 37 ++ drivers/clk/at91/clk-programmable.c | 29 - drivers/clk/at91/clk-sam9x60-pll.c | 68 ++- drivers/clk/at91/clk-system.c | 20 +++ drivers/clk/at91/clk-usb.c | 27 drivers/clk/at91/clk-utmi.c | 47 ++- drivers/clk/at91/pmc.c | 149 ++ drivers/clk/at91/pmc.h | 24 ++-- 12 files changed, 554 insertions(+), 179 deletions(-) diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index b4fc8d71daf2..0e436f9e7508 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -27,6 +27,7 @@ struct clk_generated { u32 id; u32 gckdiv; const struct clk_pcr_layout *layout; + struct at91_clk_pms pms; u8 parent_id; int chg_pid; }; @@ -34,25 +35,34 @@ struct clk_generated { #define to_clk_generated(hw) \ container_of(hw, struct clk_generated, hw) -static int clk_generated_enable(struct clk_hw *hw) +static int clk_generated_set(struct clk_generated *gck, int status) { - struct clk_generated *gck = to_clk_generated(hw); unsigned long flags; - pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", -__func__, gck->gckdiv, gck->parent_id); - spin_lock_irqsave(gck->lock, flags); regmap_write(gck->regmap, gck->layout->offset, (gck->id & gck->layout->pid_mask)); regmap_update_bits(gck->regmap, gck->layout->offset, AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask | - gck->layout->cmd | AT91_PMC_PCR_GCKEN, + gck->layout->cmd | (status ? AT91_PMC_PCR_GCKEN : 0), field_prep(gck->layout->gckcss_mask, gck->parent_id) | gck->layout->cmd | FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) | - AT91_PMC_PCR_GCKEN); + (status ? AT91_PMC_PCR_GCKEN : 0)); spin_unlock_irqrestore(gck->lock, flags); + + return 0; +} + +static int clk_generated_enable(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + + pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", +__func__, gck->gckdiv, gck->parent_id); + + clk_generated_set(gck, 1); + return 0; } @@ -239,6 +249,23 @@ static int clk_generated_set_rate(struct clk_hw *hw, return 0; } +static int clk_generated_save_context(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + + gck->pms.status = clk_generated_is_enabled(>hw); + + return 0; +} + +static void clk_generated_restore_context(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + + if (gck->pms.status) + clk_generated_set(gck, gck->pms.status); +} + static const struct clk_ops generated_ops = { .enable = clk_generated_enable, .disable = clk_generated_disable, @@ -248,6 +275,8 @@ static const struct clk_ops generated_ops = { .get_parent = clk_generated_get_parent, .set_parent = clk_generated_set_parent, .set_rate = clk_generated_set_rate, + .save_context = clk_generated_save_context, + .restore_context = clk_generated_restore_context, }; /** @@ -314,8 +343,6 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, if (ret) { kfree(gck); hw = ERR_PTR(ret); - } else { -
[RESEND PATCH 0/5] clk: at91: updates for power management and dvfs
Hi, This series addresses the power management for SAMA7G5 and also updates the master clock prescaller and master clock divider drivers to accommodate the requests at [1]. The power management part is implemented by adding save_context()/restore_context() on each clock driver (patch 1/5). Since the PM part is necessary only for backup mode (supported on SAMA5D2 and SAMA7G5) the pmc.c has been adapted to call the save_context()/restore_context() only on switches to/from backup mode (patch 2/5). Patch 3/5 adds the securam clock on SAMA7G5. This is necessary for backup mode of SAMA7G5. Patch 4/5 adds registers definitions for the new master clocks (MCK1..4) of SAMA7G5 and adapt the clk-master.c. The defines exported in include/linux/clk/at91_pmc.h will be also used by platform specific PM code. Patch 5/5 adpat the master clock divider and master clock prescaller to address the requests at [1]. Thank you, Claudiu Beznea [1] https://lore.kernel.org/lkml/20210105104426.4tmgc2l3vyicwedd@vireshk-i7/ Claudiu Beznea (5): clk: at91: re-factor clocks suspend/resume clk: at91: pmc: execute suspend/resume only for backup mode clk: at91: sama7g5: add securam's peripheral clock clk: at91: clk-master: add register definition for sama7g5's master clock clk: at91: clk-master: update for dvfs drivers/clk/at91/at91rm9200.c | 2 +- drivers/clk/at91/at91sam9260.c | 2 +- drivers/clk/at91/at91sam9g45.c | 2 +- drivers/clk/at91/at91sam9n12.c | 2 +- drivers/clk/at91/at91sam9rl.c | 2 +- drivers/clk/at91/at91sam9x5.c | 2 +- drivers/clk/at91/clk-generated.c| 45 +++- drivers/clk/at91/clk-main.c | 66 + drivers/clk/at91/clk-master.c | 395 +--- drivers/clk/at91/clk-peripheral.c | 38 ++- drivers/clk/at91/clk-pll.c | 37 +++ drivers/clk/at91/clk-programmable.c | 29 +- drivers/clk/at91/clk-sam9x60-pll.c | 68 - drivers/clk/at91/clk-system.c | 20 ++ drivers/clk/at91/clk-usb.c | 27 ++ drivers/clk/at91/clk-utmi.c | 47 +++- drivers/clk/at91/dt-compat.c| 2 +- drivers/clk/at91/pmc.c | 175 +++- drivers/clk/at91/pmc.h | 27 +- drivers/clk/at91/sam9x60.c | 2 +- drivers/clk/at91/sama5d2.c | 2 +- drivers/clk/at91/sama5d3.c | 2 +- drivers/clk/at91/sama5d4.c | 2 +- drivers/clk/at91/sama7g5.c | 3 +- include/linux/clk/at91_pmc.h| 26 ++ 25 files changed, 750 insertions(+), 275 deletions(-) -- 2.25.1
[PATCH 0/2] irqchip/mchp-eic: add driver for Microchip EIC
Hi, This patch adds support for Microchip External Interrupt Controller present on SAMA7G5. The controller supports for 2 external interrupt lines, glitch filter capabilities and is connected to GIC as follows: pinX +--+ EXT_IRQ0 +--+ int 153 (for pinX) +--+ -->| |->| |--->| | pinY | PIO | EXT_IRQ1 | EIC | int 154 (for pinY) | GIC | -->| |->| |--->| | +--+ +--++--+ where PIO is the pin controller. Thank you, Claudiu Beznea Claudiu Beznea (2): dt-bindings: mchp-eic: add bindings irqchip/mchp-eic: add support .../interrupt-controller/mchp,eic.yaml| 74 MAINTAINERS | 6 + drivers/irqchip/Kconfig | 7 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-mchp-eic.c| 350 ++ 5 files changed, 438 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/mchp,eic.yaml create mode 100644 drivers/irqchip/irq-mchp-eic.c -- 2.25.1
[PATCH 2/2] irqchip/mchp-eic: add support
Add support for Microchip External Interrupt Controller. Signed-off-by: Claudiu Beznea --- MAINTAINERS| 6 + drivers/irqchip/Kconfig| 7 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-mchp-eic.c | 350 + 4 files changed, 364 insertions(+) create mode 100644 drivers/irqchip/irq-mchp-eic.c diff --git a/MAINTAINERS b/MAINTAINERS index a008b70f3c16..ea99e5a7f519 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11585,6 +11585,12 @@ L: linux-arm-ker...@lists.infradead.org (moderated for non-subscribers) S: Supported F: drivers/usb/gadget/udc/atmel_usba_udc.* +MICROCHIP EIC DRIVER +M: Claudiu Beznea +L: linux-arm-ker...@lists.infradead.org (moderated for non-subscribers) +S: Supported +F: drivers/irqchip/irq-mchp-eic.c + MICROCHIP WILC1000 WIFI DRIVER M: Ajay Singh M: Claudiu Beznea diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 2aa79c32ee22..7c7ca33c3f7d 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -596,4 +596,11 @@ config MST_IRQ help Support MStar Interrupt Controller. +config MCHP_EIC + bool "Microchip External Interrupt Controller" + depends on ARCH_AT91 || COMPILE_TEST + select IRQ_DOMAIN + help + Support for Microchip External Interrupt Controller. + endmenu diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 94c2885882ee..f3df6eb7c4c3 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -114,3 +114,4 @@ obj-$(CONFIG_LOONGSON_PCH_PIC) += irq-loongson-pch-pic.o obj-$(CONFIG_LOONGSON_PCH_MSI) += irq-loongson-pch-msi.o obj-$(CONFIG_MST_IRQ) += irq-mst-intc.o obj-$(CONFIG_SL28CPLD_INTC)+= irq-sl28cpld.o +obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c new file mode 100644 index ..ec01877fc75f --- /dev/null +++ b/drivers/irqchip/irq-mchp-eic.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Microchip External Interrupt Controller driver + * + * Copyright (C) 2021 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MCHP_EIC_GFCS (0x0) +#define MCHP_EIC_SCFG(x) (0x4 + (x) * 0x4) +#define MCHP_EIC_SCFG_FRZ BIT(31) +#define MCHP_EIC_SCFG_EN BIT(16) +#define MCHP_EIC_SCFG_LVL BIT(9) +#define MCHP_EIC_SCFG_POL BIT(8) +#define MCHP_EIC_SCFG_GFEN BIT(4) +#define MCHP_EIC_SCFG_GFSELGENMASK(1, 0) + +#define MCHP_EIC_NIRQ (2) +#define MCHP_EIC_DEFAULT_WAIT_US (100) + +/** + * struct mchp_eic - EIC private data structure + * @base: base address + * @dev: eic device + * @clk: peripheral clock + * @chip: irq chip + * @domain: irq domain + * @irqs: irqs b/w eic and gic + * @scfg: backup for scfg registers (necessary for backup and self-refresh mode) + * @wakeup_source: wakeup source mask + */ +struct mchp_eic { + void __iomem *base; + struct device *dev; + struct clk *clk; + struct irq_chip *chip; + struct irq_domain *domain; + u32 irqs[MCHP_EIC_NIRQ]; + u32 scfg[MCHP_EIC_NIRQ]; + u32 wakeup_source; +}; + +static void mchp_eic_wait_rdy(struct mchp_eic *eic, unsigned int hwirq, + int delay_us) +{ + unsigned int tmp = readl(eic->base + MCHP_EIC_SCFG(hwirq)); + + while (delay_us >= 0 && tmp & BIT(hwirq)) { + udelay(1); + delay_us -= 1; + tmp = readl(eic->base + MCHP_EIC_SCFG(hwirq)); + } + + if (delay_us < 0) + dev_err(eic->dev, "Failed to configure IRQ=%u!\n", hwirq); +} + +static void mchp_eic_irq_mask(struct irq_data *d) +{ + struct mchp_eic *eic = irq_data_get_irq_chip_data(d); + unsigned int tmp; + + tmp = readl(eic->base + MCHP_EIC_SCFG(d->hwirq)); + tmp &= ~MCHP_EIC_SCFG_EN; + writel(tmp, eic->base + MCHP_EIC_SCFG(d->hwirq)); +} + +static void mchp_eic_irq_unmask(struct irq_data *d) +{ + struct mchp_eic *eic = irq_data_get_irq_chip_data(d); + unsigned int tmp; + + tmp = readl(eic->base + MCHP_EIC_SCFG(d->hwirq)); + tmp |= MCHP_EIC_SCFG_EN; + writel(tmp, eic->base + MCHP_EIC_SCFG(d->hwirq)); + mchp_eic_wait_rdy(eic, d->hwirq, MCHP_EIC_DEFAULT_WAIT_US); +} + +static int mchp_eic_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct mchp_eic *eic = irq_data_get_irq_chip_data(d); + unsigned int tmp; + + tmp = readl(eic->base + MCHP_EIC_SCFG(d->hwirq)); + tmp &= ~(MCHP_EIC
[PATCH 1/2] dt-bindings: mchp-eic: add bindings
Add DT bindings for Microchip External Interrupt Controller. Signed-off-by: Claudiu Beznea --- .../interrupt-controller/mchp,eic.yaml| 74 +++ 1 file changed, 74 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/mchp,eic.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/mchp,eic.yaml b/Documentation/devicetree/bindings/interrupt-controller/mchp,eic.yaml new file mode 100644 index ..5a927817aa7d --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/mchp,eic.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/mchp,eic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip External Interrupt Controller + +maintainers: + - Claudiu Beznea + +description: + This interrupt controller is found in Microchip SoCs (SAMA7G5) and provides + support for handling up to 2 external interrupt lines. + +properties: + compatible: +enum: + - microchip,sama7g5-eic + + reg: +maxItems: 1 + + interrupt-controller: true + + '#interrupt-cells': +const: 3 +description: + The first cell is the input IRQ number (between 0 and 1), the second cell + is the trigger type as defined in interrupt.txt present in this directory + and the third cell is the glitch filter (1, 2, 4, 8) in clock cycles + + 'interrupts': +description: | + Contains the GIC SPI IRQs mapped to the external interrupt lines. They + should be specified sequentially from output 0 to output 1. +minItems: 2 +maxItems: 2 + + clocks: +maxItems: 1 + + clock-names: +const: pclk + +required: + - compatible + - reg + - interrupt-controller + - '#interrupt-cells' + - 'interrupts' + - clocks + - clock-names + +additionalProperties: false + +examples: + - | +#include +#include + +eic: eic@e1628000 { + compatible = "microchip,sama7g5-eic"; + reg = <0xe1628000 0x100>; + interrupt-parent = <>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = , + ; + clocks = < PMC_TYPE_PERIPHERAL 37>; + clock-names = "pclk"; +}; + +... -- 2.25.1
[tip: timers/core] clocksource/drivers/timer-microchip-pit64b: Add clocksource suspend/resume
The following commit has been merged into the timers/core branch of tip: Commit-ID: e85c1d21b16b278f50d191155bc674633270e9c6 Gitweb: https://git.kernel.org/tip/e85c1d21b16b278f50d191155bc674633270e9c6 Author:Claudiu Beznea AuthorDate:Tue, 19 Jan 2021 14:59:25 +02:00 Committer: Daniel Lezcano CommitterDate: Wed, 03 Feb 2021 09:36:50 +01:00 clocksource/drivers/timer-microchip-pit64b: Add clocksource suspend/resume Add suspend/resume support for clocksource timer. Signed-off-by: Claudiu Beznea Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1611061165-30180-1-git-send-email-claudiu.bez...@microchip.com --- drivers/clocksource/timer-microchip-pit64b.c | 86 +++ 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c index 59e11ca..ab623b2 100644 --- a/drivers/clocksource/timer-microchip-pit64b.c +++ b/drivers/clocksource/timer-microchip-pit64b.c @@ -71,10 +71,24 @@ struct mchp_pit64b_clkevt { struct clock_event_device clkevt; }; -#define to_mchp_pit64b_timer(x) \ +#define clkevt_to_mchp_pit64b_timer(x) \ ((struct mchp_pit64b_timer *)container_of(x,\ struct mchp_pit64b_clkevt, clkevt)) +/** + * mchp_pit64b_clksrc - PIT64B clocksource data structure + * @timer: PIT64B timer + * @clksrc: clocksource + */ +struct mchp_pit64b_clksrc { + struct mchp_pit64b_timertimer; + struct clocksource clksrc; +}; + +#define clksrc_to_mchp_pit64b_timer(x) \ + ((struct mchp_pit64b_timer *)container_of(x,\ + struct mchp_pit64b_clksrc, clksrc)) + /* Base address for clocksource timer. */ static void __iomem *mchp_pit64b_cs_base; /* Default cycles for clockevent timer. */ @@ -116,6 +130,36 @@ static inline void mchp_pit64b_reset(struct mchp_pit64b_timer *timer, writel_relaxed(MCHP_PIT64B_CR_START, timer->base + MCHP_PIT64B_CR); } +static void mchp_pit64b_suspend(struct mchp_pit64b_timer *timer) +{ + writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR); + if (timer->mode & MCHP_PIT64B_MR_SGCLK) + clk_disable_unprepare(timer->gclk); + clk_disable_unprepare(timer->pclk); +} + +static void mchp_pit64b_resume(struct mchp_pit64b_timer *timer) +{ + clk_prepare_enable(timer->pclk); + if (timer->mode & MCHP_PIT64B_MR_SGCLK) + clk_prepare_enable(timer->gclk); +} + +static void mchp_pit64b_clksrc_suspend(struct clocksource *cs) +{ + struct mchp_pit64b_timer *timer = clksrc_to_mchp_pit64b_timer(cs); + + mchp_pit64b_suspend(timer); +} + +static void mchp_pit64b_clksrc_resume(struct clocksource *cs) +{ + struct mchp_pit64b_timer *timer = clksrc_to_mchp_pit64b_timer(cs); + + mchp_pit64b_resume(timer); + mchp_pit64b_reset(timer, ULLONG_MAX, MCHP_PIT64B_MR_CONT, 0); +} + static u64 mchp_pit64b_clksrc_read(struct clocksource *cs) { return mchp_pit64b_cnt_read(mchp_pit64b_cs_base); @@ -128,7 +172,7 @@ static u64 mchp_pit64b_sched_read_clk(void) static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev) { - struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev); + struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev); writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR); @@ -137,7 +181,7 @@ static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev) static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev) { - struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev); + struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev); mchp_pit64b_reset(timer, mchp_pit64b_ce_cycles, MCHP_PIT64B_MR_CONT, MCHP_PIT64B_IER_PERIOD); @@ -148,7 +192,7 @@ static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev) static int mchp_pit64b_clkevt_set_next_event(unsigned long evt, struct clock_event_device *cedev) { - struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev); + struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev); mchp_pit64b_reset(timer, evt, MCHP_PIT64B_MR_ONE_SHOT, MCHP_PIT64B_IER_PERIOD); @@ -158,21 +202,16 @@ static int mchp_pit64b_clkevt_set_next_event(unsigned long evt, static void mchp_pit64b_clkevt_suspend(struct clock_event_device *cedev) { - struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev); + struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev); - writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR); - if (timer->mode & MCHP_PIT64B_MR_SGCLK) - clk_disable_unprepare(timer->gclk); - clk_disable_unprepare
[PATCH] power: reset: at91-reset: free resources on exit path
Free resources on exit path (failure path of probe and remove). Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Claudiu Beznea --- drivers/power/reset/at91-reset.c | 25 - 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 3ff9d93a5226..2ff7833153b6 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -206,7 +206,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) if (!reset->ramc_base[idx]) { dev_err(>dev, "Could not map ram controller address\n"); of_node_put(np); - return -ENODEV; + ret = -ENODEV; + goto unmap; } idx++; } @@ -218,13 +219,15 @@ static int __init at91_reset_probe(struct platform_device *pdev) reset->args = (u32)match->data; reset->sclk = devm_clk_get(>dev, NULL); - if (IS_ERR(reset->sclk)) - return PTR_ERR(reset->sclk); + if (IS_ERR(reset->sclk)) { + ret = PTR_ERR(reset->sclk); + goto unmap; + } ret = clk_prepare_enable(reset->sclk); if (ret) { dev_err(>dev, "Could not enable slow clock\n"); - return ret; + goto unmap; } platform_set_drvdata(pdev, reset); @@ -239,21 +242,33 @@ static int __init at91_reset_probe(struct platform_device *pdev) ret = register_restart_handler(>nb); if (ret) { clk_disable_unprepare(reset->sclk); - return ret; + goto unmap; } at91_reset_status(pdev, reset->rstc_base); return 0; + +unmap: + iounmap(reset->rstc_base); + for (idx = 0; idx < ARRAY_SIZE(reset->ramc_base); idx++) + iounmap(reset->ramc_base[idx]); + + return ret; } static int __exit at91_reset_remove(struct platform_device *pdev) { struct at91_reset *reset = platform_get_drvdata(pdev); + int idx; unregister_restart_handler(>nb); clk_disable_unprepare(reset->sclk); + iounmap(reset->rstc_base); + for (idx = 0; idx < ARRAY_SIZE(reset->ramc_base); idx++) + iounmap(reset->ramc_base[idx]); + return 0; } -- 2.25.1
[PATCH] ARM: configs: at91: enable drivers for sam9x60
Enable drivers for sam9x60/sam9x60-ek: - shutdown controller - CAN - AT24 EEPROM (present on SAM9X60-EK) - MCP23S08 (present on SAM9X60-EK) - AES, TDES, SHA And use "make savedefconfig". Signed-off-by: Claudiu Beznea --- arch/arm/configs/at91_dt_defconfig | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 5f3415c743ec..e274f8c492d2 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -17,8 +17,6 @@ CONFIG_SOC_SAM9X60=y # CONFIG_ATMEL_CLOCKSOURCE_PIT is not set CONFIG_AEABI=y CONFIG_UACCESS_WITH_MEMCPY=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x2110,25165824 root=/dev/ram0 rw" @@ -38,6 +36,8 @@ CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y # CONFIG_INET_DIAG is not set CONFIG_IPV6_SIT_6RD=y +CONFIG_CAN=y +CONFIG_CAN_AT91=y CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_DEVTMPFS=y @@ -58,6 +58,7 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_ATMEL_SSC=y +CONFIG_EEPROM_AT24=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set @@ -91,7 +92,6 @@ CONFIG_RT2800USB_UNKNOWN=y CONFIG_RTL8187=m CONFIG_RTL8192CU=m # CONFIG_RTLWIFI_DEBUG is not set -CONFIG_INPUT_POLLDEV=y CONFIG_INPUT_JOYDEV=y CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set @@ -111,8 +111,8 @@ CONFIG_I2C_GPIO=y CONFIG_SPI=y CONFIG_SPI_ATMEL=y CONFIG_SPI_ATMEL_QUADSPI=y +CONFIG_PINCTRL_MCP23S08=m CONFIG_POWER_RESET=y -# CONFIG_POWER_RESET_AT91_SAMA5D2_SHDWC is not set CONFIG_POWER_SUPPLY=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y @@ -208,7 +208,9 @@ CONFIG_NLS_UTF8=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m -# CONFIG_CRYPTO_HW is not set +CONFIG_CRYPTO_DEV_ATMEL_AES=y +CONFIG_CRYPTO_DEV_ATMEL_TDES=y +CONFIG_CRYPTO_DEV_ATMEL_SHA=y CONFIG_CRC_CCITT=y CONFIG_FONTS=y CONFIG_FONT_8x8=y -- 2.7.4
[PATCH v2 0/3] pinctrl: at91-pio4: add support for slew-rate
Hi, This series adds support for slew rate on SAMA7G5. Along with this patch 3/3 fixes some checkpatch.pl warnings. Thank you, Claudiu Beznea Changes in v2: - s/sr/slew_rate_support/g in patch 2/3 - collected tags Claudiu Beznea (3): dt-bindings: pinctrl: at91-pio4: add slew-rate pinctrl: at91-pio4: add support for slew-rate pinctrl: at91-pio4: fix "Prefer 'unsigned int' to bare use of 'unsigned'" .../bindings/pinctrl/atmel,at91-pio4-pinctrl.txt | 8 +- drivers/pinctrl/pinctrl-at91-pio4.c| 137 + 2 files changed, 89 insertions(+), 56 deletions(-) -- 2.7.4