1 /* $NetBSD: flash_vrip.c,v 1.10 2014/07/25 08:10:33 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.10 2014/07/25 08:10:33 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_discard = nodiscard, 98 .d_flag = 0 99 }; 100 101 static const struct flash_command_set { 102 u_int8_t fc_set0; 103 u_int8_t fc_set1; 104 struct flashops fc_ops; 105 } flash_cmd[] = { 106 { 107 .fc_set0 = CFI_COMMSET_INTEL0, 108 .fc_set1 = CFI_COMMSET_INTEL1, 109 .fc_ops = { 110 .fo_name = "Intel", 111 .fo_erase = intel_erase, 112 .fo_write = intel_write, 113 } 114 }, 115 { 116 .fc_set0 = CFI_COMMSET_AMDFJITU0, 117 .fc_set1 = CFI_COMMSET_AMDFJITU1, 118 .fc_ops = { 119 .fo_name = "AMD/Fujitsu", 120 .fo_erase = amd_erase, 121 .fo_write = amd_write, 122 } 123 }, 124 { 125 .fc_set0 = 0, 126 .fc_set1 = 0, 127 .fc_ops = { 128 .fo_name = NULL, 129 .fo_erase = NULL, 130 .fo_write = NULL, 131 } 132 } 133 }; 134 135 136 const static struct flashops * 137 find_command_set(u_int8_t cmdset0, u_int8_t cmdset1) 138 { 139 const struct flash_command_set *fc; 140 141 for (fc = flash_cmd; fc->fc_ops.fo_name; fc++) { 142 if (cmdset0 == fc->fc_set0 && cmdset1 == fc->fc_set1) 143 return &fc->fc_ops; 144 } 145 return NULL; 146 } 147 148 static int 149 probe_cfi(bus_space_tag_t iot, bus_space_handle_t ioh) 150 { 151 const u_int8_t *idstr = CFI_QUERY_ID_STR; 152 int i; 153 u_int8_t cmdset0; 154 u_int8_t cmdset1; 155 156 /* start Common Flash Interface Query */ 157 bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY); 158 159 /* read CFI Query ID string */ 160 i = CFI_QUERY_ID_STR_REG << 1; 161 do { 162 if (bus_space_read_2(iot, ioh, i) != *idstr) { 163 bus_space_write_2(iot, ioh, 0, FLASH_RESET); 164 return 1; 165 } 166 i += 2; 167 idstr++; 168 } while (*idstr); 169 170 cmdset0 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG0 << 1); 171 cmdset1 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG1 << 1); 172 173 /* switch flash to read mode */ 174 bus_space_write_2(iot, ioh, 0, FLASH_RESET); 175 176 if (!find_command_set(cmdset0, cmdset1)) 177 return 1; 178 179 return 0; 180 } 181 182 static int 183 flash_probe(device_t parent, cfdata_t match, void *aux) 184 { 185 struct vrip_attach_args *va = aux; 186 bus_space_handle_t ioh; 187 188 if (bus_space_map(va->va_iot, va->va_addr, va->va_size, 0, &ioh)) 189 return 0; 190 if (!probe_cfi(va->va_iot, ioh)) { 191 DPRINTF("CFI ID str and command set recognized\n"); 192 goto detect; 193 } 194 if (!i28f128_probe(va->va_iot, ioh)) { 195 DPRINTF("28F128 detected\n"); 196 goto detect; 197 } 198 if (!mbm29160_probe(va->va_iot, ioh)) { 199 DPRINTF("29LV160 detected\n"); 200 goto detect; 201 } 202 return 0; 203 204 detect: 205 bus_space_unmap(va->va_iot, ioh, va->va_size); 206 return 1; 207 } 208 209 static void 210 flash_attach(device_t parent, device_t self, void *aux) 211 { 212 struct flash_softc *sc = device_private(self); 213 struct vrip_attach_args *va = aux; 214 int i; 215 int fence; 216 bus_space_tag_t iot = va->va_iot; 217 bus_space_handle_t ioh; 218 size_t block_size; 219 220 if (bus_space_map(iot, va->va_addr, va->va_size, 0, &ioh)) { 221 printf(": can't map i/o space\n"); 222 return; 223 } 224 225 sc->sc_iot = iot; 226 sc->sc_ioh = ioh; 227 sc->sc_size = va->va_size; 228 sc->sc_status = 0; 229 230 /* 231 * Read entire CFI structure 232 */ 233 bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY); 234 for (i = 0; i < CFI_TOTAL_SIZE; i++) { 235 sc->sc_cfi_raw[i] = bus_space_read_2(iot, ioh, i << 1); 236 } 237 bus_space_write_2(iot, ioh, 0, FLASH_RESET); 238 239 sc->sc_ops = find_command_set(sc->sc_cfi_raw[CFI_PRIM_COMM_REG0], 240 sc->sc_cfi_raw[CFI_PRIM_COMM_REG1]); 241 if (sc->sc_ops) { 242 printf(": using %s command set", sc->sc_ops->fo_name); 243 } else { 244 printf("opps sc->sc_ops is NULL\n"); 245 } 246 247 /* 248 * determine size of the largest block 249 */ 250 sc->sc_block_size = 0; 251 i = CFI_EBLK1_INFO_REG; 252 fence = sc->sc_cfi_raw[CFI_NUM_ERASE_BLK_REG] * CFI_EBLK_INFO_SIZE 253 + i; 254 for (; i < fence; i += CFI_EBLK_INFO_SIZE) { 255 if (sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT0] == 0 256 && sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT1] == 0) 257 continue; 258 block_size 259 = (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE0] << 8) 260 + (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE1] << 16); 261 if (sc->sc_block_size < block_size) 262 sc->sc_block_size = block_size; 263 } 264 265 if ((sc->sc_buf = malloc(sc->sc_block_size, M_DEVBUF, M_NOWAIT)) 266 == NULL) { 267 printf(": can't alloc buffer space\n"); 268 return; 269 } 270 271 sc->sc_write_buffer_size 272 = 1 << (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG0] 273 + (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG1] << 8)); 274 sc->sc_typ_word_prog_timo 275 = 1 << sc->sc_cfi_raw[CFI_TYP_WORD_PROG_REG]; 276 sc->sc_max_word_prog_timo 277 = 1 << sc->sc_cfi_raw[CFI_MAX_WORD_PROG_REG]; 278 sc->sc_typ_buffer_write_timo 279 = 1 << sc->sc_cfi_raw[CFI_TYP_BUF_WRITE_REG]; 280 sc->sc_max_buffer_write_timo 281 = 1 << sc->sc_cfi_raw[CFI_MAX_BUF_WRITE_REG]; 282 sc->sc_typ_block_erase_timo 283 = 1 << sc->sc_cfi_raw[CFI_TYP_BLOCK_ERASE_REG]; 284 sc->sc_max_block_erase_timo 285 = 1 << sc->sc_cfi_raw[CFI_MAX_BLOCK_ERASE_REG]; 286 287 printf("\n"); 288 289 #ifdef FLASH_DEBUG 290 printf("read_cfi: extract cfi\n"); 291 printf("max block size: %dbyte\n", sc->sc_block_size); 292 printf("write buffer size: %dbyte\n", sc->sc_write_buffer_size); 293 printf("typical word program timeout: %dusec\n", 294 sc->sc_typ_word_prog_timo); 295 printf("maximam word program timeout: %dusec (%d time of typ)\n", 296 sc->sc_typ_word_prog_timo * sc->sc_max_word_prog_timo, 297 sc->sc_max_word_prog_timo); 298 printf("typical buffer write timeout: %dusec\n", 299 sc->sc_typ_buffer_write_timo); 300 printf("maximam buffer write timeout: %dusec (%d time of typ)\n", 301 sc->sc_typ_buffer_write_timo * sc->sc_max_buffer_write_timo, 302 sc->sc_max_buffer_write_timo); 303 printf("typical block erase timeout: %dmsec\n", 304 sc->sc_typ_block_erase_timo); 305 printf("maximam block erase timeout: %dmsec (%d time of typ)\n", 306 sc->sc_typ_block_erase_timo * sc->sc_max_block_erase_timo, 307 sc->sc_max_block_erase_timo); 308 309 printf("read_cfi: dump cfi\n"); 310 for (i = 0; i < CFI_TOTAL_SIZE;) { 311 int j; 312 for (j = 0; j < 16; j++) { 313 printf("%02x ", sc->sc_cfi_raw[i++]); 314 } 315 printf("\n"); 316 } 317 #endif 318 } 319 320 int 321 flashopen(dev_t dev, int flag, int mode, struct lwp *l) 322 { 323 struct flash_softc *sc; 324 325 sc = device_lookup_private(&flash_cd, minor(dev)); 326 if (sc == NULL) 327 return ENXIO; 328 if (sc->sc_status & FLASH_ST_BUSY) 329 return EBUSY; 330 sc->sc_status |= FLASH_ST_BUSY; 331 return 0; 332 } 333 334 int 335 flashclose(dev_t dev, int flag, int mode, struct lwp *l) 336 { 337 struct flash_softc *sc; 338 339 sc = device_lookup_private(&flash_cd, minor(dev)); 340 sc->sc_status &= ~FLASH_ST_BUSY; 341 return 0; 342 } 343 344 int 345 flashread(dev_t dev, struct uio *uio, int flag) 346 { 347 struct flash_softc *sc; 348 bus_space_tag_t iot; 349 bus_space_handle_t ioh; 350 bus_size_t off; 351 int total; 352 int count; 353 int error; 354 355 sc = device_lookup_private(&flash_cd, minor(dev)); 356 iot = sc->sc_iot; 357 ioh = sc->sc_ioh; 358 359 off = uio->uio_offset; 360 total = min(sc->sc_size - off, uio->uio_resid); 361 362 while (total > 0) { 363 count = min(sc->sc_block_size, uio->uio_resid); 364 bus_space_read_region_1(iot, ioh, off, sc->sc_buf, count); 365 if ((error = uiomove(sc->sc_buf, count, uio)) != 0) 366 return error; 367 off += count; 368 total -= count; 369 } 370 return 0; 371 } 372 373 374 int 375 flashwrite(dev_t dev, struct uio *uio, int flag) 376 { 377 struct flash_softc *sc; 378 bus_space_tag_t iot; 379 bus_space_handle_t ioh; 380 bus_size_t off; 381 int stat; 382 int error; 383 384 sc = device_lookup_private(&flash_cd, minor(dev)); 385 386 if (sc->sc_size < uio->uio_offset + uio->uio_resid) 387 return ENOSPC; 388 if (uio->uio_offset % sc->sc_block_size) 389 return EINVAL; 390 if (uio->uio_resid % sc->sc_block_size) 391 return EINVAL; 392 393 iot = sc->sc_iot; 394 ioh = sc->sc_ioh; 395 396 for (off = uio->uio_offset; 397 uio->uio_resid > 0; 398 off += sc->sc_block_size) { 399 if ((error = uiomove(sc->sc_buf, sc->sc_block_size, uio)) != 0) 400 return error; 401 if (is_block_same(sc, off, sc->sc_buf)) 402 continue; 403 if ((stat = flash_block_erase(sc, off)) != 0) { 404 printf("block erase failed status = 0x%x\n", stat); 405 return EIO; 406 } 407 if ((stat = flash_block_write(sc, off)) != 0) { 408 printf("block write failed status = 0x%x\n", stat); 409 return EIO; 410 } 411 } 412 return 0; 413 } 414 415 /* 416 * XXX 417 * this function is too much specific for the device. 418 */ 419 static int 420 i28f128_probe(bus_space_tag_t iot, bus_space_handle_t ioh) 421 { 422 static const u_int8_t vendor_code[] = { 423 0x89, /* manufacturer code: intel */ 424 0x18, /* device code: 28F128 */ 425 }; 426 427 static const u_int8_t idstr[] = { 428 'Q', 'R', 'Y', 429 0x01, 0x00, 430 0x31, 0x00, 431 0xff 432 }; 433 434 int i; 435 436 /* start Common Flash Interface Query */ 437 bus_space_write_2(iot, ioh, 0, CFI_READ_CFI_QUERY); 438 /* read CFI Query ID string */ 439 for (i = 0; idstr[i] != 0xff; i++) { 440 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i]) 441 return 1; 442 } 443 444 /* read manufacturer code and device code */ 445 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0]) 446 return 1; 447 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1]) 448 return 1; 449 450 bus_space_write_2(iot, ioh, 0, I28F128_RESET); 451 return 0; 452 } 453 454 /* 455 * XXX 456 * this function is too much specific for the device. 457 */ 458 static int 459 mbm29160_probe(bus_space_tag_t iot, bus_space_handle_t ioh) 460 { 461 static const u_int16_t vendor_code[] = { 462 0x0004, /* manufacturer code: intel */ 463 0x2249, /* device code: 29LV160BE */ 464 }; 465 466 static const u_int8_t idstr[] = { 467 'Q', 'R', 'Y', 468 0x02, 0x00, 469 0x40, 0x00, 470 0xff 471 }; 472 473 int i; 474 475 /* start Common Flash Interface Query */ 476 bus_space_write_2(iot, ioh, 0xaa, CFI_READ_CFI_QUERY); 477 /* read CFI Query ID string */ 478 for (i = 0; idstr[i] != 0xff; i++) { 479 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i]) 480 return 1; 481 } 482 483 bus_space_write_2(iot, ioh, 0, 0xff); 484 485 /* read manufacturer code and device code */ 486 bus_space_write_2(iot, ioh, 0x555 << 1, 0xaa); 487 bus_space_write_2(iot, ioh, 0x2aa << 1, 0x55); 488 bus_space_write_2(iot, ioh, 0x555 << 1, 0x90); 489 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0]) 490 return 1; 491 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1]) 492 return 1; 493 494 bus_space_write_2(iot, ioh, 0, 0xff); 495 return 0; 496 } 497 498 static int 499 is_block_same(struct flash_softc *sc, bus_size_t offset, const void *bufp) 500 { 501 bus_space_tag_t iot = sc->sc_iot; 502 bus_space_handle_t ioh = sc->sc_ioh; 503 const u_int8_t *p = bufp; 504 int count = sc->sc_block_size; 505 506 while (count-- > 0) { 507 if (bus_space_read_1(iot, ioh, offset++) != *p++) 508 return 0; 509 } 510 return 1; 511 } 512 513 static int 514 intel_erase(struct flash_softc *sc, bus_size_t offset) 515 { 516 bus_space_tag_t iot = sc->sc_iot; 517 bus_space_handle_t ioh = sc->sc_ioh; 518 int status; 519 int i; 520 521 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_1ST); 522 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_2ND); 523 524 status = 0; 525 for (i = sc->sc_max_block_erase_timo; i > 0; i--) { 526 tsleep(sc, PRIBIO, "blockerase", 527 1 + (sc->sc_typ_block_erase_timo * hz) / 1000); 528 if ((status = bus_space_read_2(iot, ioh, offset)) 529 & I28F128_S_READY) 530 break; 531 } 532 if (i == 0) 533 status |= FLASH_TIMEOUT; 534 535 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS); 536 bus_space_write_2(iot, ioh, offset, I28F128_RESET); 537 538 return status & (FLASH_TIMEOUT 539 | I28F128_S_ERASE_SUSPEND 540 | I28F128_S_COMSEQ_ERROR 541 | I28F128_S_ERASE_ERROR 542 | I28F128_S_BLOCK_LOCKED); 543 } 544 545 static int 546 intel_write(struct flash_softc *sc, bus_size_t offset) 547 { 548 bus_space_tag_t iot = sc->sc_iot; 549 bus_space_handle_t ioh = sc->sc_ioh; 550 int wbuf_size; 551 int timo; 552 int status; 553 bus_size_t fence; 554 int i; 555 const u_int16_t *p; 556 557 /* wbuf_size = size in u_int16_t */ 558 wbuf_size = sc->sc_write_buffer_size >> 1; 559 560 p = (u_int16_t *) sc->sc_buf; 561 fence = offset + sc->sc_block_size; 562 do { 563 status = 0; 564 for (timo = sc->sc_max_buffer_write_timo; timo > 0; timo--) { 565 bus_space_write_2(iot, ioh, offset, 566 I28F128_WRITE_BUFFER); 567 status = bus_space_read_2(iot, ioh, offset); 568 if (status & I28F128_XS_BUF_AVAIL) 569 break; 570 DELAY(sc->sc_typ_buffer_write_timo); 571 } 572 if (timo == 0) { 573 status |= FLASH_TIMEOUT; 574 goto errout; 575 } 576 577 bus_space_write_2(iot, ioh, offset, wbuf_size - 1); 578 579 for (i = wbuf_size; i > 0; i--, p++, offset += 2) 580 bus_space_write_2(iot, ioh, offset, *p); 581 582 bus_space_write_2(iot, ioh, offset, I28F128_WBUF_CONFIRM); 583 584 do { 585 bus_space_write_2(iot, ioh, offset, 586 I28F128_READ_STATUS); 587 status = bus_space_read_2(iot, ioh, offset); 588 } while (!(status & I28F128_S_READY)); 589 590 } while (offset < fence); 591 592 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS); 593 bus_space_write_2(iot, ioh, offset, I28F128_RESET); 594 595 return 0; 596 597 errout: 598 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS); 599 bus_space_write_2(iot, ioh, offset, I28F128_RESET); 600 601 status &= (FLASH_TIMEOUT 602 | I28F128_S_PROG_ERROR 603 | I28F128_S_COMSEQ_ERROR 604 | I28F128_S_LOW_VOLTAGE 605 | I28F128_S_PROG_SUSPEND 606 | I28F128_S_BLOCK_LOCKED); 607 return status; 608 } 609 610 static int 611 amd_erase_sector(struct flash_softc *sc, bus_size_t offset) 612 { 613 bus_space_tag_t iot = sc->sc_iot; 614 bus_space_handle_t ioh = sc->sc_ioh; 615 int i; 616 617 DPRINTF(("amd_erase_sector offset = %08lx\n", offset)); 618 619 bus_space_write_2(iot, ioh, 620 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0); 621 bus_space_write_2(iot, ioh, 622 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1); 623 bus_space_write_2(iot, ioh, 624 MBM29LV160_COMM_ADDR2, MBM29LV160_ESECT_CMD2); 625 bus_space_write_2(iot, ioh, 626 MBM29LV160_COMM_ADDR3, MBM29LV160_ESECT_CMD3); 627 bus_space_write_2(iot, ioh, 628 MBM29LV160_COMM_ADDR4, MBM29LV160_ESECT_CMD4); 629 bus_space_write_2(iot, ioh, offset, MBM29LV160_ESECT_CMD5); 630 631 for (i = sc->sc_max_block_erase_timo; i > 0; i--) { 632 tsleep(sc, PRIBIO, "blockerase", 633 1 + (sc->sc_typ_block_erase_timo * hz) / 1000); 634 if (bus_space_read_2(iot, ioh, offset) == 0xffff) 635 return 0; 636 } 637 638 return FLASH_TIMEOUT; 639 } 640 641 static int 642 amd_erase(struct flash_softc *sc, bus_size_t offset) 643 { 644 static const struct mbm29lv_subsect { 645 u_int16_t devcode; 646 u_int32_t subsect_mask; 647 u_int32_t subsect_addr; 648 } subsect[] = { 649 { 650 MBM29LV160TE_DEVCODE, 651 MBM29LV160_SUBSECT_MASK, 652 MBM29LV160TE_SUBSECT_ADDR 653 }, 654 { 655 MBM29LV160BE_DEVCODE, 656 MBM29LV160_SUBSECT_MASK, 657 MBM29LV160BE_SUBSECT_ADDR 658 }, 659 { 0, 0, 0 } 660 }; 661 662 bus_space_tag_t iot = sc->sc_iot; 663 bus_space_handle_t ioh = sc->sc_ioh; 664 u_int16_t devcode; 665 const struct mbm29lv_subsect *ss; 666 bus_size_t fence; 667 int step; 668 int status; 669 670 bus_space_write_2(iot, ioh, 671 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0); 672 bus_space_write_2(iot, ioh, 673 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1); 674 bus_space_write_2(iot, ioh, 675 MBM29LV160_COMM_ADDR2, MBM29LV160_SIGN_CMD2); 676 devcode = bus_space_read_2(iot, ioh, MBM29LV160_DEVCODE_REG); 677 678 for (ss = subsect; ss->devcode; ss++) { 679 if (ss->devcode == devcode) 680 break; 681 } 682 if (ss->devcode == 0) { 683 printf("flash: amd_erase(): unknown device code %04x\n", 684 devcode); 685 return -1; 686 } 687 688 DPRINTF(("flash: amd_erase(): devcode = %04x subsect = %08x\n", 689 devcode, ss->subsect_addr)); 690 691 fence = offset + sc->sc_block_size; 692 step = (offset & ss->subsect_mask) == ss->subsect_addr 693 ? MBM29LV160_SUBSECT_SIZE : MBM29LV160_SECT_SIZE; 694 do { 695 if ((status = amd_erase_sector(sc, offset)) != 0) 696 return status; 697 offset += step; 698 } while (offset < fence); 699 700 return 0; 701 } 702 703 static int 704 amd_write(struct flash_softc *sc, bus_size_t offset) 705 { 706 bus_space_tag_t iot = sc->sc_iot; 707 bus_space_handle_t ioh = sc->sc_ioh; 708 int timo; 709 bus_size_t fence; 710 const u_int16_t *p; 711 712 p = (u_int16_t *) sc->sc_buf; 713 fence = offset + sc->sc_block_size; 714 do { 715 bus_space_write_2(iot, ioh, 716 MBM29LV160_COMM_ADDR0, 717 MBM29LV160_COMM_CMD0); 718 bus_space_write_2(iot, ioh, 719 MBM29LV160_COMM_ADDR1, 720 MBM29LV160_COMM_CMD1); 721 bus_space_write_2(iot, ioh, 722 MBM29LV160_COMM_ADDR2, 723 MBM29LV160_PROG_CMD2); 724 bus_space_write_2(iot, ioh, offset, *p); 725 726 for (timo = sc->sc_max_word_prog_timo; timo > 0; timo--) { 727 if (bus_space_read_2(iot, ioh, offset) == *p) 728 break; 729 DELAY(sc->sc_typ_word_prog_timo); 730 } 731 if (timo == 0) 732 return FLASH_TIMEOUT; 733 734 p++; 735 offset += 2; 736 } while (offset < fence); 737 738 return 0; 739 } 740