1239478Sadrian/*-
2239478Sadrian * Copyright (C) 2012 Margarida Gouveia
3239478Sadrian * All rights reserved.
4239478Sadrian *
5239478Sadrian * Redistribution and use in source and binary forms, with or without
6239478Sadrian * modification, are permitted provided that the following conditions
7239478Sadrian * are met:
8239478Sadrian * 1. Redistributions of source code must retain the above copyright
9239478Sadrian *    notice, this list of conditions and the following disclaimer.
10239478Sadrian * 2. Redistributions in binary form must reproduce the above copyright
11239478Sadrian *    notice, this list of conditions and the following disclaimer in the
12239478Sadrian *    documentation and/or other materials provided with the distribution.
13239478Sadrian *
14239478Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15239478Sadrian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16239478Sadrian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17239478Sadrian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18239478Sadrian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19239478Sadrian * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20239478Sadrian * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21239478Sadrian * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22239478Sadrian * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23239478Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24239478Sadrian * SUCH DAMAGE.
25239478Sadrian */
26239478Sadrian#include <sys/cdefs.h>
27239478Sadrian__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/wii/wii_pic.c 249826 2013-04-24 01:36:35Z rpaulo $");
28239478Sadrian
29239478Sadrian#include <sys/param.h>
30239478Sadrian#include <sys/systm.h>
31239478Sadrian#include <sys/module.h>
32239478Sadrian#include <sys/bus.h>
33239478Sadrian#include <sys/conf.h>
34239478Sadrian#include <sys/kernel.h>
35239478Sadrian#include <sys/malloc.h>
36239478Sadrian#include <sys/rman.h>
37249826Srpaulo#include <sys/reboot.h>
38239478Sadrian
39239478Sadrian#include <machine/bus.h>
40239478Sadrian#include <machine/platform.h>
41239478Sadrian#include <machine/intr_machdep.h>
42239478Sadrian#include <machine/resource.h>
43239478Sadrian
44239478Sadrian#include <powerpc/wii/wii_picreg.h>
45239478Sadrian
46239478Sadrian#include "pic_if.h"
47239478Sadrian
48239478Sadrianstatic int	wiipic_probe(device_t);
49239478Sadrianstatic int	wiipic_attach(device_t);
50239478Sadrianstatic void	wiipic_dispatch(device_t, struct trapframe *);
51239478Sadrianstatic void	wiipic_enable(device_t, unsigned int, unsigned int);
52239478Sadrianstatic void	wiipic_eoi(device_t, unsigned int);
53239478Sadrianstatic void	wiipic_mask(device_t, unsigned int);
54239478Sadrianstatic void	wiipic_unmask(device_t, unsigned int);
55249826Srpaulostatic void	wiipic_intr(void *);
56239478Sadrian
57239478Sadrianstruct wiipic_softc {
58239478Sadrian	device_t		 sc_dev;
59239478Sadrian	struct resource		*sc_rres;
60239478Sadrian	bus_space_tag_t		 sc_bt;
61239478Sadrian	bus_space_handle_t	 sc_bh;
62239478Sadrian	int			 sc_rrid;
63249826Srpaulo	int			 sc_irqid;
64249826Srpaulo	struct resource		*sc_irq;
65249826Srpaulo	void			*sc_irqctx;
66239478Sadrian	int			 sc_vector[WIIPIC_NIRQ];
67239478Sadrian};
68239478Sadrian
69239478Sadrianstatic device_method_t wiipic_methods[] = {
70239478Sadrian	/* Device interface */
71239478Sadrian	DEVMETHOD(device_probe,		wiipic_probe),
72239478Sadrian	DEVMETHOD(device_attach,	wiipic_attach),
73239478Sadrian
74239478Sadrian	/* PIC interface */
75239478Sadrian	DEVMETHOD(pic_dispatch,		wiipic_dispatch),
76239478Sadrian	DEVMETHOD(pic_enable,		wiipic_enable),
77239478Sadrian	DEVMETHOD(pic_eoi,		wiipic_eoi),
78239478Sadrian	DEVMETHOD(pic_mask,		wiipic_mask),
79239478Sadrian	DEVMETHOD(pic_unmask,		wiipic_unmask),
80239478Sadrian
81246655Srpaulo        DEVMETHOD_END
82239478Sadrian};
83239478Sadrian
84239478Sadrianstatic driver_t wiipic_driver = {
85239478Sadrian	"wiipic",
86239478Sadrian	wiipic_methods,
87239478Sadrian	sizeof(struct wiipic_softc)
88239478Sadrian};
89239478Sadrian
90239478Sadrianstatic devclass_t wiipic_devclass;
91239478Sadrian
92239478SadrianDRIVER_MODULE(wiipic, wiibus, wiipic_driver, wiipic_devclass, 0, 0);
93239478Sadrian
94239478Sadrianstatic __inline uint32_t
95239478Sadrianwiipic_imr_read(struct wiipic_softc *sc)
96239478Sadrian{
97239478Sadrian
98239478Sadrian	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR));
99239478Sadrian}
100239478Sadrian
101239478Sadrianstatic __inline void
102239478Sadrianwiipic_imr_write(struct wiipic_softc *sc, uint32_t imr)
103239478Sadrian{
104239478Sadrian
105239478Sadrian	bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR, imr);
106239478Sadrian}
107239478Sadrian
108239478Sadrianstatic __inline uint32_t
109239478Sadrianwiipic_icr_read(struct wiipic_softc *sc)
110239478Sadrian{
111239478Sadrian
112239478Sadrian	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR));
113239478Sadrian}
114239478Sadrian
115239478Sadrianstatic __inline void
116239478Sadrianwiipic_icr_write(struct wiipic_softc *sc, uint32_t icr)
117239478Sadrian{
118239478Sadrian
119239478Sadrian	bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR, icr);
120239478Sadrian}
121239478Sadrian
122239478Sadrianstatic int
123239478Sadrianwiipic_probe(device_t dev)
124239478Sadrian{
125239478Sadrian        device_set_desc(dev, "Nintendo Wii PIC");
126239478Sadrian
127239478Sadrian        return (BUS_PROBE_NOWILDCARD);
128239478Sadrian}
129239478Sadrian
130239478Sadrianstatic int
131239478Sadrianwiipic_attach(device_t dev)
132239478Sadrian{
133239478Sadrian	struct wiipic_softc *sc;
134239478Sadrian
135239478Sadrian	sc = device_get_softc(dev);
136239478Sadrian	sc->sc_dev = dev;
137239478Sadrian
138239478Sadrian	sc->sc_rrid = 0;
139239478Sadrian	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
140239478Sadrian	    &sc->sc_rrid, RF_ACTIVE);
141239478Sadrian	if (sc->sc_rres == NULL) {
142239478Sadrian		device_printf(dev, "could not alloc mem resource\n");
143239478Sadrian		return (ENXIO);
144239478Sadrian	}
145239478Sadrian	sc->sc_bt = rman_get_bustag(sc->sc_rres);
146239478Sadrian	sc->sc_bh = rman_get_bushandle(sc->sc_rres);
147239478Sadrian
148239478Sadrian	/* Turn off all interrupts */
149239478Sadrian	wiipic_imr_write(sc, 0x00000000);
150239478Sadrian	wiipic_icr_write(sc, 0xffffffff);
151239478Sadrian
152239478Sadrian	powerpc_register_pic(dev, 0, WIIPIC_NIRQ, 0, FALSE);
153239478Sadrian
154249826Srpaulo	/*
155249826Srpaulo	 * Setup the interrupt handler.
156249826Srpaulo	 */
157249826Srpaulo	sc->sc_irqid = 0;
158249826Srpaulo	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
159249826Srpaulo	    RF_ACTIVE);
160249826Srpaulo	if (sc->sc_irq == NULL) {
161249826Srpaulo		device_printf(dev, "could not alloc IRQ resource\n");
162249826Srpaulo		return (ENXIO);
163249826Srpaulo	}
164249826Srpaulo	bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE,
165249826Srpaulo	    NULL, wiipic_intr, sc, &sc->sc_irqctx);
166249826Srpaulo
167239478Sadrian	return (0);
168239478Sadrian}
169239478Sadrian
170239478Sadrianstatic void
171239478Sadrianwiipic_dispatch(device_t dev, struct trapframe *tf)
172239478Sadrian{
173239478Sadrian	struct wiipic_softc *sc;
174239478Sadrian	uint32_t irq;
175239478Sadrian
176239478Sadrian	sc = device_get_softc(dev);
177249718Srpaulo	irq = wiipic_icr_read(sc) & wiipic_imr_read(sc);
178249718Srpaulo	if (irq == 0)
179249718Srpaulo		return;
180249718Srpaulo	irq = ffs(irq) - 1;
181239478Sadrian	KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq));
182239478Sadrian	powerpc_dispatch_intr(sc->sc_vector[irq], tf);
183239478Sadrian}
184239478Sadrian
185239478Sadrianstatic void
186239478Sadrianwiipic_enable(device_t dev, unsigned int irq, unsigned int vector)
187239478Sadrian{
188239478Sadrian	struct wiipic_softc *sc;
189239478Sadrian
190239478Sadrian	KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq));
191239478Sadrian	sc = device_get_softc(dev);
192239478Sadrian	sc->sc_vector[irq] = vector;
193239478Sadrian	wiipic_unmask(dev, irq);
194239478Sadrian}
195239478Sadrian
196239478Sadrianstatic void
197239478Sadrianwiipic_eoi(device_t dev, unsigned int irq)
198239478Sadrian{
199239478Sadrian	struct wiipic_softc *sc;
200239478Sadrian	uint32_t icr;
201239478Sadrian
202239478Sadrian	sc = device_get_softc(dev);
203239478Sadrian	icr = wiipic_icr_read(sc);
204239478Sadrian	icr |= (1 << irq);
205239478Sadrian	wiipic_icr_write(sc, icr);
206239478Sadrian}
207239478Sadrian
208239478Sadrianstatic void
209239478Sadrianwiipic_mask(device_t dev, unsigned int irq)
210239478Sadrian{
211239478Sadrian	struct wiipic_softc *sc;
212239478Sadrian	uint32_t imr;
213239478Sadrian
214239478Sadrian	sc = device_get_softc(dev);
215239478Sadrian	imr = wiipic_imr_read(sc);
216239478Sadrian	imr &= ~(1 << irq);
217239478Sadrian	wiipic_imr_write(sc, imr);
218239478Sadrian}
219239478Sadrian
220239478Sadrianstatic void
221239478Sadrianwiipic_unmask(device_t dev, unsigned int irq)
222239478Sadrian{
223239478Sadrian	struct wiipic_softc *sc;
224239478Sadrian	uint32_t imr;
225239478Sadrian
226239478Sadrian	sc = device_get_softc(dev);
227239478Sadrian	imr = wiipic_imr_read(sc);
228239478Sadrian	imr |= (1 << irq);
229239478Sadrian	wiipic_imr_write(sc, imr);
230239478Sadrian}
231249826Srpaulo
232249826Srpaulo/*
233249826Srpaulo * Reset button interrupt.
234249826Srpaulo */
235249826Srpaulostatic void
236249826Srpaulowiipic_intr(void *xsc)
237249826Srpaulo{
238249826Srpaulo	struct wiipic_softc *sc;
239249826Srpaulo
240249826Srpaulo	sc = (struct wiipic_softc *)xsc;
241249826Srpaulo	if (wiipic_icr_read(sc) & WIIPIC_RBS)
242249826Srpaulo		shutdown_nice(RB_AUTOBOOT);
243249826Srpaulo}
244249826Srpaulo
245