ddrphy-training.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2011-2014 Panasonic Corporation
  4. * Copyright (C) 2015-2016 Socionext Inc.
  5. */
  6. #include <linux/bitops.h>
  7. #include <linux/delay.h>
  8. #include <linux/errno.h>
  9. #include <linux/io.h>
  10. #include <linux/kernel.h>
  11. #include <linux/printk.h>
  12. #include <time.h>
  13. #include "ddrphy-init.h"
  14. #include "ddrphy-regs.h"
  15. /* for LD4, Pro4, sLD8 */
  16. #define NR_DATX8_PER_DDRPHY 2
  17. void ddrphy_prepare_training(void __iomem *phy_base, int rank)
  18. {
  19. void __iomem *dx_base = phy_base + PHY_DX_BASE;
  20. int dx;
  21. u32 tmp;
  22. for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
  23. tmp = readl(dx_base + PHY_DX_GCR);
  24. /* Specify the rank that should be write leveled */
  25. tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
  26. tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
  27. PHY_DX_GCR_WLRKEN_MASK;
  28. writel(tmp, dx_base + PHY_DX_GCR);
  29. dx_base += PHY_DX_STRIDE;
  30. }
  31. tmp = readl(phy_base + PHY_DTCR);
  32. /* Specify the rank used during data bit deskew and eye centering */
  33. tmp &= ~PHY_DTCR_DTRANK_MASK;
  34. tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
  35. /* Use Multi-Purpose Register for DQS gate training */
  36. tmp |= PHY_DTCR_DTMPR;
  37. /* Specify the rank enabled for data-training */
  38. tmp &= ~PHY_DTCR_RANKEN_MASK;
  39. tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
  40. writel(tmp, phy_base + PHY_DTCR);
  41. }
  42. struct ddrphy_init_sequence {
  43. char *description;
  44. u32 init_flag;
  45. u32 done_flag;
  46. u32 err_flag;
  47. };
  48. static const struct ddrphy_init_sequence init_sequence[] = {
  49. {
  50. "DRAM Initialization",
  51. PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
  52. PHY_PGSR0_DIDONE,
  53. PHY_PGSR0_DIERR
  54. },
  55. {
  56. "Write Leveling",
  57. PHY_PIR_WL,
  58. PHY_PGSR0_WLDONE,
  59. PHY_PGSR0_WLERR
  60. },
  61. {
  62. "Read DQS Gate Training",
  63. PHY_PIR_QSGATE,
  64. PHY_PGSR0_QSGDONE,
  65. PHY_PGSR0_QSGERR
  66. },
  67. {
  68. "Write Leveling Adjustment",
  69. PHY_PIR_WLADJ,
  70. PHY_PGSR0_WLADONE,
  71. PHY_PGSR0_WLAERR
  72. },
  73. {
  74. "Read Bit Deskew",
  75. PHY_PIR_RDDSKW,
  76. PHY_PGSR0_RDDONE,
  77. PHY_PGSR0_RDERR
  78. },
  79. {
  80. "Write Bit Deskew",
  81. PHY_PIR_WRDSKW,
  82. PHY_PGSR0_WDDONE,
  83. PHY_PGSR0_WDERR
  84. },
  85. {
  86. "Read Eye Training",
  87. PHY_PIR_RDEYE,
  88. PHY_PGSR0_REDONE,
  89. PHY_PGSR0_REERR
  90. },
  91. {
  92. "Write Eye Training",
  93. PHY_PIR_WREYE,
  94. PHY_PGSR0_WEDONE,
  95. PHY_PGSR0_WEERR
  96. }
  97. };
  98. int ddrphy_training(void __iomem *phy_base)
  99. {
  100. int i;
  101. u32 pgsr0;
  102. u32 init_flag = PHY_PIR_INIT;
  103. u32 done_flag = PHY_PGSR0_IDONE;
  104. int timeout = 50000; /* 50 msec is long enough */
  105. #ifdef DEBUG
  106. ulong start = get_timer(0);
  107. #endif
  108. for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
  109. init_flag |= init_sequence[i].init_flag;
  110. done_flag |= init_sequence[i].done_flag;
  111. }
  112. writel(init_flag, phy_base + PHY_PIR);
  113. do {
  114. if (--timeout < 0) {
  115. pr_err("timeout during DDR training\n");
  116. return -ETIMEDOUT;
  117. }
  118. udelay(1);
  119. pgsr0 = readl(phy_base + PHY_PGSR0);
  120. } while ((pgsr0 & done_flag) != done_flag);
  121. for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
  122. if (pgsr0 & init_sequence[i].err_flag) {
  123. pr_err("%s failed\n", init_sequence[i].description);
  124. return -EIO;
  125. }
  126. }
  127. #ifdef DEBUG
  128. pr_debug("DDR training: elapsed time %ld msec\n", get_timer(start));
  129. #endif
  130. return 0;
  131. }