xref: /openbsd/sys/dev/pci/glxpcib.c (revision 898184e3)
1 /*      $OpenBSD: glxpcib.c,v 1.10 2013/03/17 19:09:03 miod 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 /* PMS */
170 #define	MSR_LBAR_PMS		DIVIL_LBAR_PMS
171 #define	MSR_PMS_SIZE		0x80
172 #define	MSR_PMS_ADDR_MASK	0xff80
173 #define	AMD5536_PMS_SSC		0x54
174 #define	AMD5536_PMS_SSC_PI	0x00040000
175 #define	AMD5536_PMS_SSC_CLR_PI	0x00020000
176 #define	AMD5536_PMS_SSC_SET_PI	0x00010000
177 
178 /*
179  * MSR registers we want to preserve accross suspend/resume
180  */
181 const uint32_t glxpcib_msrlist[] = {
182 	GLIU_PAE,
183 	GLCP_GLD_MSR_PM,
184 	DIVIL_BALL_OPTS
185 };
186 
187 struct glxpcib_softc {
188 	struct device		sc_dev;
189 
190 	struct timecounter	sc_timecounter;
191 	bus_space_tag_t		sc_iot;
192 	bus_space_handle_t	sc_ioh;
193 
194 	uint64_t 		sc_msrsave[nitems(glxpcib_msrlist)];
195 
196 #ifndef SMALL_KERNEL
197 #if NGPIO > 0
198 	/* GPIO interface */
199 	bus_space_tag_t		sc_gpio_iot;
200 	bus_space_handle_t	sc_gpio_ioh;
201 	struct gpio_chipset_tag	sc_gpio_gc;
202 	gpio_pin_t		sc_gpio_pins[AMD5536_GPIO_NPINS];
203 #endif
204 	/* I2C interface */
205 	bus_space_tag_t		sc_smb_iot;
206 	bus_space_handle_t	sc_smb_ioh;
207 	struct i2c_controller	sc_smb_ic;
208 	struct rwlock		sc_smb_lck;
209 
210 	/* Watchdog */
211 	int			sc_wdog;
212 	int			sc_wdog_period;
213 #endif
214 };
215 
216 struct cfdriver glxpcib_cd = {
217 	NULL, "glxpcib", DV_DULL
218 };
219 
220 int	glxpcib_match(struct device *, void *, void *);
221 void	glxpcib_attach(struct device *, struct device *, void *);
222 int	glxpcib_activate(struct device *, int);
223 int	glxpcib_search(struct device *, void *, void *);
224 int	glxpcib_print(void *, const char *);
225 
226 struct cfattach glxpcib_ca = {
227 	sizeof(struct glxpcib_softc), glxpcib_match, glxpcib_attach,
228 	NULL, glxpcib_activate
229 };
230 
231 /* from arch/<*>/pci/pcib.c */
232 void	pcibattach(struct device *parent, struct device *self, void *aux);
233 
234 u_int	glxpcib_get_timecount(struct timecounter *tc);
235 
236 #ifndef SMALL_KERNEL
237 int     glxpcib_wdogctl_cb(void *, int);
238 #if NGPIO > 0
239 void	glxpcib_gpio_pin_ctl(void *, int, int);
240 int	glxpcib_gpio_pin_read(void *, int);
241 void	glxpcib_gpio_pin_write(void *, int, int);
242 #endif
243 int	glxpcib_smb_acquire_bus(void *, int);
244 void	glxpcib_smb_release_bus(void *, int);
245 int	glxpcib_smb_send_start(void *, int);
246 int	glxpcib_smb_send_stop(void *, int);
247 void	glxpcib_smb_send_ack(void *, int);
248 int	glxpcib_smb_initiate_xfer(void *, i2c_addr_t, int);
249 int	glxpcib_smb_read_byte(void *, uint8_t *, int);
250 int	glxpcib_smb_write_byte(void *, uint8_t, int);
251 void	glxpcib_smb_reset(struct glxpcib_softc *);
252 int	glxpcib_smb_wait(struct glxpcib_softc *, int, int);
253 #endif
254 
255 const struct pci_matchid glxpcib_devices[] = {
256 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_CS5536_PCIB }
257 };
258 
259 int
260 glxpcib_match(struct device *parent, void *match, void *aux)
261 {
262 	if (pci_matchbyid((struct pci_attach_args *)aux, glxpcib_devices,
263 	    nitems(glxpcib_devices))) {
264 		/* needs to win over pcib */
265 		return 2;
266 	}
267 
268 	return 0;
269 }
270 
271 void
272 glxpcib_attach(struct device *parent, struct device *self, void *aux)
273 {
274 	struct glxpcib_softc *sc = (struct glxpcib_softc *)self;
275 	struct timecounter *tc = &sc->sc_timecounter;
276 #ifndef SMALL_KERNEL
277 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
278 	u_int64_t wa;
279 #if NGPIO > 0
280 	u_int64_t ga;
281 	struct gpiobus_attach_args gba;
282 	int i, gpio = 0;
283 #endif
284 	u_int64_t sa;
285 	struct i2cbus_attach_args iba;
286 	int i2c = 0;
287 	bus_space_handle_t tmpioh;
288 #endif
289 	tc->tc_get_timecount = glxpcib_get_timecount;
290 	tc->tc_counter_mask = 0xffffffff;
291 	tc->tc_frequency = 3579545;
292 	tc->tc_name = "CS5536";
293 	tc->tc_quality = 1000;
294 	tc->tc_priv = sc;
295 	tc_init(tc);
296 
297 	printf(": rev %d, 32-bit %lluHz timer",
298 	    (int)rdmsr(AMD5536_REV) & AMD5536_REV_MASK,
299 	    tc->tc_frequency);
300 
301 #ifndef SMALL_KERNEL
302 	/* Attach the watchdog timer */
303 	sc->sc_iot = pa->pa_iot;
304 	wa = rdmsr(MSR_LBAR_MFGPT);
305 	if (wa & MSR_LBAR_ENABLE &&
306 	    !bus_space_map(sc->sc_iot, wa & MSR_MFGPT_ADDR_MASK,
307 	    MSR_MFGPT_SIZE, 0, &sc->sc_ioh)) {
308 		/* count in seconds (as upper level desires) */
309 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_SETUP,
310 		    AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2EV |
311 		    AMD5536_MFGPT_CMP2 | AMD5536_MFGPT_DIV_MASK |
312 		    AMD5536_MFGPT_STOP_EN);
313 		wdog_register(glxpcib_wdogctl_cb, sc);
314 		sc->sc_wdog = 1;
315 		printf(", watchdog");
316 	}
317 
318 #if NGPIO > 0
319 	/* map GPIO I/O space */
320 	sc->sc_gpio_iot = pa->pa_iot;
321 	ga = rdmsr(MSR_LBAR_GPIO);
322 	if (ga & MSR_LBAR_ENABLE &&
323 	    !bus_space_map(sc->sc_gpio_iot, ga & MSR_GPIO_ADDR_MASK,
324 	    MSR_GPIO_SIZE, 0, &sc->sc_gpio_ioh)) {
325 		printf(", gpio");
326 
327 		/* initialize pin array */
328 		for (i = 0; i < AMD5536_GPIO_NPINS; i++) {
329 			sc->sc_gpio_pins[i].pin_num = i;
330 			sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
331 			    GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN |
332 			    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN |
333 			    GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
334 
335 			/* read initial state */
336 			sc->sc_gpio_pins[i].pin_state =
337 			    glxpcib_gpio_pin_read(sc, i);
338 		}
339 
340 		/* create controller tag */
341 		sc->sc_gpio_gc.gp_cookie = sc;
342 		sc->sc_gpio_gc.gp_pin_read = glxpcib_gpio_pin_read;
343 		sc->sc_gpio_gc.gp_pin_write = glxpcib_gpio_pin_write;
344 		sc->sc_gpio_gc.gp_pin_ctl = glxpcib_gpio_pin_ctl;
345 
346 		gba.gba_name = "gpio";
347 		gba.gba_gc = &sc->sc_gpio_gc;
348 		gba.gba_pins = sc->sc_gpio_pins;
349 		gba.gba_npins = AMD5536_GPIO_NPINS;
350 		gpio = 1;
351 
352 	}
353 #endif /* NGPIO */
354 
355 	/* Map SMB I/O space */
356 	sc->sc_smb_iot = pa->pa_iot;
357 	sa = rdmsr(MSR_LBAR_SMB);
358 	if (sa & MSR_LBAR_ENABLE &&
359 	    !bus_space_map(sc->sc_smb_iot, sa & MSR_SMB_ADDR_MASK,
360 	    MSR_SMB_SIZE, 0, &sc->sc_smb_ioh)) {
361 		printf(", i2c");
362 
363 		/* Enable controller */
364 		bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
365 		    AMD5536_SMB_CTL2, AMD5536_SMB_CTL2_EN |
366 		    AMD5536_SMB_CTL2_FREQ);
367 
368 		/* Disable interrupts */
369 		bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
370 		    AMD5536_SMB_CTL1, 0);
371 
372 		/* Disable slave address */
373 		bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
374 		    AMD5536_SMB_ADDR, 0);
375 
376 		/* Stall the bus after start */
377 		bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
378 		    AMD5536_SMB_CTL1, AMD5536_SMB_CTL1_STASTRE);
379 
380 		/* Attach I2C framework */
381 		sc->sc_smb_ic.ic_cookie = sc;
382 		sc->sc_smb_ic.ic_acquire_bus = glxpcib_smb_acquire_bus;
383 		sc->sc_smb_ic.ic_release_bus = glxpcib_smb_release_bus;
384 		sc->sc_smb_ic.ic_send_start = glxpcib_smb_send_start;
385 		sc->sc_smb_ic.ic_send_stop = glxpcib_smb_send_stop;
386 		sc->sc_smb_ic.ic_initiate_xfer = glxpcib_smb_initiate_xfer;
387 		sc->sc_smb_ic.ic_read_byte = glxpcib_smb_read_byte;
388 		sc->sc_smb_ic.ic_write_byte = glxpcib_smb_write_byte;
389 
390 		rw_init(&sc->sc_smb_lck, "iiclk");
391 
392 		bzero(&iba, sizeof(iba));
393 		iba.iba_name = "iic";
394 		iba.iba_tag = &sc->sc_smb_ic;
395 		i2c = 1;
396 	}
397 
398 	/* Map PMS I/O space and enable the ``Power Immediate'' feature */
399 	sa = rdmsr(MSR_LBAR_PMS);
400 	if (sa & MSR_LBAR_ENABLE &&
401 	    !bus_space_map(pa->pa_iot, sa & MSR_PMS_ADDR_MASK,
402 	    MSR_PMS_SIZE, 0, &tmpioh)) {
403 		bus_space_write_4(pa->pa_iot, tmpioh, AMD5536_PMS_SSC,
404 		    AMD5536_PMS_SSC_SET_PI);
405 		bus_space_barrier(pa->pa_iot, tmpioh, AMD5536_PMS_SSC, 4,
406 		    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
407 		bus_space_unmap(pa->pa_iot, tmpioh, MSR_PMS_SIZE);
408 	}
409 #endif /* SMALL_KERNEL */
410 	pcibattach(parent, self, aux);
411 
412 #ifndef SMALL_KERNEL
413 #if NGPIO > 0
414 	if (gpio)
415 		config_found(&sc->sc_dev, &gba, gpiobus_print);
416 #endif
417 	if (i2c)
418 		config_found(&sc->sc_dev, &iba, iicbus_print);
419 #endif
420 
421 	config_search(glxpcib_search, self, pa);
422 }
423 
424 int
425 glxpcib_activate(struct device *self, int act)
426 {
427 #ifndef SMALL_KERNEL
428 	struct glxpcib_softc *sc = (struct glxpcib_softc *)self;
429 	uint i;
430 #endif
431 	int rv = 0;
432 
433 	switch (act) {
434 	case DVACT_QUIESCE:
435 		rv = config_activate_children(self, act);
436 		break;
437 	case DVACT_SUSPEND:
438 #ifndef SMALL_KERNEL
439 		if (sc->sc_wdog) {
440 			sc->sc_wdog_period = bus_space_read_2(sc->sc_iot,
441 			    sc->sc_ioh, AMD5536_MFGPT0_CMP2);
442 			glxpcib_wdogctl_cb(sc, 0);
443 		}
444 #endif
445 		rv = config_activate_children(self, act);
446 #ifndef SMALL_KERNEL
447 		for (i = 0; i < nitems(glxpcib_msrlist); i++)
448 			sc->sc_msrsave[i] = rdmsr(glxpcib_msrlist[i]);
449 #endif
450 
451 		break;
452 	case DVACT_POWERDOWN:
453 		rv = config_activate_children(self, act);
454 		break;
455 	case DVACT_RESUME:
456 #ifndef SMALL_KERNEL
457 		if (sc->sc_wdog)
458 			glxpcib_wdogctl_cb(sc, sc->sc_wdog_period);
459 		for (i = 0; i < nitems(glxpcib_msrlist); i++)
460 			wrmsr(glxpcib_msrlist[i], sc->sc_msrsave[i]);
461 #endif
462 		rv = config_activate_children(self, act);
463 		break;
464 	}
465 	return (rv);
466 }
467 
468 u_int
469 glxpcib_get_timecount(struct timecounter *tc)
470 {
471         return rdmsr(AMD5536_TMC);
472 }
473 
474 #ifndef SMALL_KERNEL
475 int
476 glxpcib_wdogctl_cb(void *v, int period)
477 {
478 	struct glxpcib_softc *sc = v;
479 
480 	if (period > 0xffff)
481 		period = 0xffff;
482 
483 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_SETUP,
484 	    AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2);
485 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CNT, 0);
486 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CMP2, period);
487 
488 	if (period)
489 		wrmsr(AMD5536_MFGPT_NR,
490 		    rdmsr(AMD5536_MFGPT_NR) | AMD5536_MFGPT0_C2_RSTEN);
491 	else
492 		wrmsr(AMD5536_MFGPT_NR,
493 		    rdmsr(AMD5536_MFGPT_NR) & ~AMD5536_MFGPT0_C2_RSTEN);
494 
495 	return period;
496 }
497 
498 #if NGPIO > 0
499 int
500 glxpcib_gpio_pin_read(void *arg, int pin)
501 {
502 	struct glxpcib_softc *sc = arg;
503 	u_int32_t data;
504 	int reg, off = 0;
505 
506 	reg = AMD5536_GPIO_IN_EN;
507 	if (pin > 15) {
508 		pin &= 0x0f;
509 		off = AMD5536_GPIOH_OFFSET;
510 	}
511 	reg += off;
512 	data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);
513 
514 	if (data & (1 << pin))
515 		reg = AMD5536_GPIO_READ_BACK + off;
516 	else
517 		reg = AMD5536_GPIO_OUT_VAL + off;
518 
519 	data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);
520 
521 	return data & 1 << pin ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
522 }
523 
524 void
525 glxpcib_gpio_pin_write(void *arg, int pin, int value)
526 {
527 	struct glxpcib_softc *sc = arg;
528 	u_int32_t data;
529 	int reg;
530 
531 	reg = AMD5536_GPIO_OUT_VAL;
532 	if (pin > 15) {
533 		pin &= 0x0f;
534 		reg += AMD5536_GPIOH_OFFSET;
535 	}
536 	if (value == 1)
537 		data = 1 << pin;
538 	else
539 		data = 1 << (pin + 16);
540 
541 	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data);
542 }
543 
544 void
545 glxpcib_gpio_pin_ctl(void *arg, int pin, int flags)
546 {
547 	struct glxpcib_softc *sc = arg;
548 	int n, reg[7], val[7], nreg = 0, off = 0;
549 
550 	if (pin > 15) {
551 		pin &= 0x0f;
552 		off = AMD5536_GPIOH_OFFSET;
553 	}
554 
555 	reg[nreg] = AMD5536_GPIO_IN_EN + off;
556 	if (flags & GPIO_PIN_INPUT)
557 		val[nreg++] = 1 << pin;
558 	else
559 		val[nreg++] = 1 << (pin + 16);
560 
561 	reg[nreg] = AMD5536_GPIO_OUT_EN + off;
562 	if (flags & GPIO_PIN_OUTPUT)
563 		val[nreg++] = 1 << pin;
564 	else
565 		val[nreg++] = 1 << (pin + 16);
566 
567 	reg[nreg] = AMD5536_GPIO_OD_EN + off;
568 	if (flags & GPIO_PIN_OPENDRAIN)
569 		val[nreg++] = 1 << pin;
570 	else
571 		val[nreg++] = 1 << (pin + 16);
572 
573 	reg[nreg] = AMD5536_GPIO_PU_EN + off;
574 	if (flags & GPIO_PIN_PULLUP)
575 		val[nreg++] = 1 << pin;
576 	else
577 		val[nreg++] = 1 << (pin + 16);
578 
579 	reg[nreg] = AMD5536_GPIO_PD_EN + off;
580 	if (flags & GPIO_PIN_PULLDOWN)
581 		val[nreg++] = 1 << pin;
582 	else
583 		val[nreg++] = 1 << (pin + 16);
584 
585 	reg[nreg] = AMD5536_GPIO_IN_INVRT_EN + off;
586 	if (flags & GPIO_PIN_INVIN)
587 		val[nreg++] = 1 << pin;
588 	else
589 		val[nreg++] = 1 << (pin + 16);
590 
591 	reg[nreg] = AMD5536_GPIO_OUT_INVRT_EN + off;
592 	if (flags & GPIO_PIN_INVOUT)
593 		val[nreg++] = 1 << pin;
594 	else
595 		val[nreg++] = 1 << (pin + 16);
596 
597 	/* set flags */
598 	for (n = 0; n < nreg; n++)
599 		bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg[n],
600 		    val[n]);
601 }
602 #endif /* GPIO */
603 
604 int
605 glxpcib_smb_acquire_bus(void *arg, int flags)
606 {
607 	struct glxpcib_softc *sc = arg;
608 
609 	if (cold || flags & I2C_F_POLL)
610 		return (0);
611 
612 	return (rw_enter(&sc->sc_smb_lck, RW_WRITE | RW_INTR));
613 }
614 
615 void
616 glxpcib_smb_release_bus(void *arg, int flags)
617 {
618 	struct glxpcib_softc *sc = arg;
619 
620 	if (cold || flags & I2C_F_POLL)
621 		return;
622 
623 	rw_exit(&sc->sc_smb_lck);
624 }
625 
626 int
627 glxpcib_smb_send_start(void *arg, int flags)
628 {
629 	struct glxpcib_softc *sc = arg;
630 	u_int8_t ctl;
631 
632 	ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
633 	    AMD5536_SMB_CTL1);
634 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1,
635 	    ctl | AMD5536_SMB_CTL1_START);
636 
637 	return (0);
638 }
639 
640 int
641 glxpcib_smb_send_stop(void *arg, int flags)
642 {
643 	struct glxpcib_softc *sc = arg;
644 	u_int8_t ctl;
645 
646 	ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
647 	    AMD5536_SMB_CTL1);
648 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1,
649 	    ctl | AMD5536_SMB_CTL1_STOP);
650 
651 	return (0);
652 }
653 
654 void
655 glxpcib_smb_send_ack(void *arg, int flags)
656 {
657 	struct glxpcib_softc *sc = arg;
658 	u_int8_t ctl;
659 
660 	ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
661 	    AMD5536_SMB_CTL1);
662 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1,
663 	    ctl | AMD5536_SMB_CTL1_ACK);
664 }
665 
666 int
667 glxpcib_smb_initiate_xfer(void *arg, i2c_addr_t addr, int flags)
668 {
669 	struct glxpcib_softc *sc = arg;
670 	int error, dir;
671 
672 	/* Issue start condition */
673 	glxpcib_smb_send_start(sc, flags);
674 
675 	/* Wait for bus mastership */
676 	if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_MASTER |
677 	    AMD5536_SMB_STS_SDAST, flags)) != 0)
678 		return (error);
679 
680 	/* Send address byte */
681 	dir = (flags & I2C_F_READ ? 1 : 0);
682 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_SDA,
683 	    (addr << 1) | dir);
684 
685 	return (0);
686 }
687 
688 int
689 glxpcib_smb_read_byte(void *arg, uint8_t *bytep, int flags)
690 {
691 	struct glxpcib_softc *sc = arg;
692 	int error;
693 
694 	/* Wait for the bus to be ready */
695 	if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags)))
696 		return (error);
697 
698 	/* Acknowledge the last byte */
699 	if (flags & I2C_F_LAST)
700 		glxpcib_smb_send_ack(sc, 0);
701 
702 	/* Read data byte */
703 	*bytep = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
704 	    AMD5536_SMB_SDA);
705 
706 	return (0);
707 }
708 
709 int
710 glxpcib_print(void *args, const char *parentname)
711 {
712 	struct glxpcib_attach_args *gaa = (struct glxpcib_attach_args *)args;
713 
714 	if (parentname != NULL)
715 		printf("%s at %s", gaa->gaa_name, parentname);
716 
717 	return UNCONF;
718 }
719 
720 int
721 glxpcib_search(struct device *parent, void *gcf, void *args)
722 {
723 	struct glxpcib_softc *sc = (struct glxpcib_softc *)parent;
724 	struct cfdata *cf = (struct cfdata *)gcf;
725 	struct pci_attach_args *pa = (struct pci_attach_args *)args;
726 	struct glxpcib_attach_args gaa;
727 
728 	gaa.gaa_name = cf->cf_driver->cd_name;
729 	gaa.gaa_pa = pa;
730 	gaa.gaa_iot = sc->sc_iot;
731 	gaa.gaa_ioh = sc->sc_ioh;
732 
733 	/*
734 	 * These devices are attached directly, either from
735 	 * glxpcib_attach() or later in time from pcib_callback().
736 	 */
737 	if (strcmp(cf->cf_driver->cd_name, "gpio") == 0 ||
738 	    strcmp(cf->cf_driver->cd_name, "iic") == 0 ||
739 	    strcmp(cf->cf_driver->cd_name, "isa") == 0)
740 		return 0;
741 
742 	if (cf->cf_attach->ca_match(parent, cf, &gaa) == 0)
743 		return 0;
744 
745 	config_attach(parent, cf, &gaa, glxpcib_print);
746 	return 1;
747 }
748 
749 int
750 glxpcib_smb_write_byte(void *arg, uint8_t byte, int flags)
751 {
752 	struct glxpcib_softc *sc = arg;
753 	int error;
754 
755 	/* Wait for the bus to be ready */
756 	if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags)))
757 		return (error);
758 
759 	/* Send stop after the last byte */
760 	if (flags & I2C_F_STOP)
761 		glxpcib_smb_send_stop(sc, 0);
762 
763 	/* Write data byte */
764 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_SDA,
765 	    byte);
766 
767 	return (0);
768 }
769 
770 void
771 glxpcib_smb_reset(struct glxpcib_softc *sc)
772 {
773 	u_int8_t st;
774 
775 	/* Clear MASTER, NEGACK and BER */
776 	st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS);
777 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS, st |
778 	    AMD5536_SMB_STS_MASTER | AMD5536_SMB_STS_NEGACK |
779 	    AMD5536_SMB_STS_BER);
780 
781 	/* Disable and re-enable controller */
782 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2, 0);
783 	bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2,
784 	    AMD5536_SMB_CTL2_EN | AMD5536_SMB_CTL2_FREQ);
785 
786 	/* Send stop */
787 	glxpcib_smb_send_stop(sc, 0);
788 }
789 
790 int
791 glxpcib_smb_wait(struct glxpcib_softc *sc, int bits, int flags)
792 {
793 	u_int8_t st;
794 	int i;
795 
796 	for (i = 0; i < 100; i++) {
797 		st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
798 		    AMD5536_SMB_STS);
799 		if (st & AMD5536_SMB_STS_BER) {
800 			printf("%s: bus error, bits=%#x st=%#x\n",
801 			    sc->sc_dev.dv_xname, bits, st);
802 			glxpcib_smb_reset(sc);
803 			return (EIO);
804 		}
805 		if ((bits & AMD5536_SMB_STS_MASTER) == 0 &&
806 		    (st & AMD5536_SMB_STS_NEGACK)) {
807 			glxpcib_smb_reset(sc);
808 			return (EIO);
809 		}
810 		if (st & AMD5536_SMB_STS_STASTR)
811 			bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
812 			    AMD5536_SMB_STS, AMD5536_SMB_STS_STASTR);
813 		if ((st & bits) == bits)
814 			break;
815 		delay(2);
816 	}
817 	if ((st & bits) != bits) {
818 		glxpcib_smb_reset(sc);
819 		return (ETIMEDOUT);
820 	}
821 	return (0);
822 }
823 #endif /* SMALL_KERNEL */
824