soc/intel/ptl: Update ME specification version to 21
[coreboot.git] / src / drivers / spi / spi_flash_sfdp.c
blob94509fdf56c7b13407daf4c9488bab0566edc467
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <console/console.h>
4 #include <spi-generic.h>
5 #include <spi_flash.h>
6 #include <types.h>
8 #include "spi_flash_internal.h"
11 * Assumptions (not) made in the code:
12 * - code is supposed to be endian-safe
14 * Limitations:
15 * - only legacy access protocol supported:
16 * - only NOR flash
17 * - read SFDP instruction is sufficient and no fetch SFDP instruction needed
18 * - always 3 byte addresses for SFDP
19 * - only 1 bit SPI mode supported
20 * - always 8 dummy cycles after the address is sent
23 #define CMD_READ_SFDP 0x5a
25 static void read_sfdp_data_update_buffer_offset(uint8_t *buf_cmd, uint32_t offset)
27 buf_cmd[1] = offset >> 16 & 0xff;
28 buf_cmd[2] = offset >> 8 & 0xff;
29 buf_cmd[3] = offset >> 0 & 0xff;
32 static enum cb_err read_sfdp_data(const struct spi_flash *flash, uint32_t offset, size_t len,
33 uint8_t *buf)
35 uint8_t buf_cmd[5];
37 buf_cmd[0] = CMD_READ_SFDP;
38 /* the read offset in buf_cmd[1..3] gets written in
39 read_sfdp_data_update_buffer_offset */
40 buf_cmd[4] = 0; /* dummy byte */
42 uint8_t *data = buf;
44 /* split data transfers into chunks that each fit into the SPI controller's buffer */
45 while (len) {
46 uint32_t xfer_len = spi_crop_chunk(&flash->spi, sizeof(buf_cmd), len);
47 read_sfdp_data_update_buffer_offset(buf_cmd, offset);
48 if (spi_flash_cmd_multi(&flash->spi, buf_cmd, sizeof(buf_cmd), data, xfer_len))
49 return CB_ERR;
50 offset += xfer_len;
51 data += xfer_len;
52 len -= xfer_len;
55 return CB_SUCCESS;
58 #define SFDP_HEADER_OFFSET 0
59 #define SFDP_HEADER_LEN (2 * sizeof(uint32_t))
60 #define SFDP_HEADER_SIGNATURE 0x50444653 /* LE: "SFDP" */
61 #define SFDP_HEADER_ACCESS_PROTOCOL_LEGACY 0xff
62 /* header byte offsets */
63 #define SFDP_HEADER_SIGNATURE_0 0
64 #define SFDP_HEADER_SIGNATURE_1 1
65 #define SFDP_HEADER_SIGNATURE_2 2
66 #define SFDP_HEADER_SIGNATURE_3 3
67 #define SFDP_HEADER_MINOR_REV 4
68 #define SFDP_HEADER_MAJOR_REV 5
69 #define SFDP_HEADER_PARAMETER_HEADER_NUMBER 6
70 #define SFDP_HEADER_ACCESS_PROTOCOL 7
72 static enum cb_err get_sfdp_header(const struct spi_flash *flash, uint16_t *sfdp_revision,
73 uint8_t *number_of_parameter_headers,
74 uint8_t *access_prototcol)
76 uint8_t buf[SFDP_HEADER_LEN];
77 uint32_t signature;
79 if (read_sfdp_data(flash, SFDP_HEADER_OFFSET, SFDP_HEADER_LEN, buf) != CB_SUCCESS)
80 return CB_ERR;
82 signature = buf[SFDP_HEADER_SIGNATURE_0] | buf[SFDP_HEADER_SIGNATURE_1] << 8 |
83 buf[SFDP_HEADER_SIGNATURE_2] << 16 | buf[SFDP_HEADER_SIGNATURE_3] << 24;
84 *sfdp_revision = buf[SFDP_HEADER_MINOR_REV] | buf[SFDP_HEADER_MAJOR_REV] << 8;
85 *number_of_parameter_headers = buf[SFDP_HEADER_PARAMETER_HEADER_NUMBER] + 1;
86 *access_prototcol = buf[SFDP_HEADER_ACCESS_PROTOCOL];
88 if (signature != SFDP_HEADER_SIGNATURE)
89 return CB_ERR;
91 /* We make the assumption in the code that the legacy access protocol is used */
92 if (*access_prototcol != SFDP_HEADER_ACCESS_PROTOCOL_LEGACY)
93 return CB_ERR;
95 return CB_SUCCESS;
98 #define SFDP_PARAMETER_HEADER_LEN (2 * sizeof(uint32_t))
99 #define SFDP_PARAMETER_HEADER_OFFSET(n) (SFDP_HEADER_OFFSET + SFDP_HEADER_LEN + \
100 n * SFDP_PARAMETER_HEADER_LEN)
101 /* parameter header byte offsets */
102 #define SFDP_PARAMETER_HEADER_ID_LSB 0
103 #define SFDP_PARAMETER_HEADER_MINOR_REV 1
104 #define SFDP_PARAMETER_HEADER_MAJOR_REV 2
105 #define SFDP_PARAMETER_HEADER_LENGTH_DWORDS 3
106 #define SFDP_PARAMETER_HEADER_POINTER_0 4
107 #define SFDP_PARAMETER_HEADER_POINTER_1 5
108 #define SFDP_PARAMETER_HEADER_POINTER_2 6
109 #define SFDP_PARAMETER_HEADER_ID_MSB 7
111 /* get_sfdp_parameter_header_by_index must be called with a valid index */
112 static enum cb_err get_sfdp_parameter_header_by_index(const struct spi_flash *flash,
113 uint8_t index, uint16_t *id,
114 uint16_t *revision,
115 uint8_t *length_dwords,
116 uint32_t *table_pointer)
118 uint8_t buf[SFDP_PARAMETER_HEADER_LEN];
120 if (read_sfdp_data(flash, SFDP_PARAMETER_HEADER_OFFSET(index),
121 SFDP_PARAMETER_HEADER_LEN, buf) != CB_SUCCESS)
122 return CB_ERR;
124 *id = buf[SFDP_PARAMETER_HEADER_ID_LSB] | buf[SFDP_PARAMETER_HEADER_ID_MSB] << 8;
125 *revision = buf[SFDP_PARAMETER_HEADER_MINOR_REV] |
126 buf[SFDP_PARAMETER_HEADER_MAJOR_REV] << 8;
127 *length_dwords = buf[SFDP_PARAMETER_HEADER_LENGTH_DWORDS];
128 *table_pointer = buf[SFDP_PARAMETER_HEADER_POINTER_0] |
129 buf[SFDP_PARAMETER_HEADER_POINTER_1] << 8 |
130 buf[SFDP_PARAMETER_HEADER_POINTER_2] << 16;
132 /* the parameter table pointer byte address must be DWORD-aligned */
133 if (!IS_ALIGNED(*table_pointer, sizeof(uint32_t)))
134 return CB_ERR;
136 /* TODO: check id validity? */
138 return CB_SUCCESS;
141 void spi_flash_print_sfdp_headers(const struct spi_flash *flash)
143 enum cb_err stat;
144 uint16_t sfdp_rev;
145 uint8_t param_header_count;
146 uint8_t access_protocol;
148 if (get_sfdp_header(flash, &sfdp_rev, &param_header_count, &access_protocol) !=
149 CB_SUCCESS) {
150 printk(BIOS_ERR, "Failed to read SFDP header from SPI flash\n");
151 return;
154 printk(BIOS_DEBUG, "SFDP header found in SPI flash.\n");
155 printk(BIOS_DEBUG, "major rev %#x, minor rev %#x, access protocol %#x, "
156 "number of headers %d\n", sfdp_rev >> 8, sfdp_rev & 0xff, access_protocol,
157 param_header_count);
159 uint16_t tbl_id;
160 uint16_t tbl_rev;
161 uint8_t tbl_len_dwords;
162 uint32_t tbl_pointer;
164 for (unsigned int i = 0; i < param_header_count; i++) {
165 stat = get_sfdp_parameter_header_by_index(flash, i, &tbl_id, &tbl_rev,
166 &tbl_len_dwords, &tbl_pointer);
168 if (stat == CB_SUCCESS) {
169 printk(BIOS_DEBUG, "SFPD header with index %d:\n", i);
170 printk(BIOS_DEBUG, " table ID %#x, major rev %#x, minor rev %#x\n",
171 tbl_id, tbl_rev >> 8, tbl_rev & 0xff);
172 printk(BIOS_DEBUG, " table pointer %#x, table length DWORDS %#x\n",
173 tbl_pointer, tbl_len_dwords);
174 } else {
175 printk(BIOS_ERR, "Cound't read SFPD header with index %d.\n", i);
180 static enum cb_err find_sfdp_parameter_header(const struct spi_flash *flash, uint16_t table_id,
181 uint16_t *revision, uint8_t *length_dwords,
182 uint32_t *table_pointer)
184 enum cb_err stat;
185 uint16_t sfdp_rev;
186 uint8_t param_header_count;
187 uint8_t access_protocol;
189 if (get_sfdp_header(flash, &sfdp_rev, &param_header_count, &access_protocol) !=
190 CB_SUCCESS)
191 return CB_ERR;
193 /* TODO: add version check? */
195 uint16_t tbl_id;
196 uint16_t tbl_rev;
197 uint8_t tbl_len_dwords;
198 uint32_t tbl_pointer;
200 for (unsigned int i = 0; i < param_header_count; i++) {
201 stat = get_sfdp_parameter_header_by_index(flash, i, &tbl_id, &tbl_rev,
202 &tbl_len_dwords, &tbl_pointer);
204 if (stat == CB_SUCCESS && tbl_id == table_id) {
205 *revision = tbl_rev;
206 *length_dwords = tbl_len_dwords;
207 *table_pointer = tbl_pointer;
208 return CB_SUCCESS;
212 printk(BIOS_WARNING, "Cound't find SFPD header with table ID %#x.\n", table_id);
214 return CB_ERR;
217 #define SFDP_PARAMETER_ID_RPMC 0xff03
219 #define SFDP_RPMC_TABLE_LENGTH_DWORDS 2
220 #define SFDP_RPMC_TABLE_SUPPORTED_MAJOR_REV 1
222 /* RPMC parameter table byte offsets and fields */
223 #define SFDP_RPMC_TABLE_CONFIG 0
224 #define SFDP_RPMC_TABLE_CONFIG_FLASH_HARDENING_BIT BIT(0)
225 #define SFDP_RPMC_TABLE_CONFIG_MONOTONIC_COUNTER_SIZE_BIT BIT(1)
226 #define SFDP_RPMC_TABLE_CONFIG_BUSY_POLLING_METHOD BIT(2)
227 #define SFDP_RPMC_TABLE_CONFIG_RESERVED BIT(3)
228 #define SFDP_RPMC_TABLE_CONFIG_RESERVED_VALUE 0x08
229 #define SFDP_RPMC_TABLE_CONFIG_NUM_COUNTERS_MASK 0xf0
230 #define SFDP_RPMC_TABLE_CONFIG_NUM_COUNTERS_SHIFT 4
231 #define SFDP_RPMC_TABLE_RPMC_OP1 1
232 #define SFDP_RPMC_TABLE_RPMC_OP2 2
233 #define SFDP_RPMC_TABLE_UPDATE_RATE 3
234 #define SFDP_RPMC_TABLE_UPDATE_RATE_MASK 0x0f
235 #define SFDP_RPMC_TABLE_UPDATE_RATE_RESERVED_MASK 0xf0
236 #define SFDP_RPMC_TABLE_UPDATE_RATE_RESERVED_VALUE 0xf0
237 #define SFDP_RPMC_TABLE_READ_COUNTER_POLLING_DELAY 4
238 #define SFDP_RPMC_TABLE_WRITE_COUNTER_POLLING_SHORT_DELAY 5
239 #define SFDP_RPMC_TABLE_WRITE_COUNTER_POLLING_LONG_DELAY 6
240 #define SFDP_RPMC_TABLE_RESERVED_BYTE 7
241 #define SFDP_RPMC_TABLE_RESERVED_BYTE_VALUE 0xff
243 static uint64_t calc_rpmc_update_rate_s(uint8_t val)
245 /* val is at most 15, so this won't overflow */
246 return 5 * 1 << (val & SFDP_RPMC_TABLE_UPDATE_RATE_MASK);
249 #define SPDF_RPMC_DELAY_VALUE_MASK 0x1f
250 #define SPDF_RPMC_DELAY_UNIT_MASK 0x60
251 #define SPDF_RPMC_DELAY_UNIT_SHIFT 5
252 #define SPDF_RPMC_DELAY_SHORT_UNIT_0_US 1 /* 1us */
253 #define SPDF_RPMC_DELAY_SHORT_UNIT_1_US 16 /* 16us */
254 #define SPDF_RPMC_DELAY_SHORT_UNIT_2_US 128 /* 128us */
255 #define SPDF_RPMC_DELAY_SHORT_UNIT_3_US 1000 /* 1ms */
256 #define SPDF_RPMC_DELAY_LONG_UNIT_0_US 1000 /* 1ms */
257 #define SPDF_RPMC_DELAY_LONG_UNIT_1_US 16000 /* 16ms */
258 #define SPDF_RPMC_DELAY_LONG_UNIT_2_US 128000 /* 128ms */
259 #define SPDF_RPMC_DELAY_LONG_UNIT_3_US 1000000 /* 1s */
261 static uint64_t calc_rpmc_short_delay_us(uint8_t val)
263 const uint8_t value = val & SPDF_RPMC_DELAY_VALUE_MASK;
264 const uint8_t shift = (val & SPDF_RPMC_DELAY_UNIT_MASK) >> SPDF_RPMC_DELAY_UNIT_SHIFT;
265 uint64_t multiplier;
267 switch (shift) {
268 case 0:
269 multiplier = SPDF_RPMC_DELAY_SHORT_UNIT_0_US;
270 break;
271 case 1:
272 multiplier = SPDF_RPMC_DELAY_SHORT_UNIT_1_US;
273 break;
274 case 2:
275 multiplier = SPDF_RPMC_DELAY_SHORT_UNIT_2_US;
276 break;
277 default:
278 multiplier = SPDF_RPMC_DELAY_SHORT_UNIT_3_US;
279 break;
282 return value * multiplier;
285 static uint64_t calc_rpmc_long_delay_us(uint8_t val)
287 const uint8_t value = val & SPDF_RPMC_DELAY_VALUE_MASK;
288 const uint8_t shift = (val & SPDF_RPMC_DELAY_UNIT_MASK) >> SPDF_RPMC_DELAY_UNIT_SHIFT;
289 uint64_t multiplier;
291 switch (shift) {
292 case 0:
293 multiplier = SPDF_RPMC_DELAY_LONG_UNIT_0_US;
294 break;
295 case 1:
296 multiplier = SPDF_RPMC_DELAY_LONG_UNIT_1_US;
297 break;
298 case 2:
299 multiplier = SPDF_RPMC_DELAY_LONG_UNIT_2_US;
300 break;
301 default:
302 multiplier = SPDF_RPMC_DELAY_LONG_UNIT_3_US;
303 break;
306 return value * multiplier;
309 enum cb_err spi_flash_get_sfdp_rpmc(const struct spi_flash *flash,
310 struct sfdp_rpmc_info *rpmc_info)
312 uint16_t rev;
313 uint8_t length_dwords;
314 uint32_t table_pointer;
315 uint8_t buf[SFDP_RPMC_TABLE_LENGTH_DWORDS * sizeof(uint32_t)];
317 if (find_sfdp_parameter_header(flash, SFDP_PARAMETER_ID_RPMC, &rev, &length_dwords,
318 &table_pointer) != CB_SUCCESS)
319 return CB_ERR;
321 if (length_dwords != SFDP_RPMC_TABLE_LENGTH_DWORDS)
322 return CB_ERR;
324 if (rev >> 8 != SFDP_RPMC_TABLE_SUPPORTED_MAJOR_REV) {
325 printk(BIOS_ERR, "Unsupprted major RPMC table revision %#x\n", rev >> 8);
326 return CB_ERR;
329 if (read_sfdp_data(flash, table_pointer, sizeof(buf), buf) != CB_SUCCESS)
330 return CB_ERR;
332 if ((buf[SFDP_RPMC_TABLE_CONFIG] & SFDP_RPMC_TABLE_CONFIG_RESERVED) !=
333 SFDP_RPMC_TABLE_CONFIG_RESERVED_VALUE ||
334 (buf[SFDP_RPMC_TABLE_UPDATE_RATE] & SFDP_RPMC_TABLE_UPDATE_RATE_RESERVED_MASK) !=
335 SFDP_RPMC_TABLE_UPDATE_RATE_RESERVED_VALUE ||
336 buf[SFDP_RPMC_TABLE_RESERVED_BYTE] != SFDP_RPMC_TABLE_RESERVED_BYTE_VALUE) {
337 printk(BIOS_ERR, "Unexpected reserved values in RPMC table\n");
338 return CB_ERR;
341 rpmc_info->flash_hardening = !!(buf[SFDP_RPMC_TABLE_CONFIG] &
342 SFDP_RPMC_TABLE_CONFIG_FLASH_HARDENING_BIT);
343 rpmc_info->monotonic_counter_size = (buf[SFDP_RPMC_TABLE_CONFIG] &
344 SFDP_RPMC_TABLE_CONFIG_FLASH_HARDENING_BIT) ?
345 SFDP_RPMC_COUNTER_BITS_RESERVED :
346 SFDP_RPMC_COUNTER_BITS_32;
347 rpmc_info->busy_polling_method = (buf[SFDP_RPMC_TABLE_CONFIG] &
348 SFDP_RPMC_TABLE_CONFIG_BUSY_POLLING_METHOD) ?
349 SFDP_RPMC_POLL_READ_STATUS :
350 SFDP_RPMC_POLL_OP2_EXTENDED_STATUS;
351 rpmc_info->number_of_counters = ((buf[SFDP_RPMC_TABLE_CONFIG] &
352 SFDP_RPMC_TABLE_CONFIG_NUM_COUNTERS_MASK) >>
353 SFDP_RPMC_TABLE_CONFIG_NUM_COUNTERS_SHIFT) + 1;
354 rpmc_info->op1_write_command = buf[SFDP_RPMC_TABLE_RPMC_OP1];
355 rpmc_info->op2_read_command = buf[SFDP_RPMC_TABLE_RPMC_OP2];
356 rpmc_info->update_rate_s = calc_rpmc_update_rate_s(buf[SFDP_RPMC_TABLE_UPDATE_RATE] &
357 SFDP_RPMC_TABLE_UPDATE_RATE_MASK);
358 rpmc_info->read_counter_polling_delay_us = calc_rpmc_short_delay_us(
359 buf[SFDP_RPMC_TABLE_READ_COUNTER_POLLING_DELAY]);
360 rpmc_info->write_counter_polling_short_delay_us = calc_rpmc_short_delay_us(
361 buf[SFDP_RPMC_TABLE_WRITE_COUNTER_POLLING_SHORT_DELAY]);
362 rpmc_info->write_counter_polling_long_delay_us = calc_rpmc_long_delay_us(
363 buf[SFDP_RPMC_TABLE_WRITE_COUNTER_POLLING_LONG_DELAY]);
364 return CB_SUCCESS;