Home | History | Annotate | Line # | Download | only in s3c2xx0
s3c2440_dma.c revision 1.1.6.3
      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.3  yamt 	uint8_t	dp_id;
     82  1.1.6.3  yamt 	uint8_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.3  yamt 	uint8_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.3  yamt static void dmac_start(uint8_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.3  yamt 		uint8_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.3  yamt 		uint8_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.3  yamt dmac_start(uint8_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