1/* $OpenBSD: glxpcib.c,v 1.16 2022/03/11 18:00:45 mpi Exp $ */ 2 3/* 4 * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org> 5 * Copyright (c) 2007 Michael Shalayeff 6 * All rights reserved. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 17 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 18 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21/* 22 * AMD CS5536 series LPC bridge also containing timer, watchdog, and GPIO. 23 */ 24 25#include <sys/param.h> 26#include <sys/systm.h> 27#include <sys/device.h> 28#include <sys/gpio.h> 29#include <sys/timetc.h> 30#include <sys/rwlock.h> 31 32#include <machine/bus.h> 33#ifdef __i386__ 34#include <machine/cpufunc.h> 35#endif 36 37#include <dev/gpio/gpiovar.h> 38#include <dev/i2c/i2cvar.h> 39 40#include <dev/pci/pcireg.h> 41#include <dev/pci/pcivar.h> 42#include <dev/pci/pcidevs.h> 43 44#include <dev/pci/glxreg.h> 45#include <dev/pci/glxvar.h> 46 47#include "gpio.h" 48 49#define AMD5536_REV GLCP_CHIP_REV_ID 50#define AMD5536_REV_MASK 0xff 51#define AMD5536_TMC PMC_LTMR 52 53#define MSR_LBAR_ENABLE 0x100000000ULL 54 55/* Multi-Functional General Purpose Timer */ 56#define MSR_LBAR_MFGPT DIVIL_LBAR_MFGPT 57#define MSR_MFGPT_SIZE 0x40 58#define MSR_MFGPT_ADDR_MASK 0xffc0 59#define AMD5536_MFGPT0_CMP1 0x00000000 60#define AMD5536_MFGPT0_CMP2 0x00000002 61#define AMD5536_MFGPT0_CNT 0x00000004 62#define AMD5536_MFGPT0_SETUP 0x00000006 63#define AMD5536_MFGPT_DIV_MASK 0x000f /* div = 1 << mask */ 64#define AMD5536_MFGPT_CLKSEL 0x0010 65#define AMD5536_MFGPT_REV_EN 0x0020 66#define AMD5536_MFGPT_CMP1DIS 0x0000 67#define AMD5536_MFGPT_CMP1EQ 0x0040 68#define AMD5536_MFGPT_CMP1GE 0x0080 69#define AMD5536_MFGPT_CMP1EV 0x00c0 70#define AMD5536_MFGPT_CMP2DIS 0x0000 71#define AMD5536_MFGPT_CMP2EQ 0x0100 72#define AMD5536_MFGPT_CMP2GE 0x0200 73#define AMD5536_MFGPT_CMP2EV 0x0300 74#define AMD5536_MFGPT_STOP_EN 0x0800 75#define AMD5536_MFGPT_SET 0x1000 76#define AMD5536_MFGPT_CMP1 0x2000 77#define AMD5536_MFGPT_CMP2 0x4000 78#define AMD5536_MFGPT_CNT_EN 0x8000 79#define AMD5536_MFGPT_IRQ MFGPT_IRQ 80#define AMD5536_MFGPT0_C1_IRQM 0x00000001 81#define AMD5536_MFGPT1_C1_IRQM 0x00000002 82#define AMD5536_MFGPT2_C1_IRQM 0x00000004 83#define AMD5536_MFGPT3_C1_IRQM 0x00000008 84#define AMD5536_MFGPT4_C1_IRQM 0x00000010 85#define AMD5536_MFGPT5_C1_IRQM 0x00000020 86#define AMD5536_MFGPT6_C1_IRQM 0x00000040 87#define AMD5536_MFGPT7_C1_IRQM 0x00000080 88#define AMD5536_MFGPT0_C2_IRQM 0x00000100 89#define AMD5536_MFGPT1_C2_IRQM 0x00000200 90#define AMD5536_MFGPT2_C2_IRQM 0x00000400 91#define AMD5536_MFGPT3_C2_IRQM 0x00000800 92#define AMD5536_MFGPT4_C2_IRQM 0x00001000 93#define AMD5536_MFGPT5_C2_IRQM 0x00002000 94#define AMD5536_MFGPT6_C2_IRQM 0x00004000 95#define AMD5536_MFGPT7_C2_IRQM 0x00008000 96#define AMD5536_MFGPT_NR MFGPT_NR 97#define AMD5536_MFGPT0_C1_NMIM 0x00000001 98#define AMD5536_MFGPT1_C1_NMIM 0x00000002 99#define AMD5536_MFGPT2_C1_NMIM 0x00000004 100#define AMD5536_MFGPT3_C1_NMIM 0x00000008 101#define AMD5536_MFGPT4_C1_NMIM 0x00000010 102#define AMD5536_MFGPT5_C1_NMIM 0x00000020 103#define AMD5536_MFGPT6_C1_NMIM 0x00000040 104#define AMD5536_MFGPT7_C1_NMIM 0x00000080 105#define AMD5536_MFGPT0_C2_NMIM 0x00000100 106#define AMD5536_MFGPT1_C2_NMIM 0x00000200 107#define AMD5536_MFGPT2_C2_NMIM 0x00000400 108#define AMD5536_MFGPT3_C2_NMIM 0x00000800 109#define AMD5536_MFGPT4_C2_NMIM 0x00001000 110#define AMD5536_MFGPT5_C2_NMIM 0x00002000 111#define AMD5536_MFGPT6_C2_NMIM 0x00004000 112#define AMD5536_MFGPT7_C2_NMIM 0x00008000 113#define AMD5536_NMI_LEG 0x00010000 114#define AMD5536_MFGPT0_C2_RSTEN 0x01000000 115#define AMD5536_MFGPT1_C2_RSTEN 0x02000000 116#define AMD5536_MFGPT2_C2_RSTEN 0x04000000 117#define AMD5536_MFGPT3_C2_RSTEN 0x08000000 118#define AMD5536_MFGPT4_C2_RSTEN 0x10000000 119#define AMD5536_MFGPT5_C2_RSTEN 0x20000000 120#define AMD5536_MFGPT_SETUP MFGPT_SETUP 121 122/* GPIO */ 123#define MSR_LBAR_GPIO DIVIL_LBAR_GPIO 124#define MSR_GPIO_SIZE 0x100 125#define MSR_GPIO_ADDR_MASK 0xff00 126#define AMD5536_GPIO_NPINS 32 127#define AMD5536_GPIOH_OFFSET 0x80 /* high bank register offset */ 128#define AMD5536_GPIO_OUT_VAL 0x00 /* output value */ 129#define AMD5536_GPIO_OUT_EN 0x04 /* output enable */ 130#define AMD5536_GPIO_OD_EN 0x08 /* open-drain enable */ 131#define AMD5536_GPIO_OUT_INVRT_EN 0x0c /* invert output */ 132#define AMD5536_GPIO_PU_EN 0x18 /* pull-up enable */ 133#define AMD5536_GPIO_PD_EN 0x1c /* pull-down enable */ 134#define AMD5536_GPIO_IN_EN 0x20 /* input enable */ 135#define AMD5536_GPIO_IN_INVRT_EN 0x24 /* invert input */ 136#define AMD5536_GPIO_READ_BACK 0x30 /* read back value */ 137 138/* SMB */ 139#define MSR_LBAR_SMB DIVIL_LBAR_SMB 140#define MSR_SMB_SIZE 0x08 141#define MSR_SMB_ADDR_MASK 0xfff8 142#define AMD5536_SMB_SDA 0x00 /* serial data */ 143#define AMD5536_SMB_STS 0x01 /* status */ 144#define AMD5536_SMB_STS_SLVSTOP 0x80 /* slave stop */ 145#define AMD5536_SMB_STS_SDAST 0x40 /* smb data status */ 146#define AMD5536_SMB_STS_BER 0x20 /* bus error */ 147#define AMD5536_SMB_STS_NEGACK 0x10 /* negative acknowledge */ 148#define AMD5536_SMB_STS_STASTR 0x08 /* stall after start */ 149#define AMD5536_SMB_STS_MASTER 0x02 /* master */ 150#define AMD5536_SMB_STS_XMIT 0x01 /* transmit or receive */ 151#define AMD5536_SMB_CST 0x02 /* control status */ 152#define AMD5536_SMB_CST_MATCH 0x04 /* address match */ 153#define AMD5536_SMB_CST_BB 0x02 /* bus busy */ 154#define AMD5536_SMB_CST_BUSY 0x01 /* busy */ 155#define AMD5536_SMB_CTL1 0x03 /* control 1 */ 156#define AMD5536_SMB_CTL1_STASTRE 0x80 /* stall after start enable */ 157#define AMD5536_SMB_CTL1_ACK 0x10 /* receive acknowledge */ 158#define AMD5536_SMB_CTL1_INTEN 0x04 /* interrupt enable */ 159#define AMD5536_SMB_CTL1_STOP 0x02 /* stop */ 160#define AMD5536_SMB_CTL1_START 0x01 /* start */ 161#define AMD5536_SMB_ADDR 0x04 /* serial address */ 162#define AMD5536_SMB_ADDR_SAEN 0x80 /* slave enable */ 163#define AMD5536_SMB_CTL2 0x05 /* control 2 */ 164#define AMD5536_SMB_CTL2_EN 0x01 /* enable clock */ 165#define AMD5536_SMB_CTL2_FREQ 0x78 /* 100 kHz */ 166#define AMD5536_SMB_CTL3 0x06 /* control 3 */ 167 168/* PMS */ 169#define MSR_LBAR_PMS DIVIL_LBAR_PMS 170#define MSR_PMS_SIZE 0x80 171#define MSR_PMS_ADDR_MASK 0xff80 172#define AMD5536_PMS_SSC 0x54 173#define AMD5536_PMS_SSC_PI 0x00040000 174#define AMD5536_PMS_SSC_CLR_PI 0x00020000 175#define AMD5536_PMS_SSC_SET_PI 0x00010000 176 177/* 178 * MSR registers we want to preserve across suspend/resume 179 */ 180const uint32_t glxpcib_msrlist[] = { 181 GLIU_PAE, 182 GLCP_GLD_MSR_PM, 183 DIVIL_BALL_OPTS 184}; 185 186struct 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 215struct cfdriver glxpcib_cd = { 216 NULL, "glxpcib", DV_DULL 217}; 218 219int glxpcib_match(struct device *, void *, void *); 220void glxpcib_attach(struct device *, struct device *, void *); 221int glxpcib_activate(struct device *, int); 222int glxpcib_search(struct device *, void *, void *); 223int glxpcib_print(void *, const char *); 224 225const 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 */ 231void pcibattach(struct device *parent, struct device *self, void *aux); 232 233u_int glxpcib_get_timecount(struct timecounter *tc); 234 235#ifndef SMALL_KERNEL 236int glxpcib_wdogctl_cb(void *, int); 237#if NGPIO > 0 238void glxpcib_gpio_pin_ctl(void *, int, int); 239int glxpcib_gpio_pin_read(void *, int); 240void glxpcib_gpio_pin_write(void *, int, int); 241#endif 242int glxpcib_smb_acquire_bus(void *, int); 243void glxpcib_smb_release_bus(void *, int); 244int glxpcib_smb_send_start(void *, int); 245int glxpcib_smb_send_stop(void *, int); 246void glxpcib_smb_send_ack(void *, int); 247int glxpcib_smb_initiate_xfer(void *, i2c_addr_t, int); 248int glxpcib_smb_read_byte(void *, uint8_t *, int); 249int glxpcib_smb_write_byte(void *, uint8_t, int); 250void glxpcib_smb_reset(struct glxpcib_softc *); 251int glxpcib_smb_wait(struct glxpcib_softc *, int, int); 252#endif 253 254const struct pci_matchid glxpcib_devices[] = { 255 { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_PCIB } 256}; 257 258int 259glxpcib_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 270void 271glxpcib_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 423int 424glxpcib_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 471u_int 472glxpcib_get_timecount(struct timecounter *tc) 473{ 474 return rdmsr(AMD5536_TMC); 475} 476 477#ifndef SMALL_KERNEL 478int 479glxpcib_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 502int 503glxpcib_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 527void 528glxpcib_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 547void 548glxpcib_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 607int 608glxpcib_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 618void 619glxpcib_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 629int 630glxpcib_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 643int 644glxpcib_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 657void 658glxpcib_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 669int 670glxpcib_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 691int 692glxpcib_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 712int 713glxpcib_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 723int 724glxpcib_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 752int 753glxpcib_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 773void 774glxpcib_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 793int 794glxpcib_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