xref: /openbsd-src/sys/dev/pci/glxpcib.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*      $OpenBSD: glxpcib.c,v 1.5 2012/03/06 12:57:36 mikeb Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
5  * Copyright (c) 2007 Michael Shalayeff
6  * All rights reserved.
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
17  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
18  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 /*
22  * AMD CS5536 series LPC bridge also containing timer, watchdog, and GPIO.
23  */
24 
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/proc.h>
28 #include <sys/device.h>
29 #include <sys/gpio.h>
30 #include <sys/timetc.h>
31 #include <sys/rwlock.h>
32 
33 #include <machine/bus.h>
34 #ifdef __i386__
35 #include <machine/cpufunc.h>
36 #endif
37 
38 #include <dev/gpio/gpiovar.h>
39 #include <dev/i2c/i2cvar.h>
40 
41 #include <dev/pci/pcireg.h>
42 #include <dev/pci/pcivar.h>
43 #include <dev/pci/pcidevs.h>
44 
45 #include <dev/pci/glxreg.h>
46 #include <dev/pci/glxvar.h>
47 
48 #include "gpio.h"
49 
50 #define	AMD5536_REV		GLCP_CHIP_REV_ID
51 #define	AMD5536_REV_MASK	0xff
52 #define	AMD5536_TMC		PMC_LTMR
53 
54 #define	MSR_LBAR_ENABLE		0x100000000ULL
55 
56 /* Multi-Functional General Purpose Timer */
57 #define	MSR_LBAR_MFGPT		DIVIL_LBAR_MFGPT
58 #define	MSR_MFGPT_SIZE		0x40
59 #define	MSR_MFGPT_ADDR_MASK	0xffc0
60 #define	AMD5536_MFGPT0_CMP1	0x00000000
61 #define	AMD5536_MFGPT0_CMP2	0x00000002
62 #define	AMD5536_MFGPT0_CNT	0x00000004
63 #define	AMD5536_MFGPT0_SETUP	0x00000006
64 #define	AMD5536_MFGPT_DIV_MASK	0x000f	/* div = 1 << mask */
65 #define	AMD5536_MFGPT_CLKSEL	0x0010
66 #define	AMD5536_MFGPT_REV_EN	0x0020
67 #define	AMD5536_MFGPT_CMP1DIS	0x0000
68 #define	AMD5536_MFGPT_CMP1EQ	0x0040
69 #define	AMD5536_MFGPT_CMP1GE	0x0080
70 #define	AMD5536_MFGPT_CMP1EV	0x00c0
71 #define	AMD5536_MFGPT_CMP2DIS	0x0000
72 #define	AMD5536_MFGPT_CMP2EQ	0x0100
73 #define	AMD5536_MFGPT_CMP2GE	0x0200
74 #define	AMD5536_MFGPT_CMP2EV	0x0300
75 #define	AMD5536_MFGPT_STOP_EN	0x0800
76 #define	AMD5536_MFGPT_SET	0x1000
77 #define	AMD5536_MFGPT_CMP1	0x2000
78 #define	AMD5536_MFGPT_CMP2	0x4000
79 #define	AMD5536_MFGPT_CNT_EN	0x8000
80 #define	AMD5536_MFGPT_IRQ	MFGPT_IRQ
81 #define	AMD5536_MFGPT0_C1_IRQM	0x00000001
82 #define	AMD5536_MFGPT1_C1_IRQM	0x00000002
83 #define	AMD5536_MFGPT2_C1_IRQM	0x00000004
84 #define	AMD5536_MFGPT3_C1_IRQM	0x00000008
85 #define	AMD5536_MFGPT4_C1_IRQM	0x00000010
86 #define	AMD5536_MFGPT5_C1_IRQM	0x00000020
87 #define	AMD5536_MFGPT6_C1_IRQM	0x00000040
88 #define	AMD5536_MFGPT7_C1_IRQM	0x00000080
89 #define	AMD5536_MFGPT0_C2_IRQM	0x00000100
90 #define	AMD5536_MFGPT1_C2_IRQM	0x00000200
91 #define	AMD5536_MFGPT2_C2_IRQM	0x00000400
92 #define	AMD5536_MFGPT3_C2_IRQM	0x00000800
93 #define	AMD5536_MFGPT4_C2_IRQM	0x00001000
94 #define	AMD5536_MFGPT5_C2_IRQM	0x00002000
95 #define	AMD5536_MFGPT6_C2_IRQM	0x00004000
96 #define	AMD5536_MFGPT7_C2_IRQM	0x00008000
97 #define	AMD5536_MFGPT_NR	MFGPT_NR
98 #define	AMD5536_MFGPT0_C1_NMIM	0x00000001
99 #define	AMD5536_MFGPT1_C1_NMIM	0x00000002
100 #define	AMD5536_MFGPT2_C1_NMIM	0x00000004
101 #define	AMD5536_MFGPT3_C1_NMIM	0x00000008
102 #define	AMD5536_MFGPT4_C1_NMIM	0x00000010
103 #define	AMD5536_MFGPT5_C1_NMIM	0x00000020
104 #define	AMD5536_MFGPT6_C1_NMIM	0x00000040
105 #define	AMD5536_MFGPT7_C1_NMIM	0x00000080
106 #define	AMD5536_MFGPT0_C2_NMIM	0x00000100
107 #define	AMD5536_MFGPT1_C2_NMIM	0x00000200
108 #define	AMD5536_MFGPT2_C2_NMIM	0x00000400
109 #define	AMD5536_MFGPT3_C2_NMIM	0x00000800
110 #define	AMD5536_MFGPT4_C2_NMIM	0x00001000
111 #define	AMD5536_MFGPT5_C2_NMIM	0x00002000
112 #define	AMD5536_MFGPT6_C2_NMIM	0x00004000
113 #define	AMD5536_MFGPT7_C2_NMIM	0x00008000
114 #define	AMD5536_NMI_LEG		0x00010000
115 #define	AMD5536_MFGPT0_C2_RSTEN	0x01000000
116 #define	AMD5536_MFGPT1_C2_RSTEN	0x02000000
117 #define	AMD5536_MFGPT2_C2_RSTEN	0x04000000
118 #define	AMD5536_MFGPT3_C2_RSTEN	0x08000000
119 #define	AMD5536_MFGPT4_C2_RSTEN	0x10000000
120 #define	AMD5536_MFGPT5_C2_RSTEN	0x20000000
121 #define	AMD5536_MFGPT_SETUP	MFGPT_SETUP
122 
123 /* GPIO */
124 #define	MSR_LBAR_GPIO		DIVIL_LBAR_GPIO
125 #define	MSR_GPIO_SIZE		0x100
126 #define	MSR_GPIO_ADDR_MASK	0xff00
127 #define	AMD5536_GPIO_NPINS	32
128 #define	AMD5536_GPIOH_OFFSET	0x80	/* high bank register offset */
129 #define	AMD5536_GPIO_OUT_VAL	0x00	/* output value */
130 #define	AMD5536_GPIO_OUT_EN	0x04	/* output enable */
131 #define	AMD5536_GPIO_OD_EN	0x08	/* open-drain enable */
132 #define AMD5536_GPIO_OUT_INVRT_EN 0x0c	/* invert output */
133 #define	AMD5536_GPIO_PU_EN	0x18	/* pull-up enable */
134 #define	AMD5536_GPIO_PD_EN	0x1c	/* pull-down enable */
135 #define	AMD5536_GPIO_IN_EN	0x20	/* input enable */
136 #define AMD5536_GPIO_IN_INVRT_EN 0x24	/* invert input */
137 #define	AMD5536_GPIO_READ_BACK	0x30	/* read back value */
138 
139 /* SMB */
140 #define MSR_LBAR_SMB		DIVIL_LBAR_SMB
141 #define MSR_SMB_SIZE		0x08
142 #define MSR_SMB_ADDR_MASK	0xfff8
143 #define AMD5536_SMB_SDA		0x00 /* serial data */
144 #define AMD5536_SMB_STS		0x01 /* status */
145 #define AMD5536_SMB_STS_SLVSTOP	0x80 /* slave stop */
146 #define AMD5536_SMB_STS_SDAST	0x40 /* smb data status */
147 #define AMD5536_SMB_STS_BER	0x20 /* bus error */
148 #define AMD5536_SMB_STS_NEGACK	0x10 /* negative acknowledge */
149 #define AMD5536_SMB_STS_STASTR	0x08 /* stall after start */
150 #define AMD5536_SMB_STS_MASTER	0x02 /* master */
151 #define AMD5536_SMB_STS_XMIT	0x01 /* transmit or receive */
152 #define AMD5536_SMB_CST		0x02 /* control status */
153 #define AMD5536_SMB_CST_MATCH	0x04 /* address match */
154 #define AMD5536_SMB_CST_BB	0x02 /* bus busy */
155 #define AMD5536_SMB_CST_BUSY	0x01 /* busy */
156 #define AMD5536_SMB_CTL1	0x03 /* control 1 */
157 #define AMD5536_SMB_CTL1_STASTRE 0x80 /* stall after start enable */
158 #define AMD5536_SMB_CTL1_ACK	0x10 /* receive acknowledge */
159 #define AMD5536_SMB_CTL1_INTEN	0x04 /* interrupt enable  */
160 #define AMD5536_SMB_CTL1_STOP	0x02 /* stop */
161 #define AMD5536_SMB_CTL1_START	0x01 /* start */
162 #define AMD5536_SMB_ADDR	0x04 /* serial address */
163 #define AMD5536_SMB_ADDR_SAEN	0x80 /* slave enable */
164 #define AMD5536_SMB_CTL2	0x05 /* control 2 */
165 #define AMD5536_SMB_CTL2_EN	0x01 /* enable clock */
166 #define AMD5536_SMB_CTL2_FREQ	0x78 /* 100 kHz */
167 #define AMD5536_SMB_CTL3	0x06 /* control 3 */
168 
169 /*
170  * MSR registers we want to preserve accross suspend/resume
171  */
172 const uint32_t glxpcib_msrlist[] = {
173 	GLIU_PAE,
174 	GLCP_GLD_MSR_PM,
175 	DIVIL_BALL_OPTS
176 };
177 
178 struct glxpcib_softc {
179 	struct device		sc_dev;
180 
181 	struct timecounter	sc_timecounter;
182 	bus_space_tag_t		sc_iot;
183 	bus_space_handle_t	sc_ioh;
184 
185 	uint64_t 		sc_msrsave[nitems(glxpcib_msrlist)];
186 
187 #ifndef SMALL_KERNEL
188 #if NGPIO > 0
189 	/* GPIO interface */
190 	bus_space_tag_t		sc_gpio_iot;
191 	bus_space_handle_t	sc_gpio_ioh;
192 	struct gpio_chipset_tag	sc_gpio_gc;
193 	gpio_pin_t		sc_gpio_pins[AMD5536_GPIO_NPINS];
194 #endif
195 	/* I2C interface */
196 	bus_space_tag_t		sc_smb_iot;
197 	bus_space_handle_t	sc_smb_ioh;
198 	struct i2c_controller	sc_smb_ic;
199 	struct rwlock		sc_smb_lck;
200 
201 	/* Watchdog */
202 	int			sc_wdog;
203 	int			sc_wdog_period;
204 #endif
205 };
206 
207 struct cfdriver glxpcib_cd = {
208 	NULL, "glxpcib", DV_DULL
209 };
210 
211 int	glxpcib_match(struct device *, void *, void *);
212 void	glxpcib_attach(struct device *, struct device *, void *);
213 int	glxpcib_activate(struct device *, int);
214 
215 struct cfattach glxpcib_ca = {
216 	sizeof(struct glxpcib_softc), glxpcib_match, glxpcib_attach,
217 	NULL, glxpcib_activate
218 };
219 
220 /* from arch/<*>/pci/pcib.c */
221 void	pcibattach(struct device *parent, struct device *self, void *aux);
222 
223 u_int	glxpcib_get_timecount(struct timecounter *tc);
224 
225 #ifndef SMALL_KERNEL
226 int     glxpcib_wdogctl_cb(void *, int);
227 #if NGPIO > 0
228 void	glxpcib_gpio_pin_ctl(void *, int, int);
229 int	glxpcib_gpio_pin_read(void *, int);
230 void	glxpcib_gpio_pin_write(void *, int, int);
231 #endif
232 int	glxpcib_smb_acquire_bus(void *, int);
233 void	glxpcib_smb_release_bus(void *, int);
234 int	glxpcib_smb_send_start(void *, int);
235 int	glxpcib_smb_send_stop(void *, int);
236 void	glxpcib_smb_send_ack(void *, int);
237 int	glxpcib_smb_initiate_xfer(void *, i2c_addr_t, int);
238 int	glxpcib_smb_read_byte(void *, uint8_t *, int);
239 int	glxpcib_smb_write_byte(void *, uint8_t, int);
240 void	glxpcib_smb_reset(struct glxpcib_softc *);
241 int	glxpcib_smb_wait(struct glxpcib_softc *, int, int);
242 #endif
243 
244 const struct pci_matchid glxpcib_devices[] = {
245 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_CS5536_PCIB }
246 };
247 
248 int
249 glxpcib_match(struct device *parent, void *match, void *aux)
250 {
251 	if (pci_matchbyid((struct pci_attach_args *)aux, glxpcib_devices,
252 	    nitems(glxpcib_devices))) {
253 		/* needs to win over pcib */
254 		return 2;
255 	}
256 
257 	return 0;
258 }
259 
260 void
261 glxpcib_attach(struct device *parent, struct device *self, void *aux)
262 {
263 	struct glxpcib_softc *sc = (struct glxpcib_softc *)self;
264 	struct timecounter *tc = &sc->sc_timecounter;
265 #ifndef SMALL_KERNEL
266 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
267 	u_int64_t wa;
268 #if NGPIO > 0
269 	u_int64_t ga;
270 	struct gpiobus_attach_args gba;
271 	int i, gpio = 0;
272 #endif
273 	u_int64_t sa;
274 	struct i2cbus_attach_args iba;
275 	int i2c = 0;
276 #endif
277 	tc->tc_get_timecount = glxpcib_get_timecount;
278 	tc->tc_counter_mask = 0xffffffff;
279 	tc->tc_frequency = 3579545;
280 	tc->tc_name = "CS5536";
281 #ifdef __loongson__
282 	tc->tc_quality = 0;
283 #else
284 	tc->tc_quality = 1000;
285 #endif
286 	tc->tc_priv = sc;
287 	tc_init(tc);
288 
289 	printf(": rev %d, 32-bit %lluHz timer",
290 	    (int)rdmsr(AMD5536_REV) & AMD5536_REV_MASK,
291 	    tc->tc_frequency);
292 
293 #ifndef SMALL_KERNEL
294 	/* Attach the watchdog timer */
295 	sc->sc_iot = pa->pa_iot;
296 	wa = rdmsr(MSR_LBAR_MFGPT);
297 	if (wa & MSR_LBAR_ENABLE &&
298 	    !bus_space_map(sc->sc_iot, wa & MSR_MFGPT_ADDR_MASK,
299 	    MSR_MFGPT_SIZE, 0, &sc->sc_ioh)) {
300 		/* count in seconds (as upper level desires) */
301 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_SETUP,
302 		    AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2EV |
303 		    AMD5536_MFGPT_CMP2 | AMD5536_MFGPT_DIV_MASK);
304 		wdog_register(sc, glxpcib_wdogctl_cb);
305 		sc->sc_wdog = 1;
306 		printf(", watchdog");
307 	}
308 
309 #if NGPIO > 0
310 	/* map GPIO I/O space */
311 	sc->sc_gpio_iot = pa->pa_iot;
312 	ga = rdmsr(MSR_LBAR_GPIO);
313 	if (ga & MSR_LBAR_ENABLE &&
314 	    !bus_space_map(sc->sc_gpio_iot, ga & MSR_GPIO_ADDR_MASK,
315 	    MSR_GPIO_SIZE, 0, &sc->sc_gpio_ioh)) {
316 		printf(", gpio");
317 
318 		/* initialize pin array */
319 		for (i = 0; i < AMD5536_GPIO_NPINS; i++) {
320 			sc->sc_gpio_pins[i].pin_num = i;
321 			sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
322 			    GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN |
323 			    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN |
324 			    GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
325 
326 			/* read initial state */
327 			sc->sc_gpio_pins[i].pin_state =
328 			    glxpcib_gpio_pin_read(sc, i);
329 		}
330 
331 		/* create controller tag */
332 		sc->sc_gpio_gc.gp_cookie = sc;
333 		sc->sc_gpio_gc.gp_pin_read = glxpcib_gpio_pin_read;
334 		sc->sc_gpio_gc.gp_pin_write = glxpcib_gpio_pin_write;
335 		sc->sc_gpio_gc.gp_pin_ctl = glxpcib_gpio_pin_ctl;
336 
337 		gba.gba_name = "gpio";
338 		gba.gba_gc = &sc->sc_gpio_gc;
339 		gba.gba_pins = sc->sc_gpio_pins;
340 		gba.gba_npins = AMD5536_GPIO_NPINS;
341 		gpio = 1;
342 
343 	}
344 #endif /* NGPIO */
345 
346 	/* Map SMB I/O space */
347 	sc->sc_smb_iot = pa->pa_iot;
348 	sa = rdmsr(MSR_LBAR_SMB);
349 	if (sa & MSR_LBAR_ENABLE &&
350 	    !bus_space_map(sc->sc_smb_iot, sa & MSR_SMB_ADDR_MASK,
351 	    MSR_SMB_SIZE, 0, &sc->sc_smb_ioh)) {
352 		printf(", i2c");
353 
354 		/* Enable controller */
355 		bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
356 		    AMD5536_SMB_CTL2, AMD5536_SMB_CTL2_EN |
357 		    AMD5536_SMB_CTL2_FREQ);
358 
359 		/* Disable interrupts */
360 		bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
361 		    AMD5536_SMB_CTL1, 0);
362 
363 		/* Disable slave address */
364 		bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
365 		    AMD5536_SMB_ADDR, 0);
366 
367 		/* Stall the bus after start */
368 		bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
369 		    AMD5536_SMB_CTL1, AMD5536_SMB_CTL1_STASTRE);
370 
371 		/* Attach I2C framework */
372 		sc->sc_smb_ic.ic_cookie = sc;
373 		sc->sc_smb_ic.ic_acquire_bus = glxpcib_smb_acquire_bus;
374 		sc->sc_smb_ic.ic_release_bus = glxpcib_smb_release_bus;
375 		sc->sc_smb_ic.ic_send_start = glxpcib_smb_send_start;
376 		sc->sc_smb_ic.ic_send_stop = glxpcib_smb_send_stop;
377 		sc->sc_smb_ic.ic_initiate_xfer = glxpcib_smb_initiate_xfer;
378 		sc->sc_smb_ic.ic_read_byte = glxpcib_smb_read_byte;
379 		sc->sc_smb_ic.ic_write_byte = glxpcib_smb_write_byte;
380 
381 		rw_init(&sc->sc_smb_lck, "iiclk");
382 
383 		bzero(&iba, sizeof(iba));
384 		iba.iba_name = "iic";
385 		iba.iba_tag = &sc->sc_smb_ic;
386 		i2c = 1;
387 	}
388 #endif /* SMALL_KERNEL */
389 	pcibattach(parent, self, aux);
390 
391 #ifndef SMALL_KERNEL
392 #if NGPIO > 0
393 	if (gpio)
394 		config_found(&sc->sc_dev, &gba, gpiobus_print);
395 #endif
396 	if (i2c)
397 		config_found(&sc->sc_dev, &iba, iicbus_print);
398 #endif
399 }
400 
401 int
402 glxpcib_activate(struct device *self, int act)
403 {
404 #ifndef SMALL_KERNEL
405 	struct glxpcib_softc *sc = (struct glxpcib_softc *)self;
406 	uint i;
407 #endif
408 	int rv = 0;
409 
410 	switch (act) {
411 	case DVACT_QUIESCE:
412 		rv = config_activate_children(self, act);
413 		break;
414 	case DVACT_SUSPEND:
415 #ifndef SMALL_KERNEL
416 		if (sc->sc_wdog) {
417 			sc->sc_wdog_period = bus_space_read_2(sc->sc_iot,
418 			    sc->sc_ioh, AMD5536_MFGPT0_CMP2);
419 			glxpcib_wdogctl_cb(sc, 0);
420 		}
421 #endif
422 		rv = config_activate_children(self, act);
423 #ifndef SMALL_KERNEL
424 		for (i = 0; i < nitems(glxpcib_msrlist); i++)
425 			sc->sc_msrsave[i] = rdmsr(glxpcib_msrlist[i]);
426 #endif
427 
428 		break;
429 	case DVACT_RESUME:
430 #ifndef SMALL_KERNEL
431 		if (sc->sc_wdog)
432 			glxpcib_wdogctl_cb(sc, sc->sc_wdog_period);
433 		for (i = 0; i < nitems(glxpcib_msrlist); i++)
434 			wrmsr(glxpcib_msrlist[i], sc->sc_msrsave[i]);
435 #endif
436 		rv = config_activate_children(self, act);
437 		break;
438 	}
439 	return (rv);
440 }
441 
442 u_int
443 glxpcib_get_timecount(struct timecounter *tc)
444 {
445         return rdmsr(AMD5536_TMC);
446 }
447 
448 #ifndef SMALL_KERNEL
449 int
450 glxpcib_wdogctl_cb(void *v, int period)
451 {
452 	struct glxpcib_softc *sc = v;
453 
454 	if (period > 0xffff)
455 		period = 0xffff;
456 
457 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_SETUP,
458 	    AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2);
459 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CNT, 0);
460 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CMP2, period);
461 
462 	if (period)
463 		wrmsr(AMD5536_MFGPT_NR,
464 		    rdmsr(AMD5536_MFGPT_NR) | AMD5536_MFGPT0_C2_RSTEN);
465 	else
466 		wrmsr(AMD5536_MFGPT_NR,
467 		    rdmsr(AMD5536_MFGPT_NR) & ~AMD5536_MFGPT0_C2_RSTEN);
468 
469 	return period;
470 }
471 
472 #if NGPIO > 0
473 int
474 glxpcib_gpio_pin_read(void *arg, int pin)
475 {
476 	struct glxpcib_softc *sc = arg;
477 	u_int32_t data;
478 	int reg, off = 0;
479 
480 	reg = AMD5536_GPIO_IN_EN;
481 	if (pin > 15) {
482 		pin &= 0x0f;
483 		off = AMD5536_GPIOH_OFFSET;
484 	}
485 	reg += off;
486 	data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);
487 
488 	if (data & (1 << pin))
489 		reg = AMD5536_GPIO_READ_BACK + off;
490 	else
491 		reg = AMD5536_GPIO_OUT_VAL + off;
492 
493 	data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);
494 
495 	return data & 1 << pin ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
496 }
497 
498 void
499 glxpcib_gpio_pin_write(void *arg, int pin, int value)
500 {
501 	struct glxpcib_softc *sc = arg;
502 	u_int32_t data;
503 	int reg;
504 
505 	reg = AMD5536_GPIO_OUT_VAL;
506 	if (pin > 15) {
507 		pin &= 0x0f;
508 		reg += AMD5536_GPIOH_OFFSET;
509 	}
510 	if (value == 1)
511 		data = 1 << pin;
512 	else
513 		data = 1 << (pin + 16);
514 
515 	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data);
516 }
517 
518 void
519 glxpcib_gpio_pin_ctl(void *arg, int pin, int flags)
520 {
521 	struct glxpcib_softc *sc = arg;
522 	int n, reg[7], val[7], nreg = 0, off = 0;
523 
524 	if (pin > 15) {
525 		pin &= 0x0f;
526 		off = AMD5536_GPIOH_OFFSET;
527 	}
528 
529 	reg[nreg] = AMD5536_GPIO_IN_EN + off;
530 	if (flags & GPIO_PIN_INPUT)
531 		val[nreg++] = 1 << pin;
532 	else
533 		val[nreg++] = 1 << (pin + 16);
534 
535 	reg[nreg] = AMD5536_GPIO_OUT_EN + off;
536 	if (flags & GPIO_PIN_OUTPUT)
537 		val[nreg++] = 1 << pin;
538 	else
539 		val[nreg++] = 1 << (pin + 16);
540 
541 	reg[nreg] = AMD5536_GPIO_OD_EN + off;
542 	if (flags & GPIO_PIN_OPENDRAIN)
543 		val[nreg++] = 1 << pin;
544 	else
545 		val[nreg++] = 1 << (pin + 16);
546 
547 	reg[nreg] = AMD5536_GPIO_PU_EN + off;
548 	if (flags & GPIO_PIN_PULLUP)
549 		val[nreg++] = 1 << pin;
550 	else
551 		val[nreg++] = 1 << (pin + 16);
552 
553 	reg[nreg] = AMD5536_GPIO_PD_EN + off;
554 	if (flags & GPIO_PIN_PULLDOWN)
555 		val[nreg++] = 1 << pin;
556 	else
557 		val[nreg++] = 1 << (pin + 16);
558 
559 	reg[nreg] = AMD5536_GPIO_IN_INVRT_EN + off;
560 	if (flags & GPIO_PIN_INVIN)
561 		val[nreg++] = 1 << pin;
562 	else
563 		val[nreg++] = 1 << (pin + 16);
564 
565 	reg[nreg] = AMD5536_GPIO_OUT_INVRT_EN + off;
566 	if (flags & GPIO_PIN_INVOUT)
567 		val[nreg++] = 1 << pin;
568 	else
569 		val[nreg++] = 1 << (pin + 16);
570 
571 	/* set flags */
572 	for (n = 0; n < nreg; n++)
573 		bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg[n],
574 		    val[n]);
575 }
576 #endif /* GPIO */
577 
578 int
579 glxpcib_smb_acquire_bus(void *arg, int flags)
580 {
581 	struct glxpcib_softc *sc = arg;
582 
583 	if (cold || flags & I2C_F_POLL)
584 		return (0);
585 
586 	return (rw_enter(&sc->sc_smb_lck, RW_WRITE | RW_INTR));
587 }
588 
589 void
590 glxpcib_smb_release_bus(void *arg, int flags)
591 {
592 	struct glxpcib_softc *sc = arg;
593 
594 	if (cold || flags & I2C_F_POLL)
595 		return;
596 
597 	rw_exit(&sc->sc_smb_lck);
598 }
599 
600 int
601 glxpcib_smb_send_start(void *arg, int flags)
602 {
603 	struct glxpcib_softc *sc = arg;
604 	u_int8_t ctl;
605 
606 	ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
607 	    AMD5536_SMB_CTL1);
608 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1,
609 	    ctl | AMD5536_SMB_CTL1_START);
610 
611 	return (0);
612 }
613 
614 int
615 glxpcib_smb_send_stop(void *arg, int flags)
616 {
617 	struct glxpcib_softc *sc = arg;
618 	u_int8_t ctl;
619 
620 	ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
621 	    AMD5536_SMB_CTL1);
622 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1,
623 	    ctl | AMD5536_SMB_CTL1_STOP);
624 
625 	return (0);
626 }
627 
628 void
629 glxpcib_smb_send_ack(void *arg, int flags)
630 {
631 	struct glxpcib_softc *sc = arg;
632 	u_int8_t ctl;
633 
634 	ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
635 	    AMD5536_SMB_CTL1);
636 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1,
637 	    ctl | AMD5536_SMB_CTL1_ACK);
638 }
639 
640 int
641 glxpcib_smb_initiate_xfer(void *arg, i2c_addr_t addr, int flags)
642 {
643 	struct glxpcib_softc *sc = arg;
644 	int error, dir;
645 
646 	/* Issue start condition */
647 	glxpcib_smb_send_start(sc, flags);
648 
649 	/* Wait for bus mastership */
650 	if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_MASTER |
651 	    AMD5536_SMB_STS_SDAST, flags)) != 0)
652 		return (error);
653 
654 	/* Send address byte */
655 	dir = (flags & I2C_F_READ ? 1 : 0);
656 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_SDA,
657 	    (addr << 1) | dir);
658 
659 	return (0);
660 }
661 
662 int
663 glxpcib_smb_read_byte(void *arg, uint8_t *bytep, int flags)
664 {
665 	struct glxpcib_softc *sc = arg;
666 	int error;
667 
668 	/* Wait for the bus to be ready */
669 	if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags)))
670 		return (error);
671 
672 	/* Acknowledge the last byte */
673 	if (flags & I2C_F_LAST)
674 		glxpcib_smb_send_ack(sc, 0);
675 
676 	/* Read data byte */
677 	*bytep = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
678 	    AMD5536_SMB_SDA);
679 
680 	return (0);
681 }
682 
683 int
684 glxpcib_smb_write_byte(void *arg, uint8_t byte, int flags)
685 {
686 	struct glxpcib_softc *sc = arg;
687 	int error;
688 
689 	/* Wait for the bus to be ready */
690 	if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags)))
691 		return (error);
692 
693 	/* Send stop after the last byte */
694 	if (flags & I2C_F_STOP)
695 		glxpcib_smb_send_stop(sc, 0);
696 
697 	/* Write data byte */
698 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_SDA,
699 	    byte);
700 
701 	return (0);
702 }
703 
704 void
705 glxpcib_smb_reset(struct glxpcib_softc *sc)
706 {
707 	u_int8_t st;
708 
709 	/* Clear MASTER, NEGACK and BER */
710 	st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS);
711 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS, st |
712 	    AMD5536_SMB_STS_MASTER | AMD5536_SMB_STS_NEGACK |
713 	    AMD5536_SMB_STS_BER);
714 
715 	/* Disable and re-enable controller */
716 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2, 0);
717 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2,
718 	    AMD5536_SMB_CTL2_EN | AMD5536_SMB_CTL2_FREQ);
719 
720 	/* Send stop */
721 	glxpcib_smb_send_stop(sc, 0);
722 }
723 
724 int
725 glxpcib_smb_wait(struct glxpcib_softc *sc, int bits, int flags)
726 {
727 	u_int8_t st;
728 	int i;
729 
730 	for (i = 0; i < 100; i++) {
731 		st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
732 		    AMD5536_SMB_STS);
733 		if (st & AMD5536_SMB_STS_BER) {
734 			printf("%s: bus error, bits=%#x st=%#x\n",
735 			    sc->sc_dev.dv_xname, bits, st);
736 			glxpcib_smb_reset(sc);
737 			return (EIO);
738 		}
739 		if ((bits & AMD5536_SMB_STS_MASTER) == 0 &&
740 		    (st & AMD5536_SMB_STS_NEGACK)) {
741 			glxpcib_smb_reset(sc);
742 			return (EIO);
743 		}
744 		if (st & AMD5536_SMB_STS_STASTR)
745 			bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
746 			    AMD5536_SMB_STS, AMD5536_SMB_STS_STASTR);
747 		if ((st & bits) == bits)
748 			break;
749 		delay(2);
750 	}
751 	if ((st & bits) != bits) {
752 		glxpcib_smb_reset(sc);
753 		return (ETIMEDOUT);
754 	}
755 	return (0);
756 }
757 #endif /* SMALL_KERNEL */
758