mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-29 23:32:23 +00:00
fusee: fix multiple-block SDMMC transfers
This commit is contained in:
parent
e5fff14689
commit
932a5bd645
1 changed files with 13 additions and 7 deletions
|
@ -172,7 +172,9 @@ enum sdmmc_register_bits {
|
||||||
MMC_TRANSFER_DMA_ENABLE = (1 << 0),
|
MMC_TRANSFER_DMA_ENABLE = (1 << 0),
|
||||||
MMC_TRANSFER_LIMIT_BLOCK_COUNT = (1 << 1),
|
MMC_TRANSFER_LIMIT_BLOCK_COUNT = (1 << 1),
|
||||||
MMC_TRANSFER_MULTIPLE_BLOCKS = (1 << 5),
|
MMC_TRANSFER_MULTIPLE_BLOCKS = (1 << 5),
|
||||||
|
MMC_TRANSFER_AUTO_CMD_MASK = (0x3 << 2),
|
||||||
MMC_TRANSFER_AUTO_CMD = (0x3 << 2),
|
MMC_TRANSFER_AUTO_CMD = (0x3 << 2),
|
||||||
|
MMC_TRANSFER_AUTO_CMD12 = (0x1 << 2),
|
||||||
MMC_TRANSFER_CARD_TO_HOST = (1 << 4),
|
MMC_TRANSFER_CARD_TO_HOST = (1 << 4),
|
||||||
|
|
||||||
/* Interrupt status */
|
/* Interrupt status */
|
||||||
|
@ -1150,17 +1152,21 @@ static void sdmmc_prepare_command_data(struct mmc *mmc, uint16_t blocks,
|
||||||
mmc->regs->argument = argument;
|
mmc->regs->argument = argument;
|
||||||
|
|
||||||
if (blocks) {
|
if (blocks) {
|
||||||
uint32_t to_write = MMC_TRANSFER_LIMIT_BLOCK_COUNT | MMC_TRANSFER_AUTO_CMD;
|
uint32_t to_write = MMC_TRANSFER_LIMIT_BLOCK_COUNT;
|
||||||
|
|
||||||
// If this controller should use DMA, set that up.
|
// If this controller should use DMA, set that up.
|
||||||
if (mmc->use_dma)
|
if (mmc->use_dma)
|
||||||
to_write |= MMC_TRANSFER_DMA_ENABLE;
|
to_write |= MMC_TRANSFER_DMA_ENABLE;
|
||||||
|
|
||||||
// If this is a multi-block datagram, indicate so.
|
// If this is a multi-block datagram, indicate so.
|
||||||
// Also, configure the host to automatically stop the card when transfers are complete.
|
|
||||||
if (blocks > 1)
|
if (blocks > 1)
|
||||||
to_write |= MMC_TRANSFER_MULTIPLE_BLOCKS;
|
to_write |= MMC_TRANSFER_MULTIPLE_BLOCKS;
|
||||||
|
|
||||||
|
// If this command should automatically terminate, set the host to
|
||||||
|
// terminate it after the block span is complete.
|
||||||
|
if (auto_terminate)
|
||||||
|
to_write |= MMC_TRANSFER_AUTO_CMD12;
|
||||||
|
|
||||||
// If this is a read, set the READ mode.
|
// If this is a read, set the READ mode.
|
||||||
if (!is_write)
|
if (!is_write)
|
||||||
to_write |= MMC_TRANSFER_CARD_TO_HOST;
|
to_write |= MMC_TRANSFER_CARD_TO_HOST;
|
||||||
|
@ -1294,6 +1300,7 @@ static int sdmmc_handle_command_response(struct mmc *mmc,
|
||||||
* @param blocks_to_transfer The number of SDMMC blocks to be transferred with the given command,
|
* @param blocks_to_transfer The number of SDMMC blocks to be transferred with the given command,
|
||||||
* or 0 to indicate that this command should not expect response data.
|
* or 0 to indicate that this command should not expect response data.
|
||||||
* @param is_write True iff the given command issues data _to_ the card, instead of vice versa.
|
* @param is_write True iff the given command issues data _to_ the card, instead of vice versa.
|
||||||
|
* @param auto_terminate True iff the gven command needs to be terminated with e.g. CMD12
|
||||||
* @param data_buffer A byte buffer that either contains the data to be sent, or which should
|
* @param data_buffer A byte buffer that either contains the data to be sent, or which should
|
||||||
* receive data, depending on the is_write argument.
|
* receive data, depending on the is_write argument.
|
||||||
*
|
*
|
||||||
|
@ -1363,7 +1370,7 @@ static int sdmmc_send_command(struct mmc *mmc, enum sdmmc_command command,
|
||||||
// Copy the response received to the output buffer, if applicable.
|
// Copy the response received to the output buffer, if applicable.
|
||||||
rc = sdmmc_handle_command_response(mmc, response_type, response_buffer);
|
rc = sdmmc_handle_command_response(mmc, response_type, response_buffer);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mmc_print(mmc, "failed to handle CMD%d response! (%d)", rc);
|
mmc_print(mmc, "failed to handle %s response! (%d)", sdmmc_get_command_string(command), rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1376,7 +1383,7 @@ static int sdmmc_send_command(struct mmc *mmc, enum sdmmc_command command,
|
||||||
// Wait for the transfer to be complete...
|
// Wait for the transfer to be complete...
|
||||||
rc = sdmmc_wait_for_transfer_completion(mmc);
|
rc = sdmmc_wait_for_transfer_completion(mmc);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mmc_print(mmc, "failed to complete CMD%d data stage via DMA (%d)", command, rc);
|
mmc_print(mmc, "failed to complete %s data stage via DMA (%d)", sdmmc_get_command_string(command), command, rc);
|
||||||
sdmmc_enable_interrupts(mmc, false);
|
sdmmc_enable_interrupts(mmc, false);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1586,7 +1593,7 @@ static int sdmmc_read_and_parse_ext_csd(struct mmc *mmc)
|
||||||
|
|
||||||
// Read the single EXT CSD block.
|
// Read the single EXT CSD block.
|
||||||
rc = sdmmc_send_command(mmc, CMD_SEND_EXT_CSD, MMC_RESPONSE_LEN48,
|
rc = sdmmc_send_command(mmc, CMD_SEND_EXT_CSD, MMC_RESPONSE_LEN48,
|
||||||
MMC_CHECKS_ALL, 0, NULL, 1, false, true, ext_csd);
|
MMC_CHECKS_ALL, 0, NULL, 1, false, false, ext_csd);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mmc_print(mmc, "ERROR: failed to read the extended CSD!");
|
mmc_print(mmc, "ERROR: failed to read the extended CSD!");
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -2301,7 +2308,6 @@ int sdmmc_select_partition(struct mmc *mmc, enum sdmmc_partition partition)
|
||||||
*/
|
*/
|
||||||
int sdmmc_read(struct mmc *mmc, void *buffer, uint32_t block, unsigned int count)
|
int sdmmc_read(struct mmc *mmc, void *buffer, uint32_t block, unsigned int count)
|
||||||
{
|
{
|
||||||
// Determine if we need to perform a single-block or multi-block read.
|
|
||||||
uint32_t command = (count == 1) ? CMD_READ_SINGLE_BLOCK : CMD_READ_MULTIPLE_BLOCK;
|
uint32_t command = (count == 1) ? CMD_READ_SINGLE_BLOCK : CMD_READ_MULTIPLE_BLOCK;
|
||||||
|
|
||||||
// Determine the argument, which indicates which address we're reading/writing.
|
// Determine the argument, which indicates which address we're reading/writing.
|
||||||
|
@ -2314,7 +2320,7 @@ int sdmmc_read(struct mmc *mmc, void *buffer, uint32_t block, unsigned int count
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the relevant read.
|
// Execute the relevant read.
|
||||||
return sdmmc_send_command(mmc, command, MMC_RESPONSE_LEN48, MMC_CHECKS_ALL, extent, NULL, count, false, true, buffer);
|
return sdmmc_send_command(mmc, command, MMC_RESPONSE_LEN48, MMC_CHECKS_ALL, extent, NULL, count, false, count > 1, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue