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