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:
Yann MAGNIN 2022-08-24 10:17:50 +02:00
parent b8abc2eae7
commit 0bf4f487c7
10 changed files with 502 additions and 205 deletions

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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,

View File

@ -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 = {

View File

@ -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,

View File

@ -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,

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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 */

View File

@ -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;