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