]> git.sur5r.net Git - u-boot/blob - arch/arm/mach-uniphier/dram/ddrphy-training.c
Merge git://git.denx.de/u-boot-fsl-qoriq
[u-boot] / arch / arm / mach-uniphier / dram / ddrphy-training.c
1 /*
2  * Copyright (C) 2011-2014 Panasonic Corporation
3  * Copyright (C) 2015-2016 Socionext Inc.
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <linux/errno.h>
10 #include <linux/io.h>
11
12 #include "ddrphy-init.h"
13 #include "ddrphy-regs.h"
14
15 /* for LD4, Pro4, sLD8 */
16 #define NR_DATX8_PER_DDRPHY     2
17
18 void ddrphy_prepare_training(void __iomem *phy_base, int rank)
19 {
20         void __iomem *dx_base = phy_base + PHY_DX_BASE;
21         int dx;
22         u32 tmp;
23
24         for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
25                 tmp = readl(dx_base + PHY_DX_GCR);
26                 /* Specify the rank that should be write leveled */
27                 tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
28                 tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
29                         PHY_DX_GCR_WLRKEN_MASK;
30                 writel(tmp, dx_base + PHY_DX_GCR);
31                 dx_base += PHY_DX_STRIDE;
32         }
33
34         tmp = readl(phy_base + PHY_DTCR);
35         /* Specify the rank used during data bit deskew and eye centering */
36         tmp &= ~PHY_DTCR_DTRANK_MASK;
37         tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
38         /* Use Multi-Purpose Register for DQS gate training */
39         tmp |= PHY_DTCR_DTMPR;
40         /* Specify the rank enabled for data-training */
41         tmp &= ~PHY_DTCR_RANKEN_MASK;
42         tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
43         writel(tmp, phy_base + PHY_DTCR);
44 }
45
46 struct ddrphy_init_sequence {
47         char *description;
48         u32 init_flag;
49         u32 done_flag;
50         u32 err_flag;
51 };
52
53 static const struct ddrphy_init_sequence init_sequence[] = {
54         {
55                 "DRAM Initialization",
56                 PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
57                 PHY_PGSR0_DIDONE,
58                 PHY_PGSR0_DIERR
59         },
60         {
61                 "Write Leveling",
62                 PHY_PIR_WL,
63                 PHY_PGSR0_WLDONE,
64                 PHY_PGSR0_WLERR
65         },
66         {
67                 "Read DQS Gate Training",
68                 PHY_PIR_QSGATE,
69                 PHY_PGSR0_QSGDONE,
70                 PHY_PGSR0_QSGERR
71         },
72         {
73                 "Write Leveling Adjustment",
74                 PHY_PIR_WLADJ,
75                 PHY_PGSR0_WLADONE,
76                 PHY_PGSR0_WLAERR
77         },
78         {
79                 "Read Bit Deskew",
80                 PHY_PIR_RDDSKW,
81                 PHY_PGSR0_RDDONE,
82                 PHY_PGSR0_RDERR
83         },
84         {
85                 "Write Bit Deskew",
86                 PHY_PIR_WRDSKW,
87                 PHY_PGSR0_WDDONE,
88                 PHY_PGSR0_WDERR
89         },
90         {
91                 "Read Eye Training",
92                 PHY_PIR_RDEYE,
93                 PHY_PGSR0_REDONE,
94                 PHY_PGSR0_REERR
95         },
96         {
97                 "Write Eye Training",
98                 PHY_PIR_WREYE,
99                 PHY_PGSR0_WEDONE,
100                 PHY_PGSR0_WEERR
101         }
102 };
103
104 int ddrphy_training(void __iomem *phy_base)
105 {
106         int i;
107         u32 pgsr0;
108         u32 init_flag = PHY_PIR_INIT;
109         u32 done_flag = PHY_PGSR0_IDONE;
110         int timeout = 50000; /* 50 msec is long enough */
111 #ifdef DISPLAY_ELAPSED_TIME
112         ulong start = get_timer(0);
113 #endif
114
115         for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
116                 init_flag |= init_sequence[i].init_flag;
117                 done_flag |= init_sequence[i].done_flag;
118         }
119
120         writel(init_flag, phy_base + PHY_PIR);
121
122         do {
123                 if (--timeout < 0) {
124                         printf("%s: error: timeout during DDR training\n",
125                                                                 __func__);
126                         return -ETIMEDOUT;
127                 }
128                 udelay(1);
129                 pgsr0 = readl(phy_base + PHY_PGSR0);
130         } while ((pgsr0 & done_flag) != done_flag);
131
132         for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
133                 if (pgsr0 & init_sequence[i].err_flag) {
134                         printf("%s: error: %s failed\n", __func__,
135                                                 init_sequence[i].description);
136                         return -EIO;
137                 }
138         }
139
140 #ifdef DISPLAY_ELAPSED_TIME
141         printf("%s: info: elapsed time %ld msec\n", get_timer(start));
142 #endif
143
144         return 0;
145 }