1 /* $NetBSD: cfi_0002.c,v 1.6 2011/12/17 19:42:41 phx 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.6 2011/12/17 19:42:41 phx 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 << (3 - cfi->cfi_portwidth); 295 /* sector addr */ 296 uint32_t wc = count - 1; /* #words - 1 */ 297 298 int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi)); 299 if (error != 0) 300 return ETIMEDOUT; 301 302 cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa); 303 cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55); 304 cfi_cmd(cfi, sa, 0x25); /* Write To Buffer */ 305 cfi_cmd(cfi, sa, wc); 306 307 switch(cfi->cfi_portwidth) { 308 case 0: 309 bus_space_write_region_1(cfi->cfi_bst, cfi->cfi_bsh, offset, 310 (const uint8_t *)datap, count); 311 break; 312 case 1: 313 bus_space_write_region_2(cfi->cfi_bst, cfi->cfi_bsh, offset, 314 (const uint16_t *)datap, count); 315 break; 316 case 2: 317 bus_space_write_region_4(cfi->cfi_bst, cfi->cfi_bsh, offset, 318 (const uint32_t *)datap, count); 319 break; 320 default: 321 panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth); 322 }; 323 324 cfi_cmd(cfi, sa, 0x29); /* Write Buffer Program Confirm */ 325 326 error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_write_nbyte(cfi)); 327 328 return error; 329 } 330 331 static int 332 cfi_0002_erase_all(device_t self) 333 { 334 struct nor_softc * const sc = device_private(self); 335 KASSERT(sc != NULL); 336 KASSERT(sc->sc_nor_if != NULL); 337 struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private; 338 KASSERT(cfi != NULL); 339 340 CFI_0002_STATS_INC(cfi, erase_all); 341 342 int error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_dflt(cfi)); 343 if (error != 0) 344 return ETIMEDOUT; 345 346 cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa); 347 cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55); 348 cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x80); /* erase start */ 349 cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa); 350 cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55); 351 cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x10); /* erase chip */ 352 353 error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_erase_all(cfi)); 354 355 return error; 356 } 357 358 static int 359 cfi_0002_erase_block(device_t self, flash_off_t offset) 360 { 361 struct nor_softc * const sc = device_private(self); 362 KASSERT(sc != NULL); 363 KASSERT(sc->sc_nor_if != NULL); 364 struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private; 365 KASSERT(cfi != NULL); 366 367 CFI_0002_STATS_INC(cfi, erase_block); 368 369 bus_size_t sa = offset << (3 - cfi->cfi_portwidth); 370 371 int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi)); 372 if (error != 0) 373 return ETIMEDOUT; 374 375 cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa); 376 cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55); 377 cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x80); /* erase start */ 378 cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0xaa); 379 cfi_cmd(cfi, cfi->cfi_unlock_addr2, 0x55); 380 cfi_cmd(cfi, sa, 0x30); /* erase sector */ 381 382 error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_erase_blk(cfi)); 383 384 return error; 385 } 386 387 /* 388 * cfi_0002_busy - nor_interface busy op 389 */ 390 static int 391 cfi_0002_busy(device_t self, flash_off_t offset, u_long usec) 392 { 393 struct nor_softc *sc = device_private(self); 394 KASSERT(sc != NULL); 395 KASSERT(sc->sc_nor_if != NULL); 396 struct cfi * const cfi = (struct cfi * const)sc->sc_nor_if->private; 397 398 CFI_0002_STATS_INC(cfi, busy); 399 400 return cfi_0002_busy_wait(cfi, offset, usec); 401 } 402 403 /* 404 * cfi_0002_busy_wait - wait until device is not busy 405 */ 406 static int 407 cfi_0002_busy_wait(struct cfi * const cfi, flash_off_t offset, u_long usec) 408 { 409 int error; 410 411 #ifdef CFI_0002_STATS 412 struct timeval start; 413 struct timeval now; 414 struct timeval delta; 415 416 if (usec > cfi->cfi_0002_stats.busy_usec_max) 417 cfi->cfi_0002_stats.busy_usec_max = usec; 418 if (usec < cfi->cfi_0002_stats.busy_usec_min) 419 cfi->cfi_0002_stats.busy_usec_min = usec; 420 microtime(&start); 421 #endif 422 if (usec > cfi->cfi_yield_time) { 423 error = cfi_0002_busy_yield(cfi, offset, usec); 424 #ifdef CFI_0002_STATS 425 microtime(&now); 426 cfi->cfi_0002_stats.busy_yield++; 427 timersub(&now, &start, &delta); 428 timeradd(&delta, 429 &cfi->cfi_0002_stats.busy_yield_tv, 430 &cfi->cfi_0002_stats.busy_yield_tv); 431 #endif 432 } else { 433 error = cfi_0002_busy_poll(cfi, offset, usec); 434 #ifdef CFI_0002_STATS 435 microtime(&now); 436 cfi->cfi_0002_stats.busy_poll++; 437 timersub(&now, &start, &delta); 438 timeradd(&delta, 439 &cfi->cfi_0002_stats.busy_poll_tv, 440 &cfi->cfi_0002_stats.busy_poll_tv); 441 #endif 442 } 443 return error; 444 } 445 446 /* 447 * cfi_0002_busy_poll - poll until device is not busy 448 */ 449 static int 450 cfi_0002_busy_poll(struct cfi * const cfi, flash_off_t offset, u_long usec) 451 { 452 u_long count = usec >> 3; 453 if (count == 0) 454 count = 1; /* enforce minimum */ 455 do { 456 if (! cfi->cfi_ops.cfi_busy(cfi, offset)) 457 return 0; /* not busy */ 458 DELAY(8); 459 } while (count-- != 0); 460 461 return ETIMEDOUT; /* busy */ 462 } 463 464 /* 465 * cfi_0002_busy_yield - yield until device is not busy 466 */ 467 static int 468 cfi_0002_busy_yield(struct cfi * const cfi, flash_off_t offset, u_long usec) 469 { 470 struct timeval start; 471 struct timeval delta; 472 struct timeval limit; 473 struct timeval now; 474 475 microtime(&start); 476 477 /* try optimism */ 478 if (! cfi->cfi_ops.cfi_busy(cfi, offset)) { 479 CFI_0002_STATS_INC(cfi, busy_yield_hit); 480 return 0; /* not busy */ 481 } 482 CFI_0002_STATS_INC(cfi, busy_yield_miss); 483 484 delta.tv_sec = usec / 1000000; 485 delta.tv_usec = usec % 1000000; 486 timeradd(&start, &delta, &limit); 487 do { 488 yield(); 489 microtime(&now); 490 if (! cfi->cfi_ops.cfi_busy(cfi, offset)) 491 return 0; /* not busy */ 492 } while (timercmp(&now, &limit, <)); 493 494 CFI_0002_STATS_INC(cfi, busy_yield_timo); 495 496 return ETIMEDOUT; /* busy */ 497 } 498 499 /* 500 * cfi_0002_busy_dq7 - DQ7 "toggle" method to check busy 501 * 502 * Check busy during/after erase, program, protect operation. 503 * 504 * NOTE: 505 * Chip manufacturers (Spansion) plan to deprecate this method. 506 */ 507 static int 508 cfi_0002_busy_dq7(struct cfi * const cfi, flash_off_t offset) 509 { 510 bus_space_tag_t bst = cfi->cfi_bst; 511 bus_space_handle_t bsh = cfi->cfi_bsh; 512 bool busy; 513 514 switch(cfi->cfi_portwidth) { 515 case 0: { 516 uint8_t r0 = bus_space_read_1(bst, bsh, 0) & __BIT(7); 517 uint8_t r1 = bus_space_read_1(bst, bsh, 0) & __BIT(7); 518 busy = (r0 != r1); 519 break; 520 } 521 case 1: { 522 uint16_t r0 = bus_space_read_2(bst, bsh, 0); 523 uint16_t r1 = bus_space_read_2(bst, bsh, 0); 524 busy = (r0 != r1); 525 break; 526 } 527 case 2: { 528 uint32_t r0 = bus_space_read_4(bst, bsh, 0); 529 uint32_t r1 = bus_space_read_4(bst, bsh, 0); 530 busy = (r0 != r1); 531 break; 532 } 533 default: 534 busy = true; /* appeas gcc */ 535 panic("%s: bad port width %d\n", 536 __func__, cfi->cfi_portwidth); 537 } 538 return busy; 539 } 540 541 #ifdef NOTYET 542 /* 543 * cfi_0002_busy_reg - read and evaluate Read Status Register 544 * 545 * NOTE: 546 * Read Status Register not present on all chips 547 * use "toggle" method when Read Status Register not available. 548 */ 549 static bool 550 cfi_0002_busy_reg(struct cfi * const cfi, flash_off_t offset) 551 { 552 bus_space_tag_t bst = cfi->cfi_bst; 553 bus_space_handle_t bsh = cfi->cfi_bsh; 554 uint32_t r; 555 556 cfi_cmd(cfi, cfi->cfi_unlock_addr1, 0x70); /* Status Register Read */ 557 558 switch(cfi->cfi_portwidth) { 559 case 0: 560 r = bus_space_read_1(bst, bsh, 0); 561 break; 562 case 1: 563 r = bus_space_read_2(bst, bsh, 0); 564 break; 565 case 2: 566 r = bus_space_read_4(bst, bsh, 0); 567 break; 568 default: 569 panic("%s: bad port width %d\n", 570 __func__, cfi->cfi_portwidth); 571 } 572 573 return ((r & __BIT(7)) == 0): 574 } 575 #endif /* NOTYET */ 576 577 #ifdef CFI_0002_STATS 578 void 579 cfi_0002_stats_reset(struct cfi *cfi) 580 { 581 memset(&cfi->cfi_0002_stats, 0, sizeof(struct cfi_0002_stats)); 582 cfi->cfi_0002_stats.busy_usec_min = ~0; 583 } 584 585 void 586 cfi_0002_stats_print(struct cfi *cfi) 587 { 588 printf("read_page %lu\n", cfi->cfi_0002_stats.read_page); 589 printf("program_page %lu\n", cfi->cfi_0002_stats.program_page); 590 printf("erase_all %lu\n", cfi->cfi_0002_stats.erase_all); 591 printf("erase_block %lu\n", cfi->cfi_0002_stats.erase_block); 592 printf("busy %lu\n", cfi->cfi_0002_stats.busy); 593 594 printf("write_nbyte_time_typ %d\n", 595 cfi->cfi_qry_data.write_nbyte_time_typ); 596 printf("write_nbyte_time_max %d\n", 597 cfi->cfi_qry_data.write_nbyte_time_max); 598 599 printf("erase_blk_time_typ %d\n", 600 cfi->cfi_qry_data.erase_blk_time_typ); 601 printf("erase_blk_time_max %d\n", 602 cfi->cfi_qry_data.erase_blk_time_max); 603 604 printf("erase_chip_time_typ %d\n", 605 cfi->cfi_qry_data.erase_chip_time_typ); 606 printf("erase_chip_time_max %d\n", 607 cfi->cfi_qry_data.erase_chip_time_max); 608 609 printf("time_write_nbyte %lu\n", cfi_0002_time_write_nbyte(cfi)); 610 printf("time_erase_blk %lu\n", cfi_0002_time_erase_blk(cfi)); 611 printf("time_erase_all %lu\n", cfi_0002_time_erase_all(cfi)); 612 613 printf("busy_usec_min %lu\n", cfi->cfi_0002_stats.busy_usec_min); 614 printf("busy_usec_max %lu\n", cfi->cfi_0002_stats.busy_usec_max); 615 616 printf("busy_poll_tv %lld.%d\n", 617 cfi->cfi_0002_stats.busy_poll_tv.tv_sec, 618 cfi->cfi_0002_stats.busy_poll_tv.tv_usec); 619 printf("busy_yield_tv %lld.%d\n", 620 cfi->cfi_0002_stats.busy_yield_tv.tv_sec, 621 cfi->cfi_0002_stats.busy_yield_tv.tv_usec); 622 printf("busy_poll %lu\n", cfi->cfi_0002_stats.busy_poll); 623 printf("busy_yield %lu\n", cfi->cfi_0002_stats.busy_yield); 624 printf("busy_yield_hit %lu\n", cfi->cfi_0002_stats.busy_yield_hit); 625 printf("busy_yield_miss %lu\n", cfi->cfi_0002_stats.busy_yield_miss); 626 printf("busy_yield_timo %lu\n", cfi->cfi_0002_stats.busy_yield_timo); 627 } 628 #endif /* CFI_0002_STATS */ 629