diff --git a/include/vhex/driver/mpu/sh/sh7305/power.h b/include/vhex/driver/mpu/sh/sh7305/power.h new file mode 100644 index 0000000..2a0d63a --- /dev/null +++ b/include/vhex/driver/mpu/sh/sh7305/power.h @@ -0,0 +1,120 @@ +#ifndef __VHEX_DRIVER_MPU_SH_SH7305_POWER__ +# define __VHEX_DRIVER_MPU_SH_SH7305_POWER__ + +#include + +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__ */ diff --git a/include/vhex/driver/mpu/sh/sh7305/tmu.h b/include/vhex/driver/mpu/sh/sh7305/tmu.h index acf909b..bf9088b 100644 --- a/include/vhex/driver/mpu/sh/sh7305/tmu.h +++ b/include/vhex/driver/mpu/sh/sh7305/tmu.h @@ -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 + +/* 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__ */ diff --git a/src/driver/mpu/sh/sh7305/dma/dma.c b/src/driver/mpu/sh/sh7305/dma/dma.c index 12dbe8d..15e8db8 100644 --- a/src/driver/mpu/sh/sh7305/dma/dma.c +++ b/src/driver/mpu/sh/sh7305/dma/dma.c @@ -1,7 +1,7 @@ #include #include +#include #include -//#include #include #include #include @@ -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, diff --git a/src/driver/mpu/sh/sh7305/intc/intc.c b/src/driver/mpu/sh/sh7305/intc/intc.c index 7275a83..823924b 100644 --- a/src/driver/mpu/sh/sh7305/intc/intc.c +++ b/src/driver/mpu/sh/sh7305/intc/intc.c @@ -1,5 +1,6 @@ #include #include +#include #include @@ -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 = { diff --git a/src/driver/mpu/sh/sh7305/keysc/keysc.c b/src/driver/mpu/sh/sh7305/keysc/keysc.c index e80620e..f390d18 100644 --- a/src/driver/mpu/sh/sh7305/keysc/keysc.c +++ b/src/driver/mpu/sh/sh7305/keysc/keysc.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -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, diff --git a/src/driver/mpu/sh/sh7305/rtc/rtc.c b/src/driver/mpu/sh/sh7305/rtc/rtc.c index 104521d..a8cadb7 100644 --- a/src/driver/mpu/sh/sh7305/rtc/rtc.c +++ b/src/driver/mpu/sh/sh7305/rtc/rtc.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -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, diff --git a/src/driver/mpu/sh/sh7305/tmu/fps.c b/src/driver/mpu/sh/sh7305/tmu/fps.c new file mode 100644 index 0000000..5bf6295 --- /dev/null +++ b/src/driver/mpu/sh/sh7305/tmu/fps.c @@ -0,0 +1,52 @@ +#include +#include +#include + +#include + +//--- +// 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); +} diff --git a/src/driver/mpu/sh/sh7305/tmu/profiling.c b/src/driver/mpu/sh/sh7305/tmu/profiling.c new file mode 100644 index 0000000..f8f1951 --- /dev/null +++ b/src/driver/mpu/sh/sh7305/tmu/profiling.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include + +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(); +} diff --git a/src/driver/mpu/sh/sh7305/tmu/tmu.c b/src/driver/mpu/sh/sh7305/tmu/tmu.c index 9f79ff4..c43ce1c 100644 --- a/src/driver/mpu/sh/sh7305/tmu/tmu.c +++ b/src/driver/mpu/sh/sh7305/tmu/tmu.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -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 */ diff --git a/src/driver/screen/R61524/r61524.c b/src/driver/screen/R61524/r61524.c index 2851a3b..1115332 100644 --- a/src/driver/screen/R61524/r61524.c +++ b/src/driver/screen/R61524/r61524.c @@ -1,6 +1,7 @@ #include #include #include +#include #include //--- @@ -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;