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