blob: 7fd44094019a66ba28679765cf38b0339b1a57d0 [file] [log] [blame]
Angel Pons27123982020-04-05 13:22:30 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Furquan Shaikh06cd9032016-12-14 12:10:21 -08002
Furquan Shaikhcbed0c22017-04-14 22:11:13 -07003#include <assert.h>
4#include <baseboard/variants.h>
5#include <cbfs.h>
6#include <console/console.h>
Furquan Shaikhfb10ceb2018-08-05 20:59:25 -07007#include <soc/gpio.h>
Furquan Shaikh06cd9032016-12-14 12:10:21 -08008#include <soc/romstage.h>
9#include <string.h>
Furquan Shaikhfb10ceb2018-08-05 20:59:25 -070010#include <variant/gpio.h>
Furquan Shaikh06cd9032016-12-14 12:10:21 -080011
12#include <fsp/soc_binding.h>
13
Furquan Shaikh48be29e2017-12-05 14:48:44 -080014/* Offset to identify DRAM type. */
15#define SPD_DRAM_TYPE_OFF 2
16#define SPD_DRAM_LPDDR3 0xf1
17#define SPD_DRAM_DDR4 0x0c
Furquan Shaikhcbed0c22017-04-14 22:11:13 -070018
Furquan Shaikh48be29e2017-12-05 14:48:44 -080019/* Length of SPD data. */
20#define SPD_LEN_LPDDR3 256
21#define SPD_LEN_DDR4 512
Furquan Shaikhcbed0c22017-04-14 22:11:13 -070022
Furquan Shaikh48be29e2017-12-05 14:48:44 -080023/* Fields that are common across different memory types. */
24#define SPD_DENSITY_BANKS_OFF 4
25#define SPD_ADDRESSING_OFF 5
26#define SPD_PART_LEN 18
27
28/* Fields that are different depending upon memory type. */
29#define SPD_ORG_OFF_LPDDR3 7
30#define SPD_BUSW_OFF_LPDDR3 8
31#define SPD_PART_OFF_LPDDR3 128
32
33#define SPD_ORG_OFF_DDR4 12
34#define SPD_BUSW_OFF_DDR4 13
35#define SPD_PART_OFF_DDR4 329
36
37#define SPD_INFO(_type) \
38 [MEMORY_##_type] = { \
39 .str = #_type, \
40 .type_code = SPD_DRAM_##_type, \
41 .len = SPD_LEN_##_type, \
42 .org_off = SPD_ORG_OFF_##_type, \
43 .busw_off = SPD_BUSW_OFF_##_type, \
44 .part_off = SPD_PART_OFF_##_type, \
45 }
46
47static const struct dram_info {
48 const char *str;
49 uint16_t type_code;
50 uint16_t len;
51 uint16_t org_off;
52 uint16_t busw_off;
53 uint16_t part_off;
54} spd_info[MEMORY_COUNT] = {
55 SPD_INFO(LPDDR3),
56 SPD_INFO(DDR4),
57};
58
59static void mainboard_print_spd_info(const uint8_t *spd, enum memory_type type)
Furquan Shaikhcbed0c22017-04-14 22:11:13 -070060{
61 const int spd_banks[8] = { 8, 16, 32, 64, -1, -1, -1, -1 };
62 const int spd_capmb[8] = { 1, 2, 4, 8, 16, 32, 64, 0 };
63 const int spd_rows[8] = { 12, 13, 14, 15, 16, -1, -1, -1 };
64 const int spd_cols[8] = { 9, 10, 11, 12, -1, -1, -1, -1 };
65 const int spd_ranks[8] = { 1, 2, 3, 4, -1, -1, -1, -1 };
66 const int spd_devw[8] = { 4, 8, 16, 32, -1, -1, -1, -1 };
67 const int spd_busw[8] = { 8, 16, 32, 64, -1, -1, -1, -1 };
68 char spd_name[SPD_PART_LEN+1] = { 0 };
Furquan Shaikh48be29e2017-12-05 14:48:44 -080069 const struct dram_info *info = &spd_info[type];
Furquan Shaikhcbed0c22017-04-14 22:11:13 -070070
Furquan Shaikh48be29e2017-12-05 14:48:44 -080071 assert (info->type_code == spd[SPD_DRAM_TYPE_OFF]);
Furquan Shaikhcbed0c22017-04-14 22:11:13 -070072
73 /* Module type */
Furquan Shaikh48be29e2017-12-05 14:48:44 -080074 printk(BIOS_INFO, "SPD: module type is %s\n", info->str);
75
76 int banks = spd_banks[(spd[SPD_DENSITY_BANKS_OFF] >> 4) & 7];
77 int capmb = spd_capmb[spd[SPD_DENSITY_BANKS_OFF] & 7] * 256;
78 int rows = spd_rows[(spd[SPD_ADDRESSING_OFF] >> 3) & 7];
79 int cols = spd_cols[spd[SPD_ADDRESSING_OFF] & 7];
80 int ranks = spd_ranks[(spd[info->org_off] >> 3) & 7];
81 int devw = spd_devw[spd[info->org_off] & 7];
82 int busw = spd_busw[spd[info->busw_off] & 7];
Furquan Shaikhcbed0c22017-04-14 22:11:13 -070083
84 /* Module Part Number */
Furquan Shaikh48be29e2017-12-05 14:48:44 -080085 memcpy(spd_name, &spd[info->part_off], SPD_PART_LEN);
Furquan Shaikhcbed0c22017-04-14 22:11:13 -070086 spd_name[SPD_PART_LEN] = 0;
87 printk(BIOS_INFO, "SPD: module part is %s\n", spd_name);
88
89 printk(BIOS_INFO,
90 "SPD: banks %d, ranks %d, rows %d, columns %d, density %d Mb\n",
91 banks, ranks, rows, cols, capmb);
92 printk(BIOS_INFO, "SPD: device width %d bits, bus width %d bits\n",
93 devw, busw);
94
95 if (capmb > 0 && busw > 0 && devw > 0 && ranks > 0) {
96 /* SIZE = DENSITY / 8 * BUS_WIDTH / SDRAM_WIDTH * RANKS */
97 printk(BIOS_INFO, "SPD: module size is %u MB (per channel)\n",
98 capmb / 8 * busw / devw * ranks);
99 }
100}
101
Furquan Shaikh908ea912018-03-02 14:36:56 -0800102static uintptr_t mainboard_get_spd_data(enum memory_type type, bool use_sec_spd)
Furquan Shaikhcbed0c22017-04-14 22:11:13 -0700103{
104 char *spd_file;
105 size_t spd_file_len;
106 int spd_index;
Furquan Shaikh48be29e2017-12-05 14:48:44 -0800107 const size_t spd_len = spd_info[type].len;
Furquan Shaikh908ea912018-03-02 14:36:56 -0800108 const char *spd_bin = use_sec_spd ? "sec-spd.bin" : "spd.bin";
Furquan Shaikhcbed0c22017-04-14 22:11:13 -0700109
110 spd_index = variant_memory_sku();
111 assert(spd_index >= 0);
112 printk(BIOS_INFO, "SPD index %d\n", spd_index);
113
114 /* Load SPD data from CBFS */
Julius Werner834b3ec2020-03-04 16:52:08 -0800115 spd_file = cbfs_map(spd_bin, &spd_file_len);
Furquan Shaikhcbed0c22017-04-14 22:11:13 -0700116 if (!spd_file)
117 die("SPD data not found.");
118
119 /* make sure we have at least one SPD in the file. */
Furquan Shaikh48be29e2017-12-05 14:48:44 -0800120 if (spd_file_len < spd_len)
Furquan Shaikhcbed0c22017-04-14 22:11:13 -0700121 die("Missing SPD data.");
122
123 /* Make sure we did not overrun the buffer */
Furquan Shaikh48be29e2017-12-05 14:48:44 -0800124 if (spd_file_len < ((spd_index + 1) * spd_len))
125 die("Invalid SPD index.");
Furquan Shaikhcbed0c22017-04-14 22:11:13 -0700126
Furquan Shaikh48be29e2017-12-05 14:48:44 -0800127 spd_index *= spd_len;
128 mainboard_print_spd_info((uint8_t *)(spd_file + spd_index), type);
Furquan Shaikhcbed0c22017-04-14 22:11:13 -0700129
130 return (uintptr_t)(spd_file + spd_index);
131}
Furquan Shaikh06cd9032016-12-14 12:10:21 -0800132
133void mainboard_memory_init_params(FSPM_UPD *mupd)
134{
135 FSP_M_CONFIG *mem_cfg = &mupd->FspmConfig;
Furquan Shaikhcbed0c22017-04-14 22:11:13 -0700136 struct memory_params p;
Furquan Shaikh06cd9032016-12-14 12:10:21 -0800137
Furquan Shaikhfb10ceb2018-08-05 20:59:25 -0700138 const struct pad_config *pads;
139 size_t num;
140
141 pads = variant_romstage_gpio_table(&num);
142 gpio_configure_pads(pads, num);
143
Nicolas Boichat27c2ab62018-03-12 09:08:15 +0800144 memset(&p, 0, sizeof(p));
Furquan Shaikhcbed0c22017-04-14 22:11:13 -0700145 variant_memory_params(&p);
146
Furquan Shaikh48be29e2017-12-05 14:48:44 -0800147 assert(p.type < MEMORY_COUNT);
148
149 if (p.dq_map && p.dq_map_size)
150 memcpy(&mem_cfg->DqByteMapCh0, p.dq_map, p.dq_map_size);
151
152 if (p.dqs_map && p.dqs_map_size)
153 memcpy(&mem_cfg->DqsMapCpu2DramCh0, p.dqs_map, p.dqs_map_size);
154
Furquan Shaikhcbed0c22017-04-14 22:11:13 -0700155 memcpy(&mem_cfg->RcompResistor, p.rcomp_resistor,
156 p.rcomp_resistor_size);
157 memcpy(&mem_cfg->RcompTarget, p.rcomp_target, p.rcomp_target_size);
Furquan Shaikh06cd9032016-12-14 12:10:21 -0800158
Furquan Shaikh908ea912018-03-02 14:36:56 -0800159 mem_cfg->MemorySpdPtr00 = mainboard_get_spd_data(p.type, p.use_sec_spd);
Shelley Chenbf00401e82018-10-22 18:07:04 -0700160 if (p.single_channel)
161 mem_cfg->MemorySpdPtr10 = 0;
162 else
163 mem_cfg->MemorySpdPtr10 = mem_cfg->MemorySpdPtr00;
Furquan Shaikh48be29e2017-12-05 14:48:44 -0800164 mem_cfg->MemorySpdDataLen = spd_info[p.type].len;
Seunghwan Kimc76e53c2018-09-03 20:25:50 +0900165
166 mem_cfg->SaOcSupport = p.enable_sa_oc_support;
167 mem_cfg->SaVoltageOffset = p.sa_voltage_offset_val;
Furquan Shaikh06cd9032016-12-14 12:10:21 -0800168}