1 /* $OpenBSD: glxpcib.c,v 1.14 2014/12/10 12:27:57 mikeb Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org> 5 * Copyright (c) 2007 Michael Shalayeff 6 * All rights reserved. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 17 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 18 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 /* 22 * AMD CS5536 series LPC bridge also containing timer, watchdog, and GPIO. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/systm.h> 27 #include <sys/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 accross 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 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 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 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 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 #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 471 u_int 472 glxpcib_get_timecount(struct timecounter *tc) 473 { 474 return rdmsr(AMD5536_TMC); 475 } 476 477 #ifndef SMALL_KERNEL 478 int 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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