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