mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 21:25:19 -05:00
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:
parent
241fd0fbdb
commit
a65406e3f4
7 changed files with 59 additions and 34 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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. */
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue