1155324Simp/*-
2155324Simp * Copyright (c) 2005 Olivier Houchard.  All rights reserved.
3213496Scognet * Copyright (c) 2010 Greg Ansley.  All rights reserved.
4155324Simp *
5155324Simp * Redistribution and use in source and binary forms, with or without
6155324Simp * modification, are permitted provided that the following conditions
7155324Simp * are met:
8155324Simp * 1. Redistributions of source code must retain the above copyright
9155324Simp *    notice, this list of conditions and the following disclaimer.
10155324Simp * 2. Redistributions in binary form must reproduce the above copyright
11155324Simp *    notice, this list of conditions and the following disclaimer in the
12155324Simp *    documentation and/or other materials provided with the distribution.
13155324Simp *
14185265Simp * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15185265Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16185265Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17185265Simp * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18185265Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19185265Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20185265Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21185265Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22185265Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23185265Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24185265Simp * SUCH DAMAGE.
25155324Simp */
26155324Simp
27262925Simp#include "opt_platform.h"
28262925Simp
29155324Simp#include <sys/cdefs.h>
30155324Simp__FBSDID("$FreeBSD: releng/11.0/sys/arm/at91/at91.c 298627 2016-04-26 11:53:37Z br $");
31155324Simp
32155324Simp#include <sys/param.h>
33155324Simp#include <sys/systm.h>
34155324Simp#include <sys/bus.h>
35155324Simp#include <sys/kernel.h>
36155324Simp#include <sys/malloc.h>
37155324Simp#include <sys/module.h>
38298627Sbr#include <sys/devmap.h>
39155324Simp
40155324Simp#include <vm/vm.h>
41155324Simp#include <vm/vm_kern.h>
42155324Simp#include <vm/pmap.h>
43155324Simp#include <vm/vm_page.h>
44155324Simp#include <vm/vm_extern.h>
45155324Simp
46271398Sandrew#include <machine/armreg.h>
47155324Simp#define	_ARM32_BUS_DMA_PRIVATE
48155324Simp#include <machine/bus.h>
49155324Simp#include <machine/intr.h>
50155324Simp
51155324Simp#include <arm/at91/at91var.h>
52213496Scognet#include <arm/at91/at91_pmcvar.h>
53213496Scognet#include <arm/at91/at91_aicreg.h>
54155324Simp
55213496Scognetuint32_t at91_master_clock;
56187599Simp
57213496Scognetstruct arm32_dma_range *
58213496Scognetbus_dma_get_range(void)
59213496Scognet{
60213496Scognet
61213496Scognet	return (NULL);
62213496Scognet}
63213496Scognet
64213496Scognetint
65213496Scognetbus_dma_get_range_nb(void)
66213496Scognet{
67213496Scognet	return (0);
68213496Scognet}
69213496Scognet
70262925Simp#ifndef FDT
71262925Simp
72262925Simpstatic struct at91_softc *at91_softc;
73262925Simp
74262925Simpstatic void at91_eoi(void *);
75262925Simp
76155324Simpstatic int
77155324Simpat91_probe(device_t dev)
78155324Simp{
79213496Scognet
80260093Simp	device_set_desc(dev, soc_info.name);
81257370Snwhitehorn	return (BUS_PROBE_NOWILDCARD);
82155324Simp}
83155324Simp
84155324Simpstatic void
85155324Simpat91_identify(driver_t *drv, device_t parent)
86155324Simp{
87155324Simp
88155324Simp	BUS_ADD_CHILD(parent, 0, "atmelarm", 0);
89155324Simp}
90155324Simp
91238390Simpstatic void
92238390Simpat91_cpu_add_builtin_children(device_t dev, const struct cpu_devs *walker)
93238390Simp{
94238390Simp	int i;
95238390Simp
96269960Simp	for (i = 0; walker->name; i++, walker++) {
97238390Simp		at91_add_child(dev, i, walker->name, walker->unit,
98238390Simp		    walker->mem_base, walker->mem_len, walker->irq0,
99238390Simp		    walker->irq1, walker->irq2);
100238390Simp	}
101238390Simp}
102238390Simp
103155324Simpstatic int
104155324Simpat91_attach(device_t dev)
105155324Simp{
106155324Simp	struct at91_softc *sc = device_get_softc(dev);
107155324Simp
108257343Snwhitehorn	arm_post_filter = at91_eoi;
109257343Snwhitehorn
110155324Simp	at91_softc = sc;
111294133Simp	sc->sc_st = arm_base_bs_tag;
112213496Scognet	sc->sc_sh = AT91_BASE;
113238389Simp	sc->sc_aic_sh = AT91_BASE + AT91_SYS_BASE;
114155324Simp	sc->dev = dev;
115213496Scognet
116155324Simp	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
117164432Simp	sc->sc_irq_rman.rm_descr = "AT91 IRQs";
118155324Simp	if (rman_init(&sc->sc_irq_rman) != 0 ||
119155324Simp	    rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
120155324Simp		panic("at91_attach: failed to set up IRQ rman");
121213496Scognet
122213496Scognet	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
123213496Scognet	sc->sc_mem_rman.rm_descr = "AT91 Memory";
124213496Scognet	if (rman_init(&sc->sc_mem_rman) != 0)
125155324Simp		panic("at91_attach: failed to set up memory rman");
126261322Simp	/*
127261322Simp	 * Manage the physical space, defined as being everything that isn't
128261322Simp	 * DRAM.
129261322Simp	 */
130261322Simp	if (rman_manage_region(&sc->sc_mem_rman, 0, PHYSADDR - 1) != 0)
131261322Simp		panic("at91_attach: failed to set up memory rman");
132261322Simp	if (rman_manage_region(&sc->sc_mem_rman, PHYSADDR + (256 << 20),
133261322Simp	    0xfffffffful) != 0)
134261322Simp		panic("at91_attach: failed to set up memory rman");
135155324Simp
136238390Simp        /*
137238390Simp         * Add this device's children...
138238390Simp         */
139238390Simp	at91_cpu_add_builtin_children(dev, soc_info.soc_data->soc_children);
140238398Simp	soc_info.soc_data->soc_clock_init();
141156828Simp
142155324Simp	bus_generic_probe(dev);
143155324Simp	bus_generic_attach(dev);
144271398Sandrew	enable_interrupts(PSR_I | PSR_F);
145155324Simp	return (0);
146155324Simp}
147155324Simp
148155324Simpstatic struct resource *
149155324Simpat91_alloc_resource(device_t dev, device_t child, int type, int *rid,
150294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
151155324Simp{
152155324Simp	struct at91_softc *sc = device_get_softc(dev);
153155324Simp	struct resource_list_entry *rle;
154155324Simp	struct at91_ivar *ivar = device_get_ivars(child);
155155324Simp	struct resource_list *rl = &ivar->resources;
156261322Simp	bus_space_handle_t bsh;
157155324Simp
158155324Simp	if (device_get_parent(child) != dev)
159155324Simp		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
160155324Simp		    type, rid, start, end, count, flags));
161155324Simp
162155324Simp	rle = resource_list_find(rl, type, *rid);
163155324Simp	if (rle == NULL)
164155324Simp		return (NULL);
165155324Simp	if (rle->res)
166155324Simp		panic("Resource rid %d type %d already in use", *rid, type);
167295832Sjhibbits	if (RMAN_IS_DEFAULT_RANGE(start, end)) {
168155324Simp		start = rle->start;
169155324Simp		count = ulmax(count, rle->count);
170155324Simp		end = ulmax(rle->end, start + count - 1);
171155324Simp	}
172155324Simp	switch (type)
173155324Simp	{
174155324Simp	case SYS_RES_IRQ:
175155324Simp		rle->res = rman_reserve_resource(&sc->sc_irq_rman,
176155324Simp		    start, end, count, flags, child);
177155324Simp		break;
178155324Simp	case SYS_RES_MEMORY:
179182805Simp		rle->res = rman_reserve_resource(&sc->sc_mem_rman,
180182805Simp		    start, end, count, flags, child);
181184309Sstas		if (rle->res != NULL) {
182294133Simp			bus_space_map(arm_base_bs_tag, start,
183261322Simp			    rman_get_size(rle->res), 0, &bsh);
184294133Simp			rman_set_bustag(rle->res, arm_base_bs_tag);
185261322Simp			rman_set_bushandle(rle->res, bsh);
186184309Sstas		}
187155324Simp		break;
188155324Simp	}
189155324Simp	if (rle->res) {
190155324Simp		rle->start = rman_get_start(rle->res);
191155324Simp		rle->end = rman_get_end(rle->res);
192155324Simp		rle->count = count;
193157891Simp		rman_set_rid(rle->res, *rid);
194155324Simp	}
195155324Simp	return (rle->res);
196155324Simp}
197155324Simp
198155324Simpstatic struct resource_list *
199155324Simpat91_get_resource_list(device_t dev, device_t child)
200155324Simp{
201155324Simp	struct at91_ivar *ivar;
202155324Simp
203155324Simp	ivar = device_get_ivars(child);
204155324Simp	return (&(ivar->resources));
205155324Simp}
206155324Simp
207155324Simpstatic int
208155324Simpat91_release_resource(device_t dev, device_t child, int type,
209155324Simp    int rid, struct resource *r)
210155324Simp{
211155324Simp	struct resource_list *rl;
212155324Simp	struct resource_list_entry *rle;
213155324Simp
214155324Simp	rl = at91_get_resource_list(dev, child);
215155324Simp	if (rl == NULL)
216155324Simp		return (EINVAL);
217155324Simp	rle = resource_list_find(rl, type, rid);
218155324Simp	if (rle == NULL)
219155324Simp		return (EINVAL);
220155324Simp	rman_release_resource(r);
221155324Simp	rle->res = NULL;
222155324Simp	return (0);
223155324Simp}
224155324Simp
225155324Simpstatic int
226155324Simpat91_setup_intr(device_t dev, device_t child,
227236989Simp    struct resource *ires, int flags, driver_filter_t *filt,
228236989Simp    driver_intr_t *intr, void *arg, void **cookiep)
229155324Simp{
230226832Skevlo	int error;
231161704Scognet
232238348Simp	if (rman_get_start(ires) == AT91_IRQ_SYSTEM && filt == NULL)
233167261Spiso		panic("All system interrupt ISRs must be FILTER");
234226832Skevlo	error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
235226832Skevlo	    filt, intr, arg, cookiep);
236226832Skevlo	if (error)
237226832Skevlo		return (error);
238226832Skevlo
239155324Simp	return (0);
240155324Simp}
241155324Simp
242155324Simpstatic int
243155324Simpat91_teardown_intr(device_t dev, device_t child, struct resource *res,
244155324Simp    void *cookie)
245155324Simp{
246155324Simp	struct at91_softc *sc = device_get_softc(dev);
247155324Simp
248236989Simp	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR,
249155324Simp	    1 << rman_get_start(res));
250155324Simp	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
251155324Simp}
252155324Simp
253155324Simpstatic int
254155324Simpat91_activate_resource(device_t bus, device_t child, int type, int rid,
255155324Simp    struct resource *r)
256155324Simp{
257155324Simp#if 0
258294883Sjhibbits	rman_res_t p;
259155324Simp	int error;
260155324Simp
261155324Simp	if (type == SYS_RES_MEMORY) {
262155324Simp		error = bus_space_map(rman_get_bustag(r),
263155324Simp		    rman_get_bushandle(r), rman_get_size(r), 0, &p);
264236989Simp		if (error)
265155324Simp			return (error);
266155324Simp		rman_set_bushandle(r, p);
267155324Simp	}
268155324Simp#endif
269155324Simp	return (rman_activate_resource(r));
270155324Simp}
271155324Simp
272155324Simpstatic int
273155324Simpat91_print_child(device_t dev, device_t child)
274155324Simp{
275155324Simp	struct at91_ivar *ivars;
276155324Simp	struct resource_list *rl;
277155324Simp	int retval = 0;
278155324Simp
279155324Simp	ivars = device_get_ivars(child);
280155324Simp	rl = &ivars->resources;
281155324Simp
282155324Simp	retval += bus_print_child_header(dev, child);
283155324Simp
284297199Sjhibbits	retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
285297199Sjhibbits	retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
286297199Sjhibbits	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
287155324Simp	if (device_get_flags(dev))
288155324Simp		retval += printf(" flags %#x", device_get_flags(dev));
289155324Simp
290155324Simp	retval += bus_print_child_footer(dev, child);
291155324Simp
292155324Simp	return (retval);
293155324Simp}
294155324Simp
295178366Scognetstatic void
296178366Scognetat91_eoi(void *unused)
297178366Scognet{
298213496Scognet	bus_space_write_4(at91_softc->sc_st, at91_softc->sc_aic_sh,
299178366Scognet	    IC_EOICR, 0);
300178366Scognet}
301178366Scognet
302238334Simpvoid
303238334Simpat91_add_child(device_t dev, int prio, const char *name, int unit,
304238334Simp    bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2)
305238334Simp{
306238334Simp	device_t kid;
307238334Simp	struct at91_ivar *ivar;
308238334Simp
309238334Simp	kid = device_add_child_ordered(dev, prio, name, unit);
310238334Simp	if (kid == NULL) {
311238334Simp	    printf("Can't add child %s%d ordered\n", name, unit);
312238334Simp	    return;
313238334Simp	}
314238334Simp	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
315238334Simp	if (ivar == NULL) {
316238334Simp		device_delete_child(dev, kid);
317238334Simp		printf("Can't add alloc ivar\n");
318238334Simp		return;
319238334Simp	}
320238334Simp	device_set_ivars(kid, ivar);
321238334Simp	resource_list_init(&ivar->resources);
322238334Simp	if (irq0 != -1) {
323238334Simp		bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
324238334Simp		if (irq0 != AT91_IRQ_SYSTEM)
325238334Simp			at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0);
326238334Simp	}
327238334Simp	if (irq1 != 0)
328238334Simp		bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
329238334Simp	if (irq2 != 0)
330238334Simp		bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
331261322Simp	/*
332261322Simp	 * Special case for on-board devices. These have their address
333261322Simp	 * defined relative to AT91_PA_BASE in all the register files we
334261322Simp	 * have. We could change this, but that's a lot of effort which
335261322Simp	 * will be obsoleted when FDT arrives.
336261322Simp	 */
337261322Simp	if (addr != 0 && addr < 0x10000000 && addr >= 0x0f000000)
338261322Simp		addr += AT91_PA_BASE;
339238334Simp	if (addr != 0)
340238334Simp		bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
341238334Simp}
342238334Simp
343155324Simpstatic device_method_t at91_methods[] = {
344155324Simp	DEVMETHOD(device_probe, at91_probe),
345155324Simp	DEVMETHOD(device_attach, at91_attach),
346155324Simp	DEVMETHOD(device_identify, at91_identify),
347155324Simp
348155324Simp	DEVMETHOD(bus_alloc_resource, at91_alloc_resource),
349155324Simp	DEVMETHOD(bus_setup_intr, at91_setup_intr),
350155324Simp	DEVMETHOD(bus_teardown_intr, at91_teardown_intr),
351155324Simp	DEVMETHOD(bus_activate_resource, at91_activate_resource),
352155324Simp	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
353155324Simp	DEVMETHOD(bus_get_resource_list,at91_get_resource_list),
354155324Simp	DEVMETHOD(bus_set_resource,	bus_generic_rl_set_resource),
355155324Simp	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
356155324Simp	DEVMETHOD(bus_release_resource,	at91_release_resource),
357155324Simp	DEVMETHOD(bus_print_child,	at91_print_child),
358155324Simp
359155324Simp	{0, 0},
360155324Simp};
361155324Simp
362155324Simpstatic driver_t at91_driver = {
363155324Simp	"atmelarm",
364155324Simp	at91_methods,
365155324Simp	sizeof(struct at91_softc),
366155324Simp};
367213496Scognet
368155324Simpstatic devclass_t at91_devclass;
369155324Simp
370155324SimpDRIVER_MODULE(atmelarm, nexus, at91_driver, at91_devclass, 0, 0);
371262925Simp#endif
372