[BACK]Return to gscsio.c CVS log [TXT][DIR] Up to [local] / sys / dev / isa

Annotation of sys/dev/isa/gscsio.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: gscsio.c,v 1.9 2007/06/05 08:37:20 jsg Exp $  */
        !             2: /*
        !             3:  * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17:
        !            18: /*
        !            19:  * National Semiconductor Geode SC1100 Super I/O.
        !            20:  * Only ACCESS.bus logical device is supported.
        !            21:  */
        !            22:
        !            23: #include <sys/param.h>
        !            24: #include <sys/systm.h>
        !            25: #include <sys/device.h>
        !            26: #include <sys/kernel.h>
        !            27: #include <sys/rwlock.h>
        !            28: #include <sys/proc.h>
        !            29:
        !            30: #include <machine/bus.h>
        !            31:
        !            32: #include <dev/i2c/i2cvar.h>
        !            33:
        !            34: #include <dev/isa/isareg.h>
        !            35: #include <dev/isa/isavar.h>
        !            36:
        !            37: #include <dev/isa/gscsioreg.h>
        !            38:
        !            39: struct gscsio_softc {
        !            40:        struct device sc_dev;
        !            41:
        !            42:        bus_space_tag_t sc_iot;
        !            43:        bus_space_handle_t sc_ioh;
        !            44:
        !            45:        int sc_ld_en[GSCSIO_LDNUM];
        !            46:        bus_space_handle_t sc_ld_ioh0[GSCSIO_LDNUM];
        !            47:        bus_space_handle_t sc_ld_ioh1[GSCSIO_LDNUM];
        !            48:
        !            49:        /* ACCESS.bus */
        !            50:        struct gscsio_acb {
        !            51:                void *sc;
        !            52:                bus_space_handle_t ioh;
        !            53:                struct rwlock buslock;
        !            54:        } sc_acb[2];
        !            55:        struct i2c_controller sc_acb1_tag;
        !            56:        struct i2c_controller sc_acb2_tag;
        !            57: };
        !            58:
        !            59: /* Supported logical devices description */
        !            60: static const struct {
        !            61:        const char *ld_name;
        !            62:        int ld_num;
        !            63:        int ld_iosize0;
        !            64:        int ld_iosize1;
        !            65: } gscsio_ld[] = {
        !            66:        { "ACB1", GSCSIO_LDN_ACB1, 6, 0 },
        !            67:        { "ACB2", GSCSIO_LDN_ACB2, 6, 0 },
        !            68: };
        !            69:
        !            70: int    gscsio_probe(struct device *, void *, void *);
        !            71: void   gscsio_attach(struct device *, struct device *, void *);
        !            72:
        !            73: void   gscsio_acb_init(struct gscsio_acb *, i2c_tag_t);
        !            74: int    gscsio_acb_wait(struct gscsio_acb *, int, int);
        !            75: void   gscsio_acb_reset(struct gscsio_acb *acb);
        !            76:
        !            77: int    gscsio_acb_acquire_bus(void *, int);
        !            78: void   gscsio_acb_release_bus(void *, int);
        !            79: int    gscsio_acb_send_start(void *, int);
        !            80: int    gscsio_acb_send_stop(void *, int);
        !            81: int    gscsio_acb_initiate_xfer(void *, uint16_t, int);
        !            82: int    gscsio_acb_read_byte(void *, uint8_t *, int);
        !            83: int    gscsio_acb_write_byte(void *, uint8_t, int);
        !            84:
        !            85: struct cfattach gscsio_ca = {
        !            86:        sizeof(struct gscsio_softc),
        !            87:        gscsio_probe,
        !            88:        gscsio_attach
        !            89: };
        !            90:
        !            91: struct cfdriver gscsio_cd = {
        !            92:        NULL, "gscsio", DV_DULL
        !            93: };
        !            94:
        !            95: #define ACB_READ(reg) \
        !            96:        bus_space_read_1(sc->sc_iot, acb->ioh, (reg))
        !            97: #define ACB_WRITE(reg, val) \
        !            98:        bus_space_write_1(sc->sc_iot, acb->ioh, (reg), (val))
        !            99:
        !           100: static __inline u_int8_t
        !           101: idxread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx)
        !           102: {
        !           103:        bus_space_write_1(iot, ioh, GSCSIO_IDX, idx);
        !           104:
        !           105:        return (bus_space_read_1(iot, ioh, GSCSIO_DAT));
        !           106: }
        !           107:
        !           108: static __inline void
        !           109: idxwrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, u_int8_t data)
        !           110: {
        !           111:        bus_space_write_1(iot, ioh, GSCSIO_IDX, idx);
        !           112:        bus_space_write_1(iot, ioh, GSCSIO_DAT, data);
        !           113: }
        !           114:
        !           115: int
        !           116: gscsio_probe(struct device *parent, void *match, void *aux)
        !           117: {
        !           118:        struct isa_attach_args *ia = aux;
        !           119:        bus_space_tag_t iot;
        !           120:        bus_space_handle_t ioh;
        !           121:        int iobase;
        !           122:        int rv = 0;
        !           123:
        !           124:        iot = ia->ia_iot;
        !           125:        iobase = ia->ipa_io[0].base;
        !           126:        if (bus_space_map(iot, iobase, GSCSIO_IOSIZE, 0, &ioh))
        !           127:                return (0);
        !           128:        if (idxread(iot, ioh, GSCSIO_ID) == GSCSIO_ID_SC1100)
        !           129:                rv = 1;
        !           130:        bus_space_unmap(iot, ioh, GSCSIO_IOSIZE);
        !           131:
        !           132:        if (rv) {
        !           133:                ia->ipa_nio = 1;
        !           134:                ia->ipa_io[0].length = GSCSIO_IOSIZE;
        !           135:                ia->ipa_nmem = 0;
        !           136:                ia->ipa_nirq = 0;
        !           137:                ia->ipa_ndrq = 0;
        !           138:        }
        !           139:
        !           140:        return (rv);
        !           141: }
        !           142:
        !           143: void
        !           144: gscsio_attach(struct device *parent, struct device *self, void *aux)
        !           145: {
        !           146:        struct gscsio_softc *sc = (void *)self;
        !           147:        struct isa_attach_args *ia = aux;
        !           148:        int i;
        !           149:        int iobase;
        !           150:
        !           151:        sc->sc_iot = ia->ia_iot;
        !           152:        if (bus_space_map(sc->sc_iot, ia->ipa_io[0].base, GSCSIO_IOSIZE,
        !           153:            0, &sc->sc_ioh)) {
        !           154:                printf(": can't map I/O space\n");
        !           155:                return;
        !           156:        }
        !           157:        printf(": SC1100 SIO rev %d:",
        !           158:            idxread(sc->sc_iot, sc->sc_ioh, GSCSIO_REV));
        !           159:
        !           160:        /* Configure all supported logical devices */
        !           161:        for (i = 0; i < sizeof (gscsio_ld) / sizeof(gscsio_ld[0]); i++) {
        !           162:                sc->sc_ld_en[gscsio_ld[i].ld_num] = 0;
        !           163:
        !           164:                /* Select the device and check if it's activated */
        !           165:                idxwrite(sc->sc_iot, sc->sc_ioh, GSCSIO_LDN,
        !           166:                    gscsio_ld[i].ld_num);
        !           167:                if ((idxread(sc->sc_iot, sc->sc_ioh, GSCSIO_ACT) &
        !           168:                    GSCSIO_ACT_EN) == 0)
        !           169:                        continue;
        !           170:
        !           171:                /* Map I/O space 0 if necessary */
        !           172:                if (gscsio_ld[i].ld_iosize0 != 0) {
        !           173:                        iobase = idxread(sc->sc_iot, sc->sc_ioh,
        !           174:                            GSCSIO_IO0_MSB);
        !           175:                        iobase <<= 8;
        !           176:                        iobase |= idxread(sc->sc_iot, sc->sc_ioh,
        !           177:                            GSCSIO_IO0_LSB);
        !           178:                        if (bus_space_map(sc->sc_iot, iobase,
        !           179:                            gscsio_ld[i].ld_iosize0, 0,
        !           180:                            &sc->sc_ld_ioh0[gscsio_ld[i].ld_num]))
        !           181:                                continue;
        !           182:                }
        !           183:
        !           184:                /* Map I/O space 1 if necessary */
        !           185:                if (gscsio_ld[i].ld_iosize1 != 0) {
        !           186:                        iobase = idxread(sc->sc_iot, sc->sc_ioh,
        !           187:                            GSCSIO_IO1_MSB);
        !           188:                        iobase <<= 8;
        !           189:                        iobase |= idxread(sc->sc_iot, sc->sc_ioh,
        !           190:                            GSCSIO_IO1_LSB);
        !           191:                        if (bus_space_map(sc->sc_iot, iobase,
        !           192:                            gscsio_ld[i].ld_iosize1, 0,
        !           193:                            &sc->sc_ld_ioh0[gscsio_ld[i].ld_num])) {
        !           194:                                bus_space_unmap(sc->sc_iot,
        !           195:                                    sc->sc_ld_ioh0[gscsio_ld[i].ld_num],
        !           196:                                    gscsio_ld[i].ld_iosize0);
        !           197:                                continue;
        !           198:                        }
        !           199:                }
        !           200:
        !           201:                sc->sc_ld_en[gscsio_ld[i].ld_num] = 1;
        !           202:                printf(" %s", gscsio_ld[i].ld_name);
        !           203:        }
        !           204:        printf("\n");
        !           205:
        !           206:        /* Initialize ACCESS.bus 1 */
        !           207:        if (sc->sc_ld_en[GSCSIO_LDN_ACB1]) {
        !           208:                sc->sc_acb[0].sc = sc;
        !           209:                sc->sc_acb[0].ioh = sc->sc_ld_ioh0[GSCSIO_LDN_ACB1];
        !           210:                rw_init(&sc->sc_acb[0].buslock, "iiclk");
        !           211:                gscsio_acb_init(&sc->sc_acb[0], &sc->sc_acb1_tag);
        !           212:        }
        !           213:
        !           214:        /* Initialize ACCESS.bus 2 */
        !           215:        if (sc->sc_ld_en[GSCSIO_LDN_ACB2]) {
        !           216:                sc->sc_acb[1].sc = sc;
        !           217:                sc->sc_acb[1].ioh = sc->sc_ld_ioh0[GSCSIO_LDN_ACB2];
        !           218:                rw_init(&sc->sc_acb[1].buslock, "iiclk");
        !           219:                gscsio_acb_init(&sc->sc_acb[1], &sc->sc_acb2_tag);
        !           220:        }
        !           221: }
        !           222:
        !           223: void
        !           224: gscsio_acb_init(struct gscsio_acb *acb, i2c_tag_t tag)
        !           225: {
        !           226:        struct gscsio_softc *sc = acb->sc;
        !           227:        struct i2cbus_attach_args iba;
        !           228:
        !           229:        /* Enable ACB and configure clock frequency */
        !           230:        ACB_WRITE(GSCSIO_ACB_CTL2, GSCSIO_ACB_CTL2_EN |
        !           231:            (GSCSIO_ACB_FREQ << GSCSIO_ACB_CTL2_FREQ_SHIFT));
        !           232:
        !           233:        /* Select polling mode */
        !           234:        ACB_WRITE(GSCSIO_ACB_CTL1, ACB_READ(GSCSIO_ACB_CTL1) &
        !           235:            ~GSCSIO_ACB_CTL1_INTEN);
        !           236:
        !           237:        /* Disable slave address */
        !           238:        ACB_WRITE(GSCSIO_ACB_ADDR, ACB_READ(GSCSIO_ACB_ADDR) &
        !           239:            ~GSCSIO_ACB_ADDR_SAEN);
        !           240:
        !           241:        /* Attach I2C framework */
        !           242:        tag->ic_cookie = acb;
        !           243:        tag->ic_acquire_bus = gscsio_acb_acquire_bus;
        !           244:        tag->ic_release_bus = gscsio_acb_release_bus;
        !           245:        tag->ic_send_start = gscsio_acb_send_start;
        !           246:        tag->ic_send_stop = gscsio_acb_send_stop;
        !           247:        tag->ic_initiate_xfer = gscsio_acb_initiate_xfer;
        !           248:        tag->ic_read_byte = gscsio_acb_read_byte;
        !           249:        tag->ic_write_byte = gscsio_acb_write_byte;
        !           250:
        !           251:        bzero(&iba, sizeof(iba));
        !           252:        iba.iba_name = "iic";
        !           253:        iba.iba_tag = tag;
        !           254:        config_found(&sc->sc_dev, &iba, iicbus_print);
        !           255: }
        !           256:
        !           257: int
        !           258: gscsio_acb_wait(struct gscsio_acb *acb, int bits, int flags)
        !           259: {
        !           260:        struct gscsio_softc *sc = acb->sc;
        !           261:        u_int8_t st;
        !           262:        int i;
        !           263:
        !           264:        for (i = 0; i < 100; i++) {
        !           265:                st = ACB_READ(GSCSIO_ACB_ST);
        !           266:                if (st & GSCSIO_ACB_ST_BER) {
        !           267:                        printf("%s: bus error, flags=0x%x\n",
        !           268:                            sc->sc_dev.dv_xname, flags);
        !           269:                        gscsio_acb_reset(acb);
        !           270:                        return (EIO);
        !           271:                }
        !           272:                if (st & GSCSIO_ACB_ST_NEGACK) {
        !           273: #if 0
        !           274:                        printf("%s: negative ack, flags=0x%x\n",
        !           275:                            sc->sc_dev.dv_xname, flags);
        !           276: #endif
        !           277:                        gscsio_acb_reset(acb);
        !           278:                        return (EIO);
        !           279:                }
        !           280:                if ((st & bits) == bits)
        !           281:                        break;
        !           282:                delay(10);
        !           283:        }
        !           284:        if ((st & bits) != bits) {
        !           285:                printf("%s: timeout, flags=0x%x\n",
        !           286:                    sc->sc_dev.dv_xname, flags);
        !           287:                gscsio_acb_reset(acb);
        !           288:                return (ETIMEDOUT);
        !           289:        }
        !           290:
        !           291:        return (0);
        !           292: }
        !           293:
        !           294: void
        !           295: gscsio_acb_reset(struct gscsio_acb *acb)
        !           296: {
        !           297:        struct gscsio_softc *sc = acb->sc;
        !           298:        u_int8_t st, ctl;
        !           299:
        !           300:        /* Clear MASTER, NEGACK and BER */
        !           301:        st = ACB_READ(GSCSIO_ACB_ST);
        !           302:        st |= GSCSIO_ACB_ST_MASTER | GSCSIO_ACB_ST_NEGACK | GSCSIO_ACB_ST_BER;
        !           303:        ACB_WRITE(GSCSIO_ACB_ST, st);
        !           304:
        !           305:        /* Disable and re-enable ACB */
        !           306:        ACB_WRITE(GSCSIO_ACB_CTL2, 0);
        !           307:        ACB_WRITE(GSCSIO_ACB_CTL2, GSCSIO_ACB_CTL2_EN |
        !           308:            (GSCSIO_ACB_FREQ << GSCSIO_ACB_CTL2_FREQ_SHIFT));
        !           309:
        !           310:        /* Send stop */
        !           311:        ctl = ACB_READ(GSCSIO_ACB_CTL1);
        !           312:        ctl |= GSCSIO_ACB_CTL1_STOP;
        !           313:        ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
        !           314: }
        !           315:
        !           316: int
        !           317: gscsio_acb_acquire_bus(void *cookie, int flags)
        !           318: {
        !           319:        struct gscsio_acb *acb = cookie;
        !           320:
        !           321:        if (cold || flags & I2C_F_POLL)
        !           322:                return (0);
        !           323:
        !           324:        return (rw_enter(&acb->buslock, RW_WRITE | RW_INTR));
        !           325: }
        !           326:
        !           327: void
        !           328: gscsio_acb_release_bus(void *cookie, int flags)
        !           329: {
        !           330:        struct gscsio_acb *acb = cookie;
        !           331:
        !           332:        if (cold || flags & I2C_F_POLL)
        !           333:                return;
        !           334:
        !           335:        rw_exit(&acb->buslock);
        !           336: }
        !           337:
        !           338: int
        !           339: gscsio_acb_send_start(void *cookie, int flags)
        !           340: {
        !           341:        struct gscsio_acb *acb = cookie;
        !           342:        struct gscsio_softc *sc = acb->sc;
        !           343:        u_int8_t ctl;
        !           344:
        !           345:        ctl = ACB_READ(GSCSIO_ACB_CTL1);
        !           346:        ctl |= GSCSIO_ACB_CTL1_START;
        !           347:        ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
        !           348:
        !           349:        return (0);
        !           350: }
        !           351:
        !           352: int
        !           353: gscsio_acb_send_stop(void *cookie, int flags)
        !           354: {
        !           355:        struct gscsio_acb *acb = cookie;
        !           356:        struct gscsio_softc *sc = acb->sc;
        !           357:        u_int8_t ctl;
        !           358:
        !           359:        ctl = ACB_READ(GSCSIO_ACB_CTL1);
        !           360:        ctl |= GSCSIO_ACB_CTL1_STOP;
        !           361:        ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
        !           362:
        !           363:        return (0);
        !           364: }
        !           365:
        !           366: int
        !           367: gscsio_acb_initiate_xfer(void *cookie, uint16_t addr, int flags)
        !           368: {
        !           369:        struct gscsio_acb *acb = cookie;
        !           370:        struct gscsio_softc *sc = acb->sc;
        !           371:        u_int8_t ctl;
        !           372:        int dir;
        !           373:        int error;
        !           374:
        !           375:        /* Issue start condition */
        !           376:        ctl = ACB_READ(GSCSIO_ACB_CTL1);
        !           377:        ctl |= GSCSIO_ACB_CTL1_START;
        !           378:        ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
        !           379:
        !           380:        /* Wait for bus mastership */
        !           381:        if ((error = gscsio_acb_wait(acb,
        !           382:            GSCSIO_ACB_ST_MASTER | GSCSIO_ACB_ST_SDAST, flags)))
        !           383:                return (error);
        !           384:
        !           385:        /* Send address byte */
        !           386:        dir = (flags & I2C_F_READ ? 1 : 0);
        !           387:        ACB_WRITE(GSCSIO_ACB_SDA, (addr << 1) | dir);
        !           388:
        !           389:        return (0);
        !           390: }
        !           391:
        !           392: int
        !           393: gscsio_acb_read_byte(void *cookie, uint8_t *bytep, int flags)
        !           394: {
        !           395:        struct gscsio_acb *acb = cookie;
        !           396:        struct gscsio_softc *sc = acb->sc;
        !           397:        u_int8_t ctl;
        !           398:        int error;
        !           399:
        !           400:        /* Wait for the bus to be ready */
        !           401:        if ((error = gscsio_acb_wait(acb, GSCSIO_ACB_ST_SDAST, flags)))
        !           402:                return (error);
        !           403:
        !           404:        /* Acknowledge the last byte */
        !           405:        if (flags & I2C_F_LAST) {
        !           406:                ctl = ACB_READ(GSCSIO_ACB_CTL1);
        !           407:                ctl |= GSCSIO_ACB_CTL1_ACK;
        !           408:                ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
        !           409:        }
        !           410:
        !           411:        /* Read data byte */
        !           412:        *bytep = ACB_READ(GSCSIO_ACB_SDA);
        !           413:
        !           414:        return (0);
        !           415: }
        !           416:
        !           417: int
        !           418: gscsio_acb_write_byte(void *cookie, uint8_t byte, int flags)
        !           419: {
        !           420:        struct gscsio_acb *acb = cookie;
        !           421:        struct gscsio_softc *sc = acb->sc;
        !           422:        u_int8_t ctl;
        !           423:        int error;
        !           424:
        !           425:        /* Wait for the bus to be ready */
        !           426:        if ((error = gscsio_acb_wait(acb, GSCSIO_ACB_ST_SDAST, flags)))
        !           427:                return (error);
        !           428:
        !           429:        /* Send stop after the last byte */
        !           430:        if (flags & I2C_F_STOP) {
        !           431:                ctl = ACB_READ(GSCSIO_ACB_CTL1);
        !           432:                ctl |= GSCSIO_ACB_CTL1_STOP;
        !           433:                ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
        !           434:        }
        !           435:
        !           436:        /* Write data byte */
        !           437:        ACB_WRITE(GSCSIO_ACB_SDA, byte);
        !           438:
        !           439:        return (0);
        !           440: }

CVSweb