]>
Commit | Line | Data |
---|---|---|
4549e789 | 1 | // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause |
e70f70aa PD |
2 | /* |
3 | * Copyright (C) 2018, STMicroelectronics - All Rights Reserved | |
e70f70aa PD |
4 | */ |
5 | ||
66b3b9db PD |
6 | #define LOG_CATEGORY UCLASS_RAM |
7 | ||
d678a59d | 8 | #include <common.h> |
e70f70aa | 9 | #include <clk.h> |
f7ae49fc | 10 | #include <log.h> |
e70f70aa PD |
11 | #include <ram.h> |
12 | #include <reset.h> | |
13 | #include <timer.h> | |
14 | #include <asm/io.h> | |
15 | #include <asm/arch/ddr.h> | |
cd93d625 | 16 | #include <linux/bitops.h> |
c05ed00a | 17 | #include <linux/delay.h> |
e70f70aa | 18 | #include <linux/iopoll.h> |
1e94b46f | 19 | #include <linux/printk.h> |
e70f70aa PD |
20 | #include "stm32mp1_ddr.h" |
21 | #include "stm32mp1_ddr_regs.h" | |
22 | ||
23 | #define RCC_DDRITFCR 0xD8 | |
24 | ||
25 | #define RCC_DDRITFCR_DDRCAPBRST (BIT(14)) | |
26 | #define RCC_DDRITFCR_DDRCAXIRST (BIT(15)) | |
27 | #define RCC_DDRITFCR_DDRCORERST (BIT(16)) | |
28 | #define RCC_DDRITFCR_DPHYAPBRST (BIT(17)) | |
29 | #define RCC_DDRITFCR_DPHYRST (BIT(18)) | |
30 | #define RCC_DDRITFCR_DPHYCTLRST (BIT(19)) | |
0d44ad8b MV |
31 | #define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK(22, 20) |
32 | #define RCC_DDRITFCR_DDRCKMOD_ASR BIT(20) | |
e70f70aa PD |
33 | |
34 | struct reg_desc { | |
35 | const char *name; | |
36 | u16 offset; /* offset for base address */ | |
37 | u8 par_offset; /* offset for parameter array */ | |
38 | }; | |
39 | ||
40 | #define INVALID_OFFSET 0xFF | |
41 | ||
42 | #define DDRCTL_REG(x, y) \ | |
43 | {#x,\ | |
44 | offsetof(struct stm32mp1_ddrctl, x),\ | |
45 | offsetof(struct y, x)} | |
46 | ||
47 | #define DDRPHY_REG(x, y) \ | |
48 | {#x,\ | |
49 | offsetof(struct stm32mp1_ddrphy, x),\ | |
50 | offsetof(struct y, x)} | |
51 | ||
01a75108 PD |
52 | #define DDR_REG_DYN(x) \ |
53 | {#x,\ | |
54 | offsetof(struct stm32mp1_ddrctl, x),\ | |
55 | INVALID_OFFSET} | |
56 | ||
57 | #define DDRPHY_REG_DYN(x) \ | |
58 | {#x,\ | |
59 | offsetof(struct stm32mp1_ddrphy, x),\ | |
60 | INVALID_OFFSET} | |
61 | ||
53bb8316 PD |
62 | /*********************************************************** |
63 | * PARAMETERS: value get from device tree : | |
64 | * size / order need to be aligned with binding | |
65 | * modification NOT ALLOWED !!! | |
66 | ***********************************************************/ | |
67 | #define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */ | |
68 | #define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */ | |
69 | #define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */ | |
70 | #define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */ | |
71 | ||
72 | #define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */ | |
73 | #define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */ | |
53bb8316 | 74 | |
e70f70aa | 75 | #define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg) |
53bb8316 | 76 | static const struct reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = { |
e70f70aa PD |
77 | DDRCTL_REG_REG(mstr), |
78 | DDRCTL_REG_REG(mrctrl0), | |
79 | DDRCTL_REG_REG(mrctrl1), | |
80 | DDRCTL_REG_REG(derateen), | |
81 | DDRCTL_REG_REG(derateint), | |
82 | DDRCTL_REG_REG(pwrctl), | |
83 | DDRCTL_REG_REG(pwrtmg), | |
84 | DDRCTL_REG_REG(hwlpctl), | |
85 | DDRCTL_REG_REG(rfshctl0), | |
86 | DDRCTL_REG_REG(rfshctl3), | |
87 | DDRCTL_REG_REG(crcparctl0), | |
88 | DDRCTL_REG_REG(zqctl0), | |
89 | DDRCTL_REG_REG(dfitmg0), | |
90 | DDRCTL_REG_REG(dfitmg1), | |
91 | DDRCTL_REG_REG(dfilpcfg0), | |
92 | DDRCTL_REG_REG(dfiupd0), | |
93 | DDRCTL_REG_REG(dfiupd1), | |
94 | DDRCTL_REG_REG(dfiupd2), | |
95 | DDRCTL_REG_REG(dfiphymstr), | |
96 | DDRCTL_REG_REG(odtmap), | |
97 | DDRCTL_REG_REG(dbg0), | |
98 | DDRCTL_REG_REG(dbg1), | |
99 | DDRCTL_REG_REG(dbgcmd), | |
100 | DDRCTL_REG_REG(poisoncfg), | |
101 | DDRCTL_REG_REG(pccfg), | |
102 | }; | |
103 | ||
104 | #define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing) | |
53bb8316 | 105 | static const struct reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = { |
e70f70aa PD |
106 | DDRCTL_REG_TIMING(rfshtmg), |
107 | DDRCTL_REG_TIMING(dramtmg0), | |
108 | DDRCTL_REG_TIMING(dramtmg1), | |
109 | DDRCTL_REG_TIMING(dramtmg2), | |
110 | DDRCTL_REG_TIMING(dramtmg3), | |
111 | DDRCTL_REG_TIMING(dramtmg4), | |
112 | DDRCTL_REG_TIMING(dramtmg5), | |
113 | DDRCTL_REG_TIMING(dramtmg6), | |
114 | DDRCTL_REG_TIMING(dramtmg7), | |
115 | DDRCTL_REG_TIMING(dramtmg8), | |
116 | DDRCTL_REG_TIMING(dramtmg14), | |
117 | DDRCTL_REG_TIMING(odtcfg), | |
118 | }; | |
119 | ||
120 | #define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map) | |
53bb8316 | 121 | static const struct reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = { |
e70f70aa PD |
122 | DDRCTL_REG_MAP(addrmap1), |
123 | DDRCTL_REG_MAP(addrmap2), | |
124 | DDRCTL_REG_MAP(addrmap3), | |
125 | DDRCTL_REG_MAP(addrmap4), | |
126 | DDRCTL_REG_MAP(addrmap5), | |
127 | DDRCTL_REG_MAP(addrmap6), | |
128 | DDRCTL_REG_MAP(addrmap9), | |
129 | DDRCTL_REG_MAP(addrmap10), | |
130 | DDRCTL_REG_MAP(addrmap11), | |
131 | }; | |
132 | ||
133 | #define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf) | |
53bb8316 | 134 | static const struct reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = { |
e70f70aa PD |
135 | DDRCTL_REG_PERF(sched), |
136 | DDRCTL_REG_PERF(sched1), | |
137 | DDRCTL_REG_PERF(perfhpr1), | |
138 | DDRCTL_REG_PERF(perflpr1), | |
139 | DDRCTL_REG_PERF(perfwr1), | |
140 | DDRCTL_REG_PERF(pcfgr_0), | |
141 | DDRCTL_REG_PERF(pcfgw_0), | |
142 | DDRCTL_REG_PERF(pcfgqos0_0), | |
143 | DDRCTL_REG_PERF(pcfgqos1_0), | |
144 | DDRCTL_REG_PERF(pcfgwqos0_0), | |
145 | DDRCTL_REG_PERF(pcfgwqos1_0), | |
146 | DDRCTL_REG_PERF(pcfgr_1), | |
147 | DDRCTL_REG_PERF(pcfgw_1), | |
148 | DDRCTL_REG_PERF(pcfgqos0_1), | |
149 | DDRCTL_REG_PERF(pcfgqos1_1), | |
150 | DDRCTL_REG_PERF(pcfgwqos0_1), | |
151 | DDRCTL_REG_PERF(pcfgwqos1_1), | |
152 | }; | |
153 | ||
154 | #define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg) | |
53bb8316 | 155 | static const struct reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = { |
e70f70aa PD |
156 | DDRPHY_REG_REG(pgcr), |
157 | DDRPHY_REG_REG(aciocr), | |
158 | DDRPHY_REG_REG(dxccr), | |
159 | DDRPHY_REG_REG(dsgcr), | |
160 | DDRPHY_REG_REG(dcr), | |
161 | DDRPHY_REG_REG(odtcr), | |
162 | DDRPHY_REG_REG(zq0cr1), | |
163 | DDRPHY_REG_REG(dx0gcr), | |
164 | DDRPHY_REG_REG(dx1gcr), | |
165 | DDRPHY_REG_REG(dx2gcr), | |
166 | DDRPHY_REG_REG(dx3gcr), | |
167 | }; | |
168 | ||
169 | #define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing) | |
53bb8316 | 170 | static const struct reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = { |
e70f70aa PD |
171 | DDRPHY_REG_TIMING(ptr0), |
172 | DDRPHY_REG_TIMING(ptr1), | |
173 | DDRPHY_REG_TIMING(ptr2), | |
174 | DDRPHY_REG_TIMING(dtpr0), | |
175 | DDRPHY_REG_TIMING(dtpr1), | |
176 | DDRPHY_REG_TIMING(dtpr2), | |
177 | DDRPHY_REG_TIMING(mr0), | |
178 | DDRPHY_REG_TIMING(mr1), | |
179 | DDRPHY_REG_TIMING(mr2), | |
180 | DDRPHY_REG_TIMING(mr3), | |
181 | }; | |
182 | ||
01a75108 PD |
183 | /************************************************************** |
184 | * DYNAMIC REGISTERS: only used for debug purpose (read/modify) | |
185 | **************************************************************/ | |
186 | #ifdef CONFIG_STM32MP1_DDR_INTERACTIVE | |
187 | static const struct reg_desc ddr_dyn[] = { | |
188 | DDR_REG_DYN(stat), | |
189 | DDR_REG_DYN(init0), | |
190 | DDR_REG_DYN(dfimisc), | |
191 | DDR_REG_DYN(dfistat), | |
192 | DDR_REG_DYN(swctl), | |
193 | DDR_REG_DYN(swstat), | |
194 | DDR_REG_DYN(pctrl_0), | |
195 | DDR_REG_DYN(pctrl_1), | |
196 | }; | |
197 | ||
198 | #define DDR_REG_DYN_SIZE ARRAY_SIZE(ddr_dyn) | |
199 | ||
200 | static const struct reg_desc ddrphy_dyn[] = { | |
201 | DDRPHY_REG_DYN(pir), | |
202 | DDRPHY_REG_DYN(pgsr), | |
203 | DDRPHY_REG_DYN(zq0sr0), | |
204 | DDRPHY_REG_DYN(zq0sr1), | |
205 | DDRPHY_REG_DYN(dx0gsr0), | |
206 | DDRPHY_REG_DYN(dx0gsr1), | |
9819fe34 PD |
207 | DDRPHY_REG_DYN(dx0dllcr), |
208 | DDRPHY_REG_DYN(dx0dqtr), | |
209 | DDRPHY_REG_DYN(dx0dqstr), | |
01a75108 PD |
210 | DDRPHY_REG_DYN(dx1gsr0), |
211 | DDRPHY_REG_DYN(dx1gsr1), | |
9819fe34 PD |
212 | DDRPHY_REG_DYN(dx1dllcr), |
213 | DDRPHY_REG_DYN(dx1dqtr), | |
214 | DDRPHY_REG_DYN(dx1dqstr), | |
01a75108 PD |
215 | DDRPHY_REG_DYN(dx2gsr0), |
216 | DDRPHY_REG_DYN(dx2gsr1), | |
9819fe34 PD |
217 | DDRPHY_REG_DYN(dx2dllcr), |
218 | DDRPHY_REG_DYN(dx2dqtr), | |
219 | DDRPHY_REG_DYN(dx2dqstr), | |
01a75108 PD |
220 | DDRPHY_REG_DYN(dx3gsr0), |
221 | DDRPHY_REG_DYN(dx3gsr1), | |
9819fe34 PD |
222 | DDRPHY_REG_DYN(dx3dllcr), |
223 | DDRPHY_REG_DYN(dx3dqtr), | |
224 | DDRPHY_REG_DYN(dx3dqstr), | |
01a75108 PD |
225 | }; |
226 | ||
227 | #define DDRPHY_REG_DYN_SIZE ARRAY_SIZE(ddrphy_dyn) | |
228 | ||
229 | #endif | |
230 | ||
53bb8316 PD |
231 | /***************************************************************** |
232 | * REGISTERS ARRAY: used to parse device tree and interactive mode | |
233 | *****************************************************************/ | |
e70f70aa PD |
234 | enum reg_type { |
235 | REG_REG, | |
236 | REG_TIMING, | |
237 | REG_PERF, | |
238 | REG_MAP, | |
239 | REGPHY_REG, | |
240 | REGPHY_TIMING, | |
01a75108 PD |
241 | #ifdef CONFIG_STM32MP1_DDR_INTERACTIVE |
242 | /* dynamic registers => managed in driver or not changed, | |
243 | * can be dumped in interactive mode | |
244 | */ | |
245 | REG_DYN, | |
246 | REGPHY_DYN, | |
247 | #endif | |
e70f70aa PD |
248 | REG_TYPE_NB |
249 | }; | |
250 | ||
251 | enum base_type { | |
252 | DDR_BASE, | |
253 | DDRPHY_BASE, | |
254 | NONE_BASE | |
255 | }; | |
256 | ||
257 | struct ddr_reg_info { | |
258 | const char *name; | |
259 | const struct reg_desc *desc; | |
260 | u8 size; | |
261 | enum base_type base; | |
262 | }; | |
263 | ||
e70f70aa PD |
264 | const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = { |
265 | [REG_REG] = { | |
53bb8316 | 266 | "static", ddr_reg, DDRCTL_REG_REG_SIZE, DDR_BASE}, |
e70f70aa | 267 | [REG_TIMING] = { |
53bb8316 | 268 | "timing", ddr_timing, DDRCTL_REG_TIMING_SIZE, DDR_BASE}, |
e70f70aa | 269 | [REG_PERF] = { |
53bb8316 | 270 | "perf", ddr_perf, DDRCTL_REG_PERF_SIZE, DDR_BASE}, |
e70f70aa | 271 | [REG_MAP] = { |
53bb8316 | 272 | "map", ddr_map, DDRCTL_REG_MAP_SIZE, DDR_BASE}, |
e70f70aa | 273 | [REGPHY_REG] = { |
53bb8316 | 274 | "static", ddrphy_reg, DDRPHY_REG_REG_SIZE, DDRPHY_BASE}, |
e70f70aa | 275 | [REGPHY_TIMING] = { |
53bb8316 | 276 | "timing", ddrphy_timing, DDRPHY_REG_TIMING_SIZE, DDRPHY_BASE}, |
01a75108 PD |
277 | #ifdef CONFIG_STM32MP1_DDR_INTERACTIVE |
278 | [REG_DYN] = { | |
279 | "dyn", ddr_dyn, DDR_REG_DYN_SIZE, DDR_BASE}, | |
280 | [REGPHY_DYN] = { | |
281 | "dyn", ddrphy_dyn, DDRPHY_REG_DYN_SIZE, DDRPHY_BASE}, | |
282 | #endif | |
283 | ||
e70f70aa PD |
284 | }; |
285 | ||
286 | const char *base_name[] = { | |
287 | [DDR_BASE] = "ctl", | |
288 | [DDRPHY_BASE] = "phy", | |
289 | }; | |
290 | ||
291 | static u32 get_base_addr(const struct ddr_info *priv, enum base_type base) | |
292 | { | |
293 | if (base == DDRPHY_BASE) | |
294 | return (u32)priv->phy; | |
295 | else | |
296 | return (u32)priv->ctl; | |
297 | } | |
298 | ||
299 | static void set_reg(const struct ddr_info *priv, | |
300 | enum reg_type type, | |
301 | const void *param) | |
302 | { | |
303 | unsigned int i; | |
304 | unsigned int *ptr, value; | |
305 | enum base_type base = ddr_registers[type].base; | |
306 | u32 base_addr = get_base_addr(priv, base); | |
307 | const struct reg_desc *desc = ddr_registers[type].desc; | |
308 | ||
66b3b9db | 309 | log_debug("init %s\n", ddr_registers[type].name); |
e70f70aa PD |
310 | for (i = 0; i < ddr_registers[type].size; i++) { |
311 | ptr = (unsigned int *)(base_addr + desc[i].offset); | |
312 | if (desc[i].par_offset == INVALID_OFFSET) { | |
66b3b9db | 313 | log_err("invalid parameter offset for %s", desc[i].name); |
e70f70aa PD |
314 | } else { |
315 | value = *((u32 *)((u32)param + | |
316 | desc[i].par_offset)); | |
317 | writel(value, ptr); | |
66b3b9db PD |
318 | log_debug("[0x%x] %s= 0x%08x\n", |
319 | (u32)ptr, desc[i].name, value); | |
e70f70aa PD |
320 | } |
321 | } | |
322 | } | |
323 | ||
01a75108 PD |
324 | #ifdef CONFIG_STM32MP1_DDR_INTERACTIVE |
325 | static void stm32mp1_dump_reg_desc(u32 base_addr, const struct reg_desc *desc) | |
326 | { | |
327 | unsigned int *ptr; | |
328 | ||
329 | ptr = (unsigned int *)(base_addr + desc->offset); | |
330 | printf("%s= 0x%08x\n", desc->name, readl(ptr)); | |
331 | } | |
332 | ||
333 | static void stm32mp1_dump_param_desc(u32 par_addr, const struct reg_desc *desc) | |
334 | { | |
335 | unsigned int *ptr; | |
336 | ||
337 | ptr = (unsigned int *)(par_addr + desc->par_offset); | |
338 | printf("%s= 0x%08x\n", desc->name, readl(ptr)); | |
339 | } | |
340 | ||
341 | static const struct reg_desc *found_reg(const char *name, enum reg_type *type) | |
342 | { | |
343 | unsigned int i, j; | |
344 | const struct reg_desc *desc; | |
345 | ||
346 | for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) { | |
347 | desc = ddr_registers[i].desc; | |
348 | for (j = 0; j < ddr_registers[i].size; j++) { | |
349 | if (strcmp(name, desc[j].name) == 0) { | |
350 | *type = i; | |
351 | return &desc[j]; | |
352 | } | |
353 | } | |
354 | } | |
355 | *type = REG_TYPE_NB; | |
356 | return NULL; | |
357 | } | |
358 | ||
359 | int stm32mp1_dump_reg(const struct ddr_info *priv, | |
360 | const char *name) | |
361 | { | |
362 | unsigned int i, j; | |
363 | const struct reg_desc *desc; | |
364 | u32 base_addr; | |
365 | enum base_type p_base; | |
366 | enum reg_type type; | |
367 | const char *p_name; | |
368 | enum base_type filter = NONE_BASE; | |
369 | int result = -1; | |
370 | ||
371 | if (name) { | |
372 | if (strcmp(name, base_name[DDR_BASE]) == 0) | |
373 | filter = DDR_BASE; | |
374 | else if (strcmp(name, base_name[DDRPHY_BASE]) == 0) | |
375 | filter = DDRPHY_BASE; | |
376 | } | |
377 | ||
378 | for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) { | |
379 | p_base = ddr_registers[i].base; | |
380 | p_name = ddr_registers[i].name; | |
381 | if (!name || (filter == p_base || !strcmp(name, p_name))) { | |
382 | result = 0; | |
383 | desc = ddr_registers[i].desc; | |
384 | base_addr = get_base_addr(priv, p_base); | |
385 | printf("==%s.%s==\n", base_name[p_base], p_name); | |
386 | for (j = 0; j < ddr_registers[i].size; j++) | |
387 | stm32mp1_dump_reg_desc(base_addr, &desc[j]); | |
388 | } | |
389 | } | |
390 | if (result) { | |
391 | desc = found_reg(name, &type); | |
392 | if (desc) { | |
393 | p_base = ddr_registers[type].base; | |
394 | base_addr = get_base_addr(priv, p_base); | |
395 | stm32mp1_dump_reg_desc(base_addr, desc); | |
396 | result = 0; | |
397 | } | |
398 | } | |
399 | return result; | |
400 | } | |
401 | ||
402 | void stm32mp1_edit_reg(const struct ddr_info *priv, | |
403 | char *name, char *string) | |
404 | { | |
405 | unsigned long *ptr, value; | |
406 | enum reg_type type; | |
407 | enum base_type base; | |
408 | const struct reg_desc *desc; | |
409 | u32 base_addr; | |
410 | ||
411 | desc = found_reg(name, &type); | |
412 | ||
413 | if (!desc) { | |
414 | printf("%s not found\n", name); | |
415 | return; | |
416 | } | |
417 | if (strict_strtoul(string, 16, &value) < 0) { | |
418 | printf("invalid value %s\n", string); | |
419 | return; | |
420 | } | |
421 | base = ddr_registers[type].base; | |
422 | base_addr = get_base_addr(priv, base); | |
423 | ptr = (unsigned long *)(base_addr + desc->offset); | |
424 | writel(value, ptr); | |
425 | printf("%s= 0x%08x\n", desc->name, readl(ptr)); | |
426 | } | |
427 | ||
428 | static u32 get_par_addr(const struct stm32mp1_ddr_config *config, | |
429 | enum reg_type type) | |
430 | { | |
431 | u32 par_addr = 0x0; | |
432 | ||
433 | switch (type) { | |
434 | case REG_REG: | |
435 | par_addr = (u32)&config->c_reg; | |
436 | break; | |
437 | case REG_TIMING: | |
438 | par_addr = (u32)&config->c_timing; | |
439 | break; | |
440 | case REG_PERF: | |
441 | par_addr = (u32)&config->c_perf; | |
442 | break; | |
443 | case REG_MAP: | |
444 | par_addr = (u32)&config->c_map; | |
445 | break; | |
446 | case REGPHY_REG: | |
447 | par_addr = (u32)&config->p_reg; | |
448 | break; | |
449 | case REGPHY_TIMING: | |
450 | par_addr = (u32)&config->p_timing; | |
451 | break; | |
01a75108 PD |
452 | case REG_DYN: |
453 | case REGPHY_DYN: | |
454 | case REG_TYPE_NB: | |
455 | par_addr = (u32)NULL; | |
456 | break; | |
457 | } | |
458 | ||
459 | return par_addr; | |
460 | } | |
461 | ||
462 | int stm32mp1_dump_param(const struct stm32mp1_ddr_config *config, | |
463 | const char *name) | |
464 | { | |
465 | unsigned int i, j; | |
466 | const struct reg_desc *desc; | |
467 | u32 par_addr; | |
468 | enum base_type p_base; | |
469 | enum reg_type type; | |
470 | const char *p_name; | |
471 | enum base_type filter = NONE_BASE; | |
472 | int result = -EINVAL; | |
473 | ||
474 | if (name) { | |
475 | if (strcmp(name, base_name[DDR_BASE]) == 0) | |
476 | filter = DDR_BASE; | |
477 | else if (strcmp(name, base_name[DDRPHY_BASE]) == 0) | |
478 | filter = DDRPHY_BASE; | |
479 | } | |
480 | ||
481 | for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) { | |
482 | par_addr = get_par_addr(config, i); | |
483 | if (!par_addr) | |
484 | continue; | |
485 | p_base = ddr_registers[i].base; | |
486 | p_name = ddr_registers[i].name; | |
487 | if (!name || (filter == p_base || !strcmp(name, p_name))) { | |
488 | result = 0; | |
489 | desc = ddr_registers[i].desc; | |
490 | printf("==%s.%s==\n", base_name[p_base], p_name); | |
491 | for (j = 0; j < ddr_registers[i].size; j++) | |
492 | stm32mp1_dump_param_desc(par_addr, &desc[j]); | |
493 | } | |
494 | } | |
495 | if (result) { | |
496 | desc = found_reg(name, &type); | |
497 | if (desc) { | |
498 | par_addr = get_par_addr(config, type); | |
499 | if (par_addr) { | |
500 | stm32mp1_dump_param_desc(par_addr, desc); | |
501 | result = 0; | |
502 | } | |
503 | } | |
504 | } | |
505 | return result; | |
506 | } | |
507 | ||
508 | void stm32mp1_edit_param(const struct stm32mp1_ddr_config *config, | |
509 | char *name, char *string) | |
510 | { | |
511 | unsigned long *ptr, value; | |
512 | enum reg_type type; | |
513 | const struct reg_desc *desc; | |
514 | u32 par_addr; | |
515 | ||
516 | desc = found_reg(name, &type); | |
517 | if (!desc) { | |
518 | printf("%s not found\n", name); | |
519 | return; | |
520 | } | |
521 | if (strict_strtoul(string, 16, &value) < 0) { | |
522 | printf("invalid value %s\n", string); | |
523 | return; | |
524 | } | |
525 | par_addr = get_par_addr(config, type); | |
526 | if (!par_addr) { | |
527 | printf("no parameter %s\n", name); | |
528 | return; | |
529 | } | |
530 | ptr = (unsigned long *)(par_addr + desc->par_offset); | |
531 | writel(value, ptr); | |
532 | printf("%s= 0x%08x\n", desc->name, readl(ptr)); | |
533 | } | |
534 | #endif | |
535 | ||
536 | __weak bool stm32mp1_ddr_interactive(void *priv, | |
537 | enum stm32mp1_ddr_interact_step step, | |
538 | const struct stm32mp1_ddr_config *config) | |
539 | { | |
540 | return false; | |
541 | } | |
542 | ||
543 | #define INTERACTIVE(step)\ | |
544 | stm32mp1_ddr_interactive(priv, step, config) | |
545 | ||
e70f70aa PD |
546 | static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) |
547 | { | |
548 | u32 pgsr; | |
549 | int ret; | |
550 | ||
551 | ret = readl_poll_timeout(&phy->pgsr, pgsr, | |
552 | pgsr & (DDRPHYC_PGSR_IDONE | | |
553 | DDRPHYC_PGSR_DTERR | | |
554 | DDRPHYC_PGSR_DTIERR | | |
555 | DDRPHYC_PGSR_DFTERR | | |
556 | DDRPHYC_PGSR_RVERR | | |
557 | DDRPHYC_PGSR_RVEIRR), | |
558 | 1000000); | |
66b3b9db PD |
559 | log_debug("\n[0x%08x] pgsr = 0x%08x ret=%d\n", |
560 | (u32)&phy->pgsr, pgsr, ret); | |
e70f70aa PD |
561 | } |
562 | ||
b3c29dc9 | 563 | static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir) |
e70f70aa PD |
564 | { |
565 | pir |= DDRPHYC_PIR_INIT; | |
566 | writel(pir, &phy->pir); | |
66b3b9db PD |
567 | log_debug("[0x%08x] pir = 0x%08x -> 0x%08x\n", |
568 | (u32)&phy->pir, pir, readl(&phy->pir)); | |
e70f70aa PD |
569 | |
570 | /* need to wait 10 configuration clock before start polling */ | |
571 | udelay(10); | |
572 | ||
573 | /* Wait DRAM initialization and Gate Training Evaluation complete */ | |
574 | ddrphy_idone_wait(phy); | |
575 | } | |
576 | ||
577 | /* start quasi dynamic register update */ | |
578 | static void start_sw_done(struct stm32mp1_ddrctl *ctl) | |
579 | { | |
580 | clrbits_le32(&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); | |
581 | } | |
582 | ||
583 | /* wait quasi dynamic register update */ | |
584 | static void wait_sw_done_ack(struct stm32mp1_ddrctl *ctl) | |
585 | { | |
586 | int ret; | |
587 | u32 swstat; | |
588 | ||
589 | setbits_le32(&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); | |
590 | ||
591 | ret = readl_poll_timeout(&ctl->swstat, swstat, | |
592 | swstat & DDRCTRL_SWSTAT_SW_DONE_ACK, | |
593 | 1000000); | |
594 | if (ret) | |
595 | panic("Timeout initialising DRAM : DDR->swstat = %x\n", | |
596 | swstat); | |
597 | ||
66b3b9db | 598 | log_debug("[0x%08x] swstat = 0x%08x\n", (u32)&ctl->swstat, swstat); |
e70f70aa PD |
599 | } |
600 | ||
601 | /* wait quasi dynamic register update */ | |
602 | static void wait_operating_mode(struct ddr_info *priv, int mode) | |
603 | { | |
604 | u32 stat, val, mask, val2 = 0, mask2 = 0; | |
605 | int ret; | |
606 | ||
607 | mask = DDRCTRL_STAT_OPERATING_MODE_MASK; | |
608 | val = mode; | |
609 | /* self-refresh due to software => check also STAT.selfref_type */ | |
610 | if (mode == DDRCTRL_STAT_OPERATING_MODE_SR) { | |
611 | mask |= DDRCTRL_STAT_SELFREF_TYPE_MASK; | |
c3ec370a | 612 | val |= DDRCTRL_STAT_SELFREF_TYPE_SR; |
e70f70aa PD |
613 | } else if (mode == DDRCTRL_STAT_OPERATING_MODE_NORMAL) { |
614 | /* normal mode: handle also automatic self refresh */ | |
615 | mask2 = DDRCTRL_STAT_OPERATING_MODE_MASK | | |
616 | DDRCTRL_STAT_SELFREF_TYPE_MASK; | |
617 | val2 = DDRCTRL_STAT_OPERATING_MODE_SR | | |
618 | DDRCTRL_STAT_SELFREF_TYPE_ASR; | |
619 | } | |
620 | ||
621 | ret = readl_poll_timeout(&priv->ctl->stat, stat, | |
622 | ((stat & mask) == val) || | |
623 | (mask2 && ((stat & mask2) == val2)), | |
624 | 1000000); | |
625 | ||
626 | if (ret) | |
627 | panic("Timeout DRAM : DDR->stat = %x\n", stat); | |
628 | ||
66b3b9db | 629 | log_debug("[0x%08x] stat = 0x%08x\n", (u32)&priv->ctl->stat, stat); |
e70f70aa PD |
630 | } |
631 | ||
b3c29dc9 | 632 | static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl) |
e70f70aa PD |
633 | { |
634 | start_sw_done(ctl); | |
635 | /* quasi-dynamic register update*/ | |
636 | setbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); | |
b604a41c PD |
637 | clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN | |
638 | DDRCTRL_PWRCTL_SELFREF_EN); | |
e70f70aa PD |
639 | clrbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); |
640 | wait_sw_done_ack(ctl); | |
641 | } | |
642 | ||
b3c29dc9 PD |
643 | static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, |
644 | u32 rfshctl3, u32 pwrctl) | |
e70f70aa PD |
645 | { |
646 | start_sw_done(ctl); | |
647 | if (!(rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH)) | |
648 | clrbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); | |
649 | if (pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) | |
650 | setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); | |
b604a41c PD |
651 | if ((pwrctl & DDRCTRL_PWRCTL_SELFREF_EN)) |
652 | setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_EN); | |
e70f70aa PD |
653 | setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); |
654 | wait_sw_done_ack(ctl); | |
655 | } | |
656 | ||
221869ef | 657 | static void stm32mp1_asr_enable(struct ddr_info *priv, const u32 pwrctl) |
0d44ad8b MV |
658 | { |
659 | struct stm32mp1_ddrctl *ctl = priv->ctl; | |
660 | ||
221869ef MV |
661 | /* SSR is the best we can do. */ |
662 | if (!(pwrctl & DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE)) | |
663 | return; | |
664 | ||
0d44ad8b MV |
665 | clrsetbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCKMOD_MASK, |
666 | RCC_DDRITFCR_DDRCKMOD_ASR); | |
667 | ||
668 | start_sw_done(ctl); | |
669 | ||
670 | setbits_le32(&ctl->hwlpctl, DDRCTRL_HWLPCTL_HW_LP_EN); | |
671 | writel(DDRCTRL_PWRTMG_POWERDOWN_TO_X32(0x10) | | |
672 | DDRCTRL_PWRTMG_SELFREF_TO_X32(0x01), | |
673 | &ctl->pwrtmg); | |
221869ef MV |
674 | |
675 | /* HSR we can do. */ | |
0d44ad8b | 676 | setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); |
221869ef MV |
677 | |
678 | if (pwrctl & DDRCTRL_PWRCTL_SELFREF_EN) /* ASR we can do. */ | |
679 | setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_EN); | |
0d44ad8b MV |
680 | |
681 | setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); | |
682 | wait_sw_done_ack(ctl); | |
683 | } | |
684 | ||
e70f70aa | 685 | /* board-specific DDR power initializations. */ |
1767ac2d | 686 | __weak int board_ddr_power_init(enum ddr_type ddr_type) |
e70f70aa PD |
687 | { |
688 | return 0; | |
689 | } | |
690 | ||
691 | __maybe_unused | |
692 | void stm32mp1_ddr_init(struct ddr_info *priv, | |
693 | const struct stm32mp1_ddr_config *config) | |
694 | { | |
695 | u32 pir; | |
1767ac2d | 696 | int ret = -EINVAL; |
e9a20f8a PD |
697 | char bus_width; |
698 | ||
699 | switch (config->c_reg.mstr & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) { | |
700 | case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER: | |
701 | bus_width = 8; | |
702 | break; | |
703 | case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF: | |
704 | bus_width = 16; | |
705 | break; | |
706 | default: | |
707 | bus_width = 32; | |
708 | break; | |
709 | } | |
710 | ||
1767ac2d PD |
711 | |
712 | if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3) | |
713 | ret = board_ddr_power_init(STM32MP_DDR3); | |
e9a20f8a PD |
714 | else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) { |
715 | if (bus_width == 32) | |
716 | ret = board_ddr_power_init(STM32MP_LPDDR2_32); | |
717 | else | |
718 | ret = board_ddr_power_init(STM32MP_LPDDR2_16); | |
719 | } else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) { | |
720 | if (bus_width == 32) | |
721 | ret = board_ddr_power_init(STM32MP_LPDDR3_32); | |
722 | else | |
723 | ret = board_ddr_power_init(STM32MP_LPDDR3_16); | |
724 | } | |
e70f70aa PD |
725 | if (ret) |
726 | panic("ddr power init failed\n"); | |
727 | ||
01a75108 | 728 | start: |
66b3b9db PD |
729 | log_debug("name = %s\n", config->info.name); |
730 | log_debug("speed = %d kHz\n", config->info.speed); | |
731 | log_debug("size = 0x%x\n", config->info.size); | |
e70f70aa PD |
732 | /* |
733 | * 1. Program the DWC_ddr_umctl2 registers | |
734 | * 1.1 RESETS: presetn, core_ddrc_rstn, aresetn | |
735 | */ | |
736 | /* Assert All DDR part */ | |
737 | setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST); | |
738 | setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST); | |
739 | setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST); | |
740 | setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST); | |
741 | setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST); | |
742 | setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST); | |
743 | ||
744 | /* 1.2. start CLOCK */ | |
745 | if (stm32mp1_ddr_clk_enable(priv, config->info.speed)) | |
c60fed14 | 746 | panic("invalid DRAM clock : %d kHz\n", |
e70f70aa PD |
747 | config->info.speed); |
748 | ||
749 | /* 1.3. deassert reset */ | |
750 | /* de-assert PHY rstn and ctl_rstn via DPHYRST and DPHYCTLRST */ | |
751 | clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST); | |
752 | clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST); | |
753 | /* De-assert presetn once the clocks are active | |
754 | * and stable via DDRCAPBRST bit | |
755 | */ | |
756 | clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST); | |
757 | ||
0cb1aa94 PD |
758 | /* 1.4. wait 128 cycles to permit initialization of end logic */ |
759 | udelay(2); | |
760 | /* for PCLK = 133MHz => 1 us is enough, 2 to allow lower frequency */ | |
e70f70aa | 761 | |
01a75108 PD |
762 | if (INTERACTIVE(STEP_DDR_RESET)) |
763 | goto start; | |
764 | ||
e70f70aa PD |
765 | /* 1.5. initialize registers ddr_umctl2 */ |
766 | /* Stop uMCTL2 before PHY is ready */ | |
767 | clrbits_le32(&priv->ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); | |
66b3b9db PD |
768 | log_debug("[0x%08x] dfimisc = 0x%08x\n", |
769 | (u32)&priv->ctl->dfimisc, readl(&priv->ctl->dfimisc)); | |
e70f70aa PD |
770 | |
771 | set_reg(priv, REG_REG, &config->c_reg); | |
772 | set_reg(priv, REG_TIMING, &config->c_timing); | |
773 | set_reg(priv, REG_MAP, &config->c_map); | |
774 | ||
775 | /* skip CTRL init, SDRAM init is done by PHY PUBL */ | |
776 | clrsetbits_le32(&priv->ctl->init0, | |
777 | DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK, | |
778 | DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL); | |
779 | ||
780 | set_reg(priv, REG_PERF, &config->c_perf); | |
781 | ||
01a75108 PD |
782 | if (INTERACTIVE(STEP_CTL_INIT)) |
783 | goto start; | |
784 | ||
e70f70aa PD |
785 | /* 2. deassert reset signal core_ddrc_rstn, aresetn and presetn */ |
786 | clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST); | |
787 | clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST); | |
788 | clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST); | |
789 | ||
790 | /* 3. start PHY init by accessing relevant PUBL registers | |
791 | * (DXGCR, DCR, PTR*, MR*, DTPR*) | |
792 | */ | |
793 | set_reg(priv, REGPHY_REG, &config->p_reg); | |
794 | set_reg(priv, REGPHY_TIMING, &config->p_timing); | |
e70f70aa | 795 | |
01a75108 PD |
796 | if (INTERACTIVE(STEP_PHY_INIT)) |
797 | goto start; | |
798 | ||
e70f70aa PD |
799 | /* 4. Monitor PHY init status by polling PUBL register PGSR.IDONE |
800 | * Perform DDR PHY DRAM initialization and Gate Training Evaluation | |
801 | */ | |
802 | ddrphy_idone_wait(priv->phy); | |
803 | ||
804 | /* 5. Indicate to PUBL that controller performs SDRAM initialization | |
805 | * by setting PIR.INIT and PIR CTLDINIT and pool PGSR.IDONE | |
806 | * DRAM init is done by PHY, init0.skip_dram.init = 1 | |
807 | */ | |
808 | pir = DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | DDRPHYC_PIR_ZCAL | | |
809 | DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_DRAMINIT | DDRPHYC_PIR_ICPC; | |
810 | ||
811 | if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3) | |
812 | pir |= DDRPHYC_PIR_DRAMRST; /* only for DDR3 */ | |
813 | ||
814 | stm32mp1_ddrphy_init(priv->phy, pir); | |
815 | ||
816 | /* 6. SET DFIMISC.dfi_init_complete_en to 1 */ | |
817 | /* Enable quasi-dynamic register programming*/ | |
818 | start_sw_done(priv->ctl); | |
819 | setbits_le32(&priv->ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); | |
820 | wait_sw_done_ack(priv->ctl); | |
821 | ||
822 | /* 7. Wait for DWC_ddr_umctl2 to move to normal operation mode | |
823 | * by monitoring STAT.operating_mode signal | |
824 | */ | |
825 | /* wait uMCTL2 ready */ | |
826 | ||
827 | wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL); | |
828 | ||
9819fe34 | 829 | log_debug("DDR DQS training : "); |
e70f70aa PD |
830 | /* 8. Disable Auto refresh and power down by setting |
831 | * - RFSHCTL3.dis_au_refresh = 1 | |
832 | * - PWRCTL.powerdown_en = 0 | |
833 | * - DFIMISC.dfiinit_complete_en = 0 | |
834 | */ | |
9819fe34 | 835 | stm32mp1_refresh_disable(priv->ctl); |
e70f70aa PD |
836 | |
837 | /* 9. Program PUBL PGCR to enable refresh during training and rank to train | |
838 | * not done => keep the programed value in PGCR | |
839 | */ | |
840 | ||
841 | /* 10. configure PUBL PIR register to specify which training step to run */ | |
9819fe34 PD |
842 | /* RVTRN is excuted only on LPDDR2/LPDDR3 */ |
843 | if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3) | |
844 | pir = DDRPHYC_PIR_QSTRN; | |
845 | else | |
846 | pir = DDRPHYC_PIR_QSTRN | DDRPHYC_PIR_RVTRN; | |
847 | stm32mp1_ddrphy_init(priv->phy, pir); | |
e70f70aa PD |
848 | |
849 | /* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */ | |
9819fe34 | 850 | ddrphy_idone_wait(priv->phy); |
e70f70aa PD |
851 | |
852 | /* 12. set back registers in step 8 to the orginal values if desidered */ | |
9819fe34 PD |
853 | stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3, |
854 | config->c_reg.pwrctl); | |
e70f70aa | 855 | |
0d44ad8b | 856 | /* Enable auto-self-refresh, which saves a bit of power at runtime. */ |
221869ef | 857 | stm32mp1_asr_enable(priv, config->c_reg.pwrctl); |
0d44ad8b | 858 | |
e70f70aa PD |
859 | /* enable uMCTL2 AXI port 0 and 1 */ |
860 | setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); | |
861 | setbits_le32(&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); | |
01a75108 PD |
862 | |
863 | if (INTERACTIVE(STEP_DDR_READY)) | |
864 | goto start; | |
e70f70aa | 865 | } |