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 |
} |