xref: /openbsd-src/sys/dev/pci/piixpm.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: piixpm.c,v 1.39 2013/10/01 20:06:02 sf Exp $	*/
2 
3 /*
4  * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@openbsd.org>
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 /*
20  * Intel PIIX and compatible Power Management controller driver.
21  */
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/kernel.h>
27 #include <sys/rwlock.h>
28 
29 #include <machine/bus.h>
30 
31 #include <dev/pci/pcidevs.h>
32 #include <dev/pci/pcireg.h>
33 #include <dev/pci/pcivar.h>
34 
35 #include <dev/pci/piixreg.h>
36 
37 #include <dev/i2c/i2cvar.h>
38 
39 #ifdef PIIXPM_DEBUG
40 #define DPRINTF(x) printf x
41 #else
42 #define DPRINTF(x)
43 #endif
44 
45 #define PIIXPM_DELAY	200
46 #define PIIXPM_TIMEOUT	1
47 
48 struct piixpm_softc {
49 	struct device		sc_dev;
50 
51 	bus_space_tag_t		sc_iot;
52 	bus_space_handle_t	sc_ioh;
53 	void *			sc_ih;
54 	int			sc_poll;
55 
56 	struct i2c_controller	sc_i2c_tag;
57 	struct rwlock		sc_i2c_lock;
58 	struct {
59 		i2c_op_t     op;
60 		void *       buf;
61 		size_t       len;
62 		int          flags;
63 		volatile int error;
64 	}			sc_i2c_xfer;
65 };
66 
67 int	piixpm_match(struct device *, void *, void *);
68 void	piixpm_attach(struct device *, struct device *, void *);
69 
70 int	piixpm_i2c_acquire_bus(void *, int);
71 void	piixpm_i2c_release_bus(void *, int);
72 int	piixpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
73 	    void *, size_t, int);
74 
75 int	piixpm_intr(void *);
76 
77 struct cfattach piixpm_ca = {
78 	sizeof(struct piixpm_softc),
79 	piixpm_match,
80 	piixpm_attach
81 };
82 
83 struct cfdriver piixpm_cd = {
84 	NULL, "piixpm", DV_DULL
85 };
86 
87 const struct pci_matchid piixpm_ids[] = {
88 	{ PCI_VENDOR_AMD, PCI_PRODUCT_AMD_HUDSON2_SMB },
89 
90 	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB200_SMB },
91 	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB300_SMB },
92 	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB400_SMB },
93 	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SBX00_SMB },
94 
95 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_PM },
96 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_PM },
97 
98 	{ PCI_VENDOR_RCC, PCI_PRODUCT_RCC_CSB5 },
99 	{ PCI_VENDOR_RCC, PCI_PRODUCT_RCC_CSB6 },
100 	{ PCI_VENDOR_RCC, PCI_PRODUCT_RCC_HT_1000 },
101 	{ PCI_VENDOR_RCC, PCI_PRODUCT_RCC_HT_1100 },
102 	{ PCI_VENDOR_RCC, PCI_PRODUCT_RCC_OSB4 },
103 
104 	{ PCI_VENDOR_SMSC, PCI_PRODUCT_SMSC_VICTORY66_PM }
105 };
106 
107 int
108 piixpm_match(struct device *parent, void *match, void *aux)
109 {
110 	return (pci_matchbyid(aux, piixpm_ids,
111 	    sizeof(piixpm_ids) / sizeof(piixpm_ids[0])));
112 }
113 
114 void
115 piixpm_attach(struct device *parent, struct device *self, void *aux)
116 {
117 	struct piixpm_softc *sc = (struct piixpm_softc *)self;
118 	struct pci_attach_args *pa = aux;
119 	bus_space_handle_t ioh;
120 	u_int16_t smb0en;
121 	bus_addr_t base;
122 	pcireg_t conf;
123 	pci_intr_handle_t ih;
124 	const char *intrstr = NULL;
125 	struct i2cbus_attach_args iba;
126 
127 	sc->sc_iot = pa->pa_iot;
128 
129 	if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
130 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_HUDSON2_SMB) ||
131 	    (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI &&
132 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SBX00_SMB &&
133 	    PCI_REVISION(pa->pa_class) >= 0x40)) {
134 		/*
135 		 * On the AMD SB800+, the SMBus I/O registers are well
136 		 * hidden.  We need to look at the "SMBus0En" Power
137 		 * Management register to find out where they live.
138 		 * We use indirect IO access through the index/data
139 		 * pair at 0xcd6/0xcd7 to access "SMBus0En".  Since
140 		 * the index/data pair may be needed by other drivers,
141 		 * we only map them for the duration that we actually
142 		 * need them.
143 		 */
144 		if (bus_space_map(sc->sc_iot, SB800_PMREG_BASE,
145 		    SB800_PMREG_SIZE, 0, &ioh) != 0) {
146 			printf(": can't map i/o space\n");
147 			return;
148 		}
149 
150 		/* Read "SmBus0En" */
151 		bus_space_write_1(sc->sc_iot, ioh, 0, SB800_PMREG_SMB0EN);
152 		smb0en = bus_space_read_1(sc->sc_iot, ioh, 1);
153 		bus_space_write_1(sc->sc_iot, ioh, 0, SB800_PMREG_SMB0EN + 1);
154 		smb0en |= (bus_space_read_1(sc->sc_iot, ioh, 1) << 8);
155 
156 		bus_space_unmap(sc->sc_iot, ioh, SB800_PMREG_SIZE);
157 
158 		if ((smb0en & SB800_SMB0EN_EN) == 0) {
159 			printf(": SMBus disabled\n");
160 			return;
161 		}
162 
163 		/* Map I/O space */
164 		base = smb0en & SB800_SMB0EN_BASE_MASK;
165 		if (base == 0 || bus_space_map(sc->sc_iot, base,
166 		    SB800_SMB_SIZE, 0, &sc->sc_ioh)) {
167 			printf(": can't map i/o space");
168 			return;
169 		}
170 
171 		/* Read configuration */
172 		conf = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SB800_SMB_HOSTC);
173 		if (conf & SB800_SMB_HOSTC_SMI)
174 			conf = PIIX_SMB_HOSTC_SMI;
175 		else
176 			conf = PIIX_SMB_HOSTC_IRQ;
177 	} else {
178 		/* Read configuration */
179 		conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC);
180 		DPRINTF((": conf 0x%08x", conf));
181 
182 		if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) {
183 			printf(": SMBus disabled\n");
184 			return;
185 		}
186 
187 		/* Map I/O space */
188 		base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) &
189 		    PIIX_SMB_BASE_MASK;
190 		if (base == 0 || bus_space_map(sc->sc_iot, base,
191 		    PIIX_SMB_SIZE, 0, &sc->sc_ioh)) {
192 			printf(": can't map i/o space\n");
193 			return;
194 		}
195 	}
196 
197 	sc->sc_poll = 1;
198 	if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_SMI) {
199 		/* No PCI IRQ */
200 		printf(": SMI");
201 	} else {
202 		if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_IRQ) {
203 			/* Install interrupt handler */
204 			if (pci_intr_map(pa, &ih) == 0) {
205 				intrstr = pci_intr_string(pa->pa_pc, ih);
206 				sc->sc_ih = pci_intr_establish(pa->pa_pc,
207 				    ih, IPL_BIO, piixpm_intr, sc,
208 				    sc->sc_dev.dv_xname);
209 				if (sc->sc_ih != NULL) {
210 					printf(": %s", intrstr);
211 					sc->sc_poll = 0;
212 				}
213 			}
214 		}
215 		if (sc->sc_poll)
216 			printf(": polling");
217 	}
218 
219 	printf("\n");
220 
221 	/* Attach I2C bus */
222 	rw_init(&sc->sc_i2c_lock, "iiclk");
223 	sc->sc_i2c_tag.ic_cookie = sc;
224 	sc->sc_i2c_tag.ic_acquire_bus = piixpm_i2c_acquire_bus;
225 	sc->sc_i2c_tag.ic_release_bus = piixpm_i2c_release_bus;
226 	sc->sc_i2c_tag.ic_exec = piixpm_i2c_exec;
227 
228 	bzero(&iba, sizeof(iba));
229 	iba.iba_name = "iic";
230 	iba.iba_tag = &sc->sc_i2c_tag;
231 	config_found(self, &iba, iicbus_print);
232 
233 	return;
234 }
235 
236 int
237 piixpm_i2c_acquire_bus(void *cookie, int flags)
238 {
239 	struct piixpm_softc *sc = cookie;
240 
241 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
242 		return (0);
243 
244 	return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
245 }
246 
247 void
248 piixpm_i2c_release_bus(void *cookie, int flags)
249 {
250 	struct piixpm_softc *sc = cookie;
251 
252 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
253 		return;
254 
255 	rw_exit(&sc->sc_i2c_lock);
256 }
257 
258 int
259 piixpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
260     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
261 {
262 	struct piixpm_softc *sc = cookie;
263 	u_int8_t *b;
264 	u_int8_t ctl, st;
265 	int retries;
266 
267 	DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
268 	    "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
269 	    len, flags));
270 
271 	/* Wait for bus to be idle */
272 	for (retries = 100; retries > 0; retries--) {
273 		st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS);
274 		if (!(st & PIIX_SMB_HS_BUSY))
275 			break;
276 		DELAY(PIIXPM_DELAY);
277 	}
278 	DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
279 	    PIIX_SMB_HS_BITS));
280 	if (st & PIIX_SMB_HS_BUSY)
281 		return (1);
282 
283 	if (cold || sc->sc_poll)
284 		flags |= I2C_F_POLL;
285 
286 	if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
287 		return (1);
288 
289 	/* Setup transfer */
290 	sc->sc_i2c_xfer.op = op;
291 	sc->sc_i2c_xfer.buf = buf;
292 	sc->sc_i2c_xfer.len = len;
293 	sc->sc_i2c_xfer.flags = flags;
294 	sc->sc_i2c_xfer.error = 0;
295 
296 	/* Set slave address and transfer direction */
297 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_TXSLVA,
298 	    PIIX_SMB_TXSLVA_ADDR(addr) |
299 	    (I2C_OP_READ_P(op) ? PIIX_SMB_TXSLVA_READ : 0));
300 
301 	b = (void *)cmdbuf;
302 	if (cmdlen > 0)
303 		/* Set command byte */
304 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HCMD, b[0]);
305 
306 	if (I2C_OP_WRITE_P(op)) {
307 		/* Write data */
308 		b = buf;
309 		if (len > 0)
310 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
311 			    PIIX_SMB_HD0, b[0]);
312 		if (len > 1)
313 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
314 			    PIIX_SMB_HD1, b[1]);
315 	}
316 
317 	/* Set SMBus command */
318 	if (len == 0)
319 		ctl = PIIX_SMB_HC_CMD_BYTE;
320 	else if (len == 1)
321 		ctl = PIIX_SMB_HC_CMD_BDATA;
322 	else if (len == 2)
323 		ctl = PIIX_SMB_HC_CMD_WDATA;
324 	else
325 		panic("%s: unexpected len %zd", __func__, len);
326 
327 	if ((flags & I2C_F_POLL) == 0)
328 		ctl |= PIIX_SMB_HC_INTREN;
329 
330 	/* Start transaction */
331 	ctl |= PIIX_SMB_HC_START;
332 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HC, ctl);
333 
334 	if (flags & I2C_F_POLL) {
335 		/* Poll for completion */
336 		DELAY(PIIXPM_DELAY);
337 		for (retries = 1000; retries > 0; retries--) {
338 			st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
339 			    PIIX_SMB_HS);
340 			if ((st & PIIX_SMB_HS_BUSY) == 0)
341 				break;
342 			DELAY(PIIXPM_DELAY);
343 		}
344 		if (st & PIIX_SMB_HS_BUSY)
345 			goto timeout;
346 		piixpm_intr(sc);
347 	} else {
348 		/* Wait for interrupt */
349 		if (tsleep(sc, PRIBIO, "piixpm", PIIXPM_TIMEOUT * hz))
350 			goto timeout;
351 	}
352 
353 	if (sc->sc_i2c_xfer.error)
354 		return (1);
355 
356 	return (0);
357 
358 timeout:
359 	/*
360 	 * Transfer timeout. Kill the transaction and clear status bits.
361 	 */
362 	printf("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
363 	    "flags 0x%02x: timeout, status 0x%b\n",
364 	    sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags,
365 	    st, PIIX_SMB_HS_BITS);
366 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HC,
367 	    PIIX_SMB_HC_KILL);
368 	DELAY(PIIXPM_DELAY);
369 	st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS);
370 	if ((st & PIIX_SMB_HS_FAILED) == 0)
371 		printf("%s: abort failed, status 0x%b\n",
372 		    sc->sc_dev.dv_xname, st, PIIX_SMB_HS_BITS);
373 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS, st);
374 	return (1);
375 }
376 
377 int
378 piixpm_intr(void *arg)
379 {
380 	struct piixpm_softc *sc = arg;
381 	u_int8_t st;
382 	u_int8_t *b;
383 	size_t len;
384 
385 	/* Read status */
386 	st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS);
387 	if ((st & PIIX_SMB_HS_BUSY) != 0 || (st & (PIIX_SMB_HS_INTR |
388 	    PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |
389 	    PIIX_SMB_HS_FAILED)) == 0)
390 		/* Interrupt was not for us */
391 		return (0);
392 
393 	DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
394 	    PIIX_SMB_HS_BITS));
395 
396 	/* Clear status bits */
397 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS, st);
398 
399 	/* Check for errors */
400 	if (st & (PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |
401 	    PIIX_SMB_HS_FAILED)) {
402 		sc->sc_i2c_xfer.error = 1;
403 		goto done;
404 	}
405 
406 	if (st & PIIX_SMB_HS_INTR) {
407 		if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
408 			goto done;
409 
410 		/* Read data */
411 		b = sc->sc_i2c_xfer.buf;
412 		len = sc->sc_i2c_xfer.len;
413 		if (len > 0)
414 			b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
415 			    PIIX_SMB_HD0);
416 		if (len > 1)
417 			b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
418 			    PIIX_SMB_HD1);
419 	}
420 
421 done:
422 	if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
423 		wakeup(sc);
424 	return (1);
425 }
426