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