blob: a561fad78dd1c0afafe791cf5dae670334f97a48 [file] [log] [blame]
Masahiro Yamada04191e52014-12-19 20:20:52 +09001/*
Masahiro Yamadab464ff92016-10-27 23:47:07 +09002 * Copyright (C) 2011-2014 Panasonic Corporation
3 * Copyright (C) 2015-2016 Socionext Inc.
Masahiro Yamada04191e52014-12-19 20:20:52 +09004 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#include <common.h>
Masahiro Yamada5f369212015-12-16 10:50:26 +09009#include <linux/err.h>
Masahiro Yamada663a23f2015-05-29 17:30:00 +090010#include <linux/io.h>
Masahiro Yamadaefdf3402016-01-09 01:51:13 +090011
Masahiro Yamadab464ff92016-10-27 23:47:07 +090012#include "ddrphy-init.h"
Masahiro Yamadaefdf3402016-01-09 01:51:13 +090013#include "ddrphy-regs.h"
Masahiro Yamada04191e52014-12-19 20:20:52 +090014
Masahiro Yamadab464ff92016-10-27 23:47:07 +090015void ddrphy_prepare_training(void __iomem *phy_base, int rank)
Masahiro Yamada04191e52014-12-19 20:20:52 +090016{
Masahiro Yamadab464ff92016-10-27 23:47:07 +090017 void __iomem *dx_base = phy_base + PHY_DX_BASE;
Masahiro Yamada04191e52014-12-19 20:20:52 +090018 int dx;
Masahiro Yamadab464ff92016-10-27 23:47:07 +090019 u32 tmp;
Masahiro Yamada04191e52014-12-19 20:20:52 +090020
21 for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
Masahiro Yamadab464ff92016-10-27 23:47:07 +090022 tmp = readl(dx_base + PHY_DX_GCR);
Masahiro Yamada04191e52014-12-19 20:20:52 +090023 /* Specify the rank that should be write leveled */
Masahiro Yamadab464ff92016-10-27 23:47:07 +090024 tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
25 tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
26 PHY_DX_GCR_WLRKEN_MASK;
27 writel(tmp, dx_base + PHY_DX_GCR);
28 dx_base += PHY_DX_STRIDE;
Masahiro Yamada04191e52014-12-19 20:20:52 +090029 }
30
Masahiro Yamadab464ff92016-10-27 23:47:07 +090031 tmp = readl(phy_base + PHY_DTCR);
Masahiro Yamada04191e52014-12-19 20:20:52 +090032 /* Specify the rank used during data bit deskew and eye centering */
Masahiro Yamadab464ff92016-10-27 23:47:07 +090033 tmp &= ~PHY_DTCR_DTRANK_MASK;
34 tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
Masahiro Yamada04191e52014-12-19 20:20:52 +090035 /* Use Multi-Purpose Register for DQS gate training */
Masahiro Yamadab464ff92016-10-27 23:47:07 +090036 tmp |= PHY_DTCR_DTMPR;
Masahiro Yamada04191e52014-12-19 20:20:52 +090037 /* Specify the rank enabled for data-training */
Masahiro Yamadab464ff92016-10-27 23:47:07 +090038 tmp &= ~PHY_DTCR_RANKEN_MASK;
39 tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
40 writel(tmp, phy_base + PHY_DTCR);
Masahiro Yamada04191e52014-12-19 20:20:52 +090041}
42
43struct ddrphy_init_sequence {
44 char *description;
45 u32 init_flag;
46 u32 done_flag;
47 u32 err_flag;
48};
49
Masahiro Yamadabe5b8472015-12-16 10:36:13 +090050static const struct ddrphy_init_sequence init_sequence[] = {
Masahiro Yamada04191e52014-12-19 20:20:52 +090051 {
52 "DRAM Initialization",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090053 PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
54 PHY_PGSR0_DIDONE,
55 PHY_PGSR0_DIERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090056 },
57 {
58 "Write Leveling",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090059 PHY_PIR_WL,
60 PHY_PGSR0_WLDONE,
61 PHY_PGSR0_WLERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090062 },
63 {
64 "Read DQS Gate Training",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090065 PHY_PIR_QSGATE,
66 PHY_PGSR0_QSGDONE,
67 PHY_PGSR0_QSGERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090068 },
69 {
70 "Write Leveling Adjustment",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090071 PHY_PIR_WLADJ,
72 PHY_PGSR0_WLADONE,
73 PHY_PGSR0_WLAERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090074 },
75 {
76 "Read Bit Deskew",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090077 PHY_PIR_RDDSKW,
78 PHY_PGSR0_RDDONE,
79 PHY_PGSR0_RDERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090080 },
81 {
82 "Write Bit Deskew",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090083 PHY_PIR_WRDSKW,
84 PHY_PGSR0_WDDONE,
85 PHY_PGSR0_WDERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090086 },
87 {
88 "Read Eye Training",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090089 PHY_PIR_RDEYE,
90 PHY_PGSR0_REDONE,
91 PHY_PGSR0_REERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090092 },
93 {
94 "Write Eye Training",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090095 PHY_PIR_WREYE,
96 PHY_PGSR0_WEDONE,
97 PHY_PGSR0_WEERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090098 }
99};
100
Masahiro Yamadab464ff92016-10-27 23:47:07 +0900101int ddrphy_training(void __iomem *phy_base)
Masahiro Yamada04191e52014-12-19 20:20:52 +0900102{
103 int i;
104 u32 pgsr0;
Masahiro Yamadab464ff92016-10-27 23:47:07 +0900105 u32 init_flag = PHY_PIR_INIT;
106 u32 done_flag = PHY_PGSR0_IDONE;
Masahiro Yamada04191e52014-12-19 20:20:52 +0900107 int timeout = 50000; /* 50 msec is long enough */
108#ifdef DISPLAY_ELAPSED_TIME
109 ulong start = get_timer(0);
110#endif
111
112 for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
113 init_flag |= init_sequence[i].init_flag;
114 done_flag |= init_sequence[i].done_flag;
115 }
116
Masahiro Yamadab464ff92016-10-27 23:47:07 +0900117 writel(init_flag, phy_base + PHY_PIR);
Masahiro Yamada04191e52014-12-19 20:20:52 +0900118
119 do {
120 if (--timeout < 0) {
Masahiro Yamada04191e52014-12-19 20:20:52 +0900121 printf("%s: error: timeout during DDR training\n",
122 __func__);
Masahiro Yamada5f369212015-12-16 10:50:26 +0900123 return -ETIMEDOUT;
Masahiro Yamada04191e52014-12-19 20:20:52 +0900124 }
125 udelay(1);
Masahiro Yamadab464ff92016-10-27 23:47:07 +0900126 pgsr0 = readl(phy_base + PHY_PGSR0);
Masahiro Yamada04191e52014-12-19 20:20:52 +0900127 } 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) {
Masahiro Yamada04191e52014-12-19 20:20:52 +0900131 printf("%s: error: %s failed\n", __func__,
132 init_sequence[i].description);
Masahiro Yamada5f369212015-12-16 10:50:26 +0900133 return -EIO;
Masahiro Yamada04191e52014-12-19 20:20:52 +0900134 }
135 }
136
137#ifdef DISPLAY_ELAPSED_TIME
138 printf("%s: info: elapsed time %ld msec\n", get_timer(start));
139#endif
140
141 return 0;
142}