xref: /openbsd/sys/dev/pci/glxpcib.c (revision 7335f476)
1 /*      $OpenBSD: glxpcib.c,v 1.17 2024/08/19 00:01:40 deraadt 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  */
180 const uint32_t glxpcib_msrlist[] = {
181 	GLIU_PAE,
182 	GLCP_GLD_MSR_PM,
183 	DIVIL_BALL_OPTS
184 };
185 
186 struct 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 
215 struct cfdriver glxpcib_cd = {
216 	NULL, "glxpcib", DV_DULL
217 };
218 
219 int	glxpcib_match(struct device *, void *, void *);
220 void	glxpcib_attach(struct device *, struct device *, void *);
221 int	glxpcib_activate(struct device *, int);
222 int	glxpcib_search(struct device *, void *, void *);
223 int	glxpcib_print(void *, const char *);
224 
225 const 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 */
231 void	pcibattach(struct device *parent, struct device *self, void *aux);
232 
233 u_int	glxpcib_get_timecount(struct timecounter *tc);
234 
235 #ifndef SMALL_KERNEL
236 int     glxpcib_wdogctl_cb(void *, int);
237 #if NGPIO > 0
238 void	glxpcib_gpio_pin_ctl(void *, int, int);
239 int	glxpcib_gpio_pin_read(void *, int);
240 void	glxpcib_gpio_pin_write(void *, int, int);
241 #endif
242 int	glxpcib_smb_acquire_bus(void *, int);
243 void	glxpcib_smb_release_bus(void *, int);
244 int	glxpcib_smb_send_start(void *, int);
245 int	glxpcib_smb_send_stop(void *, int);
246 void	glxpcib_smb_send_ack(void *, int);
247 int	glxpcib_smb_initiate_xfer(void *, i2c_addr_t, int);
248 int	glxpcib_smb_read_byte(void *, uint8_t *, int);
249 int	glxpcib_smb_write_byte(void *, uint8_t, int);
250 void	glxpcib_smb_reset(struct glxpcib_softc *);
251 int	glxpcib_smb_wait(struct glxpcib_softc *, int, int);
252 #endif
253 
254 const struct pci_matchid glxpcib_devices[] = {
255 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_CS5536_PCIB }
256 };
257 
258 int
glxpcib_match(struct device * parent,void * match,void * aux)259 glxpcib_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 
270 void
glxpcib_attach(struct device * parent,struct device * self,void * aux)271 glxpcib_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 
423 int
glxpcib_activate(struct device * self,int act)424 glxpcib_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 		rv = config_activate_children(self, act);
435 #ifndef SMALL_KERNEL
436 		if (sc->sc_wdog) {
437 			sc->sc_wdog_period = bus_space_read_2(sc->sc_iot,
438 			    sc->sc_ioh, AMD5536_MFGPT0_CMP2);
439 			glxpcib_wdogctl_cb(sc, 0);
440 		}
441 #endif
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 		rv = config_activate_children(self, act);
459 #ifndef SMALL_KERNEL
460 		if (sc->sc_wdog)
461 			wdog_shutdown(self);
462 #endif
463 		break;
464 	default:
465 		rv = config_activate_children(self, act);
466 		break;
467 	}
468 	return (rv);
469 }
470 
471 u_int
glxpcib_get_timecount(struct timecounter * tc)472 glxpcib_get_timecount(struct timecounter *tc)
473 {
474         return rdmsr(AMD5536_TMC);
475 }
476 
477 #ifndef SMALL_KERNEL
478 int
glxpcib_wdogctl_cb(void * v,int period)479 glxpcib_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
502 int
glxpcib_gpio_pin_read(void * arg,int pin)503 glxpcib_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 
527 void
glxpcib_gpio_pin_write(void * arg,int pin,int value)528 glxpcib_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 
547 void
glxpcib_gpio_pin_ctl(void * arg,int pin,int flags)548 glxpcib_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 
607 int
glxpcib_smb_acquire_bus(void * arg,int flags)608 glxpcib_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 
618 void
glxpcib_smb_release_bus(void * arg,int flags)619 glxpcib_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 
629 int
glxpcib_smb_send_start(void * arg,int flags)630 glxpcib_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 
643 int
glxpcib_smb_send_stop(void * arg,int flags)644 glxpcib_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 
657 void
glxpcib_smb_send_ack(void * arg,int flags)658 glxpcib_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 
669 int
glxpcib_smb_initiate_xfer(void * arg,i2c_addr_t addr,int flags)670 glxpcib_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 
691 int
glxpcib_smb_read_byte(void * arg,uint8_t * bytep,int flags)692 glxpcib_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 
712 int
glxpcib_print(void * args,const char * parentname)713 glxpcib_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 
723 int
glxpcib_search(struct device * parent,void * gcf,void * args)724 glxpcib_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 
752 int
glxpcib_smb_write_byte(void * arg,uint8_t byte,int flags)753 glxpcib_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 
773 void
glxpcib_smb_reset(struct glxpcib_softc * sc)774 glxpcib_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 
793 int
glxpcib_smb_wait(struct glxpcib_softc * sc,int bits,int flags)794 glxpcib_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