1 1.52 thorpej /* $NetBSD: elan520.c,v 1.52 2021/08/07 16:18:55 thorpej Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.1 thorpej * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.1 thorpej * by Jason R. Thorpe. 9 1.1 thorpej * 10 1.1 thorpej * Redistribution and use in source and binary forms, with or without 11 1.1 thorpej * modification, are permitted provided that the following conditions 12 1.1 thorpej * are met: 13 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer. 15 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 17 1.1 thorpej * documentation and/or other materials provided with the distribution. 18 1.1 thorpej * 19 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 30 1.1 thorpej */ 31 1.1 thorpej 32 1.1 thorpej /* 33 1.1 thorpej * Device driver for the AMD Elan SC520 System Controller. This attaches 34 1.1 thorpej * where the "pchb" driver might normally attach, and provides support for 35 1.1 thorpej * extra features on the SC520, such as the watchdog timer and GPIO. 36 1.1 thorpej * 37 1.1 thorpej * Information about the GP bus echo bug work-around is from code posted 38 1.1 thorpej * to the "soekris-tech" mailing list by Jasper Wallace. 39 1.1 thorpej */ 40 1.1 thorpej 41 1.1 thorpej #include <sys/cdefs.h> 42 1.1 thorpej 43 1.52 thorpej __KERNEL_RCSID(0, "$NetBSD: elan520.c,v 1.52 2021/08/07 16:18:55 thorpej Exp $"); 44 1.1 thorpej 45 1.1 thorpej #include <sys/param.h> 46 1.1 thorpej #include <sys/systm.h> 47 1.22 dyoung #include <sys/time.h> 48 1.1 thorpej #include <sys/device.h> 49 1.19 dyoung #include <sys/gpio.h> 50 1.19 dyoung #include <sys/mutex.h> 51 1.1 thorpej #include <sys/wdog.h> 52 1.35 dyoung #include <sys/reboot.h> 53 1.1 thorpej 54 1.5 thorpej #include <uvm/uvm_extern.h> 55 1.5 thorpej 56 1.49 dyoung #include <sys/bus.h> 57 1.1 thorpej 58 1.38 yamt #include <x86/nmi.h> 59 1.38 yamt 60 1.1 thorpej #include <dev/pci/pcivar.h> 61 1.1 thorpej 62 1.1 thorpej #include <dev/pci/pcidevs.h> 63 1.1 thorpej 64 1.10 drochner #include "gpio.h" 65 1.10 drochner #if NGPIO > 0 66 1.9 riz #include <dev/gpio/gpiovar.h> 67 1.10 drochner #endif 68 1.9 riz 69 1.1 thorpej #include <arch/i386/pci/elan520reg.h> 70 1.1 thorpej 71 1.1 thorpej #include <dev/sysmon/sysmonvar.h> 72 1.1 thorpej 73 1.22 dyoung #define ELAN_IRQ 1 74 1.23 dyoung #define PG0_PROT_SIZE PAGE_SIZE 75 1.22 dyoung 76 1.1 thorpej struct elansc_softc { 77 1.29 dyoung device_t sc_dev; 78 1.36 dyoung device_t sc_gpio; 79 1.22 dyoung device_t sc_par; 80 1.22 dyoung device_t sc_pex; 81 1.31 dyoung device_t sc_pci; 82 1.22 dyoung 83 1.40 dyoung pci_chipset_tag_t sc_pc; 84 1.40 dyoung pcitag_t sc_tag; 85 1.40 dyoung bus_dma_tag_t sc_dmat; 86 1.40 dyoung bus_dma_tag_t sc_dmat64; 87 1.40 dyoung bus_space_tag_t sc_iot; 88 1.40 dyoung bus_space_tag_t sc_memt; 89 1.40 dyoung bus_space_handle_t sc_memh; 90 1.40 dyoung int sc_pciflags; 91 1.40 dyoung 92 1.1 thorpej int sc_echobug; 93 1.1 thorpej 94 1.19 dyoung kmutex_t sc_mtx; 95 1.19 dyoung 96 1.1 thorpej struct sysmon_wdog sc_smw; 97 1.22 dyoung void *sc_eih; 98 1.22 dyoung void *sc_pih; 99 1.22 dyoung void *sc_sh; 100 1.22 dyoung uint8_t sc_mpicmode; 101 1.22 dyoung uint8_t sc_picicr; 102 1.23 dyoung int sc_pg0par; 103 1.27 dyoung int sc_textpar[3]; 104 1.11 riz #if NGPIO > 0 105 1.9 riz /* GPIO interface */ 106 1.9 riz struct gpio_chipset_tag sc_gpio_gc; 107 1.9 riz gpio_pin_t sc_gpio_pins[ELANSC_PIO_NPINS]; 108 1.11 riz #endif 109 1.1 thorpej }; 110 1.1 thorpej 111 1.44 dyoung struct pareg { 112 1.44 dyoung paddr_t start; 113 1.44 dyoung paddr_t end; 114 1.44 dyoung }; 115 1.44 dyoung 116 1.31 dyoung static bool elansc_attached = false; 117 1.22 dyoung int elansc_wpvnmi = 1; 118 1.22 dyoung int elansc_pcinmi = 1; 119 1.23 dyoung int elansc_do_protect_pg0 = 1; 120 1.22 dyoung 121 1.10 drochner #if NGPIO > 0 122 1.9 riz static int elansc_gpio_pin_read(void *, int); 123 1.9 riz static void elansc_gpio_pin_write(void *, int, int); 124 1.9 riz static void elansc_gpio_pin_ctl(void *, int, int); 125 1.10 drochner #endif 126 1.9 riz 127 1.22 dyoung static void elansc_print_par(device_t, int, uint32_t); 128 1.31 dyoung 129 1.22 dyoung static void elanpar_intr_establish(device_t, struct elansc_softc *); 130 1.22 dyoung static void elanpar_intr_disestablish(struct elansc_softc *); 131 1.26 dyoung static bool elanpar_shutdown(device_t, int); 132 1.31 dyoung 133 1.31 dyoung static void elanpex_intr_establish(device_t, struct elansc_softc *); 134 1.31 dyoung static void elanpex_intr_disestablish(struct elansc_softc *); 135 1.26 dyoung static bool elanpex_shutdown(device_t, int); 136 1.40 dyoung static int elansc_rescan(device_t, const char *, const int *); 137 1.22 dyoung 138 1.27 dyoung static void elansc_protect(struct elansc_softc *, int, paddr_t, uint32_t); 139 1.42 dyoung static bool elansc_shutdown(device_t, int); 140 1.27 dyoung 141 1.28 dyoung static const uint32_t sfkb = 64 * 1024, fkb = 4 * 1024; 142 1.28 dyoung 143 1.1 thorpej static void 144 1.19 dyoung elansc_childdetached(device_t self, device_t child) 145 1.19 dyoung { 146 1.22 dyoung struct elansc_softc *sc = device_private(self); 147 1.22 dyoung 148 1.22 dyoung if (child == sc->sc_par) 149 1.22 dyoung sc->sc_par = NULL; 150 1.22 dyoung if (child == sc->sc_pex) 151 1.22 dyoung sc->sc_pex = NULL; 152 1.31 dyoung if (child == sc->sc_pci) 153 1.31 dyoung sc->sc_pci = NULL; 154 1.40 dyoung if (child == sc->sc_gpio) 155 1.40 dyoung sc->sc_gpio = NULL; 156 1.19 dyoung } 157 1.19 dyoung 158 1.31 dyoung static int 159 1.31 dyoung elansc_match(device_t parent, cfdata_t match, void *aux) 160 1.31 dyoung { 161 1.31 dyoung struct pcibus_attach_args *pba = aux; 162 1.31 dyoung pcitag_t tag; 163 1.31 dyoung pcireg_t id; 164 1.31 dyoung 165 1.31 dyoung if (elansc_attached) 166 1.31 dyoung return 0; 167 1.31 dyoung 168 1.31 dyoung if (pcimatch(parent, match, aux) == 0) 169 1.31 dyoung return 0; 170 1.31 dyoung 171 1.31 dyoung if (pba->pba_bus != 0) 172 1.31 dyoung return 0; 173 1.31 dyoung 174 1.31 dyoung tag = pci_make_tag(pba->pba_pc, 0, 0, 0); 175 1.31 dyoung id = pci_conf_read(pba->pba_pc, tag, PCI_ID_REG); 176 1.31 dyoung 177 1.31 dyoung if (PCI_VENDOR(id) == PCI_VENDOR_AMD && 178 1.31 dyoung PCI_PRODUCT(id) == PCI_PRODUCT_AMD_SC520_SC) 179 1.31 dyoung return 10; 180 1.31 dyoung 181 1.31 dyoung return 0; 182 1.31 dyoung } 183 1.31 dyoung 184 1.31 dyoung /* 185 1.31 dyoung * Performance tuning for Soekris net4501: 186 1.31 dyoung * - enable SDRAM write buffer and read prefetching 187 1.31 dyoung */ 188 1.31 dyoung #if 0 189 1.31 dyoung uint8_t dbctl; 190 1.31 dyoung 191 1.31 dyoung dbctl = bus_space_read_1(memt, memh, MMCR_DBCTL); 192 1.31 dyoung dbctl &= ~MMCR_DBCTL_WB_WM_MASK; 193 1.31 dyoung dbctl |= MMCR_DBCTL_WB_WM_16DW; 194 1.31 dyoung dbctl |= MMCR_DBCTL_WB_ENB | MMCR_DBCTL_RAB_ENB; 195 1.31 dyoung bus_space_write_1(memt, memh, MMCR_DBCTL, dbctl); 196 1.31 dyoung #endif 197 1.31 dyoung 198 1.31 dyoung /* 199 1.31 dyoung * Performance tuning for PCI bus on the AMD Elan SC520: 200 1.31 dyoung * - enable concurrent arbitration of PCI and CPU busses 201 1.31 dyoung * (and PCI buffer) 202 1.31 dyoung * - enable PCI automatic delayed read transactions and 203 1.31 dyoung * write posting 204 1.31 dyoung * - enable PCI read buffer snooping (coherency) 205 1.31 dyoung */ 206 1.31 dyoung static void 207 1.31 dyoung elansc_perf_tune(device_t self, bus_space_tag_t memt, bus_space_handle_t memh) 208 1.31 dyoung { 209 1.31 dyoung uint8_t sysarbctl; 210 1.31 dyoung uint16_t hbctl; 211 1.31 dyoung const bool concurrency = true; /* concurrent bus arbitration */ 212 1.31 dyoung 213 1.31 dyoung sysarbctl = bus_space_read_1(memt, memh, MMCR_SYSARBCTL); 214 1.31 dyoung if ((sysarbctl & MMCR_SYSARBCTL_CNCR_MODE_ENB) != 0) { 215 1.31 dyoung aprint_debug_dev(self, 216 1.31 dyoung "concurrent arbitration mode is active\n"); 217 1.31 dyoung } else if (concurrency) { 218 1.31 dyoung aprint_verbose_dev(self, "activating concurrent " 219 1.31 dyoung "arbitration mode\n"); 220 1.31 dyoung /* activate concurrent bus arbitration */ 221 1.31 dyoung sysarbctl |= MMCR_SYSARBCTL_CNCR_MODE_ENB; 222 1.31 dyoung bus_space_write_1(memt, memh, MMCR_SYSARBCTL, sysarbctl); 223 1.31 dyoung } 224 1.31 dyoung 225 1.31 dyoung hbctl = bus_space_read_2(memt, memh, MMCR_HBCTL); 226 1.31 dyoung 227 1.31 dyoung /* target read FIFO snoop */ 228 1.31 dyoung if ((hbctl & MMCR_HBCTL_T_PURGE_RD_ENB) != 0) 229 1.31 dyoung aprint_debug_dev(self, "read-FIFO snooping is active\n"); 230 1.31 dyoung else { 231 1.31 dyoung aprint_verbose_dev(self, "activating read-FIFO snooping\n"); 232 1.31 dyoung hbctl |= MMCR_HBCTL_T_PURGE_RD_ENB; 233 1.31 dyoung } 234 1.31 dyoung 235 1.31 dyoung if ((hbctl & MMCR_HBCTL_M_WPOST_ENB) != 0) 236 1.31 dyoung aprint_debug_dev(self, "CPU->PCI write-posting is active\n"); 237 1.31 dyoung else if (concurrency) { 238 1.31 dyoung aprint_verbose_dev(self, "activating CPU->PCI write-posting\n"); 239 1.31 dyoung hbctl |= MMCR_HBCTL_M_WPOST_ENB; 240 1.31 dyoung } 241 1.31 dyoung 242 1.31 dyoung /* auto delay read txn: looks safe, but seems to cause 243 1.31 dyoung * net4526 w/ minipci ath fits 244 1.31 dyoung */ 245 1.31 dyoung #if 0 246 1.31 dyoung if ((hbctl & MMCR_HBCTL_T_DLYTR_ENB_AUTORETRY) != 0) 247 1.31 dyoung aprint_debug_dev(self, 248 1.31 dyoung "automatic read transaction delay is active\n"); 249 1.31 dyoung else { 250 1.31 dyoung aprint_verbose_dev(self, 251 1.31 dyoung "activating automatic read transaction delay\n"); 252 1.31 dyoung hbctl |= MMCR_HBCTL_T_DLYTR_ENB_AUTORETRY; 253 1.31 dyoung } 254 1.31 dyoung #endif 255 1.31 dyoung bus_space_write_2(memt, memh, MMCR_HBCTL, hbctl); 256 1.31 dyoung } 257 1.31 dyoung 258 1.19 dyoung static void 259 1.1 thorpej elansc_wdogctl_write(struct elansc_softc *sc, uint16_t val) 260 1.1 thorpej { 261 1.6 christos uint8_t echo_mode = 0; /* XXX: gcc */ 262 1.1 thorpej 263 1.19 dyoung KASSERT(mutex_owned(&sc->sc_mtx)); 264 1.1 thorpej 265 1.1 thorpej /* Switch off GP bus echo mode if we need to. */ 266 1.1 thorpej if (sc->sc_echobug) { 267 1.1 thorpej echo_mode = bus_space_read_1(sc->sc_memt, sc->sc_memh, 268 1.1 thorpej MMCR_GPECHO); 269 1.1 thorpej bus_space_write_1(sc->sc_memt, sc->sc_memh, 270 1.1 thorpej MMCR_GPECHO, echo_mode & ~GPECHO_GP_ECHO_ENB); 271 1.1 thorpej } 272 1.1 thorpej 273 1.1 thorpej /* Unlock the register. */ 274 1.1 thorpej bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, 275 1.1 thorpej WDTMRCTL_UNLOCK1); 276 1.1 thorpej bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, 277 1.1 thorpej WDTMRCTL_UNLOCK2); 278 1.1 thorpej 279 1.1 thorpej /* Write the value. */ 280 1.1 thorpej bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, val); 281 1.1 thorpej 282 1.1 thorpej /* Switch GP bus echo mode back. */ 283 1.1 thorpej if (sc->sc_echobug) 284 1.1 thorpej bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_GPECHO, 285 1.1 thorpej echo_mode); 286 1.1 thorpej } 287 1.1 thorpej 288 1.1 thorpej static void 289 1.1 thorpej elansc_wdogctl_reset(struct elansc_softc *sc) 290 1.1 thorpej { 291 1.7 christos uint8_t echo_mode = 0/* XXX: gcc */; 292 1.1 thorpej 293 1.19 dyoung KASSERT(mutex_owned(&sc->sc_mtx)); 294 1.1 thorpej 295 1.1 thorpej /* Switch off GP bus echo mode if we need to. */ 296 1.1 thorpej if (sc->sc_echobug) { 297 1.1 thorpej echo_mode = bus_space_read_1(sc->sc_memt, sc->sc_memh, 298 1.1 thorpej MMCR_GPECHO); 299 1.1 thorpej bus_space_write_1(sc->sc_memt, sc->sc_memh, 300 1.1 thorpej MMCR_GPECHO, echo_mode & ~GPECHO_GP_ECHO_ENB); 301 1.1 thorpej } 302 1.1 thorpej 303 1.1 thorpej /* Reset the watchdog. */ 304 1.1 thorpej bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, 305 1.1 thorpej WDTMRCTL_RESET1); 306 1.1 thorpej bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, 307 1.1 thorpej WDTMRCTL_RESET2); 308 1.1 thorpej 309 1.1 thorpej /* Switch GP bus echo mode back. */ 310 1.1 thorpej if (sc->sc_echobug) 311 1.1 thorpej bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_GPECHO, 312 1.1 thorpej echo_mode); 313 1.1 thorpej } 314 1.1 thorpej 315 1.1 thorpej static const struct { 316 1.1 thorpej int period; /* whole seconds */ 317 1.1 thorpej uint16_t exp; /* exponent select */ 318 1.1 thorpej } elansc_wdog_periods[] = { 319 1.1 thorpej { 1, WDTMRCTL_EXP_SEL25 }, 320 1.1 thorpej { 2, WDTMRCTL_EXP_SEL26 }, 321 1.1 thorpej { 4, WDTMRCTL_EXP_SEL27 }, 322 1.1 thorpej { 8, WDTMRCTL_EXP_SEL28 }, 323 1.1 thorpej { 16, WDTMRCTL_EXP_SEL29 }, 324 1.1 thorpej { 32, WDTMRCTL_EXP_SEL30 }, 325 1.1 thorpej { 0, 0 }, 326 1.1 thorpej }; 327 1.1 thorpej 328 1.1 thorpej static int 329 1.19 dyoung elansc_wdog_arm(struct elansc_softc *sc) 330 1.1 thorpej { 331 1.19 dyoung struct sysmon_wdog *smw = &sc->sc_smw; 332 1.1 thorpej int i; 333 1.7 christos uint16_t exp_sel = 0; /* XXX: gcc */ 334 1.1 thorpej 335 1.19 dyoung KASSERT(mutex_owned(&sc->sc_mtx)); 336 1.17 dyoung 337 1.19 dyoung if (smw->smw_period == WDOG_PERIOD_DEFAULT) { 338 1.19 dyoung smw->smw_period = 32; 339 1.19 dyoung exp_sel = WDTMRCTL_EXP_SEL30; 340 1.1 thorpej } else { 341 1.19 dyoung for (i = 0; elansc_wdog_periods[i].period != 0; i++) { 342 1.19 dyoung if (elansc_wdog_periods[i].period == 343 1.19 dyoung smw->smw_period) { 344 1.19 dyoung exp_sel = elansc_wdog_periods[i].exp; 345 1.19 dyoung break; 346 1.1 thorpej } 347 1.1 thorpej } 348 1.19 dyoung if (elansc_wdog_periods[i].period == 0) 349 1.19 dyoung return EINVAL; 350 1.1 thorpej } 351 1.19 dyoung elansc_wdogctl_write(sc, WDTMRCTL_ENB | 352 1.19 dyoung WDTMRCTL_WRST_ENB | exp_sel); 353 1.19 dyoung elansc_wdogctl_reset(sc); 354 1.19 dyoung return 0; 355 1.19 dyoung } 356 1.19 dyoung 357 1.19 dyoung static int 358 1.19 dyoung elansc_wdog_setmode(struct sysmon_wdog *smw) 359 1.19 dyoung { 360 1.19 dyoung struct elansc_softc *sc = smw->smw_cookie; 361 1.19 dyoung int rc = 0; 362 1.19 dyoung 363 1.19 dyoung mutex_enter(&sc->sc_mtx); 364 1.19 dyoung 365 1.29 dyoung if (!device_is_active(sc->sc_dev)) 366 1.19 dyoung rc = EBUSY; 367 1.19 dyoung else if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { 368 1.19 dyoung elansc_wdogctl_write(sc, 369 1.19 dyoung WDTMRCTL_WRST_ENB | WDTMRCTL_EXP_SEL30); 370 1.19 dyoung } else 371 1.19 dyoung rc = elansc_wdog_arm(sc); 372 1.19 dyoung 373 1.19 dyoung mutex_exit(&sc->sc_mtx); 374 1.19 dyoung return rc; 375 1.1 thorpej } 376 1.1 thorpej 377 1.1 thorpej static int 378 1.1 thorpej elansc_wdog_tickle(struct sysmon_wdog *smw) 379 1.1 thorpej { 380 1.1 thorpej struct elansc_softc *sc = smw->smw_cookie; 381 1.1 thorpej 382 1.19 dyoung mutex_enter(&sc->sc_mtx); 383 1.1 thorpej elansc_wdogctl_reset(sc); 384 1.19 dyoung mutex_exit(&sc->sc_mtx); 385 1.19 dyoung return 0; 386 1.1 thorpej } 387 1.1 thorpej 388 1.1 thorpej static const char *elansc_speeds[] = { 389 1.1 thorpej "(reserved 00)", 390 1.1 thorpej "100MHz", 391 1.1 thorpej "133MHz", 392 1.1 thorpej "(reserved 11)", 393 1.1 thorpej }; 394 1.1 thorpej 395 1.22 dyoung static int 396 1.22 dyoung elanpar_intr(void *arg) 397 1.22 dyoung { 398 1.22 dyoung struct elansc_softc *sc = arg; 399 1.22 dyoung uint16_t wpvsta; 400 1.22 dyoung unsigned win; 401 1.22 dyoung uint32_t par; 402 1.22 dyoung const char *wpvstr; 403 1.22 dyoung 404 1.22 dyoung wpvsta = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_WPVSTA); 405 1.22 dyoung 406 1.22 dyoung if ((wpvsta & MMCR_WPVSTA_WPV_STA) == 0) 407 1.22 dyoung return 0; 408 1.22 dyoung 409 1.22 dyoung win = __SHIFTOUT(wpvsta, MMCR_WPVSTA_WPV_WINDOW); 410 1.22 dyoung 411 1.22 dyoung par = bus_space_read_4(sc->sc_memt, sc->sc_memh, MMCR_PAR(win)); 412 1.22 dyoung 413 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WPVSTA, 414 1.22 dyoung MMCR_WPVSTA_WPV_STA); 415 1.22 dyoung 416 1.22 dyoung switch (wpvsta & MMCR_WPVSTA_WPV_MSTR) { 417 1.22 dyoung case MMCR_WPVSTA_WPV_MSTR_CPU: 418 1.22 dyoung wpvstr = "cpu"; 419 1.22 dyoung break; 420 1.22 dyoung case MMCR_WPVSTA_WPV_MSTR_PCI: 421 1.22 dyoung wpvstr = "pci"; 422 1.22 dyoung break; 423 1.22 dyoung case MMCR_WPVSTA_WPV_MSTR_GP: 424 1.22 dyoung wpvstr = "gp"; 425 1.22 dyoung break; 426 1.22 dyoung default: 427 1.22 dyoung wpvstr = "unknown"; 428 1.22 dyoung break; 429 1.22 dyoung } 430 1.35 dyoung printf_tolog("%s: %s violated write-protect window %u\n", 431 1.35 dyoung device_xname(sc->sc_par), wpvstr, win); 432 1.22 dyoung elansc_print_par(sc->sc_par, win, par); 433 1.22 dyoung return 0; 434 1.22 dyoung } 435 1.22 dyoung 436 1.22 dyoung static int 437 1.38 yamt elanpar_nmi(const struct trapframe *tf, void *arg) 438 1.38 yamt { 439 1.38 yamt 440 1.38 yamt return elanpar_intr(arg); 441 1.38 yamt } 442 1.38 yamt 443 1.38 yamt static int 444 1.22 dyoung elanpex_intr(void *arg) 445 1.22 dyoung { 446 1.22 dyoung static struct { 447 1.22 dyoung const char *string; 448 1.22 dyoung bool nonfatal; 449 1.22 dyoung } cmd[16] = { 450 1.22 dyoung [0] = {.string = "not latched"} 451 1.22 dyoung , [1] = {.string = "special cycle"} 452 1.22 dyoung , [2] = {.string = "i/o read"} 453 1.22 dyoung , [3] = {.string = "i/o write"} 454 1.22 dyoung , [4] = {.string = "4"} 455 1.22 dyoung , [5] = {.string = "5"} 456 1.22 dyoung , [6] = {.string = "memory rd"} 457 1.22 dyoung , [7] = {.string = "memory wr"} 458 1.22 dyoung , [8] = {.string = "8"} 459 1.22 dyoung , [9] = {.string = "9"} 460 1.22 dyoung , [10] = {.string = "cfg rd", .nonfatal = true} 461 1.22 dyoung , [11] = {.string = "cfg wr"} 462 1.22 dyoung , [12] = {.string = "memory rd mul"} 463 1.22 dyoung , [13] = {.string = "dual-address cycle"} 464 1.22 dyoung , [14] = {.string = "memory rd line"} 465 1.22 dyoung , [15] = {.string = "memory wr & inv"} 466 1.22 dyoung }; 467 1.22 dyoung 468 1.22 dyoung static const struct { 469 1.22 dyoung uint16_t bit; 470 1.22 dyoung const char *msg; 471 1.22 dyoung } mmsg[] = { 472 1.22 dyoung {MMCR_HBMSTIRQSTA_M_RTRTO_IRQ_STA, "retry timeout"} 473 1.22 dyoung , {MMCR_HBMSTIRQSTA_M_TABRT_IRQ_STA, "target abort"} 474 1.22 dyoung , {MMCR_HBMSTIRQSTA_M_MABRT_IRQ_STA, "abort"} 475 1.22 dyoung , {MMCR_HBMSTIRQSTA_M_SERR_IRQ_STA, "system error"} 476 1.22 dyoung , {MMCR_HBMSTIRQSTA_M_RPER_IRQ_STA, "received parity error"} 477 1.22 dyoung , {MMCR_HBMSTIRQSTA_M_DPER_IRQ_STA, "detected parity error"} 478 1.22 dyoung }, tmsg[] = { 479 1.22 dyoung {MMCR_HBTGTIRQSTA_T_DLYTO_IRQ_STA, "delayed txn timeout"} 480 1.22 dyoung , {MMCR_HBTGTIRQSTA_T_APER_IRQ_STA, "address parity"} 481 1.22 dyoung , {MMCR_HBTGTIRQSTA_T_DPER_IRQ_STA, "data parity"} 482 1.22 dyoung }; 483 1.22 dyoung uint8_t pciarbsta; 484 1.22 dyoung uint16_t mstcmd, mstirq, tgtid, tgtirq; 485 1.22 dyoung uint32_t mstaddr; 486 1.22 dyoung uint16_t mstack = 0, tgtack = 0; 487 1.22 dyoung int fatal = 0, i, handled = 0; 488 1.22 dyoung struct elansc_softc *sc = arg; 489 1.22 dyoung 490 1.22 dyoung pciarbsta = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_PCIARBSTA); 491 1.22 dyoung mstirq = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_HBMSTIRQSTA); 492 1.22 dyoung mstaddr = bus_space_read_4(sc->sc_memt, sc->sc_memh, MMCR_MSTINTADD); 493 1.22 dyoung tgtirq = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_HBTGTIRQSTA); 494 1.22 dyoung 495 1.22 dyoung if ((pciarbsta & MMCR_PCIARBSTA_GNT_TO_STA) != 0) { 496 1.35 dyoung printf_tolog( 497 1.35 dyoung "%s: grant time-out, GNT%" __PRIuBITS "# asserted\n", 498 1.35 dyoung device_xname(sc->sc_pex), 499 1.22 dyoung __SHIFTOUT(pciarbsta, MMCR_PCIARBSTA_GNT_TO_ID)); 500 1.22 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_PCIARBSTA, 501 1.22 dyoung MMCR_PCIARBSTA_GNT_TO_STA); 502 1.22 dyoung handled = true; 503 1.22 dyoung } 504 1.22 dyoung 505 1.22 dyoung mstcmd = __SHIFTOUT(mstirq, MMCR_HBMSTIRQSTA_M_CMD_IRQ_ID); 506 1.22 dyoung 507 1.22 dyoung for (i = 0; i < __arraycount(mmsg); i++) { 508 1.22 dyoung if ((mstirq & mmsg[i].bit) == 0) 509 1.22 dyoung continue; 510 1.35 dyoung printf_tolog("%s: %s %08" PRIx32 " master %s\n", 511 1.35 dyoung device_xname(sc->sc_pex), cmd[mstcmd].string, mstaddr, 512 1.35 dyoung mmsg[i].msg); 513 1.22 dyoung 514 1.22 dyoung mstack |= mmsg[i].bit; 515 1.22 dyoung if (!cmd[mstcmd].nonfatal) 516 1.22 dyoung fatal = true; 517 1.22 dyoung } 518 1.22 dyoung 519 1.22 dyoung tgtid = __SHIFTOUT(tgtirq, MMCR_HBTGTIRQSTA_T_IRQ_ID); 520 1.22 dyoung 521 1.22 dyoung for (i = 0; i < __arraycount(tmsg); i++) { 522 1.22 dyoung if ((tgtirq & tmsg[i].bit) == 0) 523 1.22 dyoung continue; 524 1.35 dyoung printf_tolog("%s: %1x target %s\n", device_xname(sc->sc_pex), 525 1.35 dyoung tgtid, tmsg[i].msg); 526 1.22 dyoung tgtack |= tmsg[i].bit; 527 1.22 dyoung } 528 1.22 dyoung 529 1.22 dyoung /* acknowledge interrupts */ 530 1.22 dyoung if (tgtack != 0) { 531 1.22 dyoung handled = true; 532 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_HBTGTIRQSTA, 533 1.22 dyoung tgtack); 534 1.22 dyoung } 535 1.22 dyoung if (mstack != 0) { 536 1.22 dyoung handled = true; 537 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_HBMSTIRQSTA, 538 1.22 dyoung mstack); 539 1.22 dyoung } 540 1.22 dyoung return fatal ? 0 : (handled ? 1 : 0); 541 1.22 dyoung } 542 1.22 dyoung 543 1.38 yamt static int 544 1.38 yamt elanpex_nmi(const struct trapframe *tf, void *arg) 545 1.38 yamt { 546 1.38 yamt 547 1.38 yamt return elanpex_intr(arg); 548 1.38 yamt } 549 1.38 yamt 550 1.22 dyoung #define elansc_print_1(__dev, __sc, __reg) \ 551 1.22 dyoung do { \ 552 1.22 dyoung aprint_debug_dev(__dev, \ 553 1.22 dyoung "%s: %s %02" PRIx8 "\n", __func__, #__reg, \ 554 1.22 dyoung bus_space_read_1((__sc)->sc_memt, (__sc)->sc_memh, __reg)); \ 555 1.22 dyoung } while (/*CONSTCOND*/0) 556 1.22 dyoung 557 1.22 dyoung static void 558 1.22 dyoung elansc_print_par(device_t dev, int i, uint32_t par) 559 1.22 dyoung { 560 1.22 dyoung uint32_t addr, sz, unit; 561 1.22 dyoung const char *tgtstr; 562 1.22 dyoung 563 1.35 dyoung if ((boothowto & AB_DEBUG) == 0) 564 1.35 dyoung return; 565 1.35 dyoung 566 1.22 dyoung switch (par & MMCR_PAR_TARGET) { 567 1.22 dyoung default: 568 1.22 dyoung case MMCR_PAR_TARGET_OFF: 569 1.22 dyoung tgtstr = "off"; 570 1.22 dyoung break; 571 1.22 dyoung case MMCR_PAR_TARGET_GPIO: 572 1.22 dyoung tgtstr = "gpio"; 573 1.22 dyoung break; 574 1.22 dyoung case MMCR_PAR_TARGET_GPMEM: 575 1.22 dyoung tgtstr = "gpmem"; 576 1.22 dyoung break; 577 1.22 dyoung case MMCR_PAR_TARGET_PCI: 578 1.22 dyoung tgtstr = "pci"; 579 1.22 dyoung break; 580 1.22 dyoung case MMCR_PAR_TARGET_BOOTCS: 581 1.22 dyoung tgtstr = "bootcs"; 582 1.22 dyoung break; 583 1.22 dyoung case MMCR_PAR_TARGET_ROMCS1: 584 1.22 dyoung tgtstr = "romcs1"; 585 1.22 dyoung break; 586 1.22 dyoung case MMCR_PAR_TARGET_ROMCS2: 587 1.22 dyoung tgtstr = "romcs2"; 588 1.22 dyoung break; 589 1.22 dyoung case MMCR_PAR_TARGET_SDRAM: 590 1.22 dyoung tgtstr = "sdram"; 591 1.22 dyoung break; 592 1.22 dyoung } 593 1.22 dyoung if ((par & MMCR_PAR_TARGET) == MMCR_PAR_TARGET_GPIO) { 594 1.22 dyoung unit = 1; 595 1.22 dyoung sz = __SHIFTOUT(par, MMCR_PAR_IO_SZ); 596 1.22 dyoung addr = __SHIFTOUT(par, MMCR_PAR_IO_ST_ADR); 597 1.22 dyoung } else if ((par & MMCR_PAR_PG_SZ) != 0) { 598 1.22 dyoung unit = 64 * 1024; 599 1.22 dyoung sz = __SHIFTOUT(par, MMCR_PAR_64KB_SZ); 600 1.22 dyoung addr = __SHIFTOUT(par, MMCR_PAR_64KB_ST_ADR); 601 1.22 dyoung } else { 602 1.22 dyoung unit = 4 * 1024; 603 1.22 dyoung sz = __SHIFTOUT(par, MMCR_PAR_4KB_SZ); 604 1.22 dyoung addr = __SHIFTOUT(par, MMCR_PAR_4KB_ST_ADR); 605 1.22 dyoung } 606 1.22 dyoung 607 1.35 dyoung printf_tolog( 608 1.35 dyoung "%s: PAR[%d] %08" PRIx32 " tgt %s attr %1" __PRIxBITS 609 1.35 dyoung " start %08" PRIx32 " size %" PRIu32 "\n", device_xname(dev), 610 1.22 dyoung i, par, tgtstr, __SHIFTOUT(par, MMCR_PAR_ATTR), 611 1.22 dyoung addr * unit, (sz + 1) * unit); 612 1.22 dyoung } 613 1.22 dyoung 614 1.22 dyoung static void 615 1.22 dyoung elansc_print_all_par(device_t dev, 616 1.22 dyoung bus_space_tag_t memt, bus_space_handle_t memh) 617 1.22 dyoung { 618 1.22 dyoung int i; 619 1.22 dyoung uint32_t par; 620 1.22 dyoung 621 1.22 dyoung for (i = 0; i < 16; i++) { 622 1.22 dyoung par = bus_space_read_4(memt, memh, MMCR_PAR(i)); 623 1.22 dyoung elansc_print_par(dev, i, par); 624 1.22 dyoung } 625 1.22 dyoung } 626 1.22 dyoung 627 1.22 dyoung static int 628 1.22 dyoung elansc_alloc_par(bus_space_tag_t memt, bus_space_handle_t memh) 629 1.22 dyoung { 630 1.22 dyoung int i; 631 1.22 dyoung uint32_t par; 632 1.22 dyoung 633 1.22 dyoung for (i = 0; i < 16; i++) { 634 1.22 dyoung 635 1.22 dyoung par = bus_space_read_4(memt, memh, MMCR_PAR(i)); 636 1.22 dyoung 637 1.22 dyoung if ((par & MMCR_PAR_TARGET) == MMCR_PAR_TARGET_OFF) 638 1.22 dyoung break; 639 1.22 dyoung } 640 1.22 dyoung if (i == 16) 641 1.22 dyoung return -1; 642 1.22 dyoung return i; 643 1.22 dyoung } 644 1.22 dyoung 645 1.22 dyoung static void 646 1.22 dyoung elansc_disable_par(bus_space_tag_t memt, bus_space_handle_t memh, int idx) 647 1.22 dyoung { 648 1.22 dyoung uint32_t par; 649 1.22 dyoung par = bus_space_read_4(memt, memh, MMCR_PAR(idx)); 650 1.22 dyoung par &= ~MMCR_PAR_TARGET; 651 1.22 dyoung par |= MMCR_PAR_TARGET_OFF; 652 1.22 dyoung bus_space_write_4(memt, memh, MMCR_PAR(idx), par); 653 1.22 dyoung } 654 1.22 dyoung 655 1.22 dyoung static int 656 1.27 dyoung region_paddr_to_par(struct pareg *region0, struct pareg *regions, uint32_t unit) 657 1.27 dyoung { 658 1.27 dyoung struct pareg *residue = regions; 659 1.27 dyoung paddr_t start, end; 660 1.27 dyoung paddr_t start0, end0; 661 1.27 dyoung 662 1.27 dyoung start0 = region0->start; 663 1.27 dyoung end0 = region0->end; 664 1.27 dyoung 665 1.27 dyoung if (start0 % unit != 0) 666 1.27 dyoung start = start0 + unit - start0 % unit; 667 1.27 dyoung else 668 1.27 dyoung start = start0; 669 1.27 dyoung 670 1.27 dyoung end = end0 - end0 % unit; 671 1.27 dyoung 672 1.27 dyoung if (start >= end) 673 1.27 dyoung return 0; 674 1.27 dyoung 675 1.27 dyoung residue->start = start; 676 1.27 dyoung residue->end = end; 677 1.27 dyoung residue++; 678 1.27 dyoung 679 1.27 dyoung if (start0 < start) { 680 1.27 dyoung residue->start = start0; 681 1.27 dyoung residue->end = start; 682 1.27 dyoung residue++; 683 1.27 dyoung } 684 1.27 dyoung if (end < end0) { 685 1.27 dyoung residue->start = end; 686 1.27 dyoung residue->end = end0; 687 1.27 dyoung residue++; 688 1.27 dyoung } 689 1.27 dyoung return residue - regions; 690 1.27 dyoung } 691 1.27 dyoung 692 1.27 dyoung static void 693 1.22 dyoung elansc_protect_text(device_t self, struct elansc_softc *sc) 694 1.22 dyoung { 695 1.27 dyoung int i, j, nregion, pidx, tidx = 0, xnregion; 696 1.22 dyoung uint32_t protsize, unprotsize; 697 1.22 dyoung paddr_t start_pa, end_pa; 698 1.22 dyoung extern char kernel_text, etext; 699 1.22 dyoung bus_space_tag_t memt; 700 1.22 dyoung bus_space_handle_t memh; 701 1.27 dyoung struct pareg region0, regions[3], xregions[3]; 702 1.27 dyoung 703 1.27 dyoung sc->sc_textpar[0] = sc->sc_textpar[1] = sc->sc_textpar[2] = -1; 704 1.22 dyoung 705 1.22 dyoung memt = sc->sc_memt; 706 1.22 dyoung memh = sc->sc_memh; 707 1.22 dyoung 708 1.27 dyoung if (!pmap_extract(pmap_kernel(), (vaddr_t)&kernel_text, 709 1.27 dyoung ®ion0.start) || 710 1.27 dyoung !pmap_extract(pmap_kernel(), (vaddr_t)&etext, 711 1.27 dyoung ®ion0.end)) 712 1.27 dyoung return; 713 1.22 dyoung 714 1.27 dyoung if (&etext - &kernel_text != region0.end - region0.start) { 715 1.22 dyoung aprint_error_dev(self, "kernel text may not be contiguous\n"); 716 1.27 dyoung return; 717 1.22 dyoung } 718 1.22 dyoung 719 1.27 dyoung if ((pidx = elansc_alloc_par(memt, memh)) == -1) { 720 1.22 dyoung aprint_error_dev(self, "cannot allocate PAR\n"); 721 1.27 dyoung return; 722 1.22 dyoung } 723 1.22 dyoung 724 1.50 christos (void) bus_space_read_4(memt, memh, MMCR_PAR(pidx)); 725 1.22 dyoung 726 1.22 dyoung aprint_debug_dev(self, 727 1.48 jym "protect kernel text at physical addresses " 728 1.48 jym "%#" PRIxPADDR " - %#" PRIxPADDR "\n", 729 1.48 jym region0.start, region0.end); 730 1.27 dyoung 731 1.27 dyoung nregion = region_paddr_to_par(®ion0, regions, sfkb); 732 1.27 dyoung if (nregion == 0) { 733 1.27 dyoung aprint_error_dev(self, "kernel text is unprotected\n"); 734 1.27 dyoung return; 735 1.27 dyoung } 736 1.27 dyoung 737 1.27 dyoung unprotsize = 0; 738 1.27 dyoung for (i = 1; i < nregion; i++) 739 1.27 dyoung unprotsize += regions[i].end - regions[i].start; 740 1.22 dyoung 741 1.27 dyoung start_pa = regions[0].start; 742 1.27 dyoung end_pa = regions[0].end; 743 1.22 dyoung 744 1.22 dyoung aprint_debug_dev(self, 745 1.48 jym "actually protect kernel text at physical addresses " 746 1.48 jym "%#" PRIxPADDR " - %#" PRIxPADDR "\n", 747 1.48 jym start_pa, end_pa); 748 1.22 dyoung 749 1.22 dyoung aprint_verbose_dev(self, 750 1.22 dyoung "%" PRIu32 " bytes of kernel text are unprotected\n", unprotsize); 751 1.22 dyoung 752 1.22 dyoung protsize = end_pa - start_pa; 753 1.22 dyoung 754 1.27 dyoung elansc_protect(sc, pidx, start_pa, protsize); 755 1.27 dyoung 756 1.27 dyoung sc->sc_textpar[tidx++] = pidx; 757 1.27 dyoung 758 1.27 dyoung unprotsize = 0; 759 1.27 dyoung for (i = 1; i < nregion; i++) { 760 1.27 dyoung xnregion = region_paddr_to_par(®ions[i], xregions, fkb); 761 1.27 dyoung if (xnregion == 0) { 762 1.48 jym aprint_verbose_dev(self, "skip region " 763 1.48 jym "%#" PRIxPADDR " - %#" PRIxPADDR "\n", 764 1.48 jym regions[i].start, regions[i].end); 765 1.27 dyoung continue; 766 1.27 dyoung } 767 1.27 dyoung if ((pidx = elansc_alloc_par(memt, memh)) == -1) { 768 1.27 dyoung unprotsize += regions[i].end - regions[i].start; 769 1.27 dyoung continue; 770 1.27 dyoung } 771 1.27 dyoung elansc_protect(sc, pidx, xregions[0].start, 772 1.27 dyoung xregions[0].end - xregions[0].start); 773 1.27 dyoung sc->sc_textpar[tidx++] = pidx; 774 1.27 dyoung 775 1.27 dyoung aprint_debug_dev(self, 776 1.48 jym "protect add'l kernel text at physical addresses " 777 1.48 jym "%#" PRIxPADDR " - %#" PRIxPADDR "\n", 778 1.48 jym xregions[0].start, xregions[0].end); 779 1.27 dyoung 780 1.27 dyoung for (j = 1; j < xnregion; j++) 781 1.27 dyoung unprotsize += xregions[j].end - xregions[j].start; 782 1.27 dyoung } 783 1.27 dyoung aprint_verbose_dev(self, 784 1.27 dyoung "%" PRIu32 " bytes of kernel text still unprotected\n", unprotsize); 785 1.27 dyoung 786 1.27 dyoung } 787 1.27 dyoung 788 1.27 dyoung static void 789 1.27 dyoung elansc_protect(struct elansc_softc *sc, int pidx, paddr_t addr, uint32_t sz) 790 1.27 dyoung { 791 1.27 dyoung uint32_t addr_field, blksz, par, size_field; 792 1.27 dyoung 793 1.27 dyoung /* set attribute, target. */ 794 1.27 dyoung par = MMCR_PAR_TARGET_SDRAM | MMCR_PAR_ATTR_NOWRITE; 795 1.27 dyoung 796 1.27 dyoung KASSERT(addr % fkb == 0 && sz % fkb == 0); 797 1.27 dyoung 798 1.27 dyoung if (addr % sfkb == 0 && sz % sfkb == 0) { 799 1.27 dyoung par |= MMCR_PAR_PG_SZ; 800 1.27 dyoung 801 1.27 dyoung size_field = MMCR_PAR_64KB_SZ; 802 1.27 dyoung addr_field = MMCR_PAR_64KB_ST_ADR; 803 1.27 dyoung blksz = 64 * 1024; 804 1.27 dyoung } else { 805 1.27 dyoung size_field = MMCR_PAR_4KB_SZ; 806 1.27 dyoung addr_field = MMCR_PAR_4KB_ST_ADR; 807 1.27 dyoung blksz = 4 * 1024; 808 1.27 dyoung } 809 1.27 dyoung 810 1.27 dyoung KASSERT(sz / blksz - 1 <= __SHIFTOUT_MASK(size_field)); 811 1.27 dyoung KASSERT(addr / blksz <= __SHIFTOUT_MASK(addr_field)); 812 1.27 dyoung 813 1.27 dyoung /* set size and address. */ 814 1.27 dyoung par |= __SHIFTIN(sz / blksz - 1, size_field); 815 1.27 dyoung par |= __SHIFTIN(addr / blksz, addr_field); 816 1.27 dyoung 817 1.27 dyoung bus_space_write_4(sc->sc_memt, sc->sc_memh, MMCR_PAR(pidx), par); 818 1.22 dyoung } 819 1.22 dyoung 820 1.22 dyoung static int 821 1.23 dyoung elansc_protect_pg0(device_t self, struct elansc_softc *sc) 822 1.22 dyoung { 823 1.27 dyoung int pidx; 824 1.23 dyoung const paddr_t pg0_paddr = 0; 825 1.22 dyoung bus_space_tag_t memt; 826 1.22 dyoung bus_space_handle_t memh; 827 1.22 dyoung 828 1.22 dyoung memt = sc->sc_memt; 829 1.22 dyoung memh = sc->sc_memh; 830 1.22 dyoung 831 1.23 dyoung if (elansc_do_protect_pg0 == 0) 832 1.22 dyoung return -1; 833 1.22 dyoung 834 1.27 dyoung if ((pidx = elansc_alloc_par(memt, memh)) == -1) 835 1.22 dyoung return -1; 836 1.22 dyoung 837 1.23 dyoung aprint_debug_dev(self, "protect page 0\n"); 838 1.22 dyoung 839 1.27 dyoung elansc_protect(sc, pidx, pg0_paddr, PG0_PROT_SIZE); 840 1.27 dyoung return pidx; 841 1.22 dyoung } 842 1.22 dyoung 843 1.22 dyoung static void 844 1.22 dyoung elanpex_intr_ack(bus_space_tag_t memt, bus_space_handle_t memh) 845 1.22 dyoung { 846 1.22 dyoung bus_space_write_1(memt, memh, MMCR_PCIARBSTA, 847 1.22 dyoung MMCR_PCIARBSTA_GNT_TO_STA); 848 1.22 dyoung bus_space_write_2(memt, memh, MMCR_HBTGTIRQSTA, MMCR_TGTIRQ_ACT); 849 1.22 dyoung bus_space_write_2(memt, memh, MMCR_HBMSTIRQSTA, MMCR_MSTIRQ_ACT); 850 1.22 dyoung } 851 1.22 dyoung 852 1.17 dyoung static bool 853 1.47 dyoung elansc_suspend(device_t dev, const pmf_qual_t *qual) 854 1.17 dyoung { 855 1.19 dyoung bool rc; 856 1.17 dyoung struct elansc_softc *sc = device_private(dev); 857 1.17 dyoung 858 1.19 dyoung mutex_enter(&sc->sc_mtx); 859 1.19 dyoung rc = ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED); 860 1.19 dyoung mutex_exit(&sc->sc_mtx); 861 1.19 dyoung if (!rc) 862 1.17 dyoung aprint_debug_dev(dev, "watchdog enabled, suspend forbidden"); 863 1.19 dyoung return rc; 864 1.17 dyoung } 865 1.17 dyoung 866 1.17 dyoung static bool 867 1.47 dyoung elansc_resume(device_t dev, const pmf_qual_t *qual) 868 1.17 dyoung { 869 1.17 dyoung struct elansc_softc *sc = device_private(dev); 870 1.17 dyoung 871 1.19 dyoung mutex_enter(&sc->sc_mtx); 872 1.17 dyoung /* Set up the watchdog registers with some defaults. */ 873 1.17 dyoung elansc_wdogctl_write(sc, WDTMRCTL_WRST_ENB | WDTMRCTL_EXP_SEL30); 874 1.17 dyoung 875 1.17 dyoung /* ...and clear it. */ 876 1.17 dyoung elansc_wdogctl_reset(sc); 877 1.19 dyoung mutex_exit(&sc->sc_mtx); 878 1.17 dyoung 879 1.31 dyoung elansc_perf_tune(dev, sc->sc_memt, sc->sc_memh); 880 1.31 dyoung 881 1.17 dyoung return true; 882 1.17 dyoung } 883 1.17 dyoung 884 1.42 dyoung static bool 885 1.42 dyoung elansc_shutdown(device_t self, int how) 886 1.42 dyoung { 887 1.42 dyoung struct elansc_softc *sc = device_private(self); 888 1.42 dyoung 889 1.42 dyoung /* Set up the watchdog registers with some defaults. */ 890 1.42 dyoung elansc_wdogctl_write(sc, WDTMRCTL_WRST_ENB | WDTMRCTL_EXP_SEL30); 891 1.42 dyoung 892 1.42 dyoung /* ...and clear it. */ 893 1.42 dyoung elansc_wdogctl_reset(sc); 894 1.42 dyoung 895 1.42 dyoung return true; 896 1.42 dyoung } 897 1.42 dyoung 898 1.18 dyoung static int 899 1.18 dyoung elansc_detach(device_t self, int flags) 900 1.18 dyoung { 901 1.19 dyoung int rc; 902 1.18 dyoung struct elansc_softc *sc = device_private(self); 903 1.18 dyoung 904 1.19 dyoung if ((rc = config_detach_children(self, flags)) != 0) 905 1.19 dyoung return rc; 906 1.19 dyoung 907 1.18 dyoung pmf_device_deregister(self); 908 1.18 dyoung 909 1.42 dyoung if ((flags & DETACH_SHUTDOWN) == 0 && 910 1.42 dyoung (rc = sysmon_wdog_unregister(&sc->sc_smw)) != 0) { 911 1.19 dyoung if (rc == ERESTART) 912 1.19 dyoung rc = EINTR; 913 1.19 dyoung return rc; 914 1.19 dyoung } 915 1.19 dyoung 916 1.19 dyoung mutex_enter(&sc->sc_mtx); 917 1.18 dyoung 918 1.42 dyoung (void)elansc_shutdown(self, 0); 919 1.18 dyoung 920 1.37 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_PICICR, sc->sc_picicr); 921 1.37 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_MPICMODE, 922 1.37 dyoung sc->sc_mpicmode); 923 1.37 dyoung 924 1.19 dyoung mutex_exit(&sc->sc_mtx); 925 1.19 dyoung mutex_destroy(&sc->sc_mtx); 926 1.33 dyoung 927 1.33 dyoung bus_space_unmap(sc->sc_memt, sc->sc_memh, PAGE_SIZE); 928 1.31 dyoung elansc_attached = false; 929 1.18 dyoung return 0; 930 1.18 dyoung } 931 1.18 dyoung 932 1.22 dyoung static void * 933 1.22 dyoung elansc_intr_establish(device_t dev, int (*handler)(void *), void *arg) 934 1.22 dyoung { 935 1.22 dyoung struct pic *pic; 936 1.22 dyoung void *ih; 937 1.22 dyoung 938 1.22 dyoung if ((pic = intr_findpic(ELAN_IRQ)) == NULL) { 939 1.22 dyoung aprint_error_dev(dev, "PIC for irq %d not found\n", 940 1.22 dyoung ELAN_IRQ); 941 1.22 dyoung return NULL; 942 1.22 dyoung } else if ((ih = intr_establish(ELAN_IRQ, pic, ELAN_IRQ, 943 1.34 ad IST_LEVEL, IPL_HIGH, handler, arg, false)) == NULL) { 944 1.22 dyoung aprint_error_dev(dev, 945 1.22 dyoung "could not establish interrupt\n"); 946 1.22 dyoung return NULL; 947 1.22 dyoung } 948 1.22 dyoung aprint_verbose_dev(dev, "interrupting at irq %d\n", ELAN_IRQ); 949 1.22 dyoung return ih; 950 1.22 dyoung } 951 1.22 dyoung 952 1.22 dyoung static bool 953 1.47 dyoung elanpex_resume(device_t self, const pmf_qual_t *qual) 954 1.22 dyoung { 955 1.22 dyoung struct elansc_softc *sc = device_private(device_parent(self)); 956 1.22 dyoung 957 1.22 dyoung elanpex_intr_establish(self, sc); 958 1.22 dyoung return sc->sc_eih != NULL; 959 1.22 dyoung } 960 1.22 dyoung 961 1.22 dyoung static bool 962 1.47 dyoung elanpex_suspend(device_t self, const pmf_qual_t *qual) 963 1.22 dyoung { 964 1.22 dyoung struct elansc_softc *sc = device_private(device_parent(self)); 965 1.22 dyoung 966 1.22 dyoung elanpex_intr_disestablish(sc); 967 1.22 dyoung 968 1.22 dyoung return true; 969 1.22 dyoung } 970 1.22 dyoung 971 1.22 dyoung static bool 972 1.47 dyoung elanpar_resume(device_t self, const pmf_qual_t *qual) 973 1.22 dyoung { 974 1.22 dyoung struct elansc_softc *sc = device_private(device_parent(self)); 975 1.22 dyoung 976 1.22 dyoung elanpar_intr_establish(self, sc); 977 1.22 dyoung return sc->sc_pih != NULL; 978 1.22 dyoung } 979 1.22 dyoung 980 1.22 dyoung static bool 981 1.47 dyoung elanpar_suspend(device_t self, const pmf_qual_t *qual) 982 1.22 dyoung { 983 1.22 dyoung struct elansc_softc *sc = device_private(device_parent(self)); 984 1.22 dyoung 985 1.25 dyoung elanpar_intr_disestablish(sc); 986 1.22 dyoung 987 1.22 dyoung return true; 988 1.22 dyoung } 989 1.22 dyoung 990 1.22 dyoung static void 991 1.22 dyoung elanpex_intr_establish(device_t self, struct elansc_softc *sc) 992 1.22 dyoung { 993 1.22 dyoung uint8_t sysarbctl; 994 1.22 dyoung uint16_t pcihostmap, mstirq, tgtirq; 995 1.22 dyoung 996 1.22 dyoung pcihostmap = bus_space_read_2(sc->sc_memt, sc->sc_memh, 997 1.22 dyoung MMCR_PCIHOSTMAP); 998 1.22 dyoung /* Priority P2 (Master PIC IR1) */ 999 1.22 dyoung pcihostmap &= ~MMCR_PCIHOSTMAP_PCI_IRQ_MAP; 1000 1.22 dyoung pcihostmap |= __SHIFTIN(__BIT(ELAN_IRQ), MMCR_PCIHOSTMAP_PCI_IRQ_MAP); 1001 1.22 dyoung if (elansc_pcinmi) 1002 1.22 dyoung pcihostmap |= MMCR_PCIHOSTMAP_PCI_NMI_ENB; 1003 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_PCIHOSTMAP, 1004 1.22 dyoung pcihostmap); 1005 1.22 dyoung 1006 1.22 dyoung elanpex_intr_ack(sc->sc_memt, sc->sc_memh); 1007 1.22 dyoung 1008 1.22 dyoung sysarbctl = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_SYSARBCTL); 1009 1.22 dyoung mstirq = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_HBMSTIRQCTL); 1010 1.22 dyoung tgtirq = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_HBTGTIRQCTL); 1011 1.22 dyoung 1012 1.22 dyoung sysarbctl |= MMCR_SYSARBCTL_GNT_TO_INT_ENB; 1013 1.22 dyoung 1014 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_RTRTO_IRQ_ENB; 1015 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_TABRT_IRQ_ENB; 1016 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_MABRT_IRQ_ENB; 1017 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_SERR_IRQ_ENB; 1018 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_RPER_IRQ_ENB; 1019 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_DPER_IRQ_ENB; 1020 1.22 dyoung 1021 1.22 dyoung tgtirq |= MMCR_HBTGTIRQCTL_T_DLYTO_IRQ_ENB; 1022 1.22 dyoung tgtirq |= MMCR_HBTGTIRQCTL_T_APER_IRQ_ENB; 1023 1.22 dyoung tgtirq |= MMCR_HBTGTIRQCTL_T_DPER_IRQ_ENB; 1024 1.22 dyoung 1025 1.22 dyoung if (elansc_pcinmi) { 1026 1.38 yamt sc->sc_eih = nmi_establish(elanpex_nmi, sc); 1027 1.22 dyoung 1028 1.35 dyoung /* Activate NMI instead of maskable interrupts for 1029 1.35 dyoung * all PCI exceptions: 1030 1.35 dyoung */ 1031 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_RTRTO_IRQ_SEL; 1032 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_TABRT_IRQ_SEL; 1033 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_MABRT_IRQ_SEL; 1034 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_SERR_IRQ_SEL; 1035 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_RPER_IRQ_SEL; 1036 1.22 dyoung mstirq |= MMCR_HBMSTIRQCTL_M_DPER_IRQ_SEL; 1037 1.22 dyoung 1038 1.22 dyoung tgtirq |= MMCR_HBTGTIRQCTL_T_DLYTO_IRQ_SEL; 1039 1.22 dyoung tgtirq |= MMCR_HBTGTIRQCTL_T_APER_IRQ_SEL; 1040 1.22 dyoung tgtirq |= MMCR_HBTGTIRQCTL_T_DPER_IRQ_SEL; 1041 1.22 dyoung } else 1042 1.22 dyoung sc->sc_eih = elansc_intr_establish(self, elanpex_intr, sc); 1043 1.22 dyoung 1044 1.22 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_SYSARBCTL, sysarbctl); 1045 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_HBMSTIRQCTL, mstirq); 1046 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_HBTGTIRQCTL, tgtirq); 1047 1.22 dyoung } 1048 1.22 dyoung 1049 1.22 dyoung static void 1050 1.22 dyoung elanpex_attach(device_t parent, device_t self, void *aux) 1051 1.22 dyoung { 1052 1.22 dyoung struct elansc_softc *sc = device_private(parent); 1053 1.22 dyoung 1054 1.22 dyoung aprint_naive(": PCI Exceptions\n"); 1055 1.22 dyoung aprint_normal(": AMD Elan SC520 PCI Exceptions\n"); 1056 1.22 dyoung 1057 1.22 dyoung elanpex_intr_establish(self, sc); 1058 1.22 dyoung 1059 1.22 dyoung aprint_debug_dev(self, "HBMSTIRQCTL %04x\n", 1060 1.22 dyoung bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_HBMSTIRQCTL)); 1061 1.22 dyoung 1062 1.22 dyoung aprint_debug_dev(self, "HBTGTIRQCTL %04x\n", 1063 1.22 dyoung bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_HBTGTIRQCTL)); 1064 1.22 dyoung 1065 1.22 dyoung aprint_debug_dev(self, "PCIHOSTMAP %04x\n", 1066 1.22 dyoung bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_PCIHOSTMAP)); 1067 1.22 dyoung 1068 1.22 dyoung pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, 1069 1.22 dyoung pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG) | 1070 1.22 dyoung PCI_COMMAND_PARITY_ENABLE|PCI_COMMAND_SERR_ENABLE); 1071 1.22 dyoung 1072 1.26 dyoung if (!pmf_device_register1(self, elanpex_suspend, elanpex_resume, 1073 1.26 dyoung elanpex_shutdown)) 1074 1.22 dyoung aprint_error_dev(self, "could not establish power hooks\n"); 1075 1.22 dyoung } 1076 1.22 dyoung 1077 1.26 dyoung static bool 1078 1.26 dyoung elanpex_shutdown(device_t self, int flags) 1079 1.22 dyoung { 1080 1.26 dyoung struct elansc_softc *sc = device_private(device_parent(self)); 1081 1.22 dyoung uint8_t sysarbctl; 1082 1.22 dyoung uint16_t pcihostmap, mstirq, tgtirq; 1083 1.22 dyoung 1084 1.22 dyoung sysarbctl = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_SYSARBCTL); 1085 1.22 dyoung sysarbctl &= ~MMCR_SYSARBCTL_GNT_TO_INT_ENB; 1086 1.22 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_SYSARBCTL, sysarbctl); 1087 1.22 dyoung 1088 1.22 dyoung mstirq = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_HBMSTIRQCTL); 1089 1.22 dyoung mstirq &= ~MMCR_HBMSTIRQCTL_M_RTRTO_IRQ_ENB; 1090 1.22 dyoung mstirq &= ~MMCR_HBMSTIRQCTL_M_TABRT_IRQ_ENB; 1091 1.22 dyoung mstirq &= ~MMCR_HBMSTIRQCTL_M_MABRT_IRQ_ENB; 1092 1.22 dyoung mstirq &= ~MMCR_HBMSTIRQCTL_M_SERR_IRQ_ENB; 1093 1.22 dyoung mstirq &= ~MMCR_HBMSTIRQCTL_M_RPER_IRQ_ENB; 1094 1.22 dyoung mstirq &= ~MMCR_HBMSTIRQCTL_M_DPER_IRQ_ENB; 1095 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_HBMSTIRQCTL, mstirq); 1096 1.22 dyoung 1097 1.22 dyoung tgtirq = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_HBTGTIRQCTL); 1098 1.22 dyoung tgtirq &= ~MMCR_HBTGTIRQCTL_T_DLYTO_IRQ_ENB; 1099 1.22 dyoung tgtirq &= ~MMCR_HBTGTIRQCTL_T_APER_IRQ_ENB; 1100 1.22 dyoung tgtirq &= ~MMCR_HBTGTIRQCTL_T_DPER_IRQ_ENB; 1101 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_HBTGTIRQCTL, tgtirq); 1102 1.22 dyoung 1103 1.22 dyoung pcihostmap = bus_space_read_2(sc->sc_memt, sc->sc_memh, 1104 1.22 dyoung MMCR_PCIHOSTMAP); 1105 1.22 dyoung /* Priority P2 (Master PIC IR1) */ 1106 1.22 dyoung pcihostmap &= ~MMCR_PCIHOSTMAP_PCI_IRQ_MAP; 1107 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_PCIHOSTMAP, 1108 1.22 dyoung pcihostmap); 1109 1.22 dyoung 1110 1.26 dyoung return true; 1111 1.26 dyoung } 1112 1.26 dyoung 1113 1.26 dyoung static void 1114 1.26 dyoung elanpex_intr_disestablish(struct elansc_softc *sc) 1115 1.26 dyoung { 1116 1.26 dyoung elanpex_shutdown(sc->sc_pex, 0); 1117 1.26 dyoung 1118 1.22 dyoung if (elansc_pcinmi) 1119 1.22 dyoung nmi_disestablish(sc->sc_eih); 1120 1.22 dyoung else 1121 1.22 dyoung intr_disestablish(sc->sc_eih); 1122 1.22 dyoung sc->sc_eih = NULL; 1123 1.22 dyoung 1124 1.22 dyoung } 1125 1.22 dyoung 1126 1.22 dyoung static int 1127 1.22 dyoung elanpex_detach(device_t self, int flags) 1128 1.22 dyoung { 1129 1.22 dyoung struct elansc_softc *sc = device_private(device_parent(self)); 1130 1.22 dyoung 1131 1.22 dyoung pmf_device_deregister(self); 1132 1.22 dyoung elanpex_intr_disestablish(sc); 1133 1.22 dyoung 1134 1.22 dyoung return 0; 1135 1.22 dyoung } 1136 1.22 dyoung 1137 1.22 dyoung static void 1138 1.22 dyoung elanpar_intr_establish(device_t self, struct elansc_softc *sc) 1139 1.22 dyoung { 1140 1.22 dyoung uint8_t adddecctl, wpvmap; 1141 1.22 dyoung 1142 1.22 dyoung wpvmap = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_WPVMAP); 1143 1.22 dyoung wpvmap &= ~MMCR_WPVMAP_INT_MAP; 1144 1.22 dyoung if (elansc_wpvnmi) 1145 1.22 dyoung wpvmap |= MMCR_WPVMAP_INT_NMI; 1146 1.22 dyoung else 1147 1.22 dyoung wpvmap |= __SHIFTIN(__BIT(ELAN_IRQ), MMCR_WPVMAP_INT_MAP); 1148 1.22 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_WPVMAP, wpvmap); 1149 1.22 dyoung 1150 1.22 dyoung /* clear interrupt status */ 1151 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WPVSTA, 1152 1.22 dyoung MMCR_WPVSTA_WPV_STA); 1153 1.22 dyoung 1154 1.22 dyoung /* establish interrupt */ 1155 1.22 dyoung if (elansc_wpvnmi) 1156 1.38 yamt sc->sc_pih = nmi_establish(elanpar_nmi, sc); 1157 1.22 dyoung else 1158 1.22 dyoung sc->sc_pih = elansc_intr_establish(self, elanpar_intr, sc); 1159 1.22 dyoung 1160 1.22 dyoung adddecctl = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_ADDDECCTL); 1161 1.22 dyoung adddecctl |= MMCR_ADDDECCTL_WPV_INT_ENB; 1162 1.22 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_ADDDECCTL, adddecctl); 1163 1.22 dyoung } 1164 1.22 dyoung 1165 1.26 dyoung static bool 1166 1.26 dyoung elanpar_shutdown(device_t self, int flags) 1167 1.26 dyoung { 1168 1.27 dyoung int i; 1169 1.26 dyoung struct elansc_softc *sc = device_private(device_parent(self)); 1170 1.26 dyoung 1171 1.27 dyoung for (i = 0; i < __arraycount(sc->sc_textpar); i++) { 1172 1.27 dyoung if (sc->sc_textpar[i] == -1) 1173 1.27 dyoung continue; 1174 1.27 dyoung elansc_disable_par(sc->sc_memt, sc->sc_memh, sc->sc_textpar[i]); 1175 1.27 dyoung sc->sc_textpar[i] = -1; 1176 1.26 dyoung } 1177 1.26 dyoung if (sc->sc_pg0par != -1) { 1178 1.26 dyoung elansc_disable_par(sc->sc_memt, sc->sc_memh, sc->sc_pg0par); 1179 1.26 dyoung sc->sc_pg0par = -1; 1180 1.26 dyoung } 1181 1.26 dyoung return true; 1182 1.26 dyoung } 1183 1.26 dyoung 1184 1.22 dyoung static void 1185 1.30 dyoung elanpar_deferred_attach(device_t self) 1186 1.30 dyoung { 1187 1.30 dyoung struct elansc_softc *sc = device_private(device_parent(self)); 1188 1.30 dyoung 1189 1.30 dyoung elansc_protect_text(self, sc); 1190 1.30 dyoung } 1191 1.30 dyoung 1192 1.30 dyoung static void 1193 1.22 dyoung elanpar_attach(device_t parent, device_t self, void *aux) 1194 1.22 dyoung { 1195 1.22 dyoung struct elansc_softc *sc = device_private(parent); 1196 1.22 dyoung 1197 1.22 dyoung aprint_naive(": Programmable Address Regions\n"); 1198 1.22 dyoung aprint_normal(": AMD Elan SC520 Programmable Address Regions\n"); 1199 1.22 dyoung 1200 1.22 dyoung elansc_print_1(self, sc, MMCR_WPVMAP); 1201 1.22 dyoung elansc_print_all_par(self, sc->sc_memt, sc->sc_memh); 1202 1.22 dyoung 1203 1.23 dyoung sc->sc_pg0par = elansc_protect_pg0(self, sc); 1204 1.30 dyoung /* XXX grotty hack to avoid trapping writes by x86_patch() 1205 1.30 dyoung * to the kernel text on a MULTIPROCESSOR kernel. 1206 1.30 dyoung */ 1207 1.30 dyoung config_interrupts(self, elanpar_deferred_attach); 1208 1.27 dyoung 1209 1.27 dyoung elansc_print_all_par(self, sc->sc_memt, sc->sc_memh); 1210 1.22 dyoung 1211 1.22 dyoung elanpar_intr_establish(self, sc); 1212 1.22 dyoung 1213 1.22 dyoung elansc_print_1(self, sc, MMCR_ADDDECCTL); 1214 1.22 dyoung 1215 1.26 dyoung if (!pmf_device_register1(self, elanpar_suspend, elanpar_resume, 1216 1.26 dyoung elanpar_shutdown)) 1217 1.22 dyoung aprint_error_dev(self, "could not establish power hooks\n"); 1218 1.22 dyoung } 1219 1.22 dyoung 1220 1.22 dyoung static void 1221 1.22 dyoung elanpar_intr_disestablish(struct elansc_softc *sc) 1222 1.22 dyoung { 1223 1.22 dyoung uint8_t adddecctl, wpvmap; 1224 1.22 dyoung 1225 1.22 dyoung /* disable interrupt, acknowledge it, disestablish our 1226 1.22 dyoung * handler, unmap it 1227 1.22 dyoung */ 1228 1.22 dyoung adddecctl = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_ADDDECCTL); 1229 1.22 dyoung adddecctl &= ~MMCR_ADDDECCTL_WPV_INT_ENB; 1230 1.22 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_ADDDECCTL, adddecctl); 1231 1.22 dyoung 1232 1.22 dyoung bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WPVSTA, 1233 1.22 dyoung MMCR_WPVSTA_WPV_STA); 1234 1.22 dyoung 1235 1.22 dyoung if (elansc_wpvnmi) 1236 1.22 dyoung nmi_disestablish(sc->sc_pih); 1237 1.22 dyoung else 1238 1.22 dyoung intr_disestablish(sc->sc_pih); 1239 1.22 dyoung sc->sc_pih = NULL; 1240 1.22 dyoung 1241 1.22 dyoung wpvmap = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_WPVMAP); 1242 1.22 dyoung wpvmap &= ~MMCR_WPVMAP_INT_MAP; 1243 1.22 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_WPVMAP, wpvmap); 1244 1.22 dyoung } 1245 1.22 dyoung 1246 1.22 dyoung static int 1247 1.22 dyoung elanpar_detach(device_t self, int flags) 1248 1.22 dyoung { 1249 1.22 dyoung struct elansc_softc *sc = device_private(device_parent(self)); 1250 1.22 dyoung 1251 1.22 dyoung pmf_device_deregister(self); 1252 1.22 dyoung 1253 1.26 dyoung elanpar_shutdown(self, 0); 1254 1.22 dyoung 1255 1.22 dyoung elanpar_intr_disestablish(sc); 1256 1.22 dyoung 1257 1.22 dyoung return 0; 1258 1.22 dyoung } 1259 1.22 dyoung 1260 1.1 thorpej static void 1261 1.21 dyoung elansc_attach(device_t parent, device_t self, void *aux) 1262 1.1 thorpej { 1263 1.17 dyoung struct elansc_softc *sc = device_private(self); 1264 1.31 dyoung struct pcibus_attach_args *pba = aux; 1265 1.1 thorpej uint16_t rev; 1266 1.22 dyoung uint8_t cpuctl, picicr, ressta; 1267 1.10 drochner #if NGPIO > 0 1268 1.22 dyoung int pin, reg, shift; 1269 1.9 riz uint16_t data; 1270 1.10 drochner #endif 1271 1.29 dyoung 1272 1.29 dyoung sc->sc_dev = self; 1273 1.29 dyoung 1274 1.31 dyoung sc->sc_pc = pba->pba_pc; 1275 1.40 dyoung sc->sc_pciflags = pba->pba_flags; 1276 1.40 dyoung sc->sc_dmat = pba->pba_dmat; 1277 1.40 dyoung sc->sc_dmat64 = pba->pba_dmat64; 1278 1.31 dyoung sc->sc_tag = pci_make_tag(sc->sc_pc, 0, 0, 0); 1279 1.1 thorpej 1280 1.14 thorpej aprint_naive(": System Controller\n"); 1281 1.14 thorpej aprint_normal(": AMD Elan SC520 System Controller\n"); 1282 1.1 thorpej 1283 1.40 dyoung sc->sc_iot = pba->pba_iot; 1284 1.31 dyoung sc->sc_memt = pba->pba_memt; 1285 1.5 thorpej if (bus_space_map(sc->sc_memt, MMCR_BASE_ADDR, PAGE_SIZE, 0, 1286 1.1 thorpej &sc->sc_memh) != 0) { 1287 1.29 dyoung aprint_error_dev(sc->sc_dev, "unable to map registers\n"); 1288 1.1 thorpej return; 1289 1.1 thorpej } 1290 1.1 thorpej 1291 1.19 dyoung mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_HIGH); 1292 1.19 dyoung 1293 1.1 thorpej rev = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_REVID); 1294 1.1 thorpej cpuctl = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_CPUCTL); 1295 1.1 thorpej 1296 1.29 dyoung aprint_normal_dev(sc->sc_dev, 1297 1.21 dyoung "product %d stepping %d.%d, CPU clock %s\n", 1298 1.1 thorpej (rev & REVID_PRODID) >> REVID_PRODID_SHIFT, 1299 1.1 thorpej (rev & REVID_MAJSTEP) >> REVID_MAJSTEP_SHIFT, 1300 1.1 thorpej (rev & REVID_MINSTEP), 1301 1.1 thorpej elansc_speeds[cpuctl & CPUCTL_CPU_CLK_SPD_MASK]); 1302 1.1 thorpej 1303 1.1 thorpej /* 1304 1.1 thorpej * SC520 rev A1 has a bug that affects the watchdog timer. If 1305 1.1 thorpej * the GP bus echo mode is enabled, writing to the watchdog control 1306 1.1 thorpej * register is blocked. 1307 1.1 thorpej * 1308 1.1 thorpej * The BIOS in some systems (e.g. the Soekris net4501) enables 1309 1.1 thorpej * GP bus echo for various reasons, so we need to switch it off 1310 1.1 thorpej * when we talk to the watchdog timer. 1311 1.1 thorpej * 1312 1.1 thorpej * XXX The step 1.1 (B1?) in my Soekris net4501 also has this 1313 1.1 thorpej * XXX problem, so we'll just enable it for all Elan SC520s 1314 1.8 keihan * XXX for now. --thorpej (at) NetBSD.org 1315 1.1 thorpej */ 1316 1.1 thorpej if (1 || rev == ((PRODID_ELAN_SC520 << REVID_PRODID_SHIFT) | 1317 1.1 thorpej (0 << REVID_MAJSTEP_SHIFT) | (1))) 1318 1.1 thorpej sc->sc_echobug = 1; 1319 1.1 thorpej 1320 1.1 thorpej /* 1321 1.1 thorpej * Determine cause of the last reset, and issue a warning if it 1322 1.1 thorpej * was due to watchdog expiry. 1323 1.1 thorpej */ 1324 1.1 thorpej ressta = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_RESSTA); 1325 1.1 thorpej if (ressta & RESSTA_WDT_RST_DET) 1326 1.29 dyoung aprint_error_dev(sc->sc_dev, 1327 1.21 dyoung "WARNING: LAST RESET DUE TO WATCHDOG EXPIRATION!\n"); 1328 1.1 thorpej bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_RESSTA, ressta); 1329 1.1 thorpej 1330 1.22 dyoung elansc_print_1(self, sc, MMCR_MPICMODE); 1331 1.22 dyoung elansc_print_1(self, sc, MMCR_SL1PICMODE); 1332 1.22 dyoung elansc_print_1(self, sc, MMCR_SL2PICMODE); 1333 1.22 dyoung elansc_print_1(self, sc, MMCR_PICICR); 1334 1.22 dyoung 1335 1.22 dyoung sc->sc_mpicmode = bus_space_read_1(sc->sc_memt, sc->sc_memh, 1336 1.22 dyoung MMCR_MPICMODE); 1337 1.22 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_MPICMODE, 1338 1.22 dyoung sc->sc_mpicmode | __BIT(ELAN_IRQ)); 1339 1.22 dyoung 1340 1.22 dyoung sc->sc_picicr = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_PICICR); 1341 1.22 dyoung picicr = sc->sc_picicr; 1342 1.22 dyoung if (elansc_pcinmi || elansc_wpvnmi) 1343 1.22 dyoung picicr |= MMCR_PICICR_NMI_ENB; 1344 1.22 dyoung #if 0 1345 1.22 dyoung /* PC/AT compatibility */ 1346 1.22 dyoung picicr |= MMCR_PICICR_S1_GINT_MODE|MMCR_PICICR_M_GINT_MODE; 1347 1.22 dyoung #endif 1348 1.22 dyoung bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_PICICR, picicr); 1349 1.22 dyoung 1350 1.22 dyoung elansc_print_1(self, sc, MMCR_PICICR); 1351 1.22 dyoung elansc_print_1(self, sc, MMCR_MPICMODE); 1352 1.22 dyoung 1353 1.22 dyoung mutex_enter(&sc->sc_mtx); 1354 1.1 thorpej /* Set up the watchdog registers with some defaults. */ 1355 1.1 thorpej elansc_wdogctl_write(sc, WDTMRCTL_WRST_ENB | WDTMRCTL_EXP_SEL30); 1356 1.1 thorpej 1357 1.1 thorpej /* ...and clear it. */ 1358 1.1 thorpej elansc_wdogctl_reset(sc); 1359 1.22 dyoung mutex_exit(&sc->sc_mtx); 1360 1.9 riz 1361 1.42 dyoung if (!pmf_device_register1(self, elansc_suspend, elansc_resume, 1362 1.42 dyoung elansc_shutdown)) 1363 1.22 dyoung aprint_error_dev(self, "could not establish power hooks\n"); 1364 1.17 dyoung 1365 1.10 drochner #if NGPIO > 0 1366 1.9 riz /* Initialize GPIO pins array */ 1367 1.9 riz for (pin = 0; pin < ELANSC_PIO_NPINS; pin++) { 1368 1.9 riz sc->sc_gpio_pins[pin].pin_num = pin; 1369 1.9 riz sc->sc_gpio_pins[pin].pin_caps = GPIO_PIN_INPUT | 1370 1.9 riz GPIO_PIN_OUTPUT; 1371 1.9 riz 1372 1.9 riz /* Read initial state */ 1373 1.9 riz reg = (pin < 16 ? MMCR_PIODIR15_0 : MMCR_PIODIR31_16); 1374 1.9 riz shift = pin % 16; 1375 1.9 riz data = bus_space_read_2(sc->sc_memt, sc->sc_memh, reg); 1376 1.9 riz if ((data & (1 << shift)) == 0) 1377 1.9 riz sc->sc_gpio_pins[pin].pin_flags = GPIO_PIN_INPUT; 1378 1.9 riz else 1379 1.9 riz sc->sc_gpio_pins[pin].pin_flags = GPIO_PIN_OUTPUT; 1380 1.9 riz if (elansc_gpio_pin_read(sc, pin) == 0) 1381 1.9 riz sc->sc_gpio_pins[pin].pin_state = GPIO_PIN_LOW; 1382 1.9 riz else 1383 1.9 riz sc->sc_gpio_pins[pin].pin_state = GPIO_PIN_HIGH; 1384 1.9 riz } 1385 1.9 riz 1386 1.9 riz /* Create controller tag */ 1387 1.9 riz sc->sc_gpio_gc.gp_cookie = sc; 1388 1.9 riz sc->sc_gpio_gc.gp_pin_read = elansc_gpio_pin_read; 1389 1.9 riz sc->sc_gpio_gc.gp_pin_write = elansc_gpio_pin_write; 1390 1.9 riz sc->sc_gpio_gc.gp_pin_ctl = elansc_gpio_pin_ctl; 1391 1.9 riz 1392 1.10 drochner #endif /* NGPIO */ 1393 1.19 dyoung 1394 1.40 dyoung elansc_rescan(sc->sc_dev, "elanparbus", NULL); 1395 1.40 dyoung elansc_rescan(sc->sc_dev, "elanpexbus", NULL); 1396 1.40 dyoung elansc_rescan(sc->sc_dev, "gpiobus", NULL); 1397 1.40 dyoung 1398 1.19 dyoung /* 1399 1.19 dyoung * Hook up the watchdog timer. 1400 1.19 dyoung */ 1401 1.29 dyoung sc->sc_smw.smw_name = device_xname(sc->sc_dev); 1402 1.19 dyoung sc->sc_smw.smw_cookie = sc; 1403 1.19 dyoung sc->sc_smw.smw_setmode = elansc_wdog_setmode; 1404 1.19 dyoung sc->sc_smw.smw_tickle = elansc_wdog_tickle; 1405 1.19 dyoung sc->sc_smw.smw_period = 32; /* actually 32.54 */ 1406 1.21 dyoung if (sysmon_wdog_register(&sc->sc_smw) != 0) { 1407 1.29 dyoung aprint_error_dev(sc->sc_dev, 1408 1.21 dyoung "unable to register watchdog with sysmon\n"); 1409 1.21 dyoung } 1410 1.31 dyoung elansc_attached = true; 1411 1.40 dyoung elansc_rescan(sc->sc_dev, "pcibus", NULL); 1412 1.1 thorpej } 1413 1.1 thorpej 1414 1.22 dyoung static int 1415 1.36 dyoung elanpex_match(device_t parent, cfdata_t match, void *aux) 1416 1.22 dyoung { 1417 1.22 dyoung struct elansc_softc *sc = device_private(parent); 1418 1.22 dyoung 1419 1.22 dyoung return sc->sc_pex == NULL; 1420 1.22 dyoung } 1421 1.22 dyoung 1422 1.22 dyoung static int 1423 1.36 dyoung elanpar_match(device_t parent, cfdata_t match, void *aux) 1424 1.22 dyoung { 1425 1.22 dyoung struct elansc_softc *sc = device_private(parent); 1426 1.22 dyoung 1427 1.22 dyoung return sc->sc_par == NULL; 1428 1.22 dyoung } 1429 1.22 dyoung 1430 1.36 dyoung /* scan for new children */ 1431 1.36 dyoung static int 1432 1.36 dyoung elansc_rescan(device_t self, const char *ifattr, const int *locators) 1433 1.36 dyoung { 1434 1.36 dyoung struct elansc_softc *sc = device_private(self); 1435 1.36 dyoung 1436 1.40 dyoung if (ifattr_match(ifattr, "elanparbus") && sc->sc_par == NULL) { 1437 1.51 thorpej sc->sc_par = config_found(sc->sc_dev, NULL, NULL, 1438 1.52 thorpej CFARGS(.iattr = "elanparbus")); 1439 1.40 dyoung } 1440 1.40 dyoung 1441 1.40 dyoung if (ifattr_match(ifattr, "elanpexbus") && sc->sc_pex == NULL) { 1442 1.51 thorpej sc->sc_pex = config_found(sc->sc_dev, NULL, NULL, 1443 1.52 thorpej CFARGS(.iattr = "elanpexbus")); 1444 1.40 dyoung } 1445 1.40 dyoung 1446 1.36 dyoung if (ifattr_match(ifattr, "gpiobus") && sc->sc_gpio == NULL) { 1447 1.36 dyoung #if NGPIO > 0 1448 1.36 dyoung struct gpiobus_attach_args gba; 1449 1.36 dyoung 1450 1.40 dyoung memset(&gba, 0, sizeof(gba)); 1451 1.40 dyoung 1452 1.36 dyoung gba.gba_gc = &sc->sc_gpio_gc; 1453 1.36 dyoung gba.gba_pins = sc->sc_gpio_pins; 1454 1.36 dyoung gba.gba_npins = ELANSC_PIO_NPINS; 1455 1.51 thorpej sc->sc_gpio = config_found(sc->sc_dev, &gba, gpiobus_print, 1456 1.52 thorpej CFARGS(.iattr = "gpiobus")); 1457 1.36 dyoung #endif 1458 1.36 dyoung } 1459 1.36 dyoung 1460 1.40 dyoung if (ifattr_match(ifattr, "pcibus") && sc->sc_pci == NULL) { 1461 1.40 dyoung struct pcibus_attach_args pba; 1462 1.36 dyoung 1463 1.40 dyoung memset(&pba, 0, sizeof(pba)); 1464 1.40 dyoung pba.pba_iot = sc->sc_iot; 1465 1.40 dyoung pba.pba_memt = sc->sc_memt; 1466 1.40 dyoung pba.pba_dmat = sc->sc_dmat; 1467 1.40 dyoung pba.pba_dmat64 = sc->sc_dmat64; 1468 1.40 dyoung pba.pba_pc = sc->sc_pc; 1469 1.40 dyoung pba.pba_flags = sc->sc_pciflags; 1470 1.40 dyoung pba.pba_bus = 0; 1471 1.40 dyoung pba.pba_bridgetag = NULL; 1472 1.51 thorpej sc->sc_pci = config_found(self, &pba, pcibusprint, 1473 1.52 thorpej CFARGS(.iattr = "pcibus")); 1474 1.40 dyoung } 1475 1.36 dyoung 1476 1.36 dyoung return 0; 1477 1.36 dyoung } 1478 1.36 dyoung 1479 1.39 dyoung CFATTACH_DECL3_NEW(elanpar, 0, 1480 1.39 dyoung elanpar_match, elanpar_attach, elanpar_detach, NULL, NULL, NULL, 1481 1.39 dyoung DVF_DETACH_SHUTDOWN); 1482 1.39 dyoung 1483 1.39 dyoung CFATTACH_DECL3_NEW(elanpex, 0, 1484 1.39 dyoung elanpex_match, elanpex_attach, elanpex_detach, NULL, NULL, NULL, 1485 1.39 dyoung DVF_DETACH_SHUTDOWN); 1486 1.22 dyoung 1487 1.39 dyoung CFATTACH_DECL3_NEW(elansc, sizeof(struct elansc_softc), 1488 1.36 dyoung elansc_match, elansc_attach, elansc_detach, NULL, elansc_rescan, 1489 1.39 dyoung elansc_childdetached, DVF_DETACH_SHUTDOWN); 1490 1.9 riz 1491 1.10 drochner #if NGPIO > 0 1492 1.9 riz static int 1493 1.9 riz elansc_gpio_pin_read(void *arg, int pin) 1494 1.9 riz { 1495 1.9 riz struct elansc_softc *sc = arg; 1496 1.9 riz int reg, shift; 1497 1.13 perry uint16_t data; 1498 1.9 riz 1499 1.9 riz reg = (pin < 16 ? MMCR_PIODATA15_0 : MMCR_PIODATA31_16); 1500 1.9 riz shift = pin % 16; 1501 1.19 dyoung 1502 1.19 dyoung mutex_enter(&sc->sc_mtx); 1503 1.9 riz data = bus_space_read_2(sc->sc_memt, sc->sc_memh, reg); 1504 1.19 dyoung mutex_exit(&sc->sc_mtx); 1505 1.9 riz 1506 1.9 riz return ((data >> shift) & 0x1); 1507 1.9 riz } 1508 1.9 riz 1509 1.9 riz static void 1510 1.9 riz elansc_gpio_pin_write(void *arg, int pin, int value) 1511 1.9 riz { 1512 1.9 riz struct elansc_softc *sc = arg; 1513 1.9 riz int reg, shift; 1514 1.13 perry uint16_t data; 1515 1.9 riz 1516 1.9 riz reg = (pin < 16 ? MMCR_PIODATA15_0 : MMCR_PIODATA31_16); 1517 1.9 riz shift = pin % 16; 1518 1.19 dyoung 1519 1.19 dyoung mutex_enter(&sc->sc_mtx); 1520 1.9 riz data = bus_space_read_2(sc->sc_memt, sc->sc_memh, reg); 1521 1.9 riz if (value == 0) 1522 1.9 riz data &= ~(1 << shift); 1523 1.9 riz else if (value == 1) 1524 1.9 riz data |= (1 << shift); 1525 1.9 riz 1526 1.9 riz bus_space_write_2(sc->sc_memt, sc->sc_memh, reg, data); 1527 1.19 dyoung mutex_exit(&sc->sc_mtx); 1528 1.9 riz } 1529 1.9 riz 1530 1.9 riz static void 1531 1.9 riz elansc_gpio_pin_ctl(void *arg, int pin, int flags) 1532 1.9 riz { 1533 1.9 riz struct elansc_softc *sc = arg; 1534 1.9 riz int reg, shift; 1535 1.13 perry uint16_t data; 1536 1.9 riz 1537 1.9 riz reg = (pin < 16 ? MMCR_PIODIR15_0 : MMCR_PIODIR31_16); 1538 1.9 riz shift = pin % 16; 1539 1.19 dyoung mutex_enter(&sc->sc_mtx); 1540 1.9 riz data = bus_space_read_2(sc->sc_memt, sc->sc_memh, reg); 1541 1.9 riz if (flags & GPIO_PIN_INPUT) 1542 1.9 riz data &= ~(1 << shift); 1543 1.9 riz if (flags & GPIO_PIN_OUTPUT) 1544 1.9 riz data |= (1 << shift); 1545 1.9 riz 1546 1.9 riz bus_space_write_2(sc->sc_memt, sc->sc_memh, reg, data); 1547 1.19 dyoung mutex_exit(&sc->sc_mtx); 1548 1.9 riz } 1549 1.10 drochner #endif /* NGPIO */ 1550