blob: bda02d062900ef5518b34e5aaaccab7261bcb849 [file] [log] [blame]
Dylan Hung82470022020-12-14 13:54:24 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) ASPEED Technology Inc.
4 */
5#include <common.h>
6#include <clk.h>
7#include <dm.h>
8#include <errno.h>
9#include <ram.h>
10#include <regmap.h>
11#include <reset.h>
12#include <asm/io.h>
13#include <asm/arch/scu_ast2600.h>
14#include <asm/arch/sdram_ast2600.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060015#include <asm/global_data.h>
Dylan Hung82470022020-12-14 13:54:24 +080016#include <linux/err.h>
17#include <linux/kernel.h>
18#include <dt-bindings/clock/ast2600-clock.h>
19
20#define DDR_PHY_TBL_CHG_ADDR 0xaeeddeea
21#define DDR_PHY_TBL_END 0xaeededed
22
Dylan Hunge7f67842022-11-11 15:30:07 +080023/**
24 * phyr030[18:16] - Ron PU (PHY side)
25 * phyr030[14:12] - Ron PD (PHY side)
26 * b'000 : disable
27 * b'001 : 240 ohm
28 * b'010 : 120 ohm
29 * b'011 : 80 ohm
30 * b'100 : 60 ohm
31 * b'101 : 48 ohm
32 * b'110 : 40 ohm
33 * b'111 : 34 ohm (default)
34 */
35#define PHY_RON ((0x7 << 16) | (0x7 << 12))
36
37/**
38 * phyr030[10:8] - ODT configuration (PHY side)
39 * b'000 : ODT disabled
40 * b'001 : 240 ohm
41 * b'010 : 120 ohm
42 * b'011 : 80 ohm (default)
43 * b'100 : 60 ohm
44 * b'101 : 48 ohm
45 * b'110 : 40 ohm
46 * b'111 : 34 ohm
47 */
48#define PHY_ODT (0x3 << 8)
49
50/**
51 * MR1[2:1] output driver impedance
52 * b'00 : 34 ohm (default)
53 * b'01 : 48 ohm
54 */
55#define DRAM_RON (0x0 << 1)
56
57/**
58 * DRAM ODT - synchronous ODT mode
59 * RTT_WR: disable
60 * RTT_NOM = RTT_PARK
61 *
62 * MR1[10:8] RTT_NOM
63 * b'000 : RTT_NOM disable
64 * b'001 : 60 ohm
65 * b'010 : 120 ohm
66 * b'011 : 40 ohm
67 * b'100 : 240 ohm
68 * b'101 : 48 ohm (default)
69 * b'110 : 80 ohm
70 * b'111 : 34 ohm
71 *
72 * MR5[8:6] RTT_PARK
73 * b'000 : RTT_PARK disable
74 * b'001 : 60 ohm
75 * b'010 : 120 ohm
76 * b'011 : 40 ohm
77 * b'100 : 240 ohm
78 * b'101 : 48 ohm (default)
79 * b'110 : 80 ohm
80 * b'111 : 34 ohm
81 *
82 * MR2[11:9] RTT_WR
83 * b'000 : Dynamic ODT off (default)
84 * b'001 : 120 ohm
85 * b'010 : 240 ohm
86 * b'011 : Hi-Z
87 * b'100 : 80 ohm
88 */
89#define RTT_WR (0x0 << 9)
90#define RTT_NOM (0x5 << 8)
91#define RTT_PARK (0x5 << 6)
92
93/**
94 * MR6[6] VrefDQ training range
95 * b'0 : range 1
96 * b'1 : range 2 (default)
97 */
98#define VREFDQ_RANGE_2 BIT(6)
99
100/**
101 * Latency setting:
102 * AL = PL = 0 (hardware fixed setting)
103 * -> WL = AL + CWL + PL = CWL
104 * -> RL = AL + CL + PL = CL
105 */
106#define CONFIG_WL 9
107#define CONFIG_RL 12
108#define T_RDDATA_EN ((CONFIG_RL - 2) << 8)
109#define T_PHY_WRLAT (CONFIG_WL - 2)
110
111/* MR0 */
112#define MR0_CL_12 (BIT(4) | BIT(2))
113#define MR0_WR12_RTP6 BIT(9)
114#define MR0_DLL_RESET BIT(8)
115#define MR0_VAL (MR0_CL_12 | MR0_WR12_RTP6 | MR0_DLL_RESET)
116
117/* MR1 */
118#define MR1_VAL (0x0001 | RTT_NOM | DRAM_RON)
119
120/* MR2 */
121#define MR2_CWL_9 0
122#define MR2_VAL (0x0000 | RTT_WR | MR2_CWL_9)
123
124/* MR3 ~ MR6 */
125#define MR3_VAL 0x0000
126#define MR4_VAL 0x0000
127#define MR5_VAL (0x0400 | RTT_PARK)
128#define MR6_VAL 0x0400
129
130/**
131 * The offset value applied to the DDR PHY write data eye training result
132 * to fine-tune the write DQ/DQS alignment
133 */
134#define WR_DATA_EYE_OFFSET (0x10 << 8)
135
Dylan Hung82470022020-12-14 13:54:24 +0800136#if defined(CONFIG_ASPEED_DDR4_800)
137u32 ast2600_sdramphy_config[165] = {
138 0x1e6e0100, // start address
139 0x00000000, // phyr000
140 0x0c002062, // phyr004
141 0x1a7a0063, // phyr008
142 0x5a7a0063, // phyr00c
143 0x1a7a0063, // phyr010
144 0x1a7a0063, // phyr014
145 0x20000000, // phyr018
146 0x20000000, // phyr01c
147 0x20000000, // phyr020
148 0x20000000, // phyr024
149 0x00000008, // phyr028
150 0x00000000, // phyr02c
Dylan Hunge7f67842022-11-11 15:30:07 +0800151 (PHY_RON | PHY_ODT), /* phyr030 */
Dylan Hung82470022020-12-14 13:54:24 +0800152 0x00000000, // phyr034
153 0x00000000, // phyr038
154 0x20000000, // phyr03c
155 0x50506000, // phyr040
156 0x50505050, // phyr044
157 0x00002f07, // phyr048
158 0x00003080, // phyr04c
159 0x04000000, // phyr050
Dylan Hunge7f67842022-11-11 15:30:07 +0800160 ((MR3_VAL << 16) | MR2_VAL), /* phyr054 */
161 ((MR0_VAL << 16) | MR1_VAL), /* phyr058 */
162 ((MR5_VAL << 16) | MR4_VAL), /* phyr05c */
163 ((0x0800 << 16) | MR6_VAL | VREFDQ_RANGE_2 | 0xe), /* phyr060 */
Dylan Hung82470022020-12-14 13:54:24 +0800164 0x00000000, // phyr064
165 0x00180008, // phyr068
166 0x00e00400, // phyr06c
167 0x00140206, // phyr070
168 0x1d4c0000, // phyr074
Dylan Hunge7f67842022-11-11 15:30:07 +0800169 (0x493e0100 | T_PHY_WRLAT), /* phyr078 */
Dylan Hung82470022020-12-14 13:54:24 +0800170 0x08060404, // phyr07c
Dylan Hunge7f67842022-11-11 15:30:07 +0800171 (0x90000000 | T_RDDATA_EN), /* phyr080 */
Dylan Hung82470022020-12-14 13:54:24 +0800172 0x06420618, // phyr084
173 0x00001002, // phyr088
174 0x05701016, // phyr08c
175 0x10000000, // phyr090
176 0xaeeddeea, // change address
177 0x1e6e019c, // new address
178 0x20202020, // phyr09c
179 0x20202020, // phyr0a0
180 0x00002020, // phyr0a4
181 0x00002020, // phyr0a8
182 0x00000001, // phyr0ac
183 0xaeeddeea, // change address
184 0x1e6e01cc, // new address
185 0x01010101, // phyr0cc
186 0x01010101, // phyr0d0
187 0x80808080, // phyr0d4
188 0x80808080, // phyr0d8
189 0xaeeddeea, // change address
190 0x1e6e0288, // new address
191 0x80808080, // phyr188
192 0x80808080, // phyr18c
193 0x80808080, // phyr190
194 0x80808080, // phyr194
195 0xaeeddeea, // change address
196 0x1e6e02f8, // new address
197 0x90909090, // phyr1f8
198 0x88888888, // phyr1fc
199 0xaeeddeea, // change address
200 0x1e6e0300, // new address
201 0x00000000, // phyr200
202 0xaeeddeea, // change address
203 0x1e6e0194, // new address
204 0x80118260, // phyr094
205 0xaeeddeea, // change address
206 0x1e6e019c, // new address
207 0x20202020, // phyr09c
208 0x20202020, // phyr0a0
209 0x00002020, // phyr0a4
Dylan Hunge7f67842022-11-11 15:30:07 +0800210 0x00000000, /* phyr0a8 */
Dylan Hung82470022020-12-14 13:54:24 +0800211 0x00000001, // phyr0ac
212 0xaeeddeea, // change address
213 0x1e6e0318, // new address
214 0x09222719, // phyr218
215 0x00aa4403, // phyr21c
216 0xaeeddeea, // change address
217 0x1e6e0198, // new address
218 0x08060000, // phyr098
219 0xaeeddeea, // change address
220 0x1e6e01b0, // new address
221 0x00000000, // phyr0b0
222 0x00000000, // phyr0b4
223 0x00000000, // phyr0b8
224 0x00000000, // phyr0bc
225 0x00000000, // phyr0c0
226 0x00000000, // phyr0c4
227 0x000aff2c, // phyr0c8
228 0xaeeddeea, // change address
229 0x1e6e01dc, // new address
230 0x00080000, // phyr0dc
231 0x00000000, // phyr0e0
232 0xaa55aa55, // phyr0e4
233 0x55aa55aa, // phyr0e8
234 0xaaaa5555, // phyr0ec
235 0x5555aaaa, // phyr0f0
236 0xaa55aa55, // phyr0f4
237 0x55aa55aa, // phyr0f8
238 0xaaaa5555, // phyr0fc
239 0x5555aaaa, // phyr100
240 0xaa55aa55, // phyr104
241 0x55aa55aa, // phyr108
242 0xaaaa5555, // phyr10c
243 0x5555aaaa, // phyr110
244 0xaa55aa55, // phyr114
245 0x55aa55aa, // phyr118
246 0xaaaa5555, // phyr11c
247 0x5555aaaa, // phyr120
248 0x20202020, // phyr124
249 0x20202020, // phyr128
250 0x20202020, // phyr12c
251 0x20202020, // phyr130
252 0x20202020, // phyr134
253 0x20202020, // phyr138
254 0x20202020, // phyr13c
255 0x20202020, // phyr140
256 0x20202020, // phyr144
257 0x20202020, // phyr148
258 0x20202020, // phyr14c
259 0x20202020, // phyr150
260 0x20202020, // phyr154
261 0x20202020, // phyr158
262 0x20202020, // phyr15c
263 0x20202020, // phyr160
264 0x20202020, // phyr164
265 0x20202020, // phyr168
266 0x20202020, // phyr16c
267 0x20202020, // phyr170
268 0xaeeddeea, // change address
269 0x1e6e0298, // new address
Dylan Hunge7f67842022-11-11 15:30:07 +0800270 0x20200000, /* phyr198 */
Dylan Hung82470022020-12-14 13:54:24 +0800271 0x20202020, // phyr19c
272 0x20202020, // phyr1a0
273 0x20202020, // phyr1a4
274 0x20202020, // phyr1a8
275 0x20202020, // phyr1ac
276 0x20202020, // phyr1b0
277 0x20202020, // phyr1b4
278 0x20202020, // phyr1b8
279 0x20202020, // phyr1bc
280 0x20202020, // phyr1c0
281 0x20202020, // phyr1c4
282 0x20202020, // phyr1c8
283 0x20202020, // phyr1cc
284 0x20202020, // phyr1d0
285 0x20202020, // phyr1d4
286 0x20202020, // phyr1d8
287 0x20202020, // phyr1dc
288 0x20202020, // phyr1e0
289 0x20202020, // phyr1e4
290 0x00002020, // phyr1e8
291 0xaeeddeea, // change address
292 0x1e6e0304, // new address
Dylan Hunge7f67842022-11-11 15:30:07 +0800293 (0x00000001 | WR_DATA_EYE_OFFSET), /* phyr204 */
Dylan Hung82470022020-12-14 13:54:24 +0800294 0xaeeddeea, // change address
295 0x1e6e027c, // new address
296 0x4e400000, // phyr17c
297 0x59595959, // phyr180
298 0x40404040, // phyr184
299 0xaeeddeea, // change address
300 0x1e6e02f4, // new address
301 0x00000059, // phyr1f4
302 0xaeededed, // end
303};
304#else
305u32 ast2600_sdramphy_config[165] = {
306 0x1e6e0100, // start address
307 0x00000000, // phyr000
308 0x0c002062, // phyr004
309 0x1a7a0063, // phyr008
310 0x5a7a0063, // phyr00c
311 0x1a7a0063, // phyr010
312 0x1a7a0063, // phyr014
313 0x20000000, // phyr018
314 0x20000000, // phyr01c
315 0x20000000, // phyr020
316 0x20000000, // phyr024
317 0x00000008, // phyr028
318 0x00000000, // phyr02c
Dylan Hunge7f67842022-11-11 15:30:07 +0800319 (PHY_RON | PHY_ODT), /* phyr030 */
Dylan Hung82470022020-12-14 13:54:24 +0800320 0x00000000, // phyr034
321 0x00000000, // phyr038
322 0x20000000, // phyr03c
323 0x50506000, // phyr040
324 0x50505050, // phyr044
325 0x00002f07, // phyr048
326 0x00003080, // phyr04c
327 0x04000000, // phyr050
Dylan Hunge7f67842022-11-11 15:30:07 +0800328 ((MR3_VAL << 16) | MR2_VAL), /* phyr054 */
329 ((MR0_VAL << 16) | MR1_VAL), /* phyr058 */
330 ((MR5_VAL << 16) | MR4_VAL), /* phyr05c */
331 ((0x0800 << 16) | MR6_VAL | VREFDQ_RANGE_2 | 0xe), /* phyr060 */
Dylan Hung82470022020-12-14 13:54:24 +0800332 0x00000000, // phyr064
333 0x00180008, // phyr068
334 0x00e00400, // phyr06c
335 0x00140206, // phyr070
336 0x1d4c0000, // phyr074
Dylan Hunge7f67842022-11-11 15:30:07 +0800337 (0x493e0100 | T_PHY_WRLAT), /* phyr078 */
Dylan Hung82470022020-12-14 13:54:24 +0800338 0x08060404, // phyr07c
Dylan Hunge7f67842022-11-11 15:30:07 +0800339 (0x90000000 | T_RDDATA_EN), /* phyr080 */
Dylan Hung82470022020-12-14 13:54:24 +0800340 0x06420c30, // phyr084
341 0x00001002, // phyr088
342 0x05701016, // phyr08c
343 0x10000000, // phyr090
344 0xaeeddeea, // change address
345 0x1e6e019c, // new address
346 0x20202020, // phyr09c
347 0x20202020, // phyr0a0
348 0x00002020, // phyr0a4
349 0x00002020, // phyr0a8
350 0x00000001, // phyr0ac
351 0xaeeddeea, // change address
352 0x1e6e01cc, // new address
353 0x01010101, // phyr0cc
354 0x01010101, // phyr0d0
355 0x80808080, // phyr0d4
356 0x80808080, // phyr0d8
357 0xaeeddeea, // change address
358 0x1e6e0288, // new address
359 0x80808080, // phyr188
360 0x80808080, // phyr18c
361 0x80808080, // phyr190
362 0x80808080, // phyr194
363 0xaeeddeea, // change address
364 0x1e6e02f8, // new address
365 0x90909090, // phyr1f8
366 0x88888888, // phyr1fc
367 0xaeeddeea, // change address
368 0x1e6e0300, // new address
369 0x00000000, // phyr200
370 0xaeeddeea, // change address
371 0x1e6e0194, // new address
Dylan Hunge7f67842022-11-11 15:30:07 +0800372 0x801112e0, // phyr094
Dylan Hung82470022020-12-14 13:54:24 +0800373 0xaeeddeea, // change address
374 0x1e6e019c, // new address
375 0x20202020, // phyr09c
376 0x20202020, // phyr0a0
377 0x00002020, // phyr0a4
Dylan Hunge7f67842022-11-11 15:30:07 +0800378 0x00000000, /* phyr0a8 */
Dylan Hung82470022020-12-14 13:54:24 +0800379 0x00000001, // phyr0ac
380 0xaeeddeea, // change address
381 0x1e6e0318, // new address
382 0x09222719, // phyr218
383 0x00aa4403, // phyr21c
384 0xaeeddeea, // change address
385 0x1e6e0198, // new address
386 0x08060000, // phyr098
387 0xaeeddeea, // change address
388 0x1e6e01b0, // new address
389 0x00000000, // phyr0b0
390 0x00000000, // phyr0b4
391 0x00000000, // phyr0b8
392 0x00000000, // phyr0bc
393 0x00000000, // phyr0c0 - ori
394 0x00000000, // phyr0c4
395 0x000aff2c, // phyr0c8
396 0xaeeddeea, // change address
397 0x1e6e01dc, // new address
398 0x00080000, // phyr0dc
399 0x00000000, // phyr0e0
400 0xaa55aa55, // phyr0e4
401 0x55aa55aa, // phyr0e8
402 0xaaaa5555, // phyr0ec
403 0x5555aaaa, // phyr0f0
404 0xaa55aa55, // phyr0f4
405 0x55aa55aa, // phyr0f8
406 0xaaaa5555, // phyr0fc
407 0x5555aaaa, // phyr100
408 0xaa55aa55, // phyr104
409 0x55aa55aa, // phyr108
410 0xaaaa5555, // phyr10c
411 0x5555aaaa, // phyr110
412 0xaa55aa55, // phyr114
413 0x55aa55aa, // phyr118
414 0xaaaa5555, // phyr11c
415 0x5555aaaa, // phyr120
416 0x20202020, // phyr124
417 0x20202020, // phyr128
418 0x20202020, // phyr12c
419 0x20202020, // phyr130
420 0x20202020, // phyr134
421 0x20202020, // phyr138
422 0x20202020, // phyr13c
423 0x20202020, // phyr140
424 0x20202020, // phyr144
425 0x20202020, // phyr148
426 0x20202020, // phyr14c
427 0x20202020, // phyr150
428 0x20202020, // phyr154
429 0x20202020, // phyr158
430 0x20202020, // phyr15c
431 0x20202020, // phyr160
432 0x20202020, // phyr164
433 0x20202020, // phyr168
434 0x20202020, // phyr16c
435 0x20202020, // phyr170
436 0xaeeddeea, // change address
437 0x1e6e0298, // new address
Dylan Hunge7f67842022-11-11 15:30:07 +0800438 0x20200000, /* phyr198 */
Dylan Hung82470022020-12-14 13:54:24 +0800439 0x20202020, // phyr19c
440 0x20202020, // phyr1a0
441 0x20202020, // phyr1a4
442 0x20202020, // phyr1a8
443 0x20202020, // phyr1ac
444 0x20202020, // phyr1b0
445 0x20202020, // phyr1b4
446 0x20202020, // phyr1b8
447 0x20202020, // phyr1bc
448 0x20202020, // phyr1c0
449 0x20202020, // phyr1c4
450 0x20202020, // phyr1c8
451 0x20202020, // phyr1cc
452 0x20202020, // phyr1d0
453 0x20202020, // phyr1d4
454 0x20202020, // phyr1d8
455 0x20202020, // phyr1dc
456 0x20202020, // phyr1e0
457 0x20202020, // phyr1e4
458 0x00002020, // phyr1e8
459 0xaeeddeea, // change address
460 0x1e6e0304, // new address
Dylan Hunge7f67842022-11-11 15:30:07 +0800461 (0x00000001 | WR_DATA_EYE_OFFSET), /* phyr204 */
Dylan Hung82470022020-12-14 13:54:24 +0800462 0xaeeddeea, // change address
463 0x1e6e027c, // new address
464 0x4e400000, // phyr17c
465 0x59595959, // phyr180
466 0x40404040, // phyr184
467 0xaeeddeea, // change address
468 0x1e6e02f4, // new address
469 0x00000059, // phyr1f4
470 0xaeededed, // end
471};
472#endif
473
474/* MPLL configuration */
475#define SCU_MPLL_FREQ_400M 0x0008405F
476#define SCU_MPLL_EXT_400M 0x0000002F
477#define SCU_MPLL_FREQ_333M 0x00488299
478#define SCU_MPLL_EXT_333M 0x0000014C
479#define SCU_MPLL_FREQ_200M 0x0078007F
480#define SCU_MPLL_EXT_200M 0x0000003F
481#define SCU_MPLL_FREQ_100M 0x0078003F
482#define SCU_MPLL_EXT_100M 0x0000001F
483
484#if defined(CONFIG_ASPEED_DDR4_1600)
485#define SCU_MPLL_FREQ_CFG SCU_MPLL_FREQ_400M
486#define SCU_MPLL_EXT_CFG SCU_MPLL_EXT_400M
487#elif defined(CONFIG_ASPEED_DDR4_1333)
488#define SCU_MPLL_FREQ_CFG SCU_MPLL_FREQ_333M
489#define SCU_MPLL_EXT_CFG SCU_MPLL_EXT_333M
490#elif defined(CONFIG_ASPEED_DDR4_800)
491#define SCU_MPLL_FREQ_CFG SCU_MPLL_FREQ_200M
492#define SCU_MPLL_EXT_CFG SCU_MPLL_EXT_200M
493#elif defined(CONFIG_ASPEED_DDR4_400)
494#define SCU_MPLL_FREQ_CFG SCU_MPLL_FREQ_100M
495#define SCU_MPLL_EXT_CFG SCU_MPLL_EXT_100M
496#else
497#error "undefined DDR4 target rate\n"
498#endif
499
500/*
501 * AC timing and SDRAM mode register setting
502 * for real chip are derived from the model GDDR4-1600
503 */
Dylan Hunge7f67842022-11-11 15:30:07 +0800504#define DDR4_MR01_MODE ((MR1_VAL << 16) | MR0_VAL)
505#define DDR4_MR23_MODE ((MR3_VAL << 16) | MR2_VAL)
506#define DDR4_MR45_MODE ((MR5_VAL << 16) | MR4_VAL)
507#define DDR4_MR6_MODE MR6_VAL
Dylan Hung82470022020-12-14 13:54:24 +0800508#define DDR4_TRFC_1600 0x467299f1
509#define DDR4_TRFC_1333 0x3a5f80c9
510#define DDR4_TRFC_800 0x23394c78
511#define DDR4_TRFC_400 0x111c263c
512
513#if defined(CONFIG_ASPEED_DDR4_1600)
514#define DDR4_TRFC DDR4_TRFC_1600
515#define DDR4_PHY_TRAIN_TRFC 0xc30
516#elif defined(CONFIG_ASPEED_DDR4_1333)
517#define DDR4_TRFC DDR4_TRFC_1333
518#define DDR4_PHY_TRAIN_TRFC 0xa25
519#elif defined(CONFIG_ASPEED_DDR4_800)
520#define DDR4_TRFC DDR4_TRFC_800
521#define DDR4_PHY_TRAIN_TRFC 0x618
522#elif defined(CONFIG_ASPEED_DDR4_400)
523#define DDR4_TRFC DDR4_TRFC_400
524#define DDR4_PHY_TRAIN_TRFC 0x30c
525#else
526#error "undefined tRFC setting"
527#endif
528
529/* supported SDRAM size */
530#define SDRAM_SIZE_1KB (1024U)
531#define SDRAM_SIZE_1MB (SDRAM_SIZE_1KB * SDRAM_SIZE_1KB)
532#define SDRAM_MIN_SIZE (256 * SDRAM_SIZE_1MB)
533#define SDRAM_MAX_SIZE (2048 * SDRAM_SIZE_1MB)
534
535DECLARE_GLOBAL_DATA_PTR;
536
537static const u32 ddr4_ac_timing[4] = {
538 0x040e0307, 0x0f4711f1, 0x0e060304, 0x00001240 };
539static const u32 ddr_max_grant_params[4] = {
540 0x44444444, 0x44444444, 0x44444444, 0x44444444 };
541
542struct dram_info {
543 struct ram_info info;
544 struct clk ddr_clk;
545 struct ast2600_sdrammc_regs *regs;
546 struct ast2600_scu *scu;
547 struct ast2600_ddr_phy *phy;
548 void __iomem *phy_setting;
549 void __iomem *phy_status;
550 ulong clock_rate;
551};
552
553static void ast2600_sdramphy_kick_training(struct dram_info *info)
554{
555 u32 data;
556 struct ast2600_sdrammc_regs *regs = info->regs;
557
558 writel(SDRAM_PHYCTRL0_NRST, &regs->phy_ctrl[0]);
559 udelay(5);
560 writel(SDRAM_PHYCTRL0_NRST | SDRAM_PHYCTRL0_INIT, &regs->phy_ctrl[0]);
561 udelay(1000);
562
563 while (1) {
564 data = readl(&regs->phy_ctrl[0]) & SDRAM_PHYCTRL0_INIT;
Dylan Hungd90da022022-11-11 15:30:06 +0800565 if (data == 0)
Dylan Hung82470022020-12-14 13:54:24 +0800566 break;
567 }
568}
569
570/**
571 * @brief load DDR-PHY configurations table to the PHY registers
572 * @param[in] p_tbl - pointer to the configuration table
573 * @param[in] info - pointer to the DRAM info struct
574 *
575 * There are two sets of MRS (Mode Registers) configuration in ast2600 memory
576 * system: one is in the SDRAM MC (memory controller) which is used in run
577 * time, and the other is in the DDR-PHY IP which is used during DDR-PHY
578 * training.
579 */
580static void ast2600_sdramphy_init(u32 *p_tbl, struct dram_info *info)
581{
582 u32 reg_base = (u32)info->phy_setting;
583 u32 addr = p_tbl[0];
584 u32 data;
585 int i = 1;
586
587 writel(0, &info->regs->phy_ctrl[0]);
588 udelay(10);
589
590 while (1) {
591 if (addr < reg_base) {
592 debug("invalid DDR-PHY addr: 0x%08x\n", addr);
593 break;
594 }
595 data = p_tbl[i++];
596
597 if (data == DDR_PHY_TBL_END) {
598 break;
599 } else if (data == DDR_PHY_TBL_CHG_ADDR) {
600 addr = p_tbl[i++];
601 } else {
602 writel(data, addr);
603 addr += 4;
604 }
605 }
606
607 data = readl(info->phy_setting + 0x84) & ~GENMASK(16, 0);
608 data |= DDR4_PHY_TRAIN_TRFC;
609 writel(data, info->phy_setting + 0x84);
610}
611
612static int ast2600_sdramphy_check_status(struct dram_info *info)
613{
614 u32 value, tmp;
615 u32 reg_base = (u32)info->phy_status;
616 int need_retrain = 0;
617
618 debug("\nSDRAM PHY training report:\n");
619
620 /* training status */
621 value = readl(reg_base + 0x00);
622 debug("rO_DDRPHY_reg offset 0x00 = 0x%08x\n", value);
623
624 if (value & BIT(3))
625 debug("\tinitial PVT calibration fail\n");
626
627 if (value & BIT(5))
628 debug("\truntime calibration fail\n");
629
630 /* PU & PD */
631 value = readl(reg_base + 0x30);
632 debug("rO_DDRPHY_reg offset 0x30 = 0x%08x\n", value);
633 debug(" PU = 0x%02x\n", value & 0xff);
634 debug(" PD = 0x%02x\n", (value >> 16) & 0xff);
635
636 /* read eye window */
637 value = readl(reg_base + 0x68);
638 if (0 == (value & GENMASK(7, 0)))
639 need_retrain = 1;
640
641 debug("rO_DDRPHY_reg offset 0x68 = 0x%08x\n", value);
642 debug(" rising edge of read data eye training pass window\n");
643 tmp = (((value & GENMASK(7, 0)) >> 0) * 100) / 255;
644 debug(" B0:%d%%\n", tmp);
645 tmp = (((value & GENMASK(15, 8)) >> 8) * 100) / 255;
646 debug(" B1:%d%%\n", tmp);
647
648 value = readl(reg_base + 0xC8);
649 debug("rO_DDRPHY_reg offset 0xC8 = 0x%08x\n", value);
650 debug(" falling edge of read data eye training pass window\n");
651 tmp = (((value & GENMASK(7, 0)) >> 0) * 100) / 255;
652 debug(" B0:%d%%\n", tmp);
653 tmp = (((value & GENMASK(15, 8)) >> 8) * 100) / 255;
654 debug(" B1:%d%%\n", tmp);
655
656 /* write eye window */
657 value = readl(reg_base + 0x7c);
658 if (0 == (value & GENMASK(7, 0)))
659 need_retrain = 1;
660
661 debug("rO_DDRPHY_reg offset 0x7C = 0x%08x\n", value);
662 debug(" rising edge of write data eye training pass window\n");
663 tmp = (((value & GENMASK(7, 0)) >> 0) * 100) / 255;
664 debug(" B0:%d%%\n", tmp);
665 tmp = (((value & GENMASK(15, 8)) >> 8) * 100) / 255;
666 debug(" B1:%d%%\n", tmp);
667
668 /* read Vref training result */
669 value = readl(reg_base + 0x88);
670 debug("rO_DDRPHY_reg offset 0x88 = 0x%08x\n", value);
671 debug(" read Vref training result\n");
672 tmp = (((value & GENMASK(7, 0)) >> 0) * 100) / 127;
673 debug(" B0:%d%%\n", tmp);
674 tmp = (((value & GENMASK(15, 8)) >> 8) * 100) / 127;
675 debug(" B1:%d%%\n", tmp);
676
677 /* write Vref training result */
678 value = readl(reg_base + 0x90);
679 debug("rO_DDRPHY_reg offset 0x90 = 0x%08x\n", value);
680
681 /* gate train */
682 value = readl(reg_base + 0x50);
683 if ((0 == (value & GENMASK(15, 0))) ||
684 (0 == (value & GENMASK(31, 16)))) {
685 need_retrain = 1;
686 }
687
688 debug("rO_DDRPHY_reg offset 0x50 = 0x%08x\n", value);
689
690 return need_retrain;
691}
692
693#ifndef CONFIG_ASPEED_BYPASS_SELFTEST
694#define MC_TEST_PATTERN_N 8
695static u32 as2600_sdrammc_test_pattern[MC_TEST_PATTERN_N] = {
696 0xcc33cc33, 0xff00ff00, 0xaa55aa55, 0x88778877,
697 0x92cc4d6e, 0x543d3cde, 0xf1e843c7, 0x7c61d253 };
698
699#define TIMEOUT_DRAM 5000000
700int ast2600_sdrammc_dg_test(struct dram_info *info, unsigned int datagen, u32 mode)
701{
702 unsigned int data;
703 unsigned int timeout = 0;
704 struct ast2600_sdrammc_regs *regs = info->regs;
705
706 writel(0, &regs->ecc_test_ctrl);
707
708 if (mode == 0)
709 writel(0x00000085 | (datagen << 3), &regs->ecc_test_ctrl);
710 else
711 writel(0x000000C1 | (datagen << 3), &regs->ecc_test_ctrl);
712
713 do {
714 data = readl(&regs->ecc_test_ctrl) & GENMASK(13, 12);
715
716 if (data & BIT(13))
717 return 0;
718
719 if (++timeout > TIMEOUT_DRAM) {
720 debug("Timeout!!\n");
721 writel(0, &regs->ecc_test_ctrl);
722 return -1;
723 }
724 } while (!data);
725
726 writel(0, &regs->ecc_test_ctrl);
727
728 return 0;
729}
730
731int ast2600_sdrammc_cbr_test(struct dram_info *info)
732{
733 u32 i;
734 struct ast2600_sdrammc_regs *regs = info->regs;
735
736 clrsetbits_le32(&regs->test_addr, GENMASK(30, 4), 0x7ffff0);
737
738 /* single */
739 for (i = 0; i < 8; i++)
740 if (ast2600_sdrammc_dg_test(info, i, 0))
741 return -1;
742
743 /* burst */
744 for (i = 0; i < 8; i++)
745 if (ast2600_sdrammc_dg_test(info, i, i))
746 return -1;
747
748 return 0;
749}
750
751static int ast2600_sdrammc_test(struct dram_info *info)
752{
753 struct ast2600_sdrammc_regs *regs = info->regs;
754
755 u32 pass_cnt = 0;
756 u32 fail_cnt = 0;
757 u32 target_cnt = 2;
758 u32 test_cnt = 0;
759 u32 pattern;
760 u32 i = 0;
761 bool finish = false;
762
763 debug("sdram mc test:\n");
764 while (!finish) {
765 pattern = as2600_sdrammc_test_pattern[i++];
766 i = i % MC_TEST_PATTERN_N;
767 debug(" pattern = %08X : ", pattern);
768 writel(pattern, &regs->test_init_val);
769
770 if (ast2600_sdrammc_cbr_test(info)) {
771 debug("fail\n");
772 fail_cnt++;
773 } else {
774 debug("pass\n");
775 pass_cnt++;
776 }
777
778 if (++test_cnt == target_cnt)
779 finish = true;
780 }
781 debug("statistics: pass/fail/total:%d/%d/%d\n", pass_cnt, fail_cnt,
782 target_cnt);
783
784 return fail_cnt;
785}
786#endif
787
788/*
789 * scu500[14:13]
790 * 2b'00: VGA memory size = 16MB
791 * 2b'01: VGA memory size = 16MB
792 * 2b'10: VGA memory size = 32MB
793 * 2b'11: VGA memory size = 64MB
794 *
795 * mcr04[3:2]
796 * 2b'00: VGA memory size = 8MB
797 * 2b'01: VGA memory size = 16MB
798 * 2b'10: VGA memory size = 32MB
799 * 2b'11: VGA memory size = 64MB
800 */
801static size_t ast2600_sdrammc_get_vga_mem_size(struct dram_info *info)
802{
803 u32 vga_hwconf;
804 size_t vga_mem_size_base = 8 * 1024 * 1024;
805
806 vga_hwconf =
807 (readl(&info->scu->hwstrap1) & SCU_HWSTRAP1_VGA_MEM_MASK) >>
808 SCU_HWSTRAP1_VGA_MEM_SHIFT;
809
810 if (vga_hwconf == 0) {
811 vga_hwconf = 1;
812 writel(vga_hwconf << SCU_HWSTRAP1_VGA_MEM_SHIFT,
813 &info->scu->hwstrap1);
814 }
815
816 clrsetbits_le32(&info->regs->config, SDRAM_CONF_VGA_SIZE_MASK,
817 ((vga_hwconf << SDRAM_CONF_VGA_SIZE_SHIFT) &
818 SDRAM_CONF_VGA_SIZE_MASK));
819
820 /* no need to reserve VGA memory if efuse[VGA disable] is set */
821 if (readl(&info->scu->efuse) & SCU_EFUSE_DIS_VGA)
822 return 0;
823
824 return vga_mem_size_base << vga_hwconf;
825}
826
827/*
828 * Find out RAM size and save it in dram_info
829 *
830 * The procedure is taken from Aspeed SDK
831 */
832static void ast2600_sdrammc_calc_size(struct dram_info *info)
833{
834 /* The controller supports 256/512/1024/2048 MB ram */
835 size_t ram_size = SDRAM_MIN_SIZE;
836 const int write_test_offset = 0x100000;
837 u32 test_pattern = 0xdeadbeef;
838 u32 cap_param = SDRAM_CONF_CAP_2048M;
839 u32 refresh_timing_param = DDR4_TRFC;
840 const u32 write_addr_base = CONFIG_SYS_SDRAM_BASE + write_test_offset;
841
842 for (ram_size = SDRAM_MAX_SIZE; ram_size > SDRAM_MIN_SIZE;
843 ram_size >>= 1) {
844 writel(test_pattern, write_addr_base + (ram_size >> 1));
845 test_pattern = (test_pattern >> 4) | (test_pattern << 28);
846 }
847
848 /* One last write to overwrite all wrapped values */
849 writel(test_pattern, write_addr_base);
850
851 /* Reset the pattern and see which value was really written */
852 test_pattern = 0xdeadbeef;
853 for (ram_size = SDRAM_MAX_SIZE; ram_size > SDRAM_MIN_SIZE;
854 ram_size >>= 1) {
855 if (readl(write_addr_base + (ram_size >> 1)) == test_pattern)
856 break;
857
858 --cap_param;
859 refresh_timing_param >>= 8;
860 test_pattern = (test_pattern >> 4) | (test_pattern << 28);
861 }
862
863 clrsetbits_le32(&info->regs->ac_timing[1],
864 (SDRAM_AC_TRFC_MASK << SDRAM_AC_TRFC_SHIFT),
865 ((refresh_timing_param & SDRAM_AC_TRFC_MASK)
866 << SDRAM_AC_TRFC_SHIFT));
867
868 info->info.base = CONFIG_SYS_SDRAM_BASE;
869 info->info.size = ram_size - ast2600_sdrammc_get_vga_mem_size(info);
870
871 clrsetbits_le32(&info->regs->config, SDRAM_CONF_CAP_MASK,
872 ((cap_param << SDRAM_CONF_CAP_SHIFT) & SDRAM_CONF_CAP_MASK));
873}
874
875static int ast2600_sdrammc_init_ddr4(struct dram_info *info)
876{
877 const u32 power_ctrl = MCR34_CKE_EN | MCR34_AUTOPWRDN_EN |
878 MCR34_MREQ_BYPASS_DIS | MCR34_RESETN_DIS |
879 MCR34_ODT_EN | MCR34_ODT_AUTO_ON |
880 (0x1 << MCR34_ODT_EXT_SHIFT);
881
882 /* init SDRAM-PHY only on real chip */
883 ast2600_sdramphy_init(ast2600_sdramphy_config, info);
884 writel((MCR34_CKE_EN | MCR34_MREQI_DIS | MCR34_RESETN_DIS),
885 &info->regs->power_ctrl);
886 udelay(5);
887 ast2600_sdramphy_kick_training(info);
888 udelay(500);
889 writel(SDRAM_RESET_DLL_ZQCL_EN, &info->regs->refresh_timing);
890
891 writel(MCR30_SET_MR(3), &info->regs->mode_setting_control);
892 writel(MCR30_SET_MR(6), &info->regs->mode_setting_control);
893 writel(MCR30_SET_MR(5), &info->regs->mode_setting_control);
894 writel(MCR30_SET_MR(4), &info->regs->mode_setting_control);
895 writel(MCR30_SET_MR(2), &info->regs->mode_setting_control);
896 writel(MCR30_SET_MR(1), &info->regs->mode_setting_control);
897 writel(MCR30_SET_MR(0) | MCR30_RESET_DLL_DELAY_EN,
898 &info->regs->mode_setting_control);
899
900 writel(SDRAM_REFRESH_EN | SDRAM_RESET_DLL_ZQCL_EN |
901 (0x5f << SDRAM_REFRESH_PERIOD_SHIFT),
902 &info->regs->refresh_timing);
903
904 /* wait self-refresh idle */
905 while (readl(&info->regs->power_ctrl) &
906 MCR34_SELF_REFRESH_STATUS_MASK)
907 ;
908
909 writel(SDRAM_REFRESH_EN | SDRAM_LOW_PRI_REFRESH_EN |
910 SDRAM_REFRESH_ZQCS_EN |
911 (0x5f << SDRAM_REFRESH_PERIOD_SHIFT) |
912 (0x42aa << SDRAM_REFRESH_PERIOD_ZQCS_SHIFT),
913 &info->regs->refresh_timing);
914
915 writel(power_ctrl, &info->regs->power_ctrl);
916 udelay(500);
917
918 return 0;
919}
920
921static void ast2600_sdrammc_unlock(struct dram_info *info)
922{
923 writel(SDRAM_UNLOCK_KEY, &info->regs->protection_key);
924 while (!readl(&info->regs->protection_key))
925 ;
926}
927
928static void ast2600_sdrammc_lock(struct dram_info *info)
929{
930 writel(~SDRAM_UNLOCK_KEY, &info->regs->protection_key);
931 while (readl(&info->regs->protection_key))
932 ;
933}
934
935static void ast2600_sdrammc_common_init(struct ast2600_sdrammc_regs *regs)
936{
937 int i;
938
939 writel(MCR34_MREQI_DIS | MCR34_RESETN_DIS, &regs->power_ctrl);
940 writel(SDRAM_VIDEO_UNLOCK_KEY, &regs->gm_protection_key);
941 writel(0x10 << MCR38_RW_MAX_GRANT_CNT_RQ_SHIFT,
942 &regs->arbitration_ctrl);
943 writel(0xFFBBFFF4, &regs->req_limit_mask);
944
945 for (i = 0; i < ARRAY_SIZE(ddr_max_grant_params); ++i)
946 writel(ddr_max_grant_params[i], &regs->max_grant_len[i]);
947
948 writel(MCR50_RESET_ALL_INTR, &regs->intr_ctrl);
949
950 writel(0x07FFFFFF, &regs->ecc_range_ctrl);
951
952 writel(0, &regs->ecc_test_ctrl);
953 writel(0x80000001, &regs->test_addr);
954 writel(0, &regs->test_fail_dq_bit);
955 writel(0, &regs->test_init_val);
956
957 writel(0xFFFFFFFF, &regs->req_input_ctrl);
958 writel(0, &regs->req_high_pri_ctrl);
959
960 udelay(600);
961
962#ifdef CONFIG_ASPEED_DDR4_DUALX8
963 writel(0x37, &regs->config);
964#else
965 writel(0x17, &regs->config);
966#endif
967
968 /* load controller setting */
969 for (i = 0; i < ARRAY_SIZE(ddr4_ac_timing); ++i)
970 writel(ddr4_ac_timing[i], &regs->ac_timing[i]);
971
972 writel(DDR4_MR01_MODE, &regs->mr01_mode_setting);
973 writel(DDR4_MR23_MODE, &regs->mr23_mode_setting);
974 writel(DDR4_MR45_MODE, &regs->mr45_mode_setting);
975 writel(DDR4_MR6_MODE, &regs->mr6_mode_setting);
976}
977
978/*
979 * Update size info according to the ECC HW setting
980 *
981 * Assume SDRAM has been initialized by SPL or the host. To get the RAM size, we
982 * don't need to calculate the ECC size again but read from MCR04 and derive the
983 * size from its value.
984 */
985static void ast2600_sdrammc_update_size(struct dram_info *info)
986{
987 struct ast2600_sdrammc_regs *regs = info->regs;
988 u32 conf = readl(&regs->config);
989 u32 cap_param;
990 size_t ram_size = SDRAM_MAX_SIZE;
991 size_t hw_size;
992
993 cap_param = (conf & SDRAM_CONF_CAP_MASK) >> SDRAM_CONF_CAP_SHIFT;
994 switch (cap_param) {
995 case SDRAM_CONF_CAP_2048M:
996 ram_size = 2048 * SDRAM_SIZE_1MB;
997 break;
998 case SDRAM_CONF_CAP_1024M:
999 ram_size = 1024 * SDRAM_SIZE_1MB;
1000 break;
1001 case SDRAM_CONF_CAP_512M:
1002 ram_size = 512 * SDRAM_SIZE_1MB;
1003 break;
1004 case SDRAM_CONF_CAP_256M:
1005 ram_size = 256 * SDRAM_SIZE_1MB;
1006 break;
1007 }
1008
1009 info->info.base = CONFIG_SYS_SDRAM_BASE;
1010 info->info.size = ram_size - ast2600_sdrammc_get_vga_mem_size(info);
1011
1012 if (0 == (conf & SDRAM_CONF_ECC_SETUP))
1013 return;
1014
1015 hw_size = readl(&regs->ecc_range_ctrl) & SDRAM_ECC_RANGE_ADDR_MASK;
1016 hw_size += (1 << SDRAM_ECC_RANGE_ADDR_SHIFT);
1017
1018 info->info.size = hw_size;
1019}
1020
1021#ifdef CONFIG_ASPEED_ECC
1022static void ast2600_sdrammc_ecc_enable(struct dram_info *info)
1023{
1024 struct ast2600_sdrammc_regs *regs = info->regs;
1025 size_t conf_size;
1026 u32 reg;
1027
1028 conf_size = CONFIG_ASPEED_ECC_SIZE * SDRAM_SIZE_1MB;
1029 if (conf_size > info->info.size) {
1030 printf("warning: ECC configured %dMB but actual size is %dMB\n",
1031 CONFIG_ASPEED_ECC_SIZE,
1032 info->info.size / SDRAM_SIZE_1MB);
1033 conf_size = info->info.size;
1034 } else if (conf_size == 0) {
1035 conf_size = info->info.size;
1036 }
1037
1038 info->info.size = (((conf_size / 9) * 8) >> 20) << 20;
1039 writel(((info->info.size >> 20) - 1) << 20, &regs->ecc_range_ctrl);
1040 reg = readl(&regs->config) | SDRAM_CONF_ECC_SETUP;
1041 writel(reg, &regs->config);
1042
1043 writel(0, &regs->test_init_val);
1044 writel(0x80000001, &regs->test_addr);
1045 writel(0x221, &regs->ecc_test_ctrl);
1046 while (0 == (readl(&regs->ecc_test_ctrl) & BIT(12)))
1047 ;
1048 writel(0, &regs->ecc_test_ctrl);
1049 writel(BIT(31), &regs->intr_ctrl);
1050 writel(0, &regs->intr_ctrl);
1051}
1052#endif
1053
1054static int ast2600_sdrammc_probe(struct udevice *dev)
1055{
1056 int ret;
1057 u32 reg;
1058 struct dram_info *priv = (struct dram_info *)dev_get_priv(dev);
1059 struct ast2600_sdrammc_regs *regs = priv->regs;
1060 struct udevice *clk_dev;
1061
1062 /* find SCU base address from clock device */
1063 ret = uclass_get_device_by_driver(UCLASS_CLK,
1064 DM_DRIVER_GET(aspeed_ast2600_scu), &clk_dev);
1065 if (ret) {
1066 debug("clock device not defined\n");
1067 return ret;
1068 }
1069
1070 priv->scu = devfdt_get_addr_ptr(clk_dev);
1071 if (IS_ERR(priv->scu)) {
1072 debug("%s(): can't get SCU\n", __func__);
1073 return PTR_ERR(priv->scu);
1074 }
1075
1076 if (readl(&priv->scu->dram_hdshk) & SCU_DRAM_HDSHK_RDY) {
1077 printf("already initialized, ");
1078 ast2600_sdrammc_update_size(priv);
1079 return 0;
1080 }
1081
1082 reg = readl(&priv->scu->mpll);
1083 reg &= ~(SCU_PLL_BYPASS | SCU_PLL_DIV_MASK |
1084 SCU_PLL_DENUM_MASK | SCU_PLL_NUM_MASK);
1085 reg |= (SCU_PLL_RST | SCU_PLL_OFF | SCU_MPLL_FREQ_CFG);
1086 writel(reg, &priv->scu->mpll);
1087 writel(SCU_MPLL_EXT_CFG, &priv->scu->mpll_ext);
1088 udelay(100);
1089 reg &= ~(SCU_PLL_RST | SCU_PLL_OFF);
1090 writel(reg, &priv->scu->mpll);
1091
1092 while ((readl(&priv->scu->mpll_ext) & BIT(31)) == 0)
1093 ;
1094
1095 ast2600_sdrammc_unlock(priv);
1096 ast2600_sdrammc_common_init(regs);
1097L_ast2600_sdramphy_train:
1098 ast2600_sdrammc_init_ddr4(priv);
1099
Dylan Hung82470022020-12-14 13:54:24 +08001100 if (ast2600_sdramphy_check_status(priv) != 0) {
1101 printf("DDR4 PHY training fail, retrain\n");
1102 goto L_ast2600_sdramphy_train;
1103 }
1104
1105 ast2600_sdrammc_calc_size(priv);
1106
1107#ifndef CONFIG_ASPEED_BYPASS_SELFTEST
1108 if (ast2600_sdrammc_test(priv) != 0) {
1109 printf("%s: DDR4 init fail\n", __func__);
1110 return -EINVAL;
1111 }
1112#endif
1113
1114#ifdef CONFIG_ASPEED_ECC
1115 ast2600_sdrammc_ecc_enable(priv);
1116#endif
1117
1118 writel(readl(&priv->scu->dram_hdshk) | SCU_DRAM_HDSHK_RDY,
1119 &priv->scu->dram_hdshk);
1120
1121 clrbits_le32(&regs->intr_ctrl, MCR50_RESET_ALL_INTR);
1122 ast2600_sdrammc_lock(priv);
1123 return 0;
1124}
1125
1126static int ast2600_sdrammc_of_to_plat(struct udevice *dev)
1127{
1128 struct dram_info *priv = dev_get_priv(dev);
1129
1130 priv->regs = (void *)(uintptr_t)devfdt_get_addr_index(dev, 0);
1131 priv->phy_setting = (void *)(uintptr_t)devfdt_get_addr_index(dev, 1);
1132 priv->phy_status = (void *)(uintptr_t)devfdt_get_addr_index(dev, 2);
1133
1134 priv->clock_rate = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
1135 "clock-frequency", 0);
1136 if (!priv->clock_rate) {
1137 debug("DDR Clock Rate not defined\n");
1138 return -EINVAL;
1139 }
1140
1141 return 0;
1142}
1143
1144static int ast2600_sdrammc_get_info(struct udevice *dev, struct ram_info *info)
1145{
1146 struct dram_info *priv = dev_get_priv(dev);
1147
1148 *info = priv->info;
1149
1150 return 0;
1151}
1152
1153static struct ram_ops ast2600_sdrammc_ops = {
1154 .get_info = ast2600_sdrammc_get_info,
1155};
1156
1157static const struct udevice_id ast2600_sdrammc_ids[] = {
1158 { .compatible = "aspeed,ast2600-sdrammc" },
1159 { }
1160};
1161
1162U_BOOT_DRIVER(sdrammc_ast2600) = {
1163 .name = "aspeed_ast2600_sdrammc",
1164 .id = UCLASS_RAM,
1165 .of_match = ast2600_sdrammc_ids,
1166 .ops = &ast2600_sdrammc_ops,
1167 .of_to_plat = ast2600_sdrammc_of_to_plat,
1168 .probe = ast2600_sdrammc_probe,
1169 .priv_auto = sizeof(struct dram_info),
1170};