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