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 *
cfi_0002_page_mode_str(uint8_t mode)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 *
cfi_0002_wp_mode_str(uint8_t mode)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
cfi_0002_time_write_nbyte(struct cfi * cfi)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
cfi_0002_time_erase_blk(struct cfi * cfi)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
cfi_0002_time_erase_all(struct cfi * cfi)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
cfi_0002_time_dflt(struct cfi * cfi)144 cfi_0002_time_dflt(struct cfi *cfi)
145 {
146 return cfi_0002_time_erase_all(cfi);
147 }
148
149 void
cfi_0002_init(struct nor_softc * const sc,struct cfi * const cfi,struct nor_chip * const chip)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
cfi_0002_version_init(struct cfi * const cfi)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
cfi_0002_print(device_t self,struct cfi * const cfi)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
cfi_0002_read_page(device_t self,flash_off_t offset,uint8_t * datap)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
cfi_0002_program_page(device_t self,flash_off_t offset,const uint8_t * datap)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
cfi_0002_erase_all(device_t self)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
cfi_0002_erase_block(device_t self,flash_off_t offset)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
cfi_0002_busy(device_t self,flash_off_t offset,u_long usec)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
cfi_0002_busy_wait(struct cfi * const cfi,flash_off_t offset,u_long usec)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
cfi_0002_busy_poll(struct cfi * const cfi,flash_off_t offset,u_long usec)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
cfi_0002_busy_yield(struct cfi * const cfi,flash_off_t offset,u_long usec)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
cfi_0002_busy_dq7(struct cfi * const cfi,flash_off_t offset)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
cfi_0002_busy_reg(struct cfi * const cfi,flash_off_t offset)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