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