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