1 /* $NetBSD: cfi_0002.c,v 1.4 2011/07/23 06:26:26 cliff Exp $ */ 2 /*- 3 * Copyright (c) 2011 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Cliff Neighbors. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "opt_flash.h" 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: cfi_0002.c,v 1.4 2011/07/23 06:26:26 cliff Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/cdefs.h> 39 #include <sys/device.h> 40 #include <sys/endian.h> 41 #include <sys/time.h> 42 43 #include <sys/bus.h> 44 45 #include <dev/nor/nor.h> 46 #include <dev/nor/cfi.h> 47 #include <dev/nor/cfi_0002.h> 48 49 50 static void cfi_0002_version_init(struct cfi * const); 51 static int cfi_0002_read_page(device_t, flash_off_t, uint8_t *); 52 static int cfi_0002_program_page(device_t, flash_off_t, const uint8_t *); 53 static int cfi_0002_erase_block(device_t, flash_off_t); 54 static int cfi_0002_erase_all(device_t); 55 static int cfi_0002_busy(device_t, flash_off_t, u_long); 56 static int cfi_0002_busy_wait(struct cfi * const, flash_off_t, u_long); 57 static int cfi_0002_busy_poll(struct cfi * const, flash_off_t, u_long); 58 static int cfi_0002_busy_yield(struct cfi * const, flash_off_t, u_long); 59 static int cfi_0002_busy_dq7(struct cfi * const , flash_off_t); 60 #ifdef NOTYET 61 static int cfi_0002_busy_reg(struct cfi * const, flash_off_t); 62 #endif 63 64 65 static const char *page_mode_str[] = { 66 "(not supported)", 67 "4 word page", 68 "8 word page", 69 "16 word page", 70 }; 71 72 static const char *wp_mode_str[] = { 73 "Flash device without WP Protect (No Boot)", 74 "Eight 8 kB Sectors at TOP and Bottom with WP (Dual Boot)", 75 "Bottom Boot Device with WP Protect (Bottom Boot)", 76 "Top Boot Device with WP Protect (Top Boot)", 77 "Uniform, Bottom WP Protect (Uniform Bottom Boot)", 78 "Uniform, Top WP Protect (Uniform Top Boot)", 79 "WP Protect for all sectors", 80 "Uniform, Top or Bottom WP Protect", 81 }; 82 83 84 static inline const char * 85 cfi_0002_page_mode_str(uint8_t mode) 86 { 87 if (mode >= __arraycount(page_mode_str)) 88 panic("%s: mode %d out of range", __func__, mode); 89 return page_mode_str[mode]; 90 } 91 92 static inline const char * 93 cfi_0002_wp_mode_str(uint8_t mode) 94 { 95 if (mode >= __arraycount(wp_mode_str)) 96 panic("%s: mode %d out of range", __func__, mode); 97 return wp_mode_str[mode]; 98 } 99 100 /* 101 * cfi_0002_time_write_nbyte - maximum usec delay waiting for write buffer 102 */ 103 static inline u_long 104 cfi_0002_time_write_nbyte(struct cfi *cfi) 105 { 106 u_int shft = cfi->cfi_qry_data.write_nbyte_time_typ; 107 shft += cfi->cfi_qry_data.write_nbyte_time_max; 108 u_long usec = 1UL << shft; 109 return usec; 110 } 111 112 /* 113 * cfi_0002_time_erase_blk - maximum usec delay waiting for erase block 114 */ 115 static inline u_long 116 cfi_0002_time_erase_blk(struct cfi *cfi) 117 { 118 u_int shft = cfi->cfi_qry_data.erase_blk_time_typ; 119 shft += cfi->cfi_qry_data.erase_blk_time_max; 120 u_long usec = 1000UL << shft; 121 return usec; 122 } 123 124 /* 125 * cfi_0002_time_erase_all - maximum usec delay waiting for erase chip 126 */ 127 static inline u_long 128 cfi_0002_time_erase_all(struct cfi *cfi) 129 { 130 u_int shft = cfi->cfi_qry_data.erase_chip_time_typ; 131 shft += cfi->cfi_qry_data.erase_chip_time_max; 132 u_long usec = 1000UL << shft; 133 return usec; 134 } 135 136 /* 137 * cfi_0002_time_dflt - maximum usec delay to use waiting for ready 138 * 139 * use the maximum delay for chip erase function 140 * that should be the worst non-sick case 141 */ 142 static inline u_long 143 cfi_0002_time_dflt(struct cfi *cfi) 144 { 145 return cfi_0002_time_erase_all(cfi); 146 } 147 148 void 149 cfi_0002_init(struct nor_softc * const sc, struct cfi * const cfi, 150 struct nor_chip * const chip) 151 { 152 CFI_0002_STATS_INIT(sc->sc_dev, cfi); 153 154 cfi_0002_version_init(cfi); 155 156 cfi->cfi_ops.cfi_reset = cfi_reset_std; 157 cfi->cfi_yield_time = 500; /* 500 usec */ 158 159 /* page size for buffered write */ 160 chip->nc_page_size = 161 1 << cfi->cfi_qry_data.write_nbyte_size_max; 162 163 /* these are unused */ 164 chip->nc_spare_size = 0; 165 chip->nc_badmarker_offs = 0; 166 167 /* establish command-set-specific interface ops */ 168 sc->sc_nor_if->read_page = cfi_0002_read_page; 169 sc->sc_nor_if->program_page = cfi_0002_program_page; 170 sc->sc_nor_if->erase_block = cfi_0002_erase_block; 171 sc->sc_nor_if->erase_all = cfi_0002_erase_all; 172 sc->sc_nor_if->busy = cfi_0002_busy; 173 174 } 175 176 /* 177 * cfi_0002_version_init - command set version-specific initialization 178 * 179 * see "Programmer's Guide for the Spansion 65 nm GL-S MirrorBit EclipseTM 180 * Flash Non-Volatile Memory Family Architecture" section 5. 181 */ 182 static void 183 cfi_0002_version_init(struct cfi * const cfi) 184 { 185 const uint8_t major = cfi->cfi_qry_data.pri.cmd_0002.version_maj; 186 const uint8_t minor = cfi->cfi_qry_data.pri.cmd_0002.version_min; 187 188 if ((minor == '3') && (major == '1')) { 189 /* cmdset version 1.3 */ 190 cfi->cfi_ops.cfi_busy = cfi_0002_busy_dq7; 191 #ifdef NOTYET 192 cfi->cfi_ops.cfi_erase_sector = cfi_0002_erase_sector_q; 193 cfi->cfi_ops.cfi_program_word = cfi_0002_program_word_ub; 194 } else if ((minor >= '5') && (major == '1')) { 195 /* cmdset version 1.5 or later */ 196 cfi->cfi_ops.cfi_busy = cfi_0002_busy_reg; 197 cfi->cfi_ops.cfi_erase_sector = cfi_0002_erase_sector_1; 198 cfi->cfi_ops.cfi_program_word = cfi_0002_program_word_no_ub; 199 #endif 200 } else { 201 /* XXX this is excessive */ 202 panic("%s: unknown cmdset version %c.%c\n", 203 __func__, major, minor); 204 } 205 206 } 207 208 void 209 cfi_0002_print(device_t self, struct cfi * const cfi) 210 { 211 #ifdef NOR_VERBOSE 212 struct cmdset_0002_query_data *pri = &cfi->cfi_qry_data.pri.cmd_0002; 213 214 aprint_normal_dev(self, "AMD/Fujitsu cmdset (0x0002) version=%c.%c\n", 215 pri->version_maj, pri->version_min); 216 aprint_normal_dev(self, "page mode type: %s\n", 217 cfi_0002_page_mode_str(pri->page_mode_type)); 218 aprint_normal_dev(self, "wp protection: %s\n", 219 cfi_0002_wp_mode_str(pri->wp_prot)); 220 aprint_normal_dev(self, "program suspend %ssupported\n", 221 (pri->prog_susp == 0) ? "not " : ""); 222 aprint_normal_dev(self, "unlock bypass %ssupported\n", 223 (pri->unlock_bypass == 0) ? "not " : ""); 224 aprint_normal_dev(self, "secure silicon sector size %#x\n", 225 1 << pri->sss_size); 226 aprint_normal_dev(self, "SW features %#x\n", pri->soft_feat); 227 aprint_normal_dev(self, "page size %d\n", 1 << pri->page_size); 228 #endif 229 } 230 231 static int 232 cfi_0002_read_page(device_t self, flash_off_t offset, uint8_t *datap) 233 { 234 struct nor_softc * const sc = device_private(self); 235 KASSERT(sc != NULL); 236 KASSERT(sc->sc_nor_if != NULL); 237 struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private; 238 KASSERT(cfi != NULL); 239 struct nor_chip * const chip = &sc->sc_chip; 240 KASSERT(chip != NULL); 241 KASSERT(chip->nc_page_mask != 0); 242 KASSERT((offset & ~chip->nc_page_mask) == 0); 243 KASSERT (chip->nc_page_size != 0); 244 KASSERT((chip->nc_page_size & ((1 << cfi->cfi_portwidth) - 1)) == 0); 245 246 CFI_0002_STATS_INC(cfi, read_page); 247 248 bus_size_t count = chip->nc_page_size >> cfi->cfi_portwidth; 249 /* #words/page */ 250 251 int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi)); 252 if (error != 0) 253 return error; 254 255 switch(cfi->cfi_portwidth) { 256 case 0: 257 bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, offset, 258 (uint8_t *)datap, count); 259 break; 260 case 1: 261 bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, offset, 262 (uint16_t *)datap, count); 263 break; 264 case 2: 265 bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, offset, 266 (uint32_t *)datap, count); 267 break; 268 default: 269 panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth); 270 }; 271 272 return 0; 273 } 274 275 static int 276 cfi_0002_program_page(device_t self, flash_off_t offset, const uint8_t *datap) 277 { 278 struct nor_softc * const sc = device_private(self); 279 KASSERT(sc != NULL); 280 KASSERT(sc->sc_nor_if != NULL); 281 struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private; 282 KASSERT(cfi != NULL); 283 struct nor_chip * const chip = &sc->sc_chip; 284 KASSERT(chip != NULL); 285 KASSERT(chip->nc_page_mask != 0); 286 KASSERT((offset & ~chip->nc_page_mask) == 0); 287 KASSERT (chip->nc_page_size != 0); 288 KASSERT((chip->nc_page_size & ((1 << cfi->cfi_portwidth) - 1)) == 0); 289 290 CFI_0002_STATS_INC(cfi, program_page); 291 292 bus_size_t count = chip->nc_page_size >> cfi->cfi_portwidth; 293 /* #words/page */ 294 bus_size_t sa = offset >> cfi->cfi_portwidth; /* sector addr */ 295 uint32_t wc = count - 1; /* #words - 1 */ 296 297 int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi)); 298 if (error != 0) 299 return ETIMEDOUT; 300 301 cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */ 302 cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */ 303 cfi_cmd(cfi, sa, 0x25); /* Write To Buffer */ 304 cfi_cmd(cfi, sa, wc); 305 306 switch(cfi->cfi_portwidth) { 307 case 0: 308 bus_space_write_region_1(cfi->cfi_bst, cfi->cfi_bsh, offset, 309 (const uint8_t *)datap, count); 310 break; 311 case 1: 312 bus_space_write_region_2(cfi->cfi_bst, cfi->cfi_bsh, offset, 313 (const uint16_t *)datap, count); 314 break; 315 case 2: 316 bus_space_write_region_4(cfi->cfi_bst, cfi->cfi_bsh, offset, 317 (const uint32_t *)datap, count); 318 break; 319 default: 320 panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth); 321 }; 322 323 cfi_cmd(cfi, sa, 0x29); /* Write Buffer Program Confirm */ 324 325 error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_write_nbyte(cfi)); 326 327 return error; 328 } 329 330 static int 331 cfi_0002_erase_all(device_t self) 332 { 333 struct nor_softc * const sc = device_private(self); 334 KASSERT(sc != NULL); 335 KASSERT(sc->sc_nor_if != NULL); 336 struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private; 337 KASSERT(cfi != NULL); 338 struct nor_chip * const chip = &sc->sc_chip; 339 KASSERT(chip != NULL); 340 341 CFI_0002_STATS_INC(cfi, erase_all); 342 343 int error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_dflt(cfi)); 344 if (error != 0) 345 return ETIMEDOUT; 346 347 cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */ 348 cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */ 349 cfi_cmd(cfi, 0x555, 0x80); /* erase start */ 350 cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */ 351 cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */ 352 cfi_cmd(cfi, 0x555, 0x10); /* erase chip */ 353 354 error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_erase_all(cfi)); 355 356 return error; 357 } 358 359 static int 360 cfi_0002_erase_block(device_t self, flash_off_t offset) 361 { 362 struct nor_softc * const sc = device_private(self); 363 KASSERT(sc != NULL); 364 KASSERT(sc->sc_nor_if != NULL); 365 struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private; 366 KASSERT(cfi != NULL); 367 struct nor_chip * const chip = &sc->sc_chip; 368 KASSERT(chip != NULL); 369 KASSERT(chip->nc_block_mask != 0); 370 KASSERT((offset & ~chip->nc_block_mask) == 0); 371 KASSERT(chip->nc_block_size != 0); 372 KASSERT((chip->nc_block_size & ((1 << cfi->cfi_portwidth) - 1)) == 0); 373 374 CFI_0002_STATS_INC(cfi, erase_block); 375 376 /* scale sector addr by portwidth or chipwidth ? */ 377 bus_size_t sa = offset >> cfi->cfi_portwidth; 378 379 int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi)); 380 if (error != 0) 381 return ETIMEDOUT; 382 383 cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */ 384 cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */ 385 cfi_cmd(cfi, 0x555, 0x80); /* erase start */ 386 cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */ 387 cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */ 388 cfi_cmd(cfi, sa, 0x30); /* erase sector */ 389 390 error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_erase_blk(cfi)); 391 392 return error; 393 } 394 395 /* 396 * cfi_0002_busy - nor_interface busy op 397 */ 398 static int 399 cfi_0002_busy(device_t self, flash_off_t offset, u_long usec) 400 { 401 struct nor_softc *sc = device_private(self); 402 KASSERT(sc != NULL); 403 KASSERT(sc->sc_nor_if != NULL); 404 struct cfi * const cfi = (struct cfi * const)sc->sc_nor_if->private; 405 406 CFI_0002_STATS_INC(cfi, busy); 407 408 return cfi_0002_busy_wait(cfi, offset, usec); 409 } 410 411 /* 412 * cfi_0002_busy_wait - wait until device is not busy 413 */ 414 static int 415 cfi_0002_busy_wait(struct cfi * const cfi, flash_off_t offset, u_long usec) 416 { 417 int error; 418 419 #ifdef CFI_0002_STATS 420 struct timeval start; 421 struct timeval now; 422 struct timeval delta; 423 424 if (usec > cfi->cfi_0002_stats.busy_usec_max) 425 cfi->cfi_0002_stats.busy_usec_max = usec; 426 if (usec < cfi->cfi_0002_stats.busy_usec_min) 427 cfi->cfi_0002_stats.busy_usec_min = usec; 428 microtime(&start); 429 #endif 430 if (usec > cfi->cfi_yield_time) { 431 error = cfi_0002_busy_yield(cfi, offset, usec); 432 #ifdef CFI_0002_STATS 433 microtime(&now); 434 cfi->cfi_0002_stats.busy_yield++; 435 timersub(&now, &start, &delta); 436 timeradd(&delta, 437 &cfi->cfi_0002_stats.busy_yield_tv, 438 &cfi->cfi_0002_stats.busy_yield_tv); 439 #endif 440 } else { 441 error = cfi_0002_busy_poll(cfi, offset, usec); 442 #ifdef CFI_0002_STATS 443 microtime(&now); 444 cfi->cfi_0002_stats.busy_poll++; 445 timersub(&now, &start, &delta); 446 timeradd(&delta, 447 &cfi->cfi_0002_stats.busy_poll_tv, 448 &cfi->cfi_0002_stats.busy_poll_tv); 449 #endif 450 } 451 return error; 452 } 453 454 /* 455 * cfi_0002_busy_poll - poll until device is not busy 456 */ 457 static int 458 cfi_0002_busy_poll(struct cfi * const cfi, flash_off_t offset, u_long usec) 459 { 460 u_long count = usec >> 3; 461 if (count == 0) 462 count = 1; /* enforce minimum */ 463 do { 464 if (! cfi->cfi_ops.cfi_busy(cfi, offset)) 465 return 0; /* not busy */ 466 DELAY(8); 467 } while (count-- != 0); 468 469 return ETIMEDOUT; /* busy */ 470 } 471 472 /* 473 * cfi_0002_busy_yield - yield until device is not busy 474 */ 475 static int 476 cfi_0002_busy_yield(struct cfi * const cfi, flash_off_t offset, u_long usec) 477 { 478 struct timeval start; 479 struct timeval delta; 480 struct timeval limit; 481 struct timeval now; 482 483 microtime(&start); 484 485 /* try optimism */ 486 if (! cfi->cfi_ops.cfi_busy(cfi, offset)) { 487 CFI_0002_STATS_INC(cfi, busy_yield_hit); 488 return 0; /* not busy */ 489 } 490 CFI_0002_STATS_INC(cfi, busy_yield_miss); 491 492 delta.tv_sec = usec / 1000000; 493 delta.tv_usec = usec % 1000000; 494 timeradd(&start, &delta, &limit); 495 do { 496 yield(); 497 microtime(&now); 498 if (! cfi->cfi_ops.cfi_busy(cfi, offset)) 499 return 0; /* not busy */ 500 } while (timercmp(&now, &limit, <)); 501 502 CFI_0002_STATS_INC(cfi, busy_yield_timo); 503 504 return ETIMEDOUT; /* busy */ 505 } 506 507 /* 508 * cfi_0002_busy_dq7 - DQ7 "toggle" method to check busy 509 * 510 * Check busy during/after erase, program, protect operation. 511 * 512 * NOTE: 513 * Chip manufacturers (Spansion) plan to deprecate this method. 514 */ 515 static int 516 cfi_0002_busy_dq7(struct cfi * const cfi, flash_off_t offset) 517 { 518 bus_space_tag_t bst = cfi->cfi_bst; 519 bus_space_handle_t bsh = cfi->cfi_bsh; 520 bool busy; 521 522 switch(cfi->cfi_portwidth) { 523 case 0: { 524 uint8_t r0 = bus_space_read_1(bst, bsh, 0) & __BIT(7); 525 uint8_t r1 = bus_space_read_1(bst, bsh, 0) & __BIT(7); 526 busy = (r0 != r1); 527 break; 528 } 529 case 1: { 530 uint16_t r0 = bus_space_read_2(bst, bsh, 0); 531 uint16_t r1 = bus_space_read_2(bst, bsh, 0); 532 busy = (r0 != r1); 533 break; 534 } 535 case 2: { 536 uint32_t r0 = bus_space_read_4(bst, bsh, 0); 537 uint32_t r1 = bus_space_read_4(bst, bsh, 0); 538 busy = (r0 != r1); 539 break; 540 } 541 default: 542 busy = true; /* appeas gcc */ 543 panic("%s: bad port width %d\n", 544 __func__, cfi->cfi_portwidth); 545 } 546 return busy; 547 } 548 549 #ifdef NOTYET 550 /* 551 * cfi_0002_busy_reg - read and evaluate Read Status Register 552 * 553 * NOTE: 554 * Read Status Register not present on all chips 555 * use "toggle" method when Read Status Register not available. 556 */ 557 static bool 558 cfi_0002_busy_reg(struct cfi * const cfi, flash_off_t offset) 559 { 560 bus_space_tag_t bst = cfi->cfi_bst; 561 bus_space_handle_t bsh = cfi->cfi_bsh; 562 uint32_t r; 563 564 cfi_cmd(cfi, 0x555, 0x70); /* Status Register Read */ 565 566 switch(cfi->cfi_portwidth) { 567 case 0: 568 r = bus_space_read_1(bst, bsh, 0); 569 break; 570 case 1: 571 r = bus_space_read_2(bst, bsh, 0); 572 break; 573 case 2: 574 r = bus_space_read_4(bst, bsh, 0); 575 break; 576 default: 577 panic("%s: bad port width %d\n", 578 __func__, cfi->cfi_portwidth); 579 } 580 581 return ((r & __BIT(7)) == 0): 582 } 583 #endif /* NOTYET */ 584 585 #ifdef CFI_0002_STATS 586 void 587 cfi_0002_stats_reset(struct cfi *cfi) 588 { 589 memset(&cfi->cfi_0002_stats, 0, sizeof(struct cfi_0002_stats)); 590 cfi->cfi_0002_stats.busy_usec_min = ~0; 591 } 592 593 void 594 cfi_0002_stats_print(struct cfi *cfi) 595 { 596 printf("read_page %lu\n", cfi->cfi_0002_stats.read_page); 597 printf("program_page %lu\n", cfi->cfi_0002_stats.program_page); 598 printf("erase_all %lu\n", cfi->cfi_0002_stats.erase_all); 599 printf("erase_block %lu\n", cfi->cfi_0002_stats.erase_block); 600 printf("busy %lu\n", cfi->cfi_0002_stats.busy); 601 602 printf("write_nbyte_time_typ %d\n", 603 cfi->cfi_qry_data.write_nbyte_time_typ); 604 printf("write_nbyte_time_max %d\n", 605 cfi->cfi_qry_data.write_nbyte_time_max); 606 607 printf("erase_blk_time_typ %d\n", 608 cfi->cfi_qry_data.erase_blk_time_typ); 609 printf("erase_blk_time_max %d\n", 610 cfi->cfi_qry_data.erase_blk_time_max); 611 612 printf("erase_chip_time_typ %d\n", 613 cfi->cfi_qry_data.erase_chip_time_typ); 614 printf("erase_chip_time_max %d\n", 615 cfi->cfi_qry_data.erase_chip_time_max); 616 617 printf("time_write_nbyte %lu\n", cfi_0002_time_write_nbyte(cfi)); 618 printf("time_erase_blk %lu\n", cfi_0002_time_erase_blk(cfi)); 619 printf("time_erase_all %lu\n", cfi_0002_time_erase_all(cfi)); 620 621 printf("busy_usec_min %lu\n", cfi->cfi_0002_stats.busy_usec_min); 622 printf("busy_usec_max %lu\n", cfi->cfi_0002_stats.busy_usec_max); 623 624 printf("busy_poll_tv %lld.%d\n", 625 cfi->cfi_0002_stats.busy_poll_tv.tv_sec, 626 cfi->cfi_0002_stats.busy_poll_tv.tv_usec); 627 printf("busy_yield_tv %lld.%d\n", 628 cfi->cfi_0002_stats.busy_yield_tv.tv_sec, 629 cfi->cfi_0002_stats.busy_yield_tv.tv_usec); 630 printf("busy_poll %lu\n", cfi->cfi_0002_stats.busy_poll); 631 printf("busy_yield %lu\n", cfi->cfi_0002_stats.busy_yield); 632 printf("busy_yield_hit %lu\n", cfi->cfi_0002_stats.busy_yield_hit); 633 printf("busy_yield_miss %lu\n", cfi->cfi_0002_stats.busy_yield_miss); 634 printf("busy_yield_timo %lu\n", cfi->cfi_0002_stats.busy_yield_timo); 635 } 636 #endif /* CFI_0002_STATS */ 637