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