1 /* $NetBSD: flash_vrip.c,v 1.9 2014/03/16 05:20:24 dholland Exp $ */ 2 3 /* 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Naoto Shimazaki of YOKOGAWA Electric Corporation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Flash Memory Driver 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: flash_vrip.c,v 1.9 2014/03/16 05:20:24 dholland Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/conf.h> 41 #include <sys/device.h> 42 #include <sys/kernel.h> 43 #include <sys/malloc.h> 44 #include <sys/proc.h> 45 #include <sys/systm.h> 46 47 #include <machine/bus.h> 48 49 #include <hpcmips/vr/vripif.h> 50 #include <hpcmips/vr/cfireg.h> 51 #include <hpcmips/vr/flashreg.h> 52 #include <hpcmips/vr/flashvar.h> 53 54 #ifdef FLASH_DEBUG 55 int flash_debug = 0; 56 #define DPRINTF(x) if (flash_debug) printf x 57 #else 58 #define DPRINTF(x) 59 #endif 60 61 static int flash_probe(device_t, cfdata_t, void *); 62 static void flash_attach(device_t, device_t, void *); 63 64 const static struct flashops * find_command_set(u_int8_t cmdset0, 65 u_int8_t cmdset1); 66 static int i28f128_probe(bus_space_tag_t, bus_space_handle_t); 67 static int mbm29160_probe(bus_space_tag_t, bus_space_handle_t); 68 static int is_block_same(struct flash_softc *, bus_size_t, const void *); 69 static int probe_cfi(bus_space_tag_t iot, bus_space_handle_t ioh); 70 71 static int intel_erase(struct flash_softc *, bus_size_t); 72 static int intel_write(struct flash_softc *, bus_size_t); 73 static int amd_erase(struct flash_softc *, bus_size_t); 74 static int amd_write(struct flash_softc *, bus_size_t); 75 76 extern struct cfdriver flash_cd; 77 78 CFATTACH_DECL_NEW(flash_vrip, sizeof(struct flash_softc), 79 flash_probe, flash_attach, NULL, NULL); 80 81 dev_type_open(flashopen); 82 dev_type_close(flashclose); 83 dev_type_read(flashread); 84 dev_type_write(flashwrite); 85 86 const struct cdevsw flash_cdevsw = { 87 .d_open = flashopen, 88 .d_close = flashclose, 89 .d_read = flashread, 90 .d_write = flashwrite, 91 .d_ioctl = noioctl, 92 .d_stop = nostop, 93 .d_tty = notty, 94 .d_poll = nopoll, 95 .d_mmap = nommap, 96 .d_kqfilter = nokqfilter, 97 .d_flag = 0 98 }; 99 100 static const struct flash_command_set { 101 u_int8_t fc_set0; 102 u_int8_t fc_set1; 103 struct flashops fc_ops; 104 } flash_cmd[] = { 105 { 106 .fc_set0 = CFI_COMMSET_INTEL0, 107 .fc_set1 = CFI_COMMSET_INTEL1, 108 .fc_ops = { 109 .fo_name = "Intel", 110 .fo_erase = intel_erase, 111 .fo_write = intel_write, 112 } 113 }, 114 { 115 .fc_set0 = CFI_COMMSET_AMDFJITU0, 116 .fc_set1 = CFI_COMMSET_AMDFJITU1, 117 .fc_ops = { 118 .fo_name = "AMD/Fujitsu", 119 .fo_erase = amd_erase, 120 .fo_write = amd_write, 121 } 122 }, 123 { 124 .fc_set0 = 0, 125 .fc_set1 = 0, 126 .fc_ops = { 127 .fo_name = NULL, 128 .fo_erase = NULL, 129 .fo_write = NULL, 130 } 131 } 132 }; 133 134 135 const static struct flashops * 136 find_command_set(u_int8_t cmdset0, u_int8_t cmdset1) 137 { 138 const struct flash_command_set *fc; 139 140 for (fc = flash_cmd; fc->fc_ops.fo_name; fc++) { 141 if (cmdset0 == fc->fc_set0 && cmdset1 == fc->fc_set1) 142 return &fc->fc_ops; 143 } 144 return NULL; 145 } 146 147 static int 148 probe_cfi(bus_space_tag_t iot, bus_space_handle_t ioh) 149 { 150 const u_int8_t *idstr = CFI_QUERY_ID_STR; 151 int i; 152 u_int8_t cmdset0; 153 u_int8_t cmdset1; 154 155 /* start Common Flash Interface Query */ 156 bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY); 157 158 /* read CFI Query ID string */ 159 i = CFI_QUERY_ID_STR_REG << 1; 160 do { 161 if (bus_space_read_2(iot, ioh, i) != *idstr) { 162 bus_space_write_2(iot, ioh, 0, FLASH_RESET); 163 return 1; 164 } 165 i += 2; 166 idstr++; 167 } while (*idstr); 168 169 cmdset0 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG0 << 1); 170 cmdset1 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG1 << 1); 171 172 /* switch flash to read mode */ 173 bus_space_write_2(iot, ioh, 0, FLASH_RESET); 174 175 if (!find_command_set(cmdset0, cmdset1)) 176 return 1; 177 178 return 0; 179 } 180 181 static int 182 flash_probe(device_t parent, cfdata_t match, void *aux) 183 { 184 struct vrip_attach_args *va = aux; 185 bus_space_handle_t ioh; 186 187 if (bus_space_map(va->va_iot, va->va_addr, va->va_size, 0, &ioh)) 188 return 0; 189 if (!probe_cfi(va->va_iot, ioh)) { 190 DPRINTF("CFI ID str and command set recognized\n"); 191 goto detect; 192 } 193 if (!i28f128_probe(va->va_iot, ioh)) { 194 DPRINTF("28F128 detected\n"); 195 goto detect; 196 } 197 if (!mbm29160_probe(va->va_iot, ioh)) { 198 DPRINTF("29LV160 detected\n"); 199 goto detect; 200 } 201 return 0; 202 203 detect: 204 bus_space_unmap(va->va_iot, ioh, va->va_size); 205 return 1; 206 } 207 208 static void 209 flash_attach(device_t parent, device_t self, void *aux) 210 { 211 struct flash_softc *sc = device_private(self); 212 struct vrip_attach_args *va = aux; 213 int i; 214 int fence; 215 bus_space_tag_t iot = va->va_iot; 216 bus_space_handle_t ioh; 217 size_t block_size; 218 219 if (bus_space_map(iot, va->va_addr, va->va_size, 0, &ioh)) { 220 printf(": can't map i/o space\n"); 221 return; 222 } 223 224 sc->sc_iot = iot; 225 sc->sc_ioh = ioh; 226 sc->sc_size = va->va_size; 227 sc->sc_status = 0; 228 229 /* 230 * Read entire CFI structure 231 */ 232 bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY); 233 for (i = 0; i < CFI_TOTAL_SIZE; i++) { 234 sc->sc_cfi_raw[i] = bus_space_read_2(iot, ioh, i << 1); 235 } 236 bus_space_write_2(iot, ioh, 0, FLASH_RESET); 237 238 sc->sc_ops = find_command_set(sc->sc_cfi_raw[CFI_PRIM_COMM_REG0], 239 sc->sc_cfi_raw[CFI_PRIM_COMM_REG1]); 240 if (sc->sc_ops) { 241 printf(": using %s command set", sc->sc_ops->fo_name); 242 } else { 243 printf("opps sc->sc_ops is NULL\n"); 244 } 245 246 /* 247 * determine size of the largest block 248 */ 249 sc->sc_block_size = 0; 250 i = CFI_EBLK1_INFO_REG; 251 fence = sc->sc_cfi_raw[CFI_NUM_ERASE_BLK_REG] * CFI_EBLK_INFO_SIZE 252 + i; 253 for (; i < fence; i += CFI_EBLK_INFO_SIZE) { 254 if (sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT0] == 0 255 && sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT1] == 0) 256 continue; 257 block_size 258 = (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE0] << 8) 259 + (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE1] << 16); 260 if (sc->sc_block_size < block_size) 261 sc->sc_block_size = block_size; 262 } 263 264 if ((sc->sc_buf = malloc(sc->sc_block_size, M_DEVBUF, M_NOWAIT)) 265 == NULL) { 266 printf(": can't alloc buffer space\n"); 267 return; 268 } 269 270 sc->sc_write_buffer_size 271 = 1 << (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG0] 272 + (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG1] << 8)); 273 sc->sc_typ_word_prog_timo 274 = 1 << sc->sc_cfi_raw[CFI_TYP_WORD_PROG_REG]; 275 sc->sc_max_word_prog_timo 276 = 1 << sc->sc_cfi_raw[CFI_MAX_WORD_PROG_REG]; 277 sc->sc_typ_buffer_write_timo 278 = 1 << sc->sc_cfi_raw[CFI_TYP_BUF_WRITE_REG]; 279 sc->sc_max_buffer_write_timo 280 = 1 << sc->sc_cfi_raw[CFI_MAX_BUF_WRITE_REG]; 281 sc->sc_typ_block_erase_timo 282 = 1 << sc->sc_cfi_raw[CFI_TYP_BLOCK_ERASE_REG]; 283 sc->sc_max_block_erase_timo 284 = 1 << sc->sc_cfi_raw[CFI_MAX_BLOCK_ERASE_REG]; 285 286 printf("\n"); 287 288 #ifdef FLASH_DEBUG 289 printf("read_cfi: extract cfi\n"); 290 printf("max block size: %dbyte\n", sc->sc_block_size); 291 printf("write buffer size: %dbyte\n", sc->sc_write_buffer_size); 292 printf("typical word program timeout: %dusec\n", 293 sc->sc_typ_word_prog_timo); 294 printf("maximam word program timeout: %dusec (%d time of typ)\n", 295 sc->sc_typ_word_prog_timo * sc->sc_max_word_prog_timo, 296 sc->sc_max_word_prog_timo); 297 printf("typical buffer write timeout: %dusec\n", 298 sc->sc_typ_buffer_write_timo); 299 printf("maximam buffer write timeout: %dusec (%d time of typ)\n", 300 sc->sc_typ_buffer_write_timo * sc->sc_max_buffer_write_timo, 301 sc->sc_max_buffer_write_timo); 302 printf("typical block erase timeout: %dmsec\n", 303 sc->sc_typ_block_erase_timo); 304 printf("maximam block erase timeout: %dmsec (%d time of typ)\n", 305 sc->sc_typ_block_erase_timo * sc->sc_max_block_erase_timo, 306 sc->sc_max_block_erase_timo); 307 308 printf("read_cfi: dump cfi\n"); 309 for (i = 0; i < CFI_TOTAL_SIZE;) { 310 int j; 311 for (j = 0; j < 16; j++) { 312 printf("%02x ", sc->sc_cfi_raw[i++]); 313 } 314 printf("\n"); 315 } 316 #endif 317 } 318 319 int 320 flashopen(dev_t dev, int flag, int mode, struct lwp *l) 321 { 322 struct flash_softc *sc; 323 324 sc = device_lookup_private(&flash_cd, minor(dev)); 325 if (sc == NULL) 326 return ENXIO; 327 if (sc->sc_status & FLASH_ST_BUSY) 328 return EBUSY; 329 sc->sc_status |= FLASH_ST_BUSY; 330 return 0; 331 } 332 333 int 334 flashclose(dev_t dev, int flag, int mode, struct lwp *l) 335 { 336 struct flash_softc *sc; 337 338 sc = device_lookup_private(&flash_cd, minor(dev)); 339 sc->sc_status &= ~FLASH_ST_BUSY; 340 return 0; 341 } 342 343 int 344 flashread(dev_t dev, struct uio *uio, int flag) 345 { 346 struct flash_softc *sc; 347 bus_space_tag_t iot; 348 bus_space_handle_t ioh; 349 bus_size_t off; 350 int total; 351 int count; 352 int error; 353 354 sc = device_lookup_private(&flash_cd, minor(dev)); 355 iot = sc->sc_iot; 356 ioh = sc->sc_ioh; 357 358 off = uio->uio_offset; 359 total = min(sc->sc_size - off, uio->uio_resid); 360 361 while (total > 0) { 362 count = min(sc->sc_block_size, uio->uio_resid); 363 bus_space_read_region_1(iot, ioh, off, sc->sc_buf, count); 364 if ((error = uiomove(sc->sc_buf, count, uio)) != 0) 365 return error; 366 off += count; 367 total -= count; 368 } 369 return 0; 370 } 371 372 373 int 374 flashwrite(dev_t dev, struct uio *uio, int flag) 375 { 376 struct flash_softc *sc; 377 bus_space_tag_t iot; 378 bus_space_handle_t ioh; 379 bus_size_t off; 380 int stat; 381 int error; 382 383 sc = device_lookup_private(&flash_cd, minor(dev)); 384 385 if (sc->sc_size < uio->uio_offset + uio->uio_resid) 386 return ENOSPC; 387 if (uio->uio_offset % sc->sc_block_size) 388 return EINVAL; 389 if (uio->uio_resid % sc->sc_block_size) 390 return EINVAL; 391 392 iot = sc->sc_iot; 393 ioh = sc->sc_ioh; 394 395 for (off = uio->uio_offset; 396 uio->uio_resid > 0; 397 off += sc->sc_block_size) { 398 if ((error = uiomove(sc->sc_buf, sc->sc_block_size, uio)) != 0) 399 return error; 400 if (is_block_same(sc, off, sc->sc_buf)) 401 continue; 402 if ((stat = flash_block_erase(sc, off)) != 0) { 403 printf("block erase failed status = 0x%x\n", stat); 404 return EIO; 405 } 406 if ((stat = flash_block_write(sc, off)) != 0) { 407 printf("block write failed status = 0x%x\n", stat); 408 return EIO; 409 } 410 } 411 return 0; 412 } 413 414 /* 415 * XXX 416 * this function is too much specific for the device. 417 */ 418 static int 419 i28f128_probe(bus_space_tag_t iot, bus_space_handle_t ioh) 420 { 421 static const u_int8_t vendor_code[] = { 422 0x89, /* manufacturer code: intel */ 423 0x18, /* device code: 28F128 */ 424 }; 425 426 static const u_int8_t idstr[] = { 427 'Q', 'R', 'Y', 428 0x01, 0x00, 429 0x31, 0x00, 430 0xff 431 }; 432 433 int i; 434 435 /* start Common Flash Interface Query */ 436 bus_space_write_2(iot, ioh, 0, CFI_READ_CFI_QUERY); 437 /* read CFI Query ID string */ 438 for (i = 0; idstr[i] != 0xff; i++) { 439 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i]) 440 return 1; 441 } 442 443 /* read manufacturer code and device code */ 444 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0]) 445 return 1; 446 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1]) 447 return 1; 448 449 bus_space_write_2(iot, ioh, 0, I28F128_RESET); 450 return 0; 451 } 452 453 /* 454 * XXX 455 * this function is too much specific for the device. 456 */ 457 static int 458 mbm29160_probe(bus_space_tag_t iot, bus_space_handle_t ioh) 459 { 460 static const u_int16_t vendor_code[] = { 461 0x0004, /* manufacturer code: intel */ 462 0x2249, /* device code: 29LV160BE */ 463 }; 464 465 static const u_int8_t idstr[] = { 466 'Q', 'R', 'Y', 467 0x02, 0x00, 468 0x40, 0x00, 469 0xff 470 }; 471 472 int i; 473 474 /* start Common Flash Interface Query */ 475 bus_space_write_2(iot, ioh, 0xaa, CFI_READ_CFI_QUERY); 476 /* read CFI Query ID string */ 477 for (i = 0; idstr[i] != 0xff; i++) { 478 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i]) 479 return 1; 480 } 481 482 bus_space_write_2(iot, ioh, 0, 0xff); 483 484 /* read manufacturer code and device code */ 485 bus_space_write_2(iot, ioh, 0x555 << 1, 0xaa); 486 bus_space_write_2(iot, ioh, 0x2aa << 1, 0x55); 487 bus_space_write_2(iot, ioh, 0x555 << 1, 0x90); 488 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0]) 489 return 1; 490 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1]) 491 return 1; 492 493 bus_space_write_2(iot, ioh, 0, 0xff); 494 return 0; 495 } 496 497 static int 498 is_block_same(struct flash_softc *sc, bus_size_t offset, const void *bufp) 499 { 500 bus_space_tag_t iot = sc->sc_iot; 501 bus_space_handle_t ioh = sc->sc_ioh; 502 const u_int8_t *p = bufp; 503 int count = sc->sc_block_size; 504 505 while (count-- > 0) { 506 if (bus_space_read_1(iot, ioh, offset++) != *p++) 507 return 0; 508 } 509 return 1; 510 } 511 512 static int 513 intel_erase(struct flash_softc *sc, bus_size_t offset) 514 { 515 bus_space_tag_t iot = sc->sc_iot; 516 bus_space_handle_t ioh = sc->sc_ioh; 517 int status; 518 int i; 519 520 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_1ST); 521 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_2ND); 522 523 status = 0; 524 for (i = sc->sc_max_block_erase_timo; i > 0; i--) { 525 tsleep(sc, PRIBIO, "blockerase", 526 1 + (sc->sc_typ_block_erase_timo * hz) / 1000); 527 if ((status = bus_space_read_2(iot, ioh, offset)) 528 & I28F128_S_READY) 529 break; 530 } 531 if (i == 0) 532 status |= FLASH_TIMEOUT; 533 534 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS); 535 bus_space_write_2(iot, ioh, offset, I28F128_RESET); 536 537 return status & (FLASH_TIMEOUT 538 | I28F128_S_ERASE_SUSPEND 539 | I28F128_S_COMSEQ_ERROR 540 | I28F128_S_ERASE_ERROR 541 | I28F128_S_BLOCK_LOCKED); 542 } 543 544 static int 545 intel_write(struct flash_softc *sc, bus_size_t offset) 546 { 547 bus_space_tag_t iot = sc->sc_iot; 548 bus_space_handle_t ioh = sc->sc_ioh; 549 int wbuf_size; 550 int timo; 551 int status; 552 bus_size_t fence; 553 int i; 554 const u_int16_t *p; 555 556 /* wbuf_size = size in u_int16_t */ 557 wbuf_size = sc->sc_write_buffer_size >> 1; 558 559 p = (u_int16_t *) sc->sc_buf; 560 fence = offset + sc->sc_block_size; 561 do { 562 status = 0; 563 for (timo = sc->sc_max_buffer_write_timo; timo > 0; timo--) { 564 bus_space_write_2(iot, ioh, offset, 565 I28F128_WRITE_BUFFER); 566 status = bus_space_read_2(iot, ioh, offset); 567 if (status & I28F128_XS_BUF_AVAIL) 568 break; 569 DELAY(sc->sc_typ_buffer_write_timo); 570 } 571 if (timo == 0) { 572 status |= FLASH_TIMEOUT; 573 goto errout; 574 } 575 576 bus_space_write_2(iot, ioh, offset, wbuf_size - 1); 577 578 for (i = wbuf_size; i > 0; i--, p++, offset += 2) 579 bus_space_write_2(iot, ioh, offset, *p); 580 581 bus_space_write_2(iot, ioh, offset, I28F128_WBUF_CONFIRM); 582 583 do { 584 bus_space_write_2(iot, ioh, offset, 585 I28F128_READ_STATUS); 586 status = bus_space_read_2(iot, ioh, offset); 587 } while (!(status & I28F128_S_READY)); 588 589 } while (offset < fence); 590 591 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS); 592 bus_space_write_2(iot, ioh, offset, I28F128_RESET); 593 594 return 0; 595 596 errout: 597 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS); 598 bus_space_write_2(iot, ioh, offset, I28F128_RESET); 599 600 status &= (FLASH_TIMEOUT 601 | I28F128_S_PROG_ERROR 602 | I28F128_S_COMSEQ_ERROR 603 | I28F128_S_LOW_VOLTAGE 604 | I28F128_S_PROG_SUSPEND 605 | I28F128_S_BLOCK_LOCKED); 606 return status; 607 } 608 609 static int 610 amd_erase_sector(struct flash_softc *sc, bus_size_t offset) 611 { 612 bus_space_tag_t iot = sc->sc_iot; 613 bus_space_handle_t ioh = sc->sc_ioh; 614 int i; 615 616 DPRINTF(("amd_erase_sector offset = %08lx\n", offset)); 617 618 bus_space_write_2(iot, ioh, 619 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0); 620 bus_space_write_2(iot, ioh, 621 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1); 622 bus_space_write_2(iot, ioh, 623 MBM29LV160_COMM_ADDR2, MBM29LV160_ESECT_CMD2); 624 bus_space_write_2(iot, ioh, 625 MBM29LV160_COMM_ADDR3, MBM29LV160_ESECT_CMD3); 626 bus_space_write_2(iot, ioh, 627 MBM29LV160_COMM_ADDR4, MBM29LV160_ESECT_CMD4); 628 bus_space_write_2(iot, ioh, offset, MBM29LV160_ESECT_CMD5); 629 630 for (i = sc->sc_max_block_erase_timo; i > 0; i--) { 631 tsleep(sc, PRIBIO, "blockerase", 632 1 + (sc->sc_typ_block_erase_timo * hz) / 1000); 633 if (bus_space_read_2(iot, ioh, offset) == 0xffff) 634 return 0; 635 } 636 637 return FLASH_TIMEOUT; 638 } 639 640 static int 641 amd_erase(struct flash_softc *sc, bus_size_t offset) 642 { 643 static const struct mbm29lv_subsect { 644 u_int16_t devcode; 645 u_int32_t subsect_mask; 646 u_int32_t subsect_addr; 647 } subsect[] = { 648 { 649 MBM29LV160TE_DEVCODE, 650 MBM29LV160_SUBSECT_MASK, 651 MBM29LV160TE_SUBSECT_ADDR 652 }, 653 { 654 MBM29LV160BE_DEVCODE, 655 MBM29LV160_SUBSECT_MASK, 656 MBM29LV160BE_SUBSECT_ADDR 657 }, 658 { 0, 0, 0 } 659 }; 660 661 bus_space_tag_t iot = sc->sc_iot; 662 bus_space_handle_t ioh = sc->sc_ioh; 663 u_int16_t devcode; 664 const struct mbm29lv_subsect *ss; 665 bus_size_t fence; 666 int step; 667 int status; 668 669 bus_space_write_2(iot, ioh, 670 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0); 671 bus_space_write_2(iot, ioh, 672 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1); 673 bus_space_write_2(iot, ioh, 674 MBM29LV160_COMM_ADDR2, MBM29LV160_SIGN_CMD2); 675 devcode = bus_space_read_2(iot, ioh, MBM29LV160_DEVCODE_REG); 676 677 for (ss = subsect; ss->devcode; ss++) { 678 if (ss->devcode == devcode) 679 break; 680 } 681 if (ss->devcode == 0) { 682 printf("flash: amd_erase(): unknown device code %04x\n", 683 devcode); 684 return -1; 685 } 686 687 DPRINTF(("flash: amd_erase(): devcode = %04x subsect = %08x\n", 688 devcode, ss->subsect_addr)); 689 690 fence = offset + sc->sc_block_size; 691 step = (offset & ss->subsect_mask) == ss->subsect_addr 692 ? MBM29LV160_SUBSECT_SIZE : MBM29LV160_SECT_SIZE; 693 do { 694 if ((status = amd_erase_sector(sc, offset)) != 0) 695 return status; 696 offset += step; 697 } while (offset < fence); 698 699 return 0; 700 } 701 702 static int 703 amd_write(struct flash_softc *sc, bus_size_t offset) 704 { 705 bus_space_tag_t iot = sc->sc_iot; 706 bus_space_handle_t ioh = sc->sc_ioh; 707 int timo; 708 bus_size_t fence; 709 const u_int16_t *p; 710 711 p = (u_int16_t *) sc->sc_buf; 712 fence = offset + sc->sc_block_size; 713 do { 714 bus_space_write_2(iot, ioh, 715 MBM29LV160_COMM_ADDR0, 716 MBM29LV160_COMM_CMD0); 717 bus_space_write_2(iot, ioh, 718 MBM29LV160_COMM_ADDR1, 719 MBM29LV160_COMM_CMD1); 720 bus_space_write_2(iot, ioh, 721 MBM29LV160_COMM_ADDR2, 722 MBM29LV160_PROG_CMD2); 723 bus_space_write_2(iot, ioh, offset, *p); 724 725 for (timo = sc->sc_max_word_prog_timo; timo > 0; timo--) { 726 if (bus_space_read_2(iot, ioh, offset) == *p) 727 break; 728 DELAY(sc->sc_typ_word_prog_timo); 729 } 730 if (timo == 0) 731 return FLASH_TIMEOUT; 732 733 p++; 734 offset += 2; 735 } while (offset < fence); 736 737 return 0; 738 } 739