From a65406e3f48daed80f4d1b8627fae38a683fecb6 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Mon, 31 Mar 2008 01:29:50 +0000 Subject: 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 --- .../target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c | 3 +- .../target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c | 12 ++++---- .../target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c | 9 +++--- .../target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c | 32 ++++++++++------------ .../target/arm/s3c2440/gigabeat-fx/system-meg-fx.c | 20 +++++++++++++- .../target/arm/s3c2440/gigabeat-fx/system-target.h | 9 ++++++ .../target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c | 8 +++--- 7 files changed, 59 insertions(+), 34 deletions(-) diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c index 4c448c2e41..9a934c2487 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c @@ -17,6 +17,7 @@ * ****************************************************************************/ #include "cpu.h" +#include "system.h" #include "adc-target.h" #include "kernel.h" @@ -35,7 +36,7 @@ void adc_init(void) int i; /* Turn on the ADC PCLK */ - CLKCON |= (1<<15); + s3c_regset(&CLKCON, 1<<15); /* Set channel 0, normal mode, disable "start by read" */ ADCCON &= ~(0x3F); diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c index 7e4e608e15..c5d23a3673 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c @@ -41,7 +41,7 @@ void i2c_write(int addr, const unsigned char *buf, int count) mutex_lock(&i2c_mtx); /* Turn on I2C clock */ - CLKCON |= (1 << 16); + s3c_regset(&CLKCON, 1 << 16); /* Set mode to master transmitter and enable lines */ 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; /* Turn off I2C clock */ - CLKCON &= ~(1 << 16); + s3c_regclr(&CLKCON, 1 << 16); mutex_unlock(&i2c_mtx); } @@ -90,11 +90,11 @@ void i2c_init(void) INTPND = IIC_MASK; /* Enable i2c interrupt in controller */ - INTMOD &= ~IIC_MASK; - INTMSK &= ~IIC_MASK; + s3c_regclr(&INTMOD, IIC_MASK); + s3c_regclr(&INTMSK, IIC_MASK); /* Turn on I2C clock */ - CLKCON |= (1 << 16); + s3c_regset(&CLKCON, 1 << 16); /* Set GPE15 (IICSDA) and GPE14 (IICSCL) to IIC */ GPECON = (GPECON & ~((3 << 30) | (3 << 28))) | @@ -108,7 +108,7 @@ void i2c_init(void) IICLC = (0 << 0); /* Turn off I2C clock */ - CLKCON &= ~(1 << 16); + s3c_regclr(&CLKCON, 1 << 16); } void IIC(void) diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c index 0d532f62c9..e6a70c9f23 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c @@ -1,4 +1,5 @@ #include "config.h" +#include "system.h" #include "cpu.h" #include "string.h" #include "lcd.h" @@ -81,7 +82,7 @@ void SPI_Send_Bytes(const unsigned char *array, int count) void Setup_LCD_SPI(void) { - CLKCON|=0x40000; + s3c_regset(&CLKCON, 0x40000); SPI_LCD_CS(false); SPCON0=0x3E; SPPRE0=24; @@ -146,8 +147,8 @@ void lcd_init_device(void) #if !defined(BOOTLOADER) lcd_poweroff = false; #endif - - CLKCON |= 0x20; /* enable LCD clock */ + + s3c_regset(&CLKCON, 0x20); /* enable LCD clock */ Setup_LCD_SPI(); @@ -204,7 +205,7 @@ void lcd_init_device(void) SPI_Send_Bytes(initbuf, sizeof(initbuf)); SPI_LCD_CS(false); - CLKCON &= ~0x40000; /* disable SPI clock */ + s3c_regclr(&CLKCON, 0x40000); /* disable SPI clock */ } /* Update a fraction of the display. */ diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c index 00be543bb6..6014f4d3af 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c @@ -38,7 +38,7 @@ static struct } dma_play_lock = { .locked = 0, - .state = (0<<19) + .state = 0, }; /* Last samplerate set by pcm_set_frequency */ @@ -71,22 +71,18 @@ void pcm_apply_settings(void) restore_fiq(status); } -/* For the locks, DMA interrupt must be disabled because the handler - manipulates INTMSK and the operation is not atomic */ +/* Mask the DMA interrupt */ void pcm_play_lock(void) { - int status = disable_fiq_save(); if (++dma_play_lock.locked == 1) - INTMSK |= (1<<19); /* Mask the DMA interrupt */ - restore_fiq(status); + s3c_regset(&INTMSK, DMA2_MASK); } +/* Unmask the DMA interrupt if enabled */ void pcm_play_unlock(void) { - int status = disable_fiq_save(); if (--dma_play_lock.locked == 0) - INTMSK &= ~dma_play_lock.state; /* Unmask the DMA interrupt if enabled */ - restore_fiq(status); + s3c_regclr(&INTMSK, dma_play_lock.state); } void pcm_play_dma_init(void) @@ -110,11 +106,11 @@ void pcm_play_dma_init(void) /* Do not service DMA requests, yet */ /* clear any pending int and mask it */ - INTMSK |= (1<<19); - SRCPND = (1<<19); + s3c_regset(&INTMSK, DMA2_MASK); + SRCPND = DMA2_MASK; /* connect to FIQ */ - INTMOD |= (1<<19); + s3c_regset(&INTMOD, DMA2_MASK); } void pcm_postinit(void) @@ -127,7 +123,7 @@ void pcm_postinit(void) static void play_start_pcm(void) { /* clear pending DMA interrupt */ - SRCPND = (1<<19); + SRCPND = DMA2_MASK; _pcm_apply_settings(); @@ -135,7 +131,7 @@ static void play_start_pcm(void) clean_dcache_range((void*)DISRC2, (DCON2 & 0xFFFFF) * 2); /* unmask DMA interrupt when unlocking */ - dma_play_lock.state = (1<<19); + dma_play_lock.state = DMA2_MASK; /* turn on the request */ IISCON |= (1<<5); @@ -154,7 +150,7 @@ static void play_start_pcm(void) static void play_stop_pcm(void) { /* Mask DMA interrupt */ - INTMSK |= (1<<19); + s3c_regset(&INTMSK, DMA2_MASK); /* De-Activate the DMA channel */ DMASKTRIG2 = 0x4; @@ -182,7 +178,7 @@ static void play_stop_pcm(void) void pcm_play_dma_start(const void *addr, size_t size) { /* Enable the IIS clock */ - CLKCON |= (1<<17); + s3c_regset(&CLKCON, 1<<17); /* stop any DMA in progress - idle IIS */ play_stop_pcm(); @@ -217,7 +213,7 @@ void pcm_play_dma_stop(void) play_stop_pcm(); /* Disconnect the IIS clock */ - CLKCON &= ~(1<<17); + s3c_regclr(&CLKCON, 1<<17); } 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 */ /* clear any pending interrupt */ - SRCPND = (1<<19); + SRCPND = DMA2_MASK; /* Buffer empty. Try to get more. */ get_more = pcm_callback_for_more; diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c index 19e9bed1e1..f789827d80 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c @@ -104,6 +104,24 @@ void memory_init(void) { 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) { /* Disable interrupts and set all to IRQ mode */ @@ -146,7 +164,7 @@ void system_init(void) /* Turn off NAND flash controller */ | (1 << 4) - + ); /* Turn off the USB PLL */ diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h index 2fab652596..5df02effa9 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h +++ b/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h @@ -26,6 +26,15 @@ #define CPUFREQ_NORMAL 98784000 #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 static inline void invalidate_icache(void) { diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c index b59e95806d..574083373a 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c @@ -89,7 +89,7 @@ bool __timer_register(void) { bool retval = true; - int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); + int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS); stop_timer(); @@ -115,14 +115,14 @@ bool __timer_register(void) retval = false; } - set_interrupt_status(oldstatus, IRQ_FIQ_STATUS); + restore_interrupt(oldstatus); return retval; } 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(); - set_interrupt_status(oldstatus, IRQ_FIQ_STATUS); + restore_interrupt(oldstatus); } -- cgit v1.2.3