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