Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / bsp / drv / dev / dma / i8237.c @ 03e9c04a

History | View | Annotate | Download (6.75 KB)

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
}