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

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