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