aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/at91/patches-5.10/214-ARM-at91-pm-save-ddr-phy-calibration-data-to-securam.patch
diff options
context:
space:
mode:
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.patch156
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
+