sdmmc v2: Refactor everything
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user