ddrphy_training.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * Copyright (C) 2011-2014 Panasonic Corporation
  3. * Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #include <common.h>
  8. #include <asm/io.h>
  9. #include <mach/ddrphy-regs.h>
  10. void ddrphy_prepare_training(struct ddrphy __iomem *phy, int rank)
  11. {
  12. int dx;
  13. u32 __iomem tmp, *p;
  14. for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
  15. p = &phy->dx[dx].gcr;
  16. tmp = readl(p);
  17. /* Specify the rank that should be write leveled */
  18. tmp &= ~DXGCR_WLRKEN_MASK;
  19. tmp |= (1 << (DXGCR_WLRKEN_SHIFT + rank)) & DXGCR_WLRKEN_MASK;
  20. writel(tmp, p);
  21. }
  22. p = &phy->dtcr;
  23. tmp = readl(p);
  24. /* Specify the rank used during data bit deskew and eye centering */
  25. tmp &= ~DTCR_DTRANK_MASK;
  26. tmp |= (rank << DTCR_DTRANK_SHIFT) & DTCR_DTRANK_MASK;
  27. /* Use Multi-Purpose Register for DQS gate training */
  28. tmp |= DTCR_DTMPR;
  29. /* Specify the rank enabled for data-training */
  30. tmp &= ~DTCR_RNKEN_MASK;
  31. tmp |= (1 << (DTCR_RNKEN_SHIFT + rank)) & DTCR_RNKEN_MASK;
  32. writel(tmp, p);
  33. }
  34. struct ddrphy_init_sequence {
  35. char *description;
  36. u32 init_flag;
  37. u32 done_flag;
  38. u32 err_flag;
  39. };
  40. static struct ddrphy_init_sequence init_sequence[] = {
  41. {
  42. "DRAM Initialization",
  43. PIR_DRAMRST | PIR_DRAMINIT,
  44. PGSR0_DIDONE,
  45. PGSR0_DIERR
  46. },
  47. {
  48. "Write Leveling",
  49. PIR_WL,
  50. PGSR0_WLDONE,
  51. PGSR0_WLERR
  52. },
  53. {
  54. "Read DQS Gate Training",
  55. PIR_QSGATE,
  56. PGSR0_QSGDONE,
  57. PGSR0_QSGERR
  58. },
  59. {
  60. "Write Leveling Adjustment",
  61. PIR_WLADJ,
  62. PGSR0_WLADONE,
  63. PGSR0_WLAERR
  64. },
  65. {
  66. "Read Bit Deskew",
  67. PIR_RDDSKW,
  68. PGSR0_RDDONE,
  69. PGSR0_RDERR
  70. },
  71. {
  72. "Write Bit Deskew",
  73. PIR_WRDSKW,
  74. PGSR0_WDDONE,
  75. PGSR0_WDERR
  76. },
  77. {
  78. "Read Eye Training",
  79. PIR_RDEYE,
  80. PGSR0_REDONE,
  81. PGSR0_REERR
  82. },
  83. {
  84. "Write Eye Training",
  85. PIR_WREYE,
  86. PGSR0_WEDONE,
  87. PGSR0_WEERR
  88. }
  89. };
  90. int ddrphy_training(struct ddrphy __iomem *phy)
  91. {
  92. int i;
  93. u32 pgsr0;
  94. u32 init_flag = PIR_INIT;
  95. u32 done_flag = PGSR0_IDONE;
  96. int timeout = 50000; /* 50 msec is long enough */
  97. #ifdef DISPLAY_ELAPSED_TIME
  98. ulong start = get_timer(0);
  99. #endif
  100. for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
  101. init_flag |= init_sequence[i].init_flag;
  102. done_flag |= init_sequence[i].done_flag;
  103. }
  104. writel(init_flag, &phy->pir);
  105. do {
  106. if (--timeout < 0) {
  107. #ifndef CONFIG_SPL_BUILD
  108. printf("%s: error: timeout during DDR training\n",
  109. __func__);
  110. #endif
  111. return -1;
  112. }
  113. udelay(1);
  114. pgsr0 = readl(&phy->pgsr[0]);
  115. } while ((pgsr0 & done_flag) != done_flag);
  116. for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
  117. if (pgsr0 & init_sequence[i].err_flag) {
  118. #ifndef CONFIG_SPL_BUILD
  119. printf("%s: error: %s failed\n", __func__,
  120. init_sequence[i].description);
  121. #endif
  122. return -1;
  123. }
  124. }
  125. #ifdef DISPLAY_ELAPSED_TIME
  126. printf("%s: info: elapsed time %ld msec\n", get_timer(start));
  127. #endif
  128. return 0;
  129. }