mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
fusee/sept: restore and further match official behavior for SDMMC
This commit is contained in:
parent
9dc7a4dc18
commit
34bb800440
3 changed files with 150 additions and 105 deletions
|
@ -1314,9 +1314,9 @@ static int sdmmc_wait_busy(sdmmc_t *sdmmc)
|
|||
|
||||
static void sdmmc_intr_enable(sdmmc_t *sdmmc)
|
||||
{
|
||||
/* Set all error bits and enable the relevant interrupts. */
|
||||
sdmmc->regs->int_enable |= 0x017F0000;
|
||||
/* Enable the relevant interrupts and set all error bits. */
|
||||
sdmmc->regs->int_enable |= (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT);
|
||||
sdmmc->regs->int_enable |= 0x017F0000;
|
||||
|
||||
/* Refresh status. */
|
||||
sdmmc->regs->int_status = sdmmc->regs->int_status;
|
||||
|
@ -1324,34 +1324,35 @@ static void sdmmc_intr_enable(sdmmc_t *sdmmc)
|
|||
|
||||
static void sdmmc_intr_disable(sdmmc_t *sdmmc)
|
||||
{
|
||||
/* Clear all error bits and the interrupts. */
|
||||
/* Clear all error bits and disable the relevant interrupts. */
|
||||
sdmmc->regs->int_enable &= ~(0x017F0000);
|
||||
sdmmc->regs->int_enable &= ~(TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT);
|
||||
|
||||
/* Refresh status. */
|
||||
sdmmc->regs->int_status = sdmmc->regs->int_status;
|
||||
}
|
||||
|
||||
static bool sdmmc_intr_check_status(sdmmc_t *sdmmc, uint16_t status_mask)
|
||||
static int sdmmc_intr_check(sdmmc_t *sdmmc, uint16_t *status_out, uint16_t status_mask)
|
||||
{
|
||||
bool is_masked = (sdmmc->regs->int_status & status_mask);
|
||||
uint32_t int_status = sdmmc->regs->int_status;
|
||||
|
||||
/* Mask status. */
|
||||
if (is_masked)
|
||||
sdmmc->regs->int_status &= status_mask;
|
||||
sdmmc_debug(sdmmc, "INTSTS: %08X", int_status);
|
||||
|
||||
return is_masked;
|
||||
}
|
||||
|
||||
static bool sdmmc_intr_check_error(sdmmc_t *sdmmc)
|
||||
{
|
||||
bool is_error = (sdmmc->regs->int_status & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT);
|
||||
/* Return the status, if necessary. */
|
||||
if (status_out)
|
||||
*status_out = (int_status & 0xFFFF);
|
||||
|
||||
/* Refresh status. */
|
||||
if (is_error)
|
||||
sdmmc->regs->int_status = sdmmc->regs->int_status;
|
||||
if (int_status & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT)
|
||||
{
|
||||
/* Acknowledge error by refreshing status. */
|
||||
sdmmc->regs->int_status = int_status;
|
||||
return -1;
|
||||
}
|
||||
else if (int_status & status_mask)
|
||||
{
|
||||
/* Mask the status. */
|
||||
sdmmc->regs->int_status = (int_status & status_mask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return is_error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdmmc_dma_init(sdmmc_t *sdmmc, sdmmc_request_t *req)
|
||||
|
@ -1442,15 +1443,23 @@ static int sdmmc_dma_update(sdmmc_t *sdmmc)
|
|||
/* Watch over the DMA transfer. */
|
||||
while (!is_timeout)
|
||||
{
|
||||
/* Check interrupts. */
|
||||
uint16_t intr_status = 0;
|
||||
int intr_res = sdmmc_intr_check(sdmmc, &intr_status, TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT);
|
||||
|
||||
/* An error has been raised. Reset. */
|
||||
if (sdmmc_intr_check_error(sdmmc))
|
||||
if (intr_res < 0)
|
||||
{
|
||||
sdmmc_do_sw_reset(sdmmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Transfer is over. */
|
||||
if (intr_status & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
|
||||
return 1;
|
||||
|
||||
/* We have a DMA interrupt. Restart the transfer where it was interrupted. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTS_DMA_INTERRUPT))
|
||||
if (intr_status & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
||||
{
|
||||
if (sdmmc->use_adma)
|
||||
{
|
||||
|
@ -1467,10 +1476,6 @@ static int sdmmc_dma_update(sdmmc_t *sdmmc)
|
|||
sdmmc->next_dma_addr += 0x80000;
|
||||
}
|
||||
|
||||
/* Transfer is over. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTS_XFER_COMPLETE))
|
||||
return 1;
|
||||
|
||||
/* Keep checking if timeout expired. */
|
||||
is_timeout = (get_time_since(timebase) > 2000000);
|
||||
}
|
||||
|
@ -1526,12 +1531,15 @@ static int sdmmc_wait_for_cmd(sdmmc_t *sdmmc)
|
|||
|
||||
/* Wait for CMD to finish. */
|
||||
while (!is_err && !is_timeout) {
|
||||
/* Check interrupts. */
|
||||
int intr_res = sdmmc_intr_check(sdmmc, 0, TEGRA_MMC_NORINTSTS_CMD_COMPLETE);
|
||||
|
||||
/* Command is done. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTS_CMD_COMPLETE))
|
||||
if (intr_res > 0)
|
||||
return 1;
|
||||
|
||||
/* Check for any raised errors. */
|
||||
is_err = sdmmc_intr_check_error(sdmmc);
|
||||
is_err = (intr_res < 0);
|
||||
|
||||
/* Keep checking if timeout expired. */
|
||||
is_timeout = (get_time_since(timebase) > 2000000);
|
||||
|
@ -1642,9 +1650,12 @@ int sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_command_t *cmd, sdmmc_request_t *req, u
|
|||
is_dma = true;
|
||||
dma_blkcnt = sdmmc_dma_init(sdmmc, req);
|
||||
|
||||
/* Warn in case initialization failed. This could indicate hardware failure. */
|
||||
/* Abort in case initialization failed. */
|
||||
if (!dma_blkcnt)
|
||||
sdmmc_warn(sdmmc, "Failed to initialize the DMA transfer!");
|
||||
{
|
||||
sdmmc_error(sdmmc, "Failed to initialize the DMA transfer!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this is a SDMA write operation, copy the data into our bounce buffer. */
|
||||
if (!sdmmc->use_adma && !req->is_read)
|
||||
|
@ -1667,12 +1678,16 @@ int sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_command_t *cmd, sdmmc_request_t *req, u
|
|||
/* Save response, if necessary. */
|
||||
sdmmc_save_response(sdmmc, cmd->flags);
|
||||
|
||||
/* Process the DMA request. */
|
||||
/* Update the DMA request. */
|
||||
if (req)
|
||||
{
|
||||
/* Warn in case updating failed. This could indicate hardware failure. */
|
||||
/* Disable interrupts and abort in case updating failed. */
|
||||
if (!sdmmc_dma_update(sdmmc))
|
||||
sdmmc_warn(sdmmc, "Failed to process the DMA transfer!");
|
||||
{
|
||||
sdmmc_warn(sdmmc, "Failed to update the DMA transfer!");
|
||||
sdmmc_intr_disable(sdmmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this is a SDMA read operation, copy the data from our bounce buffer. */
|
||||
if (!sdmmc->use_adma && req->is_read)
|
||||
|
@ -1836,7 +1851,7 @@ static int sdmmc_send_tuning(sdmmc_t *sdmmc, uint32_t opcode)
|
|||
while (!is_timeout)
|
||||
{
|
||||
/* Buffer Read Ready was asserted. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY))
|
||||
if (sdmmc_intr_check(sdmmc, 0, TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY) > 0)
|
||||
{
|
||||
/* Manually disable the Buffer Read Ready interrupt. */
|
||||
sdmmc->regs->int_enable &= ~(TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY);
|
||||
|
|
|
@ -1314,9 +1314,9 @@ static int sdmmc_wait_busy(sdmmc_t *sdmmc)
|
|||
|
||||
static void sdmmc_intr_enable(sdmmc_t *sdmmc)
|
||||
{
|
||||
/* Set all error bits and enable the relevant interrupts. */
|
||||
sdmmc->regs->int_enable |= 0x017F0000;
|
||||
/* Enable the relevant interrupts and set all error bits. */
|
||||
sdmmc->regs->int_enable |= (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT);
|
||||
sdmmc->regs->int_enable |= 0x017F0000;
|
||||
|
||||
/* Refresh status. */
|
||||
sdmmc->regs->int_status = sdmmc->regs->int_status;
|
||||
|
@ -1324,34 +1324,35 @@ static void sdmmc_intr_enable(sdmmc_t *sdmmc)
|
|||
|
||||
static void sdmmc_intr_disable(sdmmc_t *sdmmc)
|
||||
{
|
||||
/* Clear all error bits and the interrupts. */
|
||||
/* Clear all error bits and disable the relevant interrupts. */
|
||||
sdmmc->regs->int_enable &= ~(0x017F0000);
|
||||
sdmmc->regs->int_enable &= ~(TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT);
|
||||
|
||||
/* Refresh status. */
|
||||
sdmmc->regs->int_status = sdmmc->regs->int_status;
|
||||
}
|
||||
|
||||
static bool sdmmc_intr_check_status(sdmmc_t *sdmmc, uint16_t status_mask)
|
||||
static int sdmmc_intr_check(sdmmc_t *sdmmc, uint16_t *status_out, uint16_t status_mask)
|
||||
{
|
||||
bool is_masked = (sdmmc->regs->int_status & status_mask);
|
||||
uint32_t int_status = sdmmc->regs->int_status;
|
||||
|
||||
/* Mask status. */
|
||||
if (is_masked)
|
||||
sdmmc->regs->int_status &= status_mask;
|
||||
sdmmc_debug(sdmmc, "INTSTS: %08X", int_status);
|
||||
|
||||
return is_masked;
|
||||
}
|
||||
|
||||
static bool sdmmc_intr_check_error(sdmmc_t *sdmmc)
|
||||
{
|
||||
bool is_error = (sdmmc->regs->int_status & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT);
|
||||
/* Return the status, if necessary. */
|
||||
if (status_out)
|
||||
*status_out = (int_status & 0xFFFF);
|
||||
|
||||
/* Refresh status. */
|
||||
if (is_error)
|
||||
sdmmc->regs->int_status = sdmmc->regs->int_status;
|
||||
if (int_status & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT)
|
||||
{
|
||||
/* Acknowledge error by refreshing status. */
|
||||
sdmmc->regs->int_status = int_status;
|
||||
return -1;
|
||||
}
|
||||
else if (int_status & status_mask)
|
||||
{
|
||||
/* Mask the status. */
|
||||
sdmmc->regs->int_status = (int_status & status_mask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return is_error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdmmc_dma_init(sdmmc_t *sdmmc, sdmmc_request_t *req)
|
||||
|
@ -1442,15 +1443,23 @@ static int sdmmc_dma_update(sdmmc_t *sdmmc)
|
|||
/* Watch over the DMA transfer. */
|
||||
while (!is_timeout)
|
||||
{
|
||||
/* Check interrupts. */
|
||||
uint16_t intr_status = 0;
|
||||
int intr_res = sdmmc_intr_check(sdmmc, &intr_status, TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT);
|
||||
|
||||
/* An error has been raised. Reset. */
|
||||
if (sdmmc_intr_check_error(sdmmc))
|
||||
if (intr_res < 0)
|
||||
{
|
||||
sdmmc_do_sw_reset(sdmmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Transfer is over. */
|
||||
if (intr_status & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
|
||||
return 1;
|
||||
|
||||
/* We have a DMA interrupt. Restart the transfer where it was interrupted. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTS_DMA_INTERRUPT))
|
||||
if (intr_status & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
||||
{
|
||||
if (sdmmc->use_adma)
|
||||
{
|
||||
|
@ -1467,10 +1476,6 @@ static int sdmmc_dma_update(sdmmc_t *sdmmc)
|
|||
sdmmc->next_dma_addr += 0x80000;
|
||||
}
|
||||
|
||||
/* Transfer is over. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTS_XFER_COMPLETE))
|
||||
return 1;
|
||||
|
||||
/* Keep checking if timeout expired. */
|
||||
is_timeout = (get_time_since(timebase) > 2000000);
|
||||
}
|
||||
|
@ -1526,12 +1531,15 @@ static int sdmmc_wait_for_cmd(sdmmc_t *sdmmc)
|
|||
|
||||
/* Wait for CMD to finish. */
|
||||
while (!is_err && !is_timeout) {
|
||||
/* Check interrupts. */
|
||||
int intr_res = sdmmc_intr_check(sdmmc, 0, TEGRA_MMC_NORINTSTS_CMD_COMPLETE);
|
||||
|
||||
/* Command is done. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTS_CMD_COMPLETE))
|
||||
if (intr_res > 0)
|
||||
return 1;
|
||||
|
||||
/* Check for any raised errors. */
|
||||
is_err = sdmmc_intr_check_error(sdmmc);
|
||||
is_err = (intr_res < 0);
|
||||
|
||||
/* Keep checking if timeout expired. */
|
||||
is_timeout = (get_time_since(timebase) > 2000000);
|
||||
|
@ -1642,9 +1650,12 @@ int sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_command_t *cmd, sdmmc_request_t *req, u
|
|||
is_dma = true;
|
||||
dma_blkcnt = sdmmc_dma_init(sdmmc, req);
|
||||
|
||||
/* Warn in case initialization failed. This could indicate hardware failure. */
|
||||
/* Abort in case initialization failed. */
|
||||
if (!dma_blkcnt)
|
||||
sdmmc_warn(sdmmc, "Failed to initialize the DMA transfer!");
|
||||
{
|
||||
sdmmc_error(sdmmc, "Failed to initialize the DMA transfer!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this is a SDMA write operation, copy the data into our bounce buffer. */
|
||||
if (!sdmmc->use_adma && !req->is_read)
|
||||
|
@ -1667,12 +1678,16 @@ int sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_command_t *cmd, sdmmc_request_t *req, u
|
|||
/* Save response, if necessary. */
|
||||
sdmmc_save_response(sdmmc, cmd->flags);
|
||||
|
||||
/* Process the DMA request. */
|
||||
/* Update the DMA request. */
|
||||
if (req)
|
||||
{
|
||||
/* Warn in case updating failed. This could indicate hardware failure. */
|
||||
/* Disable interrupts and abort in case updating failed. */
|
||||
if (!sdmmc_dma_update(sdmmc))
|
||||
sdmmc_warn(sdmmc, "Failed to process the DMA transfer!");
|
||||
{
|
||||
sdmmc_warn(sdmmc, "Failed to update the DMA transfer!");
|
||||
sdmmc_intr_disable(sdmmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this is a SDMA read operation, copy the data from our bounce buffer. */
|
||||
if (!sdmmc->use_adma && req->is_read)
|
||||
|
@ -1836,7 +1851,7 @@ static int sdmmc_send_tuning(sdmmc_t *sdmmc, uint32_t opcode)
|
|||
while (!is_timeout)
|
||||
{
|
||||
/* Buffer Read Ready was asserted. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY))
|
||||
if (sdmmc_intr_check(sdmmc, 0, TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY) > 0)
|
||||
{
|
||||
/* Manually disable the Buffer Read Ready interrupt. */
|
||||
sdmmc->regs->int_enable &= ~(TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY);
|
||||
|
|
|
@ -1314,9 +1314,9 @@ static int sdmmc_wait_busy(sdmmc_t *sdmmc)
|
|||
|
||||
static void sdmmc_intr_enable(sdmmc_t *sdmmc)
|
||||
{
|
||||
/* Set all error bits and enable the relevant interrupts. */
|
||||
sdmmc->regs->int_enable |= 0x017F0000;
|
||||
/* Enable the relevant interrupts and set all error bits. */
|
||||
sdmmc->regs->int_enable |= (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT);
|
||||
sdmmc->regs->int_enable |= 0x017F0000;
|
||||
|
||||
/* Refresh status. */
|
||||
sdmmc->regs->int_status = sdmmc->regs->int_status;
|
||||
|
@ -1324,34 +1324,35 @@ static void sdmmc_intr_enable(sdmmc_t *sdmmc)
|
|||
|
||||
static void sdmmc_intr_disable(sdmmc_t *sdmmc)
|
||||
{
|
||||
/* Clear all error bits and the interrupts. */
|
||||
/* Clear all error bits and disable the relevant interrupts. */
|
||||
sdmmc->regs->int_enable &= ~(0x017F0000);
|
||||
sdmmc->regs->int_enable &= ~(TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT);
|
||||
|
||||
/* Refresh status. */
|
||||
sdmmc->regs->int_status = sdmmc->regs->int_status;
|
||||
}
|
||||
|
||||
static bool sdmmc_intr_check_status(sdmmc_t *sdmmc, uint16_t status_mask)
|
||||
static int sdmmc_intr_check(sdmmc_t *sdmmc, uint16_t *status_out, uint16_t status_mask)
|
||||
{
|
||||
bool is_masked = (sdmmc->regs->int_status & status_mask);
|
||||
uint32_t int_status = sdmmc->regs->int_status;
|
||||
|
||||
/* Mask status. */
|
||||
if (is_masked)
|
||||
sdmmc->regs->int_status &= status_mask;
|
||||
sdmmc_debug(sdmmc, "INTSTS: %08X", int_status);
|
||||
|
||||
return is_masked;
|
||||
}
|
||||
|
||||
static bool sdmmc_intr_check_error(sdmmc_t *sdmmc)
|
||||
{
|
||||
bool is_error = (sdmmc->regs->int_status & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT);
|
||||
/* Return the status, if necessary. */
|
||||
if (status_out)
|
||||
*status_out = (int_status & 0xFFFF);
|
||||
|
||||
/* Refresh status. */
|
||||
if (is_error)
|
||||
sdmmc->regs->int_status = sdmmc->regs->int_status;
|
||||
if (int_status & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT)
|
||||
{
|
||||
/* Acknowledge error by refreshing status. */
|
||||
sdmmc->regs->int_status = int_status;
|
||||
return -1;
|
||||
}
|
||||
else if (int_status & status_mask)
|
||||
{
|
||||
/* Mask the status. */
|
||||
sdmmc->regs->int_status = (int_status & status_mask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return is_error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdmmc_dma_init(sdmmc_t *sdmmc, sdmmc_request_t *req)
|
||||
|
@ -1442,15 +1443,23 @@ static int sdmmc_dma_update(sdmmc_t *sdmmc)
|
|||
/* Watch over the DMA transfer. */
|
||||
while (!is_timeout)
|
||||
{
|
||||
/* Check interrupts. */
|
||||
uint16_t intr_status = 0;
|
||||
int intr_res = sdmmc_intr_check(sdmmc, &intr_status, TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT);
|
||||
|
||||
/* An error has been raised. Reset. */
|
||||
if (sdmmc_intr_check_error(sdmmc))
|
||||
if (intr_res < 0)
|
||||
{
|
||||
sdmmc_do_sw_reset(sdmmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Transfer is over. */
|
||||
if (intr_status & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
|
||||
return 1;
|
||||
|
||||
/* We have a DMA interrupt. Restart the transfer where it was interrupted. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTS_DMA_INTERRUPT))
|
||||
if (intr_status & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
||||
{
|
||||
if (sdmmc->use_adma)
|
||||
{
|
||||
|
@ -1467,10 +1476,6 @@ static int sdmmc_dma_update(sdmmc_t *sdmmc)
|
|||
sdmmc->next_dma_addr += 0x80000;
|
||||
}
|
||||
|
||||
/* Transfer is over. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTS_XFER_COMPLETE))
|
||||
return 1;
|
||||
|
||||
/* Keep checking if timeout expired. */
|
||||
is_timeout = (get_time_since(timebase) > 2000000);
|
||||
}
|
||||
|
@ -1526,12 +1531,15 @@ static int sdmmc_wait_for_cmd(sdmmc_t *sdmmc)
|
|||
|
||||
/* Wait for CMD to finish. */
|
||||
while (!is_err && !is_timeout) {
|
||||
/* Check interrupts. */
|
||||
int intr_res = sdmmc_intr_check(sdmmc, 0, TEGRA_MMC_NORINTSTS_CMD_COMPLETE);
|
||||
|
||||
/* Command is done. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTS_CMD_COMPLETE))
|
||||
if (intr_res > 0)
|
||||
return 1;
|
||||
|
||||
/* Check for any raised errors. */
|
||||
is_err = sdmmc_intr_check_error(sdmmc);
|
||||
is_err = (intr_res < 0);
|
||||
|
||||
/* Keep checking if timeout expired. */
|
||||
is_timeout = (get_time_since(timebase) > 2000000);
|
||||
|
@ -1642,9 +1650,12 @@ int sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_command_t *cmd, sdmmc_request_t *req, u
|
|||
is_dma = true;
|
||||
dma_blkcnt = sdmmc_dma_init(sdmmc, req);
|
||||
|
||||
/* Warn in case initialization failed. This could indicate hardware failure. */
|
||||
/* Abort in case initialization failed. */
|
||||
if (!dma_blkcnt)
|
||||
sdmmc_warn(sdmmc, "Failed to initialize the DMA transfer!");
|
||||
{
|
||||
sdmmc_error(sdmmc, "Failed to initialize the DMA transfer!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this is a SDMA write operation, copy the data into our bounce buffer. */
|
||||
if (!sdmmc->use_adma && !req->is_read)
|
||||
|
@ -1667,12 +1678,16 @@ int sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_command_t *cmd, sdmmc_request_t *req, u
|
|||
/* Save response, if necessary. */
|
||||
sdmmc_save_response(sdmmc, cmd->flags);
|
||||
|
||||
/* Process the DMA request. */
|
||||
/* Update the DMA request. */
|
||||
if (req)
|
||||
{
|
||||
/* Warn in case updating failed. This could indicate hardware failure. */
|
||||
/* Disable interrupts and abort in case updating failed. */
|
||||
if (!sdmmc_dma_update(sdmmc))
|
||||
sdmmc_warn(sdmmc, "Failed to process the DMA transfer!");
|
||||
{
|
||||
sdmmc_warn(sdmmc, "Failed to update the DMA transfer!");
|
||||
sdmmc_intr_disable(sdmmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this is a SDMA read operation, copy the data from our bounce buffer. */
|
||||
if (!sdmmc->use_adma && req->is_read)
|
||||
|
@ -1836,7 +1851,7 @@ static int sdmmc_send_tuning(sdmmc_t *sdmmc, uint32_t opcode)
|
|||
while (!is_timeout)
|
||||
{
|
||||
/* Buffer Read Ready was asserted. */
|
||||
if (sdmmc_intr_check_status(sdmmc, TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY))
|
||||
if (sdmmc_intr_check(sdmmc, 0, TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY) > 0)
|
||||
{
|
||||
/* Manually disable the Buffer Read Ready interrupt. */
|
||||
sdmmc->regs->int_enable &= ~(TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY);
|
||||
|
|
Loading…
Reference in a new issue