diff --git a/firmware/export/config/sansaclipplus.h b/firmware/export/config/sansaclipplus.h index ab4408a..12151a7 100644 --- a/firmware/export/config/sansaclipplus.h +++ b/firmware/export/config/sansaclipplus.h @@ -188,7 +188,7 @@ #define CONFIG_LED LED_VIRTUAL /* Define this if you have adjustable CPU frequency */ -//#define HAVE_ADJUSTABLE_CPU_FREQ +#define HAVE_ADJUSTABLE_CPU_FREQ #define BOOTFILE_EXT "sansa" #define BOOTFILE "rockbox." BOOTFILE_EXT diff --git a/firmware/export/config/sansaclipv2.h b/firmware/export/config/sansaclipv2.h index 262ed36..4b83b32 100644 --- a/firmware/export/config/sansaclipv2.h +++ b/firmware/export/config/sansaclipv2.h @@ -181,7 +181,7 @@ #define CONFIG_LED LED_VIRTUAL /* Define this if you have adjustable CPU frequency */ -//#define HAVE_ADJUSTABLE_CPU_FREQ +#define HAVE_ADJUSTABLE_CPU_FREQ #define BOOTFILE_EXT "sansa" #define BOOTFILE "rockbox." BOOTFILE_EXT diff --git a/firmware/export/config/sansafuzev2.h b/firmware/export/config/sansafuzev2.h index a21eb34..bc22215 100644 --- a/firmware/export/config/sansafuzev2.h +++ b/firmware/export/config/sansafuzev2.h @@ -196,7 +196,7 @@ #endif /* !BOOTLOADER */ /* Define this if you have adjustable CPU frequency */ -//#define HAVE_ADJUSTABLE_CPU_FREQ +#define HAVE_ADJUSTABLE_CPU_FREQ #define BOOTFILE_EXT "sansa" #define BOOTFILE "rockbox." BOOTFILE_EXT diff --git a/firmware/target/arm/as3525/clock-target.h b/firmware/target/arm/as3525/clock-target.h index 96c2c26..847eef9 100644 --- a/firmware/target/arm/as3525/clock-target.h +++ b/firmware/target/arm/as3525/clock-target.h @@ -76,13 +76,7 @@ * Also note that CGU_PERI is based on fclk, not PLLA */ -#ifdef SANSA_FUZEV2 -/* display is unbearably slow at 24MHz - * 34285715 HZ works ok but 40MHz works even better*/ #define AS3525_DRAM_FREQ 40000000 /* Initial DRAM frequency */ -#else -#define AS3525_DRAM_FREQ 24000000 /* Initial DRAM frequency */ -#endif /* SANSA_FUZEV2 */ #else /* AS3525v1 */ diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c index 44e210a..286a1fc 100644 --- a/firmware/target/arm/as3525/system-as3525.c +++ b/firmware/target/arm/as3525/system-as3525.c @@ -459,32 +459,81 @@ void set_cpu_frequency(long frequency) } } #else /* as3525v2 */ -/* FIXME : disabled for now, seems to cause buggy memory accesses - * Disabling MMU or putting the function in uncached memory seems to help? */ + +static inline void clk_wait(void) +{ +#if 0 + unsigned i = 40; + do { + nop; + } while(--i); +#endif +} + void set_cpu_frequency(long frequency) { int oldstatus = disable_irq_save(); + unsigned long cgu_peri = CGU_PERI & ~(0xF << 2); + +#if AS3525_PLLA_FREQ != 240000000 +# error only suited for PLLA_FREQ == CPUFREQ_MAX == 240MHz +#endif + +#if AS3525_PCLK_FREQ == 24000000 /* Clipv2 / Clip+ */ + /* fclk 240MHz -> 24MHz */ + static const uint8_t divider[][2] = { + /* -> change fclk -> tmp pclk -> change pclk -> new pclk */ + /* fclk div pclk div fclk tmp pclk new pclk */ + { 1-1, 10-1 }, // 240 24 24 + { 2-1, 5-1 }, // 120 48 24 + { 3-1, 2-1 }, // 80 20 40 + { 5-1, 1-1 }, // 48 24 48 + { 10-1, 1-1 }, // 24 24 24 + }; +#elif AS3525_PCLK_FREQ == 40000000 /* Fuzev2 */ + /* fclk 240MHz -> 40MHz */ + static const uint8_t divider[][2] = { + /* -> change fclk -> tmp pclk -> change pclk -> new pclk */ + /* fclk div pclk div fclk tmp pclk new pclk */ + { 1-1, 6-1 }, // 240 40 40 + { 2-1, 3-1 }, // 120 20 40 + { 4-1, 2-1 }, // 60 20 30 + { 6-1, 1-1 }, // 40 20 40 + }; +#endif + + const size_t n_divs = sizeof(divider)/sizeof(divider[0]); /* We only have 2 settings */ cpu_frequency = (frequency == CPUFREQ_MAX) ? frequency : CPUFREQ_NORMAL; if(frequency == CPUFREQ_MAX) { - /* Change PCLK while FCLK is low, so it doesn't go too high */ - CGU_PERI = (CGU_PERI & ~(0xF << 2)) | (AS3525_PCLK_DIV0 << 2); - - CGU_PROC = ((AS3525_FCLK_POSTDIV << 4) | - (AS3525_FCLK_PREDIV << 2) | - AS3525_FCLK_SEL); + unsigned i = n_divs - 1; + do + { + CGU_PERI = cgu_peri | (divider[i][1] << 2); + clk_wait(); + + CGU_PROC = (divider[i][0]<< 4) + | (AS3525_FCLK_PREDIV << 2) + | AS3525_FCLK_SEL; + clk_wait(); + } while(i--); } else { - CGU_PROC = ((AS3525_FCLK_POSTDIV_UNBOOSTED << 4) | - (AS3525_FCLK_PREDIV << 2) | - AS3525_FCLK_SEL); - - /* Change PCLK after FCLK is low, so it doesn't go too high */ - CGU_PERI = (CGU_PERI & ~(0xF << 2)) | (AS3525_PCLK_DIV0_UNBOOSTED << 2); + unsigned i = 1; + do + { + CGU_PROC = (divider[i][0] << 4) + | (AS3525_FCLK_PREDIV << 2) + | AS3525_FCLK_SEL; + clk_wait(); + + CGU_PERI = cgu_peri | (divider[i][1] << 2); + clk_wait(); + } while(++i < n_divs); } restore_irq(oldstatus);