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,12 +487,12 @@ static int sdmmc_sd_send_op_cond(sdmmc_device_t *device, bool is_sd_ver2, bool i
return 0; return 0;
/* Delay a bit before asking for the voltage switch. */ /* Delay a bit before asking for the voltage switch. */
udelay(1000); mdelay(100);
/* Tell the driver to switch the voltage. */ /* Tell the driver to switch the voltage. */
if (!sdmmc_switch_voltage(device->sdmmc)) if (!sdmmc_switch_voltage(device->sdmmc))
return 0; return 0;
/* We are now running at 1.8V. */ /* We are now running at 1.8V. */
device->is_180v = true; device->is_180v = true;
} }
@ -693,15 +693,15 @@ static int sdmmc_sd_switch_hs_low(sdmmc_device_t *device, uint8_t *status)
/* Adjust the current limit. */ /* Adjust the current limit. */
if (!sdmmc_sd_set_current_limit(device, status)) if (!sdmmc_sd_set_current_limit(device, status))
return 0; return 0;
/* Invalid bus width. */ /* Invalid bus width. */
if (device->sdmmc->bus_width != SDMMC_BUS_WIDTH_4BIT) if (device->sdmmc->bus_width != SDMMC_BUS_WIDTH_4BIT)
return 0; return 0;
/* Get the supported high-speed type. */ /* Get the supported high-speed type. */
if (!sdmmc_sd_switch(device, 0, 0, 0xF, status)) if (!sdmmc_sd_switch(device, 0, 0, 0xF, status))
return 0; return 0;
/* High-speed SDR104 is supported. */ /* High-speed SDR104 is supported. */
if (status[13] & SD_MODE_UHS_SDR104) if (status[13] & SD_MODE_UHS_SDR104)
{ {
@ -748,6 +748,7 @@ static int sdmmc_sd_switch_hs_low(sdmmc_device_t *device, uint8_t *status)
else else
return 0; return 0;
/* Peek the SD card's status. */ /* Peek the SD card's status. */
return sdmmc_device_send_status(device); 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). */ /* Switch to high-speed from low voltage (if possible). */
if (!sdmmc_sd_switch_hs_low(device, switch_status)) 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; 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))) 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). */ /* Switch to high-speed from high voltage (if possible). */
if (!sdmmc_sd_switch_hs_high(device, switch_status)) 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; return 0;
} }
sdmmc_info(sdmmc, "Switched to high-speed!"); sdmmc_info(sdmmc, "Switched to high-speed from high voltage!");
} }
/* Correct any inconsistent states. */ /* 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 cid[4] = {0};
uint32_t csd[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. */ /* Initialize our device's struct. */
memset(device, 0, sizeof(sdmmc_device_t)); 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: case SDMMC_3:
switch (voltage) { switch (voltage) {
case SDMMC_VOLTAGE_1V8: 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; sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC1_1V8;
break; break;
case SDMMC_VOLTAGE_3V3: 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; sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC1_3V3;
break; break;
default: default:
sdmmc_error(sdmmc, "microsd does not support voltage %d", voltage); sdmmc_error(sdmmc, "uSD does not support requested voltage!");
return 0; return 0;
} }
break; break;
case SDMMC_2: case SDMMC_2:
case SDMMC_4: case SDMMC_4:
if (voltage != SDMMC_VOLTAGE_1V8) { 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; 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; sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC4_1V8;
break; break;
} }
@ -581,8 +579,8 @@ static int sdmmc_autocal_config(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
/* Run automatic calibration. */ /* Run automatic calibration. */
static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage) static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
{ {
bool restart_sd_clock = false;
volatile tegra_padctl_t *padctl = padctl_get_regs(); volatile tegra_padctl_t *padctl = padctl_get_regs();
bool restart_sd_clock = false;
/* SD clock is enabled. Disable it and restart later. */ /* SD clock is enabled. Disable it and restart later. */
if (sdmmc->is_sd_clk_enabled) 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)) { while ((sdmmc->regs->auto_cal_status & SDMMC_AUTOCAL_ACTIVE)) {
/* Ensure we haven't timed out. */ /* Ensure we haven't timed out. */
if (get_time_since(timebase) > SDMMC_AUTOCAL_TIMEOUT) { 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. */ /* Force a register read to refresh the clock control value. */
sdmmc_get_sd_clock_control(sdmmc); 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. */ /* Manually clear the autocal enable bit. */
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_ENABLE; sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_ENABLE);
break; break;
} }
} }
@ -696,16 +694,9 @@ static int sdmmc_int_clk_enable(sdmmc_t *sdmmc)
/* Use SDMA by default. */ /* Use SDMA by default. */
sdmmc->regs->host_control &= ~SDHCI_CTRL_DMA_MASK; sdmmc->regs->host_control &= ~SDHCI_CTRL_DMA_MASK;
/* Change to ADMA if requested. */ /* Change to ADMA if possible. */
if (sdmmc->use_adma && (sdmmc->regs->capabilities & SDHCI_CAN_DO_ADMA2)) { if (sdmmc->regs->capabilities & SDHCI_CAN_DO_ADMA2)
// TODO: Setting the ADMA flags breaks ADMA... sdmmc->use_adma = true;
/*
if (sdmmc->regs->capabilities & SDHCI_CAN_64BIT)
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA64;
else
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA32;
*/
}
/* Set the timeout to be the maximum value. */ /* Set the timeout to be the maximum value. */
sdmmc->regs->timeout_control &= 0xF0; sdmmc->regs->timeout_control &= 0xF0;
@ -847,9 +838,9 @@ static int sdmmc_dllcal_run(sdmmc_t *sdmmc)
is_timeout = (get_time_since(timebase) > 10000); is_timeout = (get_time_since(timebase) > 10000);
} }
/* Clock failed to stabilize. */ /* Calibration failed. */
if (is_timeout) { if (is_timeout) {
sdmmc_error(sdmmc, "ERROR: DLLCAL failed!"); sdmmc_error(sdmmc, "DLLCAL failed!");
return 0; return 0;
} }
@ -898,20 +889,23 @@ int sdmmc_select_speed(sdmmc_t *sdmmc, SdmmcBusSpeed bus_speed)
case SDMMC_SPEED_DDR50: case SDMMC_SPEED_DDR50:
case SDMMC_SPEED_SDR50: case SDMMC_SPEED_SDR50:
case SDMMC_SPEED_UNK14: case SDMMC_SPEED_UNK14:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK; 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_SDR104;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break; break;
/* 200MHz single-data rate (MMC). */ /* 200MHz single-data rate (MMC). */
case SDMMC_SPEED_HS400: case SDMMC_SPEED_HS400:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK; 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_HS400;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break; break;
/* 25MHz default speed (SD). */ /* 25MHz default speed (SD). */
case SDMMC_SPEED_SDR12: case SDMMC_SPEED_SDR12:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK; 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_SDR12;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break; break;
default: default:
@ -1093,7 +1087,7 @@ static int sdmmc_init_controller(sdmmc_t *sdmmc, SdmmcControllerNum controller)
sdmmc->is_clk_running = false; sdmmc->is_clk_running = false;
sdmmc->is_sd_clk_enabled = false; sdmmc->is_sd_clk_enabled = false;
sdmmc->is_tuning_tap_val_set = 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->dma_bounce_buf = (uint8_t*)SDMMC_BOUNCE_BUFFER_ADDRESS;
sdmmc->tap_val = 0; sdmmc->tap_val = 0;
sdmmc->internal_divider = 0; sdmmc->internal_divider = 0;
@ -1206,11 +1200,11 @@ void sdmmc_finish(sdmmc_t *sdmmc)
sdmmc_select_voltage(sdmmc, SDMMC_VOLTAGE_NONE); sdmmc_select_voltage(sdmmc, SDMMC_VOLTAGE_NONE);
/* Disable the SD card power. */ /* Disable the SD card power. */
if (sdmmc->controller == SDMMC_1) if (sdmmc->controller == SDMMC_1)
{ {
/* Disable GPIO output. */ /* Disable GPIO output. */
gpio_configure_direction(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_DIRECTION_INPUT); gpio_configure_direction(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_DIRECTION_INPUT);
/* Power cycle for 100ms without power. */ /* Power cycle for 100ms without power. */
mdelay(100); mdelay(100);
} }
@ -1749,7 +1743,7 @@ int sdmmc_switch_voltage(sdmmc_t *sdmmc)
sdmmc_get_sd_clock_control(sdmmc); sdmmc_get_sd_clock_control(sdmmc);
/* Wait a while. */ /* Wait a while. */
udelay(5000); mdelay(5);
/* Host control 2 flag should be set by now. */ /* Host control 2 flag should be set by now. */
if (sdmmc->regs->host_control2 & SDHCI_CTRL_VDD_180) 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); sdmmc_get_sd_clock_control(sdmmc);
/* Wait a while. */ /* Wait a while. */
udelay(1000); mdelay(1);
/* Data level is up. Voltage switching is done.*/ /* Data level is up. Voltage switching is done.*/
if (sdmmc->regs->present_state & SDHCI_DATA_LVL_MASK) if (sdmmc->regs->present_state & SDHCI_DATA_LVL_MASK)

View file

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

View file

@ -487,12 +487,12 @@ static int sdmmc_sd_send_op_cond(sdmmc_device_t *device, bool is_sd_ver2, bool i
return 0; return 0;
/* Delay a bit before asking for the voltage switch. */ /* Delay a bit before asking for the voltage switch. */
udelay(1000); mdelay(100);
/* Tell the driver to switch the voltage. */ /* Tell the driver to switch the voltage. */
if (!sdmmc_switch_voltage(device->sdmmc)) if (!sdmmc_switch_voltage(device->sdmmc))
return 0; return 0;
/* We are now running at 1.8V. */ /* We are now running at 1.8V. */
device->is_180v = true; device->is_180v = true;
} }
@ -693,15 +693,15 @@ static int sdmmc_sd_switch_hs_low(sdmmc_device_t *device, uint8_t *status)
/* Adjust the current limit. */ /* Adjust the current limit. */
if (!sdmmc_sd_set_current_limit(device, status)) if (!sdmmc_sd_set_current_limit(device, status))
return 0; return 0;
/* Invalid bus width. */ /* Invalid bus width. */
if (device->sdmmc->bus_width != SDMMC_BUS_WIDTH_4BIT) if (device->sdmmc->bus_width != SDMMC_BUS_WIDTH_4BIT)
return 0; return 0;
/* Get the supported high-speed type. */ /* Get the supported high-speed type. */
if (!sdmmc_sd_switch(device, 0, 0, 0xF, status)) if (!sdmmc_sd_switch(device, 0, 0, 0xF, status))
return 0; return 0;
/* High-speed SDR104 is supported. */ /* High-speed SDR104 is supported. */
if (status[13] & SD_MODE_UHS_SDR104) if (status[13] & SD_MODE_UHS_SDR104)
{ {
@ -748,6 +748,7 @@ static int sdmmc_sd_switch_hs_low(sdmmc_device_t *device, uint8_t *status)
else else
return 0; return 0;
/* Peek the SD card's status. */ /* Peek the SD card's status. */
return sdmmc_device_send_status(device); 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). */ /* Switch to high-speed from low voltage (if possible). */
if (!sdmmc_sd_switch_hs_low(device, switch_status)) 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; 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))) 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). */ /* Switch to high-speed from high voltage (if possible). */
if (!sdmmc_sd_switch_hs_high(device, switch_status)) 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; return 0;
} }
sdmmc_info(sdmmc, "Switched to high-speed!"); sdmmc_info(sdmmc, "Switched to high-speed from high voltage!");
} }
/* Correct any inconsistent states. */ /* 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) 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) && if ((bus_speed == SDMMC_SPEED_HS400) &&
(device->sdmmc->bus_width == SDMMC_BUS_WIDTH_8BIT) && (device->sdmmc->bus_width == SDMMC_BUS_WIDTH_8BIT) &&
(device->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) (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 cid[4] = {0};
uint32_t csd[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. */ /* Initialize our device's struct. */
memset(device, 0, sizeof(sdmmc_device_t)); 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: case SDMMC_3:
switch (voltage) { switch (voltage) {
case SDMMC_VOLTAGE_1V8: 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; sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC1_1V8;
break; break;
case SDMMC_VOLTAGE_3V3: 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; sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC1_3V3;
break; break;
default: default:
sdmmc_error(sdmmc, "microsd does not support voltage %d", voltage); sdmmc_error(sdmmc, "uSD does not support requested voltage!");
return 0; return 0;
} }
break; break;
case SDMMC_2: case SDMMC_2:
case SDMMC_4: case SDMMC_4:
if (voltage != SDMMC_VOLTAGE_1V8) { 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; 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; sdmmc->regs->auto_cal_config |= SDMMC_AUTOCAL_PDPU_SDMMC4_1V8;
break; break;
} }
@ -581,8 +579,8 @@ static int sdmmc_autocal_config(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
/* Run automatic calibration. */ /* Run automatic calibration. */
static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage) static void sdmmc_autocal_run(sdmmc_t *sdmmc, SdmmcBusVoltage voltage)
{ {
bool restart_sd_clock = false;
volatile tegra_padctl_t *padctl = padctl_get_regs(); volatile tegra_padctl_t *padctl = padctl_get_regs();
bool restart_sd_clock = false;
/* SD clock is enabled. Disable it and restart later. */ /* SD clock is enabled. Disable it and restart later. */
if (sdmmc->is_sd_clk_enabled) 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)) { while ((sdmmc->regs->auto_cal_status & SDMMC_AUTOCAL_ACTIVE)) {
/* Ensure we haven't timed out. */ /* Ensure we haven't timed out. */
if (get_time_since(timebase) > SDMMC_AUTOCAL_TIMEOUT) { 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. */ /* Force a register read to refresh the clock control value. */
sdmmc_get_sd_clock_control(sdmmc); 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. */ /* Manually clear the autocal enable bit. */
sdmmc->regs->auto_cal_config &= ~SDMMC_AUTOCAL_ENABLE; sdmmc->regs->auto_cal_config &= ~(SDMMC_AUTOCAL_ENABLE);
break; break;
} }
} }
@ -696,16 +694,9 @@ static int sdmmc_int_clk_enable(sdmmc_t *sdmmc)
/* Use SDMA by default. */ /* Use SDMA by default. */
sdmmc->regs->host_control &= ~SDHCI_CTRL_DMA_MASK; sdmmc->regs->host_control &= ~SDHCI_CTRL_DMA_MASK;
/* Change to ADMA if requested. */ /* Change to ADMA if possible. */
if (sdmmc->use_adma && (sdmmc->regs->capabilities & SDHCI_CAN_DO_ADMA2)) { if (sdmmc->regs->capabilities & SDHCI_CAN_DO_ADMA2)
// TODO: Setting the ADMA flags breaks ADMA... sdmmc->use_adma = true;
/*
if (sdmmc->regs->capabilities & SDHCI_CAN_64BIT)
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA64;
else
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA32;
*/
}
/* Set the timeout to be the maximum value. */ /* Set the timeout to be the maximum value. */
sdmmc->regs->timeout_control &= 0xF0; sdmmc->regs->timeout_control &= 0xF0;
@ -847,9 +838,9 @@ static int sdmmc_dllcal_run(sdmmc_t *sdmmc)
is_timeout = (get_time_since(timebase) > 10000); is_timeout = (get_time_since(timebase) > 10000);
} }
/* Clock failed to stabilize. */ /* Calibration failed. */
if (is_timeout) { if (is_timeout) {
sdmmc_error(sdmmc, "ERROR: DLLCAL failed!"); sdmmc_error(sdmmc, "DLLCAL failed!");
return 0; return 0;
} }
@ -898,20 +889,23 @@ int sdmmc_select_speed(sdmmc_t *sdmmc, SdmmcBusSpeed bus_speed)
case SDMMC_SPEED_DDR50: case SDMMC_SPEED_DDR50:
case SDMMC_SPEED_SDR50: case SDMMC_SPEED_SDR50:
case SDMMC_SPEED_UNK14: case SDMMC_SPEED_UNK14:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK; 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_SDR104;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break; break;
/* 200MHz single-data rate (MMC). */ /* 200MHz single-data rate (MMC). */
case SDMMC_SPEED_HS400: case SDMMC_SPEED_HS400:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK; 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_HS400;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break; break;
/* 25MHz default speed (SD). */ /* 25MHz default speed (SD). */
case SDMMC_SPEED_SDR12: case SDMMC_SPEED_SDR12:
sdmmc->regs->host_control2 &= SDHCI_CTRL_UHS_MASK; 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_SDR12;
sdmmc->regs->host_control2 |= SDHCI_CTRL_VDD_180;
break; break;
default: default:
@ -1093,7 +1087,7 @@ static int sdmmc_init_controller(sdmmc_t *sdmmc, SdmmcControllerNum controller)
sdmmc->is_clk_running = false; sdmmc->is_clk_running = false;
sdmmc->is_sd_clk_enabled = false; sdmmc->is_sd_clk_enabled = false;
sdmmc->is_tuning_tap_val_set = 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->dma_bounce_buf = (uint8_t*)SDMMC_BOUNCE_BUFFER_ADDRESS;
sdmmc->tap_val = 0; sdmmc->tap_val = 0;
sdmmc->internal_divider = 0; sdmmc->internal_divider = 0;
@ -1206,11 +1200,11 @@ void sdmmc_finish(sdmmc_t *sdmmc)
sdmmc_select_voltage(sdmmc, SDMMC_VOLTAGE_NONE); sdmmc_select_voltage(sdmmc, SDMMC_VOLTAGE_NONE);
/* Disable the SD card power. */ /* Disable the SD card power. */
if (sdmmc->controller == SDMMC_1) if (sdmmc->controller == SDMMC_1)
{ {
/* Disable GPIO output. */ /* Disable GPIO output. */
gpio_configure_direction(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_DIRECTION_INPUT); gpio_configure_direction(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_DIRECTION_INPUT);
/* Power cycle for 100ms without power. */ /* Power cycle for 100ms without power. */
mdelay(100); mdelay(100);
} }
@ -1749,7 +1743,7 @@ int sdmmc_switch_voltage(sdmmc_t *sdmmc)
sdmmc_get_sd_clock_control(sdmmc); sdmmc_get_sd_clock_control(sdmmc);
/* Wait a while. */ /* Wait a while. */
udelay(5000); mdelay(5);
/* Host control 2 flag should be set by now. */ /* Host control 2 flag should be set by now. */
if (sdmmc->regs->host_control2 & SDHCI_CTRL_VDD_180) 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); sdmmc_get_sd_clock_control(sdmmc);
/* Wait a while. */ /* Wait a while. */
udelay(1000); mdelay(1);
/* Data level is up. Voltage switching is done.*/ /* Data level is up. Voltage switching is done.*/
if (sdmmc->regs->present_state & SDHCI_DATA_LVL_MASK) if (sdmmc->regs->present_state & SDHCI_DATA_LVL_MASK)

View file

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