a46b5acb2215f7b38830ef2b6a2f448238edb49a
[openwrt/openwrt.git] / target / linux / at91 / patches-5.15 / 214-ARM-at91-pm-save-ddr-phy-calibration-data-to-securam.patch
1 From b355bb98eae3e343969fc5a0203e0dab472a6acd Mon Sep 17 00:00:00 2001
2 From: Claudiu Beznea <claudiu.beznea@microchip.com>
3 Date: Thu, 15 Apr 2021 13:50:05 +0300
4 Subject: [PATCH 214/247] ARM: at91: pm: save ddr phy calibration data to
5 securam
6
7 The resuming from backup mode is done with the help of bootloader.
8 The bootloader reconfigure the DDR controller and DDR PHY controller.
9 To speed-up the resuming process save the PHY calibration data into
10 SECURAM before suspending (securam is powered on backup mode).
11 This data will be later used by bootloader in DDR PHY reconfiguration
12 process. Also, in the process or recalibration the first 8 words of
13 the memory may get corrupted. To solve this, these 8 words are saved
14 in the securam and restored by bootloader in the process of PHY
15 configuration.
16
17 Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
18 Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
19 Link: https://lore.kernel.org/r/20210415105010.569620-20-claudiu.beznea@microchip.com
20 ---
21 arch/arm/mach-at91/pm.c | 60 ++++++++++++++++++++++++++++++++++++++++-
22 1 file changed, 59 insertions(+), 1 deletion(-)
23
24 --- a/arch/arm/mach-at91/pm.c
25 +++ b/arch/arm/mach-at91/pm.c
26 @@ -10,6 +10,7 @@
27 #include <linux/io.h>
28 #include <linux/of_address.h>
29 #include <linux/of.h>
30 +#include <linux/of_fdt.h>
31 #include <linux/of_platform.h>
32 #include <linux/parser.h>
33 #include <linux/suspend.h>
34 @@ -27,18 +28,23 @@
35 #include "generic.h"
36 #include "pm.h"
37
38 +#define BACKUP_DDR_PHY_CALIBRATION (9)
39 +
40 /**
41 * struct at91_pm_bu - AT91 power management backup unit data structure
42 * @suspended: true if suspended to backup mode
43 * @reserved: reserved
44 * @canary: canary data for memory checking after exit from backup mode
45 * @resume: resume API
46 + * @ddr_phy_calibration: DDR PHY calibration data: ZQ0CR0, first 8 words
47 + * of the memory
48 */
49 struct at91_pm_bu {
50 int suspended;
51 unsigned long reserved;
52 phys_addr_t canary;
53 phys_addr_t resume;
54 + unsigned long ddr_phy_calibration[BACKUP_DDR_PHY_CALIBRATION];
55 };
56
57 /**
58 @@ -48,6 +54,7 @@ struct at91_pm_bu {
59 * @ws_ids: wakup sources of_device_id array
60 * @data: PM data to be used on last phase of suspend
61 * @bu: backup unit mapped data (for backup mode)
62 + * @memcs: memory chip select
63 */
64 struct at91_soc_pm {
65 int (*config_shdwc_ws)(void __iomem *shdwc, u32 *mode, u32 *polarity);
66 @@ -55,6 +62,7 @@ struct at91_soc_pm {
67 const struct of_device_id *ws_ids;
68 struct at91_pm_bu *bu;
69 struct at91_pm_data data;
70 + void *memcs;
71 };
72
73 /**
74 @@ -316,6 +324,19 @@ extern u32 at91_pm_suspend_in_sram_sz;
75
76 static int at91_suspend_finish(unsigned long val)
77 {
78 + int i;
79 +
80 + if (soc_pm.data.mode == AT91_PM_BACKUP && soc_pm.data.ramc_phy) {
81 + /*
82 + * The 1st 8 words of memory might get corrupted in the process
83 + * of DDR PHY recalibration; it is saved here in securam and it
84 + * will be restored later, after recalibration, by bootloader
85 + */
86 + for (i = 1; i < BACKUP_DDR_PHY_CALIBRATION; i++)
87 + soc_pm.bu->ddr_phy_calibration[i] =
88 + *((unsigned int *)soc_pm.memcs + (i - 1));
89 + }
90 +
91 flush_cache_all();
92 outer_disable();
93
94 @@ -688,12 +709,40 @@ static bool __init at91_is_pm_mode_activ
95 soc_pm.data.suspend_mode == pm_mode);
96 }
97
98 +static int __init at91_pm_backup_scan_memcs(unsigned long node,
99 + const char *uname, int depth,
100 + void *data)
101 +{
102 + const char *type;
103 + const __be32 *reg;
104 + int *located = data;
105 + int size;
106 +
107 + /* Memory node already located. */
108 + if (*located)
109 + return 0;
110 +
111 + type = of_get_flat_dt_prop(node, "device_type", NULL);
112 +
113 + /* We are scanning "memory" nodes only. */
114 + if (!type || strcmp(type, "memory"))
115 + return 0;
116 +
117 + reg = of_get_flat_dt_prop(node, "reg", &size);
118 + if (reg) {
119 + soc_pm.memcs = __va((phys_addr_t)be32_to_cpu(*reg));
120 + *located = 1;
121 + }
122 +
123 + return 0;
124 +}
125 +
126 static int __init at91_pm_backup_init(void)
127 {
128 struct gen_pool *sram_pool;
129 struct device_node *np;
130 struct platform_device *pdev;
131 - int ret = -ENODEV;
132 + int ret = -ENODEV, located = 0;
133
134 if (!IS_ENABLED(CONFIG_SOC_SAMA5D2))
135 return -EPERM;
136 @@ -728,6 +777,15 @@ static int __init at91_pm_backup_init(vo
137 soc_pm.bu->suspended = 0;
138 soc_pm.bu->canary = __pa_symbol(&canary);
139 soc_pm.bu->resume = __pa_symbol(cpu_resume);
140 + if (soc_pm.data.ramc_phy) {
141 + of_scan_flat_dt(at91_pm_backup_scan_memcs, &located);
142 + if (!located)
143 + goto securam_fail;
144 +
145 + /* DDR3PHY_ZQ0SR0 */
146 + soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy +
147 + 0x188);
148 + }
149
150 return 0;
151