1 /*
2 * Copyright (c) 2014 Brian Swetland
3 * Copyright (c) 2014 Travis Geiselbrecht
4 *
5 * Use of this source code is governed by a MIT-style
6 * license that can be found in the LICENSE file or at
7 * https://opensource.org/licenses/MIT
8 */
9 #include <lk/debug.h>
10 #include <assert.h>
11 #include <lk/trace.h>
12 #include <lk/compiler.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <lk/err.h>
16 #include <string.h>
17 #include <rand.h>
18 #include <lk/reg.h>
19 #include <lk/pow2.h>
20
21 #include <lib/bio.h>
22 #include <lk/console_cmd.h>
23 #include <dev/qspi.h>
24 #include <dev/spiflash.h>
25 #include <kernel/thread.h>
26
27 #include <platform/zynq.h>
28
29 #define LOCAL_TRACE 0
30
31 // parameters specifically for the 16MB spansion S25FL128S flash
32 #define PARAMETER_AREA_SIZE (128*1024)
33 #define PAGE_PROGRAM_SIZE (256) // can be something else based on the part
34 #define PAGE_ERASE_SLEEP_TIME (150) // amount of time before waiting to check if erase completed
35 #define SECTOR_ERASE_SIZE (4096)
36 #define LARGE_SECTOR_ERASE_SIZE (64*1024)
37
38 #define STS_PROGRAM_ERR (1<<6)
39 #define STS_ERASE_ERR (1<<5)
40 #define STS_BUSY (1<<0)
41
42 #define MAX_GEOMETRY_COUNT (2)
43
44 struct spi_flash {
45 bool detected;
46
47 struct qspi_ctxt qspi;
48 bdev_t bdev;
49 bio_erase_geometry_info_t geometry[MAX_GEOMETRY_COUNT];
50
51 off_t size;
52 };
53
54 static struct spi_flash flash;
55
56 static ssize_t spiflash_bdev_read(struct bdev *, void *buf, off_t offset, size_t len);
57 static ssize_t spiflash_bdev_read_block(struct bdev *, void *buf, bnum_t block, uint count);
58 static ssize_t spiflash_bdev_write_block(struct bdev *, const void *buf, bnum_t block, uint count);
59 static ssize_t spiflash_bdev_erase(struct bdev *, off_t offset, size_t len);
60 static int spiflash_ioctl(struct bdev *, int request, void *argp);
61
62 // adjust 24 bit address to be correct-byte-order for 32bit qspi commands
qspi_fix_addr(uint32_t addr)63 static uint32_t qspi_fix_addr(uint32_t addr) {
64 DEBUG_ASSERT((addr & ~(0x00ffffff)) == 0); // only dealing with 24bit addresses
65
66 return ((addr & 0xff) << 24) | ((addr&0xff00) << 8) | ((addr>>8) & 0xff00);
67 }
68
qspi_rd32(struct qspi_ctxt * qspi,uint32_t addr,uint32_t * data,uint32_t count)69 static void qspi_rd32(struct qspi_ctxt *qspi, uint32_t addr, uint32_t *data, uint32_t count) {
70 qspi_rd(qspi, qspi_fix_addr(addr) | 0x6B, 4, data, count);
71 }
72
qspi_wren(struct qspi_ctxt * qspi)73 static inline void qspi_wren(struct qspi_ctxt *qspi) {
74 qspi_wr1(qspi, 0x06);
75 }
76
qspi_clsr(struct qspi_ctxt * qspi)77 static inline void qspi_clsr(struct qspi_ctxt *qspi) {
78 qspi_wr1(qspi, 0x30);
79 }
80
qspi_rd_cr1(struct qspi_ctxt * qspi)81 static inline uint32_t qspi_rd_cr1(struct qspi_ctxt *qspi) {
82 return qspi_rd1(qspi, 0x35) >> 24;
83 }
84
qspi_rd_status(struct qspi_ctxt * qspi)85 static inline uint32_t qspi_rd_status(struct qspi_ctxt *qspi) {
86 return qspi_rd1(qspi, 0x05) >> 24;
87 }
88
qspi_wr_status_cr1(struct qspi_ctxt * qspi,uint8_t status,uint8_t cr1)89 static inline void qspi_wr_status_cr1(struct qspi_ctxt *qspi, uint8_t status, uint8_t cr1) {
90 uint32_t cmd = (cr1 << 16) | (status << 8) | 0x01;
91
92 qspi_wren(qspi);
93 qspi_wr3(qspi, cmd);
94 }
95
qspi_erase_sector(struct qspi_ctxt * qspi,uint32_t addr)96 static ssize_t qspi_erase_sector(struct qspi_ctxt *qspi, uint32_t addr) {
97 uint32_t cmd;
98 uint32_t status;
99 ssize_t toerase;
100
101 LTRACEF("addr 0x%x\n", addr);
102
103 DEBUG_ASSERT(qspi);
104
105 if (addr < PARAMETER_AREA_SIZE) {
106 // erase a small parameter sector (4K)
107 DEBUG_ASSERT(IS_ALIGNED(addr, SECTOR_ERASE_SIZE));
108 if (!IS_ALIGNED(addr, SECTOR_ERASE_SIZE))
109 return ERR_INVALID_ARGS;
110
111 cmd = 0x20;
112 toerase = SECTOR_ERASE_SIZE;
113 } else {
114 // erase a large sector (64k or 256k)
115 DEBUG_ASSERT(IS_ALIGNED(addr, LARGE_SECTOR_ERASE_SIZE));
116 if (!IS_ALIGNED(addr, LARGE_SECTOR_ERASE_SIZE))
117 return ERR_INVALID_ARGS;
118
119 cmd = 0xd8;
120 toerase = LARGE_SECTOR_ERASE_SIZE;
121 }
122
123 qspi_wren(qspi);
124 qspi_wr(qspi, qspi_fix_addr(addr) | cmd, 3, 0, 0);
125
126 thread_sleep(PAGE_ERASE_SLEEP_TIME);
127 while ((status = qspi_rd_status(qspi)) & STS_BUSY)
128 ;
129
130 LTRACEF("status 0x%x\n", status);
131 if (status & (STS_PROGRAM_ERR | STS_ERASE_ERR)) {
132 TRACEF("failed @ 0x%x\n", addr);
133 qspi_clsr(qspi);
134 return ERR_IO;
135 }
136
137 return toerase;
138 }
139
qspi_write_page(struct qspi_ctxt * qspi,uint32_t addr,const uint8_t * data)140 static ssize_t qspi_write_page(struct qspi_ctxt *qspi, uint32_t addr, const uint8_t *data) {
141 uint32_t oldkhz, status;
142
143 LTRACEF("addr 0x%x, data %p\n", addr, data);
144
145 DEBUG_ASSERT(qspi);
146 DEBUG_ASSERT(data);
147 DEBUG_ASSERT(IS_ALIGNED(addr, PAGE_PROGRAM_SIZE));
148
149 if (!IS_ALIGNED(addr, PAGE_PROGRAM_SIZE))
150 return ERR_INVALID_ARGS;
151
152 oldkhz = qspi->khz;
153 if (qspi_set_speed(qspi, 80000))
154 return ERR_IO;
155
156 qspi_wren(qspi);
157 qspi_wr(qspi, qspi_fix_addr(addr) | 0x32, 3, (uint32_t *)data, PAGE_PROGRAM_SIZE / 4);
158 qspi_set_speed(qspi, oldkhz);
159
160 while ((status = qspi_rd_status(qspi)) & STS_BUSY) ;
161
162 if (status & (STS_PROGRAM_ERR | STS_ERASE_ERR)) {
163 printf("qspi_write_page failed @ %x\n", addr);
164 qspi_clsr(qspi);
165 return ERR_IO;
166 }
167 return PAGE_PROGRAM_SIZE;
168 }
169
spiflash_read_cfi(void * buf,size_t len)170 static ssize_t spiflash_read_cfi(void *buf, size_t len) {
171 DEBUG_ASSERT(len > 0 && (len % 4) == 0);
172
173 qspi_rd(&flash.qspi, 0x9f, 0, buf, len / 4);
174
175 if (len < 4)
176 return len;
177
178 /* look at byte 3 of the cfi, which says the total length of the cfi structure */
179 size_t cfi_len = ((uint8_t *)buf)[3];
180 if (cfi_len == 0)
181 cfi_len = 512;
182 else
183 cfi_len += 3;
184
185 return MIN(len, cfi_len);
186 }
187
spiflash_read_otp(void * buf,uint32_t addr,size_t len)188 static ssize_t spiflash_read_otp(void *buf, uint32_t addr, size_t len) {
189 DEBUG_ASSERT(len > 0 && (len % 4) == 0);
190
191 if (len > 1024)
192 len = 1024;
193
194 qspi_rd(&flash.qspi, 0x4b, 4, buf, len / 4);
195
196 if (len < 4)
197 return len;
198
199 return len;
200 }
201
spiflash_detect(void)202 status_t spiflash_detect(void) {
203 if (flash.detected)
204 return NO_ERROR;
205
206 qspi_init(&flash.qspi, 100000);
207
208 /* read and parse the cfi */
209 uint8_t *buf = calloc(1, 512);
210 ssize_t len = spiflash_read_cfi(buf, 512);
211 if (len < 4)
212 goto nodetect;
213
214 LTRACEF("looking at vendor/device id combination: %02x:%02x:%02x\n", buf[0], buf[1], buf[2]);
215
216 /* at the moment, we only support particular spansion flashes */
217 if (buf[0] != 0x01) goto nodetect;
218
219 if (buf[1] == 0x20 && buf[2] == 0x18) {
220 /* 128Mb version */
221 flash.size = 16*1024*1024;
222 } else if (buf[1] == 0x02 && buf[2] == 0x19) {
223 /* 256Mb version */
224 flash.size = 32*1024*1024;
225 } else {
226 TRACEF("unknown vendor/device id combination: %02x:%02x:%02x\n",
227 buf[0], buf[1], buf[2]);
228 goto nodetect;
229 }
230
231 /* Fill out our geometry info based on the CFI */
232 size_t region_count = buf[0x2C];
233 if (region_count > countof(flash.geometry)) {
234 TRACEF("erase region count (%zu) exceeds max allowed (%zu)\n",
235 region_count, countof(flash.geometry));
236 goto nodetect;
237 }
238
239 size_t offset = 0;
240 for (size_t i = 0; i < region_count; i++) {
241 const uint8_t *info = buf + 0x2D + (i << 2);
242 size_t pages = ((((size_t)info[1]) << 8) | info[0]) + 1;
243 size_t erase_size = ((((size_t)info[3]) << 8) | info[2]) << 8;
244
245 if (!ispow2(erase_size)) {
246 TRACEF("Region %zu page size (%zu) is not a power of 2\n",
247 i, erase_size);
248 goto nodetect;
249 }
250
251 flash.geometry[i].erase_size = erase_size;
252 flash.geometry[i].erase_shift = log2_uint(erase_size);
253 flash.geometry[i].start = offset;
254 flash.geometry[i].size = pages << flash.geometry[i].erase_shift;
255
256 size_t erase_mask = ((size_t)0x1 << flash.geometry[i].erase_shift) - 1;
257 if (offset & erase_mask) {
258 TRACEF("Region %zu not aligned to erase boundary (start %zu, erase size %zu)\n",
259 i, offset, erase_size);
260 goto nodetect;
261 }
262
263 offset += flash.geometry[i].size;
264 }
265
266 free(buf);
267
268 /* read the 16 byte random number out of the OTP area and add to the rand entropy pool */
269 uint32_t r[4];
270 memset(r, 0, sizeof(r));
271 spiflash_read_otp(r, 0, 16);
272
273 LTRACEF("OTP random %08x%08x%08x%08x\n", r[0], r[1], r[2], r[3]);
274 rand_add_entropy(r, sizeof(r));
275
276 flash.detected = true;
277
278 /* see if we're in serial mode */
279 uint32_t cr1 = qspi_rd_cr1(&flash.qspi);
280 if ((cr1 & (1<<1)) == 0) {
281 printf("spiflash: device not in quad mode, cannot use for read/write\n");
282 goto nouse;
283 }
284
285 /* construct the block device */
286 bio_initialize_bdev(&flash.bdev, "spi0",
287 PAGE_PROGRAM_SIZE, flash.size / PAGE_PROGRAM_SIZE,
288 region_count, flash.geometry, BIO_FLAGS_NONE);
289
290 /* override our block device hooks */
291 flash.bdev.read = &spiflash_bdev_read;
292 flash.bdev.read_block = &spiflash_bdev_read_block;
293 // flash.bdev.write has a default hook that will be okay
294 flash.bdev.write_block = &spiflash_bdev_write_block;
295 flash.bdev.erase = &spiflash_bdev_erase;
296 flash.bdev.ioctl = &spiflash_ioctl;
297
298 /* we erase to 0xff */
299 flash.bdev.erase_byte = 0xff;
300
301 bio_register_device(&flash.bdev);
302
303 LTRACEF("found flash of size 0x%llx\n", flash.size);
304
305 nouse:
306 return NO_ERROR;
307
308 nodetect:
309 LTRACEF("flash not found\n");
310
311 free(buf);
312 flash.detected = false;
313 return ERR_NOT_FOUND;
314 }
315
316 // bio layer hooks
spiflash_bdev_read(struct bdev * bdev,void * buf,off_t offset,size_t len)317 static ssize_t spiflash_bdev_read(struct bdev *bdev, void *buf, off_t offset, size_t len) {
318 LTRACEF("dev %p, buf %p, offset 0x%llx, len 0x%zx\n", bdev, buf, offset, len);
319
320 DEBUG_ASSERT(flash.detected);
321
322 len = bio_trim_range(bdev, offset, len);
323 if (len == 0)
324 return 0;
325
326 // XXX handle not multiple of 4
327 qspi_rd32(&flash.qspi, offset, buf, len / 4);
328
329 return len;
330 }
331
spiflash_bdev_read_block(struct bdev * bdev,void * buf,bnum_t block,uint count)332 static ssize_t spiflash_bdev_read_block(struct bdev *bdev, void *buf, bnum_t block, uint count) {
333 LTRACEF("dev %p, buf %p, block 0x%x, count %u\n", bdev, buf, block, count);
334
335 count = bio_trim_block_range(bdev, block, count);
336 if (count == 0)
337 return 0;
338
339 return spiflash_bdev_read(bdev, buf, block << bdev->block_shift, count << bdev->block_shift);
340 }
341
spiflash_bdev_write_block(struct bdev * bdev,const void * _buf,bnum_t block,uint count)342 static ssize_t spiflash_bdev_write_block(struct bdev *bdev, const void *_buf, bnum_t block, uint count) {
343 LTRACEF("dev %p, buf %p, block 0x%x, count %u\n", bdev, _buf, block, count);
344
345 DEBUG_ASSERT(bdev->block_size == PAGE_PROGRAM_SIZE);
346
347 count = bio_trim_block_range(bdev, block, count);
348 if (count == 0)
349 return 0;
350
351 const uint8_t *buf = _buf;
352
353 ssize_t written = 0;
354 while (count > 0) {
355 ssize_t err = qspi_write_page(&flash.qspi, block * PAGE_PROGRAM_SIZE, buf);
356 if (err < 0)
357 return err;
358
359 buf += PAGE_PROGRAM_SIZE;
360 written += err;
361 block++;
362 count--;
363 }
364
365 return written;
366 }
367
spiflash_bdev_erase(struct bdev * bdev,off_t offset,size_t len)368 static ssize_t spiflash_bdev_erase(struct bdev *bdev, off_t offset, size_t len) {
369 LTRACEF("dev %p, offset 0x%llx, len 0x%zx\n", bdev, offset, len);
370
371 len = bio_trim_range(bdev, offset, len);
372 if (len == 0)
373 return 0;
374
375 ssize_t erased = 0;
376 while (erased < (ssize_t)len) {
377 ssize_t err = qspi_erase_sector(&flash.qspi, offset);
378 if (err < 0)
379 return err;
380
381 erased += err;
382 offset += err;
383 }
384
385 return erased;
386 }
387
spiflash_ioctl(struct bdev * bdev,int request,void * argp)388 static int spiflash_ioctl(struct bdev *bdev, int request, void *argp) {
389 LTRACEF("dev %p, request %d, argp %p\n", bdev, request, argp);
390
391 int ret = NO_ERROR;
392 switch (request) {
393 case BIO_IOCTL_GET_MEM_MAP:
394 /* put the device into linear mode */
395 ret = qspi_enable_linear(&flash.qspi);
396 // Fallthrough.
397 case BIO_IOCTL_GET_MAP_ADDR:
398 if (argp)
399 *(void **)argp = (void *)QSPI_LINEAR_BASE;
400 break;
401 case BIO_IOCTL_PUT_MEM_MAP:
402 /* put the device back into regular mode */
403 ret = qspi_disable_linear(&flash.qspi);
404 break;
405 default:
406 ret = ERR_NOT_SUPPORTED;
407 }
408
409 return ret;
410 }
411
412 // debug tests
cmd_spiflash(int argc,const console_cmd_args * argv)413 static int cmd_spiflash(int argc, const console_cmd_args *argv) {
414 if (argc < 2) {
415 notenoughargs:
416 printf("not enough arguments\n");
417 usage:
418 printf("usage:\n");
419 #if LK_DEBUGLEVEL > 1
420 printf("\t%s detect\n", argv[0].str);
421 printf("\t%s cfi\n", argv[0].str);
422 printf("\t%s cr1\n", argv[0].str);
423 printf("\t%s otp\n", argv[0].str);
424 printf("\t%s linear [true/false]\n", argv[0].str);
425 printf("\t%s read <offset> <length>\n", argv[0].str);
426 printf("\t%s write <offset> <length> <address>\n", argv[0].str);
427 printf("\t%s erase <offset>\n", argv[0].str);
428 #endif
429 printf("\t%s setquad (dangerous)\n", argv[0].str);
430 return ERR_INVALID_ARGS;
431 }
432
433 #if LK_DEBUGLEVEL > 1
434 if (!strcmp(argv[1].str, "detect")) {
435 spiflash_detect();
436 } else if (!strcmp(argv[1].str, "cr1")) {
437 if (!flash.detected) {
438 printf("flash not detected\n");
439 return -1;
440 }
441
442 uint32_t cr1 = qspi_rd_cr1(&flash.qspi);
443 printf("cr1 0x%x\n", cr1);
444 } else if (!strcmp(argv[1].str, "cfi")) {
445 if (!flash.detected) {
446 printf("flash not detected\n");
447 return -1;
448 }
449
450 uint8_t *buf = calloc(1, 512);
451 ssize_t len = spiflash_read_cfi(buf, 512);
452 printf("returned cfi len %ld\n", len);
453
454 hexdump8(buf, len);
455
456 free(buf);
457 } else if (!strcmp(argv[1].str, "otp")) {
458 if (!flash.detected) {
459 printf("flash not detected\n");
460 return -1;
461 }
462
463 uint8_t *buf = calloc(1, 1024);
464 ssize_t len = spiflash_read_otp(buf, 0, 1024);
465 printf("spiflash_read_otp returns %ld\n", len);
466
467 hexdump8(buf, len);
468
469 free(buf);
470 } else if (!strcmp(argv[1].str, "linear")) {
471 if (argc < 3) goto notenoughargs;
472 if (!flash.detected) {
473 printf("flash not detected\n");
474 return -1;
475 }
476
477 if (argv[2].b)
478 qspi_enable_linear(&flash.qspi);
479 else
480 qspi_disable_linear(&flash.qspi);
481 } else if (!strcmp(argv[1].str, "read")) {
482 if (argc < 4) goto notenoughargs;
483 if (!flash.detected) {
484 printf("flash not detected\n");
485 return -1;
486 }
487
488 uint8_t *buf = calloc(1, argv[3].u);
489
490 qspi_rd32(&flash.qspi, argv[2].u, (uint32_t *)buf, argv[3].u / 4);
491
492 hexdump8(buf, argv[3].u);
493 free(buf);
494 } else if (!strcmp(argv[1].str, "write")) {
495 if (argc < 5) goto notenoughargs;
496 if (!flash.detected) {
497 printf("flash not detected\n");
498 return -1;
499 }
500
501 status_t err = qspi_write_page(&flash.qspi, argv[2].u, argv[4].p);
502 printf("write_page returns %d\n", err);
503 } else if (!strcmp(argv[1].str, "erase")) {
504 if (argc < 3) goto notenoughargs;
505 if (!flash.detected) {
506 printf("flash not detected\n");
507 return -1;
508 }
509
510 status_t err = qspi_erase_sector(&flash.qspi, argv[2].u);
511 printf("erase returns %d\n", err);
512 } else
513 #endif
514 if (!strcmp(argv[1].str, "setquad")) {
515 if (!flash.detected) {
516 printf("flash not detected\n");
517 return -1;
518 }
519
520 uint32_t cr1 = qspi_rd_cr1(&flash.qspi);
521 printf("cr1 before 0x%x\n", cr1);
522
523 if (cr1 & (1<<1)) {
524 printf("flash already in quad mode\n");
525 return 0;
526 }
527
528 qspi_wr_status_cr1(&flash.qspi, 0, cr1 | (1<<1));
529
530 thread_sleep(500);
531 cr1 = qspi_rd_cr1(&flash.qspi);
532 printf("cr1 after 0x%x\n", cr1);
533 } else {
534 printf("unknown command\n");
535 goto usage;
536 }
537
538 return 0;
539 }
540
541 STATIC_COMMAND_START
542 STATIC_COMMAND("spiflash", "spi flash manipulation utilities", cmd_spiflash)
543 STATIC_COMMAND_END(qspi);
544