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