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/bus.h>
45 
46 #include <sys/rman.h>
47 
48 #include "opt_acpi.h"
49 #include "acpi.h"
50 #include <dev/acpica/acpivar.h>
51 
52 #include "gpio_intel_var.h"
53 
54 #include "gpio_if.h"
55 
56 #define CHV_GPIO_REG_IS		0x300
57 #define CHV_GPIO_REG_MASK	0x380
58 #define CHV_GPIO_REG_PINS	0x4400	/* start of pin control registers */
59 
60 #define CHV_GPIO_REGOFF_CTL0	0x0
61 #define CHV_GPIO_REGOFF_CTL1	0x4
62 
63 #define CHV_GPIO_CTL0_RXSTATE	0x00000001u
64 #define CHV_GPIO_CTL0_TXSTATE	0x00000002u
65 #define CHV_GPIO_CTL0_GPIOCFG_MASK 0x00000700u
66 #define CHV_GPIO_CTL0_GPIOEN	0x00008000u
67 #define CHV_GPIO_CTL0_PULLUP	0x00800000u
68 #define CHV_GPIO_CTL1_INTCFG_MASK 0x00000007u
69 #define CHV_GPIO_CTL1_INVRXDATA	0x00000040u
70 
71 #define CHV_GPIO_PINSIZE	0x8	/* 8 bytes for each pin */
72 #define CHV_GPIO_PINCHUNK	15	/* 15 pins at a time */
73 #define CHV_GPIO_PININC		0x400	/* every 0x400 bytes */
74 
75 #define PIN_ADDRESS(x)					\
76     (CHV_GPIO_REG_PINS +				\
77      ((x) / CHV_GPIO_PINCHUNK) * CHV_GPIO_PININC +	\
78      ((x) % CHV_GPIO_PINCHUNK) * CHV_GPIO_PINSIZE)
79 
80 #define PIN_CTL0(x)		(PIN_ADDRESS(x) + CHV_GPIO_REGOFF_CTL0)
81 #define PIN_CTL1(x)		(PIN_ADDRESS(x) + CHV_GPIO_REGOFF_CTL1)
82 
83 static void	gpio_cherryview_init(struct gpio_intel_softc *sc);
84 static void	gpio_cherryview_intr(void *arg);
85 static int	gpio_cherryview_map_intr(struct gpio_intel_softc *sc,
86 		    uint16_t pin, int trigger, int polarity, int termination);
87 static void	gpio_cherryview_unmap_intr(struct gpio_intel_softc *sc,
88 		    struct pin_intr_map *map);
89 static void	gpio_cherryview_enable_intr(struct gpio_intel_softc *sc,
90 		    struct pin_intr_map *map);
91 static void	gpio_cherryview_disable_intr(struct gpio_intel_softc *sc,
92 		    struct pin_intr_map *map);
93 static int	gpio_cherryview_check_io_pin(struct gpio_intel_softc *sc,
94 		    uint16_t pin, int flags);
95 static int	gpio_cherryview_read_pin(struct gpio_intel_softc *sc,
96 		    uint16_t pin);
97 static void	gpio_cherryview_write_pin(struct gpio_intel_softc *sc,
98 		    uint16_t pin, int value);
99 
100 static struct gpio_intel_fns gpio_cherryview_fns = {
101 	.init = gpio_cherryview_init,
102 	.intr = gpio_cherryview_intr,
103 	.map_intr = gpio_cherryview_map_intr,
104 	.unmap_intr = gpio_cherryview_unmap_intr,
105 	.enable_intr = gpio_cherryview_enable_intr,
106 	.disable_intr = gpio_cherryview_disable_intr,
107 	.check_io_pin = gpio_cherryview_check_io_pin,
108 	.read_pin = gpio_cherryview_read_pin,
109 	.write_pin = gpio_cherryview_write_pin,
110 };
111 
112 /* _UID=1 */
113 static struct pinrange chv_sw_ranges[] = {
114 	{ 0, 7 },
115 	{ 15, 22 },
116 	{ 30, 37 },
117 	{ 45, 52 },
118 	{ 60, 67 },
119 	{ 75, 82 },
120 	{ 90, 97 },
121 	{ -1, -1 }
122 };
123 
124 /* _UID=2 */
125 static struct pinrange chv_n_ranges[] = {
126 	{ 0, 8 },
127 	{ 15, 27 },
128 	{ 30, 41 },
129 	{ 45, 56 },
130 	{ 60, 72 },
131 	{ -1, -1 }
132 };
133 
134 /* _UID=3 */
135 static struct pinrange chv_e_ranges[] = {
136 	{ 0, 11 },
137 	{ 15, 26 },
138 	{ -1, -1 }
139 };
140 
141 /* _UID=4 */
142 static struct pinrange chv_se_ranges[] = {
143 	{ 0, 7 },
144 	{ 15, 26 },
145 	{ 30, 35 },
146 	{ 45, 52 },
147 	{ 60, 69 },
148 	{ 75, 85 },
149 	{ -1, -1 }
150 };
151 
152 static struct lock gpio_lk;
153 LOCK_SYSINIT(chvgpiolk, &gpio_lk, "chvgpio", 0);
154 
155 /*
156  * Use global GPIO register lock to workaround erratum:
157  *
158  * CHT34    Multiple Drivers That Access the GPIO Registers Concurrently May
159  *          Result in Unpredictable System Behaviour
160  */
161 static inline uint32_t
162 chvgpio_read(struct gpio_intel_softc *sc, bus_size_t offset)
163 {
164 	uint32_t val;
165 
166 	lockmgr(&gpio_lk, LK_EXCLUSIVE);
167 	val = bus_read_4(sc->mem_res, offset);
168 	lockmgr(&gpio_lk, LK_RELEASE);
169 	return val;
170 }
171 
172 static inline void
173 chvgpio_write(struct gpio_intel_softc *sc, bus_size_t offset, uint32_t val)
174 {
175 	lockmgr(&gpio_lk, LK_EXCLUSIVE);
176 	bus_write_4(sc->mem_res, offset, val);
177 	lockmgr(&gpio_lk, LK_RELEASE);
178 }
179 
180 int
181 gpio_cherryview_matchuid(struct gpio_intel_softc *sc)
182 {
183 	ACPI_HANDLE handle;
184 
185 	handle = acpi_get_handle(sc->dev);
186 	if (acpi_MatchUid(handle, "1")) {
187 		sc->ranges = chv_sw_ranges;
188 	} else if (acpi_MatchUid(handle, "2")) {
189 		sc->ranges = chv_n_ranges;
190 	} else if (acpi_MatchUid(handle, "3")) {
191 		sc->ranges = chv_e_ranges;
192 	} else if (acpi_MatchUid(handle, "4")) {
193 		sc->ranges = chv_se_ranges;
194 	} else {
195 		return (ENXIO);
196 	}
197 
198 	sc->fns = &gpio_cherryview_fns;
199 
200 	return (0);
201 }
202 
203 static void
204 gpio_cherryview_init(struct gpio_intel_softc *sc)
205 {
206 	/* mask and clear all interrupt lines */
207 	chvgpio_write(sc, CHV_GPIO_REG_MASK, 0);
208 	chvgpio_write(sc, CHV_GPIO_REG_IS, 0xffff);
209 }
210 
211 static void
212 gpio_cherryview_intr(void *arg)
213 {
214 	struct gpio_intel_softc *sc = (struct gpio_intel_softc *)arg;
215 	struct pin_intr_map *mapping;
216 	uint32_t status;
217 	int i;
218 
219 	status = chvgpio_read(sc, CHV_GPIO_REG_IS);
220 	KKASSERT(NELEM(sc->intrmaps) >= 16);
221 	for (i = 0; i < 16; i++) {
222 		if (status & (1U << i)) {
223 			mapping = &sc->intrmaps[i];
224 			if (!mapping->is_level) {
225 				chvgpio_write(sc, CHV_GPIO_REG_IS,
226 				    (1U << i));
227 			}
228 			if (mapping->pin != -1 && mapping->handler != NULL)
229 				mapping->handler(mapping->arg);
230 			if (mapping->is_level) {
231 				chvgpio_write(sc, CHV_GPIO_REG_IS,
232 				    (1U << i));
233 			}
234 		}
235 	}
236 }
237 
238 /* XXX Add shared/exclusive argument. */
239 static int
240 gpio_cherryview_map_intr(struct gpio_intel_softc *sc, uint16_t pin, int trigger,
241     int polarity, int termination)
242 {
243 	uint32_t reg, reg1, reg2;
244 	uint32_t intcfg, new_intcfg, gpiocfg, new_gpiocfg;
245 	int i;
246 
247 	reg1 = chvgpio_read(sc, PIN_CTL0(pin));
248 	reg2 = chvgpio_read(sc, PIN_CTL1(pin));
249 	device_printf(sc->dev,
250 	    "pin=%d trigger=%d polarity=%d ctrl0=0x%08x ctrl1=0x%08x\n",
251 	    pin, trigger, polarity, reg1, reg2);
252 
253 	new_intcfg = intcfg = reg2 & CHV_GPIO_CTL1_INTCFG_MASK;
254 	new_gpiocfg = gpiocfg = reg1 & CHV_GPIO_CTL0_GPIOCFG_MASK;
255 
256 	/*
257 	 * Sanity Checks, for now we just abort if the configuration doesn't
258 	 * match our expectations.
259 	 */
260 	if (!(reg1 & CHV_GPIO_CTL0_GPIOEN)) {
261 		device_printf(sc->dev, "GPIO mode is disabled\n");
262 		return (ENXIO);
263 	}
264 	if (gpiocfg != 0x0 && gpiocfg != 0x200) {
265 		device_printf(sc->dev, "RX is disabled\n");
266 		if (gpiocfg == 0x100)
267 			new_gpiocfg = 0x000;
268 		else if (gpiocfg == 0x300)
269 			new_gpiocfg = 0x200;
270 		else
271 			return (ENXIO);
272 	}
273 	if (trigger == ACPI_LEVEL_SENSITIVE) {
274 		if (intcfg != 4) {
275 			device_printf(sc->dev,
276 			    "trigger is %x, should be 4 (Level)\n", intcfg);
277 			return (ENXIO);
278 		}
279 		if (polarity == ACPI_ACTIVE_BOTH) {
280 			device_printf(sc->dev,
281 			    "ACTIVE_BOTH incompatible with level trigger\n");
282 			return (ENXIO);
283 		} else if (polarity == ACPI_ACTIVE_LOW) {
284 			if (!(reg2 & CHV_GPIO_CTL1_INVRXDATA)) {
285 				device_printf(sc->dev,
286 				    "Invert RX not enabled (needed for "
287 				    "level/low trigger/polarity)\n");
288 				return (ENXIO);
289 			}
290 		} else {
291 			if (reg2 & CHV_GPIO_CTL1_INVRXDATA) {
292 				device_printf(sc->dev,
293 				    "Invert RX should not be enabled for "
294 				    "level/high trigger/polarity\n");
295 				return (ENXIO);
296 			}
297 		}
298 	} else {
299 		/*
300 		 * For edge-triggered interrupts it's definitely harmless to
301 		 * change between rising-edge, falling-edge and both-edges
302 		 * triggering.
303 		 */
304 		if (polarity == ACPI_ACTIVE_HIGH && intcfg != 2) {
305 			device_printf(sc->dev,
306 			    "Wrong interrupt configuration, is 0x%x should "
307 			    "be 0x%x\n", intcfg, 2);
308 			if (intcfg == 1 || intcfg == 3)
309 				new_intcfg = 2;
310 			else
311 				return (ENXIO);
312 		} else if (polarity == ACPI_ACTIVE_LOW && intcfg != 1) {
313 			device_printf(sc->dev,
314 			    "Wrong interrupt configuration, is 0x%x should "
315 			    "be 0x%x\n", intcfg, 1);
316 			if (intcfg == 2 || intcfg == 3)
317 				new_intcfg = 1;
318 			else
319 				return (ENXIO);
320 		} else if (polarity == ACPI_ACTIVE_BOTH && intcfg != 3) {
321 			device_printf(sc->dev,
322 			    "Wrong interrupt configuration, is 0x%x should "
323 			    "be 0x%x\n", intcfg, 3);
324 			if (intcfg == 1 || intcfg == 2)
325 				new_intcfg = 3;
326 			else
327 				return (ENXIO);
328 		}
329 	}
330 	if (termination == ACPI_PIN_CONFIG_PULLUP &&
331 	    !(reg1 & CHV_GPIO_CTL0_PULLUP)) {
332 		device_printf(sc->dev,
333 		    "Wrong termination, is pull-down, should be pull-up\n");
334 		return (ENXIO);
335 	} else if (termination == ACPI_PIN_CONFIG_PULLDOWN &&
336 	    (reg1 & CHV_GPIO_CTL0_PULLUP)) {
337 		device_printf(sc->dev,
338 		    "Wrong termination, is pull-up, should be pull-down\n");
339 		return (ENXIO);
340 	}
341 
342 	/* Check if the interrupt/line configured by BIOS/UEFI is unused */
343 	i = (reg1 >> 28) & 0xf;
344 	if (sc->intrmaps[i].pin != -1) {
345 		device_printf(sc->dev, "Interrupt line %d already used\n", i);
346 		return (ENXIO);
347 	}
348 
349 	if (new_intcfg != intcfg) {
350 		device_printf(sc->dev,
351 		    "Switching interrupt configuration from 0x%x to 0x%x\n",
352 		    intcfg, new_intcfg);
353 		reg = reg2 & ~CHV_GPIO_CTL1_INTCFG_MASK;
354 		reg |= (new_intcfg & CHV_GPIO_CTL1_INTCFG_MASK) << 0;
355 		chvgpio_write(sc, PIN_CTL1(pin), reg);
356 	}
357 
358 	if (new_gpiocfg != gpiocfg) {
359 		device_printf(sc->dev,
360 		    "Switching gpio configuration from 0x%x to 0x%x\n",
361 		    gpiocfg, new_gpiocfg);
362 		reg = reg1 & ~CHV_GPIO_CTL0_GPIOCFG_MASK;
363 		reg |= (new_gpiocfg & CHV_GPIO_CTL0_GPIOCFG_MASK) << 0;
364 		chvgpio_write(sc, PIN_CTL0(pin), reg);
365 	}
366 
367 	sc->intrmaps[i].pin = pin;
368 	sc->intrmaps[i].intidx = i;
369 	sc->intrmaps[i].orig_intcfg = intcfg;
370 	sc->intrmaps[i].orig_gpiocfg = gpiocfg;
371 
372 	if (trigger == ACPI_LEVEL_SENSITIVE)
373 		sc->intrmaps[i].is_level = 1;
374 	else
375 		sc->intrmaps[i].is_level = 0;
376 
377 	return (0);
378 }
379 
380 static void
381 gpio_cherryview_unmap_intr(struct gpio_intel_softc *sc,
382     struct pin_intr_map *map)
383 {
384 	uint32_t reg, intcfg, gpiocfg;
385 	uint16_t pin = map->pin;
386 
387 	intcfg = map->orig_intcfg;
388 	intcfg &= CHV_GPIO_CTL1_INTCFG_MASK;
389 
390 	gpiocfg = map->orig_gpiocfg;
391 	gpiocfg &= CHV_GPIO_CTL0_GPIOCFG_MASK;
392 
393 	map->pin = -1;
394 	map->intidx = -1;
395 	map->is_level = 0;
396 	map->orig_intcfg = 0;
397 	map->orig_gpiocfg = 0;
398 
399 	/* Restore interrupt configuration if needed */
400 	reg = chvgpio_read(sc, PIN_CTL1(pin));
401 	if ((reg & CHV_GPIO_CTL1_INTCFG_MASK) != intcfg) {
402 		reg &= ~CHV_GPIO_CTL1_INTCFG_MASK;
403 		reg |= intcfg;
404 		chvgpio_write(sc, PIN_CTL1(pin), reg);
405 	}
406 
407 	/* Restore gpio configuration if needed */
408 	reg = chvgpio_read(sc, PIN_CTL0(pin));
409 	if ((reg & CHV_GPIO_CTL0_GPIOCFG_MASK) != gpiocfg) {
410 		reg &= ~CHV_GPIO_CTL0_GPIOCFG_MASK;
411 		reg |= gpiocfg;
412 		chvgpio_write(sc, PIN_CTL0(pin), reg);
413 	}
414 }
415 
416 static void
417 gpio_cherryview_enable_intr(struct gpio_intel_softc *sc,
418     struct pin_intr_map *map)
419 {
420 	uint32_t reg;
421 
422 	KKASSERT(map->intidx >= 0);
423 
424 	/* clear interrupt status flag */
425 	chvgpio_write(sc, CHV_GPIO_REG_IS, (1U << map->intidx));
426 
427 	/* unmask interrupt */
428 	reg = chvgpio_read(sc, CHV_GPIO_REG_MASK);
429 	reg |= (1U << map->intidx);
430 	chvgpio_write(sc, CHV_GPIO_REG_MASK, reg);
431 }
432 
433 static void
434 gpio_cherryview_disable_intr(struct gpio_intel_softc *sc,
435     struct pin_intr_map *map)
436 {
437 	uint32_t reg;
438 
439 	KKASSERT(map->intidx >= 0);
440 
441 	/* mask interrupt line */
442 	reg = chvgpio_read(sc, CHV_GPIO_REG_MASK);
443 	reg &= ~(1U << map->intidx);
444 	chvgpio_write(sc, CHV_GPIO_REG_MASK, reg);
445 }
446 
447 static int
448 gpio_cherryview_check_io_pin(struct gpio_intel_softc *sc, uint16_t pin,
449     int flags)
450 {
451 	uint32_t reg1, reg2;
452 
453 	reg1 = chvgpio_read(sc, PIN_CTL0(pin));
454 	if (flags & (1U << 0)) {
455 		/* Verify that RX is enabled */
456 		if ((reg1 & CHV_GPIO_CTL0_GPIOCFG_MASK) != 0 &&
457 		    (reg1 & CHV_GPIO_CTL0_GPIOCFG_MASK) != 0x200) {
458 			return (0);
459 		}
460 	}
461 	reg2 = chvgpio_read(sc, PIN_CTL1(pin));
462 	if (flags & (1U << 1)) {
463 		/* Verify that interrupt is disabled */
464 		if ((reg2 & CHV_GPIO_CTL1_INTCFG_MASK) != 0)
465 			return (0);
466 		/* Verify that TX is enabled */
467 		if ((reg1 & CHV_GPIO_CTL0_GPIOCFG_MASK) != 0 &&
468 		    (reg1 & CHV_GPIO_CTL0_GPIOCFG_MASK) != 0x100) {
469 			return (0);
470 		}
471 	}
472 
473 	return (1);
474 }
475 
476 static int
477 gpio_cherryview_read_pin(struct gpio_intel_softc *sc, uint16_t pin)
478 {
479 	uint32_t reg;
480 	int val;
481 
482 	reg = chvgpio_read(sc, PIN_CTL0(pin));
483 	/* Verify that RX is enabled */
484 	KKASSERT((reg & CHV_GPIO_CTL0_GPIOCFG_MASK) == 0x0 ||
485 	    (reg & CHV_GPIO_CTL0_GPIOCFG_MASK) == 0x200);
486 
487 	if (reg & CHV_GPIO_CTL0_RXSTATE)
488 		val = 1;
489 	else
490 		val = 0;
491 
492 	return (val);
493 }
494 
495 static void
496 gpio_cherryview_write_pin(struct gpio_intel_softc *sc, uint16_t pin, int value)
497 {
498 	uint32_t reg;
499 
500 	reg = chvgpio_read(sc, PIN_CTL0(pin));
501 	/* Verify that TX is enabled */
502 	KKASSERT((reg & CHV_GPIO_CTL0_GPIOCFG_MASK) == 0 ||
503 	    (reg & CHV_GPIO_CTL0_GPIOCFG_MASK) == 0x100);
504 
505 	if (value)
506 		reg |= CHV_GPIO_CTL0_TXSTATE;
507 	else
508 		reg &= ~CHV_GPIO_CTL0_TXSTATE;
509 	chvgpio_write(sc, PIN_CTL0(pin), reg);
510 }
511