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