Coldfire: Fix the modification of IMR. Interrupts must be masked at the core level at at least the level of the interrupt being masked. Not following the datasheet and relying strictly on and/or_l causes unhandled 'Levelx' exceptions (showing itself quite often in PCM mixer work which more greatly stresses PCM lockout).

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30009 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2011-06-17 03:09:47 +00:00
parent 7b605f0416
commit d4800fa385
7 changed files with 33 additions and 18 deletions

View file

@ -266,7 +266,7 @@ void lcd_init_device(void)
DSR3 = 1;
DIVR3 = 57; /* DMA3 is mapped into vector 57 in system.c */
ICR9 = (6 << 2); /* Enable DMA3 interrupt at level 6, priority 0 */
and_l(~(1<<17), &IMR);
coldfire_imr_mod(0, 1 << 17);
mutex_init(&lcd_mtx);
_display_on();

View file

@ -51,7 +51,7 @@ void tick_start(unsigned int interval_in_ms)
TER0 = 0xff; /* Clear all events */
ICR1 = 0x8c; /* Interrupt on level 3.0 */
IMR &= ~0x200;
coldfire_imr_mod(0x000, 0x200);
}
void TIMER0(void) __attribute__ ((interrupt_handler));

View file

@ -167,7 +167,7 @@ void lcd_init_device(void)
DSR3 = 1;
DIVR3 = 57; /* DMA3 is mapped into vector 57 in system.c */
ICR9 = (6 << 2); /* Enable DMA3 interrupt at level 6, priority 0 */
and_l(~(1<<17), &IMR);
coldfire_imr_mod(0, 1 << 17);
mutex_init(&lcd_mtx);

View file

@ -219,19 +219,19 @@ void pcm_postinit(void)
static struct dma_lock dma_play_lock =
{
.locked = 0,
.state = (0 << 14) /* bit 14 is DMA0 */
.state = (1 << 14) /* bit 14 is DMA0 */
};
void pcm_play_lock(void)
{
if (++dma_play_lock.locked == 1)
or_l((1 << 14), &IMR);
coldfire_imr_mod(1 << 14, 1 << 14);
}
void pcm_play_unlock(void)
{
if (--dma_play_lock.locked == 0)
and_l(~dma_play_lock.state, &IMR);
coldfire_imr_mod(dma_play_lock.state, 1 << 14);
}
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
@ -248,7 +248,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
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 = (0 << 14);
} /* pcm_play_dma_start */
/* Stops the DMA transfer and interrupt */
@ -260,7 +260,7 @@ void pcm_play_dma_stop(void)
iis_play_reset_if_playback(true);
dma_play_lock.state = (0 << 14);
dma_play_lock.state = (1 << 14);
} /* pcm_play_dma_stop */
void pcm_play_dma_pause(bool pause)
@ -271,14 +271,14 @@ void pcm_play_dma_pause(bool pause)
and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
DSR0 = 1; /* stop channel */
iis_play_reset_if_playback(true);
dma_play_lock.state = (0 << 14);
dma_play_lock.state = (1 << 14);
}
else
{
/* restart playback on current buffer */
iis_play_reset_if_playback(true);
or_l(DMA_INT | DMA_EEXT | DMA_START, &DCR0); /* everything ON */
dma_play_lock.state = (1 << 14);
dma_play_lock.state = (0 << 14);
}
} /* pcm_play_dma_pause */
@ -344,7 +344,7 @@ const void * pcm_play_dma_get_peak_buffer(int *count)
static struct dma_lock dma_rec_lock =
{
.locked = 0,
.state = (0 << 15) /* bit 15 is DMA1 */
.state = (1 << 15) /* bit 15 is DMA1 */
};
/* For the locks, DMA interrupt must be disabled when manipulating the lock
@ -353,13 +353,13 @@ static struct dma_lock dma_rec_lock =
void pcm_rec_lock(void)
{
if (++dma_rec_lock.locked == 1)
or_l((1 << 15), &IMR);
coldfire_imr_mod(1 << 15, 1 << 15);
}
void pcm_rec_unlock(void)
{
if (--dma_rec_lock.locked == 0)
and_l(~dma_rec_lock.state, &IMR);
coldfire_imr_mod(dma_rec_lock.state, 1 << 15);
}
void pcm_rec_dma_start(void *addr, size_t size)
@ -382,7 +382,7 @@ void pcm_rec_dma_start(void *addr, size_t size)
DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
DMA_DSIZE(DMA_SIZE_LINE) | DMA_START;
dma_rec_lock.state = (1 << 15);
dma_rec_lock.state = (0 << 15);
} /* pcm_rec_dma_start */
void pcm_rec_dma_stop(void)
@ -395,7 +395,7 @@ void pcm_rec_dma_stop(void)
iis_play_reset_if_playback(false);
dma_rec_lock.state = (0 << 15);
dma_rec_lock.state = (1 << 15);
} /* pcm_rec_dma_stop */
void pcm_rec_dma_init(void)

View file

@ -268,7 +268,7 @@ void system_init(void)
will do. */
coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
IMR = 0x3ffff;
coldfire_imr_mod(0x3ffff, 0x3ffff);
INTPRI1 = 0;
INTPRI2 = 0;
INTPRI3 = 0;
@ -365,6 +365,16 @@ void coldfire_set_pllcr_audio_bits(long bits)
PLLCR = (PLLCR & ~0x70400000) | (bits & 0x70400000);
}
/* Safely modify the interrupt mask register as the core interrupt level is
required to be at least as high as the level interrupt being
masked/unmasked */
void coldfire_imr_mod(unsigned long bits, unsigned long mask)
{
unsigned long oldlevel = set_irq_level(DISABLE_INTERRUPTS);
IMR = (IMR & ~mask) | (bits & mask);
restore_irq(oldlevel);
}
/* Set DATAINCONTROL without disturbing FIFO reset state */
void coldfire_set_dataincontrol(unsigned long value)
{

View file

@ -201,6 +201,11 @@ static inline uint32_t swap_odd_even32_hw(uint32_t value)
#define DEFAULT_PLLCR_AUDIO_BITS 0x10400000
void coldfire_set_pllcr_audio_bits(long bits);
/* Safely modify the interrupt mask register as the core interrupt level is
required to be at least as high as the level interrupt being
masked/unmasked */
void coldfire_imr_mod(unsigned long bits, unsigned long mask);
/* Set DATAINCONTROL without disturbing FIFO reset state */
void coldfire_set_dataincontrol(unsigned long value);

View file

@ -89,7 +89,7 @@ bool timer_set(long cycles, bool start)
bool timer_start(void)
{
ICR2 = 0x90; /* interrupt on level 4.0 */
and_l(~(1<<10), &IMR);
coldfire_imr_mod(0, 1 << 10);
TMR1 |= 1; /* start timer */
return true;
}
@ -97,7 +97,7 @@ bool timer_start(void)
void timer_stop(void)
{
TMR1 = 0; /* disable timer 1 */
or_l((1<<10), &IMR); /* disable interrupt */
coldfire_imr_mod(1 << 10, 1 << 10); /* disable interrupt */
}
void timers_adjust_prescale(int multiplier, bool enable_irq)