0020-haswell-NRI-Add-library-to-change-margins.patch 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. From 54cfbe4cf53d16f747bfcfadd20445a0f5f1e5db Mon Sep 17 00:00:00 2001
  2. From: Angel Pons <th3fanbus@gmail.com>
  3. Date: Sun, 8 May 2022 01:11:03 +0200
  4. Subject: [PATCH 20/26] haswell NRI: Add library to change margins
  5. Implement a library to change Rx/Tx margins. It will be expanded later.
  6. Change-Id: I0b55aba428d8b4d4e16d2fbdec57235ce3ce8adf
  7. Signed-off-by: Angel Pons <th3fanbus@gmail.com>
  8. ---
  9. .../intel/haswell/native_raminit/Makefile.inc | 1 +
  10. .../haswell/native_raminit/change_margin.c | 154 ++++++++++++++++++
  11. .../haswell/native_raminit/raminit_native.h | 50 ++++++
  12. .../intel/haswell/registers/mchbar.h | 9 +
  13. 4 files changed, 214 insertions(+)
  14. create mode 100644 src/northbridge/intel/haswell/native_raminit/change_margin.c
  15. diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.inc b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
  16. index 2da950771d..ebe9e9b762 100644
  17. --- a/src/northbridge/intel/haswell/native_raminit/Makefile.inc
  18. +++ b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
  19. @@ -1,5 +1,6 @@
  20. ## SPDX-License-Identifier: GPL-2.0-or-later
  21. +romstage-y += change_margin.c
  22. romstage-y += configure_mc.c
  23. romstage-y += ddr3.c
  24. romstage-y += jedec_reset.c
  25. diff --git a/src/northbridge/intel/haswell/native_raminit/change_margin.c b/src/northbridge/intel/haswell/native_raminit/change_margin.c
  26. new file mode 100644
  27. index 0000000000..12da59580f
  28. --- /dev/null
  29. +++ b/src/northbridge/intel/haswell/native_raminit/change_margin.c
  30. @@ -0,0 +1,154 @@
  31. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  32. +
  33. +#include <commonlib/clamp.h>
  34. +#include <console/console.h>
  35. +#include <delay.h>
  36. +#include <northbridge/intel/haswell/haswell.h>
  37. +#include <timer.h>
  38. +
  39. +#include "raminit_native.h"
  40. +
  41. +void update_rxt(
  42. + struct sysinfo *ctrl,
  43. + const uint8_t channel,
  44. + const uint8_t rank,
  45. + const uint8_t byte,
  46. + const enum rxt_subfield subfield,
  47. + const int32_t value)
  48. +{
  49. + union ddr_data_rx_train_rank_reg rxt = {
  50. + .rcven = ctrl->rcven[channel][rank][byte],
  51. + .dqs_p = ctrl->rxdqsp[channel][rank][byte],
  52. + .rx_eq = ctrl->rx_eq[channel][rank][byte],
  53. + .dqs_n = ctrl->rxdqsn[channel][rank][byte],
  54. + .vref = ctrl->rxvref[channel][rank][byte],
  55. + };
  56. + int32_t new_value;
  57. + switch (subfield) {
  58. + case RXT_RCVEN:
  59. + new_value = clamp_s32(0, value, 511);
  60. + rxt.rcven = new_value;
  61. + break;
  62. + case RXT_RXDQS_P:
  63. + new_value = clamp_s32(0, value, 63);
  64. + rxt.dqs_p = new_value;
  65. + break;
  66. + case RXT_RX_EQ:
  67. + new_value = clamp_s32(0, value, 31);
  68. + rxt.rx_eq = new_value;
  69. + break;
  70. + case RXT_RXDQS_N:
  71. + new_value = clamp_s32(0, value, 63);
  72. + rxt.dqs_n = new_value;
  73. + break;
  74. + case RXT_RX_VREF:
  75. + new_value = clamp_s32(-32, value, 31);
  76. + rxt.vref = new_value;
  77. + break;
  78. + case RXT_RXDQS_BOTH:
  79. + new_value = clamp_s32(0, value, 63);
  80. + rxt.dqs_p = new_value;
  81. + rxt.dqs_n = new_value;
  82. + break;
  83. + case RXT_RESTORE:
  84. + new_value = value;
  85. + break;
  86. + default:
  87. + die("%s: Unhandled subfield index %u\n", __func__, subfield);
  88. + }
  89. +
  90. + if (new_value != value) {
  91. + printk(BIOS_ERR, "%s: Overflow for subfield %u: %d ---> %d\n",
  92. + __func__, subfield, value, new_value);
  93. + }
  94. + mchbar_write32(RX_TRAIN_ch_r_b(channel, rank, byte), rxt.raw);
  95. + download_regfile(ctrl, channel, false, rank, REG_FILE_USE_RANK, byte, true, false);
  96. +}
  97. +
  98. +void update_txt(
  99. + struct sysinfo *ctrl,
  100. + const uint8_t channel,
  101. + const uint8_t rank,
  102. + const uint8_t byte,
  103. + const enum txt_subfield subfield,
  104. + const int32_t value)
  105. +{
  106. + union ddr_data_tx_train_rank_reg txt = {
  107. + .dq_delay = ctrl->tx_dq[channel][rank][byte],
  108. + .dqs_delay = ctrl->txdqs[channel][rank][byte],
  109. + .tx_eq = ctrl->tx_eq[channel][rank][byte],
  110. + };
  111. + int32_t new_value;
  112. + switch (subfield) {
  113. + case TXT_TX_DQ:
  114. + new_value = clamp_s32(0, value, 511);
  115. + txt.dq_delay = new_value;
  116. + break;
  117. + case TXT_TXDQS:
  118. + new_value = clamp_s32(0, value, 511);
  119. + txt.dqs_delay = new_value;
  120. + break;
  121. + case TXT_TX_EQ:
  122. + new_value = clamp_s32(0, value, 63);
  123. + txt.tx_eq = new_value;
  124. + break;
  125. + case TXT_DQDQS_OFF:
  126. + new_value = value;
  127. + txt.dqs_delay += new_value;
  128. + txt.dq_delay += new_value;
  129. + break;
  130. + case TXT_RESTORE:
  131. + new_value = value;
  132. + break;
  133. + default:
  134. + die("%s: Unhandled subfield index %u\n", __func__, subfield);
  135. + }
  136. + if (new_value != value) {
  137. + printk(BIOS_ERR, "%s: Overflow for subfield %u: %d ---> %d\n",
  138. + __func__, subfield, value, new_value);
  139. + }
  140. + mchbar_write32(TX_TRAIN_ch_r_b(channel, rank, byte), txt.raw);
  141. + download_regfile(ctrl, channel, false, rank, REG_FILE_USE_RANK, byte, false, true);
  142. +}
  143. +
  144. +void download_regfile(
  145. + struct sysinfo *ctrl,
  146. + const uint8_t channel,
  147. + const bool multicast,
  148. + const uint8_t rank,
  149. + const enum regfile_mode regfile,
  150. + const uint8_t byte,
  151. + const bool read_rf_rd,
  152. + const bool read_rf_wr)
  153. +{
  154. + union reut_seq_base_addr_reg reut_seq_base_addr;
  155. + switch (regfile) {
  156. + case REG_FILE_USE_START:
  157. + reut_seq_base_addr.raw = mchbar_read64(REUT_ch_SEQ_ADDR_START(channel));
  158. + break;
  159. + case REG_FILE_USE_CURRENT:
  160. + reut_seq_base_addr.raw = mchbar_read64(REUT_ch_SEQ_ADDR_CURRENT(channel));
  161. + break;
  162. + case REG_FILE_USE_RANK:
  163. + reut_seq_base_addr.raw = 0;
  164. + if (rank >= NUM_SLOTRANKS)
  165. + die("%s: bad rank %u\n", __func__, rank);
  166. + break;
  167. + default:
  168. + die("%s: Invalid regfile param %u\n", __func__, regfile);
  169. + }
  170. + uint8_t phys_rank = rank;
  171. + if (reut_seq_base_addr.raw != 0) {
  172. + /* Map REUT logical rank to physical rank */
  173. + const uint32_t log_to_phys = mchbar_read32(REUT_ch_RANK_LOG_TO_PHYS(channel));
  174. + phys_rank = log_to_phys >> (reut_seq_base_addr.rank_addr * 4) & 0x3;
  175. + }
  176. + uint32_t reg = multicast ? DDR_DATA_ch_CONTROL_0(channel) : DQ_CONTROL_0(channel, byte);
  177. + union ddr_data_control_0_reg ddr_data_control_0 = {
  178. + .raw = mchbar_read32(reg),
  179. + };
  180. + ddr_data_control_0.read_rf_rd = read_rf_rd;
  181. + ddr_data_control_0.read_rf_wr = read_rf_wr;
  182. + ddr_data_control_0.read_rf_rank = phys_rank;
  183. + mchbar_write32(reg, ddr_data_control_0.raw);
  184. +}
  185. diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
  186. index 56df36ca8d..7c1a786780 100644
  187. --- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
  188. +++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
  189. @@ -117,6 +117,30 @@ enum test_stop {
  190. ALSOE = 3, /* Stop on all lanes error */
  191. };
  192. +enum rxt_subfield {
  193. + RXT_RCVEN = 0,
  194. + RXT_RXDQS_P = 1,
  195. + RXT_RX_EQ = 2,
  196. + RXT_RXDQS_N = 3,
  197. + RXT_RX_VREF = 4,
  198. + RXT_RXDQS_BOTH = 5,
  199. + RXT_RESTORE = 255,
  200. +};
  201. +
  202. +enum txt_subfield {
  203. + TXT_TX_DQ = 0,
  204. + TXT_TXDQS = 1,
  205. + TXT_TX_EQ = 2,
  206. + TXT_DQDQS_OFF = 3,
  207. + TXT_RESTORE = 255,
  208. +};
  209. +
  210. +enum regfile_mode {
  211. + REG_FILE_USE_RANK, /* Used when changing parameters for each rank */
  212. + REG_FILE_USE_START, /* Used when changing parameters before the test */
  213. + REG_FILE_USE_CURRENT, /* Used when changing parameters after the test */
  214. +};
  215. +
  216. struct wdb_pat {
  217. uint32_t start_ptr; /* Starting pointer in WDB */
  218. uint32_t stop_ptr; /* Stopping pointer in WDB */
  219. @@ -452,6 +476,32 @@ uint8_t select_reut_ranks(struct sysinfo *ctrl, uint8_t channel, uint8_t rankmas
  220. void run_mpr_io_test(bool clear_errors);
  221. uint8_t run_io_test(struct sysinfo *ctrl, uint8_t chanmask, uint8_t dq_pat, bool clear_errors);
  222. +void update_rxt(
  223. + struct sysinfo *ctrl,
  224. + uint8_t channel,
  225. + uint8_t rank,
  226. + uint8_t byte,
  227. + enum rxt_subfield subfield,
  228. + int32_t value);
  229. +
  230. +void update_txt(
  231. + struct sysinfo *ctrl,
  232. + uint8_t channel,
  233. + uint8_t rank,
  234. + uint8_t byte,
  235. + enum txt_subfield subfield,
  236. + int32_t value);
  237. +
  238. +void download_regfile(
  239. + struct sysinfo *ctrl,
  240. + uint8_t channel,
  241. + bool multicast,
  242. + uint8_t rank,
  243. + enum regfile_mode regfile,
  244. + uint8_t byte,
  245. + bool read_rf_rd,
  246. + bool read_rf_wr);
  247. +
  248. uint8_t get_rx_bias(const struct sysinfo *ctrl);
  249. uint8_t get_tCWL(uint32_t mem_clock_mhz);
  250. diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
  251. index 817a9f8bf8..a81559bb1e 100644
  252. --- a/src/northbridge/intel/haswell/registers/mchbar.h
  253. +++ b/src/northbridge/intel/haswell/registers/mchbar.h
  254. @@ -15,7 +15,11 @@
  255. /* Register definitions */
  256. /* DDR DATA per-channel per-bytelane */
  257. +#define RX_TRAIN_ch_r_b(ch, rank, byte) _DDRIO_C_R_B(0x0000, ch, rank, byte)
  258. +#define TX_TRAIN_ch_r_b(ch, rank, byte) _DDRIO_C_R_B(0x0020, ch, rank, byte)
  259. +
  260. #define DQ_CONTROL_2(ch, byte) _DDRIO_C_R_B(0x0064, ch, 0, byte)
  261. +#define DQ_CONTROL_0(ch, byte) _DDRIO_C_R_B(0x0074, ch, 0, byte)
  262. /* DDR CKE per-channel */
  263. #define DDR_CKE_ch_CMD_COMP_OFFSET(ch) _DDRIO_C_R_B(0x1204, ch, 0, 0)
  264. @@ -38,6 +42,9 @@
  265. #define DDR_SCRAMBLE_ch(ch) (0x2000 + 4 * (ch))
  266. #define DDR_SCRAM_MISC_CONTROL 0x2008
  267. +/* DDR DATA per-channel multicast */
  268. +#define DDR_DATA_ch_CONTROL_0(ch) _DDRIO_C_R_B(0x3074, ch, 0, 0)
  269. +
  270. /* DDR CMDN/CMDS per-channel (writes go to both CMDN and CMDS fubs) */
  271. #define DDR_CMD_ch_COMP_OFFSET(ch) _DDRIO_C_R_B(0x3204, ch, 0, 0)
  272. #define DDR_CMD_ch_PI_CODING(ch) _DDRIO_C_R_B(0x3208, ch, 0, 0)
  273. @@ -147,6 +154,8 @@
  274. #define REUT_ch_SEQ_ADDR_WRAP(ch) (0x48e8 + 8 * (ch))
  275. +#define REUT_ch_SEQ_ADDR_CURRENT(ch) (0x48f8 + 8 * (ch))
  276. +
  277. #define REUT_ch_SEQ_MISC_CTL(ch) (0x4908 + 4 * (ch))
  278. #define REUT_ch_SEQ_ADDR_INC_CTL(ch) (0x4910 + 8 * (ch))
  279. --
  280. 2.39.2