flash_vrip.c revision 1.10 1 /* $NetBSD: flash_vrip.c,v 1.10 2014/07/25 08:10:33 dholland Exp $ */
2
3 /*
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Naoto Shimazaki of YOKOGAWA Electric Corporation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Flash Memory Driver
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: flash_vrip.c,v 1.10 2014/07/25 08:10:33 dholland Exp $");
38
39 #include <sys/param.h>
40 #include <sys/conf.h>
41 #include <sys/device.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/proc.h>
45 #include <sys/systm.h>
46
47 #include <machine/bus.h>
48
49 #include <hpcmips/vr/vripif.h>
50 #include <hpcmips/vr/cfireg.h>
51 #include <hpcmips/vr/flashreg.h>
52 #include <hpcmips/vr/flashvar.h>
53
54 #ifdef FLASH_DEBUG
55 int flash_debug = 0;
56 #define DPRINTF(x) if (flash_debug) printf x
57 #else
58 #define DPRINTF(x)
59 #endif
60
61 static int flash_probe(device_t, cfdata_t, void *);
62 static void flash_attach(device_t, device_t, void *);
63
64 const static struct flashops * find_command_set(u_int8_t cmdset0,
65 u_int8_t cmdset1);
66 static int i28f128_probe(bus_space_tag_t, bus_space_handle_t);
67 static int mbm29160_probe(bus_space_tag_t, bus_space_handle_t);
68 static int is_block_same(struct flash_softc *, bus_size_t, const void *);
69 static int probe_cfi(bus_space_tag_t iot, bus_space_handle_t ioh);
70
71 static int intel_erase(struct flash_softc *, bus_size_t);
72 static int intel_write(struct flash_softc *, bus_size_t);
73 static int amd_erase(struct flash_softc *, bus_size_t);
74 static int amd_write(struct flash_softc *, bus_size_t);
75
76 extern struct cfdriver flash_cd;
77
78 CFATTACH_DECL_NEW(flash_vrip, sizeof(struct flash_softc),
79 flash_probe, flash_attach, NULL, NULL);
80
81 dev_type_open(flashopen);
82 dev_type_close(flashclose);
83 dev_type_read(flashread);
84 dev_type_write(flashwrite);
85
86 const struct cdevsw flash_cdevsw = {
87 .d_open = flashopen,
88 .d_close = flashclose,
89 .d_read = flashread,
90 .d_write = flashwrite,
91 .d_ioctl = noioctl,
92 .d_stop = nostop,
93 .d_tty = notty,
94 .d_poll = nopoll,
95 .d_mmap = nommap,
96 .d_kqfilter = nokqfilter,
97 .d_discard = nodiscard,
98 .d_flag = 0
99 };
100
101 static const struct flash_command_set {
102 u_int8_t fc_set0;
103 u_int8_t fc_set1;
104 struct flashops fc_ops;
105 } flash_cmd[] = {
106 {
107 .fc_set0 = CFI_COMMSET_INTEL0,
108 .fc_set1 = CFI_COMMSET_INTEL1,
109 .fc_ops = {
110 .fo_name = "Intel",
111 .fo_erase = intel_erase,
112 .fo_write = intel_write,
113 }
114 },
115 {
116 .fc_set0 = CFI_COMMSET_AMDFJITU0,
117 .fc_set1 = CFI_COMMSET_AMDFJITU1,
118 .fc_ops = {
119 .fo_name = "AMD/Fujitsu",
120 .fo_erase = amd_erase,
121 .fo_write = amd_write,
122 }
123 },
124 {
125 .fc_set0 = 0,
126 .fc_set1 = 0,
127 .fc_ops = {
128 .fo_name = NULL,
129 .fo_erase = NULL,
130 .fo_write = NULL,
131 }
132 }
133 };
134
135
136 const static struct flashops *
137 find_command_set(u_int8_t cmdset0, u_int8_t cmdset1)
138 {
139 const struct flash_command_set *fc;
140
141 for (fc = flash_cmd; fc->fc_ops.fo_name; fc++) {
142 if (cmdset0 == fc->fc_set0 && cmdset1 == fc->fc_set1)
143 return &fc->fc_ops;
144 }
145 return NULL;
146 }
147
148 static int
149 probe_cfi(bus_space_tag_t iot, bus_space_handle_t ioh)
150 {
151 const u_int8_t *idstr = CFI_QUERY_ID_STR;
152 int i;
153 u_int8_t cmdset0;
154 u_int8_t cmdset1;
155
156 /* start Common Flash Interface Query */
157 bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY);
158
159 /* read CFI Query ID string */
160 i = CFI_QUERY_ID_STR_REG << 1;
161 do {
162 if (bus_space_read_2(iot, ioh, i) != *idstr) {
163 bus_space_write_2(iot, ioh, 0, FLASH_RESET);
164 return 1;
165 }
166 i += 2;
167 idstr++;
168 } while (*idstr);
169
170 cmdset0 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG0 << 1);
171 cmdset1 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG1 << 1);
172
173 /* switch flash to read mode */
174 bus_space_write_2(iot, ioh, 0, FLASH_RESET);
175
176 if (!find_command_set(cmdset0, cmdset1))
177 return 1;
178
179 return 0;
180 }
181
182 static int
183 flash_probe(device_t parent, cfdata_t match, void *aux)
184 {
185 struct vrip_attach_args *va = aux;
186 bus_space_handle_t ioh;
187
188 if (bus_space_map(va->va_iot, va->va_addr, va->va_size, 0, &ioh))
189 return 0;
190 if (!probe_cfi(va->va_iot, ioh)) {
191 DPRINTF("CFI ID str and command set recognized\n");
192 goto detect;
193 }
194 if (!i28f128_probe(va->va_iot, ioh)) {
195 DPRINTF("28F128 detected\n");
196 goto detect;
197 }
198 if (!mbm29160_probe(va->va_iot, ioh)) {
199 DPRINTF("29LV160 detected\n");
200 goto detect;
201 }
202 return 0;
203
204 detect:
205 bus_space_unmap(va->va_iot, ioh, va->va_size);
206 return 1;
207 }
208
209 static void
210 flash_attach(device_t parent, device_t self, void *aux)
211 {
212 struct flash_softc *sc = device_private(self);
213 struct vrip_attach_args *va = aux;
214 int i;
215 int fence;
216 bus_space_tag_t iot = va->va_iot;
217 bus_space_handle_t ioh;
218 size_t block_size;
219
220 if (bus_space_map(iot, va->va_addr, va->va_size, 0, &ioh)) {
221 printf(": can't map i/o space\n");
222 return;
223 }
224
225 sc->sc_iot = iot;
226 sc->sc_ioh = ioh;
227 sc->sc_size = va->va_size;
228 sc->sc_status = 0;
229
230 /*
231 * Read entire CFI structure
232 */
233 bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY);
234 for (i = 0; i < CFI_TOTAL_SIZE; i++) {
235 sc->sc_cfi_raw[i] = bus_space_read_2(iot, ioh, i << 1);
236 }
237 bus_space_write_2(iot, ioh, 0, FLASH_RESET);
238
239 sc->sc_ops = find_command_set(sc->sc_cfi_raw[CFI_PRIM_COMM_REG0],
240 sc->sc_cfi_raw[CFI_PRIM_COMM_REG1]);
241 if (sc->sc_ops) {
242 printf(": using %s command set", sc->sc_ops->fo_name);
243 } else {
244 printf("opps sc->sc_ops is NULL\n");
245 }
246
247 /*
248 * determine size of the largest block
249 */
250 sc->sc_block_size = 0;
251 i = CFI_EBLK1_INFO_REG;
252 fence = sc->sc_cfi_raw[CFI_NUM_ERASE_BLK_REG] * CFI_EBLK_INFO_SIZE
253 + i;
254 for (; i < fence; i += CFI_EBLK_INFO_SIZE) {
255 if (sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT0] == 0
256 && sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT1] == 0)
257 continue;
258 block_size
259 = (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE0] << 8)
260 + (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE1] << 16);
261 if (sc->sc_block_size < block_size)
262 sc->sc_block_size = block_size;
263 }
264
265 if ((sc->sc_buf = malloc(sc->sc_block_size, M_DEVBUF, M_NOWAIT))
266 == NULL) {
267 printf(": can't alloc buffer space\n");
268 return;
269 }
270
271 sc->sc_write_buffer_size
272 = 1 << (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG0]
273 + (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG1] << 8));
274 sc->sc_typ_word_prog_timo
275 = 1 << sc->sc_cfi_raw[CFI_TYP_WORD_PROG_REG];
276 sc->sc_max_word_prog_timo
277 = 1 << sc->sc_cfi_raw[CFI_MAX_WORD_PROG_REG];
278 sc->sc_typ_buffer_write_timo
279 = 1 << sc->sc_cfi_raw[CFI_TYP_BUF_WRITE_REG];
280 sc->sc_max_buffer_write_timo
281 = 1 << sc->sc_cfi_raw[CFI_MAX_BUF_WRITE_REG];
282 sc->sc_typ_block_erase_timo
283 = 1 << sc->sc_cfi_raw[CFI_TYP_BLOCK_ERASE_REG];
284 sc->sc_max_block_erase_timo
285 = 1 << sc->sc_cfi_raw[CFI_MAX_BLOCK_ERASE_REG];
286
287 printf("\n");
288
289 #ifdef FLASH_DEBUG
290 printf("read_cfi: extract cfi\n");
291 printf("max block size: %dbyte\n", sc->sc_block_size);
292 printf("write buffer size: %dbyte\n", sc->sc_write_buffer_size);
293 printf("typical word program timeout: %dusec\n",
294 sc->sc_typ_word_prog_timo);
295 printf("maximam word program timeout: %dusec (%d time of typ)\n",
296 sc->sc_typ_word_prog_timo * sc->sc_max_word_prog_timo,
297 sc->sc_max_word_prog_timo);
298 printf("typical buffer write timeout: %dusec\n",
299 sc->sc_typ_buffer_write_timo);
300 printf("maximam buffer write timeout: %dusec (%d time of typ)\n",
301 sc->sc_typ_buffer_write_timo * sc->sc_max_buffer_write_timo,
302 sc->sc_max_buffer_write_timo);
303 printf("typical block erase timeout: %dmsec\n",
304 sc->sc_typ_block_erase_timo);
305 printf("maximam block erase timeout: %dmsec (%d time of typ)\n",
306 sc->sc_typ_block_erase_timo * sc->sc_max_block_erase_timo,
307 sc->sc_max_block_erase_timo);
308
309 printf("read_cfi: dump cfi\n");
310 for (i = 0; i < CFI_TOTAL_SIZE;) {
311 int j;
312 for (j = 0; j < 16; j++) {
313 printf("%02x ", sc->sc_cfi_raw[i++]);
314 }
315 printf("\n");
316 }
317 #endif
318 }
319
320 int
321 flashopen(dev_t dev, int flag, int mode, struct lwp *l)
322 {
323 struct flash_softc *sc;
324
325 sc = device_lookup_private(&flash_cd, minor(dev));
326 if (sc == NULL)
327 return ENXIO;
328 if (sc->sc_status & FLASH_ST_BUSY)
329 return EBUSY;
330 sc->sc_status |= FLASH_ST_BUSY;
331 return 0;
332 }
333
334 int
335 flashclose(dev_t dev, int flag, int mode, struct lwp *l)
336 {
337 struct flash_softc *sc;
338
339 sc = device_lookup_private(&flash_cd, minor(dev));
340 sc->sc_status &= ~FLASH_ST_BUSY;
341 return 0;
342 }
343
344 int
345 flashread(dev_t dev, struct uio *uio, int flag)
346 {
347 struct flash_softc *sc;
348 bus_space_tag_t iot;
349 bus_space_handle_t ioh;
350 bus_size_t off;
351 int total;
352 int count;
353 int error;
354
355 sc = device_lookup_private(&flash_cd, minor(dev));
356 iot = sc->sc_iot;
357 ioh = sc->sc_ioh;
358
359 off = uio->uio_offset;
360 total = min(sc->sc_size - off, uio->uio_resid);
361
362 while (total > 0) {
363 count = min(sc->sc_block_size, uio->uio_resid);
364 bus_space_read_region_1(iot, ioh, off, sc->sc_buf, count);
365 if ((error = uiomove(sc->sc_buf, count, uio)) != 0)
366 return error;
367 off += count;
368 total -= count;
369 }
370 return 0;
371 }
372
373
374 int
375 flashwrite(dev_t dev, struct uio *uio, int flag)
376 {
377 struct flash_softc *sc;
378 bus_space_tag_t iot;
379 bus_space_handle_t ioh;
380 bus_size_t off;
381 int stat;
382 int error;
383
384 sc = device_lookup_private(&flash_cd, minor(dev));
385
386 if (sc->sc_size < uio->uio_offset + uio->uio_resid)
387 return ENOSPC;
388 if (uio->uio_offset % sc->sc_block_size)
389 return EINVAL;
390 if (uio->uio_resid % sc->sc_block_size)
391 return EINVAL;
392
393 iot = sc->sc_iot;
394 ioh = sc->sc_ioh;
395
396 for (off = uio->uio_offset;
397 uio->uio_resid > 0;
398 off += sc->sc_block_size) {
399 if ((error = uiomove(sc->sc_buf, sc->sc_block_size, uio)) != 0)
400 return error;
401 if (is_block_same(sc, off, sc->sc_buf))
402 continue;
403 if ((stat = flash_block_erase(sc, off)) != 0) {
404 printf("block erase failed status = 0x%x\n", stat);
405 return EIO;
406 }
407 if ((stat = flash_block_write(sc, off)) != 0) {
408 printf("block write failed status = 0x%x\n", stat);
409 return EIO;
410 }
411 }
412 return 0;
413 }
414
415 /*
416 * XXX
417 * this function is too much specific for the device.
418 */
419 static int
420 i28f128_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
421 {
422 static const u_int8_t vendor_code[] = {
423 0x89, /* manufacturer code: intel */
424 0x18, /* device code: 28F128 */
425 };
426
427 static const u_int8_t idstr[] = {
428 'Q', 'R', 'Y',
429 0x01, 0x00,
430 0x31, 0x00,
431 0xff
432 };
433
434 int i;
435
436 /* start Common Flash Interface Query */
437 bus_space_write_2(iot, ioh, 0, CFI_READ_CFI_QUERY);
438 /* read CFI Query ID string */
439 for (i = 0; idstr[i] != 0xff; i++) {
440 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i])
441 return 1;
442 }
443
444 /* read manufacturer code and device code */
445 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0])
446 return 1;
447 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1])
448 return 1;
449
450 bus_space_write_2(iot, ioh, 0, I28F128_RESET);
451 return 0;
452 }
453
454 /*
455 * XXX
456 * this function is too much specific for the device.
457 */
458 static int
459 mbm29160_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
460 {
461 static const u_int16_t vendor_code[] = {
462 0x0004, /* manufacturer code: intel */
463 0x2249, /* device code: 29LV160BE */
464 };
465
466 static const u_int8_t idstr[] = {
467 'Q', 'R', 'Y',
468 0x02, 0x00,
469 0x40, 0x00,
470 0xff
471 };
472
473 int i;
474
475 /* start Common Flash Interface Query */
476 bus_space_write_2(iot, ioh, 0xaa, CFI_READ_CFI_QUERY);
477 /* read CFI Query ID string */
478 for (i = 0; idstr[i] != 0xff; i++) {
479 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i])
480 return 1;
481 }
482
483 bus_space_write_2(iot, ioh, 0, 0xff);
484
485 /* read manufacturer code and device code */
486 bus_space_write_2(iot, ioh, 0x555 << 1, 0xaa);
487 bus_space_write_2(iot, ioh, 0x2aa << 1, 0x55);
488 bus_space_write_2(iot, ioh, 0x555 << 1, 0x90);
489 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0])
490 return 1;
491 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1])
492 return 1;
493
494 bus_space_write_2(iot, ioh, 0, 0xff);
495 return 0;
496 }
497
498 static int
499 is_block_same(struct flash_softc *sc, bus_size_t offset, const void *bufp)
500 {
501 bus_space_tag_t iot = sc->sc_iot;
502 bus_space_handle_t ioh = sc->sc_ioh;
503 const u_int8_t *p = bufp;
504 int count = sc->sc_block_size;
505
506 while (count-- > 0) {
507 if (bus_space_read_1(iot, ioh, offset++) != *p++)
508 return 0;
509 }
510 return 1;
511 }
512
513 static int
514 intel_erase(struct flash_softc *sc, bus_size_t offset)
515 {
516 bus_space_tag_t iot = sc->sc_iot;
517 bus_space_handle_t ioh = sc->sc_ioh;
518 int status;
519 int i;
520
521 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_1ST);
522 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_2ND);
523
524 status = 0;
525 for (i = sc->sc_max_block_erase_timo; i > 0; i--) {
526 tsleep(sc, PRIBIO, "blockerase",
527 1 + (sc->sc_typ_block_erase_timo * hz) / 1000);
528 if ((status = bus_space_read_2(iot, ioh, offset))
529 & I28F128_S_READY)
530 break;
531 }
532 if (i == 0)
533 status |= FLASH_TIMEOUT;
534
535 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
536 bus_space_write_2(iot, ioh, offset, I28F128_RESET);
537
538 return status & (FLASH_TIMEOUT
539 | I28F128_S_ERASE_SUSPEND
540 | I28F128_S_COMSEQ_ERROR
541 | I28F128_S_ERASE_ERROR
542 | I28F128_S_BLOCK_LOCKED);
543 }
544
545 static int
546 intel_write(struct flash_softc *sc, bus_size_t offset)
547 {
548 bus_space_tag_t iot = sc->sc_iot;
549 bus_space_handle_t ioh = sc->sc_ioh;
550 int wbuf_size;
551 int timo;
552 int status;
553 bus_size_t fence;
554 int i;
555 const u_int16_t *p;
556
557 /* wbuf_size = size in u_int16_t */
558 wbuf_size = sc->sc_write_buffer_size >> 1;
559
560 p = (u_int16_t *) sc->sc_buf;
561 fence = offset + sc->sc_block_size;
562 do {
563 status = 0;
564 for (timo = sc->sc_max_buffer_write_timo; timo > 0; timo--) {
565 bus_space_write_2(iot, ioh, offset,
566 I28F128_WRITE_BUFFER);
567 status = bus_space_read_2(iot, ioh, offset);
568 if (status & I28F128_XS_BUF_AVAIL)
569 break;
570 DELAY(sc->sc_typ_buffer_write_timo);
571 }
572 if (timo == 0) {
573 status |= FLASH_TIMEOUT;
574 goto errout;
575 }
576
577 bus_space_write_2(iot, ioh, offset, wbuf_size - 1);
578
579 for (i = wbuf_size; i > 0; i--, p++, offset += 2)
580 bus_space_write_2(iot, ioh, offset, *p);
581
582 bus_space_write_2(iot, ioh, offset, I28F128_WBUF_CONFIRM);
583
584 do {
585 bus_space_write_2(iot, ioh, offset,
586 I28F128_READ_STATUS);
587 status = bus_space_read_2(iot, ioh, offset);
588 } while (!(status & I28F128_S_READY));
589
590 } while (offset < fence);
591
592 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
593 bus_space_write_2(iot, ioh, offset, I28F128_RESET);
594
595 return 0;
596
597 errout:
598 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
599 bus_space_write_2(iot, ioh, offset, I28F128_RESET);
600
601 status &= (FLASH_TIMEOUT
602 | I28F128_S_PROG_ERROR
603 | I28F128_S_COMSEQ_ERROR
604 | I28F128_S_LOW_VOLTAGE
605 | I28F128_S_PROG_SUSPEND
606 | I28F128_S_BLOCK_LOCKED);
607 return status;
608 }
609
610 static int
611 amd_erase_sector(struct flash_softc *sc, bus_size_t offset)
612 {
613 bus_space_tag_t iot = sc->sc_iot;
614 bus_space_handle_t ioh = sc->sc_ioh;
615 int i;
616
617 DPRINTF(("amd_erase_sector offset = %08lx\n", offset));
618
619 bus_space_write_2(iot, ioh,
620 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0);
621 bus_space_write_2(iot, ioh,
622 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1);
623 bus_space_write_2(iot, ioh,
624 MBM29LV160_COMM_ADDR2, MBM29LV160_ESECT_CMD2);
625 bus_space_write_2(iot, ioh,
626 MBM29LV160_COMM_ADDR3, MBM29LV160_ESECT_CMD3);
627 bus_space_write_2(iot, ioh,
628 MBM29LV160_COMM_ADDR4, MBM29LV160_ESECT_CMD4);
629 bus_space_write_2(iot, ioh, offset, MBM29LV160_ESECT_CMD5);
630
631 for (i = sc->sc_max_block_erase_timo; i > 0; i--) {
632 tsleep(sc, PRIBIO, "blockerase",
633 1 + (sc->sc_typ_block_erase_timo * hz) / 1000);
634 if (bus_space_read_2(iot, ioh, offset) == 0xffff)
635 return 0;
636 }
637
638 return FLASH_TIMEOUT;
639 }
640
641 static int
642 amd_erase(struct flash_softc *sc, bus_size_t offset)
643 {
644 static const struct mbm29lv_subsect {
645 u_int16_t devcode;
646 u_int32_t subsect_mask;
647 u_int32_t subsect_addr;
648 } subsect[] = {
649 {
650 MBM29LV160TE_DEVCODE,
651 MBM29LV160_SUBSECT_MASK,
652 MBM29LV160TE_SUBSECT_ADDR
653 },
654 {
655 MBM29LV160BE_DEVCODE,
656 MBM29LV160_SUBSECT_MASK,
657 MBM29LV160BE_SUBSECT_ADDR
658 },
659 { 0, 0, 0 }
660 };
661
662 bus_space_tag_t iot = sc->sc_iot;
663 bus_space_handle_t ioh = sc->sc_ioh;
664 u_int16_t devcode;
665 const struct mbm29lv_subsect *ss;
666 bus_size_t fence;
667 int step;
668 int status;
669
670 bus_space_write_2(iot, ioh,
671 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0);
672 bus_space_write_2(iot, ioh,
673 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1);
674 bus_space_write_2(iot, ioh,
675 MBM29LV160_COMM_ADDR2, MBM29LV160_SIGN_CMD2);
676 devcode = bus_space_read_2(iot, ioh, MBM29LV160_DEVCODE_REG);
677
678 for (ss = subsect; ss->devcode; ss++) {
679 if (ss->devcode == devcode)
680 break;
681 }
682 if (ss->devcode == 0) {
683 printf("flash: amd_erase(): unknown device code %04x\n",
684 devcode);
685 return -1;
686 }
687
688 DPRINTF(("flash: amd_erase(): devcode = %04x subsect = %08x\n",
689 devcode, ss->subsect_addr));
690
691 fence = offset + sc->sc_block_size;
692 step = (offset & ss->subsect_mask) == ss->subsect_addr
693 ? MBM29LV160_SUBSECT_SIZE : MBM29LV160_SECT_SIZE;
694 do {
695 if ((status = amd_erase_sector(sc, offset)) != 0)
696 return status;
697 offset += step;
698 } while (offset < fence);
699
700 return 0;
701 }
702
703 static int
704 amd_write(struct flash_softc *sc, bus_size_t offset)
705 {
706 bus_space_tag_t iot = sc->sc_iot;
707 bus_space_handle_t ioh = sc->sc_ioh;
708 int timo;
709 bus_size_t fence;
710 const u_int16_t *p;
711
712 p = (u_int16_t *) sc->sc_buf;
713 fence = offset + sc->sc_block_size;
714 do {
715 bus_space_write_2(iot, ioh,
716 MBM29LV160_COMM_ADDR0,
717 MBM29LV160_COMM_CMD0);
718 bus_space_write_2(iot, ioh,
719 MBM29LV160_COMM_ADDR1,
720 MBM29LV160_COMM_CMD1);
721 bus_space_write_2(iot, ioh,
722 MBM29LV160_COMM_ADDR2,
723 MBM29LV160_PROG_CMD2);
724 bus_space_write_2(iot, ioh, offset, *p);
725
726 for (timo = sc->sc_max_word_prog_timo; timo > 0; timo--) {
727 if (bus_space_read_2(iot, ioh, offset) == *p)
728 break;
729 DELAY(sc->sc_typ_word_prog_timo);
730 }
731 if (timo == 0)
732 return FLASH_TIMEOUT;
733
734 p++;
735 offset += 2;
736 } while (offset < fence);
737
738 return 0;
739 }
740