1 /* $OpenBSD: glxpcib.c,v 1.5 2012/03/06 12:57:36 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/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 /* 170 * MSR registers we want to preserve accross suspend/resume 171 */ 172 const uint32_t glxpcib_msrlist[] = { 173 GLIU_PAE, 174 GLCP_GLD_MSR_PM, 175 DIVIL_BALL_OPTS 176 }; 177 178 struct glxpcib_softc { 179 struct device sc_dev; 180 181 struct timecounter sc_timecounter; 182 bus_space_tag_t sc_iot; 183 bus_space_handle_t sc_ioh; 184 185 uint64_t sc_msrsave[nitems(glxpcib_msrlist)]; 186 187 #ifndef SMALL_KERNEL 188 #if NGPIO > 0 189 /* GPIO interface */ 190 bus_space_tag_t sc_gpio_iot; 191 bus_space_handle_t sc_gpio_ioh; 192 struct gpio_chipset_tag sc_gpio_gc; 193 gpio_pin_t sc_gpio_pins[AMD5536_GPIO_NPINS]; 194 #endif 195 /* I2C interface */ 196 bus_space_tag_t sc_smb_iot; 197 bus_space_handle_t sc_smb_ioh; 198 struct i2c_controller sc_smb_ic; 199 struct rwlock sc_smb_lck; 200 201 /* Watchdog */ 202 int sc_wdog; 203 int sc_wdog_period; 204 #endif 205 }; 206 207 struct cfdriver glxpcib_cd = { 208 NULL, "glxpcib", DV_DULL 209 }; 210 211 int glxpcib_match(struct device *, void *, void *); 212 void glxpcib_attach(struct device *, struct device *, void *); 213 int glxpcib_activate(struct device *, int); 214 215 struct cfattach glxpcib_ca = { 216 sizeof(struct glxpcib_softc), glxpcib_match, glxpcib_attach, 217 NULL, glxpcib_activate 218 }; 219 220 /* from arch/<*>/pci/pcib.c */ 221 void pcibattach(struct device *parent, struct device *self, void *aux); 222 223 u_int glxpcib_get_timecount(struct timecounter *tc); 224 225 #ifndef SMALL_KERNEL 226 int glxpcib_wdogctl_cb(void *, int); 227 #if NGPIO > 0 228 void glxpcib_gpio_pin_ctl(void *, int, int); 229 int glxpcib_gpio_pin_read(void *, int); 230 void glxpcib_gpio_pin_write(void *, int, int); 231 #endif 232 int glxpcib_smb_acquire_bus(void *, int); 233 void glxpcib_smb_release_bus(void *, int); 234 int glxpcib_smb_send_start(void *, int); 235 int glxpcib_smb_send_stop(void *, int); 236 void glxpcib_smb_send_ack(void *, int); 237 int glxpcib_smb_initiate_xfer(void *, i2c_addr_t, int); 238 int glxpcib_smb_read_byte(void *, uint8_t *, int); 239 int glxpcib_smb_write_byte(void *, uint8_t, int); 240 void glxpcib_smb_reset(struct glxpcib_softc *); 241 int glxpcib_smb_wait(struct glxpcib_softc *, int, int); 242 #endif 243 244 const struct pci_matchid glxpcib_devices[] = { 245 { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_PCIB } 246 }; 247 248 int 249 glxpcib_match(struct device *parent, void *match, void *aux) 250 { 251 if (pci_matchbyid((struct pci_attach_args *)aux, glxpcib_devices, 252 nitems(glxpcib_devices))) { 253 /* needs to win over pcib */ 254 return 2; 255 } 256 257 return 0; 258 } 259 260 void 261 glxpcib_attach(struct device *parent, struct device *self, void *aux) 262 { 263 struct glxpcib_softc *sc = (struct glxpcib_softc *)self; 264 struct timecounter *tc = &sc->sc_timecounter; 265 #ifndef SMALL_KERNEL 266 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 267 u_int64_t wa; 268 #if NGPIO > 0 269 u_int64_t ga; 270 struct gpiobus_attach_args gba; 271 int i, gpio = 0; 272 #endif 273 u_int64_t sa; 274 struct i2cbus_attach_args iba; 275 int i2c = 0; 276 #endif 277 tc->tc_get_timecount = glxpcib_get_timecount; 278 tc->tc_counter_mask = 0xffffffff; 279 tc->tc_frequency = 3579545; 280 tc->tc_name = "CS5536"; 281 #ifdef __loongson__ 282 tc->tc_quality = 0; 283 #else 284 tc->tc_quality = 1000; 285 #endif 286 tc->tc_priv = sc; 287 tc_init(tc); 288 289 printf(": rev %d, 32-bit %lluHz timer", 290 (int)rdmsr(AMD5536_REV) & AMD5536_REV_MASK, 291 tc->tc_frequency); 292 293 #ifndef SMALL_KERNEL 294 /* Attach the watchdog timer */ 295 sc->sc_iot = pa->pa_iot; 296 wa = rdmsr(MSR_LBAR_MFGPT); 297 if (wa & MSR_LBAR_ENABLE && 298 !bus_space_map(sc->sc_iot, wa & MSR_MFGPT_ADDR_MASK, 299 MSR_MFGPT_SIZE, 0, &sc->sc_ioh)) { 300 /* count in seconds (as upper level desires) */ 301 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_SETUP, 302 AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2EV | 303 AMD5536_MFGPT_CMP2 | AMD5536_MFGPT_DIV_MASK); 304 wdog_register(sc, glxpcib_wdogctl_cb); 305 sc->sc_wdog = 1; 306 printf(", watchdog"); 307 } 308 309 #if NGPIO > 0 310 /* map GPIO I/O space */ 311 sc->sc_gpio_iot = pa->pa_iot; 312 ga = rdmsr(MSR_LBAR_GPIO); 313 if (ga & MSR_LBAR_ENABLE && 314 !bus_space_map(sc->sc_gpio_iot, ga & MSR_GPIO_ADDR_MASK, 315 MSR_GPIO_SIZE, 0, &sc->sc_gpio_ioh)) { 316 printf(", gpio"); 317 318 /* initialize pin array */ 319 for (i = 0; i < AMD5536_GPIO_NPINS; i++) { 320 sc->sc_gpio_pins[i].pin_num = i; 321 sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | 322 GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | 323 GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | 324 GPIO_PIN_INVIN | GPIO_PIN_INVOUT; 325 326 /* read initial state */ 327 sc->sc_gpio_pins[i].pin_state = 328 glxpcib_gpio_pin_read(sc, i); 329 } 330 331 /* create controller tag */ 332 sc->sc_gpio_gc.gp_cookie = sc; 333 sc->sc_gpio_gc.gp_pin_read = glxpcib_gpio_pin_read; 334 sc->sc_gpio_gc.gp_pin_write = glxpcib_gpio_pin_write; 335 sc->sc_gpio_gc.gp_pin_ctl = glxpcib_gpio_pin_ctl; 336 337 gba.gba_name = "gpio"; 338 gba.gba_gc = &sc->sc_gpio_gc; 339 gba.gba_pins = sc->sc_gpio_pins; 340 gba.gba_npins = AMD5536_GPIO_NPINS; 341 gpio = 1; 342 343 } 344 #endif /* NGPIO */ 345 346 /* Map SMB I/O space */ 347 sc->sc_smb_iot = pa->pa_iot; 348 sa = rdmsr(MSR_LBAR_SMB); 349 if (sa & MSR_LBAR_ENABLE && 350 !bus_space_map(sc->sc_smb_iot, sa & MSR_SMB_ADDR_MASK, 351 MSR_SMB_SIZE, 0, &sc->sc_smb_ioh)) { 352 printf(", i2c"); 353 354 /* Enable controller */ 355 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, 356 AMD5536_SMB_CTL2, AMD5536_SMB_CTL2_EN | 357 AMD5536_SMB_CTL2_FREQ); 358 359 /* Disable interrupts */ 360 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, 361 AMD5536_SMB_CTL1, 0); 362 363 /* Disable slave address */ 364 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, 365 AMD5536_SMB_ADDR, 0); 366 367 /* Stall the bus after start */ 368 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, 369 AMD5536_SMB_CTL1, AMD5536_SMB_CTL1_STASTRE); 370 371 /* Attach I2C framework */ 372 sc->sc_smb_ic.ic_cookie = sc; 373 sc->sc_smb_ic.ic_acquire_bus = glxpcib_smb_acquire_bus; 374 sc->sc_smb_ic.ic_release_bus = glxpcib_smb_release_bus; 375 sc->sc_smb_ic.ic_send_start = glxpcib_smb_send_start; 376 sc->sc_smb_ic.ic_send_stop = glxpcib_smb_send_stop; 377 sc->sc_smb_ic.ic_initiate_xfer = glxpcib_smb_initiate_xfer; 378 sc->sc_smb_ic.ic_read_byte = glxpcib_smb_read_byte; 379 sc->sc_smb_ic.ic_write_byte = glxpcib_smb_write_byte; 380 381 rw_init(&sc->sc_smb_lck, "iiclk"); 382 383 bzero(&iba, sizeof(iba)); 384 iba.iba_name = "iic"; 385 iba.iba_tag = &sc->sc_smb_ic; 386 i2c = 1; 387 } 388 #endif /* SMALL_KERNEL */ 389 pcibattach(parent, self, aux); 390 391 #ifndef SMALL_KERNEL 392 #if NGPIO > 0 393 if (gpio) 394 config_found(&sc->sc_dev, &gba, gpiobus_print); 395 #endif 396 if (i2c) 397 config_found(&sc->sc_dev, &iba, iicbus_print); 398 #endif 399 } 400 401 int 402 glxpcib_activate(struct device *self, int act) 403 { 404 #ifndef SMALL_KERNEL 405 struct glxpcib_softc *sc = (struct glxpcib_softc *)self; 406 uint i; 407 #endif 408 int rv = 0; 409 410 switch (act) { 411 case DVACT_QUIESCE: 412 rv = config_activate_children(self, act); 413 break; 414 case DVACT_SUSPEND: 415 #ifndef SMALL_KERNEL 416 if (sc->sc_wdog) { 417 sc->sc_wdog_period = bus_space_read_2(sc->sc_iot, 418 sc->sc_ioh, AMD5536_MFGPT0_CMP2); 419 glxpcib_wdogctl_cb(sc, 0); 420 } 421 #endif 422 rv = config_activate_children(self, act); 423 #ifndef SMALL_KERNEL 424 for (i = 0; i < nitems(glxpcib_msrlist); i++) 425 sc->sc_msrsave[i] = rdmsr(glxpcib_msrlist[i]); 426 #endif 427 428 break; 429 case DVACT_RESUME: 430 #ifndef SMALL_KERNEL 431 if (sc->sc_wdog) 432 glxpcib_wdogctl_cb(sc, sc->sc_wdog_period); 433 for (i = 0; i < nitems(glxpcib_msrlist); i++) 434 wrmsr(glxpcib_msrlist[i], sc->sc_msrsave[i]); 435 #endif 436 rv = config_activate_children(self, act); 437 break; 438 } 439 return (rv); 440 } 441 442 u_int 443 glxpcib_get_timecount(struct timecounter *tc) 444 { 445 return rdmsr(AMD5536_TMC); 446 } 447 448 #ifndef SMALL_KERNEL 449 int 450 glxpcib_wdogctl_cb(void *v, int period) 451 { 452 struct glxpcib_softc *sc = v; 453 454 if (period > 0xffff) 455 period = 0xffff; 456 457 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_SETUP, 458 AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2); 459 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CNT, 0); 460 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CMP2, period); 461 462 if (period) 463 wrmsr(AMD5536_MFGPT_NR, 464 rdmsr(AMD5536_MFGPT_NR) | AMD5536_MFGPT0_C2_RSTEN); 465 else 466 wrmsr(AMD5536_MFGPT_NR, 467 rdmsr(AMD5536_MFGPT_NR) & ~AMD5536_MFGPT0_C2_RSTEN); 468 469 return period; 470 } 471 472 #if NGPIO > 0 473 int 474 glxpcib_gpio_pin_read(void *arg, int pin) 475 { 476 struct glxpcib_softc *sc = arg; 477 u_int32_t data; 478 int reg, off = 0; 479 480 reg = AMD5536_GPIO_IN_EN; 481 if (pin > 15) { 482 pin &= 0x0f; 483 off = AMD5536_GPIOH_OFFSET; 484 } 485 reg += off; 486 data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg); 487 488 if (data & (1 << pin)) 489 reg = AMD5536_GPIO_READ_BACK + off; 490 else 491 reg = AMD5536_GPIO_OUT_VAL + off; 492 493 data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg); 494 495 return data & 1 << pin ? GPIO_PIN_HIGH : GPIO_PIN_LOW; 496 } 497 498 void 499 glxpcib_gpio_pin_write(void *arg, int pin, int value) 500 { 501 struct glxpcib_softc *sc = arg; 502 u_int32_t data; 503 int reg; 504 505 reg = AMD5536_GPIO_OUT_VAL; 506 if (pin > 15) { 507 pin &= 0x0f; 508 reg += AMD5536_GPIOH_OFFSET; 509 } 510 if (value == 1) 511 data = 1 << pin; 512 else 513 data = 1 << (pin + 16); 514 515 bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data); 516 } 517 518 void 519 glxpcib_gpio_pin_ctl(void *arg, int pin, int flags) 520 { 521 struct glxpcib_softc *sc = arg; 522 int n, reg[7], val[7], nreg = 0, off = 0; 523 524 if (pin > 15) { 525 pin &= 0x0f; 526 off = AMD5536_GPIOH_OFFSET; 527 } 528 529 reg[nreg] = AMD5536_GPIO_IN_EN + off; 530 if (flags & GPIO_PIN_INPUT) 531 val[nreg++] = 1 << pin; 532 else 533 val[nreg++] = 1 << (pin + 16); 534 535 reg[nreg] = AMD5536_GPIO_OUT_EN + off; 536 if (flags & GPIO_PIN_OUTPUT) 537 val[nreg++] = 1 << pin; 538 else 539 val[nreg++] = 1 << (pin + 16); 540 541 reg[nreg] = AMD5536_GPIO_OD_EN + off; 542 if (flags & GPIO_PIN_OPENDRAIN) 543 val[nreg++] = 1 << pin; 544 else 545 val[nreg++] = 1 << (pin + 16); 546 547 reg[nreg] = AMD5536_GPIO_PU_EN + off; 548 if (flags & GPIO_PIN_PULLUP) 549 val[nreg++] = 1 << pin; 550 else 551 val[nreg++] = 1 << (pin + 16); 552 553 reg[nreg] = AMD5536_GPIO_PD_EN + off; 554 if (flags & GPIO_PIN_PULLDOWN) 555 val[nreg++] = 1 << pin; 556 else 557 val[nreg++] = 1 << (pin + 16); 558 559 reg[nreg] = AMD5536_GPIO_IN_INVRT_EN + off; 560 if (flags & GPIO_PIN_INVIN) 561 val[nreg++] = 1 << pin; 562 else 563 val[nreg++] = 1 << (pin + 16); 564 565 reg[nreg] = AMD5536_GPIO_OUT_INVRT_EN + off; 566 if (flags & GPIO_PIN_INVOUT) 567 val[nreg++] = 1 << pin; 568 else 569 val[nreg++] = 1 << (pin + 16); 570 571 /* set flags */ 572 for (n = 0; n < nreg; n++) 573 bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg[n], 574 val[n]); 575 } 576 #endif /* GPIO */ 577 578 int 579 glxpcib_smb_acquire_bus(void *arg, int flags) 580 { 581 struct glxpcib_softc *sc = arg; 582 583 if (cold || flags & I2C_F_POLL) 584 return (0); 585 586 return (rw_enter(&sc->sc_smb_lck, RW_WRITE | RW_INTR)); 587 } 588 589 void 590 glxpcib_smb_release_bus(void *arg, int flags) 591 { 592 struct glxpcib_softc *sc = arg; 593 594 if (cold || flags & I2C_F_POLL) 595 return; 596 597 rw_exit(&sc->sc_smb_lck); 598 } 599 600 int 601 glxpcib_smb_send_start(void *arg, int flags) 602 { 603 struct glxpcib_softc *sc = arg; 604 u_int8_t ctl; 605 606 ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 607 AMD5536_SMB_CTL1); 608 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1, 609 ctl | AMD5536_SMB_CTL1_START); 610 611 return (0); 612 } 613 614 int 615 glxpcib_smb_send_stop(void *arg, int flags) 616 { 617 struct glxpcib_softc *sc = arg; 618 u_int8_t ctl; 619 620 ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 621 AMD5536_SMB_CTL1); 622 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1, 623 ctl | AMD5536_SMB_CTL1_STOP); 624 625 return (0); 626 } 627 628 void 629 glxpcib_smb_send_ack(void *arg, int flags) 630 { 631 struct glxpcib_softc *sc = arg; 632 u_int8_t ctl; 633 634 ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 635 AMD5536_SMB_CTL1); 636 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1, 637 ctl | AMD5536_SMB_CTL1_ACK); 638 } 639 640 int 641 glxpcib_smb_initiate_xfer(void *arg, i2c_addr_t addr, int flags) 642 { 643 struct glxpcib_softc *sc = arg; 644 int error, dir; 645 646 /* Issue start condition */ 647 glxpcib_smb_send_start(sc, flags); 648 649 /* Wait for bus mastership */ 650 if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_MASTER | 651 AMD5536_SMB_STS_SDAST, flags)) != 0) 652 return (error); 653 654 /* Send address byte */ 655 dir = (flags & I2C_F_READ ? 1 : 0); 656 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_SDA, 657 (addr << 1) | dir); 658 659 return (0); 660 } 661 662 int 663 glxpcib_smb_read_byte(void *arg, uint8_t *bytep, int flags) 664 { 665 struct glxpcib_softc *sc = arg; 666 int error; 667 668 /* Wait for the bus to be ready */ 669 if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags))) 670 return (error); 671 672 /* Acknowledge the last byte */ 673 if (flags & I2C_F_LAST) 674 glxpcib_smb_send_ack(sc, 0); 675 676 /* Read data byte */ 677 *bytep = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 678 AMD5536_SMB_SDA); 679 680 return (0); 681 } 682 683 int 684 glxpcib_smb_write_byte(void *arg, uint8_t byte, int flags) 685 { 686 struct glxpcib_softc *sc = arg; 687 int error; 688 689 /* Wait for the bus to be ready */ 690 if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags))) 691 return (error); 692 693 /* Send stop after the last byte */ 694 if (flags & I2C_F_STOP) 695 glxpcib_smb_send_stop(sc, 0); 696 697 /* Write data byte */ 698 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_SDA, 699 byte); 700 701 return (0); 702 } 703 704 void 705 glxpcib_smb_reset(struct glxpcib_softc *sc) 706 { 707 u_int8_t st; 708 709 /* Clear MASTER, NEGACK and BER */ 710 st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS); 711 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS, st | 712 AMD5536_SMB_STS_MASTER | AMD5536_SMB_STS_NEGACK | 713 AMD5536_SMB_STS_BER); 714 715 /* Disable and re-enable controller */ 716 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2, 0); 717 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2, 718 AMD5536_SMB_CTL2_EN | AMD5536_SMB_CTL2_FREQ); 719 720 /* Send stop */ 721 glxpcib_smb_send_stop(sc, 0); 722 } 723 724 int 725 glxpcib_smb_wait(struct glxpcib_softc *sc, int bits, int flags) 726 { 727 u_int8_t st; 728 int i; 729 730 for (i = 0; i < 100; i++) { 731 st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, 732 AMD5536_SMB_STS); 733 if (st & AMD5536_SMB_STS_BER) { 734 printf("%s: bus error, bits=%#x st=%#x\n", 735 sc->sc_dev.dv_xname, bits, st); 736 glxpcib_smb_reset(sc); 737 return (EIO); 738 } 739 if ((bits & AMD5536_SMB_STS_MASTER) == 0 && 740 (st & AMD5536_SMB_STS_NEGACK)) { 741 glxpcib_smb_reset(sc); 742 return (EIO); 743 } 744 if (st & AMD5536_SMB_STS_STASTR) 745 bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, 746 AMD5536_SMB_STS, AMD5536_SMB_STS_STASTR); 747 if ((st & bits) == bits) 748 break; 749 delay(2); 750 } 751 if ((st & bits) != bits) { 752 glxpcib_smb_reset(sc); 753 return (ETIMEDOUT); 754 } 755 return (0); 756 } 757 #endif /* SMALL_KERNEL */ 758