1 /**
2   ******************************************************************************
3   * @file    stm32u5xx_hal_mmc_ex.c
4   * @author  MCD Application Team
5   * @brief   MMC card Extended HAL module driver.
6   *          This file provides firmware functions to manage the following
7   *          functionalities of the Secure Digital (MMC) peripheral:
8   *           + Extended features functions
9   *
10   ******************************************************************************
11   * @attention
12   *
13   * Copyright (c) 2021 STMicroelectronics.
14   * All rights reserved.
15   *
16   * This software is licensed under terms that can be found in the LICENSE file
17   * in the root directory of this software component.
18   * If no LICENSE file comes with this software, it is provided AS-IS.
19   *
20   ******************************************************************************
21   @verbatim
22   ==============================================================================
23                         ##### How to use this driver #####
24   ==============================================================================
25   [..]
26    The MMC Extension HAL driver can be used as follows:
27    (+) Configure Buffer0 and Buffer1 start address and Buffer size using HAL_MMCEx_ConfigDMAMultiBuffer() function.
28 
29    (+) Start Read and Write for multibuffer mode using HAL_MMCEx_ReadBlocksDMAMultiBuffer() and
30        HAL_MMCEx_WriteBlocksDMAMultiBuffer() functions.
31 
32   @endverbatim
33   ******************************************************************************
34   */
35 
36 /* Includes ------------------------------------------------------------------*/
37 #include "stm32u5xx_hal.h"
38 
39 /** @addtogroup STM32U5xx_HAL_Driver
40   * @{
41   */
42 
43 /** @defgroup MMCEx MMCEx
44   * @brief MMC Extended HAL module driver
45   * @{
46   */
47 
48 #if defined (SDMMC1) || defined (SDMMC2)
49 #ifdef HAL_MMC_MODULE_ENABLED
50 
51 /* Private typedef -----------------------------------------------------------*/
52 /* Private define ------------------------------------------------------------*/
53 /* Private macro -------------------------------------------------------------*/
54 /* Private variables ---------------------------------------------------------*/
55 /* Private function prototypes -----------------------------------------------*/
56 /* Private functions ---------------------------------------------------------*/
57 /* Exported functions --------------------------------------------------------*/
58 /** @addtogroup MMCEx_Exported_Functions
59   * @{
60   */
61 
62 
63 
64 /** @addtogroup MMCEx_Exported_Functions_Group1
65   *  @brief   Linked List management functions
66   *
67 @verbatim
68  ===============================================================================
69                    ##### Linked List management functions #####
70  ===============================================================================
71     [..]
72     This subsection provides a set of functions allowing to manage the needed functions.
73 
74 @endverbatim
75   * @{
76   */
77 
78 /**
79   * @brief  Build Linked List node.
80   * @param  pNode: Pointer to new node to add.
81   * @param  pNodeConf: Pointer to configuration parameters for new node to add.
82   * @retval HAL status
83   */
HAL_MMCEx_DMALinkedList_BuildNode(MMC_DMALinkNodeTypeDef * pNode,MMC_DMALinkNodeConfTypeDef * pNodeConf)84 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_BuildNode(MMC_DMALinkNodeTypeDef *pNode,
85                                                     MMC_DMALinkNodeConfTypeDef *pNodeConf)
86 {
87 
88   if (SDMMC_DMALinkedList_BuildNode(pNode, pNodeConf) != SDMMC_ERROR_NONE)
89   {
90     return (HAL_ERROR);
91   }
92   else
93   {
94     return (HAL_OK);
95   }
96 
97 }
98 /**
99   * @brief  Insert Linked List node.
100   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
101   * @param  pPrevNode: Pointer to previous node.
102   * @param  pNewNode: Pointer to new node to insert.
103   * @retval HAL status
104   */
HAL_MMCEx_DMALinkedList_InsertNode(MMC_DMALinkedListTypeDef * pLinkedList,MMC_DMALinkNodeTypeDef * pPrevNode,MMC_DMALinkNodeTypeDef * pNewNode)105 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_InsertNode(MMC_DMALinkedListTypeDef *pLinkedList,
106                                                      MMC_DMALinkNodeTypeDef *pPrevNode,
107                                                      MMC_DMALinkNodeTypeDef *pNewNode)
108 {
109 
110   if (SDMMC_DMALinkedList_InsertNode(pLinkedList, pPrevNode, pNewNode) != SDMMC_ERROR_NONE)
111   {
112     return (HAL_ERROR);
113   }
114   else
115   {
116     return (HAL_OK);
117   }
118 
119 }
120 /**
121   * @brief  Remove Linked List node.
122   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
123   * @param  pNode: Pointer to node to remove.
124   * @retval HAL status
125   */
HAL_MMCEx_DMALinkedList_RemoveNode(MMC_DMALinkedListTypeDef * pLinkedList,MMC_DMALinkNodeTypeDef * pNode)126 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_RemoveNode(MMC_DMALinkedListTypeDef *pLinkedList,
127                                                      MMC_DMALinkNodeTypeDef *pNode)
128 {
129 
130   if (SDMMC_DMALinkedList_RemoveNode(pLinkedList, pNode) != SDMMC_ERROR_NONE)
131   {
132     return (HAL_ERROR);
133   }
134   else
135   {
136     return (HAL_OK);
137   }
138 }
139 
140 /**
141   * @brief  Lock Linked List node.
142   * @param  pNode: Pointer to node to remove.
143   * @retval HAL status
144   */
HAL_MMCEx_DMALinkedList_LockNode(MMC_DMALinkNodeTypeDef * pNode)145 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_LockNode(MMC_DMALinkNodeTypeDef *pNode)
146 {
147 
148   if (SDMMC_DMALinkedList_LockNode(pNode) != SDMMC_ERROR_NONE)
149   {
150     return HAL_ERROR;
151   }
152   else
153   {
154     return HAL_OK;
155   }
156 }
157 
158 /**
159   * @brief  Unlock Linked List node.
160   * @param  pNode: Pointer to node to remove.
161   * @retval HAL status
162   */
HAL_MMCEx_DMALinkedList_UnlockNode(MMC_DMALinkNodeTypeDef * pNode)163 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_UnlockNode(MMC_DMALinkNodeTypeDef *pNode)
164 {
165 
166   if (SDMMC_DMALinkedList_UnlockNode(pNode) != SDMMC_ERROR_NONE)
167   {
168     return HAL_ERROR;
169   }
170   else
171   {
172     return HAL_OK;
173   }
174 }
175 
176 /**
177   * @brief  Enable Circular mode for DMA Linked List mode.
178   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
179   * @retval HAL status
180   */
HAL_MMCEx_DMALinkedList_EnableCircularMode(MMC_DMALinkedListTypeDef * pLinkedList)181 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_EnableCircularMode(MMC_DMALinkedListTypeDef *pLinkedList)
182 {
183 
184   if (SDMMC_DMALinkedList_EnableCircularMode(pLinkedList) != SDMMC_ERROR_NONE)
185   {
186     return HAL_ERROR;
187   }
188   else
189   {
190     return HAL_OK;
191   }
192 }
193 /**
194   * @brief  Disable Circular mode for DMA Linked List mode.
195   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
196   * @retval HAL status
197   */
HAL_MMCEx_DMALinkedList_DisableCircularMode(MMC_DMALinkedListTypeDef * pLinkedList)198 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_DisableCircularMode(MMC_DMALinkedListTypeDef *pLinkedList)
199 {
200 
201   if (SDMMC_DMALinkedList_DisableCircularMode(pLinkedList) != SDMMC_ERROR_NONE)
202   {
203     return HAL_ERROR;
204   }
205   else
206   {
207     return HAL_OK;
208   }
209 }
210 
211 
212 /**
213   * @brief  Reads block(s) from a specified address in a card. The received Data will be stored in linked list buffers.
214   *         linked list should be prepared before call this function .
215   * @param  hmmc: MMC handle
216   * @param  pLinkedList: pointer to first linked list node
217   * @param  BlockAdd: Block Address from where data is to be read
218   * @param  NumberOfBlocks: Total number of blocks to read
219   * @retval HAL status
220   */
HAL_MMCEx_DMALinkedList_ReadBlocks(MMC_HandleTypeDef * hmmc,MMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)221 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_ReadBlocks(MMC_HandleTypeDef *hmmc, MMC_DMALinkedListTypeDef *pLinkedList,
222                                                      uint32_t BlockAdd, uint32_t NumberOfBlocks)
223 {
224   SDMMC_DataInitTypeDef config;
225   uint32_t DmaBase0_reg;
226   uint32_t DmaBase1_reg;
227   uint32_t errorstate;
228   uint32_t add = BlockAdd;
229 
230   if (hmmc->State == HAL_MMC_STATE_READY)
231   {
232     if ((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
233     {
234       hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
235       return HAL_ERROR;
236     }
237 
238     /* Check the case of 4kB blocks (field DATA SECTOR SIZE of extended CSD register) */
239     if (((hmmc->Ext_CSD[(MMC_EXT_CSD_DATA_SEC_SIZE_INDEX / 4)] >> MMC_EXT_CSD_DATA_SEC_SIZE_POS) & 0x000000FFU) != 0x0U)
240     {
241       if ((NumberOfBlocks % 8U) != 0U)
242       {
243         /* The number of blocks should be a multiple of 8 sectors of 512 bytes = 4 KBytes */
244         hmmc->ErrorCode |= HAL_MMC_ERROR_BLOCK_LEN_ERR;
245         return HAL_ERROR;
246       }
247 
248       if ((BlockAdd % 8U) != 0U)
249       {
250         /* The address should be aligned to 8 (corresponding to 4 KBytes blocks) */
251         hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_MISALIGNED;
252         return HAL_ERROR;
253       }
254     }
255 
256     hmmc->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
257     hmmc->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
258     hmmc->Instance->IDMABAR   = (uint32_t) pLinkedList->pHeadNode;
259     hmmc->Instance->IDMALAR   = (uint32_t) SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
260                                 sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
261 
262     DmaBase0_reg = hmmc->Instance->IDMABASER;
263     DmaBase1_reg = hmmc->Instance->IDMABAR;
264 
265     if ((hmmc->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
266     {
267       hmmc->ErrorCode = HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
268       return HAL_ERROR;
269     }
270 
271     /* Initialize data control register */
272     hmmc->Instance->DCTRL = 0;
273 
274     hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
275     hmmc->State = HAL_MMC_STATE_BUSY;
276 
277     if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
278     {
279       add *= 512U;
280     }
281 
282     /* Configure the MMC DPSM (Data Path State Machine) */
283     config.DataTimeOut   = SDMMC_DATATIMEOUT;
284     config.DataLength    = MMC_BLOCKSIZE * NumberOfBlocks;
285     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
286     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;
287     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
288     config.DPSM          = SDMMC_DPSM_DISABLE;
289     (void)SDMMC_ConfigData(hmmc->Instance, &config);
290 
291     hmmc->Instance->DCTRL |= SDMMC_DCTRL_FIFORST;
292 
293     __SDMMC_CMDTRANS_ENABLE(hmmc->Instance);
294 
295     hmmc->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
296 
297     /* Read Blocks in DMA mode */
298     hmmc->Context = (MMC_CONTEXT_READ_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
299 
300     /* Read Multi Block command */
301     errorstate = SDMMC_CmdReadMultiBlock(hmmc->Instance, add);
302     if (errorstate != HAL_MMC_ERROR_NONE)
303     {
304       hmmc->State = HAL_MMC_STATE_READY;
305       hmmc->ErrorCode |= errorstate;
306       return HAL_ERROR;
307     }
308 
309     __HAL_MMC_ENABLE_IT(hmmc, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND |
310                                SDMMC_FLAG_IDMATE | SDMMC_FLAG_IDMABTC));
311 
312     return HAL_OK;
313   }
314   else
315   {
316     return HAL_BUSY;
317   }
318 
319 }
320 
321 /**
322   * @brief  Write block(s) to a specified address in a card. The transferred Data are stored linked list nodes buffers .
323   *         linked list should be prepared before call this function .
324   * @param  hmmc: MMC handle
325   * @param  pLinkedList: pointer to first linked list node
326   * @param  BlockAdd: Block Address from where data is to be read
327   * @param  NumberOfBlocks: Total number of blocks to read
328   * @retval HAL status
329   */
HAL_MMCEx_DMALinkedList_WriteBlocks(MMC_HandleTypeDef * hmmc,MMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)330 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_WriteBlocks(MMC_HandleTypeDef *hmmc, MMC_DMALinkedListTypeDef *pLinkedList,
331                                                       uint32_t BlockAdd, uint32_t NumberOfBlocks)
332 {
333   SDMMC_DataInitTypeDef config;
334   uint32_t errorstate;
335   uint32_t DmaBase0_reg;
336   uint32_t DmaBase1_reg;
337   uint32_t add = BlockAdd;
338 
339   if (hmmc->State == HAL_MMC_STATE_READY)
340   {
341     if ((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
342     {
343       hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
344       return HAL_ERROR;
345     }
346 
347     /* Check the case of 4kB blocks (field DATA SECTOR SIZE of extended CSD register) */
348     if (((hmmc->Ext_CSD[(MMC_EXT_CSD_DATA_SEC_SIZE_INDEX / 4)] >> MMC_EXT_CSD_DATA_SEC_SIZE_POS) & 0x000000FFU) != 0x0U)
349     {
350       if ((NumberOfBlocks % 8U) != 0U)
351       {
352         /* The number of blocks should be a multiple of 8 sectors of 512 bytes = 4 KBytes */
353         hmmc->ErrorCode |= HAL_MMC_ERROR_BLOCK_LEN_ERR;
354         return HAL_ERROR;
355       }
356 
357       if ((BlockAdd % 8U) != 0U)
358       {
359         /* The address should be aligned to 8 (corresponding to 4 KBytes blocks) */
360         hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_MISALIGNED;
361         return HAL_ERROR;
362       }
363     }
364 
365     hmmc->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
366     hmmc->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
367 
368     hmmc->Instance->IDMABAR = (uint32_t)  pLinkedList->pHeadNode;
369     hmmc->Instance->IDMALAR = (uint32_t)  SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
370                               sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
371 
372     DmaBase0_reg = hmmc->Instance->IDMABASER;
373     DmaBase1_reg = hmmc->Instance->IDMABAR;
374 
375     if ((hmmc->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
376     {
377       hmmc->ErrorCode = HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
378       return HAL_ERROR;
379     }
380 
381     /* Initialize data control register */
382     hmmc->Instance->DCTRL = 0;
383 
384     hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
385 
386     hmmc->State = HAL_MMC_STATE_BUSY;
387 
388     if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
389     {
390       add *= 512U;
391     }
392 
393     /* Configure the MMC DPSM (Data Path State Machine) */
394     config.DataTimeOut   = SDMMC_DATATIMEOUT;
395     config.DataLength    = MMC_BLOCKSIZE * NumberOfBlocks;
396     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
397     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;
398     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
399     config.DPSM          = SDMMC_DPSM_DISABLE;
400     (void)SDMMC_ConfigData(hmmc->Instance, &config);
401 
402     __SDMMC_CMDTRANS_ENABLE(hmmc->Instance);
403 
404     hmmc->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
405 
406     /* Write Blocks in DMA mode */
407     hmmc->Context = (MMC_CONTEXT_WRITE_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
408 
409     /* Write Multi Block command */
410     errorstate = SDMMC_CmdWriteMultiBlock(hmmc->Instance, add);
411     if (errorstate != HAL_MMC_ERROR_NONE)
412     {
413       hmmc->State = HAL_MMC_STATE_READY;
414       hmmc->ErrorCode |= errorstate;
415       return HAL_ERROR;
416     }
417 
418     __HAL_MMC_ENABLE_IT(hmmc, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND |
419                                SDMMC_FLAG_IDMATE | SDMMC_FLAG_IDMABTC));
420 
421     return HAL_OK;
422   }
423   else
424   {
425     return HAL_BUSY;
426   }
427 }
428 
429 
430 
431 /**
432   * @}
433   */
434 
435 /**
436   * @}
437   */
438 
439 #endif /* HAL_MMC_MODULE_ENABLED */
440 #endif /* SDMMC1 || SDMMC2 */
441 
442 /**
443   * @}
444   */
445 
446 /**
447   * @}
448   */
449