blob: 9e625b522849691b756d33f91be0dfe786e56309 [file] [log] [blame]
Naresh G Solanki335781a2016-10-26 19:43:14 +05301/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2016 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
Naresh G Solanki335781a2016-10-26 19:43:14 +053016#include <cbfs.h>
17#include <console/console.h>
18#include <spd_bin.h>
19#include <string.h>
Patrick Georgi0e3c59e2017-01-28 15:59:25 +010020#include <device/dram/ddr3.h>
Naresh G Solanki335781a2016-10-26 19:43:14 +053021
Naresh G Solanki335781a2016-10-26 19:43:14 +053022void dump_spd_info(struct spd_block *blk)
23{
24 u8 i;
25
26 for (i = 0; i < CONFIG_DIMM_MAX; i++)
27 if (blk->spd_array[i] != NULL && blk->spd_array[i][0] != 0) {
Furquan Shaikha26f9da2017-06-08 13:28:59 -070028 printk(BIOS_DEBUG, "SPD @ 0x%02X\n", blk->addr_map[i]);
Naresh G Solanki335781a2016-10-26 19:43:14 +053029 print_spd_info(blk->spd_array[i]);
30 }
31}
32
Eric Laiaa8d7722019-09-02 15:01:56 +080033static bool is_memory_type_ddr4(int dram_type)
Naresh G Solanki335781a2016-10-26 19:43:14 +053034{
Eric Laiaa8d7722019-09-02 15:01:56 +080035 return (dram_type == SPD_DRAM_DDR4);
36}
Naresh G Solanki335781a2016-10-26 19:43:14 +053037
Eric Laiaa8d7722019-09-02 15:01:56 +080038static const char *spd_get_module_type_string(int dram_type)
39{
40 switch (dram_type) {
Naresh G Solanki335781a2016-10-26 19:43:14 +053041 case SPD_DRAM_DDR3:
Eric Laiaa8d7722019-09-02 15:01:56 +080042 return "DDR3";
43 case SPD_DRAM_LPDDR3_INTEL:
44 case SPD_DRAM_LPDDR3_JEDEC:
45 return "LPDDR3";
46 case SPD_DRAM_DDR4:
47 return "DDR4";
48 }
49 return "UNKNOWN";
50}
51
52static int spd_get_banks(const uint8_t spd[], int dram_type)
53{
54 static const int ddr3_banks[4] = { 8, 16, 32, 64 };
55 static const int ddr4_banks[10] = { 4, 8, -1, -1, 8, 16, -1, -1, 16, 32 };
56 int index = (spd[SPD_DENSITY_BANKS] >> 4) & 0xf;
57 switch (dram_type) {
58 /* DDR3 and LPDDR3 has the same bank definition */
59 case SPD_DRAM_DDR3:
60 case SPD_DRAM_LPDDR3_INTEL:
61 case SPD_DRAM_LPDDR3_JEDEC:
62 if (index >= ARRAY_SIZE(ddr3_banks))
63 return -1;
64 return ddr3_banks[index];
65 case SPD_DRAM_DDR4:
66 if (index >= ARRAY_SIZE(ddr4_banks))
67 return -1;
68 return ddr4_banks[index];
69 default:
70 return -1;
71 }
72}
73
74static int spd_get_capmb(const uint8_t spd[])
75{
76 static const int spd_capmb[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 48, 96 };
77 int index = spd[SPD_DENSITY_BANKS] & 0xf;
78 if (index >= ARRAY_SIZE(spd_capmb))
79 return -1;
80 return spd_capmb[index] * 256;
81}
82
83static int spd_get_rows(const uint8_t spd[])
84{
85 static const int spd_rows[7] = { 12, 13, 14, 15, 16, 17, 18 };
86 int index = (spd[SPD_ADDRESSING] >> 3) & 7;
87 if (index >= ARRAY_SIZE(spd_rows))
88 return -1;
89 return spd_rows[index];
90}
91
92static int spd_get_cols(const uint8_t spd[])
93{
94 static const int spd_cols[4] = { 9, 10, 11, 12 };
95 int index = spd[SPD_ADDRESSING] & 7;
96 if (index >= ARRAY_SIZE(spd_cols))
97 return -1;
98 return spd_cols[index];
99}
100
101static int spd_get_ranks(const uint8_t spd[], int dram_type)
102{
103 static const int spd_ranks[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
104 int organ_offset = is_memory_type_ddr4(dram_type) ? DDR4_ORGANIZATION
105 : DDR3_ORGANIZATION;
106 int index = (spd[organ_offset] >> 3) & 7;
107 if (index >= ARRAY_SIZE(spd_ranks))
108 return -1;
109 return spd_ranks[index];
110}
111
112static int spd_get_devw(const uint8_t spd[], int dram_type)
113{
114 static const int spd_devw[4] = { 4, 8, 16, 32 };
115 int organ_offset = is_memory_type_ddr4(dram_type) ? DDR4_ORGANIZATION
116 : DDR3_ORGANIZATION;
117 int index = spd[organ_offset] & 7;
118 if (index >= ARRAY_SIZE(spd_devw))
119 return -1;
120 return spd_devw[index];
121}
122
123static int spd_get_busw(const uint8_t spd[], int dram_type)
124{
125 static const int spd_busw[4] = { 8, 16, 32, 64 };
126 int busw_offset = is_memory_type_ddr4(dram_type) ? DDR4_BUS_DEV_WIDTH
127 : DDR3_BUS_DEV_WIDTH;
128 int index = spd[busw_offset] & 7;
129 if (index >= ARRAY_SIZE(spd_busw))
130 return -1;
131 return spd_busw[index];
132}
133
134static void spd_get_name(const uint8_t spd[], char spd_name[], int dram_type)
135{
136 switch (dram_type) {
137 case SPD_DRAM_DDR3:
Naresh G Solanki335781a2016-10-26 19:43:14 +0530138 memcpy(spd_name, &spd[DDR3_SPD_PART_OFF], DDR3_SPD_PART_LEN);
139 spd_name[DDR3_SPD_PART_LEN] = 0;
140 break;
141 case SPD_DRAM_LPDDR3_INTEL:
142 case SPD_DRAM_LPDDR3_JEDEC:
Naresh G Solanki335781a2016-10-26 19:43:14 +0530143 memcpy(spd_name, &spd[LPDDR3_SPD_PART_OFF],
144 LPDDR3_SPD_PART_LEN);
145 spd_name[LPDDR3_SPD_PART_LEN] = 0;
146 break;
147 case SPD_DRAM_DDR4:
Naresh G Solanki335781a2016-10-26 19:43:14 +0530148 memcpy(spd_name, &spd[DDR4_SPD_PART_OFF], DDR4_SPD_PART_LEN);
149 spd_name[DDR4_SPD_PART_LEN] = 0;
Naresh G Solanki335781a2016-10-26 19:43:14 +0530150 break;
151 default:
Naresh G Solanki335781a2016-10-26 19:43:14 +0530152 break;
153 }
Eric Laiaa8d7722019-09-02 15:01:56 +0800154}
155
156void print_spd_info(uint8_t spd[])
157{
158 char spd_name[DDR4_SPD_PART_LEN+1] = { 0 };
159 int type = spd[SPD_DRAM_TYPE];
160 int banks = spd_get_banks(spd, type);
161 int capmb = spd_get_capmb(spd);
162 int rows = spd_get_rows(spd);
163 int cols = spd_get_cols(spd);
164 int ranks = spd_get_ranks(spd, type);
165 int devw = spd_get_devw(spd, type);
166 int busw = spd_get_busw(spd, type);
167
168 /* Module type */
169 printk(BIOS_INFO, "SPD: module type is %s\n",
170 spd_get_module_type_string(type));
171 /* Module Part Number */
172 spd_get_name(spd, spd_name, type);
Naresh G Solanki335781a2016-10-26 19:43:14 +0530173
174 printk(BIOS_INFO, "SPD: module part is %s\n", spd_name);
175
176 printk(BIOS_INFO,
177 "SPD: banks %d, ranks %d, rows %d, columns %d, density %d Mb\n",
178 banks, ranks, rows, cols, capmb);
179 printk(BIOS_INFO, "SPD: device width %d bits, bus width %d bits\n",
180 devw, busw);
181
182 if (capmb > 0 && busw > 0 && devw > 0 && ranks > 0) {
183 /* SIZE = DENSITY / 8 * BUS_WIDTH / SDRAM_WIDTH * RANKS */
184 printk(BIOS_INFO, "SPD: module size is %u MB (per channel)\n",
185 capmb / 8 * busw / devw * ranks);
186 }
187}
188
Naresh G Solanki335781a2016-10-26 19:43:14 +0530189int get_spd_cbfs_rdev(struct region_device *spd_rdev, u8 spd_index)
190{
191 struct cbfsf fh;
192
193 uint32_t cbfs_type = CBFS_TYPE_SPD;
194
Naresh G Solankib8a57362016-12-13 20:27:15 +0530195 if (cbfs_boot_locate(&fh, "spd.bin", &cbfs_type) < 0)
196 return -1;
Naresh G Solanki335781a2016-10-26 19:43:14 +0530197 cbfs_file_data(spd_rdev, &fh);
198 return rdev_chain(spd_rdev, spd_rdev, spd_index * CONFIG_DIMM_SPD_SIZE,
199 CONFIG_DIMM_SPD_SIZE);
200}
201
Patrick Georgi0e3c59e2017-01-28 15:59:25 +0100202#if CONFIG_DIMM_SPD_SIZE == 128
203int read_ddr3_spd_from_cbfs(u8 *buf, int idx)
204{
205 const int SPD_CRC_HI = 127;
206 const int SPD_CRC_LO = 126;
207
208 const char *spd_file;
209 size_t spd_file_len = 0;
210 size_t min_len = (idx + 1) * CONFIG_DIMM_SPD_SIZE;
211
212 spd_file = cbfs_boot_map_with_leak("spd.bin", CBFS_TYPE_SPD,
213 &spd_file_len);
214 if (!spd_file)
215 printk(BIOS_EMERG, "file [spd.bin] not found in CBFS");
216 if (spd_file_len < min_len)
217 printk(BIOS_EMERG, "Missing SPD data.");
218 if (!spd_file || spd_file_len < min_len)
219 return -1;
220
Lee Leahy73402172017-03-10 15:23:24 -0800221 memcpy(buf, spd_file + (idx * CONFIG_DIMM_SPD_SIZE),
222 CONFIG_DIMM_SPD_SIZE);
Patrick Georgi0e3c59e2017-01-28 15:59:25 +0100223
224 u16 crc = spd_ddr3_calc_crc(buf, CONFIG_DIMM_SPD_SIZE);
225
226 if (((buf[SPD_CRC_LO] == 0) && (buf[SPD_CRC_HI] == 0))
Lee Leahye20a3192017-03-09 16:21:34 -0800227 || (buf[SPD_CRC_LO] != (crc & 0xff))
228 || (buf[SPD_CRC_HI] != (crc >> 8))) {
Lee Leahy73402172017-03-10 15:23:24 -0800229 printk(BIOS_WARNING,
230 "SPD CRC %02x%02x is invalid, should be %04x\n",
Patrick Georgi0e3c59e2017-01-28 15:59:25 +0100231 buf[SPD_CRC_HI], buf[SPD_CRC_LO], crc);
232 buf[SPD_CRC_LO] = crc & 0xff;
233 buf[SPD_CRC_HI] = crc >> 8;
234 u16 i;
235 printk(BIOS_WARNING, "\nDisplay the SPD");
236 for (i = 0; i < CONFIG_DIMM_SPD_SIZE; i++) {
Lee Leahy45fde702017-03-08 18:02:24 -0800237 if ((i % 16) == 0x00)
Patrick Georgi0e3c59e2017-01-28 15:59:25 +0100238 printk(BIOS_WARNING, "\n%02x: ", i);
239 printk(BIOS_WARNING, "%02x ", buf[i]);
240 }
241 printk(BIOS_WARNING, "\n");
Lee Leahye20a3192017-03-09 16:21:34 -0800242 }
243 return 0;
Patrick Georgi0e3c59e2017-01-28 15:59:25 +0100244}
245#endif