cfi_0002.c revision 1.4 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