diff options
Diffstat (limited to 'target/linux/at91/patches-5.10/214-ARM-at91-pm-save-ddr-phy-calibration-data-to-securam.patch')
-rw-r--r-- | target/linux/at91/patches-5.10/214-ARM-at91-pm-save-ddr-phy-calibration-data-to-securam.patch | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/target/linux/at91/patches-5.10/214-ARM-at91-pm-save-ddr-phy-calibration-data-to-securam.patch b/target/linux/at91/patches-5.10/214-ARM-at91-pm-save-ddr-phy-calibration-data-to-securam.patch new file mode 100644 index 0000000000..f6306c8276 --- /dev/null +++ b/target/linux/at91/patches-5.10/214-ARM-at91-pm-save-ddr-phy-calibration-data-to-securam.patch @@ -0,0 +1,156 @@ +From b355bb98eae3e343969fc5a0203e0dab472a6acd Mon Sep 17 00:00:00 2001 +From: Claudiu Beznea <claudiu.beznea@microchip.com> +Date: Thu, 15 Apr 2021 13:50:05 +0300 +Subject: [PATCH 214/247] 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 <claudiu.beznea@microchip.com> +Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com> +Link: https://lore.kernel.org/r/20210415105010.569620-20-claudiu.beznea@microchip.com +--- + arch/arm/mach-at91/pm.c | 60 ++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 59 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c +index b047a1f2ddfb..fd3beaeec17d 100644 +--- a/arch/arm/mach-at91/pm.c ++++ b/arch/arm/mach-at91/pm.c +@@ -10,6 +10,7 @@ + #include <linux/io.h> + #include <linux/of_address.h> + #include <linux/of.h> ++#include <linux/of_fdt.h> + #include <linux/of_platform.h> + #include <linux/parser.h> + #include <linux/suspend.h> +@@ -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(); + +@@ -688,12 +709,40 @@ static bool __init at91_is_pm_mode_active(int pm_mode) + soc_pm.data.suspend_mode == pm_mode); + } + ++static int __init at91_pm_backup_scan_memcs(unsigned long node, ++ const char *uname, int depth, ++ void *data) ++{ ++ const char *type; ++ const __be32 *reg; ++ int *located = data; ++ int size; ++ ++ /* Memory node already located. */ ++ if (*located) ++ return 0; ++ ++ type = of_get_flat_dt_prop(node, "device_type", NULL); ++ ++ /* We are scanning "memory" nodes only. */ ++ if (!type || strcmp(type, "memory")) ++ return 0; ++ ++ reg = of_get_flat_dt_prop(node, "reg", &size); ++ if (reg) { ++ soc_pm.memcs = __va((phys_addr_t)be32_to_cpu(*reg)); ++ *located = 1; ++ } ++ ++ return 0; ++} ++ + static int __init at91_pm_backup_init(void) + { + struct gen_pool *sram_pool; + struct device_node *np; + struct platform_device *pdev; +- int ret = -ENODEV; ++ int ret = -ENODEV, located = 0; + + if (!IS_ENABLED(CONFIG_SOC_SAMA5D2)) + return -EPERM; +@@ -728,6 +777,15 @@ static int __init at91_pm_backup_init(void) + soc_pm.bu->suspended = 0; + soc_pm.bu->canary = __pa_symbol(&canary); + soc_pm.bu->resume = __pa_symbol(cpu_resume); ++ if (soc_pm.data.ramc_phy) { ++ of_scan_flat_dt(at91_pm_backup_scan_memcs, &located); ++ if (!located) ++ goto securam_fail; ++ ++ /* DDR3PHY_ZQ0SR0 */ ++ soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy + ++ 0x188); ++ } + + return 0; + +-- +2.32.0 + |