[BACK]Return to flash.c CVS log [TXT][DIR] Up to [local] / sys / arch / mvme68k / dev

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