133886693SMasahiro Yamada /*
26dd34ae4SMasahiro Yamada  * Copyright (C) 2011-2014 Panasonic Corporation
36dd34ae4SMasahiro Yamada  * Copyright (C) 2015-2016 Socionext Inc.
433886693SMasahiro Yamada  *
533886693SMasahiro Yamada  * SPDX-License-Identifier:	GPL-2.0+
633886693SMasahiro Yamada  */
733886693SMasahiro Yamada 
8*624c0954SMasahiro Yamada #include <linux/bitops.h>
9*624c0954SMasahiro Yamada #include <linux/delay.h>
100f4ec05bSMasahiro Yamada #include <linux/errno.h>
1133886693SMasahiro Yamada #include <linux/io.h>
12*624c0954SMasahiro Yamada #include <linux/kernel.h>
13*624c0954SMasahiro Yamada #include <linux/printk.h>
14*624c0954SMasahiro Yamada #include <time.h>
15107b3fb4SMasahiro Yamada 
166dd34ae4SMasahiro Yamada #include "ddrphy-init.h"
17107b3fb4SMasahiro Yamada #include "ddrphy-regs.h"
1833886693SMasahiro Yamada 
19adf55f63SMasahiro Yamada /* for LD4, Pro4, sLD8 */
20adf55f63SMasahiro Yamada #define NR_DATX8_PER_DDRPHY	2
21adf55f63SMasahiro Yamada 
226dd34ae4SMasahiro Yamada void ddrphy_prepare_training(void __iomem *phy_base, int rank)
2333886693SMasahiro Yamada {
246dd34ae4SMasahiro Yamada 	void __iomem *dx_base = phy_base + PHY_DX_BASE;
2533886693SMasahiro Yamada 	int dx;
266dd34ae4SMasahiro Yamada 	u32 tmp;
2733886693SMasahiro Yamada 
2833886693SMasahiro Yamada 	for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
296dd34ae4SMasahiro Yamada 		tmp = readl(dx_base + PHY_DX_GCR);
3033886693SMasahiro Yamada 		/* Specify the rank that should be write leveled */
316dd34ae4SMasahiro Yamada 		tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
326dd34ae4SMasahiro Yamada 		tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
336dd34ae4SMasahiro Yamada 			PHY_DX_GCR_WLRKEN_MASK;
346dd34ae4SMasahiro Yamada 		writel(tmp, dx_base + PHY_DX_GCR);
356dd34ae4SMasahiro Yamada 		dx_base += PHY_DX_STRIDE;
3633886693SMasahiro Yamada 	}
3733886693SMasahiro Yamada 
386dd34ae4SMasahiro Yamada 	tmp = readl(phy_base + PHY_DTCR);
3933886693SMasahiro Yamada 	/* Specify the rank used during data bit deskew and eye centering */
406dd34ae4SMasahiro Yamada 	tmp &= ~PHY_DTCR_DTRANK_MASK;
416dd34ae4SMasahiro Yamada 	tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
4233886693SMasahiro Yamada 	/* Use Multi-Purpose Register for DQS gate training */
436dd34ae4SMasahiro Yamada 	tmp |= PHY_DTCR_DTMPR;
4433886693SMasahiro Yamada 	/* Specify the rank enabled for data-training */
456dd34ae4SMasahiro Yamada 	tmp &= ~PHY_DTCR_RANKEN_MASK;
466dd34ae4SMasahiro Yamada 	tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
476dd34ae4SMasahiro Yamada 	writel(tmp, phy_base + PHY_DTCR);
4833886693SMasahiro Yamada }
4933886693SMasahiro Yamada 
5033886693SMasahiro Yamada struct ddrphy_init_sequence {
5133886693SMasahiro Yamada 	char *description;
5233886693SMasahiro Yamada 	u32 init_flag;
5333886693SMasahiro Yamada 	u32 done_flag;
5433886693SMasahiro Yamada 	u32 err_flag;
5533886693SMasahiro Yamada };
5633886693SMasahiro Yamada 
5733886693SMasahiro Yamada static const struct ddrphy_init_sequence init_sequence[] = {
5833886693SMasahiro Yamada 	{
5933886693SMasahiro Yamada 		"DRAM Initialization",
606dd34ae4SMasahiro Yamada 		PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
616dd34ae4SMasahiro Yamada 		PHY_PGSR0_DIDONE,
626dd34ae4SMasahiro Yamada 		PHY_PGSR0_DIERR
6333886693SMasahiro Yamada 	},
6433886693SMasahiro Yamada 	{
6533886693SMasahiro Yamada 		"Write Leveling",
666dd34ae4SMasahiro Yamada 		PHY_PIR_WL,
676dd34ae4SMasahiro Yamada 		PHY_PGSR0_WLDONE,
686dd34ae4SMasahiro Yamada 		PHY_PGSR0_WLERR
6933886693SMasahiro Yamada 	},
7033886693SMasahiro Yamada 	{
7133886693SMasahiro Yamada 		"Read DQS Gate Training",
726dd34ae4SMasahiro Yamada 		PHY_PIR_QSGATE,
736dd34ae4SMasahiro Yamada 		PHY_PGSR0_QSGDONE,
746dd34ae4SMasahiro Yamada 		PHY_PGSR0_QSGERR
7533886693SMasahiro Yamada 	},
7633886693SMasahiro Yamada 	{
7733886693SMasahiro Yamada 		"Write Leveling Adjustment",
786dd34ae4SMasahiro Yamada 		PHY_PIR_WLADJ,
796dd34ae4SMasahiro Yamada 		PHY_PGSR0_WLADONE,
806dd34ae4SMasahiro Yamada 		PHY_PGSR0_WLAERR
8133886693SMasahiro Yamada 	},
8233886693SMasahiro Yamada 	{
8333886693SMasahiro Yamada 		"Read Bit Deskew",
846dd34ae4SMasahiro Yamada 		PHY_PIR_RDDSKW,
856dd34ae4SMasahiro Yamada 		PHY_PGSR0_RDDONE,
866dd34ae4SMasahiro Yamada 		PHY_PGSR0_RDERR
8733886693SMasahiro Yamada 	},
8833886693SMasahiro Yamada 	{
8933886693SMasahiro Yamada 		"Write Bit Deskew",
906dd34ae4SMasahiro Yamada 		PHY_PIR_WRDSKW,
916dd34ae4SMasahiro Yamada 		PHY_PGSR0_WDDONE,
926dd34ae4SMasahiro Yamada 		PHY_PGSR0_WDERR
9333886693SMasahiro Yamada 	},
9433886693SMasahiro Yamada 	{
9533886693SMasahiro Yamada 		"Read Eye Training",
966dd34ae4SMasahiro Yamada 		PHY_PIR_RDEYE,
976dd34ae4SMasahiro Yamada 		PHY_PGSR0_REDONE,
986dd34ae4SMasahiro Yamada 		PHY_PGSR0_REERR
9933886693SMasahiro Yamada 	},
10033886693SMasahiro Yamada 	{
10133886693SMasahiro Yamada 		"Write Eye Training",
1026dd34ae4SMasahiro Yamada 		PHY_PIR_WREYE,
1036dd34ae4SMasahiro Yamada 		PHY_PGSR0_WEDONE,
1046dd34ae4SMasahiro Yamada 		PHY_PGSR0_WEERR
10533886693SMasahiro Yamada 	}
10633886693SMasahiro Yamada };
10733886693SMasahiro Yamada 
1086dd34ae4SMasahiro Yamada int ddrphy_training(void __iomem *phy_base)
10933886693SMasahiro Yamada {
11033886693SMasahiro Yamada 	int i;
11133886693SMasahiro Yamada 	u32 pgsr0;
1126dd34ae4SMasahiro Yamada 	u32 init_flag = PHY_PIR_INIT;
1136dd34ae4SMasahiro Yamada 	u32 done_flag = PHY_PGSR0_IDONE;
11433886693SMasahiro Yamada 	int timeout = 50000; /* 50 msec is long enough */
115*624c0954SMasahiro Yamada #ifdef DEBUG
11633886693SMasahiro Yamada 	ulong start = get_timer(0);
11733886693SMasahiro Yamada #endif
11833886693SMasahiro Yamada 
11933886693SMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
12033886693SMasahiro Yamada 		init_flag |= init_sequence[i].init_flag;
12133886693SMasahiro Yamada 		done_flag |= init_sequence[i].done_flag;
12233886693SMasahiro Yamada 	}
12333886693SMasahiro Yamada 
1246dd34ae4SMasahiro Yamada 	writel(init_flag, phy_base + PHY_PIR);
12533886693SMasahiro Yamada 
12633886693SMasahiro Yamada 	do {
12733886693SMasahiro Yamada 		if (--timeout < 0) {
128*624c0954SMasahiro Yamada 			pr_err("timeout during DDR training\n");
12933886693SMasahiro Yamada 			return -ETIMEDOUT;
13033886693SMasahiro Yamada 		}
13133886693SMasahiro Yamada 		udelay(1);
1326dd34ae4SMasahiro Yamada 		pgsr0 = readl(phy_base + PHY_PGSR0);
13333886693SMasahiro Yamada 	} while ((pgsr0 & done_flag) != done_flag);
13433886693SMasahiro Yamada 
13533886693SMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
13633886693SMasahiro Yamada 		if (pgsr0 & init_sequence[i].err_flag) {
137*624c0954SMasahiro Yamada 			pr_err("%s failed\n", init_sequence[i].description);
13833886693SMasahiro Yamada 			return -EIO;
13933886693SMasahiro Yamada 		}
14033886693SMasahiro Yamada 	}
14133886693SMasahiro Yamada 
142*624c0954SMasahiro Yamada #ifdef DEBUG
143*624c0954SMasahiro Yamada 	pr_debug("DDR training: elapsed time %ld msec\n", get_timer(start));
14433886693SMasahiro Yamada #endif
14533886693SMasahiro Yamada 
14633886693SMasahiro Yamada 	return 0;
14733886693SMasahiro Yamada }
148