cpg: add overclock save/restore functions

This commit is contained in:
Lephe 2023-01-05 20:25:44 +01:00
parent b3416dcc25
commit 7e859169fe
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
2 changed files with 45 additions and 41 deletions

View file

@ -135,6 +135,26 @@ int clock_get_speed(void);
leaving the add-in. */
void clock_set_speed(int speed);
/* If you want to faithfully save and restore the clock state while properly
handling clock speeds that are not Ftune/PTune's defaults, you can get a
full copy of the settings.
WARNING: Applying random settings with cpg_set_overclock_setting() might
damage your calculator! */
struct cpg_overclock_setting
{
uint32_t FLLFRQ, FRQCR;
uint32_t CS0BCR, CS2BCR, CS3BCR, CS5aBCR;
uint32_t CS0WCR, CS2WCR, CS3WCR, CS5aWCR;
};
/* Queries the clock setting from the hardware. */
void cpg_get_overclock_setting(struct cpg_overclock_setting *s);
/* Applies the specified overclock setting. */
void cpg_set_overclock_setting(struct cpg_overclock_setting const *s);
//---
// Sleep functions
//---
@ -153,27 +173,6 @@ void sleep_us_spin(uint64_t delay_us);
/* sleep_ms(): Sleep for a fixed duration in milliseconds */
#define sleep_ms(delay_ms) sleep_us((delay_ms) * 1000ull)
//---
// Low-level overclock functions
//
// These low-level functions directly read or write registers involved in
// setting the overclock level. Don't use them directly unless you understand
// how their interactions with the environment; instead, use clock_set_speed().
//---
struct cpg_overclock_setting
{
uint32_t FLLFRQ, FRQCR;
uint32_t CS0BCR, CS2BCR, CS3BCR, CS5aBCR;
uint32_t CS0WCR, CS2WCR, CS3WCR, CS5aWCR;
};
/* Queries the clock setting from the hardware. */
void cpg_get_overclock_setting(struct cpg_overclock_setting *s);
/* Applies the specified overclock setting. */
void cpg_set_overclock_setting(struct cpg_overclock_setting const *s);
#ifdef __cplusplus
}
#endif

View file

@ -77,7 +77,7 @@ void cpg_get_overclock_setting(struct cpg_overclock_setting *s)
}
}
void cpg_set_overclock_setting(struct cpg_overclock_setting const *s)
static void cpg_low_level_set_setting(struct cpg_overclock_setting const *s)
{
if(isSH3()) {
SH7705_WDT.WTCNT.WRITE = 0;
@ -117,6 +117,30 @@ void cpg_set_overclock_setting(struct cpg_overclock_setting const *s)
}
}
void cpg_set_overclock_setting(struct cpg_overclock_setting const *s)
{
uint32_t old_Pphi = clock_freq()->Pphi_f;
/* Wait for asynchronous tasks to complete */
gint_world_sync();
/* Disable interrupts during the change */
cpu_atomic_start();
/* Load the clock settings */
cpg_low_level_set_setting(s);
/* Determine the change in frequency for Pϕ and recompute CPG data */
cpg_compute_freq();
uint32_t new_Pphi = clock_freq()->Pphi_f;
/* Update timers' TCNT and TCOR to match the new clock speed */
void timer_rescale(uint32_t old_Pphi, uint32_t new_Pphi);
timer_rescale(old_Pphi, new_Pphi);
cpu_atomic_end();
}
#ifdef FX9860G
static struct cpg_overclock_setting const settings_fx9860g_sh3[5] = {
@ -486,24 +510,5 @@ void clock_set_speed(int level)
return;
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 */
gint_world_sync();
/* Disable interrupts during the change */
cpu_atomic_start();
/* Set the clock settings */
cpg_set_overclock_setting(s);
/* Determine the change in frequency for Pϕ and recompute CPG data */
cpg_compute_freq();
uint32_t new_Pphi = clock_freq()->Pphi_f;
/* Update timers' TCNT and TCOR to match the new clock speed */
void timer_rescale(uint32_t old_Pphi, uint32_t new_Pphi);
timer_rescale(old_Pphi, new_Pphi);
cpu_atomic_end();
}