|
30 | 30 |
|
31 | 31 | #include "sdcard.h" |
32 | 32 | #include "ticks.h" |
| 33 | +#include "fsl_cache.h" |
33 | 34 | #include "fsl_iomuxc.h" |
34 | 35 | #include "pin.h" |
35 | 36 |
|
@@ -294,33 +295,52 @@ static void sdcard_error_recovery(USDHC_Type *base) { |
294 | 295 | static status_t sdcard_transfer_blocking(USDHC_Type *base, usdhc_handle_t *handle, usdhc_transfer_t *transfer, uint32_t timeout_ms) { |
295 | 296 | status_t status; |
296 | 297 |
|
297 | | - usdhc_adma_config_t dma_config; |
298 | | - |
299 | | - (void)memset(&dma_config, 0, sizeof(usdhc_adma_config_t)); |
300 | | - dma_config.dmaMode = kUSDHC_DmaModeAdma2; |
301 | | - |
302 | | - #if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) |
303 | | - dma_config.burstLen = kUSDHC_EnBurstLenForINCR; |
| 298 | + usdhc_adma_config_t dma_config = { |
| 299 | + .dmaMode = kUSDHC_DmaModeAdma2, |
| 300 | + #if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) |
| 301 | + .burstLen = kUSDHC_EnBurstLenForINCR, |
| 302 | + #endif |
| 303 | + .admaTable = sdcard_adma_descriptor_table, |
| 304 | + .admaTableWords = DMA_DESCRIPTOR_BUFFER_SIZE, |
| 305 | + }; |
| 306 | + usdhc_adma_config_t *p_dma_config = &dma_config; |
| 307 | + |
| 308 | + #if __DCACHE_PRESENT |
| 309 | + size_t byte_len = transfer->data->blockCount * transfer->data->blockSize; |
| 310 | + if ((uintptr_t)transfer->data->rxData % FSL_FEATURE_L1DCACHE_LINESIZE_BYTE != 0 || |
| 311 | + byte_len % FSL_FEATURE_L1DCACHE_LINESIZE_BYTE != 0) { |
| 312 | + // A DMA RX transfer that isn't cache line aligned can be corrupted if the CPU writes the same cache line during |
| 313 | + // the read, so make a polling transfer instead. |
| 314 | + // |
| 315 | + // (Note that the USDHC driver will internally disable DMA if the address isn't 4 byte aligned, so this check only |
| 316 | + // changes behaviour for addresses which are word aligned but not cache line aligned!) |
| 317 | + p_dma_config = NULL; |
| 318 | + } |
304 | 319 | #endif |
305 | 320 |
|
306 | | - dma_config.admaTable = sdcard_adma_descriptor_table; |
307 | | - dma_config.admaTableWords = DMA_DESCRIPTOR_BUFFER_SIZE; |
308 | | - |
309 | 321 | // Wait while the card is busy before a transfer |
310 | 322 | status = kStatus_Timeout; |
311 | 323 | for (int i = 0; i < timeout_ms * 100; i++) { |
312 | 324 | // Wait until Data0 is low any more. Low indicates "Busy". |
313 | 325 | if (((transfer->data->txData == NULL) && (transfer->data->rxData == NULL)) || |
314 | 326 | (USDHC_GetPresentStatusFlags(base) & (uint32_t)kUSDHC_Data0LineLevelFlag) != 0) { |
315 | 327 | // Not busy anymore or no TX-Data |
316 | | - status = USDHC_TransferBlocking(base, &dma_config, transfer); |
| 328 | + status = USDHC_TransferBlocking(base, p_dma_config, transfer); |
317 | 329 | if (status != kStatus_Success) { |
318 | 330 | sdcard_error_recovery(base); |
319 | 331 | } |
320 | 332 | break; |
321 | 333 | } |
322 | 334 | ticks_delay_us64(10); |
323 | 335 | } |
| 336 | + |
| 337 | + #if __DCACHE_PRESENT |
| 338 | + if (p_dma_config && transfer->data->rxData) { |
| 339 | + // Invalidate any cache lines that were filled while the transfer was in progress |
| 340 | + L1CACHE_InvalidateDCacheByRange((uintptr_t)transfer->data->rxData, byte_len); |
| 341 | + } |
| 342 | + #endif |
| 343 | + |
324 | 344 | return status; |
325 | 345 |
|
326 | 346 | } |
|
0 commit comments