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