mirror of
https://github.com/CTCaer/hekate
synced 2024-12-22 11:21:23 +00:00
sdmmc v2: Refactor everything
This commit is contained in:
parent
0462f3b252
commit
5b0a0070c7
24 changed files with 830 additions and 590 deletions
|
@ -486,7 +486,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
|
@ -837,7 +837,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
|
|
|
@ -145,7 +145,7 @@ void print_mmc_info()
|
|||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
|
@ -346,7 +346,7 @@ void print_tsec_key()
|
|||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||
|
||||
// Read package1.
|
||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||
|
|
|
@ -69,7 +69,7 @@ void dump_packages12()
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out_free;
|
||||
|
@ -264,7 +264,7 @@ void _toggle_autorcm(bool enable)
|
|||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out;
|
||||
|
@ -335,7 +335,7 @@ void menu_autorcm()
|
|||
sdmmc_t sdmmc;
|
||||
bool disabled = true;
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
btn_wait();
|
||||
|
|
|
@ -200,7 +200,7 @@ void config_exosphere(launch_ctxt_t *ctxt)
|
|||
// Set warmboot binary rsa modulus.
|
||||
u8 *rsa_mod = (u8 *)malloc(512);
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 1, 1, rsa_mod);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
|
|
@ -84,7 +84,7 @@ bool sd_mount()
|
|||
if (sd_mounted)
|
||||
return true;
|
||||
|
||||
if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
|
||||
if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_BUS_WIDTH_4, SDHCI_TIMING_UHS_SDR82))
|
||||
{
|
||||
gfx_con.mute = false;
|
||||
EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!");
|
||||
|
@ -172,7 +172,7 @@ void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t
|
|||
|
||||
if (!storage)
|
||||
{
|
||||
if (!sdmmc_storage_init_mmc(&storage2, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage2, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
memcpy(emmcSN, "00000000", 9);
|
||||
else
|
||||
{
|
||||
|
@ -1151,7 +1151,7 @@ static void _patched_rcm_protection()
|
|||
return;
|
||||
|
||||
// Check if AutoRCM is enabled and protect from a permanent brick.
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
return;
|
||||
|
||||
u8 *tempbuf = (u8 *)malloc(0x200);
|
||||
|
|
|
@ -354,7 +354,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
|||
if (magic == 0xBAADF00D)
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
|
||||
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0);
|
||||
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0);
|
||||
clock_disable_cl_dvfs();
|
||||
|
||||
msleep(200);
|
||||
|
|
|
@ -132,7 +132,7 @@ static int emummc_raw_get_part_off(int part_idx)
|
|||
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
||||
{
|
||||
FILINFO fno;
|
||||
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
return 2;
|
||||
|
||||
if (h_cfg.emummc_force_disable)
|
||||
|
|
|
@ -401,7 +401,7 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check)
|
|||
if (check && !_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 2))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52))
|
||||
return 0;
|
||||
|
||||
DPRINTF("[MMC] switched to HS\n");
|
||||
|
@ -418,10 +418,10 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage)
|
|||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 3))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
return 0;
|
||||
|
||||
DPRINTF("[MMC] switched to HS200\n");
|
||||
|
@ -446,7 +446,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
|
|||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 4))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400))
|
||||
return 0;
|
||||
|
||||
DPRINTF("[MMC] switched to HS400\n");
|
||||
|
@ -457,22 +457,20 @@ DPRINTF("[MMC] switched to HS400\n");
|
|||
|
||||
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
|
||||
{
|
||||
//TODO: this should be a config item.
|
||||
// --v
|
||||
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
|
||||
if (sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
|
||||
goto out;
|
||||
|
||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
|
||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4)
|
||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400)
|
||||
return _mmc_storage_enable_HS400(storage);
|
||||
|
||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
|
||||
(sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4
|
||||
&& card_type & EXT_CSD_CARD_TYPE_HS200_1_8V
|
||||
&& (type == 4 || type == 3)))
|
||||
&& (type == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200)))
|
||||
return _mmc_storage_enable_HS200(storage);
|
||||
|
||||
out:;
|
||||
out:
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
||||
return _mmc_storage_enable_HS(storage, 1);
|
||||
|
||||
|
@ -487,13 +485,13 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage)
|
|||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
|
||||
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
|
||||
{
|
||||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||
storage->sdmmc = sdmmc;
|
||||
storage->rca = 2; //TODO: this could be a config item.
|
||||
|
||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0))
|
||||
if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_AUTO_CAL_DISABLE))
|
||||
return 0;
|
||||
DPRINTF("[MMC] after init\n");
|
||||
|
||||
|
@ -520,7 +518,7 @@ DPRINTF("[MMC] set relative addr\n");
|
|||
DPRINTF("[MMC] got csd\n");
|
||||
_mmc_storage_parse_csd(storage);
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 1))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26))
|
||||
return 0;
|
||||
DPRINTF("[MMC] after setup clock\n");
|
||||
|
||||
|
@ -558,7 +556,7 @@ DPRINTF("[MMC] got ext_csd\n");
|
|||
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
|
||||
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
|
||||
Additionally this works only when we put the device in idle mode which we don't after enabling it. */
|
||||
if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0)
|
||||
if (0 && storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2))
|
||||
{
|
||||
_mmc_storage_enable_bkops(storage);
|
||||
DPRINTF("[MMC] BKOPS enabled\n");
|
||||
|
@ -572,7 +570,7 @@ DPRINTF("[MMC] BKOPS disabled\n");
|
|||
return 0;
|
||||
DPRINTF("[MMC] succesfully switched to HS mode\n");
|
||||
|
||||
sdmmc_sd_clock_ctrl(storage->sdmmc, 1);
|
||||
sdmmc_sd_clock_ctrl(storage->sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -656,6 +654,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
|||
if (cond & SD_OCR_CCS)
|
||||
storage->has_sector_access = 1;
|
||||
|
||||
// Check if card supports 1.8V signaling.
|
||||
if (cond & SD_ROCR_S18A && supports_low_voltage)
|
||||
{
|
||||
//The low voltage regulator configuration is valid for SDMMC1 only.
|
||||
|
@ -826,7 +825,7 @@ DPRINTF("[SD] power limit raised to 800mA\n");
|
|||
DPRINTF("[SD] power limit raised to 600mA\n");
|
||||
break;
|
||||
case SD_SET_CURRENT_LIMIT_400:
|
||||
DPRINTF("[SD] power limit raised to 800mA\n");
|
||||
DPRINTF("[SD] power limit raised to 400mA\n");
|
||||
break;
|
||||
default:
|
||||
case SD_SET_CURRENT_LIMIT_200:
|
||||
|
@ -839,12 +838,12 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)
|
|||
{
|
||||
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
|
||||
return 0;
|
||||
DPRINTF("[SD] SD supports switch to (U)HS check\n");
|
||||
DPRINTF("[SD] supports switch to (U)HS mode\n");
|
||||
|
||||
u32 type_out = buf[16] & 0xF;
|
||||
if (type_out != hs_type)
|
||||
return 0;
|
||||
DPRINTF("[SD] SD supports selected (U)HS mode\n");
|
||||
DPRINTF("[SD] supports selected (U)HS mode\n");
|
||||
|
||||
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
|
||||
{
|
||||
|
@ -870,32 +869,51 @@ int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
|
|||
return 0;
|
||||
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||
|
||||
u8 access_mode = buf[13];
|
||||
|
||||
u32 hs_type = 0;
|
||||
switch (type)
|
||||
{
|
||||
case 11: // SDR104.
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
// Fall through if not supported.
|
||||
if (buf[13] & SD_MODE_UHS_SDR104)
|
||||
if (access_mode & SD_MODE_UHS_SDR104)
|
||||
{
|
||||
type = 11;
|
||||
hs_type = UHS_SDR104_BUS_SPEED;
|
||||
DPRINTF("[SD] bus speed set to SDR104\n");
|
||||
storage->csd.busspeed = 104;
|
||||
switch (type)
|
||||
{
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
storage->csd.busspeed = 104;
|
||||
break;
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
storage->csd.busspeed = 82;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 10: // SDR50.
|
||||
if (buf[13] & SD_MODE_UHS_SDR50)
|
||||
case SDHCI_TIMING_UHS_SDR50:
|
||||
if (access_mode & SD_MODE_UHS_SDR50)
|
||||
{
|
||||
type = 10;
|
||||
type = SDHCI_TIMING_UHS_SDR50;
|
||||
hs_type = UHS_SDR50_BUS_SPEED;
|
||||
DPRINTF("[SD] bus speed set to SDR50\n");
|
||||
storage->csd.busspeed = 50;
|
||||
break;
|
||||
}
|
||||
case 8: // SDR12.
|
||||
if (!(buf[13] & SD_MODE_UHS_SDR12))
|
||||
case SDHCI_TIMING_UHS_SDR25:
|
||||
if (access_mode & SD_MODE_UHS_SDR25)
|
||||
{
|
||||
type = SDHCI_TIMING_UHS_SDR25;
|
||||
hs_type = UHS_SDR50_BUS_SPEED;
|
||||
DPRINTF("[SD] bus speed set to SDR25\n");
|
||||
storage->csd.busspeed = 25;
|
||||
break;
|
||||
}
|
||||
case SDHCI_TIMING_UHS_SDR12:
|
||||
if (!(access_mode & SD_MODE_UHS_SDR12))
|
||||
return 0;
|
||||
type = 8;
|
||||
type = SDHCI_TIMING_UHS_SDR12;
|
||||
hs_type = UHS_SDR12_BUS_SPEED;
|
||||
DPRINTF("[SD] bus speed set to SDR12\n");
|
||||
storage->csd.busspeed = 12;
|
||||
|
@ -907,7 +925,7 @@ DPRINTF("[SD] bus speed set to SDR12\n");
|
|||
|
||||
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
|
||||
return 0;
|
||||
DPRINTF("[SD] SD card accepted UHS\n");
|
||||
DPRINTF("[SD] card accepted UHS\n");
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, type))
|
||||
return 0;
|
||||
DPRINTF("[SD] setup clock\n");
|
||||
|
@ -922,16 +940,19 @@ int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf)
|
|||
if (!_sd_storage_switch_get(storage, buf))
|
||||
return 0;
|
||||
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||
if (!(buf[13] & SD_MODE_HIGH_SPEED))
|
||||
|
||||
u8 access_mode = buf[13];
|
||||
|
||||
if (!(access_mode & SD_MODE_HIGH_SPEED))
|
||||
return 1;
|
||||
|
||||
if (!_sd_storage_enable_highspeed(storage, 1, buf))
|
||||
if (!_sd_storage_enable_highspeed(storage, HIGH_SPEED_BUS_SPEED, buf))
|
||||
return 0;
|
||||
|
||||
if (!_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
return sdmmc_setup_clock(storage->sdmmc, 7);
|
||||
return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25);
|
||||
}
|
||||
|
||||
static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
|
||||
|
@ -1062,7 +1083,7 @@ void sdmmc_storage_init_wait_sd()
|
|||
msleep(100 - sd_poweroff_time);
|
||||
}
|
||||
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
|
||||
{
|
||||
int is_version_1 = 0;
|
||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||
|
@ -1073,7 +1094,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||
storage->sdmmc = sdmmc;
|
||||
|
||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0))
|
||||
if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_AUTO_CAL_DISABLE))
|
||||
return 0;
|
||||
DPRINTF("[SD] after init\n");
|
||||
|
||||
|
@ -1122,7 +1143,7 @@ DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
|
|||
|
||||
if (!storage->is_low_voltage)
|
||||
{
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 6))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12))
|
||||
return 0;
|
||||
DPRINTF("[SD] after setup clock\n");
|
||||
}
|
||||
|
@ -1166,7 +1187,7 @@ DPRINTF("[SD] SD does not support wide bus width\n");
|
|||
return 0;
|
||||
DPRINTF("[SD] enabled UHS\n");
|
||||
}
|
||||
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
|
||||
else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0)
|
||||
{
|
||||
if (!_sd_storage_enable_hs_high_volt(storage, buf))
|
||||
return 0;
|
||||
|
@ -1175,7 +1196,7 @@ DPRINTF("[SD] enabled HS\n");
|
|||
storage->csd.busspeed = 25;
|
||||
}
|
||||
|
||||
sdmmc_sd_clock_ctrl(sdmmc, 1);
|
||||
sdmmc_sd_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||
|
||||
// Parse additional card info from sd status.
|
||||
if (_sd_storage_get_ssr(storage, buf))
|
||||
|
@ -1222,17 +1243,17 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
|||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||
storage->sdmmc = sdmmc;
|
||||
|
||||
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0))
|
||||
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_DDR52, SDMMC_AUTO_CAL_DISABLE))
|
||||
return 0;
|
||||
DPRINTF("[gc] after init\n");
|
||||
|
||||
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
return 0;
|
||||
DPRINTF("[gc] after tuning\n");
|
||||
|
||||
sdmmc_sd_clock_ctrl(sdmmc, 1);
|
||||
sdmmc_sd_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -107,10 +107,10 @@ typedef struct _sdmmc_storage_t
|
|||
int sdmmc_storage_end(sdmmc_storage_t *storage);
|
||||
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
||||
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
|
||||
int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
||||
void sdmmc_storage_init_wait_sd();
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
|
||||
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -43,11 +43,11 @@ static const u32 _sdmmc_bases[4] = {
|
|||
int sdmmc_get_voltage(sdmmc_t *sdmmc)
|
||||
{
|
||||
u32 p = sdmmc->regs->pwrcon;
|
||||
if (!(p & TEGRA_MMC_PWRCTL_SD_BUS_POWER))
|
||||
if (!(p & SDHCI_POWER_ON))
|
||||
return SDMMC_POWER_OFF;
|
||||
if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8)
|
||||
if (p & SDHCI_POWER_180)
|
||||
return SDMMC_POWER_1_8;
|
||||
if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3)
|
||||
if (p & SDHCI_POWER_330)
|
||||
return SDMMC_POWER_3_3;
|
||||
return -1;
|
||||
}
|
||||
|
@ -59,15 +59,15 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
|
|||
switch (power)
|
||||
{
|
||||
case SDMMC_POWER_OFF:
|
||||
sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
sdmmc->regs->pwrcon &= ~SDHCI_POWER_ON;
|
||||
break;
|
||||
case SDMMC_POWER_1_8:
|
||||
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
sdmmc->regs->pwrcon = SDHCI_POWER_180;
|
||||
pwr = SDHCI_POWER_180;
|
||||
break;
|
||||
case SDMMC_POWER_3_3:
|
||||
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
|
||||
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
|
||||
sdmmc->regs->pwrcon = SDHCI_POWER_330;
|
||||
pwr = SDHCI_POWER_330;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -75,7 +75,7 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
|
|||
|
||||
if (power != SDMMC_POWER_OFF)
|
||||
{
|
||||
pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
pwr |= SDHCI_POWER_ON;
|
||||
sdmmc->regs->pwrcon = pwr;
|
||||
}
|
||||
|
||||
|
@ -85,9 +85,9 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
|
|||
u32 sdmmc_get_bus_width(sdmmc_t *sdmmc)
|
||||
{
|
||||
u32 h = sdmmc->regs->hostctl;
|
||||
if (h & TEGRA_MMC_HOSTCTL_8BIT)
|
||||
if (h & SDHCI_CTRL_8BITBUS)
|
||||
return SDMMC_BUS_WIDTH_8;
|
||||
if (h & TEGRA_MMC_HOSTCTL_4BIT)
|
||||
if (h & SDHCI_CTRL_4BITBUS)
|
||||
return SDMMC_BUS_WIDTH_4;
|
||||
return SDMMC_BUS_WIDTH_1;
|
||||
}
|
||||
|
@ -95,14 +95,14 @@ u32 sdmmc_get_bus_width(sdmmc_t *sdmmc)
|
|||
void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width)
|
||||
{
|
||||
if (bus_width == SDMMC_BUS_WIDTH_1)
|
||||
sdmmc->regs->hostctl &= ~(TEGRA_MMC_HOSTCTL_4BIT | TEGRA_MMC_HOSTCTL_8BIT);
|
||||
sdmmc->regs->hostctl &= ~(SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS);
|
||||
else if (bus_width == SDMMC_BUS_WIDTH_4)
|
||||
{
|
||||
sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_4BIT;
|
||||
sdmmc->regs->hostctl &= ~TEGRA_MMC_HOSTCTL_8BIT;
|
||||
sdmmc->regs->hostctl |= SDHCI_CTRL_4BITBUS;
|
||||
sdmmc->regs->hostctl &= ~SDHCI_CTRL_8BITBUS;
|
||||
}
|
||||
else if (bus_width == SDMMC_BUS_WIDTH_8)
|
||||
sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_8BIT;
|
||||
sdmmc->regs->hostctl |= SDHCI_CTRL_8BITBUS;
|
||||
}
|
||||
|
||||
void sdmmc_get_venclkctl(sdmmc_t *sdmmc)
|
||||
|
@ -115,10 +115,10 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id)
|
|||
{
|
||||
u32 tap_val = 0;
|
||||
|
||||
if (id == 4)
|
||||
if (id == SDHCI_TIMING_MMC_HS400)
|
||||
sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800;
|
||||
sdmmc->regs->ventunctl0 &= 0xFFFDFFFF;
|
||||
if (id == 4)
|
||||
sdmmc->regs->ventunctl0 &= ~TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW;
|
||||
if (id == SDHCI_TIMING_MMC_HS400)
|
||||
{
|
||||
if (!sdmmc->venclkctl_set)
|
||||
return 0;
|
||||
|
@ -160,21 +160,61 @@ static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power)
|
|||
//TODO: load standard values for other controllers, can depend on power.
|
||||
}
|
||||
|
||||
static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
bool should_enable_sd_clock = false;
|
||||
if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)
|
||||
{
|
||||
should_enable_sd_clock = true;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
// Enable E_INPUT power.
|
||||
if (!(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD))
|
||||
{
|
||||
sdmmc->regs->sdmemcmppadctl |= TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
// Enable auto calibration and start auto configuration.
|
||||
sdmmc->regs->autocalcfg |= TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE | TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 10;
|
||||
while (sdmmc->regs->autocalcfg & TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
// In case autocalibration fails, we load suggested standard values.
|
||||
_sdmmc_pad_config_fallback(sdmmc, power);
|
||||
sdmmc->regs->autocalcfg &= ~TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sdmmc->regs->sdmemcmppadctl &= ~TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD;
|
||||
|
||||
if(should_enable_sd_clock)
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
||||
{
|
||||
int res = 1, should_disable_sd_clock = 0;
|
||||
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
{
|
||||
should_disable_sd_clock = 1;
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
sdmmc->regs->vendllcal |= 0x80000000;
|
||||
sdmmc->regs->vendllcal |= TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 5;
|
||||
while (sdmmc->regs->vendllcal & 0x80000000)
|
||||
while (sdmmc->regs->vendllcal & TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
|
@ -184,7 +224,7 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
|||
}
|
||||
|
||||
timeout = get_tmr_ms() + 10;
|
||||
while (sdmmc->regs->dllcfgstatus & 0x80000000)
|
||||
while (sdmmc->regs->dllcfgstatus & TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
|
@ -195,55 +235,65 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
|||
|
||||
out:;
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _sdmmc_reset(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->swrst |= SDHCI_RESET_CMD | SDHCI_RESET_DATA;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while ((sdmmc->regs->swrst & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) && get_tmr_ms() < timeout)
|
||||
;
|
||||
}
|
||||
|
||||
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
{
|
||||
// Disable the SD clock if it was enabled, and reenable it later.
|
||||
bool should_enable_sd_clock = false;
|
||||
if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)
|
||||
if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)
|
||||
{
|
||||
should_enable_sd_clock = true;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
_sdmmc_config_ven_ceata_clk(sdmmc, type);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 5:
|
||||
case 6:
|
||||
sdmmc->regs->hostctl &= 0xFB; // Should this be 0xFFFB (~4) ?
|
||||
sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330;
|
||||
case SDHCI_TIMING_MMC_ID:
|
||||
case SDHCI_TIMING_MMC_LS26:
|
||||
case SDHCI_TIMING_SD_ID:
|
||||
case SDHCI_TIMING_SD_DS12:
|
||||
sdmmc->regs->hostctl &= ~SDHCI_CTRL_HISPD;
|
||||
sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 2:
|
||||
case 7:
|
||||
sdmmc->regs->hostctl |= 4;
|
||||
sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330;
|
||||
case SDHCI_TIMING_MMC_HS52:
|
||||
case SDHCI_TIMING_SD_HS25:
|
||||
sdmmc->regs->hostctl |= SDHCI_CTRL_HISPD;
|
||||
sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 3:
|
||||
case 11:
|
||||
case 13:
|
||||
case 14:
|
||||
case SDHCI_TIMING_MMC_HS200:
|
||||
case SDHCI_TIMING_UHS_SDR50: // T210 Errata for SDR50, the host must be set to SDR104.
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
case SDHCI_TIMING_UHS_DDR50:
|
||||
case SDHCI_TIMING_MMC_DDR52:
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 4:
|
||||
case SDHCI_TIMING_MMC_HS400:
|
||||
// Non standard.
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 8:
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED;
|
||||
case SDHCI_TIMING_UHS_SDR25:
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR25_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 10:
|
||||
// T210 Errata for SDR50, the host must be set to SDR104.
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED;
|
||||
case SDHCI_TIMING_UHS_SDR12:
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
}
|
||||
|
@ -261,14 +311,16 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
|||
u16 div = divisor >> 1;
|
||||
divisor = 0;
|
||||
if (div > 0xFF)
|
||||
divisor = div >> 8;
|
||||
sdmmc->regs->clkcon = (sdmmc->regs->clkcon & 0x3F) | (div << 8) | (divisor << 6);
|
||||
divisor = div >> SDHCI_DIVIDER_SHIFT;
|
||||
|
||||
sdmmc->regs->clkcon = (sdmmc->regs->clkcon & ~(SDHCI_DIV_MASK | SDHCI_DIV_HI_MASK))
|
||||
| (div << SDHCI_DIVIDER_SHIFT) | (divisor << SDHCI_DIVIDER_HI_SHIFT);
|
||||
|
||||
// Enable the SD clock again.
|
||||
if (should_enable_sd_clock)
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
if (type == 4)
|
||||
if (type == SDHCI_TIMING_MMC_HS400)
|
||||
return _sdmmc_wait_type4(sdmmc);
|
||||
return 1;
|
||||
}
|
||||
|
@ -277,8 +329,8 @@ static void _sdmmc_sd_clock_enable(sdmmc_t *sdmmc)
|
|||
{
|
||||
if (!sdmmc->no_sd)
|
||||
{
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
sdmmc->sd_clock_enabled = 1;
|
||||
}
|
||||
|
@ -286,7 +338,7 @@ static void _sdmmc_sd_clock_enable(sdmmc_t *sdmmc)
|
|||
static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->sd_clock_enabled = 0;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd)
|
||||
|
@ -294,14 +346,14 @@ void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd)
|
|||
sdmmc->no_sd = no_sd;
|
||||
if (no_sd)
|
||||
{
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
return;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
return;
|
||||
}
|
||||
if (sdmmc->sd_clock_enabled)
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
|
@ -383,22 +435,12 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void _sdmmc_reset(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->swrst |=
|
||||
TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE | TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (sdmmc->regs->swrst << 29 >> 30 && get_tmr_ms() < timeout)
|
||||
;
|
||||
}
|
||||
|
||||
static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat)
|
||||
{
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while(sdmmc->regs->prnsts & 1) // CMD inhibit.
|
||||
while(sdmmc->regs->prnsts & SDHCI_CMD_INHIBIT)
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
@ -408,7 +450,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat)
|
|||
if (wait_dat)
|
||||
{
|
||||
timeout = get_tmr_ms() + 2000;
|
||||
while (sdmmc->regs->prnsts & 2) // DAT inhibit.
|
||||
while (sdmmc->regs->prnsts & SDHCI_DATA_INHIBIT)
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
@ -424,7 +466,7 @@ static int _sdmmc_wait_prnsts_type1(sdmmc_t *sdmmc)
|
|||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (!(sdmmc->regs->prnsts & 0x100000)) // DAT0 line level.
|
||||
while (!(sdmmc->regs->prnsts & SDHCI_DATA_0_LVL_MASK))
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
@ -442,14 +484,14 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc)
|
|||
return 0;
|
||||
break;
|
||||
case SDMMC_BUS_WIDTH_4:
|
||||
sdmmc->regs->blksize = 0x40;
|
||||
sdmmc->regs->blksize = 64;
|
||||
break;
|
||||
case SDMMC_BUS_WIDTH_8:
|
||||
sdmmc->regs->blksize = 0x80;
|
||||
sdmmc->regs->blksize = 128;
|
||||
break;
|
||||
}
|
||||
sdmmc->regs->blkcnt = 1;
|
||||
sdmmc->regs->trnmod = TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
|
||||
sdmmc->regs->trnmod = SDHCI_TRNS_READ;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -465,20 +507,15 @@ static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_pr
|
|||
case SDMMC_RSP_TYPE_4:
|
||||
case SDMMC_RSP_TYPE_5:
|
||||
if (cmd->check_busy)
|
||||
cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY |
|
||||
TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK |
|
||||
TEGRA_MMC_TRNMOD_CMD_CRC_CHECK;
|
||||
cmdflags = SDHCI_CMD_RESP_LEN48_BUSY | SDHCI_CMD_INDEX | SDHCI_CMD_CRC;
|
||||
else
|
||||
cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 |
|
||||
TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK |
|
||||
TEGRA_MMC_TRNMOD_CMD_CRC_CHECK;
|
||||
cmdflags = SDHCI_CMD_RESP_LEN48 | SDHCI_CMD_INDEX | SDHCI_CMD_CRC;
|
||||
break;
|
||||
case SDMMC_RSP_TYPE_2:
|
||||
cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 |
|
||||
TEGRA_MMC_TRNMOD_CMD_CRC_CHECK;
|
||||
cmdflags = SDHCI_CMD_RESP_LEN136 | SDHCI_CMD_CRC;
|
||||
break;
|
||||
case SDMMC_RSP_TYPE_3:
|
||||
cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48;
|
||||
cmdflags = SDHCI_CMD_RESP_LEN48;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -486,7 +523,7 @@ static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_pr
|
|||
}
|
||||
|
||||
if (is_data_present)
|
||||
cmdflags |= TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER;
|
||||
cmdflags |= SDHCI_CMD_DATA;
|
||||
sdmmc->regs->argument = cmd->arg;
|
||||
sdmmc->regs->cmdreg = (cmd->cmd << 8) | cmdflags;
|
||||
|
||||
|
@ -512,9 +549,9 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
|
||||
_sdmmc_setup_read_small_block(sdmmc);
|
||||
|
||||
sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY;
|
||||
sdmmc->regs->norintstsen |= SDHCI_INT_DATA_AVAIL;
|
||||
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
_sdmmc_parse_cmd_48(sdmmc, cmd);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
@ -522,16 +559,16 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_us() + 5000;
|
||||
while (get_tmr_us() < timeout)
|
||||
{
|
||||
if (sdmmc->regs->norintsts & 0x20)
|
||||
if (sdmmc->regs->norintsts & SDHCI_INT_DATA_AVAIL)
|
||||
{
|
||||
sdmmc->regs->norintsts = 0x20;
|
||||
sdmmc->regs->norintstsen &= 0xFFDF;
|
||||
sdmmc->regs->norintsts = SDHCI_INT_DATA_AVAIL;
|
||||
sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
return 1;
|
||||
|
@ -540,7 +577,7 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->norintstsen &= 0xFFDF;
|
||||
sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
|
@ -554,26 +591,30 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
|||
sdmmc->regs->field_1C4 = 0;
|
||||
switch (type)
|
||||
{
|
||||
case 3:
|
||||
case 4:
|
||||
case 11:
|
||||
max = 0x80;
|
||||
flag = 0x4000;
|
||||
case SDHCI_TIMING_MMC_HS200:
|
||||
case SDHCI_TIMING_MMC_HS400:
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
max = 128;
|
||||
flag = (2 << 13); // 128 iterations.
|
||||
break;
|
||||
case 10:
|
||||
case 13:
|
||||
case 14:
|
||||
max = 0x100;
|
||||
flag = 0x8000;
|
||||
case SDHCI_TIMING_UHS_SDR50:
|
||||
case SDHCI_TIMING_UHS_DDR50:
|
||||
case SDHCI_TIMING_MMC_DDR52:
|
||||
max = 256;
|
||||
flag = (4 << 13); // 256 iterations.
|
||||
break;
|
||||
case SDHCI_TIMING_UHS_SDR12:
|
||||
case SDHCI_TIMING_UHS_SDR25:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries.
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier.
|
||||
sdmmc->regs->ventunctl0 |= 0x20000;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | (1 << 6); // 1x Multiplier.
|
||||
sdmmc->regs->ventunctl0 |= TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
|
||||
|
||||
for (u32 i = 0; i < max; i++)
|
||||
{
|
||||
|
@ -591,24 +632,24 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
|||
static int _sdmmc_enable_internal_clock(sdmmc_t *sdmmc)
|
||||
{
|
||||
//Enable internal clock and wait till it is stable.
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_INT_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE))
|
||||
while (!(sdmmc->regs->clkcon & SDHCI_CLOCK_INT_STABLE))
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_CLKGEN_SELECT;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_PROG_CLOCK_MODE;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN;
|
||||
|
||||
if (!(sdmmc->regs->capareg & 0x10000000))
|
||||
if (!(sdmmc->regs->capareg & SDHCI_CAN_64BIT))
|
||||
return 0;
|
||||
|
||||
sdmmc->regs->hostctl2 |= SDHCI_ADDRESSING_64BIT_EN;
|
||||
sdmmc->regs->hostctl &= 0xE7;
|
||||
sdmmc->regs->hostctl &= ~SDHCI_CTRL_DMA_MASK;
|
||||
sdmmc->regs->timeoutcon = (sdmmc->regs->timeoutcon & 0xF0) | 0xE;
|
||||
|
||||
return 1;
|
||||
|
@ -649,56 +690,18 @@ static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
bool should_enable_sd_clock = false;
|
||||
if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)
|
||||
{
|
||||
should_enable_sd_clock = true;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
}
|
||||
|
||||
if (!(sdmmc->regs->sdmemcmppadctl & 0x80000000))
|
||||
{
|
||||
sdmmc->regs->sdmemcmppadctl |= 0x80000000;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
sdmmc->regs->autocalcfg |= 0xA0000000;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 10;
|
||||
while (sdmmc->regs->autocalcfg & 0x80000000)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
// In case autocalibration fails, we load suggested standard values.
|
||||
_sdmmc_pad_config_fallback(sdmmc, power);
|
||||
sdmmc->regs->autocalcfg &= 0xDFFFFFFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sdmmc->regs->sdmemcmppadctl &= 0x7FFFFFFF;
|
||||
|
||||
if(should_enable_sd_clock)
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
}
|
||||
|
||||
static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->norintstsen |= 0xB;
|
||||
sdmmc->regs->errintstsen |= 0x17F;
|
||||
sdmmc->regs->norintstsen |= SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
|
||||
sdmmc->regs->errintstsen |= SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR;
|
||||
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
||||
sdmmc->regs->errintsts = sdmmc->regs->errintsts;
|
||||
}
|
||||
|
||||
static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->errintstsen &= 0xFE80;
|
||||
sdmmc->regs->norintstsen &= 0xFFF4;
|
||||
sdmmc->regs->errintstsen &= ~SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR;
|
||||
sdmmc->regs->norintstsen &= ~(SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
|
||||
}
|
||||
|
||||
static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
|
||||
|
@ -706,13 +709,13 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
|
|||
u16 norintsts = sdmmc->regs->norintsts;
|
||||
u16 errintsts = sdmmc->regs->errintsts;
|
||||
|
||||
DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts);
|
||||
DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts);
|
||||
|
||||
if (pout)
|
||||
*pout = norintsts;
|
||||
|
||||
// Check for error interrupt.
|
||||
if (norintsts & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT)
|
||||
if (norintsts & SDHCI_INT_ERROR)
|
||||
{
|
||||
sdmmc->regs->errintsts = errintsts;
|
||||
return SDMMC_MASKINT_ERROR;
|
||||
|
@ -733,7 +736,7 @@ static int _sdmmc_wait_request(sdmmc_t *sdmmc)
|
|||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (1)
|
||||
{
|
||||
int res = _sdmmc_check_mask_interrupt(sdmmc, 0, TEGRA_MMC_NORINTSTS_CMD_COMPLETE);
|
||||
int res = _sdmmc_check_mask_interrupt(sdmmc, NULL, SDHCI_INT_RESPONSE);
|
||||
if (res == SDMMC_MASKINT_MASKED)
|
||||
break;
|
||||
if (res != SDMMC_MASKINT_NOERROR || get_tmr_ms() > timeout)
|
||||
|
@ -779,10 +782,10 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
|||
return 0;
|
||||
|
||||
bool should_disable_sd_clock = false;
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
{
|
||||
should_disable_sd_clock = true;
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
}
|
||||
|
@ -791,7 +794,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
|||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -807,7 +810,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
|||
u32 admaaddr = (u32)req->buf;
|
||||
|
||||
// Check alignment.
|
||||
if (admaaddr << 29)
|
||||
if (admaaddr & 7)
|
||||
return 0;
|
||||
|
||||
sdmmc->regs->admaaddr = admaaddr;
|
||||
|
@ -815,21 +818,19 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
|||
|
||||
sdmmc->dma_addr_next = (admaaddr + 0x80000) & 0xFFF80000;
|
||||
|
||||
sdmmc->regs->blksize = req->blksize | 0x7000;
|
||||
sdmmc->regs->blksize = req->blksize | 0x7000; // DMA 512KB (Detects A18 carry out).
|
||||
sdmmc->regs->blkcnt = blkcnt;
|
||||
|
||||
if (blkcnt_out)
|
||||
*blkcnt_out = blkcnt;
|
||||
|
||||
u32 trnmode = TEGRA_MMC_TRNMOD_DMA_ENABLE;
|
||||
u32 trnmode = SDHCI_TRNS_DMA;
|
||||
if (req->is_multi_block)
|
||||
trnmode = TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT |
|
||||
TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE |
|
||||
TEGRA_MMC_TRNMOD_DMA_ENABLE;
|
||||
trnmode = SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_DMA;
|
||||
if (!req->is_write)
|
||||
trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
|
||||
trnmode |= SDHCI_TRNS_READ;
|
||||
if (req->is_auto_cmd12)
|
||||
trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12;
|
||||
trnmode = (trnmode & ~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23)) | SDHCI_TRNS_AUTO_CMD12;
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
sdmmc->regs->trnmod = trnmode;
|
||||
|
||||
|
@ -850,15 +851,17 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc)
|
|||
{
|
||||
u16 intr = 0;
|
||||
res = _sdmmc_check_mask_interrupt(sdmmc, &intr,
|
||||
TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT);
|
||||
SDHCI_INT_DATA_END | SDHCI_INT_DMA_END);
|
||||
if (res < 0)
|
||||
break;
|
||||
if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
|
||||
|
||||
if (intr & SDHCI_INT_DATA_END)
|
||||
{
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
return 1; // Transfer complete.
|
||||
}
|
||||
if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
||||
|
||||
if (intr & SDHCI_INT_DMA_END)
|
||||
{
|
||||
// Update DMA.
|
||||
sdmmc->regs->admaaddr = sdmmc->dma_addr_next;
|
||||
|
@ -950,8 +953,8 @@ static int _sdmmc_config_sdmmc1()
|
|||
/*
|
||||
* Pinmux config:
|
||||
* DRV_TYPE = DRIVE_2X
|
||||
* E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V)
|
||||
* E_INPUT = ENABLE
|
||||
* E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V)
|
||||
* E_INPUT = ENABLE
|
||||
* TRISTATE = PASSTHROUGH
|
||||
* APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK
|
||||
*/
|
||||
|
@ -966,27 +969,24 @@ static int _sdmmc_config_sdmmc1()
|
|||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
|
||||
// Make sure the SDMMC1 controller is powered.
|
||||
PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12);
|
||||
PMC(APBDEV_PMC_NO_IOPOWER) &= ~(PMC_NO_IOPOWER_SDMMC1_IO_EN);
|
||||
// Assume 3.3V SD card voltage.
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN;
|
||||
|
||||
// Set enable SD card power.
|
||||
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //GPIO control, pull down.
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO);
|
||||
gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH);
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_ENABLE);
|
||||
|
||||
usleep(1000);
|
||||
|
||||
// Enable SD card power.
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000);
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 1);
|
||||
|
||||
usleep(1000);
|
||||
|
||||
// For good measure.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000;
|
||||
|
||||
usleep(1000);
|
||||
|
||||
return 1;
|
||||
|
@ -1025,7 +1025,9 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
|
|||
sdmmc->regs->veniotrimctl &= 0xFFFFFFFB;
|
||||
static const u32 trim_values[] = { 2, 8, 3, 8 };
|
||||
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24);
|
||||
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7;
|
||||
sdmmc->regs->sdmemcmppadctl =
|
||||
(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK) | 7;
|
||||
|
||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||
return 0;
|
||||
|
||||
|
@ -1091,10 +1093,10 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
|||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_voltage(sdmmc));
|
||||
|
||||
int should_disable_sd_clock = 0;
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
{
|
||||
should_disable_sd_clock = 1;
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
}
|
||||
|
@ -1103,7 +1105,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
|||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -1113,7 +1115,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||
if(sdmmc->id != SDMMC_1)
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(sdmmc, 8))
|
||||
if (!sdmmc_setup_clock(sdmmc, SDHCI_TIMING_UHS_SDR12))
|
||||
return 0;
|
||||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
@ -1127,7 +1129,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT;
|
||||
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(PMC_PWR_DET_SDMMC1_IO_EN);
|
||||
|
||||
_sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8);
|
||||
_sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8);
|
||||
|
@ -1137,7 +1139,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||
|
||||
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180)
|
||||
{
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1000);
|
||||
if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -49,24 +50,154 @@
|
|||
#define SDMMC_MASKINT_NOERROR -1
|
||||
#define SDMMC_MASKINT_ERROR -2
|
||||
|
||||
/*! SDMMC host control 2 */
|
||||
#define SDHCI_CTRL_UHS_MASK 0xFFF8
|
||||
#define SDHCI_CTRL_VDD_330 0xFFF7
|
||||
#define SDHCI_CTRL_VDD_180 8
|
||||
#define SDHCI_CTRL_EXEC_TUNING 0x40
|
||||
#define SDHCI_CTRL_TUNED_CLK 0x80
|
||||
#define SDHCI_HOST_VERSION_4_EN 0x1000
|
||||
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
|
||||
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000
|
||||
/*! SDMMC present state. */
|
||||
#define SDHCI_CMD_INHIBIT 0x1
|
||||
#define SDHCI_DATA_INHIBIT 0x2
|
||||
#define SDHCI_DOING_WRITE 0x100
|
||||
#define SDHCI_DOING_READ 0x200
|
||||
#define SDHCI_SPACE_AVAILABLE 0x400
|
||||
#define SDHCI_DATA_AVAILABLE 0x800
|
||||
#define SDHCI_CARD_PRESENT 0x10000
|
||||
#define SDHCI_CD_STABLE 0x20000
|
||||
#define SDHCI_CD_LVL 0x40000
|
||||
#define SDHCI_WRITE_PROTECT 0x80000
|
||||
#define SDHCI_DATA_LVL_MASK 0xF00000
|
||||
#define SDHCI_DATA_0_LVL_MASK 0x100000
|
||||
#define SDHCI_CMD_LVL 0x1000000
|
||||
|
||||
/*! SDMMC transfer mode. */
|
||||
#define SDHCI_TRNS_DMA 0x01
|
||||
#define SDHCI_TRNS_BLK_CNT_EN 0x02
|
||||
#define SDHCI_TRNS_AUTO_CMD12 0x04
|
||||
#define SDHCI_TRNS_AUTO_CMD23 0x08
|
||||
#define SDHCI_TRNS_AUTO_SEL 0x0C
|
||||
#define SDHCI_TRNS_WRITE 0x00
|
||||
#define SDHCI_TRNS_READ 0x10
|
||||
#define SDHCI_TRNS_MULTI 0x20
|
||||
|
||||
/*! SDMMC command. */
|
||||
#define SDHCI_CMD_RESP_MASK 0x3
|
||||
#define SDHCI_CMD_RESP_NO_RESP 0x0
|
||||
#define SDHCI_CMD_RESP_LEN136 0x1
|
||||
#define SDHCI_CMD_RESP_LEN48 0x2
|
||||
#define SDHCI_CMD_RESP_LEN48_BUSY 0x3
|
||||
#define SDHCI_CMD_CRC 0x08
|
||||
#define SDHCI_CMD_INDEX 0x10
|
||||
#define SDHCI_CMD_DATA 0x20
|
||||
#define SDHCI_CMD_ABORTCMD 0xC0
|
||||
|
||||
/*! SDMMC host control. */
|
||||
#define SDHCI_CTRL_LED 0x01
|
||||
#define SDHCI_CTRL_4BITBUS 0x02
|
||||
#define SDHCI_CTRL_HISPD 0x04
|
||||
#define SDHCI_CTRL_DMA_MASK 0x18
|
||||
#define SDHCI_CTRL_SDMA 0x00
|
||||
#define SDHCI_CTRL_ADMA1 0x08
|
||||
#define SDHCI_CTRL_ADMA32 0x10
|
||||
#define SDHCI_CTRL_ADMA64 0x18
|
||||
#define SDHCI_CTRL_8BITBUS 0x20
|
||||
#define SDHCI_CTRL_CDTEST_INS 0x40
|
||||
#define SDHCI_CTRL_CDTEST_EN 0x80
|
||||
|
||||
/*! SDMMC host control 2. */
|
||||
#define SDHCI_CTRL_UHS_MASK 0xFFF8
|
||||
#define SDHCI_CTRL_VDD_180 8
|
||||
#define SDHCI_CTRL_DRV_TYPE_B 0x00
|
||||
#define SDHCI_CTRL_DRV_TYPE_A 0x10
|
||||
#define SDHCI_CTRL_DRV_TYPE_C 0x20
|
||||
#define SDHCI_CTRL_DRV_TYPE_D 0x30
|
||||
#define SDHCI_CTRL_EXEC_TUNING 0x40
|
||||
#define SDHCI_CTRL_TUNED_CLK 0x80
|
||||
#define SDHCI_HOST_VERSION_4_EN 0x1000
|
||||
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
|
||||
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000
|
||||
|
||||
/*! SDMMC power control. */
|
||||
#define SDHCI_POWER_ON 0x01
|
||||
#define SDHCI_POWER_180 0x0A
|
||||
#define SDHCI_POWER_300 0x0C
|
||||
#define SDHCI_POWER_330 0x0E
|
||||
#define SDHCI_POWER_MASK 0xF1
|
||||
|
||||
// /*! SDMMC max current. */
|
||||
// #define SDHCI_MAX_CURRENT_330_MASK 0xFF
|
||||
// #define SDHCI_MAX_CURRENT_180_MASK 0xFF0000
|
||||
// #define SDHCI_MAX_CURRENT_MULTIPLIER 4
|
||||
|
||||
/*! SDMMC clock control. */
|
||||
#define SDHCI_DIVIDER_SHIFT 8
|
||||
#define SDHCI_DIVIDER_HI_SHIFT 6
|
||||
#define SDHCI_DIV_MASK 0xFF00
|
||||
#define SDHCI_DIV_HI_MASK 0xC0
|
||||
#define SDHCI_PROG_CLOCK_MODE 0x20
|
||||
#define SDHCI_CLOCK_CARD_EN 0x4
|
||||
#define SDHCI_CLOCK_INT_STABLE 0x2
|
||||
#define SDHCI_CLOCK_INT_EN 0x1
|
||||
|
||||
/*! SDMMC software reset. */
|
||||
#define SDHCI_RESET_ALL 0x01
|
||||
#define SDHCI_RESET_CMD 0x02
|
||||
#define SDHCI_RESET_DATA 0x04
|
||||
|
||||
/*! SDMMC interrupt status and control. */
|
||||
#define SDHCI_INT_RESPONSE 0x1
|
||||
#define SDHCI_INT_DATA_END 0x2
|
||||
#define SDHCI_INT_BLK_GAP 0x4
|
||||
#define SDHCI_INT_DMA_END 0x8
|
||||
#define SDHCI_INT_SPACE_AVAIL 0x10
|
||||
#define SDHCI_INT_DATA_AVAIL 0x20
|
||||
#define SDHCI_INT_CARD_INSERT 0x40
|
||||
#define SDHCI_INT_CARD_REMOVE 0x80
|
||||
#define SDHCI_INT_CARD_INT 0x100
|
||||
#define SDHCI_INT_RETUNE 0x1000
|
||||
#define SDHCI_INT_CQE 0x4000
|
||||
#define SDHCI_INT_ERROR 0x8000
|
||||
|
||||
/*! SDMMC error interrupt status and control. */
|
||||
#define SDHCI_ERR_INT_TIMEOUT 0x1
|
||||
#define SDHCI_ERR_INT_CRC 0x2
|
||||
#define SDHCI_ERR_INT_END_BIT 0x4
|
||||
#define SDHCI_ERR_INT_INDEX 0x8
|
||||
#define SDHCI_ERR_INT_DATA_TIMEOUT 0x10
|
||||
#define SDHCI_ERR_INT_DATA_CRC 0x20
|
||||
#define SDHCI_ERR_INT_DATA_END_BIT 0x40
|
||||
#define SDHCI_ERR_INT_BUS_POWER 0x80
|
||||
#define SDHCI_ERR_INT_AUTO_CMD_ERR 0x100
|
||||
#define SDHCI_ERR_INT_ADMA_ERROR 0x200
|
||||
|
||||
#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \
|
||||
(SDHCI_ERR_INT_AUTO_CMD_ERR | SDHCI_ERR_INT_DATA_END_BIT | \
|
||||
SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \
|
||||
SDHCI_ERR_INT_INDEX | SDHCI_ERR_INT_END_BIT | \
|
||||
SDHCI_ERR_INT_CRC | SDHCI_ERR_INT_TIMEOUT)
|
||||
|
||||
/*! SD bus speeds. */
|
||||
#define UHS_SDR12_BUS_SPEED 0
|
||||
#define HIGH_SPEED_BUS_SPEED 1
|
||||
#define UHS_SDR25_BUS_SPEED 1
|
||||
#define UHS_SDR50_BUS_SPEED 2
|
||||
#define UHS_SDR104_BUS_SPEED 3
|
||||
#define UHS_DDR50_BUS_SPEED 4
|
||||
#define HS400_BUS_SPEED 5
|
||||
#define UHS_SDR12_BUS_SPEED 0
|
||||
#define HIGH_SPEED_BUS_SPEED 1
|
||||
#define UHS_SDR25_BUS_SPEED 1
|
||||
#define UHS_SDR50_BUS_SPEED 2
|
||||
#define UHS_SDR104_BUS_SPEED 3
|
||||
#define UHS_DDR50_BUS_SPEED 4
|
||||
#define HS400_BUS_SPEED 5
|
||||
|
||||
/*! SDMMC timmings. */
|
||||
#define SDHCI_TIMING_MMC_ID 0
|
||||
#define SDHCI_TIMING_MMC_LS26 1
|
||||
#define SDHCI_TIMING_MMC_HS52 2
|
||||
#define SDHCI_TIMING_MMC_HS200 3
|
||||
#define SDHCI_TIMING_MMC_HS400 4
|
||||
#define SDHCI_TIMING_SD_ID 5
|
||||
#define SDHCI_TIMING_SD_DS12 6
|
||||
#define SDHCI_TIMING_SD_HS25 7
|
||||
#define SDHCI_TIMING_UHS_SDR12 8
|
||||
#define SDHCI_TIMING_UHS_SDR25 9
|
||||
#define SDHCI_TIMING_UHS_SDR50 10
|
||||
#define SDHCI_TIMING_UHS_SDR104 11
|
||||
#define SDHCI_TIMING_UHS_SDR82 12 // SDR104 with a 163.2MHz -> 81.6MHz clock.
|
||||
#define SDHCI_TIMING_UHS_DDR50 13
|
||||
#define SDHCI_TIMING_MMC_DDR52 14
|
||||
|
||||
#define SDHCI_CAN_64BIT 0x10000000
|
||||
|
||||
/*! Helper for SWITCH command argument. */
|
||||
#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -19,49 +20,14 @@
|
|||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_POWER 0x1
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 0xA
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0 0xC
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3 0xE
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK 0xF1
|
||||
|
||||
#define TEGRA_MMC_HOSTCTL_1BIT 0x00
|
||||
#define TEGRA_MMC_HOSTCTL_4BIT 0x02
|
||||
#define TEGRA_MMC_HOSTCTL_8BIT 0x20
|
||||
|
||||
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE 0x1
|
||||
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE 0x2
|
||||
#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE 0x4
|
||||
#define TEGRA_MMC_CLKCON_CLKGEN_SELECT 0x20
|
||||
|
||||
#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL 0x1
|
||||
#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE 0x2
|
||||
#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE 0x4
|
||||
|
||||
#define TEGRA_MMC_TRNMOD_DMA_ENABLE 0x1
|
||||
#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE 0x2
|
||||
#define TEGRA_MMC_TRNMOD_AUTO_CMD12 0x4
|
||||
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE 0x0
|
||||
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ 0x10
|
||||
#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT 0x20
|
||||
|
||||
#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK 0x8
|
||||
#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK 0x10
|
||||
#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER 0x20
|
||||
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK 0x3
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE 0x0
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 0x1
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 0x2
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY 0x3
|
||||
|
||||
#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE 0x1
|
||||
#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE 0x2
|
||||
#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT 0x8
|
||||
#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT 0x8000
|
||||
#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT 0x10000
|
||||
|
||||
#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY 0x20
|
||||
#define TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW 0x20000
|
||||
#define TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE 0x80000000
|
||||
#define TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE 0x80000000
|
||||
#define TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD 0x80000000
|
||||
#define TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK 0xFFFFFFF0
|
||||
#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE 0x20000000
|
||||
#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START 0x80000000
|
||||
#define TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE 0x80000000
|
||||
|
||||
typedef struct _t210_sdmmc_t
|
||||
{
|
||||
|
|
|
@ -737,7 +737,7 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui)
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
||||
goto out;
|
||||
|
@ -1318,7 +1318,7 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
||||
goto out;
|
||||
|
|
|
@ -376,7 +376,7 @@ void dump_emummc_file(emmc_tool_gui_t *gui)
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
||||
goto out;
|
||||
|
@ -658,7 +658,7 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start)
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
||||
goto out;
|
||||
|
|
|
@ -209,7 +209,7 @@ static void _create_mbox_emummc_raw()
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||
|
||||
u32 emmc_size_safe = storage.sec_cnt + 0xC000; // eMMC GPP size + BOOT0/1.
|
||||
|
||||
|
@ -588,7 +588,7 @@ static lv_res_t _create_mbox_emummc_migrate(lv_obj_t *btn)
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||
|
||||
bool backup = false;
|
||||
bool emummc = false;
|
||||
|
|
|
@ -435,7 +435,7 @@ static lv_res_t _create_window_tsec_keys_status(lv_obj_t *btn)
|
|||
// Read package1.
|
||||
char *build_date = malloc(32);
|
||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
@ -558,7 +558,7 @@ static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn)
|
|||
|
||||
char *txt_buf = (char *)malloc(0x1000);
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
||||
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
|
||||
|
|
|
@ -48,7 +48,7 @@ bool get_autorcm_status(bool change)
|
|||
sdmmc_t sdmmc;
|
||||
bool enabled = false;
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||
|
||||
u8 *tempbuf = (u8 *)malloc(0x200);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
|
@ -352,7 +352,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
|||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ void check_sept()
|
|||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
goto out_free;
|
||||
|
|
|
@ -89,7 +89,7 @@ bool sd_mount()
|
|||
|
||||
if (!sd_init_done)
|
||||
{
|
||||
res = !sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11);
|
||||
res = !sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_BUS_WIDTH_4, SDHCI_TIMING_UHS_SDR82);
|
||||
if (!res)
|
||||
sd_init_done = true;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t
|
|||
|
||||
if (!storage)
|
||||
{
|
||||
if (!sdmmc_storage_init_mmc(&storage2, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
if (!sdmmc_storage_init_mmc(&storage2, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
||||
memcpy(emmcSN, "00000000", 9);
|
||||
else
|
||||
{
|
||||
|
@ -278,7 +278,7 @@ lv_res_t launch_payload(lv_obj_t *list)
|
|||
if (f_read(&fp, buf, size, NULL))
|
||||
{
|
||||
f_close(&fp);
|
||||
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
|||
if (magic == 0xBAADF00D)
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
|
||||
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0);
|
||||
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0);
|
||||
clock_disable_cl_dvfs();
|
||||
|
||||
msleep(200);
|
||||
|
|
|
@ -401,7 +401,7 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check)
|
|||
if (check && !_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 2))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52))
|
||||
return 0;
|
||||
|
||||
DPRINTF("[MMC] switched to HS\n");
|
||||
|
@ -418,10 +418,10 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage)
|
|||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 3))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
return 0;
|
||||
|
||||
DPRINTF("[MMC] switched to HS200\n");
|
||||
|
@ -446,7 +446,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
|
|||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 4))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400))
|
||||
return 0;
|
||||
|
||||
DPRINTF("[MMC] switched to HS400\n");
|
||||
|
@ -457,22 +457,20 @@ DPRINTF("[MMC] switched to HS400\n");
|
|||
|
||||
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
|
||||
{
|
||||
//TODO: this should be a config item.
|
||||
// --v
|
||||
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
|
||||
if (sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
|
||||
goto out;
|
||||
|
||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
|
||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4)
|
||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400)
|
||||
return _mmc_storage_enable_HS400(storage);
|
||||
|
||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
|
||||
(sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4
|
||||
&& card_type & EXT_CSD_CARD_TYPE_HS200_1_8V
|
||||
&& (type == 4 || type == 3)))
|
||||
&& (type == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200)))
|
||||
return _mmc_storage_enable_HS200(storage);
|
||||
|
||||
out:;
|
||||
out:
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
||||
return _mmc_storage_enable_HS(storage, 1);
|
||||
|
||||
|
@ -493,7 +491,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||
storage->sdmmc = sdmmc;
|
||||
storage->rca = 2; //TODO: this could be a config item.
|
||||
|
||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0))
|
||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_AUTO_CAL_DISABLE))
|
||||
return 0;
|
||||
DPRINTF("[MMC] after init\n");
|
||||
|
||||
|
@ -520,7 +518,7 @@ DPRINTF("[MMC] set relative addr\n");
|
|||
DPRINTF("[MMC] got csd\n");
|
||||
_mmc_storage_parse_csd(storage);
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 1))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26))
|
||||
return 0;
|
||||
DPRINTF("[MMC] after setup clock\n");
|
||||
|
||||
|
@ -558,7 +556,7 @@ DPRINTF("[MMC] got ext_csd\n");
|
|||
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
|
||||
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
|
||||
Additionally this works only when we put the device in idle mode which we don't after enabling it. */
|
||||
if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0)
|
||||
if (0 && storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2))
|
||||
{
|
||||
_mmc_storage_enable_bkops(storage);
|
||||
DPRINTF("[MMC] BKOPS enabled\n");
|
||||
|
@ -572,7 +570,7 @@ DPRINTF("[MMC] BKOPS disabled\n");
|
|||
return 0;
|
||||
DPRINTF("[MMC] succesfully switched to HS mode\n");
|
||||
|
||||
sdmmc_sd_clock_ctrl(storage->sdmmc, 1);
|
||||
sdmmc_sd_clock_ctrl(storage->sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -656,6 +654,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
|||
if (cond & SD_OCR_CCS)
|
||||
storage->has_sector_access = 1;
|
||||
|
||||
// Check if card supports 1.8V signaling.
|
||||
if (cond & SD_ROCR_S18A && supports_low_voltage)
|
||||
{
|
||||
//The low voltage regulator configuration is valid for SDMMC1 only.
|
||||
|
@ -826,7 +825,7 @@ DPRINTF("[SD] power limit raised to 800mA\n");
|
|||
DPRINTF("[SD] power limit raised to 600mA\n");
|
||||
break;
|
||||
case SD_SET_CURRENT_LIMIT_400:
|
||||
DPRINTF("[SD] power limit raised to 800mA\n");
|
||||
DPRINTF("[SD] power limit raised to 400mA\n");
|
||||
break;
|
||||
default:
|
||||
case SD_SET_CURRENT_LIMIT_200:
|
||||
|
@ -839,12 +838,12 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)
|
|||
{
|
||||
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
|
||||
return 0;
|
||||
DPRINTF("[SD] SD supports switch to (U)HS check\n");
|
||||
DPRINTF("[SD] supports switch to (U)HS mode\n");
|
||||
|
||||
u32 type_out = buf[16] & 0xF;
|
||||
if (type_out != hs_type)
|
||||
return 0;
|
||||
DPRINTF("[SD] SD supports selected (U)HS mode\n");
|
||||
DPRINTF("[SD] supports selected (U)HS mode\n");
|
||||
|
||||
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
|
||||
{
|
||||
|
@ -870,32 +869,51 @@ int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
|
|||
return 0;
|
||||
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||
|
||||
u8 access_mode = buf[13];
|
||||
|
||||
u32 hs_type = 0;
|
||||
switch (type)
|
||||
{
|
||||
case 11: // SDR104.
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
// Fall through if not supported.
|
||||
if (buf[13] & SD_MODE_UHS_SDR104)
|
||||
if (access_mode & SD_MODE_UHS_SDR104)
|
||||
{
|
||||
type = 11;
|
||||
hs_type = UHS_SDR104_BUS_SPEED;
|
||||
DPRINTF("[SD] bus speed set to SDR104\n");
|
||||
storage->csd.busspeed = 104;
|
||||
switch (type)
|
||||
{
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
storage->csd.busspeed = 104;
|
||||
break;
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
storage->csd.busspeed = 82;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 10: // SDR50.
|
||||
if (buf[13] & SD_MODE_UHS_SDR50)
|
||||
case SDHCI_TIMING_UHS_SDR50:
|
||||
if (access_mode & SD_MODE_UHS_SDR50)
|
||||
{
|
||||
type = 10;
|
||||
type = SDHCI_TIMING_UHS_SDR50;
|
||||
hs_type = UHS_SDR50_BUS_SPEED;
|
||||
DPRINTF("[SD] bus speed set to SDR50\n");
|
||||
storage->csd.busspeed = 50;
|
||||
break;
|
||||
}
|
||||
case 8: // SDR12.
|
||||
if (!(buf[13] & SD_MODE_UHS_SDR12))
|
||||
case SDHCI_TIMING_UHS_SDR25:
|
||||
if (access_mode & SD_MODE_UHS_SDR25)
|
||||
{
|
||||
type = SDHCI_TIMING_UHS_SDR25;
|
||||
hs_type = UHS_SDR50_BUS_SPEED;
|
||||
DPRINTF("[SD] bus speed set to SDR25\n");
|
||||
storage->csd.busspeed = 25;
|
||||
break;
|
||||
}
|
||||
case SDHCI_TIMING_UHS_SDR12:
|
||||
if (!(access_mode & SD_MODE_UHS_SDR12))
|
||||
return 0;
|
||||
type = 8;
|
||||
type = SDHCI_TIMING_UHS_SDR12;
|
||||
hs_type = UHS_SDR12_BUS_SPEED;
|
||||
DPRINTF("[SD] bus speed set to SDR12\n");
|
||||
storage->csd.busspeed = 12;
|
||||
|
@ -907,7 +925,7 @@ DPRINTF("[SD] bus speed set to SDR12\n");
|
|||
|
||||
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
|
||||
return 0;
|
||||
DPRINTF("[SD] SD card accepted UHS\n");
|
||||
DPRINTF("[SD] card accepted UHS\n");
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, type))
|
||||
return 0;
|
||||
DPRINTF("[SD] setup clock\n");
|
||||
|
@ -922,16 +940,19 @@ int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf)
|
|||
if (!_sd_storage_switch_get(storage, buf))
|
||||
return 0;
|
||||
//gfx_hexdump(0, (u8 *)buf, 64);
|
||||
if (!(buf[13] & SD_MODE_HIGH_SPEED))
|
||||
|
||||
u8 access_mode = buf[13];
|
||||
|
||||
if (!(access_mode & SD_MODE_HIGH_SPEED))
|
||||
return 1;
|
||||
|
||||
if (!_sd_storage_enable_highspeed(storage, 1, buf))
|
||||
if (!_sd_storage_enable_highspeed(storage, HIGH_SPEED_BUS_SPEED, buf))
|
||||
return 0;
|
||||
|
||||
if (!_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
return sdmmc_setup_clock(storage->sdmmc, 7);
|
||||
return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25);
|
||||
}
|
||||
|
||||
static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
|
||||
|
@ -1073,7 +1094,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||
storage->sdmmc = sdmmc;
|
||||
|
||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0))
|
||||
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_AUTO_CAL_DISABLE))
|
||||
return 0;
|
||||
DPRINTF("[SD] after init\n");
|
||||
|
||||
|
@ -1122,7 +1143,7 @@ DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
|
|||
|
||||
if (!storage->is_low_voltage)
|
||||
{
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 6))
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12))
|
||||
return 0;
|
||||
DPRINTF("[SD] after setup clock\n");
|
||||
}
|
||||
|
@ -1166,7 +1187,7 @@ DPRINTF("[SD] SD does not support wide bus width\n");
|
|||
return 0;
|
||||
DPRINTF("[SD] enabled UHS\n");
|
||||
}
|
||||
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
|
||||
else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0)
|
||||
{
|
||||
if (!_sd_storage_enable_hs_high_volt(storage, buf))
|
||||
return 0;
|
||||
|
@ -1175,7 +1196,7 @@ DPRINTF("[SD] enabled HS\n");
|
|||
storage->csd.busspeed = 25;
|
||||
}
|
||||
|
||||
sdmmc_sd_clock_ctrl(sdmmc, 1);
|
||||
sdmmc_sd_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||
|
||||
// Parse additional card info from sd status.
|
||||
if (_sd_storage_get_ssr(storage, buf))
|
||||
|
@ -1222,17 +1243,17 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
|||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||
storage->sdmmc = sdmmc;
|
||||
|
||||
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0))
|
||||
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_DDR52, SDMMC_AUTO_CAL_DISABLE))
|
||||
return 0;
|
||||
DPRINTF("[gc] after init\n");
|
||||
|
||||
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
return 0;
|
||||
DPRINTF("[gc] after tuning\n");
|
||||
|
||||
sdmmc_sd_clock_ctrl(sdmmc, 1);
|
||||
sdmmc_sd_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -43,11 +43,11 @@ static const u32 _sdmmc_bases[4] = {
|
|||
int sdmmc_get_voltage(sdmmc_t *sdmmc)
|
||||
{
|
||||
u32 p = sdmmc->regs->pwrcon;
|
||||
if (!(p & TEGRA_MMC_PWRCTL_SD_BUS_POWER))
|
||||
if (!(p & SDHCI_POWER_ON))
|
||||
return SDMMC_POWER_OFF;
|
||||
if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8)
|
||||
if (p & SDHCI_POWER_180)
|
||||
return SDMMC_POWER_1_8;
|
||||
if (p & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3)
|
||||
if (p & SDHCI_POWER_330)
|
||||
return SDMMC_POWER_3_3;
|
||||
return -1;
|
||||
}
|
||||
|
@ -59,15 +59,15 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
|
|||
switch (power)
|
||||
{
|
||||
case SDMMC_POWER_OFF:
|
||||
sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
sdmmc->regs->pwrcon &= ~SDHCI_POWER_ON;
|
||||
break;
|
||||
case SDMMC_POWER_1_8:
|
||||
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
sdmmc->regs->pwrcon = SDHCI_POWER_180;
|
||||
pwr = SDHCI_POWER_180;
|
||||
break;
|
||||
case SDMMC_POWER_3_3:
|
||||
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
|
||||
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
|
||||
sdmmc->regs->pwrcon = SDHCI_POWER_330;
|
||||
pwr = SDHCI_POWER_330;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -75,7 +75,7 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
|
|||
|
||||
if (power != SDMMC_POWER_OFF)
|
||||
{
|
||||
pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
pwr |= SDHCI_POWER_ON;
|
||||
sdmmc->regs->pwrcon = pwr;
|
||||
}
|
||||
|
||||
|
@ -85,9 +85,9 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
|
|||
u32 sdmmc_get_bus_width(sdmmc_t *sdmmc)
|
||||
{
|
||||
u32 h = sdmmc->regs->hostctl;
|
||||
if (h & TEGRA_MMC_HOSTCTL_8BIT)
|
||||
if (h & SDHCI_CTRL_8BITBUS)
|
||||
return SDMMC_BUS_WIDTH_8;
|
||||
if (h & TEGRA_MMC_HOSTCTL_4BIT)
|
||||
if (h & SDHCI_CTRL_4BITBUS)
|
||||
return SDMMC_BUS_WIDTH_4;
|
||||
return SDMMC_BUS_WIDTH_1;
|
||||
}
|
||||
|
@ -95,14 +95,14 @@ u32 sdmmc_get_bus_width(sdmmc_t *sdmmc)
|
|||
void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width)
|
||||
{
|
||||
if (bus_width == SDMMC_BUS_WIDTH_1)
|
||||
sdmmc->regs->hostctl &= ~(TEGRA_MMC_HOSTCTL_4BIT | TEGRA_MMC_HOSTCTL_8BIT);
|
||||
sdmmc->regs->hostctl &= ~(SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS);
|
||||
else if (bus_width == SDMMC_BUS_WIDTH_4)
|
||||
{
|
||||
sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_4BIT;
|
||||
sdmmc->regs->hostctl &= ~TEGRA_MMC_HOSTCTL_8BIT;
|
||||
sdmmc->regs->hostctl |= SDHCI_CTRL_4BITBUS;
|
||||
sdmmc->regs->hostctl &= ~SDHCI_CTRL_8BITBUS;
|
||||
}
|
||||
else if (bus_width == SDMMC_BUS_WIDTH_8)
|
||||
sdmmc->regs->hostctl |= TEGRA_MMC_HOSTCTL_8BIT;
|
||||
sdmmc->regs->hostctl |= SDHCI_CTRL_8BITBUS;
|
||||
}
|
||||
|
||||
void sdmmc_get_venclkctl(sdmmc_t *sdmmc)
|
||||
|
@ -115,10 +115,10 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id)
|
|||
{
|
||||
u32 tap_val = 0;
|
||||
|
||||
if (id == 4)
|
||||
if (id == SDHCI_TIMING_MMC_HS400)
|
||||
sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800;
|
||||
sdmmc->regs->ventunctl0 &= 0xFFFDFFFF;
|
||||
if (id == 4)
|
||||
sdmmc->regs->ventunctl0 &= ~TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW;
|
||||
if (id == SDHCI_TIMING_MMC_HS400)
|
||||
{
|
||||
if (!sdmmc->venclkctl_set)
|
||||
return 0;
|
||||
|
@ -160,21 +160,61 @@ static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power)
|
|||
//TODO: load standard values for other controllers, can depend on power.
|
||||
}
|
||||
|
||||
static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
bool should_enable_sd_clock = false;
|
||||
if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)
|
||||
{
|
||||
should_enable_sd_clock = true;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
// Enable E_INPUT power.
|
||||
if (!(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD))
|
||||
{
|
||||
sdmmc->regs->sdmemcmppadctl |= TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
// Enable auto calibration and start auto configuration.
|
||||
sdmmc->regs->autocalcfg |= TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE | TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 10;
|
||||
while (sdmmc->regs->autocalcfg & TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
// In case autocalibration fails, we load suggested standard values.
|
||||
_sdmmc_pad_config_fallback(sdmmc, power);
|
||||
sdmmc->regs->autocalcfg &= ~TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sdmmc->regs->sdmemcmppadctl &= ~TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD;
|
||||
|
||||
if(should_enable_sd_clock)
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
||||
{
|
||||
int res = 1, should_disable_sd_clock = 0;
|
||||
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
{
|
||||
should_disable_sd_clock = 1;
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
sdmmc->regs->vendllcal |= 0x80000000;
|
||||
sdmmc->regs->vendllcal |= TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 5;
|
||||
while (sdmmc->regs->vendllcal & 0x80000000)
|
||||
while (sdmmc->regs->vendllcal & TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
|
@ -184,7 +224,7 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
|||
}
|
||||
|
||||
timeout = get_tmr_ms() + 10;
|
||||
while (sdmmc->regs->dllcfgstatus & 0x80000000)
|
||||
while (sdmmc->regs->dllcfgstatus & TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
|
@ -195,55 +235,65 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
|
|||
|
||||
out:;
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _sdmmc_reset(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->swrst |= SDHCI_RESET_CMD | SDHCI_RESET_DATA;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while ((sdmmc->regs->swrst & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) && get_tmr_ms() < timeout)
|
||||
;
|
||||
}
|
||||
|
||||
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
{
|
||||
// Disable the SD clock if it was enabled, and reenable it later.
|
||||
bool should_enable_sd_clock = false;
|
||||
if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)
|
||||
if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)
|
||||
{
|
||||
should_enable_sd_clock = true;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
_sdmmc_config_ven_ceata_clk(sdmmc, type);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 5:
|
||||
case 6:
|
||||
sdmmc->regs->hostctl &= 0xFB; // Should this be 0xFFFB (~4) ?
|
||||
sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330;
|
||||
case SDHCI_TIMING_MMC_ID:
|
||||
case SDHCI_TIMING_MMC_LS26:
|
||||
case SDHCI_TIMING_SD_ID:
|
||||
case SDHCI_TIMING_SD_DS12:
|
||||
sdmmc->regs->hostctl &= ~SDHCI_CTRL_HISPD;
|
||||
sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 2:
|
||||
case 7:
|
||||
sdmmc->regs->hostctl |= 4;
|
||||
sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330;
|
||||
case SDHCI_TIMING_MMC_HS52:
|
||||
case SDHCI_TIMING_SD_HS25:
|
||||
sdmmc->regs->hostctl |= SDHCI_CTRL_HISPD;
|
||||
sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 3:
|
||||
case 11:
|
||||
case 13:
|
||||
case 14:
|
||||
case SDHCI_TIMING_MMC_HS200:
|
||||
case SDHCI_TIMING_UHS_SDR50: // T210 Errata for SDR50, the host must be set to SDR104.
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
case SDHCI_TIMING_UHS_DDR50:
|
||||
case SDHCI_TIMING_MMC_DDR52:
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 4:
|
||||
case SDHCI_TIMING_MMC_HS400:
|
||||
// Non standard.
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 8:
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED;
|
||||
case SDHCI_TIMING_UHS_SDR25:
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR25_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 10:
|
||||
// T210 Errata for SDR50, the host must be set to SDR104.
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED;
|
||||
case SDHCI_TIMING_UHS_SDR12:
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
}
|
||||
|
@ -261,14 +311,16 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
|||
u16 div = divisor >> 1;
|
||||
divisor = 0;
|
||||
if (div > 0xFF)
|
||||
divisor = div >> 8;
|
||||
sdmmc->regs->clkcon = (sdmmc->regs->clkcon & 0x3F) | (div << 8) | (divisor << 6);
|
||||
divisor = div >> SDHCI_DIVIDER_SHIFT;
|
||||
|
||||
sdmmc->regs->clkcon = (sdmmc->regs->clkcon & ~(SDHCI_DIV_MASK | SDHCI_DIV_HI_MASK))
|
||||
| (div << SDHCI_DIVIDER_SHIFT) | (divisor << SDHCI_DIVIDER_HI_SHIFT);
|
||||
|
||||
// Enable the SD clock again.
|
||||
if (should_enable_sd_clock)
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
if (type == 4)
|
||||
if (type == SDHCI_TIMING_MMC_HS400)
|
||||
return _sdmmc_wait_type4(sdmmc);
|
||||
return 1;
|
||||
}
|
||||
|
@ -277,8 +329,8 @@ static void _sdmmc_sd_clock_enable(sdmmc_t *sdmmc)
|
|||
{
|
||||
if (!sdmmc->no_sd)
|
||||
{
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
sdmmc->sd_clock_enabled = 1;
|
||||
}
|
||||
|
@ -286,7 +338,7 @@ static void _sdmmc_sd_clock_enable(sdmmc_t *sdmmc)
|
|||
static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->sd_clock_enabled = 0;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd)
|
||||
|
@ -294,14 +346,14 @@ void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd)
|
|||
sdmmc->no_sd = no_sd;
|
||||
if (no_sd)
|
||||
{
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
return;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
return;
|
||||
}
|
||||
if (sdmmc->sd_clock_enabled)
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
|
@ -383,22 +435,12 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void _sdmmc_reset(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->swrst |=
|
||||
TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE | TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (sdmmc->regs->swrst << 29 >> 30 && get_tmr_ms() < timeout)
|
||||
;
|
||||
}
|
||||
|
||||
static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat)
|
||||
{
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while(sdmmc->regs->prnsts & 1) // CMD inhibit.
|
||||
while(sdmmc->regs->prnsts & SDHCI_CMD_INHIBIT)
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
@ -408,7 +450,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat)
|
|||
if (wait_dat)
|
||||
{
|
||||
timeout = get_tmr_ms() + 2000;
|
||||
while (sdmmc->regs->prnsts & 2) // DAT inhibit.
|
||||
while (sdmmc->regs->prnsts & SDHCI_DATA_INHIBIT)
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
@ -424,7 +466,7 @@ static int _sdmmc_wait_prnsts_type1(sdmmc_t *sdmmc)
|
|||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (!(sdmmc->regs->prnsts & 0x100000)) // DAT0 line level.
|
||||
while (!(sdmmc->regs->prnsts & SDHCI_DATA_0_LVL_MASK))
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
@ -442,14 +484,14 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc)
|
|||
return 0;
|
||||
break;
|
||||
case SDMMC_BUS_WIDTH_4:
|
||||
sdmmc->regs->blksize = 0x40;
|
||||
sdmmc->regs->blksize = 64;
|
||||
break;
|
||||
case SDMMC_BUS_WIDTH_8:
|
||||
sdmmc->regs->blksize = 0x80;
|
||||
sdmmc->regs->blksize = 128;
|
||||
break;
|
||||
}
|
||||
sdmmc->regs->blkcnt = 1;
|
||||
sdmmc->regs->trnmod = TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
|
||||
sdmmc->regs->trnmod = SDHCI_TRNS_READ;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -465,20 +507,15 @@ static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_pr
|
|||
case SDMMC_RSP_TYPE_4:
|
||||
case SDMMC_RSP_TYPE_5:
|
||||
if (cmd->check_busy)
|
||||
cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY |
|
||||
TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK |
|
||||
TEGRA_MMC_TRNMOD_CMD_CRC_CHECK;
|
||||
cmdflags = SDHCI_CMD_RESP_LEN48_BUSY | SDHCI_CMD_INDEX | SDHCI_CMD_CRC;
|
||||
else
|
||||
cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 |
|
||||
TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK |
|
||||
TEGRA_MMC_TRNMOD_CMD_CRC_CHECK;
|
||||
cmdflags = SDHCI_CMD_RESP_LEN48 | SDHCI_CMD_INDEX | SDHCI_CMD_CRC;
|
||||
break;
|
||||
case SDMMC_RSP_TYPE_2:
|
||||
cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 |
|
||||
TEGRA_MMC_TRNMOD_CMD_CRC_CHECK;
|
||||
cmdflags = SDHCI_CMD_RESP_LEN136 | SDHCI_CMD_CRC;
|
||||
break;
|
||||
case SDMMC_RSP_TYPE_3:
|
||||
cmdflags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48;
|
||||
cmdflags = SDHCI_CMD_RESP_LEN48;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -486,7 +523,7 @@ static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_pr
|
|||
}
|
||||
|
||||
if (is_data_present)
|
||||
cmdflags |= TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER;
|
||||
cmdflags |= SDHCI_CMD_DATA;
|
||||
sdmmc->regs->argument = cmd->arg;
|
||||
sdmmc->regs->cmdreg = (cmd->cmd << 8) | cmdflags;
|
||||
|
||||
|
@ -512,9 +549,9 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
|
||||
_sdmmc_setup_read_small_block(sdmmc);
|
||||
|
||||
sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY;
|
||||
sdmmc->regs->norintstsen |= SDHCI_INT_DATA_AVAIL;
|
||||
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
_sdmmc_parse_cmd_48(sdmmc, cmd);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
@ -522,16 +559,16 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
u32 timeout = get_tmr_us() + 5000;
|
||||
while (get_tmr_us() < timeout)
|
||||
{
|
||||
if (sdmmc->regs->norintsts & 0x20)
|
||||
if (sdmmc->regs->norintsts & SDHCI_INT_DATA_AVAIL)
|
||||
{
|
||||
sdmmc->regs->norintsts = 0x20;
|
||||
sdmmc->regs->norintstsen &= 0xFFDF;
|
||||
sdmmc->regs->norintsts = SDHCI_INT_DATA_AVAIL;
|
||||
sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
return 1;
|
||||
|
@ -540,7 +577,7 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->norintstsen &= 0xFFDF;
|
||||
sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
|
@ -554,26 +591,30 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
|||
sdmmc->regs->field_1C4 = 0;
|
||||
switch (type)
|
||||
{
|
||||
case 3:
|
||||
case 4:
|
||||
case 11:
|
||||
max = 0x80;
|
||||
flag = 0x4000;
|
||||
case SDHCI_TIMING_MMC_HS200:
|
||||
case SDHCI_TIMING_MMC_HS400:
|
||||
case SDHCI_TIMING_UHS_SDR104:
|
||||
case SDHCI_TIMING_UHS_SDR82:
|
||||
max = 128;
|
||||
flag = (2 << 13); // 128 iterations.
|
||||
break;
|
||||
case 10:
|
||||
case 13:
|
||||
case 14:
|
||||
max = 0x100;
|
||||
flag = 0x8000;
|
||||
case SDHCI_TIMING_UHS_SDR50:
|
||||
case SDHCI_TIMING_UHS_DDR50:
|
||||
case SDHCI_TIMING_MMC_DDR52:
|
||||
max = 256;
|
||||
flag = (4 << 13); // 256 iterations.
|
||||
break;
|
||||
case SDHCI_TIMING_UHS_SDR12:
|
||||
case SDHCI_TIMING_UHS_SDR25:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries.
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier.
|
||||
sdmmc->regs->ventunctl0 |= 0x20000;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | (1 << 6); // 1x Multiplier.
|
||||
sdmmc->regs->ventunctl0 |= TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
|
||||
|
||||
for (u32 i = 0; i < max; i++)
|
||||
{
|
||||
|
@ -591,24 +632,24 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
|||
static int _sdmmc_enable_internal_clock(sdmmc_t *sdmmc)
|
||||
{
|
||||
//Enable internal clock and wait till it is stable.
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_INT_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE))
|
||||
while (!(sdmmc->regs->clkcon & SDHCI_CLOCK_INT_STABLE))
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_CLKGEN_SELECT;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_PROG_CLOCK_MODE;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN;
|
||||
|
||||
if (!(sdmmc->regs->capareg & 0x10000000))
|
||||
if (!(sdmmc->regs->capareg & SDHCI_CAN_64BIT))
|
||||
return 0;
|
||||
|
||||
sdmmc->regs->hostctl2 |= SDHCI_ADDRESSING_64BIT_EN;
|
||||
sdmmc->regs->hostctl &= 0xE7;
|
||||
sdmmc->regs->hostctl &= ~SDHCI_CTRL_DMA_MASK;
|
||||
sdmmc->regs->timeoutcon = (sdmmc->regs->timeoutcon & 0xF0) | 0xE;
|
||||
|
||||
return 1;
|
||||
|
@ -649,56 +690,18 @@ static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
bool should_enable_sd_clock = false;
|
||||
if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)
|
||||
{
|
||||
should_enable_sd_clock = true;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
}
|
||||
|
||||
if (!(sdmmc->regs->sdmemcmppadctl & 0x80000000))
|
||||
{
|
||||
sdmmc->regs->sdmemcmppadctl |= 0x80000000;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
sdmmc->regs->autocalcfg |= 0xA0000000;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
|
||||
u32 timeout = get_tmr_ms() + 10;
|
||||
while (sdmmc->regs->autocalcfg & 0x80000000)
|
||||
{
|
||||
if (get_tmr_ms() > timeout)
|
||||
{
|
||||
// In case autocalibration fails, we load suggested standard values.
|
||||
_sdmmc_pad_config_fallback(sdmmc, power);
|
||||
sdmmc->regs->autocalcfg &= 0xDFFFFFFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sdmmc->regs->sdmemcmppadctl &= 0x7FFFFFFF;
|
||||
|
||||
if(should_enable_sd_clock)
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
}
|
||||
|
||||
static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->norintstsen |= 0xB;
|
||||
sdmmc->regs->errintstsen |= 0x17F;
|
||||
sdmmc->regs->norintstsen |= SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
|
||||
sdmmc->regs->errintstsen |= SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR;
|
||||
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
||||
sdmmc->regs->errintsts = sdmmc->regs->errintsts;
|
||||
}
|
||||
|
||||
static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc)
|
||||
{
|
||||
sdmmc->regs->errintstsen &= 0xFE80;
|
||||
sdmmc->regs->norintstsen &= 0xFFF4;
|
||||
sdmmc->regs->errintstsen &= ~SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR;
|
||||
sdmmc->regs->norintstsen &= ~(SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
|
||||
}
|
||||
|
||||
static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
|
||||
|
@ -706,13 +709,13 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
|
|||
u16 norintsts = sdmmc->regs->norintsts;
|
||||
u16 errintsts = sdmmc->regs->errintsts;
|
||||
|
||||
DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts);
|
||||
DPRINTF("norintsts %08X; errintsts %08X\n", norintsts, errintsts);
|
||||
|
||||
if (pout)
|
||||
*pout = norintsts;
|
||||
|
||||
// Check for error interrupt.
|
||||
if (norintsts & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT)
|
||||
if (norintsts & SDHCI_INT_ERROR)
|
||||
{
|
||||
sdmmc->regs->errintsts = errintsts;
|
||||
return SDMMC_MASKINT_ERROR;
|
||||
|
@ -733,7 +736,7 @@ static int _sdmmc_wait_request(sdmmc_t *sdmmc)
|
|||
u32 timeout = get_tmr_ms() + 2000;
|
||||
while (1)
|
||||
{
|
||||
int res = _sdmmc_check_mask_interrupt(sdmmc, 0, TEGRA_MMC_NORINTSTS_CMD_COMPLETE);
|
||||
int res = _sdmmc_check_mask_interrupt(sdmmc, NULL, SDHCI_INT_RESPONSE);
|
||||
if (res == SDMMC_MASKINT_MASKED)
|
||||
break;
|
||||
if (res != SDMMC_MASKINT_NOERROR || get_tmr_ms() > timeout)
|
||||
|
@ -779,10 +782,10 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
|||
return 0;
|
||||
|
||||
bool should_disable_sd_clock = false;
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
{
|
||||
should_disable_sd_clock = true;
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
}
|
||||
|
@ -791,7 +794,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
|||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -807,7 +810,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
|||
u32 admaaddr = (u32)req->buf;
|
||||
|
||||
// Check alignment.
|
||||
if (admaaddr << 29)
|
||||
if (admaaddr & 7)
|
||||
return 0;
|
||||
|
||||
sdmmc->regs->admaaddr = admaaddr;
|
||||
|
@ -815,21 +818,19 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
|||
|
||||
sdmmc->dma_addr_next = (admaaddr + 0x80000) & 0xFFF80000;
|
||||
|
||||
sdmmc->regs->blksize = req->blksize | 0x7000;
|
||||
sdmmc->regs->blksize = req->blksize | 0x7000; // DMA 512KB (Detects A18 carry out).
|
||||
sdmmc->regs->blkcnt = blkcnt;
|
||||
|
||||
if (blkcnt_out)
|
||||
*blkcnt_out = blkcnt;
|
||||
|
||||
u32 trnmode = TEGRA_MMC_TRNMOD_DMA_ENABLE;
|
||||
u32 trnmode = SDHCI_TRNS_DMA;
|
||||
if (req->is_multi_block)
|
||||
trnmode = TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT |
|
||||
TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE |
|
||||
TEGRA_MMC_TRNMOD_DMA_ENABLE;
|
||||
trnmode = SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_DMA;
|
||||
if (!req->is_write)
|
||||
trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
|
||||
trnmode |= SDHCI_TRNS_READ;
|
||||
if (req->is_auto_cmd12)
|
||||
trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12;
|
||||
trnmode = (trnmode & ~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23)) | SDHCI_TRNS_AUTO_CMD12;
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
sdmmc->regs->trnmod = trnmode;
|
||||
|
||||
|
@ -850,15 +851,17 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc)
|
|||
{
|
||||
u16 intr = 0;
|
||||
res = _sdmmc_check_mask_interrupt(sdmmc, &intr,
|
||||
TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT);
|
||||
SDHCI_INT_DATA_END | SDHCI_INT_DMA_END);
|
||||
if (res < 0)
|
||||
break;
|
||||
if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
|
||||
|
||||
if (intr & SDHCI_INT_DATA_END)
|
||||
{
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
return 1; // Transfer complete.
|
||||
}
|
||||
if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
||||
|
||||
if (intr & SDHCI_INT_DMA_END)
|
||||
{
|
||||
// Update DMA.
|
||||
sdmmc->regs->admaaddr = sdmmc->dma_addr_next;
|
||||
|
@ -950,8 +953,8 @@ static int _sdmmc_config_sdmmc1()
|
|||
/*
|
||||
* Pinmux config:
|
||||
* DRV_TYPE = DRIVE_2X
|
||||
* E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V)
|
||||
* E_INPUT = ENABLE
|
||||
* E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V)
|
||||
* E_INPUT = ENABLE
|
||||
* TRISTATE = PASSTHROUGH
|
||||
* APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK
|
||||
*/
|
||||
|
@ -966,27 +969,24 @@ static int _sdmmc_config_sdmmc1()
|
|||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
|
||||
// Make sure the SDMMC1 controller is powered.
|
||||
PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12);
|
||||
PMC(APBDEV_PMC_NO_IOPOWER) &= ~(PMC_NO_IOPOWER_SDMMC1_IO_EN);
|
||||
// Assume 3.3V SD card voltage.
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN;
|
||||
|
||||
// Set enable SD card power.
|
||||
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //GPIO control, pull down.
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO);
|
||||
gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH);
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_ENABLE);
|
||||
|
||||
usleep(1000);
|
||||
|
||||
// Enable SD card power.
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000);
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 1);
|
||||
|
||||
usleep(1000);
|
||||
|
||||
// For good measure.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000;
|
||||
|
||||
usleep(1000);
|
||||
|
||||
return 1;
|
||||
|
@ -1025,7 +1025,9 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
|
|||
sdmmc->regs->veniotrimctl &= 0xFFFFFFFB;
|
||||
static const u32 trim_values[] = { 2, 8, 3, 8 };
|
||||
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24);
|
||||
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7;
|
||||
sdmmc->regs->sdmemcmppadctl =
|
||||
(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK) | 7;
|
||||
|
||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||
return 0;
|
||||
|
||||
|
@ -1091,10 +1093,10 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
|||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_voltage(sdmmc));
|
||||
|
||||
int should_disable_sd_clock = 0;
|
||||
if (!(sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE))
|
||||
if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))
|
||||
{
|
||||
should_disable_sd_clock = 1;
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
}
|
||||
|
@ -1103,7 +1105,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
|||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -1113,7 +1115,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||
if(sdmmc->id != SDMMC_1)
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(sdmmc, 8))
|
||||
if (!sdmmc_setup_clock(sdmmc, SDHCI_TIMING_UHS_SDR12))
|
||||
return 0;
|
||||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
@ -1127,7 +1129,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT;
|
||||
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(PMC_PWR_DET_SDMMC1_IO_EN);
|
||||
|
||||
_sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8);
|
||||
_sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8);
|
||||
|
@ -1137,7 +1139,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||
|
||||
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180)
|
||||
{
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1000);
|
||||
if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -49,24 +50,154 @@
|
|||
#define SDMMC_MASKINT_NOERROR -1
|
||||
#define SDMMC_MASKINT_ERROR -2
|
||||
|
||||
/*! SDMMC host control 2 */
|
||||
#define SDHCI_CTRL_UHS_MASK 0xFFF8
|
||||
#define SDHCI_CTRL_VDD_330 0xFFF7
|
||||
#define SDHCI_CTRL_VDD_180 8
|
||||
#define SDHCI_CTRL_EXEC_TUNING 0x40
|
||||
#define SDHCI_CTRL_TUNED_CLK 0x80
|
||||
#define SDHCI_HOST_VERSION_4_EN 0x1000
|
||||
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
|
||||
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000
|
||||
/*! SDMMC present state. */
|
||||
#define SDHCI_CMD_INHIBIT 0x1
|
||||
#define SDHCI_DATA_INHIBIT 0x2
|
||||
#define SDHCI_DOING_WRITE 0x100
|
||||
#define SDHCI_DOING_READ 0x200
|
||||
#define SDHCI_SPACE_AVAILABLE 0x400
|
||||
#define SDHCI_DATA_AVAILABLE 0x800
|
||||
#define SDHCI_CARD_PRESENT 0x10000
|
||||
#define SDHCI_CD_STABLE 0x20000
|
||||
#define SDHCI_CD_LVL 0x40000
|
||||
#define SDHCI_WRITE_PROTECT 0x80000
|
||||
#define SDHCI_DATA_LVL_MASK 0xF00000
|
||||
#define SDHCI_DATA_0_LVL_MASK 0x100000
|
||||
#define SDHCI_CMD_LVL 0x1000000
|
||||
|
||||
/*! SDMMC transfer mode. */
|
||||
#define SDHCI_TRNS_DMA 0x01
|
||||
#define SDHCI_TRNS_BLK_CNT_EN 0x02
|
||||
#define SDHCI_TRNS_AUTO_CMD12 0x04
|
||||
#define SDHCI_TRNS_AUTO_CMD23 0x08
|
||||
#define SDHCI_TRNS_AUTO_SEL 0x0C
|
||||
#define SDHCI_TRNS_WRITE 0x00
|
||||
#define SDHCI_TRNS_READ 0x10
|
||||
#define SDHCI_TRNS_MULTI 0x20
|
||||
|
||||
/*! SDMMC command. */
|
||||
#define SDHCI_CMD_RESP_MASK 0x3
|
||||
#define SDHCI_CMD_RESP_NO_RESP 0x0
|
||||
#define SDHCI_CMD_RESP_LEN136 0x1
|
||||
#define SDHCI_CMD_RESP_LEN48 0x2
|
||||
#define SDHCI_CMD_RESP_LEN48_BUSY 0x3
|
||||
#define SDHCI_CMD_CRC 0x08
|
||||
#define SDHCI_CMD_INDEX 0x10
|
||||
#define SDHCI_CMD_DATA 0x20
|
||||
#define SDHCI_CMD_ABORTCMD 0xC0
|
||||
|
||||
/*! SDMMC host control. */
|
||||
#define SDHCI_CTRL_LED 0x01
|
||||
#define SDHCI_CTRL_4BITBUS 0x02
|
||||
#define SDHCI_CTRL_HISPD 0x04
|
||||
#define SDHCI_CTRL_DMA_MASK 0x18
|
||||
#define SDHCI_CTRL_SDMA 0x00
|
||||
#define SDHCI_CTRL_ADMA1 0x08
|
||||
#define SDHCI_CTRL_ADMA32 0x10
|
||||
#define SDHCI_CTRL_ADMA64 0x18
|
||||
#define SDHCI_CTRL_8BITBUS 0x20
|
||||
#define SDHCI_CTRL_CDTEST_INS 0x40
|
||||
#define SDHCI_CTRL_CDTEST_EN 0x80
|
||||
|
||||
/*! SDMMC host control 2. */
|
||||
#define SDHCI_CTRL_UHS_MASK 0xFFF8
|
||||
#define SDHCI_CTRL_VDD_180 8
|
||||
#define SDHCI_CTRL_DRV_TYPE_B 0x00
|
||||
#define SDHCI_CTRL_DRV_TYPE_A 0x10
|
||||
#define SDHCI_CTRL_DRV_TYPE_C 0x20
|
||||
#define SDHCI_CTRL_DRV_TYPE_D 0x30
|
||||
#define SDHCI_CTRL_EXEC_TUNING 0x40
|
||||
#define SDHCI_CTRL_TUNED_CLK 0x80
|
||||
#define SDHCI_HOST_VERSION_4_EN 0x1000
|
||||
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
|
||||
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000
|
||||
|
||||
/*! SDMMC power control. */
|
||||
#define SDHCI_POWER_ON 0x01
|
||||
#define SDHCI_POWER_180 0x0A
|
||||
#define SDHCI_POWER_300 0x0C
|
||||
#define SDHCI_POWER_330 0x0E
|
||||
#define SDHCI_POWER_MASK 0xF1
|
||||
|
||||
// /*! SDMMC max current. */
|
||||
// #define SDHCI_MAX_CURRENT_330_MASK 0xFF
|
||||
// #define SDHCI_MAX_CURRENT_180_MASK 0xFF0000
|
||||
// #define SDHCI_MAX_CURRENT_MULTIPLIER 4
|
||||
|
||||
/*! SDMMC clock control. */
|
||||
#define SDHCI_DIVIDER_SHIFT 8
|
||||
#define SDHCI_DIVIDER_HI_SHIFT 6
|
||||
#define SDHCI_DIV_MASK 0xFF00
|
||||
#define SDHCI_DIV_HI_MASK 0xC0
|
||||
#define SDHCI_PROG_CLOCK_MODE 0x20
|
||||
#define SDHCI_CLOCK_CARD_EN 0x4
|
||||
#define SDHCI_CLOCK_INT_STABLE 0x2
|
||||
#define SDHCI_CLOCK_INT_EN 0x1
|
||||
|
||||
/*! SDMMC software reset. */
|
||||
#define SDHCI_RESET_ALL 0x01
|
||||
#define SDHCI_RESET_CMD 0x02
|
||||
#define SDHCI_RESET_DATA 0x04
|
||||
|
||||
/*! SDMMC interrupt status and control. */
|
||||
#define SDHCI_INT_RESPONSE 0x1
|
||||
#define SDHCI_INT_DATA_END 0x2
|
||||
#define SDHCI_INT_BLK_GAP 0x4
|
||||
#define SDHCI_INT_DMA_END 0x8
|
||||
#define SDHCI_INT_SPACE_AVAIL 0x10
|
||||
#define SDHCI_INT_DATA_AVAIL 0x20
|
||||
#define SDHCI_INT_CARD_INSERT 0x40
|
||||
#define SDHCI_INT_CARD_REMOVE 0x80
|
||||
#define SDHCI_INT_CARD_INT 0x100
|
||||
#define SDHCI_INT_RETUNE 0x1000
|
||||
#define SDHCI_INT_CQE 0x4000
|
||||
#define SDHCI_INT_ERROR 0x8000
|
||||
|
||||
/*! SDMMC error interrupt status and control. */
|
||||
#define SDHCI_ERR_INT_TIMEOUT 0x1
|
||||
#define SDHCI_ERR_INT_CRC 0x2
|
||||
#define SDHCI_ERR_INT_END_BIT 0x4
|
||||
#define SDHCI_ERR_INT_INDEX 0x8
|
||||
#define SDHCI_ERR_INT_DATA_TIMEOUT 0x10
|
||||
#define SDHCI_ERR_INT_DATA_CRC 0x20
|
||||
#define SDHCI_ERR_INT_DATA_END_BIT 0x40
|
||||
#define SDHCI_ERR_INT_BUS_POWER 0x80
|
||||
#define SDHCI_ERR_INT_AUTO_CMD_ERR 0x100
|
||||
#define SDHCI_ERR_INT_ADMA_ERROR 0x200
|
||||
|
||||
#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \
|
||||
(SDHCI_ERR_INT_AUTO_CMD_ERR | SDHCI_ERR_INT_DATA_END_BIT | \
|
||||
SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \
|
||||
SDHCI_ERR_INT_INDEX | SDHCI_ERR_INT_END_BIT | \
|
||||
SDHCI_ERR_INT_CRC | SDHCI_ERR_INT_TIMEOUT)
|
||||
|
||||
/*! SD bus speeds. */
|
||||
#define UHS_SDR12_BUS_SPEED 0
|
||||
#define HIGH_SPEED_BUS_SPEED 1
|
||||
#define UHS_SDR25_BUS_SPEED 1
|
||||
#define UHS_SDR50_BUS_SPEED 2
|
||||
#define UHS_SDR104_BUS_SPEED 3
|
||||
#define UHS_DDR50_BUS_SPEED 4
|
||||
#define HS400_BUS_SPEED 5
|
||||
#define UHS_SDR12_BUS_SPEED 0
|
||||
#define HIGH_SPEED_BUS_SPEED 1
|
||||
#define UHS_SDR25_BUS_SPEED 1
|
||||
#define UHS_SDR50_BUS_SPEED 2
|
||||
#define UHS_SDR104_BUS_SPEED 3
|
||||
#define UHS_DDR50_BUS_SPEED 4
|
||||
#define HS400_BUS_SPEED 5
|
||||
|
||||
/*! SDMMC timmings. */
|
||||
#define SDHCI_TIMING_MMC_ID 0
|
||||
#define SDHCI_TIMING_MMC_LS26 1
|
||||
#define SDHCI_TIMING_MMC_HS52 2
|
||||
#define SDHCI_TIMING_MMC_HS200 3
|
||||
#define SDHCI_TIMING_MMC_HS400 4
|
||||
#define SDHCI_TIMING_SD_ID 5
|
||||
#define SDHCI_TIMING_SD_DS12 6
|
||||
#define SDHCI_TIMING_SD_HS25 7
|
||||
#define SDHCI_TIMING_UHS_SDR12 8
|
||||
#define SDHCI_TIMING_UHS_SDR25 9
|
||||
#define SDHCI_TIMING_UHS_SDR50 10
|
||||
#define SDHCI_TIMING_UHS_SDR104 11
|
||||
#define SDHCI_TIMING_UHS_SDR82 12 // SDR104 with a 163.2MHz -> 81.6MHz clock.
|
||||
#define SDHCI_TIMING_UHS_DDR50 13
|
||||
#define SDHCI_TIMING_MMC_DDR52 14
|
||||
|
||||
#define SDHCI_CAN_64BIT 0x10000000
|
||||
|
||||
/*! Helper for SWITCH command argument. */
|
||||
#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -19,49 +20,14 @@
|
|||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_POWER 0x1
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 0xA
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0 0xC
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3 0xE
|
||||
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK 0xF1
|
||||
|
||||
#define TEGRA_MMC_HOSTCTL_1BIT 0x00
|
||||
#define TEGRA_MMC_HOSTCTL_4BIT 0x02
|
||||
#define TEGRA_MMC_HOSTCTL_8BIT 0x20
|
||||
|
||||
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE 0x1
|
||||
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE 0x2
|
||||
#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE 0x4
|
||||
#define TEGRA_MMC_CLKCON_CLKGEN_SELECT 0x20
|
||||
|
||||
#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL 0x1
|
||||
#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE 0x2
|
||||
#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE 0x4
|
||||
|
||||
#define TEGRA_MMC_TRNMOD_DMA_ENABLE 0x1
|
||||
#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE 0x2
|
||||
#define TEGRA_MMC_TRNMOD_AUTO_CMD12 0x4
|
||||
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE 0x0
|
||||
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ 0x10
|
||||
#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT 0x20
|
||||
|
||||
#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK 0x8
|
||||
#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK 0x10
|
||||
#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER 0x20
|
||||
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK 0x3
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE 0x0
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 0x1
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 0x2
|
||||
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY 0x3
|
||||
|
||||
#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE 0x1
|
||||
#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE 0x2
|
||||
#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT 0x8
|
||||
#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT 0x8000
|
||||
#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT 0x10000
|
||||
|
||||
#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY 0x20
|
||||
#define TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW 0x20000
|
||||
#define TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE 0x80000000
|
||||
#define TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE 0x80000000
|
||||
#define TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD 0x80000000
|
||||
#define TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK 0xFFFFFFF0
|
||||
#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE 0x20000000
|
||||
#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START 0x80000000
|
||||
#define TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE 0x80000000
|
||||
|
||||
typedef struct _t210_sdmmc_t
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue