Annotation of sys/arch/mvme68k/dev/flash.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: flash.c,v 1.17 2005/12/17 07:31:26 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1995 Theo de Raadt
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26: */
27:
28: #include <sys/param.h>
29: #include <sys/ioctl.h>
30: #include <sys/proc.h>
31: #include <sys/user.h>
32: #include <sys/tty.h>
33: #include <sys/uio.h>
34: #include <sys/systm.h>
35: #include <sys/kernel.h>
36: #include <sys/malloc.h>
37: #include <sys/syslog.h>
38: #include <sys/fcntl.h>
39: #include <sys/device.h>
40:
41: #include <machine/autoconf.h>
42: #include <machine/conf.h>
43: #include <machine/cpu.h>
44: #include <machine/mioctl.h>
45:
46: #include "mc.h"
47:
48: #if NMC > 0
49: #include <mvme68k/dev/mcreg.h>
50: #endif
51:
52: #include <mvme68k/dev/flashreg.h>
53:
54: struct flashsoftc {
55: struct device sc_dev;
56: paddr_t sc_paddr;
57: volatile u_char *sc_vaddr;
58: u_char sc_manu;
59: u_char sc_ii;
60: int sc_len;
61: int sc_zonesize;
62: };
63:
64: void flashattach(struct device *, struct device *, void *);
65: int flashmatch(struct device *, void *, void *);
66:
67: struct cfattach flash_ca = {
68: sizeof(struct flashsoftc), flashmatch, flashattach
69: };
70:
71: struct cfdriver flash_cd = {
72: NULL, "flash", DV_DULL
73: };
74:
75: int flashwritebyte(struct flashsoftc *sc, int addr, u_char val);
76: int flasherasezone(struct flashsoftc *sc, int addr);
77: u_char *flashsavezone(struct flashsoftc *, int);
78: int flashwritezone(struct flashsoftc *, u_char *, int);
79:
80: struct flashii intel_flashii[] = {
81: { "28F008SA", FLII_INTEL_28F008SA, 1024*1024, 64*1024 },
82: { "28F008SA-L", FLII_INTEL_28F008SA_L, 1024*1024, 64*1024 },
83: { "28F016SA", FLII_INTEL_28F016SA, 1024*1024, 64*1024 },
84: { NULL },
85: };
86:
87: struct flashmanu {
88: char *name;
89: u_char manu;
90: struct flashii *flashii;
91: } flashmanu[] = {
92: { "intel", FLMANU_INTEL, intel_flashii },
93: { NULL, 0, NULL }
94: };
95:
96: int
97: flashmatch(parent, cf, args)
98: struct device *parent;
99: void *cf;
100: void *args;
101: {
102: struct confargs *ca = args;
103:
104: #ifdef MVME147
105: if (cputyp == CPU_147)
106: return (0);
107: #endif
108: #ifdef MVME167
109: /*
110: * XXX: 166 has 4 byte-wide flash rams side-by-side, and
111: * isn't supported (yet).
112: */
113: if (cputyp == CPU_166)
114: return (0);
115: if (cputyp == CPU_167)
116: return (0);
117: #endif
118: #ifdef MVME177
119: /*
120: * XXX: 177 has no flash.
121: */
122: if (cputyp == CPU_177)
123: return (0);
124: #endif
125:
126: if (badpaddr(ca->ca_paddr, 1))
127: return (0);
128:
129: if (!mc_hasflash())
130: return 0;
131:
132: return (1);
133: }
134:
135: void
136: flashattach(parent, self, args)
137: struct device *parent, *self;
138: void *args;
139: {
140: struct flashsoftc *sc = (struct flashsoftc *)self;
141: struct confargs *ca = args;
142: int manu, ident;
143:
144: sc->sc_paddr = ca->ca_paddr;
145: sc->sc_vaddr = (volatile u_char *)mapiodev(sc->sc_paddr, NBPG);
146:
147: switch (cputyp) {
148: #ifdef MVME162
149: case CPU_162:
150: mc_enableflashwrite(1);
151: break;
152: #endif
153: #ifdef MVME172
154: case CPU_172:
155: mc_enableflashwrite(1);
156: break;
157: #endif
158: }
159:
160: /* read manufacturer and product identifier from flash */
161: sc->sc_vaddr[0] = FLCMD_RESET;
162: sc->sc_vaddr[0] = FLCMD_READII;
163: sc->sc_manu = sc->sc_vaddr[0];
164: sc->sc_ii = sc->sc_vaddr[1];
165: sc->sc_vaddr[0] = FLCMD_RESET;
166: for (manu = 0; flashmanu[manu].name; manu++)
167: if (flashmanu[manu].manu == sc->sc_manu)
168: break;
169: if (flashmanu[manu].name == NULL) {
170: printf(": unknown manu 0x%02x ident %02x\n",
171: sc->sc_manu, sc->sc_ii);
172: return;
173: }
174: for (ident = 0; flashmanu[manu].flashii[ident].name; ident++)
175: if (flashmanu[manu].flashii[ident].ii == sc->sc_ii)
176: break;
177: if (flashmanu[manu].flashii[ident].name == NULL) {
178: printf(": unknown manu %s ident 0x%02x\n",
179: flashmanu[manu].name, sc->sc_ii);
180: return;
181: }
182: sc->sc_len = flashmanu[manu].flashii[ident].size;
183: sc->sc_zonesize = flashmanu[manu].flashii[ident].zonesize;
184: printf(": %s %s len %d", flashmanu[manu].name,
185: flashmanu[manu].flashii[ident].name, sc->sc_len);
186:
187: sc->sc_vaddr[0] = FLCMD_CLEARSTAT;
188: sc->sc_vaddr[0] = FLCMD_RESET;
189:
190: unmapiodev((vaddr_t)sc->sc_vaddr, NBPG);
191: sc->sc_vaddr = (volatile u_char *)mapiodev(sc->sc_paddr, sc->sc_len);
192: if (sc->sc_vaddr == NULL) {
193: sc->sc_len = 0;
194: printf(" -- failed to map");
195: }
196: printf("\n");
197: }
198:
199: u_char *
200: flashsavezone(sc, start)
201: struct flashsoftc *sc;
202: int start;
203: {
204: u_char *zone;
205:
206: zone = (u_char *)malloc(sc->sc_zonesize, M_TEMP, M_WAITOK);
207: sc->sc_vaddr[0] = FLCMD_RESET;
208: bcopy((u_char *)&sc->sc_vaddr[start], zone, sc->sc_zonesize);
209: return (zone);
210: }
211:
212: int
213: flashwritezone(sc, zone, start)
214: struct flashsoftc *sc;
215: u_char *zone;
216: int start;
217: {
218: u_char sr;
219: int i;
220:
221: for (i = 0; i < sc->sc_zonesize; i++) {
222: if (zone[i] == 0xff)
223: continue;
224: sc->sc_vaddr[start + i] = FLCMD_WSETUP;
225: sc->sc_vaddr[start + i] = zone[i];
226: do {
227: sc->sc_vaddr[0] = FLCMD_READSTAT;
228: sr = sc->sc_vaddr[0];
229: } while ((sr & FLSR_WSMS) == 0);
230: if (sr & FLSR_BWS)
231: return (i); /* write failed on this byte! */
232: sc->sc_vaddr[0] = FLCMD_RESET;
233: }
234: free(zone, M_TEMP);
235: return (0);
236: }
237:
238: int
239: flasherasezone(sc, addr)
240: struct flashsoftc *sc;
241: int addr;
242: {
243: u_char sr;
244:
245: printf("erasing zone at %d\n", addr);
246:
247: sc->sc_vaddr[addr] = FLCMD_ESETUP;
248: sc->sc_vaddr[addr] = FLCMD_ECONFIRM;
249:
250: sc->sc_vaddr[0] = FLCMD_READSTAT;
251: sr = sc->sc_vaddr[0];
252: while ((sr & FLSR_WSMS) == 0) {
253: sc->sc_vaddr[0] = FLCMD_READSTAT;
254: sr = sc->sc_vaddr[0];
255: }
256: printf("sr=%2x\n", sr);
257:
258: sc->sc_vaddr[0] = FLCMD_RESET;
259: if (sr & FLSR_ES)
260: return (-1);
261: return (0);
262: }
263:
264: /*
265: * Should add some light retry code. If a write fails see if an
266: * erase helps the situation... eventually flash rams become
267: * useless but perhaps we can get just one more cycle out of it.
268: */
269: int
270: flashwritebyte(sc, addr, val)
271: struct flashsoftc *sc;
272: int addr;
273: u_char val;
274: {
275: u_char sr;
276:
277: sc->sc_vaddr[addr] = FLCMD_CLEARSTAT;
278: sr = sc->sc_vaddr[0];
279: sc->sc_vaddr[addr] = FLCMD_WSETUP;
280: sc->sc_vaddr[addr] = val;
281: delay(9);
282: do {
283: sr = sc->sc_vaddr[addr];
284: } while ((sr & FLSR_WSMS) == 0);
285: printf("write status %2x\n", sr);
286:
287: sc->sc_vaddr[0] = FLCMD_RESET;
288: if (sr & FLSR_BWS)
289: return (-1); /* write failed! */
290: return (0);
291: }
292:
293:
294: /*ARGSUSED*/
295: int
296: flashopen(dev, flag, mode, p)
297: dev_t dev;
298: int flag, mode;
299: struct proc *p;
300: {
301:
302: if (minor(dev) >= flash_cd.cd_ndevs ||
303: flash_cd.cd_devs[minor(dev)] == NULL)
304: return (ENODEV);
305:
306: return (0);
307: }
308:
309: /*ARGSUSED*/
310: int
311: flashclose(dev, flag, mode, p)
312: dev_t dev;
313: int flag, mode;
314: struct proc *p;
315: {
316:
317: return (0);
318: }
319:
320: /*ARGSUSED*/
321: int
322: flashioctl(dev, cmd, data, flag, p)
323: dev_t dev;
324: u_long cmd;
325: caddr_t data;
326: int flag;
327: struct proc *p;
328: {
329: int unit = minor(dev);
330: struct flashsoftc *sc = (struct flashsoftc *) flash_cd.cd_devs[unit];
331: int error = 0;
332:
333: switch (cmd) {
334: case MIOCGSIZ:
335: *(int *)data = sc->sc_len;
336: break;
337: default:
338: error = ENOTTY;
339: break;
340: }
341: return (error);
342: }
343:
344: /*ARGSUSED*/
345: int
346: flashread(dev, uio, flags)
347: dev_t dev;
348: struct uio *uio;
349: int flags;
350: {
351: int unit = minor(dev);
352: struct flashsoftc *sc = (struct flashsoftc *) flash_cd.cd_devs[unit];
353: vaddr_t v;
354: int c;
355: struct iovec *iov;
356: int error = 0;
357:
358: while (uio->uio_resid > 0 && error == 0) {
359: iov = uio->uio_iov;
360: if (iov->iov_len == 0) {
361: uio->uio_iov++;
362: uio->uio_iovcnt--;
363: if (uio->uio_iovcnt < 0)
364: panic("flashrw");
365: continue;
366: }
367:
368: v = uio->uio_offset;
369: c = min(iov->iov_len, MAXPHYS);
370: if (v + c > sc->sc_len)
371: c = sc->sc_len - v; /* till end of FLASH */
372: if (c == 0)
373: return (0);
374: error = uiomove((u_char *)sc->sc_vaddr + v, c, uio);
375: }
376: return (error);
377: }
378:
379: /*ARGSUSED*/
380: int
381: flashwrite(dev, uio, flags)
382: dev_t dev;
383: struct uio *uio;
384: int flags;
385: {
386: int unit = minor(dev);
387: struct flashsoftc *sc = (struct flashsoftc *) flash_cd.cd_devs[unit];
388: vaddr_t v;
389: int c, i, r;
390: struct iovec *iov;
391: int error = 0;
392: u_char *cmpbuf;
393: int neederase = 0, needwrite = 0;
394: int zonestart, zoneoff;
395:
396: cmpbuf = (u_char *)malloc(sc->sc_zonesize, M_TEMP, M_WAITOK);
397:
398: while (uio->uio_resid > 0 && error == 0) {
399: iov = uio->uio_iov;
400: if (iov->iov_len == 0) {
401: uio->uio_iov++;
402: uio->uio_iovcnt--;
403: if (uio->uio_iovcnt < 0)
404: panic("flashrw");
405: continue;
406: }
407:
408: /*
409: * constrain to be at most a zone in size, and
410: * aligned to be within that one zone only.
411: */
412: v = uio->uio_offset;
413: zonestart = v & ~(sc->sc_zonesize - 1);
414: zoneoff = v & (sc->sc_zonesize - 1);
415: c = min(iov->iov_len, MAXPHYS);
416: if (v + c > sc->sc_len)
417: c = sc->sc_len - v; /* till end of FLASH */
418: if (c > sc->sc_zonesize - zoneoff)
419: c = sc->sc_zonesize - zoneoff; /* till end of zone */
420: if (c == 0)
421: return (0);
422: error = uiomove((u_char *)cmpbuf, c, uio);
423:
424: /*
425: * compare to see if we are going to need a block erase
426: * operation.
427: */
428: sc->sc_vaddr[0] = FLCMD_RESET;
429: for (i = 0; i < c; i++) {
430: u_char x = sc->sc_vaddr[v + i];
431: if (cmpbuf[i] & ~x)
432: neederase = 1;
433: if (cmpbuf[i] != x)
434: needwrite = 1;
435: }
436: if (needwrite && !neederase) {
437: /*
438: * we don't need to erase. all the bytes being
439: * written (thankfully) set bits.
440: */
441: for (i = 0; i < c; i++) {
442: if (cmpbuf[i] == sc->sc_vaddr[v + i])
443: continue;
444: r = flashwritebyte(sc, v + i, cmpbuf[i]);
445: if (r == 0)
446: continue;
447: /*
448: * this doesn't make sense. we
449: * thought we didn't need to erase,
450: * but a write failed. let's try an
451: * erase operation..
452: */
453: printf("%s: failed write at %d, trying erase\n",
454: sc->sc_dev.dv_xname, i);
455: goto tryerase;
456: }
457: } else if (neederase) {
458: u_char *mem;
459:
460: tryerase:
461: mem = flashsavezone(sc, zonestart);
462: for (i = 0; i < c; i++)
463: mem[zoneoff + i] = cmpbuf[i];
464: flasherasezone(sc, zonestart);
465: r = flashwritezone(sc, mem, zonestart);
466: if (r) {
467: printf("%s: failed at offset %x\n",
468: sc->sc_dev.dv_xname, r);
469: free(mem, M_TEMP);
470: error = EIO;
471: }
472: }
473: }
474:
475: free(cmpbuf, M_TEMP);
476: return (error);
477: }
478:
479: paddr_t
480: flashmmap(dev, off, prot)
481: dev_t dev;
482: off_t off;
483: int prot;
484: {
485: int unit = minor(dev);
486: struct flashsoftc *sc = (struct flashsoftc *) flash_cd.cd_devs[unit];
487:
488: /* allow access only in RAM */
489: if (off < 0 || off > sc->sc_len)
490: return (-1);
491: return (atop(sc->sc_paddr + off));
492: }
CVSweb