The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/at91/at91.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2005 Olivier Houchard.  All rights reserved.
    3  * Copyright (c) 2010 Greg Ansley.  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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, 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 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/kernel.h>
   34 #include <sys/malloc.h>
   35 #include <sys/module.h>
   36 
   37 #include <vm/vm.h>
   38 #include <vm/vm_kern.h>
   39 #include <vm/pmap.h>
   40 #include <vm/vm_page.h>
   41 #include <vm/vm_extern.h>
   42 
   43 #define _ARM32_BUS_DMA_PRIVATE
   44 #include <machine/bus.h>
   45 #include <machine/intr.h>
   46 
   47 #include <arm/at91/at91var.h>
   48 #include <arm/at91/at91_pmcvar.h>
   49 #include <arm/at91/at91_aicreg.h>
   50 
   51 static struct at91_softc *at91_softc;
   52 
   53 static void at91_eoi(void *);
   54 
   55 extern const struct pmap_devmap at91_devmap[];
   56 
   57 uint32_t at91_chip_id;
   58 
   59 #ifdef AT91C_MASTER_CLOCK
   60 uint32_t at91_master_clock = AT91C_MASTER_CLOCK;
   61 #else
   62 uint32_t at91_master_clock;
   63 #endif
   64 
   65 static int
   66 at91_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags,
   67     bus_space_handle_t *bshp)
   68 {
   69         vm_paddr_t pa, endpa;
   70 
   71         pa = trunc_page(bpa);
   72         if (pa >= 0xfff00000) {
   73                 *bshp = pa - 0xf0000000 + 0xd0000000;
   74                 return (0);
   75         }
   76         if (pa >= 0xdff00000)
   77                 return (0);
   78         endpa = round_page(bpa + size);
   79 
   80         *bshp = (vm_offset_t)pmap_mapdev(pa, endpa - pa);
   81                        
   82         return (0);
   83 }
   84 
   85 static void
   86 at91_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size)
   87 {
   88         vm_offset_t va, endva;
   89 
   90         va = trunc_page((vm_offset_t)t);
   91         endva = va + round_page(size);
   92 
   93         /* Free the kernel virtual mapping. */
   94         kmem_free(kernel_map, va, endva - va);
   95 }
   96 
   97 static int
   98 at91_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset,
   99     bus_size_t size, bus_space_handle_t *nbshp)
  100 {
  101 
  102         *nbshp = bsh + offset;
  103         return (0);
  104 }
  105 
  106 static void
  107 at91_barrier(void *t, bus_space_handle_t bsh, bus_size_t size, bus_size_t b, 
  108     int a)
  109 {
  110 }
  111 
  112 struct arm32_dma_range *
  113 bus_dma_get_range(void)
  114 {
  115 
  116         return (NULL);
  117 }
  118 
  119 int
  120 bus_dma_get_range_nb(void)
  121 {
  122         return (0);
  123 }
  124 
  125 bs_protos(generic);
  126 bs_protos(generic_armv4);
  127 
  128 struct bus_space at91_bs_tag = {
  129         /* cookie */
  130         (void *) 0,
  131 
  132         /* mapping/unmapping */
  133         at91_bs_map,
  134         at91_bs_unmap,
  135         at91_bs_subregion,
  136 
  137         /* allocation/deallocation */
  138         NULL,
  139         NULL,
  140 
  141         /* barrier */
  142         at91_barrier,
  143 
  144         /* read (single) */
  145         generic_bs_r_1,
  146         generic_armv4_bs_r_2,
  147         generic_bs_r_4,
  148         NULL,
  149 
  150         /* read multiple */
  151         generic_bs_rm_1,
  152         generic_armv4_bs_rm_2,
  153         generic_bs_rm_4,
  154         NULL,
  155 
  156         /* read region */
  157         generic_bs_rr_1,
  158         generic_armv4_bs_rr_2,
  159         generic_bs_rr_4,
  160         NULL,
  161 
  162         /* write (single) */
  163         generic_bs_w_1,
  164         generic_armv4_bs_w_2,
  165         generic_bs_w_4,
  166         NULL,
  167 
  168         /* write multiple */
  169         generic_bs_wm_1,
  170         generic_armv4_bs_wm_2,
  171         generic_bs_wm_4,
  172         NULL,
  173 
  174         /* write region */
  175         NULL,
  176         generic_armv4_bs_wr_2,
  177         generic_bs_wr_4,
  178         NULL,
  179 
  180         /* set multiple */
  181         NULL,
  182         NULL,
  183         NULL,
  184         NULL,
  185 
  186         /* set region */
  187         NULL,
  188         generic_armv4_bs_sr_2,
  189         generic_bs_sr_4,
  190         NULL,
  191 
  192         /* copy */
  193         NULL,
  194         generic_armv4_bs_c_2,
  195         NULL,
  196         NULL,
  197 
  198         /* read (single) stream */
  199         generic_bs_r_1,
  200         generic_armv4_bs_r_2,
  201         generic_bs_r_4,
  202         NULL,
  203 
  204         /* read multiple stream */
  205         generic_bs_rm_1,
  206         generic_armv4_bs_rm_2,
  207         generic_bs_rm_4,
  208         NULL,
  209 
  210         /* read region stream */
  211         generic_bs_rr_1,
  212         generic_armv4_bs_rr_2,
  213         generic_bs_rr_4,
  214         NULL,
  215 
  216         /* write (single) stream */
  217         generic_bs_w_1,
  218         generic_armv4_bs_w_2,
  219         generic_bs_w_4,
  220         NULL,
  221 
  222         /* write multiple stream */
  223         generic_bs_wm_1,
  224         generic_armv4_bs_wm_2,
  225         generic_bs_wm_4,
  226         NULL,
  227 
  228         /* write region stream */
  229         NULL,
  230         generic_armv4_bs_wr_2,
  231         generic_bs_wr_4,
  232         NULL,
  233 };
  234 
  235 static int
  236 at91_probe(device_t dev)
  237 {
  238 
  239         device_set_desc(dev, "AT91 device bus");
  240         arm_post_filter = at91_eoi;
  241         return (0);
  242 }
  243 
  244 static void
  245 at91_identify(driver_t *drv, device_t parent)
  246 {
  247         
  248         BUS_ADD_CHILD(parent, 0, "atmelarm", 0);
  249 }
  250 
  251 static int
  252 at91_attach(device_t dev)
  253 {
  254         struct at91_softc *sc = device_get_softc(dev);
  255         const struct pmap_devmap *pdevmap;
  256 
  257         at91_softc = sc;
  258         sc->sc_st = &at91_bs_tag;
  259         sc->sc_sh = AT91_BASE;
  260         sc->dev = dev;
  261 
  262         sc->sc_irq_rman.rm_type = RMAN_ARRAY;
  263         sc->sc_irq_rman.rm_descr = "AT91 IRQs";
  264         if (rman_init(&sc->sc_irq_rman) != 0 ||
  265             rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
  266                 panic("at91_attach: failed to set up IRQ rman");
  267 
  268         sc->sc_mem_rman.rm_type = RMAN_ARRAY;
  269         sc->sc_mem_rman.rm_descr = "AT91 Memory";
  270         if (rman_init(&sc->sc_mem_rman) != 0)
  271                 panic("at91_attach: failed to set up memory rman");
  272         for ( pdevmap = at91_devmap; pdevmap->pd_va != 0; pdevmap++) {
  273                 if (rman_manage_region(&sc->sc_mem_rman, pdevmap->pd_va,
  274                     pdevmap->pd_va + pdevmap->pd_size - 1) != 0)
  275                         panic("at91_attach: failed to set up memory rman");
  276         }
  277 
  278 
  279         /* Our device list will be added automatically by the cpu device
  280          * e.g. at91rm9200.c when it is identified. To ensure that the
  281          * CPU and PMC are attached first any other "identified" devices 
  282          * call BUS_ADD_CHILD(9) with an "order" of at least 2. */
  283 
  284         bus_generic_probe(dev);
  285         bus_generic_attach(dev);
  286         enable_interrupts(I32_bit | F32_bit);
  287         return (0);
  288 }
  289 
  290 static struct resource *
  291 at91_alloc_resource(device_t dev, device_t child, int type, int *rid,
  292     u_long start, u_long end, u_long count, u_int flags)
  293 {
  294         struct at91_softc *sc = device_get_softc(dev);
  295         struct resource_list_entry *rle;
  296         struct at91_ivar *ivar = device_get_ivars(child);
  297         struct resource_list *rl = &ivar->resources;
  298 
  299         if (device_get_parent(child) != dev)
  300                 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
  301                     type, rid, start, end, count, flags));
  302         
  303         rle = resource_list_find(rl, type, *rid);
  304         if (rle == NULL)
  305                 return (NULL);
  306         if (rle->res)
  307                 panic("Resource rid %d type %d already in use", *rid, type);
  308         if (start == 0UL && end == ~0UL) {
  309                 start = rle->start;
  310                 count = ulmax(count, rle->count);
  311                 end = ulmax(rle->end, start + count - 1);
  312         }
  313         switch (type)
  314         {
  315         case SYS_RES_IRQ:
  316                 rle->res = rman_reserve_resource(&sc->sc_irq_rman,
  317                     start, end, count, flags, child);
  318                 break;
  319         case SYS_RES_MEMORY:
  320                 rle->res = rman_reserve_resource(&sc->sc_mem_rman,
  321                     start, end, count, flags, child);
  322                 if (rle->res != NULL) {
  323                         rman_set_bustag(rle->res, &at91_bs_tag);
  324                         rman_set_bushandle(rle->res, start);
  325                 }
  326                 break;
  327         }
  328         if (rle->res) {
  329                 rle->start = rman_get_start(rle->res);
  330                 rle->end = rman_get_end(rle->res);
  331                 rle->count = count;
  332                 rman_set_rid(rle->res, *rid);
  333         }
  334         return (rle->res);
  335 }
  336 
  337 static struct resource_list *
  338 at91_get_resource_list(device_t dev, device_t child)
  339 {
  340         struct at91_ivar *ivar;
  341 
  342         ivar = device_get_ivars(child);
  343         return (&(ivar->resources));
  344 }
  345 
  346 static int
  347 at91_release_resource(device_t dev, device_t child, int type,
  348     int rid, struct resource *r)
  349 {
  350         struct resource_list *rl;
  351         struct resource_list_entry *rle;
  352 
  353         rl = at91_get_resource_list(dev, child);
  354         if (rl == NULL)
  355                 return (EINVAL);
  356         rle = resource_list_find(rl, type, rid);
  357         if (rle == NULL)
  358                 return (EINVAL);
  359         rman_release_resource(r);
  360         rle->res = NULL;
  361         return (0);
  362 }
  363 
  364 static int
  365 at91_setup_intr(device_t dev, device_t child,
  366     struct resource *ires, int flags, driver_filter_t *filt, 
  367     driver_intr_t *intr, void *arg, void **cookiep)    
  368 {
  369         struct at91_softc *sc = device_get_softc(dev);
  370 
  371         if (rman_get_start(ires) == sc->sc_irq_system && filt == NULL)
  372                 panic("All system interrupt ISRs must be FILTER");
  373         BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, 
  374             intr, arg, cookiep);
  375         bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IECR,
  376             1 << rman_get_start(ires));
  377         return (0);
  378 }
  379 
  380 static int
  381 at91_teardown_intr(device_t dev, device_t child, struct resource *res,
  382     void *cookie)
  383 {
  384         struct at91_softc *sc = device_get_softc(dev);
  385 
  386         bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 
  387             1 << rman_get_start(res));
  388         return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
  389 }
  390 
  391 static int
  392 at91_activate_resource(device_t bus, device_t child, int type, int rid,
  393     struct resource *r)
  394 {
  395 #if 0
  396         u_long p;
  397         int error;
  398         
  399         if (type == SYS_RES_MEMORY) {
  400                 error = bus_space_map(rman_get_bustag(r),
  401                     rman_get_bushandle(r), rman_get_size(r), 0, &p);
  402                 if (error) 
  403                         return (error);
  404                 rman_set_bushandle(r, p);
  405         }
  406 #endif  
  407         return (rman_activate_resource(r));
  408 }
  409 
  410 static int
  411 at91_print_child(device_t dev, device_t child)
  412 {
  413         struct at91_ivar *ivars;
  414         struct resource_list *rl;
  415         int retval = 0;
  416 
  417         ivars = device_get_ivars(child);
  418         rl = &ivars->resources;
  419 
  420         retval += bus_print_child_header(dev, child);
  421 
  422         retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
  423         retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
  424         retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
  425         if (device_get_flags(dev))
  426                 retval += printf(" flags %#x", device_get_flags(dev));
  427 
  428         retval += bus_print_child_footer(dev, child);
  429 
  430         return (retval);
  431 }
  432 
  433 void
  434 arm_mask_irq(uintptr_t nb)
  435 {
  436         
  437         bus_space_write_4(at91_softc->sc_st, 
  438             at91_softc->sc_aic_sh, IC_IDCR, 1 << nb);
  439 }
  440 
  441 int
  442 arm_get_next_irq(int last __unused)
  443 {
  444         int status;
  445         int irq;
  446         
  447         irq = bus_space_read_4(at91_softc->sc_st,
  448             at91_softc->sc_aic_sh, IC_IVR);
  449         status = bus_space_read_4(at91_softc->sc_st,
  450             at91_softc->sc_aic_sh, IC_ISR);
  451         if (status == 0) {
  452                 bus_space_write_4(at91_softc->sc_st,
  453                     at91_softc->sc_aic_sh, IC_EOICR, 1);
  454                 return (-1);
  455         }
  456         return (irq);
  457 }
  458 
  459 void
  460 arm_unmask_irq(uintptr_t nb)
  461 {
  462         
  463         bus_space_write_4(at91_softc->sc_st, 
  464         at91_softc->sc_aic_sh, IC_IECR, 1 << nb);
  465         bus_space_write_4(at91_softc->sc_st, at91_softc->sc_aic_sh,
  466             IC_EOICR, 0);
  467 }
  468 
  469 static void
  470 at91_eoi(void *unused)
  471 {
  472         bus_space_write_4(at91_softc->sc_st, at91_softc->sc_aic_sh,
  473             IC_EOICR, 0);
  474 }
  475 
  476 static device_method_t at91_methods[] = {
  477         DEVMETHOD(device_probe, at91_probe),
  478         DEVMETHOD(device_attach, at91_attach),
  479         DEVMETHOD(device_identify, at91_identify),
  480 
  481         DEVMETHOD(bus_alloc_resource, at91_alloc_resource),
  482         DEVMETHOD(bus_setup_intr, at91_setup_intr),
  483         DEVMETHOD(bus_teardown_intr, at91_teardown_intr),
  484         DEVMETHOD(bus_activate_resource, at91_activate_resource),
  485         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
  486         DEVMETHOD(bus_get_resource_list,at91_get_resource_list),
  487         DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),
  488         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
  489         DEVMETHOD(bus_release_resource, at91_release_resource),
  490         DEVMETHOD(bus_print_child,      at91_print_child),
  491 
  492         {0, 0},
  493 };
  494 
  495 static driver_t at91_driver = {
  496         "atmelarm",
  497         at91_methods,
  498         sizeof(struct at91_softc),
  499 };
  500 
  501 static devclass_t at91_devclass;
  502 
  503 DRIVER_MODULE(atmelarm, nexus, at91_driver, at91_devclass, 0, 0);

Cache object: 17a5a6a48031db1541d971f9999a811a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.