blob: fa29a430625a75beacd0a82a05b76cf1f9c661fe [file] [log] [blame]
Masahiro Yamadab614e162014-12-19 20:20:52 +09001/*
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +09002 * Copyright (C) 2011-2014 Panasonic Corporation
3 * Copyright (C) 2015-2016 Socionext Inc.
Masahiro Yamadab614e162014-12-19 20:20:52 +09004 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#include <common.h>
Masahiro Yamada0f4ec052017-01-21 18:05:24 +09009#include <linux/errno.h>
Masahiro Yamadaf6e7f072015-05-29 17:30:00 +090010#include <linux/io.h>
Masahiro Yamada107b3fb2016-01-09 01:51:13 +090011
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090012#include "ddrphy-init.h"
Masahiro Yamada107b3fb2016-01-09 01:51:13 +090013#include "ddrphy-regs.h"
Masahiro Yamadab614e162014-12-19 20:20:52 +090014
Masahiro Yamadaadf55f62016-10-27 23:47:08 +090015/* for LD4, Pro4, sLD8 */
16#define NR_DATX8_PER_DDRPHY 2
17
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090018void ddrphy_prepare_training(void __iomem *phy_base, int rank)
Masahiro Yamadab614e162014-12-19 20:20:52 +090019{
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090020 void __iomem *dx_base = phy_base + PHY_DX_BASE;
Masahiro Yamadab614e162014-12-19 20:20:52 +090021 int dx;
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090022 u32 tmp;
Masahiro Yamadab614e162014-12-19 20:20:52 +090023
24 for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090025 tmp = readl(dx_base + PHY_DX_GCR);
Masahiro Yamadab614e162014-12-19 20:20:52 +090026 /* Specify the rank that should be write leveled */
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090027 tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
28 tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
29 PHY_DX_GCR_WLRKEN_MASK;
30 writel(tmp, dx_base + PHY_DX_GCR);
31 dx_base += PHY_DX_STRIDE;
Masahiro Yamadab614e162014-12-19 20:20:52 +090032 }
33
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090034 tmp = readl(phy_base + PHY_DTCR);
Masahiro Yamadab614e162014-12-19 20:20:52 +090035 /* Specify the rank used during data bit deskew and eye centering */
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090036 tmp &= ~PHY_DTCR_DTRANK_MASK;
37 tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
Masahiro Yamadab614e162014-12-19 20:20:52 +090038 /* Use Multi-Purpose Register for DQS gate training */
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090039 tmp |= PHY_DTCR_DTMPR;
Masahiro Yamadab614e162014-12-19 20:20:52 +090040 /* Specify the rank enabled for data-training */
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090041 tmp &= ~PHY_DTCR_RANKEN_MASK;
42 tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
43 writel(tmp, phy_base + PHY_DTCR);
Masahiro Yamadab614e162014-12-19 20:20:52 +090044}
45
46struct ddrphy_init_sequence {
47 char *description;
48 u32 init_flag;
49 u32 done_flag;
50 u32 err_flag;
51};
52
Masahiro Yamadaa1c4bf82015-12-16 10:36:13 +090053static const struct ddrphy_init_sequence init_sequence[] = {
Masahiro Yamadab614e162014-12-19 20:20:52 +090054 {
55 "DRAM Initialization",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090056 PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
57 PHY_PGSR0_DIDONE,
58 PHY_PGSR0_DIERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090059 },
60 {
61 "Write Leveling",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090062 PHY_PIR_WL,
63 PHY_PGSR0_WLDONE,
64 PHY_PGSR0_WLERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090065 },
66 {
67 "Read DQS Gate Training",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090068 PHY_PIR_QSGATE,
69 PHY_PGSR0_QSGDONE,
70 PHY_PGSR0_QSGERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090071 },
72 {
73 "Write Leveling Adjustment",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090074 PHY_PIR_WLADJ,
75 PHY_PGSR0_WLADONE,
76 PHY_PGSR0_WLAERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090077 },
78 {
79 "Read Bit Deskew",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090080 PHY_PIR_RDDSKW,
81 PHY_PGSR0_RDDONE,
82 PHY_PGSR0_RDERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090083 },
84 {
85 "Write Bit Deskew",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090086 PHY_PIR_WRDSKW,
87 PHY_PGSR0_WDDONE,
88 PHY_PGSR0_WDERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090089 },
90 {
91 "Read Eye Training",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090092 PHY_PIR_RDEYE,
93 PHY_PGSR0_REDONE,
94 PHY_PGSR0_REERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090095 },
96 {
97 "Write Eye Training",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090098 PHY_PIR_WREYE,
99 PHY_PGSR0_WEDONE,
100 PHY_PGSR0_WEERR
Masahiro Yamadab614e162014-12-19 20:20:52 +0900101 }
102};
103
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +0900104int ddrphy_training(void __iomem *phy_base)
Masahiro Yamadab614e162014-12-19 20:20:52 +0900105{
106 int i;
107 u32 pgsr0;
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +0900108 u32 init_flag = PHY_PIR_INIT;
109 u32 done_flag = PHY_PGSR0_IDONE;
Masahiro Yamadab614e162014-12-19 20:20:52 +0900110 int timeout = 50000; /* 50 msec is long enough */
111#ifdef DISPLAY_ELAPSED_TIME
112 ulong start = get_timer(0);
113#endif
114
115 for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
116 init_flag |= init_sequence[i].init_flag;
117 done_flag |= init_sequence[i].done_flag;
118 }
119
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +0900120 writel(init_flag, phy_base + PHY_PIR);
Masahiro Yamadab614e162014-12-19 20:20:52 +0900121
122 do {
123 if (--timeout < 0) {
Masahiro Yamadab614e162014-12-19 20:20:52 +0900124 printf("%s: error: timeout during DDR training\n",
125 __func__);
Masahiro Yamada6a9f6ba2015-12-16 10:50:26 +0900126 return -ETIMEDOUT;
Masahiro Yamadab614e162014-12-19 20:20:52 +0900127 }
128 udelay(1);
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +0900129 pgsr0 = readl(phy_base + PHY_PGSR0);
Masahiro Yamadab614e162014-12-19 20:20:52 +0900130 } while ((pgsr0 & done_flag) != done_flag);
131
132 for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
133 if (pgsr0 & init_sequence[i].err_flag) {
Masahiro Yamadab614e162014-12-19 20:20:52 +0900134 printf("%s: error: %s failed\n", __func__,
135 init_sequence[i].description);
Masahiro Yamada6a9f6ba2015-12-16 10:50:26 +0900136 return -EIO;
Masahiro Yamadab614e162014-12-19 20:20:52 +0900137 }
138 }
139
140#ifdef DISPLAY_ELAPSED_TIME
141 printf("%s: info: elapsed time %ld msec\n", get_timer(start));
142#endif
143
144 return 0;
145}