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