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