ddrphy-training.c 2.6 KB

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