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