diff options
| author | Keith Packard <keithp@keithp.com> | 2009-06-04 10:41:34 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2009-06-04 10:41:34 -0700 | 
| commit | 210dbaa23cdacf3a6f2d6e23493e96ee2ac9bca7 (patch) | |
| tree | 42dbabd0caa7186c898da746014341d3ff31a201 /src/ao_dma.c | |
| parent | 8cce307bb3156584ba17ae5a787f645dfee5fb94 (diff) | |
Use autotools, move altos to src subdir
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src/ao_dma.c')
| -rw-r--r-- | src/ao_dma.c | 131 | 
1 files changed, 131 insertions, 0 deletions
| diff --git a/src/ao_dma.c b/src/ao_dma.c new file mode 100644 index 00000000..a4d45f14 --- /dev/null +++ b/src/ao_dma.c @@ -0,0 +1,131 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +#define NUM_DMA	5 + +/* + * The config address for DMA0 is programmed + * separately from that of DMA1-4, but for simplicity, + * we make them all contiguous. + */ + +static __xdata struct cc_dma_channel ao_dma_config[NUM_DMA]; +static __xdata uint8_t * __xdata ao_dma_done[NUM_DMA]; +static __data uint8_t ao_next_dma; + +uint8_t +ao_dma_alloc(__xdata uint8_t *done) +{ +	uint8_t id; + +	if (ao_next_dma == NUM_DMA) +		ao_panic(AO_PANIC_DMA); +	id = ao_next_dma++; +	ao_dma_done[id] = done; + +	/* When the first dma object is allocated, set up the DMA +	 * controller +	 */ +	if (id == 0) { +		DMAIRQ = 0; +		DMAIF = 0; +		IEN1 |= IEN1_DMAIE; +	} + +	return id; +} + +void +ao_dma_set_transfer(uint8_t id, +		    void __xdata *srcaddr, +		    void __xdata *dstaddr, +		    uint16_t count, +		    uint8_t cfg0, +		    uint8_t cfg1) +{ +	if (DMAARM & (1 << id)) +		ao_panic(AO_PANIC_DMA); +	ao_dma_config[id].src_high = ((uint16_t) srcaddr) >> 8; +	ao_dma_config[id].src_low = ((uint16_t) srcaddr); +	ao_dma_config[id].dst_high = ((uint16_t) dstaddr) >> 8; +	ao_dma_config[id].dst_low = ((uint16_t) dstaddr); +	ao_dma_config[id].len_high = count >> 8; +	ao_dma_config[id].len_low = count; +	ao_dma_config[id].cfg0 = cfg0; +	ao_dma_config[id].cfg1 = cfg1 | DMA_CFG1_IRQMASK; +	if (id == 0) { +		DMA0CFGH = ((uint16_t) (&ao_dma_config[0])) >> 8; +		DMA0CFGL = ((uint16_t) (&ao_dma_config[0])); +	} else { +		DMA1CFGH = ((uint16_t) (&ao_dma_config[1])) >> 8; +		DMA1CFGL = ((uint16_t) (&ao_dma_config[1])); +	} +} + +#define nop()	_asm nop _endasm; + +void +ao_dma_start(uint8_t id) +{ +	uint8_t	mask = (1 << id); +	DMAIRQ &= ~mask; +	DMAARM = 0x80 | mask; +	nop(); nop(); nop(); nop(); +	nop(); nop(); nop(); nop(); +	*(ao_dma_done[id]) = 0; +	DMAARM = mask; +	nop(); nop(); nop(); nop(); +	nop(); nop(); nop(); nop(); +	nop(); +} + +void +ao_dma_trigger(uint8_t id) +{ +	DMAREQ |= (1 << id); +} + +void +ao_dma_abort(uint8_t id) +{ +	uint8_t	mask = (1 << id); +	DMAARM = 0x80 | mask; +	DMAIRQ &= ~mask; +} + +void +ao_dma_isr(void) interrupt 8 +{ +	uint8_t id, mask; + +	/* Find the first DMA channel which is done */ +	mask = 1; +	for (id = 0; id < ao_next_dma; id++) { +		if (DMAIRQ & mask) { +			/* Clear CPU interrupt flag */ +			DMAIF = 0; +			/* Clear the completed ID */ +			DMAIRQ = ~mask; +			*(ao_dma_done[id]) = 1; +			ao_wakeup(ao_dma_done[id]); +			break; +		} +		mask <<= 1; +	} +} | 
