s3c2440_dma.c revision 1.1.6.2 1 1.1.6.2 yamt /*-
2 1.1.6.2 yamt * Copyright (c) 2012 The NetBSD Foundation, Inc.
3 1.1.6.2 yamt * All rights reserved.
4 1.1.6.2 yamt *
5 1.1.6.2 yamt * This code is derived from software contributed to The NetBSD Foundation
6 1.1.6.2 yamt * by Paul Fleischer <paul (at) xpg.dk>
7 1.1.6.2 yamt *
8 1.1.6.2 yamt * Redistribution and use in source and binary forms, with or without
9 1.1.6.2 yamt * modification, are permitted provided that the following conditions
10 1.1.6.2 yamt * are met:
11 1.1.6.2 yamt * 1. Redistributions of source code must retain the above copyright
12 1.1.6.2 yamt * notice, this list of conditions and the following disclaimer.
13 1.1.6.2 yamt * 2. Redistributions in binary form must reproduce the above copyright
14 1.1.6.2 yamt * notice, this list of conditions and the following disclaimer in the
15 1.1.6.2 yamt * documentation and/or other materials provided with the distribution.
16 1.1.6.2 yamt *
17 1.1.6.2 yamt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 1.1.6.2 yamt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 1.1.6.2 yamt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 1.1.6.2 yamt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 1.1.6.2 yamt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 1.1.6.2 yamt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 1.1.6.2 yamt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 1.1.6.2 yamt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 1.1.6.2 yamt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 1.1.6.2 yamt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 1.1.6.2 yamt * POSSIBILITY OF SUCH DAMAGE.
28 1.1.6.2 yamt */
29 1.1.6.2 yamt
30 1.1.6.2 yamt #include <sys/cdefs.h>
31 1.1.6.2 yamt
32 1.1.6.2 yamt #include <sys/param.h>
33 1.1.6.2 yamt #include <sys/systm.h>
34 1.1.6.2 yamt #include <sys/device.h>
35 1.1.6.2 yamt #include <sys/kernel.h>
36 1.1.6.2 yamt #include <sys/malloc.h>
37 1.1.6.2 yamt #include <sys/queue.h>
38 1.1.6.2 yamt
39 1.1.6.2 yamt #include <sys/mutex.h>
40 1.1.6.2 yamt #include <sys/condvar.h>
41 1.1.6.2 yamt
42 1.1.6.2 yamt #include <machine/cpu.h>
43 1.1.6.2 yamt #include <sys/bus.h>
44 1.1.6.2 yamt
45 1.1.6.2 yamt #include <arch/arm/s3c2xx0/s3c2440_dma.h>
46 1.1.6.2 yamt
47 1.1.6.2 yamt #include <arm/s3c2xx0/s3c2440var.h>
48 1.1.6.2 yamt #include <arch/arm/s3c2xx0/s3c2440reg.h>
49 1.1.6.2 yamt
50 1.1.6.2 yamt #include <uvm/uvm_extern.h>
51 1.1.6.2 yamt #include <machine/pmap.h>
52 1.1.6.2 yamt
53 1.1.6.2 yamt //#define S3C2440_DMA_DEBUG
54 1.1.6.2 yamt #ifdef S3C2440_DMA_DEBUG
55 1.1.6.2 yamt #define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0)
56 1.1.6.2 yamt #else
57 1.1.6.2 yamt #define DPRINTF(s) do {} while (/*CONSTCOND*/0)
58 1.1.6.2 yamt #endif
59 1.1.6.2 yamt
60 1.1.6.2 yamt #define DMAC_N_CHANNELS 4
61 1.1.6.2 yamt
62 1.1.6.2 yamt struct dmac_desc_segs {
63 1.1.6.2 yamt bus_dma_segment_t *ds_curseg;
64 1.1.6.2 yamt uint8_t ds_nsegs;
65 1.1.6.2 yamt };
66 1.1.6.2 yamt
67 1.1.6.2 yamt SIMPLEQ_HEAD(dmac_xfer_state_head, dmac_xfer_state);
68 1.1.6.2 yamt
69 1.1.6.2 yamt struct dmac_xfer_state {
70 1.1.6.2 yamt struct dmac_xfer dxs_xfer;
71 1.1.6.2 yamt SIMPLEQ_ENTRY(dmac_xfer_state) dxs_link;
72 1.1.6.2 yamt uint8_t dxs_channel;
73 1.1.6.2 yamt #define DMAC_NO_CHANNEL (~0)
74 1.1.6.2 yamt uint8_t dxs_width;
75 1.1.6.2 yamt bool dxs_complete;
76 1.1.6.2 yamt struct dmac_desc_segs dxs_segs[2];
77 1.1.6.2 yamt uint32_t dxs_options;
78 1.1.6.2 yamt };
79 1.1.6.2 yamt
80 1.1.6.2 yamt struct s3c2440_dmac_peripheral {
81 1.1.6.2 yamt u_int8_t dp_id;
82 1.1.6.2 yamt u_int8_t dp_channel_order[DMAC_N_CHANNELS+1];
83 1.1.6.2 yamt #define PERPH_LAST DMAC_N_CHANNELS+1
84 1.1.6.2 yamt u_int8_t dp_channel_source[DMAC_N_CHANNELS];
85 1.1.6.2 yamt #define PERPH_NA 7
86 1.1.6.2 yamt };
87 1.1.6.2 yamt
88 1.1.6.2 yamt struct s3c2440_dmac_channel {
89 1.1.6.2 yamt struct dmac_xfer_state *dc_active; /* Active transfer, NULL if none */
90 1.1.6.2 yamt
91 1.1.6.2 yamt /* Request queue. Can easily be extended to support multiple
92 1.1.6.2 yamt priorities */
93 1.1.6.2 yamt struct dmac_xfer_state_head dc_queue;
94 1.1.6.2 yamt };
95 1.1.6.2 yamt
96 1.1.6.2 yamt struct s3c2440_dmac_softc {
97 1.1.6.2 yamt bus_space_tag_t sc_iot;
98 1.1.6.2 yamt bus_space_handle_t sc_dmach;
99 1.1.6.2 yamt bus_dma_tag_t sc_dmat;
100 1.1.6.2 yamt struct kmutex sc_mutex;
101 1.1.6.2 yamt struct s3c2440_dmac_channel sc_channels[DMAC_N_CHANNELS];
102 1.1.6.2 yamt struct kmutex sc_intr_mutex;
103 1.1.6.2 yamt struct kcondvar sc_intr_cv;
104 1.1.6.2 yamt };
105 1.1.6.2 yamt
106 1.1.6.2 yamt static struct s3c2440_dmac_softc _s3c2440_dmac_sc;
107 1.1.6.2 yamt static struct s3c2440_dmac_softc *s3c2440_dmac_sc = &_s3c2440_dmac_sc;
108 1.1.6.2 yamt
109 1.1.6.2 yamt /* TODO: Consider making the order configurable. */
110 1.1.6.2 yamt static struct s3c2440_dmac_peripheral s3c2440_peripherals[] = {
111 1.1.6.2 yamt {DMAC_PERIPH_NONE, {0,1,2,3}, {0, 0, 0, 0}},
112 1.1.6.2 yamt {DMAC_PERIPH_XDREQ0, {0,PERPH_LAST}, {0, PERPH_NA, PERPH_NA, PERPH_NA}},
113 1.1.6.2 yamt {DMAC_PERIPH_XDREQ1, {1,PERPH_LAST}, {PERPH_NA, 0, PERPH_NA, PERPH_NA}},
114 1.1.6.2 yamt {DMAC_PERIPH_UART0, {0,PERPH_LAST}, {1, PERPH_NA, PERPH_NA, PERPH_NA}},
115 1.1.6.2 yamt {DMAC_PERIPH_UART1, {1,PERPH_LAST}, {PERPH_NA, 1, PERPH_NA, PERPH_NA}},
116 1.1.6.2 yamt {DMAC_PERIPH_UART2, {3,PERPH_LAST}, {PERPH_NA, PERPH_NA, PERPH_NA, 0}},
117 1.1.6.2 yamt {DMAC_PERIPH_I2SSDO, {0, 2, PERPH_LAST}, {5, PERPH_NA, 0, PERPH_NA}},
118 1.1.6.2 yamt {DMAC_PERIPH_I2SSDI, {1, 2, PERPH_LAST}, {PERPH_NA, 2, 1, PERPH_NA}},
119 1.1.6.2 yamt {DMAC_PERIPH_SDI, {3, 2, 1, PERPH_LAST}, {2, 6, 2, 1}},
120 1.1.6.2 yamt {DMAC_PERIPH_SPI0, {1, PERPH_LAST}, {PERPH_NA, 3, PERPH_NA, PERPH_NA}},
121 1.1.6.2 yamt {DMAC_PERIPH_SPI1, {3, PERPH_LAST}, {PERPH_NA, PERPH_NA, PERPH_NA, 2}},
122 1.1.6.2 yamt {DMAC_PERIPH_PCMIN, {0, 2, PERPH_LAST}, {6, PERPH_NA, 5, PERPH_NA}},
123 1.1.6.2 yamt {DMAC_PERIPH_PCMOUT, {1, 3, PERPH_LAST}, {PERPH_NA, 5, PERPH_NA, 6}},
124 1.1.6.2 yamt {DMAC_PERIPH_MICIN, {2, 3, PERPH_LAST}, {PERPH_NA, PERPH_NA, 6, 5}},
125 1.1.6.2 yamt {DMAC_PERIPH_MICOUT, {2, 3, PERPH_LAST}, {PERPH_NA, PERPH_NA, 6, 5}},
126 1.1.6.2 yamt {DMAC_PERIPH_TIMER, {0, 2, 3, PERPH_LAST}, {3, PERPH_NA, 3, 3}},
127 1.1.6.2 yamt {DMAC_PERIPH_USBEP1, {0, PERPH_LAST}, {4, PERPH_NA, PERPH_NA, PERPH_NA}},
128 1.1.6.2 yamt {DMAC_PERIPH_USBEP2, {1, PERPH_LAST}, {PERPH_NA, 4, PERPH_NA, PERPH_NA}},
129 1.1.6.2 yamt {DMAC_PERIPH_USBEP3, {2, PERPH_LAST}, {PERPH_NA, PERPH_NA, 4, PERPH_NA}},
130 1.1.6.2 yamt {DMAC_PERIPH_USBEP4, {3, PERPH_LAST}, {PERPH_NA, PERPH_NA, PERPH_NA, 4}}
131 1.1.6.2 yamt };
132 1.1.6.2 yamt
133 1.1.6.2 yamt static void dmac_start(u_int8_t channel_no, struct dmac_xfer_state*);
134 1.1.6.2 yamt static void dmac_transfer_segment(uint8_t channel_no, struct dmac_xfer_state*);
135 1.1.6.2 yamt static void dmac_channel_done(uint8_t channel_no);
136 1.1.6.2 yamt
137 1.1.6.2 yamt void
138 1.1.6.2 yamt s3c2440_dma_init(void)
139 1.1.6.2 yamt {
140 1.1.6.2 yamt struct s3c2440_dmac_softc *sc = s3c2440_dmac_sc;
141 1.1.6.2 yamt int i;
142 1.1.6.2 yamt
143 1.1.6.2 yamt sc->sc_iot = s3c2xx0_softc->sc_iot;
144 1.1.6.2 yamt sc->sc_dmach = s3c2xx0_softc->sc_dmach;
145 1.1.6.2 yamt sc->sc_dmat = s3c2xx0_softc->sc_dmat;
146 1.1.6.2 yamt for(i = 0; i<DMAC_N_CHANNELS; i++) {
147 1.1.6.2 yamt sc->sc_channels[i].dc_active = NULL;
148 1.1.6.2 yamt SIMPLEQ_INIT(&sc->sc_channels[i].dc_queue);
149 1.1.6.2 yamt }
150 1.1.6.2 yamt
151 1.1.6.2 yamt mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_BIO);
152 1.1.6.2 yamt
153 1.1.6.2 yamt mutex_init(&sc->sc_intr_mutex, MUTEX_DEFAULT, IPL_BIO);
154 1.1.6.2 yamt cv_init(&sc->sc_intr_cv, "s3c2440_dmaintr");
155 1.1.6.2 yamt
156 1.1.6.2 yamt /* Setup interrupt handler for DMA controller */
157 1.1.6.2 yamt s3c24x0_intr_establish(S3C24X0_INT_DMA0, IPL_BIO,
158 1.1.6.2 yamt IST_EDGE_RISING, s3c2440_dma_intr, (void*)1);
159 1.1.6.2 yamt s3c24x0_intr_establish(S3C24X0_INT_DMA1, IPL_BIO,
160 1.1.6.2 yamt IST_EDGE_RISING, s3c2440_dma_intr, (void*)2);
161 1.1.6.2 yamt s3c24x0_intr_establish(S3C24X0_INT_DMA2, IPL_BIO,
162 1.1.6.2 yamt IST_EDGE_RISING, s3c2440_dma_intr, (void*)3);
163 1.1.6.2 yamt s3c24x0_intr_establish(S3C24X0_INT_DMA3, IPL_BIO,
164 1.1.6.2 yamt IST_EDGE_RISING, s3c2440_dma_intr, (void*)4);
165 1.1.6.2 yamt }
166 1.1.6.2 yamt
167 1.1.6.2 yamt int
168 1.1.6.2 yamt s3c2440_dma_intr(void *arg)
169 1.1.6.2 yamt {
170 1.1.6.2 yamt /*struct s3c2xx0_softc *sc = s3c2xx0_softc;*/
171 1.1.6.2 yamt struct s3c2440_dmac_softc *sc;
172 1.1.6.2 yamt uint32_t status;
173 1.1.6.2 yamt int channel;
174 1.1.6.2 yamt struct s3c2440_dmac_channel *dc;
175 1.1.6.2 yamt
176 1.1.6.2 yamt sc = s3c2440_dmac_sc;
177 1.1.6.2 yamt
178 1.1.6.2 yamt channel = (int)arg - 1;
179 1.1.6.2 yamt dc = &sc->sc_channels[channel];
180 1.1.6.2 yamt
181 1.1.6.2 yamt DPRINTF(("s3c2440_dma_intr\n"));
182 1.1.6.2 yamt DPRINTF(("Channel %d\n", channel));
183 1.1.6.2 yamt
184 1.1.6.2 yamt status = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_STAT(channel));
185 1.1.6.2 yamt DPRINTF(("Channel %d status: %d\n", channel, status));
186 1.1.6.2 yamt
187 1.1.6.2 yamt if ( !(status & DMASTAT_BUSY) ) {
188 1.1.6.2 yamt struct dmac_xfer_state *dxs;
189 1.1.6.2 yamt struct dmac_xfer *dx;
190 1.1.6.2 yamt
191 1.1.6.2 yamt dxs = dc->dc_active;
192 1.1.6.2 yamt KASSERT(dxs != NULL);
193 1.1.6.2 yamt
194 1.1.6.2 yamt dx = &dxs->dxs_xfer;
195 1.1.6.2 yamt
196 1.1.6.2 yamt if (dx->dx_desc[DMAC_DESC_SRC].xd_increment) {
197 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_SRC].ds_nsegs--;
198 1.1.6.2 yamt if (dxs->dxs_segs[DMAC_DESC_SRC].ds_nsegs == 0) {
199 1.1.6.2 yamt dxs->dxs_complete = TRUE;
200 1.1.6.2 yamt } else {
201 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_SRC].ds_curseg++;
202 1.1.6.2 yamt }
203 1.1.6.2 yamt }
204 1.1.6.2 yamt if (dx->dx_desc[DMAC_DESC_DST].xd_increment) {
205 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_DST].ds_nsegs--;
206 1.1.6.2 yamt if (dxs->dxs_segs[DMAC_DESC_DST].ds_nsegs == 0) {
207 1.1.6.2 yamt dxs->dxs_complete = TRUE;
208 1.1.6.2 yamt } else {
209 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_DST].ds_curseg++;
210 1.1.6.2 yamt }
211 1.1.6.2 yamt }
212 1.1.6.2 yamt
213 1.1.6.2 yamt if (dxs->dxs_complete) {
214 1.1.6.2 yamt dxs->dxs_channel = DMAC_NO_CHANNEL;
215 1.1.6.2 yamt
216 1.1.6.2 yamt /* Lock the DMA mutex before tampering with
217 1.1.6.2 yamt the channel.
218 1.1.6.2 yamt */
219 1.1.6.2 yamt mutex_enter(&sc->sc_mutex);
220 1.1.6.2 yamt dmac_channel_done(channel);
221 1.1.6.2 yamt mutex_exit(&sc->sc_mutex);
222 1.1.6.2 yamt
223 1.1.6.2 yamt DPRINTF(("dx_done: %p\n", (void*)dx->dx_done));
224 1.1.6.2 yamt if (dx->dx_done != NULL) {
225 1.1.6.2 yamt (dx->dx_done)(dx, dx->dx_cookie);
226 1.1.6.2 yamt }
227 1.1.6.2 yamt } else {
228 1.1.6.2 yamt dmac_transfer_segment(channel, dxs);
229 1.1.6.2 yamt }
230 1.1.6.2 yamt }
231 1.1.6.2 yamt #if 0
232 1.1.6.2 yamt if ( !(status & DMASTAT_BUSY) ) {
233 1.1.6.2 yamt s3c2440_dma_xfer_t xfer;
234 1.1.6.2 yamt
235 1.1.6.2 yamt xfer = dma_channel_xfer[channel];
236 1.1.6.2 yamt dma_channel_xfer[channel] = NULL;
237 1.1.6.2 yamt
238 1.1.6.2 yamt DPRINTF((" Channel %d completed transfer\n", channel));
239 1.1.6.2 yamt
240 1.1.6.2 yamt if (xfer->dx_remaining > 0 &&
241 1.1.6.2 yamt xfer->dx_aborted == FALSE) {
242 1.1.6.2 yamt
243 1.1.6.2 yamt DPRINTF(("Preparing next transfer\n"));
244 1.1.6.2 yamt
245 1.1.6.2 yamt s3c2440_dma_xfer_start(xfer);
246 1.1.6.2 yamt } else {
247 1.1.6.2 yamt if (!xfer->dx_aborted && xfer->dx_callback != NULL)
248 1.1.6.2 yamt (xfer->dx_callback)(xfer->dx_callback_arg);
249 1.1.6.2 yamt
250 1.1.6.2 yamt xfer->dx_complete = TRUE;
251 1.1.6.2 yamt }
252 1.1.6.2 yamt
253 1.1.6.2 yamt }
254 1.1.6.2 yamt #endif
255 1.1.6.2 yamt
256 1.1.6.2 yamt #ifdef S3C2440_DMA_DEBUG
257 1.1.6.2 yamt status = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_CSRC(channel));
258 1.1.6.2 yamt printf("Current source for channel %d: 0x%x\n", channel, status);
259 1.1.6.2 yamt
260 1.1.6.2 yamt status = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_CDST(channel));
261 1.1.6.2 yamt printf("Current dest for channel %d: 0x%x\n", channel, status);
262 1.1.6.2 yamt #endif
263 1.1.6.2 yamt
264 1.1.6.2 yamt /* TODO: Remove this as it activates any thread waiting for a transfer
265 1.1.6.2 yamt to complete */
266 1.1.6.2 yamt mutex_enter(&sc->sc_intr_mutex);
267 1.1.6.2 yamt DPRINTF(("cv_broadcast\n"));
268 1.1.6.2 yamt cv_broadcast(&sc->sc_intr_cv);
269 1.1.6.2 yamt DPRINTF(("cv_broadcast done\n"));
270 1.1.6.2 yamt mutex_exit(&sc->sc_intr_mutex);
271 1.1.6.2 yamt
272 1.1.6.2 yamt return 1;
273 1.1.6.2 yamt }
274 1.1.6.2 yamt
275 1.1.6.2 yamt dmac_xfer_t
276 1.1.6.2 yamt s3c2440_dmac_allocate_xfer(int flags) {
277 1.1.6.2 yamt struct dmac_xfer_state *dxs;
278 1.1.6.2 yamt
279 1.1.6.2 yamt dxs = malloc(sizeof(struct dmac_xfer_state), M_DEVBUF, flags);
280 1.1.6.2 yamt
281 1.1.6.2 yamt dxs->dxs_xfer.dx_done = NULL;
282 1.1.6.2 yamt dxs->dxs_xfer.dx_sync_bus = DMAC_SYNC_BUS_AUTO;
283 1.1.6.2 yamt dxs->dxs_xfer.dx_xfer_mode = DMAC_XFER_MODE_DEMAND;
284 1.1.6.2 yamt dxs->dxs_channel = DMAC_NO_CHANNEL;
285 1.1.6.2 yamt
286 1.1.6.2 yamt return ((dmac_xfer_t)dxs);
287 1.1.6.2 yamt }
288 1.1.6.2 yamt
289 1.1.6.2 yamt void
290 1.1.6.2 yamt s3c2440_dmac_free_xfer(dmac_xfer_t dx) {
291 1.1.6.2 yamt free(dx, M_DEVBUF);
292 1.1.6.2 yamt }
293 1.1.6.2 yamt
294 1.1.6.2 yamt int
295 1.1.6.2 yamt s3c2440_dmac_start_xfer(dmac_xfer_t dx) {
296 1.1.6.2 yamt struct s3c2440_dmac_softc *sc = s3c2440_dmac_sc;
297 1.1.6.2 yamt struct dmac_xfer_state *dxs = (struct dmac_xfer_state*)dx;
298 1.1.6.2 yamt struct s3c2440_dmac_peripheral *perph;
299 1.1.6.2 yamt int i;
300 1.1.6.2 yamt bool transfer_started = FALSE;
301 1.1.6.2 yamt
302 1.1.6.2 yamt if (dxs->dxs_xfer.dx_peripheral != DMAC_PERIPH_NONE &&
303 1.1.6.2 yamt dxs->dxs_xfer.dx_peripheral >= DMAC_N_PERIPH)
304 1.1.6.2 yamt return EINVAL;
305 1.1.6.2 yamt
306 1.1.6.2 yamt dxs->dxs_complete = FALSE;
307 1.1.6.2 yamt
308 1.1.6.2 yamt perph = &s3c2440_peripherals[dxs->dxs_xfer.dx_peripheral];
309 1.1.6.2 yamt #ifdef DIAGNOSTIC
310 1.1.6.2 yamt DPRINTF(("dp_id: %d, dx_peripheral: %d\n", perph->dp_id, dxs->dxs_xfer.dx_peripheral));
311 1.1.6.2 yamt KASSERT(perph->dp_id == dxs->dxs_xfer.dx_peripheral);
312 1.1.6.2 yamt #endif
313 1.1.6.2 yamt
314 1.1.6.2 yamt mutex_enter(&sc->sc_mutex);
315 1.1.6.2 yamt /* Get list of possible channels for this peripheral.
316 1.1.6.2 yamt If none of the channels are ready to transmit, queue
317 1.1.6.2 yamt the transfer in the one with the highest priority
318 1.1.6.2 yamt (first in the order list).
319 1.1.6.2 yamt */
320 1.1.6.2 yamt for(i=0;
321 1.1.6.2 yamt perph->dp_channel_order[i] != PERPH_LAST;
322 1.1.6.2 yamt i++) {
323 1.1.6.2 yamt u_int8_t channel_no = perph->dp_channel_order[i];
324 1.1.6.2 yamt
325 1.1.6.2 yamt #ifdef DIAGNOSTIC
326 1.1.6.2 yamt /* Check that there is a mapping for the given channel.
327 1.1.6.2 yamt If this fails, there is something wrong in
328 1.1.6.2 yamt s3c2440_peripherals.
329 1.1.6.2 yamt */
330 1.1.6.2 yamt KASSERT(perph->dp_channel_source[channel_no] != PERPH_NA);
331 1.1.6.2 yamt #endif
332 1.1.6.2 yamt
333 1.1.6.2 yamt if (sc->sc_channels[channel_no].dc_active == NULL) {
334 1.1.6.2 yamt /* Transfer can start right away */
335 1.1.6.2 yamt dmac_start(channel_no, dxs);
336 1.1.6.2 yamt transfer_started = TRUE;
337 1.1.6.2 yamt break;
338 1.1.6.2 yamt }
339 1.1.6.2 yamt }
340 1.1.6.2 yamt
341 1.1.6.2 yamt if (transfer_started == FALSE) {
342 1.1.6.2 yamt u_int8_t channel_no = perph->dp_channel_order[0];
343 1.1.6.2 yamt /* Enqueue the transfer, as none of the DMA channels were
344 1.1.6.2 yamt available.
345 1.1.6.2 yamt The highest priority channel is used.
346 1.1.6.2 yamt */
347 1.1.6.2 yamt dxs->dxs_channel = channel_no;
348 1.1.6.2 yamt SIMPLEQ_INSERT_TAIL(&sc->sc_channels[channel_no].dc_queue, dxs, dxs_link);
349 1.1.6.2 yamt DPRINTF(("Enqueued transfer on channel %d\n", channel_no));
350 1.1.6.2 yamt }
351 1.1.6.2 yamt
352 1.1.6.2 yamt mutex_exit(&sc->sc_mutex);
353 1.1.6.2 yamt
354 1.1.6.2 yamt return 0;
355 1.1.6.2 yamt }
356 1.1.6.2 yamt
357 1.1.6.2 yamt static void
358 1.1.6.2 yamt dmac_start(u_int8_t channel_no, struct dmac_xfer_state *dxs) {
359 1.1.6.2 yamt struct s3c2440_dmac_softc *sc = s3c2440_dmac_sc;
360 1.1.6.2 yamt struct s3c2440_dmac_channel *dc = &sc->sc_channels[channel_no];
361 1.1.6.2 yamt uint32_t options;
362 1.1.6.2 yamt #ifdef DIAGNOSTIC
363 1.1.6.2 yamt uint32_t reg;
364 1.1.6.2 yamt #endif
365 1.1.6.2 yamt dmac_sync_bus_t sync_bus;
366 1.1.6.2 yamt struct dmac_xfer *dx = &dxs->dxs_xfer;
367 1.1.6.2 yamt
368 1.1.6.2 yamt /* Must be called with sc_mutex locked */
369 1.1.6.2 yamt
370 1.1.6.2 yamt DPRINTF(("Starting DMA transfer (%p) on channel %d\n", dxs, channel_no));
371 1.1.6.2 yamt
372 1.1.6.2 yamt KASSERT(dc->dc_active == NULL);
373 1.1.6.2 yamt
374 1.1.6.2 yamt #ifdef DIAGNOSTIC
375 1.1.6.2 yamt reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_STAT(channel_no));
376 1.1.6.2 yamt if (reg & DMASTAT_BUSY)
377 1.1.6.2 yamt panic("DMA channel is busy, cannot start new transfer!");
378 1.1.6.2 yamt
379 1.1.6.2 yamt #endif
380 1.1.6.2 yamt
381 1.1.6.2 yamt dc->dc_active = dxs;
382 1.1.6.2 yamt dxs->dxs_channel = channel_no;
383 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_SRC].ds_curseg = dx->dx_desc[DMAC_DESC_SRC].xd_dma_segs;
384 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_SRC].ds_nsegs = dx->dx_desc[DMAC_DESC_SRC].xd_nsegs;
385 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_DST].ds_curseg = dx->dx_desc[DMAC_DESC_DST].xd_dma_segs;
386 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_DST].ds_nsegs = dx->dx_desc[DMAC_DESC_DST].xd_nsegs;
387 1.1.6.2 yamt
388 1.1.6.2 yamt options = DMACON_INT_INT |
389 1.1.6.2 yamt DMACON_RELOAD_NO_AUTO;
390 1.1.6.2 yamt
391 1.1.6.2 yamt if (dxs->dxs_xfer.dx_peripheral == DMAC_PERIPH_NONE) {
392 1.1.6.2 yamt options |= DMACON_SERVMODE_WHOLE;
393 1.1.6.2 yamt } else {
394 1.1.6.2 yamt options |= DMACON_SERVMODE_SINGLE;
395 1.1.6.2 yamt }
396 1.1.6.2 yamt
397 1.1.6.2 yamt switch (dxs->dxs_xfer.dx_xfer_mode) {
398 1.1.6.2 yamt case DMAC_XFER_MODE_DEMAND:
399 1.1.6.2 yamt options |= DMACON_DEMAND;
400 1.1.6.2 yamt break;
401 1.1.6.2 yamt case DMAC_XFER_MODE_HANDSHAKE:
402 1.1.6.2 yamt options |= DMACON_HANDSHAKE;
403 1.1.6.2 yamt break;
404 1.1.6.2 yamt default:
405 1.1.6.2 yamt panic("Unknown dx_xfer_mode");
406 1.1.6.2 yamt }
407 1.1.6.2 yamt
408 1.1.6.2 yamt sync_bus = dxs->dxs_xfer.dx_sync_bus;
409 1.1.6.2 yamt
410 1.1.6.2 yamt switch (dxs->dxs_xfer.dx_xfer_width) {
411 1.1.6.2 yamt case DMAC_XFER_WIDTH_8BIT:
412 1.1.6.2 yamt DPRINTF(("8-Bit (BYTE) transfer width\n"));
413 1.1.6.2 yamt options |= DMACON_DSZ_B;
414 1.1.6.2 yamt dxs->dxs_width = 1;
415 1.1.6.2 yamt break;
416 1.1.6.2 yamt case DMAC_XFER_WIDTH_16BIT:
417 1.1.6.2 yamt DPRINTF(("16-Bit (HALF-WORD) transfer width\n"));
418 1.1.6.2 yamt options |= DMACON_DSZ_HW;
419 1.1.6.2 yamt dxs->dxs_width = 2;
420 1.1.6.2 yamt break;
421 1.1.6.2 yamt case DMAC_XFER_WIDTH_32BIT:
422 1.1.6.2 yamt DPRINTF(("32-Bit (WORD) transfer width\n"));
423 1.1.6.2 yamt options |= DMACON_DSZ_W;
424 1.1.6.2 yamt dxs->dxs_width = 4;
425 1.1.6.2 yamt break;
426 1.1.6.2 yamt default:
427 1.1.6.2 yamt panic("Unknown transfer width");
428 1.1.6.2 yamt }
429 1.1.6.2 yamt
430 1.1.6.2 yamt if (dxs->dxs_xfer.dx_peripheral == DMAC_PERIPH_NONE) {
431 1.1.6.2 yamt options |= DMACON_SW_REQ;
432 1.1.6.2 yamt if (sync_bus == DMAC_SYNC_BUS_AUTO)
433 1.1.6.2 yamt sync_bus = DMAC_SYNC_BUS_SYSTEM;
434 1.1.6.2 yamt } else {
435 1.1.6.2 yamt uint8_t source = s3c2440_peripherals[dxs->dxs_xfer.dx_peripheral].dp_channel_source[channel_no];
436 1.1.6.2 yamt DPRINTF(("Hw request source: %d, channel: %d\n", source, channel_no));
437 1.1.6.2 yamt options |= DMACON_HW_REQ | DMACON_HW_SRCSEL(source);
438 1.1.6.2 yamt if (sync_bus == DMAC_SYNC_BUS_AUTO)
439 1.1.6.2 yamt sync_bus = DMAC_SYNC_BUS_PERIPHERAL;
440 1.1.6.2 yamt }
441 1.1.6.2 yamt
442 1.1.6.2 yamt if (sync_bus == DMAC_SYNC_BUS_SYSTEM) {
443 1.1.6.2 yamt DPRINTF(("Syncing with system bus\n"));
444 1.1.6.2 yamt options |= DMACON_SYNC_AHB;
445 1.1.6.2 yamt } else if (sync_bus == DMAC_SYNC_BUS_PERIPHERAL) {
446 1.1.6.2 yamt DPRINTF(("Syncing with peripheral bus\n"));
447 1.1.6.2 yamt options |= DMACON_SYNC_APB;
448 1.1.6.2 yamt } else {
449 1.1.6.2 yamt panic("No sync bus given");
450 1.1.6.2 yamt }
451 1.1.6.2 yamt
452 1.1.6.2 yamt dxs->dxs_options = options;
453 1.1.6.2 yamt
454 1.1.6.2 yamt /* We have now configured the options that will hold for all segment transfers.
455 1.1.6.2 yamt Next, we prepare and start the transfer for the first segment */
456 1.1.6.2 yamt dmac_transfer_segment(channel_no, dxs);
457 1.1.6.2 yamt
458 1.1.6.2 yamt }
459 1.1.6.2 yamt
460 1.1.6.2 yamt static void
461 1.1.6.2 yamt dmac_transfer_segment(uint8_t channel_no, struct dmac_xfer_state *dxs)
462 1.1.6.2 yamt {
463 1.1.6.2 yamt struct s3c2440_dmac_softc *sc = s3c2440_dmac_sc;
464 1.1.6.2 yamt /* struct s3c2440_dmac_channel *dc = &sc->sc_channels[channel_no];*/
465 1.1.6.2 yamt uint32_t reg, transfer_size;
466 1.1.6.2 yamt struct dmac_xfer *dx = &dxs->dxs_xfer;
467 1.1.6.2 yamt
468 1.1.6.2 yamt DPRINTF(("dmac_transfer_segment\n"));
469 1.1.6.2 yamt
470 1.1.6.2 yamt /* Prepare the source */
471 1.1.6.2 yamt bus_space_write_4(sc->sc_iot, sc->sc_dmach,
472 1.1.6.2 yamt DMA_DISRC(channel_no),
473 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_SRC].ds_curseg->ds_addr);
474 1.1.6.2 yamt
475 1.1.6.2 yamt DPRINTF(("Source address: 0x%x\n", (unsigned)dxs->dxs_segs[DMAC_DESC_SRC].ds_curseg->ds_addr));
476 1.1.6.2 yamt DPRINTF(("Dest. address: 0x%x\n", (unsigned)dxs->dxs_segs[DMAC_DESC_DST].ds_curseg->ds_addr));
477 1.1.6.2 yamt reg = 0;
478 1.1.6.2 yamt if (dx->dx_desc[DMAC_DESC_SRC].xd_bus_type == DMAC_BUS_TYPE_PERIPHERAL) {
479 1.1.6.2 yamt reg |= DISRCC_LOC_APB;
480 1.1.6.2 yamt } else {
481 1.1.6.2 yamt reg |= DISRCC_LOC_AHB;
482 1.1.6.2 yamt }
483 1.1.6.2 yamt if (dx->dx_desc[DMAC_DESC_SRC].xd_increment) {
484 1.1.6.2 yamt reg |= DISRCC_INC_INC;
485 1.1.6.2 yamt } else {
486 1.1.6.2 yamt reg |= DISRCC_INC_FIXED;
487 1.1.6.2 yamt }
488 1.1.6.2 yamt bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DISRCC(channel_no), reg);
489 1.1.6.2 yamt
490 1.1.6.2 yamt /* Prepare the destination */
491 1.1.6.2 yamt bus_space_write_4(sc->sc_iot, sc->sc_dmach,
492 1.1.6.2 yamt DMA_DIDST(channel_no),
493 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_DST].ds_curseg->ds_addr);
494 1.1.6.2 yamt reg = 0;
495 1.1.6.2 yamt if (dx->dx_desc[DMAC_DESC_DST].xd_bus_type == DMAC_BUS_TYPE_PERIPHERAL) {
496 1.1.6.2 yamt reg |= DIDSTC_LOC_APB;
497 1.1.6.2 yamt } else {
498 1.1.6.2 yamt reg |= DIDSTC_LOC_AHB;
499 1.1.6.2 yamt }
500 1.1.6.2 yamt if (dx->dx_desc[DMAC_DESC_DST].xd_increment) {
501 1.1.6.2 yamt reg |= DIDSTC_INC_INC;
502 1.1.6.2 yamt } else {
503 1.1.6.2 yamt reg |= DIDSTC_INC_FIXED;
504 1.1.6.2 yamt }
505 1.1.6.2 yamt bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DIDSTC(channel_no), reg);
506 1.1.6.2 yamt
507 1.1.6.2 yamt /* Let the incrementing party decide how much data to transfer.
508 1.1.6.2 yamt If both are incrementing, set the transfer size to the smallest one.
509 1.1.6.2 yamt */
510 1.1.6.2 yamt if (dx->dx_desc[DMAC_DESC_SRC].xd_increment) {
511 1.1.6.2 yamt if (!dx->dx_desc[DMAC_DESC_DST].xd_increment) {
512 1.1.6.2 yamt transfer_size = dxs->dxs_segs[DMAC_DESC_SRC].ds_curseg->ds_len;
513 1.1.6.2 yamt } else {
514 1.1.6.2 yamt transfer_size = min(dxs->dxs_segs[DMAC_DESC_DST].ds_curseg->ds_len,
515 1.1.6.2 yamt dxs->dxs_segs[DMAC_DESC_SRC].ds_curseg->ds_len);
516 1.1.6.2 yamt }
517 1.1.6.2 yamt } else {
518 1.1.6.2 yamt if (dx->dx_desc[DMAC_DESC_DST].xd_increment) {
519 1.1.6.2 yamt transfer_size = dxs->dxs_segs[DMAC_DESC_DST].ds_curseg->ds_len;
520 1.1.6.2 yamt } else {
521 1.1.6.2 yamt panic("S3C2440 DMA code does not support both source and destination being non-incrementing");
522 1.1.6.2 yamt }
523 1.1.6.2 yamt }
524 1.1.6.2 yamt
525 1.1.6.2 yamt /* Set options as prepared by dmac_start and add the transfer size.
526 1.1.6.2 yamt If the transfer_size is not an even number of dxs_width,
527 1.1.6.2 yamt ensure that all bytes are transferred by adding an extra transfer
528 1.1.6.2 yamt of dxs_width.
529 1.1.6.2 yamt */
530 1.1.6.2 yamt bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_CON(channel_no),
531 1.1.6.2 yamt dxs->dxs_options |
532 1.1.6.2 yamt DMACON_TC(((transfer_size/dxs->dxs_width)+
533 1.1.6.2 yamt min((transfer_size % dxs->dxs_width), 1))));
534 1.1.6.2 yamt
535 1.1.6.2 yamt DPRINTF(("Transfer size: %d (%d)\n", transfer_size, transfer_size/dxs->dxs_width));
536 1.1.6.2 yamt
537 1.1.6.2 yamt /* Start the transfer */
538 1.1.6.2 yamt reg = DMAMASKTRIG_ON;
539 1.1.6.2 yamt if (dxs->dxs_xfer.dx_peripheral == DMAC_PERIPH_NONE) {
540 1.1.6.2 yamt reg |= DMAMASKTRIG_SW_TRIG;
541 1.1.6.2 yamt }
542 1.1.6.2 yamt bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_MASKTRIG(channel_no),
543 1.1.6.2 yamt reg);
544 1.1.6.2 yamt
545 1.1.6.2 yamt #if defined(S3C2440_DMA_DEBUG)
546 1.1.6.2 yamt reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_DISRC(channel_no));
547 1.1.6.2 yamt printf("DMA_DISRC: 0x%X\n", reg);
548 1.1.6.2 yamt
549 1.1.6.2 yamt reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_DISRCC(channel_no));
550 1.1.6.2 yamt printf("DMA_DISRCC: 0x%X\n", reg);
551 1.1.6.2 yamt
552 1.1.6.2 yamt reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_DIDST(channel_no));
553 1.1.6.2 yamt printf("DMA_DIDST: 0x%X\n", reg);
554 1.1.6.2 yamt
555 1.1.6.2 yamt reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_DIDSTC(channel_no));
556 1.1.6.2 yamt printf("DMA_DIDSTC: 0x%X\n", reg);
557 1.1.6.2 yamt
558 1.1.6.2 yamt reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_CON(channel_no));
559 1.1.6.2 yamt printf("DMA_CON: 0x%X\n", reg);
560 1.1.6.2 yamt
561 1.1.6.2 yamt reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_MASKTRIG(channel_no));
562 1.1.6.2 yamt printf("DMA_MASKTRIG: 0x%X\n", reg);
563 1.1.6.2 yamt
564 1.1.6.2 yamt reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_STAT(channel_no));
565 1.1.6.2 yamt printf("DMA_STAT: 0x%X\n", reg);
566 1.1.6.2 yamt #endif
567 1.1.6.2 yamt }
568 1.1.6.2 yamt
569 1.1.6.2 yamt static void
570 1.1.6.2 yamt dmac_channel_done(uint8_t channel_no)
571 1.1.6.2 yamt {
572 1.1.6.2 yamt struct s3c2440_dmac_softc *sc;
573 1.1.6.2 yamt struct s3c2440_dmac_channel *dc;
574 1.1.6.2 yamt
575 1.1.6.2 yamt sc = s3c2440_dmac_sc;
576 1.1.6.2 yamt
577 1.1.6.2 yamt /* sc->sc_mutex must be held when calling this function */
578 1.1.6.2 yamt
579 1.1.6.2 yamt dc = &sc->sc_channels[channel_no];
580 1.1.6.2 yamt
581 1.1.6.2 yamt dc->dc_active = NULL;
582 1.1.6.2 yamt /* We deal with the queue before calling the
583 1.1.6.2 yamt done callback, as it might start a new DMA
584 1.1.6.2 yamt transfer.
585 1.1.6.2 yamt */
586 1.1.6.2 yamt if ( SIMPLEQ_EMPTY(&dc->dc_queue) ) {
587 1.1.6.2 yamt DPRINTF(("DMA Queue empty for channel %d\n", channel_no));
588 1.1.6.2 yamt } else {
589 1.1.6.2 yamt /* There is a transfer in the queue. Start it*/
590 1.1.6.2 yamt struct dmac_xfer_state *dxs;
591 1.1.6.2 yamt DPRINTF(("Took a transfer from the queue\n"));
592 1.1.6.2 yamt dxs = SIMPLEQ_FIRST(&dc->dc_queue);
593 1.1.6.2 yamt SIMPLEQ_REMOVE_HEAD(&dc->dc_queue, dxs_link);
594 1.1.6.2 yamt
595 1.1.6.2 yamt dmac_start(channel_no, dxs);
596 1.1.6.2 yamt }
597 1.1.6.2 yamt }
598 1.1.6.2 yamt
599 1.1.6.2 yamt int
600 1.1.6.2 yamt s3c2440_dmac_wait_xfer(dmac_xfer_t dx, int timeout) {
601 1.1.6.2 yamt uint32_t complete;
602 1.1.6.2 yamt int err = 0;
603 1.1.6.2 yamt struct s3c2440_dmac_softc *sc = s3c2440_dmac_sc;
604 1.1.6.2 yamt struct dmac_xfer_state *dxs = (struct dmac_xfer_state*)dx;
605 1.1.6.2 yamt
606 1.1.6.2 yamt mutex_enter(&sc->sc_intr_mutex);
607 1.1.6.2 yamt complete = dxs->dxs_complete;
608 1.1.6.2 yamt while(complete == 0) {
609 1.1.6.2 yamt int status;
610 1.1.6.2 yamt DPRINTF(("s3c2440_dma_xfer_wait: Complete: %x\n", complete));
611 1.1.6.2 yamt
612 1.1.6.2 yamt if ( (status = cv_timedwait(&sc->sc_intr_cv,
613 1.1.6.2 yamt &sc->sc_intr_mutex, timeout)) ==
614 1.1.6.2 yamt EWOULDBLOCK ) {
615 1.1.6.2 yamt DPRINTF(("s3c2440_dma_xfer_wait: Timed out\n"));
616 1.1.6.2 yamt complete = 1;
617 1.1.6.2 yamt err = ETIMEDOUT;
618 1.1.6.2 yamt break;
619 1.1.6.2 yamt }
620 1.1.6.2 yamt
621 1.1.6.2 yamt complete = dxs->dxs_complete;
622 1.1.6.2 yamt }
623 1.1.6.2 yamt
624 1.1.6.2 yamt mutex_exit(&sc->sc_intr_mutex);
625 1.1.6.2 yamt
626 1.1.6.2 yamt #if 0
627 1.1.6.2 yamt if (err == 0 && dxs->dxs_aborted == 1) {
628 1.1.6.2 yamt /* Transfer was aborted */
629 1.1.6.2 yamt err = EIO;
630 1.1.6.2 yamt }
631 1.1.6.2 yamt #endif
632 1.1.6.2 yamt
633 1.1.6.2 yamt return err;
634 1.1.6.2 yamt }
635 1.1.6.2 yamt
636 1.1.6.2 yamt void
637 1.1.6.2 yamt s3c2440_dmac_abort_xfer(dmac_xfer_t dx) {
638 1.1.6.2 yamt struct s3c2440_dmac_softc *sc = s3c2440_dmac_sc;
639 1.1.6.2 yamt struct dmac_xfer_state *dxs = (struct dmac_xfer_state*)dx;
640 1.1.6.2 yamt struct s3c2440_dmac_channel *dc;
641 1.1.6.2 yamt bool wait = FALSE;
642 1.1.6.2 yamt
643 1.1.6.2 yamt KASSERT(dxs->dxs_channel != (uint8_t)DMAC_NO_CHANNEL);
644 1.1.6.2 yamt
645 1.1.6.2 yamt dc = &sc->sc_channels[dxs->dxs_channel];
646 1.1.6.2 yamt
647 1.1.6.2 yamt mutex_enter(&sc->sc_mutex);
648 1.1.6.2 yamt
649 1.1.6.2 yamt if (dc->dc_active == dxs) {
650 1.1.6.2 yamt uint32_t reg;
651 1.1.6.2 yamt
652 1.1.6.2 yamt bus_space_write_4(sc->sc_iot, sc->sc_dmach,
653 1.1.6.2 yamt DMA_MASKTRIG(dxs->dxs_channel),
654 1.1.6.2 yamt DMAMASKTRIG_STOP);
655 1.1.6.2 yamt reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach,
656 1.1.6.2 yamt DMA_MASKTRIG(dxs->dxs_channel));
657 1.1.6.2 yamt DPRINTF(("s3c2440_dma: channel %d mask trigger %x\n", dxs->dxs_channel, reg));
658 1.1.6.2 yamt
659 1.1.6.2 yamt if ( !(reg & DMAMASKTRIG_ON) ) {
660 1.1.6.2 yamt DPRINTF(("No wait for abort"));
661 1.1.6.2 yamt
662 1.1.6.2 yamt /* The transfer was aborted and the interrupt
663 1.1.6.2 yamt was thus not triggered. We need to cleanup the
664 1.1.6.2 yamt channel here. */
665 1.1.6.2 yamt dmac_channel_done(dxs->dxs_channel);
666 1.1.6.2 yamt } else {
667 1.1.6.2 yamt wait = TRUE;
668 1.1.6.2 yamt }
669 1.1.6.2 yamt } else {
670 1.1.6.2 yamt /* Transfer is not active, simply remove it from the queue */
671 1.1.6.2 yamt DPRINTF(("Removed transfer from queue\n"));
672 1.1.6.2 yamt SIMPLEQ_REMOVE(&dc->dc_queue, dxs, dmac_xfer_state, dxs_link);
673 1.1.6.2 yamt }
674 1.1.6.2 yamt
675 1.1.6.2 yamt mutex_exit(&sc->sc_mutex);
676 1.1.6.2 yamt
677 1.1.6.2 yamt if (wait == TRUE) {
678 1.1.6.2 yamt DPRINTF(("Abort: Wait for transfer to complete\n"));
679 1.1.6.2 yamt s3c2440_dmac_wait_xfer(dx, 0);
680 1.1.6.2 yamt }
681 1.1.6.2 yamt }
682