1 /* $OpenBSD: glxpcib.c,v 1.3 2010/10/23 17:42:57 pirofti 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 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/pci/pcireg.h> 39 #include <dev/pci/pcivar.h> 40 #include <dev/pci/pcidevs.h> 41 42 #include <dev/pci/glxreg.h> 43 #include <dev/pci/glxvar.h> 44 45 #include "gpio.h" 46 47 #define AMD5536_REV GLCP_CHIP_REV_ID 48 #define AMD5536_REV_MASK 0xff 49 #define AMD5536_TMC PMC_LTMR 50 51 #define MSR_LBAR_ENABLE 0x100000000ULL 52 53 /* Multi-Functional General Purpose Timer */ 54 #define MSR_LBAR_MFGPT DIVIL_LBAR_MFGPT 55 #define MSR_MFGPT_SIZE 0x40 56 #define MSR_MFGPT_ADDR_MASK 0xffc0 57 #define AMD5536_MFGPT0_CMP1 0x00000000 58 #define AMD5536_MFGPT0_CMP2 0x00000002 59 #define AMD5536_MFGPT0_CNT 0x00000004 60 #define AMD5536_MFGPT0_SETUP 0x00000006 61 #define AMD5536_MFGPT_DIV_MASK 0x000f /* div = 1 << mask */ 62 #define AMD5536_MFGPT_CLKSEL 0x0010 63 #define AMD5536_MFGPT_REV_EN 0x0020 64 #define AMD5536_MFGPT_CMP1DIS 0x0000 65 #define AMD5536_MFGPT_CMP1EQ 0x0040 66 #define AMD5536_MFGPT_CMP1GE 0x0080 67 #define AMD5536_MFGPT_CMP1EV 0x00c0 68 #define AMD5536_MFGPT_CMP2DIS 0x0000 69 #define AMD5536_MFGPT_CMP2EQ 0x0100 70 #define AMD5536_MFGPT_CMP2GE 0x0200 71 #define AMD5536_MFGPT_CMP2EV 0x0300 72 #define AMD5536_MFGPT_STOP_EN 0x0800 73 #define AMD5536_MFGPT_SET 0x1000 74 #define AMD5536_MFGPT_CMP1 0x2000 75 #define AMD5536_MFGPT_CMP2 0x4000 76 #define AMD5536_MFGPT_CNT_EN 0x8000 77 #define AMD5536_MFGPT_IRQ MFGPT_IRQ 78 #define AMD5536_MFGPT0_C1_IRQM 0x00000001 79 #define AMD5536_MFGPT1_C1_IRQM 0x00000002 80 #define AMD5536_MFGPT2_C1_IRQM 0x00000004 81 #define AMD5536_MFGPT3_C1_IRQM 0x00000008 82 #define AMD5536_MFGPT4_C1_IRQM 0x00000010 83 #define AMD5536_MFGPT5_C1_IRQM 0x00000020 84 #define AMD5536_MFGPT6_C1_IRQM 0x00000040 85 #define AMD5536_MFGPT7_C1_IRQM 0x00000080 86 #define AMD5536_MFGPT0_C2_IRQM 0x00000100 87 #define AMD5536_MFGPT1_C2_IRQM 0x00000200 88 #define AMD5536_MFGPT2_C2_IRQM 0x00000400 89 #define AMD5536_MFGPT3_C2_IRQM 0x00000800 90 #define AMD5536_MFGPT4_C2_IRQM 0x00001000 91 #define AMD5536_MFGPT5_C2_IRQM 0x00002000 92 #define AMD5536_MFGPT6_C2_IRQM 0x00004000 93 #define AMD5536_MFGPT7_C2_IRQM 0x00008000 94 #define AMD5536_MFGPT_NR MFGPT_NR 95 #define AMD5536_MFGPT0_C1_NMIM 0x00000001 96 #define AMD5536_MFGPT1_C1_NMIM 0x00000002 97 #define AMD5536_MFGPT2_C1_NMIM 0x00000004 98 #define AMD5536_MFGPT3_C1_NMIM 0x00000008 99 #define AMD5536_MFGPT4_C1_NMIM 0x00000010 100 #define AMD5536_MFGPT5_C1_NMIM 0x00000020 101 #define AMD5536_MFGPT6_C1_NMIM 0x00000040 102 #define AMD5536_MFGPT7_C1_NMIM 0x00000080 103 #define AMD5536_MFGPT0_C2_NMIM 0x00000100 104 #define AMD5536_MFGPT1_C2_NMIM 0x00000200 105 #define AMD5536_MFGPT2_C2_NMIM 0x00000400 106 #define AMD5536_MFGPT3_C2_NMIM 0x00000800 107 #define AMD5536_MFGPT4_C2_NMIM 0x00001000 108 #define AMD5536_MFGPT5_C2_NMIM 0x00002000 109 #define AMD5536_MFGPT6_C2_NMIM 0x00004000 110 #define AMD5536_MFGPT7_C2_NMIM 0x00008000 111 #define AMD5536_NMI_LEG 0x00010000 112 #define AMD5536_MFGPT0_C2_RSTEN 0x01000000 113 #define AMD5536_MFGPT1_C2_RSTEN 0x02000000 114 #define AMD5536_MFGPT2_C2_RSTEN 0x04000000 115 #define AMD5536_MFGPT3_C2_RSTEN 0x08000000 116 #define AMD5536_MFGPT4_C2_RSTEN 0x10000000 117 #define AMD5536_MFGPT5_C2_RSTEN 0x20000000 118 #define AMD5536_MFGPT_SETUP MFGPT_SETUP 119 120 /* GPIO */ 121 #define MSR_LBAR_GPIO DIVIL_LBAR_GPIO 122 #define MSR_GPIO_SIZE 0x100 123 #define MSR_GPIO_ADDR_MASK 0xff00 124 #define AMD5536_GPIO_NPINS 32 125 #define AMD5536_GPIOH_OFFSET 0x80 /* high bank register offset */ 126 #define AMD5536_GPIO_OUT_VAL 0x00 /* output value */ 127 #define AMD5536_GPIO_OUT_EN 0x04 /* output enable */ 128 #define AMD5536_GPIO_OD_EN 0x08 /* open-drain enable */ 129 #define AMD5536_GPIO_OUT_INVRT_EN 0x0c /* invert output */ 130 #define AMD5536_GPIO_PU_EN 0x18 /* pull-up enable */ 131 #define AMD5536_GPIO_PD_EN 0x1c /* pull-down enable */ 132 #define AMD5536_GPIO_IN_EN 0x20 /* input enable */ 133 #define AMD5536_GPIO_IN_INVRT_EN 0x24 /* invert input */ 134 #define AMD5536_GPIO_READ_BACK 0x30 /* read back value */ 135 136 /* 137 * MSR registers we want to preserve accross suspend/resume 138 */ 139 const uint32_t glxpcib_msrlist[] = { 140 GLIU_PAE, 141 GLCP_GLD_MSR_PM, 142 DIVIL_BALL_OPTS 143 }; 144 145 struct glxpcib_softc { 146 struct device sc_dev; 147 148 struct timecounter sc_timecounter; 149 bus_space_tag_t sc_iot; 150 bus_space_handle_t sc_ioh; 151 152 uint64_t sc_msrsave[nitems(glxpcib_msrlist)]; 153 154 #if !defined(SMALL_KERNEL) && NGPIO > 0 155 /* GPIO interface */ 156 bus_space_tag_t sc_gpio_iot; 157 bus_space_handle_t sc_gpio_ioh; 158 struct gpio_chipset_tag sc_gpio_gc; 159 gpio_pin_t sc_gpio_pins[AMD5536_GPIO_NPINS]; 160 int sc_wdog; 161 int sc_wdog_period; 162 #endif 163 }; 164 165 struct cfdriver glxpcib_cd = { 166 NULL, "glxpcib", DV_DULL 167 }; 168 169 int glxpcib_match(struct device *, void *, void *); 170 void glxpcib_attach(struct device *, struct device *, void *); 171 int glxpcib_activate(struct device *, int); 172 173 struct cfattach glxpcib_ca = { 174 sizeof(struct glxpcib_softc), glxpcib_match, glxpcib_attach, 175 NULL, glxpcib_activate 176 }; 177 178 /* from arch/<*>/pci/pcib.c */ 179 void pcibattach(struct device *parent, struct device *self, void *aux); 180 181 u_int glxpcib_get_timecount(struct timecounter *tc); 182 183 #if !defined(SMALL_KERNEL) && NGPIO > 0 184 void glxpcib_gpio_pin_ctl(void *, int, int); 185 int glxpcib_gpio_pin_read(void *, int); 186 void glxpcib_gpio_pin_write(void *, int, int); 187 int glxpcib_wdogctl_cb(void *, int); 188 #endif 189 190 const struct pci_matchid glxpcib_devices[] = { 191 { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_PCIB } 192 }; 193 194 int 195 glxpcib_match(struct device *parent, void *match, void *aux) 196 { 197 if (pci_matchbyid((struct pci_attach_args *)aux, glxpcib_devices, 198 nitems(glxpcib_devices))) { 199 /* needs to win over pcib */ 200 return 2; 201 } 202 203 return 0; 204 } 205 206 void 207 glxpcib_attach(struct device *parent, struct device *self, void *aux) 208 { 209 struct glxpcib_softc *sc = (struct glxpcib_softc *)self; 210 struct timecounter *tc = &sc->sc_timecounter; 211 #if !defined(SMALL_KERNEL) && NGPIO > 0 212 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 213 u_int64_t wa, ga; 214 struct gpiobus_attach_args gba; 215 int i, gpio = 0; 216 #endif 217 tc->tc_get_timecount = glxpcib_get_timecount; 218 tc->tc_counter_mask = 0xffffffff; 219 tc->tc_frequency = 3579545; 220 tc->tc_name = "CS5536"; 221 #ifdef __loongson__ 222 tc->tc_quality = 0; 223 #else 224 tc->tc_quality = 1000; 225 #endif 226 tc->tc_priv = sc; 227 tc_init(tc); 228 229 printf(": rev %d, 32-bit %lluHz timer", 230 (int)rdmsr(AMD5536_REV) & AMD5536_REV_MASK, 231 tc->tc_frequency); 232 233 #if !defined(SMALL_KERNEL) && NGPIO > 0 234 /* Attach the watchdog timer */ 235 sc->sc_iot = pa->pa_iot; 236 wa = rdmsr(MSR_LBAR_MFGPT); 237 if (wa & MSR_LBAR_ENABLE && 238 !bus_space_map(sc->sc_iot, wa & MSR_MFGPT_ADDR_MASK, 239 MSR_MFGPT_SIZE, 0, &sc->sc_ioh)) { 240 /* count in seconds (as upper level desires) */ 241 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_SETUP, 242 AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2EV | 243 AMD5536_MFGPT_CMP2 | AMD5536_MFGPT_DIV_MASK); 244 wdog_register(sc, glxpcib_wdogctl_cb); 245 sc->sc_wdog = 1; 246 printf(", watchdog"); 247 } 248 249 /* map GPIO I/O space */ 250 sc->sc_gpio_iot = pa->pa_iot; 251 ga = rdmsr(MSR_LBAR_GPIO); 252 if (ga & MSR_LBAR_ENABLE && 253 !bus_space_map(sc->sc_gpio_iot, ga & MSR_GPIO_ADDR_MASK, 254 MSR_GPIO_SIZE, 0, &sc->sc_gpio_ioh)) { 255 printf(", gpio"); 256 257 /* initialize pin array */ 258 for (i = 0; i < AMD5536_GPIO_NPINS; i++) { 259 sc->sc_gpio_pins[i].pin_num = i; 260 sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | 261 GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | 262 GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | 263 GPIO_PIN_INVIN | GPIO_PIN_INVOUT; 264 265 /* read initial state */ 266 sc->sc_gpio_pins[i].pin_state = 267 glxpcib_gpio_pin_read(sc, i); 268 } 269 270 /* create controller tag */ 271 sc->sc_gpio_gc.gp_cookie = sc; 272 sc->sc_gpio_gc.gp_pin_read = glxpcib_gpio_pin_read; 273 sc->sc_gpio_gc.gp_pin_write = glxpcib_gpio_pin_write; 274 sc->sc_gpio_gc.gp_pin_ctl = glxpcib_gpio_pin_ctl; 275 276 gba.gba_name = "gpio"; 277 gba.gba_gc = &sc->sc_gpio_gc; 278 gba.gba_pins = sc->sc_gpio_pins; 279 gba.gba_npins = AMD5536_GPIO_NPINS; 280 gpio = 1; 281 282 } 283 #endif 284 pcibattach(parent, self, aux); 285 286 #if !defined(SMALL_KERNEL) && NGPIO > 0 287 if (gpio) 288 config_found(&sc->sc_dev, &gba, gpiobus_print); 289 #endif 290 } 291 292 int 293 glxpcib_activate(struct device *self, int act) 294 { 295 #ifndef SMALL_KERNEL 296 struct glxpcib_softc *sc = (struct glxpcib_softc *)self; 297 uint i; 298 #endif 299 int rv = 0; 300 301 switch (act) { 302 case DVACT_QUIESCE: 303 rv = config_activate_children(self, act); 304 break; 305 case DVACT_SUSPEND: 306 #ifndef SMALL_KERNEL 307 if (sc->sc_wdog) { 308 sc->sc_wdog_period = bus_space_read_2(sc->sc_iot, 309 sc->sc_ioh, AMD5536_MFGPT0_CMP2); 310 glxpcib_wdogctl_cb(sc, 0); 311 } 312 #endif 313 rv = config_activate_children(self, act); 314 #ifndef SMALL_KERNEL 315 for (i = 0; i < nitems(glxpcib_msrlist); i++) 316 sc->sc_msrsave[i] = rdmsr(glxpcib_msrlist[i]); 317 #endif 318 319 break; 320 case DVACT_RESUME: 321 #ifndef SMALL_KERNEL 322 if (sc->sc_wdog) 323 glxpcib_wdogctl_cb(sc, sc->sc_wdog_period); 324 for (i = 0; i < nitems(glxpcib_msrlist); i++) 325 wrmsr(glxpcib_msrlist[i], sc->sc_msrsave[i]); 326 #endif 327 rv = config_activate_children(self, act); 328 break; 329 } 330 return (rv); 331 } 332 333 u_int 334 glxpcib_get_timecount(struct timecounter *tc) 335 { 336 return rdmsr(AMD5536_TMC); 337 } 338 339 #if !defined(SMALL_KERNEL) && NGPIO > 0 340 int 341 glxpcib_wdogctl_cb(void *v, int period) 342 { 343 struct glxpcib_softc *sc = v; 344 345 if (period > 0xffff) 346 period = 0xffff; 347 348 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_SETUP, 349 AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2); 350 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CNT, 0); 351 bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT0_CMP2, period); 352 353 if (period) 354 wrmsr(AMD5536_MFGPT_NR, 355 rdmsr(AMD5536_MFGPT_NR) | AMD5536_MFGPT0_C2_RSTEN); 356 else 357 wrmsr(AMD5536_MFGPT_NR, 358 rdmsr(AMD5536_MFGPT_NR) & ~AMD5536_MFGPT0_C2_RSTEN); 359 360 return period; 361 } 362 363 int 364 glxpcib_gpio_pin_read(void *arg, int pin) 365 { 366 struct glxpcib_softc *sc = arg; 367 u_int32_t data; 368 int reg, off = 0; 369 370 reg = AMD5536_GPIO_IN_EN; 371 if (pin > 15) { 372 pin &= 0x0f; 373 off = AMD5536_GPIOH_OFFSET; 374 } 375 reg += off; 376 data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg); 377 378 if (data & (1 << pin)) 379 reg = AMD5536_GPIO_READ_BACK + off; 380 else 381 reg = AMD5536_GPIO_OUT_VAL + off; 382 383 data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg); 384 385 return data & 1 << pin ? GPIO_PIN_HIGH : GPIO_PIN_LOW; 386 } 387 388 void 389 glxpcib_gpio_pin_write(void *arg, int pin, int value) 390 { 391 struct glxpcib_softc *sc = arg; 392 u_int32_t data; 393 int reg; 394 395 reg = AMD5536_GPIO_OUT_VAL; 396 if (pin > 15) { 397 pin &= 0x0f; 398 reg += AMD5536_GPIOH_OFFSET; 399 } 400 if (value == 1) 401 data = 1 << pin; 402 else 403 data = 1 << (pin + 16); 404 405 bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data); 406 } 407 408 void 409 glxpcib_gpio_pin_ctl(void *arg, int pin, int flags) 410 { 411 struct glxpcib_softc *sc = arg; 412 int n, reg[7], val[7], nreg = 0, off = 0; 413 414 if (pin > 15) { 415 pin &= 0x0f; 416 off = AMD5536_GPIOH_OFFSET; 417 } 418 419 reg[nreg] = AMD5536_GPIO_IN_EN + off; 420 if (flags & GPIO_PIN_INPUT) 421 val[nreg++] = 1 << pin; 422 else 423 val[nreg++] = 1 << (pin + 16); 424 425 reg[nreg] = AMD5536_GPIO_OUT_EN + off; 426 if (flags & GPIO_PIN_OUTPUT) 427 val[nreg++] = 1 << pin; 428 else 429 val[nreg++] = 1 << (pin + 16); 430 431 reg[nreg] = AMD5536_GPIO_OD_EN + off; 432 if (flags & GPIO_PIN_OPENDRAIN) 433 val[nreg++] = 1 << pin; 434 else 435 val[nreg++] = 1 << (pin + 16); 436 437 reg[nreg] = AMD5536_GPIO_PU_EN + off; 438 if (flags & GPIO_PIN_PULLUP) 439 val[nreg++] = 1 << pin; 440 else 441 val[nreg++] = 1 << (pin + 16); 442 443 reg[nreg] = AMD5536_GPIO_PD_EN + off; 444 if (flags & GPIO_PIN_PULLDOWN) 445 val[nreg++] = 1 << pin; 446 else 447 val[nreg++] = 1 << (pin + 16); 448 449 reg[nreg] = AMD5536_GPIO_IN_INVRT_EN + off; 450 if (flags & GPIO_PIN_INVIN) 451 val[nreg++] = 1 << pin; 452 else 453 val[nreg++] = 1 << (pin + 16); 454 455 reg[nreg] = AMD5536_GPIO_OUT_INVRT_EN + off; 456 if (flags & GPIO_PIN_INVOUT) 457 val[nreg++] = 1 << pin; 458 else 459 val[nreg++] = 1 << (pin + 16); 460 461 /* set flags */ 462 for (n = 0; n < nreg; n++) 463 bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg[n], 464 val[n]); 465 } 466 467 #endif 468