0010-haswell-NRI-Collect-SPD-info.patch 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. From 354969af4361bcc7dc240ef5871d169728f7f0cc Mon Sep 17 00:00:00 2001
  2. From: Angel Pons <th3fanbus@gmail.com>
  3. Date: Sat, 7 May 2022 13:48:53 +0200
  4. Subject: [PATCH 10/26] haswell NRI: Collect SPD info
  5. Collect SPD data from DIMMs and memory-down, and find the common
  6. supported settings.
  7. Change-Id: I4e6a1408a638a463ecae37a447cfed1d6556e44a
  8. Signed-off-by: Angel Pons <th3fanbus@gmail.com>
  9. ---
  10. .../intel/haswell/native_raminit/Makefile.inc | 1 +
  11. .../haswell/native_raminit/raminit_main.c | 1 +
  12. .../haswell/native_raminit/raminit_native.h | 57 +++++
  13. .../haswell/native_raminit/spd_bitmunching.c | 206 ++++++++++++++++++
  14. 4 files changed, 265 insertions(+)
  15. create mode 100644 src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c
  16. diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.inc b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
  17. index 90af951c5a..ebf7abc6ec 100644
  18. --- a/src/northbridge/intel/haswell/native_raminit/Makefile.inc
  19. +++ b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
  20. @@ -2,3 +2,4 @@
  21. romstage-y += raminit_main.c
  22. romstage-y += raminit_native.c
  23. +romstage-y += spd_bitmunching.c
  24. diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
  25. index 9b42c25b40..2d2cfa48bb 100644
  26. --- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
  27. +++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
  28. @@ -20,6 +20,7 @@ struct task_entry {
  29. };
  30. static const struct task_entry cold_boot[] = {
  31. + { collect_spd_info, true, "PROCSPD", },
  32. };
  33. /* Return a generic stepping value to make stepping checks simpler */
  34. diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
  35. index 885f0184f4..1a0793947e 100644
  36. --- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
  37. +++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
  38. @@ -3,6 +3,15 @@
  39. #ifndef HASWELL_RAMINIT_NATIVE_H
  40. #define HASWELL_RAMINIT_NATIVE_H
  41. +#include <device/dram/ddr3.h>
  42. +#include <northbridge/intel/haswell/haswell.h>
  43. +
  44. +#define SPD_LEN 256
  45. +
  46. +/* 8 data lanes + 1 ECC lane */
  47. +#define NUM_LANES 9
  48. +#define NUM_LANES_NO_ECC 8
  49. +
  50. enum raminit_boot_mode {
  51. BOOTMODE_COLD,
  52. BOOTMODE_WARM,
  53. @@ -12,6 +21,8 @@ enum raminit_boot_mode {
  54. enum raminit_status {
  55. RAMINIT_STATUS_SUCCESS = 0,
  56. + RAMINIT_STATUS_NO_MEMORY_INSTALLED,
  57. + RAMINIT_STATUS_UNSUPPORTED_MEMORY,
  58. RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/
  59. };
  60. @@ -21,14 +32,60 @@ enum generic_stepping {
  61. STEPPING_C0 = 3,
  62. };
  63. +struct raminit_dimm_info {
  64. + spd_raw_data raw_spd;
  65. + struct dimm_attr_ddr3_st data;
  66. + uint8_t spd_addr;
  67. + bool valid;
  68. +};
  69. +
  70. struct sysinfo {
  71. enum raminit_boot_mode bootmode;
  72. enum generic_stepping stepping;
  73. uint32_t cpu; /* CPUID value */
  74. bool dq_pins_interleaved;
  75. +
  76. + /** TODO: ECC support untested **/
  77. + bool is_ecc;
  78. +
  79. + /**
  80. + * FIXME: LPDDR support is incomplete. The largest chunks are missing,
  81. + * but some LPDDR-specific variations in algorithms have been handled.
  82. + * LPDDR-specific functions have stubs which will halt upon execution.
  83. + */
  84. + bool lpddr;
  85. +
  86. + struct raminit_dimm_info dimms[NUM_CHANNELS][NUM_SLOTS];
  87. + union dimm_flags_ddr3_st flags;
  88. + uint16_t cas_supported;
  89. +
  90. + /* Except for tCK, everything is eventually stored in DCLKs */
  91. + uint32_t tCK;
  92. + uint32_t tAA; /* Also known as tCL */
  93. + uint32_t tWR;
  94. + uint32_t tRCD;
  95. + uint32_t tRRD;
  96. + uint32_t tRP;
  97. + uint32_t tRAS;
  98. + uint32_t tRC;
  99. + uint32_t tRFC;
  100. + uint32_t tWTR;
  101. + uint32_t tRTP;
  102. + uint32_t tFAW;
  103. + uint32_t tCWL;
  104. + uint32_t tCMD;
  105. +
  106. + uint8_t lanes; /* 8 or 9 */
  107. + uint8_t chanmap;
  108. + uint8_t dpc[NUM_CHANNELS]; /* DIMMs per channel */
  109. + uint8_t rankmap[NUM_CHANNELS];
  110. + uint8_t rank_mirrored[NUM_CHANNELS];
  111. + uint32_t channel_size_mb[NUM_CHANNELS];
  112. };
  113. void raminit_main(enum raminit_boot_mode bootmode);
  114. +enum raminit_status collect_spd_info(struct sysinfo *ctrl);
  115. +
  116. #endif
  117. diff --git a/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c b/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c
  118. new file mode 100644
  119. index 0000000000..dbe02c72d0
  120. --- /dev/null
  121. +++ b/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c
  122. @@ -0,0 +1,206 @@
  123. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  124. +
  125. +#include <cbfs.h>
  126. +#include <commonlib/clamp.h>
  127. +#include <console/console.h>
  128. +#include <device/dram/ddr3.h>
  129. +#include <device/smbus_host.h>
  130. +#include <northbridge/intel/haswell/haswell.h>
  131. +#include <northbridge/intel/haswell/raminit.h>
  132. +#include <string.h>
  133. +#include <types.h>
  134. +
  135. +#include "raminit_native.h"
  136. +
  137. +static const uint8_t *get_spd_data_from_cbfs(struct spd_info *spdi)
  138. +{
  139. + if (!CONFIG(HAVE_SPD_IN_CBFS))
  140. + return NULL;
  141. +
  142. + printk(RAM_DEBUG, "SPD index %u\n", spdi->spd_index);
  143. +
  144. + size_t spd_file_len;
  145. + uint8_t *spd_file = cbfs_map("spd.bin", &spd_file_len);
  146. +
  147. + if (!spd_file) {
  148. + printk(BIOS_ERR, "SPD data not found in CBFS\n");
  149. + return NULL;
  150. + }
  151. +
  152. + if (spd_file_len < ((spdi->spd_index + 1) * SPD_LEN)) {
  153. + printk(BIOS_ERR, "SPD index override to 0 - old hardware?\n");
  154. + spdi->spd_index = 0;
  155. + }
  156. +
  157. + if (spd_file_len < SPD_LEN) {
  158. + printk(BIOS_ERR, "Invalid SPD data in CBFS\n");
  159. + return NULL;
  160. + }
  161. +
  162. + return spd_file + (spdi->spd_index * SPD_LEN);
  163. +}
  164. +
  165. +static void get_spd_for_dimm(struct raminit_dimm_info *const dimm, const uint8_t *cbfs_spd)
  166. +{
  167. + if (dimm->spd_addr == SPD_MEMORY_DOWN) {
  168. + if (cbfs_spd) {
  169. + memcpy(dimm->raw_spd, cbfs_spd, SPD_LEN);
  170. + dimm->valid = true;
  171. + printk(RAM_DEBUG, "memory-down\n");
  172. + return;
  173. + } else {
  174. + printk(RAM_DEBUG, "memory-down but no CBFS SPD data, ignoring\n");
  175. + return;
  176. + }
  177. + }
  178. + printk(RAM_DEBUG, "slotted ");
  179. + const uint8_t spd_mem_type = smbus_read_byte(dimm->spd_addr, SPD_MEMORY_TYPE);
  180. + if (spd_mem_type != SPD_MEMORY_TYPE_SDRAM_DDR3) {
  181. + printk(RAM_DEBUG, "and not DDR3, ignoring\n");
  182. + return;
  183. + }
  184. + printk(RAM_DEBUG, "and DDR3\n");
  185. + if (i2c_eeprom_read(dimm->spd_addr, 0, SPD_LEN, dimm->raw_spd) != SPD_LEN) {
  186. + printk(BIOS_WARNING, "I2C block read failed, trying SMBus byte reads\n");
  187. + for (uint32_t i = 0; i < SPD_LEN; i++)
  188. + dimm->raw_spd[i] = smbus_read_byte(dimm->spd_addr, i);
  189. + }
  190. + dimm->valid = true;
  191. +}
  192. +
  193. +static void get_spd_data(struct sysinfo *ctrl)
  194. +{
  195. + struct spd_info spdi = {0};
  196. + mb_get_spd_map(&spdi);
  197. + const uint8_t *cbfs_spd = get_spd_data_from_cbfs(&spdi);
  198. + for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
  199. + for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) {
  200. + struct raminit_dimm_info *const dimm = &ctrl->dimms[channel][slot];
  201. + dimm->spd_addr = spdi.addresses[channel + channel + slot];
  202. + if (!dimm->spd_addr)
  203. + continue;
  204. +
  205. + printk(RAM_DEBUG, "CH%uS%u is ", channel, slot);
  206. + get_spd_for_dimm(dimm, cbfs_spd);
  207. + }
  208. + }
  209. +}
  210. +
  211. +static void decode_spd(struct raminit_dimm_info *const dimm)
  212. +{
  213. + /** TODO: Hook up somewhere, and handle lack of XMP data **/
  214. + const bool enable_xmp = false;
  215. + memset(&dimm->data, 0, sizeof(dimm->data));
  216. + if (enable_xmp)
  217. + spd_xmp_decode_ddr3(&dimm->data, dimm->raw_spd, DDR3_XMP_PROFILE_1);
  218. + else
  219. + spd_decode_ddr3(&dimm->data, dimm->raw_spd);
  220. +
  221. + if (CONFIG(DEBUG_RAM_SETUP))
  222. + dram_print_spd_ddr3(&dimm->data);
  223. +}
  224. +
  225. +static enum raminit_status find_common_spd_parameters(struct sysinfo *ctrl)
  226. +{
  227. + ctrl->cas_supported = 0xffff;
  228. + ctrl->flags.raw = 0xffffffff;
  229. +
  230. + ctrl->tCK = 0;
  231. + ctrl->tAA = 0;
  232. + ctrl->tWR = 0;
  233. + ctrl->tRCD = 0;
  234. + ctrl->tRRD = 0;
  235. + ctrl->tRP = 0;
  236. + ctrl->tRAS = 0;
  237. + ctrl->tRC = 0;
  238. + ctrl->tRFC = 0;
  239. + ctrl->tWTR = 0;
  240. + ctrl->tRTP = 0;
  241. + ctrl->tFAW = 0;
  242. + ctrl->tCWL = 0;
  243. + ctrl->tCMD = 0;
  244. + ctrl->chanmap = 0;
  245. +
  246. + bool yes_ecc = false;
  247. + bool not_ecc = false;
  248. +
  249. + for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
  250. + ctrl->dpc[channel] = 0;
  251. + ctrl->rankmap[channel] = 0;
  252. + ctrl->rank_mirrored[channel] = 0;
  253. + ctrl->channel_size_mb[channel] = 0;
  254. + for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) {
  255. + struct raminit_dimm_info *const dimm = &ctrl->dimms[channel][slot];
  256. + if (!dimm->valid)
  257. + continue;
  258. +
  259. + printk(RAM_DEBUG, "\nCH%uS%u SPD:\n", channel, slot);
  260. + decode_spd(dimm);
  261. +
  262. + ctrl->chanmap |= BIT(channel);
  263. + ctrl->dpc[channel]++;
  264. + ctrl->channel_size_mb[channel] += dimm->data.size_mb;
  265. +
  266. + /* The first rank of a populated slot is always present */
  267. + const uint8_t rank = slot + slot;
  268. + assert(dimm->data.ranks);
  269. + ctrl->rankmap[channel] |= (BIT(dimm->data.ranks) - 1) << rank;
  270. +
  271. + if (dimm->data.flags.pins_mirrored)
  272. + ctrl->rank_mirrored[channel] |= BIT(rank + 1);
  273. +
  274. + /* Find common settings */
  275. + ctrl->cas_supported &= dimm->data.cas_supported;
  276. + ctrl->flags.raw &= dimm->data.flags.raw;
  277. + ctrl->tCK = MAX(ctrl->tCK, dimm->data.tCK);
  278. + ctrl->tAA = MAX(ctrl->tAA, dimm->data.tAA);
  279. + ctrl->tWR = MAX(ctrl->tWR, dimm->data.tWR);
  280. + ctrl->tRCD = MAX(ctrl->tRCD, dimm->data.tRCD);
  281. + ctrl->tRRD = MAX(ctrl->tRRD, dimm->data.tRRD);
  282. + ctrl->tRP = MAX(ctrl->tRP, dimm->data.tRP);
  283. + ctrl->tRAS = MAX(ctrl->tRAS, dimm->data.tRAS);
  284. + ctrl->tRC = MAX(ctrl->tRC, dimm->data.tRC);
  285. + ctrl->tRFC = MAX(ctrl->tRFC, dimm->data.tRFC);
  286. + ctrl->tWTR = MAX(ctrl->tWTR, dimm->data.tWTR);
  287. + ctrl->tRTP = MAX(ctrl->tRTP, dimm->data.tRTP);
  288. + ctrl->tFAW = MAX(ctrl->tFAW, dimm->data.tFAW);
  289. + ctrl->tCWL = MAX(ctrl->tCWL, dimm->data.tCWL);
  290. + ctrl->tCMD = MAX(ctrl->tCMD, dimm->data.tCMD);
  291. +
  292. + yes_ecc |= dimm->data.flags.is_ecc;
  293. + not_ecc |= !dimm->data.flags.is_ecc;
  294. + }
  295. + }
  296. +
  297. + if (!ctrl->chanmap) {
  298. + printk(BIOS_ERR, "No DIMMs were found\n");
  299. + return RAMINIT_STATUS_NO_MEMORY_INSTALLED;
  300. + }
  301. + if (!ctrl->cas_supported) {
  302. + printk(BIOS_ERR, "Could not resolve common CAS latency\n");
  303. + return RAMINIT_STATUS_UNSUPPORTED_MEMORY;
  304. + }
  305. + /** TODO: Properly handle ECC support and ECC forced **/
  306. + if (yes_ecc && not_ecc) {
  307. + /** TODO: Test if the ECC DIMMs can be operated as non-ECC DIMMs **/
  308. + printk(BIOS_ERR, "Both ECC and non-ECC DIMMs present, this is unsupported\n");
  309. + return RAMINIT_STATUS_UNSUPPORTED_MEMORY;
  310. + }
  311. + if (yes_ecc)
  312. + ctrl->lanes = NUM_LANES;
  313. + else
  314. + ctrl->lanes = NUM_LANES_NO_ECC;
  315. +
  316. + ctrl->is_ecc = yes_ecc;
  317. +
  318. + /** TODO: Complete LPDDR support **/
  319. + ctrl->lpddr = false;
  320. +
  321. + return RAMINIT_STATUS_SUCCESS;
  322. +}
  323. +
  324. +enum raminit_status collect_spd_info(struct sysinfo *ctrl)
  325. +{
  326. + get_spd_data(ctrl);
  327. + return find_common_spd_parameters(ctrl);
  328. +}
  329. --
  330. 2.39.2