1 /**
2   ******************************************************************************
3   * @file    stm32n6xx_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) 2023 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 "stm32n6xx_hal.h"
38 
39 /** @addtogroup STM32N6xx_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 /** @addtogroup MMCEx_Exported_Functions_Group1
64   *  @brief   Linked List management functions
65   *
66 @verbatim
67  ===============================================================================
68                    ##### Linked List management functions #####
69  ===============================================================================
70     [..]
71     This subsection provides a set of functions allowing to manage the needed functions.
72 
73 @endverbatim
74   * @{
75   */
76 
77 /**
78   * @brief  Build Linked List node.
79   * @param  pNode: Pointer to new node to add.
80   * @param  pNodeConf: Pointer to configuration parameters for new node to add.
81   * @retval HAL status
82   */
HAL_MMCEx_DMALinkedList_BuildNode(MMC_DMALinkNodeTypeDef * pNode,MMC_DMALinkNodeConfTypeDef * pNodeConf)83 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_BuildNode(MMC_DMALinkNodeTypeDef *pNode,
84                                                     MMC_DMALinkNodeConfTypeDef *pNodeConf)
85 {
86 
87   if (SDMMC_DMALinkedList_BuildNode(pNode, pNodeConf) != SDMMC_ERROR_NONE)
88   {
89     return (HAL_ERROR);
90   }
91   else
92   {
93     return (HAL_OK);
94   }
95 
96 }
97 /**
98   * @brief  Insert Linked List node.
99   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
100   * @param  pPrevNode: Pointer to previous node.
101   * @param  pNewNode: Pointer to new node to insert.
102   * @retval HAL status
103   */
HAL_MMCEx_DMALinkedList_InsertNode(MMC_DMALinkedListTypeDef * pLinkedList,MMC_DMALinkNodeTypeDef * pPrevNode,MMC_DMALinkNodeTypeDef * pNewNode)104 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_InsertNode(MMC_DMALinkedListTypeDef *pLinkedList,
105                                                      MMC_DMALinkNodeTypeDef *pPrevNode,
106                                                      MMC_DMALinkNodeTypeDef *pNewNode)
107 {
108 
109   if (SDMMC_DMALinkedList_InsertNode(pLinkedList, pPrevNode, pNewNode) != SDMMC_ERROR_NONE)
110   {
111     return (HAL_ERROR);
112   }
113   else
114   {
115     return (HAL_OK);
116   }
117 
118 }
119 /**
120   * @brief  Remove Linked List node.
121   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
122   * @param  pNode: Pointer to node to remove.
123   * @retval HAL status
124   */
HAL_MMCEx_DMALinkedList_RemoveNode(MMC_DMALinkedListTypeDef * pLinkedList,MMC_DMALinkNodeTypeDef * pNode)125 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_RemoveNode(MMC_DMALinkedListTypeDef *pLinkedList,
126                                                      MMC_DMALinkNodeTypeDef *pNode)
127 {
128 
129   if (SDMMC_DMALinkedList_RemoveNode(pLinkedList, pNode) != SDMMC_ERROR_NONE)
130   {
131     return (HAL_ERROR);
132   }
133   else
134   {
135     return (HAL_OK);
136   }
137 }
138 
139 /**
140   * @brief  Lock Linked List node.
141   * @param  pNode: Pointer to node to remove.
142   * @retval HAL status
143   */
HAL_MMCEx_DMALinkedList_LockNode(MMC_DMALinkNodeTypeDef * pNode)144 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_LockNode(MMC_DMALinkNodeTypeDef *pNode)
145 {
146 
147   if (SDMMC_DMALinkedList_LockNode(pNode) != SDMMC_ERROR_NONE)
148   {
149     return HAL_ERROR;
150   }
151   else
152   {
153     return HAL_OK;
154   }
155 }
156 
157 /**
158   * @brief  Unlock Linked List node.
159   * @param  pNode: Pointer to node to remove.
160   * @retval HAL status
161   */
HAL_MMCEx_DMALinkedList_UnlockNode(MMC_DMALinkNodeTypeDef * pNode)162 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_UnlockNode(MMC_DMALinkNodeTypeDef *pNode)
163 {
164 
165   if (SDMMC_DMALinkedList_UnlockNode(pNode) != SDMMC_ERROR_NONE)
166   {
167     return HAL_ERROR;
168   }
169   else
170   {
171     return HAL_OK;
172   }
173 }
174 
175 /**
176   * @brief  Enable Circular mode for DMA Linked List mode.
177   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
178   * @retval HAL status
179   */
HAL_MMCEx_DMALinkedList_EnableCircularMode(MMC_DMALinkedListTypeDef * pLinkedList)180 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_EnableCircularMode(MMC_DMALinkedListTypeDef *pLinkedList)
181 {
182 
183   if (SDMMC_DMALinkedList_EnableCircularMode(pLinkedList) != SDMMC_ERROR_NONE)
184   {
185     return HAL_ERROR;
186   }
187   else
188   {
189     return HAL_OK;
190   }
191 }
192 /**
193   * @brief  Disable Circular mode for DMA Linked List mode.
194   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
195   * @retval HAL status
196   */
HAL_MMCEx_DMALinkedList_DisableCircularMode(MMC_DMALinkedListTypeDef * pLinkedList)197 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_DisableCircularMode(MMC_DMALinkedListTypeDef *pLinkedList)
198 {
199 
200   if (SDMMC_DMALinkedList_DisableCircularMode(pLinkedList) != SDMMC_ERROR_NONE)
201   {
202     return HAL_ERROR;
203   }
204   else
205   {
206     return HAL_OK;
207   }
208 }
209 
210 
211 /**
212   * @brief  Reads block(s) from a specified address in a card. The received Data will be stored in linked list buffers.
213   *         linked list should be prepared before call this function .
214   * @param  hmmc: MMC handle
215   * @param  pLinkedList: pointer to first linked list node
216   * @param  BlockAdd: Block Address from where data is to be read
217   * @param  NumberOfBlocks: Total number of blocks to read
218   * @retval HAL status
219   */
HAL_MMCEx_DMALinkedList_ReadBlocks(MMC_HandleTypeDef * hmmc,const MMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)220 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_ReadBlocks(MMC_HandleTypeDef *hmmc,
221                                                      const 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,const MMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)330 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_WriteBlocks(MMC_HandleTypeDef *hmmc,
331                                                       const MMC_DMALinkedListTypeDef *pLinkedList,
332                                                       uint32_t BlockAdd, uint32_t NumberOfBlocks)
333 {
334   SDMMC_DataInitTypeDef config;
335   uint32_t errorstate;
336   uint32_t DmaBase0_reg;
337   uint32_t DmaBase1_reg;
338   uint32_t add = BlockAdd;
339 
340   if (hmmc->State == HAL_MMC_STATE_READY)
341   {
342     if ((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
343     {
344       hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
345       return HAL_ERROR;
346     }
347 
348     /* Check the case of 4kB blocks (field DATA SECTOR SIZE of extended CSD register) */
349     if (((hmmc->Ext_CSD[(MMC_EXT_CSD_DATA_SEC_SIZE_INDEX / 4)] >> MMC_EXT_CSD_DATA_SEC_SIZE_POS) & 0x000000FFU) != 0x0U)
350     {
351       if ((NumberOfBlocks % 8U) != 0U)
352       {
353         /* The number of blocks should be a multiple of 8 sectors of 512 bytes = 4 KBytes */
354         hmmc->ErrorCode |= HAL_MMC_ERROR_BLOCK_LEN_ERR;
355         return HAL_ERROR;
356       }
357 
358       if ((BlockAdd % 8U) != 0U)
359       {
360         /* The address should be aligned to 8 (corresponding to 4 KBytes blocks) */
361         hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_MISALIGNED;
362         return HAL_ERROR;
363       }
364     }
365 
366     hmmc->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
367     hmmc->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
368 
369     hmmc->Instance->IDMABAR = (uint32_t)  pLinkedList->pHeadNode;
370     hmmc->Instance->IDMALAR = (uint32_t)  SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
371                               sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
372 
373     DmaBase0_reg = hmmc->Instance->IDMABASER;
374     DmaBase1_reg = hmmc->Instance->IDMABAR;
375 
376     if ((hmmc->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
377     {
378       hmmc->ErrorCode = HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
379       return HAL_ERROR;
380     }
381 
382     /* Initialize data control register */
383     hmmc->Instance->DCTRL = 0;
384 
385     hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
386 
387     hmmc->State = HAL_MMC_STATE_BUSY;
388 
389     if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
390     {
391       add *= 512U;
392     }
393 
394     /* Configure the MMC DPSM (Data Path State Machine) */
395     config.DataTimeOut   = SDMMC_DATATIMEOUT;
396     config.DataLength    = MMC_BLOCKSIZE * NumberOfBlocks;
397     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
398     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;
399     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
400     config.DPSM          = SDMMC_DPSM_DISABLE;
401     (void)SDMMC_ConfigData(hmmc->Instance, &config);
402 
403     __SDMMC_CMDTRANS_ENABLE(hmmc->Instance);
404 
405     hmmc->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
406 
407     /* Write Blocks in DMA mode */
408     hmmc->Context = (MMC_CONTEXT_WRITE_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
409 
410     /* Write Multi Block command */
411     errorstate = SDMMC_CmdWriteMultiBlock(hmmc->Instance, add);
412     if (errorstate != HAL_MMC_ERROR_NONE)
413     {
414       hmmc->State = HAL_MMC_STATE_READY;
415       hmmc->ErrorCode |= errorstate;
416       return HAL_ERROR;
417     }
418 
419     __HAL_MMC_ENABLE_IT(hmmc, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND |
420                                SDMMC_FLAG_IDMATE | SDMMC_FLAG_IDMABTC));
421 
422     return HAL_OK;
423   }
424   else
425   {
426     return HAL_BUSY;
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