]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/at91/at91.c
Properly support the GPIO_PIN_PRESET_{LOW,HIGH} options when configuring
[FreeBSD/FreeBSD.git] / sys / arm / at91 / at91.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2005 Olivier Houchard.  All rights reserved.
5  * Copyright (c) 2010 Greg Ansley.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include "opt_platform.h"
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/module.h>
40 #include <sys/devmap.h>
41
42 #include <vm/vm.h>
43 #include <vm/vm_kern.h>
44 #include <vm/pmap.h>
45 #include <vm/vm_page.h>
46 #include <vm/vm_extern.h>
47
48 #include <machine/armreg.h>
49 #define _ARM32_BUS_DMA_PRIVATE
50 #include <machine/bus.h>
51 #include <machine/intr.h>
52
53 #include <arm/at91/at91var.h>
54 #include <arm/at91/at91_pmcvar.h>
55 #include <arm/at91/at91_aicreg.h>
56
57 uint32_t at91_master_clock;
58
59 struct arm32_dma_range *
60 bus_dma_get_range(void)
61 {
62
63         return (NULL);
64 }
65
66 int
67 bus_dma_get_range_nb(void)
68 {
69         return (0);
70 }
71
72 #ifndef FDT
73
74 static struct at91_softc *at91_softc;
75
76 static void at91_eoi(void *);
77
78 static int
79 at91_probe(device_t dev)
80 {
81
82         device_set_desc(dev, soc_info.name);
83         return (BUS_PROBE_NOWILDCARD);
84 }
85
86 static void
87 at91_identify(driver_t *drv, device_t parent)
88 {
89         
90         BUS_ADD_CHILD(parent, 0, "atmelarm", 0);
91 }
92
93 static void
94 at91_cpu_add_builtin_children(device_t dev, const struct cpu_devs *walker)
95 {
96         int i;
97
98         for (i = 0; walker->name; i++, walker++) {
99                 at91_add_child(dev, i, walker->name, walker->unit,
100                     walker->mem_base, walker->mem_len, walker->irq0,
101                     walker->irq1, walker->irq2);
102         }
103 }
104
105 static int
106 at91_attach(device_t dev)
107 {
108         struct at91_softc *sc = device_get_softc(dev);
109
110         arm_post_filter = at91_eoi;
111
112         at91_softc = sc;
113         sc->sc_st = arm_base_bs_tag;
114         sc->sc_sh = AT91_BASE;
115         sc->sc_aic_sh = AT91_BASE + AT91_SYS_BASE;
116         sc->dev = dev;
117
118         sc->sc_irq_rman.rm_type = RMAN_ARRAY;
119         sc->sc_irq_rman.rm_descr = "AT91 IRQs";
120         if (rman_init(&sc->sc_irq_rman) != 0 ||
121             rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
122                 panic("at91_attach: failed to set up IRQ rman");
123
124         sc->sc_mem_rman.rm_type = RMAN_ARRAY;
125         sc->sc_mem_rman.rm_descr = "AT91 Memory";
126         if (rman_init(&sc->sc_mem_rman) != 0)
127                 panic("at91_attach: failed to set up memory rman");
128         /*
129          * Manage the physical space, defined as being everything that isn't
130          * DRAM.
131          */
132         if (rman_manage_region(&sc->sc_mem_rman, 0, PHYSADDR - 1) != 0)
133                 panic("at91_attach: failed to set up memory rman");
134         if (rman_manage_region(&sc->sc_mem_rman, PHYSADDR + (256 << 20),
135             0xfffffffful) != 0)
136                 panic("at91_attach: failed to set up memory rman");
137
138         /*
139          * Add this device's children...
140          */
141         at91_cpu_add_builtin_children(dev, soc_info.soc_data->soc_children);
142         soc_info.soc_data->soc_clock_init();
143
144         bus_generic_probe(dev);
145         bus_generic_attach(dev);
146         enable_interrupts(PSR_I | PSR_F);
147         return (0);
148 }
149
150 static struct resource *
151 at91_alloc_resource(device_t dev, device_t child, int type, int *rid,
152     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
153 {
154         struct at91_softc *sc = device_get_softc(dev);
155         struct resource_list_entry *rle;
156         struct at91_ivar *ivar = device_get_ivars(child);
157         struct resource_list *rl = &ivar->resources;
158         bus_space_handle_t bsh;
159
160         if (device_get_parent(child) != dev)
161                 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
162                     type, rid, start, end, count, flags));
163         
164         rle = resource_list_find(rl, type, *rid);
165         if (rle == NULL)
166                 return (NULL);
167         if (rle->res)
168                 panic("Resource rid %d type %d already in use", *rid, type);
169         if (RMAN_IS_DEFAULT_RANGE(start, end)) {
170                 start = rle->start;
171                 count = ulmax(count, rle->count);
172                 end = ulmax(rle->end, start + count - 1);
173         }
174         switch (type)
175         {
176         case SYS_RES_IRQ:
177                 rle->res = rman_reserve_resource(&sc->sc_irq_rman,
178                     start, end, count, flags, child);
179                 break;
180         case SYS_RES_MEMORY:
181                 rle->res = rman_reserve_resource(&sc->sc_mem_rman,
182                     start, end, count, flags, child);
183                 if (rle->res != NULL) {
184                         bus_space_map(arm_base_bs_tag, start,
185                             rman_get_size(rle->res), 0, &bsh);
186                         rman_set_bustag(rle->res, arm_base_bs_tag);
187                         rman_set_bushandle(rle->res, bsh);
188                 }
189                 break;
190         }
191         if (rle->res) {
192                 rle->start = rman_get_start(rle->res);
193                 rle->end = rman_get_end(rle->res);
194                 rle->count = count;
195                 rman_set_rid(rle->res, *rid);
196         }
197         return (rle->res);
198 }
199
200 static struct resource_list *
201 at91_get_resource_list(device_t dev, device_t child)
202 {
203         struct at91_ivar *ivar;
204
205         ivar = device_get_ivars(child);
206         return (&(ivar->resources));
207 }
208
209 static int
210 at91_release_resource(device_t dev, device_t child, int type,
211     int rid, struct resource *r)
212 {
213         struct resource_list *rl;
214         struct resource_list_entry *rle;
215
216         rl = at91_get_resource_list(dev, child);
217         if (rl == NULL)
218                 return (EINVAL);
219         rle = resource_list_find(rl, type, rid);
220         if (rle == NULL)
221                 return (EINVAL);
222         rman_release_resource(r);
223         rle->res = NULL;
224         return (0);
225 }
226
227 static int
228 at91_setup_intr(device_t dev, device_t child,
229     struct resource *ires, int flags, driver_filter_t *filt,
230     driver_intr_t *intr, void *arg, void **cookiep)
231 {
232         int error;
233
234         if (rman_get_start(ires) == AT91_IRQ_SYSTEM && filt == NULL)
235                 panic("All system interrupt ISRs must be FILTER");
236         error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
237             filt, intr, arg, cookiep);
238         if (error)
239                 return (error);
240
241         return (0);
242 }
243
244 static int
245 at91_teardown_intr(device_t dev, device_t child, struct resource *res,
246     void *cookie)
247 {
248         struct at91_softc *sc = device_get_softc(dev);
249
250         bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR,
251             1 << rman_get_start(res));
252         return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
253 }
254
255 static int
256 at91_activate_resource(device_t bus, device_t child, int type, int rid,
257     struct resource *r)
258 {
259 #if 0
260         rman_res_t p;
261         int error;
262         
263         if (type == SYS_RES_MEMORY) {
264                 error = bus_space_map(rman_get_bustag(r),
265                     rman_get_bushandle(r), rman_get_size(r), 0, &p);
266                 if (error)
267                         return (error);
268                 rman_set_bushandle(r, p);
269         }
270 #endif  
271         return (rman_activate_resource(r));
272 }
273
274 static int
275 at91_print_child(device_t dev, device_t child)
276 {
277         struct at91_ivar *ivars;
278         struct resource_list *rl;
279         int retval = 0;
280
281         ivars = device_get_ivars(child);
282         rl = &ivars->resources;
283
284         retval += bus_print_child_header(dev, child);
285
286         retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
287         retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
288         retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
289         if (device_get_flags(dev))
290                 retval += printf(" flags %#x", device_get_flags(dev));
291
292         retval += bus_print_child_footer(dev, child);
293
294         return (retval);
295 }
296
297 static void
298 at91_eoi(void *unused)
299 {
300         bus_space_write_4(at91_softc->sc_st, at91_softc->sc_aic_sh,
301             IC_EOICR, 0);
302 }
303
304 void
305 at91_add_child(device_t dev, int prio, const char *name, int unit,
306     bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2)
307 {
308         device_t kid;
309         struct at91_ivar *ivar;
310
311         kid = device_add_child_ordered(dev, prio, name, unit);
312         if (kid == NULL) {
313             printf("Can't add child %s%d ordered\n", name, unit);
314             return;
315         }
316         ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
317         if (ivar == NULL) {
318                 device_delete_child(dev, kid);
319                 printf("Can't add alloc ivar\n");
320                 return;
321         }
322         device_set_ivars(kid, ivar);
323         resource_list_init(&ivar->resources);
324         if (irq0 != -1) {
325                 bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
326                 if (irq0 != AT91_IRQ_SYSTEM)
327                         at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0);
328         }
329         if (irq1 != 0)
330                 bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
331         if (irq2 != 0)
332                 bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
333         /*
334          * Special case for on-board devices. These have their address
335          * defined relative to AT91_PA_BASE in all the register files we
336          * have. We could change this, but that's a lot of effort which
337          * will be obsoleted when FDT arrives.
338          */
339         if (addr != 0 && addr < 0x10000000 && addr >= 0x0f000000) 
340                 addr += AT91_PA_BASE;
341         if (addr != 0)
342                 bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
343 }
344
345 static device_method_t at91_methods[] = {
346         DEVMETHOD(device_probe, at91_probe),
347         DEVMETHOD(device_attach, at91_attach),
348         DEVMETHOD(device_identify, at91_identify),
349
350         DEVMETHOD(bus_alloc_resource, at91_alloc_resource),
351         DEVMETHOD(bus_setup_intr, at91_setup_intr),
352         DEVMETHOD(bus_teardown_intr, at91_teardown_intr),
353         DEVMETHOD(bus_activate_resource, at91_activate_resource),
354         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
355         DEVMETHOD(bus_get_resource_list,at91_get_resource_list),
356         DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),
357         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
358         DEVMETHOD(bus_release_resource, at91_release_resource),
359         DEVMETHOD(bus_print_child,      at91_print_child),
360
361         {0, 0},
362 };
363
364 static driver_t at91_driver = {
365         "atmelarm",
366         at91_methods,
367         sizeof(struct at91_softc),
368 };
369
370 static devclass_t at91_devclass;
371
372 DRIVER_MODULE(atmelarm, nexus, at91_driver, at91_devclass, 0, 0);
373 #endif