1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
233886693SMasahiro Yamada /*
36dd34ae4SMasahiro Yamada  * Copyright (C) 2011-2014 Panasonic Corporation
46dd34ae4SMasahiro Yamada  * Copyright (C) 2015-2016 Socionext Inc.
533886693SMasahiro Yamada  */
633886693SMasahiro Yamada 
7624c0954SMasahiro Yamada #include <linux/bitops.h>
8624c0954SMasahiro Yamada #include <linux/delay.h>
90f4ec05bSMasahiro Yamada #include <linux/errno.h>
1033886693SMasahiro Yamada #include <linux/io.h>
11624c0954SMasahiro Yamada #include <linux/kernel.h>
12624c0954SMasahiro Yamada #include <linux/printk.h>
13624c0954SMasahiro Yamada #include <time.h>
14107b3fb4SMasahiro Yamada 
156dd34ae4SMasahiro Yamada #include "ddrphy-init.h"
16107b3fb4SMasahiro Yamada #include "ddrphy-regs.h"
1733886693SMasahiro Yamada 
18adf55f63SMasahiro Yamada /* for LD4, Pro4, sLD8 */
19adf55f63SMasahiro Yamada #define NR_DATX8_PER_DDRPHY	2
20adf55f63SMasahiro Yamada 
ddrphy_prepare_training(void __iomem * phy_base,int rank)216dd34ae4SMasahiro Yamada void ddrphy_prepare_training(void __iomem *phy_base, int rank)
2233886693SMasahiro Yamada {
236dd34ae4SMasahiro Yamada 	void __iomem *dx_base = phy_base + PHY_DX_BASE;
2433886693SMasahiro Yamada 	int dx;
256dd34ae4SMasahiro Yamada 	u32 tmp;
2633886693SMasahiro Yamada 
2733886693SMasahiro Yamada 	for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
286dd34ae4SMasahiro Yamada 		tmp = readl(dx_base + PHY_DX_GCR);
2933886693SMasahiro Yamada 		/* Specify the rank that should be write leveled */
306dd34ae4SMasahiro Yamada 		tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
316dd34ae4SMasahiro Yamada 		tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
326dd34ae4SMasahiro Yamada 			PHY_DX_GCR_WLRKEN_MASK;
336dd34ae4SMasahiro Yamada 		writel(tmp, dx_base + PHY_DX_GCR);
346dd34ae4SMasahiro Yamada 		dx_base += PHY_DX_STRIDE;
3533886693SMasahiro Yamada 	}
3633886693SMasahiro Yamada 
376dd34ae4SMasahiro Yamada 	tmp = readl(phy_base + PHY_DTCR);
3833886693SMasahiro Yamada 	/* Specify the rank used during data bit deskew and eye centering */
396dd34ae4SMasahiro Yamada 	tmp &= ~PHY_DTCR_DTRANK_MASK;
406dd34ae4SMasahiro Yamada 	tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
4133886693SMasahiro Yamada 	/* Use Multi-Purpose Register for DQS gate training */
426dd34ae4SMasahiro Yamada 	tmp |= PHY_DTCR_DTMPR;
4333886693SMasahiro Yamada 	/* Specify the rank enabled for data-training */
446dd34ae4SMasahiro Yamada 	tmp &= ~PHY_DTCR_RANKEN_MASK;
456dd34ae4SMasahiro Yamada 	tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
466dd34ae4SMasahiro Yamada 	writel(tmp, phy_base + PHY_DTCR);
4733886693SMasahiro Yamada }
4833886693SMasahiro Yamada 
4933886693SMasahiro Yamada struct ddrphy_init_sequence {
5033886693SMasahiro Yamada 	char *description;
5133886693SMasahiro Yamada 	u32 init_flag;
5233886693SMasahiro Yamada 	u32 done_flag;
5333886693SMasahiro Yamada 	u32 err_flag;
5433886693SMasahiro Yamada };
5533886693SMasahiro Yamada 
5633886693SMasahiro Yamada static const struct ddrphy_init_sequence init_sequence[] = {
5733886693SMasahiro Yamada 	{
5833886693SMasahiro Yamada 		"DRAM Initialization",
596dd34ae4SMasahiro Yamada 		PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
606dd34ae4SMasahiro Yamada 		PHY_PGSR0_DIDONE,
616dd34ae4SMasahiro Yamada 		PHY_PGSR0_DIERR
6233886693SMasahiro Yamada 	},
6333886693SMasahiro Yamada 	{
6433886693SMasahiro Yamada 		"Write Leveling",
656dd34ae4SMasahiro Yamada 		PHY_PIR_WL,
666dd34ae4SMasahiro Yamada 		PHY_PGSR0_WLDONE,
676dd34ae4SMasahiro Yamada 		PHY_PGSR0_WLERR
6833886693SMasahiro Yamada 	},
6933886693SMasahiro Yamada 	{
7033886693SMasahiro Yamada 		"Read DQS Gate Training",
716dd34ae4SMasahiro Yamada 		PHY_PIR_QSGATE,
726dd34ae4SMasahiro Yamada 		PHY_PGSR0_QSGDONE,
736dd34ae4SMasahiro Yamada 		PHY_PGSR0_QSGERR
7433886693SMasahiro Yamada 	},
7533886693SMasahiro Yamada 	{
7633886693SMasahiro Yamada 		"Write Leveling Adjustment",
776dd34ae4SMasahiro Yamada 		PHY_PIR_WLADJ,
786dd34ae4SMasahiro Yamada 		PHY_PGSR0_WLADONE,
796dd34ae4SMasahiro Yamada 		PHY_PGSR0_WLAERR
8033886693SMasahiro Yamada 	},
8133886693SMasahiro Yamada 	{
8233886693SMasahiro Yamada 		"Read Bit Deskew",
836dd34ae4SMasahiro Yamada 		PHY_PIR_RDDSKW,
846dd34ae4SMasahiro Yamada 		PHY_PGSR0_RDDONE,
856dd34ae4SMasahiro Yamada 		PHY_PGSR0_RDERR
8633886693SMasahiro Yamada 	},
8733886693SMasahiro Yamada 	{
8833886693SMasahiro Yamada 		"Write Bit Deskew",
896dd34ae4SMasahiro Yamada 		PHY_PIR_WRDSKW,
906dd34ae4SMasahiro Yamada 		PHY_PGSR0_WDDONE,
916dd34ae4SMasahiro Yamada 		PHY_PGSR0_WDERR
9233886693SMasahiro Yamada 	},
9333886693SMasahiro Yamada 	{
9433886693SMasahiro Yamada 		"Read Eye Training",
956dd34ae4SMasahiro Yamada 		PHY_PIR_RDEYE,
966dd34ae4SMasahiro Yamada 		PHY_PGSR0_REDONE,
976dd34ae4SMasahiro Yamada 		PHY_PGSR0_REERR
9833886693SMasahiro Yamada 	},
9933886693SMasahiro Yamada 	{
10033886693SMasahiro Yamada 		"Write Eye Training",
1016dd34ae4SMasahiro Yamada 		PHY_PIR_WREYE,
1026dd34ae4SMasahiro Yamada 		PHY_PGSR0_WEDONE,
1036dd34ae4SMasahiro Yamada 		PHY_PGSR0_WEERR
10433886693SMasahiro Yamada 	}
10533886693SMasahiro Yamada };
10633886693SMasahiro Yamada 
ddrphy_training(void __iomem * phy_base)1076dd34ae4SMasahiro Yamada int ddrphy_training(void __iomem *phy_base)
10833886693SMasahiro Yamada {
10933886693SMasahiro Yamada 	int i;
11033886693SMasahiro Yamada 	u32 pgsr0;
1116dd34ae4SMasahiro Yamada 	u32 init_flag = PHY_PIR_INIT;
1126dd34ae4SMasahiro Yamada 	u32 done_flag = PHY_PGSR0_IDONE;
11333886693SMasahiro Yamada 	int timeout = 50000; /* 50 msec is long enough */
114624c0954SMasahiro Yamada #ifdef DEBUG
11533886693SMasahiro Yamada 	ulong start = get_timer(0);
11633886693SMasahiro Yamada #endif
11733886693SMasahiro Yamada 
11833886693SMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
11933886693SMasahiro Yamada 		init_flag |= init_sequence[i].init_flag;
12033886693SMasahiro Yamada 		done_flag |= init_sequence[i].done_flag;
12133886693SMasahiro Yamada 	}
12233886693SMasahiro Yamada 
1236dd34ae4SMasahiro Yamada 	writel(init_flag, phy_base + PHY_PIR);
12433886693SMasahiro Yamada 
12533886693SMasahiro Yamada 	do {
12633886693SMasahiro Yamada 		if (--timeout < 0) {
127624c0954SMasahiro Yamada 			pr_err("timeout during DDR training\n");
12833886693SMasahiro Yamada 			return -ETIMEDOUT;
12933886693SMasahiro Yamada 		}
13033886693SMasahiro Yamada 		udelay(1);
1316dd34ae4SMasahiro Yamada 		pgsr0 = readl(phy_base + PHY_PGSR0);
13233886693SMasahiro Yamada 	} while ((pgsr0 & done_flag) != done_flag);
13333886693SMasahiro Yamada 
13433886693SMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
13533886693SMasahiro Yamada 		if (pgsr0 & init_sequence[i].err_flag) {
136624c0954SMasahiro Yamada 			pr_err("%s failed\n", init_sequence[i].description);
13733886693SMasahiro Yamada 			return -EIO;
13833886693SMasahiro Yamada 		}
13933886693SMasahiro Yamada 	}
14033886693SMasahiro Yamada 
141624c0954SMasahiro Yamada #ifdef DEBUG
142624c0954SMasahiro Yamada 	pr_debug("DDR training: elapsed time %ld msec\n", get_timer(start));
14333886693SMasahiro Yamada #endif
14433886693SMasahiro Yamada 
14533886693SMasahiro Yamada 	return 0;
14633886693SMasahiro Yamada }
147