arm64: add better and more generic spin-table support
[oweals/u-boot.git] / arch / arm / mach-uniphier / dram / ddrphy-training.c
1 /*
2  * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <linux/err.h>
9 #include <linux/io.h>
10
11 #include "ddrphy-regs.h"
12
13 void ddrphy_prepare_training(struct ddrphy __iomem *phy, int rank)
14 {
15         int dx;
16         u32 __iomem tmp, *p;
17
18         for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
19                 p = &phy->dx[dx].gcr;
20
21                 tmp = readl(p);
22                 /* Specify the rank that should be write leveled */
23                 tmp &= ~DXGCR_WLRKEN_MASK;
24                 tmp |= (1 << (DXGCR_WLRKEN_SHIFT + rank)) & DXGCR_WLRKEN_MASK;
25                 writel(tmp, p);
26         }
27
28         p = &phy->dtcr;
29
30         tmp = readl(p);
31         /* Specify the rank used during data bit deskew and eye centering */
32         tmp &= ~DTCR_DTRANK_MASK;
33         tmp |= (rank << DTCR_DTRANK_SHIFT) & DTCR_DTRANK_MASK;
34         /* Use Multi-Purpose Register for DQS gate training */
35         tmp |= DTCR_DTMPR;
36         /* Specify the rank enabled for data-training */
37         tmp &= ~DTCR_RANKEN_MASK;
38         tmp |= (1 << (DTCR_RANKEN_SHIFT + rank)) & DTCR_RANKEN_MASK;
39         writel(tmp, p);
40 }
41
42 struct ddrphy_init_sequence {
43         char *description;
44         u32 init_flag;
45         u32 done_flag;
46         u32 err_flag;
47 };
48
49 static const struct ddrphy_init_sequence init_sequence[] = {
50         {
51                 "DRAM Initialization",
52                 PIR_DRAMRST | PIR_DRAMINIT,
53                 PGSR0_DIDONE,
54                 PGSR0_DIERR
55         },
56         {
57                 "Write Leveling",
58                 PIR_WL,
59                 PGSR0_WLDONE,
60                 PGSR0_WLERR
61         },
62         {
63                 "Read DQS Gate Training",
64                 PIR_QSGATE,
65                 PGSR0_QSGDONE,
66                 PGSR0_QSGERR
67         },
68         {
69                 "Write Leveling Adjustment",
70                 PIR_WLADJ,
71                 PGSR0_WLADONE,
72                 PGSR0_WLAERR
73         },
74         {
75                 "Read Bit Deskew",
76                 PIR_RDDSKW,
77                 PGSR0_RDDONE,
78                 PGSR0_RDERR
79         },
80         {
81                 "Write Bit Deskew",
82                 PIR_WRDSKW,
83                 PGSR0_WDDONE,
84                 PGSR0_WDERR
85         },
86         {
87                 "Read Eye Training",
88                 PIR_RDEYE,
89                 PGSR0_REDONE,
90                 PGSR0_REERR
91         },
92         {
93                 "Write Eye Training",
94                 PIR_WREYE,
95                 PGSR0_WEDONE,
96                 PGSR0_WEERR
97         }
98 };
99
100 int ddrphy_training(struct ddrphy __iomem *phy)
101 {
102         int i;
103         u32 pgsr0;
104         u32 init_flag = PIR_INIT;
105         u32 done_flag = PGSR0_IDONE;
106         int timeout = 50000; /* 50 msec is long enough */
107 #ifdef DISPLAY_ELAPSED_TIME
108         ulong start = get_timer(0);
109 #endif
110
111         for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
112                 init_flag |= init_sequence[i].init_flag;
113                 done_flag |= init_sequence[i].done_flag;
114         }
115
116         writel(init_flag, &phy->pir);
117
118         do {
119                 if (--timeout < 0) {
120                         printf("%s: error: timeout during DDR training\n",
121                                                                 __func__);
122                         return -ETIMEDOUT;
123                 }
124                 udelay(1);
125                 pgsr0 = readl(&phy->pgsr[0]);
126         } while ((pgsr0 & done_flag) != done_flag);
127
128         for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
129                 if (pgsr0 & init_sequence[i].err_flag) {
130                         printf("%s: error: %s failed\n", __func__,
131                                                 init_sequence[i].description);
132                         return -EIO;
133                 }
134         }
135
136 #ifdef DISPLAY_ELAPSED_TIME
137         printf("%s: info: elapsed time %ld msec\n", get_timer(start));
138 #endif
139
140         return 0;
141 }