ddr_calibrate.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2018 Stefan Roese <sr@denx.de>
  4. *
  5. * This code is mostly based on the code extracted from this MediaTek
  6. * github repository:
  7. *
  8. * https://github.com/MediaTek-Labs/linkit-smart-uboot.git
  9. *
  10. * I was not able to find a specific license or other developers
  11. * copyrights here, so I can't add them here.
  12. *
  13. * Most functions in this file are copied from the MediaTek U-Boot
  14. * repository. Without any documentation, it was impossible to really
  15. * implement this differently. So its mostly a cleaned-up version of
  16. * the original code, with only support for the MT7628 / MT7688 SoC.
  17. */
  18. #include <common.h>
  19. #include <cpu_func.h>
  20. #include <linux/io.h>
  21. #include <asm/cacheops.h>
  22. #include <asm/io.h>
  23. #include "mt76xx.h"
  24. #define NUM_OF_CACHELINE 128
  25. #define MIN_START 6
  26. #define MIN_FINE_START 0xf
  27. #define MAX_START 7
  28. #define MAX_FINE_START 0x0
  29. #define CPU_FRAC_DIV 1
  30. #if defined(CONFIG_ONBOARD_DDR2_SIZE_256MBIT)
  31. #define DRAM_BUTTOM 0x02000000
  32. #endif
  33. #if defined(CONFIG_ONBOARD_DDR2_SIZE_512MBIT)
  34. #define DRAM_BUTTOM 0x04000000
  35. #endif
  36. #if defined(CONFIG_ONBOARD_DDR2_SIZE_1024MBIT)
  37. #define DRAM_BUTTOM 0x08000000
  38. #endif
  39. #if defined(CONFIG_ONBOARD_DDR2_SIZE_2048MBIT)
  40. #define DRAM_BUTTOM 0x10000000
  41. #endif
  42. static inline void cal_memcpy(void *src, void *dst, u32 size)
  43. {
  44. u8 *psrc = (u8 *)src;
  45. u8 *pdst = (u8 *)dst;
  46. int i;
  47. for (i = 0; i < size; i++, psrc++, pdst++)
  48. *pdst = *psrc;
  49. }
  50. static inline void cal_memset(void *src, u8 pat, u32 size)
  51. {
  52. u8 *psrc = (u8 *)src;
  53. int i;
  54. for (i = 0; i < size; i++, psrc++)
  55. *psrc = pat;
  56. }
  57. #define pref_op(hint, addr) \
  58. __asm__ __volatile__( \
  59. ".set push\n" \
  60. ".set noreorder\n" \
  61. "pref %0, %1\n" \
  62. ".set pop\n" \
  63. : \
  64. : "i" (hint), "R" (*(u8 *)(addr)))
  65. static inline void cal_patgen(u32 start_addr, u32 size, u32 bias)
  66. {
  67. u32 *addr = (u32 *)start_addr;
  68. int i;
  69. for (i = 0; i < size; i++)
  70. addr[i] = start_addr + i + bias;
  71. }
  72. static inline int test_loop(int k, int dqs, u32 test_dqs, u32 *coarse_dqs,
  73. u32 offs, u32 pat, u32 val)
  74. {
  75. u32 nc_addr;
  76. u32 *c_addr;
  77. int i;
  78. for (nc_addr = 0xa0000000;
  79. nc_addr < (0xa0000000 + DRAM_BUTTOM - NUM_OF_CACHELINE * 32);
  80. nc_addr += (DRAM_BUTTOM >> 6) + offs) {
  81. writel(0x00007474, (void *)MT76XX_MEMCTRL_BASE + 0x64);
  82. wmb(); /* Make sure store if finished */
  83. c_addr = (u32 *)(nc_addr & 0xdfffffff);
  84. cal_memset(((u8 *)c_addr), 0x1F, NUM_OF_CACHELINE * 32);
  85. cal_patgen(nc_addr, NUM_OF_CACHELINE * 8, pat);
  86. if (dqs > 0)
  87. writel(0x00000074 |
  88. (((k == 1) ? coarse_dqs[dqs] : test_dqs) << 12) |
  89. (((k == 0) ? val : test_dqs) << 8),
  90. (void *)MT76XX_MEMCTRL_BASE + 0x64);
  91. else
  92. writel(0x00007400 |
  93. (((k == 1) ? coarse_dqs[dqs] : test_dqs) << 4) |
  94. (((k == 0) ? val : test_dqs) << 0),
  95. (void *)MT76XX_MEMCTRL_BASE + 0x64);
  96. wmb(); /* Make sure store if finished */
  97. invalidate_dcache_range((u32)c_addr,
  98. (u32)c_addr +
  99. NUM_OF_CACHELINE * 32);
  100. wmb(); /* Make sure store if finished */
  101. for (i = 0; i < NUM_OF_CACHELINE * 8; i++) {
  102. if (i % 8 == 0)
  103. pref_op(0, &c_addr[i]);
  104. }
  105. for (i = 0; i < NUM_OF_CACHELINE * 8; i++) {
  106. if (c_addr[i] != nc_addr + i + pat)
  107. return -1;
  108. }
  109. }
  110. return 0;
  111. }
  112. void ddr_calibrate(void)
  113. {
  114. u32 min_coarse_dqs[2];
  115. u32 max_coarse_dqs[2];
  116. u32 min_fine_dqs[2];
  117. u32 max_fine_dqs[2];
  118. u32 coarse_dqs[2];
  119. u32 fine_dqs[2];
  120. int reg = 0, ddr_cfg2_reg;
  121. int flag;
  122. int i, k;
  123. int dqs = 0;
  124. u32 min_coarse_dqs_bnd, min_fine_dqs_bnd, coarse_dqs_dll, fine_dqs_dll;
  125. u32 val;
  126. u32 fdiv = 0, frac = 0;
  127. /* Setup clock to run at full speed */
  128. val = readl((void *)MT76XX_DYN_CFG0_REG);
  129. fdiv = (u32)((val >> 8) & 0x0F);
  130. if (CPU_FRAC_DIV < 1 || CPU_FRAC_DIV > 10)
  131. frac = val & 0x0f;
  132. else
  133. frac = CPU_FRAC_DIV;
  134. while (frac < fdiv) {
  135. val = readl((void *)MT76XX_DYN_CFG0_REG);
  136. fdiv = (val >> 8) & 0x0f;
  137. fdiv--;
  138. val &= ~(0x0f << 8);
  139. val |= (fdiv << 8);
  140. writel(val, (void *)MT76XX_DYN_CFG0_REG);
  141. udelay(500);
  142. val = readl((void *)MT76XX_DYN_CFG0_REG);
  143. fdiv = (val >> 8) & 0x0f;
  144. }
  145. clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
  146. ddr_cfg2_reg = readl((void *)MT76XX_MEMCTRL_BASE + 0x48);
  147. clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x48,
  148. (0x3 << 28) | (0x3 << 26));
  149. min_coarse_dqs[0] = MIN_START;
  150. min_coarse_dqs[1] = MIN_START;
  151. min_fine_dqs[0] = MIN_FINE_START;
  152. min_fine_dqs[1] = MIN_FINE_START;
  153. max_coarse_dqs[0] = MAX_START;
  154. max_coarse_dqs[1] = MAX_START;
  155. max_fine_dqs[0] = MAX_FINE_START;
  156. max_fine_dqs[1] = MAX_FINE_START;
  157. dqs = 0;
  158. /* Add by KP, DQS MIN boundary */
  159. reg = readl((void *)MT76XX_MEMCTRL_BASE + 0x20);
  160. coarse_dqs_dll = (reg & 0xf00) >> 8;
  161. fine_dqs_dll = (reg & 0xf0) >> 4;
  162. if (coarse_dqs_dll <= 8)
  163. min_coarse_dqs_bnd = 8 - coarse_dqs_dll;
  164. else
  165. min_coarse_dqs_bnd = 0;
  166. if (fine_dqs_dll <= 8)
  167. min_fine_dqs_bnd = 8 - fine_dqs_dll;
  168. else
  169. min_fine_dqs_bnd = 0;
  170. /* DQS MIN boundary */
  171. DQS_CAL:
  172. for (k = 0; k < 2; k++) {
  173. u32 test_dqs;
  174. if (k == 0)
  175. test_dqs = MAX_START;
  176. else
  177. test_dqs = MAX_FINE_START;
  178. do {
  179. flag = test_loop(k, dqs, test_dqs, max_coarse_dqs,
  180. 0x400, 0x3, 0xf);
  181. if (flag == -1)
  182. break;
  183. test_dqs++;
  184. } while (test_dqs <= 0xf);
  185. if (k == 0) {
  186. max_coarse_dqs[dqs] = test_dqs;
  187. } else {
  188. test_dqs--;
  189. if (test_dqs == MAX_FINE_START - 1) {
  190. max_coarse_dqs[dqs]--;
  191. max_fine_dqs[dqs] = 0xf;
  192. } else {
  193. max_fine_dqs[dqs] = test_dqs;
  194. }
  195. }
  196. }
  197. for (k = 0; k < 2; k++) {
  198. u32 test_dqs;
  199. if (k == 0)
  200. test_dqs = MIN_START;
  201. else
  202. test_dqs = MIN_FINE_START;
  203. do {
  204. flag = test_loop(k, dqs, test_dqs, min_coarse_dqs,
  205. 0x480, 0x1, 0x0);
  206. if (k == 0) {
  207. if (flag == -1 ||
  208. test_dqs == min_coarse_dqs_bnd)
  209. break;
  210. test_dqs--;
  211. if (test_dqs < min_coarse_dqs_bnd)
  212. break;
  213. } else {
  214. if (flag == -1) {
  215. test_dqs++;
  216. break;
  217. } else if (test_dqs == min_fine_dqs_bnd) {
  218. break;
  219. }
  220. test_dqs--;
  221. if (test_dqs < min_fine_dqs_bnd)
  222. break;
  223. }
  224. } while (test_dqs >= 0);
  225. if (k == 0) {
  226. min_coarse_dqs[dqs] = test_dqs;
  227. } else {
  228. if (test_dqs == MIN_FINE_START + 1) {
  229. min_coarse_dqs[dqs]++;
  230. min_fine_dqs[dqs] = 0x0;
  231. } else {
  232. min_fine_dqs[dqs] = test_dqs;
  233. }
  234. }
  235. }
  236. if (dqs == 0) {
  237. dqs = 1;
  238. goto DQS_CAL;
  239. }
  240. for (i = 0; i < 2; i++) {
  241. u32 temp;
  242. coarse_dqs[i] = (max_coarse_dqs[i] + min_coarse_dqs[i]) >> 1;
  243. temp =
  244. (((max_coarse_dqs[i] + min_coarse_dqs[i]) % 2) * 4) +
  245. ((max_fine_dqs[i] + min_fine_dqs[i]) >> 1);
  246. if (temp >= 0x10) {
  247. coarse_dqs[i]++;
  248. fine_dqs[i] = (temp - 0x10) + 0x8;
  249. } else {
  250. fine_dqs[i] = temp;
  251. }
  252. }
  253. reg = (coarse_dqs[1] << 12) | (fine_dqs[1] << 8) |
  254. (coarse_dqs[0] << 4) | fine_dqs[0];
  255. clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
  256. writel(reg, (void *)MT76XX_MEMCTRL_BASE + 0x64);
  257. writel(ddr_cfg2_reg, (void *)MT76XX_MEMCTRL_BASE + 0x48);
  258. setbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
  259. for (i = 0; i < 2; i++)
  260. debug("[%02X%02X%02X%02X]", min_coarse_dqs[i],
  261. min_fine_dqs[i], max_coarse_dqs[i], max_fine_dqs[i]);
  262. debug("\nDDR Calibration DQS reg = %08X\n", reg);
  263. }