meg-fx: It's important to make sure certain interrupt-related registers have bits changed atomically.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16894 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2008-03-31 01:29:50 +00:00
parent 241fd0fbdb
commit a65406e3f4
7 changed files with 59 additions and 34 deletions

View file

@ -17,6 +17,7 @@
* *
****************************************************************************/ ****************************************************************************/
#include "cpu.h" #include "cpu.h"
#include "system.h"
#include "adc-target.h" #include "adc-target.h"
#include "kernel.h" #include "kernel.h"
@ -35,7 +36,7 @@ void adc_init(void)
int i; int i;
/* Turn on the ADC PCLK */ /* Turn on the ADC PCLK */
CLKCON |= (1<<15); s3c_regset(&CLKCON, 1<<15);
/* Set channel 0, normal mode, disable "start by read" */ /* Set channel 0, normal mode, disable "start by read" */
ADCCON &= ~(0x3F); ADCCON &= ~(0x3F);

View file

@ -41,7 +41,7 @@ void i2c_write(int addr, const unsigned char *buf, int count)
mutex_lock(&i2c_mtx); mutex_lock(&i2c_mtx);
/* Turn on I2C clock */ /* Turn on I2C clock */
CLKCON |= (1 << 16); s3c_regset(&CLKCON, 1 << 16);
/* Set mode to master transmitter and enable lines */ /* Set mode to master transmitter and enable lines */
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB; IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
@ -74,7 +74,7 @@ void i2c_write(int addr, const unsigned char *buf, int count)
IICSTAT = 0; IICSTAT = 0;
/* Turn off I2C clock */ /* Turn off I2C clock */
CLKCON &= ~(1 << 16); s3c_regclr(&CLKCON, 1 << 16);
mutex_unlock(&i2c_mtx); mutex_unlock(&i2c_mtx);
} }
@ -90,11 +90,11 @@ void i2c_init(void)
INTPND = IIC_MASK; INTPND = IIC_MASK;
/* Enable i2c interrupt in controller */ /* Enable i2c interrupt in controller */
INTMOD &= ~IIC_MASK; s3c_regclr(&INTMOD, IIC_MASK);
INTMSK &= ~IIC_MASK; s3c_regclr(&INTMSK, IIC_MASK);
/* Turn on I2C clock */ /* Turn on I2C clock */
CLKCON |= (1 << 16); s3c_regset(&CLKCON, 1 << 16);
/* Set GPE15 (IICSDA) and GPE14 (IICSCL) to IIC */ /* Set GPE15 (IICSDA) and GPE14 (IICSCL) to IIC */
GPECON = (GPECON & ~((3 << 30) | (3 << 28))) | GPECON = (GPECON & ~((3 << 30) | (3 << 28))) |
@ -108,7 +108,7 @@ void i2c_init(void)
IICLC = (0 << 0); IICLC = (0 << 0);
/* Turn off I2C clock */ /* Turn off I2C clock */
CLKCON &= ~(1 << 16); s3c_regclr(&CLKCON, 1 << 16);
} }
void IIC(void) void IIC(void)

View file

@ -1,4 +1,5 @@
#include "config.h" #include "config.h"
#include "system.h"
#include "cpu.h" #include "cpu.h"
#include "string.h" #include "string.h"
#include "lcd.h" #include "lcd.h"
@ -81,7 +82,7 @@ void SPI_Send_Bytes(const unsigned char *array, int count)
void Setup_LCD_SPI(void) void Setup_LCD_SPI(void)
{ {
CLKCON|=0x40000; s3c_regset(&CLKCON, 0x40000);
SPI_LCD_CS(false); SPI_LCD_CS(false);
SPCON0=0x3E; SPCON0=0x3E;
SPPRE0=24; SPPRE0=24;
@ -147,7 +148,7 @@ void lcd_init_device(void)
lcd_poweroff = false; lcd_poweroff = false;
#endif #endif
CLKCON |= 0x20; /* enable LCD clock */ s3c_regset(&CLKCON, 0x20); /* enable LCD clock */
Setup_LCD_SPI(); Setup_LCD_SPI();
@ -204,7 +205,7 @@ void lcd_init_device(void)
SPI_Send_Bytes(initbuf, sizeof(initbuf)); SPI_Send_Bytes(initbuf, sizeof(initbuf));
SPI_LCD_CS(false); SPI_LCD_CS(false);
CLKCON &= ~0x40000; /* disable SPI clock */ s3c_regclr(&CLKCON, 0x40000); /* disable SPI clock */
} }
/* Update a fraction of the display. */ /* Update a fraction of the display. */

View file

@ -38,7 +38,7 @@ static struct
} dma_play_lock = } dma_play_lock =
{ {
.locked = 0, .locked = 0,
.state = (0<<19) .state = 0,
}; };
/* Last samplerate set by pcm_set_frequency */ /* Last samplerate set by pcm_set_frequency */
@ -71,22 +71,18 @@ void pcm_apply_settings(void)
restore_fiq(status); restore_fiq(status);
} }
/* For the locks, DMA interrupt must be disabled because the handler /* Mask the DMA interrupt */
manipulates INTMSK and the operation is not atomic */
void pcm_play_lock(void) void pcm_play_lock(void)
{ {
int status = disable_fiq_save();
if (++dma_play_lock.locked == 1) if (++dma_play_lock.locked == 1)
INTMSK |= (1<<19); /* Mask the DMA interrupt */ s3c_regset(&INTMSK, DMA2_MASK);
restore_fiq(status);
} }
/* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void) void pcm_play_unlock(void)
{ {
int status = disable_fiq_save();
if (--dma_play_lock.locked == 0) if (--dma_play_lock.locked == 0)
INTMSK &= ~dma_play_lock.state; /* Unmask the DMA interrupt if enabled */ s3c_regclr(&INTMSK, dma_play_lock.state);
restore_fiq(status);
} }
void pcm_play_dma_init(void) void pcm_play_dma_init(void)
@ -110,11 +106,11 @@ void pcm_play_dma_init(void)
/* Do not service DMA requests, yet */ /* Do not service DMA requests, yet */
/* clear any pending int and mask it */ /* clear any pending int and mask it */
INTMSK |= (1<<19); s3c_regset(&INTMSK, DMA2_MASK);
SRCPND = (1<<19); SRCPND = DMA2_MASK;
/* connect to FIQ */ /* connect to FIQ */
INTMOD |= (1<<19); s3c_regset(&INTMOD, DMA2_MASK);
} }
void pcm_postinit(void) void pcm_postinit(void)
@ -127,7 +123,7 @@ void pcm_postinit(void)
static void play_start_pcm(void) static void play_start_pcm(void)
{ {
/* clear pending DMA interrupt */ /* clear pending DMA interrupt */
SRCPND = (1<<19); SRCPND = DMA2_MASK;
_pcm_apply_settings(); _pcm_apply_settings();
@ -135,7 +131,7 @@ static void play_start_pcm(void)
clean_dcache_range((void*)DISRC2, (DCON2 & 0xFFFFF) * 2); clean_dcache_range((void*)DISRC2, (DCON2 & 0xFFFFF) * 2);
/* unmask DMA interrupt when unlocking */ /* unmask DMA interrupt when unlocking */
dma_play_lock.state = (1<<19); dma_play_lock.state = DMA2_MASK;
/* turn on the request */ /* turn on the request */
IISCON |= (1<<5); IISCON |= (1<<5);
@ -154,7 +150,7 @@ static void play_start_pcm(void)
static void play_stop_pcm(void) static void play_stop_pcm(void)
{ {
/* Mask DMA interrupt */ /* Mask DMA interrupt */
INTMSK |= (1<<19); s3c_regset(&INTMSK, DMA2_MASK);
/* De-Activate the DMA channel */ /* De-Activate the DMA channel */
DMASKTRIG2 = 0x4; DMASKTRIG2 = 0x4;
@ -182,7 +178,7 @@ static void play_stop_pcm(void)
void pcm_play_dma_start(const void *addr, size_t size) void pcm_play_dma_start(const void *addr, size_t size)
{ {
/* Enable the IIS clock */ /* Enable the IIS clock */
CLKCON |= (1<<17); s3c_regset(&CLKCON, 1<<17);
/* stop any DMA in progress - idle IIS */ /* stop any DMA in progress - idle IIS */
play_stop_pcm(); play_stop_pcm();
@ -217,7 +213,7 @@ void pcm_play_dma_stop(void)
play_stop_pcm(); play_stop_pcm();
/* Disconnect the IIS clock */ /* Disconnect the IIS clock */
CLKCON &= ~(1<<17); s3c_regclr(&CLKCON, 1<<17);
} }
void pcm_play_dma_pause(bool pause) void pcm_play_dma_pause(bool pause)
@ -245,7 +241,7 @@ void fiq_handler(void)
register pcm_more_callback_type get_more; /* No stack for this */ register pcm_more_callback_type get_more; /* No stack for this */
/* clear any pending interrupt */ /* clear any pending interrupt */
SRCPND = (1<<19); SRCPND = DMA2_MASK;
/* Buffer empty. Try to get more. */ /* Buffer empty. Try to get more. */
get_more = pcm_callback_for_more; get_more = pcm_callback_for_more;

View file

@ -104,6 +104,24 @@ void memory_init(void) {
enable_mmu(); enable_mmu();
} }
void s3c_regmod(volatile int *reg, unsigned int set, unsigned int clr)
{
int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
unsigned int val = *reg;
*reg = (val | set) & ~clr;
restore_interrupt(oldstatus);
}
void s3c_regset(volatile int *reg, unsigned int mask)
{
s3c_regmod(reg, mask, 0);
}
void s3c_regclr(volatile int *reg, unsigned int mask)
{
s3c_regmod(reg, 0, mask);
}
void system_init(void) void system_init(void)
{ {
/* Disable interrupts and set all to IRQ mode */ /* Disable interrupts and set all to IRQ mode */

View file

@ -26,6 +26,15 @@
#define CPUFREQ_NORMAL 98784000 #define CPUFREQ_NORMAL 98784000
#define CPUFREQ_MAX 296352000 #define CPUFREQ_MAX 296352000
/* Functions to set and clear regiser bits atomically */
/* Set and clear register bits */
void s3c_regmod(volatile int *reg, unsigned int set, unsigned int clr);
/* Set register bits */
void s3c_regset(volatile int *reg, unsigned int mask);
/* Clear register bits */
void s3c_regclr(volatile int *reg, unsigned int mask);
#define HAVE_INVALIDATE_ICACHE #define HAVE_INVALIDATE_ICACHE
static inline void invalidate_icache(void) static inline void invalidate_icache(void)
{ {

View file

@ -89,7 +89,7 @@ bool __timer_register(void)
{ {
bool retval = true; bool retval = true;
int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
stop_timer(); stop_timer();
@ -115,14 +115,14 @@ bool __timer_register(void)
retval = false; retval = false;
} }
set_interrupt_status(oldstatus, IRQ_FIQ_STATUS); restore_interrupt(oldstatus);
return retval; return retval;
} }
void __timer_unregister(void) void __timer_unregister(void)
{ {
int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
stop_timer(); stop_timer();
set_interrupt_status(oldstatus, IRQ_FIQ_STATUS); restore_interrupt(oldstatus);
} }