1 /* $OpenBSD: glxpcib.c,v 1.10 2013/03/17 19:09:03 miod 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_QUIESCE: 435 rv = config_activate_children(self, act); 436 break; 437 case DVACT_SUSPEND: 438 #ifndef SMALL_KERNEL 439 if (sc->sc_wdog) { 440 sc->sc_wdog_period = bus_space_read_2(sc->sc_iot, 441 sc->sc_ioh, AMD5536_MFGPT0_CMP2); 442 glxpcib_wdogctl_cb(sc, 0); 443 } 444 #endif 445 rv = config_activate_children(self, act); 446 #ifndef SMALL_KERNEL 447 for (i = 0; i < nitems(glxpcib_msrlist); i++) 448 sc->sc_msrsave[i] = rdmsr(glxpcib_msrlist[i]); 449 #endif 450 451 break; 452 case DVACT_POWERDOWN: 453 rv = config_activate_children(self, act); 454 break; 455 case DVACT_RESUME: 456 #ifndef SMALL_KERNEL 457 if (sc->sc_wdog) 458 glxpcib_wdogctl_cb(sc, sc->sc_wdog_period); 459 for (i = 0; i < nitems(glxpcib_msrlist); i++) 460 wrmsr(glxpcib_msrlist[i], sc->sc_msrsave[i]); 461 #endif 462 rv = config_activate_children(self, act); 463 break; 464 } 465 return (rv); 466 } 467 468 u_int 469 glxpcib_get_timecount(struct timecounter *tc) 470 { 471 return rdmsr(AMD5536_TMC); 472 } 473 474 #ifndef SMALL_KERNEL 475 int 476 glxpcib_wdogctl_cb(void *v, int period) 477 { 478 struct glxpcib_softc *sc = v; 479 480 if (period > 0xffff) 481 period = 0xffff; 482 483 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_SETUP, 484 AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2); 485 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CNT, 0); 486 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CMP2, period); 487 488 if (period) 489 wrmsr(AMD5536_MFGPT_NR, 490 rdmsr(AMD5536_MFGPT_NR) | AMD5536_MFGPT0_C2_RSTEN); 491 else 492 wrmsr(AMD5536_MFGPT_NR, 493 rdmsr(AMD5536_MFGPT_NR) & ~AMD5536_MFGPT0_C2_RSTEN); 494 495 return period; 496 } 497 498 #if NGPIO > 0 499 int 500 glxpcib_gpio_pin_read(void *arg, int pin) 501 { 502 struct glxpcib_softc *sc = arg; 503 u_int32_t data; 504 int reg, off = 0; 505 506 reg = AMD5536_GPIO_IN_EN; 507 if (pin > 15) { 508 pin &= 0x0f; 509 off = AMD5536_GPIOH_OFFSET; 510 } 511 reg += off; 512 data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg); 513 514 if (data & (1 << pin)) 515 reg = AMD5536_GPIO_READ_BACK + off; 516 else 517 reg = AMD5536_GPIO_OUT_VAL + off; 518 519 data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg); 520 521 return data & 1 << pin ? GPIO_PIN_HIGH : GPIO_PIN_LOW; 522 } 523 524 void 525 glxpcib_gpio_pin_write(void *arg, int pin, int value) 526 { 527 struct glxpcib_softc *sc = arg; 528 u_int32_t data; 529 int reg; 530 531 reg = AMD5536_GPIO_OUT_VAL; 532 if (pin > 15) { 533 pin &= 0x0f; 534 reg += AMD5536_GPIOH_OFFSET; 535 } 536 if (value == 1) 537 data = 1 << pin; 538 else 539 data = 1 << (pin + 16); 540 541 bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data); 542 } 543 544 void 545 glxpcib_gpio_pin_ctl(void *arg, int pin, int flags) 546 { 547 struct glxpcib_softc *sc = arg; 548 int n, reg[7], val[7], nreg = 0, off = 0; 549 550 if (pin > 15) { 551 pin &= 0x0f; 552 off = AMD5536_GPIOH_OFFSET; 553 } 554 555 reg[nreg] = AMD5536_GPIO_IN_EN + off; 556 if (flags & GPIO_PIN_INPUT) 557 val[nreg++] = 1 << pin; 558 else 559 val[nreg++] = 1 << (pin + 16); 560 561 reg[nreg] = AMD5536_GPIO_OUT_EN + off; 562 if (flags & GPIO_PIN_OUTPUT) 563 val[nreg++] = 1 << pin; 564 else 565 val[nreg++] = 1 << (pin + 16); 566 567 reg[nreg] = AMD5536_GPIO_OD_EN + off; 568 if (flags & GPIO_PIN_OPENDRAIN) 569 val[nreg++] = 1 << pin; 570 else 571 val[nreg++] = 1 << (pin + 16); 572 573 reg[nreg] = AMD5536_GPIO_PU_EN + off; 574 if (flags & GPIO_PIN_PULLUP) 575 val[nreg++] = 1 << pin; 576 else 577 val[nreg++] = 1 << (pin + 16); 578 579 reg[nreg] = AMD5536_GPIO_PD_EN + off; 580 if (flags & GPIO_PIN_PULLDOWN) 581 val[nreg++] = 1 << pin; 582 else 583 val[nreg++] = 1 << (pin + 16); 584 585 reg[nreg] = AMD5536_GPIO_IN_INVRT_EN + off; 586 if (flags & GPIO_PIN_INVIN) 587 val[nreg++] = 1 << pin; 588 else 589 val[nreg++] = 1 << (pin + 16); 590 591 reg[nreg] = AMD5536_GPIO_OUT_INVRT_EN + off; 592 if (flags & GPIO_PIN_INVOUT) 593 val[nreg++] = 1 << pin; 594 else 595 val[nreg++] = 1 << (pin + 16); 596 597 /* set flags */ 598 for (n = 0; n < nreg; n++) 599 bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg[n], 600 val[n]); 601 } 602 #endif /* GPIO */ 603 604 int 605 glxpcib_smb_acquire_bus(void *arg, int flags) 606 { 607 struct glxpcib_softc *sc = arg; 608 609 if (cold || flags & I2C_F_POLL) 610 return (0); 611 612 return (rw_enter(&sc->sc_smb_lck, RW_WRITE | RW_INTR)); 613 } 614 615 void 616 glxpcib_smb_release_bus(void *arg, int flags) 617 { 618 struct glxpcib_softc *sc = arg; 619 620 if (cold || flags & I2C_F_POLL) 621 return; 622 623 rw_exit(&sc->sc_smb_lck); 624 } 625 626 int 627 glxpcib_smb_send_start(void *arg, int flags) 628 { 629 struct glxpcib_softc *sc = arg; 630 u_int8_t ctl; 631 632 ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 633 AMD5536_SMB_CTL1); 634 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1, 635 ctl | AMD5536_SMB_CTL1_START); 636 637 return (0); 638 } 639 640 int 641 glxpcib_smb_send_stop(void *arg, int flags) 642 { 643 struct glxpcib_softc *sc = arg; 644 u_int8_t ctl; 645 646 ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 647 AMD5536_SMB_CTL1); 648 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1, 649 ctl | AMD5536_SMB_CTL1_STOP); 650 651 return (0); 652 } 653 654 void 655 glxpcib_smb_send_ack(void *arg, int flags) 656 { 657 struct glxpcib_softc *sc = arg; 658 u_int8_t ctl; 659 660 ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 661 AMD5536_SMB_CTL1); 662 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1, 663 ctl | AMD5536_SMB_CTL1_ACK); 664 } 665 666 int 667 glxpcib_smb_initiate_xfer(void *arg, i2c_addr_t addr, int flags) 668 { 669 struct glxpcib_softc *sc = arg; 670 int error, dir; 671 672 /* Issue start condition */ 673 glxpcib_smb_send_start(sc, flags); 674 675 /* Wait for bus mastership */ 676 if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_MASTER | 677 AMD5536_SMB_STS_SDAST, flags)) != 0) 678 return (error); 679 680 /* Send address byte */ 681 dir = (flags & I2C_F_READ ? 1 : 0); 682 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_SDA, 683 (addr << 1) | dir); 684 685 return (0); 686 } 687 688 int 689 glxpcib_smb_read_byte(void *arg, uint8_t *bytep, int flags) 690 { 691 struct glxpcib_softc *sc = arg; 692 int error; 693 694 /* Wait for the bus to be ready */ 695 if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags))) 696 return (error); 697 698 /* Acknowledge the last byte */ 699 if (flags & I2C_F_LAST) 700 glxpcib_smb_send_ack(sc, 0); 701 702 /* Read data byte */ 703 *bytep = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 704 AMD5536_SMB_SDA); 705 706 return (0); 707 } 708 709 int 710 glxpcib_print(void *args, const char *parentname) 711 { 712 struct glxpcib_attach_args *gaa = (struct glxpcib_attach_args *)args; 713 714 if (parentname != NULL) 715 printf("%s at %s", gaa->gaa_name, parentname); 716 717 return UNCONF; 718 } 719 720 int 721 glxpcib_search(struct device *parent, void *gcf, void *args) 722 { 723 struct glxpcib_softc *sc = (struct glxpcib_softc *)parent; 724 struct cfdata *cf = (struct cfdata *)gcf; 725 struct pci_attach_args *pa = (struct pci_attach_args *)args; 726 struct glxpcib_attach_args gaa; 727 728 gaa.gaa_name = cf->cf_driver->cd_name; 729 gaa.gaa_pa = pa; 730 gaa.gaa_iot = sc->sc_iot; 731 gaa.gaa_ioh = sc->sc_ioh; 732 733 /* 734 * These devices are attached directly, either from 735 * glxpcib_attach() or later in time from pcib_callback(). 736 */ 737 if (strcmp(cf->cf_driver->cd_name, "gpio") == 0 || 738 strcmp(cf->cf_driver->cd_name, "iic") == 0 || 739 strcmp(cf->cf_driver->cd_name, "isa") == 0) 740 return 0; 741 742 if (cf->cf_attach->ca_match(parent, cf, &gaa) == 0) 743 return 0; 744 745 config_attach(parent, cf, &gaa, glxpcib_print); 746 return 1; 747 } 748 749 int 750 glxpcib_smb_write_byte(void *arg, uint8_t byte, int flags) 751 { 752 struct glxpcib_softc *sc = arg; 753 int error; 754 755 /* Wait for the bus to be ready */ 756 if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags))) 757 return (error); 758 759 /* Send stop after the last byte */ 760 if (flags & I2C_F_STOP) 761 glxpcib_smb_send_stop(sc, 0); 762 763 /* Write data byte */ 764 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_SDA, 765 byte); 766 767 return (0); 768 } 769 770 void 771 glxpcib_smb_reset(struct glxpcib_softc *sc) 772 { 773 u_int8_t st; 774 775 /* Clear MASTER, NEGACK and BER */ 776 st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS); 777 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS, st | 778 AMD5536_SMB_STS_MASTER | AMD5536_SMB_STS_NEGACK | 779 AMD5536_SMB_STS_BER); 780 781 /* Disable and re-enable controller */ 782 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2, 0); 783 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2, 784 AMD5536_SMB_CTL2_EN | AMD5536_SMB_CTL2_FREQ); 785 786 /* Send stop */ 787 glxpcib_smb_send_stop(sc, 0); 788 } 789 790 int 791 glxpcib_smb_wait(struct glxpcib_softc *sc, int bits, int flags) 792 { 793 u_int8_t st; 794 int i; 795 796 for (i = 0; i < 100; i++) { 797 st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 798 AMD5536_SMB_STS); 799 if (st & AMD5536_SMB_STS_BER) { 800 printf("%s: bus error, bits=%#x st=%#x\n", 801 sc->sc_dev.dv_xname, bits, st); 802 glxpcib_smb_reset(sc); 803 return (EIO); 804 } 805 if ((bits & AMD5536_SMB_STS_MASTER) == 0 && 806 (st & AMD5536_SMB_STS_NEGACK)) { 807 glxpcib_smb_reset(sc); 808 return (EIO); 809 } 810 if (st & AMD5536_SMB_STS_STASTR) 811 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, 812 AMD5536_SMB_STS, AMD5536_SMB_STS_STASTR); 813 if ((st & bits) == bits) 814 break; 815 delay(2); 816 } 817 if ((st & bits) != bits) { 818 glxpcib_smb_reset(sc); 819 return (ETIMEDOUT); 820 } 821 return (0); 822 } 823 #endif /* SMALL_KERNEL */ 824