Angel Pons | 62079a5 | 2020-04-05 13:21:34 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 2 | |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 3 | #include <cbfs.h> |
| 4 | #include <console/console.h> |
Aaron Durbin | 9506aea | 2015-07-24 13:06:12 -0500 | [diff] [blame] | 5 | #include <gpio.h> |
Duncan Laurie | 44b01fd | 2015-09-03 16:19:42 -0700 | [diff] [blame] | 6 | #include <soc/gpio.h> |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 7 | #include <soc/romstage.h> |
Duncan Laurie | 44b01fd | 2015-09-03 16:19:42 -0700 | [diff] [blame] | 8 | #include <string.h> |
Matt DeVillier | 0b9cfe6 | 2018-06-26 13:07:32 -0500 | [diff] [blame] | 9 | #include <baseboard/variant.h> |
Nico Huber | feb50f1 | 2019-05-04 17:06:06 +0200 | [diff] [blame] | 10 | |
| 11 | #include "spd_util.h" |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 12 | #include "spd.h" |
| 13 | |
| 14 | static void mainboard_print_spd_info(uint8_t spd[]) |
| 15 | { |
| 16 | const int spd_banks[8] = { 8, 16, 32, 64, -1, -1, -1, -1 }; |
| 17 | const int spd_capmb[8] = { 1, 2, 4, 8, 16, 32, 64, 0 }; |
| 18 | const int spd_rows[8] = { 12, 13, 14, 15, 16, -1, -1, -1 }; |
| 19 | const int spd_cols[8] = { 9, 10, 11, 12, -1, -1, -1, -1 }; |
| 20 | const int spd_ranks[8] = { 1, 2, 3, 4, -1, -1, -1, -1 }; |
| 21 | const int spd_devw[8] = { 4, 8, 16, 32, -1, -1, -1, -1 }; |
| 22 | const int spd_busw[8] = { 8, 16, 32, 64, -1, -1, -1, -1 }; |
| 23 | char spd_name[SPD_PART_LEN+1] = { 0 }; |
| 24 | |
| 25 | int banks = spd_banks[(spd[SPD_DENSITY_BANKS] >> 4) & 7]; |
| 26 | int capmb = spd_capmb[spd[SPD_DENSITY_BANKS] & 7] * 256; |
| 27 | int rows = spd_rows[(spd[SPD_ADDRESSING] >> 3) & 7]; |
| 28 | int cols = spd_cols[spd[SPD_ADDRESSING] & 7]; |
| 29 | int ranks = spd_ranks[(spd[SPD_ORGANIZATION] >> 3) & 7]; |
| 30 | int devw = spd_devw[spd[SPD_ORGANIZATION] & 7]; |
| 31 | int busw = spd_busw[spd[SPD_BUS_DEV_WIDTH] & 7]; |
| 32 | |
| 33 | /* Module type */ |
| 34 | printk(BIOS_INFO, "SPD: module type is "); |
| 35 | switch (spd[SPD_DRAM_TYPE]) { |
| 36 | case SPD_DRAM_DDR3: |
| 37 | printk(BIOS_INFO, "DDR3\n"); |
| 38 | break; |
| 39 | case SPD_DRAM_LPDDR3: |
| 40 | printk(BIOS_INFO, "LPDDR3\n"); |
| 41 | break; |
| 42 | default: |
| 43 | printk(BIOS_INFO, "Unknown (%02x)\n", spd[SPD_DRAM_TYPE]); |
| 44 | break; |
| 45 | } |
| 46 | |
| 47 | /* Module Part Number */ |
| 48 | memcpy(spd_name, &spd[SPD_PART_OFF], SPD_PART_LEN); |
| 49 | spd_name[SPD_PART_LEN] = 0; |
| 50 | printk(BIOS_INFO, "SPD: module part is %s\n", spd_name); |
| 51 | |
| 52 | printk(BIOS_INFO, |
| 53 | "SPD: banks %d, ranks %d, rows %d, columns %d, density %d Mb\n", |
| 54 | banks, ranks, rows, cols, capmb); |
| 55 | printk(BIOS_INFO, "SPD: device width %d bits, bus width %d bits\n", |
| 56 | devw, busw); |
| 57 | |
| 58 | if (capmb > 0 && busw > 0 && devw > 0 && ranks > 0) { |
| 59 | /* SIZE = DENSITY / 8 * BUS_WIDTH / SDRAM_WIDTH * RANKS */ |
| 60 | printk(BIOS_INFO, "SPD: module size is %u MB (per channel)\n", |
| 61 | capmb / 8 * busw / devw * ranks); |
| 62 | } |
| 63 | } |
| 64 | |
Matt DeVillier | 0b9cfe6 | 2018-06-26 13:07:32 -0500 | [diff] [blame] | 65 | __weak int is_dual_channel(const int spd_index) |
| 66 | { |
| 67 | /* default to dual channel */ |
| 68 | return 1; |
| 69 | } |
| 70 | |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 71 | /* Copy SPD data for on-board memory */ |
Michael Niewöhner | f89cb24 | 2019-10-09 21:02:36 +0200 | [diff] [blame] | 72 | void spd_memory_init_params(FSPM_UPD *mupd, int spd_index) |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 73 | { |
Michael Niewöhner | f89cb24 | 2019-10-09 21:02:36 +0200 | [diff] [blame] | 74 | FSP_M_CONFIG *mem_cfg; |
| 75 | mem_cfg = &mupd->FspmConfig; |
Nico Huber | feb50f1 | 2019-05-04 17:06:06 +0200 | [diff] [blame] | 76 | uint8_t *spd_file; |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 77 | size_t spd_file_len; |
Duncan Laurie | d8d6866 | 2015-07-22 09:21:29 -0700 | [diff] [blame] | 78 | |
Duncan Laurie | 44b01fd | 2015-09-03 16:19:42 -0700 | [diff] [blame] | 79 | printk(BIOS_INFO, "SPD index %d\n", spd_index); |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 80 | |
| 81 | /* Load SPD data from CBFS */ |
Julius Werner | 834b3ec | 2020-03-04 16:52:08 -0800 | [diff] [blame^] | 82 | spd_file = cbfs_map("spd.bin", &spd_file_len); |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 83 | if (!spd_file) |
| 84 | die("SPD data not found."); |
| 85 | |
| 86 | /* make sure we have at least one SPD in the file. */ |
| 87 | if (spd_file_len < SPD_LEN) |
| 88 | die("Missing SPD data."); |
| 89 | |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 90 | /* Make sure we did not overrun the buffer */ |
| 91 | if (spd_file_len < ((spd_index + 1) * SPD_LEN)) { |
Duncan Laurie | d8d6866 | 2015-07-22 09:21:29 -0700 | [diff] [blame] | 92 | printk(BIOS_ERR, "SPD index override to 1 - old hardware?\n"); |
| 93 | spd_index = 1; |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 94 | } |
| 95 | |
Nico Huber | feb50f1 | 2019-05-04 17:06:06 +0200 | [diff] [blame] | 96 | const size_t spd_offset = spd_index * SPD_LEN; |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 97 | /* Make sure a valid SPD was found */ |
Nico Huber | feb50f1 | 2019-05-04 17:06:06 +0200 | [diff] [blame] | 98 | if (spd_file[spd_offset] == 0) |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 99 | die("Invalid SPD data."); |
| 100 | |
Nico Huber | feb50f1 | 2019-05-04 17:06:06 +0200 | [diff] [blame] | 101 | /* Assume same memory in both channels */ |
Michael Niewöhner | f89cb24 | 2019-10-09 21:02:36 +0200 | [diff] [blame] | 102 | mem_cfg->MemorySpdPtr00 = (uintptr_t)spd_file + spd_offset; |
Nico Huber | feb50f1 | 2019-05-04 17:06:06 +0200 | [diff] [blame] | 103 | if (is_dual_channel(spd_index)) |
Michael Niewöhner | f89cb24 | 2019-10-09 21:02:36 +0200 | [diff] [blame] | 104 | mem_cfg->MemorySpdPtr10 = mem_cfg->MemorySpdPtr00; |
Nico Huber | feb50f1 | 2019-05-04 17:06:06 +0200 | [diff] [blame] | 105 | |
| 106 | mainboard_print_spd_info(spd_file + spd_offset); |
Patrick Georgi | 406313d | 2015-07-20 22:01:32 +0200 | [diff] [blame] | 107 | } |