/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2008 by Catalin Patulea * Copyright (C) 2008 by Maurus Cuelenaere * Copyright (C) 2009 by Karl Kurbjun * * 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 "registers.h" #include "arm.h" #include "dma.h" /* This is placed at the right (aligned) address using linker.cmd. */ #pragma DATA_SECTION (data, ".dma") #define DSP_BUFFER_SIZE PCM_SIZE/2 /* This is the buffer on the DSP side used for SARAM to McBSP (IIS) */ signed short data[DSP_BUFFER_SIZE]; /* These two describe the location of the buffer on the ARM (set in DSPHINT * and dspinit) */ volatile unsigned short sdem_addrh; volatile unsigned short sdem_addrl; /* This is the size of the ARM buffer (set in DSPHINT and dspinit) */ volatile unsigned short sdem_dsp_size; /* These two variables keep track of the buffer level in the DSP, dsp_level, * (SARAM to McBSP) and the level on the ARM buffer (sdem_level). */ unsigned short dsp_level=0; unsigned short sdem_level=0; /* This is used to keep track of the last SDRAM to SARAM transfer */ unsigned short last_size; /* This tells us which half of the DSP buffer (data) is free */ unsigned short dma0_unlocked; int waiting=0; /* rebuffer sets up the next SDRAM to SARAM transfer and tells the ARM when it * is done with a buffer. */ /* Notes: Right now this can handle buffer sizes that are smaller even multiples * of DSP_BUFFER_SIZE cleanly. It won't fail with buffers that are larger or * non-multiples, but it won't sound right. The upper limit on larger buffers * is the size of a short. If larger buffer sizes are needed the code on the * ARM side needs to be changed to update a full long. */ void rebuffer(void) { unsigned long sdem_addr; /* If the sdem_level is equal to the buffer size the ARM code gave * (sdem_dsp_size) then reset the size and ask the arm for another buffer */ if(sdem_level==sdem_dsp_size) { sdem_level=0; /* Get a new buffer (location and size) from ARM */ status.msg = MSG_REFILL; waiting=1; startack(); } if(!waiting) { /* Size is in bytes (but forced 32 bit transfers */ if( (dsp_level + (sdem_dsp_size - sdem_level) ) > DSP_BUFFER_SIZE) { last_size = DSP_BUFFER_SIZE-dsp_level; } else { last_size = sdem_dsp_size-sdem_level; } /* DSP addresses are 16 bit (word) */ DSP_ADDRL = (unsigned short)data + (dma0_unlocked >> 1) + (dsp_level>>1); DSP_ADDRH = 0; /* SDRAM addresses are 8 bit (byte) * Warning: These addresses are forced to 32 bit alignment! */ sdem_addr = ((unsigned long)sdem_addrh << 16 | sdem_addrl) + sdem_level; SDEM_ADDRL = sdem_addr & 0xffff; SDEM_ADDRH = sdem_addr >> 16; /* Set the size of the SDRAM to SARAM transfer (demac transfer) */ DMA_SIZE = last_size; DMA_CTRL = 0; /* These are just debug signals that are not used/needed right now */ status.payload.refill._DMA_TRG = DMA_TRG; status.payload.refill._SDEM_ADDRH = SDEM_ADDRH; status.payload.refill._SDEM_ADDRL = SDEM_ADDRL; status.payload.refill._DSP_ADDRH = DSP_ADDRH; status.payload.refill._DSP_ADDRL = DSP_ADDRL; /* Start the demac transfer */ DMA_TRG = 1; } } /* This interupt handler is for the SARAM (on DSP) to McBSP IIS DMA transfer. * It interupts at 1/2 empty and empty so that we can start filling a new buffer * from SDRAM when a half is free. dsp_level should always be full when this * interupt occurs except for the initial start. */ interrupt void handle_dma0(void) { /* Byte offset to half-buffer locked by DMA0. 0 for top, PCM_SIZE/2(0x4000) for bottom */ unsigned short dma0_locked; IFR = 1 << 6; /* DMSRC0 is the beginning of the DMA0-locked SARAM half-buffer. */ DMSA = 0x00 /* DMSRC0 */; dma0_locked = (DMSDN << 1) & (DSP_BUFFER_SIZE); dma0_unlocked = dma0_locked ^ (DSP_BUFFER_SIZE); dsp_level = 0; /* Start the SDRAM to SARAM copy */ rebuffer(); } /* This interupt handler runs every time a DMA transfer is complete from SDRAM * to the SARAM buffer. It is used to update the SARAM buffer level * (dsp_level), the SDRAM buffer level (sdem_level) and to rebuffer if the dsp * buffer is not full. */ interrupt void handle_dmac(void) { IFR = 1 << 11; dsp_level+=last_size; sdem_level+=last_size; if(dsp_level