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