sdmmc v2: Bus/IO clock refactoring and fixes

Use the exact same clocks with HOS and utilize low jitter clock parents.

Add back our compatibility mode and the missing timeout clock parent.

Hekate main will continue to use PLLP clock parent for all.
This commit is contained in:
CTCaer 2020-04-30 01:26:55 +03:00
parent 67ae7b9dcb
commit 51985ed2ca
4 changed files with 241 additions and 108 deletions

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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);