diff options
author | Dominik Wenger <domonoky@googlemail.com> | 2009-10-22 17:45:02 +0000 |
---|---|---|
committer | Dominik Wenger <domonoky@googlemail.com> | 2009-10-22 17:45:02 +0000 |
commit | 5b4938a8ca8494afa560200b67eb76df4224caea (patch) | |
tree | a3051a2e0abf058d9b8a7b09483d3a3f381b8e50 /firmware/target/arm/s3c2440/dma-s3c2440.c | |
parent | 724d1e0f3cfba44d7aa4248d15c3ce35a718a91f (diff) | |
download | rockbox-5b4938a8ca8494afa560200b67eb76df4224caea.tar.gz rockbox-5b4938a8ca8494afa560200b67eb76df4224caea.zip |
Working Bootloader for mini2440.
Flyspray: FS#10701
Author: Bob Cousins
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23316 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/s3c2440/dma-s3c2440.c')
-rw-r--r-- | firmware/target/arm/s3c2440/dma-s3c2440.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/firmware/target/arm/s3c2440/dma-s3c2440.c b/firmware/target/arm/s3c2440/dma-s3c2440.c new file mode 100644 index 0000000000..b83897cb22 --- /dev/null +++ b/firmware/target/arm/s3c2440/dma-s3c2440.c @@ -0,0 +1,207 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright 2009 by Bob Cousins + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include <stdbool.h> +#include "config.h" +#include "panic.h" +#include "system.h" +#include "mmu-arm.h" +#include "s3c2440.h" +#include "dma-target.h" +#include "system-target.h" + +#define NUM_CHANNELS 4 + +static int dma_used = 0; + +/* Status flags */ +#define STATUS_CHANNEL_ACTIVE (1<<0) + +struct dma_channel_state +{ + volatile unsigned status; + void (*callback)(void); +} dma_state [NUM_CHANNELS]; + +struct dma_channel_regs +{ + volatile unsigned long disrc; + volatile unsigned long disrcc; + volatile unsigned long didst; + volatile unsigned long didstc; + volatile unsigned long dcon; + volatile unsigned long dstat; + volatile unsigned long dcsrc; + volatile unsigned long dcdst; + volatile unsigned long dmasktrig; + volatile unsigned long reserved [7]; /* pad to 0x40 bytes */ +}; + + +struct dma_channel_regs *dma_regs [4] = + { + (struct dma_channel_regs *) &DISRC0, + (struct dma_channel_regs *) &DISRC1, + (struct dma_channel_regs *) &DISRC2, + (struct dma_channel_regs *) &DISRC3 + } +; + + +void dma_init(void) +{ + /* TODO */ + + /* Enable interupt on DMA Finish */ + /* Clear pending source */ + SRCPND = DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK; + INTPND = DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK; + + /* Enable interrupt in controller */ + s3c_regclr32(&INTMOD, DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK); + s3c_regclr32(&INTMSK, DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK); +} + +void dma_retain(void) +{ + /* TODO */ + dma_used++; + if(dma_used > 0) + { + /* Enable DMA controller, clock? */ + } +} + +void dma_release(void) +{ + /* TODO */ + if (dma_used > 0) + dma_used--; + if(dma_used == 0) + { + /* Disable DMA */ + } +} + + +inline void dma_disable_channel(int channel) +{ + struct dma_channel_regs *regs = dma_regs [channel]; + + /* disable the specified channel */ + + /* Reset the channel */ + regs->dmasktrig |= DMASKTRIG_STOP; + + /* Wait for DMA controller to be ready */ + while(regs->dmasktrig & DMASKTRIG_ON) + ; + while(regs->dstat & DSTAT_STAT_BUSY) + ; +} + +void dma_enable_channel(int channel, struct dma_request *request) +{ + struct dma_channel_regs *regs = dma_regs [channel]; + + /* TODO - transfer sizes (assumes word) */ + + if (DMA_GET_SRC(request->source_map, channel) == DMA_INVALID) + panicf ("DMA: invalid channel"); + + /* setup a transfer on specified channel */ + dma_disable_channel (channel); + + if((unsigned long)request->source_addr < UNCACHED_BASE_ADDR) + regs->disrc = (unsigned long)request->source_addr + UNCACHED_BASE_ADDR; + else + regs->disrc = (unsigned long)request->source_addr; + regs->disrcc = request->source_control; + + if((unsigned long)request->dest_addr < UNCACHED_BASE_ADDR) + regs->didst = (unsigned long)request->dest_addr + UNCACHED_BASE_ADDR; + else + regs->didst = (unsigned long)request->dest_addr; + regs->didstc = request->dest_control; + + regs->dcon = request->control | request->count | + DMA_GET_SRC(request->source_map, channel) * DCON_HWSRCSEL; + + dma_state [channel].callback = request->callback; + + /* Activate the channel */ + invalidate_dcache_range((void *)request->dest_addr, request->count * 4); + + dma_state [channel].status |= STATUS_CHANNEL_ACTIVE; + regs->dmasktrig = DMASKTRIG_ON; + + if ((request->control & DCON_HW_SEL) == 0) + { + /* Start DMA */ + regs->dmasktrig |= DMASKTRIG_SW_TRIG; + } + +} + +/* ISRs */ +inline void generic_isr (unsigned channel) +{ + if (dma_state [channel].status | STATUS_CHANNEL_ACTIVE) + { + if (dma_state [channel].callback) + /* call callback for relevant channel */ + dma_state [channel].callback(); + + dma_state [channel].status &= ~STATUS_CHANNEL_ACTIVE; + } +} + +void DMA0(void) +{ + generic_isr (0); + /* Ack the interrupt */ + SRCPND = DMA0_MASK; + INTPND = DMA0_MASK; +} + +void DMA1(void) +{ + generic_isr (1); + /* Ack the interrupt */ + SRCPND = DMA1_MASK; + INTPND = DMA1_MASK; +} + +void DMA2(void) +{ + generic_isr (2); + /* Ack the interrupt */ + SRCPND = DMA2_MASK; + INTPND = DMA2_MASK; +} + +void DMA3(void) +{ + generic_isr (3); + /* Ack the interrupt */ + SRCPND = DMA3_MASK; + INTPND = DMA3_MASK; +} |