1ea65c980SMasahiro Yamada /*
20f4ec05bSMasahiro Yamada * Copyright (C) 2015-2017 Socionext Inc.
30f4ec05bSMasahiro Yamada * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
4ea65c980SMasahiro Yamada *
5ea65c980SMasahiro Yamada * based on commit 21b6e480f92ccc38fe0502e3116411d6509d3bf2 of Diag by:
6ea65c980SMasahiro Yamada * Copyright (C) 2015 Socionext Inc.
7ea65c980SMasahiro Yamada *
8ea65c980SMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+
9ea65c980SMasahiro Yamada */
10ea65c980SMasahiro Yamada
11ea65c980SMasahiro Yamada #include <common.h>
120f4ec05bSMasahiro Yamada #include <linux/errno.h>
13ea65c980SMasahiro Yamada #include <linux/io.h>
14ea65c980SMasahiro Yamada #include <linux/sizes.h>
15ea65c980SMasahiro Yamada #include <asm/processor.h>
16ea65c980SMasahiro Yamada
17ea65c980SMasahiro Yamada #include "../init.h"
18ea65c980SMasahiro Yamada #include "../soc-info.h"
19ea65c980SMasahiro Yamada #include "ddrmphy-regs.h"
20ea65c980SMasahiro Yamada #include "umc-regs.h"
21ea65c980SMasahiro Yamada
22ea65c980SMasahiro Yamada #define DRAM_CH_NR 3
23ea65c980SMasahiro Yamada
24ea65c980SMasahiro Yamada enum dram_freq {
25ea65c980SMasahiro Yamada DRAM_FREQ_1866M,
26ea65c980SMasahiro Yamada DRAM_FREQ_2133M,
27ea65c980SMasahiro Yamada DRAM_FREQ_NR,
28ea65c980SMasahiro Yamada };
29ea65c980SMasahiro Yamada
30ea65c980SMasahiro Yamada enum dram_size {
31ea65c980SMasahiro Yamada DRAM_SZ_256M,
32ea65c980SMasahiro Yamada DRAM_SZ_512M,
33ea65c980SMasahiro Yamada DRAM_SZ_NR,
34ea65c980SMasahiro Yamada };
35ea65c980SMasahiro Yamada
36fada9eafSMasahiro Yamada /* PHY */
37ea65c980SMasahiro Yamada static u32 ddrphy_pgcr2[DRAM_FREQ_NR] = {0x00FC7E5D, 0x00FC90AB};
38ea65c980SMasahiro Yamada static u32 ddrphy_ptr0[DRAM_FREQ_NR] = {0x0EA09205, 0x10C0A6C6};
39ea65c980SMasahiro Yamada static u32 ddrphy_ptr1[DRAM_FREQ_NR] = {0x0DAC041B, 0x0FA104B1};
40ea65c980SMasahiro Yamada static u32 ddrphy_ptr3[DRAM_FREQ_NR] = {0x15171e45, 0x18182357};
41ea65c980SMasahiro Yamada static u32 ddrphy_ptr4[DRAM_FREQ_NR] = {0x0e9ad8e9, 0x10b34157};
42ea65c980SMasahiro Yamada static u32 ddrphy_dtpr0[DRAM_FREQ_NR] = {0x35a00d88, 0x39e40e88};
43ea65c980SMasahiro Yamada static u32 ddrphy_dtpr1[DRAM_FREQ_NR] = {0x2288cc2c, 0x228a04d0};
44ea65c980SMasahiro Yamada static u32 ddrphy_dtpr2[DRAM_FREQ_NR] = {0x50005e00, 0x50006a00};
45ea65c980SMasahiro Yamada static u32 ddrphy_dtpr3[DRAM_FREQ_NR] = {0x0010cb49, 0x0010ec89};
46ea65c980SMasahiro Yamada static u32 ddrphy_mr0[DRAM_FREQ_NR] = {0x00000115, 0x00000125};
47ea65c980SMasahiro Yamada static u32 ddrphy_mr2[DRAM_FREQ_NR] = {0x000002a0, 0x000002a8};
48ea65c980SMasahiro Yamada
49ea65c980SMasahiro Yamada /* dependent on package and board design */
50ea65c980SMasahiro Yamada static u32 ddrphy_acbdlr0[DRAM_CH_NR] = {0x0000000c, 0x0000000c, 0x00000009};
51ea65c980SMasahiro Yamada
52ea65c980SMasahiro Yamada /* DDR multiPHY */
ddrphy_get_rank(int dx)53ea65c980SMasahiro Yamada static inline int ddrphy_get_rank(int dx)
54ea65c980SMasahiro Yamada {
55ea65c980SMasahiro Yamada return dx / 2;
56ea65c980SMasahiro Yamada }
57ea65c980SMasahiro Yamada
ddrphy_fifo_reset(void __iomem * phy_base)58ea65c980SMasahiro Yamada static void ddrphy_fifo_reset(void __iomem *phy_base)
59ea65c980SMasahiro Yamada {
60ea65c980SMasahiro Yamada u32 tmp;
61ea65c980SMasahiro Yamada
62fada9eafSMasahiro Yamada tmp = readl(phy_base + MPHY_PGCR0);
63fada9eafSMasahiro Yamada tmp &= ~MPHY_PGCR0_PHYFRST;
64fada9eafSMasahiro Yamada writel(tmp, phy_base + MPHY_PGCR0);
65ea65c980SMasahiro Yamada
66ea65c980SMasahiro Yamada udelay(1);
67ea65c980SMasahiro Yamada
68fada9eafSMasahiro Yamada tmp |= MPHY_PGCR0_PHYFRST;
69fada9eafSMasahiro Yamada writel(tmp, phy_base + MPHY_PGCR0);
70ea65c980SMasahiro Yamada
71ea65c980SMasahiro Yamada udelay(1);
72ea65c980SMasahiro Yamada }
73ea65c980SMasahiro Yamada
ddrphy_vt_ctrl(void __iomem * phy_base,int enable)74ea65c980SMasahiro Yamada static void ddrphy_vt_ctrl(void __iomem *phy_base, int enable)
75ea65c980SMasahiro Yamada {
76ea65c980SMasahiro Yamada u32 tmp;
77ea65c980SMasahiro Yamada
78fada9eafSMasahiro Yamada tmp = readl(phy_base + MPHY_PGCR1);
79ea65c980SMasahiro Yamada
80ea65c980SMasahiro Yamada if (enable)
81fada9eafSMasahiro Yamada tmp &= ~MPHY_PGCR1_INHVT;
82ea65c980SMasahiro Yamada else
83fada9eafSMasahiro Yamada tmp |= MPHY_PGCR1_INHVT;
84ea65c980SMasahiro Yamada
85fada9eafSMasahiro Yamada writel(tmp, phy_base + MPHY_PGCR1);
86ea65c980SMasahiro Yamada
87ea65c980SMasahiro Yamada if (!enable) {
88fada9eafSMasahiro Yamada while (!(readl(phy_base + MPHY_PGSR1) & MPHY_PGSR1_VTSTOP))
89ea65c980SMasahiro Yamada cpu_relax();
90ea65c980SMasahiro Yamada }
91ea65c980SMasahiro Yamada }
92ea65c980SMasahiro Yamada
ddrphy_dqs_delay_fixup(void __iomem * phy_base,int nr_dx,int step)93ea65c980SMasahiro Yamada static void ddrphy_dqs_delay_fixup(void __iomem *phy_base, int nr_dx, int step)
94ea65c980SMasahiro Yamada {
95ea65c980SMasahiro Yamada int dx;
96ea65c980SMasahiro Yamada u32 lcdlr1, rdqsd;
97fada9eafSMasahiro Yamada void __iomem *dx_base = phy_base + MPHY_DX_BASE;
98ea65c980SMasahiro Yamada
99ea65c980SMasahiro Yamada ddrphy_vt_ctrl(phy_base, 0);
100ea65c980SMasahiro Yamada
101ea65c980SMasahiro Yamada for (dx = 0; dx < nr_dx; dx++) {
102fada9eafSMasahiro Yamada lcdlr1 = readl(dx_base + MPHY_DX_LCDLR1);
103ea65c980SMasahiro Yamada rdqsd = (lcdlr1 >> 8) & 0xff;
104ea65c980SMasahiro Yamada rdqsd = clamp(rdqsd + step, 0U, 0xffU);
105ea65c980SMasahiro Yamada lcdlr1 = (lcdlr1 & ~(0xff << 8)) | (rdqsd << 8);
106fada9eafSMasahiro Yamada writel(lcdlr1, dx_base + MPHY_DX_LCDLR1);
107fada9eafSMasahiro Yamada readl(dx_base + MPHY_DX_LCDLR1); /* relax */
108fada9eafSMasahiro Yamada dx_base += MPHY_DX_STRIDE;
109ea65c980SMasahiro Yamada }
110ea65c980SMasahiro Yamada
111ea65c980SMasahiro Yamada ddrphy_vt_ctrl(phy_base, 1);
112ea65c980SMasahiro Yamada }
113ea65c980SMasahiro Yamada
ddrphy_get_system_latency(void __iomem * phy_base,int width)114ea65c980SMasahiro Yamada static int ddrphy_get_system_latency(void __iomem *phy_base, int width)
115ea65c980SMasahiro Yamada {
116fada9eafSMasahiro Yamada void __iomem *dx_base = phy_base + MPHY_DX_BASE;
117ea65c980SMasahiro Yamada const int nr_dx = width / 8;
118ea65c980SMasahiro Yamada int dx, rank;
119ea65c980SMasahiro Yamada u32 gtr;
120ea65c980SMasahiro Yamada int dgsl, dgsl_min = INT_MAX, dgsl_max = 0;
121ea65c980SMasahiro Yamada
122ea65c980SMasahiro Yamada for (dx = 0; dx < nr_dx; dx++) {
123fada9eafSMasahiro Yamada gtr = readl(dx_base + MPHY_DX_GTR);
124ea65c980SMasahiro Yamada for (rank = 0; rank < 4; rank++) {
125ea65c980SMasahiro Yamada dgsl = gtr & 0x7;
126ea65c980SMasahiro Yamada /* if dgsl is zero, this rank was not trained. skip. */
127ea65c980SMasahiro Yamada if (dgsl) {
128ea65c980SMasahiro Yamada dgsl_min = min(dgsl_min, dgsl);
129ea65c980SMasahiro Yamada dgsl_max = max(dgsl_max, dgsl);
130ea65c980SMasahiro Yamada }
131ea65c980SMasahiro Yamada gtr >>= 3;
132ea65c980SMasahiro Yamada }
133fada9eafSMasahiro Yamada dx_base += MPHY_DX_STRIDE;
134ea65c980SMasahiro Yamada }
135ea65c980SMasahiro Yamada
136ea65c980SMasahiro Yamada if (dgsl_min != dgsl_max)
137ea65c980SMasahiro Yamada printf("DQS Gateing System Latencies are not all leveled.\n");
138ea65c980SMasahiro Yamada
139ea65c980SMasahiro Yamada return dgsl_max;
140ea65c980SMasahiro Yamada }
141ea65c980SMasahiro Yamada
ddrphy_init(void __iomem * phy_base,enum dram_freq freq,int width,int ch)142ea65c980SMasahiro Yamada static void ddrphy_init(void __iomem *phy_base, enum dram_freq freq, int width,
143ea65c980SMasahiro Yamada int ch)
144ea65c980SMasahiro Yamada {
145ea65c980SMasahiro Yamada u32 tmp;
146ea65c980SMasahiro Yamada void __iomem *zq_base, *dx_base;
147ea65c980SMasahiro Yamada int zq, dx;
148ea65c980SMasahiro Yamada int nr_dx;
149ea65c980SMasahiro Yamada
150ea65c980SMasahiro Yamada nr_dx = width / 8;
151ea65c980SMasahiro Yamada
152fada9eafSMasahiro Yamada writel(MPHY_PIR_ZCALBYP, phy_base + MPHY_PIR);
153ea65c980SMasahiro Yamada /*
154ea65c980SMasahiro Yamada * Disable RGLVT bit (Read DQS Gating LCDL Delay VT Compensation)
155ea65c980SMasahiro Yamada * to avoid read error issue.
156ea65c980SMasahiro Yamada */
157fada9eafSMasahiro Yamada writel(0x07d81e37, phy_base + MPHY_PGCR0);
158fada9eafSMasahiro Yamada writel(0x0200c4e0, phy_base + MPHY_PGCR1);
159ea65c980SMasahiro Yamada
160ea65c980SMasahiro Yamada tmp = ddrphy_pgcr2[freq];
161ea65c980SMasahiro Yamada if (width >= 32)
162fada9eafSMasahiro Yamada tmp |= MPHY_PGCR2_DUALCHN | MPHY_PGCR2_ACPDDC;
163fada9eafSMasahiro Yamada writel(tmp, phy_base + MPHY_PGCR2);
164ea65c980SMasahiro Yamada
165fada9eafSMasahiro Yamada writel(ddrphy_ptr0[freq], phy_base + MPHY_PTR0);
166fada9eafSMasahiro Yamada writel(ddrphy_ptr1[freq], phy_base + MPHY_PTR1);
167fada9eafSMasahiro Yamada writel(0x00083def, phy_base + MPHY_PTR2);
168fada9eafSMasahiro Yamada writel(ddrphy_ptr3[freq], phy_base + MPHY_PTR3);
169fada9eafSMasahiro Yamada writel(ddrphy_ptr4[freq], phy_base + MPHY_PTR4);
170ea65c980SMasahiro Yamada
171fada9eafSMasahiro Yamada writel(ddrphy_acbdlr0[ch], phy_base + MPHY_ACBDLR0);
172ea65c980SMasahiro Yamada
173fada9eafSMasahiro Yamada writel(0x55555555, phy_base + MPHY_ACIOCR1);
174fada9eafSMasahiro Yamada writel(0x00000000, phy_base + MPHY_ACIOCR2);
175fada9eafSMasahiro Yamada writel(0x55555555, phy_base + MPHY_ACIOCR3);
176fada9eafSMasahiro Yamada writel(0x00000000, phy_base + MPHY_ACIOCR4);
177fada9eafSMasahiro Yamada writel(0x00000055, phy_base + MPHY_ACIOCR5);
178fada9eafSMasahiro Yamada writel(0x00181aa4, phy_base + MPHY_DXCCR);
179ea65c980SMasahiro Yamada
180fada9eafSMasahiro Yamada writel(0x0024641e, phy_base + MPHY_DSGCR);
181fada9eafSMasahiro Yamada writel(0x0000040b, phy_base + MPHY_DCR);
182fada9eafSMasahiro Yamada writel(ddrphy_dtpr0[freq], phy_base + MPHY_DTPR0);
183fada9eafSMasahiro Yamada writel(ddrphy_dtpr1[freq], phy_base + MPHY_DTPR1);
184fada9eafSMasahiro Yamada writel(ddrphy_dtpr2[freq], phy_base + MPHY_DTPR2);
185fada9eafSMasahiro Yamada writel(ddrphy_dtpr3[freq], phy_base + MPHY_DTPR3);
186fada9eafSMasahiro Yamada writel(ddrphy_mr0[freq], phy_base + MPHY_MR0);
187fada9eafSMasahiro Yamada writel(0x00000006, phy_base + MPHY_MR1);
188fada9eafSMasahiro Yamada writel(ddrphy_mr2[freq], phy_base + MPHY_MR2);
189fada9eafSMasahiro Yamada writel(0x00000000, phy_base + MPHY_MR3);
190ea65c980SMasahiro Yamada
191ea65c980SMasahiro Yamada tmp = 0;
192ea65c980SMasahiro Yamada for (dx = 0; dx < nr_dx; dx++)
193fada9eafSMasahiro Yamada tmp |= BIT(MPHY_DTCR_RANKEN_SHIFT + ddrphy_get_rank(dx));
194fada9eafSMasahiro Yamada writel(0x90003087 | tmp, phy_base + MPHY_DTCR);
195ea65c980SMasahiro Yamada
196fada9eafSMasahiro Yamada writel(0x00000000, phy_base + MPHY_DTAR0);
197fada9eafSMasahiro Yamada writel(0x00000008, phy_base + MPHY_DTAR1);
198fada9eafSMasahiro Yamada writel(0x00000010, phy_base + MPHY_DTAR2);
199fada9eafSMasahiro Yamada writel(0x00000018, phy_base + MPHY_DTAR3);
200fada9eafSMasahiro Yamada writel(0xdd22ee11, phy_base + MPHY_DTDR0);
201fada9eafSMasahiro Yamada writel(0x7788bb44, phy_base + MPHY_DTDR1);
202ea65c980SMasahiro Yamada
203ea65c980SMasahiro Yamada /* impedance control settings */
204fada9eafSMasahiro Yamada writel(0x04048900, phy_base + MPHY_ZQCR);
205ea65c980SMasahiro Yamada
206fada9eafSMasahiro Yamada zq_base = phy_base + MPHY_ZQ_BASE;
207ea65c980SMasahiro Yamada for (zq = 0; zq < 4; zq++) {
208ea65c980SMasahiro Yamada /*
209ea65c980SMasahiro Yamada * board-dependent
210ea65c980SMasahiro Yamada * PXS2: CH0ZQ0=0x5B, CH1ZQ0=0x5B, CH2ZQ0=0x59, others=0x5D
211ea65c980SMasahiro Yamada */
212fada9eafSMasahiro Yamada writel(0x0007BB5D, zq_base + MPHY_ZQ_PR);
213fada9eafSMasahiro Yamada zq_base += MPHY_ZQ_STRIDE;
214ea65c980SMasahiro Yamada }
215ea65c980SMasahiro Yamada
216ea65c980SMasahiro Yamada /* DATX8 settings */
217fada9eafSMasahiro Yamada dx_base = phy_base + MPHY_DX_BASE;
218ea65c980SMasahiro Yamada for (dx = 0; dx < 4; dx++) {
219fada9eafSMasahiro Yamada tmp = readl(dx_base + MPHY_DX_GCR0);
220fada9eafSMasahiro Yamada tmp &= ~MPHY_DX_GCR0_WLRKEN_MASK;
221fada9eafSMasahiro Yamada tmp |= BIT(MPHY_DX_GCR0_WLRKEN_SHIFT + ddrphy_get_rank(dx)) &
222fada9eafSMasahiro Yamada MPHY_DX_GCR0_WLRKEN_MASK;
223fada9eafSMasahiro Yamada writel(tmp, dx_base + MPHY_DX_GCR0);
224ea65c980SMasahiro Yamada
225fada9eafSMasahiro Yamada writel(0x00000000, dx_base + MPHY_DX_GCR1);
226fada9eafSMasahiro Yamada writel(0x00000000, dx_base + MPHY_DX_GCR2);
227fada9eafSMasahiro Yamada writel(0x00000000, dx_base + MPHY_DX_GCR3);
228fada9eafSMasahiro Yamada dx_base += MPHY_DX_STRIDE;
229ea65c980SMasahiro Yamada }
230ea65c980SMasahiro Yamada
231fada9eafSMasahiro Yamada while (!(readl(phy_base + MPHY_PGSR0) & MPHY_PGSR0_IDONE))
232ea65c980SMasahiro Yamada cpu_relax();
233ea65c980SMasahiro Yamada
234ea65c980SMasahiro Yamada ddrphy_dqs_delay_fixup(phy_base, nr_dx, -4);
235ea65c980SMasahiro Yamada }
236ea65c980SMasahiro Yamada
237ea65c980SMasahiro Yamada struct ddrphy_init_sequence {
238ea65c980SMasahiro Yamada char *description;
239ea65c980SMasahiro Yamada u32 init_flag;
240ea65c980SMasahiro Yamada u32 done_flag;
241ea65c980SMasahiro Yamada u32 err_flag;
242ea65c980SMasahiro Yamada };
243ea65c980SMasahiro Yamada
244ea65c980SMasahiro Yamada static const struct ddrphy_init_sequence impedance_calibration_sequence[] = {
245ea65c980SMasahiro Yamada {
246ea65c980SMasahiro Yamada "Impedance Calibration",
247fada9eafSMasahiro Yamada MPHY_PIR_ZCAL,
248fada9eafSMasahiro Yamada MPHY_PGSR0_ZCDONE,
249fada9eafSMasahiro Yamada MPHY_PGSR0_ZCERR,
250ea65c980SMasahiro Yamada },
251ea65c980SMasahiro Yamada { /* sentinel */ }
252ea65c980SMasahiro Yamada };
253ea65c980SMasahiro Yamada
254ea65c980SMasahiro Yamada static const struct ddrphy_init_sequence dram_init_sequence[] = {
255ea65c980SMasahiro Yamada {
256ea65c980SMasahiro Yamada "DRAM Initialization",
257fada9eafSMasahiro Yamada MPHY_PIR_DRAMRST | MPHY_PIR_DRAMINIT,
258fada9eafSMasahiro Yamada MPHY_PGSR0_DIDONE,
259ea65c980SMasahiro Yamada 0,
260ea65c980SMasahiro Yamada },
261ea65c980SMasahiro Yamada { /* sentinel */ }
262ea65c980SMasahiro Yamada };
263ea65c980SMasahiro Yamada
264ea65c980SMasahiro Yamada static const struct ddrphy_init_sequence training_sequence[] = {
265ea65c980SMasahiro Yamada {
266ea65c980SMasahiro Yamada "Write Leveling",
267fada9eafSMasahiro Yamada MPHY_PIR_WL,
268fada9eafSMasahiro Yamada MPHY_PGSR0_WLDONE,
269fada9eafSMasahiro Yamada MPHY_PGSR0_WLERR,
270ea65c980SMasahiro Yamada },
271ea65c980SMasahiro Yamada {
272ea65c980SMasahiro Yamada "Read DQS Gate Training",
273fada9eafSMasahiro Yamada MPHY_PIR_QSGATE,
274fada9eafSMasahiro Yamada MPHY_PGSR0_QSGDONE,
275fada9eafSMasahiro Yamada MPHY_PGSR0_QSGERR,
276ea65c980SMasahiro Yamada },
277ea65c980SMasahiro Yamada {
278ea65c980SMasahiro Yamada "Write Leveling Adjustment",
279fada9eafSMasahiro Yamada MPHY_PIR_WLADJ,
280fada9eafSMasahiro Yamada MPHY_PGSR0_WLADONE,
281fada9eafSMasahiro Yamada MPHY_PGSR0_WLAERR,
282ea65c980SMasahiro Yamada },
283ea65c980SMasahiro Yamada {
284ea65c980SMasahiro Yamada "Read Bit Deskew",
285fada9eafSMasahiro Yamada MPHY_PIR_RDDSKW,
286fada9eafSMasahiro Yamada MPHY_PGSR0_RDDONE,
287fada9eafSMasahiro Yamada MPHY_PGSR0_RDERR,
288ea65c980SMasahiro Yamada },
289ea65c980SMasahiro Yamada {
290ea65c980SMasahiro Yamada "Write Bit Deskew",
291fada9eafSMasahiro Yamada MPHY_PIR_WRDSKW,
292fada9eafSMasahiro Yamada MPHY_PGSR0_WDDONE,
293fada9eafSMasahiro Yamada MPHY_PGSR0_WDERR,
294ea65c980SMasahiro Yamada },
295ea65c980SMasahiro Yamada {
296ea65c980SMasahiro Yamada "Read Eye Training",
297fada9eafSMasahiro Yamada MPHY_PIR_RDEYE,
298fada9eafSMasahiro Yamada MPHY_PGSR0_REDONE,
299fada9eafSMasahiro Yamada MPHY_PGSR0_REERR,
300ea65c980SMasahiro Yamada },
301ea65c980SMasahiro Yamada {
302ea65c980SMasahiro Yamada "Write Eye Training",
303fada9eafSMasahiro Yamada MPHY_PIR_WREYE,
304fada9eafSMasahiro Yamada MPHY_PGSR0_WEDONE,
305fada9eafSMasahiro Yamada MPHY_PGSR0_WEERR,
306ea65c980SMasahiro Yamada },
307ea65c980SMasahiro Yamada { /* sentinel */ }
308ea65c980SMasahiro Yamada };
309ea65c980SMasahiro Yamada
__ddrphy_training(void __iomem * phy_base,const struct ddrphy_init_sequence * seq)310ea65c980SMasahiro Yamada static int __ddrphy_training(void __iomem *phy_base,
311ea65c980SMasahiro Yamada const struct ddrphy_init_sequence *seq)
312ea65c980SMasahiro Yamada {
313ea65c980SMasahiro Yamada const struct ddrphy_init_sequence *s;
314ea65c980SMasahiro Yamada u32 pgsr0;
315fada9eafSMasahiro Yamada u32 init_flag = MPHY_PIR_INIT;
316fada9eafSMasahiro Yamada u32 done_flag = MPHY_PGSR0_IDONE;
317ea65c980SMasahiro Yamada int timeout = 50000; /* 50 msec is long enough */
318ea65c980SMasahiro Yamada #ifdef DISPLAY_ELAPSED_TIME
319ea65c980SMasahiro Yamada ulong start = get_timer(0);
320ea65c980SMasahiro Yamada #endif
321ea65c980SMasahiro Yamada
322ea65c980SMasahiro Yamada for (s = seq; s->description; s++) {
323ea65c980SMasahiro Yamada init_flag |= s->init_flag;
324ea65c980SMasahiro Yamada done_flag |= s->done_flag;
325ea65c980SMasahiro Yamada }
326ea65c980SMasahiro Yamada
327fada9eafSMasahiro Yamada writel(init_flag, phy_base + MPHY_PIR);
328ea65c980SMasahiro Yamada
329ea65c980SMasahiro Yamada do {
330ea65c980SMasahiro Yamada if (--timeout < 0) {
331ea65c980SMasahiro Yamada pr_err("%s: error: timeout during DDR training\n",
332ea65c980SMasahiro Yamada __func__);
333ea65c980SMasahiro Yamada return -ETIMEDOUT;
334ea65c980SMasahiro Yamada }
335ea65c980SMasahiro Yamada udelay(1);
336fada9eafSMasahiro Yamada pgsr0 = readl(phy_base + MPHY_PGSR0);
337ea65c980SMasahiro Yamada } while ((pgsr0 & done_flag) != done_flag);
338ea65c980SMasahiro Yamada
339ea65c980SMasahiro Yamada for (s = seq; s->description; s++) {
340ea65c980SMasahiro Yamada if (pgsr0 & s->err_flag) {
341ea65c980SMasahiro Yamada pr_err("%s: error: %s failed\n", __func__,
342ea65c980SMasahiro Yamada s->description);
343ea65c980SMasahiro Yamada return -EIO;
344ea65c980SMasahiro Yamada }
345ea65c980SMasahiro Yamada }
346ea65c980SMasahiro Yamada
347ea65c980SMasahiro Yamada #ifdef DISPLAY_ELAPSED_TIME
348ea65c980SMasahiro Yamada printf("%s: info: elapsed time %ld msec\n", get_timer(start));
349ea65c980SMasahiro Yamada #endif
350ea65c980SMasahiro Yamada
351ea65c980SMasahiro Yamada return 0;
352ea65c980SMasahiro Yamada }
353ea65c980SMasahiro Yamada
ddrphy_impedance_calibration(void __iomem * phy_base)354ea65c980SMasahiro Yamada static int ddrphy_impedance_calibration(void __iomem *phy_base)
355ea65c980SMasahiro Yamada {
356ea65c980SMasahiro Yamada int ret;
357ea65c980SMasahiro Yamada u32 tmp;
358ea65c980SMasahiro Yamada
359ea65c980SMasahiro Yamada ret = __ddrphy_training(phy_base, impedance_calibration_sequence);
360ea65c980SMasahiro Yamada if (ret)
361ea65c980SMasahiro Yamada return ret;
362ea65c980SMasahiro Yamada
363ea65c980SMasahiro Yamada /*
364ea65c980SMasahiro Yamada * Because of a hardware bug, IDONE flag is set when the first ZQ block
365ea65c980SMasahiro Yamada * is calibrated. The flag does not guarantee the completion for all
366ea65c980SMasahiro Yamada * the ZQ blocks. Wait a little more just in case.
367ea65c980SMasahiro Yamada */
368ea65c980SMasahiro Yamada udelay(1);
369ea65c980SMasahiro Yamada
370ea65c980SMasahiro Yamada /* reflect ZQ settings and enable average algorithm*/
371fada9eafSMasahiro Yamada tmp = readl(phy_base + MPHY_ZQCR);
372fada9eafSMasahiro Yamada tmp |= MPHY_ZQCR_FORCE_ZCAL_VT_UPDATE;
373fada9eafSMasahiro Yamada writel(tmp, phy_base + MPHY_ZQCR);
374fada9eafSMasahiro Yamada tmp &= ~MPHY_ZQCR_FORCE_ZCAL_VT_UPDATE;
375fada9eafSMasahiro Yamada tmp |= MPHY_ZQCR_AVGEN;
376fada9eafSMasahiro Yamada writel(tmp, phy_base + MPHY_ZQCR);
377ea65c980SMasahiro Yamada
378ea65c980SMasahiro Yamada return 0;
379ea65c980SMasahiro Yamada }
380ea65c980SMasahiro Yamada
ddrphy_dram_init(void __iomem * phy_base)381ea65c980SMasahiro Yamada static int ddrphy_dram_init(void __iomem *phy_base)
382ea65c980SMasahiro Yamada {
383ea65c980SMasahiro Yamada return __ddrphy_training(phy_base, dram_init_sequence);
384ea65c980SMasahiro Yamada }
385ea65c980SMasahiro Yamada
ddrphy_training(void __iomem * phy_base)386ea65c980SMasahiro Yamada static int ddrphy_training(void __iomem *phy_base)
387ea65c980SMasahiro Yamada {
388ea65c980SMasahiro Yamada return __ddrphy_training(phy_base, training_sequence);
389ea65c980SMasahiro Yamada }
390ea65c980SMasahiro Yamada
391ea65c980SMasahiro Yamada /* UMC */
392fada9eafSMasahiro Yamada static u32 umc_cmdctla[DRAM_FREQ_NR] = {0x66DD131D, 0x77EE1722};
393fada9eafSMasahiro Yamada /*
394fada9eafSMasahiro Yamada * The ch2 is a different generation UMC core.
395fada9eafSMasahiro Yamada * The register spec is different, unfortunately.
396fada9eafSMasahiro Yamada */
397fada9eafSMasahiro Yamada static u32 umc_cmdctlb_ch01[DRAM_FREQ_NR] = {0x13E87C44, 0x18F88C44};
398fada9eafSMasahiro Yamada static u32 umc_cmdctlb_ch2[DRAM_FREQ_NR] = {0x19E8DC44, 0x1EF8EC44};
399fada9eafSMasahiro Yamada static u32 umc_spcctla[DRAM_FREQ_NR][DRAM_SZ_NR] = {
400fada9eafSMasahiro Yamada {0x004A071D, 0x0078071D},
401fada9eafSMasahiro Yamada {0x0055081E, 0x0089081E},
402fada9eafSMasahiro Yamada };
403fada9eafSMasahiro Yamada
404fada9eafSMasahiro Yamada static u32 umc_spcctlb[] = {0x00FF000A, 0x00FF000B};
405fada9eafSMasahiro Yamada /* The ch2 is different for some reason only hardware guys know... */
406fada9eafSMasahiro Yamada static u32 umc_flowctla_ch01[] = {0x0800001E, 0x08000022};
407fada9eafSMasahiro Yamada static u32 umc_flowctla_ch2[] = {0x0800001E, 0x0800001E};
408fada9eafSMasahiro Yamada
umc_set_system_latency(void __iomem * dc_base,int phy_latency)409ea65c980SMasahiro Yamada static void umc_set_system_latency(void __iomem *dc_base, int phy_latency)
410ea65c980SMasahiro Yamada {
411ea65c980SMasahiro Yamada u32 val;
412ea65c980SMasahiro Yamada int latency;
413ea65c980SMasahiro Yamada
414ea65c980SMasahiro Yamada val = readl(dc_base + UMC_RDATACTL_D0);
415ea65c980SMasahiro Yamada latency = (val & UMC_RDATACTL_RADLTY_MASK) >> UMC_RDATACTL_RADLTY_SHIFT;
416ea65c980SMasahiro Yamada latency += (val & UMC_RDATACTL_RAD2LTY_MASK) >>
417ea65c980SMasahiro Yamada UMC_RDATACTL_RAD2LTY_SHIFT;
418ea65c980SMasahiro Yamada /*
419ea65c980SMasahiro Yamada * UMC works at the half clock rate of the PHY.
420ea65c980SMasahiro Yamada * The LSB of latency is ignored
421ea65c980SMasahiro Yamada */
422ea65c980SMasahiro Yamada latency += phy_latency & ~1;
423ea65c980SMasahiro Yamada
424ea65c980SMasahiro Yamada val &= ~(UMC_RDATACTL_RADLTY_MASK | UMC_RDATACTL_RAD2LTY_MASK);
425ea65c980SMasahiro Yamada if (latency > 0xf) {
426ea65c980SMasahiro Yamada val |= 0xf << UMC_RDATACTL_RADLTY_SHIFT;
427ea65c980SMasahiro Yamada val |= (latency - 0xf) << UMC_RDATACTL_RAD2LTY_SHIFT;
428ea65c980SMasahiro Yamada } else {
429ea65c980SMasahiro Yamada val |= latency << UMC_RDATACTL_RADLTY_SHIFT;
430ea65c980SMasahiro Yamada }
431ea65c980SMasahiro Yamada
432ea65c980SMasahiro Yamada writel(val, dc_base + UMC_RDATACTL_D0);
433ea65c980SMasahiro Yamada writel(val, dc_base + UMC_RDATACTL_D1);
434ea65c980SMasahiro Yamada
435ea65c980SMasahiro Yamada readl(dc_base + UMC_RDATACTL_D1); /* relax */
436ea65c980SMasahiro Yamada }
437ea65c980SMasahiro Yamada
438ea65c980SMasahiro Yamada /* enable/disable auto refresh */
umc_refresh_ctrl(void __iomem * dc_base,int enable)439*1d21e1b9SMasahiro Yamada static void umc_refresh_ctrl(void __iomem *dc_base, int enable)
440ea65c980SMasahiro Yamada {
441ea65c980SMasahiro Yamada u32 tmp;
442ea65c980SMasahiro Yamada
443ea65c980SMasahiro Yamada tmp = readl(dc_base + UMC_SPCSETB);
444ea65c980SMasahiro Yamada tmp &= ~UMC_SPCSETB_AREFMD_MASK;
445ea65c980SMasahiro Yamada
446ea65c980SMasahiro Yamada if (enable)
447ea65c980SMasahiro Yamada tmp |= UMC_SPCSETB_AREFMD_ARB;
448ea65c980SMasahiro Yamada else
449ea65c980SMasahiro Yamada tmp |= UMC_SPCSETB_AREFMD_REG;
450ea65c980SMasahiro Yamada
451ea65c980SMasahiro Yamada writel(tmp, dc_base + UMC_SPCSETB);
452ea65c980SMasahiro Yamada udelay(1);
453ea65c980SMasahiro Yamada }
454ea65c980SMasahiro Yamada
umc_ud_init(void __iomem * umc_base,int ch)455ea65c980SMasahiro Yamada static void umc_ud_init(void __iomem *umc_base, int ch)
456ea65c980SMasahiro Yamada {
457ea65c980SMasahiro Yamada writel(0x00000003, umc_base + UMC_BITPERPIXELMODE_D0);
458ea65c980SMasahiro Yamada
459ea65c980SMasahiro Yamada if (ch == 2)
460ea65c980SMasahiro Yamada writel(0x00000033, umc_base + UMC_PAIR1DOFF_D0);
461ea65c980SMasahiro Yamada }
462ea65c980SMasahiro Yamada
umc_dc_init(void __iomem * dc_base,enum dram_freq freq,unsigned long size,int width,int ch)463ea65c980SMasahiro Yamada static int umc_dc_init(void __iomem *dc_base, enum dram_freq freq,
464ea65c980SMasahiro Yamada unsigned long size, int width, int ch)
465ea65c980SMasahiro Yamada {
466ea65c980SMasahiro Yamada enum dram_size size_e;
467ea65c980SMasahiro Yamada int latency;
468ea65c980SMasahiro Yamada u32 val;
469ea65c980SMasahiro Yamada
470ea65c980SMasahiro Yamada switch (size) {
471ea65c980SMasahiro Yamada case 0:
472ea65c980SMasahiro Yamada return 0;
473ea65c980SMasahiro Yamada case SZ_256M:
474ea65c980SMasahiro Yamada size_e = DRAM_SZ_256M;
475ea65c980SMasahiro Yamada break;
476ea65c980SMasahiro Yamada case SZ_512M:
477ea65c980SMasahiro Yamada size_e = DRAM_SZ_512M;
478ea65c980SMasahiro Yamada break;
479ea65c980SMasahiro Yamada default:
480ea65c980SMasahiro Yamada pr_err("unsupported DRAM size 0x%08lx (per 16bit) for ch%d\n",
481ea65c980SMasahiro Yamada size, ch);
482ea65c980SMasahiro Yamada return -EINVAL;
483ea65c980SMasahiro Yamada }
484ea65c980SMasahiro Yamada
485ea65c980SMasahiro Yamada writel(umc_cmdctla[freq], dc_base + UMC_CMDCTLA);
486ea65c980SMasahiro Yamada
487ea65c980SMasahiro Yamada writel(ch == 2 ? umc_cmdctlb_ch2[freq] : umc_cmdctlb_ch01[freq],
488ea65c980SMasahiro Yamada dc_base + UMC_CMDCTLB);
489ea65c980SMasahiro Yamada
490ea65c980SMasahiro Yamada writel(umc_spcctla[freq][size_e], dc_base + UMC_SPCCTLA);
491ea65c980SMasahiro Yamada writel(umc_spcctlb[freq], dc_base + UMC_SPCCTLB);
492ea65c980SMasahiro Yamada
493ea65c980SMasahiro Yamada val = 0x000e000e;
494ea65c980SMasahiro Yamada latency = 12;
495ea65c980SMasahiro Yamada /* ES2 inserted one more FF to the logic. */
496ea65c980SMasahiro Yamada if (uniphier_get_soc_model() >= 2)
497ea65c980SMasahiro Yamada latency += 2;
498ea65c980SMasahiro Yamada
499ea65c980SMasahiro Yamada if (latency > 0xf) {
500ea65c980SMasahiro Yamada val |= 0xf << UMC_RDATACTL_RADLTY_SHIFT;
501ea65c980SMasahiro Yamada val |= (latency - 0xf) << UMC_RDATACTL_RAD2LTY_SHIFT;
502ea65c980SMasahiro Yamada } else {
503ea65c980SMasahiro Yamada val |= latency << UMC_RDATACTL_RADLTY_SHIFT;
504ea65c980SMasahiro Yamada }
505ea65c980SMasahiro Yamada
506ea65c980SMasahiro Yamada writel(val, dc_base + UMC_RDATACTL_D0);
507ea65c980SMasahiro Yamada if (width >= 32)
508ea65c980SMasahiro Yamada writel(val, dc_base + UMC_RDATACTL_D1);
509ea65c980SMasahiro Yamada
510ea65c980SMasahiro Yamada writel(0x04060A02, dc_base + UMC_WDATACTL_D0);
511ea65c980SMasahiro Yamada if (width >= 32)
512ea65c980SMasahiro Yamada writel(0x04060A02, dc_base + UMC_WDATACTL_D1);
513ea65c980SMasahiro Yamada writel(0x04000000, dc_base + UMC_DATASET);
514ea65c980SMasahiro Yamada writel(0x00400020, dc_base + UMC_DCCGCTL);
515ea65c980SMasahiro Yamada writel(0x00000084, dc_base + UMC_FLOWCTLG);
516ea65c980SMasahiro Yamada writel(0x00000000, dc_base + UMC_ACSSETA);
517ea65c980SMasahiro Yamada
518ea65c980SMasahiro Yamada writel(ch == 2 ? umc_flowctla_ch2[freq] : umc_flowctla_ch01[freq],
519ea65c980SMasahiro Yamada dc_base + UMC_FLOWCTLA);
520ea65c980SMasahiro Yamada
521ea65c980SMasahiro Yamada writel(0x00004400, dc_base + UMC_FLOWCTLC);
522ea65c980SMasahiro Yamada writel(0x200A0A00, dc_base + UMC_SPCSETB);
523ea65c980SMasahiro Yamada writel(0x00000520, dc_base + UMC_DFICUPDCTLA);
524ea65c980SMasahiro Yamada writel(0x0000000D, dc_base + UMC_RESPCTL);
525ea65c980SMasahiro Yamada
526ea65c980SMasahiro Yamada if (ch != 2) {
527ea65c980SMasahiro Yamada writel(0x00202000, dc_base + UMC_FLOWCTLB);
528ea65c980SMasahiro Yamada writel(0xFDBFFFFF, dc_base + UMC_FLOWCTLOB0);
529ea65c980SMasahiro Yamada writel(0xFFFFFFFF, dc_base + UMC_FLOWCTLOB1);
530ea65c980SMasahiro Yamada writel(0x00080700, dc_base + UMC_BSICMAPSET);
531ea65c980SMasahiro Yamada } else {
532ea65c980SMasahiro Yamada writel(0x00200000, dc_base + UMC_FLOWCTLB);
533ea65c980SMasahiro Yamada writel(0x00000000, dc_base + UMC_BSICMAPSET);
534ea65c980SMasahiro Yamada }
535ea65c980SMasahiro Yamada
536ea65c980SMasahiro Yamada writel(0x00000000, dc_base + UMC_ERRMASKA);
537ea65c980SMasahiro Yamada writel(0x00000000, dc_base + UMC_ERRMASKB);
538ea65c980SMasahiro Yamada
539ea65c980SMasahiro Yamada return 0;
540ea65c980SMasahiro Yamada }
541ea65c980SMasahiro Yamada
umc_ch_init(void __iomem * umc_ch_base,enum dram_freq freq,unsigned long size,unsigned int width,int ch)542ea65c980SMasahiro Yamada static int umc_ch_init(void __iomem *umc_ch_base, enum dram_freq freq,
543ea65c980SMasahiro Yamada unsigned long size, unsigned int width, int ch)
544ea65c980SMasahiro Yamada {
545ea65c980SMasahiro Yamada void __iomem *dc_base = umc_ch_base + 0x00011000;
546ea65c980SMasahiro Yamada void __iomem *phy_base = umc_ch_base + 0x00030000;
547ea65c980SMasahiro Yamada int ret;
548ea65c980SMasahiro Yamada
549ea65c980SMasahiro Yamada writel(0x00000002, dc_base + UMC_INITSET);
550ea65c980SMasahiro Yamada while (readl(dc_base + UMC_INITSTAT) & BIT(2))
551ea65c980SMasahiro Yamada cpu_relax();
552ea65c980SMasahiro Yamada
553ea65c980SMasahiro Yamada /* deassert PHY reset signals */
554ea65c980SMasahiro Yamada writel(UMC_DIOCTLA_CTL_NRST | UMC_DIOCTLA_CFG_NRST,
555ea65c980SMasahiro Yamada dc_base + UMC_DIOCTLA);
556ea65c980SMasahiro Yamada
557ea65c980SMasahiro Yamada ddrphy_init(phy_base, freq, width, ch);
558ea65c980SMasahiro Yamada
559ea65c980SMasahiro Yamada ret = ddrphy_impedance_calibration(phy_base);
560ea65c980SMasahiro Yamada if (ret)
561ea65c980SMasahiro Yamada return ret;
562ea65c980SMasahiro Yamada
563ea65c980SMasahiro Yamada ddrphy_dram_init(phy_base);
564ea65c980SMasahiro Yamada if (ret)
565ea65c980SMasahiro Yamada return ret;
566ea65c980SMasahiro Yamada
567ea65c980SMasahiro Yamada ret = umc_dc_init(dc_base, freq, size, width, ch);
568ea65c980SMasahiro Yamada if (ret)
569ea65c980SMasahiro Yamada return ret;
570ea65c980SMasahiro Yamada
571ea65c980SMasahiro Yamada umc_ud_init(umc_ch_base, ch);
572ea65c980SMasahiro Yamada
573ea65c980SMasahiro Yamada ret = ddrphy_training(phy_base);
574ea65c980SMasahiro Yamada if (ret)
575ea65c980SMasahiro Yamada return ret;
576ea65c980SMasahiro Yamada
577ea65c980SMasahiro Yamada udelay(1);
578ea65c980SMasahiro Yamada
579ea65c980SMasahiro Yamada /* match the system latency between UMC and PHY */
580ea65c980SMasahiro Yamada umc_set_system_latency(dc_base,
581ea65c980SMasahiro Yamada ddrphy_get_system_latency(phy_base, width));
582ea65c980SMasahiro Yamada
583ea65c980SMasahiro Yamada udelay(1);
584ea65c980SMasahiro Yamada
585ea65c980SMasahiro Yamada /* stop auto refresh before clearing FIFO in PHY */
586ea65c980SMasahiro Yamada umc_refresh_ctrl(dc_base, 0);
587ea65c980SMasahiro Yamada ddrphy_fifo_reset(phy_base);
588ea65c980SMasahiro Yamada umc_refresh_ctrl(dc_base, 1);
589ea65c980SMasahiro Yamada
590ea65c980SMasahiro Yamada udelay(10);
591ea65c980SMasahiro Yamada
592ea65c980SMasahiro Yamada return 0;
593ea65c980SMasahiro Yamada }
594ea65c980SMasahiro Yamada
um_init(void __iomem * um_base)595ea65c980SMasahiro Yamada static void um_init(void __iomem *um_base)
596ea65c980SMasahiro Yamada {
597ea65c980SMasahiro Yamada writel(0x000000ff, um_base + UMC_MBUS0);
598ea65c980SMasahiro Yamada writel(0x000000ff, um_base + UMC_MBUS1);
599ea65c980SMasahiro Yamada writel(0x000000ff, um_base + UMC_MBUS2);
600ea65c980SMasahiro Yamada writel(0x000000ff, um_base + UMC_MBUS3);
601ea65c980SMasahiro Yamada }
602ea65c980SMasahiro Yamada
uniphier_pxs2_umc_init(const struct uniphier_board_data * bd)6035b660066SMasahiro Yamada int uniphier_pxs2_umc_init(const struct uniphier_board_data *bd)
604ea65c980SMasahiro Yamada {
605ea65c980SMasahiro Yamada void __iomem *um_base = (void __iomem *)0x5b600000;
606ea65c980SMasahiro Yamada void __iomem *umc_ch_base = (void __iomem *)0x5b800000;
607ea65c980SMasahiro Yamada enum dram_freq freq;
608ea65c980SMasahiro Yamada int ch, ret;
609ea65c980SMasahiro Yamada
610ea65c980SMasahiro Yamada switch (bd->dram_freq) {
611ea65c980SMasahiro Yamada case 1866:
612ea65c980SMasahiro Yamada freq = DRAM_FREQ_1866M;
613ea65c980SMasahiro Yamada break;
614ea65c980SMasahiro Yamada case 2133:
615ea65c980SMasahiro Yamada freq = DRAM_FREQ_2133M;
616ea65c980SMasahiro Yamada break;
617ea65c980SMasahiro Yamada default:
618ea65c980SMasahiro Yamada pr_err("unsupported DRAM frequency %d MHz\n", bd->dram_freq);
619ea65c980SMasahiro Yamada return -EINVAL;
620ea65c980SMasahiro Yamada }
621ea65c980SMasahiro Yamada
622dd38374dSMasahiro Yamada for (ch = 0; ch < DRAM_CH_NR; ch++) {
623ea65c980SMasahiro Yamada unsigned long size = bd->dram_ch[ch].size;
624ea65c980SMasahiro Yamada unsigned int width = bd->dram_ch[ch].width;
625ea65c980SMasahiro Yamada
626dd38374dSMasahiro Yamada if (size) {
627dd38374dSMasahiro Yamada ret = umc_ch_init(umc_ch_base, freq,
628dd38374dSMasahiro Yamada size / (width / 16), width, ch);
629ea65c980SMasahiro Yamada if (ret) {
630ea65c980SMasahiro Yamada pr_err("failed to initialize UMC ch%d\n", ch);
631ea65c980SMasahiro Yamada return ret;
632ea65c980SMasahiro Yamada }
633dd38374dSMasahiro Yamada }
634ea65c980SMasahiro Yamada
635ea65c980SMasahiro Yamada umc_ch_base += 0x00200000;
636ea65c980SMasahiro Yamada }
637ea65c980SMasahiro Yamada
638ea65c980SMasahiro Yamada um_init(um_base);
639ea65c980SMasahiro Yamada
640ea65c980SMasahiro Yamada return 0;
641ea65c980SMasahiro Yamada }
642