1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2013 Rui Paulo <rpaulo@FreeBSD.org>
5 * Copyright (c) 2017 Manuel Stuehn
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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 the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/poll.h>
33#include <sys/time.h>
34#include <sys/uio.h>
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/fcntl.h>
38#include <sys/bus.h>
39#include <sys/conf.h>
40#include <sys/kernel.h>
41#include <sys/lock.h>
42#include <sys/module.h>
43#include <sys/malloc.h>
44#include <sys/mutex.h>
45#include <sys/rman.h>
46#include <sys/types.h>
47#include <sys/sysctl.h>
48#include <sys/event.h>
49#include <sys/selinfo.h>
50#include <machine/bus.h>
51#include <machine/cpu.h>
52#include <machine/frame.h>
53#include <machine/intr.h>
54#include <machine/atomic.h>
55
56#include <dev/ofw/openfirm.h>
57#include <dev/ofw/ofw_bus.h>
58#include <dev/ofw/ofw_bus_subr.h>
59
60#include <dev/extres/clk/clk.h>
61
62#include <arm/ti/ti_sysc.h>
63#include <arm/ti/ti_pruss.h>
64#include <arm/ti/ti_prm.h>
65
66#ifdef DEBUG
67#define	DPRINTF(fmt, ...)	do {	\
68	printf("%s: ", __func__);	\
69	printf(fmt, __VA_ARGS__);	\
70} while (0)
71#else
72#define	DPRINTF(fmt, ...)
73#endif
74
75static d_open_t			ti_pruss_irq_open;
76static d_read_t			ti_pruss_irq_read;
77static d_poll_t			ti_pruss_irq_poll;
78
79static device_probe_t		ti_pruss_probe;
80static device_attach_t		ti_pruss_attach;
81static device_detach_t		ti_pruss_detach;
82static void			ti_pruss_intr(void *);
83static d_open_t			ti_pruss_open;
84static d_mmap_t			ti_pruss_mmap;
85static void 			ti_pruss_irq_kqread_detach(struct knote *);
86static int 			ti_pruss_irq_kqevent(struct knote *, long);
87static d_kqfilter_t		ti_pruss_irq_kqfilter;
88static void			ti_pruss_privdtor(void *data);
89
90#define	TI_PRUSS_PRU_IRQS 2
91#define	TI_PRUSS_HOST_IRQS 8
92#define	TI_PRUSS_IRQS (TI_PRUSS_HOST_IRQS+TI_PRUSS_PRU_IRQS)
93#define	TI_PRUSS_EVENTS 64
94#define	NOT_SET_STR "NONE"
95#define	TI_TS_ARRAY 16
96
97struct ctl
98{
99	size_t cnt;
100	size_t idx;
101};
102
103struct ts_ring_buf
104{
105	struct ctl ctl;
106	uint64_t ts[TI_TS_ARRAY];
107};
108
109struct ti_pruss_irqsc
110{
111	struct mtx		sc_mtx;
112	struct cdev		*sc_pdev;
113	struct selinfo		sc_selinfo;
114	int8_t			channel;
115	int8_t			last;
116	int8_t			event;
117	bool			enable;
118	struct ts_ring_buf	tstamps;
119};
120
121static struct cdevsw ti_pruss_cdevirq = {
122	.d_version =	D_VERSION,
123	.d_name =	"ti_pruss_irq",
124	.d_open =	ti_pruss_irq_open,
125	.d_read =	ti_pruss_irq_read,
126	.d_poll =	ti_pruss_irq_poll,
127	.d_kqfilter =	ti_pruss_irq_kqfilter,
128};
129
130struct ti_pruss_softc {
131	struct mtx		sc_mtx;
132	struct resource 	*sc_mem_res;
133	struct resource 	*sc_irq_res[TI_PRUSS_HOST_IRQS];
134	void            	*sc_intr[TI_PRUSS_HOST_IRQS];
135	struct ti_pruss_irqsc	sc_irq_devs[TI_PRUSS_IRQS];
136	bus_space_tag_t		sc_bt;
137	bus_space_handle_t	sc_bh;
138	struct cdev		*sc_pdev;
139	struct selinfo		sc_selinfo;
140	bool			sc_glob_irqen;
141};
142
143static struct cdevsw ti_pruss_cdevsw = {
144	.d_version =	D_VERSION,
145	.d_name =	"ti_pruss",
146	.d_open =	ti_pruss_open,
147	.d_mmap =	ti_pruss_mmap,
148};
149
150static device_method_t ti_pruss_methods[] = {
151	DEVMETHOD(device_probe,		ti_pruss_probe),
152	DEVMETHOD(device_attach,	ti_pruss_attach),
153	DEVMETHOD(device_detach,	ti_pruss_detach),
154
155	DEVMETHOD_END
156};
157
158static driver_t ti_pruss_driver = {
159	"ti_pruss",
160	ti_pruss_methods,
161	sizeof(struct ti_pruss_softc)
162};
163
164static devclass_t ti_pruss_devclass;
165
166DRIVER_MODULE(ti_pruss, simplebus, ti_pruss_driver, ti_pruss_devclass, 0, 0);
167MODULE_DEPEND(ti_pruss, ti_sysc, 1, 1, 1);
168MODULE_DEPEND(ti_pruss, ti_prm, 1, 1, 1);
169
170static struct resource_spec ti_pruss_irq_spec[] = {
171	{ SYS_RES_IRQ,	    0,  RF_ACTIVE },
172	{ SYS_RES_IRQ,	    1,  RF_ACTIVE },
173	{ SYS_RES_IRQ,	    2,  RF_ACTIVE },
174	{ SYS_RES_IRQ,	    3,  RF_ACTIVE },
175	{ SYS_RES_IRQ,	    4,  RF_ACTIVE },
176	{ SYS_RES_IRQ,	    5,  RF_ACTIVE },
177	{ SYS_RES_IRQ,	    6,  RF_ACTIVE },
178	{ SYS_RES_IRQ,	    7,  RF_ACTIVE },
179	{ -1,               0,  0 }
180};
181CTASSERT(TI_PRUSS_HOST_IRQS == nitems(ti_pruss_irq_spec) - 1);
182
183static int
184ti_pruss_irq_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
185{
186	struct ctl* irqs;
187	struct ti_pruss_irqsc *sc;
188	sc = dev->si_drv1;
189
190	irqs = malloc(sizeof(struct ctl), M_DEVBUF, M_WAITOK);
191	if (!irqs)
192	    return (ENOMEM);
193
194	irqs->cnt = sc->tstamps.ctl.cnt;
195	irqs->idx = sc->tstamps.ctl.idx;
196
197	return devfs_set_cdevpriv(irqs, ti_pruss_privdtor);
198}
199
200static void
201ti_pruss_privdtor(void *data)
202{
203    free(data, M_DEVBUF);
204}
205
206static int
207ti_pruss_irq_poll(struct cdev *dev, int events, struct thread *td)
208{
209	struct ctl* irqs;
210	struct ti_pruss_irqsc *sc;
211	sc = dev->si_drv1;
212
213	devfs_get_cdevpriv((void**)&irqs);
214
215	if (events & (POLLIN | POLLRDNORM)) {
216		if (sc->tstamps.ctl.cnt != irqs->cnt)
217			return events & (POLLIN | POLLRDNORM);
218		else
219			selrecord(td, &sc->sc_selinfo);
220	}
221	return 0;
222}
223
224static int
225ti_pruss_irq_read(struct cdev *cdev, struct uio *uio, int ioflag)
226{
227	const size_t ts_len = sizeof(uint64_t);
228	struct ti_pruss_irqsc* irq;
229	struct ctl* priv;
230	int error = 0;
231	size_t idx;
232	ssize_t level;
233
234	irq = cdev->si_drv1;
235
236	if (uio->uio_resid < ts_len)
237		return (EINVAL);
238
239	error = devfs_get_cdevpriv((void**)&priv);
240	if (error)
241	    return (error);
242
243	mtx_lock(&irq->sc_mtx);
244
245	if (irq->tstamps.ctl.cnt - priv->cnt > TI_TS_ARRAY)
246	{
247		priv->cnt = irq->tstamps.ctl.cnt;
248		priv->idx = irq->tstamps.ctl.idx;
249		mtx_unlock(&irq->sc_mtx);
250		return (ENXIO);
251	}
252
253	do {
254		idx = priv->idx;
255		level = irq->tstamps.ctl.idx - idx;
256		if (level < 0)
257			level += TI_TS_ARRAY;
258
259		if (level == 0) {
260			if (ioflag & O_NONBLOCK) {
261				mtx_unlock(&irq->sc_mtx);
262				return (EWOULDBLOCK);
263			}
264
265			error = msleep(irq, &irq->sc_mtx, PCATCH | PDROP,
266				"pruirq", 0);
267			if (error)
268				return error;
269
270			mtx_lock(&irq->sc_mtx);
271		}
272	}while(level == 0);
273
274	mtx_unlock(&irq->sc_mtx);
275
276	error = uiomove(&irq->tstamps.ts[idx], ts_len, uio);
277
278	if (++idx == TI_TS_ARRAY)
279		idx = 0;
280	priv->idx = idx;
281
282	atomic_add_32(&priv->cnt, 1);
283
284	return (error);
285}
286
287static struct ti_pruss_irq_arg {
288	int 		       irq;
289	struct ti_pruss_softc *sc;
290} ti_pruss_irq_args[TI_PRUSS_IRQS];
291
292static __inline uint32_t
293ti_pruss_reg_read(struct ti_pruss_softc *sc, uint32_t reg)
294{
295	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
296}
297
298static __inline void
299ti_pruss_reg_write(struct ti_pruss_softc *sc, uint32_t reg, uint32_t val)
300{
301	bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
302}
303
304static __inline void
305ti_pruss_interrupts_clear(struct ti_pruss_softc *sc)
306{
307	/* disable global interrupt */
308	ti_pruss_reg_write(sc, PRUSS_INTC_GER, 0 );
309
310	/* clear all events */
311	ti_pruss_reg_write(sc, PRUSS_INTC_SECR0, 0xFFFFFFFF);
312	ti_pruss_reg_write(sc, PRUSS_INTC_SECR1, 0xFFFFFFFF);
313
314	/* disable all host interrupts */
315	ti_pruss_reg_write(sc, PRUSS_INTC_HIER, 0);
316}
317
318static __inline int
319ti_pruss_interrupts_enable(struct ti_pruss_softc *sc, int8_t irq, bool enable)
320{
321	if (enable && ((sc->sc_irq_devs[irq].channel == -1) ||
322	    (sc->sc_irq_devs[irq].event== -1)))
323	{
324		device_printf( sc->sc_pdev->si_drv1,
325			"Interrupt chain not fully configured, not possible to enable\n" );
326		return (EINVAL);
327	}
328
329	sc->sc_irq_devs[irq].enable = enable;
330
331	if (sc->sc_irq_devs[irq].sc_pdev) {
332		destroy_dev(sc->sc_irq_devs[irq].sc_pdev);
333		sc->sc_irq_devs[irq].sc_pdev = NULL;
334	}
335
336	if (enable) {
337		sc->sc_irq_devs[irq].sc_pdev = make_dev(&ti_pruss_cdevirq, 0, UID_ROOT, GID_WHEEL,
338		    0600, "pruss%d.irq%d", device_get_unit(sc->sc_pdev->si_drv1), irq);
339		sc->sc_irq_devs[irq].sc_pdev->si_drv1 = &sc->sc_irq_devs[irq];
340
341		sc->sc_irq_devs[irq].tstamps.ctl.idx = 0;
342	}
343
344	uint32_t reg = enable ? PRUSS_INTC_HIEISR : PRUSS_INTC_HIDISR;
345	ti_pruss_reg_write(sc, reg, sc->sc_irq_devs[irq].channel);
346
347	reg = enable ? PRUSS_INTC_EISR : PRUSS_INTC_EICR;
348	ti_pruss_reg_write(sc, reg, sc->sc_irq_devs[irq].event );
349
350	return (0);
351}
352
353static __inline void
354ti_pruss_map_write(struct ti_pruss_softc *sc, uint32_t basereg, uint8_t index, uint8_t content)
355{
356	const size_t regadr = basereg + index & ~0x03;
357	const size_t bitpos = (index & 0x03) * 8;
358	uint32_t rmw = ti_pruss_reg_read(sc, regadr);
359	rmw = (rmw & ~( 0xF << bitpos)) | ( (content & 0xF) << bitpos);
360	ti_pruss_reg_write(sc, regadr, rmw);
361}
362
363static int
364ti_pruss_event_map( SYSCTL_HANDLER_ARGS )
365{
366	struct ti_pruss_softc *sc;
367	const int8_t irq = arg2;
368	int err;
369	char event[sizeof(NOT_SET_STR)];
370
371	sc = arg1;
372
373	if(sc->sc_irq_devs[irq].event == -1)
374		bcopy(NOT_SET_STR, event, sizeof(event));
375	else
376		snprintf(event, sizeof(event), "%d", sc->sc_irq_devs[irq].event);
377
378	err = sysctl_handle_string(oidp, event, sizeof(event), req);
379	if(err != 0)
380		return (err);
381
382	if (req->newptr) {  // write event
383		if (strcmp(NOT_SET_STR, event) == 0) {
384			ti_pruss_interrupts_enable(sc, irq, false);
385			sc->sc_irq_devs[irq].event = -1;
386		} else {
387			if (sc->sc_irq_devs[irq].channel == -1) {
388				device_printf( sc->sc_pdev->si_drv1,
389					"corresponding channel not configured\n");
390				return (ENXIO);
391			}
392
393			const int8_t channelnr = sc->sc_irq_devs[irq].channel;
394			const int8_t eventnr = strtol( event, NULL, 10 ); // TODO: check if strol is valid
395			if (eventnr > TI_PRUSS_EVENTS || eventnr < 0) {
396				device_printf( sc->sc_pdev->si_drv1,
397					"Event number %d not valid (0 - %d)",
398					channelnr, TI_PRUSS_EVENTS -1);
399				return (EINVAL);
400			}
401
402			sc->sc_irq_devs[irq].channel = channelnr;
403			sc->sc_irq_devs[irq].event = eventnr;
404
405			// event[nr] <= channel
406			ti_pruss_map_write(sc, PRUSS_INTC_CMR_BASE,
407			    eventnr, channelnr);
408		}
409	}
410	return (err);
411}
412
413static int
414ti_pruss_channel_map(SYSCTL_HANDLER_ARGS)
415{
416	struct ti_pruss_softc *sc;
417	int err;
418	char channel[sizeof(NOT_SET_STR)];
419	const int8_t irq = arg2;
420
421	sc = arg1;
422
423	if (sc->sc_irq_devs[irq].channel == -1)
424		bcopy(NOT_SET_STR, channel, sizeof(channel));
425	else
426		snprintf(channel, sizeof(channel), "%d", sc->sc_irq_devs[irq].channel);
427
428	err = sysctl_handle_string(oidp, channel, sizeof(channel), req);
429	if (err != 0)
430		return (err);
431
432	if (req->newptr) { // write event
433		if (strcmp(NOT_SET_STR, channel) == 0) {
434			ti_pruss_interrupts_enable(sc, irq, false);
435			ti_pruss_reg_write(sc, PRUSS_INTC_HIDISR,
436			    sc->sc_irq_devs[irq].channel);
437			sc->sc_irq_devs[irq].channel = -1;
438		} else {
439			const int8_t channelnr = strtol(channel, NULL, 10); // TODO: check if strol is valid
440			if (channelnr > TI_PRUSS_IRQS || channelnr < 0)
441			{
442				device_printf(sc->sc_pdev->si_drv1,
443					"Channel number %d not valid (0 - %d)",
444					channelnr, TI_PRUSS_IRQS-1);
445				return (EINVAL);
446			}
447
448			sc->sc_irq_devs[irq].channel = channelnr;
449			sc->sc_irq_devs[irq].last = -1;
450
451			// channel[nr] <= irqnr
452			ti_pruss_map_write(sc, PRUSS_INTC_HMR_BASE,
453				irq, channelnr);
454		}
455	}
456
457	return (err);
458}
459
460static int
461ti_pruss_interrupt_enable(SYSCTL_HANDLER_ARGS)
462{
463	struct ti_pruss_softc *sc;
464	int err;
465	bool irqenable;
466	const int8_t irq = arg2;
467
468	sc = arg1;
469	irqenable = sc->sc_irq_devs[arg2].enable;
470
471	err = sysctl_handle_bool(oidp, &irqenable, arg2, req);
472	if (err != 0)
473		return (err);
474
475	if (req->newptr) // write enable
476		return ti_pruss_interrupts_enable(sc, irq, irqenable);
477
478	return (err);
479}
480
481static int
482ti_pruss_global_interrupt_enable(SYSCTL_HANDLER_ARGS)
483{
484	struct ti_pruss_softc *sc;
485	int err;
486	bool glob_irqen;
487
488	sc = arg1;
489	glob_irqen = sc->sc_glob_irqen;
490
491	err = sysctl_handle_bool(oidp, &glob_irqen, arg2, req);
492	if (err != 0)
493		return (err);
494
495	if (req->newptr) {
496		sc->sc_glob_irqen = glob_irqen;
497		ti_pruss_reg_write(sc, PRUSS_INTC_GER, glob_irqen);
498	}
499
500	return (err);
501}
502static int
503ti_pruss_probe(device_t dev)
504{
505
506	if (!ofw_bus_status_okay(dev))
507		return (ENXIO);
508
509	if (ofw_bus_is_compatible(dev, "ti,pruss-v1") ||
510	    ofw_bus_is_compatible(dev, "ti,pruss-v2")) {
511		device_set_desc(dev, "TI Programmable Realtime Unit Subsystem");
512		return (BUS_PROBE_DEFAULT);
513	}
514
515	return (ENXIO);
516}
517
518static int
519ti_pruss_attach(device_t dev)
520{
521	struct ti_pruss_softc *sc;
522	int rid, i, err, ncells;
523	uint32_t reg;
524	phandle_t node;
525	clk_t l3_gclk, pruss_ocp_gclk;
526	phandle_t ti_prm_ref, *cells;
527        device_t ti_prm_dev;
528
529	rid = 0;
530	sc = device_get_softc(dev);
531	node = ofw_bus_get_node(device_get_parent(dev));
532	if (node <= 0) {
533		device_printf(dev, "Cant get ofw node\n");
534		return (ENXIO);
535	}
536
537	/*
538	 * Follow activate pattern from sys/arm/ti/am335x/am335x_prcm.c
539	 * by Damjan Marion
540	 */
541
542	/* Set MODULEMODE to ENABLE(2) */
543	/* Wait for MODULEMODE to become ENABLE(2) */
544	if (ti_sysc_clock_enable(device_get_parent(dev)) != 0) {
545		device_printf(dev, "Could not enable PRUSS clock\n");
546		return (ENXIO);
547	}
548
549	/* Set CLKTRCTRL to SW_WKUP(2) */
550	/* Wait for the 200 MHz OCP clock to become active */
551	/* Wait for the 200 MHz IEP clock to become active */
552	/* Wait for the 192 MHz UART clock to become active */
553	/*
554	 * At the moment there is no reference to CM_PER_PRU_ICSS_CLKSTCTRL@140
555	 * in the devicetree. The register reset state are SW_WKUP(2) as default
556	 * so at the moment ignore setting this register.
557	 */
558
559	/* Select L3F as OCP clock */
560	/* Get the clock and set the parent */
561	err = clk_get_by_name(dev, "l3_gclk", &l3_gclk);
562	if (err) {
563		device_printf(dev, "Cant get l3_gclk err %d\n", err);
564		return (ENXIO);
565	}
566
567	err = clk_get_by_name(dev, "pruss_ocp_gclk@530", &pruss_ocp_gclk);
568	if (err) {
569		device_printf(dev, "Cant get pruss_ocp_gclk@530 err %d\n", err);
570		return (ENXIO);
571	}
572
573	err = clk_set_parent_by_clk(pruss_ocp_gclk, l3_gclk);
574	if (err) {
575		device_printf(dev,
576		    "Cant set pruss_ocp_gclk parent to l3_gclk err %d\n", err);
577		return (ENXIO);
578	}
579
580	/* Clear the RESET bit */
581	/* Find the ti_prm */
582	/* #reset-cells should not been used in this way but... */
583	err = ofw_bus_parse_xref_list_alloc(node, "resets", "#reset-cells", 0,
584	    &ti_prm_ref, &ncells, &cells);
585	OF_prop_free(cells);
586	if (err) {
587		device_printf(dev,
588		    "Cant fetch \"resets\" reference %x\n", err);
589		return (ENXIO);
590	}
591
592	ti_prm_dev = OF_device_from_xref(ti_prm_ref);
593	if (ti_prm_dev == NULL) {
594		device_printf(dev, "Cant get device from \"resets\"\n");
595		return (ENXIO);
596	}
597
598	err = ti_prm_reset(ti_prm_dev);
599	if (err) {
600		device_printf(dev, "ti_prm_reset failed %d\n", err);
601		return (ENXIO);
602	}
603	/* End of clock activation */
604
605	mtx_init(&sc->sc_mtx, "TI PRUSS", NULL, MTX_DEF);
606	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
607	    RF_ACTIVE);
608	if (sc->sc_mem_res == NULL) {
609		device_printf(dev, "could not allocate memory resource\n");
610		return (ENXIO);
611	}
612
613	struct sysctl_ctx_list *clist = device_get_sysctl_ctx(dev);
614	if (!clist)
615		return (EINVAL);
616
617	struct sysctl_oid *poid;
618	poid = device_get_sysctl_tree( dev );
619	if (!poid)
620		return (EINVAL);
621
622	sc->sc_glob_irqen = false;
623	struct sysctl_oid *irq_root = SYSCTL_ADD_NODE(clist, SYSCTL_CHILDREN(poid),
624	    OID_AUTO, "irq", CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
625	    "PRUSS Host Interrupts");
626	SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(poid), OID_AUTO,
627	    "global_interrupt_enable",
628	    CTLFLAG_RW | CTLTYPE_U8 | CTLFLAG_NEEDGIANT,
629	    sc, 0, ti_pruss_global_interrupt_enable,
630	    "CU", "Global interrupt enable");
631
632	sc->sc_bt = rman_get_bustag(sc->sc_mem_res);
633	sc->sc_bh = rman_get_bushandle(sc->sc_mem_res);
634	if (bus_alloc_resources(dev, ti_pruss_irq_spec, sc->sc_irq_res) != 0) {
635		device_printf(dev, "could not allocate interrupt resource\n");
636		ti_pruss_detach(dev);
637		return (ENXIO);
638	}
639
640	ti_pruss_interrupts_clear(sc);
641
642	for (i = 0; i < TI_PRUSS_IRQS; i++) {
643		char name[8];
644		snprintf(name, sizeof(name), "%d", i);
645
646		struct sysctl_oid *irq_nodes = SYSCTL_ADD_NODE(clist, SYSCTL_CHILDREN(irq_root),
647		    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
648		    "PRUSS Interrupts");
649		SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(irq_nodes), OID_AUTO,
650		    "channel", CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_NEEDGIANT,
651		    sc, i, ti_pruss_channel_map,
652		    "A", "Channel attached to this irq");
653		SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(irq_nodes), OID_AUTO,
654		    "event", CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_NEEDGIANT,
655		    sc, i, ti_pruss_event_map,
656		    "A", "Event attached to this irq");
657		SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(irq_nodes), OID_AUTO,
658		    "enable", CTLFLAG_RW | CTLTYPE_U8 | CTLFLAG_NEEDGIANT,
659		    sc, i, ti_pruss_interrupt_enable,
660		    "CU", "Enable/Disable interrupt");
661
662		sc->sc_irq_devs[i].event = -1;
663		sc->sc_irq_devs[i].channel = -1;
664		sc->sc_irq_devs[i].tstamps.ctl.idx = 0;
665
666		if (i < TI_PRUSS_HOST_IRQS) {
667			ti_pruss_irq_args[i].irq = i;
668			ti_pruss_irq_args[i].sc = sc;
669			if (bus_setup_intr(dev, sc->sc_irq_res[i],
670			    INTR_MPSAFE | INTR_TYPE_MISC,
671			    NULL, ti_pruss_intr, &ti_pruss_irq_args[i],
672			    &sc->sc_intr[i]) != 0) {
673				device_printf(dev,
674				    "unable to setup the interrupt handler\n");
675				ti_pruss_detach(dev);
676
677				return (ENXIO);
678			}
679			mtx_init(&sc->sc_irq_devs[i].sc_mtx, "TI PRUSS IRQ", NULL, MTX_DEF);
680			knlist_init_mtx(&sc->sc_irq_devs[i].sc_selinfo.si_note, &sc->sc_irq_devs[i].sc_mtx);
681		}
682	}
683
684	reg = ti_pruss_reg_read(sc,
685	    ti_sysc_get_sysc_address_offset_host(device_get_parent(dev)));
686
687	if (ti_pruss_reg_read(sc, PRUSS_AM33XX_INTC) == PRUSS_AM33XX_REV)
688		device_printf(dev, "AM33xx PRU-ICSS\n");
689
690	sc->sc_pdev = make_dev(&ti_pruss_cdevsw, 0, UID_ROOT, GID_WHEEL,
691	    0600, "pruss%d", device_get_unit(dev));
692	sc->sc_pdev->si_drv1 = dev;
693
694	/*  Acc. to datasheet always write 1 to polarity registers */
695	ti_pruss_reg_write(sc, PRUSS_INTC_SIPR0, 0xFFFFFFFF);
696	ti_pruss_reg_write(sc, PRUSS_INTC_SIPR1, 0xFFFFFFFF);
697
698	/* Acc. to datasheet always write 0 to event type registers */
699	ti_pruss_reg_write(sc, PRUSS_INTC_SITR0, 0);
700	ti_pruss_reg_write(sc, PRUSS_INTC_SITR1, 0);
701
702	return (0);
703}
704
705static int
706ti_pruss_detach(device_t dev)
707{
708	struct ti_pruss_softc *sc = device_get_softc(dev);
709
710	ti_pruss_interrupts_clear(sc);
711
712	for (int i = 0; i < TI_PRUSS_HOST_IRQS; i++) {
713		ti_pruss_interrupts_enable( sc, i, false );
714
715		if (sc->sc_intr[i])
716			bus_teardown_intr(dev, sc->sc_irq_res[i], sc->sc_intr[i]);
717		if (sc->sc_irq_res[i])
718			bus_release_resource(dev, SYS_RES_IRQ,
719			    rman_get_rid(sc->sc_irq_res[i]),
720			    sc->sc_irq_res[i]);
721		knlist_clear(&sc->sc_irq_devs[i].sc_selinfo.si_note, 0);
722		mtx_lock(&sc->sc_irq_devs[i].sc_mtx);
723		if (!knlist_empty(&sc->sc_irq_devs[i].sc_selinfo.si_note))
724			printf("IRQ %d KQueue not empty!\n", i );
725		mtx_unlock(&sc->sc_irq_devs[i].sc_mtx);
726		knlist_destroy(&sc->sc_irq_devs[i].sc_selinfo.si_note);
727		mtx_destroy(&sc->sc_irq_devs[i].sc_mtx);
728	}
729
730	mtx_destroy(&sc->sc_mtx);
731	if (sc->sc_mem_res)
732		bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_mem_res),
733		    sc->sc_mem_res);
734	if (sc->sc_pdev)
735		destroy_dev(sc->sc_pdev);
736
737	return (0);
738}
739
740static void
741ti_pruss_intr(void *arg)
742{
743	int val;
744	struct ti_pruss_irq_arg *iap = arg;
745	struct ti_pruss_softc *sc = iap->sc;
746	/*
747	 * Interrupts pr1_host_intr[0:7] are mapped to
748	 * Host-2 to Host-9 of PRU-ICSS IRQ-controller.
749	 */
750	const int pru_int = iap->irq + TI_PRUSS_PRU_IRQS;
751	const int pru_int_mask = (1 << pru_int);
752	const int pru_channel = sc->sc_irq_devs[pru_int].channel;
753	const int pru_event = sc->sc_irq_devs[pru_channel].event;
754
755	val = ti_pruss_reg_read(sc, PRUSS_INTC_HIER);
756	if (!(val & pru_int_mask))
757		return;
758
759	ti_pruss_reg_write(sc, PRUSS_INTC_HIDISR, pru_int);
760	ti_pruss_reg_write(sc, PRUSS_INTC_SICR, pru_event);
761	ti_pruss_reg_write(sc, PRUSS_INTC_HIEISR, pru_int);
762
763	struct ti_pruss_irqsc* irq = &sc->sc_irq_devs[pru_channel];
764	size_t wr = irq->tstamps.ctl.idx;
765
766	struct timespec ts;
767	nanouptime(&ts);
768	irq->tstamps.ts[wr] = ts.tv_sec * 1000000000 + ts.tv_nsec;
769
770	if (++wr == TI_TS_ARRAY)
771		wr = 0;
772	atomic_add_32(&irq->tstamps.ctl.cnt, 1);
773
774	irq->tstamps.ctl.idx = wr;
775
776	KNOTE_UNLOCKED(&irq->sc_selinfo.si_note, pru_int);
777	wakeup(irq);
778	selwakeup(&irq->sc_selinfo);
779}
780
781static int
782ti_pruss_open(struct cdev *cdev __unused, int oflags __unused,
783    int devtype __unused, struct thread *td __unused)
784{
785	return (0);
786}
787
788static int
789ti_pruss_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr,
790    int nprot, vm_memattr_t *memattr)
791{
792	device_t dev = cdev->si_drv1;
793	struct ti_pruss_softc *sc = device_get_softc(dev);
794
795	if (offset >= rman_get_size(sc->sc_mem_res))
796		return (ENOSPC);
797	*paddr = rman_get_start(sc->sc_mem_res) + offset;
798	*memattr = VM_MEMATTR_UNCACHEABLE;
799
800	return (0);
801}
802
803static struct filterops ti_pruss_kq_read = {
804	.f_isfd = 1,
805	.f_detach = ti_pruss_irq_kqread_detach,
806	.f_event = ti_pruss_irq_kqevent,
807};
808
809static void
810ti_pruss_irq_kqread_detach(struct knote *kn)
811{
812	struct ti_pruss_irqsc *sc = kn->kn_hook;
813
814	knlist_remove(&sc->sc_selinfo.si_note, kn, 0);
815}
816
817static int
818ti_pruss_irq_kqevent(struct knote *kn, long hint)
819{
820    struct ti_pruss_irqsc* irq_sc;
821    int notify;
822
823    irq_sc = kn->kn_hook;
824
825    if (hint > 0)
826        kn->kn_data = hint - 2;
827
828    if (hint > 0 || irq_sc->last > 0)
829        notify = 1;
830    else
831        notify = 0;
832
833    irq_sc->last = hint;
834
835    return (notify);
836}
837
838static int
839ti_pruss_irq_kqfilter(struct cdev *cdev, struct knote *kn)
840{
841	struct ti_pruss_irqsc *sc = cdev->si_drv1;
842
843	switch (kn->kn_filter) {
844	case EVFILT_READ:
845		kn->kn_hook = sc;
846		kn->kn_fop = &ti_pruss_kq_read;
847		knlist_add(&sc->sc_selinfo.si_note, kn, 0);
848		break;
849	default:
850		return (EINVAL);
851	}
852
853	return (0);
854}
855