From eb0e41c1ccb0dcf35efa7e1434bb0e35c9df1543 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Fri, 7 Aug 2020 00:44:55 -0400 Subject: jz4760: Support dynamic reclocking! default/low speed is 192 MHz, Max is 576 Downclock PCLK/MCLK/etc to 96MHz to save a bit of juice Honestly the high speed could be dialed down to, eg 384 as this thing is so bloody fast.. Change-Id: Ie65597c74290f1603e65f69dae8e75b59c8ba0b4 --- firmware/export/config/xduoox3.h | 14 ++++- .../target/mips/ingenic_jz47xx/ata-sd-jz4760.c | 16 ++++-- .../target/mips/ingenic_jz47xx/system-jz4760.c | 61 +++++++++++++++------- 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/firmware/export/config/xduoox3.h b/firmware/export/config/xduoox3.h index f510495bd9..999b6b9912 100644 --- a/firmware/export/config/xduoox3.h +++ b/firmware/export/config/xduoox3.h @@ -148,8 +148,18 @@ /* Define this if you have a Ingenic JZ4760B */ #define CONFIG_CPU JZ4760B -/* Define this to the CPU frequency */ -#define CPU_FREQ 480000000 /* CPU clock: 480 MHz -- Keep a multiple of 48MHz! */ +/* We have adjustable frequency */ +#define CPUFREQ_MAX 576000000 // datasheet sez 600MHz max. Must be multiple of 48! +#define CPUFREQ_MIN 192000000 +#define CPUFREQ_DEFAULT CPUFREQ_MIN + +#define HAVE_ADJUSTABLE_CPU_FREQ +#ifdef HAVE_ADJUSTABLE_CPU_FREQ +//#define HAVE_GUI_BOOST +#define CPUFREQ_NORMAL CPUFREQ_MIN +#else +#define CPU_FREQ CPUFREQ_MAX +#endif /* Define this if you want to use the JZ47XX i2c interface */ #define CONFIG_I2C I2C_JZ47XX diff --git a/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4760.c b/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4760.c index 0135c1ced9..6862262045 100644 --- a/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4760.c @@ -633,14 +633,23 @@ static inline unsigned int jz_sd_calc_clkrt(const int drive, unsigned int rate) return clkrt; } -static inline void cpm_select_msc_clk(unsigned int rate) +#ifndef HAVE_ADJUSTABLE_CPU_FREQ +#define cpu_frequency __cpm_get_pllout2() +#endif + +void cpm_select_msc_clk(void) { - unsigned int div = __cpm_get_pllout2() / rate; + unsigned int div = cpu_frequency / SD_CLOCK_FAST; + if (div == 0) div = 1; + if (div == __cpm_get_mscdiv()) + return; + REG_CPM_MSCCDR = MSCCDR_MCS | (div - 1); DEBUG("MSCCLK == %x\n", REG_CPM_MSCCDR); + __cpm_enable_pll_change(); } /* Set the MMC clock frequency */ @@ -651,9 +660,8 @@ static void jz_sd_set_clock(const int drive, unsigned int rate) jz_sd_stop_clock(drive); /* select clock source from CPM */ - cpm_select_msc_clk(rate); + cpm_select_msc_clk(); - __cpm_enable_pll_change(); clkrt = jz_sd_calc_clkrt(drive, rate); REG_MSC_CLKRT(MSC_CHN(drive)) = clkrt; diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4760.c b/firmware/target/mips/ingenic_jz47xx/system-jz4760.c index 73e9ab7749..c28aa8f967 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/system-jz4760.c @@ -417,38 +417,44 @@ static inline unsigned int pll_calc_m_n_od(unsigned int speed, unsigned int xtal static void pll0_init(unsigned int freq) { register unsigned int cfcr, plcr1; - int usbdiv; + int usbdiv, offset; /** divisors, * for jz4760b,I:H:H2:P:M:S. * DIV should be one of [1, 2, 3, 4, 6, 8] */ - const int div[6] = {1, 4, 4, 4, 4, 4}; + const int div[2][6] = { { 1, 2, 2, 2, 2, 2 }, + { 1, 6, 6, 6, 6, 6 } }; const int n2FR[9] = { 0, 0, 1, 2, 3, 0, 4, 0, 5 }; - /* @ CPU_FREQ of 492MHZ, this means: - 492MHz CCLK - 123MHz HCLK - 123MHz H2CLK - 123MHz PCLK - 123MHz MCLK - 123MHZ SCLK ( must equal H2CLK or HCLK/2) + /* @ CPU_FREQ of 576/192MHz, this means: + CCLK (= HCLK*n, H2CLK*n, PCLK*o) + 96MHz HCLK (= MCLK or 2x MCLK, PCLK*n) + 96MHz H2CLK (= HCLK or HCLK/2, PCLK*n) + 96MHz PCLK + 96MHz MCLK (= PCLK*n) + 96MHZ SCLK (= H2CLK or HCLK/2) */ + if (freq > CPUFREQ_NORMAL) + offset = 1; + else + offset = 0; + /* set ahb **/ REG32(HARB0_BASE) = 0x00300000; REG32(0xb3070048) = 0x00000000; REG32(HARB2_BASE) = 0x00FFFFFF; cfcr = CPCCR_PCS | // no divisor on PLL for peripherals - (n2FR[div[0]] << CPCCR_CDIV_LSB) | - (n2FR[div[1]] << CPCCR_HDIV_LSB) | - (n2FR[div[2]] << CPCCR_H2DIV_LSB) | - (n2FR[div[3]] << CPCCR_PDIV_LSB) | - (n2FR[div[4]] << CPCCR_MDIV_LSB) | - (n2FR[div[5]] << CPCCR_SDIV_LSB); + (n2FR[div[offset][0]] << CPCCR_CDIV_LSB) | + (n2FR[div[offset][1]] << CPCCR_HDIV_LSB) | + (n2FR[div[offset][2]] << CPCCR_H2DIV_LSB) | + (n2FR[div[offset][3]] << CPCCR_PDIV_LSB) | + (n2FR[div[offset][4]] << CPCCR_MDIV_LSB) | + (n2FR[div[offset][5]] << CPCCR_SDIV_LSB); // write REG_DDRC_CTRL 8 times to clear ddr fifo REG_DDRC_CTRL = 0; @@ -569,6 +575,10 @@ int serial_preinit(void) return 0; } +#ifndef HAVE_ADJUSTABLE_CPU_FREQ +#define cpu_frequency CPU_FREQ +#endif + void usb_preinit(void) { /* Clear ECS bit of CPCCR, 0:clock source is EXCLK, 1:clock source is EXCLK/2 */ @@ -589,7 +599,7 @@ void usb_preinit(void) REG_CPM_USBVBFIL = 0x80; /* rdt */ - REG_CPM_USBRDT = (600 * (CPU_FREQ / 1000000)) / 1000; + REG_CPM_USBRDT = (600 * (CPUFREQ_DEFAULT / 1000000)) / 1000; /* rdt - filload_en */ REG_CPM_USBRDT |= (1 << 25); @@ -649,8 +659,8 @@ void ICODE_ATTR system_main(void) mmu_init(); - pll0_init(CPU_FREQ); // PLL0 drives everything but audio - pll1_disable(); // Leave PLL1 disabled until audio needs it + pll0_init(CPUFREQ_DEFAULT); // PLL0 drives everything but audio + pll1_disable(); // Leave PLL1 disabled until audio needs it serial_preinit(); usb_preinit(); @@ -713,9 +723,22 @@ int system_memory_guard(int newmode) return 0; } + #ifdef HAVE_ADJUSTABLE_CPU_FREQ +void cpm_select_msc_clk(void); + void set_cpu_frequency(long frequency) { - serial_putsf("set_cpu_frequency: %d\n", frequency); + if (frequency == cpu_frequency) + return; + else if (frequency < CPUFREQ_MIN) + frequency = CPUFREQ_MIN; + else if (frequency > CPUFREQ_MAX) + frequency = CPUFREQ_MAX; + + pll0_init(frequency); + // FIX PCLK (ie i2c)? + cpu_frequency = __cpm_get_pllout2(); + cpm_select_msc_clk(); } #endif -- cgit v1.2.3