VxKernel 0.6.0-20 : Add POWER management
@add <> driver/mpu/sh/sh7305 | [power] add power hardware module <> driver/screen | [r61524] add triple buffering (DMA) @update <> driver/mpu/sh/sh7305 | [dma] proper power handling | [intc] proper power handling | [keysc] proper power handling | [intc] proper power handling | [tmu] proper power handling | [tmu] isolate FPS API | [tmu] isolate profiling API @fix <> driver/mpu/sh/sh7305 | [tmu] proper expose FPS functions
This commit is contained in:
parent
b8abc2eae7
commit
0bf4f487c7
|
@ -0,0 +1,120 @@
|
|||
#ifndef __VHEX_DRIVER_MPU_SH_SH7305_POWER__
|
||||
# define __VHEX_DRIVER_MPU_SH_SH7305_POWER__
|
||||
|
||||
#include <vhex/defs/attributes.h>
|
||||
|
||||
struct __sh7305_power
|
||||
{
|
||||
/* Standby Control Register: only one of the bits may be set at any
|
||||
given time. Setting several bits is prohibited! */
|
||||
lword_union(STBCR,
|
||||
uint32_t :24;
|
||||
uint32_t STBY :1; /* Map [sleep] to standby mode */
|
||||
uint32_t :1;
|
||||
uint32_t RSTBY :1; /* Map [sleep] to R-standby mode */
|
||||
uint32_t :1;
|
||||
uint32_t :4;
|
||||
);
|
||||
pad(12);
|
||||
|
||||
/* Module Stop Control Register 0
|
||||
Stopping the TLB (bit 31), IC (bit 30 or OC (bit 29) seems somewhat
|
||||
dangerous, plus requires special operations. */
|
||||
lword_union(MSTPCR0,
|
||||
uint32_t TLB :1;
|
||||
uint32_t IC :1;
|
||||
uint32_t OC :1;
|
||||
uint32_t RS :1;
|
||||
|
||||
uint32_t IL :1;
|
||||
uint32_t SndCache :1;
|
||||
uint32_t _unknown1 :1;
|
||||
uint32_t :1;
|
||||
|
||||
uint32_t :1;
|
||||
uint32_t INTC :1;
|
||||
uint32_t DMA :1;
|
||||
uint32_t SuperHyway :1;
|
||||
|
||||
uint32_t HUDI :1;
|
||||
uint32_t _unknown2 :1;
|
||||
uint32_t UBC :1;
|
||||
uint32_t :1;
|
||||
|
||||
uint32_t TMU :1;
|
||||
uint32_t CMT :1;
|
||||
uint32_t RWDT :1;
|
||||
uint32_t _high :1;
|
||||
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
|
||||
uint32_t SCIF :1;
|
||||
uint32_t KEYSC :1;
|
||||
uint32_t RTC :1;
|
||||
uint32_t :1;
|
||||
|
||||
uint32_t :1;
|
||||
uint32_t MSIOF0 :1;
|
||||
uint32_t MSIOF1 :1;
|
||||
uint32_t :1;
|
||||
);
|
||||
pad(4);
|
||||
|
||||
/* Module Stop Control Register 2 */
|
||||
lword_union(MSTPCR2,
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
uint32_t MMC :1;
|
||||
uint32_t :1;
|
||||
|
||||
uint32_t ADC :1;
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
uint32_t USB :1;
|
||||
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
uint32_t SDC :1;
|
||||
uint32_t :1;
|
||||
|
||||
uint32_t :1;
|
||||
uint32_t FLCTL :1;
|
||||
uint32_t ECC :1;
|
||||
uint32_t :1;
|
||||
|
||||
uint32_t I2C :1;
|
||||
uint32_t :1;
|
||||
uint32_t FSI_SPU :1;
|
||||
uint32_t _unknown1 :1;
|
||||
|
||||
uint32_t :1;
|
||||
uint32_t LCD :1;
|
||||
uint32_t BCD :1;
|
||||
uint32_t ETMU :1;
|
||||
|
||||
uint32_t :1;
|
||||
uint32_t Cmod2A :1;
|
||||
uint32_t :1;
|
||||
uint32_t :1;
|
||||
);
|
||||
pad(4);
|
||||
|
||||
/* Boot Address Register
|
||||
I really don't suggest writing to BAR. */
|
||||
uint32_t const BAR;
|
||||
|
||||
};
|
||||
|
||||
#define SH7305_POWER (*((volatile struct __sh7305_power *)0xa4150020))
|
||||
|
||||
|
||||
|
||||
#endif /* __VHEX_DRIVER_MPU_SH_SH7305_POWER__ */
|
|
@ -142,4 +142,19 @@ extern uint32_t sh7305_tmu_prof_time(timer_prof_t *prof);
|
|||
/* sh7305_tmu_prof_quit() : uninit the profoling object */
|
||||
extern int sh7305_tmu_prof_quit(timer_prof_t *prof);
|
||||
|
||||
/* FSP */
|
||||
|
||||
#include <vhex/timer/fps.h>
|
||||
|
||||
/* sh7305_tmu_fps_init() : initialize fps object */
|
||||
extern void sh7305_tmu_fps_init(fps_t *fps);
|
||||
|
||||
/* sh7305_tmu_fps_sync() : compute frame statistic and wait whanted FPS */
|
||||
extern void sh7305_tmu_fps_sync(fps_t *fps, int fps_target);
|
||||
|
||||
/* sh7305_fps_quit() : uninit the fps object */
|
||||
extern void sh7305_tmu_fps_quit(fps_t *fps);
|
||||
|
||||
|
||||
|
||||
#endif /* __VHEX_MPU_SH7305_TMU__ */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/dma.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/power.h>
|
||||
#include <vhex/driver/cpu.h>
|
||||
//#include <vhex/driver/mpu/sh/sh7305/power.h>
|
||||
#include <vhex/driver.h>
|
||||
#include <vhex/defs/call.h>
|
||||
#include <vhex/dma/interface.h>
|
||||
|
@ -316,7 +316,23 @@ struct dma_ctx {
|
|||
);
|
||||
};
|
||||
|
||||
/* __dma_configure() : configure the DMA */
|
||||
static bool __dma_hpowered(void)
|
||||
{
|
||||
return (SH7305_POWER.MSTPCR0.DMA == 0);
|
||||
}
|
||||
|
||||
static int __dma_hpoweron(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.DMA = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __dma_hpoweroff(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.DMA = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __dma_configure(struct dma_ctx *s)
|
||||
{
|
||||
extern void sh7305_dma_inth_te(void);
|
||||
|
@ -372,7 +388,6 @@ static void __dma_configure(struct dma_ctx *s)
|
|||
sh7305_intc_priority(INTC_DMA_DADERR, 3);
|
||||
}
|
||||
|
||||
/* __rtc_hsave() : save hardware information */
|
||||
static void __dma_hsave(struct dma_ctx *s)
|
||||
{
|
||||
sh7305_dma_channel_t * ch;
|
||||
|
@ -389,7 +404,6 @@ static void __dma_hsave(struct dma_ctx *s)
|
|||
s->DMAOR.word = SH7305_DMA.DMAOR.word;
|
||||
}
|
||||
|
||||
/* __dma_hrestore() : restore hardware information */
|
||||
static void __dma_hrestore(struct dma_ctx *s)
|
||||
{
|
||||
sh7305_dma_channel_t * ch;
|
||||
|
@ -410,6 +424,9 @@ static void __dma_hrestore(struct dma_ctx *s)
|
|||
|
||||
struct vhex_driver drv_dma = {
|
||||
.name = "DMA",
|
||||
.hpowered = (void*)&__dma_hpowered,
|
||||
.hpoweron = (void*)&__dma_hpoweron,
|
||||
.hpoweroff = (void*)&__dma_hpoweroff,
|
||||
.hsave = (void*)&__dma_hsave,
|
||||
.hrestore = (void*)&__dma_hrestore,
|
||||
.configure = (void*)&__dma_configure,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <vhex/driver.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/power.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
@ -144,6 +145,23 @@ void *sh7305_intc_install_inth_generic(int event_code, vhex_call_t callback)
|
|||
// hardware configuration call
|
||||
//---
|
||||
|
||||
static bool __intc_hpowered(void)
|
||||
{
|
||||
return (SH7305_POWER.MSTPCR0.INTC == 0);
|
||||
}
|
||||
|
||||
static int __intc_hpoweron(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.INTC = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __intc_hpoweroff(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.INTC = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* __intc_configure() : configure the Interrupt Controller
|
||||
|
||||
Note that we don't touch to the NMI configuration because this part is
|
||||
|
@ -255,8 +273,6 @@ static void __intc_hrestore(struct intc_ctx *state)
|
|||
*SH7305_INTC.INTMSK00 = state->intmsk00;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* declare the INTC driver */
|
||||
|
||||
struct vhex_driver drv_intc = {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/keysc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/power.h>
|
||||
#include <vhex/keyboard/interface.h>
|
||||
#include <vhex/driver.h>
|
||||
|
||||
|
@ -10,6 +11,23 @@ struct keysc_ctx {
|
|||
|
||||
/* hardware configuration call */
|
||||
|
||||
static bool __keysc_hpowered(void)
|
||||
{
|
||||
return (SH7305_POWER.MSTPCR0.KEYSC == 0);
|
||||
}
|
||||
|
||||
static int __keysc_hpoweron(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.KEYSC = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __keysc_hpoweroff(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.KEYSC = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* __keysc_configure() : configure the SH7305_KEYSC module */
|
||||
static void __keysc_configure(struct keysc_ctx *ctx)
|
||||
{
|
||||
|
@ -123,6 +141,9 @@ static void __keysc_hrestore(struct keysc_ctx *ctx)
|
|||
|
||||
struct vhex_driver drv_keysc = {
|
||||
.name = "KEYSC",
|
||||
.hpowered = (void*)&__keysc_hpowered,
|
||||
.hpoweron = (void*)&__keysc_hpoweron,
|
||||
.hpoweroff = (void*)&__keysc_hpoweroff,
|
||||
.hsave = (void*)&__keysc_hsave,
|
||||
.hrestore = (void*)&__keysc_hrestore,
|
||||
.configure = (void*)&__keysc_configure,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/rtc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/power.h>
|
||||
#include <vhex/rtc/interface.h>
|
||||
#include <vhex/defs/call.h>
|
||||
#include <vhex/driver.h>
|
||||
|
@ -63,6 +64,23 @@ struct rtc_ctx {
|
|||
struct __sh7305_rtc_s rtc;
|
||||
};
|
||||
|
||||
static bool __rtc_hpowered(void)
|
||||
{
|
||||
return (SH7305_POWER.MSTPCR0.RTC == 0);
|
||||
}
|
||||
|
||||
static int __rtc_hpoweron(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.RTC = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __rtc_hpoweroff(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.RTC = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* __rtc_configure() : configure the RTC */
|
||||
static void __rtc_configure(struct rtc_ctx *state)
|
||||
{
|
||||
|
@ -206,6 +224,9 @@ int sh7305_rtc_set_time(rtc_time_t const *time)
|
|||
|
||||
struct vhex_driver drv_rtc = {
|
||||
.name = "RTC",
|
||||
.hpowered = (void*)&__rtc_hpowered,
|
||||
.hpoweron = (void*)&__rtc_hpoweron,
|
||||
.hpoweroff = (void*)&__rtc_hpoweroff,
|
||||
.hsave = (void*)&__rtc_hsave,
|
||||
.hrestore = (void*)&__rtc_hrestore,
|
||||
.configure = (void*)&__rtc_configure,
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
#include <vhex/timer/fps.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/tmu.h>
|
||||
#include <vhex/driver/cpu.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//---
|
||||
// Public FPS API
|
||||
//---
|
||||
|
||||
extern uint32_t *tmu_prof_tcnt;
|
||||
|
||||
/* sh7305_tmu_fps_init() : initialize fps object */
|
||||
void sh7305_tmu_fps_init(fps_t *fps)
|
||||
{
|
||||
cpu_atomic_start();
|
||||
sh7305_tmu_prof_init(NULL);
|
||||
memset(fps, 0x00, sizeof(fps_t));
|
||||
fps->keyframe = *tmu_prof_tcnt;
|
||||
cpu_atomic_end();
|
||||
}
|
||||
|
||||
/* sh7305_tmu_fps_sync() : compute frame statistic and wait whanted FPS */
|
||||
void sh7305_tmu_fps_sync(fps_t *fps, int fps_target)
|
||||
{
|
||||
uint32_t snap;
|
||||
|
||||
snap = *tmu_prof_tcnt;
|
||||
|
||||
fps->objectif = 1000000 / fps_target;
|
||||
fps->render = fps->keyframe - snap;
|
||||
fps->margin = fps->objectif - fps->render;
|
||||
fps->fps_real = 1000000 / fps->render;
|
||||
|
||||
fps->fps = fps->fps_real;
|
||||
if (fps->margin <= 0)
|
||||
fps->fps = fps_target;
|
||||
|
||||
while (1) {
|
||||
if (*tmu_prof_tcnt - fps->keyframe >= fps->objectif)
|
||||
break;
|
||||
}
|
||||
|
||||
fps->keyframe = *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_fps_quit() : uninit the fps object */
|
||||
void sh7305_tmu_fps_quit(fps_t *fps)
|
||||
{
|
||||
(void)fps;
|
||||
sh7305_tmu_prof_quit(NULL);
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
#include <vhex/timer.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/tmu.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/cpg.h>
|
||||
#include <vhex/driver/cpu.h>
|
||||
|
||||
uint32_t volatile *tmu_prof_tcnt = NULL;
|
||||
static int tmu_prof_counter = 0;
|
||||
static int tmu_prof_timer = -1;
|
||||
|
||||
extern int available(int id);
|
||||
|
||||
/* Shortcut to set registers that are slow to update */
|
||||
#define set(lval, rval) do(lval = rval); while(rval != lval)
|
||||
|
||||
//---
|
||||
// Public profiling API
|
||||
//---
|
||||
|
||||
/* sh7305_tmu_prof_make() : initialise a new */
|
||||
int sh7305_tmu_prof_init(timer_prof_t *prof)
|
||||
{
|
||||
cpu_atomic_start();
|
||||
|
||||
if (tmu_prof_tcnt == NULL) {
|
||||
tmu_prof_timer = -1;
|
||||
for(int t = 0; t < 2; t++)
|
||||
{
|
||||
if (!available(t))
|
||||
continue;
|
||||
tmu_prof_timer = t;
|
||||
tmu_prof_tcnt = &SH7305_TMU.TMU[t].TCNT;
|
||||
|
||||
SH7305_TMU.TMU[t].TCOR = 0xffffffff;
|
||||
SH7305_TMU.TMU[t].TCNT = 0xffffffff;
|
||||
SH7305_TMU.TMU[t].TCR.TPSC = TIMER_Pphi_4;
|
||||
set(SH7305_TMU.TMU[t].TCR.UNF, 0);
|
||||
SH7305_TMU.TMU[t].TCR.UNIE = 0;
|
||||
SH7305_TMU.TMU[t].TCR.CKEG = 0;
|
||||
|
||||
SH7305_TMU.TSTR |= 1 << t;
|
||||
|
||||
break;
|
||||
}
|
||||
if (tmu_prof_timer < 0) {
|
||||
cpu_atomic_end();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (prof != NULL) {
|
||||
prof->rec = 0;
|
||||
prof->elapsed = 0;
|
||||
}
|
||||
|
||||
tmu_prof_counter += 1;
|
||||
|
||||
cpu_atomic_end();
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_enter(): Start counting time for a function */
|
||||
void sh7305_tmu_prof_enter(timer_prof_t *prof)
|
||||
{
|
||||
if (tmu_prof_tcnt != NULL)
|
||||
prof->elapsed += *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_enter_rec(): Start counting time for a recursive function */
|
||||
void sh7305_tmu_prof_enter_rec(timer_prof_t *prof)
|
||||
{
|
||||
if (!prof->rec++ && tmu_prof_tcnt != NULL)
|
||||
prof->elapsed += *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_leave_rec(): Start counting time for a recursive function */
|
||||
void sh7305_tmu_prof_leave_rec(timer_prof_t *prof)
|
||||
{
|
||||
if (!--prof->rec && tmu_prof_tcnt != NULL)
|
||||
prof->elapsed -= *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_leave(): Stop counting time for a function */
|
||||
void sh7305_tmu_prof_leave(timer_prof_t *prof)
|
||||
{
|
||||
if (tmu_prof_tcnt != NULL)
|
||||
prof->elapsed -= *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
|
||||
/* sh7305_prof_time(): Time spent in a given context, in microseconds */
|
||||
uint32_t sh7305_tmu_prof_time(timer_prof_t *prof)
|
||||
{
|
||||
struct cpg_clock_frequency cpg_freq;
|
||||
|
||||
cpg_clock_freq(&cpg_freq);
|
||||
return ((uint64_t)prof->elapsed * 4 * 1000000) / cpg_freq.Pphi_f;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_quit() : uninit the profoling object */
|
||||
int sh7305_tmu_prof_quit(timer_prof_t *prof)
|
||||
{
|
||||
(void)prof;
|
||||
|
||||
cpu_atomic_start();
|
||||
if (--tmu_prof_counter <= 0) {
|
||||
if(tmu_prof_timer >= 0)
|
||||
sh7305_tmu_stop(tmu_prof_timer);
|
||||
tmu_prof_timer = -1;
|
||||
tmu_prof_tcnt = NULL;
|
||||
}
|
||||
cpu_atomic_end();
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/tmu.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/cpu.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/cpg.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/power.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
#include <vhex/driver/cpu.h>
|
||||
#include <vhex/driver.h>
|
||||
|
@ -33,6 +34,7 @@ struct tmu_ctx {
|
|||
uint16_t TSTR;
|
||||
} timer[9];
|
||||
uint8_t TSTR;
|
||||
uint8_t power_bmp;
|
||||
};
|
||||
|
||||
//---
|
||||
|
@ -118,7 +120,7 @@ static int control(tid_t id, int state)
|
|||
}
|
||||
|
||||
/* available(): Check if a timer is available (UNIE cleared, not running) */
|
||||
static int available(int id)
|
||||
int available(int id)
|
||||
{
|
||||
if (id < 0 || id >= 9)
|
||||
return (-1);
|
||||
|
@ -328,164 +330,19 @@ void sh7305_tmu_set_tcor(tid_t id, uint32_t value)
|
|||
}
|
||||
|
||||
|
||||
//---
|
||||
// Public profiling API
|
||||
//---
|
||||
|
||||
static uint32_t volatile *tmu_prof_tcnt = NULL;
|
||||
static int tmu_prof_counter = 0;
|
||||
static int tmu_prof_timer = -1;
|
||||
|
||||
/* sh7305_tmu_prof_make() : initialise a new */
|
||||
int sh7305_tmu_prof_init(timer_prof_t *prof)
|
||||
{
|
||||
cpu_atomic_start();
|
||||
|
||||
if (tmu_prof_tcnt == NULL) {
|
||||
tmu_prof_timer = -1;
|
||||
for(int t = 0; t < 2; t++)
|
||||
{
|
||||
if (!available(t))
|
||||
continue;
|
||||
tmu_prof_timer = t;
|
||||
tmu_prof_tcnt = &TMU[t].TCNT;
|
||||
|
||||
TMU[t].TCOR = 0xffffffff;
|
||||
TMU[t].TCNT = 0xffffffff;
|
||||
TMU[t].TCR.TPSC = TIMER_Pphi_4;
|
||||
set(TMU[t].TCR.UNF, 0);
|
||||
TMU[t].TCR.UNIE = 0;
|
||||
TMU[t].TCR.CKEG = 0;
|
||||
|
||||
*TSTR = *TSTR | (1 << t);
|
||||
|
||||
break;
|
||||
}
|
||||
if (tmu_prof_timer < 0) {
|
||||
cpu_atomic_end();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (prof != NULL) {
|
||||
prof->rec = 0;
|
||||
prof->elapsed = 0;
|
||||
}
|
||||
|
||||
tmu_prof_counter += 1;
|
||||
|
||||
cpu_atomic_end();
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_enter(): Start counting time for a function */
|
||||
void sh7305_tmu_prof_enter(timer_prof_t *prof)
|
||||
{
|
||||
if (tmu_prof_tcnt != NULL)
|
||||
prof->elapsed += *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_enter_rec(): Start counting time for a recursive function */
|
||||
void sh7305_tmu_prof_enter_rec(timer_prof_t *prof)
|
||||
{
|
||||
if (!prof->rec++ && tmu_prof_tcnt != NULL)
|
||||
prof->elapsed += *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_leave_rec(): Start counting time for a recursive function */
|
||||
void sh7305_tmu_prof_leave_rec(timer_prof_t *prof)
|
||||
{
|
||||
if (!--prof->rec && tmu_prof_tcnt != NULL)
|
||||
prof->elapsed -= *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_leave(): Stop counting time for a function */
|
||||
void sh7305_tmu_prof_leave(timer_prof_t *prof)
|
||||
{
|
||||
if (tmu_prof_tcnt != NULL)
|
||||
prof->elapsed -= *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
|
||||
/* sh7305_prof_time(): Time spent in a given context, in microseconds */
|
||||
uint32_t sh7305_tmu_prof_time(timer_prof_t *prof)
|
||||
{
|
||||
struct cpg_clock_frequency cpg_freq;
|
||||
|
||||
cpg_clock_freq(&cpg_freq);
|
||||
return ((uint64_t)prof->elapsed * 4 * 1000000) / cpg_freq.Pphi_f;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_quit() : uninit the profoling object */
|
||||
int sh7305_tmu_prof_quit(timer_prof_t *prof)
|
||||
{
|
||||
(void)prof;
|
||||
|
||||
cpu_atomic_start();
|
||||
if (--tmu_prof_counter <= 0) {
|
||||
if(tmu_prof_timer >= 0)
|
||||
sh7305_tmu_stop(tmu_prof_timer);
|
||||
tmu_prof_timer = -1;
|
||||
tmu_prof_tcnt = NULL;
|
||||
}
|
||||
cpu_atomic_end();
|
||||
}
|
||||
|
||||
//---
|
||||
// Public FPS API
|
||||
//---
|
||||
|
||||
|
||||
/* sh7305_tmu_fps_init() : initialize fps object */
|
||||
void sh7305_tmu_fps_init(fps_t *fps)
|
||||
{
|
||||
cpu_atomic_start();
|
||||
sh7305_tmu_prof_init(NULL);
|
||||
memset(fps, 0x00, sizeof(fps_t));
|
||||
fps->keyframe = *tmu_prof_tcnt;
|
||||
cpu_atomic_end();
|
||||
}
|
||||
|
||||
/* sh7305_tmu_fps_sync() : compute frame statistic and wait whanted FPS */
|
||||
void sh7305_tmu_fps_sync(fps_t *fps, int fps_target)
|
||||
{
|
||||
uint32_t snap;
|
||||
|
||||
snap = *tmu_prof_tcnt;
|
||||
|
||||
fps->objectif = 1000000 / fps_target;
|
||||
fps->render = fps->keyframe - snap;
|
||||
fps->margin = fps->objectif - fps->render;
|
||||
fps->fps_real = 1000000 / fps->render;
|
||||
|
||||
fps->fps = fps->fps_real;
|
||||
if (fps->margin <= 0)
|
||||
fps->fps = fps_target;
|
||||
|
||||
|
||||
while (1) {
|
||||
if (*tmu_prof_tcnt - fps->keyframe >= fps->objectif)
|
||||
break;
|
||||
}
|
||||
|
||||
fps->keyframe = *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_fps_quit() : uninit the fps object */
|
||||
void sh7305_tmu_fps_quit(fps_t *fps)
|
||||
{
|
||||
(void)fps;
|
||||
sh7305_tmu_prof_quit(NULL);
|
||||
}
|
||||
|
||||
|
||||
//---
|
||||
// hardware specification
|
||||
//---
|
||||
|
||||
|
||||
/* __tmu_configure() : configure the SH7305 TMU/ETMU module */
|
||||
static void __tmu_configure(struct tmu_ctx *s)
|
||||
{
|
||||
memset(s, 0x00, sizeof(struct tmu_ctx));
|
||||
|
||||
/* force enable power */
|
||||
s->power_bmp = 3;
|
||||
|
||||
/* prepare timers comtext */
|
||||
s->TSTR = 0;
|
||||
for(int i = 0; i < 9; i++)
|
||||
|
@ -560,24 +417,37 @@ static void __tmu_hsave(struct tmu_ctx *s)
|
|||
{
|
||||
struct tmu_state_stored_timer *c;
|
||||
|
||||
s->TSTR = *TSTR;
|
||||
/* power workaround */
|
||||
s->power_bmp = 0;
|
||||
|
||||
/* classic timer */
|
||||
for(int i = 0; i < 3; i++) {
|
||||
s->timer[i].TCOR = TMU[i].TCOR;
|
||||
s->timer[i].TCNT = TMU[i].TCNT;
|
||||
s->timer[i].TCR = TMU[i].TCR.word;
|
||||
if (SH7305_POWER.MSTPCR0.TMU == 0)
|
||||
{
|
||||
s->TSTR = *TSTR;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
s->timer[i].TCOR = TMU[i].TCOR;
|
||||
s->timer[i].TCNT = TMU[i].TCNT;
|
||||
s->timer[i].TCR = TMU[i].TCR.word;
|
||||
}
|
||||
s->power_bmp |= 1;
|
||||
}
|
||||
|
||||
/* extra timer */
|
||||
c = &s->timer[3];
|
||||
for(int i = 0; i < 6; i++) {
|
||||
/* Don't snapshot an interrupt state, because the timer state
|
||||
is sometimes garbage protected by a masked interrupt. */
|
||||
c[i].TCOR = ETMU[i].TCOR ? ETMU[i].TCOR : 0xffffffff;
|
||||
c[i].TCNT = ETMU[i].TCNT ? ETMU[i].TCNT : c->TCOR;
|
||||
c[i].TCR = ETMU[i].TCR.byte & 0xd;
|
||||
c[i].TSTR = ETMU[i].TSTR;
|
||||
if (SH7305_POWER.MSTPCR2.ETMU == 0)
|
||||
{
|
||||
c = &s->timer[3];
|
||||
for(int i = 0; i < 6; i++)
|
||||
{
|
||||
/* Don't snapshot an interrupt state, because the timer
|
||||
state is sometimes garbage protected by a masked
|
||||
interrupt. */
|
||||
c[i].TCOR = ETMU[i].TCOR ? ETMU[i].TCOR : 0xffffffff;
|
||||
c[i].TCNT = ETMU[i].TCNT ? ETMU[i].TCNT : c->TCOR;
|
||||
c[i].TCR = ETMU[i].TCR.byte & 0xd;
|
||||
c[i].TSTR = ETMU[i].TSTR;
|
||||
}
|
||||
s->power_bmp |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -586,30 +456,59 @@ static void __tmu_hrestore(struct tmu_ctx *s)
|
|||
{
|
||||
struct tmu_state_stored_timer const *c;
|
||||
|
||||
*TSTR = 0;
|
||||
/* power workaround */
|
||||
SH7305_POWER.MSTPCR0.TMU = (s->power_bmp & 1) ? 0 : 1;
|
||||
SH7305_POWER.MSTPCR2.ETMU = (s->power_bmp & 2) ? 0 : 1;
|
||||
|
||||
/* classic timer */
|
||||
for(int i = 0; i < 3; i++)
|
||||
if (SH7305_POWER.MSTPCR0.TMU == 0)
|
||||
{
|
||||
TMU[i].TCOR = s->timer[i].TCOR;
|
||||
TMU[i].TCNT = s->timer[i].TCNT;
|
||||
TMU[i].TCR.word = s->timer[i].TCR;
|
||||
*TSTR = 0;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
TMU[i].TCOR = s->timer[i].TCOR;
|
||||
TMU[i].TCNT = s->timer[i].TCNT;
|
||||
TMU[i].TCR.word = s->timer[i].TCR;
|
||||
}
|
||||
*TSTR = s->TSTR;
|
||||
}
|
||||
|
||||
/* extra timer */
|
||||
c = &s->timer[3];
|
||||
for(int i = 0; i < 6; i++)
|
||||
if (SH7305_POWER.MSTPCR2.ETMU == 0)
|
||||
{
|
||||
set(ETMU[i].TCOR, c[i].TCOR);
|
||||
set(ETMU[i].TCNT, c[i].TCNT);
|
||||
set(ETMU[i].TCR.byte, c[i].TCR);
|
||||
set(ETMU[i].TSTR, c[i].TSTR);
|
||||
c = &s->timer[3];
|
||||
for(int i = 0; i < 6; i++)
|
||||
{
|
||||
set(ETMU[i].TCOR, c[i].TCOR);
|
||||
set(ETMU[i].TCNT, c[i].TCNT);
|
||||
set(ETMU[i].TCR.byte, c[i].TCR);
|
||||
set(ETMU[i].TSTR, c[i].TSTR);
|
||||
}
|
||||
}
|
||||
|
||||
*TSTR = s->TSTR;
|
||||
}
|
||||
|
||||
//@note : we use the TMU and the ETMU hardware module, so we have two
|
||||
// alimentation to check. If one of them is powered, return that the whole
|
||||
// driver is powered. The __tmu_hsave() and __tmu_hresotre() will handle the
|
||||
// power management
|
||||
static bool __dma_hpowered(void)
|
||||
{
|
||||
return (SH7305_POWER.MSTPCR0.TMU == 0 || SH7305_POWER.MSTPCR2.ETMU == 0);
|
||||
}
|
||||
|
||||
static int __dma_hpoweron(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.TMU = 0;
|
||||
SH7305_POWER.MSTPCR2.ETMU = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __dma_hpoweroff(void)
|
||||
{
|
||||
SH7305_POWER.MSTPCR0.TMU = 1;
|
||||
SH7305_POWER.MSTPCR2.ETMU = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* declare the TMU driver */
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <vhex/defs/types.h>
|
||||
#include <vhex/driver.h>
|
||||
#include <vhex/driver/screen/r61524.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/dma.h>
|
||||
#include <vhex/display/interface.h>
|
||||
|
||||
//---
|
||||
|
@ -12,28 +13,15 @@ extern uint32_t vhex_vram0;
|
|||
extern uint32_t vhex_vram1;
|
||||
|
||||
static uint32_t *vhex_vram = &vhex_vram0;
|
||||
static bool r61524_atomic_transfert = false;
|
||||
static dma_id_t dma = -1;
|
||||
|
||||
/* r61524_frame_start() - prepar the screen and reset surfaces */
|
||||
VALIGNED(4) int r61524_frame_start(dsurface_t *surface)
|
||||
{
|
||||
/* Set the windows size */
|
||||
r61524_select(horizontal_ram_start);
|
||||
r61524_write(0);
|
||||
r61524_select(horizontal_ram_end);
|
||||
r61524_write(395);
|
||||
r61524_select(vertical_ram_start);
|
||||
r61524_write(0);
|
||||
r61524_select(vertical_ram_end);
|
||||
r61524_write(223);
|
||||
|
||||
/* Set the RAM position */
|
||||
r61524_select(ram_address_horizontal);
|
||||
r61524_write(0);
|
||||
r61524_select(ram_address_vertical);
|
||||
r61524_write(0);
|
||||
|
||||
/* Bind address 0xb4000000 to the data write command */
|
||||
r61524_select(write_data);
|
||||
// NOTE IF YOU WHANT TO ENABLE FRAGMENT AGAIN
|
||||
// You need to force the windows configuration (in
|
||||
// r61524_frame_frag_send) !!!
|
||||
|
||||
/* initialize surface information */
|
||||
// surface->vram = (void*)0xe5017000;
|
||||
|
@ -67,12 +55,48 @@ VALIGNED(4) int r61524_frame_frag_next(dsurface_t *surface)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
VALIGNED(4) VWEAK int r61524_frame_frag_send(dsurface_t *surface)
|
||||
{
|
||||
uint16_t *vram = surface->vram;
|
||||
for (int i = 0; i < 396*224; ++i) {
|
||||
r61524_write(vram[i]);
|
||||
/* wait last DMA transfert */
|
||||
if (dma >= 0)
|
||||
sh7305_dma_wait(dma);
|
||||
|
||||
/* Set the windows size */
|
||||
r61524_select(horizontal_ram_start);
|
||||
r61524_write(0);
|
||||
r61524_select(horizontal_ram_end);
|
||||
r61524_write(395);
|
||||
r61524_select(vertical_ram_start);
|
||||
r61524_write(0);
|
||||
r61524_select(vertical_ram_end);
|
||||
r61524_write(223);
|
||||
|
||||
/* Set the RAM position */
|
||||
r61524_select(ram_address_horizontal);
|
||||
r61524_write(0);
|
||||
r61524_select(ram_address_vertical);
|
||||
r61524_write(0);
|
||||
|
||||
/* Bind address 0xb4000000 to the data write command */
|
||||
r61524_select(write_data);
|
||||
|
||||
if (r61524_atomic_transfert) {
|
||||
uint16_t *vram = surface->vram;
|
||||
for (int i = 0; i < 396*224; ++i) {
|
||||
r61524_write(vram[i]);
|
||||
}
|
||||
} else {
|
||||
dma = sh7305_dma_transfert_async(
|
||||
(uintptr_t)surface->vram, DMA_ADDR_INC,
|
||||
(uintptr_t)0xb4000000, DMA_ADDR_FIXED,
|
||||
DMA_BLOCK_SIZE_32B,
|
||||
5544
|
||||
);
|
||||
vhex_vram = (vhex_vram == &vhex_vram0) ? &vhex_vram1 : &vhex_vram0;
|
||||
surface->vram = vhex_vram;
|
||||
}
|
||||
|
||||
#if 0
|
||||
uint16_t * restrict yram = surface->vram;
|
||||
int size = (surface->y1 == 220) ? 1584 : 3960;
|
||||
|
|
Loading…
Reference in New Issue