blob: 16041322f31b2cd705bd18d4d0e2ae79621eff97 [file] [log] [blame]
Angel Pons0612b272020-04-05 15:46:56 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Barnali Sarkar89331cd2017-02-16 17:22:37 +05303
Kyösti Mälkki13f66502019-03-03 08:01:05 +02004#include <device/mmio.h>
Elyes HAOUASf97c1c92019-12-03 18:22:06 +01005#include <commonlib/helpers.h>
Barnali Sarkar89331cd2017-02-16 17:22:37 +05306#include <console/console.h>
7#include <fast_spi_def.h>
8#include <intelblocks/fast_spi.h>
Barnali Sarkar89331cd2017-02-16 17:22:37 +05309#include <soc/pci_devs.h>
10#include <spi_flash.h>
11#include <string.h>
12#include <timer.h>
13
14/* Helper to create a FAST_SPI context on API entry. */
15#define BOILERPLATE_CREATE_CTX(ctx) \
16 struct fast_spi_flash_ctx real_ctx; \
17 struct fast_spi_flash_ctx *ctx = &real_ctx; \
18 _fast_spi_flash_get_ctx(ctx)
19
20/*
21 * Anything that's not success is <0. Provided solely for readability, as these
22 * constants are not used outside this file.
23 */
24enum errors {
25 SUCCESS = 0,
26 E_TIMEOUT = -1,
27 E_HW_ERROR = -2,
28 E_ARGUMENT = -3,
29};
30
31/* Reduce data-passing burden by grouping transaction data in a context. */
32struct fast_spi_flash_ctx {
33 uintptr_t mmio_base;
34};
35
36static void _fast_spi_flash_get_ctx(struct fast_spi_flash_ctx *ctx)
37{
38 ctx->mmio_base = (uintptr_t)fast_spi_get_bar();
39}
40
41/* Read register from the FAST_SPI flash controller. */
42static uint32_t fast_spi_flash_ctrlr_reg_read(struct fast_spi_flash_ctx *ctx,
43 uint16_t reg)
44{
45 uintptr_t addr = ALIGN_DOWN(ctx->mmio_base + reg, sizeof(uint32_t));
46 return read32((void *)addr);
47}
48
49/* Write to register in FAST_SPI flash controller. */
50static void fast_spi_flash_ctrlr_reg_write(struct fast_spi_flash_ctx *ctx,
51 uint16_t reg, uint32_t val)
52{
53 uintptr_t addr = ALIGN_DOWN(ctx->mmio_base + reg, sizeof(uint32_t));
54 write32((void *)addr, val);
55}
56
57/*
58 * The hardware datasheet is not clear on what HORD values actually do. It
59 * seems that HORD_SFDP provides access to the first 8 bytes of the SFDP, which
60 * is the signature and revision fields. HORD_JEDEC provides access to the
61 * actual flash parameters, and is most likely what you want to use when
62 * probing the flash from software.
63 * It's okay to rely on SFDP, since the SPI flash controller requires an SFDP
64 * 1.5 or newer compliant FAST_SPI flash chip.
65 * NOTE: Due to the register layout of the hardware, all accesses will be
66 * aligned to a 4 byte boundary.
67 */
68static uint32_t fast_spi_flash_read_sfdp_param(struct fast_spi_flash_ctx *ctx,
69 uint16_t sfdp_reg)
70{
71 uint32_t ptinx_index = sfdp_reg & SPIBAR_PTINX_IDX_MASK;
72 fast_spi_flash_ctrlr_reg_write(ctx, SPIBAR_PTINX,
73 ptinx_index | SPIBAR_PTINX_HORD_JEDEC);
74 return fast_spi_flash_ctrlr_reg_read(ctx, SPIBAR_PTDATA);
75}
76
77/* Fill FDATAn FIFO in preparation for a write transaction. */
78static void fill_xfer_fifo(struct fast_spi_flash_ctx *ctx, const void *data,
79 size_t len)
80{
81 /* YES! memcpy() works. FDATAn does not require 32-bit accesses. */
82 memcpy((void *)(ctx->mmio_base + SPIBAR_FDATA(0)), data, len);
83}
84
85/* Drain FDATAn FIFO after a read transaction populates data. */
86static void drain_xfer_fifo(struct fast_spi_flash_ctx *ctx, void *dest,
87 size_t len)
88{
89 /* YES! memcpy() works. FDATAn does not require 32-bit accesses. */
90 memcpy(dest, (void *)(ctx->mmio_base + SPIBAR_FDATA(0)), len);
91}
92
93/* Fire up a transfer using the hardware sequencer. */
94static void start_hwseq_xfer(struct fast_spi_flash_ctx *ctx,
95 uint32_t hsfsts_cycle, uint32_t flash_addr, size_t len)
96{
97 /* Make sure all W1C status bits get cleared. */
98 uint32_t hsfsts = SPIBAR_HSFSTS_W1C_BITS;
99 /* Set up transaction parameters. */
100 hsfsts |= hsfsts_cycle & SPIBAR_HSFSTS_FCYCLE_MASK;
101 hsfsts |= SPIBAR_HSFSTS_FDBC(len - 1);
102
103 fast_spi_flash_ctrlr_reg_write(ctx, SPIBAR_FADDR, flash_addr);
104 fast_spi_flash_ctrlr_reg_write(ctx, SPIBAR_HSFSTS_CTL,
105 hsfsts | SPIBAR_HSFSTS_FGO);
106}
107
108static int wait_for_hwseq_xfer(struct fast_spi_flash_ctx *ctx,
109 uint32_t flash_addr)
110{
111 struct stopwatch sw;
112 uint32_t hsfsts;
113
114 stopwatch_init_msecs_expire(&sw, SPIBAR_HWSEQ_XFER_TIMEOUT);
115 do {
116 hsfsts = fast_spi_flash_ctrlr_reg_read(ctx, SPIBAR_HSFSTS_CTL);
117
118 if (hsfsts & SPIBAR_HSFSTS_FCERR) {
119 printk(BIOS_ERR, "SPI Transaction Error at Flash Offset %x HSFSTS = 0x%08x\n",
120 flash_addr, hsfsts);
121 return E_HW_ERROR;
122 }
123
124 if (hsfsts & SPIBAR_HSFSTS_FDONE)
125 return SUCCESS;
126 } while (!(stopwatch_expired(&sw)));
127
128 printk(BIOS_ERR, "SPI Transaction Timeout (Exceeded %d ms) at Flash Offset %x HSFSTS = 0x%08x\n",
129 SPIBAR_HWSEQ_XFER_TIMEOUT, flash_addr, hsfsts);
130 return E_TIMEOUT;
131}
132
133/* Execute FAST_SPI flash transfer. This is a blocking call. */
134static int exec_sync_hwseq_xfer(struct fast_spi_flash_ctx *ctx,
135 uint32_t hsfsts_cycle, uint32_t flash_addr,
136 size_t len)
137{
138 start_hwseq_xfer(ctx, hsfsts_cycle, flash_addr, len);
139 return wait_for_hwseq_xfer(ctx, flash_addr);
140}
141
142/*
143 * Ensure read/write xfer len is not greater than SPIBAR_FDATA_FIFO_SIZE and
Furquan Shaikhfc1a1232017-05-12 00:19:56 -0700144 * that the operation does not cross page boundary.
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530145 */
Furquan Shaikhfc1a1232017-05-12 00:19:56 -0700146static size_t get_xfer_len(const struct spi_flash *flash, uint32_t addr,
147 size_t len)
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530148{
Elyes HAOUASf97c1c92019-12-03 18:22:06 +0100149 size_t xfer_len = MIN(len, SPIBAR_FDATA_FIFO_SIZE);
Furquan Shaikhfc1a1232017-05-12 00:19:56 -0700150 size_t bytes_left = ALIGN_UP(addr, flash->page_size) - addr;
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530151
152 if (bytes_left)
Elyes HAOUASf97c1c92019-12-03 18:22:06 +0100153 xfer_len = MIN(xfer_len, bytes_left);
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530154
155 return xfer_len;
156}
157
158
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530159static int fast_spi_flash_erase(const struct spi_flash *flash,
160 uint32_t offset, size_t len)
161{
162 int ret;
163 size_t erase_size;
164 uint32_t erase_cycle;
165
166 BOILERPLATE_CREATE_CTX(ctx);
167
168 if (!IS_ALIGNED(offset, 4 * KiB) || !IS_ALIGNED(len, 4 * KiB)) {
169 printk(BIOS_ERR, "BUG! SPI erase region not sector aligned\n");
170 return E_ARGUMENT;
171 }
172
173 while (len) {
174 if (IS_ALIGNED(offset, 64 * KiB) && (len >= 64 * KiB)) {
175 erase_size = 64 * KiB;
176 erase_cycle = SPIBAR_HSFSTS_CYCLE_64K_ERASE;
177 } else {
178 erase_size = 4 * KiB;
179 erase_cycle = SPIBAR_HSFSTS_CYCLE_4K_ERASE;
180 }
181 printk(BIOS_SPEW, "Erasing flash addr %x + %zu KiB\n",
182 offset, erase_size / KiB);
183
184 ret = exec_sync_hwseq_xfer(ctx, erase_cycle, offset, 0);
185 if (ret != SUCCESS)
186 return ret;
187
188 offset += erase_size;
189 len -= erase_size;
190 }
191
192 return SUCCESS;
193}
194
195static int fast_spi_flash_read(const struct spi_flash *flash,
196 uint32_t addr, size_t len, void *buf)
197{
198 int ret;
199 size_t xfer_len;
200 uint8_t *data = buf;
201
202 BOILERPLATE_CREATE_CTX(ctx);
203
204 while (len) {
Furquan Shaikhfc1a1232017-05-12 00:19:56 -0700205 xfer_len = get_xfer_len(flash, addr, len);
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530206
207 ret = exec_sync_hwseq_xfer(ctx, SPIBAR_HSFSTS_CYCLE_READ,
208 addr, xfer_len);
209 if (ret != SUCCESS)
210 return ret;
211
212 drain_xfer_fifo(ctx, data, xfer_len);
213
214 addr += xfer_len;
215 data += xfer_len;
216 len -= xfer_len;
217 }
218
219 return SUCCESS;
220}
221
222static int fast_spi_flash_write(const struct spi_flash *flash,
223 uint32_t addr, size_t len, const void *buf)
224{
225 int ret;
226 size_t xfer_len;
227 const uint8_t *data = buf;
228
229 BOILERPLATE_CREATE_CTX(ctx);
230
231 while (len) {
Furquan Shaikhfc1a1232017-05-12 00:19:56 -0700232 xfer_len = get_xfer_len(flash, addr, len);
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530233 fill_xfer_fifo(ctx, data, xfer_len);
234
235 ret = exec_sync_hwseq_xfer(ctx, SPIBAR_HSFSTS_CYCLE_WRITE,
236 addr, xfer_len);
237 if (ret != SUCCESS)
238 return ret;
239
240 addr += xfer_len;
241 data += xfer_len;
242 len -= xfer_len;
243 }
244
245 return SUCCESS;
246}
247
248static int fast_spi_flash_status(const struct spi_flash *flash,
249 uint8_t *reg)
250{
251 int ret;
252 BOILERPLATE_CREATE_CTX(ctx);
253
254 ret = exec_sync_hwseq_xfer(ctx, SPIBAR_HSFSTS_CYCLE_RD_STATUS, 0,
255 sizeof(*reg));
256 if (ret != SUCCESS)
257 return ret;
258
259 drain_xfer_fifo(ctx, reg, sizeof(*reg));
260 return ret;
261}
262
Furquan Shaikhe2fc5e22017-05-17 17:26:01 -0700263const struct spi_flash_ops fast_spi_flash_ops = {
264 .read = fast_spi_flash_read,
265 .write = fast_spi_flash_write,
266 .erase = fast_spi_flash_erase,
267 .status = fast_spi_flash_status,
268};
269
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530270/*
271 * We can't use FDOC and FDOD to read FLCOMP, as previous platforms did.
272 * For details see:
273 * Ch 31, SPI: p. 194
274 * The size of the flash component is always taken from density field in the
275 * SFDP table. FLCOMP.C0DEN is no longer used by the Flash Controller.
276 */
Furquan Shaikha1491572017-05-17 19:14:06 -0700277static int fast_spi_flash_probe(const struct spi_slave *dev,
278 struct spi_flash *flash)
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530279{
280 BOILERPLATE_CREATE_CTX(ctx);
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530281 uint32_t flash_bits;
282
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530283 /*
284 * bytes = (bits + 1) / 8;
285 * But we need to do the addition in a way which doesn't overflow for
286 * 4 Gbit devices (flash_bits == 0xffffffff).
287 */
288 flash_bits = fast_spi_flash_read_sfdp_param(ctx, 0x04);
289 flash->size = (flash_bits >> 3) + 1;
290
291 memcpy(&flash->spi, dev, sizeof(*dev));
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530292
293 /* Can erase both 4 KiB and 64 KiB chunks. Declare the smaller size. */
294 flash->sector_size = 4 * KiB;
Furquan Shaikhfc1a1232017-05-12 00:19:56 -0700295 flash->page_size = 256;
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530296 /*
297 * FIXME: Get erase+cmd, and status_cmd from SFDP.
298 *
299 * flash->erase_cmd = ???
300 * flash->status_cmd = ???
301 */
302
Furquan Shaikhe2fc5e22017-05-17 17:26:01 -0700303 flash->ops = &fast_spi_flash_ops;
Furquan Shaikh30221b42017-05-15 14:35:15 -0700304 return 0;
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530305}
306
Barnali Sarkar89331cd2017-02-16 17:22:37 +0530307/*
308 * Minimal set of commands to read WPSR from FAST_SPI.
309 * Returns 0 on success, < 0 on failure.
310 */
311int fast_spi_flash_read_wpsr(u8 *sr)
312{
313 uint8_t rdsr;
314 int ret = 0;
315
316 fast_spi_init();
317
318 /* sending NULL for spiflash struct parameter since we are not
319 * calling HWSEQ read_status() call via Probe.
320 */
321 ret = fast_spi_flash_status(NULL, &rdsr);
322 if (ret) {
323 printk(BIOS_ERR, "SPI rdsr failed\n");
324 return ret;
325 }
326 *sr = rdsr & WPSR_MASK_SRP0_BIT;
327
328 return 0;
329}
Furquan Shaikhf1db5fd2017-05-02 19:43:20 -0700330
331static int fast_spi_flash_ctrlr_setup(const struct spi_slave *dev)
332{
333 if (dev->cs != 0) {
334 printk(BIOS_ERR, "%s: Invalid CS for fast SPI bus=0x%x,cs=0x%x!\n",
335 __func__, dev->bus, dev->cs);
336 return -1;
337 }
338
339 return 0;
340}
341
Aaron Durbin2b96f422017-12-14 15:32:37 -0700342#define SPI_FPR_SHIFT 12
343#define SPI_FPR_MASK 0x7fff
344#define SPI_FPR_BASE_SHIFT 0
345#define SPI_FPR_LIMIT_SHIFT 16
346#define SPI_FPR_RPE (1 << 15) /* Read Protect */
347#define SPI_FPR_WPE (1 << 31) /* Write Protect */
348#define SPI_FPR(base, limit) \
349 (((((limit) >> SPI_FPR_SHIFT) & SPI_FPR_MASK) << SPI_FPR_LIMIT_SHIFT) |\
350 ((((base) >> SPI_FPR_SHIFT) & SPI_FPR_MASK) << SPI_FPR_BASE_SHIFT))
351
352/*
353 * Protect range of SPI flash defined by [start, start+size-1] using Flash
354 * Protected Range (FPR) register if available.
355 */
356static int fast_spi_flash_protect(const struct spi_flash *flash,
Rizwan Qureshif9f50932018-12-31 15:19:16 +0530357 const struct region *region,
358 const enum ctrlr_prot_type type)
Aaron Durbin2b96f422017-12-14 15:32:37 -0700359{
360 u32 start = region_offset(region);
361 u32 end = start + region_sz(region) - 1;
362 u32 reg;
Rizwan Qureshif9f50932018-12-31 15:19:16 +0530363 u32 protect_mask = 0;
Aaron Durbin2b96f422017-12-14 15:32:37 -0700364 int fpr;
365 uintptr_t fpr_base;
366 BOILERPLATE_CREATE_CTX(ctx);
367
368 fpr_base = ctx->mmio_base + SPIBAR_FPR_BASE;
369
370 /* Find first empty FPR */
371 for (fpr = 0; fpr < SPIBAR_FPR_MAX; fpr++) {
372 reg = read32((void *)fpr_base);
373 if (reg == 0)
374 break;
375 fpr_base += sizeof(uint32_t);
376 }
377
378 if (fpr >= SPIBAR_FPR_MAX) {
379 printk(BIOS_ERR, "ERROR: No SPI FPR free!\n");
380 return -1;
381 }
382
Rizwan Qureshif9f50932018-12-31 15:19:16 +0530383 switch (type) {
384 case WRITE_PROTECT:
385 protect_mask |= SPI_FPR_WPE;
386 break;
387 case READ_PROTECT:
388 protect_mask |= SPI_FPR_RPE;
389 break;
390 case READ_WRITE_PROTECT:
391 protect_mask |= (SPI_FPR_RPE | SPI_FPR_WPE);
392 break;
393 default:
394 printk(BIOS_ERR, "ERROR: Seeking invalid protection!\n");
395 return -1;
396 }
397
Aaron Durbin2b96f422017-12-14 15:32:37 -0700398 /* Set protected range base and limit */
Rizwan Qureshif9f50932018-12-31 15:19:16 +0530399 reg = SPI_FPR(start, end) | protect_mask;
Aaron Durbin2b96f422017-12-14 15:32:37 -0700400
401 /* Set the FPR register and verify it is protected */
402 write32((void *)fpr_base, reg);
403 reg = read32((void *)fpr_base);
Rizwan Qureshif9f50932018-12-31 15:19:16 +0530404 if (!(reg & protect_mask)) {
Aaron Durbin2b96f422017-12-14 15:32:37 -0700405 printk(BIOS_ERR, "ERROR: Unable to set SPI FPR %d\n", fpr);
406 return -1;
407 }
408
409 printk(BIOS_INFO, "%s: FPR %d is enabled for range 0x%08x-0x%08x\n",
410 __func__, fpr, start, end);
411 return 0;
412}
413
Furquan Shaikhf1db5fd2017-05-02 19:43:20 -0700414const struct spi_ctrlr fast_spi_flash_ctrlr = {
415 .setup = fast_spi_flash_ctrlr_setup,
Furquan Shaikhde705fa2017-04-19 19:27:28 -0700416 .max_xfer_size = SPI_CTRLR_DEFAULT_MAX_XFER_SIZE,
Furquan Shaikha1491572017-05-17 19:14:06 -0700417 .flash_probe = fast_spi_flash_probe,
Aaron Durbin2b96f422017-12-14 15:32:37 -0700418 .flash_protect = fast_spi_flash_protect,
Furquan Shaikhf1db5fd2017-05-02 19:43:20 -0700419};