Annotation of sys/arch/mvme68k/dev/flash.c, Revision 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