forked from len0rd/rockbox
Give pcm-coldfire.c a much needed shakedown. Fixes FS#9378 - metronome freezes (works for me now on X5 and H120 after running it at 400bpm for an hour or so). The reason seems to have been DMA_INT in DCR should also be cleared when forcing a channel stop. Also fixes a dodgey keyclick without music playing that I was getting on H120.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19991 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
b411f5eee5
commit
ca5ca5b6ef
1 changed files with 159 additions and 161 deletions
|
|
@ -8,6 +8,7 @@
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 by Michael Sevakis
|
* Copyright (C) 2006 by Michael Sevakis
|
||||||
|
* Copyright (C) 2005 by Linus Nielsen Feltzing
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -28,45 +29,30 @@
|
||||||
#include "spdif.h"
|
#include "spdif.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
|
#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
|
||||||
(IIS_PLAY & (7 << 8)) | \
|
(IIS_PLAY & (7 << 8)) | \
|
||||||
(4 << 2) ) /* 64 bit clocks / word clock */
|
(4 << 2) ) /* 64 bit clocks / word clock */
|
||||||
#define IIS_FIFO_RESET (1 << 11)
|
#define IIS_FIFO_RESET (1 << 11)
|
||||||
#define PDIR2_FIFO_RESET (1 << 9)
|
#define PDIR2_FIFO_RESET (1 << 9)
|
||||||
|
|
||||||
#if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(IAUDIO_M3)
|
#if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(IAUDIO_M3)
|
||||||
#define SET_IIS_PLAY(x) IIS1CONFIG = (x)
|
#define IIS_PLAY IIS1CONFIG
|
||||||
#define IIS_PLAY IIS1CONFIG
|
|
||||||
#else
|
#else
|
||||||
#define SET_IIS_PLAY(x) IIS2CONFIG = (x)
|
#define IIS_PLAY IIS2CONFIG
|
||||||
#define IIS_PLAY IIS2CONFIG
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct dma_lock
|
#ifdef HAVE_SPDIF_OUT
|
||||||
{
|
/* EBU TX auto sync, PDIR2 fifo auto sync, IIS1 fifo auto sync */
|
||||||
int locked;
|
#define AUDIOGLOB_DEFPARM ((1 << 10) | (1 << 8) | (1 << 7))
|
||||||
unsigned long state;
|
#else
|
||||||
};
|
/* PDIR2 fifo auto sync, IIS1 fifo auto sync */
|
||||||
|
#define AUDIOGLOB_DEFPARM ((1 << 8) | (1 << 7))
|
||||||
static bool is_playback_monitoring(void)
|
#endif
|
||||||
{
|
|
||||||
return (IIS_PLAY & (7 << 8)) == (3 << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iis_play_reset_if_playback(bool if_playback)
|
|
||||||
{
|
|
||||||
bool is_playback = is_playback_monitoring();
|
|
||||||
|
|
||||||
if (is_playback != if_playback)
|
|
||||||
return;
|
|
||||||
|
|
||||||
or_l(IIS_FIFO_RESET, &IIS_PLAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/** Sample rates **/
|
||||||
#define PLLCR_SET_AUDIO_BITS_DEFPARM \
|
#define PLLCR_SET_AUDIO_BITS_DEFPARM \
|
||||||
((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
|
((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
|
||||||
|
|
||||||
/** Sample rates **/
|
|
||||||
#define FPARM_CLOCKSEL 0
|
#define FPARM_CLOCKSEL 0
|
||||||
#define FPARM_CLSEL 1
|
#define FPARM_CLSEL 1
|
||||||
#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
|
#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
|
||||||
|
|
@ -91,62 +77,62 @@ static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] =
|
||||||
|
|
||||||
static const unsigned char *freq_ent;
|
static const unsigned char *freq_ent;
|
||||||
|
|
||||||
/* apply audio settings */
|
/* Lock status struct for playback and recording */
|
||||||
static bool _pcm_dma_apply_settings(bool clear_reset)
|
struct dma_lock
|
||||||
{
|
{
|
||||||
bool did_reset = false;
|
int locked;
|
||||||
unsigned long iis_play_defparm;
|
unsigned long state;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void iis_play_reset(void)
|
||||||
|
{
|
||||||
|
or_l(IIS_FIFO_RESET, &IIS_PLAY);
|
||||||
|
and_l(~IIS_FIFO_RESET, &IIS_PLAY);
|
||||||
|
PDOR3 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_playback_monitoring(void)
|
||||||
|
{
|
||||||
|
return (IIS_PLAY & (7 << 8)) == (3 << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iis_play_reset_if_playback(bool if_playback)
|
||||||
|
{
|
||||||
int level = set_irq_level(DMA_IRQ_LEVEL);
|
int level = set_irq_level(DMA_IRQ_LEVEL);
|
||||||
|
if (is_playback_monitoring() == if_playback)
|
||||||
/* remember table entry */
|
iis_play_reset();
|
||||||
freq_ent = pcm_freq_parms[pcm_fsel];
|
|
||||||
|
|
||||||
iis_play_defparm = IIS_PLAY_DEFPARM;
|
|
||||||
|
|
||||||
if (pcm_sampr != pcm_curr_sampr)
|
|
||||||
{
|
|
||||||
/* Reprogramming bits 15-12 requires FIFO to be in a reset
|
|
||||||
condition - Users Manual 17-8, Note 11 */
|
|
||||||
or_l(IIS_FIFO_RESET, &IIS_PLAY);
|
|
||||||
/* Important for TLV320 - this must happen in the correct order
|
|
||||||
or starting recording will sound absolutely awful once in
|
|
||||||
awhile - audiohw_set_frequency then coldfire_set_pllcr_audio_bits
|
|
||||||
*/
|
|
||||||
SET_IIS_PLAY(IIS_PLAY_DEFPARM | IIS_FIFO_RESET);
|
|
||||||
audiohw_set_frequency(pcm_fsel);
|
|
||||||
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
|
|
||||||
did_reset = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If a reset was done because of a sample rate change, IIS_PLAY will have
|
|
||||||
been set already, so only needs to be set again if the reset flag must
|
|
||||||
be cleared. If the frequency didn't change, it was never altered and
|
|
||||||
the reset flag can just be removed or no action taken. */
|
|
||||||
if (clear_reset)
|
|
||||||
SET_IIS_PLAY(IIS_PLAY_DEFPARM & ~IIS_FIFO_RESET);
|
|
||||||
|
|
||||||
restore_irq(level);
|
restore_irq(level);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
/* apply audio settings */
|
||||||
logf("IISPLAY: %08X", IIS_PLAY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return did_reset;
|
|
||||||
} /* _pcm_dma_apply_settings */
|
|
||||||
|
|
||||||
/* This clears the reset bit to enable monitoring immediately if monitoring
|
/* This clears the reset bit to enable monitoring immediately if monitoring
|
||||||
recording sources or always if playback is in progress - we might be
|
recording sources or always if playback is in progress - we might be
|
||||||
switching samplerates on the fly */
|
switching samplerates on the fly */
|
||||||
void pcm_dma_apply_settings(void)
|
void pcm_dma_apply_settings(void)
|
||||||
{
|
{
|
||||||
int level = set_irq_level(DMA_IRQ_LEVEL);
|
int level = set_irq_level(DMA_IRQ_LEVEL);
|
||||||
bool pbm = is_playback_monitoring();
|
|
||||||
bool kick = (DCR0 & DMA_EEXT) != 0 && pbm;
|
|
||||||
|
|
||||||
/* Clear reset if not playback monitoring or peripheral request is
|
/* remember table entry */
|
||||||
active and playback monitoring */
|
freq_ent = pcm_freq_parms[pcm_fsel];
|
||||||
if (_pcm_dma_apply_settings(!pbm || kick) && kick)
|
|
||||||
|
/* Reprogramming bits 15-12 requires FIFO to be in a reset
|
||||||
|
condition - Users Manual 17-8, Note 11 */
|
||||||
|
or_l(IIS_FIFO_RESET, &IIS_PLAY);
|
||||||
|
/* Important for TLV320 - this must happen in the correct order
|
||||||
|
or starting recording will sound absolutely awful once in
|
||||||
|
awhile - audiohw_set_frequency then coldfire_set_pllcr_audio_bits
|
||||||
|
*/
|
||||||
|
IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET;
|
||||||
|
restore_irq(level);
|
||||||
|
|
||||||
|
audiohw_set_frequency(pcm_fsel);
|
||||||
|
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
|
||||||
|
|
||||||
|
level = set_irq_level(DMA_IRQ_LEVEL);
|
||||||
|
|
||||||
|
IIS_PLAY = IIS_PLAY_DEFPARM;
|
||||||
|
|
||||||
|
if ((DCR0 & DMA_EEXT) != 0 && is_playback_monitoring())
|
||||||
PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
|
PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
|
||||||
|
|
||||||
restore_irq(level);
|
restore_irq(level);
|
||||||
|
|
@ -156,24 +142,18 @@ void pcm_play_dma_init(void)
|
||||||
{
|
{
|
||||||
freq_ent = pcm_freq_parms[pcm_fsel];
|
freq_ent = pcm_freq_parms[pcm_fsel];
|
||||||
|
|
||||||
AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */
|
AUDIOGLOB = AUDIOGLOB_DEFPARM;
|
||||||
| (1 << 7) /* PDIR2 fifo auto sync */
|
DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
|
||||||
#ifdef HAVE_SPDIF_OUT
|
|
||||||
| (1 << 10) /* EBU TX auto sync */
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
|
|
||||||
and_l(0xffffff00, &DMAROUTE);
|
and_l(0xffffff00, &DMAROUTE);
|
||||||
or_l(DMA0_REQ_AUDIO_1, &DMAROUTE);
|
or_l(DMA0_REQ_AUDIO_1, &DMAROUTE);
|
||||||
DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
|
DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
|
||||||
|
BCR0 = 0; /* No bytes waiting */
|
||||||
/* Call pcm_play_dma_stop to initialize everything. */
|
ICR6 = (6 << 2); /* Enable interrupt at level 6, priority 0 */
|
||||||
pcm_play_dma_stop();
|
|
||||||
|
|
||||||
/* Setup Coldfire I2S before initializing hardware or changing
|
/* Setup Coldfire I2S before initializing hardware or changing
|
||||||
other settings. */
|
other settings. */
|
||||||
or_l(IIS_FIFO_RESET, &IIS_PLAY);
|
or_l(IIS_FIFO_RESET, &IIS_PLAY);
|
||||||
SET_IIS_PLAY(IIS_PLAY_DEFPARM | IIS_FIFO_RESET);
|
IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET;
|
||||||
audio_set_output_source(AUDIO_SRC_PLAYBACK);
|
audio_set_output_source(AUDIO_SRC_PLAYBACK);
|
||||||
|
|
||||||
/* Initialize default register values. */
|
/* Initialize default register values. */
|
||||||
|
|
@ -187,13 +167,12 @@ void pcm_play_dma_init(void)
|
||||||
#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
|
#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
|
||||||
spdif_init();
|
spdif_init();
|
||||||
#endif
|
#endif
|
||||||
/* Enable interrupt at level 6, priority 0 */
|
|
||||||
ICR6 = (6 << 2);
|
|
||||||
} /* pcm_play_dma_init */
|
} /* pcm_play_dma_init */
|
||||||
|
|
||||||
void pcm_postinit(void)
|
void pcm_postinit(void)
|
||||||
{
|
{
|
||||||
audiohw_postinit();
|
audiohw_postinit();
|
||||||
|
iis_play_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DMA **/
|
/** DMA **/
|
||||||
|
|
@ -225,22 +204,22 @@ void pcm_play_unlock(void)
|
||||||
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
|
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
|
||||||
void pcm_play_dma_start(const void *addr, size_t size)
|
void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
{
|
{
|
||||||
logf("pcm_play_dma_start");
|
/* Stop any DMA in progress */
|
||||||
|
pcm_play_dma_stop();
|
||||||
|
|
||||||
/* stop any DMA in progress */
|
addr = (void *)(((long)addr + 3) & ~3);
|
||||||
DSR0 = 1;
|
size &= ~3;
|
||||||
DCR0 = 0;
|
|
||||||
|
if (size <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Set up DMA transfer */
|
/* Set up DMA transfer */
|
||||||
SAR0 = (unsigned long)addr; /* Source address */
|
SAR0 = (unsigned long)addr; /* Source address */
|
||||||
DAR0 = (unsigned long)&PDOR3; /* Destination address */
|
DAR0 = (unsigned long)&PDOR3; /* Destination address */
|
||||||
BCR0 = (unsigned long)size; /* Bytes to transfer */
|
BCR0 = (unsigned long)size; /* Bytes to transfer */
|
||||||
|
|
||||||
/* Enable the FIFO and force one write to it */
|
DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_SINC |
|
||||||
_pcm_dma_apply_settings(is_playback_monitoring());
|
DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
|
||||||
|
|
||||||
DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
|
|
||||||
DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
|
|
||||||
|
|
||||||
dma_play_lock.state = (1 << 14);
|
dma_play_lock.state = (1 << 14);
|
||||||
} /* pcm_play_dma_start */
|
} /* pcm_play_dma_start */
|
||||||
|
|
@ -248,12 +227,10 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
/* Stops the DMA transfer and interrupt */
|
/* Stops the DMA transfer and interrupt */
|
||||||
void pcm_play_dma_stop(void)
|
void pcm_play_dma_stop(void)
|
||||||
{
|
{
|
||||||
DSR0 = 1;
|
and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
|
||||||
DCR0 = 0;
|
BCR0 = 0; /* No bytes remaining */
|
||||||
BCR0 = 0;
|
DSR0 = 1; /* Clear interrupt, errors, stop transfer */
|
||||||
|
|
||||||
/* Place TX FIFO in reset condition if playback monitoring is on.
|
|
||||||
Recording monitoring something else should not be stopped. */
|
|
||||||
iis_play_reset_if_playback(true);
|
iis_play_reset_if_playback(true);
|
||||||
|
|
||||||
dma_play_lock.state = (0 << 14);
|
dma_play_lock.state = (0 << 14);
|
||||||
|
|
@ -264,16 +241,16 @@ void pcm_play_dma_pause(bool pause)
|
||||||
if (pause)
|
if (pause)
|
||||||
{
|
{
|
||||||
/* pause playback on current buffer */
|
/* pause playback on current buffer */
|
||||||
and_l(~DMA_EEXT, &DCR0);
|
and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
|
||||||
|
DSR0 = 1; /* stop channel */
|
||||||
iis_play_reset_if_playback(true);
|
iis_play_reset_if_playback(true);
|
||||||
dma_play_lock.state = (0 << 14);
|
dma_play_lock.state = (0 << 14);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* restart playback on current buffer */
|
/* restart playback on current buffer */
|
||||||
/* Enable the FIFO and force one write to it */
|
iis_play_reset_if_playback(true);
|
||||||
_pcm_dma_apply_settings(is_playback_monitoring());
|
or_l(DMA_INT | DMA_EEXT | DMA_START, &DCR0); /* everything ON */
|
||||||
or_l(DMA_EEXT | DMA_START, &DCR0);
|
|
||||||
dma_play_lock.state = (1 << 14);
|
dma_play_lock.state = (1 << 14);
|
||||||
}
|
}
|
||||||
} /* pcm_play_dma_pause */
|
} /* pcm_play_dma_pause */
|
||||||
|
|
@ -288,38 +265,14 @@ size_t pcm_get_bytes_waiting(void)
|
||||||
void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
|
void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
|
||||||
void DMA0(void)
|
void DMA0(void)
|
||||||
{
|
{
|
||||||
int res = DSR0;
|
unsigned long res = DSR0;
|
||||||
|
|
||||||
DSR0 = 1; /* Clear interrupt */
|
and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
|
||||||
and_l(~DMA_EEXT, &DCR0); /* Disable peripheral request */
|
DSR0 = 1; /* Clear interrupt and errors */
|
||||||
/* Stop on error */
|
|
||||||
if ((res & 0x70) == 0)
|
if (res & 0x70)
|
||||||
{
|
|
||||||
pcm_more_callback_type get_more = pcm_callback_for_more;
|
|
||||||
unsigned char *next_start;
|
|
||||||
size_t next_size = 0;
|
|
||||||
|
|
||||||
if (get_more)
|
|
||||||
get_more(&next_start, &next_size);
|
|
||||||
|
|
||||||
if (next_size > 0)
|
|
||||||
{
|
|
||||||
SAR0 = (unsigned long)next_start; /* Source address */
|
|
||||||
BCR0 = next_size; /* Bytes to transfer */
|
|
||||||
or_l(DMA_EEXT, &DCR0); /* Enable peripheral request */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Finished playing */
|
|
||||||
#if 0
|
|
||||||
/* int. logfs can trash the display */
|
|
||||||
logf("DMA0 No Data:0x%04x", res);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
/* Stop on error */
|
||||||
logf("DMA0 err: %02x", res);
|
logf("DMA0 err: %02x", res);
|
||||||
#if 0
|
#if 0
|
||||||
logf(" SAR0: %08x", SAR0);
|
logf(" SAR0: %08x", SAR0);
|
||||||
|
|
@ -328,6 +281,27 @@ void DMA0(void)
|
||||||
logf(" DCR0: %08x", DCR0);
|
logf(" DCR0: %08x", DCR0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcm_more_callback_type get_more = pcm_callback_for_more;
|
||||||
|
unsigned char *start;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
if (get_more)
|
||||||
|
get_more(&start, &size);
|
||||||
|
|
||||||
|
start = (unsigned char *)(((long)start + 3) & ~3);
|
||||||
|
size &= ~3;
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
SAR0 = (unsigned long)start; /* Source address */
|
||||||
|
BCR0 = size; /* Bytes to transfer */
|
||||||
|
or_l(DMA_EEXT | DMA_INT, &DCR0); /* per request and int ON */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Finished playing */
|
||||||
|
}
|
||||||
|
|
||||||
/* Stop interrupt and futher transfers */
|
/* Stop interrupt and futher transfers */
|
||||||
pcm_play_dma_stop();
|
pcm_play_dma_stop();
|
||||||
|
|
@ -337,8 +311,15 @@ void DMA0(void)
|
||||||
|
|
||||||
const void * pcm_play_dma_get_peak_buffer(int *count)
|
const void * pcm_play_dma_get_peak_buffer(int *count)
|
||||||
{
|
{
|
||||||
unsigned long addr = SAR0;
|
unsigned long addr, cnt;
|
||||||
int cnt = BCR0;
|
|
||||||
|
/* Make sure interrupt doesn't change the second value after we read the
|
||||||
|
* first value. */
|
||||||
|
int level = set_irq_level(DMA_IRQ_LEVEL);
|
||||||
|
addr = SAR0;
|
||||||
|
cnt = BCR0;
|
||||||
|
restore_irq(level);
|
||||||
|
|
||||||
*count = (cnt & 0xffffff) >> 2;
|
*count = (cnt & 0xffffff) >> 2;
|
||||||
return (void *)((addr + 2) & ~3);
|
return (void *)((addr + 2) & ~3);
|
||||||
} /* pcm_play_dma_get_peak_buffer */
|
} /* pcm_play_dma_get_peak_buffer */
|
||||||
|
|
@ -370,13 +351,15 @@ void pcm_rec_unlock(void)
|
||||||
void pcm_rec_dma_start(void *addr, size_t size)
|
void pcm_rec_dma_start(void *addr, size_t size)
|
||||||
{
|
{
|
||||||
/* stop any DMA in progress */
|
/* stop any DMA in progress */
|
||||||
and_l(~DMA_EEXT, &DCR1);
|
pcm_rec_dma_stop();
|
||||||
DSR1 = 1;
|
|
||||||
|
addr = (void *)(((long)addr + 3) & ~3);
|
||||||
|
size &= ~3;
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
|
and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
|
||||||
/* Clear TX FIFO reset bit if the source is not set to monitor playback
|
|
||||||
otherwise maintain independence between playback and recording. */
|
|
||||||
_pcm_dma_apply_settings(!is_playback_monitoring());
|
|
||||||
|
|
||||||
/* Start the DMA transfer.. */
|
/* Start the DMA transfer.. */
|
||||||
#ifdef HAVE_SPDIF_REC
|
#ifdef HAVE_SPDIF_REC
|
||||||
|
|
@ -384,10 +367,10 @@ void pcm_rec_dma_start(void *addr, size_t size)
|
||||||
INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
|
INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SAR1 = (unsigned long)&PDIR2; /* Source address */
|
|
||||||
pcm_rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */
|
pcm_rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */
|
||||||
DAR1 = (unsigned long)addr; /* Destination address */
|
SAR1 = (unsigned long)&PDIR2; /* Source address */
|
||||||
BCR1 = (unsigned long)size; /* Bytes to transfer */
|
DAR1 = (unsigned long)addr; /* Destination address */
|
||||||
|
BCR1 = (unsigned long)size; /* Bytes to transfer */
|
||||||
|
|
||||||
DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
|
DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
|
||||||
DMA_DSIZE(DMA_SIZE_LINE) | DMA_START;
|
DMA_DSIZE(DMA_SIZE_LINE) | DMA_START;
|
||||||
|
|
@ -397,9 +380,10 @@ void pcm_rec_dma_start(void *addr, size_t size)
|
||||||
|
|
||||||
void pcm_rec_dma_stop(void)
|
void pcm_rec_dma_stop(void)
|
||||||
{
|
{
|
||||||
DSR1 = 1; /* Clear interrupt */
|
and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */
|
||||||
DCR1 = 0;
|
DSR1 = 1; /* Clear interrupt, errors, stop transfer */
|
||||||
BCR1 = 0;
|
BCR1 = 0; /* No bytes received */
|
||||||
|
|
||||||
or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
|
or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
|
||||||
|
|
||||||
iis_play_reset_if_playback(false);
|
iis_play_reset_if_playback(false);
|
||||||
|
|
@ -422,6 +406,8 @@ void pcm_rec_dma_init(void)
|
||||||
|
|
||||||
void pcm_rec_dma_close(void)
|
void pcm_rec_dma_close(void)
|
||||||
{
|
{
|
||||||
|
pcm_rec_dma_stop();
|
||||||
|
|
||||||
and_l(0xffff00ff, &DMAROUTE);
|
and_l(0xffff00ff, &DMAROUTE);
|
||||||
ICR7 = 0x00; /* Disable interrupt */
|
ICR7 = 0x00; /* Disable interrupt */
|
||||||
dma_rec_lock.state = (0 << 15);
|
dma_rec_lock.state = (0 << 15);
|
||||||
|
|
@ -432,12 +418,12 @@ void pcm_rec_dma_close(void)
|
||||||
void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
|
void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
|
||||||
void DMA1(void)
|
void DMA1(void)
|
||||||
{
|
{
|
||||||
int res = DSR1;
|
unsigned long res = DSR1;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
pcm_more_callback_type2 more_ready;
|
pcm_more_callback_type2 more_ready;
|
||||||
|
|
||||||
DSR1 = 1; /* Clear interrupt */
|
and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */
|
||||||
and_l(~DMA_EEXT, &DCR1); /* Disable peripheral request */
|
DSR1 = 1; /* Clear interrupt and errors */
|
||||||
|
|
||||||
if (res & 0x70)
|
if (res & 0x70)
|
||||||
{
|
{
|
||||||
|
|
@ -468,10 +454,6 @@ void DMA1(void)
|
||||||
if (more_ready != NULL && more_ready(status) >= 0)
|
if (more_ready != NULL && more_ready(status) >= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* int. logfs can trash the display */
|
|
||||||
logf("DMA1 done:%04x %d", res, status);
|
|
||||||
#endif
|
|
||||||
/* Finished recording */
|
/* Finished recording */
|
||||||
pcm_rec_dma_stop();
|
pcm_rec_dma_stop();
|
||||||
/* Inform PCM that we're done */
|
/* Inform PCM that we're done */
|
||||||
|
|
@ -481,16 +463,32 @@ void DMA1(void)
|
||||||
/* Continue transferring data in - call from interrupt callback */
|
/* Continue transferring data in - call from interrupt callback */
|
||||||
void pcm_record_more(void *start, size_t size)
|
void pcm_record_more(void *start, size_t size)
|
||||||
{
|
{
|
||||||
|
start = (void *)(((long)start + 3) & ~3);
|
||||||
|
size &= ~3;
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
{
|
||||||
|
pcm_rec_dma_stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pcm_rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
|
pcm_rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
|
||||||
DAR1 = (unsigned long)start; /* Destination address */
|
DAR1 = (unsigned long)start; /* Destination address */
|
||||||
BCR1 = (unsigned long)size; /* Bytes to transfer */
|
BCR1 = (unsigned long)size; /* Bytes to transfer */
|
||||||
or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */
|
or_l(DMA_EEXT | DMA_INT, &DCR1); /* per request and int ON */
|
||||||
} /* pcm_record_more */
|
} /* pcm_record_more */
|
||||||
|
|
||||||
const void * pcm_rec_dma_get_peak_buffer(int *count)
|
const void * pcm_rec_dma_get_peak_buffer(int *count)
|
||||||
{
|
{
|
||||||
unsigned long addr = (unsigned long)pcm_rec_peak_addr;
|
unsigned long addr, end;
|
||||||
unsigned long end = DAR1;
|
|
||||||
|
/* Make sure interrupt doesn't change the second value after we read the
|
||||||
|
* first value. */
|
||||||
|
int level = set_irq_level(DMA_IRQ_LEVEL);
|
||||||
|
addr = (unsigned long)pcm_rec_peak_addr;
|
||||||
|
end = DAR1;
|
||||||
|
restore_irq(level);
|
||||||
|
|
||||||
addr >>= 2;
|
addr >>= 2;
|
||||||
*count = (end >> 2) - addr;
|
*count = (end >> 2) - addr;
|
||||||
return (void *)(addr << 2);
|
return (void *)(addr << 2);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue