blob: 1decdf1cbff50de581fb764483f52995c060f66d [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Masahiro Yamadab614e162014-12-19 20:20:52 +09002/*
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +09003 * Copyright (C) 2011-2014 Panasonic Corporation
4 * Copyright (C) 2015-2016 Socionext Inc.
Masahiro Yamadab614e162014-12-19 20:20:52 +09005 */
6
Masahiro Yamada624c0952017-10-23 00:19:36 +09007#include <linux/bitops.h>
8#include <linux/delay.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 Yamada624c0952017-10-23 00:19:36 +090011#include <linux/kernel.h>
12#include <linux/printk.h>
13#include <time.h>
Masahiro Yamada107b3fb2016-01-09 01:51:13 +090014
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090015#include "ddrphy-init.h"
Masahiro Yamada107b3fb2016-01-09 01:51:13 +090016#include "ddrphy-regs.h"
Masahiro Yamadab614e162014-12-19 20:20:52 +090017
Masahiro Yamadaadf55f62016-10-27 23:47:08 +090018/* for LD4, Pro4, sLD8 */
19#define NR_DATX8_PER_DDRPHY 2
20
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090021void ddrphy_prepare_training(void __iomem *phy_base, int rank)
Masahiro Yamadab614e162014-12-19 20:20:52 +090022{
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090023 void __iomem *dx_base = phy_base + PHY_DX_BASE;
Masahiro Yamadab614e162014-12-19 20:20:52 +090024 int dx;
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090025 u32 tmp;
Masahiro Yamadab614e162014-12-19 20:20:52 +090026
27 for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090028 tmp = readl(dx_base + PHY_DX_GCR);
Masahiro Yamadab614e162014-12-19 20:20:52 +090029 /* Specify the rank that should be write leveled */
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090030 tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
31 tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
32 PHY_DX_GCR_WLRKEN_MASK;
33 writel(tmp, dx_base + PHY_DX_GCR);
34 dx_base += PHY_DX_STRIDE;
Masahiro Yamadab614e162014-12-19 20:20:52 +090035 }
36
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090037 tmp = readl(phy_base + PHY_DTCR);
Masahiro Yamadab614e162014-12-19 20:20:52 +090038 /* Specify the rank used during data bit deskew and eye centering */
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090039 tmp &= ~PHY_DTCR_DTRANK_MASK;
40 tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
Masahiro Yamadab614e162014-12-19 20:20:52 +090041 /* Use Multi-Purpose Register for DQS gate training */
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090042 tmp |= PHY_DTCR_DTMPR;
Masahiro Yamadab614e162014-12-19 20:20:52 +090043 /* Specify the rank enabled for data-training */
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090044 tmp &= ~PHY_DTCR_RANKEN_MASK;
45 tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
46 writel(tmp, phy_base + PHY_DTCR);
Masahiro Yamadab614e162014-12-19 20:20:52 +090047}
48
49struct ddrphy_init_sequence {
50 char *description;
51 u32 init_flag;
52 u32 done_flag;
53 u32 err_flag;
54};
55
Masahiro Yamadaa1c4bf82015-12-16 10:36:13 +090056static const struct ddrphy_init_sequence init_sequence[] = {
Masahiro Yamadab614e162014-12-19 20:20:52 +090057 {
58 "DRAM Initialization",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090059 PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
60 PHY_PGSR0_DIDONE,
61 PHY_PGSR0_DIERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090062 },
63 {
64 "Write Leveling",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090065 PHY_PIR_WL,
66 PHY_PGSR0_WLDONE,
67 PHY_PGSR0_WLERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090068 },
69 {
70 "Read DQS Gate Training",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090071 PHY_PIR_QSGATE,
72 PHY_PGSR0_QSGDONE,
73 PHY_PGSR0_QSGERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090074 },
75 {
76 "Write Leveling Adjustment",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090077 PHY_PIR_WLADJ,
78 PHY_PGSR0_WLADONE,
79 PHY_PGSR0_WLAERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090080 },
81 {
82 "Read Bit Deskew",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090083 PHY_PIR_RDDSKW,
84 PHY_PGSR0_RDDONE,
85 PHY_PGSR0_RDERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090086 },
87 {
88 "Write Bit Deskew",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090089 PHY_PIR_WRDSKW,
90 PHY_PGSR0_WDDONE,
91 PHY_PGSR0_WDERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090092 },
93 {
94 "Read Eye Training",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +090095 PHY_PIR_RDEYE,
96 PHY_PGSR0_REDONE,
97 PHY_PGSR0_REERR
Masahiro Yamadab614e162014-12-19 20:20:52 +090098 },
99 {
100 "Write Eye Training",
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +0900101 PHY_PIR_WREYE,
102 PHY_PGSR0_WEDONE,
103 PHY_PGSR0_WEERR
Masahiro Yamadab614e162014-12-19 20:20:52 +0900104 }
105};
106
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +0900107int ddrphy_training(void __iomem *phy_base)
Masahiro Yamadab614e162014-12-19 20:20:52 +0900108{
109 int i;
110 u32 pgsr0;
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +0900111 u32 init_flag = PHY_PIR_INIT;
112 u32 done_flag = PHY_PGSR0_IDONE;
Masahiro Yamadab614e162014-12-19 20:20:52 +0900113 int timeout = 50000; /* 50 msec is long enough */
Masahiro Yamada624c0952017-10-23 00:19:36 +0900114#ifdef DEBUG
Masahiro Yamadab614e162014-12-19 20:20:52 +0900115 ulong start = get_timer(0);
116#endif
117
118 for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
119 init_flag |= init_sequence[i].init_flag;
120 done_flag |= init_sequence[i].done_flag;
121 }
122
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +0900123 writel(init_flag, phy_base + PHY_PIR);
Masahiro Yamadab614e162014-12-19 20:20:52 +0900124
125 do {
126 if (--timeout < 0) {
Masahiro Yamada624c0952017-10-23 00:19:36 +0900127 pr_err("timeout during DDR training\n");
Masahiro Yamada6a9f6ba2015-12-16 10:50:26 +0900128 return -ETIMEDOUT;
Masahiro Yamadab614e162014-12-19 20:20:52 +0900129 }
130 udelay(1);
Masahiro Yamada6dd34ae2016-10-27 23:47:07 +0900131 pgsr0 = readl(phy_base + PHY_PGSR0);
Masahiro Yamadab614e162014-12-19 20:20:52 +0900132 } while ((pgsr0 & done_flag) != done_flag);
133
134 for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
135 if (pgsr0 & init_sequence[i].err_flag) {
Masahiro Yamada624c0952017-10-23 00:19:36 +0900136 pr_err("%s failed\n", init_sequence[i].description);
Masahiro Yamada6a9f6ba2015-12-16 10:50:26 +0900137 return -EIO;
Masahiro Yamadab614e162014-12-19 20:20:52 +0900138 }
139 }
140
Masahiro Yamada624c0952017-10-23 00:19:36 +0900141#ifdef DEBUG
142 pr_debug("DDR training: elapsed time %ld msec\n", get_timer(start));
Masahiro Yamadab614e162014-12-19 20:20:52 +0900143#endif
144
145 return 0;
146}