1 /* 2 * Copyright (c) 2016 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Imre Vadász <imre@vdsz.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * Cherryview GPIO support. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/module.h> 42 #include <sys/errno.h> 43 #include <sys/lock.h> 44 #include <sys/mutex.h> 45 #include <sys/bus.h> 46 47 #include <sys/rman.h> 48 49 #include "opt_acpi.h" 50 #include "acpi.h" 51 #include <dev/acpica/acpivar.h> 52 53 #include "gpio_intel_var.h" 54 55 #include "gpio_if.h" 56 57 #define CHV_GPIO_REG_IS 0x300 58 #define CHV_GPIO_REG_MASK 0x380 59 #define CHV_GPIO_REG_PINS 0x4400 /* start of pin control registers */ 60 61 #define CHV_GPIO_REGOFF_CTL0 0x0 62 #define CHV_GPIO_REGOFF_CTL1 0x4 63 64 #define CHV_GPIO_CTL0_RXSTATE 0x00000001u 65 #define CHV_GPIO_CTL0_TXSTATE 0x00000002u 66 #define CHV_GPIO_CTL0_GPIOCFG_MASK 0x00000700u 67 #define CHV_GPIO_CTL0_GPIOEN 0x00008000u 68 #define CHV_GPIO_CTL0_PULLUP 0x00800000u 69 #define CHV_GPIO_CTL1_INTCFG_MASK 0x00000007u 70 #define CHV_GPIO_CTL1_INVRXDATA 0x00000040u 71 72 #define CHV_GPIO_PINSIZE 0x8 /* 8 bytes for each pin */ 73 #define CHV_GPIO_PINCHUNK 15 /* 15 pins at a time */ 74 #define CHV_GPIO_PININC 0x400 /* every 0x400 bytes */ 75 76 #define PIN_ADDRESS(x) \ 77 (CHV_GPIO_REG_PINS + \ 78 ((x) / CHV_GPIO_PINCHUNK) * CHV_GPIO_PININC + \ 79 ((x) % CHV_GPIO_PINCHUNK) * CHV_GPIO_PINSIZE) 80 81 #define PIN_CTL0(x) (PIN_ADDRESS(x) + CHV_GPIO_REGOFF_CTL0) 82 #define PIN_CTL1(x) (PIN_ADDRESS(x) + CHV_GPIO_REGOFF_CTL1) 83 84 static void gpio_cherryview_init(struct gpio_intel_softc *sc); 85 static void gpio_cherryview_intr(void *arg); 86 static int gpio_cherryview_map_intr(struct gpio_intel_softc *sc, 87 uint16_t pin, int trigger, int polarity, int termination, 88 void *arg, driver_intr_t *handler); 89 static void gpio_cherryview_unmap_intr(struct gpio_intel_softc *sc, 90 uint16_t pin); 91 static int gpio_cherryview_read_pin(struct gpio_intel_softc *sc, 92 uint16_t pin); 93 static void gpio_cherryview_write_pin(struct gpio_intel_softc *sc, 94 uint16_t pin, int value); 95 96 static struct gpio_intel_fns gpio_cherryview_fns = { 97 .init = gpio_cherryview_init, 98 .intr = gpio_cherryview_intr, 99 .map_intr = gpio_cherryview_map_intr, 100 .unmap_intr = gpio_cherryview_unmap_intr, 101 .read_pin = gpio_cherryview_read_pin, 102 .write_pin = gpio_cherryview_write_pin, 103 }; 104 105 /* _UID=1 */ 106 static struct pinrange chv_sw_ranges[] = { 107 { 0, 7 }, 108 { 15, 22 }, 109 { 30, 37 }, 110 { 45, 52 }, 111 { 60, 67 }, 112 { 75, 82 }, 113 { 90, 97 }, 114 { -1, -1 } 115 }; 116 117 /* _UID=2 */ 118 static struct pinrange chv_n_ranges[] = { 119 { 0, 8 }, 120 { 15, 27 }, 121 { 30, 41 }, 122 { 45, 56 }, 123 { 60, 72 }, 124 { -1, -1 } 125 }; 126 127 /* _UID=3 */ 128 static struct pinrange chv_e_ranges[] = { 129 { 0, 11 }, 130 { 15, 26 }, 131 { -1, -1 } 132 }; 133 134 /* _UID=4 */ 135 static struct pinrange chv_se_ranges[] = { 136 { 0, 7 }, 137 { 15, 26 }, 138 { 30, 35 }, 139 { 45, 52 }, 140 { 60, 69 }, 141 { 75, 85 }, 142 { -1, -1 } 143 }; 144 145 static struct lock gpio_lk; 146 LOCK_SYSINIT(chvgpiolk, &gpio_lk, "chvgpio", 0); 147 148 /* 149 * Use global GPIO register lock to workaround erratum: 150 * 151 * CHT34 Multiple Drivers That Access the GPIO Registers Concurrently May 152 * Result in Unpredictable System Behaviour 153 */ 154 static inline uint32_t 155 chvgpio_read(struct gpio_intel_softc *sc, bus_size_t offset) 156 { 157 uint32_t val; 158 159 lockmgr(&gpio_lk, LK_EXCLUSIVE); 160 val = bus_read_4(sc->mem_res, offset); 161 lockmgr(&gpio_lk, LK_RELEASE); 162 return val; 163 } 164 165 static inline void 166 chvgpio_write(struct gpio_intel_softc *sc, bus_size_t offset, uint32_t val) 167 { 168 lockmgr(&gpio_lk, LK_EXCLUSIVE); 169 bus_write_4(sc->mem_res, offset, val); 170 lockmgr(&gpio_lk, LK_RELEASE); 171 } 172 173 int 174 gpio_cherryview_matchuid(struct gpio_intel_softc *sc) 175 { 176 ACPI_HANDLE handle; 177 178 handle = acpi_get_handle(sc->dev); 179 if (acpi_MatchUid(handle, "1")) { 180 sc->ranges = chv_sw_ranges; 181 } else if (acpi_MatchUid(handle, "2")) { 182 sc->ranges = chv_n_ranges; 183 } else if (acpi_MatchUid(handle, "3")) { 184 sc->ranges = chv_e_ranges; 185 } else if (acpi_MatchUid(handle, "4")) { 186 sc->ranges = chv_se_ranges; 187 } else { 188 return (ENXIO); 189 } 190 191 sc->fns = &gpio_cherryview_fns; 192 193 return (0); 194 } 195 196 static void 197 gpio_cherryview_init(struct gpio_intel_softc *sc) 198 { 199 /* mask and clear all interrupt lines */ 200 chvgpio_write(sc, CHV_GPIO_REG_MASK, 0); 201 chvgpio_write(sc, CHV_GPIO_REG_IS, 0xffff); 202 } 203 204 static void 205 gpio_cherryview_intr(void *arg) 206 { 207 struct gpio_intel_softc *sc = (struct gpio_intel_softc *)arg; 208 struct pin_intr_map *mapping; 209 uint32_t status; 210 int i; 211 212 status = chvgpio_read(sc, CHV_GPIO_REG_IS); 213 for (i = 0; i < 16; i++) { 214 if (status & (1U << i)) { 215 mapping = &sc->intrmaps[i]; 216 if (!mapping->is_level) { 217 chvgpio_write(sc, CHV_GPIO_REG_IS, 218 (1U << i)); 219 } 220 if (mapping->pin != -1 && mapping->handler != NULL) 221 mapping->handler(mapping->arg); 222 if (mapping->is_level) { 223 chvgpio_write(sc, CHV_GPIO_REG_IS, 224 (1U << i)); 225 } 226 } 227 } 228 } 229 230 /* XXX Add shared/exclusive argument. */ 231 static int 232 gpio_cherryview_map_intr(struct gpio_intel_softc *sc, uint16_t pin, int trigger, 233 int polarity, int termination, void *arg, driver_intr_t *handler) 234 { 235 uint32_t reg, reg1, reg2; 236 uint32_t intcfg, new_intcfg, gpiocfg, new_gpiocfg; 237 int i; 238 239 reg1 = chvgpio_read(sc, PIN_CTL0(pin)); 240 reg2 = chvgpio_read(sc, PIN_CTL1(pin)); 241 device_printf(sc->dev, 242 "pin=%d trigger=%d polarity=%d ctrl0=0x%08x ctrl1=0x%08x\n", 243 pin, trigger, polarity, reg1, reg2); 244 245 new_intcfg = intcfg = reg2 & CHV_GPIO_CTL1_INTCFG_MASK; 246 new_gpiocfg = gpiocfg = reg1 & CHV_GPIO_CTL0_GPIOCFG_MASK; 247 248 /* 249 * Sanity Checks, for now we just abort if the configuration doesn't 250 * match our expectations. 251 */ 252 if (!(reg1 & CHV_GPIO_CTL0_GPIOEN)) { 253 device_printf(sc->dev, "GPIO mode is disabled\n"); 254 return (ENXIO); 255 } 256 if (gpiocfg != 0x0 && gpiocfg != 0x200) { 257 device_printf(sc->dev, "RX is disabled\n"); 258 if (gpiocfg == 0x100) 259 new_gpiocfg = 0x000; 260 else if (gpiocfg == 0x300) 261 new_gpiocfg = 0x200; 262 else 263 return (ENXIO); 264 } 265 if (trigger == ACPI_LEVEL_SENSITIVE) { 266 if (intcfg != 4) { 267 device_printf(sc->dev, 268 "trigger is %x, should be 4 (Level)\n", intcfg); 269 return (ENXIO); 270 } 271 if (polarity == ACPI_ACTIVE_BOTH) { 272 device_printf(sc->dev, 273 "ACTIVE_BOTH incompatible with level trigger\n"); 274 return (ENXIO); 275 } else if (polarity == ACPI_ACTIVE_LOW) { 276 if (!(reg2 & CHV_GPIO_CTL1_INVRXDATA)) { 277 device_printf(sc->dev, 278 "Invert RX not enabled (needed for " 279 "level/low trigger/polarity)\n"); 280 return (ENXIO); 281 } 282 } else { 283 if (reg2 & CHV_GPIO_CTL1_INVRXDATA) { 284 device_printf(sc->dev, 285 "Invert RX should not be enabled for " 286 "level/high trigger/polarity\n"); 287 return (ENXIO); 288 } 289 } 290 } else { 291 /* 292 * For edge-triggered interrupts it's definitely harmless to 293 * change between rising-edge, falling-edge and both-edges 294 * triggering. 295 */ 296 if (polarity == ACPI_ACTIVE_HIGH && intcfg != 2) { 297 device_printf(sc->dev, 298 "Wrong interrupt configuration, is 0x%x should " 299 "be 0x%x\n", intcfg, 2); 300 if (intcfg == 1 || intcfg == 3) 301 new_intcfg = 2; 302 else 303 return (ENXIO); 304 } else if (polarity == ACPI_ACTIVE_LOW && intcfg != 1) { 305 device_printf(sc->dev, 306 "Wrong interrupt configuration, is 0x%x should " 307 "be 0x%x\n", intcfg, 1); 308 if (intcfg == 2 || intcfg == 3) 309 new_intcfg = 1; 310 else 311 return (ENXIO); 312 } else if (polarity == ACPI_ACTIVE_BOTH && intcfg != 3) { 313 device_printf(sc->dev, 314 "Wrong interrupt configuration, is 0x%x should " 315 "be 0x%x\n", intcfg, 3); 316 if (intcfg == 1 || intcfg == 2) 317 new_intcfg = 3; 318 else 319 return (ENXIO); 320 } 321 } 322 if (termination == ACPI_PIN_CONFIG_PULLUP && 323 !(reg1 & CHV_GPIO_CTL0_PULLUP)) { 324 device_printf(sc->dev, 325 "Wrong termination, is pull-down, should be pull-up\n"); 326 return (ENXIO); 327 } else if (termination == ACPI_PIN_CONFIG_PULLDOWN && 328 (reg1 & CHV_GPIO_CTL0_PULLUP)) { 329 device_printf(sc->dev, 330 "Wrong termination, is pull-up, should be pull-down\n"); 331 return (ENXIO); 332 } 333 334 /* Check if the interrupt/line configured by BIOS/UEFI is unused */ 335 i = (reg1 >> 28) & 0xf; 336 if (sc->intrmaps[i].pin != -1) { 337 device_printf(sc->dev, "Interrupt line %d already used\n", i); 338 return (ENXIO); 339 } 340 341 if (new_intcfg != intcfg) { 342 device_printf(sc->dev, 343 "Switching interrupt configuration from 0x%x to 0x%x\n", 344 intcfg, new_intcfg); 345 reg = reg2 & ~CHV_GPIO_CTL1_INTCFG_MASK; 346 reg |= (new_intcfg & CHV_GPIO_CTL1_INTCFG_MASK) << 0; 347 chvgpio_write(sc, PIN_CTL1(pin), reg); 348 } 349 350 if (new_gpiocfg != gpiocfg) { 351 device_printf(sc->dev, 352 "Switching gpio configuration from 0x%x to 0x%x\n", 353 gpiocfg, new_gpiocfg); 354 reg = reg1 & ~CHV_GPIO_CTL0_GPIOCFG_MASK; 355 reg |= (new_gpiocfg & CHV_GPIO_CTL0_GPIOCFG_MASK) << 0; 356 chvgpio_write(sc, PIN_CTL0(pin), reg); 357 } 358 359 sc->intrmaps[i].pin = pin; 360 sc->intrmaps[i].arg = arg; 361 sc->intrmaps[i].handler = handler; 362 sc->intrmaps[i].orig_intcfg = intcfg; 363 sc->intrmaps[i].orig_gpiocfg = gpiocfg; 364 365 if (trigger == ACPI_LEVEL_SENSITIVE) 366 sc->intrmaps[i].is_level = 1; 367 else 368 sc->intrmaps[i].is_level = 0; 369 370 /* unmask interrupt */ 371 reg = chvgpio_read(sc, CHV_GPIO_REG_MASK); 372 reg |= (1 << i); 373 chvgpio_write(sc, CHV_GPIO_REG_MASK, reg); 374 375 return (0); 376 } 377 378 static void 379 gpio_cherryview_unmap_intr(struct gpio_intel_softc *sc, uint16_t pin) 380 { 381 uint32_t reg, intcfg, gpiocfg; 382 int i; 383 384 for (i = 0; i < 16; i++) { 385 if (sc->intrmaps[i].pin == pin) { 386 intcfg = sc->intrmaps[i].orig_intcfg; 387 intcfg &= CHV_GPIO_CTL1_INTCFG_MASK; 388 389 gpiocfg = sc->intrmaps[i].orig_gpiocfg; 390 gpiocfg &= CHV_GPIO_CTL0_GPIOCFG_MASK; 391 392 sc->intrmaps[i].pin = -1; 393 sc->intrmaps[i].arg = NULL; 394 sc->intrmaps[i].handler = NULL; 395 sc->intrmaps[i].is_level = 0; 396 sc->intrmaps[i].orig_intcfg = 0; 397 sc->intrmaps[i].orig_gpiocfg = 0; 398 399 /* mask interrupt line */ 400 reg = chvgpio_read(sc, CHV_GPIO_REG_MASK); 401 reg &= ~(1 << i); 402 chvgpio_write(sc, CHV_GPIO_REG_MASK, reg); 403 404 /* Restore interrupt configuration if needed */ 405 reg = chvgpio_read(sc, PIN_CTL1(pin)); 406 if ((reg & CHV_GPIO_CTL1_INTCFG_MASK) != intcfg) { 407 reg &= ~CHV_GPIO_CTL1_INTCFG_MASK; 408 reg |= intcfg; 409 chvgpio_write(sc, PIN_CTL1(pin), reg); 410 } 411 412 /* Restore gpio configuration if needed */ 413 reg = chvgpio_read(sc, PIN_CTL0(pin)); 414 if ((reg & CHV_GPIO_CTL0_GPIOCFG_MASK) != gpiocfg) { 415 reg &= ~CHV_GPIO_CTL0_GPIOCFG_MASK; 416 reg |= gpiocfg; 417 chvgpio_write(sc, PIN_CTL0(pin), reg); 418 } 419 } 420 } 421 } 422 423 static int 424 gpio_cherryview_read_pin(struct gpio_intel_softc *sc, uint16_t pin) 425 { 426 uint32_t reg; 427 int val; 428 429 reg = chvgpio_read(sc, PIN_CTL0(pin)); 430 /* Verify that RX is enabled */ 431 KKASSERT((reg & CHV_GPIO_CTL0_GPIOCFG_MASK) == 0x0 || 432 (reg & CHV_GPIO_CTL0_GPIOCFG_MASK) == 0x200); 433 434 if (reg & CHV_GPIO_CTL0_RXSTATE) 435 val = 1; 436 else 437 val = 0; 438 439 return (val); 440 } 441 442 static void 443 gpio_cherryview_write_pin(struct gpio_intel_softc *sc, uint16_t pin, int value) 444 { 445 uint32_t reg1, reg2; 446 447 reg2 = chvgpio_read(sc, PIN_CTL1(pin)); 448 /* Verify that interrupt is disabled */ 449 KKASSERT((reg2 & CHV_GPIO_CTL1_INTCFG_MASK) == 0); 450 451 reg1 = chvgpio_read(sc, PIN_CTL0(pin)); 452 /* Verify that TX is enabled */ 453 KKASSERT((reg1 & CHV_GPIO_CTL0_GPIOCFG_MASK) == 0 || 454 (reg1 & CHV_GPIO_CTL0_GPIOCFG_MASK) == 0x100); 455 456 if (value) 457 reg1 |= CHV_GPIO_CTL0_TXSTATE; 458 else 459 reg1 &= ~CHV_GPIO_CTL0_TXSTATE; 460 chvgpio_write(sc, PIN_CTL0(pin), reg1); 461 } 462