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