blob: a98b814df07f343d145c0a2ef116311f0f7b452f [file] [log] [blame]
Masahiro Yamadab614e162014-12-19 20:20:52 +09001/*
Masahiro Yamadaf6e7f072015-05-29 17:30:00 +09002 * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
Masahiro Yamadab614e162014-12-19 20:20:52 +09003 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.h>
Masahiro Yamadaf6e7f072015-05-29 17:30:00 +09008#include <linux/io.h>
Masahiro Yamadaa86ac952015-02-27 02:26:44 +09009#include <mach/ddrphy-regs.h>
Masahiro Yamadab614e162014-12-19 20:20:52 +090010
11void ddrphy_prepare_training(struct ddrphy __iomem *phy, int rank)
12{
13 int dx;
14 u32 __iomem tmp, *p;
15
16 for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
17 p = &phy->dx[dx].gcr;
18
19 tmp = readl(p);
20 /* Specify the rank that should be write leveled */
21 tmp &= ~DXGCR_WLRKEN_MASK;
22 tmp |= (1 << (DXGCR_WLRKEN_SHIFT + rank)) & DXGCR_WLRKEN_MASK;
23 writel(tmp, p);
24 }
25
26 p = &phy->dtcr;
27
28 tmp = readl(p);
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 */
33 tmp |= DTCR_DTMPR;
34 /* Specify the rank enabled for data-training */
35 tmp &= ~DTCR_RNKEN_MASK;
36 tmp |= (1 << (DTCR_RNKEN_SHIFT + rank)) & DTCR_RNKEN_MASK;
37 writel(tmp, p);
38}
39
40struct ddrphy_init_sequence {
41 char *description;
42 u32 init_flag;
43 u32 done_flag;
44 u32 err_flag;
45};
46
47static struct ddrphy_init_sequence init_sequence[] = {
48 {
49 "DRAM Initialization",
50 PIR_DRAMRST | PIR_DRAMINIT,
51 PGSR0_DIDONE,
52 PGSR0_DIERR
53 },
54 {
55 "Write Leveling",
56 PIR_WL,
57 PGSR0_WLDONE,
58 PGSR0_WLERR
59 },
60 {
61 "Read DQS Gate Training",
62 PIR_QSGATE,
63 PGSR0_QSGDONE,
64 PGSR0_QSGERR
65 },
66 {
67 "Write Leveling Adjustment",
68 PIR_WLADJ,
69 PGSR0_WLADONE,
70 PGSR0_WLAERR
71 },
72 {
73 "Read Bit Deskew",
74 PIR_RDDSKW,
75 PGSR0_RDDONE,
76 PGSR0_RDERR
77 },
78 {
79 "Write Bit Deskew",
80 PIR_WRDSKW,
81 PGSR0_WDDONE,
82 PGSR0_WDERR
83 },
84 {
85 "Read Eye Training",
86 PIR_RDEYE,
87 PGSR0_REDONE,
88 PGSR0_REERR
89 },
90 {
91 "Write Eye Training",
92 PIR_WREYE,
93 PGSR0_WEDONE,
94 PGSR0_WEERR
95 }
96};
97
98int ddrphy_training(struct ddrphy __iomem *phy)
99{
100 int i;
101 u32 pgsr0;
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);
107#endif
108
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;
112 }
113
114 writel(init_flag, &phy->pir);
115
116 do {
117 if (--timeout < 0) {
Masahiro Yamadab614e162014-12-19 20:20:52 +0900118 printf("%s: error: timeout during DDR training\n",
119 __func__);
Masahiro Yamadab614e162014-12-19 20:20:52 +0900120 return -1;
121 }
122 udelay(1);
123 pgsr0 = readl(&phy->pgsr[0]);
124 } while ((pgsr0 & done_flag) != done_flag);
125
126 for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
127 if (pgsr0 & init_sequence[i].err_flag) {
Masahiro Yamadab614e162014-12-19 20:20:52 +0900128 printf("%s: error: %s failed\n", __func__,
129 init_sequence[i].description);
Masahiro Yamadab614e162014-12-19 20:20:52 +0900130 return -1;
131 }
132 }
133
134#ifdef DISPLAY_ELAPSED_TIME
135 printf("%s: info: elapsed time %ld msec\n", get_timer(start));
136#endif
137
138 return 0;
139}