ddrphy-training.c 3.0 KB

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