mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-29 13:03:36 +01:00
cpg, tmu: add spin waiting and spin delay functions for drivers
This change adds a new TMU function timer_spinwait() which waits for a timer to raise its UNF flag. This makes it possible to wait even when interrupts are disabled. This is used by the new CPG function sleep_us_spin() which waits for a given delay without using interrupts. This is currently used in SPU initialization.
This commit is contained in:
parent
858ec8aa12
commit
8ff7d89d33
5 changed files with 50 additions and 10 deletions
|
@ -67,6 +67,11 @@ const clock_frequency_t *clock_freq(void);
|
||||||
function selects a timer with timer_setup() called with TIMER_ANY. */
|
function selects a timer with timer_setup() called with TIMER_ANY. */
|
||||||
void sleep_us(uint64_t delay_us);
|
void sleep_us(uint64_t delay_us);
|
||||||
|
|
||||||
|
/* sleep_us_spin(): Actively sleep for a fixed duration in microseconds
|
||||||
|
Like sleep_us(), but uses timer_spinwait() and does not rely on interrupts
|
||||||
|
being enabled. Useful in timer code running without interrupts. */
|
||||||
|
void sleep_us_spin(uint64_t delay_us);
|
||||||
|
|
||||||
/* sleep_ms(): Sleep for a fixed duration in milliseconds */
|
/* sleep_ms(): Sleep for a fixed duration in milliseconds */
|
||||||
#define sleep_ms(delay_ms) sleep_us((delay_ms) * 1000ull)
|
#define sleep_ms(delay_ms) sleep_us((delay_ms) * 1000ull)
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
* Set a specific ID in timer_setup(), in which case the delay is no longer
|
* Set a specific ID in timer_setup(), in which case the delay is no longer
|
||||||
interpreter as count of µs, but as a TCOR value.
|
interpreter as count of µs, but as a TCOR value.
|
||||||
* If this ID is a TMU, you can further add (with + or |) a prescaler
|
* If this ID is a TMU, you can further add (with + or |) a prescaler
|
||||||
specification, one of TIMER_Po_{4,16,64,256}.
|
specification, one of TIMER_Pphi_{4,16,64,256}.
|
||||||
* Regardless of how the timer was obtained, you can use timer_reload() to
|
* Regardless of how the timer was obtained, you can use timer_reload() to
|
||||||
replace the value of TCOR.
|
replace the value of TCOR.
|
||||||
* Also note that TMU0, TMU1, TMU2 and the ETMU have respective interrupt
|
* Also note that TMU0, TMU1, TMU2 and the ETMU have respective interrupt
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
Standard TMU can count at different speeds. A fast speed offers more
|
Standard TMU can count at different speeds. A fast speed offers more
|
||||||
precision but a slower speed offers longer delays. gint automatically
|
precision but a slower speed offers longer delays. gint automatically
|
||||||
selects suitable speed by default.
|
selects suitable speeds by default.
|
||||||
|
|
||||||
If you want something very particular, you can add (with + or |) a prescaler
|
If you want something very particular, you can add (with + or |) a prescaler
|
||||||
value to a chosen ID in timer_setup() to request that specific value. The
|
value to a chosen ID in timer_setup() to request that specific value. The
|
||||||
|
@ -186,6 +186,12 @@ void timer_stop(int timer);
|
||||||
it may have only paused. If the timer never stops, you're in trouble. */
|
it may have only paused. If the timer never stops, you're in trouble. */
|
||||||
void timer_wait(int timer);
|
void timer_wait(int timer);
|
||||||
|
|
||||||
|
/* timer_spinwait(): Actively wait for a timer to raise UNF
|
||||||
|
Waits until the timer raises UNF, without sleeping. This is useful for
|
||||||
|
delays in driver code that is run when interrupts are disabled. This relies
|
||||||
|
neither on the interrupt signal nor on the UNIE flag. */
|
||||||
|
void timer_spinwait(int timer);
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Low-level functions
|
// Low-level functions
|
||||||
//---
|
//---
|
||||||
|
|
|
@ -56,7 +56,9 @@ static void sh7705_probe(void)
|
||||||
/* Deduce the frequency of the main clocks. This value is ckio/3 */
|
/* Deduce the frequency of the main clocks. This value is ckio/3 */
|
||||||
int ckio_3 = 9830400;
|
int ckio_3 = 9830400;
|
||||||
|
|
||||||
/* Exchange the setting values 2 and 3 */
|
/* Exchange the setting values 2 and 3 (corresponding to /3 and /4)
|
||||||
|
This means that /1, /2, /4 are now 0, 1, 2, which is perfect for a
|
||||||
|
quick bit shift */
|
||||||
idiv = idiv ^ (idiv >> 1);
|
idiv = idiv ^ (idiv >> 1);
|
||||||
pdiv = pdiv ^ (pdiv >> 1);
|
pdiv = pdiv ^ (pdiv >> 1);
|
||||||
|
|
||||||
|
@ -87,8 +89,8 @@ static void sh7305_probe(void)
|
||||||
if(CPG.FLLFRQ.SELXM == 1) fll >>= 1;
|
if(CPG.FLLFRQ.SELXM == 1) fll >>= 1;
|
||||||
freq.FLL = fll;
|
freq.FLL = fll;
|
||||||
|
|
||||||
/* On SH7724, the divider ratio is given by 1 / (setting + 1), but
|
/* On SH7724, the divider ratio is given by 1 / (setting + 1), but on
|
||||||
SH7305 behaves as 1 / (2^setting + 1). */
|
the SH7305 it is 1 / (2^setting + 1). */
|
||||||
|
|
||||||
int divb = CPG.FRQCRA.BFC;
|
int divb = CPG.FRQCRA.BFC;
|
||||||
int divi = CPG.FRQCRA.IFC;
|
int divi = CPG.FRQCRA.IFC;
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
#include <gint/clock.h>
|
#include <gint/clock.h>
|
||||||
#include <gint/timer.h>
|
#include <gint/timer.h>
|
||||||
|
|
||||||
/* sleep_us(): Sleep for a fixed duration in microseconds */
|
static void do_sleep(uint64_t delay_us, int spin)
|
||||||
void sleep_us(uint64_t delay_us)
|
|
||||||
{
|
{
|
||||||
volatile int flag = 0;
|
volatile int flag = 0;
|
||||||
|
|
||||||
|
@ -14,5 +13,18 @@ void sleep_us(uint64_t delay_us)
|
||||||
if(timer < 0) return;
|
if(timer < 0) return;
|
||||||
|
|
||||||
timer_start(timer);
|
timer_start(timer);
|
||||||
timer_wait(timer);
|
if(spin) timer_spinwait(timer);
|
||||||
|
else timer_wait(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sleep_us(): Sleep for a fixed duration in microseconds */
|
||||||
|
void sleep_us(uint64_t delay_us)
|
||||||
|
{
|
||||||
|
do_sleep(delay_us, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sleep_us_spin(): Actively sleep for a fixed duration in microseconds */
|
||||||
|
void sleep_us_spin(uint64_t delay_us)
|
||||||
|
{
|
||||||
|
do_sleep(delay_us, 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,13 +261,13 @@ void timer_stop(int id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* timer_wait() - wait until a timer is stopped */
|
/* timer_wait(): Wait for a timer to stop */
|
||||||
void timer_wait(int id)
|
void timer_wait(int id)
|
||||||
{
|
{
|
||||||
if(id < 3)
|
if(id < 3)
|
||||||
{
|
{
|
||||||
tmu_t *T = &TMU[id];
|
tmu_t *T = &TMU[id];
|
||||||
/* Sleep if an interruption will wake us up */
|
/* Sleep only if an interrupt will be there to wake us up */
|
||||||
while(*TSTR & (1 << id)) if(T->TCR.UNIE) sleep();
|
while(*TSTR & (1 << id)) if(T->TCR.UNIE) sleep();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -277,6 +277,21 @@ void timer_wait(int id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* timer_spinwait(): Actively wait for a timer to raise UNF */
|
||||||
|
void timer_spinwait(int id)
|
||||||
|
{
|
||||||
|
if(id < 3)
|
||||||
|
{
|
||||||
|
tmu_t *T = &TMU[id];
|
||||||
|
while(!T->TCR.UNF) {}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
etmu_t *T = &ETMU[id-3];
|
||||||
|
while(!T->TCR.UNF) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Predefined timer callbacks
|
// Predefined timer callbacks
|
||||||
//---
|
//---
|
||||||
|
|
Loading…
Reference in a new issue