Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/drv/dev/dma/i8237.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dma_attach
  2. dma_detach
  3. dma_setup
  4. dma_stop
  5. dma_alloc
  6. dma_init

   1 /*-
   2  * Copyright (c) 2005, Kohsuke Ohtani
   3  * 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  * 3. Neither the name of the author nor the names of any co-contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * i8237.c - Intel 8237 DMA controller
  32  */
  33 
  34 /**
  35  *  Memo:
  36  *
  37  *  [Mode Register]
  38  *
  39  *      Bits     Function
  40  *      -------- Mode Selection
  41  *      00          Demand Mode
  42  *      01          Single Mode
  43  *      10          Block Mode
  44  *      11          Cascade Mode
  45  *      -------- Address Increment/Decrement
  46  *        1         Address Decrement
  47  *        0         Address Increment
  48  *      -------- Auto-Initialization Enable
  49  *         1        Auto-Initialization DMA
  50  *         0        Single-Cycle DMA
  51  *      -------- Transfer Type
  52  *          00      Verify
  53  *          01      Write
  54  *          10      Read
  55  *          11      Illegal
  56  *      -------- Channel Selection
  57  *            00    Channel 0 (4)
  58  *            01    Channel 1 (5)
  59  *            10    Channel 2 (6)
  60  *            11    Channel 3 (7)
  61  *
  62  *  [Single Mask Register]
  63  *
  64  *      Bits     Function
  65  *      --------
  66  *      00000    Unused, Set to 0
  67  *      -------- Set/Clear Mask
  68  *           1      Set (Disable Channel)
  69  *           0      Clear (Enable Channel)
  70  *      -------- Channel Selection
  71  *            00    Channel 0 (4)
  72  *            01    Channel 1 (5)
  73  *            10    Channel 2 (6)
  74  *            11    Channel 3 (7)
  75  *
  76  *
  77  */
  78 
  79 #include <sys/cdefs.h>
  80 #include <driver.h>
  81 #include <cpufunc.h>
  82 
  83 #ifdef DEBUG
  84 #define DPRINTF(a) printf a
  85 #else
  86 #define DPRINTF(a)
  87 #endif
  88 
  89 #define NR_DMAS         8
  90 
  91 #define DMA_MAX         (1024 * 64)
  92 #define DMA_MASK        (DMA_MAX-1)
  93 #define DMA_ALIGN(n)    ((((paddr_t)(n)) + DMA_MASK) & ~DMA_MASK)
  94 
  95 void            dma_stop(dma_t handle);
  96 static int      dma_init(struct driver *self);
  97 
  98 
  99 /*
 100  * DMA descriptor
 101  */
 102 struct dma {
 103         int     chan;           /* dma channel */
 104         int     in_use;         /* true if used */
 105 };
 106 
 107 /*
 108  * DMA i/o port
 109  */
 110 struct dma_port {
 111         int     mask;
 112         int     mode;
 113         int     clear;
 114         int     addr;
 115         int     count;
 116         int     page;
 117 };
 118 
 119 static const struct dma_port dma_regs[] = {
 120 /*      mask,  mode,  clear, addr,  count, page */
 121         {0x0a, 0x0b, 0x0c, 0x00, 0x01, 0x87},   /* Channel 0 */
 122         {0x0a, 0x0b, 0x0c, 0x02, 0x03, 0x83},   /* Channel 1 */
 123         {0x0a, 0x0b, 0x0c, 0x04, 0x05, 0x81},   /* Channel 2 */
 124         {0x0a, 0x0b, 0x0c, 0x06, 0x07, 0x82},   /* Channel 3 */
 125         {0xd4, 0xd6, 0xd8, 0xc0, 0xc2, 0x8f},   /* Channel 4 (n/a) */
 126         {0xd4, 0xd6, 0xd8, 0xc4, 0xc6, 0x8b},   /* Channel 5 */
 127         {0xd4, 0xd6, 0xd8, 0xc8, 0xca, 0x89},   /* Channel 6 */
 128         {0xd4, 0xd6, 0xd8, 0xcc, 0xce, 0x8a},   /* Channel 7 */
 129 };
 130 
 131 static struct dma dma_table[NR_DMAS];
 132 
 133 struct driver i8237_driver = {
 134         /* name */      "dma",
 135         /* devsops */   NULL,
 136         /* devsz */     0,
 137         /* flags */     0,
 138         /* probe */     NULL,
 139         /* init */      dma_init,
 140         /* shutdown */  NULL,
 141 };
 142 
 143 
 144 /*
 145  * Attach dma.
 146  * Return dma handle on success, or panic on failure.
 147  * DMA4 can not be used with pc.
 148  */
 149 dma_t
 150 dma_attach(int chan)
 151 {
 152         struct dma *dma;
 153         int s;
 154 
 155         ASSERT(chan >= 0 && chan < NR_DMAS);
 156         ASSERT(chan != 4);
 157         DPRINTF(("DMA%d attached\n", chan));
 158 
 159         s = splhigh();
 160         dma = &dma_table[chan];
 161         if (dma->in_use) {
 162                 panic("dma_attach");
 163         } else {
 164                 dma->chan = chan;
 165                 dma->in_use = 1;
 166         }
 167         dma_stop((dma_t)dma);
 168         splx(s);
 169         return (dma_t)dma;
 170 }
 171 
 172 /*
 173  * Detach dma.
 174  */
 175 void
 176 dma_detach(dma_t handle)
 177 {
 178         struct dma *dma = (struct dma *)handle;
 179         int s;
 180 
 181         ASSERT(dma->in_use);
 182         DPRINTF(("DMA%d detached\n", dma->chan));
 183 
 184         s = splhigh();
 185         dma->in_use = 0;
 186         splx(s);
 187 }
 188 
 189 void
 190 dma_setup(dma_t handle, void *addr, u_long count, int read)
 191 {
 192         struct dma *dma = (struct dma *)handle;
 193         const struct dma_port *regs;
 194         u_int chan, bits, mode;
 195         paddr_t paddr;
 196         int s;
 197 
 198         ASSERT(handle);
 199         paddr = kvtop(addr);
 200 
 201         /* dma address must be under 16M. */
 202         ASSERT(paddr < 0xffffff);
 203 
 204         s = splhigh();
 205 
 206         chan = (u_int)dma->chan;
 207         regs = &dma_regs[chan];
 208         bits = (chan < 4) ? chan : chan >> 2;
 209         mode = read ? 0x44U : 0x48U;
 210         count--;
 211 
 212         bus_write_8(regs->mask, bits | 0x04);   /* Disable channel */
 213         bus_write_8(regs->clear, 0x00);         /* Clear byte pointer flip-flop */
 214         bus_write_8(regs->mode, bits | mode);   /* Set mode */
 215         bus_write_8(regs->addr, (u_char)((paddr >> 0) & 0xff)); /* Address low */
 216         bus_write_8(regs->addr, (u_char)((paddr >> 8) & 0xff)); /* Address high */
 217         bus_write_8(regs->page, (u_char)((paddr >> 16) & 0xff));        /* Page address */
 218         bus_write_8(regs->clear, 0x00);         /* Clear byte pointer flip-flop */
 219         bus_write_8(regs->count, (u_char)((count >> 0) & 0xff));        /* Count low */
 220         bus_write_8(regs->count, (u_char)((count >> 8) & 0xff));        /* Count high */
 221         bus_write_8(regs->mask, bits);          /* Enable channel */
 222 
 223         splx(s);
 224 }
 225 
 226 void
 227 dma_stop(dma_t handle)
 228 {
 229         struct dma *dma = (struct dma *)handle;
 230         u_int chan;
 231         u_int bits;
 232         int s;
 233 
 234         ASSERT(handle);
 235         s = splhigh();
 236         chan = (u_int)dma->chan;
 237 
 238         bits = (chan < 4) ? chan : chan >> 2;
 239         bus_write_8(dma_regs[chan].mask, bits | 0x04);  /* Disable channel */
 240         splx(s);
 241 }
 242 
 243 /*
 244  * Allocate DMA buffer
 245  *
 246  * Return page address in 64K byte boundary.
 247  * The caller must deallocate the pages by using page_free().
 248  */
 249 void *
 250 dma_alloc(size_t size)
 251 {
 252         paddr_t tmp, base;
 253 
 254         if (size > DMA_MAX)
 255                 return NULL;
 256 
 257         sched_lock();
 258 
 259         /*
 260          * Try to allocate temporary buffer for enough size (64K + size).
 261          */
 262         size = round_page(size);
 263         tmp = page_alloc((size_t)(DMA_MAX + size));
 264         if (tmp == 0) {
 265                 sched_unlock();
 266                 return NULL;
 267         }
 268         page_free(tmp, (size_t)(DMA_MAX + size));
 269 
 270         /*
 271          * Now, we know the free address with 64k boundary.
 272          */
 273         base = DMA_ALIGN(tmp);
 274         page_reserve(base, size);
 275 
 276         sched_unlock();
 277         return ptokv(base);
 278 }
 279 
 280 static int
 281 dma_init(struct driver *self)
 282 {
 283 
 284         return 0;
 285 }

/* [<][>][^][v][top][bottom][index][help] */