1 /* $NetBSD: flash_vrip.c,v 1.15 2023/09/12 19:32:00 andvar 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.15 2023/09/12 19:32:00 andvar 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/kmem.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 vrflash_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 vrflash_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 *
find_command_set(u_int8_t cmdset0,u_int8_t cmdset1)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
probe_cfi(bus_space_tag_t iot,bus_space_handle_t ioh)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
flash_probe(device_t parent,cfdata_t match,void * aux)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
flash_attach(device_t parent,device_t self,void * aux)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 sc->sc_buf = kmem_alloc(sc->sc_block_size, KM_SLEEP);
266
267 sc->sc_write_buffer_size
268 = 1 << (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG0]
269 + (sc->sc_cfi_raw[CFI_MAX_WBUF_SIZE_REG1] << 8));
270 sc->sc_typ_word_prog_timo
271 = 1 << sc->sc_cfi_raw[CFI_TYP_WORD_PROG_REG];
272 sc->sc_max_word_prog_timo
273 = 1 << sc->sc_cfi_raw[CFI_MAX_WORD_PROG_REG];
274 sc->sc_typ_buffer_write_timo
275 = 1 << sc->sc_cfi_raw[CFI_TYP_BUF_WRITE_REG];
276 sc->sc_max_buffer_write_timo
277 = 1 << sc->sc_cfi_raw[CFI_MAX_BUF_WRITE_REG];
278 sc->sc_typ_block_erase_timo
279 = 1 << sc->sc_cfi_raw[CFI_TYP_BLOCK_ERASE_REG];
280 sc->sc_max_block_erase_timo
281 = 1 << sc->sc_cfi_raw[CFI_MAX_BLOCK_ERASE_REG];
282
283 printf("\n");
284
285 #ifdef FLASH_DEBUG
286 printf("read_cfi: extract cfi\n");
287 printf("max block size: %dbyte\n", sc->sc_block_size);
288 printf("write buffer size: %dbyte\n", sc->sc_write_buffer_size);
289 printf("typical word program timeout: %dusec\n",
290 sc->sc_typ_word_prog_timo);
291 printf("maximam word program timeout: %dusec (%d time of typ)\n",
292 sc->sc_typ_word_prog_timo * sc->sc_max_word_prog_timo,
293 sc->sc_max_word_prog_timo);
294 printf("typical buffer write timeout: %dusec\n",
295 sc->sc_typ_buffer_write_timo);
296 printf("maximam buffer write timeout: %dusec (%d time of typ)\n",
297 sc->sc_typ_buffer_write_timo * sc->sc_max_buffer_write_timo,
298 sc->sc_max_buffer_write_timo);
299 printf("typical block erase timeout: %dmsec\n",
300 sc->sc_typ_block_erase_timo);
301 printf("maximam block erase timeout: %dmsec (%d time of typ)\n",
302 sc->sc_typ_block_erase_timo * sc->sc_max_block_erase_timo,
303 sc->sc_max_block_erase_timo);
304
305 printf("read_cfi: dump cfi\n");
306 for (i = 0; i < CFI_TOTAL_SIZE;) {
307 int j;
308 for (j = 0; j < 16; j++) {
309 printf("%02x ", sc->sc_cfi_raw[i++]);
310 }
311 printf("\n");
312 }
313 #endif
314 }
315
316 int
flashopen(dev_t dev,int flag,int mode,struct lwp * l)317 flashopen(dev_t dev, int flag, int mode, struct lwp *l)
318 {
319 struct flash_softc *sc;
320
321 sc = device_lookup_private(&vrflash_cd, minor(dev));
322 if (sc == NULL)
323 return ENXIO;
324 if (sc->sc_status & FLASH_ST_BUSY)
325 return EBUSY;
326 sc->sc_status |= FLASH_ST_BUSY;
327 return 0;
328 }
329
330 int
flashclose(dev_t dev,int flag,int mode,struct lwp * l)331 flashclose(dev_t dev, int flag, int mode, struct lwp *l)
332 {
333 struct flash_softc *sc;
334
335 sc = device_lookup_private(&vrflash_cd, minor(dev));
336 sc->sc_status &= ~FLASH_ST_BUSY;
337 return 0;
338 }
339
340 int
flashread(dev_t dev,struct uio * uio,int flag)341 flashread(dev_t dev, struct uio *uio, int flag)
342 {
343 struct flash_softc *sc;
344 bus_space_tag_t iot;
345 bus_space_handle_t ioh;
346 bus_size_t off;
347 int total;
348 int count;
349 int error;
350
351 sc = device_lookup_private(&vrflash_cd, minor(dev));
352 iot = sc->sc_iot;
353 ioh = sc->sc_ioh;
354
355 off = uio->uio_offset;
356 total = uimin(sc->sc_size - off, uio->uio_resid);
357
358 while (total > 0) {
359 count = uimin(sc->sc_block_size, uio->uio_resid);
360 bus_space_read_region_1(iot, ioh, off, sc->sc_buf, count);
361 if ((error = uiomove(sc->sc_buf, count, uio)) != 0)
362 return error;
363 off += count;
364 total -= count;
365 }
366 return 0;
367 }
368
369
370 int
flashwrite(dev_t dev,struct uio * uio,int flag)371 flashwrite(dev_t dev, struct uio *uio, int flag)
372 {
373 struct flash_softc *sc;
374 bus_size_t off;
375 int stat;
376 int error;
377
378 sc = device_lookup_private(&vrflash_cd, minor(dev));
379
380 if (sc->sc_size < uio->uio_offset + uio->uio_resid)
381 return ENOSPC;
382 if (uio->uio_offset % sc->sc_block_size)
383 return EINVAL;
384 if (uio->uio_resid % sc->sc_block_size)
385 return EINVAL;
386
387 for (off = uio->uio_offset;
388 uio->uio_resid > 0;
389 off += sc->sc_block_size) {
390 if ((error = uiomove(sc->sc_buf, sc->sc_block_size, uio)) != 0)
391 return error;
392 if (is_block_same(sc, off, sc->sc_buf))
393 continue;
394 if ((stat = flash_block_erase(sc, off)) != 0) {
395 printf("block erase failed status = 0x%x\n", stat);
396 return EIO;
397 }
398 if ((stat = flash_block_write(sc, off)) != 0) {
399 printf("block write failed status = 0x%x\n", stat);
400 return EIO;
401 }
402 }
403 return 0;
404 }
405
406 /*
407 * XXX
408 * this function is too much specific for the device.
409 */
410 static int
i28f128_probe(bus_space_tag_t iot,bus_space_handle_t ioh)411 i28f128_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
412 {
413 static const u_int8_t vendor_code[] = {
414 0x89, /* manufacturer code: intel */
415 0x18, /* device code: 28F128 */
416 };
417
418 static const u_int8_t idstr[] = {
419 'Q', 'R', 'Y',
420 0x01, 0x00,
421 0x31, 0x00,
422 0xff
423 };
424
425 int i;
426
427 /* start Common Flash Interface Query */
428 bus_space_write_2(iot, ioh, 0, CFI_READ_CFI_QUERY);
429 /* read CFI Query ID string */
430 for (i = 0; idstr[i] != 0xff; i++) {
431 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i])
432 return 1;
433 }
434
435 /* read manufacturer code and device code */
436 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0])
437 return 1;
438 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1])
439 return 1;
440
441 bus_space_write_2(iot, ioh, 0, I28F128_RESET);
442 return 0;
443 }
444
445 /*
446 * XXX
447 * this function is too much specific for the device.
448 */
449 static int
mbm29160_probe(bus_space_tag_t iot,bus_space_handle_t ioh)450 mbm29160_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
451 {
452 static const u_int16_t vendor_code[] = {
453 0x0004, /* manufacturer code: intel */
454 0x2249, /* device code: 29LV160BE */
455 };
456
457 static const u_int8_t idstr[] = {
458 'Q', 'R', 'Y',
459 0x02, 0x00,
460 0x40, 0x00,
461 0xff
462 };
463
464 int i;
465
466 /* start Common Flash Interface Query */
467 bus_space_write_2(iot, ioh, 0xaa, CFI_READ_CFI_QUERY);
468 /* read CFI Query ID string */
469 for (i = 0; idstr[i] != 0xff; i++) {
470 if (bus_space_read_2(iot, ioh, (0x10 + i) << 1) != idstr[i])
471 return 1;
472 }
473
474 bus_space_write_2(iot, ioh, 0, 0xff);
475
476 /* read manufacturer code and device code */
477 bus_space_write_2(iot, ioh, 0x555 << 1, 0xaa);
478 bus_space_write_2(iot, ioh, 0x2aa << 1, 0x55);
479 bus_space_write_2(iot, ioh, 0x555 << 1, 0x90);
480 if (bus_space_read_2(iot, ioh, 0x00) != vendor_code[0])
481 return 1;
482 if (bus_space_read_2(iot, ioh, 0x02) != vendor_code[1])
483 return 1;
484
485 bus_space_write_2(iot, ioh, 0, 0xff);
486 return 0;
487 }
488
489 static int
is_block_same(struct flash_softc * sc,bus_size_t offset,const void * bufp)490 is_block_same(struct flash_softc *sc, bus_size_t offset, const void *bufp)
491 {
492 bus_space_tag_t iot = sc->sc_iot;
493 bus_space_handle_t ioh = sc->sc_ioh;
494 const u_int8_t *p = bufp;
495 int count = sc->sc_block_size;
496
497 while (count-- > 0) {
498 if (bus_space_read_1(iot, ioh, offset++) != *p++)
499 return 0;
500 }
501 return 1;
502 }
503
504 static int
intel_erase(struct flash_softc * sc,bus_size_t offset)505 intel_erase(struct flash_softc *sc, bus_size_t offset)
506 {
507 bus_space_tag_t iot = sc->sc_iot;
508 bus_space_handle_t ioh = sc->sc_ioh;
509 int status;
510 int i;
511
512 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_1ST);
513 bus_space_write_2(iot, ioh, offset, I28F128_BLK_ERASE_2ND);
514
515 status = 0;
516 for (i = sc->sc_max_block_erase_timo; i > 0; i--) {
517 tsleep(sc, PRIBIO, "blockerase",
518 1 + (sc->sc_typ_block_erase_timo * hz) / 1000);
519 if ((status = bus_space_read_2(iot, ioh, offset))
520 & I28F128_S_READY)
521 break;
522 }
523 if (i == 0)
524 status |= FLASH_TIMEOUT;
525
526 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
527 bus_space_write_2(iot, ioh, offset, I28F128_RESET);
528
529 return status & (FLASH_TIMEOUT
530 | I28F128_S_ERASE_SUSPEND
531 | I28F128_S_COMSEQ_ERROR
532 | I28F128_S_ERASE_ERROR
533 | I28F128_S_BLOCK_LOCKED);
534 }
535
536 static int
intel_write(struct flash_softc * sc,bus_size_t offset)537 intel_write(struct flash_softc *sc, bus_size_t offset)
538 {
539 bus_space_tag_t iot = sc->sc_iot;
540 bus_space_handle_t ioh = sc->sc_ioh;
541 int wbuf_size;
542 int timo;
543 int status;
544 bus_size_t fence;
545 int i;
546 const u_int16_t *p;
547
548 /* wbuf_size = size in u_int16_t */
549 wbuf_size = sc->sc_write_buffer_size >> 1;
550
551 p = (u_int16_t *) sc->sc_buf;
552 fence = offset + sc->sc_block_size;
553 do {
554 status = 0;
555 for (timo = sc->sc_max_buffer_write_timo; timo > 0; timo--) {
556 bus_space_write_2(iot, ioh, offset,
557 I28F128_WRITE_BUFFER);
558 status = bus_space_read_2(iot, ioh, offset);
559 if (status & I28F128_XS_BUF_AVAIL)
560 break;
561 DELAY(sc->sc_typ_buffer_write_timo);
562 }
563 if (timo == 0) {
564 status |= FLASH_TIMEOUT;
565 goto errout;
566 }
567
568 bus_space_write_2(iot, ioh, offset, wbuf_size - 1);
569
570 for (i = wbuf_size; i > 0; i--, p++, offset += 2)
571 bus_space_write_2(iot, ioh, offset, *p);
572
573 bus_space_write_2(iot, ioh, offset, I28F128_WBUF_CONFIRM);
574
575 do {
576 bus_space_write_2(iot, ioh, offset,
577 I28F128_READ_STATUS);
578 status = bus_space_read_2(iot, ioh, offset);
579 } while (!(status & I28F128_S_READY));
580
581 } while (offset < fence);
582
583 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
584 bus_space_write_2(iot, ioh, offset, I28F128_RESET);
585
586 return 0;
587
588 errout:
589 bus_space_write_2(iot, ioh, offset, I28F128_CLEAR_STATUS);
590 bus_space_write_2(iot, ioh, offset, I28F128_RESET);
591
592 status &= (FLASH_TIMEOUT
593 | I28F128_S_PROG_ERROR
594 | I28F128_S_COMSEQ_ERROR
595 | I28F128_S_LOW_VOLTAGE
596 | I28F128_S_PROG_SUSPEND
597 | I28F128_S_BLOCK_LOCKED);
598 return status;
599 }
600
601 static int
amd_erase_sector(struct flash_softc * sc,bus_size_t offset)602 amd_erase_sector(struct flash_softc *sc, bus_size_t offset)
603 {
604 bus_space_tag_t iot = sc->sc_iot;
605 bus_space_handle_t ioh = sc->sc_ioh;
606 int i;
607
608 DPRINTF(("amd_erase_sector offset = %08lx\n", offset));
609
610 bus_space_write_2(iot, ioh,
611 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0);
612 bus_space_write_2(iot, ioh,
613 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1);
614 bus_space_write_2(iot, ioh,
615 MBM29LV160_COMM_ADDR2, MBM29LV160_ESECT_CMD2);
616 bus_space_write_2(iot, ioh,
617 MBM29LV160_COMM_ADDR3, MBM29LV160_ESECT_CMD3);
618 bus_space_write_2(iot, ioh,
619 MBM29LV160_COMM_ADDR4, MBM29LV160_ESECT_CMD4);
620 bus_space_write_2(iot, ioh, offset, MBM29LV160_ESECT_CMD5);
621
622 for (i = sc->sc_max_block_erase_timo; i > 0; i--) {
623 tsleep(sc, PRIBIO, "blockerase",
624 1 + (sc->sc_typ_block_erase_timo * hz) / 1000);
625 if (bus_space_read_2(iot, ioh, offset) == 0xffff)
626 return 0;
627 }
628
629 return FLASH_TIMEOUT;
630 }
631
632 static int
amd_erase(struct flash_softc * sc,bus_size_t offset)633 amd_erase(struct flash_softc *sc, bus_size_t offset)
634 {
635 static const struct mbm29lv_subsect {
636 u_int16_t devcode;
637 u_int32_t subsect_mask;
638 u_int32_t subsect_addr;
639 } subsect[] = {
640 {
641 MBM29LV160TE_DEVCODE,
642 MBM29LV160_SUBSECT_MASK,
643 MBM29LV160TE_SUBSECT_ADDR
644 },
645 {
646 MBM29LV160BE_DEVCODE,
647 MBM29LV160_SUBSECT_MASK,
648 MBM29LV160BE_SUBSECT_ADDR
649 },
650 { 0, 0, 0 }
651 };
652
653 bus_space_tag_t iot = sc->sc_iot;
654 bus_space_handle_t ioh = sc->sc_ioh;
655 u_int16_t devcode;
656 const struct mbm29lv_subsect *ss;
657 bus_size_t fence;
658 int step;
659 int status;
660
661 bus_space_write_2(iot, ioh,
662 MBM29LV160_COMM_ADDR0, MBM29LV160_COMM_CMD0);
663 bus_space_write_2(iot, ioh,
664 MBM29LV160_COMM_ADDR1, MBM29LV160_COMM_CMD1);
665 bus_space_write_2(iot, ioh,
666 MBM29LV160_COMM_ADDR2, MBM29LV160_SIGN_CMD2);
667 devcode = bus_space_read_2(iot, ioh, MBM29LV160_DEVCODE_REG);
668
669 for (ss = subsect; ss->devcode; ss++) {
670 if (ss->devcode == devcode)
671 break;
672 }
673 if (ss->devcode == 0) {
674 printf("flash: amd_erase(): unknown device code %04x\n",
675 devcode);
676 return -1;
677 }
678
679 DPRINTF(("flash: amd_erase(): devcode = %04x subsect = %08x\n",
680 devcode, ss->subsect_addr));
681
682 fence = offset + sc->sc_block_size;
683 step = (offset & ss->subsect_mask) == ss->subsect_addr
684 ? MBM29LV160_SUBSECT_SIZE : MBM29LV160_SECT_SIZE;
685 do {
686 if ((status = amd_erase_sector(sc, offset)) != 0)
687 return status;
688 offset += step;
689 } while (offset < fence);
690
691 return 0;
692 }
693
694 static int
amd_write(struct flash_softc * sc,bus_size_t offset)695 amd_write(struct flash_softc *sc, bus_size_t offset)
696 {
697 bus_space_tag_t iot = sc->sc_iot;
698 bus_space_handle_t ioh = sc->sc_ioh;
699 int timo;
700 bus_size_t fence;
701 const u_int16_t *p;
702
703 p = (u_int16_t *) sc->sc_buf;
704 fence = offset + sc->sc_block_size;
705 do {
706 bus_space_write_2(iot, ioh,
707 MBM29LV160_COMM_ADDR0,
708 MBM29LV160_COMM_CMD0);
709 bus_space_write_2(iot, ioh,
710 MBM29LV160_COMM_ADDR1,
711 MBM29LV160_COMM_CMD1);
712 bus_space_write_2(iot, ioh,
713 MBM29LV160_COMM_ADDR2,
714 MBM29LV160_PROG_CMD2);
715 bus_space_write_2(iot, ioh, offset, *p);
716
717 for (timo = sc->sc_max_word_prog_timo; timo > 0; timo--) {
718 if (bus_space_read_2(iot, ioh, offset) == *p)
719 break;
720 DELAY(sc->sc_typ_word_prog_timo);
721 }
722 if (timo == 0)
723 return FLASH_TIMEOUT;
724
725 p++;
726 offset += 2;
727 } while (offset < fence);
728
729 return 0;
730 }
731