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