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

Annotation of sys/dev/pci/alipm.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: alipm.c,v 1.13 2007/05/03 12:19:01 dlg Exp $  */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2005 Mark Kettenis
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: #include <sys/param.h>
        !            20: #include <sys/device.h>
        !            21: #include <sys/kernel.h>
        !            22: #include <sys/rwlock.h>
        !            23: #include <sys/proc.h>
        !            24: #include <sys/systm.h>
        !            25:
        !            26: #include <dev/i2c/i2cvar.h>
        !            27:
        !            28: #include <dev/pci/pcidevs.h>
        !            29: #include <dev/pci/pcireg.h>
        !            30: #include <dev/pci/pcivar.h>
        !            31:
        !            32: #ifdef __sparc64__
        !            33: #include <arch/sparc64/dev/ofwi2cvar.h>
        !            34: #endif
        !            35:
        !            36: /*
        !            37:  * Acer Labs M7101 Power register definitions.
        !            38:  */
        !            39:
        !            40: /* PCI configuration registers. */
        !            41: #define ALIPM_CONF     0xd0            /* general configuration */
        !            42: #define ALIPM_CONF_SMBEN       0x0400          /* enable SMBus */
        !            43: #define ALIPM_BASE     0xe0            /* ACPI and SMBus base address */
        !            44: #define ALIPM_SMB_HOSTC        0xf0            /* host configuration */
        !            45: #define ALIPM_SMB_HOSTC_HSTEN  0x00000001      /* enable host controller */
        !            46: #define ALIPM_SMB_HOSTC_CLOCK  0x00e00000      /* clock speed */
        !            47: #define ALIPM_SMB_HOSTC_149K   0x00000000      /* 149 KHz clock */
        !            48: #define ALIPM_SMB_HOSTC_74K    0x00200000      /*  74 KHz clock */
        !            49: #define ALIPM_SMB_HOSTC_37K    0x00400000      /*  37 KHz clock */
        !            50: #define ALIPM_SMB_HOSTC_223K   0x00800000      /* 223 KHz clock */
        !            51: #define ALIPM_SMB_HOSTC_111K   0x00a00000      /* 111 KHz clock */
        !            52: #define ALIPM_SMB_HOSTC_55K    0x00c00000      /*  55 KHz clock */
        !            53:
        !            54: #define ALIPM_SMB_SIZE         32      /* SMBus I/O space size */
        !            55:
        !            56: /* SMBus I/O registers */
        !            57: #define ALIPM_SMB_HS   0x00            /* host status */
        !            58: #define ALIPM_SMB_HS_IDLE      0x04
        !            59: #define ALIPM_SMB_HS_BUSY      0x08    /* running a command */
        !            60: #define ALIPM_SMB_HS_DONE      0x10    /* command completed */
        !            61: #define ALIPM_SMB_HS_DEVERR    0x20    /* command error */
        !            62: #define ALIPM_SMB_HS_BUSERR    0x40    /* transaction collision */
        !            63: #define ALIPM_SMB_HS_FAILED    0x80    /* failed bus transaction */
        !            64: #define ALIPM_SMB_HS_BITS \
        !            65:   "\020\003IDLE\004BUSY\005DONE\006DEVERR\007BUSERR\010FAILED"
        !            66: #define ALIPM_SMB_HC   0x01            /* host control */
        !            67: #define ALIPM_SMB_HC_KILL      0x04            /* kill command */
        !            68: #define ALIPM_SMB_HC_RESET     0x08            /* reset bus */
        !            69: #define ALIPM_SMB_HC_CMD_QUICK 0x00            /* QUICK command */
        !            70: #define ALIPM_SMB_HC_CMD_BYTE  0x10            /* BYTE command */
        !            71: #define ALIPM_SMB_HC_CMD_BDATA 0x20            /* BYTE DATA command */
        !            72: #define ALIPM_SMB_HC_CMD_WDATA 0x30            /* WORD DATA command */
        !            73: #define ALIPM_SMB_HC_CMD_BLOCK 0x40            /* BLOCK command */
        !            74: #define ALIPM_SMB_START                0x02    /* start command */
        !            75: #define ALIPM_SMB_TXSLVA       0x03    /* transmit slave address */
        !            76: #define ALIPM_SMB_TXSLVA_READ  (1 << 0)        /* read direction */
        !            77: #define ALIPM_SMB_TXSLVA_ADDR(x) (((x) & 0x7f) << 1) /* 7-bit address */
        !            78: #define ALIPM_SMB_HD0          0x04    /* host data 0 */
        !            79: #define ALIPM_SMB_HD1          0x05    /* host data 1 */
        !            80: #define ALIPM_SMB_HBDB         0x06    /* host block data byte */
        !            81: #define ALIPM_SMB_HCMD         0x07    /* host command */
        !            82:
        !            83: /*
        !            84:  * Newer chips have a more standard, but different PCI configuration
        !            85:  * register layout.
        !            86:  */
        !            87:
        !            88: #define ALIPM_SMB_BASE 0x14            /* SMBus base address */
        !            89: #define ALIPM_SMB_HOSTX        0xe0            /* host configuration */
        !            90:
        !            91: #ifdef ALIPM_DEBUG
        !            92: #define DPRINTF(x) printf x
        !            93: #else
        !            94: #define DPRINTF(x)
        !            95: #endif
        !            96:
        !            97: #define ALIPM_DELAY    100
        !            98: #define ALIPM_TIMEOUT  1
        !            99:
        !           100: struct alipm_softc {
        !           101:        struct device sc_dev;
        !           102:
        !           103:        bus_space_tag_t sc_iot;
        !           104:        bus_space_handle_t sc_ioh;
        !           105:
        !           106:        struct i2c_controller sc_smb_tag;
        !           107:        struct rwlock sc_smb_lock;
        !           108: };
        !           109:
        !           110: int    alipm_match(struct device *, void *, void *);
        !           111: void   alipm_attach(struct device *, struct device *, void *);
        !           112:
        !           113: int    alipm_smb_acquire_bus(void *, int);
        !           114: void   alipm_smb_release_bus(void *, int);
        !           115: int    alipm_smb_exec(void *, i2c_op_t, i2c_addr_t, const void *,
        !           116:            size_t, void *, size_t, int);
        !           117:
        !           118: struct cfattach alipm_ca = {
        !           119:        sizeof(struct alipm_softc),
        !           120:        alipm_match,
        !           121:        alipm_attach
        !           122: };
        !           123:
        !           124: struct cfdriver alipm_cd = {
        !           125:        NULL, "alipm", DV_DULL
        !           126: };
        !           127:
        !           128: int
        !           129: alipm_match(struct device *parent, void *match, void *aux)
        !           130: {
        !           131:        struct pci_attach_args *pa = aux;
        !           132:
        !           133:        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI &&
        !           134:            (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALI_M7101))
        !           135:                return (1);
        !           136:        return (0);
        !           137: }
        !           138:
        !           139: void
        !           140: alipm_attach(struct device *parent, struct device *self, void *aux)
        !           141: {
        !           142:        struct alipm_softc *sc = (struct alipm_softc *) self;
        !           143:        struct pci_attach_args *pa = aux;
        !           144:        struct i2cbus_attach_args iba;
        !           145:        pcireg_t iobase, reg;
        !           146:        bus_size_t iosize = ALIPM_SMB_SIZE;
        !           147:
        !           148:        /* Old chips don't have the PCI 2.2 Capabilities List. */
        !           149:        reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
        !           150:        if ((reg & PCI_STATUS_CAPLIST_SUPPORT) == 0) {
        !           151:                /* Map I/O space */
        !           152:                iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, ALIPM_BASE);
        !           153:                sc->sc_iot = pa->pa_iot;
        !           154:                if (iobase == 0 ||
        !           155:                    bus_space_map(sc->sc_iot, iobase >> 16,
        !           156:                    iosize, 0, &sc->sc_ioh)) {
        !           157:                        printf(": can't map I/O space\n");
        !           158:                        return;
        !           159:                }
        !           160:
        !           161:                reg = pci_conf_read(pa->pa_pc, pa->pa_tag, ALIPM_CONF);
        !           162:                if ((reg & ALIPM_CONF_SMBEN) == 0) {
        !           163:                        printf(": SMBus disabled\n");
        !           164:                        goto fail;
        !           165:                }
        !           166:
        !           167:                reg = pci_conf_read(pa->pa_pc, pa->pa_tag, ALIPM_SMB_HOSTC);
        !           168:                if ((reg & ALIPM_SMB_HOSTC_HSTEN) == 0) {
        !           169:                        printf(": SMBus host disabled\n");
        !           170:                        goto fail;
        !           171:                }
        !           172:        } else {
        !           173:                /* Map I/O space */
        !           174:                if (pci_mapreg_map(pa, ALIPM_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
        !           175:                    &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, ALIPM_SMB_SIZE)) {
        !           176:                        printf(": can't map I/O space\n");
        !           177:                        return;
        !           178:                }
        !           179:
        !           180:                reg = pci_conf_read(pa->pa_pc, pa->pa_tag, ALIPM_SMB_HOSTX);
        !           181:                if ((reg & ALIPM_SMB_HOSTC_HSTEN) == 0) {
        !           182:                        printf(": SMBus host disabled\n");
        !           183:                        goto fail;
        !           184:                }
        !           185:        }
        !           186:
        !           187:        switch (reg & ALIPM_SMB_HOSTC_CLOCK) {
        !           188:        case ALIPM_SMB_HOSTC_149K:
        !           189:                printf(": 149KHz clock");
        !           190:                break;
        !           191:        case ALIPM_SMB_HOSTC_74K:
        !           192:                printf(": 74KHz clock");
        !           193:                break;
        !           194:        case ALIPM_SMB_HOSTC_37K:
        !           195:                printf(": 37KHz clock");
        !           196:                break;
        !           197:        case ALIPM_SMB_HOSTC_223K:
        !           198:                printf(": 223KHz clock");
        !           199:                break;
        !           200:        case ALIPM_SMB_HOSTC_111K:
        !           201:                printf(": 111KHz clock");
        !           202:                break;
        !           203:        case ALIPM_SMB_HOSTC_55K:
        !           204:                printf(": 55KHz clock");
        !           205:                break;
        !           206:        default:
        !           207:                printf(" unknown clock speed");
        !           208:                break;
        !           209:        }
        !           210:
        !           211:        printf("\n");
        !           212:
        !           213:        /* Attach I2C bus */
        !           214:        rw_init(&sc->sc_smb_lock, "alipm");
        !           215:        sc->sc_smb_tag.ic_cookie = sc;
        !           216:        sc->sc_smb_tag.ic_acquire_bus = alipm_smb_acquire_bus;
        !           217:        sc->sc_smb_tag.ic_release_bus = alipm_smb_release_bus;
        !           218:        sc->sc_smb_tag.ic_exec = alipm_smb_exec;
        !           219:
        !           220:        bzero(&iba, sizeof iba);
        !           221:        iba.iba_name = "iic";
        !           222:        iba.iba_tag = &sc->sc_smb_tag;
        !           223: #ifdef __sparc64__
        !           224:        iba.iba_bus_scan = ofwiic_pci_scan;
        !           225:        iba.iba_bus_scan_arg = pa;
        !           226: #endif
        !           227:        config_found(&sc->sc_dev, &iba, iicbus_print);
        !           228:
        !           229:        return;
        !           230:
        !           231: fail:
        !           232:        bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
        !           233: }
        !           234:
        !           235: int
        !           236: alipm_smb_acquire_bus(void *cookie, int flags)
        !           237: {
        !           238:        struct alipm_softc *sc = cookie;
        !           239:
        !           240:        if (flags & I2C_F_POLL)
        !           241:                return (0);
        !           242:
        !           243:        return (rw_enter(&sc->sc_smb_lock, RW_WRITE | RW_INTR));
        !           244: }
        !           245:
        !           246: void
        !           247: alipm_smb_release_bus(void *cookie, int flags)
        !           248: {
        !           249:        struct alipm_softc *sc = cookie;
        !           250:
        !           251:        if (flags & I2C_F_POLL)
        !           252:                return;
        !           253:
        !           254:        rw_exit(&sc->sc_smb_lock);
        !           255: }
        !           256:
        !           257: int
        !           258: alipm_smb_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
        !           259:     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
        !           260: {
        !           261:        struct alipm_softc *sc = cookie;
        !           262:        u_int8_t *b;
        !           263:        u_int8_t ctl, st;
        !           264:        int retries, error = 0;
        !           265:
        !           266:        DPRINTF(("%s: exec op %d, addr 0x%x, cmdlen %d, len %d, "
        !           267:            "flags 0x%x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
        !           268:            len, flags));
        !           269:
        !           270:        if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
        !           271:                return (EOPNOTSUPP);
        !           272:
        !           273:        /* Clear status bits */
        !           274:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS,
        !           275:            ALIPM_SMB_HS_DONE | ALIPM_SMB_HS_FAILED |
        !           276:            ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR);
        !           277:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
        !           278:            BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
        !           279:
        !           280:        /* Wait until bus is idle */
        !           281:        for (retries = 1000; retries > 0; retries--) {
        !           282:                st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS);
        !           283:                bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
        !           284:                    BUS_SPACE_BARRIER_READ);
        !           285:                if (st & (ALIPM_SMB_HS_IDLE | ALIPM_SMB_HS_FAILED |
        !           286:                    ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR))
        !           287:                        break;
        !           288:                DELAY(ALIPM_DELAY);
        !           289:        }
        !           290:        if (retries == 0) {
        !           291:                printf("%s: timeout st 0x%b\n", sc->sc_dev.dv_xname,
        !           292:                    st, ALIPM_SMB_HS_BITS);
        !           293:                return (ETIMEDOUT);
        !           294:        }
        !           295:        if (st & (ALIPM_SMB_HS_FAILED |
        !           296:            ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR)) {
        !           297:                printf("%s: error st 0x%b\n", sc->sc_dev.dv_xname,
        !           298:                    st, ALIPM_SMB_HS_BITS);
        !           299:                return (EIO);
        !           300:        }
        !           301:
        !           302:        /* Set slave address and transfer direction. */
        !           303:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_TXSLVA,
        !           304:            ALIPM_SMB_TXSLVA_ADDR(addr) |
        !           305:            (I2C_OP_READ_P(op) ? ALIPM_SMB_TXSLVA_READ : 0));
        !           306:
        !           307:        b = (void *)cmdbuf;
        !           308:        if (cmdlen > 0)
        !           309:                /* Set command byte */
        !           310:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
        !           311:                     ALIPM_SMB_HCMD, b[0]);
        !           312:
        !           313:        if (I2C_OP_WRITE_P(op)) {
        !           314:                /* Write data. */
        !           315:                b = buf;
        !           316:                if (len > 0)
        !           317:                        bus_space_write_1(sc->sc_iot, sc->sc_ioh,
        !           318:                            ALIPM_SMB_HD0, b[0]);
        !           319:                if (len > 1)
        !           320:                        bus_space_write_1(sc->sc_iot, sc->sc_ioh,
        !           321:                            ALIPM_SMB_HD1, b[1]);
        !           322:        }
        !           323:
        !           324:        /* Set SMBus command */
        !           325:        if (len == 0)
        !           326:                ctl = ALIPM_SMB_HC_CMD_BYTE;
        !           327:        else if (len == 1)
        !           328:                ctl = ALIPM_SMB_HC_CMD_BDATA;
        !           329:        else if (len == 2)
        !           330:                ctl = ALIPM_SMB_HC_CMD_WDATA;
        !           331:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HC, ctl);
        !           332:
        !           333:        /* Start transaction */
        !           334:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, ALIPM_SMB_SIZE,
        !           335:            BUS_SPACE_BARRIER_WRITE);
        !           336:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_START, 0xff);
        !           337:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, ALIPM_SMB_SIZE,
        !           338:            BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
        !           339:
        !           340:        /* Poll for completion */
        !           341:        DELAY(ALIPM_DELAY);
        !           342:        for (retries = 1000; retries > 0; retries--) {
        !           343:                st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS);
        !           344:                bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
        !           345:                    BUS_SPACE_BARRIER_READ);
        !           346:                if (st & (ALIPM_SMB_HS_IDLE | ALIPM_SMB_HS_FAILED |
        !           347:                    ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR))
        !           348:                        break;
        !           349:                DELAY(ALIPM_DELAY);
        !           350:        }
        !           351:        if (retries == 0) {
        !           352:                printf("%s: timeout st 0x%b, resetting\n",
        !           353:                    sc->sc_dev.dv_xname, st, ALIPM_SMB_HS_BITS);
        !           354:                bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HC,
        !           355:                    ALIPM_SMB_HC_RESET);
        !           356:                bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, ALIPM_SMB_SIZE,
        !           357:                     BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
        !           358:                st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS);
        !           359:                bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
        !           360:                    BUS_SPACE_BARRIER_READ);
        !           361:                error = ETIMEDOUT;
        !           362:                goto done;
        !           363:        }
        !           364:
        !           365:        if ((st & ALIPM_SMB_HS_DONE) == 0) {
        !           366:                bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HC,
        !           367:                     ALIPM_SMB_HC_KILL);
        !           368:                bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, ALIPM_SMB_SIZE,
        !           369:                     BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
        !           370:                st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS);
        !           371:                bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
        !           372:                    BUS_SPACE_BARRIER_READ);
        !           373:                if ((st & ALIPM_SMB_HS_FAILED) == 0)
        !           374:                        printf("%s: error st 0x%b\n", sc->sc_dev.dv_xname,
        !           375:                            st, ALIPM_SMB_HS_BITS);
        !           376:        }
        !           377:
        !           378:        /* Check for errors */
        !           379:        if (st & (ALIPM_SMB_HS_FAILED |
        !           380:            ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR)) {
        !           381:                error = EIO;
        !           382:                goto done;
        !           383:        }
        !           384:
        !           385:        if (I2C_OP_READ_P(op)) {
        !           386:                /* Read data */
        !           387:                b = buf;
        !           388:                if (len > 0) {
        !           389:                        b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
        !           390:                            ALIPM_SMB_HD0);
        !           391:                        bus_space_barrier(sc->sc_iot, sc->sc_ioh,
        !           392:                            ALIPM_SMB_HD0, 1, BUS_SPACE_BARRIER_READ);
        !           393:                }
        !           394:                if (len > 1) {
        !           395:                        b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
        !           396:                            ALIPM_SMB_HD1);
        !           397:                        bus_space_barrier(sc->sc_iot, sc->sc_ioh,
        !           398:                            ALIPM_SMB_HD1, 1, BUS_SPACE_BARRIER_READ);
        !           399:                }
        !           400:        }
        !           401:
        !           402: done:
        !           403:        /* Clear status bits */
        !           404:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, st);
        !           405:
        !           406:        return (error);
        !           407: }

CVSweb