1244195Sgonzo/*-
2244195Sgonzo * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@bluezbox.com>
3244195Sgonzo * All rights reserved.
4244195Sgonzo *
5244195Sgonzo * Redistribution and use in source and binary forms, with or without
6244195Sgonzo * modification, are permitted provided that the following conditions
7244195Sgonzo * are met:
8244195Sgonzo * 1. Redistributions of source code must retain the above copyright
9244195Sgonzo *    notice, this list of conditions and the following disclaimer.
10244195Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11244195Sgonzo *    notice, this list of conditions and the following disclaimer in the
12244195Sgonzo *    documentation and/or other materials provided with the distribution.
13244195Sgonzo *
14244195Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15244195Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16244195Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17244195Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18244195Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19244195Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20244195Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21244195Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22244195Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23244195Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24244195Sgonzo * SUCH DAMAGE.
25244195Sgonzo */
26244195Sgonzo
27244195Sgonzo
28244195Sgonzo#include <sys/cdefs.h>
29244195Sgonzo__FBSDID("$FreeBSD$");
30244195Sgonzo
31244195Sgonzo#include <sys/param.h>
32244195Sgonzo#include <sys/systm.h>
33244195Sgonzo#include <sys/bus.h>
34244195Sgonzo#include <sys/kernel.h>
35244195Sgonzo#include <sys/ktr.h>
36244195Sgonzo#include <sys/module.h>
37244195Sgonzo#include <sys/rman.h>
38244195Sgonzo#include <machine/bus.h>
39244195Sgonzo#include <machine/intr.h>
40244195Sgonzo
41244195Sgonzo#include <dev/fdt/fdt_common.h>
42244195Sgonzo#include <dev/ofw/openfirm.h>
43244195Sgonzo#include <dev/ofw/ofw_bus.h>
44244195Sgonzo#include <dev/ofw/ofw_bus_subr.h>
45244195Sgonzo
46244195Sgonzo#ifdef  DEBUG
47244195Sgonzo#define dprintf(fmt, args...) printf(fmt, ##args)
48244195Sgonzo#else
49244195Sgonzo#define dprintf(fmt, args...)
50244195Sgonzo#endif
51244195Sgonzo
52244195Sgonzo#define	VICIRQSTATUS	0x000
53244195Sgonzo#define	VICFIQSTATUS	0x004
54244195Sgonzo#define	VICRAWINTR	0x008
55244195Sgonzo#define	VICINTSELECT	0x00C
56244195Sgonzo#define	VICINTENABLE	0x010
57244195Sgonzo#define	VICINTENCLEAR	0x014
58244195Sgonzo#define	VICSOFTINT	0x018
59244195Sgonzo#define	VICSOFTINTCLEAR	0x01C
60244195Sgonzo#define	VICPROTECTION	0x020
61244195Sgonzo#define	VICPERIPHID	0xFE0
62244195Sgonzo#define	VICPRIMECELLID	0xFF0
63244195Sgonzo
64244195Sgonzo#define	VIC_NIRQS	32
65244195Sgonzo
66244195Sgonzostruct pl190_intc_softc {
67244195Sgonzo	device_t		sc_dev;
68244195Sgonzo	struct resource *	intc_res;
69244195Sgonzo};
70244195Sgonzo
71244195Sgonzostatic struct pl190_intc_softc *pl190_intc_sc = NULL;
72244195Sgonzo
73244195Sgonzo#define	intc_vic_read_4(reg)		\
74244195Sgonzo    bus_read_4(pl190_intc_sc->intc_res, (reg))
75244195Sgonzo#define	intc_vic_write_4(reg, val)		\
76244195Sgonzo    bus_write_4(pl190_intc_sc->intc_res, (reg), (val))
77244195Sgonzo
78244195Sgonzostatic int
79244195Sgonzopl190_intc_probe(device_t dev)
80244195Sgonzo{
81266152Sian
82266152Sian	if (!ofw_bus_status_okay(dev))
83266152Sian		return (ENXIO);
84266152Sian
85244195Sgonzo	if (!ofw_bus_is_compatible(dev, "arm,versatile-vic"))
86244195Sgonzo		return (ENXIO);
87244195Sgonzo	device_set_desc(dev, "ARM PL190 VIC");
88244195Sgonzo	return (BUS_PROBE_DEFAULT);
89244195Sgonzo}
90244195Sgonzo
91244195Sgonzostatic int
92244195Sgonzopl190_intc_attach(device_t dev)
93244195Sgonzo{
94244195Sgonzo	struct		pl190_intc_softc *sc = device_get_softc(dev);
95244195Sgonzo	uint32_t	id;
96244195Sgonzo	int		i, rid;
97244195Sgonzo
98244195Sgonzo	sc->sc_dev = dev;
99244195Sgonzo
100244195Sgonzo	if (pl190_intc_sc)
101244195Sgonzo		return (ENXIO);
102244195Sgonzo
103244195Sgonzo	/* Request memory resources */
104244195Sgonzo	rid = 0;
105244195Sgonzo	sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
106244195Sgonzo	    RF_ACTIVE);
107244195Sgonzo	if (sc->intc_res == NULL) {
108244195Sgonzo		device_printf(dev, "Error: could not allocate memory resources\n");
109244195Sgonzo		return (ENXIO);
110244195Sgonzo	}
111244195Sgonzo
112244195Sgonzo	pl190_intc_sc = sc;
113244195Sgonzo	/*
114244195Sgonzo	 * All interrupts should use IRQ line
115244195Sgonzo	 */
116244195Sgonzo	intc_vic_write_4(VICINTSELECT, 0x00000000);
117244195Sgonzo	/* Disable all interrupts */
118244195Sgonzo	intc_vic_write_4(VICINTENCLEAR, 0xffffffff);
119244195Sgonzo	/* Enable INT31, SIC IRQ */
120261455Seadler	intc_vic_write_4(VICINTENABLE, (1U << 31));
121244195Sgonzo
122244195Sgonzo	id = 0;
123244195Sgonzo	for (i = 3; i >= 0; i--) {
124244195Sgonzo		id = (id << 8) |
125244195Sgonzo		     (intc_vic_read_4(VICPERIPHID + i*4) & 0xff);
126244195Sgonzo	}
127244195Sgonzo
128244195Sgonzo	device_printf(dev, "Peripheral ID: %08x\n", id);
129244195Sgonzo
130244195Sgonzo	id = 0;
131244195Sgonzo	for (i = 3; i >= 0; i--) {
132244195Sgonzo		id = (id << 8) |
133244195Sgonzo		     (intc_vic_read_4(VICPRIMECELLID + i*4) & 0xff);
134244195Sgonzo	}
135244195Sgonzo
136244195Sgonzo	device_printf(dev, "PrimeCell ID: %08x\n", id);
137244195Sgonzo
138244195Sgonzo	return (0);
139244195Sgonzo}
140244195Sgonzo
141244195Sgonzostatic device_method_t pl190_intc_methods[] = {
142244195Sgonzo	DEVMETHOD(device_probe,		pl190_intc_probe),
143244195Sgonzo	DEVMETHOD(device_attach,	pl190_intc_attach),
144244195Sgonzo	{ 0, 0 }
145244195Sgonzo};
146244195Sgonzo
147244195Sgonzostatic driver_t pl190_intc_driver = {
148244195Sgonzo	"intc",
149244195Sgonzo	pl190_intc_methods,
150244195Sgonzo	sizeof(struct pl190_intc_softc),
151244195Sgonzo};
152244195Sgonzo
153244195Sgonzostatic devclass_t pl190_intc_devclass;
154244195Sgonzo
155270075SianEARLY_DRIVER_MODULE(intc, simplebus, pl190_intc_driver, pl190_intc_devclass,
156270075Sian    0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
157244195Sgonzo
158244195Sgonzoint
159244195Sgonzoarm_get_next_irq(int last_irq)
160244195Sgonzo{
161244195Sgonzo	uint32_t pending;
162244195Sgonzo	int32_t irq = last_irq + 1;
163244195Sgonzo
164244195Sgonzo	/* Sanity check */
165244195Sgonzo	if (irq < 0)
166244195Sgonzo		irq = 0;
167244195Sgonzo
168244195Sgonzo	pending = intc_vic_read_4(VICIRQSTATUS);
169244195Sgonzo	while (irq < VIC_NIRQS) {
170244195Sgonzo		if (pending & (1 << irq))
171244195Sgonzo			return (irq);
172244195Sgonzo		irq++;
173244195Sgonzo	}
174244195Sgonzo
175244195Sgonzo	return (-1);
176244195Sgonzo}
177244195Sgonzo
178244195Sgonzovoid
179244195Sgonzoarm_mask_irq(uintptr_t nb)
180244195Sgonzo{
181244195Sgonzo
182244195Sgonzo	dprintf("%s: %d\n", __func__, nb);
183244195Sgonzo	intc_vic_write_4(VICINTENCLEAR, (1 << nb));
184244195Sgonzo}
185244195Sgonzo
186244195Sgonzovoid
187244195Sgonzoarm_unmask_irq(uintptr_t nb)
188244195Sgonzo{
189244195Sgonzo
190244195Sgonzo	dprintf("%s: %d\n", __func__, nb);
191244195Sgonzo	intc_vic_write_4(VICINTENABLE, (1 << nb));
192244195Sgonzo}
193