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