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