sdmmc v2: Refactor everything

This commit is contained in:
CTCaer 2020-04-29 18:53:29 +03:00
parent 0462f3b252
commit 5b0a0070c7
24 changed files with 830 additions and 590 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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
{

View file

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

View file

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

View file

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

View file

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

View file

@ -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!#");

View file

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

View file

@ -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
{

View file

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

View file

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

View file

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

View file

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

View file

@ -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
{