2 * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
4 * SPDX-License-Identifier: GPL-2.0+
9 #include <mach/ddrphy-regs.h>
11 void ddrphy_prepare_training(struct ddrphy __iomem
*phy
, int rank
)
16 for (dx
= 0; dx
< NR_DATX8_PER_DDRPHY
; dx
++) {
20 /* Specify the rank that should be write leveled */
21 tmp
&= ~DXGCR_WLRKEN_MASK
;
22 tmp
|= (1 << (DXGCR_WLRKEN_SHIFT
+ rank
)) & DXGCR_WLRKEN_MASK
;
29 /* Specify the rank used during data bit deskew and eye centering */
30 tmp
&= ~DTCR_DTRANK_MASK
;
31 tmp
|= (rank
<< DTCR_DTRANK_SHIFT
) & DTCR_DTRANK_MASK
;
32 /* Use Multi-Purpose Register for DQS gate training */
34 /* Specify the rank enabled for data-training */
35 tmp
&= ~DTCR_RNKEN_MASK
;
36 tmp
|= (1 << (DTCR_RNKEN_SHIFT
+ rank
)) & DTCR_RNKEN_MASK
;
40 struct ddrphy_init_sequence
{
47 static struct ddrphy_init_sequence init_sequence
[] = {
49 "DRAM Initialization",
50 PIR_DRAMRST
| PIR_DRAMINIT
,
61 "Read DQS Gate Training",
67 "Write Leveling Adjustment",
98 int ddrphy_training(struct ddrphy __iomem
*phy
)
102 u32 init_flag
= PIR_INIT
;
103 u32 done_flag
= PGSR0_IDONE
;
104 int timeout
= 50000; /* 50 msec is long enough */
105 #ifdef DISPLAY_ELAPSED_TIME
106 ulong start
= get_timer(0);
109 for (i
= 0; i
< ARRAY_SIZE(init_sequence
); i
++) {
110 init_flag
|= init_sequence
[i
].init_flag
;
111 done_flag
|= init_sequence
[i
].done_flag
;
114 writel(init_flag
, &phy
->pir
);
118 printf("%s: error: timeout during DDR training\n",
123 pgsr0
= readl(&phy
->pgsr
[0]);
124 } while ((pgsr0
& done_flag
) != done_flag
);
126 for (i
= 0; i
< ARRAY_SIZE(init_sequence
); i
++) {
127 if (pgsr0
& init_sequence
[i
].err_flag
) {
128 printf("%s: error: %s failed\n", __func__
,
129 init_sequence
[i
].description
);
134 #ifdef DISPLAY_ELAPSED_TIME
135 printf("%s: info: elapsed time %ld msec\n", get_timer(start
));