mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Revision:
148:21d94c44109e
Parent:
144:ef7eb2e8f9f7
--- a/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_sdhc.c	Fri Sep 16 16:24:25 2016 +0100
+++ b/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_sdhc.c	Fri Sep 30 18:07:01 2016 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,9 @@
 #define SDHC_NEXT_CLKFS(x) ((x) <<= 1U)
 #define SDHC_PREV_CLKFS(x) ((x) >>= 1U)
 
+/* Typedef for interrupt handler. */
+typedef void (*sdhc_isr_t)(SDHC_Type *base, sdhc_handle_t *handle);
+
 /*! @brief ADMA table configuration */
 typedef struct _sdhc_adma_table_config
 {
@@ -230,6 +233,9 @@
 /*! @brief SDHC clock array name */
 static const clock_ip_name_t s_sdhcClock[] = SDHC_CLOCKS;
 
+/* SDHC ISR for transactional APIs. */
+static sdhc_isr_t s_sdhcIsr;
+
 /*******************************************************************************
  * Code
  ******************************************************************************/
@@ -288,10 +294,8 @@
 
 static void SDHC_StartTransfer(SDHC_Type *base, sdhc_command_t *command, sdhc_data_t *data)
 {
-    assert(command);
-
     uint32_t flags = 0U;
-    sdhc_transfer_config_t sdhcTransferConfig;
+    sdhc_transfer_config_t sdhcTransferConfig = {0};
     sdhc_dma_mode_t dmaMode;
 
     /* Define the flag corresponding to each response type. */
@@ -315,7 +319,7 @@
             flags |= (kSDHC_ResponseLength48Flag);
             break;
         case kSDHC_ResponseTypeR5: /* Response 5 */
-            flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag);
+            flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
             break;
         case kSDHC_ResponseTypeR5b: /* Response 5 with busy */
             flags |= (kSDHC_ResponseLength48BusyFlag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
@@ -355,18 +359,9 @@
                 flags |= kSDHC_EnableAutoCommand12Flag;
             }
         }
-        if (data->blockCount > SDHC_MAX_BLOCK_COUNT)
-        {
-            sdhcTransferConfig.dataBlockSize = data->blockSize;
-            sdhcTransferConfig.dataBlockCount = SDHC_MAX_BLOCK_COUNT;
 
-            flags &= ~(uint32_t)kSDHC_EnableBlockCountFlag;
-        }
-        else
-        {
-            sdhcTransferConfig.dataBlockSize = data->blockSize;
-            sdhcTransferConfig.dataBlockCount = data->blockCount;
-        }
+        sdhcTransferConfig.dataBlockSize = data->blockSize;
+        sdhcTransferConfig.dataBlockCount = data->blockCount;
     }
     else
     {
@@ -382,8 +377,6 @@
 
 static void SDHC_ReceiveCommandResponse(SDHC_Type *base, sdhc_command_t *command)
 {
-    assert(command);
-
     uint32_t i;
 
     if (command->responseType != kSDHC_ResponseTypeNone)
@@ -412,13 +405,22 @@
 
 static uint32_t SDHC_ReadDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords)
 {
-    assert(data);
-
     uint32_t i;
     uint32_t totalWords;
     uint32_t wordsCanBeRead; /* The words can be read at this time. */
     uint32_t readWatermark = ((base->WML & SDHC_WML_RDWML_MASK) >> SDHC_WML_RDWML_SHIFT);
 
+    /*
+     * Add non aligned access support ,user need make sure your buffer size is big
+     * enough to hold the data,in other words,user need make sure the buffer size
+     * is 4 byte aligned
+     */
+    if (data->blockSize % sizeof(uint32_t) != 0U)
+    {
+        data->blockSize +=
+            sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+    }
+
     totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
 
     /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
@@ -451,12 +453,21 @@
 
 static status_t SDHC_ReadByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
 {
-    assert(data);
-
     uint32_t totalWords;
     uint32_t transferredWords = 0U;
     status_t error = kStatus_Success;
 
+    /*
+     * Add non aligned access support ,user need make sure your buffer size is big
+     * enough to hold the data,in other words,user need make sure the buffer size
+     * is 4 byte aligned
+     */
+    if (data->blockSize % sizeof(uint32_t) != 0U)
+    {
+        data->blockSize +=
+            sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+    }
+
     totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
 
     while ((error == kStatus_Success) && (transferredWords < totalWords))
@@ -489,13 +500,22 @@
 
 static uint32_t SDHC_WriteDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords)
 {
-    assert(data);
-
     uint32_t i;
     uint32_t totalWords;
     uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
     uint32_t writeWatermark = ((base->WML & SDHC_WML_WRWML_MASK) >> SDHC_WML_WRWML_SHIFT);
 
+    /*
+     * Add non aligned access support ,user need make sure your buffer size is big
+     * enough to hold the data,in other words,user need make sure the buffer size
+     * is 4 byte aligned
+     */
+    if (data->blockSize % sizeof(uint32_t) != 0U)
+    {
+        data->blockSize +=
+            sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+    }
+
     totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
 
     /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
@@ -528,12 +548,21 @@
 
 static status_t SDHC_WriteByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
 {
-    assert(data);
-
     uint32_t totalWords;
     uint32_t transferredWords = 0U;
     status_t error = kStatus_Success;
 
+    /*
+     * Add non aligned access support ,user need make sure your buffer size is big
+     * enough to hold the data,in other words,user need make sure the buffer size
+     * is 4 byte aligned
+     */
+    if (data->blockSize % sizeof(uint32_t) != 0U)
+    {
+        data->blockSize +=
+            sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+    }
+
     totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
 
     while ((error == kStatus_Success) && (transferredWords < totalWords))
@@ -576,8 +605,6 @@
 
 static status_t SDHC_SendCommandBlocking(SDHC_Type *base, sdhc_command_t *command)
 {
-    assert(command);
-
     status_t error = kStatus_Success;
 
     /* Wait command complete or SDHC encounters error. */
@@ -602,8 +629,6 @@
 
 static status_t SDHC_TransferByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
 {
-    assert(data);
-
     status_t error = kStatus_Success;
 
     if (data->rxData)
@@ -669,8 +694,6 @@
 
 static void SDHC_TransferHandleCardDetect(sdhc_handle_t *handle, uint32_t interruptFlags)
 {
-    assert(interruptFlags & kSDHC_CardDetectFlag);
-
     if (interruptFlags & kSDHC_CardInsertionFlag)
     {
         if (handle->callback.CardInserted)
@@ -689,7 +712,7 @@
 
 static void SDHC_TransferHandleCommand(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags)
 {
-    assert(interruptFlags & kSDHC_CommandFlag);
+    assert(handle->command);
 
     if ((interruptFlags & kSDHC_CommandErrorFlag) && (!(handle->data)) && (handle->callback.TransferComplete))
     {
@@ -709,7 +732,6 @@
 static void SDHC_TransferHandleData(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags)
 {
     assert(handle->data);
-    assert(interruptFlags & kSDHC_DataFlag);
 
     if ((!(handle->data->enableIgnoreError)) && (interruptFlags & (kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag)) &&
         (handle->callback.TransferComplete))
@@ -759,6 +781,8 @@
 #if !defined FSL_SDHC_ENABLE_ADMA1
     assert(config->dmaMode != kSDHC_DmaModeAdma1);
 #endif /* FSL_SDHC_ENABLE_ADMA1 */
+    assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U));
+    assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U));
 
     uint32_t proctl;
     uint32_t wml;
@@ -850,7 +874,8 @@
 
 uint32_t SDHC_SetSdClock(SDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
 {
-    assert(busClock_Hz && (busClock_Hz < srcClock_Hz));
+    assert(srcClock_Hz != 0U);
+    assert((busClock_Hz != 0U) && (busClock_Hz <= srcClock_Hz));
 
     uint32_t divisor;
     uint32_t prescaler;
@@ -898,7 +923,7 @@
 {
     base->SYSCTL |= SDHC_SYSCTL_INITA_MASK;
     /* Delay some time to wait card become active state. */
-    while (!(base->SYSCTL & SDHC_SYSCTL_INITA_MASK))
+    while (base->SYSCTL & SDHC_SYSCTL_INITA_MASK)
     {
         if (!timeout)
         {
@@ -913,6 +938,8 @@
 void SDHC_SetTransferConfig(SDHC_Type *base, const sdhc_transfer_config_t *config)
 {
     assert(config);
+    assert(config->dataBlockSize <= (SDHC_BLKATTR_BLKSIZE_MASK >> SDHC_BLKATTR_BLKSIZE_SHIFT));
+    assert(config->dataBlockCount <= (SDHC_BLKATTR_BLKCNT_MASK >> SDHC_BLKATTR_BLKCNT_SHIFT));
 
     base->BLKATTR = ((base->BLKATTR & ~(SDHC_BLKATTR_BLKSIZE_MASK | SDHC_BLKATTR_BLKCNT_MASK)) |
                      (SDHC_BLKATTR_BLKSIZE(config->dataBlockSize) | SDHC_BLKATTR_BLKCNT(config->dataBlockCount)));
@@ -975,12 +1002,13 @@
 void SDHC_SetMmcBootConfig(SDHC_Type *base, const sdhc_boot_config_t *config)
 {
     assert(config);
-
-    uint32_t mmcboot;
+    assert(config->ackTimeoutCount <= (SDHC_MMCBOOT_DTOCVACK_MASK >> SDHC_MMCBOOT_DTOCVACK_SHIFT));
+    assert(config->blockCount <= (SDHC_MMCBOOT_BOOTBLKCNT_MASK >> SDHC_MMCBOOT_BOOTBLKCNT_SHIFT));
 
-    mmcboot = base->MMCBOOT;
-    mmcboot |= (SDHC_MMCBOOT_DTOCVACK(config->ackTimeoutCount) | SDHC_MMCBOOT_BOOTMODE(config->bootMode) |
-                SDHC_MMCBOOT_BOOTBLKCNT(config->blockCount));
+    uint32_t mmcboot = 0U;
+
+    mmcboot = (SDHC_MMCBOOT_DTOCVACK(config->ackTimeoutCount) | SDHC_MMCBOOT_BOOTMODE(config->bootMode) |
+              SDHC_MMCBOOT_BOOTBLKCNT(config->blockCount));
     if (config->enableBootAck)
     {
         mmcboot |= SDHC_MMCBOOT_BOOTACK_MASK;
@@ -1016,6 +1044,9 @@
         (!data) || (!dataBytes)
 #if !defined FSL_SDHC_ENABLE_ADMA1
         || (dmaMode == kSDHC_DmaModeAdma1)
+#else
+        /* Buffer address configured in ADMA1 descriptor must be 4KB aligned. */
+        || ((dmaMode == kSDHC_DmaModeAdma1) && (((uint32_t)data % SDHC_ADMA1_LENGTH_ALIGN) != 0U))
 #endif /* FSL_SDHC_ENABLE_ADMA1 */
             )
     {
@@ -1029,6 +1060,17 @@
                 break;
 #if defined FSL_SDHC_ENABLE_ADMA1
             case kSDHC_DmaModeAdma1:
+                /*
+                * Add non aligned access support ,user need make sure your buffer size is big
+                * enough to hold the data,in other words,user need make sure the buffer size
+                * is 4 byte aligned
+                */
+                if (dataBytes % sizeof(uint32_t) != 0U)
+                {
+                    dataBytes +=
+                        sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); /* make the data length as word-aligned */
+                }
+
                 startAddress = data;
                 /* Check if ADMA descriptor's number is enough. */
                 entries = ((dataBytes / SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
@@ -1054,7 +1096,7 @@
                             adma1EntryAddress[i + 1U] =
                                 ((uint32_t)(startAddress) << SDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT);
                             adma1EntryAddress[i + 1U] |=
-                                (SDHC_ADMA1_DESCRIPTOR_TYPE_TRANSFER | SDHC_ADMA1_DESCRIPTOR_END_MASK);
+                                (kSDHC_Adma1DescriptorTypeTransfer | kSDHC_Adma1DescriptorEndFlag);
                         }
                         else
                         {
@@ -1075,6 +1117,17 @@
                 break;
 #endif /* FSL_SDHC_ENABLE_ADMA1 */
             case kSDHC_DmaModeAdma2:
+                /*
+                 * Add non aligned access support ,user need make sure your buffer size is big
+                 * enough to hold the data,in other words,user need make sure the buffer size
+                 * is 4 byte aligned
+                 */
+                if (dataBytes % sizeof(uint32_t) != 0U)
+                {
+                    dataBytes +=
+                        sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); /* make the data length as word-aligned */
+                }
+
                 startAddress = data;
                 /* Check if ADMA descriptor's number is enough. */
                 entries = ((dataBytes / SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
@@ -1125,15 +1178,14 @@
 status_t SDHC_TransferBlocking(SDHC_Type *base, uint32_t *admaTable, uint32_t admaTableWords, sdhc_transfer_t *transfer)
 {
     assert(transfer);
-    assert(transfer->command); /* Command must not be NULL, data can be NULL. */
 
     status_t error = kStatus_Success;
     sdhc_dma_mode_t dmaMode = (sdhc_dma_mode_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT);
     sdhc_command_t *command = transfer->command;
     sdhc_data_t *data = transfer->data;
 
-    /* DATA-PORT is 32-bit align, ADMA2 4 bytes align, ADMA1 is 4096 bytes align */
-    if ((!command) || (data && (data->blockSize % 4U)))
+    /* make sure the cmd/block count is valid */
+    if ((!command) || (data && (data->blockCount > SDHC_MAX_BLOCK_COUNT)))
     {
         error = kStatus_InvalidArgument;
     }
@@ -1147,7 +1199,7 @@
         {
         }
 
-        /* Update ADMA descriptor table if data isn't NULL. */
+        /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
         if (data && (kStatus_Success != SDHC_SetAdmaTableConfig(base, dmaMode, admaTable, admaTableWords,
                                                                 (data->rxData ? data->rxData : data->txData),
                                                                 (data->blockCount * data->blockSize))))
@@ -1156,9 +1208,8 @@
         }
         else
         {
+            /* Send command and receive data. */
             SDHC_StartTransfer(base, command, data);
-
-            /* Send command and receive data. */
             if (kStatus_Success != SDHC_SendCommandBlocking(base, command))
             {
                 error = kStatus_SDHC_SendCommandFailed;
@@ -1200,6 +1251,10 @@
 
     /* Enable interrupt in NVIC. */
     SDHC_SetTransferInterrupt(base, true);
+
+    /* save IRQ handler */
+    s_sdhcIsr = SDHC_TransferHandleIRQ;
+
     EnableIRQ(s_sdhcIRQ[SDHC_GetInstance(base)]);
 }
 
@@ -1213,8 +1268,8 @@
     sdhc_command_t *command = transfer->command;
     sdhc_data_t *data = transfer->data;
 
-    /* DATA-PORT is 32-bit align, ADMA2 4 bytes align, ADMA1 is 4096 bytes align */
-    if ((!(transfer->command)) || ((transfer->data) && (transfer->data->blockSize % 4U)))
+    /* make sure cmd/block count is valid */
+    if ((!command) || (data && (data->blockCount > SDHC_MAX_BLOCK_COUNT)))
     {
         error = kStatus_InvalidArgument;
     }
@@ -1228,7 +1283,7 @@
         }
         else
         {
-            /* Update ADMA descriptor table and reset transferred words if data isn't NULL. */
+            /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
             if (data && (kStatus_Success != SDHC_SetAdmaTableConfig(base, dmaMode, admaTable, admaTableWords,
                                                                     (data->rxData ? data->rxData : data->txData),
                                                                     (data->blockCount * data->blockSize))))
@@ -1243,6 +1298,7 @@
                 handle->interruptFlags = 0U;
                 /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
                 handle->transferredWords = 0U;
+
                 SDHC_StartTransfer(base, command, data);
             }
         }
@@ -1289,6 +1345,6 @@
 {
     assert(s_sdhcHandle[0]);
 
-    SDHC_TransferHandleIRQ(SDHC, s_sdhcHandle[0]);
+    s_sdhcIsr(SDHC, s_sdhcHandle[0]);
 }
 #endif