Merge pull request #126 from desowin/sdmmc-autocal

Make sdmmc autocalibration follow TRM procedure
This commit is contained in:
TuxSH 2018-06-06 18:09:00 +02:00 committed by GitHub
commit f5163fa35d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 14 deletions

View file

@ -11,4 +11,14 @@
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xa98) #define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xa98)
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xab4) #define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xab4)
#define SDMMC1_PAD_CAL_DRVUP_SHIFT (20)
#define SDMMC1_PAD_CAL_DRVDN_SHIFT (12)
#define SDMMC1_PAD_CAL_DRVUP_MASK (0x7Fu << SDMMC1_PAD_CAL_DRVUP_SHIFT)
#define SDMMC1_PAD_CAL_DRVDN_MASK (0x7Fu << SDMMC1_PAD_CAL_DRVDN_SHIFT)
#define CFG2TMC_EMMC4_PAD_DRVUP_COMP_SHIFT (8)
#define CFG2TMC_EMMC4_PAD_DRVDN_COMP_SHIFT (2)
#define CFG2TMC_EMMC4_PAD_DRVUP_COMP_MASK (0x3Fu << CFG2TMC_EMMC4_PAD_DRVUP_COMP_SHIFT)
#define CFG2TMC_EMMC4_PAD_DRVDN_COMP_MASK (0x3Fu << CFG2TMC_EMMC4_PAD_DRVDN_COMP_SHIFT)
#endif #endif

View file

@ -17,6 +17,7 @@
#include "supplies.h" #include "supplies.h"
#include "pmc.h" #include "pmc.h"
#include "pad_control.h" #include "pad_control.h"
#include "apb_misc.h"
#define TEGRA_SDMMC_BASE (0x700B0000) #define TEGRA_SDMMC_BASE (0x700B0000)
#define TEGRA_SDMMC_SIZE (0x200) #define TEGRA_SDMMC_SIZE (0x200)
@ -462,11 +463,12 @@ enum sdmmc_command_magic {
/* Misc constants */ /* Misc constants */
MMC_DEFAULT_BLOCK_ORDER = 9, MMC_DEFAULT_BLOCK_ORDER = 9,
MMC_VOLTAGE_SWITCH_TIME = 5000, // 5mS MMC_VOLTAGE_SWITCH_TIME = 5000, // 5ms
MMC_POST_CLOCK_DELAY = 1000, // 1mS MMC_POST_CLOCK_DELAY = 1000, // 1ms
MMC_SPEED_MMC_OFFSET = 10, MMC_SPEED_MMC_OFFSET = 10,
MMC_TUNING_TIMEOUT = 150 * 1000, // 150mS MMC_AUTOCAL_TIMEOUT = 10 * 1000, // 10ms
MMC_TUNING_TIMEOUT = 150 * 1000, // 150ms
MMC_TUNING_BLOCK_ORDER_4BIT = 6, MMC_TUNING_BLOCK_ORDER_4BIT = 6,
MMC_TUNING_BLOCK_ORDER_8BIT = 7, MMC_TUNING_BLOCK_ORDER_8BIT = 7,
}; };
@ -975,6 +977,7 @@ void sdmmc_clock_enable(struct mmc *mmc, bool enabled)
static int sdmmc_run_autocal(struct mmc *mmc, bool restart_sd_clock) static int sdmmc_run_autocal(struct mmc *mmc, bool restart_sd_clock)
{ {
uint32_t timebase; uint32_t timebase;
int ret = 0;
// Stop the SD card's clock, so our autocal sequence doesn't // Stop the SD card's clock, so our autocal sequence doesn't
// confuse the target card. // confuse the target card.
@ -982,16 +985,34 @@ static int sdmmc_run_autocal(struct mmc *mmc, bool restart_sd_clock)
// Start automatic calibration... // Start automatic calibration...
mmc->regs->auto_cal_config |= (MMC_AUTOCAL_START | MMC_AUTOCAL_ENABLE); mmc->regs->auto_cal_config |= (MMC_AUTOCAL_START | MMC_AUTOCAL_ENABLE);
udelay(1000); udelay(1);
// ... and wait until the autocal is complete // ... and wait until the autocal is complete
timebase = get_time(); timebase = get_time();
while ((mmc->regs->auto_cal_status & MMC_AUTOCAL_ACTIVE)) { while ((mmc->regs->auto_cal_status & MMC_AUTOCAL_ACTIVE)) {
// Ensure we haven't timed out... // Ensure we haven't timed out...
if (get_time_since(timebase) > mmc->timeout) { if (get_time_since(timebase) > MMC_AUTOCAL_TIMEOUT) {
mmc_print(mmc, "ERROR: autocal timed out!"); mmc_print(mmc, "ERROR: autocal timed out!");
return ETIMEDOUT; if (mmc->controller == SWITCH_MICROSD) {
// Fallback driver strengths from Tegra X1 TRM
uint32_t drvup = (mmc->operating_voltage == MMC_VOLTAGE_3V3) ? 0x12 : 0x11;
uint32_t drvdn = (mmc->operating_voltage == MMC_VOLTAGE_3V3) ? 0x12 : 0x15;
uint32_t value = APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL_0;
value &= ~(SDMMC1_PAD_CAL_DRVUP_MASK | SDMMC1_PAD_CAL_DRVDN_MASK);
value |= (drvup << SDMMC1_PAD_CAL_DRVUP_SHIFT);
value |= (drvdn << SDMMC1_PAD_CAL_DRVDN_SHIFT);
APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL_0 = value;
} else if (mmc->controller == SWITCH_EMMC) {
uint32_t value = APB_MISC_GP_EMMC4_PAD_CFGPADCTRL_0;
value &= ~(CFG2TMC_EMMC4_PAD_DRVUP_COMP_MASK | CFG2TMC_EMMC4_PAD_DRVDN_COMP_MASK);
value |= (0x10 << CFG2TMC_EMMC4_PAD_DRVUP_COMP_SHIFT);
value |= (0x10 << CFG2TMC_EMMC4_PAD_DRVDN_COMP_SHIFT);
APB_MISC_GP_EMMC4_PAD_CFGPADCTRL_0 = value;
}
mmc->regs->auto_cal_config &= ~MMC_AUTOCAL_ENABLE;
ret = ETIMEDOUT;
break;
} }
} }
@ -999,7 +1020,7 @@ static int sdmmc_run_autocal(struct mmc *mmc, bool restart_sd_clock)
if (restart_sd_clock) if (restart_sd_clock)
sdmmc_clock_enable(mmc, true); sdmmc_clock_enable(mmc, true);
return 0; return ret;
} }

View file

@ -11,4 +11,14 @@
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xa98) #define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xa98)
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xab4) #define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xab4)
#define SDMMC1_PAD_CAL_DRVUP_SHIFT (20)
#define SDMMC1_PAD_CAL_DRVDN_SHIFT (12)
#define SDMMC1_PAD_CAL_DRVUP_MASK (0x7Fu << SDMMC1_PAD_CAL_DRVUP_SHIFT)
#define SDMMC1_PAD_CAL_DRVDN_MASK (0x7Fu << SDMMC1_PAD_CAL_DRVDN_SHIFT)
#define CFG2TMC_EMMC4_PAD_DRVUP_COMP_SHIFT (8)
#define CFG2TMC_EMMC4_PAD_DRVDN_COMP_SHIFT (2)
#define CFG2TMC_EMMC4_PAD_DRVUP_COMP_MASK (0x3Fu << CFG2TMC_EMMC4_PAD_DRVUP_COMP_SHIFT)
#define CFG2TMC_EMMC4_PAD_DRVDN_COMP_MASK (0x3Fu << CFG2TMC_EMMC4_PAD_DRVDN_COMP_SHIFT)
#endif #endif

View file

@ -17,6 +17,7 @@
#include "supplies.h" #include "supplies.h"
#include "pmc.h" #include "pmc.h"
#include "pad_control.h" #include "pad_control.h"
#include "apb_misc.h"
#define TEGRA_SDMMC_BASE (0x700B0000) #define TEGRA_SDMMC_BASE (0x700B0000)
#define TEGRA_SDMMC_SIZE (0x200) #define TEGRA_SDMMC_SIZE (0x200)
@ -462,11 +463,12 @@ enum sdmmc_command_magic {
/* Misc constants */ /* Misc constants */
MMC_DEFAULT_BLOCK_ORDER = 9, MMC_DEFAULT_BLOCK_ORDER = 9,
MMC_VOLTAGE_SWITCH_TIME = 5000, // 5mS MMC_VOLTAGE_SWITCH_TIME = 5000, // 5ms
MMC_POST_CLOCK_DELAY = 1000, // 1mS MMC_POST_CLOCK_DELAY = 1000, // 1ms
MMC_SPEED_MMC_OFFSET = 10, MMC_SPEED_MMC_OFFSET = 10,
MMC_TUNING_TIMEOUT = 150 * 1000, // 150mS MMC_AUTOCAL_TIMEOUT = 10 * 1000, // 10ms
MMC_TUNING_TIMEOUT = 150 * 1000, // 150ms
MMC_TUNING_BLOCK_ORDER_4BIT = 6, MMC_TUNING_BLOCK_ORDER_4BIT = 6,
MMC_TUNING_BLOCK_ORDER_8BIT = 7, MMC_TUNING_BLOCK_ORDER_8BIT = 7,
}; };
@ -975,6 +977,7 @@ void sdmmc_clock_enable(struct mmc *mmc, bool enabled)
static int sdmmc_run_autocal(struct mmc *mmc, bool restart_sd_clock) static int sdmmc_run_autocal(struct mmc *mmc, bool restart_sd_clock)
{ {
uint32_t timebase; uint32_t timebase;
int ret = 0;
// Stop the SD card's clock, so our autocal sequence doesn't // Stop the SD card's clock, so our autocal sequence doesn't
// confuse the target card. // confuse the target card.
@ -982,16 +985,34 @@ static int sdmmc_run_autocal(struct mmc *mmc, bool restart_sd_clock)
// Start automatic calibration... // Start automatic calibration...
mmc->regs->auto_cal_config |= (MMC_AUTOCAL_START | MMC_AUTOCAL_ENABLE); mmc->regs->auto_cal_config |= (MMC_AUTOCAL_START | MMC_AUTOCAL_ENABLE);
udelay(1000); udelay(1);
// ... and wait until the autocal is complete // ... and wait until the autocal is complete
timebase = get_time(); timebase = get_time();
while ((mmc->regs->auto_cal_status & MMC_AUTOCAL_ACTIVE)) { while ((mmc->regs->auto_cal_status & MMC_AUTOCAL_ACTIVE)) {
// Ensure we haven't timed out... // Ensure we haven't timed out...
if (get_time_since(timebase) > mmc->timeout) { if (get_time_since(timebase) > MMC_AUTOCAL_TIMEOUT) {
mmc_print(mmc, "ERROR: autocal timed out!"); mmc_print(mmc, "ERROR: autocal timed out!");
return ETIMEDOUT; if (mmc->controller == SWITCH_MICROSD) {
// Fallback driver strengths from Tegra X1 TRM
uint32_t drvup = (mmc->operating_voltage == MMC_VOLTAGE_3V3) ? 0x12 : 0x11;
uint32_t drvdn = (mmc->operating_voltage == MMC_VOLTAGE_3V3) ? 0x12 : 0x15;
uint32_t value = APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL_0;
value &= ~(SDMMC1_PAD_CAL_DRVUP_MASK | SDMMC1_PAD_CAL_DRVDN_MASK);
value |= (drvup << SDMMC1_PAD_CAL_DRVUP_SHIFT);
value |= (drvdn << SDMMC1_PAD_CAL_DRVDN_SHIFT);
APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL_0 = value;
} else if (mmc->controller == SWITCH_EMMC) {
uint32_t value = APB_MISC_GP_EMMC4_PAD_CFGPADCTRL_0;
value &= ~(CFG2TMC_EMMC4_PAD_DRVUP_COMP_MASK | CFG2TMC_EMMC4_PAD_DRVDN_COMP_MASK);
value |= (0x10 << CFG2TMC_EMMC4_PAD_DRVUP_COMP_SHIFT);
value |= (0x10 << CFG2TMC_EMMC4_PAD_DRVDN_COMP_SHIFT);
APB_MISC_GP_EMMC4_PAD_CFGPADCTRL_0 = value;
}
mmc->regs->auto_cal_config &= ~MMC_AUTOCAL_ENABLE;
ret = ETIMEDOUT;
break;
} }
} }
@ -999,7 +1020,7 @@ static int sdmmc_run_autocal(struct mmc *mmc, bool restart_sd_clock)
if (restart_sd_clock) if (restart_sd_clock)
sdmmc_clock_enable(mmc, true); sdmmc_clock_enable(mmc, true);
return 0; return ret;
} }