blob: c26f56367e08c89f687393bae4b93b5c149f905a [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Masahiro Yamada04191e52014-12-19 20:20:52 +09002/*
Masahiro Yamadab464ff92016-10-27 23:47:07 +09003 * Copyright (C) 2011-2014 Panasonic Corporation
4 * Copyright (C) 2015-2016 Socionext Inc.
Masahiro Yamada04191e52014-12-19 20:20:52 +09005 */
6
Simon Glass0f2af882020-05-10 11:40:05 -06007#include <log.h>
Masahiro Yamada4647aca2017-10-23 00:19:36 +09008#include <linux/bitops.h>
9#include <linux/delay.h>
Masahiro Yamadae4e789d2017-01-21 18:05:24 +090010#include <linux/errno.h>
Masahiro Yamada663a23f2015-05-29 17:30:00 +090011#include <linux/io.h>
Masahiro Yamada4647aca2017-10-23 00:19:36 +090012#include <linux/kernel.h>
13#include <linux/printk.h>
14#include <time.h>
Masahiro Yamadaefdf3402016-01-09 01:51:13 +090015
Masahiro Yamadab464ff92016-10-27 23:47:07 +090016#include "ddrphy-init.h"
Masahiro Yamadaefdf3402016-01-09 01:51:13 +090017#include "ddrphy-regs.h"
Masahiro Yamada04191e52014-12-19 20:20:52 +090018
Masahiro Yamada913b3d02016-10-27 23:47:08 +090019/* for LD4, Pro4, sLD8 */
20#define NR_DATX8_PER_DDRPHY 2
21
Masahiro Yamadab464ff92016-10-27 23:47:07 +090022void ddrphy_prepare_training(void __iomem *phy_base, int rank)
Masahiro Yamada04191e52014-12-19 20:20:52 +090023{
Masahiro Yamadab464ff92016-10-27 23:47:07 +090024 void __iomem *dx_base = phy_base + PHY_DX_BASE;
Masahiro Yamada04191e52014-12-19 20:20:52 +090025 int dx;
Masahiro Yamadab464ff92016-10-27 23:47:07 +090026 u32 tmp;
Masahiro Yamada04191e52014-12-19 20:20:52 +090027
28 for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
Masahiro Yamadab464ff92016-10-27 23:47:07 +090029 tmp = readl(dx_base + PHY_DX_GCR);
Masahiro Yamada04191e52014-12-19 20:20:52 +090030 /* Specify the rank that should be write leveled */
Masahiro Yamadab464ff92016-10-27 23:47:07 +090031 tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
32 tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
33 PHY_DX_GCR_WLRKEN_MASK;
34 writel(tmp, dx_base + PHY_DX_GCR);
35 dx_base += PHY_DX_STRIDE;
Masahiro Yamada04191e52014-12-19 20:20:52 +090036 }
37
Masahiro Yamadab464ff92016-10-27 23:47:07 +090038 tmp = readl(phy_base + PHY_DTCR);
Masahiro Yamada04191e52014-12-19 20:20:52 +090039 /* Specify the rank used during data bit deskew and eye centering */
Masahiro Yamadab464ff92016-10-27 23:47:07 +090040 tmp &= ~PHY_DTCR_DTRANK_MASK;
41 tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
Masahiro Yamada04191e52014-12-19 20:20:52 +090042 /* Use Multi-Purpose Register for DQS gate training */
Masahiro Yamadab464ff92016-10-27 23:47:07 +090043 tmp |= PHY_DTCR_DTMPR;
Masahiro Yamada04191e52014-12-19 20:20:52 +090044 /* Specify the rank enabled for data-training */
Masahiro Yamadab464ff92016-10-27 23:47:07 +090045 tmp &= ~PHY_DTCR_RANKEN_MASK;
46 tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
47 writel(tmp, phy_base + PHY_DTCR);
Masahiro Yamada04191e52014-12-19 20:20:52 +090048}
49
50struct ddrphy_init_sequence {
51 char *description;
52 u32 init_flag;
53 u32 done_flag;
54 u32 err_flag;
55};
56
Masahiro Yamadabe5b8472015-12-16 10:36:13 +090057static const struct ddrphy_init_sequence init_sequence[] = {
Masahiro Yamada04191e52014-12-19 20:20:52 +090058 {
59 "DRAM Initialization",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090060 PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
61 PHY_PGSR0_DIDONE,
62 PHY_PGSR0_DIERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090063 },
64 {
65 "Write Leveling",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090066 PHY_PIR_WL,
67 PHY_PGSR0_WLDONE,
68 PHY_PGSR0_WLERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090069 },
70 {
71 "Read DQS Gate Training",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090072 PHY_PIR_QSGATE,
73 PHY_PGSR0_QSGDONE,
74 PHY_PGSR0_QSGERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090075 },
76 {
77 "Write Leveling Adjustment",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090078 PHY_PIR_WLADJ,
79 PHY_PGSR0_WLADONE,
80 PHY_PGSR0_WLAERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090081 },
82 {
83 "Read Bit Deskew",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090084 PHY_PIR_RDDSKW,
85 PHY_PGSR0_RDDONE,
86 PHY_PGSR0_RDERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090087 },
88 {
89 "Write Bit Deskew",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090090 PHY_PIR_WRDSKW,
91 PHY_PGSR0_WDDONE,
92 PHY_PGSR0_WDERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090093 },
94 {
95 "Read Eye Training",
Masahiro Yamadab464ff92016-10-27 23:47:07 +090096 PHY_PIR_RDEYE,
97 PHY_PGSR0_REDONE,
98 PHY_PGSR0_REERR
Masahiro Yamada04191e52014-12-19 20:20:52 +090099 },
100 {
101 "Write Eye Training",
Masahiro Yamadab464ff92016-10-27 23:47:07 +0900102 PHY_PIR_WREYE,
103 PHY_PGSR0_WEDONE,
104 PHY_PGSR0_WEERR
Masahiro Yamada04191e52014-12-19 20:20:52 +0900105 }
106};
107
Masahiro Yamadab464ff92016-10-27 23:47:07 +0900108int ddrphy_training(void __iomem *phy_base)
Masahiro Yamada04191e52014-12-19 20:20:52 +0900109{
110 int i;
111 u32 pgsr0;
Masahiro Yamadab464ff92016-10-27 23:47:07 +0900112 u32 init_flag = PHY_PIR_INIT;
113 u32 done_flag = PHY_PGSR0_IDONE;
Masahiro Yamada04191e52014-12-19 20:20:52 +0900114 int timeout = 50000; /* 50 msec is long enough */
Masahiro Yamada4647aca2017-10-23 00:19:36 +0900115#ifdef DEBUG
Masahiro Yamada04191e52014-12-19 20:20:52 +0900116 ulong start = get_timer(0);
117#endif
118
119 for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
120 init_flag |= init_sequence[i].init_flag;
121 done_flag |= init_sequence[i].done_flag;
122 }
123
Masahiro Yamadab464ff92016-10-27 23:47:07 +0900124 writel(init_flag, phy_base + PHY_PIR);
Masahiro Yamada04191e52014-12-19 20:20:52 +0900125
126 do {
127 if (--timeout < 0) {
Masahiro Yamada4647aca2017-10-23 00:19:36 +0900128 pr_err("timeout during DDR training\n");
Masahiro Yamada5f369212015-12-16 10:50:26 +0900129 return -ETIMEDOUT;
Masahiro Yamada04191e52014-12-19 20:20:52 +0900130 }
131 udelay(1);
Masahiro Yamadab464ff92016-10-27 23:47:07 +0900132 pgsr0 = readl(phy_base + PHY_PGSR0);
Masahiro Yamada04191e52014-12-19 20:20:52 +0900133 } while ((pgsr0 & done_flag) != done_flag);
134
135 for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
136 if (pgsr0 & init_sequence[i].err_flag) {
Masahiro Yamada4647aca2017-10-23 00:19:36 +0900137 pr_err("%s failed\n", init_sequence[i].description);
Masahiro Yamada5f369212015-12-16 10:50:26 +0900138 return -EIO;
Masahiro Yamada04191e52014-12-19 20:20:52 +0900139 }
140 }
141
Masahiro Yamada4647aca2017-10-23 00:19:36 +0900142#ifdef DEBUG
143 pr_debug("DDR training: elapsed time %ld msec\n", get_timer(start));
Masahiro Yamada04191e52014-12-19 20:20:52 +0900144#endif
145
146 return 0;
147}