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/xscale/i80321/i80321_aau.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  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   23  */
   24 
   25 #include <sys/cdefs.h>
   26 __FBSDID("$FreeBSD$");
   27 
   28 #include <sys/param.h>
   29 #include <sys/systm.h>
   30 #include <sys/bus.h>
   31 #include <sys/kernel.h>
   32 #include <sys/module.h>
   33 #include <sys/malloc.h>
   34 #include <sys/rman.h>
   35 #include <sys/lock.h>
   36 #include <sys/mutex.h>
   37 #include <sys/proc.h>
   38 
   39 #include <vm/vm.h>
   40 #include <vm/pmap.h>
   41 #include <vm/vm_map.h>
   42 #include <machine/bus.h>
   43 #include <machine/cpu.h>
   44 #include <machine/md_var.h>
   45 
   46 #include <arm/xscale/i80321/i80321reg.h>
   47 #include <arm/xscale/i80321/i80321var.h>
   48 #include <arm/xscale/i80321/iq80321reg.h>
   49 #include <arm/xscale/i80321/iq80321var.h>
   50 #include <arm/xscale/i80321/i80321_intr.h>
   51 
   52 typedef struct i80321_aaudesc_s {
   53         vm_paddr_t next_desc;
   54         uint32_t sar[4];
   55         vm_paddr_t local_addr;
   56         vm_size_t count;
   57         uint32_t descr_ctrl;
   58 } __packed      i80321_aaudesc_t;
   59 
   60 typedef struct i80321_aauring_s {
   61         i80321_aaudesc_t *desc;
   62         vm_paddr_t phys_addr;
   63         bus_dmamap_t map;
   64 } i80321_aauring_t;
   65 
   66 #define AAU_RING_SIZE 64
   67 
   68 struct i80321_aau_softc {
   69         bus_space_tag_t sc_st;
   70         bus_space_handle_t sc_aau_sh;
   71         bus_dma_tag_t dmatag;
   72         i80321_aauring_t aauring[AAU_RING_SIZE];
   73         int flags;
   74 #define BUSY    0x1
   75         int unit;
   76         struct mtx mtx;
   77 };
   78 
   79 static int
   80 i80321_aau_probe(device_t dev)
   81 {
   82         device_set_desc(dev, "I80321 AAU");
   83         return (0);
   84 }
   85 
   86 static struct i80321_aau_softc *aau_softc;
   87 
   88 static void
   89 i80321_mapphys(void *arg, bus_dma_segment_t *segs, int nseg, int error)
   90 {
   91         vm_paddr_t *addr = (vm_paddr_t *)arg;
   92 
   93         *addr = segs->ds_addr;
   94 }
   95 
   96 #define AAU_REG_WRITE(softc, reg, val) \
   97     bus_space_write_4((softc)->sc_st, (softc)->sc_aau_sh, \
   98         (reg), (val))
   99 #define AAU_REG_READ(softc, reg) \
  100     bus_space_read_4((softc)->sc_st, (softc)->sc_aau_sh, \
  101         (reg))
  102 
  103 static int aau_bzero(void *, int, int);
  104 
  105 static int
  106 i80321_aau_attach(device_t dev)
  107 {
  108         struct i80321_aau_softc *softc = device_get_softc(dev);
  109         struct i80321_softc *sc = device_get_softc(device_get_parent(dev));
  110         struct i80321_aaudesc_s *aaudescs;
  111 
  112         mtx_init(&softc->mtx, "AAU mtx", NULL, MTX_SPIN);
  113         softc->sc_st = sc->sc_st;
  114         if (bus_space_subregion(softc->sc_st, sc->sc_sh, VERDE_AAU_BASE, 
  115             VERDE_AAU_SIZE, &softc->sc_aau_sh) != 0)
  116                 panic("%s: unable to subregion AAU registers",
  117                     device_get_name(dev));
  118         if (bus_dma_tag_create(NULL, sizeof(i80321_aaudesc_t), 0,
  119             BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 
  120             AAU_RING_SIZE * sizeof(i80321_aaudesc_t),
  121             1, sizeof(i80321_aaudesc_t), BUS_DMA_ALLOCNOW, busdma_lock_mutex, 
  122             &Giant, &softc->dmatag))
  123                 panic("Couldn't create a dma tag");
  124         if (bus_dmamem_alloc(softc->dmatag, (void **)&aaudescs,
  125             BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &softc->aauring[0].map))
  126                 panic("Couldn't alloc dma memory");
  127 
  128         for (int i = 0; i < AAU_RING_SIZE; i++) {
  129                 if (i > 0)
  130                         if (bus_dmamap_create(softc->dmatag, 0,
  131                             &softc->aauring[i].map))
  132                                 panic("Couldn't create dma map");
  133                 softc->aauring[i].desc = &aaudescs[i];
  134                 bus_dmamap_load(softc->dmatag, softc->aauring[i].map,
  135                     softc->aauring[i].desc, sizeof(i80321_aaudesc_t),
  136                     i80321_mapphys, &softc->aauring[i].phys_addr, 0);
  137                 bzero(softc->aauring[i].desc, sizeof(i80321_aaudesc_t));
  138         }
  139         aau_softc = softc;
  140         _arm_bzero = aau_bzero;
  141         _min_bzero_size = 1024;
  142         return (0);
  143 }
  144 
  145 static __inline void
  146 test_virt_addr(void *addr, int len)
  147 {
  148         int to_nextpage;
  149 
  150         while (len > 0) {
  151                 *(char *)addr = 0;
  152                 to_nextpage = ((vm_offset_t)addr & ~PAGE_MASK) +
  153                     PAGE_SIZE - (vm_offset_t)addr;
  154                 if (to_nextpage >= len)
  155                         break;
  156                 len -= to_nextpage;
  157                 addr = (void *)((vm_offset_t)addr + to_nextpage);
  158         }
  159 }
  160 
  161 static int
  162 aau_bzero(void *dst, int len, int flags)
  163 {
  164         struct i80321_aau_softc *sc = aau_softc;
  165         i80321_aaudesc_t *desc;
  166         int ret;
  167         int csr;
  168         int descnb = 0;
  169         int tmplen = len;
  170         int to_nextpagedst;
  171         int min_hop;
  172         vm_paddr_t pa, tmppa;
  173 
  174         if (!sc)
  175                 return (-1);
  176         mtx_lock_spin(&sc->mtx);
  177         if (sc->flags & BUSY) {
  178                 mtx_unlock_spin(&sc->mtx);
  179                 return (-1);
  180         }
  181         sc->flags |= BUSY;
  182         mtx_unlock_spin(&sc->mtx);
  183         desc = sc->aauring[0].desc;
  184         if (flags & IS_PHYSICAL) {
  185                 desc->local_addr = (vm_paddr_t)dst;
  186                 desc->next_desc = 0;
  187                 desc->count = len;
  188                 desc->descr_ctrl = 2 << 1 | 1 << 31; /* Fill, enable dest write */
  189                 bus_dmamap_sync(sc->dmatag, sc->aauring[0].map, 
  190                     BUS_DMASYNC_PREWRITE);
  191         } else {
  192                 test_virt_addr(dst, len);
  193                 if ((vm_offset_t)dst & (31))
  194                         cpu_dcache_wb_range((vm_offset_t)dst & ~31, 32);
  195                 if (((vm_offset_t)dst + len) & 31)
  196                         cpu_dcache_wb_range(((vm_offset_t)dst + len) & ~31,
  197                             32);
  198                 cpu_dcache_inv_range((vm_offset_t)dst, len);
  199                 while (tmplen > 0) {
  200                         pa = vtophys(dst);
  201                         to_nextpagedst = ((vm_offset_t)dst & ~PAGE_MASK) +
  202                             PAGE_SIZE - (vm_offset_t)dst;
  203                         while (to_nextpagedst < tmplen) {
  204                                 tmppa = vtophys((vm_offset_t)dst +
  205                                     to_nextpagedst);
  206                                 if (tmppa != pa + to_nextpagedst)
  207                                         break;
  208                                 to_nextpagedst += PAGE_SIZE;
  209                         }
  210                         min_hop = to_nextpagedst;
  211                         if (min_hop < 64) {
  212                                 tmplen -= min_hop;
  213                                 bzero(dst, min_hop);
  214                                 cpu_dcache_wbinv_range((vm_offset_t)dst,
  215                                     min_hop);
  216 
  217                                 dst = (void *)((vm_offset_t)dst + min_hop);
  218                                 if (tmplen <= 0 && descnb > 0) {
  219                                         sc->aauring[descnb - 1].desc->next_desc
  220                                             = 0;
  221                                         bus_dmamap_sync(sc->dmatag, 
  222                                             sc->aauring[descnb - 1].map, 
  223                                             BUS_DMASYNC_PREWRITE);
  224                                 }
  225                                 continue;
  226                         }
  227                         desc->local_addr = pa;
  228                         desc->count = tmplen > min_hop ? min_hop : tmplen;
  229                         desc->descr_ctrl = 2 << 1 | 1 << 31; /* Fill, enable dest write */;
  230                         if (min_hop < tmplen) {
  231                                 tmplen -= min_hop;
  232                                 dst = (void *)((vm_offset_t)dst + min_hop);
  233                         } else
  234                                 tmplen = 0;
  235                         if (descnb + 1 >= AAU_RING_SIZE) {
  236                                 mtx_lock_spin(&sc->mtx);
  237                                 sc->flags &= ~BUSY;
  238                                 mtx_unlock_spin(&sc->mtx);
  239                                 return (-1);
  240                         }
  241                         if (tmplen > 0) {
  242                                 desc->next_desc = sc->aauring[descnb + 1].
  243                                     phys_addr;
  244                                 bus_dmamap_sync(sc->dmatag, 
  245                                     sc->aauring[descnb].map, 
  246                                     BUS_DMASYNC_PREWRITE);
  247                                 desc = sc->aauring[descnb + 1].desc;
  248                                 descnb++;
  249                         } else {
  250                                 desc->next_desc = 0;
  251                                 bus_dmamap_sync(sc->dmatag, 
  252                                     sc->aauring[descnb].map, 
  253                                     BUS_DMASYNC_PREWRITE);
  254                         }
  255                                                                         
  256                 }
  257 
  258         }
  259         AAU_REG_WRITE(sc, 0x0c /* Descriptor addr */,
  260             sc->aauring[0].phys_addr);
  261         AAU_REG_WRITE(sc, 0 /* Control register */, 1 << 0/* Start transfer */);
  262         while ((csr = AAU_REG_READ(sc, 0x4)) & (1 << 10));
  263         /* Wait until it's done. */
  264         if (csr & (1 << 5)) /* error */
  265                 ret = -1;
  266         else
  267                 ret = 0;
  268         /* Clear the interrupt. */
  269         AAU_REG_WRITE(sc, 0x4, csr);
  270         /* Stop the AAU. */
  271         AAU_REG_WRITE(sc, 0, 0);
  272         mtx_lock_spin(&sc->mtx);
  273         sc->flags &= ~BUSY;
  274         mtx_unlock_spin(&sc->mtx);
  275         return (ret);
  276 }
  277 
  278 static device_method_t i80321_aau_methods[] = {
  279         DEVMETHOD(device_probe, i80321_aau_probe),
  280         DEVMETHOD(device_attach, i80321_aau_attach),
  281         {0, 0},
  282 };
  283 
  284 static driver_t i80321_aau_driver = {
  285         "i80321_aau",
  286         i80321_aau_methods,
  287         sizeof(struct i80321_aau_softc),
  288 };
  289 
  290 static devclass_t i80321_aau_devclass;
  291 
  292 DRIVER_MODULE(i80321_aau, iq, i80321_aau_driver, i80321_aau_devclass, 0, 0);

Cache object: f0a2c576beb6a81d5964ce04429f2d64


[ 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.