From b3416dcc25cf8b46e45f4144cde48f528cb533c7 Mon Sep 17 00:00:00 2001 From: Lephe Date: Thu, 5 Jan 2023 20:01:58 +0100 Subject: [PATCH] cpg: add overclock for SH3/SH4 fx-9860G and G-III (#23) Co-authored-by: Slyvtt --- include/gint/clock.h | 52 +++-- include/gint/mpu/bsc.h | 74 ++++++ include/gint/mpu/cpg.h | 6 + include/gint/mpu/wdt.h | 52 +++++ src/cpg/cpg.c | 41 +--- src/cpg/overclock.c | 512 ++++++++++++++++++++++++++++++----------- 6 files changed, 549 insertions(+), 188 deletions(-) create mode 100644 include/gint/mpu/wdt.h diff --git a/include/gint/clock.h b/include/gint/clock.h index 0a9c226..dc5e5ea 100644 --- a/include/gint/clock.h +++ b/include/gint/clock.h @@ -68,28 +68,40 @@ enum { /* Combinations of hardware settings that are none of Ftune's levels */ CLOCK_SPEED_UNKNOWN = 0, - /* Ftune's 5 default overclock levels. The main settings are listed below, - thoug many more are involved. - - On SH4 fx-9860G-likr: - (Not supported yet) - - On the fx G-III series: - (Not supported yet) + /* Ftune's 5 default overclock levels. The main settings are listed + below, though many more are involved. + On SH3 fx-9860G-like: + F1: CPU @ 29 MHz [Default speed] + F2: CPU @ 58 MHz [Similar to G-III default] + F3: CPU @ 88 MHz + F4: CPU @ 118 MHz [Fastest CPU option] + F5: CPU @ 118 MHz [Reduced memory wait times] + On SH4 fx-9860G-like: + F1: CPU @ 29 MHz, BFC @ 29 MHz [Default speed] + F2: CPU @ 58 MHz, BFC @ 29 MHz [Similar to G-III default] + F3: CPU @ 29 MHz, BFC @ 29 MHz [SH3 default] + F4: CPU @ 118 MHz, BFC @ 59 MHz + F5: CPU @ 236 MHz, BFC @ 118 MHz [Fastest option] + On G-III / Graph 35+E II: + F1: CPU @ 58 MHz, BFC @ 29 MHz [Default speed] + F2: CPU @ 58 MHz, BFC @ 29 MHz [fx-CG 10/20 default] + F3: CPU @ 29 MHz, BFC @ 29 MHz [SH3 default] + F4: CPU @ 118 MHz, BFC @ 58 MHz + F5: CPU @ 235 MHz, BFC @ 58 MHz [Fastest option] On fx-CG 10/20: - F1: CPU @ 58 MHz, BFC @ 29 MHz [Default speed] - F2: CPU @ 58 MHz, BFC @ 29 MHz [Improved memory speed] - F3: CPU @ 118 MHz, BFC @ 58 MHz [Faster than F2] - F4: CPU @ 118 MHz, BFC @ 118 MHz [Fastest bus option] - F5: CPU @ 191 MHz, BFC @ 94 MHz [Fastest CPU option] + F1: CPU @ 58 MHz, BFC @ 29 MHz [Default speed] + F2: CPU @ 58 MHz, BFC @ 29 MHz [Improved memory speed] + F3: CPU @ 118 MHz, BFC @ 58 MHz [Faster than F2] + F4: CPU @ 118 MHz, BFC @ 118 MHz [Fastest bus option] + F5: CPU @ 191 MHz, BFC @ 94 MHz [Fastest CPU option] + On fx-CG 50: + F1: CPU @ 116 MHz, BFC @ 58 MHz [Default speed] + F2: CPU @ 58 MHz, BFC @ 29 MHz [fx-CG 10/20 default] + F3: CPU @ 94 MHz, BFC @ 47 MHz [Clearly slow: F2 < F3 < F1] + F4: CPU @ 232 MHz, BFC @ 58 MHz [Fastest CPU option] + F5: CPU @ 189 MHz, BFC @ 94 MHz [Fastest bus option] */ - On fx-CG 50: - F1: CPU @ 116 MHz, BFC @ 58 MHz [Default speed] - F2: CPU @ 58 MHz, BFC @ 29 MHz [Clearly slower: F2 < F3 < F1] - F3: CPU @ 94 MHz, BFC @ 47 MHz [Clearly slower: F2 < F3 < F1] - F4: CPU @ 232 MHz, BFC @ 58 MHz [Fastest CPU option] - F5: CPU @ 189 MHz, BFC @ 94 MHz [Fastest bus option] */ CLOCK_SPEED_F1 = 1, CLOCK_SPEED_F2 = 2, CLOCK_SPEED_F3 = 3, @@ -100,7 +112,6 @@ enum { CLOCK_SPEED_DEFAULT = CLOCK_SPEED_F1, }; -#ifdef FXCG50 /* clock_get_speed(): Determine the current clock speed This function compares the current hardware state with the settings for each @@ -123,7 +134,6 @@ int clock_get_speed(void); Currently the clock speed is not reset during a world switch nor when leaving the add-in. */ void clock_set_speed(int speed); -#endif //--- // Sleep functions diff --git a/include/gint/mpu/bsc.h b/include/gint/mpu/bsc.h index 6f65a0b..9c4e290 100644 --- a/include/gint/mpu/bsc.h +++ b/include/gint/mpu/bsc.h @@ -12,6 +12,80 @@ extern "C" { #include #include +//--- +// SH7705 But State Controller. Refer to: +// Renesas SH7705 Group Hardware Manual +// Section 7: Bus State Controller (BSC) +//--- + +typedef volatile lword_union(sh7705_bsc_CSnBCR_t, + uint32_t :2; + uint32_t IWW :2; /* Wait cycles for Write-Read and Write-Write */ + uint32_t :1; + uint32_t IWRWD :2; /* Wait cycles for other-space Read-Write */ + uint32_t :1; + uint32_t IWRWS :2; /* Wait cycles for same-space Read-Write */ + uint32_t :1; + uint32_t IWRRD :2; /* Wait cycles for other-space Read-Read */ + uint32_t :1; + uint32_t IWRRS :2; /* Wait cycles for same-space Read-Read */ + uint32_t :1; + uint32_t TYPE :3; /* Memory type */ + uint32_t :1; + uint32_t BSZ :2; /* Data bus size */ + uint32_t :9; +); + +/* Warning: the layout of this register changes with n *and* with the memory + type. This version is not exhaustive. Check the manual! */ +typedef volatile lword_union(sh7705_bsc_CSnWCR_t, + uint32_t :13; + uint32_t WW :3; /* Write access wait cycles */ + uint32_t :3; + uint32_t SW :2; /* Wait from CSn/address to RD/WEn assertion */ + uint32_t WR :4; /* Access wait cycles */ + uint32_t WM :1; /* Whether to use external wait */ + uint32_t :4; + uint32_t HW :2; /* Wait from RD/WEn to CSn/address negation */ +); + +typedef volatile struct +{ + lword_union(CMNCR, + uint32_t :24; + uint32_t DMAIW :2; /* DMA single-address wait states */ + uint32_t DMAIWA :1; /* DMAIW wait states insertion method */ + uint32_t :1; + uint32_t const ENDIAN :1; /* Global CPU endianness flag */ + uint32_t :1; + uint32_t HIZMEM :1; /* High-Z memory Control*/ + uint32_t HIZCNT :1; /* High-Z Control*/ + ); + + sh7705_bsc_CSnBCR_t CS0BCR; + sh7705_bsc_CSnBCR_t CS2BCR; + sh7705_bsc_CSnBCR_t CS3BCR; + sh7705_bsc_CSnBCR_t CS4BCR; + sh7705_bsc_CSnBCR_t CS5ABCR; + sh7705_bsc_CSnBCR_t CS5BBCR; + sh7705_bsc_CSnBCR_t CS6ABCR; + sh7705_bsc_CSnBCR_t CS6BBCR; + + sh7705_bsc_CSnWCR_t CS0WCR; + sh7705_bsc_CSnWCR_t CS2WCR; + sh7705_bsc_CSnWCR_t CS3WCR; + sh7705_bsc_CSnWCR_t CS4WCR; + sh7705_bsc_CSnWCR_t CS5AWCR; + sh7705_bsc_CSnWCR_t CS5BWCR; + sh7705_bsc_CSnWCR_t CS6AWCR; + sh7705_bsc_CSnWCR_t CS6BWCR; + + /* TODO: There are more registers (not involved in overclocking). */ +} GPACKED(4) sh7705_bsc_t; + +#define SH7705_BSC (*(sh7705_bsc_t *)0xa4fd0000) + + //--- // SH7305 But State Controller. Refer to: // Renesas SH7730 Group Hardware Manual diff --git a/include/gint/mpu/cpg.h b/include/gint/mpu/cpg.h index a9bafdf..5f30899 100644 --- a/include/gint/mpu/cpg.h +++ b/include/gint/mpu/cpg.h @@ -32,6 +32,12 @@ typedef volatile struct uint16_t PFC :2; /* Peripheral clock divider */ ); + byte_union(UCLKCR, + uint8_t USSCS :2; /* Source Clock Selection Bit */ + uint8_t USBEN :1; /* USB On-Chip Oscillator Enable */ + uint8_t :5; + ); + } GPACKED(4) sh7705_cpg_t; #define SH7705_CPG (*((sh7705_cpg_t *)0xffffff80)) diff --git a/include/gint/mpu/wdt.h b/include/gint/mpu/wdt.h new file mode 100644 index 0000000..3b2cb91 --- /dev/null +++ b/include/gint/mpu/wdt.h @@ -0,0 +1,52 @@ +//--- +// gint:mpu:wdt - Watchdog Timer +//--- + +#ifndef GINT_MPU_WDT +#define GINT_MPU_WDT + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +//--- +// SH7705 WatchDog Timer. Refer to: +// "Renesas SH7705 Group Hardware Manual" +// Section 10: "WatchDog Timer (WDT)" +//--- + +/* sh7705_wdt_t - Watch Dog Timer */ +typedef volatile struct +{ + /* WDT registers are unique in access size; reads are performed with + 8-bit accesses, but writes are performed with 16-bit accesses. */ + + union { + uint8_t READ; + uint16_t WRITE; + } WTCNT; + + union { + byte_union(READ, + uint8_t TME :1; /* Timer Enable */ + uint8_t WTIT :1; /* Watchdog/Interval Select */ + uint8_t RSTS :1; /* Watchdog Reset Select */ + uint8_t WOVF :1; /* Watchdog Overflow Flag */ + uint8_t IOVF :1; /* Interval Overflow Flag */ + uint8_t CKS :3; /* Clock Select */ + ); + uint16_t WRITE; + } WTCSR; + +} sh7705_wdt_t; + +#define SH7705_WDT (*((sh7705_wdt_t *)0xffffff84)) + +#ifdef __cplusplus +} +#endif + +#endif /* GINT_MPU_WDT */ diff --git a/src/cpg/cpg.c b/src/cpg/cpg.c index 8149271..ecaa134 100644 --- a/src/cpg/cpg.c +++ b/src/cpg/cpg.c @@ -27,7 +27,6 @@ const clock_frequency_t *clock_freq(void) //--- #if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50)) -#define CPG SH7705_CPG void sh7705_probe(void) { @@ -41,35 +40,23 @@ void sh7705_probe(void) int ckio = xtal * pll2; /* This signal is multiplied by the PLL1 circuit */ - int pll1 = CPG.FRQCR.STC + 1; + int pll1 = SH7705_CPG.FRQCR.STC + 1; - /* Iphi and Pphi have dividers (Bphi is always equal to CKIO) */ - int idiv = CPG.FRQCR.IFC; - int pdiv = CPG.FRQCR.PFC; - - /* Fill in the setting structure */ + /* Fill in the setting structure. Iϕ and Pϕ have dividers, while Bϕ is + always equal to CKIO. */ freq.PLL1 = pll1; freq.PLL2 = pll2; freq.Bphi_div = 1; - freq.Iphi_div = idiv + 1; - freq.Pphi_div = pdiv + 1; - - /* Deduce the frequency of the main clocks. This value is ckio/3 */ - int ckio_3 = 9830400; - - /* 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); + freq.Iphi_div = SH7705_CPG.FRQCR.IFC + 1; + freq.Pphi_div = SH7705_CPG.FRQCR.PFC + 1; + /* Deduce the frequency of the main clocks */ freq.CKIO_f = ckio; freq.Bphi_f = ckio; - freq.Iphi_f = (idiv == 3) ? ckio_3 : ckio >> idiv; - freq.Pphi_f = (pdiv == 3) ? ckio_3 : ckio >> pdiv; + freq.Iphi_f = (ckio * pll1) / freq.Iphi_div; + freq.Pphi_f = (ckio * pll1) / freq.Pphi_div; } -#undef CPG #endif /* FX9860G and platform-agnostic */ //--- @@ -134,9 +121,7 @@ static void configure(void) { /* Disable spread spectrum in SSGSCR */ if(isSH4()) - { SH7305_CPG.SSCGCR.SSEN = 0; - } cpg_compute_freq(); } @@ -147,18 +132,16 @@ static void configure(void) static void hsave(cpg_state_t *s) { - if(isSH4()) { + if(isSH4()) s->SSCGCR = SH7305_CPG.SSCGCR.lword; - cpg_get_overclock_setting(&s->speed); - } + cpg_get_overclock_setting(&s->speed); } static void hrestore(cpg_state_t const *s) { - if(isSH4()) { + if(isSH4()) SH7305_CPG.SSCGCR.lword = s->SSCGCR; - cpg_set_overclock_setting(&s->speed); - } + cpg_set_overclock_setting(&s->speed); } gint_driver_t drv_cpg = { diff --git a/src/cpg/overclock.c b/src/cpg/overclock.c index a5211b4..fa097f3 100644 --- a/src/cpg/overclock.c +++ b/src/cpg/overclock.c @@ -14,137 +14,285 @@ #include #include #include - -#define CPG SH7305_CPG -#define BSC SH7305_BSC +#include //--- // Low-level clock speed access //--- -#define SDMR3_CL2 ((volatile uint8_t *)0xFEC15040) -#define SDMR3_CL3 ((volatile uint8_t *)0xFEC15060) - -void cpg_get_overclock_setting(struct cpg_overclock_setting *s) -{ - if(!isSH4()) - return; - - s->FLLFRQ = CPG.FLLFRQ.lword; - s->FRQCR = CPG.FRQCR.lword; - - s->CS0BCR = BSC.CS0BCR.lword; - s->CS0WCR = BSC.CS0WCR.lword; - s->CS2BCR = BSC.CS2BCR.lword; - s->CS2WCR = BSC.CS2WCR.lword; - s->CS3BCR = BSC.CS3BCR.lword; - s->CS3WCR = BSC.CS3WCR.lword; - s->CS5aBCR = BSC.CS5ABCR.lword; - s->CS5aWCR = BSC.CS5AWCR.lword; -} - -void cpg_set_overclock_setting(struct cpg_overclock_setting const *s) -{ - if(!isSH4()) - return; - - BSC.CS0WCR.WR = 11; /* 18 cycles */ - - CPG.FLLFRQ.lword = s->FLLFRQ; - CPG.FRQCR.lword = s->FRQCR; - CPG.FRQCR.KICK = 1; - while(CPG.LSTATS != 0) {} - - BSC.CS0BCR.lword = s->CS0BCR; - BSC.CS0WCR.lword = s->CS0WCR; - BSC.CS2BCR.lword = s->CS2BCR; - BSC.CS2WCR.lword = s->CS2WCR; - BSC.CS3BCR.lword = s->CS3BCR; - BSC.CS3WCR.lword = s->CS3WCR; - - if(BSC.CS3WCR.A3CL == 1) - *SDMR3_CL2 = 0; - else - *SDMR3_CL3 = 0; - - BSC.CS5ABCR.lword = s->CS5aBCR; - BSC.CS5AWCR.lword = s->CS5aWCR; -} +#define SH7305_SDMR3_CL2 ((volatile uint8_t *)0xFEC15040) +#define SH7305_SDMR3_CL3 ((volatile uint8_t *)0xFEC15060) //--- // Predefined clock speeds //--- -#ifdef FXCG50 +/* SH7305 CPG */ +#define SH4_PLL_32x 0b011111 +#define SH4_PLL_26x 0b011001 +#define SH4_PLL_16x 0b001111 +#define SH4_DIV_2 0 +#define SH4_DIV_4 1 +#define SH4_DIV_8 2 +#define SH4_DIV_16 3 +#define SH4_DIV_32 4 -#define PLL_32x 0b011111 -#define PLL_26x 0b011001 -#define PLL_16x 0b001111 -#define DIV_2 0 -#define DIV_4 1 -#define DIV_8 2 -#define DIV_16 3 -#define DIV_32 4 +/* SH7705-like CPG */ +#define SH3_PLL_1x 0 +#define SH3_PLL_2x 1 +#define SH3_PLL_3x 2 +#define SH3_PLL_4x 3 +#define SH3_DIV_1 0 +#define SH3_DIV_2 1 +#define SH3_DIV_3 2 +#define SH3_DIV_4 3 -static struct cpg_overclock_setting settings_cg50[5] = { +void cpg_get_overclock_setting(struct cpg_overclock_setting *s) +{ + if(isSH3()) { + s->FLLFRQ = -1; + s->FRQCR = SH7705_CPG.FRQCR.word; + + s->CS0BCR = SH7705_BSC.CS0BCR.lword; + s->CS0WCR = SH7705_BSC.CS0WCR.lword; + s->CS2BCR = SH7705_BSC.CS2BCR.lword; + s->CS2WCR = SH7705_BSC.CS2WCR.lword; + s->CS3BCR = SH7705_BSC.CS3BCR.lword; + s->CS3WCR = SH7705_BSC.CS3WCR.lword; + s->CS5aBCR = SH7705_BSC.CS5ABCR.lword; + s->CS5aWCR = SH7705_BSC.CS5AWCR.lword; + } + else { + s->FLLFRQ = SH7305_CPG.FLLFRQ.lword; + s->FRQCR = SH7305_CPG.FRQCR.lword; + + s->CS0BCR = SH7305_BSC.CS0BCR.lword; + s->CS0WCR = SH7305_BSC.CS0WCR.lword; + s->CS2BCR = SH7305_BSC.CS2BCR.lword; + s->CS2WCR = SH7305_BSC.CS2WCR.lword; + s->CS3BCR = SH7305_BSC.CS3BCR.lword; + s->CS3WCR = SH7305_BSC.CS3WCR.lword; + s->CS5aBCR = SH7305_BSC.CS5ABCR.lword; + s->CS5aWCR = SH7305_BSC.CS5AWCR.lword; + } +} + +void cpg_set_overclock_setting(struct cpg_overclock_setting const *s) +{ + if(isSH3()) { + SH7705_WDT.WTCNT.WRITE = 0; + SH7705_WDT.WTCSR.WRITE = 0x65; + SH7705_CPG.FRQCR.word = s->FRQCR | 0x1000; + SH7705_BSC.CS0BCR.lword = s->CS0BCR; + SH7705_BSC.CS0WCR.lword = s->CS0WCR; + SH7705_BSC.CS2BCR.lword = s->CS2BCR; + SH7705_BSC.CS2WCR.lword = s->CS2WCR; + SH7705_BSC.CS3BCR.lword = s->CS3BCR; + SH7705_BSC.CS3WCR.lword = s->CS3WCR; + SH7705_BSC.CS5ABCR.lword = s->CS5aBCR; + SH7705_BSC.CS5AWCR.lword = s->CS5aWCR; + } + else { + SH7305_BSC.CS0WCR.WR = 11; /* 18 cycles */ + + SH7305_CPG.FLLFRQ.lword = s->FLLFRQ; + SH7305_CPG.FRQCR.lword = s->FRQCR; + SH7305_CPG.FRQCR.KICK = 1; + while(SH7305_CPG.LSTATS != 0) {} + + SH7305_BSC.CS0BCR.lword = s->CS0BCR; + SH7305_BSC.CS0WCR.lword = s->CS0WCR; + SH7305_BSC.CS2BCR.lword = s->CS2BCR; + SH7305_BSC.CS2WCR.lword = s->CS2WCR; + SH7305_BSC.CS3BCR.lword = s->CS3BCR; + SH7305_BSC.CS3WCR.lword = s->CS3WCR; + + if(SH7305_BSC.CS3WCR.A3CL == 1) + *SH7305_SDMR3_CL2 = 0; + else + *SH7305_SDMR3_CL3 = 0; + + SH7305_BSC.CS5ABCR.lword = s->CS5aBCR; + SH7305_BSC.CS5AWCR.lword = s->CS5aWCR; + } +} + +#ifdef FX9860G + +static struct cpg_overclock_setting const settings_fx9860g_sh3[5] = { /* CLOCK_SPEED_F1 */ - { .FLLFRQ = 0x00004000 + 900, - .FRQCR = 0x0F011112, - .CS0BCR = 0x36DA0400, - .CS2BCR = 0x36DA3400, - .CS3BCR = 0x36DB4400, - .CS5aBCR = 0x17DF0400, - .CS0WCR = 0x000003C0, - .CS2WCR = 0x000003C0, - .CS3WCR = 0x000024D1, - .CS5aWCR = 0x000203C1 }, + { .FRQCR = 0x1001, + .CS0BCR = 0x02480400, + .CS2BCR = 0x02483400, + .CS3BCR = 0x36DB0600, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x00000140, + .CS2WCR = 0x00000140, + .CS3WCR = 0x00000500, + .CS5aWCR = 0x00000D41 }, /* CLOCK_SPEED_F2 */ - { .FLLFRQ = 0x00004000 + 900, - .FRQCR = (PLL_16x<<24)+(DIV_4<<20)+(DIV_8<<12)+(DIV_8<<8)+DIV_8, - .CS0BCR = 0x24920400, - .CS2BCR = 0x24923400, - .CS3BCR = 0x24924400, - .CS5aBCR = 0x17DF0400, - .CS0WCR = 0x00000340, - .CS2WCR = 0x000003C0, - .CS3WCR = 0x000024D1, - .CS5aWCR = 0x000203C1 }, + { .FRQCR = (SH3_PLL_2x<<8)+(SH3_DIV_1<<4)+SH3_DIV_2, + .CS0BCR = 0x02480400, + .CS2BCR = 0x02483400, + .CS3BCR = 0x36DB0600, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x00000140, + .CS2WCR = 0x00000140, + .CS3WCR = 0x00000500, + .CS5aWCR = 0x00000D41 }, /* CLOCK_SPEED_F3 */ - { .FLLFRQ = 0x00004000 + 900, - .FRQCR = (PLL_26x<<24)+(DIV_4<<20)+(DIV_8<<12)+(DIV_8<<8)+DIV_8, - .CS0BCR = 0x24920400, - .CS2BCR = 0x24923400, - .CS3BCR = 0x24924400, - .CS5aBCR = 0x17DF0400, - .CS0WCR = 0x00000240, - .CS2WCR = 0x000003C0, - .CS3WCR = 0x000024D1, - .CS5aWCR = 0x000203C1 }, + { .FRQCR = (SH3_PLL_3x<<8)+(SH3_DIV_1<<4)+SH3_DIV_3, + .CS0BCR = 0x02480400, + .CS2BCR = 0x02483400, + .CS3BCR = 0x36DB0600, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x00000140, + .CS2WCR = 0x00000140, + .CS3WCR = 0x00000500, + .CS5aWCR = 0x00000D41 }, /* CLOCK_SPEED_F4 */ - { .FLLFRQ = 0x00004000 + 900, - .FRQCR = (PLL_32x<<24)+(DIV_2<<20)+(DIV_4<<12)+(DIV_8<<8)+DIV_16, - .CS0BCR = 0x24920400, - .CS2BCR = 0x24923400, - .CS3BCR = 0x24924400, - .CS5aBCR = 0x17DF0400, - .CS0WCR = 0x000002C0, - .CS2WCR = 0x000003C0, - .CS3WCR = 0x000024D1, - .CS5aWCR = 0x000203C1 }, + { .FRQCR = (SH3_PLL_4x<<8)+(SH3_DIV_1<<4)+SH3_DIV_4, + .CS0BCR = 0x02480400, + .CS2BCR = 0x02483400, + .CS3BCR = 0x36DB0600, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x00000140, + .CS2WCR = 0x00000140, + .CS3WCR = 0x00000500, + .CS5aWCR = 0x00000D41 }, /* CLOCK_SPEED_F5 */ - { .FLLFRQ = 0x00004000 + 900, - .FRQCR = (PLL_26x<<24)+(DIV_2<<20)+(DIV_4<<12)+(DIV_4<<8)+DIV_8, - .CS0BCR = 0x24920400, - .CS2BCR = 0x24923400, - .CS3BCR = 0x24924400, - .CS5aBCR = 0x17DF0400, - .CS0WCR = 0x00000440, - .CS2WCR = 0x000003C0, - .CS3WCR = 0x000024D1, - .CS5aWCR = 0x000203C1 }, + { .FRQCR = (SH3_PLL_4x<<8)+(SH3_DIV_1<<4)+SH3_DIV_4, + .CS0BCR = 0x02480400, + .CS2BCR = 0x02483400, + .CS3BCR = 0x36DB0600, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x000000C0, + .CS2WCR = 0x000100C0, + .CS3WCR = 0x00000500, + .CS5aWCR = 0x00000D41 }, }; -static struct cpg_overclock_setting settings_cg20[5] = { +static struct cpg_overclock_setting const settings_fx9860g_sh4[5] = { + /* CLOCK_SPEED_F1 */ + { .FLLFRQ = 0x00004384, + .FRQCR = 0x0F202203, + .CS0BCR = 0x24920400, + .CS2BCR = 0x24923400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x000005C0, + .CS2WCR = 0x00000140, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00000D41 }, + /* CLOCK_SPEED_F2 */ + { .FLLFRQ = 0x00004384, + .FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16, + .CS0BCR = 0x24920400, + .CS2BCR = 0x24923400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x000001C0, + .CS2WCR = 0x00000140, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00000D41 }, + /* CLOCK_SPEED_F3 */ + { .FLLFRQ = 0x00004384, + .FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_8<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16, + .CS0BCR = 0x04900400, + .CS2BCR = 0x04903400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x24920200, + .CS0WCR = 0x00000140, + .CS2WCR = 0x00000140, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00000D41 }, + /* CLOCK_SPEED_F4 */ + { .FLLFRQ = 0x00004384, + .FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16, + .CS0BCR = 0x04900400, + .CS2BCR = 0x04903400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x000001C0, + .CS2WCR = 0x00020140, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00000D41 }, + /* CLOCK_SPEED_F5 */ + { .FLLFRQ = 0x00004384, + .FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_4<<8)+SH4_DIV_16, + .CS0BCR = 0x14900400, + .CS2BCR = 0x04903400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x000003C0, + .CS2WCR = 0x000302C0, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00000D41 }, +}; + +static struct cpg_overclock_setting const settings_g35pe2[5] = { + /* CLOCK_SPEED_F1 */ + { .FLLFRQ = 0x00004384, + .FRQCR = 0x0F112213, + .CS0BCR = 0x24920400, + .CS2BCR = 0x24923400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x000001C0, + .CS2WCR = 0x000001C0, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00031340 }, + /* CLOCK_SPEED_F2 */ + { .FLLFRQ = 0x00004384, + .FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16, + .CS0BCR = 0x24920400, + .CS2BCR = 0x24923400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x000001C0, + .CS2WCR = 0x00000140, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00000D41 }, + /* CLOCK_SPEED_F3 */ + { .FLLFRQ = 0x00004384, + .FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_8<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16, + .CS0BCR = 0x04900400, + .CS2BCR = 0x04903400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x24920200, + .CS0WCR = 0x00000140, + .CS2WCR = 0x00000140, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00000D41 }, + /* CLOCK_SPEED_F4 */ + { .FLLFRQ = 0x00004384, + .FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_16, + .CS0BCR = 0x04900400, + .CS2BCR = 0x04903400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x000001C0, + .CS2WCR = 0x00020140, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00031B40 }, + /* CLOCK_SPEED_F5 */ + { .FLLFRQ = 0x00004384, + .FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_8<<8)+SH4_DIV_16, + .CS0BCR = 0x14900400, + .CS2BCR = 0x04903400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x224A0200, + .CS0WCR = 0x000001C0, + .CS2WCR = 0x00020140, + .CS3WCR = 0x000024D0, + .CS5aWCR = 0x00031B40 }, +}; + +#endif /* FX9860G */ + +#ifdef FXCG50 + +static struct cpg_overclock_setting const settings_prizm[5] = { /* CLOCK_SPEED_F1 */ { .FLLFRQ = 0x00004000 + 900, .FRQCR = 0x0F102203, @@ -158,7 +306,7 @@ static struct cpg_overclock_setting settings_cg20[5] = { .CS5aWCR = 0x00010240 }, /* CLOCK_SPEED_F2 */ { .FLLFRQ = 0x00004000 + 900, - .FRQCR = (PLL_32x<<24)+(DIV_8<<20)+(DIV_16<<12)+(DIV_16<<8)+DIV_32, + .FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_8<<20)+(SH4_DIV_16<<12)+(SH4_DIV_16<<8)+SH4_DIV_32, .CS0BCR = 0x04900400, .CS2BCR = 0x04903400, .CS3BCR = 0x24924400, @@ -169,7 +317,7 @@ static struct cpg_overclock_setting settings_cg20[5] = { .CS5aWCR = 0x00010240 }, /* CLOCK_SPEED_F3 */ { .FLLFRQ = 0x00004000 + 900, - .FRQCR = (PLL_32x<<24)+(DIV_4<<20)+(DIV_8<<12)+(DIV_8<<8)+DIV_32, + .FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_32, .CS0BCR = 0x24900400, .CS2BCR = 0x04903400, .CS3BCR = 0x24924400, @@ -180,7 +328,7 @@ static struct cpg_overclock_setting settings_cg20[5] = { .CS5aWCR = 0x00010240 }, /* CLOCK_SPEED_F4 */ { .FLLFRQ = 0x00004000 + 900, - .FRQCR = (PLL_32x<<24)+(DIV_4<<20)+(DIV_4<<12)+(DIV_4<<8)+DIV_32, + .FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_4<<12)+(SH4_DIV_4<<8)+SH4_DIV_32, .CS0BCR = 0x44900400, .CS2BCR = 0x04903400, .CS3BCR = 0x24924400, @@ -191,7 +339,7 @@ static struct cpg_overclock_setting settings_cg20[5] = { .CS5aWCR = 0x00010240 }, /* CLOCK_SPEED_F5 */ { .FLLFRQ = 0x00004000 + 900, - .FRQCR = (PLL_26x<<24)+(DIV_2<<20)+(DIV_4<<12)+(DIV_4<<8)+DIV_16, + .FRQCR = (SH4_PLL_26x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_4<<8)+SH4_DIV_16, .CS0BCR = 0x34900400, .CS2BCR = 0x04903400, .CS3BCR = 0x24924400, @@ -202,35 +350,125 @@ static struct cpg_overclock_setting settings_cg20[5] = { .CS5aWCR = 0x00010240 }, }; -static struct cpg_overclock_setting *get_settings(void) +static struct cpg_overclock_setting const settings_fxcg50[5] = { + /* CLOCK_SPEED_F1 */ + { .FLLFRQ = 0x00004000 + 900, + .FRQCR = 0x0F011112, + .CS0BCR = 0x36DA0400, + .CS2BCR = 0x36DA3400, + .CS3BCR = 0x36DB4400, + .CS5aBCR = 0x17DF0400, + .CS0WCR = 0x000003C0, + .CS2WCR = 0x000003C0, + .CS3WCR = 0x000024D1, + .CS5aWCR = 0x000203C1 }, + /* CLOCK_SPEED_F2 */ + { .FLLFRQ = 0x00004000 + 900, + .FRQCR = (SH4_PLL_16x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_8, + .CS0BCR = 0x24920400, + .CS2BCR = 0x24923400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x17DF0400, + .CS0WCR = 0x00000340, + .CS2WCR = 0x000003C0, + .CS3WCR = 0x000024D1, + .CS5aWCR = 0x000203C1 }, + /* CLOCK_SPEED_F3 */ + { .FLLFRQ = 0x00004000 + 900, + .FRQCR = (SH4_PLL_26x<<24)+(SH4_DIV_4<<20)+(SH4_DIV_8<<12)+(SH4_DIV_8<<8)+SH4_DIV_8, + .CS0BCR = 0x24920400, + .CS2BCR = 0x24923400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x17DF0400, + .CS0WCR = 0x00000240, + .CS2WCR = 0x000003C0, + .CS3WCR = 0x000024D1, + .CS5aWCR = 0x000203C1 }, + /* CLOCK_SPEED_F4 */ + { .FLLFRQ = 0x00004000 + 900, + .FRQCR = (SH4_PLL_32x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_8<<8)+SH4_DIV_16, + .CS0BCR = 0x24920400, + .CS2BCR = 0x24923400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x17DF0400, + .CS0WCR = 0x000002C0, + .CS2WCR = 0x000003C0, + .CS3WCR = 0x000024D1, + .CS5aWCR = 0x000203C1 }, + /* CLOCK_SPEED_F5 */ + { .FLLFRQ = 0x00004000 + 900, + .FRQCR = (SH4_PLL_26x<<24)+(SH4_DIV_2<<20)+(SH4_DIV_4<<12)+(SH4_DIV_4<<8)+SH4_DIV_8, + .CS0BCR = 0x24920400, + .CS2BCR = 0x24923400, + .CS3BCR = 0x24924400, + .CS5aBCR = 0x17DF0400, + .CS0WCR = 0x00000440, + .CS2WCR = 0x000003C0, + .CS3WCR = 0x000024D1, + .CS5aWCR = 0x000203C1 }, +}; + +#endif /* FXCG50 */ + +static struct cpg_overclock_setting const *get_settings(void) { - if(gint[HWCALC] == HWCALC_FXCG50) - return settings_cg50; +#ifdef FX9860G + if(gint[HWCALC] == HWCALC_FX9860G_SH3) + return settings_fx9860g_sh3; + if(gint[HWCALC] == HWCALC_FX9860G_SH4) + return settings_fx9860g_sh4; + if(gint[HWCALC] == HWCALC_G35PE2) + return settings_g35pe2; +#endif /* FX9860G */ + +#ifdef FXCG50 if(gint[HWCALC] == HWCALC_PRIZM) - return settings_cg20; + return settings_prizm; + if(gint[HWCALC] == HWCALC_FXCG50) + return settings_fxcg50; +#endif /* FXCG50 */ + return NULL; } int clock_get_speed(void) { - struct cpg_overclock_setting *settings = get_settings(); + struct cpg_overclock_setting const *settings = get_settings(); if(!settings) return CLOCK_SPEED_UNKNOWN; - for(int i = 0; i < 5; i++) { - struct cpg_overclock_setting *s = &settings[i]; + if(isSH3()) { + for(int i = 0; i < 5; i++) { + struct cpg_overclock_setting const *s = &settings[i]; - if(CPG.FLLFRQ.lword == s->FLLFRQ - && CPG.FRQCR.lword == s->FRQCR - && BSC.CS0BCR.lword == s->CS0BCR - && BSC.CS2BCR.lword == s->CS2BCR - && BSC.CS3BCR.lword == s->CS3BCR - && BSC.CS5ABCR.lword == s->CS5aBCR - && BSC.CS0WCR.lword == s->CS0WCR - && BSC.CS2WCR.lword == s->CS2WCR - && BSC.CS3WCR.lword == s->CS3WCR - && BSC.CS5AWCR.lword == s->CS5aWCR) - return CLOCK_SPEED_F1 + i; + if(SH7705_CPG.FRQCR.word == (s->FRQCR | 0x1000) + && SH7705_BSC.CS0BCR.lword == s->CS0BCR + && SH7705_BSC.CS2BCR.lword == s->CS2BCR + && SH7705_BSC.CS3BCR.lword == s->CS3BCR + && SH7705_BSC.CS5ABCR.lword == s->CS5aBCR + && SH7705_BSC.CS0WCR.lword == s->CS0WCR + && SH7705_BSC.CS2WCR.lword == s->CS2WCR + && SH7705_BSC.CS3WCR.lword == s->CS3WCR + && SH7705_BSC.CS5AWCR.lword == s->CS5aWCR) + return CLOCK_SPEED_F1 + i; + } + } + else { + for(int i = 0; i < 5; i++) { + struct cpg_overclock_setting const *s = &settings[i]; + + if(SH7305_CPG.FLLFRQ.lword == s->FLLFRQ + && SH7305_CPG.FRQCR.lword == s->FRQCR + && SH7305_BSC.CS0BCR.lword == s->CS0BCR + && SH7305_BSC.CS2BCR.lword == s->CS2BCR + && SH7305_BSC.CS3BCR.lword == s->CS3BCR + && SH7305_BSC.CS5ABCR.lword == s->CS5aBCR + && SH7305_BSC.CS0WCR.lword == s->CS0WCR + && SH7305_BSC.CS2WCR.lword == s->CS2WCR + && SH7305_BSC.CS3WCR.lword == s->CS3WCR + && SH7305_BSC.CS5AWCR.lword == s->CS5aWCR) + return CLOCK_SPEED_F1 + i; + } } return CLOCK_SPEED_UNKNOWN; @@ -243,11 +481,11 @@ void clock_set_speed(int level) if(clock_get_speed() == level) return; - struct cpg_overclock_setting *settings = get_settings(); + struct cpg_overclock_setting const *settings = get_settings(); if(!settings) return; - struct cpg_overclock_setting *s = &settings[level - CLOCK_SPEED_F1]; + struct cpg_overclock_setting const *s = &settings[level - CLOCK_SPEED_F1]; uint32_t old_Pphi = clock_freq()->Pphi_f; /* Wait for asynchronous tasks to complete */ @@ -269,5 +507,3 @@ void clock_set_speed(int level) cpu_atomic_end(); } - -#endif