mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
fusee: Fix SDMMC high speed support and other bugs.
This commit is contained in:
parent
eaa282b915
commit
e58927a8ab
6 changed files with 84 additions and 97 deletions
|
@ -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));
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue