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