1 /* $NetBSD: spiflash.c,v 1.8 2008/05/04 14:21:56 xtraeme Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center. 5 * Copyright (c) 2006 Garrett D'Amore. 6 * All rights reserved. 7 * 8 * Portions of this code were written by Garrett D'Amore for the 9 * Champaign-Urbana Community Wireless Network Project. 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer in the documentation and/or other materials provided 19 * with the distribution. 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgements: 22 * This product includes software developed by the Urbana-Champaign 23 * Independent Media Center. 24 * This product includes software developed by Garrett D'Amore. 25 * 4. Urbana-Champaign Independent Media Center's name and Garrett 26 * D'Amore's name may not be used to endorse or promote products 27 * derived from this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT 30 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR 31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT 34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT, 35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: spiflash.c,v 1.8 2008/05/04 14:21:56 xtraeme Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/conf.h> 49 #include <sys/proc.h> 50 #include <sys/systm.h> 51 #include <sys/device.h> 52 #include <sys/kernel.h> 53 #include <sys/file.h> 54 #include <sys/ioctl.h> 55 #include <sys/disk.h> 56 #include <sys/disklabel.h> 57 #include <sys/buf.h> 58 #include <sys/bufq.h> 59 #include <sys/uio.h> 60 #include <sys/kthread.h> 61 #include <sys/malloc.h> 62 #include <sys/errno.h> 63 64 #include <dev/spi/spivar.h> 65 #include <dev/spi/spiflash.h> 66 67 /* 68 * This is an MI block driver for SPI flash devices. It could probably be 69 * converted to some more generic framework, if someone wanted to create one 70 * for NOR flashes. Note that some flashes have the ability to handle 71 * interrupts. 72 */ 73 74 struct spiflash_softc { 75 struct disk sc_dk; 76 77 struct spiflash_hw_if sc_hw; 78 void *sc_cookie; 79 80 const char *sc_name; 81 struct spi_handle *sc_handle; 82 int sc_device_size; 83 int sc_write_size; 84 int sc_erase_size; 85 int sc_read_size; 86 int sc_device_blks; 87 88 struct bufq_state *sc_waitq; 89 struct bufq_state *sc_workq; 90 struct bufq_state *sc_doneq; 91 lwp_t *sc_thread; 92 }; 93 94 #define sc_getname sc_hw.sf_getname 95 #define sc_gethandle sc_hw.sf_gethandle 96 #define sc_getsize sc_hw.sf_getsize 97 #define sc_getflags sc_hw.sf_getflags 98 #define sc_erase sc_hw.sf_erase 99 #define sc_write sc_hw.sf_write 100 #define sc_read sc_hw.sf_read 101 #define sc_getstatus sc_hw.sf_getstatus 102 #define sc_setstatus sc_hw.sf_setstatus 103 104 struct spiflash_attach_args { 105 const struct spiflash_hw_if *hw; 106 void *cookie; 107 }; 108 109 #define STATIC 110 STATIC int spiflash_match(device_t , cfdata_t , void *); 111 STATIC void spiflash_attach(device_t , device_t , void *); 112 STATIC int spiflash_print(void *, const char *); 113 STATIC int spiflash_common_erase(spiflash_handle_t, size_t, size_t); 114 STATIC int spiflash_common_write(spiflash_handle_t, size_t, size_t, 115 const uint8_t *); 116 STATIC int spiflash_common_read(spiflash_handle_t, size_t, size_t, uint8_t *); 117 STATIC void spiflash_process_done(spiflash_handle_t, int); 118 STATIC void spiflash_process_read(spiflash_handle_t); 119 STATIC void spiflash_process_write(spiflash_handle_t); 120 STATIC void spiflash_thread(void *); 121 STATIC int spiflash_nsectors(spiflash_handle_t, struct buf *); 122 STATIC int spiflash_nsectors(spiflash_handle_t, struct buf *); 123 STATIC int spiflash_sector(spiflash_handle_t, struct buf *); 124 125 CFATTACH_DECL_NEW(spiflash, sizeof(struct spiflash_softc), 126 spiflash_match, spiflash_attach, NULL, NULL); 127 128 #ifdef SPIFLASH_DEBUG 129 #define DPRINTF(x) do { printf x; } while (0/*CONSTCOND*/) 130 #else 131 #define DPRINTF(x) do { } while (0/*CONSTCOND*/) 132 #endif 133 134 extern struct cfdriver spiflash_cd; 135 136 dev_type_open(spiflash_open); 137 dev_type_close(spiflash_close); 138 dev_type_read(spiflash_read); 139 dev_type_write(spiflash_write); 140 dev_type_ioctl(spiflash_ioctl); 141 dev_type_strategy(spiflash_strategy); 142 143 const struct bdevsw spiflash_bdevsw = { 144 .d_open = spiflash_open, 145 .d_close = spiflash_close, 146 .d_strategy = spiflash_strategy, 147 .d_ioctl = spiflash_ioctl, 148 .d_dump = nodump, 149 .d_psize = nosize, 150 .d_flag = D_DISK, 151 }; 152 153 const struct cdevsw spiflash_cdevsw = { 154 .d_open = spiflash_open, 155 .d_close = spiflash_close, 156 .d_read = spiflash_read, 157 .d_write = spiflash_write, 158 .d_ioctl = spiflash_ioctl, 159 .d_stop = nostop, 160 .d_tty = notty, 161 .d_poll = nopoll, 162 .d_mmap = nommap, 163 .d_kqfilter = nokqfilter, 164 .d_flag = D_DISK, 165 }; 166 167 static struct dkdriver spiflash_dkdriver = { spiflash_strategy, NULL }; 168 169 spiflash_handle_t 170 spiflash_attach_mi(const struct spiflash_hw_if *hw, void *cookie, 171 device_t dev) 172 { 173 struct spiflash_attach_args sfa; 174 sfa.hw = hw; 175 sfa.cookie = cookie; 176 177 return (spiflash_handle_t)config_found(dev, &sfa, spiflash_print); 178 } 179 180 int 181 spiflash_print(void *aux, const char *pnp) 182 { 183 if (pnp != NULL) 184 printf("spiflash at %s\n", pnp); 185 186 return UNCONF; 187 } 188 189 int 190 spiflash_match(device_t parent, cfdata_t cf, void *aux) 191 { 192 193 return 1; 194 } 195 196 void 197 spiflash_attach(device_t parent, device_t self, void *aux) 198 { 199 struct spiflash_softc *sc = device_private(self); 200 struct spiflash_attach_args *sfa = aux; 201 void *cookie = sfa->cookie; 202 203 sc->sc_hw = *sfa->hw; 204 sc->sc_cookie = cookie; 205 sc->sc_name = sc->sc_getname(cookie); 206 sc->sc_handle = sc->sc_gethandle(cookie); 207 sc->sc_device_size = sc->sc_getsize(cookie, SPIFLASH_SIZE_DEVICE); 208 sc->sc_erase_size = sc->sc_getsize(cookie, SPIFLASH_SIZE_ERASE); 209 sc->sc_write_size = sc->sc_getsize(cookie, SPIFLASH_SIZE_WRITE); 210 sc->sc_read_size = sc->sc_getsize(cookie, SPIFLASH_SIZE_READ); 211 sc->sc_device_blks = sc->sc_device_size / DEV_BSIZE; 212 213 if (sc->sc_read == NULL) 214 sc->sc_read = spiflash_common_read; 215 if (sc->sc_write == NULL) 216 sc->sc_write = spiflash_common_write; 217 if (sc->sc_erase == NULL) 218 sc->sc_erase = spiflash_common_erase; 219 220 aprint_naive(": SPI flash\n"); 221 aprint_normal(": %s SPI flash\n", sc->sc_name); 222 /* XXX: note that this has to change for boot-sectored flash */ 223 aprint_normal_dev(self, "%d KB, %d sectors of %d KB each\n", 224 sc->sc_device_size / 1024, 225 sc->sc_device_size / sc->sc_erase_size, 226 sc->sc_erase_size / 1024); 227 228 /* first-come first-served strategy works best for us */ 229 bufq_alloc(&sc->sc_waitq, "fcfs", BUFQ_SORT_RAWBLOCK); 230 bufq_alloc(&sc->sc_workq, "fcfs", BUFQ_SORT_RAWBLOCK); 231 bufq_alloc(&sc->sc_doneq, "fcfs", BUFQ_SORT_RAWBLOCK); 232 233 sc->sc_dk.dk_driver = &spiflash_dkdriver; 234 sc->sc_dk.dk_name = device_xname(self); 235 236 disk_attach(&sc->sc_dk); 237 238 /* arrange to allocate the kthread */ 239 kthread_create(PRI_NONE, 0, NULL, spiflash_thread, sc, 240 &sc->sc_thread, "spiflash"); 241 } 242 243 int 244 spiflash_open(dev_t dev, int flags, int mode, struct lwp *l) 245 { 246 spiflash_handle_t sc; 247 248 if ((sc = device_lookup(&spiflash_cd, DISKUNIT(dev))) == NULL) 249 return ENXIO; 250 251 /* 252 * XXX: We need to handle partitions here. The problem is 253 * that it isn't entirely clear to me how to deal with this. 254 * There are devices that could be used "in the raw" with a 255 * NetBSD label, but then you get into devices that have other 256 * kinds of data on them -- some have VxWorks data, some have 257 * RedBoot data, and some have other contraints -- for example 258 * some devices might have a portion that is read-only, 259 * whereas others might have a portion that is read-write. 260 * 261 * For now we just permit access to the entire device. 262 */ 263 return 0; 264 } 265 266 int 267 spiflash_close(dev_t dev, int flags, int mode, struct lwp *l) 268 { 269 spiflash_handle_t sc; 270 271 if ((sc = device_lookup(&spiflash_cd, DISKUNIT(dev))) == NULL) 272 return ENXIO; 273 274 return 0; 275 } 276 277 int 278 spiflash_read(dev_t dev, struct uio *uio, int ioflag) 279 { 280 281 return physio(spiflash_strategy, NULL, dev, B_READ, minphys, uio); 282 } 283 284 int 285 spiflash_write(dev_t dev, struct uio *uio, int ioflag) 286 { 287 288 return physio(spiflash_strategy, NULL, dev, B_WRITE, minphys, uio); 289 } 290 291 int 292 spiflash_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 293 { 294 spiflash_handle_t sc; 295 296 if ((sc = device_lookup(&spiflash_cd, DISKUNIT(dev))) == NULL) 297 return ENXIO; 298 299 return EINVAL; 300 } 301 302 void 303 spiflash_strategy(struct buf *bp) 304 { 305 spiflash_handle_t sc; 306 int s; 307 308 sc = device_lookup(&spiflash_cd, DISKUNIT(bp->b_dev)); 309 if (sc == NULL) { 310 bp->b_error = ENXIO; 311 biodone(bp); 312 return; 313 } 314 315 if (((bp->b_bcount % sc->sc_write_size) != 0) || 316 (bp->b_blkno < 0)) { 317 bp->b_error = EINVAL; 318 biodone(bp); 319 return; 320 } 321 322 /* no work? */ 323 if (bp->b_bcount == 0) { 324 biodone(bp); 325 return; 326 } 327 328 if (bounds_check_with_mediasize(bp, DEV_BSIZE, 329 sc->sc_device_blks) <= 0) { 330 biodone(bp); 331 return; 332 } 333 334 bp->b_resid = bp->b_bcount; 335 336 /* all ready, hand off to thread for async processing */ 337 s = splbio(); 338 BUFQ_PUT(sc->sc_waitq, bp); 339 wakeup(&sc->sc_thread); 340 splx(s); 341 } 342 343 void 344 spiflash_process_done(spiflash_handle_t sc, int err) 345 { 346 struct buf *bp; 347 int cnt = 0; 348 int flag = 0; 349 350 while ((bp = BUFQ_GET(sc->sc_doneq)) != NULL) { 351 flag = bp->b_flags & B_READ; 352 if ((bp->b_error = err) == 0) 353 bp->b_resid = 0; 354 cnt += bp->b_bcount - bp->b_resid; 355 biodone(bp); 356 } 357 disk_unbusy(&sc->sc_dk, cnt, flag); 358 } 359 360 void 361 spiflash_process_read(spiflash_handle_t sc) 362 { 363 struct buf *bp; 364 int err = 0; 365 366 disk_busy(&sc->sc_dk); 367 while ((bp = BUFQ_GET(sc->sc_workq)) != NULL) { 368 size_t addr = bp->b_blkno * DEV_BSIZE; 369 uint8_t *data = bp->b_data; 370 int cnt = bp->b_resid; 371 372 BUFQ_PUT(sc->sc_doneq, bp); 373 374 DPRINTF(("read from addr %x, cnt %d\n", (unsigned)addr, cnt)); 375 376 if ((err = sc->sc_read(sc, addr, cnt, data)) != 0) { 377 /* error occurred, fail all pending workq bufs */ 378 bufq_move(sc->sc_doneq, sc->sc_workq); 379 break; 380 } 381 382 bp->b_resid -= cnt; 383 data += cnt; 384 addr += cnt; 385 } 386 spiflash_process_done(sc, err); 387 } 388 389 void 390 spiflash_process_write(spiflash_handle_t sc) 391 { 392 int len; 393 size_t base; 394 daddr_t blkno; 395 uint8_t *save; 396 int err = 0, neederase = 0; 397 struct buf *bp; 398 399 /* 400 * due to other considerations, we are guaranteed that 401 * we will only have multiple buffers if they are all in 402 * the same erase sector. Therefore we never need to look 403 * beyond the first block to determine how much data we need 404 * to save. 405 */ 406 407 bp = BUFQ_PEEK(sc->sc_workq); 408 len = spiflash_nsectors(sc, bp) * sc->sc_erase_size; 409 blkno = bp->b_blkno; 410 base = (blkno * DEV_BSIZE) & ~ (sc->sc_erase_size - 1); 411 412 /* get ourself a scratch buffer */ 413 save = malloc(len, M_DEVBUF, M_WAITOK); 414 415 disk_busy(&sc->sc_dk); 416 /* read in as much of the data as we need */ 417 DPRINTF(("reading in %d bytes\n", len)); 418 if ((err = sc->sc_read(sc, base, len, save)) != 0) { 419 bufq_move(sc->sc_doneq, sc->sc_workq); 420 spiflash_process_done(sc, err); 421 return; 422 } 423 424 /* 425 * now coalesce the writes into the save area, but also 426 * check to see if we need to do an erase 427 */ 428 while ((bp = BUFQ_GET(sc->sc_workq)) != NULL) { 429 uint8_t *data, *dst; 430 int resid = bp->b_resid; 431 432 DPRINTF(("coalesce write, blkno %x, count %d, resid %d\n", 433 (unsigned)bp->b_blkno, bp->b_bcount, resid)); 434 435 data = bp->b_data; 436 dst = save + (bp->b_blkno - blkno) * DEV_BSIZE; 437 438 /* 439 * NOR flash bits. We can clear a bit, but we cannot 440 * set a bit, without erasing. This should help reduce 441 * unnecessary erases. 442 */ 443 while (resid) { 444 if ((*data) & ~(*dst)) 445 neederase = 1; 446 *dst++ = *data++; 447 resid--; 448 } 449 450 BUFQ_PUT(sc->sc_doneq, bp); 451 } 452 453 /* 454 * do the erase, if we need to. 455 */ 456 if (neederase) { 457 DPRINTF(("erasing from %x - %x\n", base, base + len)); 458 if ((err = sc->sc_erase(sc, base, len)) != 0) { 459 spiflash_process_done(sc, err); 460 return; 461 } 462 } 463 464 /* 465 * now write our save area, and finish up. 466 */ 467 DPRINTF(("flashing %d bytes to %x from %x\n", len, 468 base, (unsigned)save)); 469 err = sc->sc_write(sc, base, len, save); 470 spiflash_process_done(sc, err); 471 } 472 473 474 int 475 spiflash_nsectors(spiflash_handle_t sc, struct buf *bp) 476 { 477 unsigned addr, sector; 478 479 addr = bp->b_blkno * DEV_BSIZE; 480 sector = addr / sc->sc_erase_size; 481 482 addr += bp->b_bcount; 483 addr--; 484 return (((addr / sc->sc_erase_size) - sector) + 1); 485 } 486 487 int 488 spiflash_sector(spiflash_handle_t sc, struct buf *bp) 489 { 490 unsigned addr, sector; 491 492 addr = bp->b_blkno * DEV_BSIZE; 493 sector = addr / sc->sc_erase_size; 494 495 /* if it spans multiple blocks, error it */ 496 addr += bp->b_bcount; 497 addr--; 498 if (sector != (addr / sc->sc_erase_size)) 499 return -1; 500 501 return sector; 502 } 503 504 void 505 spiflash_thread(void *arg) 506 { 507 spiflash_handle_t sc = arg; 508 struct buf *bp; 509 int s; 510 int sector; 511 512 s = splbio(); 513 for (;;) { 514 if ((bp = BUFQ_GET(sc->sc_waitq)) == NULL) { 515 tsleep(&sc->sc_thread, PRIBIO, "spiflash_thread", 0); 516 continue; 517 } 518 519 BUFQ_PUT(sc->sc_workq, bp); 520 521 if (bp->b_flags & B_READ) { 522 /* just do the read */ 523 spiflash_process_read(sc); 524 continue; 525 } 526 527 /* 528 * Because writing a flash filesystem is particularly 529 * painful, involving erase, modify, write, we prefer 530 * to coalesce writes to the same sector together. 531 */ 532 533 sector = spiflash_sector(sc, bp); 534 535 /* 536 * if the write spans multiple sectors, skip 537 * coalescing. (It would be nice if we could break 538 * these up. minphys is honored for read/write, but 539 * not necessarily for bread.) 540 */ 541 if (sector < 0) 542 goto dowrite; 543 544 while ((bp = BUFQ_PEEK(sc->sc_waitq)) != NULL) { 545 /* can't deal with read requests! */ 546 if (bp->b_flags & B_READ) 547 break; 548 549 /* is it for the same sector? */ 550 if (spiflash_sector(sc, bp) != sector) 551 break; 552 553 bp = BUFQ_GET(sc->sc_waitq); 554 BUFQ_PUT(sc->sc_workq, bp); 555 } 556 557 dowrite: 558 spiflash_process_write(sc); 559 } 560 } 561 /* 562 * SPI flash common implementation. 563 */ 564 565 /* 566 * Most devices take on the order of 1 second for each block that they 567 * delete. 568 */ 569 int 570 spiflash_common_erase(spiflash_handle_t sc, size_t start, size_t size) 571 { 572 int rv; 573 574 if ((start % sc->sc_erase_size) || (size % sc->sc_erase_size)) 575 return EINVAL; 576 577 /* the second test is to test against wrap */ 578 if ((start > sc->sc_device_size) || 579 ((start + size) > sc->sc_device_size)) 580 return EINVAL; 581 582 /* 583 * XXX: check protection status? Requires master table mapping 584 * sectors to status bits, and so forth. 585 */ 586 587 while (size) { 588 if ((rv = spiflash_write_enable(sc)) != 0) { 589 spiflash_write_disable(sc); 590 return rv; 591 } 592 if ((rv = spiflash_cmd(sc, SPIFLASH_CMD_ERASE, 3, start, 0, 593 NULL, NULL)) != 0) { 594 spiflash_write_disable(sc); 595 return rv; 596 } 597 598 /* 599 * The devices I have all say typical for sector erase 600 * is ~1sec. We check ten times that often. (There 601 * is no way to interrupt on this.) 602 */ 603 if ((rv = spiflash_wait(sc, hz / 10)) != 0) 604 return rv; 605 606 start += sc->sc_erase_size; 607 size -= sc->sc_erase_size; 608 609 /* NB: according to the docs I have, the write enable 610 * is automatically cleared upon completion of an erase 611 * command, so there is no need to explicitly disable it. 612 */ 613 } 614 615 return 0; 616 } 617 618 int 619 spiflash_common_write(spiflash_handle_t sc, size_t start, size_t size, 620 const uint8_t *data) 621 { 622 int rv; 623 624 if ((start % sc->sc_write_size) || (size % sc->sc_write_size)) 625 return EINVAL; 626 627 while (size) { 628 int cnt; 629 630 if ((rv = spiflash_write_enable(sc)) != 0) { 631 spiflash_write_disable(sc); 632 return rv; 633 } 634 635 cnt = min(size, sc->sc_write_size); 636 if ((rv = spiflash_cmd(sc, SPIFLASH_CMD_PROGRAM, 3, start, 637 cnt, data, NULL)) != 0) { 638 spiflash_write_disable(sc); 639 return rv; 640 } 641 642 /* 643 * It seems that most devices can write bits fairly 644 * quickly. For example, one part I have access to 645 * takes ~5msec to process the entire 256 byte page. 646 * Probably this should be modified to cope with 647 * device-specific timing, and maybe also take into 648 * account systems with higher values of HZ (which 649 * could benefit from sleeping.) 650 */ 651 if ((rv = spiflash_wait(sc, 0)) != 0) 652 return rv; 653 654 data += cnt; 655 start += cnt; 656 size -= cnt; 657 } 658 659 return 0; 660 } 661 662 int 663 spiflash_common_read(spiflash_handle_t sc, size_t start, size_t size, 664 uint8_t *data) 665 { 666 int rv; 667 668 while (size) { 669 int cnt; 670 671 if (sc->sc_read_size > 0) 672 cnt = min(size, sc->sc_read_size); 673 else 674 cnt = size; 675 676 if ((rv = spiflash_cmd(sc, SPIFLASH_CMD_READ, 3, start, 677 cnt, NULL, data)) != 0) { 678 return rv; 679 } 680 681 start += cnt; 682 size -= cnt; 683 } 684 685 return 0; 686 } 687 688 /* read status register */ 689 int 690 spiflash_read_status(spiflash_handle_t sc, uint8_t *sr) 691 { 692 693 return spiflash_cmd(sc, SPIFLASH_CMD_RDSR, 0, 0, 1, NULL, sr); 694 } 695 696 int 697 spiflash_write_enable(spiflash_handle_t sc) 698 { 699 700 return spiflash_cmd(sc, SPIFLASH_CMD_WREN, 0, 0, 0, NULL, NULL); 701 } 702 703 int 704 spiflash_write_disable(spiflash_handle_t sc) 705 { 706 707 return spiflash_cmd(sc, SPIFLASH_CMD_WRDI, 0, 0, 0, NULL, NULL); 708 } 709 710 int 711 spiflash_cmd(spiflash_handle_t sc, uint8_t cmd, 712 size_t addrlen, uint32_t addr, 713 size_t cnt, const uint8_t *wdata, uint8_t *rdata) 714 { 715 struct spi_transfer trans; 716 struct spi_chunk chunk1, chunk2; 717 char buf[4]; 718 int i; 719 720 buf[0] = cmd; 721 722 if (addrlen > 3) 723 return EINVAL; 724 725 for (i = addrlen; i > 0; i--) { 726 buf[i] = addr & 0xff; 727 addr >>= 8; 728 } 729 spi_transfer_init(&trans); 730 spi_chunk_init(&chunk1, addrlen + 1, buf, NULL); 731 spi_transfer_add(&trans, &chunk1); 732 if (cnt) { 733 spi_chunk_init(&chunk2, cnt, wdata, rdata); 734 spi_transfer_add(&trans, &chunk2); 735 } 736 737 spi_transfer(sc->sc_handle, &trans); 738 spi_wait(&trans); 739 740 if (trans.st_flags & SPI_F_ERROR) 741 return trans.st_errno; 742 return 0; 743 } 744 745 int 746 spiflash_wait(spiflash_handle_t sc, int tmo) 747 { 748 int rv; 749 uint8_t sr; 750 751 for (;;) { 752 if ((rv = spiflash_read_status(sc, &sr)) != 0) 753 return rv; 754 755 if ((sr & SPIFLASH_SR_BUSY) == 0) 756 break; 757 /* 758 * The devices I have all say typical for sector 759 * erase is ~1sec. We check time times that often. 760 * (There is no way to interrupt on this.) 761 */ 762 if (tmo) 763 tsleep(&sr, PWAIT, "spiflash_wait", tmo); 764 } 765 return 0; 766 } 767