cfi_0002.c revision 1.4 1 1.4 cliff /* $NetBSD: cfi_0002.c,v 1.4 2011/07/23 06:26:26 cliff Exp $ */
2 1.3 cliff /*-
3 1.3 cliff * Copyright (c) 2011 The NetBSD Foundation, Inc.
4 1.3 cliff * All rights reserved.
5 1.3 cliff *
6 1.3 cliff * This code is derived from software contributed to The NetBSD Foundation
7 1.3 cliff * by Cliff Neighbors.
8 1.3 cliff *
9 1.3 cliff * Redistribution and use in source and binary forms, with or without
10 1.3 cliff * modification, are permitted provided that the following conditions
11 1.3 cliff * are met:
12 1.3 cliff * 1. Redistributions of source code must retain the above copyright
13 1.3 cliff * notice, this list of conditions and the following disclaimer.
14 1.3 cliff * 2. Redistributions in binary form must reproduce the above copyright
15 1.3 cliff * notice, this list of conditions and the following disclaimer in the
16 1.3 cliff * documentation and/or other materials provided with the distribution.
17 1.3 cliff *
18 1.3 cliff * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 1.3 cliff * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 1.3 cliff * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 1.3 cliff * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 1.3 cliff * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 1.3 cliff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 1.3 cliff * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 1.3 cliff * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 1.3 cliff * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 1.3 cliff * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 1.3 cliff * POSSIBILITY OF SUCH DAMAGE.
29 1.3 cliff */
30 1.1 cliff
31 1.1 cliff #include "opt_flash.h"
32 1.1 cliff
33 1.1 cliff #include <sys/cdefs.h>
34 1.4 cliff __KERNEL_RCSID(0, "$NetBSD: cfi_0002.c,v 1.4 2011/07/23 06:26:26 cliff Exp $");
35 1.1 cliff
36 1.1 cliff #include <sys/param.h>
37 1.1 cliff #include <sys/systm.h>
38 1.1 cliff #include <sys/cdefs.h>
39 1.1 cliff #include <sys/device.h>
40 1.1 cliff #include <sys/endian.h>
41 1.1 cliff #include <sys/time.h>
42 1.1 cliff
43 1.2 dyoung #include <sys/bus.h>
44 1.1 cliff
45 1.1 cliff #include <dev/nor/nor.h>
46 1.1 cliff #include <dev/nor/cfi.h>
47 1.1 cliff #include <dev/nor/cfi_0002.h>
48 1.1 cliff
49 1.1 cliff
50 1.1 cliff static void cfi_0002_version_init(struct cfi * const);
51 1.1 cliff static int cfi_0002_read_page(device_t, flash_off_t, uint8_t *);
52 1.1 cliff static int cfi_0002_program_page(device_t, flash_off_t, const uint8_t *);
53 1.1 cliff static int cfi_0002_erase_block(device_t, flash_off_t);
54 1.1 cliff static int cfi_0002_erase_all(device_t);
55 1.1 cliff static int cfi_0002_busy(device_t, flash_off_t, u_long);
56 1.1 cliff static int cfi_0002_busy_wait(struct cfi * const, flash_off_t, u_long);
57 1.1 cliff static int cfi_0002_busy_poll(struct cfi * const, flash_off_t, u_long);
58 1.1 cliff static int cfi_0002_busy_yield(struct cfi * const, flash_off_t, u_long);
59 1.1 cliff static int cfi_0002_busy_dq7(struct cfi * const , flash_off_t);
60 1.1 cliff #ifdef NOTYET
61 1.1 cliff static int cfi_0002_busy_reg(struct cfi * const, flash_off_t);
62 1.1 cliff #endif
63 1.1 cliff
64 1.1 cliff
65 1.1 cliff static const char *page_mode_str[] = {
66 1.1 cliff "(not supported)",
67 1.1 cliff "4 word page",
68 1.1 cliff "8 word page",
69 1.1 cliff "16 word page",
70 1.1 cliff };
71 1.1 cliff
72 1.1 cliff static const char *wp_mode_str[] = {
73 1.1 cliff "Flash device without WP Protect (No Boot)",
74 1.1 cliff "Eight 8 kB Sectors at TOP and Bottom with WP (Dual Boot)",
75 1.1 cliff "Bottom Boot Device with WP Protect (Bottom Boot)",
76 1.1 cliff "Top Boot Device with WP Protect (Top Boot)",
77 1.1 cliff "Uniform, Bottom WP Protect (Uniform Bottom Boot)",
78 1.1 cliff "Uniform, Top WP Protect (Uniform Top Boot)",
79 1.1 cliff "WP Protect for all sectors",
80 1.1 cliff "Uniform, Top or Bottom WP Protect",
81 1.1 cliff };
82 1.1 cliff
83 1.1 cliff
84 1.1 cliff static inline const char *
85 1.1 cliff cfi_0002_page_mode_str(uint8_t mode)
86 1.1 cliff {
87 1.1 cliff if (mode >= __arraycount(page_mode_str))
88 1.1 cliff panic("%s: mode %d out of range", __func__, mode);
89 1.1 cliff return page_mode_str[mode];
90 1.1 cliff }
91 1.1 cliff
92 1.1 cliff static inline const char *
93 1.1 cliff cfi_0002_wp_mode_str(uint8_t mode)
94 1.1 cliff {
95 1.1 cliff if (mode >= __arraycount(wp_mode_str))
96 1.1 cliff panic("%s: mode %d out of range", __func__, mode);
97 1.1 cliff return wp_mode_str[mode];
98 1.1 cliff }
99 1.1 cliff
100 1.1 cliff /*
101 1.1 cliff * cfi_0002_time_write_nbyte - maximum usec delay waiting for write buffer
102 1.1 cliff */
103 1.1 cliff static inline u_long
104 1.1 cliff cfi_0002_time_write_nbyte(struct cfi *cfi)
105 1.1 cliff {
106 1.1 cliff u_int shft = cfi->cfi_qry_data.write_nbyte_time_typ;
107 1.1 cliff shft += cfi->cfi_qry_data.write_nbyte_time_max;
108 1.1 cliff u_long usec = 1UL << shft;
109 1.1 cliff return usec;
110 1.1 cliff }
111 1.1 cliff
112 1.1 cliff /*
113 1.1 cliff * cfi_0002_time_erase_blk - maximum usec delay waiting for erase block
114 1.1 cliff */
115 1.1 cliff static inline u_long
116 1.1 cliff cfi_0002_time_erase_blk(struct cfi *cfi)
117 1.1 cliff {
118 1.1 cliff u_int shft = cfi->cfi_qry_data.erase_blk_time_typ;
119 1.1 cliff shft += cfi->cfi_qry_data.erase_blk_time_max;
120 1.1 cliff u_long usec = 1000UL << shft;
121 1.1 cliff return usec;
122 1.1 cliff }
123 1.1 cliff
124 1.1 cliff /*
125 1.1 cliff * cfi_0002_time_erase_all - maximum usec delay waiting for erase chip
126 1.1 cliff */
127 1.1 cliff static inline u_long
128 1.1 cliff cfi_0002_time_erase_all(struct cfi *cfi)
129 1.1 cliff {
130 1.4 cliff u_int shft = cfi->cfi_qry_data.erase_chip_time_typ;
131 1.4 cliff shft += cfi->cfi_qry_data.erase_chip_time_max;
132 1.1 cliff u_long usec = 1000UL << shft;
133 1.1 cliff return usec;
134 1.1 cliff }
135 1.1 cliff
136 1.1 cliff /*
137 1.1 cliff * cfi_0002_time_dflt - maximum usec delay to use waiting for ready
138 1.1 cliff *
139 1.1 cliff * use the maximum delay for chip erase function
140 1.1 cliff * that should be the worst non-sick case
141 1.1 cliff */
142 1.1 cliff static inline u_long
143 1.1 cliff cfi_0002_time_dflt(struct cfi *cfi)
144 1.1 cliff {
145 1.1 cliff return cfi_0002_time_erase_all(cfi);
146 1.1 cliff }
147 1.1 cliff
148 1.1 cliff void
149 1.1 cliff cfi_0002_init(struct nor_softc * const sc, struct cfi * const cfi,
150 1.1 cliff struct nor_chip * const chip)
151 1.1 cliff {
152 1.1 cliff CFI_0002_STATS_INIT(sc->sc_dev, cfi);
153 1.1 cliff
154 1.1 cliff cfi_0002_version_init(cfi);
155 1.1 cliff
156 1.1 cliff cfi->cfi_ops.cfi_reset = cfi_reset_std;
157 1.1 cliff cfi->cfi_yield_time = 500; /* 500 usec */
158 1.1 cliff
159 1.1 cliff /* page size for buffered write */
160 1.1 cliff chip->nc_page_size =
161 1.1 cliff 1 << cfi->cfi_qry_data.write_nbyte_size_max;
162 1.1 cliff
163 1.1 cliff /* these are unused */
164 1.1 cliff chip->nc_spare_size = 0;
165 1.1 cliff chip->nc_badmarker_offs = 0;
166 1.1 cliff
167 1.1 cliff /* establish command-set-specific interface ops */
168 1.1 cliff sc->sc_nor_if->read_page = cfi_0002_read_page;
169 1.1 cliff sc->sc_nor_if->program_page = cfi_0002_program_page;
170 1.1 cliff sc->sc_nor_if->erase_block = cfi_0002_erase_block;
171 1.1 cliff sc->sc_nor_if->erase_all = cfi_0002_erase_all;
172 1.1 cliff sc->sc_nor_if->busy = cfi_0002_busy;
173 1.1 cliff
174 1.1 cliff }
175 1.1 cliff
176 1.1 cliff /*
177 1.1 cliff * cfi_0002_version_init - command set version-specific initialization
178 1.1 cliff *
179 1.1 cliff * see "Programmer's Guide for the Spansion 65 nm GL-S MirrorBit EclipseTM
180 1.1 cliff * Flash Non-Volatile Memory Family Architecture" section 5.
181 1.1 cliff */
182 1.1 cliff static void
183 1.1 cliff cfi_0002_version_init(struct cfi * const cfi)
184 1.1 cliff {
185 1.1 cliff const uint8_t major = cfi->cfi_qry_data.pri.cmd_0002.version_maj;
186 1.1 cliff const uint8_t minor = cfi->cfi_qry_data.pri.cmd_0002.version_min;
187 1.1 cliff
188 1.1 cliff if ((minor == '3') && (major == '1')) {
189 1.1 cliff /* cmdset version 1.3 */
190 1.1 cliff cfi->cfi_ops.cfi_busy = cfi_0002_busy_dq7;
191 1.1 cliff #ifdef NOTYET
192 1.1 cliff cfi->cfi_ops.cfi_erase_sector = cfi_0002_erase_sector_q;
193 1.1 cliff cfi->cfi_ops.cfi_program_word = cfi_0002_program_word_ub;
194 1.1 cliff } else if ((minor >= '5') && (major == '1')) {
195 1.1 cliff /* cmdset version 1.5 or later */
196 1.1 cliff cfi->cfi_ops.cfi_busy = cfi_0002_busy_reg;
197 1.1 cliff cfi->cfi_ops.cfi_erase_sector = cfi_0002_erase_sector_1;
198 1.1 cliff cfi->cfi_ops.cfi_program_word = cfi_0002_program_word_no_ub;
199 1.1 cliff #endif
200 1.1 cliff } else {
201 1.1 cliff /* XXX this is excessive */
202 1.1 cliff panic("%s: unknown cmdset version %c.%c\n",
203 1.1 cliff __func__, major, minor);
204 1.1 cliff }
205 1.1 cliff
206 1.1 cliff }
207 1.1 cliff
208 1.1 cliff void
209 1.1 cliff cfi_0002_print(device_t self, struct cfi * const cfi)
210 1.1 cliff {
211 1.1 cliff #ifdef NOR_VERBOSE
212 1.1 cliff struct cmdset_0002_query_data *pri = &cfi->cfi_qry_data.pri.cmd_0002;
213 1.1 cliff
214 1.1 cliff aprint_normal_dev(self, "AMD/Fujitsu cmdset (0x0002) version=%c.%c\n",
215 1.1 cliff pri->version_maj, pri->version_min);
216 1.1 cliff aprint_normal_dev(self, "page mode type: %s\n",
217 1.1 cliff cfi_0002_page_mode_str(pri->page_mode_type));
218 1.1 cliff aprint_normal_dev(self, "wp protection: %s\n",
219 1.1 cliff cfi_0002_wp_mode_str(pri->wp_prot));
220 1.1 cliff aprint_normal_dev(self, "program suspend %ssupported\n",
221 1.1 cliff (pri->prog_susp == 0) ? "not " : "");
222 1.1 cliff aprint_normal_dev(self, "unlock bypass %ssupported\n",
223 1.1 cliff (pri->unlock_bypass == 0) ? "not " : "");
224 1.1 cliff aprint_normal_dev(self, "secure silicon sector size %#x\n",
225 1.1 cliff 1 << pri->sss_size);
226 1.1 cliff aprint_normal_dev(self, "SW features %#x\n", pri->soft_feat);
227 1.1 cliff aprint_normal_dev(self, "page size %d\n", 1 << pri->page_size);
228 1.1 cliff #endif
229 1.1 cliff }
230 1.1 cliff
231 1.1 cliff static int
232 1.1 cliff cfi_0002_read_page(device_t self, flash_off_t offset, uint8_t *datap)
233 1.1 cliff {
234 1.1 cliff struct nor_softc * const sc = device_private(self);
235 1.1 cliff KASSERT(sc != NULL);
236 1.1 cliff KASSERT(sc->sc_nor_if != NULL);
237 1.1 cliff struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
238 1.1 cliff KASSERT(cfi != NULL);
239 1.1 cliff struct nor_chip * const chip = &sc->sc_chip;
240 1.1 cliff KASSERT(chip != NULL);
241 1.1 cliff KASSERT(chip->nc_page_mask != 0);
242 1.1 cliff KASSERT((offset & ~chip->nc_page_mask) == 0);
243 1.1 cliff KASSERT (chip->nc_page_size != 0);
244 1.1 cliff KASSERT((chip->nc_page_size & ((1 << cfi->cfi_portwidth) - 1)) == 0);
245 1.1 cliff
246 1.1 cliff CFI_0002_STATS_INC(cfi, read_page);
247 1.1 cliff
248 1.1 cliff bus_size_t count = chip->nc_page_size >> cfi->cfi_portwidth;
249 1.1 cliff /* #words/page */
250 1.1 cliff
251 1.1 cliff int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
252 1.1 cliff if (error != 0)
253 1.1 cliff return error;
254 1.1 cliff
255 1.1 cliff switch(cfi->cfi_portwidth) {
256 1.1 cliff case 0:
257 1.1 cliff bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, offset,
258 1.1 cliff (uint8_t *)datap, count);
259 1.1 cliff break;
260 1.1 cliff case 1:
261 1.1 cliff bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, offset,
262 1.1 cliff (uint16_t *)datap, count);
263 1.1 cliff break;
264 1.1 cliff case 2:
265 1.1 cliff bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, offset,
266 1.1 cliff (uint32_t *)datap, count);
267 1.1 cliff break;
268 1.1 cliff default:
269 1.1 cliff panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth);
270 1.1 cliff };
271 1.1 cliff
272 1.1 cliff return 0;
273 1.1 cliff }
274 1.1 cliff
275 1.1 cliff static int
276 1.1 cliff cfi_0002_program_page(device_t self, flash_off_t offset, const uint8_t *datap)
277 1.1 cliff {
278 1.1 cliff struct nor_softc * const sc = device_private(self);
279 1.1 cliff KASSERT(sc != NULL);
280 1.1 cliff KASSERT(sc->sc_nor_if != NULL);
281 1.1 cliff struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
282 1.1 cliff KASSERT(cfi != NULL);
283 1.1 cliff struct nor_chip * const chip = &sc->sc_chip;
284 1.1 cliff KASSERT(chip != NULL);
285 1.1 cliff KASSERT(chip->nc_page_mask != 0);
286 1.1 cliff KASSERT((offset & ~chip->nc_page_mask) == 0);
287 1.1 cliff KASSERT (chip->nc_page_size != 0);
288 1.1 cliff KASSERT((chip->nc_page_size & ((1 << cfi->cfi_portwidth) - 1)) == 0);
289 1.1 cliff
290 1.1 cliff CFI_0002_STATS_INC(cfi, program_page);
291 1.1 cliff
292 1.1 cliff bus_size_t count = chip->nc_page_size >> cfi->cfi_portwidth;
293 1.1 cliff /* #words/page */
294 1.1 cliff bus_size_t sa = offset >> cfi->cfi_portwidth; /* sector addr */
295 1.1 cliff uint32_t wc = count - 1; /* #words - 1 */
296 1.1 cliff
297 1.1 cliff int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
298 1.1 cliff if (error != 0)
299 1.1 cliff return ETIMEDOUT;
300 1.1 cliff
301 1.1 cliff cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
302 1.1 cliff cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
303 1.1 cliff cfi_cmd(cfi, sa, 0x25); /* Write To Buffer */
304 1.1 cliff cfi_cmd(cfi, sa, wc);
305 1.1 cliff
306 1.1 cliff switch(cfi->cfi_portwidth) {
307 1.1 cliff case 0:
308 1.1 cliff bus_space_write_region_1(cfi->cfi_bst, cfi->cfi_bsh, offset,
309 1.1 cliff (const uint8_t *)datap, count);
310 1.1 cliff break;
311 1.1 cliff case 1:
312 1.1 cliff bus_space_write_region_2(cfi->cfi_bst, cfi->cfi_bsh, offset,
313 1.1 cliff (const uint16_t *)datap, count);
314 1.1 cliff break;
315 1.1 cliff case 2:
316 1.1 cliff bus_space_write_region_4(cfi->cfi_bst, cfi->cfi_bsh, offset,
317 1.1 cliff (const uint32_t *)datap, count);
318 1.1 cliff break;
319 1.1 cliff default:
320 1.1 cliff panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth);
321 1.1 cliff };
322 1.1 cliff
323 1.1 cliff cfi_cmd(cfi, sa, 0x29); /* Write Buffer Program Confirm */
324 1.1 cliff
325 1.1 cliff error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_write_nbyte(cfi));
326 1.1 cliff
327 1.1 cliff return error;
328 1.1 cliff }
329 1.1 cliff
330 1.1 cliff static int
331 1.1 cliff cfi_0002_erase_all(device_t self)
332 1.1 cliff {
333 1.1 cliff struct nor_softc * const sc = device_private(self);
334 1.1 cliff KASSERT(sc != NULL);
335 1.1 cliff KASSERT(sc->sc_nor_if != NULL);
336 1.1 cliff struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
337 1.1 cliff KASSERT(cfi != NULL);
338 1.1 cliff struct nor_chip * const chip = &sc->sc_chip;
339 1.1 cliff KASSERT(chip != NULL);
340 1.1 cliff
341 1.1 cliff CFI_0002_STATS_INC(cfi, erase_all);
342 1.1 cliff
343 1.1 cliff int error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_dflt(cfi));
344 1.1 cliff if (error != 0)
345 1.1 cliff return ETIMEDOUT;
346 1.1 cliff
347 1.1 cliff cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
348 1.1 cliff cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
349 1.1 cliff cfi_cmd(cfi, 0x555, 0x80); /* erase start */
350 1.1 cliff cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
351 1.1 cliff cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
352 1.1 cliff cfi_cmd(cfi, 0x555, 0x10); /* erase chip */
353 1.1 cliff
354 1.1 cliff error = cfi_0002_busy_wait(cfi, 0, cfi_0002_time_erase_all(cfi));
355 1.1 cliff
356 1.1 cliff return error;
357 1.1 cliff }
358 1.1 cliff
359 1.1 cliff static int
360 1.1 cliff cfi_0002_erase_block(device_t self, flash_off_t offset)
361 1.1 cliff {
362 1.1 cliff struct nor_softc * const sc = device_private(self);
363 1.1 cliff KASSERT(sc != NULL);
364 1.1 cliff KASSERT(sc->sc_nor_if != NULL);
365 1.1 cliff struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private;
366 1.1 cliff KASSERT(cfi != NULL);
367 1.1 cliff struct nor_chip * const chip = &sc->sc_chip;
368 1.1 cliff KASSERT(chip != NULL);
369 1.1 cliff KASSERT(chip->nc_block_mask != 0);
370 1.1 cliff KASSERT((offset & ~chip->nc_block_mask) == 0);
371 1.1 cliff KASSERT(chip->nc_block_size != 0);
372 1.1 cliff KASSERT((chip->nc_block_size & ((1 << cfi->cfi_portwidth) - 1)) == 0);
373 1.1 cliff
374 1.1 cliff CFI_0002_STATS_INC(cfi, erase_block);
375 1.1 cliff
376 1.1 cliff /* scale sector addr by portwidth or chipwidth ? */
377 1.1 cliff bus_size_t sa = offset >> cfi->cfi_portwidth;
378 1.1 cliff
379 1.1 cliff int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi));
380 1.1 cliff if (error != 0)
381 1.1 cliff return ETIMEDOUT;
382 1.1 cliff
383 1.1 cliff cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
384 1.1 cliff cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
385 1.1 cliff cfi_cmd(cfi, 0x555, 0x80); /* erase start */
386 1.1 cliff cfi_cmd(cfi, 0x555, 0xaa); /* unlock 1 */
387 1.1 cliff cfi_cmd(cfi, 0x2aa, 0x55); /* unlock 2 */
388 1.1 cliff cfi_cmd(cfi, sa, 0x30); /* erase sector */
389 1.1 cliff
390 1.1 cliff error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_erase_blk(cfi));
391 1.1 cliff
392 1.1 cliff return error;
393 1.1 cliff }
394 1.1 cliff
395 1.1 cliff /*
396 1.1 cliff * cfi_0002_busy - nor_interface busy op
397 1.1 cliff */
398 1.1 cliff static int
399 1.1 cliff cfi_0002_busy(device_t self, flash_off_t offset, u_long usec)
400 1.1 cliff {
401 1.1 cliff struct nor_softc *sc = device_private(self);
402 1.1 cliff KASSERT(sc != NULL);
403 1.1 cliff KASSERT(sc->sc_nor_if != NULL);
404 1.1 cliff struct cfi * const cfi = (struct cfi * const)sc->sc_nor_if->private;
405 1.1 cliff
406 1.1 cliff CFI_0002_STATS_INC(cfi, busy);
407 1.1 cliff
408 1.1 cliff return cfi_0002_busy_wait(cfi, offset, usec);
409 1.1 cliff }
410 1.1 cliff
411 1.1 cliff /*
412 1.1 cliff * cfi_0002_busy_wait - wait until device is not busy
413 1.1 cliff */
414 1.1 cliff static int
415 1.1 cliff cfi_0002_busy_wait(struct cfi * const cfi, flash_off_t offset, u_long usec)
416 1.1 cliff {
417 1.1 cliff int error;
418 1.1 cliff
419 1.1 cliff #ifdef CFI_0002_STATS
420 1.1 cliff struct timeval start;
421 1.1 cliff struct timeval now;
422 1.1 cliff struct timeval delta;
423 1.1 cliff
424 1.1 cliff if (usec > cfi->cfi_0002_stats.busy_usec_max)
425 1.1 cliff cfi->cfi_0002_stats.busy_usec_max = usec;
426 1.1 cliff if (usec < cfi->cfi_0002_stats.busy_usec_min)
427 1.1 cliff cfi->cfi_0002_stats.busy_usec_min = usec;
428 1.1 cliff microtime(&start);
429 1.1 cliff #endif
430 1.1 cliff if (usec > cfi->cfi_yield_time) {
431 1.1 cliff error = cfi_0002_busy_yield(cfi, offset, usec);
432 1.1 cliff #ifdef CFI_0002_STATS
433 1.1 cliff microtime(&now);
434 1.1 cliff cfi->cfi_0002_stats.busy_yield++;
435 1.1 cliff timersub(&now, &start, &delta);
436 1.1 cliff timeradd(&delta,
437 1.1 cliff &cfi->cfi_0002_stats.busy_yield_tv,
438 1.1 cliff &cfi->cfi_0002_stats.busy_yield_tv);
439 1.1 cliff #endif
440 1.1 cliff } else {
441 1.1 cliff error = cfi_0002_busy_poll(cfi, offset, usec);
442 1.1 cliff #ifdef CFI_0002_STATS
443 1.1 cliff microtime(&now);
444 1.1 cliff cfi->cfi_0002_stats.busy_poll++;
445 1.1 cliff timersub(&now, &start, &delta);
446 1.1 cliff timeradd(&delta,
447 1.1 cliff &cfi->cfi_0002_stats.busy_poll_tv,
448 1.1 cliff &cfi->cfi_0002_stats.busy_poll_tv);
449 1.1 cliff #endif
450 1.1 cliff }
451 1.1 cliff return error;
452 1.1 cliff }
453 1.1 cliff
454 1.1 cliff /*
455 1.1 cliff * cfi_0002_busy_poll - poll until device is not busy
456 1.1 cliff */
457 1.1 cliff static int
458 1.1 cliff cfi_0002_busy_poll(struct cfi * const cfi, flash_off_t offset, u_long usec)
459 1.1 cliff {
460 1.1 cliff u_long count = usec >> 3;
461 1.1 cliff if (count == 0)
462 1.1 cliff count = 1; /* enforce minimum */
463 1.1 cliff do {
464 1.1 cliff if (! cfi->cfi_ops.cfi_busy(cfi, offset))
465 1.1 cliff return 0; /* not busy */
466 1.1 cliff DELAY(8);
467 1.1 cliff } while (count-- != 0);
468 1.1 cliff
469 1.1 cliff return ETIMEDOUT; /* busy */
470 1.1 cliff }
471 1.1 cliff
472 1.1 cliff /*
473 1.1 cliff * cfi_0002_busy_yield - yield until device is not busy
474 1.1 cliff */
475 1.1 cliff static int
476 1.1 cliff cfi_0002_busy_yield(struct cfi * const cfi, flash_off_t offset, u_long usec)
477 1.1 cliff {
478 1.1 cliff struct timeval start;
479 1.1 cliff struct timeval delta;
480 1.1 cliff struct timeval limit;
481 1.1 cliff struct timeval now;
482 1.1 cliff
483 1.1 cliff microtime(&start);
484 1.1 cliff
485 1.1 cliff /* try optimism */
486 1.1 cliff if (! cfi->cfi_ops.cfi_busy(cfi, offset)) {
487 1.1 cliff CFI_0002_STATS_INC(cfi, busy_yield_hit);
488 1.1 cliff return 0; /* not busy */
489 1.1 cliff }
490 1.1 cliff CFI_0002_STATS_INC(cfi, busy_yield_miss);
491 1.1 cliff
492 1.1 cliff delta.tv_sec = usec / 1000000;
493 1.1 cliff delta.tv_usec = usec % 1000000;
494 1.1 cliff timeradd(&start, &delta, &limit);
495 1.1 cliff do {
496 1.1 cliff yield();
497 1.1 cliff microtime(&now);
498 1.1 cliff if (! cfi->cfi_ops.cfi_busy(cfi, offset))
499 1.1 cliff return 0; /* not busy */
500 1.1 cliff } while (timercmp(&now, &limit, <));
501 1.1 cliff
502 1.1 cliff CFI_0002_STATS_INC(cfi, busy_yield_timo);
503 1.1 cliff
504 1.1 cliff return ETIMEDOUT; /* busy */
505 1.1 cliff }
506 1.1 cliff
507 1.1 cliff /*
508 1.1 cliff * cfi_0002_busy_dq7 - DQ7 "toggle" method to check busy
509 1.1 cliff *
510 1.1 cliff * Check busy during/after erase, program, protect operation.
511 1.1 cliff *
512 1.1 cliff * NOTE:
513 1.1 cliff * Chip manufacturers (Spansion) plan to deprecate this method.
514 1.1 cliff */
515 1.1 cliff static int
516 1.1 cliff cfi_0002_busy_dq7(struct cfi * const cfi, flash_off_t offset)
517 1.1 cliff {
518 1.1 cliff bus_space_tag_t bst = cfi->cfi_bst;
519 1.1 cliff bus_space_handle_t bsh = cfi->cfi_bsh;
520 1.1 cliff bool busy;
521 1.1 cliff
522 1.1 cliff switch(cfi->cfi_portwidth) {
523 1.1 cliff case 0: {
524 1.1 cliff uint8_t r0 = bus_space_read_1(bst, bsh, 0) & __BIT(7);
525 1.1 cliff uint8_t r1 = bus_space_read_1(bst, bsh, 0) & __BIT(7);
526 1.1 cliff busy = (r0 != r1);
527 1.1 cliff break;
528 1.1 cliff }
529 1.1 cliff case 1: {
530 1.1 cliff uint16_t r0 = bus_space_read_2(bst, bsh, 0);
531 1.1 cliff uint16_t r1 = bus_space_read_2(bst, bsh, 0);
532 1.1 cliff busy = (r0 != r1);
533 1.1 cliff break;
534 1.1 cliff }
535 1.1 cliff case 2: {
536 1.1 cliff uint32_t r0 = bus_space_read_4(bst, bsh, 0);
537 1.1 cliff uint32_t r1 = bus_space_read_4(bst, bsh, 0);
538 1.1 cliff busy = (r0 != r1);
539 1.1 cliff break;
540 1.1 cliff }
541 1.1 cliff default:
542 1.1 cliff busy = true; /* appeas gcc */
543 1.1 cliff panic("%s: bad port width %d\n",
544 1.1 cliff __func__, cfi->cfi_portwidth);
545 1.1 cliff }
546 1.1 cliff return busy;
547 1.1 cliff }
548 1.1 cliff
549 1.1 cliff #ifdef NOTYET
550 1.1 cliff /*
551 1.1 cliff * cfi_0002_busy_reg - read and evaluate Read Status Register
552 1.1 cliff *
553 1.1 cliff * NOTE:
554 1.1 cliff * Read Status Register not present on all chips
555 1.1 cliff * use "toggle" method when Read Status Register not available.
556 1.1 cliff */
557 1.1 cliff static bool
558 1.1 cliff cfi_0002_busy_reg(struct cfi * const cfi, flash_off_t offset)
559 1.1 cliff {
560 1.1 cliff bus_space_tag_t bst = cfi->cfi_bst;
561 1.1 cliff bus_space_handle_t bsh = cfi->cfi_bsh;
562 1.1 cliff uint32_t r;
563 1.1 cliff
564 1.1 cliff cfi_cmd(cfi, 0x555, 0x70); /* Status Register Read */
565 1.1 cliff
566 1.1 cliff switch(cfi->cfi_portwidth) {
567 1.1 cliff case 0:
568 1.1 cliff r = bus_space_read_1(bst, bsh, 0);
569 1.1 cliff break;
570 1.1 cliff case 1:
571 1.1 cliff r = bus_space_read_2(bst, bsh, 0);
572 1.1 cliff break;
573 1.1 cliff case 2:
574 1.1 cliff r = bus_space_read_4(bst, bsh, 0);
575 1.1 cliff break;
576 1.1 cliff default:
577 1.1 cliff panic("%s: bad port width %d\n",
578 1.1 cliff __func__, cfi->cfi_portwidth);
579 1.1 cliff }
580 1.1 cliff
581 1.1 cliff return ((r & __BIT(7)) == 0):
582 1.1 cliff }
583 1.1 cliff #endif /* NOTYET */
584 1.1 cliff
585 1.1 cliff #ifdef CFI_0002_STATS
586 1.1 cliff void
587 1.1 cliff cfi_0002_stats_reset(struct cfi *cfi)
588 1.1 cliff {
589 1.1 cliff memset(&cfi->cfi_0002_stats, 0, sizeof(struct cfi_0002_stats));
590 1.1 cliff cfi->cfi_0002_stats.busy_usec_min = ~0;
591 1.1 cliff }
592 1.1 cliff
593 1.1 cliff void
594 1.1 cliff cfi_0002_stats_print(struct cfi *cfi)
595 1.1 cliff {
596 1.1 cliff printf("read_page %lu\n", cfi->cfi_0002_stats.read_page);
597 1.1 cliff printf("program_page %lu\n", cfi->cfi_0002_stats.program_page);
598 1.1 cliff printf("erase_all %lu\n", cfi->cfi_0002_stats.erase_all);
599 1.1 cliff printf("erase_block %lu\n", cfi->cfi_0002_stats.erase_block);
600 1.1 cliff printf("busy %lu\n", cfi->cfi_0002_stats.busy);
601 1.1 cliff
602 1.1 cliff printf("write_nbyte_time_typ %d\n",
603 1.1 cliff cfi->cfi_qry_data.write_nbyte_time_typ);
604 1.1 cliff printf("write_nbyte_time_max %d\n",
605 1.1 cliff cfi->cfi_qry_data.write_nbyte_time_max);
606 1.1 cliff
607 1.1 cliff printf("erase_blk_time_typ %d\n",
608 1.1 cliff cfi->cfi_qry_data.erase_blk_time_typ);
609 1.1 cliff printf("erase_blk_time_max %d\n",
610 1.1 cliff cfi->cfi_qry_data.erase_blk_time_max);
611 1.1 cliff
612 1.4 cliff printf("erase_chip_time_typ %d\n",
613 1.4 cliff cfi->cfi_qry_data.erase_chip_time_typ);
614 1.4 cliff printf("erase_chip_time_max %d\n",
615 1.4 cliff cfi->cfi_qry_data.erase_chip_time_max);
616 1.1 cliff
617 1.1 cliff printf("time_write_nbyte %lu\n", cfi_0002_time_write_nbyte(cfi));
618 1.1 cliff printf("time_erase_blk %lu\n", cfi_0002_time_erase_blk(cfi));
619 1.1 cliff printf("time_erase_all %lu\n", cfi_0002_time_erase_all(cfi));
620 1.1 cliff
621 1.1 cliff printf("busy_usec_min %lu\n", cfi->cfi_0002_stats.busy_usec_min);
622 1.1 cliff printf("busy_usec_max %lu\n", cfi->cfi_0002_stats.busy_usec_max);
623 1.1 cliff
624 1.1 cliff printf("busy_poll_tv %lld.%d\n",
625 1.1 cliff cfi->cfi_0002_stats.busy_poll_tv.tv_sec,
626 1.1 cliff cfi->cfi_0002_stats.busy_poll_tv.tv_usec);
627 1.1 cliff printf("busy_yield_tv %lld.%d\n",
628 1.1 cliff cfi->cfi_0002_stats.busy_yield_tv.tv_sec,
629 1.1 cliff cfi->cfi_0002_stats.busy_yield_tv.tv_usec);
630 1.1 cliff printf("busy_poll %lu\n", cfi->cfi_0002_stats.busy_poll);
631 1.1 cliff printf("busy_yield %lu\n", cfi->cfi_0002_stats.busy_yield);
632 1.1 cliff printf("busy_yield_hit %lu\n", cfi->cfi_0002_stats.busy_yield_hit);
633 1.1 cliff printf("busy_yield_miss %lu\n", cfi->cfi_0002_stats.busy_yield_miss);
634 1.1 cliff printf("busy_yield_timo %lu\n", cfi->cfi_0002_stats.busy_yield_timo);
635 1.1 cliff }
636 1.1 cliff #endif /* CFI_0002_STATS */
637