1/*-
2 * Copyright (C) 2012 Margarida Gouveia
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/wii/wii_pic.c 249826 2013-04-24 01:36:35Z rpaulo $");
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/module.h>
32#include <sys/bus.h>
33#include <sys/conf.h>
34#include <sys/kernel.h>
35#include <sys/malloc.h>
36#include <sys/rman.h>
37#include <sys/reboot.h>
38
39#include <machine/bus.h>
40#include <machine/platform.h>
41#include <machine/intr_machdep.h>
42#include <machine/resource.h>
43
44#include <powerpc/wii/wii_picreg.h>
45
46#include "pic_if.h"
47
48static int	wiipic_probe(device_t);
49static int	wiipic_attach(device_t);
50static void	wiipic_dispatch(device_t, struct trapframe *);
51static void	wiipic_enable(device_t, unsigned int, unsigned int);
52static void	wiipic_eoi(device_t, unsigned int);
53static void	wiipic_mask(device_t, unsigned int);
54static void	wiipic_unmask(device_t, unsigned int);
55static void	wiipic_intr(void *);
56
57struct wiipic_softc {
58	device_t		 sc_dev;
59	struct resource		*sc_rres;
60	bus_space_tag_t		 sc_bt;
61	bus_space_handle_t	 sc_bh;
62	int			 sc_rrid;
63	int			 sc_irqid;
64	struct resource		*sc_irq;
65	void			*sc_irqctx;
66	int			 sc_vector[WIIPIC_NIRQ];
67};
68
69static device_method_t wiipic_methods[] = {
70	/* Device interface */
71	DEVMETHOD(device_probe,		wiipic_probe),
72	DEVMETHOD(device_attach,	wiipic_attach),
73
74	/* PIC interface */
75	DEVMETHOD(pic_dispatch,		wiipic_dispatch),
76	DEVMETHOD(pic_enable,		wiipic_enable),
77	DEVMETHOD(pic_eoi,		wiipic_eoi),
78	DEVMETHOD(pic_mask,		wiipic_mask),
79	DEVMETHOD(pic_unmask,		wiipic_unmask),
80
81        DEVMETHOD_END
82};
83
84static driver_t wiipic_driver = {
85	"wiipic",
86	wiipic_methods,
87	sizeof(struct wiipic_softc)
88};
89
90static devclass_t wiipic_devclass;
91
92DRIVER_MODULE(wiipic, wiibus, wiipic_driver, wiipic_devclass, 0, 0);
93
94static __inline uint32_t
95wiipic_imr_read(struct wiipic_softc *sc)
96{
97
98	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR));
99}
100
101static __inline void
102wiipic_imr_write(struct wiipic_softc *sc, uint32_t imr)
103{
104
105	bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR, imr);
106}
107
108static __inline uint32_t
109wiipic_icr_read(struct wiipic_softc *sc)
110{
111
112	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR));
113}
114
115static __inline void
116wiipic_icr_write(struct wiipic_softc *sc, uint32_t icr)
117{
118
119	bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR, icr);
120}
121
122static int
123wiipic_probe(device_t dev)
124{
125        device_set_desc(dev, "Nintendo Wii PIC");
126
127        return (BUS_PROBE_NOWILDCARD);
128}
129
130static int
131wiipic_attach(device_t dev)
132{
133	struct wiipic_softc *sc;
134
135	sc = device_get_softc(dev);
136	sc->sc_dev = dev;
137
138	sc->sc_rrid = 0;
139	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
140	    &sc->sc_rrid, RF_ACTIVE);
141	if (sc->sc_rres == NULL) {
142		device_printf(dev, "could not alloc mem resource\n");
143		return (ENXIO);
144	}
145	sc->sc_bt = rman_get_bustag(sc->sc_rres);
146	sc->sc_bh = rman_get_bushandle(sc->sc_rres);
147
148	/* Turn off all interrupts */
149	wiipic_imr_write(sc, 0x00000000);
150	wiipic_icr_write(sc, 0xffffffff);
151
152	powerpc_register_pic(dev, 0, WIIPIC_NIRQ, 0, FALSE);
153
154	/*
155	 * Setup the interrupt handler.
156	 */
157	sc->sc_irqid = 0;
158	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
159	    RF_ACTIVE);
160	if (sc->sc_irq == NULL) {
161		device_printf(dev, "could not alloc IRQ resource\n");
162		return (ENXIO);
163	}
164	bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE,
165	    NULL, wiipic_intr, sc, &sc->sc_irqctx);
166
167	return (0);
168}
169
170static void
171wiipic_dispatch(device_t dev, struct trapframe *tf)
172{
173	struct wiipic_softc *sc;
174	uint32_t irq;
175
176	sc = device_get_softc(dev);
177	irq = wiipic_icr_read(sc) & wiipic_imr_read(sc);
178	if (irq == 0)
179		return;
180	irq = ffs(irq) - 1;
181	KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq));
182	powerpc_dispatch_intr(sc->sc_vector[irq], tf);
183}
184
185static void
186wiipic_enable(device_t dev, unsigned int irq, unsigned int vector)
187{
188	struct wiipic_softc *sc;
189
190	KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq));
191	sc = device_get_softc(dev);
192	sc->sc_vector[irq] = vector;
193	wiipic_unmask(dev, irq);
194}
195
196static void
197wiipic_eoi(device_t dev, unsigned int irq)
198{
199	struct wiipic_softc *sc;
200	uint32_t icr;
201
202	sc = device_get_softc(dev);
203	icr = wiipic_icr_read(sc);
204	icr |= (1 << irq);
205	wiipic_icr_write(sc, icr);
206}
207
208static void
209wiipic_mask(device_t dev, unsigned int irq)
210{
211	struct wiipic_softc *sc;
212	uint32_t imr;
213
214	sc = device_get_softc(dev);
215	imr = wiipic_imr_read(sc);
216	imr &= ~(1 << irq);
217	wiipic_imr_write(sc, imr);
218}
219
220static void
221wiipic_unmask(device_t dev, unsigned int irq)
222{
223	struct wiipic_softc *sc;
224	uint32_t imr;
225
226	sc = device_get_softc(dev);
227	imr = wiipic_imr_read(sc);
228	imr |= (1 << irq);
229	wiipic_imr_write(sc, imr);
230}
231
232/*
233 * Reset button interrupt.
234 */
235static void
236wiipic_intr(void *xsc)
237{
238	struct wiipic_softc *sc;
239
240	sc = (struct wiipic_softc *)xsc;
241	if (wiipic_icr_read(sc) & WIIPIC_RBS)
242		shutdown_nice(RB_AUTOBOOT);
243}
244
245