]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/mach-uniphier/ddrphy_training.c
ARM: UniPhier: replace <asm/io.h> with <linux/io.h>
[karo-tx-uboot.git] / arch / arm / mach-uniphier / 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/io.h>
9 #include <mach/ddrphy-regs.h>
10
11 void 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
40 struct ddrphy_init_sequence {
41         char *description;
42         u32 init_flag;
43         u32 done_flag;
44         u32 err_flag;
45 };
46
47 static 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
98 int 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) {
118 #ifndef CONFIG_SPL_BUILD
119                         printf("%s: error: timeout during DDR training\n",
120                                                                 __func__);
121 #endif
122                         return -1;
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 #ifndef CONFIG_SPL_BUILD
131                         printf("%s: error: %s failed\n", __func__,
132                                                 init_sequence[i].description);
133 #endif
134                         return -1;
135                 }
136         }
137
138 #ifdef DISPLAY_ELAPSED_TIME
139         printf("%s: info: elapsed time %ld msec\n", get_timer(start));
140 #endif
141
142         return 0;
143 }