1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * Juno DMC-400 driver
9 */
10
11 #include "juno_dmc400.h"
12 #include "juno_id.h"
13 #include "juno_scc.h"
14 #include "scp_config.h"
15 #include "system_clock.h"
16
17 #include <mod_juno_dmc400.h>
18 #include <mod_power_domain.h>
19 #include <mod_system_power.h>
20 #include <mod_timer.h>
21
22 #include <fwk_assert.h>
23 #include <fwk_core.h>
24 #include <fwk_event.h>
25 #include <fwk_interrupt.h>
26 #include <fwk_log.h>
27 #include <fwk_macros.h>
28 #include <fwk_module.h>
29 #include <fwk_module_idx.h>
30 #include <fwk_notification.h>
31 #include <fwk_status.h>
32
33 #include <fmw_cmsis.h>
34
35 #include <stddef.h>
36
37 struct juno_dmc400_ctx {
38 const struct mod_juno_dmc400_ddr_phy_api *ddr_phy_api;
39 const struct mod_timer_api *timer_api;
40 unsigned int dmc_refclk_ratio;
41 };
42
43 static struct juno_dmc400_ctx ctx;
44
45 #define DDR_CHANNEL_COUNT 2
46
47 /*
48 * Static helpers
49 */
50
ddr_clock_div_set_check(void * data)51 static bool ddr_clock_div_set_check(void *data)
52 {
53 return ((SCP_CONFIG->DMCCLK_CONTROL & DMCCLK_CONTROL_CRNTCLKDIV) ==
54 (CLKDIV << 16));
55 }
56
ddr_clock_sel_set_check(void * data)57 static bool ddr_clock_sel_set_check(void *data)
58 {
59 return ((SCP_CONFIG->DMCCLK_CONTROL & DMCCLK_CONTROL_CRNTCLK) ==
60 (DMCCLK_CONTROL_CLKSEL_SYSINCLK << 12));
61 }
62
ddr_clock_enable_check(void * data)63 static bool ddr_clock_enable_check(void *data)
64 {
65 uint32_t clock_enable_status;
66
67 clock_enable_status = SCP_CONFIG->CLOCK_ENABLE_STATUS;
68
69 return ((clock_enable_status & SCP_CONFIG_CLOCK_ENABLE_DMCCLKEN) != 0);
70 }
71
dmc_user_config_dfi_check(void * data)72 static bool dmc_user_config_dfi_check(void *data)
73 {
74 const struct mod_juno_dmc400_reg *dmc = data;
75 uint32_t init_complete_mask;
76
77 init_complete_mask = (DMC_USER_STATUS_DFI_INIT_COMPLETE_0 |
78 DMC_USER_STATUS_DFI_INIT_COMPLETE_1);
79
80 return ((dmc->USER_STATUS & init_complete_mask) == init_complete_mask);
81 }
82
ddr_cmd_config_check(void * data)83 static bool ddr_cmd_config_check(void *data)
84 {
85 const struct mod_juno_dmc400_reg *dmc = data;
86
87 return (dmc->MEMC_STATUS == DMC400_CMD_CONFIG);
88 }
89
ddr_cmd_go_check(void * data)90 static bool ddr_cmd_go_check(void *data)
91 {
92 const struct mod_juno_dmc400_reg *dmc = data;
93
94 return (dmc->MEMC_STATUS == DMC400_CMD_GO);
95 }
96
ddr_cmd_sleep_check(void * data)97 static bool ddr_cmd_sleep_check(void *data)
98 {
99 const struct mod_juno_dmc400_reg *dmc = data;
100
101 return (dmc->MEMC_STATUS == DMC400_CMD_SLEEP);
102 }
103
ddr_cmd_low_power_check(void * data)104 static bool ddr_cmd_low_power_check(void *data)
105 {
106 const struct mod_juno_dmc400_reg *dmc = data;
107
108 return ((dmc->MEMC_STATUS & DMC_MEMC_STATUS) == DMC400_CMD_SLEEP);
109 }
110
dmc_delay_cycles(uint32_t dmc_cycles)111 static void dmc_delay_cycles(uint32_t dmc_cycles)
112 {
113 unsigned int i;
114
115 for (i = 0; i < (dmc_cycles / ctx.dmc_refclk_ratio); i++) {
116 __NOP();
117 }
118 }
119
init_ddr_chip(struct mod_juno_dmc400_reg * dmc,uint32_t dev)120 static void init_ddr_chip(struct mod_juno_dmc400_reg *dmc, uint32_t dev)
121 {
122 dmc->DIRECT_CMD = dev;
123 dmc_delay_cycles(20);
124 dmc->DIRECT_CMD = 0x10020018U | dev;
125 dmc_delay_cycles(1);
126 dmc->DIRECT_CMD = 0x10030000U | dev;
127 dmc_delay_cycles(1);
128 dmc->DIRECT_CMD = 0x10010046U | dev;
129 dmc_delay_cycles(1);
130 dmc->DIRECT_CMD = 0x10000D70U | dev;
131 dmc_delay_cycles(60);
132 dmc->DIRECT_CMD = 0x50000400U | dev;
133 dmc_delay_cycles(1);
134 }
135
ddr_clock_div_set(fwk_id_t timer_id)136 static int ddr_clock_div_set(fwk_id_t timer_id)
137 {
138 fwk_assert(CLKDIV <= 16);
139 fwk_assert(CLKDIV != 0);
140
141 SCP_CONFIG->DMCCLK_CONTROL =
142 (SCP_CONFIG->DMCCLK_CONTROL & ~DMCCLK_CONTROL_CLKDIV) | (CLKDIV << 4);
143
144 return ctx.timer_api->wait(timer_id,
145 DMC400_CLOCK_DIV_SET_WAIT_TIMEOUT_US,
146 ddr_clock_div_set_check,
147 NULL);
148 }
149
ddr_clock_sel_set(fwk_id_t timer_id)150 static int ddr_clock_sel_set(fwk_id_t timer_id)
151 {
152 SCP_CONFIG->DMCCLK_CONTROL =
153 ((SCP_CONFIG->DMCCLK_CONTROL & ~DMCCLK_CONTROL_CLKSEL) |
154 DMCCLK_CONTROL_CLKSEL_SYSINCLK);
155
156 return ctx.timer_api->wait(timer_id,
157 DMC400_CLOCK_SEL_SET_WAIT_TIMEOUT_US,
158 ddr_clock_sel_set_check,
159 NULL);
160 }
161
ddr_clock_enable(fwk_id_t timer_id)162 static int ddr_clock_enable(fwk_id_t timer_id)
163 {
164 SCP_CONFIG->CLOCK_ENABLE_SET |= SCP_CONFIG_CLOCK_ENABLE_DMCCLKEN;
165
166 return ctx.timer_api->wait(timer_id,
167 DMC400_CLOCK_ENABLE_WAIT_TIMEOUT_US,
168 ddr_clock_enable_check,
169 NULL);
170 }
171
ddr_remove_poreset(struct mod_juno_dmc400_reg * dmc)172 static void ddr_remove_poreset(struct mod_juno_dmc400_reg *dmc)
173 {
174 dmc->USER_CONFIG0 |=
175 DMC_USER_CONFIG_CORE_PRSTN | DMC_USER_CONFIG_CORE_SRSTN;
176 dmc->USER_CONFIG1 |=
177 DMC_USER_CONFIG_CORE_PRSTN | DMC_USER_CONFIG_CORE_SRSTN;
178
179 dmc_delay_cycles(DELAY_DDR_PORESET_CYCLES);
180 }
181
ddr_phy_init(fwk_id_t id)182 static int ddr_phy_init(fwk_id_t id)
183 {
184 int status;
185 const struct mod_juno_dmc400_element_config *element_config;
186 const struct mod_juno_dmc400_module_config *module_config;
187 struct mod_juno_dmc400_reg *dmc;
188
189 module_config = fwk_module_get_data(fwk_module_id_juno_dmc400);
190 element_config = fwk_module_get_data(id);
191 dmc = (struct mod_juno_dmc400_reg *)element_config->dmc;
192
193 status = ctx.ddr_phy_api->configure_ddr(element_config->ddr_phy_0_id);
194 if (status != FWK_SUCCESS) {
195 return status;
196 }
197
198 status = ctx.ddr_phy_api->configure_ddr(element_config->ddr_phy_1_id);
199 if (status != FWK_SUCCESS) {
200 return status;
201 }
202
203 /* Initialize PHYs */
204 dmc->USER_CONFIG0 |= DMC_USER_CONFIG_DFI_INIT_START;
205 dmc->USER_CONFIG1 |= DMC_USER_CONFIG_DFI_INIT_START;
206
207 if (!element_config->is_platform_fvp) {
208 /* Wait for the PHYs initialization to complete */
209 status = ctx.timer_api->wait(module_config->timer_id,
210 DMC400_PHY_INIT_WAIT_TIMEOUT_US,
211 dmc_user_config_dfi_check,
212 dmc);
213 if (status != FWK_SUCCESS) {
214 return status;
215 }
216 }
217
218 /* Remove initialization request */
219 dmc->USER_CONFIG0 &= ~DMC_USER_CONFIG_DFI_INIT_START;
220 dmc->USER_CONFIG1 &= ~DMC_USER_CONFIG_DFI_INIT_START;
221
222 return FWK_SUCCESS;
223 }
224
ddr_clk_init(fwk_id_t id)225 static int ddr_clk_init(fwk_id_t id)
226 {
227 int status;
228 const struct mod_juno_dmc400_module_config *module_config;
229 const struct mod_juno_dmc400_element_config *element_config;
230 struct mod_juno_dmc400_reg *dmc;
231
232 module_config = fwk_module_get_data(fwk_module_id_juno_dmc400);
233 element_config = fwk_module_get_data(id);
234 dmc = (struct mod_juno_dmc400_reg *)element_config->dmc;
235
236 /* Clock divider */
237 status = ddr_clock_div_set(module_config->timer_id);
238 if (status != FWK_SUCCESS) {
239 return status;
240 }
241
242 /* Clock source */
243 status = ddr_clock_sel_set(module_config->timer_id);
244 if (status != FWK_SUCCESS) {
245 return status;
246 }
247
248 /* Clock enable */
249 status = ddr_clock_enable(module_config->timer_id);
250 if (status != FWK_SUCCESS) {
251 return status;
252 }
253
254 /* Set DDR PHY PLLs after DMCCLK is stable */
255 status = ctx.ddr_phy_api->configure_clk(fwk_module_id_juno_ddr_phy400);
256 if (status != FWK_SUCCESS) {
257 return status;
258 }
259
260 ddr_remove_poreset(dmc);
261
262 return FWK_SUCCESS;
263 }
264
ddr_dmc_init(fwk_id_t id)265 static int ddr_dmc_init(fwk_id_t id)
266 {
267 uint32_t ddr_chip_count, chip, channel, dev;
268 const struct mod_juno_dmc400_element_config *element_config;
269 struct mod_juno_dmc400_reg *dmc;
270
271 element_config = fwk_module_get_data(id);
272 dmc = (struct mod_juno_dmc400_reg *)element_config->dmc;
273
274 /* QoS control */
275 dmc->TURNAROUND_PRIORITY = 0x0000008C;
276 dmc->HIT_PRIORITY = 0x00000000;
277 dmc->QOS0_CONTROL = 0x00000000;
278 dmc->QOS1_CONTROL = 0x00000001;
279 dmc->QOS2_CONTROL = 0x00000002;
280 dmc->QOS3_CONTROL = 0x00000003;
281 dmc->QOS4_CONTROL = 0x00000004;
282 dmc->QOS5_CONTROL = 0x00000005;
283 dmc->QOS6_CONTROL = 0x00000006;
284 dmc->QOS7_CONTROL = 0x00000007;
285 dmc->QOS8_CONTROL = 0x00000008;
286 dmc->QOS9_CONTROL = 0x00000009;
287 dmc->QOS10_CONTROL = 0x0000000A;
288 dmc->QOS11_CONTROL = 0x0000000B;
289 dmc->QOS12_CONTROL = 0x0000000C;
290 dmc->QOS13_CONTROL = 0x0000000D;
291 dmc->QOS14_CONTROL = 0x0000000E;
292 dmc->QOS15_CONTROL = 0x0000000F;
293 dmc->TIMEOUT_CONTROL = 0x00000002;
294 dmc->QUEUE_CONTROL = 0x00000000;
295 dmc->WRITE_PRIORITY_CONTROL = 0x00000001;
296 dmc->WRITE_PRIORITY_CONTROL2 = 0xBBBB8888;
297 dmc->READ_PRIORITY_CONTROL = 0x88000002;
298 dmc->READ_PRIORITY_CONTROL2 = 0xCCCCCCCC;
299
300 dmc->ACCESS_ADDRESS_MATCH_31_00 = 0x00000000;
301 dmc->ACCESS_ADDRESS_MATCH_63_32 = 0x00000000;
302 dmc->ACCESS_ADDRESS_MASK_31_00 = 0x00000000;
303 dmc->ACCESS_ADDRESS_MASK_63_32 = 0x000000FE;
304 dmc->REFRESH_CONTROL = 0x00000000;
305 dmc->INTERRUPT_CONTROL = 0x00000000;
306 dmc->INTERRUPT_CLR = 0x00000000;
307 dmc->FORMAT_CONTROL = 0x11000103;
308
309 /* Timings frequency-dependent */
310 dmc->T_LPRESP = 0x00000007;
311 dmc->T_REFI = 0x00000186;
312 dmc->T_RFC = 0x008C008C;
313 dmc->T_MRR = 0x00000002;
314 dmc->T_MRW = 0x00000007;
315 dmc->T_RCD = 0x00000006;
316 dmc->T_RAS = 0x0000000F;
317 dmc->T_RP = 0x00000006;
318 dmc->T_RPALL = 0x00000007;
319 dmc->T_RRD = 0x00000004;
320 dmc->T_FAW = 0x00000011;
321 dmc->T_RTR = 0x0000000B;
322 dmc->T_RTW = 0x00000007;
323 dmc->T_RTP = 0x00000004;
324 dmc->T_WR = 0x0000000D;
325 dmc->T_WTR = 0x0004000A;
326 dmc->T_WTW = 0x000C0000;
327 dmc->READ_LATENCY = 0x0000000C;
328 dmc->WRITE_LATENCY = 0x00000009;
329 dmc->T_RDDATA_EN = 0x00000003;
330 dmc->T_PHYWRLAT = 0x00000001;
331 dmc->WRLVL_MRS = 0x000000C6;
332
333 /* Set sync-up bridge */
334 dmc->USER_CONFIG0 |=
335 DMC_USER_CONFIG_TWRDATA_DELAY | DMC_USER_CONFIG_TWRDATA_EN_DELAY;
336 dmc->USER_CONFIG1 |=
337 DMC_USER_CONFIG_TWRDATA_DELAY | DMC_USER_CONFIG_TWRDATA_EN_DELAY;
338
339 dmc->T_EP = 0x00000004;
340 dmc->T_XP = 0x000B0004;
341 dmc->T_ESR = 0x00000004;
342 dmc->T_XSR = 0x01000090;
343 dmc->T_SRCKD = 0x00000005;
344 dmc->T_CKSRD = 0x00000005;
345 dmc->T_ECKD = 0x00000005;
346 dmc->T_XCKD = 0x00000005;
347
348 /* General control */
349 dmc->ADDRESS_CONTROL = element_config->address_control;
350
351 dmc->DECODE_CONTROL = 0x10000043;
352 dmc->MODE_CONTROL = 0x00000012;
353 dmc->LOW_POWER_CONTROL = 0x00000010;
354
355 /* Direct commands to initialize LPDDR3 */
356 ddr_chip_count = element_config->ddr_chip_count;
357 for (channel = 0; channel < DDR_CHANNEL_COUNT; channel++) {
358 for (chip = 0; chip < ddr_chip_count; chip++) {
359 dev = (channel << 24) | (chip << 20);
360
361 init_ddr_chip(dmc, dev);
362 }
363 }
364
365 dmc_delay_cycles(DELAY_DDR_INIT_LPDDR3_CYCLES);
366
367 /* Auto refresh */
368 dmc->DIRECT_CMD = DIRECT_CMD_AUTOREFRESH |
369 DIRECT_CMD_CHANNEL_0_ADDR |
370 DIRECT_CMD_CHIP_0_ADDR;
371
372 if (element_config->ddr_chip_count > 1) {
373 dmc->DIRECT_CMD = DIRECT_CMD_AUTOREFRESH |
374 DIRECT_CMD_CHANNEL_0_ADDR |
375 DIRECT_CMD_CHIP_1_ADDR;
376 }
377
378 dmc->DIRECT_CMD = DIRECT_CMD_AUTOREFRESH |
379 DIRECT_CMD_CHANNEL_1_ADDR |
380 DIRECT_CMD_CHIP_0_ADDR;
381
382 if (element_config->ddr_chip_count > 1) {
383 dmc->DIRECT_CMD = DIRECT_CMD_AUTOREFRESH |
384 DIRECT_CMD_CHANNEL_1_ADDR |
385 DIRECT_CMD_CHIP_1_ADDR;
386 }
387
388 return FWK_SUCCESS;
389 }
390
391 /*
392 * The training sequence must run with interrupts disabled
393 */
ddr_training(fwk_id_t id)394 static int ddr_training(fwk_id_t id)
395 {
396 int status;
397 uint64_t timeout, remaining_ticks, counter;
398 const struct mod_juno_dmc400_element_config *element_config;
399 const struct mod_juno_dmc400_module_config *module_config;
400 struct mod_juno_dmc400_reg *dmc;
401
402 module_config = fwk_module_get_data(fwk_module_id_juno_dmc400);
403 element_config = fwk_module_get_data(id);
404 dmc = (struct mod_juno_dmc400_reg *)element_config->dmc;
405
406 if (element_config->is_platform_fvp) {
407 /* Training unsupported on FVP */
408 return FWK_SUCCESS;
409 }
410
411 /* Configure the time-out for the DDR programming */
412 status = ctx.timer_api->time_to_timestamp(module_config->timer_id,
413 DMC400_TRAINING_TIMEOUT_US,
414 &timeout);
415 if (status != FWK_SUCCESS) {
416 return status;
417 }
418
419 status = ctx.timer_api->get_counter(module_config->timer_id, &counter);
420 if (status != FWK_SUCCESS) {
421 return status;
422 }
423
424 timeout += counter;
425
426 /* Training related setup */
427 dmc->RDLVL_CONTROL = 0x00001002;
428 dmc->T_RDLVL_EN = 0x00000020;
429 dmc->T_RDLVL_RR = 0x00000014;
430 dmc->WRLVL_CONTROL = 0x00001002;
431 dmc->WRLVL_DIRECT = 0x00000000;
432 dmc->T_WRLVL_EN = 0x00000028;
433 dmc->T_WRLVL_WW = 0x0000001B;
434
435 /*
436 * Write training
437 */
438
439 /* Channel 0, chip 0 */
440 dmc->WRLVL_DIRECT = WRITE_LEVELING_REQUEST_SEND |
441 WRITE_LEVELING_CHANNEL_0 |
442 WRITE_LEVELING_CHIP_0;
443 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M0_MASK) !=
444 DMC_CHANNEL_STATUS_M0_IDLE) {
445 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
446 &remaining_ticks);
447 if (status != FWK_SUCCESS) {
448 return status;
449 }
450 if (remaining_ticks == 0) {
451 goto timeout;
452 }
453 }
454
455 /* Channel 1, chip 0 */
456 dmc->WRLVL_DIRECT = WRITE_LEVELING_REQUEST_SEND |
457 WRITE_LEVELING_CHANNEL_1 |
458 WRITE_LEVELING_CHIP_0;
459 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M1_MASK) !=
460 DMC_CHANNEL_STATUS_M1_IDLE) {
461 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
462 &remaining_ticks);
463 if (status != FWK_SUCCESS) {
464 return status;
465 }
466 if (remaining_ticks == 0) {
467 goto timeout;
468 }
469 }
470
471 if (element_config->ddr_chip_count > 1) {
472 /* Channel 0, chip 1 */
473 dmc->WRLVL_DIRECT = WRITE_LEVELING_REQUEST_SEND |
474 WRITE_LEVELING_CHANNEL_0 |
475 WRITE_LEVELING_CHIP_1;
476 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M0_MASK) !=
477 DMC_CHANNEL_STATUS_M0_IDLE) {
478 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
479 &remaining_ticks);
480 if (status != FWK_SUCCESS) {
481 return status;
482 }
483 if (remaining_ticks == 0) {
484 goto timeout;
485 }
486 }
487
488 /* Channel 1, chip 1 */
489 dmc->WRLVL_DIRECT = WRITE_LEVELING_REQUEST_SEND |
490 WRITE_LEVELING_CHANNEL_1 |
491 WRITE_LEVELING_CHIP_1;
492 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M1_MASK) !=
493 DMC_CHANNEL_STATUS_M1_IDLE) {
494 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
495 &remaining_ticks);
496 if (status != FWK_SUCCESS) {
497 return status;
498 }
499 if (remaining_ticks == 0) {
500 goto timeout;
501 }
502 }
503 }
504
505 /*
506 * Read Gate training
507 */
508
509 /* Channel 0, chip 0 */
510 dmc->RDLVL_DIRECT = READ_GATE_TRAINING_REQUEST_SEND |
511 READ_LEVELING_CHANNEL_0 |
512 READ_LEVELING_CHIP_0;
513 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M0_MASK) !=
514 DMC_CHANNEL_STATUS_M0_IDLE) {
515 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
516 &remaining_ticks);
517 if (status != FWK_SUCCESS) {
518 return status;
519 }
520 if (remaining_ticks == 0) {
521 goto timeout;
522 }
523 }
524
525 /* Channel 1, chip 0 */
526 dmc->RDLVL_DIRECT = READ_GATE_TRAINING_REQUEST_SEND |
527 READ_LEVELING_CHANNEL_1 |
528 READ_LEVELING_CHIP_0;
529 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M1_MASK) !=
530 DMC_CHANNEL_STATUS_M1_IDLE) {
531 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
532 &remaining_ticks);
533 if (status != FWK_SUCCESS) {
534 return status;
535 }
536 if (remaining_ticks == 0) {
537 goto timeout;
538 }
539 }
540
541 if (element_config->ddr_chip_count > 1) {
542 /* Channel 0, chip 1 */
543 dmc->RDLVL_DIRECT = READ_GATE_TRAINING_REQUEST_SEND |
544 READ_LEVELING_CHANNEL_0 |
545 READ_LEVELING_CHIP_1;
546 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M0_MASK) !=
547 DMC_CHANNEL_STATUS_M0_IDLE) {
548 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
549 &remaining_ticks);
550 if (status != FWK_SUCCESS) {
551 return status;
552 }
553 if (remaining_ticks == 0) {
554 goto timeout;
555 }
556 }
557
558 /* Channel 1, chip 1 */
559 dmc->RDLVL_DIRECT = READ_GATE_TRAINING_REQUEST_SEND |
560 READ_LEVELING_CHANNEL_1 |
561 READ_LEVELING_CHIP_1;
562 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M1_MASK) !=
563 DMC_CHANNEL_STATUS_M1_IDLE) {
564 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
565 &remaining_ticks);
566 if (status != FWK_SUCCESS) {
567 return status;
568 }
569 if (remaining_ticks == 0) {
570 goto timeout;
571 }
572 }
573 }
574
575 /*
576 * Read Eye training
577 */
578
579 /* Channel 0, chip 0 */
580 dmc->RDLVL_DIRECT = READ_EYE_TRAINING_REQUEST_SEND |
581 READ_LEVELING_CHANNEL_0 |
582 READ_LEVELING_CHIP_0;
583 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M0_MASK) !=
584 DMC_CHANNEL_STATUS_M0_IDLE) {
585 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
586 &remaining_ticks);
587 if (status != FWK_SUCCESS) {
588 return status;
589 }
590 if (remaining_ticks == 0) {
591 goto timeout;
592 }
593 }
594
595 /* Channel 1, chip 0 */
596 dmc->RDLVL_DIRECT = READ_EYE_TRAINING_REQUEST_SEND |
597 READ_LEVELING_CHANNEL_1 |
598 READ_LEVELING_CHIP_0;
599 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M1_MASK) !=
600 DMC_CHANNEL_STATUS_M1_IDLE) {
601 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
602 &remaining_ticks);
603 if (status != FWK_SUCCESS) {
604 return status;
605 }
606 if (remaining_ticks == 0) {
607 goto timeout;
608 }
609 }
610
611 if (element_config->ddr_chip_count > 1) {
612 /* Channel 0, chip 1 */
613 dmc->RDLVL_DIRECT = READ_EYE_TRAINING_REQUEST_SEND |
614 READ_LEVELING_CHANNEL_0 |
615 READ_LEVELING_CHIP_1;
616 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M0_MASK) !=
617 DMC_CHANNEL_STATUS_M0_IDLE) {
618 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
619 &remaining_ticks);
620 if (status != FWK_SUCCESS) {
621 return status;
622 }
623 if (remaining_ticks == 0) {
624 goto timeout;
625 }
626 }
627
628 /* Channel 1, chip 1 */
629 dmc->RDLVL_DIRECT = READ_EYE_TRAINING_REQUEST_SEND |
630 READ_LEVELING_CHANNEL_1 |
631 READ_LEVELING_CHIP_1;
632 while ((dmc->CHANNEL_STATUS & DMC_CHANNEL_STATUS_M1_MASK) !=
633 DMC_CHANNEL_STATUS_M1_IDLE) {
634 status = ctx.timer_api->remaining(module_config->timer_id, timeout,
635 &remaining_ticks);
636 if (status != FWK_SUCCESS) {
637 return status;
638 }
639 if (remaining_ticks == 0) {
640 goto timeout;
641 }
642 }
643
644 }
645
646 return FWK_SUCCESS;
647
648 timeout:
649 FWK_LOG_WARN("[DMC] Training time-out");
650
651 return FWK_E_TIMEOUT;
652 }
653
ddr_retraining(fwk_id_t id)654 static int ddr_retraining(fwk_id_t id)
655 {
656 int status;
657 unsigned int flags;
658 const struct mod_juno_dmc400_element_config *element_config;
659 const struct mod_juno_dmc400_module_config *module_config;
660 struct mod_juno_dmc400_reg *dmc;
661
662 module_config = fwk_module_get_data(fwk_module_id_juno_dmc400);
663 element_config = fwk_module_get_data(id);
664 dmc = (struct mod_juno_dmc400_reg *)element_config->dmc;
665
666 flags = fwk_interrupt_global_disable();
667
668 dmc->MEMC_CMD = DMC400_CMD_CONFIG;
669 status = ctx.timer_api->wait(module_config->timer_id,
670 DMC400_CONFIG_WAIT_TIMEOUT_US,
671 ddr_cmd_config_check,
672 dmc);
673 if (status != FWK_SUCCESS) {
674 return status;
675 }
676
677 status = ddr_training(id);
678 if (status != FWK_SUCCESS) {
679 return status;
680 }
681
682 dmc->MEMC_CMD = DMC400_CMD_GO;
683
684 fwk_interrupt_global_enable(flags);
685
686 status = fwk_interrupt_enable((unsigned int)PHY_TRAINING_IRQ);
687 if (status != FWK_SUCCESS) {
688 return status;
689 }
690
691 FWK_LOG_INFO("[DMC] Re-training done");
692
693 return FWK_SUCCESS;
694 }
695
ddr_wake(fwk_id_t id)696 static int ddr_wake(fwk_id_t id)
697 {
698 int status;
699 uint32_t ddr_chip_count, chip, channel, dev;
700 const struct mod_juno_dmc400_element_config *element_config;
701 const struct mod_juno_dmc400_module_config *module_config;
702 struct mod_juno_dmc400_reg *dmc;
703
704 module_config = fwk_module_get_data(fwk_module_id_juno_dmc400);
705 element_config = fwk_module_get_data(id);
706 dmc = (struct mod_juno_dmc400_reg *)element_config->dmc;
707
708 dmc_delay_cycles(64);
709
710 /* Disable PHY retention */
711 status = ctx.ddr_phy_api->configure_retention(fwk_module_id_juno_ddr_phy400,
712 false);
713 if (status != FWK_SUCCESS) {
714 return status;
715 }
716
717 dmc_delay_cycles(64);
718
719 /*
720 * The DDR modules need to be sent a NOP during the transition
721 * from DMC sleep to DMC configure modes in order to disable
722 * self-refresh.
723 */
724 dmc->MEMC_CMD = DMC400_CMD_CONFIG;
725 status = ctx.timer_api->wait(module_config->timer_id,
726 DMC400_CONFIG_WAIT_TIMEOUT_US,
727 ddr_cmd_config_check,
728 dmc);
729 if (status != FWK_SUCCESS) {
730 return status;
731 }
732
733 ddr_chip_count = element_config->ddr_chip_count;
734 for (channel = 0; channel < DDR_CHANNEL_COUNT; channel++) {
735 for (chip = 0; chip < ddr_chip_count; chip++) {
736 dev = (channel << 24) | (chip << 20);
737
738 dmc->DIRECT_CMD = dev;
739 dmc_delay_cycles(20);
740 }
741 }
742
743 dmc->MEMC_CMD = DMC400_CMD_GO;
744 status = ctx.timer_api->wait(module_config->timer_id,
745 DMC400_CONFIG_WAIT_TIMEOUT_US,
746 ddr_cmd_go_check,
747 dmc);
748 if (status != FWK_SUCCESS) {
749 return status;
750 }
751
752 dmc_delay_cycles(64);
753
754 /* Re-run training program */
755 return ddr_retraining(id);
756 }
757
ddr_resume(const struct mod_juno_dmc400_element_config * config,fwk_id_t id)758 static int ddr_resume(const struct mod_juno_dmc400_element_config *config,
759 fwk_id_t id)
760 {
761 int status;
762 const struct mod_juno_dmc400_module_config *module_config;
763 struct mod_juno_dmc400_reg *dmc;
764
765 module_config = fwk_module_get_data(fwk_module_id_juno_dmc400);
766 dmc = (struct mod_juno_dmc400_reg *)config->dmc;
767
768 status = ddr_clk_init(id);
769 if (status != FWK_SUCCESS) {
770 return status;
771 }
772
773 status = ddr_phy_init(id);
774 if (status != FWK_SUCCESS) {
775 return status;
776 }
777
778 status = ddr_dmc_init(id);
779 if (status != FWK_SUCCESS) {
780 return status;
781 }
782
783 /* Sleep the DMC */
784 dmc->MEMC_CMD = DMC400_CMD_SLEEP;
785 status = ctx.timer_api->wait(module_config->timer_id,
786 DMC400_CONFIG_WAIT_TIMEOUT_US,
787 ddr_cmd_sleep_check,
788 dmc);
789 if (status != FWK_SUCCESS) {
790 return status;
791 }
792
793 status = ddr_wake(id);
794 if (status != FWK_SUCCESS) {
795 return status;
796 }
797
798 status = fwk_notification_unsubscribe(
799 mod_pd_notification_id_power_state_transition,
800 config->pd_id,
801 id);
802 if (status != FWK_SUCCESS) {
803 return status;
804 }
805
806 return fwk_notification_subscribe(
807 mod_pd_notification_id_power_state_pre_transition,
808 config->pd_id,
809 id);
810 }
811
ddr_suspend(const struct mod_juno_dmc400_element_config * config,fwk_id_t id)812 static int ddr_suspend(const struct mod_juno_dmc400_element_config *config,
813 fwk_id_t id)
814 {
815 int status;
816 struct mod_juno_dmc400_reg *dmc;
817 const struct mod_juno_dmc400_module_config *module_config;
818
819 module_config = fwk_module_get_data(fwk_module_id_juno_dmc400);
820 dmc = (struct mod_juno_dmc400_reg *)config->dmc;
821
822 status = fwk_interrupt_disable((unsigned int)PHY_TRAINING_IRQ);
823 if (status != FWK_SUCCESS) {
824 return FWK_E_STATE;
825 }
826
827 /* Set low power mode */
828 dmc->MEMC_CMD = DMC400_CMD_SLEEP;
829 status = ctx.timer_api->wait(module_config->timer_id,
830 DMC400_CONFIG_WAIT_TIMEOUT_US,
831 ddr_cmd_low_power_check,
832 dmc);
833
834 dmc_delay_cycles(64);
835
836 /* Wait for the PHYs to be idle */
837 status = ctx.ddr_phy_api->configure_idle(config->ddr_phy_0_id);
838 if (status != FWK_SUCCESS) {
839 return status;
840 }
841
842 status = ctx.ddr_phy_api->configure_idle(config->ddr_phy_1_id);
843 if (status != FWK_SUCCESS) {
844 return status;
845 }
846
847 /* Enable PHY retention */
848 status = ctx.ddr_phy_api->configure_retention(fwk_module_id_juno_ddr_phy400,
849 true);
850 if (status != FWK_SUCCESS) {
851 return status;
852 }
853
854 status = fwk_notification_unsubscribe(
855 mod_pd_notification_id_power_state_pre_transition,
856 config->pd_id,
857 id);
858 if (status != FWK_SUCCESS) {
859 return status;
860 }
861
862 return fwk_notification_subscribe(
863 mod_pd_notification_id_power_state_transition,
864 config->pd_id,
865 id);
866 }
867
ddr_phy_irq_handler(void)868 static void ddr_phy_irq_handler(void)
869 {
870 int status;
871 struct fwk_event req_event;
872 enum juno_idx_revision revision = JUNO_IDX_REVISION_COUNT;
873 fwk_id_t id = FWK_ID_ELEMENT(FWK_MODULE_IDX_JUNO_DMC400, 0);
874
875 status = juno_id_get_revision(&revision);
876 fwk_assert(status == FWK_SUCCESS);
877
878 /*
879 * Retrain can be requested only by Juno R0
880 */
881 fwk_assert(revision == JUNO_IDX_REVISION_R0);
882
883 status = fwk_interrupt_disable((unsigned int)PHY_TRAINING_IRQ);
884 fwk_assert(status == FWK_SUCCESS);
885
886 req_event = (struct fwk_event) {
887 .source_id = id,
888 .target_id = id,
889 .id = juno_dmc400_event_id_training,
890 };
891
892 status = fwk_put_event(&req_event);
893 fwk_assert(status == FWK_SUCCESS);
894 }
895
896 /*
897 * Framework handlers
898 */
899
juno_dmc400_init(fwk_id_t module_id,unsigned int element_count,const void * data)900 static int juno_dmc400_init(fwk_id_t module_id,
901 unsigned int element_count,
902 const void *data) {
903
904 fwk_assert(data != NULL);
905 fwk_assert(element_count == 1);
906
907 return FWK_SUCCESS;
908 }
909
juno_dmc400_element_init(fwk_id_t element_id,unsigned int sub_element_count,const void * data)910 static int juno_dmc400_element_init(fwk_id_t element_id,
911 unsigned int sub_element_count,
912 const void *data) {
913
914 fwk_assert(data != NULL);
915
916 return FWK_SUCCESS;
917 }
918
juno_dmc400_bind(fwk_id_t id,unsigned int round)919 static int juno_dmc400_bind(fwk_id_t id, unsigned int round)
920 {
921
922 int status;
923 const struct mod_juno_dmc400_module_config *module_config;
924
925 /* Nothing to do in the second round of calls */
926 if (round >= 1) {
927 return FWK_SUCCESS;
928 }
929
930 /* Nothing to do in case of elements */
931 if (fwk_module_is_valid_element_id(id)) {
932 return FWK_SUCCESS;
933 }
934
935 module_config = fwk_module_get_data(fwk_module_id_juno_dmc400);
936 fwk_assert(module_config != NULL);
937
938 status = fwk_module_bind(module_config->ddr_phy_module_id,
939 module_config->ddr_phy_api_id, &ctx.ddr_phy_api);
940 if (status != FWK_SUCCESS) {
941 return status;
942 }
943
944 status = fwk_module_bind(module_config->timer_id,
945 FWK_ID_API(FWK_MODULE_IDX_TIMER, 0),
946 &ctx.timer_api);
947 if (status != FWK_SUCCESS) {
948 return status;
949 }
950
951 return FWK_SUCCESS;
952 }
953
juno_dmc400_start(fwk_id_t id)954 static int juno_dmc400_start(fwk_id_t id)
955 {
956 int status;
957 unsigned int flags;
958 const struct mod_juno_dmc400_element_config *element_config;
959 struct mod_juno_dmc400_reg *dmc;
960
961 /* Nothing to start for the module */
962 if (fwk_module_is_valid_module_id(id)) {
963 return FWK_SUCCESS;
964 }
965
966 if (SCC->GPR0 & SCC_GPR0_DDR_DISABLE) {
967 FWK_LOG_INFO("[DMC] GPR_0 disable flag set: skipping init");
968
969 return FWK_SUCCESS;
970 }
971
972 element_config = fwk_module_get_data(id);
973
974 dmc = (struct mod_juno_dmc400_reg *)element_config->dmc;
975 if (!fwk_expect(dmc != NULL)) {
976 return FWK_E_PARAM;
977 }
978
979 fwk_assert(CLKDIV > 0);
980
981 ctx.dmc_refclk_ratio = (DDR_FREQUENCY_MHZ * FWK_MHZ) / CLOCK_RATE_REFCLK;
982 fwk_assert(ctx.dmc_refclk_ratio > 0);
983
984 FWK_LOG_INFO("[DMC] Initializing DMC-400 at 0x%x", (uintptr_t)dmc);
985
986 status = ddr_clk_init(id);
987 if (status != FWK_SUCCESS) {
988 return status;
989 }
990
991 status = ddr_phy_init(id);
992 if (status != FWK_SUCCESS) {
993 return status;
994 }
995
996 status = ddr_dmc_init(id);
997 if (status != FWK_SUCCESS) {
998 return status;
999 }
1000
1001 flags = fwk_interrupt_global_disable();
1002
1003 status = ddr_training(id);
1004 if (status != FWK_SUCCESS) {
1005 return status;
1006 }
1007
1008 fwk_interrupt_global_enable(flags);
1009
1010 status = fwk_interrupt_set_isr(
1011 (unsigned int)PHY_TRAINING_IRQ, ddr_phy_irq_handler);
1012 if (status != FWK_SUCCESS) {
1013 return FWK_E_STATE;
1014 }
1015
1016 status = fwk_interrupt_clear_pending((unsigned int)PHY_TRAINING_IRQ);
1017 if (status != FWK_SUCCESS) {
1018 return FWK_E_STATE;
1019 }
1020
1021 status = fwk_interrupt_enable((unsigned int)PHY_TRAINING_IRQ);
1022 if (status != FWK_SUCCESS) {
1023 return status;
1024 }
1025
1026 /* Configure Integration Tests */
1027 dmc->INTEG_CFG = 0x00000000;
1028 dmc->INTEG_OUTPUTS = 0x00000000;
1029
1030 FWK_LOG_INFO("[DMC] DDR Ready");
1031
1032 /* Switch to READY */
1033 dmc->MEMC_CMD = DMC400_CMD_GO;
1034
1035 return fwk_notification_subscribe(
1036 mod_pd_notification_id_power_state_pre_transition,
1037 element_config->pd_id,
1038 id);
1039 }
1040
juno_dmc400_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)1041 static int juno_dmc400_process_notification(const struct fwk_event *event,
1042 struct fwk_event *resp_event)
1043 {
1044 const struct mod_juno_dmc400_element_config *element_config;
1045 const struct mod_pd_power_state_transition_notification_params
1046 *pd_transition_params;
1047 const struct mod_pd_power_state_pre_transition_notification_params
1048 *pd_pre_transition_params;
1049 int status;
1050 struct mod_pd_power_state_pre_transition_notification_resp_params
1051 *pd_resp_params;
1052
1053 if (!fwk_module_is_valid_element_id(event->target_id)) {
1054 return FWK_E_PARAM;
1055 }
1056
1057 element_config = fwk_module_get_data(event->target_id);
1058
1059 if (fwk_id_is_equal(event->id,
1060 mod_pd_notification_id_power_state_transition)) {
1061 pd_transition_params =
1062 (const struct mod_pd_power_state_transition_notification_params *)
1063 event->params;
1064 if (pd_transition_params->state != MOD_PD_STATE_ON) {
1065 return FWK_SUCCESS;
1066 } else {
1067 return ddr_resume(element_config, event->target_id);
1068 }
1069 } else if (fwk_id_is_equal(event->id,
1070 mod_pd_notification_id_power_state_pre_transition)) {
1071 pd_pre_transition_params =
1072 (const struct mod_pd_power_state_pre_transition_notification_params *)
1073 event->params;
1074 pd_resp_params =
1075 (struct mod_pd_power_state_pre_transition_notification_resp_params *)
1076 resp_event->params;
1077
1078 if ((pd_pre_transition_params->target_state == MOD_PD_STATE_OFF) ||
1079 (pd_pre_transition_params->target_state ==
1080 MOD_SYSTEM_POWER_POWER_STATE_SLEEP0)) {
1081 status = ddr_suspend(element_config, event->target_id);
1082
1083 pd_resp_params->status = status;
1084
1085 return status;
1086 } else {
1087 return FWK_SUCCESS;
1088 }
1089 } else {
1090 return FWK_E_HANDLER;
1091 }
1092 }
1093
juno_dmc400_process_event(const struct fwk_event * event,struct fwk_event * resp)1094 static int juno_dmc400_process_event(const struct fwk_event *event,
1095 struct fwk_event *resp)
1096 {
1097 if (fwk_id_get_event_idx(event->id) >= JUNO_DMC400_EVENT_IDX_COUNT) {
1098 return FWK_E_PARAM;
1099 }
1100
1101 return ddr_retraining(event->target_id);
1102 }
1103
1104 struct fwk_module module_juno_dmc400 = {
1105 .type = FWK_MODULE_TYPE_DRIVER,
1106 .api_count = 0,
1107 .event_count = (unsigned int)JUNO_DMC400_EVENT_IDX_COUNT,
1108 .init = juno_dmc400_init,
1109 .element_init = juno_dmc400_element_init,
1110 .bind = juno_dmc400_bind,
1111 .start = juno_dmc400_start,
1112 .process_notification = juno_dmc400_process_notification,
1113 .process_event = juno_dmc400_process_event,
1114 };
1115