4 * GEMINI LPC Host Controller
6 #include "opt_gemini.h"
10 __KERNEL_RCSID(0, "$NetBSD$");
12 #include <sys/param.h>
13 #include <sys/callout.h>
14 #include <sys/cdefs.h>
15 #include <sys/device.h>
16 #include <sys/kernel.h>
17 #include <sys/systm.h>
18 #include <sys/malloc.h>
20 #include <machine/param.h>
21 #include <machine/bus.h>
23 #include <arm/gemini/gemini_lpchcvar.h>
24 #include <arm/gemini/gemini_lpcvar.h>
25 #include <arm/gemini/gemini_reg.h>
28 gemini_lpchc_sirq_cfg(bus_space_tag_t iot
, bus_space_handle_t ioh
,
29 bus_size_t offset
, uint32_t bit
, boolean_t doset
)
33 r
= bus_space_read_4(iot
, ioh
, offset
);
38 bus_space_write_4(iot
, ioh
, offset
, r
);
42 gemini_lpchc_sirq_ack(bus_space_tag_t iot
, bus_space_handle_t ioh
,
47 r
= bus_space_read_4(iot
, ioh
, GEMINI_LPCHC_SERIRQSTS
);
50 bus_space_write_4(iot
, ioh
, GEMINI_LPCHC_SERIRQSTS
, r
);
54 gemini_lpchc_sirq_disable(bus_space_tag_t iot
, bus_space_handle_t ioh
)
58 r
= bus_space_read_4(iot
, ioh
, GEMINI_LPCHC_IRQCTL
);
59 r
&= ~LPCHC_IRQCTL_SIRQEN
;
60 bus_space_write_4(iot
, ioh
, GEMINI_LPCHC_IRQCTL
, r
);
64 gemini_lpchc_sirq_enable(bus_space_tag_t iot
, bus_space_handle_t ioh
)
68 r
= bus_space_read_4(iot
, ioh
, GEMINI_LPCHC_IRQCTL
);
69 r
|= LPCHC_IRQCTL_SIRQEN
;
70 r
|= LPCHC_IRQCTL_SIRQMS
; /* XXX "continuous mode" */
71 r
|= IRQCTL_SIRQFW_8
; /* XXX SIRW Frame Width 8 clocks */
72 bus_space_write_4(iot
, ioh
, GEMINI_LPCHC_IRQCTL
, r
);
74 delay(10); /* wait 1 serial IRQ cycle */
75 r
&= ~LPCHC_IRQCTL_SIRQMS
; /* XXX "quiet mode" */
76 bus_space_write_4(iot
, ioh
, GEMINI_LPCHC_IRQCTL
, r
);
81 gemini_lpchc_intrq_init(gemini_lpchc_softc_t
*sc
)
83 SIMPLEQ_INIT(&sc
->sc_intrq
);
87 gemini_lpchc_intrq_empty(gemini_lpchc_softc_t
*sc
)
89 return SIMPLEQ_EMPTY(&sc
->sc_intrq
);
93 gemini_lpchc_intrq_insert(gemini_lpchc_softc_t
*sc
, int (*func
)(void *),
94 void *arg
, uint32_t bit
, boolean_t isedge
)
96 gemini_lpchc_intrq_t
*iqp
;
98 iqp
= malloc(sizeof(*iqp
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
100 printf("gemini_lpchc_intrq_insert: malloc failed\n");
107 iqp
->iq_isedge
= isedge
;
108 SIMPLEQ_INSERT_TAIL(&sc
->sc_intrq
, iqp
, iq_q
);
114 gemini_lpchc_intrq_remove(gemini_lpchc_softc_t
*sc
, void *cookie
)
116 gemini_lpchc_intrq_t
*iqp
;
118 SIMPLEQ_FOREACH(iqp
, &sc
->sc_intrq
, iq_q
) {
119 if ((void *)iqp
== cookie
) {
120 SIMPLEQ_REMOVE(&sc
->sc_intrq
,
121 iqp
, gemini_lpchc_intrq
, iq_q
);
129 gemini_lpchc_intrq_dispatch(gemini_lpchc_softc_t
*sc
)
131 gemini_lpchc_intrq_t
*iqp
;
135 r
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, GEMINI_LPCHC_SERIRQSTS
);
136 r
&= ~LPCHC_SERIRQSTS_RESV
;
137 SIMPLEQ_FOREACH(iqp
, &sc
->sc_intrq
, iq_q
) {
138 if ((r
& iqp
->iq_bit
) != 0) {
139 if (iqp
->iq_isedge
) {
140 gemini_lpchc_sirq_ack(sc
->sc_iot
, sc
->sc_ioh
,
143 rv
|= (*iqp
->iq_func
)(iqp
->iq_arg
);
150 gemini_lpchc_init(lpcintrtag_t tag
)
152 gemini_lpchc_softc_t
*sc
= tag
;
155 gemini_lpchc_intrq_init(sc
);
157 r
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, GEMINI_LPCHC_CSR
);
159 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, GEMINI_LPCHC_CSR
, r
);
163 gemini_lpchc_intr_establish(lpcintrtag_t tag
, uint irq
,
164 int ipl
, int type
, int (*func
)(void *), void *arg
)
166 gemini_lpchc_softc_t
*sc
= tag
;
167 bus_space_tag_t iot
= sc
->sc_iot
;
168 bus_space_handle_t ioh
= sc
->sc_ioh
;
174 isedge
= ((type
== IST_EDGE_RISING
) || (type
== IST_EDGE_FALLING
));
175 ishigh
= ((type
== IST_EDGE_RISING
) || (type
== IST_LEVEL_HIGH
));
177 if (irq
>= GEMINI_LPCHC_NSERIRQ
) {
178 printf("%s: bad irq %d\n", __FUNCTION__
, irq
);
184 bit
= (1 << GEMINI_LPCHC_NSERIRQ
) -1; /* XXX */
188 gemini_lpchc_sirq_cfg(iot
, ioh
, GEMINI_LPCHC_SERIRQTYP
,
191 /* set IRQ polarity */
192 gemini_lpchc_sirq_cfg(iot
, ioh
, GEMINI_LPCHC_SERIRQPOLARITY
,
195 /* ack a-priori edge status */
197 gemini_lpchc_sirq_ack(iot
, ioh
, bit
);
199 if (gemini_lpchc_intrq_empty(sc
))
200 gemini_lpchc_sirq_enable(iot
, ioh
);
202 ih
= gemini_lpchc_intrq_insert(sc
, func
, arg
, bit
, isedge
);
204 if (gemini_lpchc_intrq_empty(sc
))
205 gemini_lpchc_sirq_disable(iot
, ioh
);
211 gemini_lpchc_intr_disestablish(lpcintrtag_t tag
, void *ih
)
213 gemini_lpchc_softc_t
*sc
= tag
;
215 gemini_lpchc_intrq_remove(sc
, ih
);
216 if (gemini_lpchc_intrq_empty(sc
))
217 gemini_lpchc_sirq_disable(sc
->sc_iot
, sc
->sc_ioh
);
221 gemini_lpchc_intr(void *arg
)
223 gemini_lpchc_softc_t
*sc
= arg
;
226 printf("%s: enter\n", __FUNCTION__
);
227 rv
= gemini_lpchc_intrq_dispatch(sc
);
228 printf("%s: exit\n", __FUNCTION__
);