cfi_0002.c revision 1.7 1 /* $NetBSD: cfi_0002.c,v 1.7 2014/07/24 23:25:53 joerg 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.7 2014/07/24 23:25:53 joerg 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 #ifdef NOR_VERBOSE
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 static inline const char *
84 cfi_0002_page_mode_str(uint8_t mode)
85 {
86 if (mode >= __arraycount(page_mode_str))
87 panic("%s: mode %d out of range", __func__, mode);
88 return page_mode_str[mode];
89 }
90
91 static inline const char *
92 cfi_0002_wp_mode_str(uint8_t mode)
93 {
94 if (mode >= __arraycount(wp_mode_str))
95 panic("%s: mode %d out of range", __func__, mode);
96 return wp_mode_str[mode];
97 }
98 #endif
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