diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2020-08-07 00:44:55 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2020-08-07 11:42:45 -0400 |
commit | eb0e41c1ccb0dcf35efa7e1434bb0e35c9df1543 (patch) | |
tree | 8989f4d1bfe2c24d67d72026f97ec8e0cc11f949 | |
parent | 62146ed73513ec62b57163d229c6719b9349c640 (diff) | |
download | rockbox-eb0e41c1ccb0dcf35efa7e1434bb0e35c9df1543.tar.gz rockbox-eb0e41c1ccb0dcf35efa7e1434bb0e35c9df1543.zip |
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
-rw-r--r-- | firmware/export/config/xduoox3.h | 14 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/ata-sd-jz4760.c | 16 | ||||
-rw-r--r-- | firmware/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 @@ | |||
148 | /* Define this if you have a Ingenic JZ4760B */ | 148 | /* Define this if you have a Ingenic JZ4760B */ |
149 | #define CONFIG_CPU JZ4760B | 149 | #define CONFIG_CPU JZ4760B |
150 | 150 | ||
151 | /* Define this to the CPU frequency */ | 151 | /* We have adjustable frequency */ |
152 | #define CPU_FREQ 480000000 /* CPU clock: 480 MHz -- Keep a multiple of 48MHz! */ | 152 | #define CPUFREQ_MAX 576000000 // datasheet sez 600MHz max. Must be multiple of 48! |
153 | #define CPUFREQ_MIN 192000000 | ||
154 | #define CPUFREQ_DEFAULT CPUFREQ_MIN | ||
155 | |||
156 | #define HAVE_ADJUSTABLE_CPU_FREQ | ||
157 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
158 | //#define HAVE_GUI_BOOST | ||
159 | #define CPUFREQ_NORMAL CPUFREQ_MIN | ||
160 | #else | ||
161 | #define CPU_FREQ CPUFREQ_MAX | ||
162 | #endif | ||
153 | 163 | ||
154 | /* Define this if you want to use the JZ47XX i2c interface */ | 164 | /* Define this if you want to use the JZ47XX i2c interface */ |
155 | #define CONFIG_I2C I2C_JZ47XX | 165 | #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) | |||
633 | return clkrt; | 633 | return clkrt; |
634 | } | 634 | } |
635 | 635 | ||
636 | static inline void cpm_select_msc_clk(unsigned int rate) | 636 | #ifndef HAVE_ADJUSTABLE_CPU_FREQ |
637 | #define cpu_frequency __cpm_get_pllout2() | ||
638 | #endif | ||
639 | |||
640 | void cpm_select_msc_clk(void) | ||
637 | { | 641 | { |
638 | unsigned int div = __cpm_get_pllout2() / rate; | 642 | unsigned int div = cpu_frequency / SD_CLOCK_FAST; |
643 | |||
639 | if (div == 0) | 644 | if (div == 0) |
640 | div = 1; | 645 | div = 1; |
641 | 646 | ||
647 | if (div == __cpm_get_mscdiv()) | ||
648 | return; | ||
649 | |||
642 | REG_CPM_MSCCDR = MSCCDR_MCS | (div - 1); | 650 | REG_CPM_MSCCDR = MSCCDR_MCS | (div - 1); |
643 | DEBUG("MSCCLK == %x\n", REG_CPM_MSCCDR); | 651 | DEBUG("MSCCLK == %x\n", REG_CPM_MSCCDR); |
652 | __cpm_enable_pll_change(); | ||
644 | } | 653 | } |
645 | 654 | ||
646 | /* Set the MMC clock frequency */ | 655 | /* Set the MMC clock frequency */ |
@@ -651,9 +660,8 @@ static void jz_sd_set_clock(const int drive, unsigned int rate) | |||
651 | jz_sd_stop_clock(drive); | 660 | jz_sd_stop_clock(drive); |
652 | 661 | ||
653 | /* select clock source from CPM */ | 662 | /* select clock source from CPM */ |
654 | cpm_select_msc_clk(rate); | 663 | cpm_select_msc_clk(); |
655 | 664 | ||
656 | __cpm_enable_pll_change(); | ||
657 | clkrt = jz_sd_calc_clkrt(drive, rate); | 665 | clkrt = jz_sd_calc_clkrt(drive, rate); |
658 | REG_MSC_CLKRT(MSC_CHN(drive)) = clkrt; | 666 | REG_MSC_CLKRT(MSC_CHN(drive)) = clkrt; |
659 | 667 | ||
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 | |||
417 | static void pll0_init(unsigned int freq) | 417 | static void pll0_init(unsigned int freq) |
418 | { | 418 | { |
419 | register unsigned int cfcr, plcr1; | 419 | register unsigned int cfcr, plcr1; |
420 | int usbdiv; | 420 | int usbdiv, offset; |
421 | 421 | ||
422 | /** divisors, | 422 | /** divisors, |
423 | * for jz4760b,I:H:H2:P:M:S. | 423 | * for jz4760b,I:H:H2:P:M:S. |
424 | * DIV should be one of [1, 2, 3, 4, 6, 8] | 424 | * DIV should be one of [1, 2, 3, 4, 6, 8] |
425 | */ | 425 | */ |
426 | const int div[6] = {1, 4, 4, 4, 4, 4}; | 426 | const int div[2][6] = { { 1, 2, 2, 2, 2, 2 }, |
427 | { 1, 6, 6, 6, 6, 6 } }; | ||
427 | const int n2FR[9] = { | 428 | const int n2FR[9] = { |
428 | 0, 0, 1, 2, 3, 0, 4, 0, 5 | 429 | 0, 0, 1, 2, 3, 0, 4, 0, 5 |
429 | }; | 430 | }; |
430 | 431 | ||
431 | /* @ CPU_FREQ of 492MHZ, this means: | 432 | /* @ CPU_FREQ of 576/192MHz, this means: |
432 | 492MHz CCLK | 433 | CCLK (= HCLK*n, H2CLK*n, PCLK*o) |
433 | 123MHz HCLK | 434 | 96MHz HCLK (= MCLK or 2x MCLK, PCLK*n) |
434 | 123MHz H2CLK | 435 | 96MHz H2CLK (= HCLK or HCLK/2, PCLK*n) |
435 | 123MHz PCLK | 436 | 96MHz PCLK |
436 | 123MHz MCLK | 437 | 96MHz MCLK (= PCLK*n) |
437 | 123MHZ SCLK ( must equal H2CLK or HCLK/2) | 438 | 96MHZ SCLK (= H2CLK or HCLK/2) |
438 | */ | 439 | */ |
439 | 440 | ||
441 | if (freq > CPUFREQ_NORMAL) | ||
442 | offset = 1; | ||
443 | else | ||
444 | offset = 0; | ||
445 | |||
440 | /* set ahb **/ | 446 | /* set ahb **/ |
441 | REG32(HARB0_BASE) = 0x00300000; | 447 | REG32(HARB0_BASE) = 0x00300000; |
442 | REG32(0xb3070048) = 0x00000000; | 448 | REG32(0xb3070048) = 0x00000000; |
443 | REG32(HARB2_BASE) = 0x00FFFFFF; | 449 | REG32(HARB2_BASE) = 0x00FFFFFF; |
444 | 450 | ||
445 | cfcr = CPCCR_PCS | // no divisor on PLL for peripherals | 451 | cfcr = CPCCR_PCS | // no divisor on PLL for peripherals |
446 | (n2FR[div[0]] << CPCCR_CDIV_LSB) | | 452 | (n2FR[div[offset][0]] << CPCCR_CDIV_LSB) | |
447 | (n2FR[div[1]] << CPCCR_HDIV_LSB) | | 453 | (n2FR[div[offset][1]] << CPCCR_HDIV_LSB) | |
448 | (n2FR[div[2]] << CPCCR_H2DIV_LSB) | | 454 | (n2FR[div[offset][2]] << CPCCR_H2DIV_LSB) | |
449 | (n2FR[div[3]] << CPCCR_PDIV_LSB) | | 455 | (n2FR[div[offset][3]] << CPCCR_PDIV_LSB) | |
450 | (n2FR[div[4]] << CPCCR_MDIV_LSB) | | 456 | (n2FR[div[offset][4]] << CPCCR_MDIV_LSB) | |
451 | (n2FR[div[5]] << CPCCR_SDIV_LSB); | 457 | (n2FR[div[offset][5]] << CPCCR_SDIV_LSB); |
452 | 458 | ||
453 | // write REG_DDRC_CTRL 8 times to clear ddr fifo | 459 | // write REG_DDRC_CTRL 8 times to clear ddr fifo |
454 | REG_DDRC_CTRL = 0; | 460 | REG_DDRC_CTRL = 0; |
@@ -569,6 +575,10 @@ int serial_preinit(void) | |||
569 | return 0; | 575 | return 0; |
570 | } | 576 | } |
571 | 577 | ||
578 | #ifndef HAVE_ADJUSTABLE_CPU_FREQ | ||
579 | #define cpu_frequency CPU_FREQ | ||
580 | #endif | ||
581 | |||
572 | void usb_preinit(void) | 582 | void usb_preinit(void) |
573 | { | 583 | { |
574 | /* Clear ECS bit of CPCCR, 0:clock source is EXCLK, 1:clock source is EXCLK/2 */ | 584 | /* Clear ECS bit of CPCCR, 0:clock source is EXCLK, 1:clock source is EXCLK/2 */ |
@@ -589,7 +599,7 @@ void usb_preinit(void) | |||
589 | REG_CPM_USBVBFIL = 0x80; | 599 | REG_CPM_USBVBFIL = 0x80; |
590 | 600 | ||
591 | /* rdt */ | 601 | /* rdt */ |
592 | REG_CPM_USBRDT = (600 * (CPU_FREQ / 1000000)) / 1000; | 602 | REG_CPM_USBRDT = (600 * (CPUFREQ_DEFAULT / 1000000)) / 1000; |
593 | 603 | ||
594 | /* rdt - filload_en */ | 604 | /* rdt - filload_en */ |
595 | REG_CPM_USBRDT |= (1 << 25); | 605 | REG_CPM_USBRDT |= (1 << 25); |
@@ -649,8 +659,8 @@ void ICODE_ATTR system_main(void) | |||
649 | 659 | ||
650 | mmu_init(); | 660 | mmu_init(); |
651 | 661 | ||
652 | pll0_init(CPU_FREQ); // PLL0 drives everything but audio | 662 | pll0_init(CPUFREQ_DEFAULT); // PLL0 drives everything but audio |
653 | pll1_disable(); // Leave PLL1 disabled until audio needs it | 663 | pll1_disable(); // Leave PLL1 disabled until audio needs it |
654 | 664 | ||
655 | serial_preinit(); | 665 | serial_preinit(); |
656 | usb_preinit(); | 666 | usb_preinit(); |
@@ -713,9 +723,22 @@ int system_memory_guard(int newmode) | |||
713 | return 0; | 723 | return 0; |
714 | } | 724 | } |
715 | 725 | ||
726 | |||
716 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 727 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
728 | void cpm_select_msc_clk(void); | ||
729 | |||
717 | void set_cpu_frequency(long frequency) | 730 | void set_cpu_frequency(long frequency) |
718 | { | 731 | { |
719 | serial_putsf("set_cpu_frequency: %d\n", frequency); | 732 | if (frequency == cpu_frequency) |
733 | return; | ||
734 | else if (frequency < CPUFREQ_MIN) | ||
735 | frequency = CPUFREQ_MIN; | ||
736 | else if (frequency > CPUFREQ_MAX) | ||
737 | frequency = CPUFREQ_MAX; | ||
738 | |||
739 | pll0_init(frequency); | ||
740 | // FIX PCLK (ie i2c)? | ||
741 | cpu_frequency = __cpm_get_pllout2(); | ||
742 | cpm_select_msc_clk(); | ||
720 | } | 743 | } |
721 | #endif | 744 | #endif |