1/* $NetBSD: igpio.c,v 1.5 2023/01/07 03:27:01 msaitoh Exp $ */
2
3/*
4 * Copyright (c) 2021,2022 Emmanuel Dreyfus
5 * All rights reserved.
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 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30
31#include <sys/param.h>
32#include <sys/bus.h>
33#include <sys/device.h>
34#include <sys/intr.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/kmem.h>
38#include <sys/endian.h>
39#include <sys/gpio.h>
40
41#include <dev/gpio/gpiovar.h>
42#include "gpio.h"
43
44#include <dev/ic/igpiovar.h>
45#include <dev/ic/igpioreg.h>
46
47struct igpio_intr {
48	int (*ii_func)(void *);
49	void *ii_arg;
50	struct igpio_bank *ii_bank;
51	int ii_pin;
52};
53
54struct igpio_bank {
55	int ib_barno;
56	int ib_revid;
57	int ib_cap;
58	int ib_padbar;
59	struct igpio_bank_setup *ib_setup;
60	struct igpio_softc *ib_sc;
61	struct igpio_intr *ib_intr;
62	kmutex_t ib_mtx;
63};
64
65
66static int igpio_debug = 0;
67#define DPRINTF(x) if (igpio_debug) printf x;
68
69static char *
70igpio_padcfg0_print(uint32_t val, int idx)
71{
72	uint32_t rxev, pmode;
73	static char buf0[256];
74	static char buf1[256];
75	char *buf = (idx % 2) ? &buf0[0] : &buf1[0];
76	size_t len = sizeof(buf0) - 1;
77	size_t wr = 0;
78	uint32_t unknown_bits =
79	    __BITS(3,7)|__BITS(14,16)|__BITS(21,22)|__BITS(27,31);
80	int b;
81
82	rxev =
83	    (val & IGPIO_PADCFG0_RXEVCFG_MASK) >> IGPIO_PADCFG0_RXEVCFG_SHIFT;
84	wr += snprintf(buf + wr, len - wr, "rxev ");
85	switch (rxev) {
86	case IGPIO_PADCFG0_RXEVCFG_LEVEL:
87		wr += snprintf(buf + wr, len - wr, "level");
88		break;
89	case IGPIO_PADCFG0_RXEVCFG_EDGE:
90		wr += snprintf(buf + wr, len - wr, "edge");
91		break;
92	case IGPIO_PADCFG0_RXEVCFG_DISABLED:
93		wr += snprintf(buf + wr, len - wr, "disabled");
94		break;
95	case IGPIO_PADCFG0_RXEVCFG_EDGE_BOTH:
96		wr += snprintf(buf + wr, len - wr, "edge both");
97		break;
98	default:
99		break;
100	}
101
102	if (val & IGPIO_PADCFG0_PREGFRXSEL)
103		wr += snprintf(buf + wr, len - wr, ", pregfrxsel");
104
105	if (val & IGPIO_PADCFG0_RXINV)
106		wr += snprintf(buf + wr, len - wr, ", rxinv");
107
108	if (val & (IGPIO_PADCFG0_GPIROUTIOXAPIC|IGPIO_PADCFG0_GPIROUTSCI|
109		   IGPIO_PADCFG0_GPIROUTSMI|IGPIO_PADCFG0_GPIROUTNMI)) {
110		wr += snprintf(buf + wr, len - wr, ", gpirout");
111
112		if (val & IGPIO_PADCFG0_GPIROUTIOXAPIC)
113			wr += snprintf(buf + wr, len - wr, " ioxapic");
114
115		if (val & IGPIO_PADCFG0_GPIROUTSCI)
116			wr += snprintf(buf + wr, len - wr, " sci");
117
118		if (val & IGPIO_PADCFG0_GPIROUTSMI)
119			wr += snprintf(buf + wr, len - wr, " smi");
120
121		if (val & IGPIO_PADCFG0_GPIROUTNMI)
122			wr += snprintf(buf + wr, len - wr, " nmi");
123	}
124
125	pmode =
126	    (val & IGPIO_PADCFG0_PMODE_MASK) >> IGPIO_PADCFG0_PMODE_SHIFT;
127	switch (pmode) {
128	case IGPIO_PADCFG0_PMODE_GPIO:
129		wr += snprintf(buf + wr, len - wr, ", pmode gpio");
130		break;
131	default:
132		wr += snprintf(buf + wr, len - wr, ", pmode %d", pmode);
133		break;
134	}
135
136	if (val & IGPIO_PADCFG0_GPIORXDIS)
137		wr += snprintf(buf + wr, len - wr, ", rx disabled");
138	else
139		wr += snprintf(buf + wr, len - wr, ", rx %d",
140		    !!(val & IGPIO_PADCFG0_GPIORXSTATE));
141
142	if (val & IGPIO_PADCFG0_GPIOTXDIS)
143		wr += snprintf(buf + wr, len - wr, ", tx disabled");
144	else
145		wr += snprintf(buf + wr, len - wr, ", tx %d",
146		    !!(val & IGPIO_PADCFG0_GPIOTXSTATE));
147
148	if (val & unknown_bits) {
149		wr += snprintf(buf + wr, len - wr, ", unknown bits");
150		for (b = 0; b < 32; b++) {
151			if (!(__BIT(b) & unknown_bits & val))
152				continue;
153			wr += snprintf(buf + wr, len - wr, " %d", b);
154		}
155	}
156
157	return buf;
158}
159
160
161static struct igpio_bank_setup *
162igpio_find_bank_setup(struct igpio_bank *ib, int barno)
163{
164	struct igpio_bank_setup *ibs;
165
166	for (ibs = igpio_bank_setup; ibs->ibs_acpi_hid; ibs++) {
167		if (strcmp(ib->ib_sc->sc_acpi_hid, ibs->ibs_acpi_hid) != 0)
168			continue;
169		if (ibs->ibs_barno != barno)
170			continue;
171
172		return ibs;
173	}
174
175	return NULL;
176}
177
178static struct igpio_bank *
179igpio_find_bank(struct igpio_softc *sc, int pin)
180{
181	int i;
182	struct igpio_bank *ib;
183
184	for (i = 0; i < sc->sc_nbar; i++) {
185		ib = &sc->sc_banks[i];
186		if (pin >= ib->ib_setup->ibs_first_pin &&
187		    pin <= ib->ib_setup->ibs_last_pin)
188			goto out;
189	}
190
191	ib = NULL;
192out:
193	return ib;
194}
195
196static int
197igpio_bank_pin(struct igpio_bank *ib, int pin)
198{
199	return pin - ib->ib_setup->ibs_first_pin;
200}
201
202#if 0
203static void
204igpio_hexdump(struct igpio_softc *sc, int n)
205{
206	int i, j;
207	uint8_t v;
208	size_t len = MIN(sc->sc_length[n], 2048);
209
210	printf("bar %d\n", n);
211	for (j = 0; j < len; j += 16) {
212		printf("%04x ", j);
213		for (i = 0; i < 16 && i + j < len; i++) {
214			v = bus_space_read_1(sc->sc_bst, sc->sc_bsh[n], i + j);
215			printf("%02x ", v);
216		}
217		printf("\n");
218	}
219}
220#endif
221
222void
223igpio_attach(struct igpio_softc *sc)
224{
225	device_t self = sc->sc_dev;
226	int i,j;
227	struct gpiobus_attach_args gba;
228	int success = 0;
229
230	sc->sc_banks =
231	    kmem_zalloc(sizeof(*sc->sc_banks) * sc->sc_nbar, KM_SLEEP);
232
233	sc->sc_npins = 0;
234
235	for (i = 0; i < sc->sc_nbar; i++) {
236		struct igpio_bank *ib = &sc->sc_banks[i];
237		struct igpio_bank_setup *ibs;
238		bus_size_t reg;
239		uint32_t val;
240		int error;
241		int npins;
242
243		ib->ib_barno = i;
244		ib->ib_sc = sc;
245
246		mutex_init(&ib->ib_mtx, MUTEX_DEFAULT, IPL_VM);
247
248		error = bus_space_map(sc->sc_bst, sc->sc_base[i],
249		    sc->sc_length[i], 0, &sc->sc_bsh[i]);
250		if (error) {
251			aprint_error_dev(self, "couldn't map registers\n");
252			goto out;
253		}
254
255		reg = IGPIO_REVID;
256		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[i], reg);
257		if (val == 0) {
258			aprint_error_dev(self, "couldn't find revid\n");
259			goto out;
260		}
261		ib->ib_revid = val >> 16;
262
263		DPRINTF(("revid[%d] = #%x\n", i, ib->ib_revid));
264
265		if (ib->ib_revid > 0x94) {
266			ib->ib_cap |= IGPIO_PINCTRL_FEATURE_DEBOUNCE;
267			ib->ib_cap |= IGPIO_PINCTRL_FEATURE_1K_PD;
268		}
269
270		reg = IGPIO_CAPLIST;
271		do {
272			/* higher 16 bits: value, lower 16 bits, next reg */
273			val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[i], reg);
274
275			reg = val & 0xffff;
276			val = val >> 16;
277
278			switch (val) {
279			case IGPIO_CAPLIST_ID_GPIO_HW_INFO:
280				ib->ib_cap |=
281				    IGPIO_PINCTRL_FEATURE_GPIO_HW_INFO;
282				break;
283			case IGPIO_CAPLIST_ID_PWM:
284				ib->ib_cap |= IGPIO_PINCTRL_FEATURE_PWM;
285				break;
286			case IGPIO_CAPLIST_ID_BLINK:
287				ib->ib_cap |= IGPIO_PINCTRL_FEATURE_BLINK;
288				break;
289			case IGPIO_CAPLIST_ID_EXP:
290				ib->ib_cap |= IGPIO_PINCTRL_FEATURE_EXP;
291				break;
292			default:
293				break;
294			}
295		} while (reg);
296		DPRINTF(("cap[%d] = #%x\n", i, ib->ib_cap));
297
298		reg = IGPIO_PADBAR;
299		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[i], reg);
300		ib->ib_padbar = val;
301		DPRINTF(("padbar[%d] = #%x\n", i, ib->ib_padbar));
302		if (ib->ib_padbar > sc->sc_length[i]) {
303			printf("PADBAR = #%x higher than max #%lx\n",
304			    ib->ib_padbar, sc->sc_length[i]);
305			goto out;
306		}
307
308		ib->ib_setup = igpio_find_bank_setup(ib, i);
309		if (ib->ib_setup == NULL) {
310			printf("Missing BAR %d\n", i);
311			goto out;
312		}
313
314		ibs = ib->ib_setup;
315
316		DPRINTF(("setup[%d] = "
317		    "{ barno = %d, first_pin = %d, last_pin = %d }\n",
318		    i, ibs->ibs_barno, ibs->ibs_first_pin, ibs->ibs_last_pin));
319
320		npins = 1 + ibs->ibs_last_pin - ibs->ibs_first_pin;
321
322		ib->ib_intr =
323		    kmem_zalloc(sizeof(*ib->ib_intr) * npins, KM_SLEEP);
324
325		sc->sc_npins += npins;
326	}
327
328	if (sc->sc_npins < 1 || sc->sc_npins > 4096) {
329		printf("Unexpected pin count %d\n", sc->sc_npins);
330		goto out;
331	}
332
333	sc->sc_pins =
334	    kmem_zalloc(sizeof(*sc->sc_pins) * sc->sc_npins, KM_SLEEP);
335
336	for (j = 0; j < sc->sc_npins; j++) {
337		sc->sc_pins[j].pin_num = j;
338		sc->sc_pins[j].pin_caps =
339		    GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INOUT |
340		    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_PIN_INVIN;
341		sc->sc_pins[j].pin_intrcaps =
342		    GPIO_INTR_POS_EDGE | GPIO_INTR_NEG_EDGE |
343		    GPIO_INTR_DOUBLE_EDGE | GPIO_INTR_HIGH_LEVEL |
344		    GPIO_INTR_LOW_LEVEL | GPIO_INTR_MPSAFE;
345		sc->sc_pins[j].pin_state = igpio_pin_read(sc, j);
346	}
347
348	sc->sc_gc.gp_cookie = sc;
349	sc->sc_gc.gp_pin_read = igpio_pin_read;
350	sc->sc_gc.gp_pin_write = igpio_pin_write;
351	sc->sc_gc.gp_pin_ctl = igpio_pin_ctl;
352	sc->sc_gc.gp_intr_establish = igpio_intr_establish;
353	sc->sc_gc.gp_intr_disestablish = igpio_intr_disestablish;
354	sc->sc_gc.gp_intr_str = igpio_intr_str;
355
356	memset(&gba, 0, sizeof(gba));
357	gba.gba_gc = &sc->sc_gc;
358	gba.gba_pins = sc->sc_pins;
359	gba.gba_npins = sc->sc_npins;
360
361#if NGPIO > 0
362	config_found(sc->sc_dev, &gba, gpiobus_print, CFARGS_NONE);
363#endif
364
365	success = 1;
366out:
367	if (!success)
368		igpio_detach(sc);
369
370	return;
371}
372
373void
374igpio_detach(struct igpio_softc *sc)
375{
376	int i;
377
378	for (i = 0; i < sc->sc_nbar; i++) {
379		struct igpio_bank *ib = &sc->sc_banks[i];
380		struct igpio_bank_setup *ibs = ib->ib_setup;
381		int npins = 1 + ibs->ibs_last_pin - ibs->ibs_first_pin;
382
383		if (ib->ib_intr != NULL) {
384			kmem_free(ib->ib_intr, sizeof(*ib->ib_intr) * npins);
385			ib->ib_intr = NULL;
386		}
387	}
388
389	if (sc->sc_pins != NULL) {
390		kmem_free(sc->sc_pins, sizeof(*sc->sc_pins) * sc->sc_npins);
391		sc->sc_pins = NULL;
392	}
393
394	if (sc->sc_banks != NULL) {
395		kmem_free(sc->sc_banks, sizeof(*sc->sc_banks) * sc->sc_nbar);
396		sc->sc_banks = NULL;
397	}
398
399	return;
400}
401
402static bus_addr_t
403igpio_pincfg(struct igpio_bank *ib, int pin, int reg)
404{
405	int nregs = (ib->ib_cap & IGPIO_PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2;
406	bus_addr_t pincfg;
407
408	pincfg = ib->ib_padbar + reg + (pin * nregs * 4);
409#if 0
410	DPRINTF(("%s bar %d pin %d reg #%x pincfg = %p\n",
411	    __func__, ib->ib_barno, pin, reg, (void *)pincfg));
412#endif
413	return pincfg;
414}
415
416#if notyet
417static struct igpio_pin_group *
418igpio_find_group(struct igpio_bank *ib, int pin)
419{
420	struct igpio_bank_setup *ibs = ib->ib_setup;
421	struct igpio_pin_group *found_ipg = NULL;
422	struct igpio_pin_group *ipg;
423
424	if (pin > ibs->ibs_last_pin) {
425		DPRINTF(("%s: barno %d, pin = %d > past pin = %d\n", __func__,
426		    ibs->ibs_barno, pin, ibs->ibs_last_pin));
427		return NULL;
428	}
429
430	for (ipg = igpio_pin_group; ipg->ipg_acpi_hid; ipg++) {
431		if (strcmp(ipg->ipg_acpi_hid, ibs->ibs_acpi_hid) != 0)
432			continue;
433
434		if (pin > ipg->ipg_first_pin) {
435			found_ipg = ipg;
436			continue;
437		}
438	}
439
440	return found_ipg;
441}
442
443static bus_addr_t
444igpio_groupcfg(struct igpio_bank *ib, int pin)
445{
446	struct igpio_bank_setup *ibs = ib->ib_setup;
447	struct igpio_pin_group *ipg;
448	bus_addr_t groupcfg;
449
450	if ((ipg = igpio_find_group(ib, pin)) == NULL)
451		return (bus_addr_t)NULL;
452
453	groupcfg = ib->ib_padbar
454		 + (ipg->ipg_groupno * 4)
455		 + (pin - ipg->ipg_first_pin) / 2;
456
457	DPRINTF(("%s: barno %d, pin = %d, found group %d \"%s\", cfg %p\n", \
458	    __func__, ibs->ibs_barno, pin, ipg->ipg_groupno,		    \
459	    ipg->ipg_name, (void *)groupcfg));
460
461	return groupcfg;
462}
463#endif
464
465
466int
467igpio_pin_read(void *priv, int pin)
468{
469	struct igpio_softc *sc = priv;
470	struct igpio_bank *ib = igpio_find_bank(sc, pin);
471	bus_addr_t cfg0;
472	uint32_t val;
473
474	pin = igpio_bank_pin(ib, pin);
475	cfg0  = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
476
477	mutex_enter(&ib->ib_mtx);
478
479	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
480	DPRINTF(("%s: bar %d pin %d val #%x (%s)\n", __func__,
481	    ib->ib_barno, pin, val, igpio_padcfg0_print(val, 0)));
482
483	if (val & IGPIO_PADCFG0_GPIOTXDIS)
484		val = (val & IGPIO_PADCFG0_GPIORXSTATE) ? 1 : 0;
485	else
486		val = (val & IGPIO_PADCFG0_GPIOTXSTATE) ? 1 : 0;
487
488	mutex_exit(&ib->ib_mtx);
489
490	return val;
491}
492
493void
494igpio_pin_write(void *priv, int pin, int value)
495{
496	struct igpio_softc *sc = priv;
497	struct igpio_bank *ib = igpio_find_bank(sc, pin);
498	bus_addr_t cfg0;
499	uint32_t val, newval;
500
501	pin = igpio_bank_pin(ib, pin);
502	cfg0 = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
503
504	mutex_enter(&ib->ib_mtx);
505
506	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
507
508	if (value)
509		newval = val |  IGPIO_PADCFG0_GPIOTXSTATE;
510	else
511		newval = val & ~IGPIO_PADCFG0_GPIOTXSTATE;
512
513	DPRINTF(("%s: bar %d pin %d value %d val #%x (%s) -> #%x (%s)\n",
514	    __func__, ib->ib_barno, pin, value,
515	    val, igpio_padcfg0_print(val, 0),
516	    newval, igpio_padcfg0_print(newval, 1)));
517
518	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0, newval);
519
520	mutex_exit(&ib->ib_mtx);
521
522	return;
523}
524
525void
526igpio_pin_ctl(void *priv, int pin, int flags)
527{
528	struct igpio_softc *sc = priv;
529	struct igpio_bank *ib = igpio_find_bank(sc, pin);
530	bus_addr_t cfg0, cfg1;
531	uint32_t val0, newval0;
532	uint32_t val1, newval1;
533
534	pin = igpio_bank_pin(ib, pin);
535	cfg0  = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
536	cfg1  = igpio_pincfg(ib, pin, IGPIO_PADCFG1);
537
538	mutex_enter(&ib->ib_mtx);
539
540	val0 = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
541	val1 = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg1);
542
543	newval0 = val0;
544	newval1 = val1;
545
546	newval0 &= ~IGPIO_PADCFG0_PMODE_MASK;
547	newval0 |=  IGPIO_PADCFG0_PMODE_GPIO;
548
549	newval0 |= IGPIO_PADCFG0_GPIORXDIS;
550	newval0 |= IGPIO_PADCFG0_GPIOTXDIS;
551
552	newval0 &= ~(IGPIO_PADCFG0_GPIROUTIOXAPIC | IGPIO_PADCFG0_GPIROUTSCI);
553	newval0 &= ~(IGPIO_PADCFG0_GPIROUTSMI | IGPIO_PADCFG0_GPIROUTNMI);
554
555	if (flags & GPIO_PIN_INPUT) {
556		newval0 &= ~IGPIO_PADCFG0_GPIORXDIS;
557		newval0 |=  IGPIO_PADCFG0_GPIOTXDIS;
558	}
559
560	if (flags & GPIO_PIN_OUTPUT) {
561		newval0 &= ~IGPIO_PADCFG0_GPIOTXDIS;
562		newval0 |=  IGPIO_PADCFG0_GPIORXDIS;
563	}
564
565	if (flags & GPIO_PIN_INOUT) {
566		newval0 &= ~IGPIO_PADCFG0_GPIOTXDIS;
567		newval0 &= ~IGPIO_PADCFG0_GPIORXDIS;
568	}
569
570	if (flags & GPIO_PIN_INVIN)
571		newval0 |=  IGPIO_PADCFG0_RXINV;
572	else
573		newval0 &= ~IGPIO_PADCFG0_RXINV;
574
575	newval1 &= ~IGPIO_PADCFG1_TERM_MASK;
576	if (flags & GPIO_PIN_PULLUP) {
577		newval1 |=  IGPIO_PADCFG1_TERM_UP;
578		newval1 |=  IGPIO_PADCFG1_TERM_5K;
579	}
580
581	if (flags & GPIO_PIN_PULLDOWN) {
582		newval1 &= ~IGPIO_PADCFG1_TERM_UP;
583		newval1 |=  IGPIO_PADCFG1_TERM_5K;
584	}
585
586	DPRINTF(("%s: bar %d pin %d flags #%x val0 #%x (%s) -> #%x (%s), "
587	    "val1 #%x -> #%x\n", __func__, ib->ib_barno, pin, flags,
588	    val0, igpio_padcfg0_print(val0, 0),
589	    newval0, igpio_padcfg0_print(newval0, 1),
590	    val1, newval1));
591
592	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0, newval0);
593	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg1, newval1);
594
595	mutex_exit(&ib->ib_mtx);
596
597	return;
598}
599
600void *
601igpio_intr_establish(void *priv, int pin, int ipl, int irqmode,
602    int (*func)(void *), void *arg)
603{
604	struct igpio_softc *sc = priv;
605	struct igpio_bank *ib = igpio_find_bank(sc, pin);
606	bus_addr_t cfg0;
607	uint32_t val, newval;
608	struct igpio_intr *ii;
609
610	pin = igpio_bank_pin(ib, pin);
611	cfg0 = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
612
613	ii = &ib->ib_intr[pin];
614	ii->ii_func = func;
615	ii->ii_arg = arg;
616	ii->ii_pin = pin;
617	ii->ii_bank = ib;
618
619	mutex_enter(&ib->ib_mtx);
620
621	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
622	newval = val;
623
624	newval &= ~IGPIO_PADCFG0_PMODE_MASK;
625	newval |=  IGPIO_PADCFG0_PMODE_GPIO;
626
627	newval &= ~IGPIO_PADCFG0_GPIORXDIS;
628	newval |=  IGPIO_PADCFG0_GPIOTXDIS;
629
630	newval |= (IGPIO_PADCFG0_GPIROUTIOXAPIC | IGPIO_PADCFG0_GPIROUTSCI);
631	newval |= (IGPIO_PADCFG0_GPIROUTSMI | IGPIO_PADCFG0_GPIROUTNMI);
632
633	newval &= ~IGPIO_PADCFG0_RXINV;
634	newval &= ~IGPIO_PADCFG0_RXEVCFG_EDGE;
635	newval &= ~IGPIO_PADCFG0_RXEVCFG_LEVEL;
636	newval &= ~IGPIO_PADCFG0_RXEVCFG_DISABLED;
637
638	switch (irqmode & GPIO_INTR_EDGE_MASK) {
639	case GPIO_INTR_DOUBLE_EDGE:
640		newval |= IGPIO_PADCFG0_RXEVCFG_EDGE_BOTH;
641		break;
642	case GPIO_INTR_NEG_EDGE:
643		newval |= IGPIO_PADCFG0_RXEVCFG_EDGE;
644		newval |= IGPIO_PADCFG0_RXINV;
645		break;
646	case GPIO_INTR_POS_EDGE:
647		newval |= IGPIO_PADCFG0_RXEVCFG_EDGE;
648		break;
649	default:
650		switch (irqmode & GPIO_INTR_LEVEL_MASK) {
651		case GPIO_INTR_HIGH_LEVEL:
652			newval |= IGPIO_PADCFG0_RXEVCFG_LEVEL;
653			break;
654		case GPIO_INTR_LOW_LEVEL:
655			newval |= IGPIO_PADCFG0_RXEVCFG_LEVEL;
656			newval |= IGPIO_PADCFG0_RXINV;
657			break;
658		default:
659			newval |= IGPIO_PADCFG0_RXEVCFG_DISABLED;
660			break;
661		}
662		break;
663	}
664
665
666	DPRINTF(("%s: bar %d pin %d val #%x (%s) -> #%x (%s)\n",
667	    __func__, ib->ib_barno, pin,
668	    val, igpio_padcfg0_print(val, 0),
669	    newval, igpio_padcfg0_print(newval, 1)));
670
671	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0, newval);
672
673	mutex_exit(&ib->ib_mtx);
674
675	return ii;
676}
677
678void
679igpio_intr_disestablish(void *priv, void *ih)
680{
681	struct igpio_softc *sc = priv;
682	struct igpio_bank *ib;
683	struct igpio_intr *ii = ih;
684	int pin;
685	bus_addr_t cfg0;
686	uint32_t val, newval;
687
688	if (ih == NULL)
689		return;
690
691	pin = ii->ii_pin;
692	ib = igpio_find_bank(sc, pin);
693	pin = igpio_bank_pin(ib, pin);
694	cfg0  = igpio_pincfg(ib, pin, IGPIO_PADCFG0);
695
696	mutex_enter(&ib->ib_mtx);
697
698	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0);
699	newval = val;
700
701	newval &= ~IGPIO_PADCFG0_PMODE_MASK;
702	newval |=  IGPIO_PADCFG0_PMODE_GPIO;
703
704	newval &= ~(IGPIO_PADCFG0_GPIROUTIOXAPIC | IGPIO_PADCFG0_GPIROUTSCI);
705	newval &= ~(IGPIO_PADCFG0_GPIROUTSMI | IGPIO_PADCFG0_GPIROUTNMI);
706
707	DPRINTF(("%s: bar %d pin %d val #%x (%s) -> #%x (%s)\n", \
708	    __func__, ib->ib_barno, pin,
709	    val, igpio_padcfg0_print(val, 0),
710	    newval, igpio_padcfg0_print(newval, 1)));
711
712	bus_space_write_4(sc->sc_bst, sc->sc_bsh[ib->ib_barno], cfg0, newval);
713
714	mutex_exit(&ib->ib_mtx);
715
716	ii->ii_func = NULL;
717	ii->ii_arg = NULL;
718
719	return;
720}
721
722bool
723igpio_intr_str(void *priv, int pin, int irqmode,
724    char *buf, size_t buflen)
725{
726	struct igpio_softc *sc = priv;
727	const char *name = device_xname(sc->sc_dev);
728	int rv;
729
730	rv = snprintf(buf, buflen, "%s pin %d", name, pin);
731
732	return (rv < buflen);
733}
734
735int
736igpio_intr(void *priv)
737{
738	struct igpio_softc *sc = priv;
739	int i;
740	int ret = 0;
741
742	for (i = 0; i < sc->sc_nbar; i++) {
743		struct igpio_bank *ib = &sc->sc_banks[i];
744		struct igpio_bank_setup *ibs = ib->ib_setup;
745		bus_space_handle_t bsh = sc->sc_bsh[i];
746		struct igpio_pin_group *ipg;
747
748		mutex_enter(&ib->ib_mtx);
749
750		for (ipg = igpio_pin_group; ipg->ipg_acpi_hid; ipg++) {
751			int offset;
752			bus_addr_t is_reg;
753			bus_addr_t ie_reg;
754			uint32_t raised;
755			uint32_t pending;
756			uint32_t enabled;
757			int b;
758
759			if (strcmp(ipg->ipg_acpi_hid,
760			    ibs->ibs_acpi_hid) != 0)
761				continue;
762
763			offset = ib->ib_padbar + ipg->ipg_groupno * 4;
764			is_reg = offset + ibs->ibs_gpi_is;
765			ie_reg = offset + ibs->ibs_gpi_ie;
766
767			raised = bus_space_read_4(sc->sc_bst, bsh, is_reg);
768			enabled = bus_space_read_4(sc->sc_bst, bsh, ie_reg);
769
770			/*
771			 * find pins for which interrupt is pending
772			 * and enabled
773			 */
774			pending = raised & enabled;
775
776			for (b = 0; b < 32; b++) {
777				int pin;
778				int (*func)(void *);
779				void *arg;
780
781				if ((pending & (1 << b)) == 0)
782					continue;
783
784				pin = ipg->ipg_first_pin + b;
785				func = ib->ib_intr[pin].ii_func;
786				arg = ib->ib_intr[pin].ii_arg;
787
788				/* XXX ack intr, handled or not? */
789				raised &= ~(1 << b);
790
791				if (func == NULL)
792					continue;
793
794				ret |= func(arg);
795			}
796
797			bus_space_write_4(sc->sc_bst, bsh, is_reg, raised);
798
799		}
800
801		mutex_exit(&ib->ib_mtx);
802
803	}
804
805	return ret;
806}
807