[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

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