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
833886693SMasahiro Yamada #include <common.h>
9*0f4ec05bSMasahiro Yamada #include <linux/errno.h>
1033886693SMasahiro Yamada #include <linux/io.h>
11107b3fb4SMasahiro Yamada
126dd34ae4SMasahiro Yamada #include "ddrphy-init.h"
13107b3fb4SMasahiro Yamada #include "ddrphy-regs.h"
1433886693SMasahiro Yamada
15adf55f63SMasahiro Yamada /* for LD4, Pro4, sLD8 */
16adf55f63SMasahiro Yamada #define NR_DATX8_PER_DDRPHY 2
17adf55f63SMasahiro Yamada
ddrphy_prepare_training(void __iomem * phy_base,int rank)186dd34ae4SMasahiro Yamada void ddrphy_prepare_training(void __iomem *phy_base, int rank)
1933886693SMasahiro Yamada {
206dd34ae4SMasahiro Yamada void __iomem *dx_base = phy_base + PHY_DX_BASE;
2133886693SMasahiro Yamada int dx;
226dd34ae4SMasahiro Yamada u32 tmp;
2333886693SMasahiro Yamada
2433886693SMasahiro Yamada for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
256dd34ae4SMasahiro Yamada tmp = readl(dx_base + PHY_DX_GCR);
2633886693SMasahiro Yamada /* Specify the rank that should be write leveled */
276dd34ae4SMasahiro Yamada tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
286dd34ae4SMasahiro Yamada tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
296dd34ae4SMasahiro Yamada PHY_DX_GCR_WLRKEN_MASK;
306dd34ae4SMasahiro Yamada writel(tmp, dx_base + PHY_DX_GCR);
316dd34ae4SMasahiro Yamada dx_base += PHY_DX_STRIDE;
3233886693SMasahiro Yamada }
3333886693SMasahiro Yamada
346dd34ae4SMasahiro Yamada tmp = readl(phy_base + PHY_DTCR);
3533886693SMasahiro Yamada /* Specify the rank used during data bit deskew and eye centering */
366dd34ae4SMasahiro Yamada tmp &= ~PHY_DTCR_DTRANK_MASK;
376dd34ae4SMasahiro Yamada tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
3833886693SMasahiro Yamada /* Use Multi-Purpose Register for DQS gate training */
396dd34ae4SMasahiro Yamada tmp |= PHY_DTCR_DTMPR;
4033886693SMasahiro Yamada /* Specify the rank enabled for data-training */
416dd34ae4SMasahiro Yamada tmp &= ~PHY_DTCR_RANKEN_MASK;
426dd34ae4SMasahiro Yamada tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
436dd34ae4SMasahiro Yamada writel(tmp, phy_base + PHY_DTCR);
4433886693SMasahiro Yamada }
4533886693SMasahiro Yamada
4633886693SMasahiro Yamada struct ddrphy_init_sequence {
4733886693SMasahiro Yamada char *description;
4833886693SMasahiro Yamada u32 init_flag;
4933886693SMasahiro Yamada u32 done_flag;
5033886693SMasahiro Yamada u32 err_flag;
5133886693SMasahiro Yamada };
5233886693SMasahiro Yamada
5333886693SMasahiro Yamada static const struct ddrphy_init_sequence init_sequence[] = {
5433886693SMasahiro Yamada {
5533886693SMasahiro Yamada "DRAM Initialization",
566dd34ae4SMasahiro Yamada PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
576dd34ae4SMasahiro Yamada PHY_PGSR0_DIDONE,
586dd34ae4SMasahiro Yamada PHY_PGSR0_DIERR
5933886693SMasahiro Yamada },
6033886693SMasahiro Yamada {
6133886693SMasahiro Yamada "Write Leveling",
626dd34ae4SMasahiro Yamada PHY_PIR_WL,
636dd34ae4SMasahiro Yamada PHY_PGSR0_WLDONE,
646dd34ae4SMasahiro Yamada PHY_PGSR0_WLERR
6533886693SMasahiro Yamada },
6633886693SMasahiro Yamada {
6733886693SMasahiro Yamada "Read DQS Gate Training",
686dd34ae4SMasahiro Yamada PHY_PIR_QSGATE,
696dd34ae4SMasahiro Yamada PHY_PGSR0_QSGDONE,
706dd34ae4SMasahiro Yamada PHY_PGSR0_QSGERR
7133886693SMasahiro Yamada },
7233886693SMasahiro Yamada {
7333886693SMasahiro Yamada "Write Leveling Adjustment",
746dd34ae4SMasahiro Yamada PHY_PIR_WLADJ,
756dd34ae4SMasahiro Yamada PHY_PGSR0_WLADONE,
766dd34ae4SMasahiro Yamada PHY_PGSR0_WLAERR
7733886693SMasahiro Yamada },
7833886693SMasahiro Yamada {
7933886693SMasahiro Yamada "Read Bit Deskew",
806dd34ae4SMasahiro Yamada PHY_PIR_RDDSKW,
816dd34ae4SMasahiro Yamada PHY_PGSR0_RDDONE,
826dd34ae4SMasahiro Yamada PHY_PGSR0_RDERR
8333886693SMasahiro Yamada },
8433886693SMasahiro Yamada {
8533886693SMasahiro Yamada "Write Bit Deskew",
866dd34ae4SMasahiro Yamada PHY_PIR_WRDSKW,
876dd34ae4SMasahiro Yamada PHY_PGSR0_WDDONE,
886dd34ae4SMasahiro Yamada PHY_PGSR0_WDERR
8933886693SMasahiro Yamada },
9033886693SMasahiro Yamada {
9133886693SMasahiro Yamada "Read Eye Training",
926dd34ae4SMasahiro Yamada PHY_PIR_RDEYE,
936dd34ae4SMasahiro Yamada PHY_PGSR0_REDONE,
946dd34ae4SMasahiro Yamada PHY_PGSR0_REERR
9533886693SMasahiro Yamada },
9633886693SMasahiro Yamada {
9733886693SMasahiro Yamada "Write Eye Training",
986dd34ae4SMasahiro Yamada PHY_PIR_WREYE,
996dd34ae4SMasahiro Yamada PHY_PGSR0_WEDONE,
1006dd34ae4SMasahiro Yamada PHY_PGSR0_WEERR
10133886693SMasahiro Yamada }
10233886693SMasahiro Yamada };
10333886693SMasahiro Yamada
ddrphy_training(void __iomem * phy_base)1046dd34ae4SMasahiro Yamada int ddrphy_training(void __iomem *phy_base)
10533886693SMasahiro Yamada {
10633886693SMasahiro Yamada int i;
10733886693SMasahiro Yamada u32 pgsr0;
1086dd34ae4SMasahiro Yamada u32 init_flag = PHY_PIR_INIT;
1096dd34ae4SMasahiro Yamada u32 done_flag = PHY_PGSR0_IDONE;
11033886693SMasahiro Yamada int timeout = 50000; /* 50 msec is long enough */
11133886693SMasahiro Yamada #ifdef DISPLAY_ELAPSED_TIME
11233886693SMasahiro Yamada ulong start = get_timer(0);
11333886693SMasahiro Yamada #endif
11433886693SMasahiro Yamada
11533886693SMasahiro Yamada for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
11633886693SMasahiro Yamada init_flag |= init_sequence[i].init_flag;
11733886693SMasahiro Yamada done_flag |= init_sequence[i].done_flag;
11833886693SMasahiro Yamada }
11933886693SMasahiro Yamada
1206dd34ae4SMasahiro Yamada writel(init_flag, phy_base + PHY_PIR);
12133886693SMasahiro Yamada
12233886693SMasahiro Yamada do {
12333886693SMasahiro Yamada if (--timeout < 0) {
12433886693SMasahiro Yamada printf("%s: error: timeout during DDR training\n",
12533886693SMasahiro Yamada __func__);
12633886693SMasahiro Yamada return -ETIMEDOUT;
12733886693SMasahiro Yamada }
12833886693SMasahiro Yamada udelay(1);
1296dd34ae4SMasahiro Yamada pgsr0 = readl(phy_base + PHY_PGSR0);
13033886693SMasahiro Yamada } while ((pgsr0 & done_flag) != done_flag);
13133886693SMasahiro Yamada
13233886693SMasahiro Yamada for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
13333886693SMasahiro Yamada if (pgsr0 & init_sequence[i].err_flag) {
13433886693SMasahiro Yamada printf("%s: error: %s failed\n", __func__,
13533886693SMasahiro Yamada init_sequence[i].description);
13633886693SMasahiro Yamada return -EIO;
13733886693SMasahiro Yamada }
13833886693SMasahiro Yamada }
13933886693SMasahiro Yamada
14033886693SMasahiro Yamada #ifdef DISPLAY_ELAPSED_TIME
14133886693SMasahiro Yamada printf("%s: info: elapsed time %ld msec\n", get_timer(start));
14233886693SMasahiro Yamada #endif
14333886693SMasahiro Yamada
14433886693SMasahiro Yamada return 0;
14533886693SMasahiro Yamada }
146