mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43: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. */
|
||||
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 */
|
||||
#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
|
||||
interpreter as count of µs, but as a TCOR value.
|
||||
* 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
|
||||
replace the value of TCOR.
|
||||
* 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
|
||||
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
|
||||
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. */
|
||||
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
|
||||
//---
|
||||
|
|
|
@ -56,7 +56,9 @@ static void sh7705_probe(void)
|
|||
/* Deduce the frequency of the main clocks. This value is ckio/3 */
|
||||
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);
|
||||
pdiv = pdiv ^ (pdiv >> 1);
|
||||
|
||||
|
@ -87,8 +89,8 @@ static void sh7305_probe(void)
|
|||
if(CPG.FLLFRQ.SELXM == 1) fll >>= 1;
|
||||
freq.FLL = fll;
|
||||
|
||||
/* On SH7724, the divider ratio is given by 1 / (setting + 1), but
|
||||
SH7305 behaves as 1 / (2^setting + 1). */
|
||||
/* On SH7724, the divider ratio is given by 1 / (setting + 1), but on
|
||||
the SH7305 it is 1 / (2^setting + 1). */
|
||||
|
||||
int divb = CPG.FRQCRA.BFC;
|
||||
int divi = CPG.FRQCRA.IFC;
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
#include <gint/clock.h>
|
||||
#include <gint/timer.h>
|
||||
|
||||
/* sleep_us(): Sleep for a fixed duration in microseconds */
|
||||
void sleep_us(uint64_t delay_us)
|
||||
static void do_sleep(uint64_t delay_us, int spin)
|
||||
{
|
||||
volatile int flag = 0;
|
||||
|
||||
|
@ -14,5 +13,18 @@ void sleep_us(uint64_t delay_us)
|
|||
if(timer < 0) return;
|
||||
|
||||
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)
|
||||
{
|
||||
if(id < 3)
|
||||
{
|
||||
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();
|
||||
}
|
||||
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
|
||||
//---
|
||||
|
|
Loading…
Reference in a new issue