diff --git a/bootloader/soc/clock.c b/bootloader/soc/clock.c index 03e0925..806d5f8 100644 --- a/bootloader/soc/clock.c +++ b/bootloader/soc/clock.c @@ -89,6 +89,10 @@ static clock_t _clock_pwm = { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz. }; +static clock_t _clock_sdmmc_legacy_tm = { + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, 1, 4, 66 +}; + void clock_enable(const clock_t *clk) { // Put clock into reset. @@ -258,10 +262,10 @@ void clock_enable_pllc(u32 divn) CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ; usleep(10); - // Set PLLC4 dividers. + // Set PLLC dividers. CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1. - // Enable PLLC4 and wait for Phase and Frequency lock. + // Enable PLLC and wait for Phase and Frequency lock. CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE; while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK)) ; @@ -423,56 +427,78 @@ static void _clock_sdmmc_clear_enable(u32 id) } } -static u32 _clock_sdmmc_table[8] = { 0 }; +static void _clock_sdmmc_config_legacy_tm() +{ + clock_t *clk = &_clock_sdmmc_legacy_tm; + if (!(CLOCK(clk->enable) & (1 << clk->index))) + clock_enable(clk); +} -#define PLLP_OUT0 0x0 -static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) +typedef struct _clock_sdmmc_t +{ + u32 clock; + u32 real_clock; +} clock_sdmmc_t; + +static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 }; + +#define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0 +#define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3 +#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1 + +static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val) { u32 divisor = 0; - u32 source = PLLP_OUT0; + u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0; + + if (id > SDMMC_4) + return 0; // Get IO clock divisor. switch (val) { case 25000: - *pout = 24728; + *pclock = 24728; divisor = 31; // 16.5 div. break; case 26000: - *pout = 25500; + *pclock = 25500; divisor = 30; // 16 div. break; case 40800: - *pout = 40800; + *pclock = 40800; divisor = 18; // 10 div. break; case 50000: - *pout = 48000; + *pclock = 48000; divisor = 15; // 8.5 div. break; case 52000: - *pout = 51000; + *pclock = 51000; divisor = 14; // 8 div. break; case 100000: - *pout = 90667; + *pclock = 90667; divisor = 7; // 4.5 div. break; - case 200000: - *pout = 163200; + case 164000: + *pclock = 163200; divisor = 3; // 2.5 div. break; - case 208000: - *pout = 204000; + case 200000: + *pclock = 204000; divisor = 2; // 2 div. break; default: - *pout = 24728; + *pclock = 24728; divisor = 31; // 16.5 div. } - _clock_sdmmc_table[2 * id] = val; - _clock_sdmmc_table[2 * id + 1] = *pout; + _clock_sdmmc_table[id].clock = val; + _clock_sdmmc_table[id].real_clock = *pclock; + + // Set SDMMC legacy timeout clock. + _clock_sdmmc_config_legacy_tm(); // Set SDMMC clock. switch (id) @@ -494,70 +520,75 @@ static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) return 1; } -void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val) +void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val) { - if (_clock_sdmmc_table[2 * id] == val) + if (_clock_sdmmc_table[id].clock == val) { - *pout = _clock_sdmmc_table[2 * id + 1]; + *pclock = _clock_sdmmc_table[id].real_clock; } else { int is_enabled = _clock_sdmmc_is_enabled(id); if (is_enabled) _clock_sdmmc_clear_enable(id); - _clock_sdmmc_config_clock_host(pout, id, val); + _clock_sdmmc_config_clock_host(pclock, id, val); if (is_enabled) _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); } } -void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type) +void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type) { // Get Card clock divisor. switch (type) { - case 0: - *pout = 26000; + case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz. + *pclock = 26000; *pdivisor = 66; break; - case 1: - *pout = 26000; + case SDHCI_TIMING_MMC_LS26: + *pclock = 26000; *pdivisor = 1; break; - case 2: - *pout = 52000; + case SDHCI_TIMING_MMC_HS52: + *pclock = 52000; *pdivisor = 1; break; - case 3: - case 4: - case 11: - *pout = 200000; + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_MMC_HS400: + case SDHCI_TIMING_UHS_SDR104: + *pclock = 200000; *pdivisor = 1; break; - case 5: - *pout = 25000; + case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz. + *pclock = 25000; *pdivisor = 64; break; - case 6: - case 8: - *pout = 25000; + case SDHCI_TIMING_SD_DS12: + case SDHCI_TIMING_UHS_SDR12: + *pclock = 25000; *pdivisor = 1; break; - case 7: - *pout = 50000; + case SDHCI_TIMING_SD_HS25: + case SDHCI_TIMING_UHS_SDR25: + *pclock = 50000; *pdivisor = 1; break; - case 10: - *pout = 100000; + case SDHCI_TIMING_UHS_SDR50: + *pclock = 100000; *pdivisor = 1; break; - case 13: - *pout = 40800; + case SDHCI_TIMING_UHS_SDR82: + *pclock = 164000; *pdivisor = 1; break; - case 14: - *pout = 200000; + case SDHCI_TIMING_UHS_DDR50: + *pclock = 40800; + *pdivisor = 1; + break; + case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz. + *pclock = 200000; *pdivisor = 2; break; } @@ -570,15 +601,15 @@ int clock_sdmmc_is_not_reset_and_enabled(u32 id) void clock_sdmmc_enable(u32 id, u32 val) { - u32 div = 0; + u32 clock = 0; if (_clock_sdmmc_is_enabled(id)) _clock_sdmmc_clear_enable(id); _clock_sdmmc_set_reset(id); - _clock_sdmmc_config_clock_host(&div, id, val); + _clock_sdmmc_config_clock_host(&clock, id, val); _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); - usleep((100000 + div - 1) / div); + usleep((100000 + clock - 1) / clock); _clock_sdmmc_clear_reset(id); _clock_sdmmc_is_reset(id); } diff --git a/bootloader/soc/clock.h b/bootloader/soc/clock.h index c76b23c..b849cfe 100644 --- a/bootloader/soc/clock.h +++ b/bootloader/soc/clock.h @@ -193,8 +193,8 @@ void clock_enable_pwm(); void clock_disable_pwm(); void clock_enable_pllc(u32 divn); void clock_disable_pllc(); -void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); -void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type); +void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val); +void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type); int clock_sdmmc_is_not_reset_and_enabled(u32 id); void clock_sdmmc_enable(u32 id, u32 val); void clock_sdmmc_disable(u32 id); diff --git a/nyx/nyx_gui/soc/clock.c b/nyx/nyx_gui/soc/clock.c index 03e0925..0a3b181 100644 --- a/nyx/nyx_gui/soc/clock.c +++ b/nyx/nyx_gui/soc/clock.c @@ -89,6 +89,10 @@ static clock_t _clock_pwm = { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz. }; +static clock_t _clock_sdmmc_legacy_tm = { + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, 1, 4, 66 +}; + void clock_enable(const clock_t *clk) { // Put clock into reset. @@ -258,10 +262,10 @@ void clock_enable_pllc(u32 divn) CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ; usleep(10); - // Set PLLC4 dividers. + // Set PLLC dividers. CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1. - // Enable PLLC4 and wait for Phase and Frequency lock. + // Enable PLLC and wait for Phase and Frequency lock. CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE; while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK)) ; @@ -285,6 +289,56 @@ void clock_disable_pllc() usleep(10); } +#define PLLC4_ENABLED (1 << 31) +#define PLLC4_IN_USE (~PLLC4_ENABLED) + +static u32 pllc4_enabled = 0; + +static void _clock_enable_pllc4(u32 mask) +{ + pllc4_enabled |= mask; + + if (pllc4_enabled & PLLC4_ENABLED) + return; + + // Enable Phase and Frequency lock detection. + //CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; + + // Disable PLL and IDDQ in case they are on. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLC4_BASE_IDDQ; + usleep(10); + + // Set PLLC4 dividers. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = (104 << 8) | 4; // DIVM: 4, DIVP: 1. + + // Enable PLLC4 and wait for Phase and Frequency lock. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLCX_BASE_ENABLE; + while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLCX_BASE_LOCK)) + ; + + msleep(1); // Wait a bit for PLL to stabilize. + + pllc4_enabled |= PLLC4_ENABLED; +} + +static void _clock_disable_pllc4(u32 mask) +{ + pllc4_enabled &= ~mask; + + if (pllc4_enabled & PLLC4_IN_USE) + return; + + //FIXME: This causes issues with L4T/TWRP. + return; + + // Disable PLLC4. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLCX_BASE_REF_DIS | PLLC4_BASE_IDDQ; + + pllc4_enabled = 0; +} + #define L_SWR_SDMMC1_RST (1 << 14) #define L_SWR_SDMMC2_RST (1 << 9) #define L_SWR_SDMMC4_RST (1 << 15) @@ -423,56 +477,98 @@ static void _clock_sdmmc_clear_enable(u32 id) } } -static u32 _clock_sdmmc_table[8] = { 0 }; +static void _clock_sdmmc_config_legacy_tm() +{ + clock_t *clk = &_clock_sdmmc_legacy_tm; + if (!(CLOCK(clk->enable) & (1 << clk->index))) + clock_enable(clk); +} -#define PLLP_OUT0 0x0 -static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) +typedef struct _clock_sdmmc_t +{ + u32 clock; + u32 real_clock; +} clock_sdmmc_t; + +static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 }; + +#define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0 +#define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3 +#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1 + +static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val) { u32 divisor = 0; - u32 source = PLLP_OUT0; + u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0; + + if (id > SDMMC_4) + return 0; // Get IO clock divisor. switch (val) { case 25000: - *pout = 24728; + *pclock = 24728; divisor = 31; // 16.5 div. break; case 26000: - *pout = 25500; + *pclock = 25500; divisor = 30; // 16 div. break; case 40800: - *pout = 40800; + *pclock = 40800; divisor = 18; // 10 div. break; case 50000: - *pout = 48000; + *pclock = 48000; divisor = 15; // 8.5 div. break; case 52000: - *pout = 51000; + *pclock = 51000; divisor = 14; // 8 div. break; case 100000: - *pout = 90667; - divisor = 7; // 4.5 div. - break; - case 200000: - *pout = 163200; - divisor = 3; // 2.5 div. - break; - case 208000: - *pout = 204000; + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + *pclock = 99840; divisor = 2; // 2 div. break; + case 164000: + *pclock = 163200; + divisor = 3; // 2.5 div. + break; + case 200000: // 240MHz evo+. + switch (id) + { + case SDMMC_1: + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + break; + case SDMMC_2: + source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; + break; + case SDMMC_3: + source = SDMMC_CLOCK_SRC_PLLC4_OUT2; + break; + case SDMMC_4: + source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; + break; + } + *pclock = 199680; + divisor = 0; // 1 div. + break; default: - *pout = 24728; + *pclock = 24728; divisor = 31; // 16.5 div. } - _clock_sdmmc_table[2 * id] = val; - _clock_sdmmc_table[2 * id + 1] = *pout; + _clock_sdmmc_table[id].clock = val; + _clock_sdmmc_table[id].real_clock = *pclock; + + // Enable PLLC4 if in use by any SDMMC. + if (source) + _clock_enable_pllc4(1 << id); + + // Set SDMMC legacy timeout clock. + _clock_sdmmc_config_legacy_tm(); // Set SDMMC clock. switch (id) @@ -494,70 +590,75 @@ static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) return 1; } -void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val) +void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val) { - if (_clock_sdmmc_table[2 * id] == val) + if (_clock_sdmmc_table[id].clock == val) { - *pout = _clock_sdmmc_table[2 * id + 1]; + *pclock = _clock_sdmmc_table[id].real_clock; } else { int is_enabled = _clock_sdmmc_is_enabled(id); if (is_enabled) _clock_sdmmc_clear_enable(id); - _clock_sdmmc_config_clock_host(pout, id, val); + _clock_sdmmc_config_clock_host(pclock, id, val); if (is_enabled) _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); } } -void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type) +void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type) { // Get Card clock divisor. switch (type) { - case 0: - *pout = 26000; + case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz. + *pclock = 26000; *pdivisor = 66; break; - case 1: - *pout = 26000; + case SDHCI_TIMING_MMC_LS26: + *pclock = 26000; *pdivisor = 1; break; - case 2: - *pout = 52000; + case SDHCI_TIMING_MMC_HS52: + *pclock = 52000; *pdivisor = 1; break; - case 3: - case 4: - case 11: - *pout = 200000; + case SDHCI_TIMING_MMC_HS200: + case SDHCI_TIMING_MMC_HS400: + case SDHCI_TIMING_UHS_SDR104: + *pclock = 200000; *pdivisor = 1; break; - case 5: - *pout = 25000; + case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz. + *pclock = 25000; *pdivisor = 64; break; - case 6: - case 8: - *pout = 25000; + case SDHCI_TIMING_SD_DS12: + case SDHCI_TIMING_UHS_SDR12: + *pclock = 25000; *pdivisor = 1; break; - case 7: - *pout = 50000; + case SDHCI_TIMING_SD_HS25: + case SDHCI_TIMING_UHS_SDR25: + *pclock = 50000; *pdivisor = 1; break; - case 10: - *pout = 100000; + case SDHCI_TIMING_UHS_SDR50: + *pclock = 100000; *pdivisor = 1; break; - case 13: - *pout = 40800; + case SDHCI_TIMING_UHS_SDR82: + *pclock = 164000; *pdivisor = 1; break; - case 14: - *pout = 200000; + case SDHCI_TIMING_UHS_DDR50: + *pclock = 40800; + *pdivisor = 1; + break; + case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz. + *pclock = 200000; *pdivisor = 2; break; } @@ -570,15 +671,15 @@ int clock_sdmmc_is_not_reset_and_enabled(u32 id) void clock_sdmmc_enable(u32 id, u32 val) { - u32 div = 0; + u32 clock = 0; if (_clock_sdmmc_is_enabled(id)) _clock_sdmmc_clear_enable(id); _clock_sdmmc_set_reset(id); - _clock_sdmmc_config_clock_host(&div, id, val); + _clock_sdmmc_config_clock_host(&clock, id, val); _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); - usleep((100000 + div - 1) / div); + usleep((100000 + clock - 1) / clock); _clock_sdmmc_clear_reset(id); _clock_sdmmc_is_reset(id); } @@ -588,4 +689,5 @@ void clock_sdmmc_disable(u32 id) _clock_sdmmc_set_reset(id); _clock_sdmmc_clear_enable(id); _clock_sdmmc_is_reset(id); + _clock_disable_pllc4(1 << id); } diff --git a/nyx/nyx_gui/soc/clock.h b/nyx/nyx_gui/soc/clock.h index c76b23c..b849cfe 100644 --- a/nyx/nyx_gui/soc/clock.h +++ b/nyx/nyx_gui/soc/clock.h @@ -193,8 +193,8 @@ void clock_enable_pwm(); void clock_disable_pwm(); void clock_enable_pllc(u32 divn); void clock_disable_pllc(); -void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); -void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type); +void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val); +void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type); int clock_sdmmc_is_not_reset_and_enabled(u32 id); void clock_sdmmc_enable(u32 id, u32 val); void clock_sdmmc_disable(u32 id);