flash_vrip.c revision 1.9 1 /* $NetBSD: flash_vrip.c,v 1.9 2014/03/16 05:20:24 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.9 2014/03/16 05:20:24 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_flag = 0
98 };
99
100 static const struct flash_command_set {
101 u_int8_t fc_set0;
102 u_int8_t fc_set1;
103 struct flashops fc_ops;
104 } flash_cmd[] = {
105 {
106 .fc_set0 = CFI_COMMSET_INTEL0,
107 .fc_set1 = CFI_COMMSET_INTEL1,
108 .fc_ops = {
109 .fo_name = "Intel",
110 .fo_erase = intel_erase,
111 .fo_write = intel_write,
112 }
113 },
114 {
115 .fc_set0 = CFI_COMMSET_AMDFJITU0,
116 .fc_set1 = CFI_COMMSET_AMDFJITU1,
117 .fc_ops = {
118 .fo_name = "AMD/Fujitsu",
119 .fo_erase = amd_erase,
120 .fo_write = amd_write,
121 }
122 },
123 {
124 .fc_set0 = 0,
125 .fc_set1 = 0,
126 .fc_ops = {
127 .fo_name = NULL,
128 .fo_erase = NULL,
129 .fo_write = NULL,
130 }
131 }
132 };
133
134
135 const static struct flashops *
136 find_command_set(u_int8_t cmdset0, u_int8_t cmdset1)
137 {
138 const struct flash_command_set *fc;
139
140 for (fc = flash_cmd; fc->fc_ops.fo_name; fc++) {
141 if (cmdset0 == fc->fc_set0 && cmdset1 == fc->fc_set1)
142 return &fc->fc_ops;
143 }
144 return NULL;
145 }
146
147 static int
148 probe_cfi(bus_space_tag_t iot, bus_space_handle_t ioh)
149 {
150 const u_int8_t *idstr = CFI_QUERY_ID_STR;
151 int i;
152 u_int8_t cmdset0;
153 u_int8_t cmdset1;
154
155 /* start Common Flash Interface Query */
156 bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY);
157
158 /* read CFI Query ID string */
159 i = CFI_QUERY_ID_STR_REG << 1;
160 do {
161 if (bus_space_read_2(iot, ioh, i) != *idstr) {
162 bus_space_write_2(iot, ioh, 0, FLASH_RESET);
163 return 1;
164 }
165 i += 2;
166 idstr++;
167 } while (*idstr);
168
169 cmdset0 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG0 << 1);
170 cmdset1 = bus_space_read_2(iot, ioh, CFI_PRIM_COMM_REG1 << 1);
171
172 /* switch flash to read mode */
173 bus_space_write_2(iot, ioh, 0, FLASH_RESET);
174
175 if (!find_command_set(cmdset0, cmdset1))
176 return 1;
177
178 return 0;
179 }
180
181 static int
182 flash_probe(device_t parent, cfdata_t match, void *aux)
183 {
184 struct vrip_attach_args *va = aux;
185 bus_space_handle_t ioh;
186
187 if (bus_space_map(va->va_iot, va->va_addr, va->va_size, 0, &ioh))
188 return 0;
189 if (!probe_cfi(va->va_iot, ioh)) {
190 DPRINTF("CFI ID str and command set recognized\n");
191 goto detect;
192 }
193 if (!i28f128_probe(va->va_iot, ioh)) {
194 DPRINTF("28F128 detected\n");
195 goto detect;
196 }
197 if (!mbm29160_probe(va->va_iot, ioh)) {
198 DPRINTF("29LV160 detected\n");
199 goto detect;
200 }
201 return 0;
202
203 detect:
204 bus_space_unmap(va->va_iot, ioh, va->va_size);
205 return 1;
206 }
207
208 static void
209 flash_attach(device_t parent, device_t self, void *aux)
210 {
211 struct flash_softc *sc = device_private(self);
212 struct vrip_attach_args *va = aux;
213 int i;
214 int fence;
215 bus_space_tag_t iot = va->va_iot;
216 bus_space_handle_t ioh;
217 size_t block_size;
218
219 if (bus_space_map(iot, va->va_addr, va->va_size, 0, &ioh)) {
220 printf(": can't map i/o space\n");
221 return;
222 }
223
224 sc->sc_iot = iot;
225 sc->sc_ioh = ioh;
226 sc->sc_size = va->va_size;
227 sc->sc_status = 0;
228
229 /*
230 * Read entire CFI structure
231 */
232 bus_space_write_2(iot, ioh, CFI_QUERY_OFFSET, CFI_READ_CFI_QUERY);
233 for (i = 0; i < CFI_TOTAL_SIZE; i++) {
234 sc->sc_cfi_raw[i] = bus_space_read_2(iot, ioh, i << 1);
235 }
236 bus_space_write_2(iot, ioh, 0, FLASH_RESET);
237
238 sc->sc_ops = find_command_set(sc->sc_cfi_raw[CFI_PRIM_COMM_REG0],
239 sc->sc_cfi_raw[CFI_PRIM_COMM_REG1]);
240 if (sc->sc_ops) {
241 printf(": using %s command set", sc->sc_ops->fo_name);
242 } else {
243 printf("opps sc->sc_ops is NULL\n");
244 }
245
246 /*
247 * determine size of the largest block
248 */
249 sc->sc_block_size = 0;
250 i = CFI_EBLK1_INFO_REG;
251 fence = sc->sc_cfi_raw[CFI_NUM_ERASE_BLK_REG] * CFI_EBLK_INFO_SIZE
252 + i;
253 for (; i < fence; i += CFI_EBLK_INFO_SIZE) {
254 if (sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT0] == 0
255 && sc->sc_cfi_raw[i + CFI_EBLK_INFO_NSECT1] == 0)
256 continue;
257 block_size
258 = (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE0] << 8)
259 + (sc->sc_cfi_raw[i + CFI_EBLK_INFO_SECSIZE1] << 16);
260 if (sc->sc_block_size < block_size)
261 sc->sc_block_size = block_size;
262 }
263
264 if ((sc->sc_buf = malloc(sc->sc_block_size, M_DEVBUF, M_NOWAIT))
265 == NULL) {
266 printf(": can't alloc buffer space\n");
267 return;
268 }
269
270 sc->sc_write_buffer_size
271 = 1 << (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG0]
272 + (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG1] << 8));
273 sc->sc_typ_word_prog_timo
274 = 1 << sc->sc_cfi_raw[CFI_TYP_WORD_PROG_REG];
275 sc->sc_max_word_prog_timo
276 = 1 << sc->sc_cfi_raw[CFI_MAX_WORD_PROG_REG];
277 sc->sc_typ_buffer_write_timo
278 = 1 << sc->sc_cfi_raw[CFI_TYP_BUF_WRITE_REG];
279 sc->sc_max_buffer_write_timo
280 = 1 << sc->sc_cfi_raw[CFI_MAX_BUF_WRITE_REG];
281 sc->sc_typ_block_erase_timo
282 = 1 << sc->sc_cfi_raw[CFI_TYP_BLOCK_ERASE_REG];
283 sc->sc_max_block_erase_timo
284 = 1 << sc->sc_cfi_raw[CFI_MAX_BLOCK_ERASE_REG];
285
286 printf("\n");
287
288 #ifdef FLASH_DEBUG
289 printf("read_cfi: extract cfi\n");
290 printf("max block size: %dbyte\n", sc->sc_block_size);
291 printf("write buffer size: %dbyte\n", sc->sc_write_buffer_size);
292 printf("typical word program timeout: %dusec\n",
293 sc->sc_typ_word_prog_timo);
294 printf("maximam word program timeout: %dusec (%d time of typ)\n",
295 sc->sc_typ_word_prog_timo * sc->sc_max_word_prog_timo,
296 sc->sc_max_word_prog_timo);
297 printf("typical buffer write timeout: %dusec\n",
298 sc->sc_typ_buffer_write_timo);
299 printf("maximam buffer write timeout: %dusec (%d time of typ)\n",
300 sc->sc_typ_buffer_write_timo * sc->sc_max_buffer_write_timo,
301 sc->sc_max_buffer_write_timo);
302 printf("typical block erase timeout: %dmsec\n",
303 sc->sc_typ_block_erase_timo);
304 printf("maximam block erase timeout: %dmsec (%d time of typ)\n",
305 sc->sc_typ_block_erase_timo * sc->sc_max_block_erase_timo,
306 sc->sc_max_block_erase_timo);
307
308 printf("read_cfi: dump cfi\n");
309 for (i = 0; i < CFI_TOTAL_SIZE;) {
310 int j;
311 for (j = 0; j < 16; j++) {
312 printf("%02x ", sc->sc_cfi_raw[i++]);
313 }
314 printf("\n");
315 }
316 #endif
317 }
318
319 int
320 flashopen(dev_t dev, int flag, int mode, struct lwp *l)
321 {
322 struct flash_softc *sc;
323
324 sc = device_lookup_private(&flash_cd, minor(dev));
325 if (sc == NULL)
326 return ENXIO;
327 if (sc->sc_status & FLASH_ST_BUSY)
328 return EBUSY;
329 sc->sc_status |= FLASH_ST_BUSY;
330 return 0;
331 }
332
333 int
334 flashclose(dev_t dev, int flag, int mode, struct lwp *l)
335 {
336 struct flash_softc *sc;
337
338 sc = device_lookup_private(&flash_cd, minor(dev));
339 sc->sc_status &= ~FLASH_ST_BUSY;
340 return 0;
341 }
342
343 int
344 flashread(dev_t dev, struct uio *uio, int flag)
345 {
346 struct flash_softc *sc;
347 bus_space_tag_t iot;
348 bus_space_handle_t ioh;
349 bus_size_t off;
350 int total;
351 int count;
352 int error;
353
354 sc = device_lookup_private(&flash_cd, minor(dev));
355 iot = sc->sc_iot;
356 ioh = sc->sc_ioh;
357
358 off = uio->uio_offset;
359 total = min(sc->sc_size - off, uio->uio_resid);
360
361 while (total > 0) {
362 count = min(sc->sc_block_size, uio->uio_resid);
363 bus_space_read_region_1(iot, ioh, off, sc->sc_buf, count);
364 if ((error = uiomove(sc->sc_buf, count, uio)) != 0)
365 return error;
366 off += count;
367 total -= count;
368 }
369 return 0;
370 }
371
372
373 int
374 flashwrite(dev_t dev, struct uio *uio, int flag)
375 {
376 struct flash_softc *sc;
377 bus_space_tag_t iot;
378 bus_space_handle_t ioh;
379 bus_size_t off;
380 int stat;
381 int error;
382
383 sc = device_lookup_private(&flash_cd, minor(dev));
384
385 if (sc->sc_size < uio->uio_offset + uio->uio_resid)
386 return ENOSPC;
387 if (uio->uio_offset % sc->sc_block_size)
388 return EINVAL;
389 if (uio->uio_resid % sc->sc_block_size)
390 return EINVAL;
391
392 iot = sc->sc_iot;
393 ioh = sc->sc_ioh;
394
395 for (off = uio->uio_offset;
396 uio->uio_resid > 0;
397 off += sc->sc_block_size) {
398 if ((error = uiomove(sc->sc_buf, sc->sc_block_size, uio)) != 0)
399 return error;
400 if (is_block_same(sc, off, sc->sc_buf))
401 continue;
402 if ((stat = flash_block_erase(sc, off)) != 0) {
403 printf("block erase failed status = 0x%x\n", stat);
404 return EIO;
405 }
406 if ((stat = flash_block_write(sc, off)) != 0) {
407 printf("block write failed status = 0x%x\n", stat);
408 return EIO;
409 }
410 }
411 return 0;
412 }
413
414 /*
415 * XXX
416 * this function is too much specific for the device.
417 */
418 static int
419 i28f128_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
420 {
421 static const u_int8_t vendor_code[] = {
422 0x89, /* manufacturer code: intel */
423 0x18, /* device code: 28F128 */
424 };
425
426 static const u_int8_t idstr[] = {
427 'Q', 'R', 'Y',
428 0x01, 0x00,
429 0x31, 0x00,
430 0xff
431 };
432
433 int i;
434
435 /* start Common Flash Interface Query */
436 bus_space_write_2(iot, ioh, 0, CFI_READ_CFI_QUERY);
437 /* read CFI Query ID string */
438 for (i = 0; idstr[i] != 0xff; i++) {
439 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i])
440 return 1;
441 }
442
443 /* read manufacturer code and device code */
444 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0])
445 return 1;
446 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1])
447 return 1;
448
449 bus_space_write_2(iot, ioh, 0, I28F128_RESET);
450 return 0;
451 }
452
453 /*
454 * XXX
455 * this function is too much specific for the device.
456 */
457 static int
458 mbm29160_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
459 {
460 static const u_int16_t vendor_code[] = {
461 0x0004, /* manufacturer code: intel */
462 0x2249, /* device code: 29LV160BE */
463 };
464
465 static const u_int8_t idstr[] = {
466 'Q', 'R', 'Y',
467 0x02, 0x00,
468 0x40, 0x00,
469 0xff
470 };
471
472 int i;
473
474 /* start Common Flash Interface Query */
475 bus_space_write_2(iot, ioh, 0xaa, CFI_READ_CFI_QUERY);
476 /* read CFI Query ID string */
477 for (i = 0; idstr[i] != 0xff; i++) {
478 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i])
479 return 1;
480 }
481
482 bus_space_write_2(iot, ioh, 0, 0xff);
483
484 /* read manufacturer code and device code */
485 bus_space_write_2(iot, ioh, 0x555 << 1, 0xaa);
486 bus_space_write_2(iot, ioh, 0x2aa << 1, 0x55);
487 bus_space_write_2(iot, ioh, 0x555 << 1, 0x90);
488 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0])
489 return 1;
490 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1])
491 return 1;
492
493 bus_space_write_2(iot, ioh, 0, 0xff);
494 return 0;
495 }
496
497 static int
498 is_block_same(struct flash_softc *sc, bus_size_t offset, const void *bufp)
499 {
500 bus_space_tag_t iot = sc->sc_iot;
501 bus_space_handle_t ioh = sc->sc_ioh;
502 const u_int8_t *p = bufp;
503 int count = sc->sc_block_size;
504
505 while (count-- > 0) {
506 if (bus_space_read_1(iot, ioh, offset++) != *p++)
507 return 0;
508 }
509 return 1;
510 }
511
512 static int
513 intel_erase(struct flash_softc *sc, bus_size_t offset)
514 {
515 bus_space_tag_t iot = sc->sc_iot;
516 bus_space_handle_t ioh = sc->sc_ioh;
517 int status;
518 int i;
519
520 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_1ST);
521 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_2ND);
522
523 status = 0;
524 for (i = sc->sc_max_block_erase_timo; i > 0; i--) {
525 tsleep(sc, PRIBIO, "blockerase",
526 1 + (sc->sc_typ_block_erase_timo * hz) / 1000);
527 if ((status = bus_space_read_2(iot, ioh, offset))
528 & I28F128_S_READY)
529 break;
530 }
531 if (i == 0)
532 status |= FLASH_TIMEOUT;
533
534 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
535 bus_space_write_2(iot, ioh, offset, I28F128_RESET);
536
537 return status & (FLASH_TIMEOUT
538 | I28F128_S_ERASE_SUSPEND
539 | I28F128_S_COMSEQ_ERROR
540 | I28F128_S_ERASE_ERROR
541 | I28F128_S_BLOCK_LOCKED);
542 }
543
544 static int
545 intel_write(struct flash_softc *sc, bus_size_t offset)
546 {
547 bus_space_tag_t iot = sc->sc_iot;
548 bus_space_handle_t ioh = sc->sc_ioh;
549 int wbuf_size;
550 int timo;
551 int status;
552 bus_size_t fence;
553 int i;
554 const u_int16_t *p;
555
556 /* wbuf_size = size in u_int16_t */
557 wbuf_size = sc->sc_write_buffer_size >> 1;
558
559 p = (u_int16_t *) sc->sc_buf;
560 fence = offset + sc->sc_block_size;
561 do {
562 status = 0;
563 for (timo = sc->sc_max_buffer_write_timo; timo > 0; timo--) {
564 bus_space_write_2(iot, ioh, offset,
565 I28F128_WRITE_BUFFER);
566 status = bus_space_read_2(iot, ioh, offset);
567 if (status & I28F128_XS_BUF_AVAIL)
568 break;
569 DELAY(sc->sc_typ_buffer_write_timo);
570 }
571 if (timo == 0) {
572 status |= FLASH_TIMEOUT;
573 goto errout;
574 }
575
576 bus_space_write_2(iot, ioh, offset, wbuf_size - 1);
577
578 for (i = wbuf_size; i > 0; i--, p++, offset += 2)
579 bus_space_write_2(iot, ioh, offset, *p);
580
581 bus_space_write_2(iot, ioh, offset, I28F128_WBUF_CONFIRM);
582
583 do {
584 bus_space_write_2(iot, ioh, offset,
585 I28F128_READ_STATUS);
586 status = bus_space_read_2(iot, ioh, offset);
587 } while (!(status & I28F128_S_READY));
588
589 } while (offset < fence);
590
591 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
592 bus_space_write_2(iot, ioh, offset, I28F128_RESET);
593
594 return 0;
595
596 errout:
597 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
598 bus_space_write_2(iot, ioh, offset, I28F128_RESET);
599
600 status &= (FLASH_TIMEOUT
601 | I28F128_S_PROG_ERROR
602 | I28F128_S_COMSEQ_ERROR
603 | I28F128_S_LOW_VOLTAGE
604 | I28F128_S_PROG_SUSPEND
605 | I28F128_S_BLOCK_LOCKED);
606 return status;
607 }
608
609 static int
610 amd_erase_sector(struct flash_softc *sc, bus_size_t offset)
611 {
612 bus_space_tag_t iot = sc->sc_iot;
613 bus_space_handle_t ioh = sc->sc_ioh;
614 int i;
615
616 DPRINTF(("amd_erase_sector offset = %08lx\n", offset));
617
618 bus_space_write_2(iot, ioh,
619 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0);
620 bus_space_write_2(iot, ioh,
621 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1);
622 bus_space_write_2(iot, ioh,
623 MBM29LV160_COMM_ADDR2, MBM29LV160_ESECT_CMD2);
624 bus_space_write_2(iot, ioh,
625 MBM29LV160_COMM_ADDR3, MBM29LV160_ESECT_CMD3);
626 bus_space_write_2(iot, ioh,
627 MBM29LV160_COMM_ADDR4, MBM29LV160_ESECT_CMD4);
628 bus_space_write_2(iot, ioh, offset, MBM29LV160_ESECT_CMD5);
629
630 for (i = sc->sc_max_block_erase_timo; i > 0; i--) {
631 tsleep(sc, PRIBIO, "blockerase",
632 1 + (sc->sc_typ_block_erase_timo * hz) / 1000);
633 if (bus_space_read_2(iot, ioh, offset) == 0xffff)
634 return 0;
635 }
636
637 return FLASH_TIMEOUT;
638 }
639
640 static int
641 amd_erase(struct flash_softc *sc, bus_size_t offset)
642 {
643 static const struct mbm29lv_subsect {
644 u_int16_t devcode;
645 u_int32_t subsect_mask;
646 u_int32_t subsect_addr;
647 } subsect[] = {
648 {
649 MBM29LV160TE_DEVCODE,
650 MBM29LV160_SUBSECT_MASK,
651 MBM29LV160TE_SUBSECT_ADDR
652 },
653 {
654 MBM29LV160BE_DEVCODE,
655 MBM29LV160_SUBSECT_MASK,
656 MBM29LV160BE_SUBSECT_ADDR
657 },
658 { 0, 0, 0 }
659 };
660
661 bus_space_tag_t iot = sc->sc_iot;
662 bus_space_handle_t ioh = sc->sc_ioh;
663 u_int16_t devcode;
664 const struct mbm29lv_subsect *ss;
665 bus_size_t fence;
666 int step;
667 int status;
668
669 bus_space_write_2(iot, ioh,
670 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0);
671 bus_space_write_2(iot, ioh,
672 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1);
673 bus_space_write_2(iot, ioh,
674 MBM29LV160_COMM_ADDR2, MBM29LV160_SIGN_CMD2);
675 devcode = bus_space_read_2(iot, ioh, MBM29LV160_DEVCODE_REG);
676
677 for (ss = subsect; ss->devcode; ss++) {
678 if (ss->devcode == devcode)
679 break;
680 }
681 if (ss->devcode == 0) {
682 printf("flash: amd_erase(): unknown device code %04x\n",
683 devcode);
684 return -1;
685 }
686
687 DPRINTF(("flash: amd_erase(): devcode = %04x subsect = %08x\n",
688 devcode, ss->subsect_addr));
689
690 fence = offset + sc->sc_block_size;
691 step = (offset & ss->subsect_mask) == ss->subsect_addr
692 ? MBM29LV160_SUBSECT_SIZE : MBM29LV160_SECT_SIZE;
693 do {
694 if ((status = amd_erase_sector(sc, offset)) != 0)
695 return status;
696 offset += step;
697 } while (offset < fence);
698
699 return 0;
700 }
701
702 static int
703 amd_write(struct flash_softc *sc, bus_size_t offset)
704 {
705 bus_space_tag_t iot = sc->sc_iot;
706 bus_space_handle_t ioh = sc->sc_ioh;
707 int timo;
708 bus_size_t fence;
709 const u_int16_t *p;
710
711 p = (u_int16_t *) sc->sc_buf;
712 fence = offset + sc->sc_block_size;
713 do {
714 bus_space_write_2(iot, ioh,
715 MBM29LV160_COMM_ADDR0,
716 MBM29LV160_COMM_CMD0);
717 bus_space_write_2(iot, ioh,
718 MBM29LV160_COMM_ADDR1,
719 MBM29LV160_COMM_CMD1);
720 bus_space_write_2(iot, ioh,
721 MBM29LV160_COMM_ADDR2,
722 MBM29LV160_PROG_CMD2);
723 bus_space_write_2(iot, ioh, offset, *p);
724
725 for (timo = sc->sc_max_word_prog_timo; timo > 0; timo--) {
726 if (bus_space_read_2(iot, ioh, offset) == *p)
727 break;
728 DELAY(sc->sc_typ_word_prog_timo);
729 }
730 if (timo == 0)
731 return FLASH_TIMEOUT;
732
733 p++;
734 offset += 2;
735 } while (offset < fence);
736
737 return 0;
738 }
739