xref: /netbsd-src/sys/dev/nor/cfi_0002.c (revision 343f6c784afa9fa274c2c92f8d06e56ec7aea606)
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