fusee: Fix SDMMC high speed support and other bugs.

This commit is contained in:
hexkyz 2018-07-23 20:14:53 +01:00
parent eaa282b915
commit e58927a8ab
6 changed files with 84 additions and 97 deletions

View file

@ -487,7 +487,7 @@ static int sdmmc_sd_send_op_cond(sdmmc_device_t *device, bool is_sd_ver2, bool i
return 0;
/* Delay a bit before asking for the voltage switch. */
udelay(1000);
mdelay(100);
/* Tell the driver to switch the voltage. */
if (!sdmmc_switch_voltage(device->sdmmc))
@ -748,6 +748,7 @@ static int sdmmc_sd_switch_hs_low(sdmmc_device_t *device, uint8_t *status)
else
return 0;
/* Peek the SD card's status. */
return sdmmc_device_send_status(device);
}
@ -974,22 +975,22 @@ int sdmmc_device_sd_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth b
/* Switch to high-speed from low voltage (if possible). */
if (!sdmmc_sd_switch_hs_low(device, switch_status))
{
sdmmc_error(sdmmc, "Failed to switch to high-speed!");
sdmmc_error(sdmmc, "Failed to switch to high-speed from low voltage!");
return 0;
}
sdmmc_info(sdmmc, "Switched to high-speed!");
sdmmc_info(sdmmc, "Switched to high-speed from low voltage!");
}
else if ((device->scr.sda_vsn & (SD_SCR_SPEC_VER_1 | SD_SCR_SPEC_VER_2)) && ((bus_speed != SDMMC_SPEED_UNK6)))
{
/* Switch to high-speed from high voltage (if possible). */
if (!sdmmc_sd_switch_hs_high(device, switch_status))
{
sdmmc_error(sdmmc, "Failed to switch to high-speed!");
sdmmc_error(sdmmc, "Failed to switch to high-speed from high voltage!");
return 0;
}
sdmmc_info(sdmmc, "Switched to high-speed!");
sdmmc_info(sdmmc, "Switched to high-speed from high voltage!");
}
/* Correct any inconsistent states. */
@ -1373,7 +1374,7 @@ int sdmmc_device_mmc_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth
{
uint32_t cid[4] = {0};
uint32_t csd[4] = {0};
uint8_t *ext_csd = (uint8_t *)SDMMC_BOUNCE_BUFFER_ADDRESS; // TODO: Better way to do this.
uint8_t ext_csd[512] = {0};
/* Initialize our device's struct. */
memset(device, 0, sizeof(sdmmc_device_t));

View file

@ -549,28 +549,26 @@ static int sdmmc_autocal_config(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
case SDMMC_3:
switch (voltage) {
case SDMMC_VOLTAGE_1V8:
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_PDPU_CONFIG_MASK;
sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_PDPU_CONFIG_MASK);
sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC1_1V8;
break;
case SDMMC_VOLTAGE_3V3:
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_PDPU_CONFIG_MASK;
sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_PDPU_CONFIG_MASK);
sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC1_3V3;
break;
default:
sdmmc_error(sdmmc, "microsd does not support voltage %d", voltage);
sdmmc_error(sdmmc, "uSD does not support requested voltage!");
return 0;
}
break;
case SDMMC_2:
case SDMMC_4:
if (voltage != SDMMC_VOLTAGE_1V8) {
sdmmc_error(sdmmc, "eMMC can only run at 1V8, but sdmmc struct claims voltage %d", voltage);
sdmmc_error(sdmmc, "eMMC can only run at 1V8!");
return 0;
}
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_PDPU_CONFIG_MASK;
sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_PDPU_CONFIG_MASK);
sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC4_1V8;
break;
}
@ -581,8 +579,8 @@ static int sdmmc_autocal_config(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
/* Run automatic calibration. */
static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
{
bool restart_sd_clock = false;
volatile tegra_padctl_t *padctl = padctl_get_regs();
bool restart_sd_clock = false;
/* SD clock is enabled. Disable it and restart later. */
if (sdmmc->is_sd_clk_enabled)
@ -619,7 +617,7 @@ static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
while ((sdmmc->regs->auto_cal_status & SDMMC_AUTOCAL_ACTIVE)) {
/* Ensure we haven't timed out. */
if (get_time_since(timebase) > SDMMC_AUTOCAL_TIMEOUT) {
sdmmc_error(sdmmc, "autocal timed out!");
sdmmc_error(sdmmc, "Auto-calibration timed out!");
/* Force a register read to refresh the clock control value. */
sdmmc_get_sd_clock_control(sdmmc);
@ -642,7 +640,7 @@ static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
}
/* Manually clear the autocal enable bit. */
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_ENABLE;
sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_ENABLE);
break;
}
}
@ -696,16 +694,9 @@ static int sdmmc_int_clk_enable(sdmmc_t *sdmmc)
/* Use SDMA by default. */
sdmmc->regs->host_control &= ~SDHCI_CTRL_DMA_MASK;
/* Change to ADMA if requested. */
if (sdmmc->use_adma && (sdmmc->regs->capabilities & SDHCI_CAN_DO_ADMA2)) {
// TODO: Setting the ADMA flags breaks ADMA...
/*
if (sdmmc->regs->capabilities & SDHCI_CAN_64BIT)
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA64;
else
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA32;
*/
}
/* Change to ADMA if possible. */
if (sdmmc->regs->capabilities & SDHCI_CAN_DO_ADMA2)
sdmmc->use_adma = true;
/* Set the timeout to be the maximum value. */
sdmmc->regs->timeout_control &= 0xF0;
@ -847,9 +838,9 @@ static int sdmmc_dllcal_run(sdmmc_t *sdmmc)
is_timeout = (get_time_since(timebase) > 10000);
}
/* Clock failed to stabilize. */
/* Calibration failed. */
if (is_timeout) {
sdmmc_error(sdmmc, "ERROR: DLLCAL failed!");
sdmmc_error(sdmmc, "DLLCAL failed!");
return 0;
}
@ -898,20 +889,23 @@ int sdmmc_select_speed(sdmmc_t *sdmmc, SdmmcBusSpeed bus_speed)
case SDMMC_SPEED_DDR50:
case SDMMC_SPEED_SDR50:
case SDMMC_SPEED_UNK14:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK;
sdmmc->regs->host_control2 |= (SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180);
sdmmc->regs->host_control2 &= ~(SDHCI_CTRL_UHS_MASK);
sdmmc->regs->host_control2 |= SDHCI_CTRL_UHS_SDR104;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break;
/* 200MHz single-data rate (MMC). */
case SDMMC_SPEED_HS400:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK;
sdmmc->regs->host_control2 |= (SDHCI_CTRL_HS400 | SDHCI_CTRL_VDD_180);
sdmmc->regs->host_control2 &= ~(SDHCI_CTRL_UHS_MASK);
sdmmc->regs->host_control2 |= SDHCI_CTRL_HS400;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break;
/* 25MHz default speed (SD). */
case SDMMC_SPEED_SDR12:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK;
sdmmc->regs->host_control2 |= (SDHCI_CTRL_UHS_SDR12 | SDHCI_CTRL_VDD_180);
sdmmc->regs->host_control2 &= ~(SDHCI_CTRL_UHS_MASK);
sdmmc->regs->host_control2 |= SDHCI_CTRL_UHS_SDR12;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break;
default:
@ -1093,7 +1087,7 @@ static int sdmmc_init_controller(sdmmc_t *sdmmc, SdmmcControllerNum controller)
sdmmc->is_clk_running = false;
sdmmc->is_sd_clk_enabled = false;
sdmmc->is_tuning_tap_val_set = false;
sdmmc->use_adma = true;
sdmmc->use_adma = false;
sdmmc->dma_bounce_buf = (uint8_t*)SDMMC_BOUNCE_BUFFER_ADDRESS;
sdmmc->tap_val = 0;
sdmmc->internal_divider = 0;
@ -1749,7 +1743,7 @@ int sdmmc_switch_voltage(sdmmc_t *sdmmc)
sdmmc_get_sd_clock_control(sdmmc);
/* Wait a while. */
udelay(5000);
mdelay(5);
/* Host control 2 flag should be set by now. */
if (sdmmc->regs->host_control2 & SDHCI_CTRL_VDD_180)
@ -1761,7 +1755,7 @@ int sdmmc_switch_voltage(sdmmc_t *sdmmc)
sdmmc_get_sd_clock_control(sdmmc);
/* Wait a while. */
udelay(1000);
mdelay(1);
/* Data level is up. Voltage switching is done.*/
if (sdmmc->regs->present_state & SDHCI_DATA_LVL_MASK)

View file

@ -106,7 +106,7 @@ typedef struct {
uint16_t slot_int_status;
uint16_t host_version;
/* vendor specific registers */
/* Vendor specific registers */
uint32_t vendor_clock_cntrl;
uint32_t vendor_sys_sw_cntrl;
uint32_t vendor_err_intr_status;
@ -121,12 +121,12 @@ typedef struct {
uint32_t _0x12c[0x20];
uint32_t vendor_io_trim_cntrl;
/* start of sdmmc2/sdmmc4 only */
/* Start of sdmmc2/sdmmc4 only */
uint32_t vendor_dllcal_cfg;
uint32_t vendor_dll_ctrl0;
uint32_t vendor_dll_ctrl1;
uint32_t vendor_dllcal_cfg_sta;
/* end of sdmmc2/sdmmc4 only */
/* End of sdmmc2/sdmmc4 only */
uint32_t vendor_tuning_cntrl0;
uint32_t vendor_tuning_cntrl1;

View file

@ -487,7 +487,7 @@ static int sdmmc_sd_send_op_cond(sdmmc_device_t *device, bool is_sd_ver2, bool i
return 0;
/* Delay a bit before asking for the voltage switch. */
udelay(1000);
mdelay(100);
/* Tell the driver to switch the voltage. */
if (!sdmmc_switch_voltage(device->sdmmc))
@ -748,6 +748,7 @@ static int sdmmc_sd_switch_hs_low(sdmmc_device_t *device, uint8_t *status)
else
return 0;
/* Peek the SD card's status. */
return sdmmc_device_send_status(device);
}
@ -974,22 +975,22 @@ int sdmmc_device_sd_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth b
/* Switch to high-speed from low voltage (if possible). */
if (!sdmmc_sd_switch_hs_low(device, switch_status))
{
sdmmc_error(sdmmc, "Failed to switch to high-speed!");
sdmmc_error(sdmmc, "Failed to switch to high-speed from low voltage!");
return 0;
}
sdmmc_info(sdmmc, "Switched to high-speed!");
sdmmc_info(sdmmc, "Switched to high-speed from low voltage!");
}
else if ((device->scr.sda_vsn & (SD_SCR_SPEC_VER_1 | SD_SCR_SPEC_VER_2)) && ((bus_speed != SDMMC_SPEED_UNK6)))
{
/* Switch to high-speed from high voltage (if possible). */
if (!sdmmc_sd_switch_hs_high(device, switch_status))
{
sdmmc_error(sdmmc, "Failed to switch to high-speed!");
sdmmc_error(sdmmc, "Failed to switch to high-speed from high voltage!");
return 0;
}
sdmmc_info(sdmmc, "Switched to high-speed!");
sdmmc_info(sdmmc, "Switched to high-speed from high voltage!");
}
/* Correct any inconsistent states. */
@ -1322,9 +1323,6 @@ static int sdmmc_mmc_select_hs400(sdmmc_device_t *device)
static int sdmmc_mmc_select_timing(sdmmc_device_t *device, SdmmcBusSpeed bus_speed)
{
// FIXME: Tuning is broken. Use HS52 for now.
return sdmmc_mmc_select_hs(device, false);
if ((bus_speed == SDMMC_SPEED_HS400) &&
(device->sdmmc->bus_width == SDMMC_BUS_WIDTH_8BIT) &&
(device->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
@ -1376,7 +1374,7 @@ int sdmmc_device_mmc_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth
{
uint32_t cid[4] = {0};
uint32_t csd[4] = {0};
uint8_t *ext_csd = (uint8_t *)SDMMC_BOUNCE_BUFFER_ADDRESS; // TODO: Better way to do this.
uint8_t ext_csd[512] = {0};
/* Initialize our device's struct. */
memset(device, 0, sizeof(sdmmc_device_t));

View file

@ -549,28 +549,26 @@ static int sdmmc_autocal_config(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
case SDMMC_3:
switch (voltage) {
case SDMMC_VOLTAGE_1V8:
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_PDPU_CONFIG_MASK;
sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_PDPU_CONFIG_MASK);
sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC1_1V8;
break;
case SDMMC_VOLTAGE_3V3:
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_PDPU_CONFIG_MASK;
sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_PDPU_CONFIG_MASK);
sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC1_3V3;
break;
default:
sdmmc_error(sdmmc, "microsd does not support voltage %d", voltage);
sdmmc_error(sdmmc, "uSD does not support requested voltage!");
return 0;
}
break;
case SDMMC_2:
case SDMMC_4:
if (voltage != SDMMC_VOLTAGE_1V8) {
sdmmc_error(sdmmc, "eMMC can only run at 1V8, but sdmmc struct claims voltage %d", voltage);
sdmmc_error(sdmmc, "eMMC can only run at 1V8!");
return 0;
}
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_PDPU_CONFIG_MASK;
sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_PDPU_CONFIG_MASK);
sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC4_1V8;
break;
}
@ -581,8 +579,8 @@ static int sdmmc_autocal_config(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
/* Run automatic calibration. */
static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
{
bool restart_sd_clock = false;
volatile tegra_padctl_t *padctl = padctl_get_regs();
bool restart_sd_clock = false;
/* SD clock is enabled. Disable it and restart later. */
if (sdmmc->is_sd_clk_enabled)
@ -619,7 +617,7 @@ static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
while ((sdmmc->regs->auto_cal_status & SDMMC_AUTOCAL_ACTIVE)) {
/* Ensure we haven't timed out. */
if (get_time_since(timebase) > SDMMC_AUTOCAL_TIMEOUT) {
sdmmc_error(sdmmc, "autocal timed out!");
sdmmc_error(sdmmc, "Auto-calibration timed out!");
/* Force a register read to refresh the clock control value. */
sdmmc_get_sd_clock_control(sdmmc);
@ -642,7 +640,7 @@ static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
}
/* Manually clear the autocal enable bit. */
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_ENABLE;
sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_ENABLE);
break;
}
}
@ -696,16 +694,9 @@ static int sdmmc_int_clk_enable(sdmmc_t *sdmmc)
/* Use SDMA by default. */
sdmmc->regs->host_control &= ~SDHCI_CTRL_DMA_MASK;
/* Change to ADMA if requested. */
if (sdmmc->use_adma && (sdmmc->regs->capabilities & SDHCI_CAN_DO_ADMA2)) {
// TODO: Setting the ADMA flags breaks ADMA...
/*
if (sdmmc->regs->capabilities & SDHCI_CAN_64BIT)
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA64;
else
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA32;
*/
}
/* Change to ADMA if possible. */
if (sdmmc->regs->capabilities & SDHCI_CAN_DO_ADMA2)
sdmmc->use_adma = true;
/* Set the timeout to be the maximum value. */
sdmmc->regs->timeout_control &= 0xF0;
@ -847,9 +838,9 @@ static int sdmmc_dllcal_run(sdmmc_t *sdmmc)
is_timeout = (get_time_since(timebase) > 10000);
}
/* Clock failed to stabilize. */
/* Calibration failed. */
if (is_timeout) {
sdmmc_error(sdmmc, "ERROR: DLLCAL failed!");
sdmmc_error(sdmmc, "DLLCAL failed!");
return 0;
}
@ -898,20 +889,23 @@ int sdmmc_select_speed(sdmmc_t *sdmmc, SdmmcBusSpeed bus_speed)
case SDMMC_SPEED_DDR50:
case SDMMC_SPEED_SDR50:
case SDMMC_SPEED_UNK14:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK;
sdmmc->regs->host_control2 |= (SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180);
sdmmc->regs->host_control2 &= ~(SDHCI_CTRL_UHS_MASK);
sdmmc->regs->host_control2 |= SDHCI_CTRL_UHS_SDR104;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break;
/* 200MHz single-data rate (MMC). */
case SDMMC_SPEED_HS400:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK;
sdmmc->regs->host_control2 |= (SDHCI_CTRL_HS400 | SDHCI_CTRL_VDD_180);
sdmmc->regs->host_control2 &= ~(SDHCI_CTRL_UHS_MASK);
sdmmc->regs->host_control2 |= SDHCI_CTRL_HS400;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break;
/* 25MHz default speed (SD). */
case SDMMC_SPEED_SDR12:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK;
sdmmc->regs->host_control2 |= (SDHCI_CTRL_UHS_SDR12 | SDHCI_CTRL_VDD_180);
sdmmc->regs->host_control2 &= ~(SDHCI_CTRL_UHS_MASK);
sdmmc->regs->host_control2 |= SDHCI_CTRL_UHS_SDR12;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break;
default:
@ -1093,7 +1087,7 @@ static int sdmmc_init_controller(sdmmc_t *sdmmc, SdmmcControllerNum controller)
sdmmc->is_clk_running = false;
sdmmc->is_sd_clk_enabled = false;
sdmmc->is_tuning_tap_val_set = false;
sdmmc->use_adma = true;
sdmmc->use_adma = false;
sdmmc->dma_bounce_buf = (uint8_t*)SDMMC_BOUNCE_BUFFER_ADDRESS;
sdmmc->tap_val = 0;
sdmmc->internal_divider = 0;
@ -1749,7 +1743,7 @@ int sdmmc_switch_voltage(sdmmc_t *sdmmc)
sdmmc_get_sd_clock_control(sdmmc);
/* Wait a while. */
udelay(5000);
mdelay(5);
/* Host control 2 flag should be set by now. */
if (sdmmc->regs->host_control2 & SDHCI_CTRL_VDD_180)
@ -1761,7 +1755,7 @@ int sdmmc_switch_voltage(sdmmc_t *sdmmc)
sdmmc_get_sd_clock_control(sdmmc);
/* Wait a while. */
udelay(1000);
mdelay(1);
/* Data level is up. Voltage switching is done.*/
if (sdmmc->regs->present_state & SDHCI_DATA_LVL_MASK)

View file

@ -106,7 +106,7 @@ typedef struct {
uint16_t slot_int_status;
uint16_t host_version;
/* vendor specific registers */
/* Vendor specific registers */
uint32_t vendor_clock_cntrl;
uint32_t vendor_sys_sw_cntrl;
uint32_t vendor_err_intr_status;
@ -121,12 +121,12 @@ typedef struct {
uint32_t _0x12c[0x20];
uint32_t vendor_io_trim_cntrl;
/* start of sdmmc2/sdmmc4 only */
/* Start of sdmmc2/sdmmc4 only */
uint32_t vendor_dllcal_cfg;
uint32_t vendor_dll_ctrl0;
uint32_t vendor_dll_ctrl1;
uint32_t vendor_dllcal_cfg_sta;
/* end of sdmmc2/sdmmc4 only */
/* End of sdmmc2/sdmmc4 only */
uint32_t vendor_tuning_cntrl0;
uint32_t vendor_tuning_cntrl1;