From abe676e453a5fe3d170574488e9c5c45d3ead0c6 Mon Sep 17 00:00:00 2001 From: Dawid Wojtas Date: Fri, 26 Jan 2024 10:44:50 +0100 Subject: [PATCH] [BH-1866] Port new eMMC driver to Pure This port updates only the eMMC driver and a few files from new FSL. This change should solve an issue with init eMMC memory. --- board/rt1051/cmsis/MIMXRT1051_features.h | 16 +- module-bsp/board/rt1051/CMakeLists.txt | 3 + .../rt1051/bellpx/bsp/lpm/PowerProfile.cpp | 2 +- .../bsp/eMMC/fsl_component_generic_list.c | 493 +++ .../bsp/eMMC/fsl_component_generic_list.h | 219 ++ module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.c | 2694 +++++++++-------- module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.h | 697 +++-- .../rt1051/bsp/eMMC/fsl_os_abstraction.h | 948 ++++++ .../bsp/eMMC/fsl_os_abstraction_config.h | 44 + .../bsp/eMMC/fsl_os_abstraction_free_rtos.c | 1117 +++++++ .../bsp/eMMC/fsl_os_abstraction_free_rtos.h | 132 + .../board/rt1051/bsp/eMMC/fsl_sdmmc_common.c | 270 +- .../board/rt1051/bsp/eMMC/fsl_sdmmc_common.h | 421 ++- .../board/rt1051/bsp/eMMC/fsl_sdmmc_host.c | 1097 +++++-- .../board/rt1051/bsp/eMMC/fsl_sdmmc_host.h | 1121 +++---- .../board/rt1051/bsp/eMMC/fsl_sdmmc_osa.c | 275 ++ .../board/rt1051/bsp/eMMC/fsl_sdmmc_osa.h | 170 ++ .../board/rt1051/bsp/eMMC/fsl_sdmmc_spec.h | 662 ++-- .../rt1051/common/fsl_drivers/fsl_common.h | 15 + .../rt1051/common/fsl_drivers/fsl_usdhc.c | 1823 ++++++++--- .../rt1051/common/fsl_drivers/fsl_usdhc.h | 2355 +++++++------- .../board/rt1051/puretx/board/pin_mux.h | 5 +- .../board/rt1051/puretx/clock_config.cpp | 4 +- module-bsp/board/rt1051/puretx/pin_mux.c | 183 +- module-platform/rt1051/src/disk_emmc.cpp | 61 +- module-platform/rt1051/src/disk_emmc.hpp | 2 + products/PurePhone/BinaryAssetsVersions.cmake | 4 +- 27 files changed, 10146 insertions(+), 4687 deletions(-) create mode 100644 module-bsp/board/rt1051/bsp/eMMC/fsl_component_generic_list.c create mode 100644 module-bsp/board/rt1051/bsp/eMMC/fsl_component_generic_list.h create mode 100644 module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction.h create mode 100644 module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_config.h create mode 100644 module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_free_rtos.c create mode 100644 module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_free_rtos.h create mode 100644 module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_osa.c create mode 100644 module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_osa.h diff --git a/board/rt1051/cmsis/MIMXRT1051_features.h b/board/rt1051/cmsis/MIMXRT1051_features.h index ef23a939684c0831cd2cd64494ba94e0286f699e..014b7be200bc776f8863aa1b2f30260ebd9af5a8 100644 --- a/board/rt1051/cmsis/MIMXRT1051_features.h +++ b/board/rt1051/cmsis/MIMXRT1051_features.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md /* @@ -594,6 +594,20 @@ #define FSL_FEATURE_USDHC_HAS_SDR50_MODE (1) /* @brief Has SDR104 support (HOST_CTRL_CAP[SDR104_SUPPORT]) */ #define FSL_FEATURE_USDHC_HAS_SDR104_MODE (1) +/* @brief USDHC has reset control */ +#define FSL_FEATURE_USDHC_HAS_RESET (0) +/* @brief USDHC has no bitfield WTMK_LVL[WR_BRST_LEN] and WTMK_LVL[RD_BRST_LEN] */ +#define FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN (0) +/* @brief If USDHC instance support 8 bit width */ +#define FSL_FEATURE_USDHC_INSTANCE_SUPPORT_8_BIT_WIDTHn(x) (((x) == USDHC1) ? (0) : (((x) == USDHC2) ? (1) : (-1))) +/* @brief If USDHC instance support HS400 mode */ +#define FSL_FEATURE_USDHC_INSTANCE_SUPPORT_HS400_MODEn(x) (0) +/* @brief If USDHC instance support 1v8 signal */ +#define FSL_FEATURE_USDHC_INSTANCE_SUPPORT_1V8_SIGNALn(x) (1) +/* @brief Has no retuning time counter (HOST_CTRL_CAP[TIME_COUNT_RETURNING]) */ +#define FSL_FEATURE_USDHC_REGISTER_HOST_CTRL_CAP_HAS_NO_RETUNING_TIME_COUNTER (0) +/* @brief Has no VSELECT bit in VEND_SPEC register */ +#define FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT (0) /* XBARA module features */ diff --git a/module-bsp/board/rt1051/CMakeLists.txt b/module-bsp/board/rt1051/CMakeLists.txt index 88022f23185fba07c169ed27c8bafac0e111c447..b6eec7cac15afaa9cc115d49ad17c16576899e47 100644 --- a/module-bsp/board/rt1051/CMakeLists.txt +++ b/module-bsp/board/rt1051/CMakeLists.txt @@ -19,6 +19,9 @@ target_sources(module-bsp bsp/eMMC/fsl_sdmmc_common.c bsp/eMMC/fsl_sdmmc_event.c bsp/eMMC/fsl_sdmmc_host.c + bsp/eMMC/fsl_sdmmc_osa.c + bsp/eMMC/fsl_os_abstraction_free_rtos.c + bsp/eMMC/fsl_component_generic_list.c bsp/headset/headset.cpp bsp/keypad_backlight/keypad_backlight.cpp bsp/light_sensor/light_sensor.cpp diff --git a/module-bsp/board/rt1051/bellpx/bsp/lpm/PowerProfile.cpp b/module-bsp/board/rt1051/bellpx/bsp/lpm/PowerProfile.cpp index 1a4111ef6b2bd140847d8da43d755e5d5e6eda2a..f8f53f362c950519953195236d37cf47f9e860a1 100644 --- a/module-bsp/board/rt1051/bellpx/bsp/lpm/PowerProfile.cpp +++ b/module-bsp/board/rt1051/bellpx/bsp/lpm/PowerProfile.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_component_generic_list.c b/module-bsp/board/rt1051/bsp/eMMC/fsl_component_generic_list.c new file mode 100644 index 0000000000000000000000000000000000000000..17fa3fd8d18f84ce1ee544a5a9c8afb707b8737b --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_component_generic_list.c @@ -0,0 +1,493 @@ +/* + * Copyright 2018-2019, 2022 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*! ********************************************************************************* +************************************************************************************* +* Include +************************************************************************************* +********************************************************************************** */ +#include "fsl_component_generic_list.h" + +#if defined(OSA_USED) +#include "fsl_os_abstraction.h" +#if (defined(USE_RTOS) && (USE_RTOS > 0U)) +#define LIST_ENTER_CRITICAL() \ + OSA_SR_ALLOC(); \ + OSA_ENTER_CRITICAL() +#define LIST_EXIT_CRITICAL() OSA_EXIT_CRITICAL() +#else +#define LIST_ENTER_CRITICAL() +#define LIST_EXIT_CRITICAL() +#endif +#else +#define LIST_ENTER_CRITICAL() uint32_t regPrimask = DisableGlobalIRQ(); +#define LIST_EXIT_CRITICAL() EnableGlobalIRQ(regPrimask); +#endif + +static list_status_t LIST_Error_Check(list_handle_t list, list_element_handle_t newElement) +{ + list_status_t listStatus = kLIST_Ok; +#if (defined(GENERIC_LIST_DUPLICATED_CHECKING) && (GENERIC_LIST_DUPLICATED_CHECKING > 0U)) + list_element_handle_t element = list->head; +#endif + if ((list->max != 0U) && (list->max == list->size)) + { + listStatus = kLIST_Full; /*List is full*/ + } +#if (defined(GENERIC_LIST_DUPLICATED_CHECKING) && (GENERIC_LIST_DUPLICATED_CHECKING > 0U)) + else + { + while (element != NULL) /*Scan list*/ + { + /* Determine if element is duplicated */ + if (element == newElement) + { + listStatus = kLIST_DuplicateError; + break; + } + element = element->next; + } + } +#endif + return listStatus; +} + +/*! ********************************************************************************* +************************************************************************************* +* Public functions +************************************************************************************* +********************************************************************************** */ +/*! ********************************************************************************* + * \brief Initializes the list descriptor. + * + * \param[in] list - LIST_ handle to init. + * max - Maximum number of elements in list. 0 for unlimited. + * + * \return void. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +void LIST_Init(list_handle_t list, uint32_t max) +{ + list->head = NULL; + list->tail = NULL; + list->max = max; + list->size = 0; +} + +/*! ********************************************************************************* + * \brief Gets the list that contains the given element. + * + * \param[in] element - Handle of the element. + * + * \return NULL if element is orphan. + * Handle of the list the element is inserted into. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +list_handle_t LIST_GetList(list_element_handle_t element) +{ + return element->list; +} + +/*! ********************************************************************************* + * \brief Links element to the tail of the list. + * + * \param[in] list - ID of list to insert into. + * element - element to add + * + * \return kLIST_Full if list is full. + * kLIST_Ok if insertion was successful. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +list_status_t LIST_AddTail(list_handle_t list, list_element_handle_t element) +{ + LIST_ENTER_CRITICAL(); + list_status_t listStatus = kLIST_Ok; + + listStatus = LIST_Error_Check(list, element); + if (listStatus == kLIST_Ok) /* Avoiding list status error */ + { + if (list->size == 0U) + { + list->head = element; + } + else + { + list->tail->next = element; + } +#if (defined(GENERIC_LIST_LIGHT) && (GENERIC_LIST_LIGHT > 0U)) +#else + element->prev = list->tail; +#endif + element->list = list; + element->next = NULL; + list->tail = element; + list->size++; + } + + LIST_EXIT_CRITICAL(); + return listStatus; +} + +/*! ********************************************************************************* + * \brief Links element to the head of the list. + * + * \param[in] list - ID of list to insert into. + * element - element to add + * + * \return kLIST_Full if list is full. + * kLIST_Ok if insertion was successful. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +list_status_t LIST_AddHead(list_handle_t list, list_element_handle_t element) +{ + LIST_ENTER_CRITICAL(); + list_status_t listStatus = kLIST_Ok; + + listStatus = LIST_Error_Check(list, element); + if (listStatus == kLIST_Ok) /* Avoiding list status error */ + { + /* Links element to the head of the list */ + if (list->size == 0U) + { + list->tail = element; + } +#if (defined(GENERIC_LIST_LIGHT) && (GENERIC_LIST_LIGHT > 0U)) +#else + else + { + list->head->prev = element; + } + element->prev = NULL; +#endif + element->list = list; + element->next = list->head; + list->head = element; + list->size++; + } + + LIST_EXIT_CRITICAL(); + return listStatus; +} + +/*! ********************************************************************************* + * \brief Unlinks element from the head of the list. + * + * \param[in] list - ID of list to remove from. + * + * \return NULL if list is empty. + * ID of removed element(pointer) if removal was successful. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +list_element_handle_t LIST_RemoveHead(list_handle_t list) +{ + list_element_handle_t element; + + LIST_ENTER_CRITICAL(); + + if ((NULL == list) || (list->size == 0U)) + { + element = NULL; /*LIST_ is empty*/ + } + else + { + element = list->head; + list->size--; + if (list->size == 0U) + { + list->tail = NULL; + } +#if (defined(GENERIC_LIST_LIGHT) && (GENERIC_LIST_LIGHT > 0U)) +#else + else + { + element->next->prev = NULL; + } +#endif + element->list = NULL; + list->head = element->next; /*Is NULL if element is head*/ + } + + LIST_EXIT_CRITICAL(); + return element; +} + +/*! ********************************************************************************* + * \brief Gets head element ID. + * + * \param[in] list - ID of list. + * + * \return NULL if list is empty. + * ID of head element if list is not empty. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +list_element_handle_t LIST_GetHead(list_handle_t list) +{ + return list->head; +} + +/*! ********************************************************************************* + * \brief Gets next element ID. + * + * \param[in] element - ID of the element. + * + * \return NULL if element is tail. + * ID of next element if exists. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +list_element_handle_t LIST_GetNext(list_element_handle_t element) +{ + return element->next; +} + +/*! ********************************************************************************* + * \brief Gets previous element ID. + * + * \param[in] element - ID of the element. + * + * \return NULL if element is head. + * ID of previous element if exists. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +list_element_handle_t LIST_GetPrev(list_element_handle_t element) +{ +#if (defined(GENERIC_LIST_LIGHT) && (GENERIC_LIST_LIGHT > 0U)) + return NULL; +#else + return element->prev; +#endif +} + +/*! ********************************************************************************* + * \brief Unlinks an element from its list. + * + * \param[in] element - ID of the element to remove. + * + * \return kLIST_OrphanElement if element is not part of any list. + * kLIST_Ok if removal was successful. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +list_status_t LIST_RemoveElement(list_element_handle_t element) +{ + list_status_t listStatus = kLIST_Ok; + LIST_ENTER_CRITICAL(); + + if (element->list == NULL) + { + listStatus = kLIST_OrphanElement; /*Element was previusly removed or never added*/ + } + else + { +#if (defined(GENERIC_LIST_LIGHT) && (GENERIC_LIST_LIGHT > 0U)) + list_element_handle_t element_list = element->list->head; + while (NULL != element_list) + { + if (element->list->head == element) + { + element->list->head = element_list->next; + break; + } + if (element_list->next == element) + { + element_list->next = element->next; + break; + } + element_list = element_list->next; + } +#else + if (element->prev == NULL) /*Element is head or solo*/ + { + element->list->head = element->next; /*is null if solo*/ + } + if (element->next == NULL) /*Element is tail or solo*/ + { + element->list->tail = element->prev; /*is null if solo*/ + } + if (element->prev != NULL) /*Element is not head*/ + { + element->prev->next = element->next; + } + if (element->next != NULL) /*Element is not tail*/ + { + element->next->prev = element->prev; + } +#endif + element->list->size--; + element->list = NULL; + } + + LIST_EXIT_CRITICAL(); + return listStatus; +} + +/*! ********************************************************************************* + * \brief Links an element in the previous position relative to a given member + * of a list. + * + * \param[in] element - ID of a member of a list. + * newElement - new element to insert before the given member. + * + * \return kLIST_OrphanElement if element is not part of any list. + * kLIST_Full if list is full. + * kLIST_Ok if insertion was successful. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +list_status_t LIST_AddPrevElement(list_element_handle_t element, list_element_handle_t newElement) +{ + list_status_t listStatus = kLIST_Ok; + LIST_ENTER_CRITICAL(); + + if (element->list == NULL) + { + listStatus = kLIST_OrphanElement; /*Element was previusly removed or never added*/ + } + else + { + listStatus = LIST_Error_Check(element->list, newElement); + if (listStatus == kLIST_Ok) + { +#if (defined(GENERIC_LIST_LIGHT) && (GENERIC_LIST_LIGHT > 0U)) + list_element_handle_t element_list = element->list->head; + while (NULL != element_list) + { + if ((element_list->next == element) || (element_list == element)) + { + if (element_list == element) + { + element->list->head = newElement; + } + else + { + element_list->next = newElement; + } + newElement->list = element->list; + newElement->next = element; + element->list->size++; + break; + } + element_list = element_list->next; + } + +#else + if (element->prev == NULL) /*Element is list head*/ + { + element->list->head = newElement; + } + else + { + element->prev->next = newElement; + } + newElement->list = element->list; + element->list->size++; + newElement->next = element; + newElement->prev = element->prev; + element->prev = newElement; +#endif + } + } + + LIST_EXIT_CRITICAL(); + return listStatus; +} + +/*! ********************************************************************************* + * \brief Gets the current size of a list. + * + * \param[in] list - ID of the list. + * + * \return Current size of the list. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +uint32_t LIST_GetSize(list_handle_t list) +{ + return list->size; +} + +/*! ********************************************************************************* + * \brief Gets the number of free places in the list. + * + * \param[in] list - ID of the list. + * + * \return Available size of the list. + * + * \pre + * + * \post + * + * \remarks + * + ********************************************************************************** */ +uint32_t LIST_GetAvailableSize(list_handle_t list) +{ + return (list->max - list->size); /*Gets the number of free places in the list*/ +} diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_component_generic_list.h b/module-bsp/board/rt1051/bsp/eMMC/fsl_component_generic_list.h new file mode 100644 index 0000000000000000000000000000000000000000..53e12b58560c9fcde4af84e56ebe8a30f6eac521 --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_component_generic_list.h @@ -0,0 +1,219 @@ +/* + * Copyright 2018-2020, 2022 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _GENERIC_LIST_H_ +#define _GENERIC_LIST_H_ + +#ifndef SDK_COMPONENT_DEPENDENCY_FSL_COMMON +#define SDK_COMPONENT_DEPENDENCY_FSL_COMMON (1U) +#endif +#if (defined(SDK_COMPONENT_DEPENDENCY_FSL_COMMON) && (SDK_COMPONENT_DEPENDENCY_FSL_COMMON > 0U)) +#include "fsl_common.h" +#else +#endif +/*! + * @addtogroup GenericList + * @{ + */ + +/********************************************************************************** + * Include + ***********************************************************************************/ + +/********************************************************************************** + * Public macro definitions + ***********************************************************************************/ +/*! @brief Definition to determine whether use list light. */ +#ifndef GENERIC_LIST_LIGHT +#define GENERIC_LIST_LIGHT (1) +#endif + +/*! @brief Definition to determine whether enable list duplicated checking. */ +#ifndef GENERIC_LIST_DUPLICATED_CHECKING +#define GENERIC_LIST_DUPLICATED_CHECKING (0) +#endif + +/********************************************************************************** + * Public type definitions + ***********************************************************************************/ +/*! @brief The list status */ +#if (defined(SDK_COMPONENT_DEPENDENCY_FSL_COMMON) && (SDK_COMPONENT_DEPENDENCY_FSL_COMMON > 0U)) +typedef enum _list_status +{ + kLIST_Ok = kStatus_Success, /*!< Success */ + kLIST_DuplicateError = MAKE_STATUS(kStatusGroup_LIST, 1), /*!< Duplicate Error */ + kLIST_Full = MAKE_STATUS(kStatusGroup_LIST, 2), /*!< FULL */ + kLIST_Empty = MAKE_STATUS(kStatusGroup_LIST, 3), /*!< Empty */ + kLIST_OrphanElement = MAKE_STATUS(kStatusGroup_LIST, 4), /*!< Orphan Element */ + kLIST_NotSupport = MAKE_STATUS(kStatusGroup_LIST, 5), /*!< Not Support */ +} list_status_t; +#else +typedef enum _list_status +{ + kLIST_Ok = 0, /*!< Success */ + kLIST_DuplicateError = 1, /*!< Duplicate Error */ + kLIST_Full = 2, /*!< FULL */ + kLIST_Empty = 3, /*!< Empty */ + kLIST_OrphanElement = 4, /*!< Orphan Element */ + kLIST_NotSupport = 5, /*!< Not Support */ +} list_status_t; +#endif + +/*! @brief The list structure*/ +typedef struct list_label +{ + struct list_element_tag *head; /*!< list head */ + struct list_element_tag *tail; /*!< list tail */ + uint32_t size; /*!< list size */ + uint32_t max; /*!< list max number of elements */ +} list_label_t, *list_handle_t; +#if (defined(GENERIC_LIST_LIGHT) && (GENERIC_LIST_LIGHT > 0U)) +/*! @brief The list element*/ +typedef struct list_element_tag +{ + struct list_element_tag *next; /*!< next list element */ + struct list_label *list; /*!< pointer to the list */ +} list_element_t, *list_element_handle_t; +#else +/*! @brief The list element*/ +typedef struct list_element_tag +{ + struct list_element_tag *next; /*!< next list element */ + struct list_element_tag *prev; /*!< previous list element */ + struct list_label *list; /*!< pointer to the list */ +} list_element_t, *list_element_handle_t; +#endif +/********************************************************************************** + * Public prototypes + ***********************************************************************************/ +/********************************************************************************** + * API + **********************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* _cplusplus */ +/*! + * @brief Initialize the list. + * + * This function initialize the list. + * + * @param list - List handle to initialize. + * @param max - Maximum number of elements in list. 0 for unlimited. + */ +void LIST_Init(list_handle_t list, uint32_t max); + +/*! + * @brief Gets the list that contains the given element. + * + * + * @param element - Handle of the element. + * @retval NULL if element is orphan, Handle of the list the element is inserted into. + */ +list_handle_t LIST_GetList(list_element_handle_t element); + +/*! + * @brief Links element to the head of the list. + * + * @param list - Handle of the list. + * @param element - Handle of the element. + * @retval kLIST_Full if list is full, kLIST_Ok if insertion was successful. + */ +list_status_t LIST_AddHead(list_handle_t list, list_element_handle_t element); + +/*! + * @brief Links element to the tail of the list. + * + * @param list - Handle of the list. + * @param element - Handle of the element. + * @retval kLIST_Full if list is full, kLIST_Ok if insertion was successful. + */ +list_status_t LIST_AddTail(list_handle_t list, list_element_handle_t element); + +/*! + * @brief Unlinks element from the head of the list. + * + * @param list - Handle of the list. + * + * @retval NULL if list is empty, handle of removed element(pointer) if removal was successful. + */ +list_element_handle_t LIST_RemoveHead(list_handle_t list); + +/*! + * @brief Gets head element handle. + * + * @param list - Handle of the list. + * + * @retval NULL if list is empty, handle of removed element(pointer) if removal was successful. + */ +list_element_handle_t LIST_GetHead(list_handle_t list); + +/*! + * @brief Gets next element handle for given element handle. + * + * @param element - Handle of the element. + * + * @retval NULL if list is empty, handle of removed element(pointer) if removal was successful. + */ +list_element_handle_t LIST_GetNext(list_element_handle_t element); + +/*! + * @brief Gets previous element handle for given element handle. + * + * @param element - Handle of the element. + * + * @retval NULL if list is empty, handle of removed element(pointer) if removal was successful. + */ +list_element_handle_t LIST_GetPrev(list_element_handle_t element); + +/*! + * @brief Unlinks an element from its list. + * + * @param element - Handle of the element. + * + * @retval kLIST_OrphanElement if element is not part of any list. + * @retval kLIST_Ok if removal was successful. + */ +list_status_t LIST_RemoveElement(list_element_handle_t element); + +/*! + * @brief Links an element in the previous position relative to a given member of a list. + * + * @param element - Handle of the element. + * @param newElement - New element to insert before the given member. + * + * @retval kLIST_OrphanElement if element is not part of any list. + * @retval kLIST_Ok if removal was successful. + */ +list_status_t LIST_AddPrevElement(list_element_handle_t element, list_element_handle_t newElement); + +/*! + * @brief Gets the current size of a list. + * + * @param list - Handle of the list. + * + * @retval Current size of the list. + */ +uint32_t LIST_GetSize(list_handle_t list); + +/*! + * @brief Gets the number of free places in the list. + * + * @param list - Handle of the list. + * + * @retval Available size of the list. + */ +uint32_t LIST_GetAvailableSize(list_handle_t list); + +/* @} */ + +#if defined(__cplusplus) +} +#endif +/*! @}*/ +#endif /*_GENERIC_LIST_H_*/ diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.c b/module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.c index 4fe53561d0e75d2044529a69584ca35d076a110f..1941e78177d52f3cc083a504042ac0270144b596 100644 --- a/module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.c +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.c @@ -1,50 +1,31 @@ /* - * The Clear BSD License * Copyright (c) 2015, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted (subject to the limitations in the disclaimer below) provided - * that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * o Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #include #include "fsl_mmc.h" -#include - /******************************************************************************* * Definitons ******************************************************************************/ /*! @brief The divide value used to avoid float point calculation when calculate max speed in normal mode. */ #define DIVIDER_IN_TRANSFER_SPEED (10U) - -#define keMMC_HIGH_VOLTAGE_RANGE 0xC0FF8000U /*!< for eMMC > 2Gb sector mode */ - +/*! @brief MMC CMD1 retry times */ +#ifndef MMC_CMD1_RETRY_TIMES +#define MMC_CMD1_RETRY_TIMES (10000U) +#endif +#ifndef MMC_CMD13_RETRY_TIMES +#define MMC_CMD13_RETRY_TIMES (1000000U) +#endif +#ifndef MMC_CARD_ACCESS_WAIT_IDLE_TIMEOUT +#define MMC_CARD_ACCESS_WAIT_IDLE_TIMEOUT (10000U) +#endif +/*!@brief power reset delay */ +#define MMC_POWER_RESET_DELAY (500U) /******************************************************************************* * Prototypes ******************************************************************************/ @@ -56,7 +37,7 @@ * @retval kStatus_SDMMC_TransferFailed Transfer failed. * @retval kStatus_Success Operate successfully. */ -inline static status_t MMC_SelectCard(mmc_card_t *card, bool isSelected); +static inline status_t MMC_SelectCard(mmc_card_t *card, bool isSelected); /*! * @brief Send SET_BLOCK_COUNT command. @@ -66,7 +47,7 @@ inline static status_t MMC_SelectCard(mmc_card_t *card, bool isSelected); * @retval kStatus_SDMMC_TransferFailed Transfer failed. * @retval kStatus_Success Operate successfully. */ -inline static status_t MMC_SetBlockCount(mmc_card_t *card, uint32_t blockCount); +static inline status_t MMC_SetBlockCount(mmc_card_t *card, uint32_t blockCount); /*! * @brief Send GO_IDLE command to reset all cards to idle state @@ -75,7 +56,7 @@ inline static status_t MMC_SetBlockCount(mmc_card_t *card, uint32_t blockCount); * @retval kStatus_SDMMC_TransferFailed Transfer failed. * @retval kStatus_Success Operate successfully. */ -inline static status_t MMC_GoIdle(mmc_card_t *card); +static inline status_t MMC_GoIdle(mmc_card_t *card); /*! * @brief Send STOP_TRANSMISSION command to card to stop ongoing data transferring. @@ -94,17 +75,7 @@ static status_t MMC_StopTransmission(mmc_card_t *card); * @retval kStatus_SDMMC_TransferFailed Transfer failed. * @retval kStatus_Success Operate successfully. */ -inline static status_t MMC_SetBlockSize(mmc_card_t *card, uint32_t blockSize); - -/*! - * @brief switch voltage. - * - * @param card Card descriptor. - * @param opcode use to send operation condition - * @retval kStatus_SDMMC_HostNotSupport Host doesn't support the voltage window to access the card. - * @retval kStatus_Success Operate successfully. - */ -static status_t MMC_SwitchVoltage(mmc_card_t *card, uint32_t *opCode); +static inline status_t MMC_SetBlockSize(mmc_card_t *card, uint32_t blockSize); /*! * @brief Send SEND_OPERATION_CONDITION command to validate if the card support host's voltage window @@ -141,6 +112,15 @@ static void MMC_DecodeCsd(mmc_card_t *card, uint32_t *rawCsd); */ static void MMC_SetMaxFrequency(mmc_card_t *card); +/*! + * @brief Set erase unit size of the card + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure Extended CSD failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card); + /*! * @brief Send SWITCH command to set the specific byte in Extended CSD. * @@ -156,11 +136,12 @@ static void MMC_SetMaxFrequency(mmc_card_t *card); * * @param card Card descriptor. * @param config Configuration for Extended CSD. + * @param timeout switch command timeout value. * @retval kStatus_SDMMC_TransferFailed Transfer failed. * @retval kStatus_SDMMC_WaitWriteCompleteFailed Wait write complete failed. * @retval kStatus_Success Operate successfully. */ -static status_t MMC_SetExtendedCsdConfig(mmc_card_t *card, const mmc_extended_csd_config_t *config); +static status_t MMC_SetExtendedCsdConfig(mmc_card_t *card, const mmc_extended_csd_config_t *config, uint32_t timeout); /*! * @brief Decode the Extended CSD register @@ -187,7 +168,7 @@ static status_t MMC_SendExtendedCsd(mmc_card_t *card, uint8_t *targetAddr, uint3 * @param card Card descriptor. * @return The power class switch status. */ -static status_t MMC_SetPowerClass(mmc_card_t *card) __attribute__((used)); +static status_t MMC_SetPowerClass(mmc_card_t *card); /*! * @brief Send test pattern to get the functional pin in the MMC bus @@ -353,8 +334,7 @@ static status_t MMC_CheckEraseGroupRange(mmc_card_t *card, uint32_t startGroup, * @retval kStatus_SDMMC_TuningFail tuning fail. * @retval kStatus_SDMMC_TransferFailed transfer fail */ -inline static status_t MMC_ExecuteTuning(mmc_card_t *card); - +static inline status_t MMC_ExecuteTuning(mmc_card_t *card); /*! * @brief Read data from specific MMC card * @@ -390,6 +370,17 @@ static status_t MMC_Read( static status_t MMC_Write( mmc_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockSize, uint32_t blockCount); +/*! + * @brief MMC card erase function + * + * @param card Card descriptor. + * @param startGroupAddress start erase group address. + * @param endGroupAddress end erase group address. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_Erase(mmc_card_t *card, uint32_t startGroupAddress, uint32_t endGroupAddress); + /*! * @brief card transfer function wrapper * This function is used to do tuning before transfer if the cmd won't casue re-tuning @@ -401,9 +392,18 @@ static status_t MMC_Write( * @retval kStatus_SDMMC_TuningFail tuning fail * @retval kStatus_Success transfer success */ -static status_t MMC_Transfer(mmc_card_t *card, SDMMCHOST_TRANSFER *content, uint32_t retry); +static status_t MMC_Transfer(mmc_card_t *card, sdmmchost_transfer_t *content, uint32_t retry); -static status_t MMC_SendIdentifyDevice(mmc_card_t *card, uint32_t arg); +/*! + * @brief card validate operation voltage + * This function is used to validate the operation voltage bettwen host and card + * + * @param card Card descriptor. + * @param opcode Retry times. + * @retval kStatus_Fail the operation voltage condition doesn't match between card and host + * @retval kStatus_Success voltage validate successfully + */ +static status_t MMC_ValidateOperationVoltage(mmc_card_t *card, uint32_t *opcode); /******************************************************************************* * Variables @@ -411,301 +411,312 @@ static status_t MMC_SendIdentifyDevice(mmc_card_t *card, uint32_t arg); /* Frequency unit defined in TRANSFER SPEED field in CSD */ static const uint32_t g_transerSpeedFrequencyUnit[] = {100000U, 1000000U, 10000000U, 100000000U}; /* The multiplying value defined in TRANSFER SPEED field in CSD */ -static const uint32_t g_transerSpeedMultiplierFactor[] = { - 0U, 10U, 12U, 13U, 15U, 20U, 26U, 30U, 35U, 40U, 45U, 52U, 55U, 60U, 70U, 80U}; -/* g_sdmmc statement */ -extern uint32_t g_sdmmc[SDK_SIZEALIGN(SDMMC_GLOBAL_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)]; +static const uint32_t g_transerSpeedMultiplierFactor[] = {0U, 10U, 12U, 13U, 15U, 20U, 26U, 30U, + 35U, 40U, 45U, 52U, 55U, 60U, 70U, 80U}; /******************************************************************************* * Code ******************************************************************************/ -inline static status_t MMC_SelectCard(mmc_card_t *card, bool isSelected) +static inline status_t MMC_SelectCard(mmc_card_t *card, bool isSelected) { - assert(card); + assert(card != NULL); - return SDMMC_SelectCard(card->host.base, card->host.transfer, card->relativeAddress, isSelected); + return SDMMC_SelectCard(card->host, card->relativeAddress, isSelected); } -inline static status_t MMC_SetBlockCount(mmc_card_t *card, uint32_t blockCount) +static inline status_t MMC_SetBlockCount(mmc_card_t *card, uint32_t blockCount) { - assert(card); + assert(card != NULL); - return SDMMC_SetBlockCount(card->host.base, card->host.transfer, blockCount); + return SDMMC_SetBlockCount(card->host, blockCount); } -inline static status_t MMC_GoIdle(mmc_card_t *card) +static inline status_t MMC_GoIdle(mmc_card_t *card) { - assert(card); + assert(card != NULL); - return SDMMC_GoIdle(card->host.base, card->host.transfer); + return SDMMC_GoIdle(card->host); } -inline static status_t MMC_SetBlockSize(mmc_card_t *card, uint32_t blockSize) +static inline status_t MMC_SetBlockSize(mmc_card_t *card, uint32_t blockSize) { - assert(card); + assert(card != NULL); - return SDMMC_SetBlockSize(card->host.base, card->host.transfer, blockSize); + return SDMMC_SetBlockSize(card->host, blockSize); } static status_t MMC_ExecuteTuning(mmc_card_t *card) { - assert(card); + assert(card != NULL); uint32_t blockSize = 0U; - if (card->busWidth == kMMC_DataBusWidth4bit) { + if (card->busWidth == kMMC_DataBusWidth4bit) + { blockSize = 64U; } - else if (card->busWidth == kMMC_DataBusWidth8bit) { + else if (card->busWidth == kMMC_DataBusWidth8bit) + { blockSize = 128U; } - else { + else + { /* do not need tuning in this situation */ return kStatus_Success; } - return SDMMC_ExecuteTuning(card->host.base, card->host.transfer, kMMC_SendTuningBlock, blockSize); + return SDMMCHOST_ExecuteTuning(card->host, (uint32_t)kMMC_SendTuningBlock, + (uint32_t *)FSL_SDMMC_CARD_INTERNAL_BUFFER_ALIGN_ADDR(card->internalBuffer), + blockSize); } -static status_t MMC_Transfer(mmc_card_t *card, SDMMCHOST_TRANSFER *content, uint32_t retry) +static status_t MMC_Transfer(mmc_card_t *card, sdmmchost_transfer_t *content, uint32_t retry) { - assert(card->host.transfer); - assert(content); + assert(content != NULL); status_t error; + uint32_t retuningCount = 3U; - do { - error = card->host.transfer(card->host.base, content); - if (((error == SDMMCHOST_RETUNING_REQUEST) || (error == SDMMCHOST_TUNING_ERROR)) && - ((card->busTiming == kMMC_HighSpeed200Timing) || (card->busTiming == kMMC_HighSpeed400Timing))) { - /* tuning error need reset tuning circuit */ - if (error == SDMMCHOST_TUNING_ERROR) { - SDMMCHOST_RESET_TUNING(card->host.base, 100U); - } - /* execute re-tuning */ - if (MMC_ExecuteTuning(card) != kStatus_Success) { - error = kStatus_SDMMC_TuningFail; - break; - } - else { - continue; - } - } - else if (error != kStatus_Success) { - error = kStatus_SDMMC_TransferFailed; + do + { + error = SDMMCHOST_TransferFunction(card->host, content); + + if (error == kStatus_Success) + { + break; } - else { + + if (((retry == 0U) && (content->data != NULL)) || (error == kStatus_SDMMC_ReTuningRequest)) + { + /* abort previous transfer firstly */ + (void)MMC_StopTransmission(card); + + if (card->busTiming == kMMC_HighSpeed200Timing) + { + if (--retuningCount == 0U) + { + break; + } + /* perform retuning */ + if (MMC_ExecuteTuning(card) != kStatus_Success) + { + error = kStatus_SDMMC_TuningFail; + SDMMC_LOG("\r\nError: retuning failed."); + break; + } + else + { + SDMMC_LOG("\r\nlog: retuning successfully."); + continue; + } + } } - if (retry != 0U) { + if (retry != 0U) + { retry--; } - else { + else + { break; } - } while ((error != kStatus_Success) && (error != kStatus_SDMMC_TuningFail)); + } while (true); return error; } -status_t MMC_WaitWriteComplete(mmc_card_t *card) +static status_t MMC_SendStatus(mmc_card_t *card, uint32_t *status) { - assert(card); - - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; + assert(card != NULL); + status_t error = kStatus_Success; + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + uint32_t retry = 10; - command.index = kSDMMC_SendStatus; + command.index = (uint32_t)kSDMMC_SendStatus; command.argument = card->relativeAddress << 16U; command.responseType = kCARD_ResponseTypeR1; - do { - content.command = &command; - content.data = 0U; - if (kStatus_Success != MMC_Transfer(card, &content, 2U)) { - return kStatus_SDMMC_TransferFailed; - } + content.command = &command; + content.data = NULL; - /* check the response error */ - if ((command.response[0U] & (kSDMMC_R1ErrorAllFlag | kSDMMC_R1SwitchErrorFlag))) { - return kStatus_SDMMC_WaitWriteCompleteFailed; + while (retry != 0U) + { + error = MMC_Transfer(card, &content, 2U); + if ((--retry == 0U) && (error != kStatus_Success)) + { + return kStatus_SDMMC_TransferFailed; } - if ((command.response[0U] & kSDMMC_R1ReadyForDataFlag) && - (SDMMC_R1_CURRENT_STATE(command.response[0U]) != kSDMMC_R1StateProgram)) { + if (kStatus_Success == error) + { break; } - } while (true); + } - return kStatus_Success; + *status = command.response[0U]; + + return error; } -static status_t MMC_StopTransmission(mmc_card_t *card) +status_t MMC_PollingCardStatusBusy(mmc_card_t *card, bool checkStatus, uint32_t timeoutMs) { - assert(card); + assert(card != NULL); - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; + uint32_t statusTimeoutUs = timeoutMs * 1000U; + bool cardBusy = false; + status_t error = kStatus_SDMMC_CardStatusBusy; + uint32_t status = 0U; - command.index = kSDMMC_StopTransmission; - command.argument = 0U; - command.type = kCARD_CommandTypeAbort; - command.responseType = kCARD_ResponseTypeR1b; - command.responseErrorFlags = kSDMMC_R1ErrorAllFlag; + do + { + cardBusy = SDMMCHOST_IsCardBusy(card->host); - content.command = &command; - content.data = 0U; - if (kStatus_Success != MMC_Transfer(card, &content, 2U)) { - return kStatus_SDMMC_TransferFailed; - } + if (cardBusy == false) + { + if (checkStatus) + { + error = MMC_SendStatus(card, &status); + if (kStatus_Success == error) + { + /* check the response error */ + if (0U != (status & (SDMMC_R1_ALL_ERROR_FLAG | SDMMC_MASK(kSDMMC_R1SwitchErrorFlag)))) + { + SDMMC_LOG("\r\nError: CMD13 report switch error %x.", status); + + error = kStatus_SDMMC_SwitchFailed; + } + else if ((0U != (status & SDMMC_MASK(kSDMMC_R1ReadyForDataFlag))) && + (SDMMC_R1_CURRENT_STATE(status) != (uint32_t)kSDMMC_R1StateProgram)) + { + error = kStatus_SDMMC_CardStatusIdle; + break; + } + else + { + SDMMC_LOG("\r\nWarning: CMD13 report busy %x.", status); + error = kStatus_SDMMC_CardStatusBusy; + } + } + else + { + error = kStatus_SDMMC_TransferFailed; + break; + } + } + else + { + error = kStatus_SDMMC_CardStatusIdle; + break; + } + } - return kStatus_Success; -} + if (statusTimeoutUs != 0U) + { + /* Delay 125us to throttle the polling rate */ + statusTimeoutUs -= SDMMC_OSADelayUs(125U); + } -static status_t MMC_SwitchVoltage(mmc_card_t *card, uint32_t *opCode) __attribute__((used)); -static status_t MMC_SwitchVoltage(mmc_card_t *card, uint32_t *opCode) -{ - mmc_voltage_window_t tempVoltage = kMMC_VoltageWindowNone; - /* Get host's voltage window. */ - if (((kSDMMCHOST_SupportV330 != SDMMCHOST_NOT_SUPPORT) || (kSDMMCHOST_SupportV300 != SDMMCHOST_NOT_SUPPORT)) && - (card->ocr & MMC_OCR_V270TO360_MASK) && - ((card->hostVoltageWindowVCC == kMMC_VoltageWindowNone) || - (card->hostVoltageWindowVCC == kMMC_VoltageWindows270to360))) { - /* Save host intended voltage range */ - tempVoltage = kMMC_VoltageWindows270to360; - /* set the opcode */ - *opCode = MMC_OCR_V270TO360_MASK; - /* power off the card first */ - SDMMCHOST_ENABLE_MMC_POWER(false); - /* power off time */ - SDMMCHOST_Delay(1U); - /*switch voltage to 3.3V*/ - SDMMCHOST_SWITCH_VCC_TO_330V(); - /* repower the card */ - SDMMCHOST_ENABLE_MMC_POWER(true); - /* meet emmc spec, wait 1ms and 74 clocks */ - SDMMCHOST_Delay(2U); - } - - if ((kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) && (card->ocr & MMC_OCR_V170TO195_MASK) && - ((card->hostVoltageWindowVCC == kMMC_VoltageWindowNone) || - (card->hostVoltageWindowVCC == kMMC_VoltageWindow170to195))) { - /* Save host intended voltage range */ - tempVoltage = kMMC_VoltageWindow170to195; - /* set the opcode */ - *opCode = MMC_OCR_V170TO195_MASK; - /* power off the card first */ - SDMMCHOST_ENABLE_MMC_POWER(false); - /* power off time */ - SDMMCHOST_Delay(1U); - /* switch voltage to 1.8V */ - SDMMCHOST_SWITCH_VCC_TO_180V(); - /* repower the card */ - SDMMCHOST_ENABLE_MMC_POWER(true); - /* meet emmc spec, wait 1ms and 74 clocks */ - SDMMCHOST_Delay(2U); - } - - card->hostVoltageWindowVCC = tempVoltage; + } while (statusTimeoutUs != 0U); - return kStatus_Success; + return error; } -static status_t MMC_SendIdentifyDevice(mmc_card_t *card, uint32_t arg) +static status_t MMC_StopTransmission(mmc_card_t *card) { - uint32_t count = 0; - uint32_t validvoltage = 0; - - while (validvoltage == 0) { - if (count++ == 0xFFFF) { - return kStatus_Timeout; - } + assert(card != NULL); - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; - - command.index = kMMC_SendOperationCondition; - command.argument = arg; - command.responseType = kCARD_ResponseTypeR3; - - content.command = &command; - content.data = NULL; - - if (kStatus_Success != card->host.transfer(card->host.base, &content)) { - return kStatus_SDMMC_TransferFailed; - } + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + status_t error = kStatus_Success; - /* Get operating voltage*/ - validvoltage = ((command.response[0] & MMC_OCR_BUSY_MASK) ? 1 : 0); + command.index = (uint32_t)kSDMMC_StopTransmission; + command.argument = 0U; + command.type = kCARD_CommandTypeAbort; + command.responseType = kCARD_ResponseTypeR1b; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; - card->ocr = command.response[0U]; - if (((card->ocr & MMC_OCR_ACCESS_MODE_MASK) >> MMC_OCR_ACCESS_MODE_SHIFT) == kMMC_AccessModeSector) { - card->flags |= kMMC_SupportHighCapacityFlag; - } + content.command = &command; + content.data = NULL; + error = SDMMCHOST_TransferFunction(card->host, &content); + if (kStatus_Success != error) + { + return kStatus_SDMMC_TransferFailed; } return kStatus_Success; } -static status_t MMC_SendOperationCondition(mmc_card_t *card, uint32_t arg) __attribute((used)); static status_t MMC_SendOperationCondition(mmc_card_t *card, uint32_t arg) { - assert(card); - assert(card->host.transfer); + assert(card != NULL); - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_TRANSFER content = {0}; + sdmmchost_cmd_t command = {0}; + sdmmchost_transfer_t content = {0}; status_t error; - uint32_t i = FSL_SDMMC_MAX_VOLTAGE_RETRIES; + uint32_t i = MMC_CMD1_RETRY_TIMES; /* Send CMD1 with the intended voltage range in the argument(either 0x00FF8000 or 0x00000080) */ - command.index = kMMC_SendOperationCondition; + command.index = (uint32_t)kMMC_SendOperationCondition; command.argument = arg; command.responseType = kCARD_ResponseTypeR3; content.command = &command; content.data = NULL; - do { - if (kStatus_Success != card->host.transfer(card->host.base, &content)) { - return kStatus_SDMMC_TransferFailed; - } + do + { + error = SDMMCHOST_TransferFunction(card->host, &content); - if ((arg == 0U) && (command.response[0U] != 0U)) { - error = kStatus_Success; - } - /* Repeat CMD1 until the busy bit is cleared. */ - else if (!(command.response[0U] & MMC_OCR_BUSY_MASK)) { - error = kStatus_Timeout; - } - else { - error = kStatus_Success; + if (error == kStatus_Success) + { + /* record OCR register */ card->ocr = command.response[0U]; - if (((card->ocr & MMC_OCR_ACCESS_MODE_MASK) >> MMC_OCR_ACCESS_MODE_SHIFT) == kMMC_AccessModeSector) { - card->flags |= kMMC_SupportHighCapacityFlag; + + if ((arg == 0U) && (command.response[0U] != 0U)) + { + error = kStatus_Success; + } + /* Repeat CMD1 until the busy bit is cleared. */ + else if (0U == (command.response[0U] & MMC_OCR_BUSY_MASK)) + { + error = kStatus_Timeout; + } + else + { + error = kStatus_Success; + if (((card->ocr & MMC_OCR_ACCESS_MODE_MASK) >> MMC_OCR_ACCESS_MODE_SHIFT) == + (uint32_t)kMMC_AccessModeSector) + { + card->flags |= (uint32_t)kMMC_SupportHighCapacityFlag; + } } } - } while ((i--) && (error != kStatus_Success)); + + SDMMC_OSADelay(10U); + + } while ((0U != i--) && (error != kStatus_Success)); return error; } static status_t MMC_SetRelativeAddress(mmc_card_t *card) { - assert(card); - assert(card->host.transfer); + assert(card != NULL); - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_TRANSFER content = {0}; + sdmmchost_cmd_t command = {0}; + sdmmchost_transfer_t content = {0}; + status_t error = kStatus_Success; /* Send CMD3 with a chosen relative address, with value greater than 1 */ - command.index = kMMC_SetRelativeAddress; + command.index = (uint32_t)kMMC_SetRelativeAddress; command.argument = (MMC_DEFAULT_RELATIVE_ADDRESS << 16U); command.responseType = kCARD_ResponseTypeR1; content.command = &command; content.data = NULL; - if ((kStatus_Success == card->host.transfer(card->host.base, &content)) || - (!((command.response[0U]) & kSDMMC_R1ErrorAllFlag))) { + error = SDMMCHOST_TransferFunction(card->host, &content); + if ((kStatus_Success == error) || (0U == ((command.response[0U]) & SDMMC_R1_ALL_ERROR_FLAG))) + { card->relativeAddress = MMC_DEFAULT_RELATIVE_ADDRESS; return kStatus_Success; } @@ -715,8 +726,8 @@ static status_t MMC_SetRelativeAddress(mmc_card_t *card) static void MMC_DecodeCsd(mmc_card_t *card, uint32_t *rawCsd) { - assert(card); - assert(rawCsd); + assert(card != NULL); + assert(rawCsd != NULL); mmc_csd_t *csd; uint32_t multiplier; @@ -730,17 +741,21 @@ static void MMC_DecodeCsd(mmc_card_t *card, uint32_t *rawCsd) csd->cardCommandClass = (uint16_t)((rawCsd[2U] & 0xFFF00000U) >> 20U); /* Max block length read/write one time */ csd->readBlockLength = (uint8_t)((rawCsd[2U] & 0xF0000U) >> 16U); - if (rawCsd[2U] & 0x8000U) { - csd->flags |= kMMC_CsdReadBlockPartialFlag; + if ((rawCsd[2U] & 0x8000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdReadBlockPartialFlag; } - if (rawCsd[2U] & 0x4000U) { - csd->flags |= kMMC_CsdWriteBlockMisalignFlag; + if ((rawCsd[2U] & 0x4000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdWriteBlockMisalignFlag; } - if (rawCsd[2U] & 0x2000U) { - csd->flags |= kMMC_CsdReadBlockMisalignFlag; + if ((rawCsd[2U] & 0x2000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdReadBlockMisalignFlag; } - if (rawCsd[2U] & 0x1000U) { - csd->flags |= kMMC_CsdDsrImplementedFlag; + if ((rawCsd[2U] & 0x1000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdDsrImplementedFlag; } csd->deviceSize = (uint16_t)(((rawCsd[2U] & 0x3FFU) << 2U) + ((rawCsd[1U] & 0xC0000000U) >> 30U)); csd->readCurrentVddMin = (uint8_t)((rawCsd[1U] & 0x38000000U) >> 27U); @@ -751,29 +766,36 @@ static void MMC_DecodeCsd(mmc_card_t *card, uint32_t *rawCsd) csd->eraseGroupSize = (uint8_t)((rawCsd[1U] & 0x00007C00U) >> 10U); csd->eraseGroupSizeMultiplier = (uint8_t)((rawCsd[1U] & 0x000003E0U) >> 5U); csd->writeProtectGroupSize = (uint8_t)(rawCsd[1U] & 0x0000001FU); - if (rawCsd[0U] & 0x80000000U) { - csd->flags |= kMMC_CsdWriteProtectGroupEnabledFlag; + if ((rawCsd[0U] & 0x80000000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdWriteProtectGroupEnabledFlag; } csd->defaultEcc = (uint8_t)((rawCsd[0U] & 0x60000000U) >> 29U); csd->writeSpeedFactor = (uint8_t)((rawCsd[0U] & 0x1C000000U) >> 26U); csd->maxWriteBlockLength = (uint8_t)((rawCsd[0U] & 0x03C00000U) >> 22U); - if (rawCsd[0U] & 0x00200000U) { - csd->flags |= kMMC_CsdWriteBlockPartialFlag; + if ((rawCsd[0U] & 0x00200000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdWriteBlockPartialFlag; } - if (rawCsd[0U] & 0x00010000U) { - csd->flags |= kMMC_ContentProtectApplicationFlag; + if ((rawCsd[0U] & 0x00010000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_ContentProtectApplicationFlag; } - if (rawCsd[0U] & 0x00008000U) { - csd->flags |= kMMC_CsdFileFormatGroupFlag; + if ((rawCsd[0U] & 0x00008000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdFileFormatGroupFlag; } - if (rawCsd[0U] & 0x00004000U) { - csd->flags |= kMMC_CsdCopyFlag; + if ((rawCsd[0U] & 0x00004000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdCopyFlag; } - if (rawCsd[0U] & 0x00002000U) { - csd->flags |= kMMC_CsdPermanentWriteProtectFlag; + if ((rawCsd[0U] & 0x00002000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdPermanentWriteProtectFlag; } - if (rawCsd[0U] & 0x00001000U) { - csd->flags |= kMMC_CsdTemporaryWriteProtectFlag; + if ((rawCsd[0U] & 0x00001000U) != 0U) + { + csd->flags |= (uint16_t)kMMC_CsdTemporaryWriteProtectFlag; } csd->fileFormat = (uint8_t)((rawCsd[0U] & 0x00000C00U) >> 10U); csd->eccCode = (uint8_t)((rawCsd[0U] & 0x00000300U) >> 8U); @@ -781,18 +803,18 @@ static void MMC_DecodeCsd(mmc_card_t *card, uint32_t *rawCsd) /* Calculate the device total block count. */ /* For the card capacity of witch higher than 2GB, the maximum possible value should be set to this register is 0xFFF. */ - if (card->csd.deviceSize != 0xFFFU) { - multiplier = (2U << (card->csd.deviceSizeMultiplier + 2U - 1U)); - card->userPartitionBlocks = (((card->csd.deviceSize + 1U) * multiplier) / FSL_SDMMC_DEFAULT_BLOCK_SIZE); + if (card->csd.deviceSize != 0xFFFU) + { + multiplier = (2UL << (card->csd.deviceSizeMultiplier + 2U - 1U)); + card->userPartitionBlocks = (((card->csd.deviceSize + 1UL) * multiplier) / FSL_SDMMC_DEFAULT_BLOCK_SIZE); } card->blockSize = FSL_SDMMC_DEFAULT_BLOCK_SIZE; } -static void MMC_SetMaxFrequency(mmc_card_t *card) __attribute__((used)); static void MMC_SetMaxFrequency(mmc_card_t *card) { - assert(card); + assert(card != NULL); uint32_t frequencyUnit; uint32_t multiplierFactor; @@ -806,33 +828,43 @@ static void MMC_SetMaxFrequency(mmc_card_t *card) frequencyUnit = g_transerSpeedFrequencyUnit[READ_MMC_TRANSFER_SPEED_FREQUENCY_UNIT(card->csd)]; multiplierFactor = g_transerSpeedMultiplierFactor[READ_MMC_TRANSFER_SPEED_MULTIPLIER(card->csd)]; maxBusClock_Hz = (frequencyUnit * multiplierFactor) / DIVIDER_IN_TRANSFER_SPEED; - card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, maxBusClock_Hz); + card->busClock_Hz = SDMMCHOST_SetCardClock(card->host, maxBusClock_Hz); } -status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card) __attribute__((used)); -status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card) +static status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card) { - assert(card); + assert(card != NULL); uint32_t erase_group_size; uint32_t erase_group_multiplier; mmc_extended_csd_config_t extendedCsdconfig; - if (((!(card->flags & kMMC_SupportHighCapacityFlag)) || (card->extendedCsd.highCapacityEraseUnitSize == 0)) || - (card->extendedCsd.highCapacityEraseTimeout == 0)) { + /* Legacy mmc card , do not support the command */ + if ((card->csd.systemSpecificationVersion == (uint32_t)kMMC_SpecificationVersion3) && + (card->csd.csdStructureVersion == (uint32_t)kMMC_CsdStrucureVersion12)) + { + return kStatus_Success; + } + + if (((0U == (card->flags & (uint32_t)kMMC_SupportHighCapacityFlag)) || + (card->extendedCsd.highCapacityEraseUnitSize == 0U)) || + (card->extendedCsd.highCapacityEraseTimeout == 0U)) + { erase_group_size = card->csd.eraseGroupSize; erase_group_multiplier = card->csd.eraseGroupSizeMultiplier; card->eraseGroupBlocks = ((erase_group_size + 1U) * (erase_group_multiplier + 1U)); } - else { + else + { /* Erase Unit Size = 512Kbyte * HC_ERASE_GRP_SIZE. Block size is 512 bytes. */ - card->eraseGroupBlocks = (card->extendedCsd.highCapacityEraseUnitSize * 1024U); + card->eraseGroupBlocks = (card->extendedCsd.highCapacityEraseUnitSize * 1024UL); /* Enable high capacity erase unit size. */ extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeSetBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexEraseGroupDefinition; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexEraseGroupDefinition; extendedCsdconfig.ByteValue = 0x01U; /* The high capacity erase unit size enable bit is bit 0 */ extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { return kStatus_SDMMC_ConfigureExtendedCsdFailed; } } @@ -840,35 +872,39 @@ status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card) return kStatus_Success; } -static status_t MMC_SetExtendedCsdConfig(mmc_card_t *card, const mmc_extended_csd_config_t *config) +static status_t MMC_SetExtendedCsdConfig(mmc_card_t *card, const mmc_extended_csd_config_t *config, uint32_t timeout) { - assert(card); - assert(card->host.transfer); - assert(config); + assert(card != NULL); + assert(config != NULL); - uint32_t parameter = 0U; - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_TRANSFER content = {0}; + status_t error = kStatus_Success; + uint32_t parameter = 0U; + sdmmchost_cmd_t command = {0}; + sdmmchost_transfer_t content = {0}; + uint32_t timeoutMS = timeout == 0U ? card->extendedCsd.genericCMD6Timeout : timeout; parameter |= ((uint32_t)(config->commandSet) << MMC_SWITCH_COMMAND_SET_SHIFT); parameter |= ((uint32_t)(config->ByteValue) << MMC_SWITCH_VALUE_SHIFT); parameter |= ((uint32_t)(config->ByteIndex) << MMC_SWITCH_BYTE_INDEX_SHIFT); parameter |= ((uint32_t)(config->accessMode) << MMC_SWITCH_ACCESS_MODE_SHIFT); - - command.index = kMMC_Switch; + command.index = (uint32_t)kMMC_Switch; command.argument = parameter; command.responseType = kCARD_ResponseTypeR1b; /* Send switch command to set the pointed byte in Extended CSD. */ - command.responseErrorFlags = kSDMMC_R1ErrorAllFlag | kSDMMC_R1SwitchErrorFlag; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG | SDMMC_MASK(kSDMMC_R1SwitchErrorFlag); content.command = &command; content.data = NULL; - if (kStatus_Success != MMC_Transfer(card, &content, 2U)) { + error = MMC_Transfer(card, &content, 2U); + if (kStatus_Success != error) + { return kStatus_SDMMC_TransferFailed; } /* Wait for the card write process complete because of that card read process and write process use one buffer. */ - if (kStatus_Success != MMC_WaitWriteComplete(card)) { - return kStatus_SDMMC_WaitWriteCompleteFailed; + error = MMC_PollingCardStatusBusy(card, true, timeoutMS == 0U ? MMC_CARD_ACCESS_WAIT_IDLE_TIMEOUT : timeoutMS); + if (kStatus_SDMMC_CardStatusIdle != error) + { + return kStatus_SDMMC_PollingCardIdleFailed; } return kStatus_Success; @@ -876,14 +912,13 @@ static status_t MMC_SetExtendedCsdConfig(mmc_card_t *card, const mmc_extended_cs static void MMC_DecodeExtendedCsd(mmc_card_t *card, uint32_t *rawExtendedCsd) { - assert(card); - assert(rawExtendedCsd); + assert(card != NULL); + assert(rawExtendedCsd != NULL); uint8_t *buffer = (uint8_t *)rawExtendedCsd; mmc_extended_csd_t *extendedCsd = &(card->extendedCsd); /* Extended CSD is transferred as a data block from least byte indexed 0. */ - extendedCsd->partitioningSupport = buffer[160U]; extendedCsd->bootPartitionWP = buffer[173U]; extendedCsd->bootWPStatus = buffer[174U]; extendedCsd->highDensityEraseGroupDefinition = buffer[175U]; @@ -894,7 +929,6 @@ static void MMC_DecodeExtendedCsd(mmc_card_t *card, uint32_t *rawExtendedCsd) extendedCsd->dataBusWidth = buffer[183U]; extendedCsd->highSpeedTiming = buffer[185U]; extendedCsd->powerClass = buffer[187U]; - extendedCsd->partitionSwitchTiming = buffer[199U]; extendedCsd->commandSetRevision = buffer[189U]; extendedCsd->commandSet = buffer[191U]; extendedCsd->extendecCsdVersion = buffer[192U]; @@ -907,6 +941,7 @@ static void MMC_DecodeExtendedCsd(mmc_card_t *card, uint32_t *rawExtendedCsd) extendedCsd->ioDriverStrength = buffer[197U]; + extendedCsd->partitionSwitchTimeout = buffer[199U]; extendedCsd->powerClass52MHz195V = buffer[200U]; extendedCsd->powerClass26MHz195V = buffer[201U]; extendedCsd->powerClass52MHz360V = buffer[202U]; @@ -927,7 +962,8 @@ static void MMC_DecodeExtendedCsd(mmc_card_t *card, uint32_t *rawExtendedCsd) /* Get user partition size. */ extendedCsd->sectorCount = ((((uint32_t)buffer[215U]) << 24U) + (((uint32_t)buffer[214U]) << 16U) + (((uint32_t)buffer[213U]) << 8U) + (uint32_t)buffer[212U]); - if (card->flags & kMMC_SupportHighCapacityFlag) { + if ((card->flags & (uint32_t)kMMC_SupportHighCapacityFlag) != 0U) + { card->userPartitionBlocks = card->extendedCsd.sectorCount; } @@ -940,96 +976,81 @@ static void MMC_DecodeExtendedCsd(mmc_card_t *card, uint32_t *rawExtendedCsd) extendedCsd->highCapacityEraseUnitSize = buffer[224U]; extendedCsd->accessSize = buffer[225U]; - /* General purpose partition multipliers */ - extendedCsd->generalPartition1Multi0 = buffer[143U]; - extendedCsd->generalPartition1Multi1 = buffer[144U]; - extendedCsd->generalPartition1Multi2 = buffer[145U]; - - extendedCsd->generalPartition2Multi0 = buffer[146U]; - extendedCsd->generalPartition2Multi1 = buffer[147U]; - extendedCsd->generalPartition2Multi2 = buffer[148U]; - - extendedCsd->generalPartition3Multi0 = buffer[149U]; - extendedCsd->generalPartition3Multi1 = buffer[150U]; - extendedCsd->generalPartition3Multi2 = buffer[151U]; - - extendedCsd->generalPartition4Multi0 = buffer[152U]; - extendedCsd->generalPartition4Multi1 = buffer[153U]; - extendedCsd->generalPartition4Multi2 = buffer[154U]; - - extendedCsd->partitioningSettingCompleted = buffer[155U]; - /* Get boot partition size: 128KB * BOOT_SIZE_MULT*/ card->bootPartitionBlocks = ((128U * 1024U * buffer[226U]) / FSL_SDMMC_DEFAULT_BLOCK_SIZE); + /* support HS400 data strobe */ + if (buffer[184] == 1U) + { + card->flags |= (uint32_t)kMMC_SupportEnhanceHS400StrobeFlag; + } + /* Check if card support boot mode. */ - if (buffer[228U] & 0x1U) { - card->flags |= kMMC_SupportAlternateBootFlag; + if ((buffer[228U] & 0x1U) != 0U) + { + card->flags |= (uint32_t)kMMC_SupportAlternateBootFlag; } - else if (buffer[228U] & 0x2U) { - card->flags |= kMMC_SupportDDRBootFlag; + else if ((buffer[228U] & 0x2U) != 0U) + { + card->flags |= (uint32_t)kMMC_SupportDDRBootFlag; } - else if (buffer[228U] & 0x4U) { - card->flags |= kMMC_SupportHighSpeedBootFlag; + else if ((buffer[228U] & 0x4U) != 0U) + { + card->flags |= (uint32_t)kMMC_SupportHighSpeedBootFlag; } - else { + else + { + /* empty with intentional */ } /* cache size unit 1kb */ extendedCsd->cacheSize = (((uint32_t)buffer[252U]) << 24) | (((uint32_t)buffer[251U]) << 16) | (((uint32_t)buffer[250U]) << 8) | (((uint32_t)buffer[249U])); + extendedCsd->genericCMD6Timeout = buffer[248U] * 10UL; extendedCsd->supportedCommandSet = buffer[504U]; } static status_t MMC_SendExtendedCsd(mmc_card_t *card, uint8_t *targetAddr, uint32_t byteIndex) { - assert(card); - assert(card->host.transfer); + assert(card != NULL); - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_DATA data = {0}; - uint32_t i; + sdmmchost_cmd_t command = {0}; + sdmmchost_transfer_t content = {0}; + sdmmchost_data_t data = {0}; + uint32_t *alignBuffer = (uint32_t *)FSL_SDMMC_CARD_INTERNAL_BUFFER_ALIGN_ADDR(card->internalBuffer); + status_t error = kStatus_Success; - command.index = kMMC_SendExtendedCsd; + /* Legacy mmc card , do not support the command */ + if ((card->csd.systemSpecificationVersion == (uint32_t)kMMC_SpecificationVersion3) && + (card->csd.csdStructureVersion == (uint32_t)kMMC_CsdStrucureVersion12)) + { + return kStatus_Success; + } + + (void)memset(alignBuffer, 0, MMC_EXTENDED_CSD_BYTES); + + command.index = (uint32_t)kMMC_SendExtendedCsd; command.argument = 0U; command.responseType = kCARD_ResponseTypeR1; data.blockCount = 1U; data.blockSize = MMC_EXTENDED_CSD_BYTES; - data.rxData = card->rawExtendedCsd; + data.rxData = alignBuffer; content.command = &command; content.data = &data; - if ((kStatus_Success == card->host.transfer(card->host.base, &content)) && - (!(command.response[0U] & kSDMMC_R1ErrorAllFlag))) { - /* The response is from bit 127:8 in R2, corresponding to command.response[3][31:0] to - command.response[0U][31:8] */ - switch (card->host.config.endianMode) { - case kSDMMCHOST_EndianModeLittle: - /* Doesn't need to switch byte sequence when decode bytes as little endian sequence. */ - break; - case kSDMMCHOST_EndianModeBig: - /* In big endian mode, the SD bus byte transferred first is the byte stored in highest position - in a word which cause 4 byte's sequence in a word is not consistent with their original sequence - from card. */ - for (i = 0U; i < MMC_EXTENDED_CSD_BYTES / 4U; i++) { - card->rawExtendedCsd[i] = SWAP_WORD_BYTE_SEQUENCE(card->rawExtendedCsd[i]); - } - break; - case kSDMMCHOST_EndianModeHalfWordBig: - for (i = 0U; i < MMC_EXTENDED_CSD_BYTES / 4U; i++) { - card->rawExtendedCsd[i] = SWAP_HALF_WROD_BYTE_SEQUENCE(card->rawExtendedCsd[i]); - } - break; - default: - return kStatus_SDMMC_NotSupportYet; - } - if (targetAddr != NULL) { - *targetAddr = ((uint8_t *)card->rawExtendedCsd)[byteIndex]; + error = SDMMCHOST_TransferFunction(card->host, &content); + if ((kStatus_Success == error) && (0U == (command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG))) + { + SDMMCHOST_ConvertDataToLittleEndian(card->host, alignBuffer, MMC_EXTENDED_CSD_BYTES / 4U, + kSDMMC_DataPacketFormatLSBFirst); + if (targetAddr != NULL) + { + *targetAddr = (uint8_t)alignBuffer[byteIndex]; } - else { - MMC_DecodeExtendedCsd(card, card->rawExtendedCsd); + else + { + MMC_DecodeExtendedCsd(card, alignBuffer); } return kStatus_Success; @@ -1040,77 +1061,112 @@ static status_t MMC_SendExtendedCsd(mmc_card_t *card, uint8_t *targetAddr, uint3 static status_t MMC_SetPowerClass(mmc_card_t *card) { - assert(card); + assert(card != NULL); uint8_t mask = 0, shift = 0U; uint8_t powerClass = 0; mmc_extended_csd_config_t extendedCsdconfig; - if ((card->busWidth == kMMC_DataBusWidth4bit) || (card->busWidth == kMMC_DataBusWidth4bitDDR)) { + /* Legacy mmc card , do not support the command */ + if ((card->csd.systemSpecificationVersion == (uint32_t)kMMC_SpecificationVersion3) && + (card->csd.csdStructureVersion == (uint32_t)kMMC_CsdStrucureVersion12)) + { + return kStatus_Success; + } + + if ((card->busWidth == kMMC_DataBusWidth4bit) || (card->busWidth == kMMC_DataBusWidth4bitDDR)) + { mask = MMC_POWER_CLASS_4BIT_MASK; /* The mask of 4 bit bus width's power class */ shift = 0U; } - else if ((card->busWidth == kMMC_DataBusWidth8bit) || (card->busWidth == kMMC_DataBusWidth8bitDDR)) { + else if ((card->busWidth == kMMC_DataBusWidth8bit) || (card->busWidth == kMMC_DataBusWidth8bitDDR)) + { mask = MMC_POWER_CLASS_8BIT_MASK; /* The mask of 8 bit bus width's power class */ shift = 4U; } - else { + else + { return kStatus_Success; } - switch (card->hostVoltageWindowVCC) { - case kMMC_VoltageWindows270to360: + switch (card->hostVoltageWindowVCC) + { + case kMMC_VoltageWindows270to360: - if (card->busTiming == kMMC_HighSpeed200Timing) { - if (card->hostVoltageWindowVCCQ == kMMC_VoltageWindow170to195) { - powerClass = ((card->extendedCsd.powerClass200MHZVCCQ195VVCC360V) & mask); + if (card->busTiming == kMMC_HighSpeed200Timing) + { + if (card->hostVoltageWindowVCCQ == kMMC_VoltageWindow170to195) + { + powerClass = ((card->extendedCsd.powerClass200MHZVCCQ195VVCC360V) & mask); + } + else if (card->hostVoltageWindowVCCQ == kMMC_VoltageWindow120) + { + powerClass = ((card->extendedCsd.powerClass200MHZVCCQ130VVCC360V) & mask); + } + else + { + /* intentional empty */ + } } - else if (card->hostVoltageWindowVCCQ == kMMC_VoltageWindow120) { - powerClass = ((card->extendedCsd.powerClass200MHZVCCQ130VVCC360V) & mask); + else if (card->busTiming == kMMC_HighSpeed400Timing) + { + powerClass = ((card->extendedCsd.powerClass200MHZDDR360V) & mask); + } + else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busWidth > kMMC_DataBusWidth8bit)) + { + powerClass = ((card->extendedCsd.powerClass52MHZDDR360V) & mask); + } + else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busClock_Hz > MMC_CLOCK_26MHZ)) + { + powerClass = ((card->extendedCsd.powerClass52MHz360V) & mask); + } + else if (card->busTiming == kMMC_HighSpeedTiming) + { + powerClass = ((card->extendedCsd.powerClass26MHz360V) & mask); + } + else + { + /* intentional empty */ } - } - else if (card->busTiming == kMMC_HighSpeed400Timing) { - powerClass = ((card->extendedCsd.powerClass200MHZDDR360V) & mask); - } - else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busWidth > kMMC_DataBusWidth8bit)) { - powerClass = ((card->extendedCsd.powerClass52MHZDDR360V) & mask); - } - else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busClock_Hz > MMC_CLOCK_26MHZ)) { - powerClass = ((card->extendedCsd.powerClass52MHz360V) & mask); - } - else if (card->busTiming == kMMC_HighSpeedTiming) { - powerClass = ((card->extendedCsd.powerClass26MHz360V) & mask); - } - break; + break; - case kMMC_VoltageWindow170to195: + case kMMC_VoltageWindow170to195: - if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busClock_Hz <= MMC_CLOCK_26MHZ)) { - powerClass = ((card->extendedCsd.powerClass26MHz195V) & mask); - } - else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busClock_Hz > MMC_CLOCK_26MHZ)) { - powerClass = ((card->extendedCsd.powerClass52MHz195V) & mask); - } - else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busWidth > kMMC_DataBusWidth8bit)) { - powerClass = ((card->extendedCsd.powerClass52MHZDDR195V) & mask); - } + if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busClock_Hz <= MMC_CLOCK_26MHZ)) + { + powerClass = ((card->extendedCsd.powerClass26MHz195V) & mask); + } + else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busClock_Hz > MMC_CLOCK_26MHZ)) + { + powerClass = ((card->extendedCsd.powerClass52MHz195V) & mask); + } + else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busWidth > kMMC_DataBusWidth8bit)) + { + powerClass = ((card->extendedCsd.powerClass52MHZDDR195V) & mask); + } + else + { + /* intentional empty */ + } - break; - default: - powerClass = 0; - break; + break; + default: + powerClass = 0; + break; } /* due to 8bit power class position [7:4] */ powerClass >>= shift; - if (powerClass > 0U) { + if (powerClass > 0U) + { extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexPowerClass; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexPowerClass; extendedCsdconfig.ByteValue = powerClass; extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { return kStatus_SDMMC_ConfigureExtendedCsdFailed; } /* restore power class */ @@ -1122,16 +1178,16 @@ static status_t MMC_SetPowerClass(mmc_card_t *card) static status_t MMC_SendTestPattern(mmc_card_t *card, uint32_t blockSize, uint32_t *pattern) { - assert(card); - assert(card->host.transfer); + assert(card != NULL); assert(blockSize <= FSL_SDMMC_DEFAULT_BLOCK_SIZE); - assert(pattern); + assert(pattern != NULL); - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_DATA data = {0}; + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + sdmmchost_data_t data = {0}; + status_t error = kStatus_Success; - command.index = kMMC_SendingBusTest; + command.index = (uint32_t)kMMC_SendingBusTest; command.argument = 0U; command.responseType = kCARD_ResponseTypeR1; @@ -1143,8 +1199,9 @@ static status_t MMC_SendTestPattern(mmc_card_t *card, uint32_t blockSize, uint32 content.command = &command; content.data = &data; - if ((kStatus_Success != card->host.transfer(card->host.base, &content)) || - (command.response[0U] & kSDMMC_R1ErrorAllFlag)) { + error = SDMMCHOST_TransferFunction(card->host, &content); + if ((kStatus_Success != error) || ((command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG) != 0U)) + { return kStatus_SDMMC_TransferFailed; } @@ -1153,16 +1210,16 @@ static status_t MMC_SendTestPattern(mmc_card_t *card, uint32_t blockSize, uint32 static status_t MMC_ReceiveTestPattern(mmc_card_t *card, uint32_t blockSize, uint32_t *pattern) { - assert(card); - assert(card->host.transfer); + assert(card != NULL); assert(blockSize <= FSL_SDMMC_DEFAULT_BLOCK_SIZE); - assert(pattern); + assert(pattern != NULL); - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_DATA data = {0}; + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + sdmmchost_data_t data = {0}; + status_t error = kStatus_Success; - command.index = kMMC_BusTestRead; + command.index = (uint32_t)kMMC_BusTestRead; command.responseType = kCARD_ResponseTypeR1; /* Ignore errors in bus test procedure to improve chances that the test will work. */ @@ -1173,8 +1230,9 @@ static status_t MMC_ReceiveTestPattern(mmc_card_t *card, uint32_t blockSize, uin content.command = &command; content.data = &data; - if ((kStatus_Success != card->host.transfer(card->host.base, &content)) || - ((command.response[0U]) & kSDMMC_R1ErrorAllFlag)) { + error = SDMMCHOST_TransferFunction(card->host, &content); + if ((kStatus_Success != error) || (((command.response[0U]) & SDMMC_R1_ALL_ERROR_FLAG) != 0U)) + { return kStatus_SDMMC_TransferFailed; } @@ -1183,79 +1241,56 @@ static status_t MMC_ReceiveTestPattern(mmc_card_t *card, uint32_t blockSize, uin static status_t MMC_TestDataBusWidth(mmc_card_t *card, mmc_data_bus_width_t width) { - assert(card); + assert(card != NULL); uint32_t blockSize = 0U; uint32_t tempsendPattern = 0U; - uint32_t *tempPattern = g_sdmmc; + uint32_t *tempPattern = (uint32_t *)FSL_SDMMC_CARD_INTERNAL_BUFFER_ALIGN_ADDR(card->internalBuffer); uint32_t xorMask = 0U; uint32_t xorResult = 0U; /* For 8 data lines the data block would be (MSB to LSB): 0x0000_0000_0000_AA55, For 4 data lines the data block would be (MSB to LSB): 0x0000_005A, For only 1 data line the data block would be: 0x80 */ - switch (width) { - case kMMC_DataBusWidth8bit: - case kMMC_DataBusWidth8bitDDR: - blockSize = 8U; - tempPattern[0U] = 0xAA55U; - xorMask = 0xFFFFU; - xorResult = 0xFFFFU; - break; - case kMMC_DataBusWidth4bit: - case kMMC_DataBusWidth4bitDDR: - blockSize = 4U; - tempPattern[0U] = 0x5AU; - xorMask = 0xFFU; - xorResult = 0xFFU; - break; - default: - blockSize = 4U; - tempPattern[0U] = 0x80U; - xorMask = 0xFFU; - xorResult = 0xC0U; - break; - } - switch (card->host.config.endianMode) { - case kSDMMCHOST_EndianModeLittle: - /* Doesn't need to switch byte sequence when decodes bytes as little endian sequence. */ - break; - case kSDMMCHOST_EndianModeBig: - /* In big endian mode, the byte transferred first is the byte stored in highest byte position in a word - which will cause the card receive the inverted byte sequence in a word in bus test procedure. So the - sequence of 4 bytes stored in a word should be converted. */ - tempPattern[0] = SWAP_WORD_BYTE_SEQUENCE(tempPattern[0]); - xorMask = SWAP_WORD_BYTE_SEQUENCE(xorMask); - xorResult = SWAP_WORD_BYTE_SEQUENCE(xorResult); - break; - case kSDMMCHOST_EndianModeHalfWordBig: - /* In half word big endian mode, the byte transferred first is the lower byte in the higher half word. - 0xAA55U should be converted to 0xAA550000U to set the 0x55 to be the first byte to transfer. */ - tempPattern[0] = SWAP_HALF_WROD_BYTE_SEQUENCE(tempPattern[0]); - xorMask = SWAP_HALF_WROD_BYTE_SEQUENCE(xorMask); - xorResult = SWAP_HALF_WROD_BYTE_SEQUENCE(xorResult); - tempPattern[0] = SWAP_WORD_BYTE_SEQUENCE(tempPattern[0]); - xorMask = SWAP_WORD_BYTE_SEQUENCE(xorMask); - xorResult = SWAP_WORD_BYTE_SEQUENCE(xorResult); - break; - default: - return kStatus_SDMMC_NotSupportYet; + switch (width) + { + case kMMC_DataBusWidth8bit: + case kMMC_DataBusWidth8bitDDR: + blockSize = 8U; + tempPattern[0U] = 0xAA55U; + xorMask = 0xFFFFU; + xorResult = 0xFFFFU; + break; + case kMMC_DataBusWidth4bit: + case kMMC_DataBusWidth4bitDDR: + blockSize = 4U; + tempPattern[0U] = 0x5AU; + xorMask = 0xFFU; + xorResult = 0xFFU; + break; + default: + blockSize = 4U; + tempPattern[0U] = 0x80U; + xorMask = 0xFFU; + xorResult = 0xC0U; + break; } - if (kStatus_Success != MMC_SendTestPattern(card, blockSize, tempPattern)) { - return kStatus_SDMMC_SendTestPatternFailed; - } + SDMMCHOST_ConvertDataToLittleEndian(card->host, &tempPattern[0], 1U, kSDMMC_DataPacketFormatLSBFirst); + SDMMCHOST_ConvertDataToLittleEndian(card->host, &xorMask, 1U, kSDMMC_DataPacketFormatLSBFirst); + SDMMCHOST_ConvertDataToLittleEndian(card->host, &xorResult, 1U, kSDMMC_DataPacketFormatLSBFirst); + + (void)MMC_SendTestPattern(card, blockSize, tempPattern); /* restore the send pattern */ tempsendPattern = tempPattern[0U]; /* reset the global buffer */ tempPattern[0U] = 0U; - if (kStatus_Success != MMC_ReceiveTestPattern(card, blockSize, tempPattern)) { - return kStatus_SDMMC_ReceiveTestPatternFailed; - } + (void)MMC_ReceiveTestPattern(card, blockSize, tempPattern); /* XOR the send pattern and receive pattern */ - if (((tempPattern[0U] ^ tempsendPattern) & xorMask) != xorResult) { + if (((tempPattern[0U] ^ tempsendPattern) & xorMask) != xorResult) + { return kStatus_Fail; } @@ -1264,98 +1299,141 @@ static status_t MMC_TestDataBusWidth(mmc_card_t *card, mmc_data_bus_width_t widt static status_t MMC_SetDataBusWidth(mmc_card_t *card, mmc_data_bus_width_t width) { - assert(card); + assert(card != NULL); mmc_extended_csd_config_t extendedCsdconfig; /* Set data bus width */ extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexBusWidth; - extendedCsdconfig.ByteValue = width; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexBusWidth; + extendedCsdconfig.ByteValue = (uint8_t)width; extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { return kStatus_SDMMC_ConfigureExtendedCsdFailed; } /* restore data bus width */ - card->extendedCsd.dataBusWidth = width; + card->extendedCsd.dataBusWidth = (uint8_t)width; return kStatus_Success; } static status_t MMC_SetMaxDataBusWidth(mmc_card_t *card, mmc_high_speed_timing_t targetTiming) { - assert(card); + assert(card != NULL); status_t error = kStatus_Fail; - switch (card->busWidth) { - case kMMC_DataBusWidth1bit: - case kMMC_DataBusWidth8bitDDR: - /* Test and set the data bus width for card. */ - if ((SDMMCHOST_NOT_SUPPORT != kSDMMCHOST_Support8BitBusWidth) && - (card->flags & (kMMC_SupportHighSpeedDDR52MHZ180V300VFlag | kMMC_SupportHighSpeedDDR52MHZ120VFlag)) && - ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed400Timing))) { - SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH8BIT); - if ((kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth8bitDDR)) && - (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth8bitDDR))) { - error = kStatus_Success; - card->busWidth = kMMC_DataBusWidth8bitDDR; - break; - } - /* HS400 mode only support 8bit data bus */ - else if (card->busTiming == kMMC_HighSpeed400Timing) { - return kStatus_SDMMC_SetDataBusWidthFailed; - } + do + { + if (card->busWidth == kMMC_DataBusWidth1bit) + { + card->busWidth = kMMC_DataBusWidth8bitDDR; } - __attribute__((fallthrough)); - case kMMC_DataBusWidth4bitDDR: - if ((SDMMCHOST_NOT_SUPPORT != kSDMMCHOST_Support4BitBusWidth) && - (card->flags & (kMMC_SupportHighSpeedDDR52MHZ180V300VFlag | kMMC_SupportHighSpeedDDR52MHZ120VFlag)) && - ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed400Timing))) { - SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH4BIT); - if ((kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth4bitDDR)) && - (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth4bitDDR))) { - error = kStatus_Success; - card->busWidth = kMMC_DataBusWidth4bitDDR; - break; + if (card->busWidth == kMMC_DataBusWidth8bitDDR) + { + if (((card->host->capability & + ((uint32_t)kSDMMCHOST_Support8BitDataWidth | (uint32_t)kSDMMCHOST_SupportDDRMode)) == + ((uint32_t)kSDMMCHOST_Support8BitDataWidth | (uint32_t)kSDMMCHOST_SupportDDRMode)) && + (0U != (card->flags & ((uint32_t)kMMC_SupportHighSpeedDDR52MHZ180V300VFlag | + (uint32_t)kMMC_SupportHighSpeedDDR52MHZ120VFlag))) && + ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed400Timing)) && + ((card->usrParam.capability & (uint32_t)kSDMMC_Support8BitWidth) != 0U)) + { + SDMMCHOST_SetCardBusWidth(card->host, kSDMMC_BusWdith8Bit); + if (kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth8bitDDR)) + { + if (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth8bitDDR)) + { + error = kStatus_Success; + card->busWidth = kMMC_DataBusWidth8bitDDR; + break; + } + } + + /* HS400 mode only support 8bit data bus */ + if (card->busTiming == kMMC_HighSpeed400Timing) + { + return kStatus_SDMMC_SetDataBusWidthFailed; + } } + card->busWidth = kMMC_DataBusWidth4bitDDR; } - __attribute__((fallthrough)); - case kMMC_DataBusWidth8bit: - if ((SDMMCHOST_NOT_SUPPORT != kSDMMCHOST_Support8BitBusWidth) && - ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed200Timing))) { - SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH8BIT); - if ((kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth8bit)) && - (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth8bit))) { - error = kStatus_Success; - card->busWidth = kMMC_DataBusWidth8bit; - break; + + if (card->busWidth == kMMC_DataBusWidth4bitDDR) + { + if (((card->host->capability & + ((uint32_t)kSDMMCHOST_Support4BitDataWidth | (uint32_t)kSDMMCHOST_SupportDDRMode)) == + ((uint32_t)kSDMMCHOST_Support4BitDataWidth | (uint32_t)kSDMMCHOST_SupportDDRMode)) && + (0U != (card->flags & ((uint32_t)kMMC_SupportHighSpeedDDR52MHZ180V300VFlag | + (uint32_t)kMMC_SupportHighSpeedDDR52MHZ120VFlag))) && + ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed400Timing))) + { + SDMMCHOST_SetCardBusWidth(card->host, kSDMMC_BusWdith4Bit); + if (kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth4bitDDR)) + { + if (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth4bitDDR)) + { + error = kStatus_Success; + card->busWidth = kMMC_DataBusWidth4bitDDR; + break; + } + } } + card->busWidth = kMMC_DataBusWidth8bit; } - __attribute__((fallthrough)); - case kMMC_DataBusWidth4bit: - if ((SDMMCHOST_NOT_SUPPORT != kSDMMCHOST_Support4BitBusWidth) && - ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed200Timing))) { - SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH4BIT); - if ((kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth4bit)) && - (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth4bit))) { - error = kStatus_Success; - card->busWidth = kMMC_DataBusWidth4bit; - break; + + if (card->busWidth == kMMC_DataBusWidth8bit) + { + if (((card->host->capability & (uint32_t)kSDMMCHOST_Support8BitDataWidth) != 0U) && + ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed200Timing)) && + ((card->usrParam.capability & (uint32_t)kSDMMC_Support8BitWidth) != 0U)) + { + SDMMCHOST_SetCardBusWidth(card->host, kSDMMC_BusWdith8Bit); + if (kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth8bit)) + { + if (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth8bit)) + { + error = kStatus_Success; + card->busWidth = kMMC_DataBusWidth8bit; + break; + } + } } - /* HS200 mode only support 4bit/8bit data bus */ - else if (targetTiming == kMMC_HighSpeed200Timing) { - return kStatus_SDMMC_SetDataBusWidthFailed; + card->busWidth = kMMC_DataBusWidth4bit; + } + + if (card->busWidth == kMMC_DataBusWidth4bit) + { + if (((card->host->capability & (uint32_t)kSDMMCHOST_Support8BitDataWidth) != 0U) && + ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed200Timing))) + { + SDMMCHOST_SetCardBusWidth(card->host, kSDMMC_BusWdith4Bit); + if (kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth4bit)) + { + if (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth4bit)) + { + error = kStatus_Success; + card->busWidth = kMMC_DataBusWidth4bit; + break; + } + } + /* HS200 mode only support 4bit/8bit data bus */ + if (targetTiming == kMMC_HighSpeed200Timing) + { + return kStatus_SDMMC_SetDataBusWidthFailed; + } } } - default: - break; - } - if (error == kStatus_Fail) { + } while (false); + + if (error == kStatus_Fail) + { /* Card's data bus width will be default 1 bit mode. */ - SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH1BIT); + SDMMCHOST_SetCardBusWidth(card->host, kSDMMC_BusWdith1Bit); + card->busWidth = kMMC_DataBusWidth1bit; } return kStatus_Success; @@ -1363,26 +1441,28 @@ static status_t MMC_SetMaxDataBusWidth(mmc_card_t *card, mmc_high_speed_timing_t static status_t MMC_SwitchHSTiming(mmc_card_t *card, uint8_t timing, uint8_t driverStrength) { - assert(card); + assert(card != NULL); uint8_t hsTiming = 0; mmc_extended_csd_config_t extendedCsdconfig; /* check the target driver strength support or not */ - if (((card->extendedCsd.ioDriverStrength & (1 << driverStrength)) == 0U) && - (card->extendedCsd.extendecCsdVersion >= kMMC_ExtendedCsdRevision17)) { + if (((card->extendedCsd.ioDriverStrength & (1U << driverStrength)) == 0U) && + (card->extendedCsd.extendecCsdVersion >= (uint8_t)kMMC_ExtendedCsdRevision17)) + { return kStatus_SDMMC_NotSupportYet; } /* calucate the register value */ - hsTiming = (timing & 0xF) | (uint8_t)(driverStrength << 4U); + hsTiming = (timing & 0xFU) | (uint8_t)(driverStrength << 4U); /* Switch to high speed timing. */ extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexHighSpeedTiming; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexHighSpeedTiming; extendedCsdconfig.ByteValue = hsTiming; extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { return kStatus_SDMMC_ConfigureExtendedCsdFailed; } @@ -1393,64 +1473,47 @@ static status_t MMC_SwitchHSTiming(mmc_card_t *card, uint8_t timing, uint8_t dri static status_t MMC_SwitchToHighSpeed(mmc_card_t *card) { - assert(card); + assert(card != NULL); uint32_t freq = 0U; - /* TODO: Change it when custom board arrives */ -#if 0 - /* check VCCQ voltage supply */ - if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) - { - if ((card->hostVoltageWindowVCCQ != kMMC_VoltageWindow170to195) && - (card->extendedCsd.extendecCsdVersion > kMMC_ExtendedCsdRevision10)) - { - SDMMCHOST_SWITCH_VOLTAGE180V(card->host.base, true); - card->hostVoltageWindowVCCQ = kMMC_VoltageWindow170to195; - } - } - else if (kSDMMCHOST_SupportV120 != SDMMCHOST_NOT_SUPPORT) - { - if ((card->hostVoltageWindowVCCQ != kMMC_VoltageWindow120) && - (card->extendedCsd.extendecCsdVersion >= kMMC_ExtendedCsdRevision16)) - { - SDMMCHOST_SWITCH_VOLTAGE120V(card->host.base, true); - card->hostVoltageWindowVCCQ = kMMC_VoltageWindow120; - } - } - else - { - card->hostVoltageWindowVCCQ = kMMC_VoltageWindows270to360; - } -#endif - if (kStatus_Success != MMC_SwitchHSTiming(card, kMMC_HighSpeedTiming, kMMC_DriverStrength0)) { + if (kStatus_Success != MMC_SwitchHSTiming(card, (uint8_t)kMMC_HighSpeedTiming, kMMC_DriverStrength0)) + { return kStatus_SDMMC_SwitchBusTimingFailed; } - if ((card->busWidth == kMMC_DataBusWidth4bitDDR) || (card->busWidth == kMMC_DataBusWidth8bitDDR)) { - freq = MMC_CLOCK_DDR52; - SDMMCHOST_ENABLE_DDR_MODE(card->host.base, true, 0U); + if ((card->flags & (uint32_t)kMMC_SupportHighSpeed52MHZFlag) != 0U) + { + freq = FSL_SDMMC_CARD_MAX_BUS_FREQ(card->usrParam.maxFreq, MMC_CLOCK_52MHZ); } - else if (card->flags & kMMC_SupportHighSpeed52MHZFlag) { - freq = MMC_CLOCK_52MHZ; + else if ((card->flags & (uint32_t)kMMC_SupportHighSpeed26MHZFlag) != 0U) + { + freq = FSL_SDMMC_CARD_MAX_BUS_FREQ(card->usrParam.maxFreq, MMC_CLOCK_26MHZ); } - else if (card->flags & kMMC_SupportHighSpeed26MHZFlag) { - freq = MMC_CLOCK_26MHZ; + else + { + /* Intentional empty */ } - // TODO: remove it when custom board arrives, currently 52Mhz is too much for eMMC micro adapter :// - freq = MMC_CLOCK_26MHZ; - card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, freq); + card->busClock_Hz = SDMMCHOST_SetCardClock(card->host, freq); /* config io speed and strength */ - SDMMCHOST_CONFIG_MMC_IO(CARD_BUS_FREQ_100MHZ1, CARD_BUS_STRENGTH_7); - + if (card->usrParam.ioStrength != NULL) + { + card->usrParam.ioStrength(MMC_CLOCK_52MHZ); + } /* Set card data width, it is nessesary to config the the data bus here, to meet emmc5.0 specification, * when you are working in DDR mode , HS_TIMING must set before set bus width */ - if (MMC_SetMaxDataBusWidth(card, kMMC_HighSpeedTiming) != kStatus_Success) { + if (MMC_SetMaxDataBusWidth(card, kMMC_HighSpeedTiming) != kStatus_Success) + { return kStatus_SDMMC_SetDataBusWidthFailed; } + if ((card->busWidth == kMMC_DataBusWidth4bitDDR) || (card->busWidth == kMMC_DataBusWidth8bitDDR)) + { + SDMMCHOST_EnableDDRMode(card->host, true, 0U); + } + card->busTiming = kMMC_HighSpeedTiming; return kStatus_Success; @@ -1458,166 +1521,231 @@ static status_t MMC_SwitchToHighSpeed(mmc_card_t *card) static status_t MMC_SwitchToHS200(mmc_card_t *card, uint32_t freq) { - assert(card); - -#if 1 - /* check VCCQ voltage supply */ - if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) { - if (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow170to195) { - SDMMCHOST_SWITCH_VOLTAGE180V(card->host.base, true); - card->hostVoltageWindowVCCQ = kMMC_VoltageWindow170to195; - } - } - else if (kSDMMCHOST_SupportV120 != SDMMCHOST_NOT_SUPPORT) { - if (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow120) { - SDMMCHOST_SWITCH_VOLTAGE120V(card->host.base, true); - card->hostVoltageWindowVCCQ = kMMC_VoltageWindow120; - } - } - else { + assert(card != NULL); + + status_t error = kStatus_Fail; + + if ((card->hostVoltageWindowVCCQ != kMMC_VoltageWindow170to195) && + (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow120)) + { return kStatus_SDMMC_InvalidVoltage; } -#endif - /* select bus width before select bus timing for HS200 mode */ - if (MMC_SetMaxDataBusWidth(card, kMMC_HighSpeed200Timing) != kStatus_Success) { + if (MMC_SetMaxDataBusWidth(card, kMMC_HighSpeed200Timing) != kStatus_Success) + { return kStatus_SDMMC_SetDataBusWidthFailed; } /* switch to HS200 mode */ - if (kStatus_Success != MMC_SwitchHSTiming(card, kMMC_HighSpeed200Timing, kMMC_DriverStrength0)) { + if (kStatus_Success != MMC_SwitchHSTiming(card, (uint8_t)kMMC_HighSpeed200Timing, kMMC_DriverStrength0)) + { return kStatus_SDMMC_SwitchBusTimingFailed; } - card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, freq); + card->busClock_Hz = SDMMCHOST_SetCardClock(card->host, freq); /* config io speed and strength */ - SDMMCHOST_CONFIG_MMC_IO(CARD_BUS_FREQ_200MHZ, CARD_BUS_STRENGTH_7); + if (card->usrParam.ioStrength != NULL) + { + card->usrParam.ioStrength(freq); + } /* excute tuning for HS200 */ - if (MMC_ExecuteTuning(card) != kStatus_Success) { + if (MMC_ExecuteTuning(card) != kStatus_Success) + { return kStatus_SDMMC_TuningFail; } - /* Wait for the card status ready. */ - if (kStatus_Success != MMC_WaitWriteComplete(card)) { - return kStatus_SDMMC_WaitWriteCompleteFailed; - } - card->busTiming = kMMC_HighSpeed200Timing; + error = MMC_PollingCardStatusBusy(card, true, MMC_CARD_ACCESS_WAIT_IDLE_TIMEOUT); + if (kStatus_SDMMC_CardStatusIdle != error) + { + return kStatus_SDMMC_PollingCardIdleFailed; + } + return kStatus_Success; } static status_t MMC_SwitchToHS400(mmc_card_t *card) { - assert(card); + assert(card != NULL); - /* check VCCQ voltage supply */ - if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) { - if (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow170to195) { - SDMMCHOST_SWITCH_VOLTAGE180V(card->host.base, true); - card->hostVoltageWindowVCCQ = kMMC_VoltageWindow170to195; - } + uint32_t status = 0U; + uint32_t hs400Freq = FSL_SDMMC_CARD_MAX_BUS_FREQ(card->usrParam.maxFreq, MMC_CLOCK_HS400); + status_t error = kStatus_Fail; + + if ((card->hostVoltageWindowVCCQ != kMMC_VoltageWindow170to195) && + (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow120)) + { + return kStatus_SDMMC_InvalidVoltage; } - else if (kSDMMCHOST_SupportV120 != SDMMCHOST_NOT_SUPPORT) { - if (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow120) { - SDMMCHOST_SWITCH_VOLTAGE120V(card->host.base, true); - card->hostVoltageWindowVCCQ = kMMC_VoltageWindow120; - } + + if (card->host->hostController.sourceClock_Hz < MMC_CLOCK_HS400) + { + hs400Freq = card->host->hostController.sourceClock_Hz; } - else { - return kStatus_SDMMC_InvalidVoltage; + + if ((card->host->hostController.sourceClock_Hz > MMC_CLOCK_HS400) && + (card->host->hostController.sourceClock_Hz % MMC_CLOCK_HS400 != 0U)) + { + hs400Freq = card->host->hostController.sourceClock_Hz / + (card->host->hostController.sourceClock_Hz / MMC_CLOCK_HS400 + 1U); + } + /* HS400 mode support 8 bit data bus only */ + card->busWidth = kMMC_DataBusWidth8bit; + /* switch to HS200 perform tuning */ + if (kStatus_Success != MMC_SwitchToHS200(card, hs400Freq / 2U)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; } - /* check data bus width is 8 bit , otherwise return false */ - if (card->busWidth == kMMC_DataBusWidth8bit) { + /* check data bus width is 8 bit , otherwise return false*/ + if (card->busWidth != kMMC_DataBusWidth8bit) + { return kStatus_SDMMC_SwitchBusTimingFailed; } - /* switch to high speed first */ - card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, MMC_CLOCK_52MHZ); - SDMMCHOST_CONFIG_MMC_IO(CARD_BUS_FREQ_100MHZ1, CARD_BUS_STRENGTH_5); + /* + * For the issue found in stress test of repeat emmc initialization operation, after HS200 switch complete, the emmc + * status not correct for switching to high speed, normally the emmc should stay in TRAN state, but sometimes the + * emmc status is in DATA state which will cause switch to High speed failed. when such issue happen, software will + * try to use CMD12 to reset the emmc status to TRAN before switch to high speed for HS400. + */ + error = MMC_SendStatus(card, &status); + if (error != kStatus_Success) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + + if (SDMMC_R1_CURRENT_STATE(status) == (uint32_t)kSDMMC_R1StateSendData) + { + SDMMC_LOG("status uncorrect for switching to High speed timing, try use CMD12 to get back to TRAN state\r\n"); + /* try to get back to transfer state before switch to High speed */ + (void)MMC_StopTransmission(card); + } + /*switch to high speed*/ - if (kStatus_Success != MMC_SwitchHSTiming(card, kMMC_HighSpeedTiming, kMMC_DriverStrength0)) { + if (kStatus_Success != MMC_SwitchHSTiming(card, (uint8_t)kMMC_HighSpeedTiming, kMMC_DriverStrength0)) + { return kStatus_SDMMC_ConfigureExtendedCsdFailed; } + + /* switch to high speed first */ + card->busClock_Hz = SDMMCHOST_SetCardClock(card->host, MMC_CLOCK_52MHZ); + /* config io strength */ + if (card->usrParam.ioStrength != NULL) + { + card->usrParam.ioStrength(MMC_CLOCK_52MHZ); + } + card->busTiming = kMMC_HighSpeed400Timing; /* switch to 8 bit DDR data bus width */ - if (kStatus_Success != MMC_SetDataBusWidth(card, kMMC_DataBusWidth8bitDDR)) { + if (kStatus_Success != MMC_SetDataBusWidth(card, kMMC_DataBusWidth8bitDDR)) + { return kStatus_SDMMC_SetDataBusWidthFailed; } /* switch to HS400 */ - if (kStatus_Success != MMC_SwitchHSTiming(card, kMMC_HighSpeed400Timing, kMMC_DriverStrength0)) { + if (kStatus_Success != MMC_SwitchHSTiming(card, (uint8_t)kMMC_HighSpeed400Timing, kMMC_DriverStrength0)) + { return kStatus_SDMMC_SwitchBusTimingFailed; } /* config to target freq */ - card->busClock_Hz = - SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SDMMCHOST_SUPPORT_HS400_FREQ); + card->busClock_Hz = SDMMCHOST_SetCardClock(card->host, hs400Freq / 2U); /* config io speed and strength */ - SDMMCHOST_CONFIG_MMC_IO(CARD_BUS_FREQ_200MHZ, CARD_BUS_STRENGTH_7); + if (card->usrParam.ioStrength != NULL) + { + card->usrParam.ioStrength(MMC_CLOCK_HS200); + } /* enable HS400 mode */ - SDMMCHOST_ENABLE_HS400_MODE(card->host.base, true); + SDMMCHOST_EnableHS400Mode(card->host, true); /* enable DDR mode */ - SDMMCHOST_ENABLE_DDR_MODE(card->host.base, true, 0U); - /* config strobe DLL */ - SDMMCHOST_CONFIG_STROBE_DLL( - card->host.base, SDMMCHOST_STROBE_DLL_DELAY_TARGET, SDMMCHOST_STROBE_DLL_DELAY_UPDATE_INTERVAL); - /* enable DLL */ - SDMMCHOST_ENABLE_STROBE_DLL(card->host.base, true); + SDMMCHOST_EnableDDRMode(card->host, true, 0U); + /* config strobe DLL*/ + SDMMCHOST_EnableStrobeDll(card->host, true); return kStatus_Success; } static status_t MMC_SelectBusTiming(mmc_card_t *card) { - assert(card); - - mmc_high_speed_timing_t targetTiming = card->busTiming; - - switch (targetTiming) { - case kMMC_HighSpeedTimingNone: - case kMMC_HighSpeed400Timing: - /* fall through */ - if ((card->flags & (kMMC_SupportHS400DDR200MHZ180VFlag | kMMC_SupportHS400DDR200MHZ120VFlag)) && - ((kSDMMCHOST_SupportHS400 != SDMMCHOST_NOT_SUPPORT))) { - /* switch to HS200 perform tuning */ - if (kStatus_Success != MMC_SwitchToHS200(card, SDMMCHOST_SUPPORT_HS400_FREQ / 2U)) { - return kStatus_SDMMC_SwitchBusTimingFailed; + assert(card != NULL); + + /* Legacy mmc card , do not support the command */ + if ((card->csd.systemSpecificationVersion == (uint8_t)kMMC_SpecificationVersion3) && + (card->csd.csdStructureVersion == (uint8_t)kMMC_CsdStrucureVersion12)) + { + return kStatus_Success; + } + + do + { + if (card->busTiming == kMMC_HighSpeedTimingNone) + { + /* if timing not specified, probe card capability from HS400 mode */ + card->busTiming = kMMC_HighSpeed400Timing; + } + + if (card->busTiming == kMMC_EnhanceHighSpeed400Timing) + { + return kStatus_SDMMC_NotSupportYet; + } + + if (card->busTiming == kMMC_HighSpeed400Timing) + { + if (((card->host->capability & (uint32_t)kSDMMCHOST_SupportHS400) != 0U) && + ((card->hostVoltageWindowVCCQ == kMMC_VoltageWindow170to195) || + (card->hostVoltageWindowVCCQ == kMMC_VoltageWindow120)) && + ((card->flags & + ((uint32_t)kMMC_SupportHS400DDR200MHZ180VFlag | (uint32_t)kMMC_SupportHS400DDR200MHZ120VFlag)) != 0U)) + { + /* switch to HS400 */ + if (kStatus_Success != MMC_SwitchToHS400(card)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + break; } - /* switch to HS400 */ - if (kStatus_Success != MMC_SwitchToHS400(card)) { - return kStatus_SDMMC_SwitchBusTimingFailed; + + card->busTiming = kMMC_HighSpeed200Timing; + } + + if (card->busTiming == kMMC_HighSpeed200Timing) + { + if (((card->host->capability & (uint32_t)kSDMMCHOST_SupportHS200) != 0U) && + ((card->hostVoltageWindowVCCQ == kMMC_VoltageWindow170to195) || + (card->hostVoltageWindowVCCQ == kMMC_VoltageWindow120)) && + (0U != (card->flags & + ((uint32_t)kMMC_SupportHS200200MHZ180VFlag | (uint32_t)kMMC_SupportHS200200MHZ120VFlag)))) + { + if (kStatus_Success != + MMC_SwitchToHS200(card, FSL_SDMMC_CARD_MAX_BUS_FREQ(card->usrParam.maxFreq, MMC_CLOCK_HS200))) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + break; } - break; + + card->busTiming = kMMC_HighSpeedTiming; } - __attribute__((fallthrough)); - case kMMC_HighSpeed200Timing: - if ((card->flags & (kMMC_SupportHS200200MHZ180VFlag | kMMC_SupportHS200200MHZ120VFlag)) && - ((kSDMMCHOST_SupportHS200 != SDMMCHOST_NOT_SUPPORT))) { - if (kStatus_Success != MMC_SwitchToHS200(card, SDMMCHOST_SUPPORT_HS200_FREQ)) { + + if (card->busTiming == kMMC_HighSpeedTiming) + { + if (kStatus_Success != MMC_SwitchToHighSpeed(card)) + { return kStatus_SDMMC_SwitchBusTimingFailed; } break; } - __attribute__((fallthrough)); - case kMMC_HighSpeedTiming: - if (kStatus_Success != MMC_SwitchToHighSpeed(card)) { - return kStatus_SDMMC_SwitchBusTimingFailed; - } - break; - - default: - card->busTiming = kMMC_HighSpeedTimingNone; - } + } while (false); return kStatus_Success; } static void MMC_DecodeCid(mmc_card_t *card, uint32_t *rawCid) { - assert(card); - assert(rawCid); + assert(card != NULL); + assert(rawCid != NULL); mmc_cid_t *cid; @@ -1642,20 +1770,22 @@ static void MMC_DecodeCid(mmc_card_t *card, uint32_t *rawCid) static status_t MMC_AllSendCid(mmc_card_t *card) { - assert(card); - assert(card->host.transfer); + assert(card != NULL); - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + status_t error = kStatus_Success; - command.index = kSDMMC_AllSendCid; + command.index = (uint32_t)kSDMMC_AllSendCid; command.argument = 0U; command.responseType = kCARD_ResponseTypeR2; content.command = &command; content.data = NULL; - if (kStatus_Success == card->host.transfer(card->host.base, &content)) { - memcpy(card->rawCid, command.response, sizeof(card->rawCid)); + error = SDMMCHOST_TransferFunction(card->host, &content); + if (kStatus_Success == error) + { + (void)memcpy(card->internalBuffer, (uint8_t *)command.response, 16U); MMC_DecodeCid(card, command.response); return kStatus_Success; @@ -1666,23 +1796,25 @@ static status_t MMC_AllSendCid(mmc_card_t *card) static status_t MMC_SendCsd(mmc_card_t *card) { - assert(card); - assert(card->host.transfer); + assert(card != NULL); - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_TRANSFER content = {0}; + sdmmchost_cmd_t command = {0}; + sdmmchost_transfer_t content = {0}; + status_t error = kStatus_Success; - command.index = kSDMMC_SendCsd; + command.index = (uint32_t)kSDMMC_SendCsd; command.argument = (card->relativeAddress << 16U); command.responseType = kCARD_ResponseTypeR2; content.command = &command; - content.data = 0U; - if (kStatus_Success == card->host.transfer(card->host.base, &content)) { - memcpy(card->rawCsd, command.response, sizeof(card->rawCsd)); + content.data = NULL; + error = SDMMCHOST_TransferFunction(card->host, &content); + if (kStatus_Success == error) + { + (void)memcpy(card->internalBuffer, (uint8_t *)command.response, 16U); /* The response is from bit 127:8 in R2, corresponding to command.response[3][31:0] to command.response[0U][31:8]. */ - MMC_DecodeCsd(card, card->rawCsd); + MMC_DecodeCsd(card, (uint32_t *)(uint32_t)card->internalBuffer); return kStatus_Success; } @@ -1692,32 +1824,33 @@ static status_t MMC_SendCsd(mmc_card_t *card) static status_t MMC_CheckBlockRange(mmc_card_t *card, uint32_t startBlock, uint32_t blockCount) { - assert(card); - assert(blockCount); + assert(card != NULL); + assert(blockCount != 0U); status_t error = kStatus_Success; uint32_t partitionBlocks; - switch (card->currentPartition) { - case kMMC_AccessPartitionUserArea: { - partitionBlocks = card->userPartitionBlocks; - break; - } - case kMMC_AccessPartitionBoot1: - case kMMC_AccessPartitionBoot2: { - /* Boot partition 1 and partition 2 have the same partition size. */ - partitionBlocks = card->bootPartitionBlocks; - break; - } - case kMMC_AccessGeneralPurposePartition1: - partitionBlocks = card->systemPartitionBlocks; - break; - default: - error = kStatus_InvalidArgument; - break; + switch (card->currentPartition) + { + case kMMC_AccessPartitionUserAera: + { + partitionBlocks = card->userPartitionBlocks; + break; + } + case kMMC_AccessPartitionBoot1: + case kMMC_AccessPartitionBoot2: + { + /* Boot partition 1 and partition 2 have the same partition size. */ + partitionBlocks = card->bootPartitionBlocks; + break; + } + default: + error = kStatus_InvalidArgument; + break; } /* Check if the block range accessed is within current partition's block boundary. */ - if ((error == kStatus_Success) && ((startBlock + blockCount) > partitionBlocks)) { + if ((error == kStatus_Success) && ((startBlock + blockCount) > partitionBlocks)) + { error = kStatus_InvalidArgument; } @@ -1726,40 +1859,47 @@ static status_t MMC_CheckBlockRange(mmc_card_t *card, uint32_t startBlock, uint3 static status_t MMC_CheckEraseGroupRange(mmc_card_t *card, uint32_t startGroup, uint32_t endGroup) { - assert(card); + assert(card != NULL); status_t error = kStatus_Success; uint32_t partitionBlocks; uint32_t eraseGroupBoundary; - switch (card->currentPartition) { - case kMMC_AccessPartitionUserArea: { - partitionBlocks = card->userPartitionBlocks; - break; - } - case kMMC_AccessPartitionBoot1: - case kMMC_AccessPartitionBoot2: { - /* Boot partition 1 and partition 2 have the same partition size. */ - partitionBlocks = card->bootPartitionBlocks; - break; - } - default: - error = kStatus_InvalidArgument; - break; + switch (card->currentPartition) + { + case kMMC_AccessPartitionUserAera: + { + partitionBlocks = card->userPartitionBlocks; + break; + } + case kMMC_AccessPartitionBoot1: + case kMMC_AccessPartitionBoot2: + { + /* Boot partition 1 and partition 2 have the same partition size. */ + partitionBlocks = card->bootPartitionBlocks; + break; + } + default: + error = kStatus_InvalidArgument; + break; } - if (error == kStatus_Success) { + if (error == kStatus_Success) + { /* Check if current partition's total block count is integer multiples of the erase group size. */ - if ((partitionBlocks % card->eraseGroupBlocks) == 0U) { + if ((partitionBlocks % card->eraseGroupBlocks) == 0U) + { eraseGroupBoundary = (partitionBlocks / card->eraseGroupBlocks); } - else { + else + { /* Card will ignore the unavailable blocks within the last erase group automatically. */ eraseGroupBoundary = (partitionBlocks / card->eraseGroupBlocks + 1U); } /* Check if the group range accessed is within current partition's erase group boundary. */ - if ((startGroup > eraseGroupBoundary) || (endGroup > eraseGroupBoundary)) { + if ((startGroup > eraseGroupBoundary) || (endGroup > eraseGroupBoundary)) + { error = kStatus_InvalidArgument; } } @@ -1770,75 +1910,75 @@ static status_t MMC_CheckEraseGroupRange(mmc_card_t *card, uint32_t startGroup, static status_t MMC_Read( mmc_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockSize, uint32_t blockCount) { - assert(card); - assert(card->host.transfer); - assert(buffer); - assert(blockCount); - assert(blockSize); + assert(card != NULL); + assert(buffer != NULL); + assert(blockCount != 0U); + assert(blockSize != 0U); assert(blockSize == FSL_SDMMC_DEFAULT_BLOCK_SIZE); - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_DATA data = {0}; - SDMMCHOST_TRANSFER content = {0}; + sdmmchost_cmd_t command = {0}; + sdmmchost_data_t data = {0}; + sdmmchost_transfer_t content = {0}; status_t error; - if (((card->flags & kMMC_SupportHighCapacityFlag) && (blockSize != 512U)) || (blockSize > card->blockSize) || - (blockSize > card->host.capability.maxBlockLength) || (blockSize % 4U)) { + if ((((card->flags & (uint32_t)kMMC_SupportHighCapacityFlag) != 0U) && (blockSize != 512U)) || + (blockSize > card->blockSize) || (blockSize > card->host->maxBlockSize) || (0U != (blockSize % 4U))) + { return kStatus_SDMMC_CardNotSupport; } - /* Wait for the card write process complete because of that card read process and write process use one buffer. */ - if (kStatus_Success != MMC_WaitWriteComplete(card)) { - return kStatus_SDMMC_WaitWriteCompleteFailed; - } - - /* Set block size */ - if (kStatus_Success != MMC_SetBlockSize(card, FSL_SDMMC_DEFAULT_BLOCK_SIZE)) { - return kStatus_SDMMC_SetBlockCountFailed; + error = MMC_PollingCardStatusBusy(card, true, MMC_CARD_ACCESS_WAIT_IDLE_TIMEOUT); + if (kStatus_SDMMC_CardStatusIdle != error) + { + SDMMC_LOG("Error : read failed with wrong card status\r\n"); + return kStatus_SDMMC_PollingCardIdleFailed; } data.blockSize = blockSize; data.blockCount = blockCount; - data.rxData = (uint32_t *)buffer; + data.rxData = (uint32_t *)(uint32_t)buffer; data.enableAutoCommand12 = true; - command.index = kSDMMC_ReadMultipleBlock; - if (data.blockCount == 1U) { - command.index = kSDMMC_ReadSingleBlock; + command.index = (uint32_t)kSDMMC_ReadMultipleBlock; + if (data.blockCount == 1U) + { + command.index = (uint32_t)kSDMMC_ReadSingleBlock; } - else { - if ((!(data.enableAutoCommand12)) && (card->enablePreDefinedBlockCount)) { + else + { + if (card->enablePreDefinedBlockCount) + { + data.enableAutoCommand12 = false; /* If enabled the pre-define count read/write feature of the card, need to set block count firstly. */ - if (kStatus_Success != MMC_SetBlockCount(card, blockCount)) { + if (kStatus_Success != MMC_SetBlockCount(card, blockCount)) + { return kStatus_SDMMC_SetBlockCountFailed; } } } - command.argument = startBlock; - - /* eMMC cards support only block addressing */ -#if 0 - if (!(card->flags & kMMC_SupportHighCapacityFlag)) + if (0U == (card->flags & (uint32_t)kMMC_SupportHighCapacityFlag)) { - //command.argument *= data.blockSize; + command.argument *= data.blockSize; } -#endif command.responseType = kCARD_ResponseTypeR1; - command.responseErrorFlags = kSDMMC_R1ErrorAllFlag; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; content.command = &command; content.data = &data; /* should check tuning error during every transfer */ - error = MMC_Transfer(card, &content, 1U); - if (kStatus_Success != error) { + error = MMC_Transfer(card, &content, 3U); + if (kStatus_Success != error) + { return error; } /* When host's AUTO_COMMAND12 feature isn't enabled and PRE_DEFINED_COUNT command isn't enabled in multiple blocks transmission, sends STOP_TRANSMISSION command. */ - if ((blockCount > 1U) && (!(data.enableAutoCommand12)) && (!card->enablePreDefinedBlockCount)) { - if (kStatus_Success != MMC_StopTransmission(card)) { + if ((blockCount > 1U) && (!(data.enableAutoCommand12)) && (!card->enablePreDefinedBlockCount)) + { + if (kStatus_Success != MMC_StopTransmission(card)) + { return kStatus_SDMMC_StopTransmissionFailed; } } @@ -1849,80 +1989,78 @@ static status_t MMC_Read( static status_t MMC_Write( mmc_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockSize, uint32_t blockCount) { - assert(card); - assert(card->host.transfer); - assert(buffer); - assert(blockCount); - assert(blockSize); + assert(card != NULL); + assert(buffer != NULL); + assert(blockCount != 0U); + assert(blockSize != 0U); assert(blockSize == FSL_SDMMC_DEFAULT_BLOCK_SIZE); - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_DATA data = {0}; - SDMMCHOST_TRANSFER content = {0}; + sdmmchost_cmd_t command = {0}; + sdmmchost_data_t data = {0}; + sdmmchost_transfer_t content = {0}; status_t error; /* Check address range */ - if (((card->flags & kMMC_SupportHighCapacityFlag) && (blockSize != 512U)) || (blockSize > card->blockSize) || - (blockSize > card->host.capability.maxBlockLength) || (blockSize % 4U)) { + if ((((card->flags & (uint32_t)kMMC_SupportHighCapacityFlag) != 0U) && (blockSize != 512U)) || + (blockSize > card->blockSize) || (blockSize > card->host->maxBlockSize) || (0U != (blockSize % 4U))) + { return kStatus_SDMMC_CardNotSupport; } - /* Wait for the card's buffer to be not full to write to improve the write performance. */ - while ((GET_SDMMCHOST_STATUS(card->host.base) & CARD_DATA0_STATUS_MASK) != CARD_DATA0_NOT_BUSY) {} - - /* Wait for the card write process complete */ - if (kStatus_Success != MMC_WaitWriteComplete(card)) { - return kStatus_SDMMC_WaitWriteCompleteFailed; - } - - /* Set block size */ - if (kStatus_Success != MMC_SetBlockSize(card, FSL_SDMMC_DEFAULT_BLOCK_SIZE)) { - return kStatus_SDMMC_SetBlockCountFailed; + /* send CMD13 to make sure card is ready for data */ + error = MMC_PollingCardStatusBusy(card, true, MMC_CARD_ACCESS_WAIT_IDLE_TIMEOUT); + if (kStatus_SDMMC_CardStatusIdle != error) + { + SDMMC_LOG("Error : write card busy with wrong card status\r\n"); + return kStatus_SDMMC_PollingCardIdleFailed; } data.blockSize = blockSize; data.blockCount = blockCount; - data.txData = (const uint32_t *)buffer; + data.txData = (const uint32_t *)(uint32_t)buffer; data.enableAutoCommand12 = true; - command.index = kSDMMC_WriteMultipleBlock; - if (data.blockCount == 1U) { - command.index = kSDMMC_WriteSingleBlock; + command.index = (uint32_t)kSDMMC_WriteMultipleBlock; + if (data.blockCount == 1U) + { + command.index = (uint32_t)kSDMMC_WriteSingleBlock; } - else { - if ((!(data.enableAutoCommand12)) && (card->enablePreDefinedBlockCount)) { + else + { + if (card->enablePreDefinedBlockCount) + { + data.enableAutoCommand12 = false; /* If enabled the pre-define count read/write featue of the card, need to set block count firstly */ - if (kStatus_Success != MMC_SetBlockCount(card, blockCount)) { + if (kStatus_Success != MMC_SetBlockCount(card, blockCount)) + { return kStatus_SDMMC_SetBlockCountFailed; } } } - command.argument = startBlock; - - /* eMMC cards support only block addressing */ -#if 0 - if (!(card->flags & kMMC_SupportHighCapacityFlag)) + if (0U == (card->flags & (uint32_t)kMMC_SupportHighCapacityFlag)) { - //command.argument *= blockSize; + command.argument *= blockSize; } -#endif command.responseType = kCARD_ResponseTypeR1; - command.responseErrorFlags = kSDMMC_R1ErrorAllFlag; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; content.command = &command; content.data = &data; /* should check tuning error during every transfer */ - error = MMC_Transfer(card, &content, 1U); - if (kStatus_Success != error) { + error = MMC_Transfer(card, &content, 3U); + if (kStatus_Success != error) + { return error; } /* When host's AUTO_COMMAND12 feature isn't enabled and PRE_DEFINED_COUNT command isn't enabled in multiple blocks transmission, sends STOP_TRANSMISSION command. */ - if ((blockCount > 1U) && (!(data.enableAutoCommand12)) && (!card->enablePreDefinedBlockCount)) { - if (kStatus_Success != MMC_StopTransmission(card)) { + if ((blockCount > 1U) && (!(data.enableAutoCommand12)) && (!card->enablePreDefinedBlockCount)) + { + if (kStatus_Success != MMC_StopTransmission(card)) + { return kStatus_SDMMC_StopTransmissionFailed; } } @@ -1930,134 +2068,198 @@ static status_t MMC_Write( return kStatus_Success; } -static void MMC_CalculateMultiplier(uint32_t multiplier, uint8_t multisplit[3]) +static status_t MMC_ValidateOperationVoltage(mmc_card_t *card, uint32_t *opcode) { - uint8_t *multi2x16 = &multisplit[2]; - uint8_t *multi2x8 = &multisplit[1]; - uint8_t *multi2x0 = &multisplit[0]; - // at first check if required multiplier is bigger or equal to 256 - if (multiplier >= 256) { - *multi2x16 = multiplier / 256; - - // if remainder from 256 divide is bigger than 64 ? - if ((multiplier % 256) >= 64) { - *multi2x8 = (multiplier % 256) / 64; - *multi2x0 = ((multiplier % 256) % 64); + status_t status = kStatus_Fail; + + if (card->hostVoltageWindowVCC == kMMC_VoltageWindow170to195) + { + if ((card->ocr & MMC_OCR_V170TO195_MASK) != 0U) + { + *opcode |= MMC_OCR_V170TO195_MASK; + status = kStatus_Success; } } - else if (multiplier >= 64) { - *multi2x16 = multiplier / 64; - *multi2x0 = multiplier % 64; + else if (card->hostVoltageWindowVCC == kMMC_VoltageWindows270to360) + { + if ((card->ocr & MMC_OCR_V270TO360_MASK) != 0U) + { + *opcode |= MMC_OCR_V270TO360_MASK; + status = kStatus_Success; + } } - else { - *multi2x0 = multiplier; + else + { + /* Intentional empty */ } + + return status; } -status_t MMC_CardInit(mmc_card_t *card) +static status_t mmccard_init(mmc_card_t *card) { - assert(card); + assert(card != NULL); + assert((card->hostVoltageWindowVCC != kMMC_VoltageWindowNone) && + (card->hostVoltageWindowVCC != kMMC_VoltageWindow120)); + assert(card->hostVoltageWindowVCCQ != kMMC_VoltageWindowNone); + + uint32_t opcode = 0U; + status_t error = kStatus_Success; - if (!card->isHostReady) { + if (!card->isHostReady) + { return kStatus_SDMMC_HostNotReady; } /* set DATA bus width */ - SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH1BIT); + SDMMCHOST_SetCardBusWidth(card->host, kSDMMC_BusWdith1Bit); /* Set clock to 400KHz. */ - card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SDMMC_CLOCK_400KHZ); - /* get host capability first */ - GET_SDMMCHOST_CAPABILITY(card->host.base, &(card->host.capability)); + card->busClock_Hz = SDMMCHOST_SetCardClock(card->host, SDMMC_CLOCK_400KHZ); + error = MMC_GoIdle(card); /* Send CMD0 to reset the bus */ - if (kStatus_Success != MMC_GoIdle(card)) { + if (kStatus_Success != error) + { return kStatus_SDMMC_GoIdleFailed; } - if (kStatus_Success != MMC_SendIdentifyDevice(card, keMMC_HIGH_VOLTAGE_RANGE)) { - return kStatus_SDMMC_NotSupportYet; + /* Hand-shaking with card to validata the voltage range Host first sending its expected + information.*/ + error = MMC_SendOperationCondition(card, 0U); + if (kStatus_Success != error) + { + return kStatus_SDMMC_HandShakeOperationConditionFailed; + } + + error = MMC_ValidateOperationVoltage(card, &opcode); + if (kStatus_Success != error) + { + return kStatus_SDMMC_InvalidVoltage; + } + + /* Get host's access mode. */ + opcode |= (card->host->maxBlockSize >= FSL_SDMMC_DEFAULT_BLOCK_SIZE ? + (uint32_t)kMMC_AccessModeSector << MMC_OCR_ACCESS_MODE_SHIFT : + (uint32_t)kMMC_AccessModeByte << MMC_OCR_ACCESS_MODE_SHIFT); + + error = MMC_SendOperationCondition(card, opcode); + if (kStatus_Success != error) + { + return kStatus_SDMMC_HandShakeOperationConditionFailed; } /* Get card CID */ - if (kStatus_Success != MMC_AllSendCid(card)) { + error = MMC_AllSendCid(card); + if (kStatus_Success != error) + { return kStatus_SDMMC_AllSendCidFailed; } + error = MMC_SetRelativeAddress(card); /* Set the card relative address */ - if (kStatus_Success != MMC_SetRelativeAddress(card)) { + if (kStatus_Success != error) + { return kStatus_SDMMC_SetRelativeAddressFailed; } + error = MMC_SendCsd(card); /* Get the CSD register content */ - if (kStatus_Success != MMC_SendCsd(card)) { + if (kStatus_Success != error) + { return kStatus_SDMMC_SendCsdFailed; } + /* Set to maximum speed in normal mode. */ + MMC_SetMaxFrequency(card); + /* Send CMD7 with the card's relative address to place the card in transfer state. Puts current selected card in transfer state. */ - if (kStatus_Success != MMC_SelectCard(card, true)) { + error = MMC_SelectCard(card, true); + if (kStatus_Success != error) + { return kStatus_SDMMC_SelectCardFailed; } /* Get Extended CSD register content. */ - if (kStatus_Success != MMC_SendExtendedCsd(card, NULL, 0U)) { + error = MMC_SendExtendedCsd(card, NULL, 0U); + if (kStatus_Success != error) + { return kStatus_SDMMC_SendExtendedCsdFailed; } - mmc_extended_csd_config_t extendedCsdconfig; - - /* Set Erase Group Definition Bit to 1 */ - extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexEraseGroupDefinition; - extendedCsdconfig.ByteValue = 1; - extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { - return kStatus_SDMMC_ConfigureExtendedCsdFailed; + error = MMC_SetMaxEraseUnitSize(card); + /* Set to max erase unit size */ + if (kStatus_Success != error) + { + return kStatus_SDMMC_EnableHighCapacityEraseFailed; } -#if 0 - if(kStatus_Success != MMC_SetGeneralPurposePartitioning(card, kMMC_AccessGeneralPurposePartition1, 512*512)) + error = MMC_SetBlockSize(card, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + /* set block size */ + if (kStatus_Success != error) { - return kStatus_SDMMC_PartitioningFailed; + return kStatus_SDMMC_SetCardBlockSizeFailed; } -#endif - if (kStatus_Success != MMC_SelectBusTiming(card)) { + error = MMC_SelectBusTiming(card); + /* switch to host support speed mode, then switch MMC data bus width and select power class */ + if (kStatus_Success != error) + { return kStatus_SDMMC_SwitchBusTimingFailed; } - // check if system partition configured - if (card->extendedCsd.generalPartition1Multi0 || card->extendedCsd.generalPartition1Multi1 || - card->extendedCsd.generalPartition1Multi2) { - - /* Calculate system partition block count */ - card->systemPartitionBlocks = - ((512 * 1024) * card->extendedCsd.highCapacityWriteProtectGroupSize * - card->extendedCsd.highCapacityEraseUnitSize * - (card->extendedCsd.generalPartition1Multi0 ? card->extendedCsd.generalPartition1Multi0 : 1) * - (card->extendedCsd.generalPartition1Multi1 ? card->extendedCsd.generalPartition1Multi1 * 64 : 1) * - (card->extendedCsd.generalPartition1Multi2 ? card->extendedCsd.generalPartition1Multi2 * 256 : 1)) / - FSL_SDMMC_DEFAULT_BLOCK_SIZE; + error = MMC_SetPowerClass(card); + /* switch power class */ + if (kStatus_Success != error) + { + return kStatus_SDMMC_SetPowerClassFail; } + /* trying to enable the cache */ + (void)MMC_EnableCacheControl(card, true); + /* Set card default to access non-boot partition */ - card->currentPartition = kMMC_AccessPartitionUserArea; + card->currentPartition = kMMC_AccessPartitionUserAera; return kStatus_Success; } +status_t MMC_CardInit(mmc_card_t *card) +{ + assert(card != NULL); + + status_t error = kStatus_Success; + /* create mutex lock */ + (void)SDMMC_OSAMutexCreate(&card->lock); + (void)SDMMC_OSAMutexLock(&card->lock, osaWaitForever_c); + + error = mmccard_init(card); + + (void)SDMMC_OSAMutexUnlock(&card->lock); + + return error; +} + void MMC_CardDeinit(mmc_card_t *card) { - assert(card); + assert(card != NULL); - MMC_SelectCard(card, false); + (void)SDMMC_OSAMutexLock(&card->lock, osaWaitForever_c); + + (void)MMC_SelectCard(card, false); + + (void)SDMMC_OSAMutexDestroy(&card->lock); } status_t MMC_HostInit(mmc_card_t *card) { - assert(card); + assert(card != NULL); - if ((!card->isHostReady) && SDMMCHOST_Init(&(card->host), NULL) != kStatus_Success) { - return kStatus_Fail; + if (!card->isHostReady) + { + if (SDMMCHOST_Init(card->host) != kStatus_Success) + { + return kStatus_Fail; + } } /* set the host status flag, after the card re-plug in, don't need init host again */ @@ -2068,41 +2270,67 @@ status_t MMC_HostInit(mmc_card_t *card) void MMC_HostDeinit(mmc_card_t *card) { - assert(card); + assert(card != NULL); - SDMMCHOST_Deinit(&(card->host)); + SDMMCHOST_Deinit(card->host); /* should re-init host */ card->isHostReady = false; } void MMC_HostReset(SDMMCHOST_CONFIG *host) { - SDMMCHOST_Reset(host->base); + SDMMCHOST_Reset(host); +} + +void MMC_HostDoReset(mmc_card_t *card) +{ + SDMMCHOST_Reset(card->host); +} + +void MMC_SetCardPower(mmc_card_t *card, bool enable) +{ + SDMMCHOST_SetCardPower(card->host, enable); + SDMMC_OSADelay(MMC_POWER_RESET_DELAY); } status_t MMC_Init(mmc_card_t *card) { - assert(card); + assert(card != NULL); - /* reset the host */ - MMC_HostReset(&(card->host)); + status_t error = kStatus_Success; - if (!card->isHostReady) { - if (MMC_HostInit(card) != kStatus_Success) { - return kStatus_SDMMC_HostNotReady; + if (!card->isHostReady) + { + if (MMC_HostInit(card) != kStatus_Success) + { + error = kStatus_SDMMC_HostNotReady; } } - else { + else + { /* reset the host */ - MMC_HostReset(&(card->host)); + MMC_HostDoReset(card); } - return MMC_CardInit(card); + if (error == kStatus_Success) + { + /* reset card power */ + MMC_SetCardPower(card, false); + MMC_SetCardPower(card, true); + + error = MMC_CardInit(card); + if (error != kStatus_Success) + { + error = kStatus_SDMMC_CardInitFailed; + } + } + + return error; } void MMC_Deinit(mmc_card_t *card) { - assert(card); + assert(card != NULL); MMC_CardDeinit(card); MMC_HostDeinit(card); @@ -2110,366 +2338,447 @@ void MMC_Deinit(mmc_card_t *card) bool MMC_CheckReadOnly(mmc_card_t *card) { - assert(card); + assert(card != NULL); - return ((card->csd.flags & kMMC_CsdPermanentWriteProtectFlag) || - (card->csd.flags & kMMC_CsdTemporaryWriteProtectFlag)); + return (((card->csd.flags & (uint16_t)kMMC_CsdPermanentWriteProtectFlag) != 0U) || + ((card->csd.flags & (uint16_t)kMMC_CsdTemporaryWriteProtectFlag) != 0U)); } status_t MMC_SelectPartition(mmc_card_t *card, mmc_access_partition_t partitionNumber) { - assert(card); + assert(card != NULL); uint8_t bootConfig; mmc_extended_csd_config_t extendedCsdconfig; + status_t error = kStatus_Success; + + (void)SDMMC_OSAMutexLock(&card->lock, osaWaitForever_c); bootConfig = card->extendedCsd.partitionConfig; - bootConfig &= ~MMC_PARTITION_CONFIG_PARTITION_ACCESS_MASK; - bootConfig |= ((uint32_t)partitionNumber << MMC_PARTITION_CONFIG_PARTITION_ACCESS_SHIFT); + bootConfig &= ~(uint8_t)MMC_PARTITION_CONFIG_PARTITION_ACCESS_MASK; + bootConfig |= ((uint8_t)partitionNumber << MMC_PARTITION_CONFIG_PARTITION_ACCESS_SHIFT); extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexPartitionConfig; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexPartitionConfig; extendedCsdconfig.ByteValue = bootConfig; extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { - return kStatus_SDMMC_ConfigureExtendedCsdFailed; + if (kStatus_Success != + MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, (uint32_t)card->extendedCsd.partitionSwitchTimeout * 10U)) + { + error = kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + else + { + /* Save current configuration. */ + card->extendedCsd.partitionConfig = bootConfig; + card->currentPartition = partitionNumber; } - /* Save current configuration. */ - card->extendedCsd.partitionConfig = bootConfig; - card->currentPartition = partitionNumber; + (void)SDMMC_OSAMutexUnlock(&card->lock); - return kStatus_Success; + return error; } status_t MMC_ReadBlocks(mmc_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockCount) { - assert(card); - assert(buffer); - assert(blockCount); + assert(card != NULL); + assert(buffer != NULL); + assert(blockCount != 0U); - const uint8_t maxAttempts = 5; uint32_t blockCountOneTime; /* The block count can be erased in one time sending READ_BLOCKS command. */ uint32_t blockDone; /* The blocks has been read. */ uint32_t blockLeft; /* Left blocks to be read. */ uint8_t *nextBuffer; - bool dataAddrAlign = true; - bool errorOccured = false; - bool isWriteOk = false; + bool dataAddrAlign = true; + uint8_t *alignBuffer = (uint8_t *)FSL_SDMMC_CARD_INTERNAL_BUFFER_ALIGN_ADDR(card->internalBuffer); + status_t error = kStatus_Success; + + (void)SDMMC_OSAMutexLock(&card->lock, osaWaitForever_c); blockLeft = blockCount; blockDone = 0U; - if (kStatus_Success != MMC_CheckBlockRange(card, startBlock, blockCount)) { - return kStatus_InvalidArgument; + error = MMC_CheckBlockRange(card, startBlock, blockCount); + if (kStatus_Success != error) + { + error = kStatus_InvalidArgument; } - - while (blockLeft) { - nextBuffer = (buffer + blockDone * FSL_SDMMC_DEFAULT_BLOCK_SIZE); - if (!card->noInteralAlign && (!dataAddrAlign || (((uint32_t)nextBuffer) & (sizeof(uint32_t) - 1U)))) { - blockLeft--; - blockCountOneTime = 1U; - memset(g_sdmmc, 0U, FSL_SDMMC_DEFAULT_BLOCK_SIZE); - dataAddrAlign = false; - } - else { - if (blockLeft > card->host.capability.maxBlockCount) { - blockLeft = (blockLeft - card->host.capability.maxBlockCount); - blockCountOneTime = card->host.capability.maxBlockCount; - } - else { - blockCountOneTime = blockLeft; - blockLeft = 0U; - } - } - - for (uint8_t i = 0; i < maxAttempts; i++) + else + { + while (blockLeft != 0U) { - if (errorOccured) + nextBuffer = (uint8_t *)((uint32_t)buffer + blockDone * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + if (!card->noInteralAlign && (!dataAddrAlign || ((((uint32_t)nextBuffer) & (sizeof(uint32_t) - 1U)) != 0U))) { - if (MMC_Init(card) == kStatus_Success) + blockLeft--; + blockCountOneTime = 1U; + (void)memset(alignBuffer, 0, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + dataAddrAlign = false; + } + else + { + if (blockLeft > card->host->maxBlockCount) { - LOG_ERROR("MMC reinit OK\n"); - errorOccured = false; + blockLeft = (blockLeft - card->host->maxBlockCount); + blockCountOneTime = card->host->maxBlockCount; } else { - LOG_ERROR("MMC reinit error\n"); - continue; - } + blockCountOneTime = blockLeft; + blockLeft = 0U; + } } - if (kStatus_Success != MMC_Read(card, dataAddrAlign ? nextBuffer : (uint8_t *)g_sdmmc, (startBlock + blockDone), - FSL_SDMMC_DEFAULT_BLOCK_SIZE, blockCountOneTime)) - { - LOG_ERROR("MMC_Read transfer failed\n"); - errorOccured = true; - } - else + error = MMC_Read(card, dataAddrAlign ? nextBuffer : (uint8_t *)alignBuffer, (startBlock + blockDone), + FSL_SDMMC_DEFAULT_BLOCK_SIZE, blockCountOneTime); + if (kStatus_Success != error) { - isWriteOk = true; + error = kStatus_SDMMC_TransferFailed; break; } - } - - if (!isWriteOk) - { - return kStatus_SDMMC_TransferFailed; - } - blockDone += blockCountOneTime; + blockDone += blockCountOneTime; - if (!card->noInteralAlign && (!dataAddrAlign)) { - memcpy(nextBuffer, (uint8_t *)&g_sdmmc, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + if (!card->noInteralAlign && (!dataAddrAlign)) + { + (void)memcpy(nextBuffer, alignBuffer, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + } } } - return kStatus_Success; + (void)SDMMC_OSAMutexUnlock(&card->lock); + + return error; } status_t MMC_WriteBlocks(mmc_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockCount) { - assert(card); - assert(buffer); - assert(blockCount); + assert(card != NULL); + assert(buffer != NULL); + assert(blockCount != 0U); - const uint8_t maxAttempts = 5; uint32_t blockCountOneTime; uint32_t blockLeft; uint32_t blockDone; const uint8_t *nextBuffer; - bool dataAddrAlign = true; - bool errorOccured = false; - bool isWriteOk = false; + bool dataAddrAlign = true; + uint8_t *alignBuffer = (uint8_t *)FSL_SDMMC_CARD_INTERNAL_BUFFER_ALIGN_ADDR(card->internalBuffer); + status_t error = kStatus_Success; + + (void)SDMMC_OSAMutexLock(&card->lock, osaWaitForever_c); blockLeft = blockCount; blockDone = 0U; - if (kStatus_Success != MMC_CheckBlockRange(card, startBlock, blockCount)) { - return kStatus_InvalidArgument; + error = MMC_CheckBlockRange(card, startBlock, blockCount); + if (kStatus_Success != error) + { + error = kStatus_InvalidArgument; } - - while (blockLeft) { - nextBuffer = (buffer + blockDone * FSL_SDMMC_DEFAULT_BLOCK_SIZE); - if (!card->noInteralAlign && (!dataAddrAlign || (((uint32_t)nextBuffer) & (sizeof(uint32_t) - 1U)))) { - blockLeft--; - blockCountOneTime = 1U; - memcpy((uint8_t *)&g_sdmmc, nextBuffer, FSL_SDMMC_DEFAULT_BLOCK_SIZE); - dataAddrAlign = false; - } - else { - if (blockLeft > card->host.capability.maxBlockCount) { - blockLeft = (blockLeft - card->host.capability.maxBlockCount); - blockCountOneTime = card->host.capability.maxBlockCount; - } - else { - blockCountOneTime = blockLeft; - blockLeft = 0U; - } - } - - for (uint8_t i = 0; i < maxAttempts; i++) + else + { + while (blockLeft != 0U) { - if (errorOccured) + nextBuffer = (uint8_t *)((uint32_t)buffer + blockDone * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + if (!card->noInteralAlign && (!dataAddrAlign || (0U != (((uint32_t)nextBuffer) & (sizeof(uint32_t) - 1U))))) + { + blockLeft--; + blockCountOneTime = 1U; + (void)memcpy(alignBuffer, nextBuffer, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + dataAddrAlign = false; + } + else { - if (MMC_Init(card) == kStatus_Success) + if (blockLeft > card->host->maxBlockCount) { - LOG_ERROR("MMC reinit OK\n"); - errorOccured = false; + blockLeft = (blockLeft - card->host->maxBlockCount); + blockCountOneTime = card->host->maxBlockCount; } else { - LOG_ERROR("MMC reinit error\n"); - continue; - } + blockCountOneTime = blockLeft; + blockLeft = 0U; + } } - - if (kStatus_Success != MMC_Write(card, dataAddrAlign ? nextBuffer : (uint8_t *)g_sdmmc, - (startBlock + blockDone), FSL_SDMMC_DEFAULT_BLOCK_SIZE, blockCountOneTime)) + error = MMC_Write(card, dataAddrAlign ? nextBuffer : (uint8_t *)alignBuffer, (startBlock + blockDone), + FSL_SDMMC_DEFAULT_BLOCK_SIZE, blockCountOneTime); + if (kStatus_Success != error) { - LOG_ERROR("MMC_Write transfer failed\n"); - errorOccured = true; + error = kStatus_SDMMC_TransferFailed; + break; } - else + + blockDone += blockCountOneTime; + if (!card->noInteralAlign && (!dataAddrAlign)) { - isWriteOk = true; - break; + (void)memset(alignBuffer, 0, FSL_SDMMC_DEFAULT_BLOCK_SIZE); } } + } - if (!isWriteOk) - { - return kStatus_SDMMC_TransferFailed; - } + (void)SDMMC_OSAMutexUnlock(&card->lock); + return error; +} - blockDone += blockCountOneTime; - if (!card->noInteralAlign) { - memset(g_sdmmc, 0U, FSL_SDMMC_DEFAULT_BLOCK_SIZE); - } +status_t MMC_EnableCacheControl(mmc_card_t *card, bool enable) +{ + assert(card != NULL); + + uint8_t cacheCtrl = 0; + + mmc_extended_csd_config_t extendedCsdconfig; + + /* check the target driver strength support or not */ + if (card->extendedCsd.cacheSize == 0U) + { + SDMMC_LOG("The cache is not supported by the mmc device\r\n"); + return kStatus_SDMMC_NotSupportYet; } + if (enable) + { + cacheCtrl = MMC_CACHE_CONTROL_ENABLE; + } + + /* Switch to high speed timing. */ + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexCacheControl; + extendedCsdconfig.ByteValue = cacheCtrl; + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { + SDMMC_LOG("cache enabled failed\r\n"); + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + + card->extendedCsd.cacheCtrl = cacheCtrl; + return kStatus_Success; } -status_t MMC_EraseGroups(mmc_card_t *card, uint32_t startGroup, uint32_t endGroup) +status_t MMC_FlushCache(mmc_card_t *card) { - assert(card); - assert(card->host.transfer); + assert(card != NULL); - uint32_t startGroupAddress; - uint32_t endGroupAddress; - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_TRANSFER content = {0}; + mmc_extended_csd_config_t extendedCsdconfig; + status_t error = kStatus_Success; - if (kStatus_Success != MMC_CheckEraseGroupRange(card, startGroup, endGroup)) { - return kStatus_InvalidArgument; + /* check the target driver strength support or not */ + if ((card->extendedCsd.cacheSize == 0U) || (card->extendedCsd.cacheCtrl != MMC_CACHE_CONTROL_ENABLE)) + { + SDMMC_LOG("The cache is not supported or not enabled, please check\r\n"); + error = kStatus_SDMMC_NotSupportYet; + } + else + { + /* Switch to high speed timing. */ + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexFlushCache; + extendedCsdconfig.ByteValue = MMC_CACHE_TRIGGER_FLUSH; + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { + SDMMC_LOG("cache flush failed\r\n"); + error = kStatus_SDMMC_ConfigureExtendedCsdFailed; + } } - /* Wait for the card's buffer to be not full to write to improve the write performance. */ - while ((GET_SDMMCHOST_STATUS(card->host.base) & CARD_DATA0_STATUS_MASK) != CARD_DATA0_NOT_BUSY) {} + return error; +} + +status_t MMC_SetSleepAwake(mmc_card_t *card, mmc_sleep_awake_t state) +{ + assert(card != NULL); + status_t error = kStatus_Success; + + sdmmchost_cmd_t command = {0}; + sdmmchost_transfer_t content = {0}; + + if (card->extendedCsd.extendecCsdVersion <= + (uint32_t)kMMC_ExtendedCsdRevision13) /* V4.3 or above version card support boot mode */ + { + return kStatus_SDMMC_NotSupportYet; + } - if (kStatus_Success != MMC_WaitWriteComplete(card)) { - return kStatus_SDMMC_WaitWriteCompleteFailed; + error = MMC_PollingCardStatusBusy(card, false, MMC_CARD_ACCESS_WAIT_IDLE_TIMEOUT); + if (kStatus_SDMMC_CardStatusIdle != error) + { + return kStatus_SDMMC_PollingCardIdleFailed; } - /* Calculate the start group address and end group address */ - startGroupAddress = startGroup; - endGroupAddress = endGroup; - if (card->flags & kMMC_SupportHighCapacityFlag) { - /* The implementation of a higher than 2GB of density of memory will not be backwards compatible with the - lower densities.First of all the address argument for higher than 2GB of density of memory is changed to - be sector address (512B sectors) instead of byte address */ - startGroupAddress = (startGroupAddress * (card->eraseGroupBlocks)); - endGroupAddress = (endGroupAddress * (card->eraseGroupBlocks)); + /* deselect the card before enter into sleep state */ + if (state == kMMC_Sleep) + { + if (MMC_SelectCard(card, false) != kStatus_Success) + { + return kStatus_SDMMC_DeselectCardFailed; + } } - else { - /* The address unit is byte when card capacity is lower than 2GB */ - startGroupAddress = (startGroupAddress * (card->eraseGroupBlocks) * FSL_SDMMC_DEFAULT_BLOCK_SIZE); - endGroupAddress = (endGroupAddress * (card->eraseGroupBlocks) * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + + command.index = (uint32_t)kMMC_SleepAwake; + command.argument = ((uint32_t)state << 15U) | (card->relativeAddress << 16U); + command.responseType = kCARD_ResponseTypeR1b; + + content.command = &command; + content.data = NULL; + + error = MMC_Transfer(card, &content, 0U); + if (kStatus_Success != error) + { + return kStatus_SDMMC_TransferFailed; } + /* Sleep awake timeout value 100ns * 2^sleepAwakeTimeout */ + error = MMC_PollingCardStatusBusy(card, false, (1UL << card->extendedCsd.sleepAwakeTimeout) / 10000U); + if (kStatus_SDMMC_CardStatusIdle != error) + { + return kStatus_SDMMC_PollingCardIdleFailed; + } + + /* select the card after wake up */ + if (state == kMMC_Awake) + { + if (MMC_SelectCard(card, true) != kStatus_Success) + { + return kStatus_SDMMC_SelectCardFailed; + } + } + + return kStatus_Success; +} + +static status_t MMC_Erase(mmc_card_t *card, uint32_t startGroupAddress, uint32_t endGroupAddress) +{ + sdmmchost_cmd_t command = {0}; + sdmmchost_transfer_t content = {0}; + status_t error = kStatus_Success; + /* Set the start erase group address */ - command.index = kMMC_EraseGroupStart; + command.index = (uint32_t)kMMC_EraseGroupStart; command.argument = startGroupAddress; command.responseType = kCARD_ResponseTypeR1; - command.responseErrorFlags = kSDMMC_R1ErrorAllFlag; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; content.command = &command; content.data = NULL; - if (kStatus_Success != MMC_Transfer(card, &content, 0U)) { + error = MMC_Transfer(card, &content, 0U); + if (kStatus_Success != error) + { return kStatus_SDMMC_TransferFailed; } /* Set the end erase group address */ - command.index = kMMC_EraseGroupEnd; + command.index = (uint32_t)kMMC_EraseGroupEnd; command.argument = endGroupAddress; content.command = &command; content.data = NULL; - if (kStatus_Success != MMC_Transfer(card, &content, 0U)) { + error = MMC_Transfer(card, &content, 0U); + if (kStatus_Success != error) + { return kStatus_SDMMC_TransferFailed; } /* Start the erase process */ - command.index = kSDMMC_Erase; + command.index = (uint32_t)kSDMMC_Erase; command.argument = 0U; command.responseType = kCARD_ResponseTypeR1b; - command.responseErrorFlags = kSDMMC_R1ErrorAllFlag; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; content.command = &command; content.data = NULL; - if (kStatus_Success != MMC_Transfer(card, &content, 0U)) { + error = MMC_Transfer(card, &content, 0U); + if (kStatus_Success != error) + { return kStatus_SDMMC_TransferFailed; } return kStatus_Success; } -status_t MMC_SetGeneralPurposePartitioning(mmc_card_t *card, mmc_access_partition_t partition, uint32_t size) +status_t MMC_EraseGroups(mmc_card_t *card, uint32_t startGroup, uint32_t endGroup) { - assert(card); - - uint8_t byteIndex = 0; - - if (((card->extendedCsd.partitioningSupport & kMMC_ExtCsdExtPartitionSupport) == 0) || - ((card->extendedCsd.partitioningSupport & kMMC_ExtCsdEnhancePartitionSupport) == 0) || - ((card->extendedCsd.partitioningSupport & kMMC_ExtCsdPartitioningSupport) == 0)) { - return kStatus_SDMMC_PartitioningNotSupported; - } - switch (partition) { - case kMMC_AccessGeneralPurposePartition1: - byteIndex = kMMC_ExtendedCsdIndexGenPartition1Base; - break; - case kMMC_AccessGeneralPurposePartition2: - byteIndex = kMMC_ExtendedCsdIndexGenPartition2Base; - break; - case kMMC_AccessGeneralPurposePartition3: - byteIndex = kMMC_ExtendedCsdIndexGenPartition3Base; - break; - case kMMC_AccessGeneralPurposePartition4: - byteIndex = kMMC_ExtendedCsdIndexGenPartition4Base; - break; - default: - return kStatus_SDMMC_ConfigureExtendedCsdFailed; - } + assert(card != NULL); - mmc_extended_csd_config_t extendedCsdconfig; + uint32_t startGroupAddress; + uint32_t endGroupAddress; + status_t error = kStatus_Success; + uint32_t eraseTimeout = MMC_CARD_ACCESS_WAIT_IDLE_TIMEOUT; - /* Set Erase Group Definition Bit to 1 */ - extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexEraseGroupDefinition; - extendedCsdconfig.ByteValue = 1; - extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { - return kStatus_SDMMC_ConfigureExtendedCsdFailed; - } + (void)SDMMC_OSAMutexLock(&card->lock, osaWaitForever_c); - uint8_t multipliers[3] = {0}; - uint32_t required_size = size; // in KBytes + error = MMC_CheckEraseGroupRange(card, startGroup, endGroup); + if (kStatus_Success != error) + { + error = kStatus_InvalidArgument; + } + else + { + error = MMC_PollingCardStatusBusy(card, true, 0U); + if (error != kStatus_SDMMC_CardStatusIdle) + { + error = kStatus_SDMMC_PollingCardIdleFailed; + } + } - uint32_t multiplier = required_size / (512 * card->extendedCsd.highCapacityWriteProtectGroupSize * - card->extendedCsd.highCapacityEraseUnitSize); + if (error == kStatus_SDMMC_CardStatusIdle) + { + /* Calculate the start group address and end group address */ + startGroupAddress = startGroup; + endGroupAddress = endGroup; + if ((card->flags & (uint32_t)kMMC_SupportHighCapacityFlag) != 0U) + { + /* The implementation of a higher than 2GB of density of memory will not be backwards compatible with the + lower densities.First of all the address argument for higher than 2GB of density of memory is changed to + be sector address (512B sectors) instead of byte address */ + startGroupAddress = (startGroupAddress * (card->eraseGroupBlocks)); + endGroupAddress = (endGroupAddress * (card->eraseGroupBlocks)); + } + else + { + /* The address unit is byte when card capacity is lower than 2GB */ + startGroupAddress = (startGroupAddress * (card->eraseGroupBlocks) * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + endGroupAddress = (endGroupAddress * (card->eraseGroupBlocks) * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + } - MMC_CalculateMultiplier(multiplier, multipliers); + error = MMC_Erase(card, startGroupAddress, endGroupAddress); + if (error == kStatus_Success) + { + if ((0U != (card->flags & (uint32_t)kMMC_SupportHighCapacityFlag)) && + (card->extendedCsd.highCapacityEraseTimeout != 0U)) + { + eraseTimeout = + (uint32_t)card->extendedCsd.highCapacityEraseTimeout * 300U * (endGroup - startGroup + 1U); + } - uint8_t i = 0; - for (i = 0; i < 3; i++) { - extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = byteIndex++; - extendedCsdconfig.ByteValue = multipliers[i]; - extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { - return kStatus_SDMMC_ConfigureExtendedCsdFailed; + error = MMC_PollingCardStatusBusy(card, true, eraseTimeout); + if (kStatus_SDMMC_CardStatusIdle != error) + { + error = kStatus_SDMMC_PollingCardIdleFailed; + } + else + { + error = kStatus_Success; + } } } - /* Get Extended CSD register content. */ - if (kStatus_Success != MMC_SendExtendedCsd(card, NULL, 0U)) { - return kStatus_SDMMC_SendExtendedCsdFailed; - } - - /* Set Partitioning Completed bit */ - extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeSetBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexPartitioningCompleted; - extendedCsdconfig.ByteValue = 1; - extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { - return kStatus_SDMMC_ConfigureExtendedCsdFailed; - } + (void)SDMMC_OSAMutexUnlock(&card->lock); - return kStatus_Success; + return error; } status_t MMC_SetBootConfigWP(mmc_card_t *card, uint8_t wp) { - assert(card); + assert(card != NULL); mmc_extended_csd_config_t extendedCsdconfig; extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexBootConfigWP; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexBootConfigWP; extendedCsdconfig.ByteValue = wp; extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { return kStatus_SDMMC_ConfigureExtendedCsdFailed; } @@ -2480,91 +2789,103 @@ status_t MMC_SetBootConfigWP(mmc_card_t *card, uint8_t wp) status_t MMC_SetBootPartitionWP(mmc_card_t *card, mmc_boot_partition_wp_t bootPartitionWP) { - assert(card); + assert(card != NULL); mmc_extended_csd_config_t extendedCsdconfig; extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexBootPartitionWP; - extendedCsdconfig.ByteValue = bootPartitionWP; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexBootPartitionWP; + extendedCsdconfig.ByteValue = (uint8_t)bootPartitionWP; extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { return kStatus_SDMMC_ConfigureExtendedCsdFailed; } - card->extendedCsd.bootPartitionWP = bootPartitionWP; + card->extendedCsd.bootPartitionWP = (uint8_t)bootPartitionWP; return kStatus_Success; } status_t MMC_SetBootConfig(mmc_card_t *card, const mmc_boot_config_t *config) { - assert(card); - assert(config); + assert(card != NULL); + assert(config != NULL); uint8_t bootParameter; - uint8_t bootBusWidth = config->bootDataBusWidth; + uint8_t bootBusWidth = (uint8_t)config->bootDataBusWidth; mmc_extended_csd_config_t extendedCsdconfig; if (card->extendedCsd.extendecCsdVersion <= - kMMC_ExtendedCsdRevision13) /* V4.3 or above version card support boot mode */ + (uint32_t)kMMC_ExtendedCsdRevision13) /* V4.3 or above version card support boot mode */ { return kStatus_SDMMC_NotSupportYet; } /* Set the BOOT_CONFIG field of Extended CSD */ bootParameter = card->extendedCsd.partitionConfig; - bootParameter &= ~(MMC_PARTITION_CONFIG_BOOT_ACK_MASK | MMC_PARTITION_CONFIG_PARTITION_ENABLE_MASK); + bootParameter &= + ~((uint8_t)MMC_PARTITION_CONFIG_BOOT_ACK_MASK | (uint8_t)MMC_PARTITION_CONFIG_PARTITION_ENABLE_MASK); bootParameter |= ((config->enableBootAck ? 1U : 0U) << MMC_PARTITION_CONFIG_BOOT_ACK_SHIFT); - bootParameter |= ((uint32_t)(config->bootPartition) << MMC_PARTITION_CONFIG_PARTITION_ENABLE_SHIFT); + bootParameter |= ((uint8_t)(config->bootPartition) << MMC_PARTITION_CONFIG_PARTITION_ENABLE_SHIFT); extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexPartitionConfig; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexPartitionConfig; extendedCsdconfig.ByteValue = bootParameter; extendedCsdconfig.commandSet = kMMC_CommandSetStandard; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { return kStatus_SDMMC_ConfigureExtendedCsdFailed; } card->extendedCsd.partitionConfig = bootParameter; /* data bus remapping */ - if (bootBusWidth == kMMC_DataBusWidth1bit) { + if (bootBusWidth == (uint8_t)kMMC_DataBusWidth1bit) + { bootBusWidth = 0U; } - else if ((bootBusWidth == kMMC_DataBusWidth4bit) || (bootBusWidth == kMMC_DataBusWidth4bitDDR)) { + else if ((bootBusWidth == (uint8_t)kMMC_DataBusWidth4bit) || (bootBusWidth == (uint8_t)kMMC_DataBusWidth4bitDDR)) + { bootBusWidth = 1U; } - else { + else + { bootBusWidth = 2U; } /*Set BOOT_BUS_CONDITIONS in Extended CSD */ bootParameter = card->extendedCsd.bootDataBusConditions; - bootParameter &= ~(MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_MASK | MMC_BOOT_BUS_CONDITION_BUS_WIDTH_MASK | - MMC_BOOT_BUS_CONDITION_BOOT_MODE_MASK); + bootParameter &= (uint8_t) ~(MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_MASK | + MMC_BOOT_BUS_CONDITION_BUS_WIDTH_MASK | MMC_BOOT_BUS_CONDITION_BOOT_MODE_MASK); bootParameter |= - ((config->retainBootbusCondition ? true : false) << MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_SHIFT); + (uint8_t)((config->retainBootbusCondition ? 1U : 0U) << MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_SHIFT); bootParameter |= bootBusWidth << MMC_BOOT_BUS_CONDITION_BUS_WIDTH_SHIFT; - bootParameter |= (uint32_t)(config->bootTimingMode); + bootParameter |= ((uint8_t)(config->bootTimingMode) << MMC_BOOT_BUS_CONDITION_BOOT_MODE_SHIFT) & + MMC_BOOT_BUS_CONDITION_BOOT_MODE_MASK; extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; - extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexBootBusConditions; + extendedCsdconfig.ByteIndex = (uint8_t)kMMC_ExtendedCsdIndexBootBusConditions; extendedCsdconfig.ByteValue = bootParameter; - if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) { + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig, 0U)) + { return kStatus_SDMMC_ConfigureBootFailed; } card->extendedCsd.bootDataBusConditions = bootParameter; /* check and configure the boot config write protect */ - bootParameter = config->pwrBootConfigProtection | ((uint8_t)(config->premBootConfigProtection) << 4U); - if (bootParameter != (card->extendedCsd.bootConfigProtect)) { - if (kStatus_Success != MMC_SetBootConfigWP(card, bootParameter)) { + bootParameter = (uint8_t)config->pwrBootConfigProtection | (((uint8_t)config->premBootConfigProtection) << 4U); + if (bootParameter != (card->extendedCsd.bootConfigProtect)) + { + if (kStatus_Success != MMC_SetBootConfigWP(card, bootParameter)) + { return kStatus_SDMMC_ConfigureBootFailed; } } /* check and configure the boot partition write protect */ - if (card->extendedCsd.bootPartitionWP != (uint8_t)(config->bootPartitionWP)) { - if (kStatus_Success != MMC_SetBootPartitionWP(card, config->bootPartitionWP)) { + if (card->extendedCsd.bootPartitionWP != (uint8_t)(config->bootPartitionWP)) + { + if (kStatus_Success != MMC_SetBootPartitionWP(card, config->bootPartitionWP)) + { return kStatus_SDMMC_ConfigureBootFailed; } } @@ -2575,103 +2896,84 @@ status_t MMC_SetBootConfig(mmc_card_t *card, const mmc_boot_config_t *config) status_t MMC_StartBoot(mmc_card_t *card, const mmc_boot_config_t *mmcConfig, uint8_t *buffer, - SDMMCHOST_BOOT_CONFIG *hostConfig) + sdmmchost_boot_config_t *hostConfig) { - assert(card); - assert(mmcConfig); - assert(buffer); + assert(card != NULL); + assert(mmcConfig != NULL); + assert(buffer != NULL); - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_DATA data = {0}; - uint32_t tempClock = 0U; + sdmmchost_cmd_t command = {0}; + uint32_t tempClock = 0U; - if (!card->isHostReady) { + if (!card->isHostReady) + { return kStatus_Fail; } /* send card active */ - SDMMCHOST_SEND_CARD_ACTIVE(card->host.base, 100U); - /* config the host */ - SDMMCHOST_SETMMCBOOTCONFIG(card->host.base, hostConfig); + SDMMCHOST_SendCardActive(card->host); /* enable MMC boot */ - SDMMCHOST_ENABLE_MMC_BOOT(card->host.base, true); + SDMMCHOST_EnableBoot(card->host, true); - if (mmcConfig->bootTimingMode == kMMC_BootModeSDRWithDefaultTiming) { + if (mmcConfig->bootTimingMode == kMMC_BootModeSDRWithDefaultTiming) + { /* Set clock to 400KHz. */ tempClock = SDMMC_CLOCK_400KHZ; } - else { + else + { /* Set clock to 52MHZ. */ tempClock = MMC_CLOCK_52MHZ; } - SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, tempClock); + (void)SDMMCHOST_SetCardClock(card->host, tempClock); - if (mmcConfig->bootTimingMode == kMMC_BootModeDDRTiming) { + if (((card->host->capability & (uint32_t)kSDMMCHOST_SupportDDRMode) != 0U) && + (mmcConfig->bootTimingMode == kMMC_BootModeDDRTiming)) + { /* enable DDR mode */ - SDMMCHOST_ENABLE_DDR_MODE(card->host.base, true, 0U); + SDMMCHOST_EnableDDRMode(card->host, true, 0U); } /* data bus remapping */ - if (mmcConfig->bootDataBusWidth == kMMC_DataBusWidth1bit) { - SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH1BIT); + if (mmcConfig->bootDataBusWidth == kMMC_DataBusWidth1bit) + { + SDMMCHOST_SetCardBusWidth(card->host, kSDMMC_BusWdith1Bit); } else if ((mmcConfig->bootDataBusWidth == kMMC_DataBusWidth4bit) || - (mmcConfig->bootDataBusWidth == kMMC_DataBusWidth4bitDDR)) { - SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH4BIT); + (mmcConfig->bootDataBusWidth == kMMC_DataBusWidth4bitDDR)) + { + SDMMCHOST_SetCardBusWidth(card->host, kSDMMC_BusWdith4Bit); } - else { - SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH8BIT); + else + { + SDMMCHOST_SetCardBusWidth(card->host, kSDMMC_BusWdith8Bit); } - if (kMMC_BootModeAlternative == (uint32_t)SDMMCHOST_GET_HOST_CONFIG_BOOT_MODE(hostConfig)) { + if (kMMC_BootModeAlternative == mmcConfig->bootMode) + { /* alternative boot mode */ - command.argument = 0xFFFFFFFA; + command.argument = 0xFFFFFFFAU; } - command.index = kSDMMC_GoIdleState; - - data.blockSize = SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(hostConfig); - data.blockCount = SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(hostConfig); - data.rxData = (uint32_t *)buffer; - SDMMCHOST_ENABLE_BOOT_FLAG(data); - - content.data = &data; - content.command = &command; + command.index = (uint32_t)kSDMMC_GoIdleState; /* should check tuning error during every transfer*/ - if (kStatus_Success != MMC_Transfer(card, &content, 1U)) { + if (kStatus_Success != SDMMCHOST_StartBoot(card->host, hostConfig, &command, buffer)) + { return kStatus_SDMMC_TransferFailed; } return kStatus_Success; } -status_t MMC_ReadBootData(mmc_card_t *card, uint8_t *buffer, SDMMCHOST_BOOT_CONFIG *hostConfig) +status_t MMC_ReadBootData(mmc_card_t *card, uint8_t *buffer, sdmmchost_boot_config_t *hostConfig) { - assert(card); - assert(buffer); - - SDMMCHOST_COMMAND command = {0}; - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_DATA data = {0}; - - /* enable MMC boot */ - SDMMCHOST_ENABLE_MMC_BOOT(card->host.base, true); - /* config the host */ - SDMMCHOST_SETMMCBOOTCONFIG(card->host.base, hostConfig); - data.blockSize = SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(hostConfig); - data.blockCount = SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(hostConfig); - data.rxData = (uint32_t *)buffer; - SDMMCHOST_ENABLE_BOOT_CONTINOUS_FLAG(data); - /* no command should be send out */ - SDMMCHOST_EMPTY_CMD_FLAG(command); - - content.data = &data; - content.command = &command; + assert(card != NULL); + assert(buffer != NULL); /* should check tuning error during every transfer*/ - if (kStatus_Success != MMC_Transfer(card, &content, 1U)) { + if (kStatus_Success != SDMMCHOST_ReadBootData(card->host, hostConfig, buffer)) + { return kStatus_SDMMC_TransferFailed; } @@ -2680,16 +2982,18 @@ status_t MMC_ReadBootData(mmc_card_t *card, uint8_t *buffer, SDMMCHOST_BOOT_CONF status_t MMC_StopBoot(mmc_card_t *card, uint32_t bootMode) { - assert(card); + assert(card != NULL); /* Disable boot mode */ - if (kMMC_BootModeAlternative == bootMode) { + if ((uint32_t)kMMC_BootModeAlternative == bootMode) + { /* Send CMD0 to reset the bus */ - if (kStatus_Success != MMC_GoIdle(card)) { + if (kStatus_Success != MMC_GoIdle(card)) + { return kStatus_SDMMC_GoIdleFailed; } } /* disable MMC boot */ - SDMMCHOST_ENABLE_MMC_BOOT(card->host.base, false); + SDMMCHOST_EnableBoot(card->host, false); return kStatus_Success; } diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.h b/module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.h index a04cb8636101e390e8dbc0473e01bd5cb597ff86..04fdd848796a909176447ab3bc0fb792b838ab6c 100644 --- a/module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.h +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.h @@ -1,35 +1,9 @@ /* - * The Clear BSD License * Copyright (c) 2015, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2021 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted (subject to the limitations in the disclaimer below) provided - * that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * o Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _FSL_MMC_H_ @@ -38,16 +12,21 @@ #include "fsl_sdmmc_common.h" /*! - * @addtogroup MMCCARD + * @addtogroup mmccard MMC Card Driver + * @ingroup card * @{ */ /******************************************************************************* * Definitions ******************************************************************************/ +/*! @brief Middleware mmc version. */ +#define FSL_MMC_DRIVER_VERSION (MAKE_VERSION(2U, 5U, 0U)) /*2.5.0*/ -/*! @brief MMC card flags */ -enum _mmc_card_flag +/*! @brief MMC card flags + * @anchor _mmc_card_flag + */ +enum { kMMC_SupportHighSpeed26MHZFlag = (1U << 0U), /*!< Support high speed 26MHZ */ kMMC_SupportHighSpeed52MHZFlag = (1U << 1U), /*!< Support high speed 52MHZ */ @@ -60,301 +39,403 @@ enum _mmc_card_flag kMMC_SupportHighCapacityFlag = (1U << 8U), /*!< Support high capacity */ kMMC_SupportAlternateBootFlag = (1U << 9U), /*!< Support alternate boot */ kMMC_SupportDDRBootFlag = (1U << 10U), /*!< support DDR boot flag*/ - kMMC_SupportHighSpeedBootFlag = (1U << 11U), /*!< support high speed boot flag*/ + kMMC_SupportHighSpeedBootFlag = (1U << 11U), /*!< support high speed boot flag */ + kMMC_SupportEnhanceHS400StrobeFlag = (1U << 12U), /*!< support enhance HS400 strobe */ }; +/*! @brief mmccard sleep/awake state */ +typedef enum _mmc_sleep_awake +{ + kMMC_Sleep = 1U, /*!< MMC card sleep */ + kMMC_Awake = 0U, /*!< MMC card awake */ +} mmc_sleep_awake_t; + +/*! @brief card io strength control */ +typedef void (*mmc_io_strength_t)(uint32_t busFreq); + +/*! @brief card user parameter */ +typedef struct _mmc_usr_param +{ + mmc_io_strength_t ioStrength; /*!< switch sd io strength */ + uint32_t maxFreq; /*!< board support maximum frequency */ + uint32_t capability; /*!< board capability flag */ +} mmc_usr_param_t; + /*! * @brief mmc card state * - * Define the card structure including the necessary fields to identify and describe the card. + * Defines the card structure including the necessary fields to identify and describe the card. */ typedef struct _mmc_card { - SDMMCHOST_CONFIG host; /*!< Host information */ + sdmmchost_t *host; /*!< Host information */ + mmc_usr_param_t usrParam; /*!< user parameter */ - bool isHostReady; /*!< Use this flag to indicate if need host re-init or not*/ - bool noInteralAlign; /*!< use this flag to disable sdmmc align. If disable, sdmmc will not make sure the - data buffer address is word align, otherwise all the transfer are align to low level driver */ - uint32_t busClock_Hz; /*!< MMC bus clock united in Hz */ - uint32_t relativeAddress; /*!< Relative address of the card */ + bool isHostReady; /*!< Use this flag to indicate if host re-init needed or not*/ + bool noInteralAlign; /*!< Use this flag to disable sdmmc align. If disabled, sdmmc will not make sure the + data buffer address is word align, otherwise all the transfer are aligned to low level driver. */ + uint32_t busClock_Hz; /*!< MMC bus clock united in Hz */ + uint32_t relativeAddress; /*!< Relative address of the card */ bool enablePreDefinedBlockCount; /*!< Enable PRE-DEFINED block count when read/write */ - uint32_t flags; /*!< Capability flag in _mmc_card_flag */ - uint32_t rawCid[4U]; /*!< Raw CID content */ - uint32_t rawCsd[4U]; /*!< Raw CSD content */ - uint32_t rawExtendedCsd[MMC_EXTENDED_CSD_BYTES / 4U]; /*!< Raw MMC Extended CSD content */ - uint32_t ocr; /*!< Raw OCR content */ - mmc_cid_t cid; /*!< CID */ - mmc_csd_t csd; /*!< CSD */ - mmc_extended_csd_t extendedCsd; /*!< Extended CSD */ - uint32_t blockSize; /*!< Card block size */ - uint32_t systemPartitionBlocks; /*!< Card total block number in system partition */ - uint32_t userPartitionBlocks; /*!< Card total block number in user partition */ - uint32_t bootPartitionBlocks; /*!< Boot partition size united as block size */ - uint32_t eraseGroupBlocks; /*!< Erase group size united as block size */ - mmc_access_partition_t currentPartition; /*!< Current access partition */ - mmc_voltage_window_t hostVoltageWindowVCCQ; /*!< Host IO voltage window */ - mmc_voltage_window_t hostVoltageWindowVCC; /*!< application must set this value according to board specific */ - mmc_high_speed_timing_t busTiming; /*!< indicate the current work timing mode*/ - mmc_data_bus_width_t busWidth; /*!< indicate the current work bus width */ + uint32_t flags; /*!< Capability flag in @ref _mmc_card_flag */ + + uint8_t internalBuffer[FSL_SDMMC_CARD_INTERNAL_BUFFER_SIZE]; /*!< raw buffer used for mmc driver internal */ + uint32_t ocr; /*!< Raw OCR content */ + mmc_cid_t cid; /*!< CID */ + mmc_csd_t csd; /*!< CSD */ + mmc_extended_csd_t extendedCsd; /*!< Extended CSD */ + uint32_t blockSize; /*!< Card block size */ + uint32_t userPartitionBlocks; /*!< Card total block number in user partition */ + uint32_t bootPartitionBlocks; /*!< Boot partition size united as block size */ + uint32_t eraseGroupBlocks; /*!< Erase group size united as block size */ + mmc_access_partition_t currentPartition; /*!< Current access partition */ + mmc_voltage_window_t hostVoltageWindowVCCQ; /*!< application must set this value according to board specific */ + mmc_voltage_window_t hostVoltageWindowVCC; /*!< application must set this value according to board specific */ + mmc_high_speed_timing_t busTiming; /*!< indicates the current work timing mode*/ + mmc_data_bus_width_t busWidth; /*!< indicates the current work bus width */ + sdmmc_osa_mutex_t lock; /*!< card access lock */ } mmc_card_t; /************************************************************************************************* * API ************************************************************************************************/ #if defined(__cplusplus) -extern "C" -{ +extern "C" { #endif - /*! - * @name MMCCARD Function - * @{ - */ - - /*! - * @brief Initializes the MMC card and host. - * - * @param card Card descriptor. - * - * @retval kStatus_SDMMC_HostNotReady host is not ready. - * @retval kStatus_SDMMC_GoIdleFailed Go idle failed. - * @retval kStatus_SDMMC_SendOperationConditionFailed Send operation condition failed. - * @retval kStatus_SDMMC_AllSendCidFailed Send CID failed. - * @retval kStatus_SDMMC_SetRelativeAddressFailed Set relative address failed. - * @retval kStatus_SDMMC_SendCsdFailed Send CSD failed. - * @retval kStatus_SDMMC_CardNotSupport Card not support. - * @retval kStatus_SDMMC_SelectCardFailed Send SELECT_CARD command failed. - * @retval kStatus_SDMMC_SendExtendedCsdFailed Send EXT_CSD failed. - * @retval kStatus_SDMMC_SetBusWidthFailed Set bus width failed. - * @retval kStatus_SDMMC_SwitchHighSpeedFailed Switch high speed failed. - * @retval kStatus_SDMMC_SetCardBlockSizeFailed Set card block size failed. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_Init(mmc_card_t *card); - - /*! - * @brief Deinitializes the card and host. - * - * @param card Card descriptor. - */ - void MMC_Deinit(mmc_card_t *card); - - /*! - * @brief intialize the card. - * - * @param card Card descriptor. - * - * @retval kStatus_SDMMC_HostNotReady host is not ready. - * @retval kStatus_SDMMC_GoIdleFailed Go idle failed. - * @retval kStatus_SDMMC_SendOperationConditionFailed Send operation condition failed. - * @retval kStatus_SDMMC_AllSendCidFailed Send CID failed. - * @retval kStatus_SDMMC_SetRelativeAddressFailed Set relative address failed. - * @retval kStatus_SDMMC_SendCsdFailed Send CSD failed. - * @retval kStatus_SDMMC_CardNotSupport Card not support. - * @retval kStatus_SDMMC_SelectCardFailed Send SELECT_CARD command failed. - * @retval kStatus_SDMMC_SendExtendedCsdFailed Send EXT_CSD failed. - * @retval kStatus_SDMMC_SetBusWidthFailed Set bus width failed. - * @retval kStatus_SDMMC_SwitchHighSpeedFailed Switch high speed failed. - * @retval kStatus_SDMMC_SetCardBlockSizeFailed Set card block size failed. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_CardInit(mmc_card_t *card); - - /*! - * @brief Deinitializes the card. - * - * @param card Card descriptor. - */ - void MMC_CardDeinit(mmc_card_t *card); - - /*! - * @brief initialize the host. - * - * This function deinitializes the specific host. - * - * @param card Card descriptor. - */ - status_t MMC_HostInit(mmc_card_t *card); - - /*! - * @brief Deinitializes the host. - * - * This function deinitializes the host. - * - * @param card Card descriptor. - */ - void MMC_HostDeinit(mmc_card_t *card); - - /*! - * @brief reset the host. - * - * This function reset the specific host. - * - * @param host host descriptor. - */ - void MMC_HostReset(SDMMCHOST_CONFIG *host); - - /*! - * @brief Checks if the card is read-only. - * - * @param card Card descriptor. - * @retval true Card is read only. - * @retval false Card isn't read only. - */ - bool MMC_CheckReadOnly(mmc_card_t *card); - - /*! - * @brief Reads data blocks from the card. - * - * @param card Card descriptor. - * @param buffer The buffer to save data. - * @param startBlock The start block index. - * @param blockCount The number of blocks to read. - * @retval kStatus_InvalidArgument Invalid argument. - * @retval kStatus_SDMMC_CardNotSupport Card not support. - * @retval kStatus_SDMMC_SetBlockCountFailed Set block count failed. - * @retval kStatus_SDMMC_TransferFailed Transfer failed. - * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_ReadBlocks(mmc_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockCount); - - /*! - * @brief Writes data blocks to the card. - * - * @param card Card descriptor. - * @param buffer The buffer to save data blocks. - * @param startBlock Start block number to write. - * @param blockCount Block count. - * @retval kStatus_InvalidArgument Invalid argument. - * @retval kStatus_SDMMC_NotSupportYet Not support now. - * @retval kStatus_SDMMC_SetBlockCountFailed Set block count failed. - * @retval kStatus_SDMMC_WaitWriteCompleteFailed Send status failed. - * @retval kStatus_SDMMC_TransferFailed Transfer failed. - * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_WriteBlocks(mmc_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockCount); - - /*! - * @brief Erases groups of the card. - * - * Erase group is the smallest erase unit in MMC card. The erase range is [startGroup, endGroup]. - * - * @param card Card descriptor. - * @param startGroup Start group number. - * @param endGroup End group number. - * @retval kStatus_InvalidArgument Invalid argument. - * @retval kStatus_SDMMC_WaitWriteCompleteFailed Send status failed. - * @retval kStatus_SDMMC_TransferFailed Transfer failed. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_EraseGroups(mmc_card_t *card, uint32_t startGroup, uint32_t endGroup); - - /*! - * @brief Selects the partition to access. - * - * @param card Card descriptor. - * @param partitionNumber The partition number. - * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure EXT_CSD failed. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_SelectPartition(mmc_card_t *card, mmc_access_partition_t partitionNumber); - - /*! - * @brief Configures the boot activity of the card. - * - * @param card Card descriptor. - * @param config Boot configuration structure. - * @retval kStatus_SDMMC_NotSupportYet Not support now. - * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure EXT_CSD failed. - * @retval kStatus_SDMMC_ConfigureBootFailed Configure boot failed. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_SetBootConfig(mmc_card_t *card, const mmc_boot_config_t *config); - - /*! - * @brief MMC card start boot. - * - * @param card Card descriptor. - * @param mmcConfig mmc Boot configuration structure. - * @param buffer address to recieve data. - * @param hostConfig host boot configurations. - * @retval kStatus_Fail fail. - * @retval kStatus_SDMMC_TransferFailed transfer fail. - * @retval kStatus_SDMMC_GoIdleFailed reset card fail. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_StartBoot(mmc_card_t *card, - const mmc_boot_config_t *mmcConfig, - uint8_t *buffer, - SDMMCHOST_BOOT_CONFIG *hostConfig); - - /*! - * @brief MMC card set boot configuration write protect. - * - * @param card Card descriptor. - * @param wp write protect value. - */ - status_t MMC_SetBootConfigWP(mmc_card_t *card, uint8_t wp); - - /*! - * @brief MMC card continous read boot data. - * - * @param card Card descriptor. - * @param buffer buffer address. - * @param hostConfig host boot configurations. - */ - status_t MMC_ReadBootData(mmc_card_t *card, uint8_t *buffer, SDMMCHOST_BOOT_CONFIG *hostConfig); - - /*! - * @brief MMC card stop boot mode. - * - * @param card Card descriptor. - * @param bootMode boot mode. - */ - status_t MMC_StopBoot(mmc_card_t *card, uint32_t bootMode); - - /*! - * @brief MMC card set boot partition write protect. - * - * @param card Card descriptor. - * @param bootPartitionWP boot partition write protect value. - */ - status_t MMC_SetBootPartitionWP(mmc_card_t *card, mmc_boot_partition_wp_t bootPartitionWP); - - /*! - * @brief MMC card configure General Purpose Partitions size. - * - * @param card Card descriptor. - * @param partition partition number(only General Purpose Partitions are supported). - * @param size Size of newly configured partition in KBytes! - * - * IMPORTANT NOTE: This function should be called only once. This is because partition configuration bits - * can be set only once per device i.e they are fuse bits. It is not know if each partition can be configured - * individually or if partitions must be configured all at once. - * Anyway invoke this function VERY CAREFULLY, YOU"VE GOT ONLY ONE CHANCE ! - * - */ - status_t MMC_SetGeneralPurposePartitioning(mmc_card_t *card, mmc_access_partition_t partition, uint32_t size); - - /*! - * @brief Wait write process complete. - * - * @param card Card descriptor. - * @retval kStatus_Timeout Operation timeout. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_WaitWriteComplete(mmc_card_t *card); - - /*! - * @brief Set erase unit size of the card - * - * @param card Card descriptor. - * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure Extended CSD failed. - * @retval kStatus_Success Operate successfully. - */ - status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card); +/*! + * @name MMCCARD Function + * @{ + */ + +/*! + * @brief Initializes the MMC card and host. + * + * @param card Card descriptor. + * + * Thread safe function, please note that the function will create the mutex lock dynamically by default, + * so to avoid the mutex to be created redundantly, application must follow bellow sequence for card re-initialization: + * @code + MMC_Deinit(card); + MMC_Init(card); + * @endcode + * + * @retval #kStatus_SDMMC_HostNotReady Host is not ready. + * @retval #kStatus_SDMMC_GoIdleFailed Going idle failed. + * @retval #kStatus_SDMMC_HandShakeOperationConditionFailed Sending operation condition failed. + * @retval #kStatus_SDMMC_AllSendCidFailed Sending CID failed. + * @retval #kStatus_SDMMC_SetRelativeAddressFailed Setging relative address failed. + * @retval #kStatus_SDMMC_SendCsdFailed Sending CSD failed. + * @retval #kStatus_SDMMC_CardNotSupport Card not support. + * @retval #kStatus_SDMMC_SelectCardFailed Sending SELECT_CARD command failed. + * @retval #kStatus_SDMMC_SendExtendedCsdFailed Sending EXT_CSD failed. + * @retval #kStatus_SDMMC_SetDataBusWidthFailed Setting bus width failed. + * @retval #kStatus_SDMMC_SwitchBusTimingFailed Switching high speed failed. + * @retval #kStatus_SDMMC_SetCardBlockSizeFailed Setting card block size failed. + * @retval #kStatus_SDMMC_SetPowerClassFail Setting card power class failed. + * @retval #kStatus_Success Operation succeeded. + */ +status_t MMC_Init(mmc_card_t *card); + +/*! + * @brief Deinitializes the card and host. + * + * @note It is a thread safe function. + * + * @param card Card descriptor. + */ +void MMC_Deinit(mmc_card_t *card); + +/*! + * @brief Initializes the card. + * + * Thread safe function, please note that the function will create the mutex lock dynamically by default, + * so to avoid the mutex to be created redundantly, application must follow bellow sequence for card re-initialization: + * @code + MMC_CardDeinit(card); + MMC_CardInit(card); + * @endcode + * + * @param card Card descriptor. + * + * @retval #kStatus_SDMMC_HostNotReady Host is not ready. + * @retval #kStatus_SDMMC_GoIdleFailed Going idle failed. + * @retval #kStatus_SDMMC_HandShakeOperationConditionFailed Sending operation condition failed. + * @retval #kStatus_SDMMC_AllSendCidFailed Sending CID failed. + * @retval #kStatus_SDMMC_SetRelativeAddressFailed Setting relative address failed. + * @retval #kStatus_SDMMC_SendCsdFailed Sending CSD failed. + * @retval #kStatus_SDMMC_CardNotSupport Card not support. + * @retval #kStatus_SDMMC_SelectCardFailed Sending SELECT_CARD command failed. + * @retval #kStatus_SDMMC_SendExtendedCsdFailed Sending EXT_CSD failed. + * @retval #kStatus_SDMMC_SetDataBusWidthFailed Setting bus width failed. + * @retval #kStatus_SDMMC_SwitchBusTimingFailed Switching high speed failed. + * @retval #kStatus_SDMMC_SetCardBlockSizeFailed Setting card block size failed. + * @retval #kStatus_SDMMC_SetPowerClassFail Setting card power class failed. + * @retval #kStatus_Success Operation succeeded. + */ +status_t MMC_CardInit(mmc_card_t *card); + +/*! + * @brief Deinitializes the card. + * + * @note It is a thread safe function. + * + * @param card Card descriptor. + */ +void MMC_CardDeinit(mmc_card_t *card); + +/*! + * @brief initialize the host. + * + * This function deinitializes the specific host. + * + * @param card Card descriptor. + */ +status_t MMC_HostInit(mmc_card_t *card); + +/*! + * @brief Deinitializes the host. + * + * This function deinitializes the host. + * + * @param card Card descriptor. + */ +void MMC_HostDeinit(mmc_card_t *card); + +/*! + * @brief Resets the host. + * + * This function resets the specific host. + * + * @param card Card descriptor. + */ +void MMC_HostDoReset(mmc_card_t *card); + +/*! + * @brief Resets the host. + * + * @deprecated Do not use this function. It has been superceded by @ref MMC_HostDoReset. + * This function resets the specific host. + * + * @param host Host descriptor. + */ +void MMC_HostReset(SDMMCHOST_CONFIG *host); + +/*! + * @brief Sets card power. + * + * @param card Card descriptor. + * @param enable True is powering on, false is powering off. + */ +void MMC_SetCardPower(mmc_card_t *card, bool enable); + +/*! + * @brief Checks if the card is read-only. + * + * @param card Card descriptor. + * @retval true Card is read only. + * @retval false Card isn't read only. + */ +bool MMC_CheckReadOnly(mmc_card_t *card); + +/*! + * @brief Reads data blocks from the card. + * + * @note It is a thread safe function. + * + * @param card Card descriptor. + * @param buffer The buffer to save data. + * @param startBlock The start block index. + * @param blockCount The number of blocks to read. + * @retval #kStatus_InvalidArgument Invalid argument. + * @retval #kStatus_SDMMC_CardNotSupport Card not support. + * @retval #kStatus_SDMMC_SetBlockCountFailed Setting block count failed. + * @retval #kStatus_SDMMC_TransferFailed Transfer failed. + * @retval #kStatus_SDMMC_StopTransmissionFailed Stopping transmission failed. + * @retval #kStatus_Success Operation succeeded. + */ +status_t MMC_ReadBlocks(mmc_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockCount); + +/*! + * @brief Writes data blocks to the card. + * + * @note + * 1. It is a thread safe function. + * 2. It is an async write function which means that the card status may still be busy after the function returns. + * Application can call function MMC_PollingCardStatusBusy to wait for the card status to be idle after the write + * operation. + * + * @param card Card descriptor. + * @param buffer The buffer to save data blocks. + * @param startBlock Start block number to write. + * @param blockCount Block count. + * @retval #kStatus_InvalidArgument Invalid argument. + * @retval #kStatus_SDMMC_NotSupportYet Not support now. + * @retval #kStatus_SDMMC_SetBlockCountFailed Setting block count failed. + * @retval #kStatus_SDMMC_WaitWriteCompleteFailed Sending status failed. + * @retval #kStatus_SDMMC_TransferFailed Transfer failed. + * @retval #kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. + * @retval #kStatus_Success Operation succeeded. + */ +status_t MMC_WriteBlocks(mmc_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockCount); + +/*! + * @brief Erases groups of the card. + * + * The erase command is best used to erase the entire device or a partition. + * Erase group is the smallest erase unit in MMC card. The erase range is [startGroup, endGroup]. + * + * @note + * 1. It is a thread safe function. + * 2. This function always polls card busy status according to the timeout value defined in the card register after + * all the erase command sent out. + * + * @param card Card descriptor. + * @param startGroup Start group number. + * @param endGroup End group number. + * @retval #kStatus_InvalidArgument Invalid argument. + * @retval #kStatus_SDMMC_WaitWriteCompleteFailed Send status failed. + * @retval #kStatus_SDMMC_TransferFailed Transfer failed. + * @retval #kStatus_Success Operation succeeded. + */ +status_t MMC_EraseGroups(mmc_card_t *card, uint32_t startGroup, uint32_t endGroup); + +/*! + * @brief Selects the partition to access. + * + * @note It is a thread safe function. + * + * @param card Card descriptor. + * @param partitionNumber The partition number. + * @retval #kStatus_SDMMC_ConfigureExtendedCsdFailed Configuring EXT_CSD failed. + * @retval #kStatus_Success Operation succeeded. + */ +status_t MMC_SelectPartition(mmc_card_t *card, mmc_access_partition_t partitionNumber); + +/*! + * @brief Configures the boot activity of the card. + * + * @param card Card descriptor. + * @param config Boot configuration structure. + * @retval #kStatus_SDMMC_NotSupportYet Not support now. + * @retval #kStatus_SDMMC_ConfigureExtendedCsdFailed Configuring EXT_CSD failed. + * @retval #kStatus_SDMMC_ConfigureBootFailed Configuring boot failed. + * @retval #kStatus_Success Operation succeeded. + */ +status_t MMC_SetBootConfig(mmc_card_t *card, const mmc_boot_config_t *config); + +/*! + * @brief MMC card start boot. + * + * @param card Card descriptor. + * @param mmcConfig The mmc Boot configuration structure. + * @param buffer Address to receive data. + * @param hostConfig Host boot configurations. + * @retval #kStatus_Fail Failed. + * @retval #kStatus_SDMMC_TransferFailed Transfer failed. + * @retval #kStatus_SDMMC_GoIdleFailed Resetting card failed. + * @retval #kStatus_Success Operation succeeded. + */ +status_t MMC_StartBoot(mmc_card_t *card, + const mmc_boot_config_t *mmcConfig, + uint8_t *buffer, + sdmmchost_boot_config_t *hostConfig); + +/*! + * @brief MMC card set boot configuration write protect. + * + * @param card Card descriptor. + * @param wp Write protect value. + */ +status_t MMC_SetBootConfigWP(mmc_card_t *card, uint8_t wp); + +/*! + * @brief MMC card continuous read boot data. + * + * @param card Card descriptor. + * @param buffer Buffer address. + * @param hostConfig Host boot configurations. + */ +status_t MMC_ReadBootData(mmc_card_t *card, uint8_t *buffer, sdmmchost_boot_config_t *hostConfig); + +/*! + * @brief MMC card stop boot mode. + * + * @param card Card descriptor. + * @param bootMode Boot mode. + */ +status_t MMC_StopBoot(mmc_card_t *card, uint32_t bootMode); + +/*! + * @brief MMC card set boot partition write protect. + * + * @param card Card descriptor. + * @param bootPartitionWP Boot partition write protect value. + */ +status_t MMC_SetBootPartitionWP(mmc_card_t *card, mmc_boot_partition_wp_t bootPartitionWP); + +/*! + * @brief MMC card cache control function. + * + * The mmc device's cache is enabled by the driver by default. + * The cache should in typical case reduce the access time (compared to an access to the main nonvolatile storage) for + * both write and read. + * + * @param card Card descriptor. + * @param enable True is enabling the cache, false is disabling the cache. + */ +status_t MMC_EnableCacheControl(mmc_card_t *card, bool enable); + +/*! + * @brief MMC card cache flush function. + * + * A Flush operation refers to the requirement, from the host to the device, to write the cached data to the nonvolatile + * memory. Prior to a flush, the device may autonomously write data to the nonvolatile memory, but after the flush + * operation all data in the volatile area must be written to nonvolatile memory. There is no requirement for flush due + * to switching between the partitions. (Note: This also implies that the cache data shall not be lost when switching + * between partitions). Cached data may be lost in SLEEP state, so host should flush the cache before placing the device + * into SLEEP state. + * + * @param card Card descriptor. + */ +status_t MMC_FlushCache(mmc_card_t *card); + +/*! + * @brief MMC sets card sleep awake state. + * + * The Sleep/Awake command is used to initiate the state transition between Standby state and Sleep state. + * The memory device indicates the transition phase busy by pulling down the DAT0 line. + * The Sleep/Standby state is reached when the memory device stops pulling down the DAT0 line, then the function + * returns. + * + * @param card Card descriptor. + * @param state The sleep/awake command argument, refer to @ref mmc_sleep_awake_t. + * + * @retval kStatus_SDMMC_NotSupportYet Indicates the memory device doesn't support the Sleep/Awake command. + * @retval kStatus_SDMMC_TransferFailed Indicates command transferred fail. + * @retval kStatus_SDMMC_PollingCardIdleFailed Indicates polling DAT0 busy timeout. + * @retval kStatus_SDMMC_DeselectCardFailed Indicates deselect card command failed. + * @retval kStatus_SDMMC_SelectCardFailed Indicates select card command failed. + * @retval kStatus_Success Indicates the card state switched successfully. + */ +status_t MMC_SetSleepAwake(mmc_card_t *card, mmc_sleep_awake_t state); + +/*! + * @brief Polling card idle status. + * + * This function can be used to poll the status from busy to idle, the function will return with the card + * status being idle or timeout or command failed. + * + * @param card Card descriptor. + * @param checkStatus True is send CMD and read DAT0 status to check card status, false is read DAT0 status only. + * @param timeoutMs Polling card status timeout value. + * + * @retval kStatus_SDMMC_CardStatusIdle Card is idle. + * @retval kStatus_SDMMC_CardStatusBusy Card is busy. + * @retval kStatus_SDMMC_TransferFailed Command tranfer failed. + * @retval kStatus_SDMMC_SwitchFailed Status command reports switch error. + */ +status_t MMC_PollingCardStatusBusy(mmc_card_t *card, bool checkStatus, uint32_t timeoutMs); /* @} */ #if defined(__cplusplus) diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction.h b/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction.h new file mode 100644 index 0000000000000000000000000000000000000000..d8b435ac9fd2c86a2b20655f6e971032619e66e6 --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction.h @@ -0,0 +1,948 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2020 NXP + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_OS_ABSTRACTION_H_ +#define _FSL_OS_ABSTRACTION_H_ + +#ifndef SDK_COMPONENT_DEPENDENCY_FSL_COMMON +#define SDK_COMPONENT_DEPENDENCY_FSL_COMMON (1U) +#endif +#if (defined(SDK_COMPONENT_DEPENDENCY_FSL_COMMON) && (SDK_COMPONENT_DEPENDENCY_FSL_COMMON > 0U)) +#include "fsl_common.h" +#else +#endif + +#include "fsl_os_abstraction_config.h" +#include "fsl_component_generic_list.h" + +/*! + * @addtogroup osa_adapter + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Type for the Task Priority*/ +typedef uint16_t osa_task_priority_t; +/*! @brief Type for a task handler */ +typedef void *osa_task_handle_t; +/*! @brief Type for the parameter to be passed to the task at its creation */ +typedef void *osa_task_param_t; +/*! @brief Type for task pointer. Task prototype declaration */ +typedef void (*osa_task_ptr_t)(osa_task_param_t task_param); +/*! @brief Type for the semaphore handler */ +typedef void *osa_semaphore_handle_t; +/*! @brief Type for the mutex handler */ +typedef void *osa_mutex_handle_t; +/*! @brief Type for the event handler */ +typedef void *osa_event_handle_t; +/*! @brief Type for an event flags group, bit 32 is reserved. */ +typedef uint32_t osa_event_flags_t; +/*! @brief Message definition. */ +typedef void *osa_msg_handle_t; +/*! @brief Type for the message queue handler */ +typedef void *osa_msgq_handle_t; +/*! @brief Type for the Timer handler */ +typedef void *osa_timer_handle_t; +/*! @brief Type for the Timer callback function pointer. */ +typedef void (*osa_timer_fct_ptr_t)(void const *argument); +/*! @brief Thread Definition structure contains startup information of a thread.*/ +typedef struct osa_task_def_tag +{ + osa_task_ptr_t pthread; /*!< start address of thread function*/ + uint32_t tpriority; /*!< initial thread priority*/ + uint32_t instances; /*!< maximum number of instances of that thread function*/ + uint32_t stacksize; /*!< stack size requirements in bytes; 0 is default stack size*/ + uint32_t *tstack; /*!< stack pointer*/ + void *tlink; /*!< link pointer*/ + uint8_t *tname; /*!< name pointer*/ + uint8_t useFloat; /*!< is use float*/ +} osa_task_def_t; +/*! @brief Thread Link Definition structure .*/ +typedef struct osa_thread_link_tag +{ + uint8_t link[12]; /*!< link*/ + osa_task_handle_t osThreadId; /*!< thread id*/ + osa_task_def_t *osThreadDefHandle; /*!< pointer of thread define handle*/ + uint32_t *osThreadStackHandle; /*!< pointer of thread stack handle*/ +} osa_thread_link_t, *osa_thread_link_handle_t; + +/*! @brief Definition structure contains timer parameters.*/ +typedef struct osa_time_def_tag +{ + osa_timer_fct_ptr_t pfCallback; /* < start address of a timer function */ + void *argument; /* < argument of a timer function */ +} osa_time_def_t; + +/*! @brief Type for the timer definition*/ +typedef enum _osa_timer +{ + KOSA_TimerOnce = 0, /*!< one-shot timer*/ + KOSA_TimerPeriodic = 1 /*!< repeating timer*/ +} osa_timer_t; + +/*! @brief Defines the return status of OSA's functions */ +#if (defined(SDK_COMPONENT_DEPENDENCY_FSL_COMMON) && (SDK_COMPONENT_DEPENDENCY_FSL_COMMON > 0U)) +typedef enum _osa_status +{ + KOSA_StatusSuccess = kStatus_Success, /*!< Success */ + KOSA_StatusError = MAKE_STATUS(kStatusGroup_OSA, 1), /*!< Failed */ + KOSA_StatusTimeout = MAKE_STATUS(kStatusGroup_OSA, 2), /*!< Timeout occurs while waiting */ + KOSA_StatusIdle = MAKE_STATUS(kStatusGroup_OSA, 3), /*!< Used for bare metal only, the wait object is not ready + and timeout still not occur */ +} osa_status_t; +#else +typedef enum _osa_status +{ + KOSA_StatusSuccess = 0, /*!< Success */ + KOSA_StatusError = 1, /*!< Failed */ + KOSA_StatusTimeout = 2, /*!< Timeout occurs while waiting */ + KOSA_StatusIdle = 3, /*!< Used for bare metal only, the wait object is not ready + and timeout still not occur */ +} osa_status_t; + +#endif + +#ifdef USE_RTOS +#undef USE_RTOS +#endif + +#if defined(SDK_OS_MQX) +#define USE_RTOS (1) +#elif defined(SDK_OS_FREE_RTOS) +#define USE_RTOS (1) +#if (defined(GENERIC_LIST_LIGHT) && (GENERIC_LIST_LIGHT > 0U)) +#define OSA_TASK_HANDLE_SIZE (12U) +#else +#define OSA_TASK_HANDLE_SIZE (16U) +#endif +#define OSA_EVENT_HANDLE_SIZE (8U) +#define OSA_SEM_HANDLE_SIZE (4U) +#define OSA_MUTEX_HANDLE_SIZE (4U) +#define OSA_MSGQ_HANDLE_SIZE (4U) +#define OSA_MSG_HANDLE_SIZE (0U) +#elif defined(SDK_OS_UCOSII) +#define USE_RTOS (1) +#elif defined(SDK_OS_UCOSIII) +#define USE_RTOS (1) +#elif defined(FSL_RTOS_THREADX) +#define USE_RTOS (1) +#else +#define USE_RTOS (0) +#if (defined(GENERIC_LIST_LIGHT) && (GENERIC_LIST_LIGHT > 0U)) +#define OSA_TASK_HANDLE_SIZE (24U) +#else +#define OSA_TASK_HANDLE_SIZE (28U) +#endif +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +#define OSA_EVENT_HANDLE_SIZE (20U) +#else +#define OSA_EVENT_HANDLE_SIZE (16U) +#endif /* FSL_OSA_TASK_ENABLE */ +#if (defined(FSL_OSA_BM_TIMEOUT_ENABLE) && (FSL_OSA_BM_TIMEOUT_ENABLE > 0U)) +#define OSA_SEM_HANDLE_SIZE (16U) +#define OSA_MUTEX_HANDLE_SIZE (12U) +#else +#define OSA_SEM_HANDLE_SIZE (8U) +#define OSA_MUTEX_HANDLE_SIZE (4U) +#endif +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +#define OSA_MSGQ_HANDLE_SIZE (32U) +#else +#define OSA_MSGQ_HANDLE_SIZE (28U) +#endif /* FSL_OSA_TASK_ENABLE */ +#define OSA_MSG_HANDLE_SIZE (4U) +#endif + +/*! @brief Priority setting for OSA. */ +#ifndef OSA_PRIORITY_IDLE +#define OSA_PRIORITY_IDLE (6) +#endif + +#ifndef OSA_PRIORITY_LOW +#define OSA_PRIORITY_LOW (5) +#endif + +#ifndef OSA_PRIORITY_BELOW_NORMAL +#define OSA_PRIORITY_BELOW_NORMAL (4) +#endif + +#ifndef OSA_PRIORITY_NORMAL +#define OSA_PRIORITY_NORMAL (3) +#endif + +#ifndef OSA_PRIORITY_ABOVE_NORMAL +#define OSA_PRIORITY_ABOVE_NORMAL (2) +#endif + +#ifndef OSA_PRIORITY_HIGH +#define OSA_PRIORITY_HIGH (1) +#endif + +#ifndef OSA_PRIORITY_REAL_TIME +#define OSA_PRIORITY_REAL_TIME (0) +#endif + +#ifndef OSA_TASK_PRIORITY_MAX +#define OSA_TASK_PRIORITY_MAX (0) +#endif + +#ifndef OSA_TASK_PRIORITY_MIN +#define OSA_TASK_PRIORITY_MIN (15) +#endif + +#define SIZE_IN_UINT32_UNITS(size) (((size) + sizeof(uint32_t) - 1) / sizeof(uint32_t)) + +/*! @brief Constant to pass as timeout value in order to wait indefinitely. */ +#define osaWaitNone_c ((uint32_t)(0)) +#define osaWaitForever_c ((uint32_t)(-1)) +#define osaEventFlagsAll_c ((osa_event_flags_t)(0x00FFFFFF)) +#define osThreadStackArray(name) osThread_##name##_stack +#define osThreadStackDef(name, stacksize, instances) \ + const uint32_t osThreadStackArray(name)[SIZE_IN_UINT32_UNITS(stacksize) * (instances)]; + +/* ==== Thread Management ==== */ + +/* Create a Thread Definition with function, priority, and stack requirements. + * \param name name of the thread function. + * \param priority initial priority of the thread function. + * \param instances number of possible thread instances. + * \param stackSz stack size (in bytes) requirements for the thread function. + * \param useFloat + */ +#if defined(SDK_OS_MQX) +#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \ + osa_thread_link_t osThreadLink_##name[instances] = {0}; \ + osThreadStackDef(name, stackSz, instances) osa_task_def_t os_thread_def_##name = { \ + (name), (priority), (instances), (stackSz), osThreadStackArray(name), osThreadLink_##name, \ + (uint8_t *)#name, (useFloat)} +#elif defined(SDK_OS_UCOSII) +#if gTaskMultipleInstancesManagement_c +#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \ + osa_thread_link_t osThreadLink_##name[instances] = {0}; \ + osThreadStackDef(name, stackSz, instances) osa_task_def_t os_thread_def_##name = { \ + (name), (priority), (instances), (stackSz), osThreadStackArray(name), osThreadLink_##name, \ + (uint8_t *)#name, (useFloat)} +#else +#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \ + osThreadStackDef(name, stackSz, instances) osa_task_def_t os_thread_def_##name = { \ + (name), (priority), (instances), (stackSz), osThreadStackArray(name), NULL, (uint8_t *)#name, (useFloat)} +#endif +#elif defined(FSL_RTOS_THREADX) +#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \ + uint32_t s_stackBuffer##name[(stackSz + sizeof(uint32_t) - 1U) / sizeof(uint32_t)]; \ + static const osa_task_def_t os_thread_def_##name = { \ + (name), (priority), (instances), (stackSz), s_stackBuffer##name, NULL, (uint8_t *)#name, (useFloat)} +#else +#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \ + const osa_task_def_t os_thread_def_##name = {(name), (priority), (instances), (stackSz), \ + NULL, NULL, (uint8_t *)#name, (useFloat)} +#endif +/* Access a Thread defintion. + * \param name name of the thread definition object. + */ +#define OSA_TASK(name) (const osa_task_def_t *)&os_thread_def_##name + +#define OSA_TASK_PROTO(name) extern osa_task_def_t os_thread_def_##name +/* ==== Timer Management ==== + * Define a Timer object. + * \param name name of the timer object. + * \param function name of the timer call back function. + */ + +#define OSA_TIMER_DEF(name, function) osa_time_def_t os_timer_def_##name = {(function), NULL} + +/* Access a Timer definition. + * \param name name of the timer object. + */ +#define OSA_TIMER(name) &os_timer_def_##name + +/* ==== Buffer Definition ==== */ + +/*! + * @brief Defines the semaphore handle + * + * This macro is used to define a 4 byte aligned semaphore handle. + * Then use "(osa_semaphore_handle_t)name" to get the semaphore handle. + * + * The macro should be global and could be optional. You could also define semaphore handle by yourself. + * + * This is an example, + * @code + * OSA_SEMAPHORE_HANDLE_DEFINE(semaphoreHandle); + * @endcode + * + * @param name The name string of the semaphore handle. + */ +#define OSA_SEMAPHORE_HANDLE_DEFINE(name) \ + uint32_t name[(OSA_SEM_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t)] + +/*! + * @brief Defines the mutex handle + * + * This macro is used to define a 4 byte aligned mutex handle. + * Then use "(osa_mutex_handle_t)name" to get the mutex handle. + * + * The macro should be global and could be optional. You could also define mutex handle by yourself. + * + * This is an example, + * @code + * OSA_MUTEX_HANDLE_DEFINE(mutexHandle); + * @endcode + * + * @param name The name string of the mutex handle. + */ +#define OSA_MUTEX_HANDLE_DEFINE(name) uint32_t name[(OSA_MUTEX_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t)] + +/*! + * @brief Defines the event handle + * + * This macro is used to define a 4 byte aligned event handle. + * Then use "(osa_event_handle_t)name" to get the event handle. + * + * The macro should be global and could be optional. You could also define event handle by yourself. + * + * This is an example, + * @code + * OSA_EVENT_HANDLE_DEFINE(eventHandle); + * @endcode + * + * @param name The name string of the event handle. + */ +#define OSA_EVENT_HANDLE_DEFINE(name) uint32_t name[(OSA_EVENT_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t)] + +/*! + * @brief Defines the message queue handle + * + * This macro is used to define a 4 byte aligned message queue handle. + * Then use "(osa_msgq_handle_t)name" to get the message queue handle. + * + * The macro should be global and could be optional. You could also define message queue handle by yourself. + * + * This is an example, + * @code + * OSA_MSGQ_HANDLE_DEFINE(msgqHandle, 3, sizeof(msgStruct)); + * @endcode + * + * @param name The name string of the message queue handle. + * @param numberOfMsgs Number of messages. + * @param msgSize Message size. + * + */ +#if defined(SDK_OS_FREE_RTOS) +/*< Macro For FREE_RTOS*/ +#define OSA_MSGQ_HANDLE_DEFINE(name, numberOfMsgs, msgSize) \ + uint32_t name[(OSA_MSGQ_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t)] +#else +/*< Macro For BARE_MATEL*/ +#define OSA_MSGQ_HANDLE_DEFINE(name, numberOfMsgs, msgSize) \ + uint32_t name[((OSA_MSGQ_HANDLE_SIZE + numberOfMsgs * msgSize) + sizeof(uint32_t) - 1U) / sizeof(uint32_t)] +#endif + +/*! + * @brief Defines the TASK handle + * + * This macro is used to define a 4 byte aligned TASK handle. + * Then use "(osa_task_handle_t)name" to get the TASK handle. + * + * The macro should be global and could be optional. You could also define TASK handle by yourself. + * + * This is an example, + * @code + * OSA_TASK_HANDLE_DEFINE(taskHandle); + * @endcode + * + * @param name The name string of the TASK handle. + */ +#define OSA_TASK_HANDLE_DEFINE(name) uint32_t name[(OSA_TASK_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t)] + +#if defined(SDK_OS_FREE_RTOS) +#include "fsl_os_abstraction_free_rtos.h" +#elif defined(FSL_RTOS_THREADX) +#include "fsl_os_abstraction_threadx.h" +#else +#include "fsl_os_abstraction_bm.h" +#endif + +extern const uint8_t gUseRtos_c; + +/* + * alloc the temporary memory to store the status + */ +#define OSA_SR_ALLOC() uint32_t osaCurrentSr = 0U; +/* + * Enter critical mode + */ +#define OSA_ENTER_CRITICAL() OSA_EnterCritical(&osaCurrentSr) +/* + * Exit critical mode and retore the previous mode + */ +#define OSA_EXIT_CRITICAL() OSA_ExitCritical(osaCurrentSr) + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Reserves the requested amount of memory in bytes. + * + * The function is used to reserve the requested amount of memory in bytes and initializes it to 0. + * + * @param length Amount of bytes to reserve. + * + * @return Pointer to the reserved memory. NULL if memory can't be allocated. + */ +void *OSA_MemoryAllocate(uint32_t length); + +/*! + * @brief Frees the memory previously reserved. + * + * The function is used to free the memory block previously reserved. + * + * @param p Pointer to the start of the memory block previously reserved. + * + */ +void OSA_MemoryFree(void *p); + +/*! + * @brief Enter critical with nesting mode. + * + * @param sr Store current status and return to caller. + */ +void OSA_EnterCritical(uint32_t *sr); + +/*! + * @brief Exit critical with nesting mode. + * + * @param sr Previous status to restore. + */ +void OSA_ExitCritical(uint32_t sr); + +/*! + * @name Task management + * @{ + */ + +/*! + * @brief Initialize OSA. + * + * This function is used to setup the basic services. + * + * Example below shows how to use this API to create the task handle. + * @code + * OSA_Init(); + * @endcode + */ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +void OSA_Init(void); +#endif + +/*! + * @brief Start OSA schedule. + * + * This function is used to start OSA scheduler. + * + * Example below shows how to use this API to start osa schedule. + * @code + * OSA_Start(); + * @endcode + */ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +void OSA_Start(void); +#endif + +/*! + * @brief Creates a task. + * + * This function is used to create task based on the resources defined + * by the macro OSA_TASK_DEFINE. + * + * Example below shows how to use this API to create the task handle. + * @code + * OSA_TASK_HANDLE_DEFINE(taskHandle); + * OSA_TASK_DEFINE( Job1, OSA_PRIORITY_HIGH, 1, 800, 0); + * OSA_TaskCreate((osa_task_handle_t)taskHandle, OSA_TASK(Job1), (osa_task_param_t)NULL); + * @endcode + * + * @param taskHandle Pointer to a memory space of size OSA_TASK_HANDLE_SIZE allocated by the caller, task handle. + * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices. + * You can define the handle in the following two ways: + * #OSA_TASK_HANDLE_DEFINE(taskHandle); + * or + * uint32_t taskHandle[((OSA_TASK_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]; + * @param thread_def pointer to theosa_task_def_t structure which defines the task. + * @param task_param Pointer to be passed to the task when it is created. + * @retval KOSA_StatusSuccess The task is successfully created. + * @retval KOSA_StatusError The task can not be created. + */ +#if ((defined(FSL_OSA_TASK_ENABLE)) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_status_t OSA_TaskCreate(osa_task_handle_t taskHandle, + const osa_task_def_t *thread_def, + osa_task_param_t task_param); +#endif /* FSL_OSA_TASK_ENABLE */ + +/*! + * @brief Gets the handler of active task. + * + * @return Handler to current active task. + */ +#if ((defined(FSL_OSA_TASK_ENABLE)) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_task_handle_t OSA_TaskGetCurrentHandle(void); +#endif /* FSL_OSA_TASK_ENABLE */ + +/*! + * @brief Puts the active task to the end of scheduler's queue. + * + * When a task calls this function, it gives up the CPU and puts itself to the + * end of a task ready list. + * + * @retval KOSA_StatusSuccess The function is called successfully. + * @retval KOSA_StatusError Error occurs with this function. + */ +#if ((defined(FSL_OSA_TASK_ENABLE)) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_status_t OSA_TaskYield(void); +#endif /* FSL_OSA_TASK_ENABLE */ + +/*! + * @brief Gets the priority of a task. + * + * @param taskHandle The handler of the task whose priority is received. + * + * @return Task's priority. + */ +#if ((defined(FSL_OSA_TASK_ENABLE)) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_task_priority_t OSA_TaskGetPriority(osa_task_handle_t taskHandle); +#endif /* FSL_OSA_TASK_ENABLE */ + +/*! + * @brief Sets the priority of a task. + * + * @param taskHandle The handler of the task whose priority is set. + * @param taskPriority The priority to set. + * + * @retval KOSA_StatusSuccess Task's priority is set successfully. + * @retval KOSA_StatusError Task's priority can not be set. + */ +#if ((defined(FSL_OSA_TASK_ENABLE)) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_status_t OSA_TaskSetPriority(osa_task_handle_t taskHandle, osa_task_priority_t taskPriority); +#endif /* FSL_OSA_TASK_ENABLE */ + +/*! + * @brief Destroys a previously created task. + * + * @param taskHandle The handler of the task to destroy. + * + * @retval KOSA_StatusSuccess The task was successfully destroyed. + * @retval KOSA_StatusError Task destruction failed or invalid parameter. + */ +#if ((defined(FSL_OSA_TASK_ENABLE)) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_status_t OSA_TaskDestroy(osa_task_handle_t taskHandle); +#endif /* FSL_OSA_TASK_ENABLE */ + +/*! + * @brief Creates a semaphore with a given value. + * + * This function creates a semaphore and sets the value to the parameter + * initValue. + * + * Example below shows how to use this API to create the semaphore handle. + * @code + * OSA_SEMAPHORE_HANDLE_DEFINE(semaphoreHandle); + * OSA_SemaphoreCreate((osa_semaphore_handle_t)semaphoreHandle, 0xff); + * @endcode + * + * @param semaphoreHandle Pointer to a memory space of size OSA_SEM_HANDLE_SIZE allocated by the caller. + * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices. + * You can define the handle in the following two ways: + * #OSA_SEMAPHORE_HANDLE_DEFINE(semaphoreHandle); + * or + * uint32_t semaphoreHandle[((OSA_SEM_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]; + * @param initValue Initial value the semaphore will be set to. + * + * @retval KOSA_StatusSuccess the new semaphore if the semaphore is created successfully. + * @retval KOSA_StatusError if the semaphore can not be created. + */ +osa_status_t OSA_SemaphoreCreate(osa_semaphore_handle_t semaphoreHandle, uint32_t initValue); + +/*! + * @brief Creates a binary semaphore. + * + * This function creates a binary semaphore + * + * Example below shows how to use this API to create the semaphore handle. + * @code + * OSA_SEMAPHORE_HANDLE_DEFINE(semaphoreHandle); + * OSA_SemaphoreCreateBinary((osa_semaphore_handle_t)semaphoreHandle); + * @endcode + * + * @param semaphoreHandle Pointer to a memory space of size OSA_SEM_HANDLE_SIZE allocated by the caller. + * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices. + * You can define the handle in the following two ways: + * #OSA_SEMAPHORE_HANDLE_DEFINE(semaphoreHandle); + * or + * uint32_t semaphoreHandle[((OSA_SEM_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]; + * + * @retval KOSA_StatusSuccess the new binary semaphore if the binary semaphore is created successfully. + * @retval KOSA_StatusError if the binary semaphore can not be created. + */ +osa_status_t OSA_SemaphoreCreateBinary(osa_semaphore_handle_t semaphoreHandle); + +/*! + * @brief Destroys a previously created semaphore. + * + * @param semaphoreHandle The semaphore handle. + * The macro SEMAPHORE_HANDLE_BUFFER_GET is used to get the semaphore buffer pointer, + * and should not be used before the macro SEMAPHORE_HANDLE_BUFFER_DEFINE is used. + * + * @retval KOSA_StatusSuccess The semaphore is successfully destroyed. + * @retval KOSA_StatusError The semaphore can not be destroyed. + */ +osa_status_t OSA_SemaphoreDestroy(osa_semaphore_handle_t semaphoreHandle); + +/*! + * @brief Pending a semaphore with timeout. + * + * This function checks the semaphore's counting value. If it is positive, + * decreases it and returns KOSA_StatusSuccess. Otherwise, a timeout is used + * to wait. + * + * @param semaphoreHandle The semaphore handle. + * @param millisec The maximum number of milliseconds to wait if semaphore is not + * positive. Pass osaWaitForever_c to wait indefinitely, pass 0 + * will return KOSA_StatusTimeout immediately. + * + * @retval KOSA_StatusSuccess The semaphore is received. + * @retval KOSA_StatusTimeout The semaphore is not received within the specified 'timeout'. + * @retval KOSA_StatusError An incorrect parameter was passed. + */ +osa_status_t OSA_SemaphoreWait(osa_semaphore_handle_t semaphoreHandle, uint32_t millisec); + +/*! + * @brief Signals for someone waiting on the semaphore to wake up. + * + * Wakes up one task that is waiting on the semaphore. If no task is waiting, increases + * the semaphore's counting value. + * + * @param semaphoreHandle The semaphore handle to signal. + * + * @retval KOSA_StatusSuccess The semaphore is successfully signaled. + * @retval KOSA_StatusError The object can not be signaled or invalid parameter. + * + */ +osa_status_t OSA_SemaphorePost(osa_semaphore_handle_t semaphoreHandle); + +/*! + * @brief Create an unlocked mutex. + * + * This function creates a non-recursive mutex and sets it to unlocked status. + * + * Example below shows how to use this API to create the mutex handle. + * @code + * OSA_MUTEX_HANDLE_DEFINE(mutexHandle); + * OSA_MutexCreate((osa_mutex_handle_t)mutexHandle); + * @endcode + * + * @param mutexHandle Pointer to a memory space of size OSA_MUTEX_HANDLE_SIZE allocated by the caller. + * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices. + * You can define the handle in the following two ways: + * #OSA_MUTEX_HANDLE_DEFINE(mutexHandle); + * or + * uint32_t mutexHandle[((OSA_MUTEX_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]; + * @retval KOSA_StatusSuccess the new mutex if the mutex is created successfully. + * @retval KOSA_StatusError if the mutex can not be created. + */ +osa_status_t OSA_MutexCreate(osa_mutex_handle_t mutexHandle); + +/*! + * @brief Waits for a mutex and locks it. + * + * This function checks the mutex's status. If it is unlocked, locks it and returns the + * KOSA_StatusSuccess. Otherwise, waits for a timeout in milliseconds to lock. + * + * @param mutexHandle The mutex handle. + * @param millisec The maximum number of milliseconds to wait for the mutex. + * If the mutex is locked, Pass the value osaWaitForever_c will + * wait indefinitely, pass 0 will return KOSA_StatusTimeout + * immediately. + * + * @retval KOSA_StatusSuccess The mutex is locked successfully. + * @retval KOSA_StatusTimeout Timeout occurred. + * @retval KOSA_StatusError Incorrect parameter was passed. + * + * @note This is non-recursive mutex, a task can not try to lock the mutex it has locked. + */ +osa_status_t OSA_MutexLock(osa_mutex_handle_t mutexHandle, uint32_t millisec); + +/*! + * @brief Unlocks a previously locked mutex. + * + * @param mutexHandle The mutex handle. + * + * @retval KOSA_StatusSuccess The mutex is successfully unlocked. + * @retval KOSA_StatusError The mutex can not be unlocked or invalid parameter. + */ +osa_status_t OSA_MutexUnlock(osa_mutex_handle_t mutexHandle); + +/*! + * @brief Destroys a previously created mutex. + * + * @param mutexHandle The mutex handle. + * + * @retval KOSA_StatusSuccess The mutex is successfully destroyed. + * @retval KOSA_StatusError The mutex can not be destroyed. + * + */ +osa_status_t OSA_MutexDestroy(osa_mutex_handle_t mutexHandle); + +/*! + * @brief Initializes an event object with all flags cleared. + * + * This function creates an event object and set its clear mode. If autoClear + * is 1, when a task gets the event flags, these flags will be + * cleared automatically. Otherwise these flags must + * be cleared manually. + * + * Example below shows how to use this API to create the event handle. + * @code + * OSA_EVENT_HANDLE_DEFINE(eventHandle); + * OSA_EventCreate((osa_event_handle_t)eventHandle, 0); + * @endcode + * + * @param eventHandle Pointer to a memory space of size OSA_EVENT_HANDLE_SIZE allocated by the caller. + * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices. + * You can define the handle in the following two ways: + * #OSA_EVENT_HANDLE_DEFINE(eventHandle); + * or + * uint32_t eventHandle[((OSA_EVENT_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]; + * @param autoClear 1 The event is auto-clear. + * 0 The event manual-clear + * @retval KOSA_StatusSuccess the new event if the event is created successfully. + * @retval KOSA_StatusError if the event can not be created. + */ +osa_status_t OSA_EventCreate(osa_event_handle_t eventHandle, uint8_t autoClear); + +/*! + * @brief Sets one or more event flags. + * + * Sets specified flags of an event object. + * + * @param eventHandle The event handle. + * @param flagsToSet Flags to be set. + * + * @retval KOSA_StatusSuccess The flags were successfully set. + * @retval KOSA_StatusError An incorrect parameter was passed. + */ +osa_status_t OSA_EventSet(osa_event_handle_t eventHandle, osa_event_flags_t flagsToSet); + +/*! + * @brief Clears one or more flags. + * + * Clears specified flags of an event object. + * + * @param eventHandle The event handle. + * @param flagsToClear Flags to be clear. + * + * @retval KOSA_StatusSuccess The flags were successfully cleared. + * @retval KOSA_StatusError An incorrect parameter was passed. + */ +osa_status_t OSA_EventClear(osa_event_handle_t eventHandle, osa_event_flags_t flagsToClear); + +/*! + * @brief Get event's flags. + * + * Get specified flags of an event object. + * + * @param eventHandle The event handle. + * The macro EVENT_HANDLE_BUFFER_GET is used to get the event buffer pointer, + * and should not be used before the macro EVENT_HANDLE_BUFFER_DEFINE is used. + * @param flagsMask The flags user want to get are specified by this parameter. + * @param pFlagsOfEvent The event flags are obtained by this parameter. + * + * @retval KOSA_StatusSuccess The event flags were successfully got. + * @retval KOSA_StatusError An incorrect parameter was passed. + */ +osa_status_t OSA_EventGet(osa_event_handle_t eventHandle, + osa_event_flags_t flagsMask, + osa_event_flags_t *pFlagsOfEvent); + +/*! + * @brief Waits for specified event flags to be set. + * + * This function waits for a combination of flags to be set in an event object. + * Applications can wait for any/all bits to be set. Also this function could + * obtain the flags who wakeup the waiting task. + * + * @param eventHandle The event handle. + * @param flagsToWait Flags that to wait. + * @param waitAll Wait all flags or any flag to be set. + * @param millisec The maximum number of milliseconds to wait for the event. + * If the wait condition is not met, pass osaWaitForever_c will + * wait indefinitely, pass 0 will return KOSA_StatusTimeout + * immediately. + * @param pSetFlags Flags that wakeup the waiting task are obtained by this parameter. + * + * @retval KOSA_StatusSuccess The wait condition met and function returns successfully. + * @retval KOSA_StatusTimeout Has not met wait condition within timeout. + * @retval KOSA_StatusError An incorrect parameter was passed. + + * + * @note Please pay attention to the flags bit width, FreeRTOS uses the most + * significant 8 bis as control bits, so do not wait these bits while using + * FreeRTOS. + * + */ +osa_status_t OSA_EventWait(osa_event_handle_t eventHandle, + osa_event_flags_t flagsToWait, + uint8_t waitAll, + uint32_t millisec, + osa_event_flags_t *pSetFlags); + +/*! + * @brief Destroys a previously created event object. + * + * @param eventHandle The event handle. + * + * @retval KOSA_StatusSuccess The event is successfully destroyed. + * @retval KOSA_StatusError Event destruction failed. + */ +osa_status_t OSA_EventDestroy(osa_event_handle_t eventHandle); + +/*! + * @brief Initializes a message queue. + * + * This function allocates memory for and initializes a message queue. Message queue elements are hardcoded as void*. + * + * Example below shows how to use this API to create the massage queue handle. + * @code + * OSA_MSGQ_HANDLE_DEFINE(msgqHandle); + * OSA_MsgQCreate((osa_msgq_handle_t)msgqHandle, 5U, sizeof(msg)); + * @endcode + * + * @param msgqHandle Pointer to a memory space of size #(OSA_MSGQ_HANDLE_SIZE + msgNo*msgSize) on bare-matel + * and #(OSA_MSGQ_HANDLE_SIZE) on FreeRTOS allocated by the caller, message queue handle. + * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices. + * You can define the handle in the following two ways: + * #OSA_MSGQ_HANDLE_DEFINE(msgqHandle); + * or + * For bm: uint32_t msgqHandle[((OSA_MSGQ_HANDLE_SIZE + msgNo*msgSize + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]; + * For freertos: uint32_t msgqHandle[((OSA_MSGQ_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]; + * @param msgNo :number of messages the message queue should accommodate. + * @param msgSize :size of a single message structure. + * + * @retval KOSA_StatusSuccess Message queue successfully Create. + * @retval KOSA_StatusError Message queue create failure. + */ +osa_status_t OSA_MsgQCreate(osa_msgq_handle_t msgqHandle, uint32_t msgNo, uint32_t msgSize); + +/*! + * @brief Puts a message at the end of the queue. + * + * This function puts a message to the end of the message queue. If the queue + * is full, this function returns the KOSA_StatusError; + * + * @param msgqHandle Message Queue handler. + * @param pMessage Pointer to the message to be put into the queue. + * + * @retval KOSA_StatusSuccess Message successfully put into the queue. + * @retval KOSA_StatusError The queue was full or an invalid parameter was passed. + */ +osa_status_t OSA_MsgQPut(osa_msgq_handle_t msgqHandle, osa_msg_handle_t pMessage); + +/*! + * @brief Reads and remove a message at the head of the queue. + * + * This function gets a message from the head of the message queue. If the + * queue is empty, timeout is used to wait. + * + * @param msgqHandle Message Queue handler. + * @param pMessage Pointer to a memory to save the message. + * @param millisec The number of milliseconds to wait for a message. If the + * queue is empty, pass osaWaitForever_c will wait indefinitely, + * pass 0 will return KOSA_StatusTimeout immediately. + * + * @retval KOSA_StatusSuccess Message successfully obtained from the queue. + * @retval KOSA_StatusTimeout The queue remains empty after timeout. + * @retval KOSA_StatusError Invalid parameter. + */ +osa_status_t OSA_MsgQGet(osa_msgq_handle_t msgqHandle, osa_msg_handle_t pMessage, uint32_t millisec); + +/*! + * @brief Get the available message + * + * This function is used to get the available message. + * + * @param msgqHandle Message Queue handler. + * + * @return Available message count + */ +int OSA_MsgQAvailableMsgs(osa_msgq_handle_t msgqHandle); + +/*! + * @brief Destroys a previously created queue. + * + * @param msgqHandle Message Queue handler. + * + * @retval KOSA_StatusSuccess The queue was successfully destroyed. + * @retval KOSA_StatusError Message queue destruction failed. + */ +osa_status_t OSA_MsgQDestroy(osa_msgq_handle_t msgqHandle); + +/*! + * @brief Enable all interrupts. + */ +void OSA_InterruptEnable(void); + +/*! + * @brief Disable all interrupts. + */ +void OSA_InterruptDisable(void); + +/*! + * @brief Enable all interrupts using PRIMASK. + */ +void OSA_EnableIRQGlobal(void); + +/*! + * @brief Disable all interrupts using PRIMASK. + */ +void OSA_DisableIRQGlobal(void); + +/*! + * @brief Delays execution for a number of milliseconds. + * + * @param millisec The time in milliseconds to wait. + */ +void OSA_TimeDelay(uint32_t millisec); + +/*! + * @brief This function gets current time in milliseconds. + * + * @retval current time in milliseconds + */ +uint32_t OSA_TimeGetMsec(void); + +/*! + * @brief Installs the interrupt handler. + * + * @param IRQNumber IRQ number of the interrupt. + * @param handler The interrupt handler to install. + */ +void OSA_InstallIntHandler(uint32_t IRQNumber, void (*handler)(void)); + +/*! @}*/ +#ifdef __cplusplus +} +#endif +/*! @}*/ +#endif diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_config.h b/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_config.h new file mode 100644 index 0000000000000000000000000000000000000000..5af0a6303e81d494db6e12f3d5eb3dd1df3cc307 --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_config.h @@ -0,0 +1,44 @@ +/*! + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_OS_ABSTRACTION_CONFIG_H_ +#define _FSL_OS_ABSTRACTION_CONFIG_H_ + +#ifndef gMainThreadStackSize_c +#define gMainThreadStackSize_c 1024 +#endif + +#ifndef gMainThreadPriority_c +#define gMainThreadPriority_c 7 +#endif + +#ifndef gTaskMultipleInstancesManagement_c +#define gTaskMultipleInstancesManagement_c 0 +#endif + +/*! @brief Definition to determine whether enable OSA's TASK module. */ +#ifndef OSA_USED +#ifndef FSL_OSA_TASK_ENABLE +#define FSL_OSA_TASK_ENABLE 0U +#endif +#else +#if defined(FSL_OSA_TASK_ENABLE) +#undef FSL_OSA_TASK_ENABLE +#endif +#define FSL_OSA_TASK_ENABLE 1U +#endif /* OSA_USED */ + +#ifndef FSL_OSA_MAIN_FUNC_ENABLE +#define FSL_OSA_MAIN_FUNC_ENABLE 0U +#endif + +#ifndef FSL_OSA_BM_TIMEOUT_ENABLE +#define FSL_OSA_BM_TIMEOUT_ENABLE 0U +#endif + +#endif /* _FSL_OS_ABSTRACTION_CONFIG_H_ */ diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_free_rtos.c b/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_free_rtos.c new file mode 100644 index 0000000000000000000000000000000000000000..f9281cff3d25dcc8c6f6a67e57a5d49005a7aa37 --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_free_rtos.c @@ -0,0 +1,1117 @@ +/*! ********************************************************************************* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017, 2019 NXP + * All rights reserved. + * + * + * This is the source file for the OS Abstraction layer for freertos. + * + * SPDX-License-Identifier: BSD-3-Clause + ********************************************************************************** */ + +/*! ********************************************************************************* +************************************************************************************* +* Include +************************************************************************************* +********************************************************************************** */ +#include "fsl_common.h" +#include "fsl_os_abstraction.h" +#include "fsl_os_abstraction_free_rtos.h" +#include +#include "fsl_component_generic_list.h" + +/*! ********************************************************************************* +************************************************************************************* +* Private macros +************************************************************************************* +********************************************************************************** */ + +/* Weak function. */ +#if defined(__GNUC__) +#define __WEAK_FUNC __attribute__((weak)) +#elif defined(__ICCARM__) +#define __WEAK_FUNC __weak +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) +#define __WEAK_FUNC __attribute__((weak)) +#endif + +#define millisecToTicks(millisec) (((millisec)*configTICK_RATE_HZ + 999U) / 1000U) + +#ifdef DEBUG_ASSERT +#define OS_ASSERT(condition) \ + if (!(condition)) \ + while (1) \ + ; +#else +#define OS_ASSERT(condition) (void)(condition); +#endif + +/*! @brief Converts milliseconds to ticks*/ +#define MSEC_TO_TICK(msec) \ + (((uint32_t)(msec) + 500uL / (uint32_t)configTICK_RATE_HZ) * (uint32_t)configTICK_RATE_HZ / 1000uL) +#define TICKS_TO_MSEC(tick) ((uint32_t)((uint64_t)(tick)*1000uL / (uint64_t)configTICK_RATE_HZ)) +/************************************************************************************ +************************************************************************************* +* Private type definitions +************************************************************************************* +************************************************************************************/ +typedef struct osa_freertos_task +{ + list_element_t link; + TaskHandle_t taskHandle; +} osa_freertos_task_t; + +typedef struct _osa_event_struct +{ + EventGroupHandle_t handle; /* The event handle */ + uint8_t autoClear; /*!< Auto clear or manual clear */ +} osa_event_struct_t; + +/*! @brief State structure for bm osa manager. */ +typedef struct _osa_state +{ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) + list_label_t taskList; +#if (defined(FSL_OSA_MAIN_FUNC_ENABLE) && (FSL_OSA_MAIN_FUNC_ENABLE > 0U)) + OSA_TASK_HANDLE_DEFINE(mainTaskHandle); +#endif +#endif + uint32_t basePriority; + int32_t basePriorityNesting; + uint32_t interruptDisableCount; +} osa_state_t; + +/*! ********************************************************************************* +************************************************************************************* +* Private prototypes +************************************************************************************* +********************************************************************************** */ +__WEAK_FUNC void main_task(void const *argument); +__WEAK_FUNC void main_task(void const *argument) +{ +} + +void startup_task(void *argument); + +/*! ********************************************************************************* +************************************************************************************* +* Public memory declarations +************************************************************************************* +********************************************************************************** */ +const uint8_t gUseRtos_c = USE_RTOS; /* USE_RTOS = 0 for BareMetal and 1 for OS */ + +static osa_state_t s_osaState = {0}; +/*! ********************************************************************************* +************************************************************************************* +* Private memory declarations +************************************************************************************* +********************************************************************************** */ + +/*! ********************************************************************************* +************************************************************************************* +* Public functions +************************************************************************************* +********************************************************************************** */ +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MemoryAllocate + * Description : Reserves the requested amount of memory in bytes. + * + *END**************************************************************************/ +void *OSA_MemoryAllocate(uint32_t length) +{ + void *p = (void *)pvPortMalloc(length); + + if (NULL != p) + { + (void)memset(p, 0, length); + } + + return p; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MemoryFree + * Description : Frees the memory previously reserved. + * + *END**************************************************************************/ +void OSA_MemoryFree(void *p) +{ + vPortFree(p); +} + +void OSA_EnterCritical(uint32_t *sr) +{ +#if defined(__GIC_PRIO_BITS) + if ((__get_CPSR() & CPSR_M_Msk) == 0x13) +#else + if (0U != __get_IPSR()) +#endif + { + *sr = portSET_INTERRUPT_MASK_FROM_ISR(); + } + else + { + portENTER_CRITICAL(); + } +} + +void OSA_ExitCritical(uint32_t sr) +{ +#if defined(__GIC_PRIO_BITS) + if ((__get_CPSR() & CPSR_M_Msk) == 0x13) +#else + if (0U != __get_IPSR()) +#endif + { + portCLEAR_INTERRUPT_MASK_FROM_ISR(sr); + } + else + { + portEXIT_CRITICAL(); + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : startup_task + * Description : Wrapper over main_task.. + * + *END**************************************************************************/ +void startup_task(void *argument) +{ + main_task(argument); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetCurrentHandle + * Description : This function is used to get current active task's handler. + * + *END**************************************************************************/ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_task_handle_t OSA_TaskGetCurrentHandle(void) +{ + list_element_handle_t list_element; + osa_freertos_task_t *ptask; + + list_element = LIST_GetHead(&s_osaState.taskList); + while (NULL != list_element) + { + ptask = (osa_freertos_task_t *)(void *)list_element; + if (ptask->taskHandle == xTaskGetCurrentTaskHandle()) + { + return (osa_task_handle_t)ptask; + } + list_element = LIST_GetNext(list_element); + } + return NULL; +} +#endif + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskYield + * Description : When a task calls this function, it will give up CPU and put + * itself to the tail of ready list. + * + *END**************************************************************************/ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_status_t OSA_TaskYield(void) +{ + taskYIELD(); + return KOSA_StatusSuccess; +} +#endif + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetPriority + * Description : This function returns task's priority by task handler. + * + *END**************************************************************************/ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_task_priority_t OSA_TaskGetPriority(osa_task_handle_t taskHandle) +{ + assert(NULL != taskHandle); + osa_freertos_task_t *ptask = (osa_freertos_task_t *)taskHandle; + return (osa_task_priority_t)(PRIORITY_RTOS_TO_OSA(uxTaskPriorityGet(ptask->taskHandle))); +} +#endif + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskSetPriority + * Description : This function sets task's priority by task handler. + * + *END**************************************************************************/ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_status_t OSA_TaskSetPriority(osa_task_handle_t taskHandle, osa_task_priority_t taskPriority) +{ + assert(NULL != taskHandle); + osa_freertos_task_t *ptask = (osa_freertos_task_t *)taskHandle; + vTaskPrioritySet((task_handler_t)ptask->taskHandle, PRIORITY_OSA_TO_RTOS(taskPriority)); + return KOSA_StatusSuccess; +} +#endif + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskCreate + * Description : This function is used to create a task and make it ready. + * Param[in] : threadDef - Definition of the thread. + * task_param - Parameter to pass to the new thread. + * Return Thread handle of the new thread, or NULL if failed. + * + *END**************************************************************************/ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_status_t OSA_TaskCreate(osa_task_handle_t taskHandle, const osa_task_def_t *thread_def, osa_task_param_t task_param) +{ + osa_status_t status = KOSA_StatusError; + assert(sizeof(osa_freertos_task_t) == OSA_TASK_HANDLE_SIZE); + assert(NULL != taskHandle); + TaskHandle_t pxCreatedTask; + osa_freertos_task_t *ptask = (osa_freertos_task_t *)taskHandle; + OSA_InterruptDisable(); + if (xTaskCreate((TaskFunction_t)thread_def->pthread, /* pointer to the task */ + (char const *)thread_def->tname, /* task name for kernel awareness debugging */ + (configSTACK_DEPTH_TYPE)thread_def->stacksize / sizeof(portSTACK_TYPE), /* task stack size */ + (task_param_t)task_param, /* optional task startup argument */ + PRIORITY_OSA_TO_RTOS(thread_def->tpriority), /* initial priority */ + &pxCreatedTask /* optional task handle to create */ + ) == pdPASS) + { + ptask->taskHandle = pxCreatedTask; + + (void)LIST_AddTail(&s_osaState.taskList, (list_element_handle_t) & (ptask->link)); + + status = KOSA_StatusSuccess; + } + OSA_InterruptEnable(); + return status; +} +#endif + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskDestroy + * Description : This function destroy a task. + * Param[in] :taskHandle - Thread handle. + * Return KOSA_StatusSuccess if the task is destroied, otherwise return KOSA_StatusError. + * + *END**************************************************************************/ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +osa_status_t OSA_TaskDestroy(osa_task_handle_t taskHandle) +{ + assert(NULL != taskHandle); + osa_freertos_task_t *ptask = (osa_freertos_task_t *)taskHandle; + osa_status_t status; + uint16_t oldPriority; + /*Change priority to avoid context switches*/ + oldPriority = OSA_TaskGetPriority(OSA_TaskGetCurrentHandle()); + (void)OSA_TaskSetPriority(OSA_TaskGetCurrentHandle(), OSA_PRIORITY_REAL_TIME); +#if INCLUDE_vTaskDelete /* vTaskDelete() enabled */ + vTaskDelete((task_handler_t)ptask->taskHandle); + status = KOSA_StatusSuccess; +#else + status = KOSA_StatusError; /* vTaskDelete() not available */ +#endif + (void)OSA_TaskSetPriority(OSA_TaskGetCurrentHandle(), oldPriority); + OSA_InterruptDisable(); + (void)LIST_RemoveElement(taskHandle); + OSA_InterruptEnable(); + return status; +} +#endif + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeDelay + * Description : This function is used to suspend the active thread for the given number of milliseconds. + * + *END**************************************************************************/ +void OSA_TimeDelay(uint32_t millisec) +{ + vTaskDelay(millisecToTicks(millisec)); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeGetMsec + * Description : This function gets current time in milliseconds. + * + *END**************************************************************************/ +uint32_t OSA_TimeGetMsec(void) +{ + TickType_t ticks; + + if (0U != __get_IPSR()) + { + ticks = xTaskGetTickCountFromISR(); + } + else + { + ticks = xTaskGetTickCount(); + } + + return TICKS_TO_MSEC(ticks); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreCreate + * Description : This function is used to create a semaphore. + * Return : Semaphore handle of the new semaphore, or NULL if failed. + * + *END**************************************************************************/ +osa_status_t OSA_SemaphoreCreate(osa_semaphore_handle_t semaphoreHandle, uint32_t initValue) +{ + assert(sizeof(osa_semaphore_handle_t) == OSA_SEM_HANDLE_SIZE); + assert(NULL != semaphoreHandle); + + union + { + QueueHandle_t sem; + uint32_t semhandle; + } xSemaHandle; + + xSemaHandle.sem = xSemaphoreCreateCounting(0xFF, initValue); + if (NULL != xSemaHandle.sem) + { + *(uint32_t *)semaphoreHandle = xSemaHandle.semhandle; + return KOSA_StatusSuccess; + } + return KOSA_StatusError; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreCreateBinary + * Description : This function is used to create a binary semaphore. + * Return : Semaphore handle of the new binary semaphore, or NULL if failed. + * + *END**************************************************************************/ +osa_status_t OSA_SemaphoreCreateBinary(osa_semaphore_handle_t semaphoreHandle) +{ + assert(sizeof(osa_semaphore_handle_t) == OSA_SEM_HANDLE_SIZE); + assert(NULL != semaphoreHandle); + + union + { + QueueHandle_t sem; + uint32_t semhandle; + } xSemaHandle; + + xSemaHandle.sem = xSemaphoreCreateBinary(); + if (NULL != xSemaHandle.sem) + { + *(uint32_t *)semaphoreHandle = xSemaHandle.semhandle; + return KOSA_StatusSuccess; + } + return KOSA_StatusError; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreDestroy + * Description : This function is used to destroy a semaphore. + * Return : KOSA_StatusSuccess if the semaphore is destroyed successfully, otherwise return KOSA_StatusError. + * + *END**************************************************************************/ +osa_status_t OSA_SemaphoreDestroy(osa_semaphore_handle_t semaphoreHandle) +{ + assert(NULL != semaphoreHandle); + QueueHandle_t sem = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)semaphoreHandle); + + vSemaphoreDelete(sem); + return KOSA_StatusSuccess; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreWait + * Description : This function checks the semaphore's counting value, if it is + * positive, decreases it and returns KOSA_StatusSuccess, otherwise, timeout + * will be used for wait. The parameter timeout indicates how long should wait + * in milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will + * return KOSA_StatusTimeout immediately if semaphore is not positive. + * This function returns KOSA_StatusSuccess if the semaphore is received, returns + * KOSA_StatusTimeout if the semaphore is not received within the specified + * 'timeout', returns KOSA_StatusError if any errors occur during waiting. + * + *END**************************************************************************/ +osa_status_t OSA_SemaphoreWait(osa_semaphore_handle_t semaphoreHandle, uint32_t millisec) +{ + uint32_t timeoutTicks; + assert(NULL != semaphoreHandle); + QueueHandle_t sem = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)semaphoreHandle); + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = MSEC_TO_TICK(millisec); + } + + if (((BaseType_t)0) == (BaseType_t)xSemaphoreTake(sem, timeoutTicks)) + { + return KOSA_StatusTimeout; /* timeout */ + } + else + { + return KOSA_StatusSuccess; /* semaphore taken */ + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphorePost + * Description : This function is used to wake up one task that wating on the + * semaphore. If no task is waiting, increase the semaphore. The function returns + * KOSA_StatusSuccess if the semaphre is post successfully, otherwise returns + * KOSA_StatusError. + * + *END**************************************************************************/ +osa_status_t OSA_SemaphorePost(osa_semaphore_handle_t semaphoreHandle) +{ + assert(NULL != semaphoreHandle); + osa_status_t status = KOSA_StatusError; + QueueHandle_t sem = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)semaphoreHandle); + + if (0U != __get_IPSR()) + { + portBASE_TYPE taskToWake = (portBASE_TYPE)pdFALSE; + + if (((BaseType_t)1) == (BaseType_t)xSemaphoreGiveFromISR(sem, &taskToWake)) + { + portYIELD_FROM_ISR((taskToWake)); + status = KOSA_StatusSuccess; + } + else + { + status = KOSA_StatusError; + } + } + else + { + if (((BaseType_t)1) == (BaseType_t)xSemaphoreGive(sem)) + { + status = KOSA_StatusSuccess; /* sync object given */ + } + else + { + status = KOSA_StatusError; + } + } + return status; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexCreate + * Description : This function is used to create a mutex. + * Return : Mutex handle of the new mutex, or NULL if failed. + * + *END**************************************************************************/ +osa_status_t OSA_MutexCreate(osa_mutex_handle_t mutexHandle) +{ + assert(sizeof(osa_mutex_handle_t) == OSA_MUTEX_HANDLE_SIZE); + assert(NULL != mutexHandle); + + union + { + QueueHandle_t mutex; + uint32_t pmutexHandle; + } xMutexHandle; + + xMutexHandle.mutex = xSemaphoreCreateRecursiveMutex(); + if (NULL != xMutexHandle.mutex) + { + *(uint32_t *)mutexHandle = xMutexHandle.pmutexHandle; + return KOSA_StatusSuccess; + } + return KOSA_StatusError; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexLock + * Description : This function checks the mutex's status, if it is unlocked, + * lock it and returns KOSA_StatusSuccess, otherwise, wait for the mutex. + * This function returns KOSA_StatusSuccess if the mutex is obtained, returns + * KOSA_StatusError if any errors occur during waiting. If the mutex has been + * locked, pass 0 as timeout will return KOSA_StatusTimeout immediately. + * + *END**************************************************************************/ +osa_status_t OSA_MutexLock(osa_mutex_handle_t mutexHandle, uint32_t millisec) +{ + assert(NULL != mutexHandle); + uint32_t timeoutTicks; + QueueHandle_t mutex = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)mutexHandle); + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = MSEC_TO_TICK(millisec); + } + + if (((BaseType_t)0) == (BaseType_t)xSemaphoreTakeRecursive(mutex, timeoutTicks)) + { + return KOSA_StatusTimeout; /* timeout */ + } + else + { + return KOSA_StatusSuccess; /* semaphore taken */ + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexUnlock + * Description : This function is used to unlock a mutex. + * + *END**************************************************************************/ +osa_status_t OSA_MutexUnlock(osa_mutex_handle_t mutexHandle) +{ + assert(NULL != mutexHandle); + QueueHandle_t mutex = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)mutexHandle); + + if (((BaseType_t)0) == (BaseType_t)xSemaphoreGiveRecursive(mutex)) + { + return KOSA_StatusError; + } + else + { + return KOSA_StatusSuccess; + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexDestroy + * Description : This function is used to destroy a mutex. + * Return : KOSA_StatusSuccess if the lock object is destroyed successfully, otherwise return KOSA_StatusError. + * + *END**************************************************************************/ +osa_status_t OSA_MutexDestroy(osa_mutex_handle_t mutexHandle) +{ + assert(NULL != mutexHandle); + QueueHandle_t mutex = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)mutexHandle); + + vSemaphoreDelete(mutex); + return KOSA_StatusSuccess; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventCreate + * Description : This function is used to create a event object. + * Return : Event handle of the new event, or NULL if failed. + * + *END**************************************************************************/ +osa_status_t OSA_EventCreate(osa_event_handle_t eventHandle, uint8_t autoClear) +{ + assert(NULL != eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + pEventStruct->handle = xEventGroupCreate(); + if (NULL != pEventStruct->handle) + { + pEventStruct->autoClear = autoClear; + } + else + { + return KOSA_StatusError; + } + return KOSA_StatusSuccess; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventSet + * Description : Set one or more event flags of an event object. + * Return : KOSA_StatusSuccess if set successfully, KOSA_StatusError if failed. + * + *END**************************************************************************/ +osa_status_t OSA_EventSet(osa_event_handle_t eventHandle, osa_event_flags_t flagsToSet) +{ + portBASE_TYPE taskToWake = (portBASE_TYPE)pdFALSE; + BaseType_t result; + assert(NULL != eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + if (NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + if (0U != __get_IPSR()) + { +#if (configUSE_TRACE_FACILITY == 1) + result = xEventGroupSetBitsFromISR(pEventStruct->handle, (event_flags_t)flagsToSet, &taskToWake); +#else + result = xEventGroupSetBitsFromISR((void *)pEventStruct->handle, (event_flags_t)flagsToSet, &taskToWake); +#endif + assert(pdPASS == result); + (void)result; + portYIELD_FROM_ISR((taskToWake)); + } + else + { + (void)xEventGroupSetBits(pEventStruct->handle, (event_flags_t)flagsToSet); + } + + (void)result; + return KOSA_StatusSuccess; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventClear + * Description : Clear one or more event flags of an event object. + * Return :KOSA_StatusSuccess if clear successfully, KOSA_StatusError if failed. + * + *END**************************************************************************/ +osa_status_t OSA_EventClear(osa_event_handle_t eventHandle, osa_event_flags_t flagsToClear) +{ + assert(NULL != eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + if (NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + + if (0U != __get_IPSR()) + { +#if (configUSE_TRACE_FACILITY == 1) + (void)xEventGroupClearBitsFromISR(pEventStruct->handle, (event_flags_t)flagsToClear); +#else + (void)xEventGroupClearBitsFromISR((void *)pEventStruct->handle, (event_flags_t)flagsToClear); +#endif + } + else + { + (void)xEventGroupClearBits(pEventStruct->handle, (event_flags_t)flagsToClear); + } + return KOSA_StatusSuccess; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventGet + * Description : This function is used to get event's flags that specified by prameter + * flagsMask, and the flags (user specified) are obatianed by parameter pFlagsOfEvent. So + * you should pass the parameter 0xffffffff to specify you want to check all. + * Return :KOSA_StatusSuccess if event flags were successfully got, KOSA_StatusError if failed. + * + *END**************************************************************************/ +osa_status_t OSA_EventGet(osa_event_handle_t eventHandle, osa_event_flags_t flagsMask, osa_event_flags_t *pFlagsOfEvent) +{ + assert(NULL != eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + EventBits_t eventFlags; + + if (NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + + if (NULL == pFlagsOfEvent) + { + return KOSA_StatusError; + } + + if (0U != __get_IPSR()) + { + eventFlags = xEventGroupGetBitsFromISR(pEventStruct->handle); + } + else + { + eventFlags = xEventGroupGetBits(pEventStruct->handle); + } + + *pFlagsOfEvent = (osa_event_flags_t)eventFlags & flagsMask; + + return KOSA_StatusSuccess; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventWait + * Description : This function checks the event's status, if it meets the wait + * condition, return KOSA_StatusSuccess, otherwise, timeout will be used for + * wait. The parameter timeout indicates how long should wait in milliseconds. + * Pass osaWaitForever_c to wait indefinitely, pass 0 will return the value + * KOSA_StatusTimeout immediately if wait condition is not met. The event flags + * will be cleared if the event is auto clear mode. Flags that wakeup waiting + * task could be obtained from the parameter setFlags. + * This function returns KOSA_StatusSuccess if wait condition is met, returns + * KOSA_StatusTimeout if wait condition is not met within the specified + * 'timeout', returns KOSA_StatusError if any errors occur during waiting. + * + *END**************************************************************************/ +osa_status_t OSA_EventWait(osa_event_handle_t eventHandle, + osa_event_flags_t flagsToWait, + uint8_t waitAll, + uint32_t millisec, + osa_event_flags_t *pSetFlags) +{ + assert(NULL != eventHandle); + BaseType_t clearMode; + uint32_t timeoutTicks; + event_flags_t flagsSave; + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + /* Clean FreeRTOS cotrol flags */ + flagsToWait = flagsToWait & 0x00FFFFFFU; + if (NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = millisec / portTICK_PERIOD_MS; + } + + clearMode = (pEventStruct->autoClear != 0U) ? pdTRUE : pdFALSE; + + flagsSave = xEventGroupWaitBits(pEventStruct->handle, (event_flags_t)flagsToWait, clearMode, (BaseType_t)waitAll, + timeoutTicks); + + flagsSave &= (event_flags_t)flagsToWait; + if (NULL != pSetFlags) + { + *pSetFlags = (osa_event_flags_t)flagsSave; + } + + if (0U != flagsSave) + { + return KOSA_StatusSuccess; + } + else + { + return KOSA_StatusTimeout; + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventDestroy + * Description : This function is used to destroy a event object. Return + * KOSA_StatusSuccess if the event object is destroyed successfully, otherwise + * return KOSA_StatusError. + * + *END**************************************************************************/ +osa_status_t OSA_EventDestroy(osa_event_handle_t eventHandle) +{ + assert(NULL != eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + if (NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + vEventGroupDelete(pEventStruct->handle); + return KOSA_StatusSuccess; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQCreate + * Description : This function is used to create a message queue. + * Return : the handle to the message queue if create successfully, otherwise + * return NULL. + * + *END**************************************************************************/ +osa_status_t OSA_MsgQCreate(osa_msgq_handle_t msgqHandle, uint32_t msgNo, uint32_t msgSize) +{ + assert(sizeof(osa_msgq_handle_t) == OSA_MSGQ_HANDLE_SIZE); + assert(NULL != msgqHandle); + + union + { + QueueHandle_t msgq; + uint32_t pmsgqHandle; + } xMsgqHandle; + + /* Create the message queue where the number and size is specified by msgNo and msgSize */ + xMsgqHandle.msgq = xQueueCreate(msgNo, msgSize); + if (NULL != xMsgqHandle.msgq) + { + *(uint32_t *)msgqHandle = xMsgqHandle.pmsgqHandle; + return KOSA_StatusSuccess; + } + return KOSA_StatusError; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQPut + * Description : This function is used to put a message to a message queue. + * Return : KOSA_StatusSuccess if the message is put successfully, otherwise return KOSA_StatusError. + * + *END**************************************************************************/ +osa_status_t OSA_MsgQPut(osa_msgq_handle_t msgqHandle, osa_msg_handle_t pMessage) +{ + osa_status_t osaStatus; + assert(NULL != msgqHandle); + portBASE_TYPE taskToWake = (portBASE_TYPE)pdFALSE; + QueueHandle_t handler = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)msgqHandle); + + if (0U != __get_IPSR()) + { + if (((BaseType_t)1) == (BaseType_t)xQueueSendToBackFromISR(handler, pMessage, &taskToWake)) + { + portYIELD_FROM_ISR((taskToWake)); + osaStatus = KOSA_StatusSuccess; + } + else + { + osaStatus = KOSA_StatusError; + } + } + else + { + osaStatus = (xQueueSendToBack(handler, pMessage, 0) == pdPASS) ? (KOSA_StatusSuccess) : (KOSA_StatusError); + } + + return osaStatus; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQGet + * Description : This function checks the queue's status, if it is not empty, + * get message from it and return KOSA_StatusSuccess, otherwise, timeout will + * be used for wait. The parameter timeout indicates how long should wait in + * milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will return + * KOSA_StatusTimeout immediately if queue is empty. + * This function returns KOSA_StatusSuccess if message is got successfully, + * returns KOSA_StatusTimeout if message queue is empty within the specified + * 'timeout', returns KOSA_StatusError if any errors occur during waiting. + * + *END**************************************************************************/ +osa_status_t OSA_MsgQGet(osa_msgq_handle_t msgqHandle, osa_msg_handle_t pMessage, uint32_t millisec) +{ + osa_status_t osaStatus; + assert(NULL != msgqHandle); + QueueHandle_t handler = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)msgqHandle); + + uint32_t timeoutTicks; + + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = MSEC_TO_TICK(millisec); + } + if (pdPASS != xQueueReceive(handler, pMessage, timeoutTicks)) + { + osaStatus = KOSA_StatusTimeout; /* not able to send it to the queue? */ + } + else + { + osaStatus = KOSA_StatusSuccess; + } + return osaStatus; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQAvailableMsgs + * Description : This function is used to get the available message. + * Return : Available message count + * + *END**************************************************************************/ +int OSA_MsgQAvailableMsgs(osa_msgq_handle_t msgqHandle) +{ + QueueHandle_t handler; + assert(NULL != msgqHandle); + handler = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)msgqHandle); + return (int)uxQueueMessagesWaiting((QueueHandle_t)handler); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQDestroy + * Description : This function is used to destroy the message queue. + * Return : KOSA_StatusSuccess if the message queue is destroyed successfully, otherwise return KOSA_StatusError. + * + *END**************************************************************************/ +osa_status_t OSA_MsgQDestroy(osa_msgq_handle_t msgqHandle) +{ + assert(NULL != msgqHandle); + QueueHandle_t handler = (QueueHandle_t)(void *)(uint32_t *)(*(uint32_t *)msgqHandle); + + vQueueDelete(handler); + return KOSA_StatusSuccess; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptEnable(void) +{ + if (0U != __get_IPSR()) + { + if (1 == s_osaState.basePriorityNesting) + { + portCLEAR_INTERRUPT_MASK_FROM_ISR(s_osaState.basePriority); + } + + if (s_osaState.basePriorityNesting > 0) + { + s_osaState.basePriorityNesting--; + } + } + else + { + portEXIT_CRITICAL(); + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptDisable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptDisable(void) +{ + if (0U != __get_IPSR()) + { + if (0 == s_osaState.basePriorityNesting) + { + s_osaState.basePriority = portSET_INTERRUPT_MASK_FROM_ISR(); + } + s_osaState.basePriorityNesting++; + } + else + { + portENTER_CRITICAL(); + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EnableIRQGlobal + * Description : enable interrupts using PRIMASK register. + * + *END**************************************************************************/ +void OSA_EnableIRQGlobal(void) +{ + if (s_osaState.interruptDisableCount > 0U) + { + s_osaState.interruptDisableCount--; + + if (0U == s_osaState.interruptDisableCount) + { + __enable_irq(); + } + /* call core API to enable the global interrupt*/ + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_DisableIRQGlobal + * Description : disable interrupts using PRIMASK register. + * + *END**************************************************************************/ +void OSA_DisableIRQGlobal(void) +{ + /* call core API to disable the global interrupt*/ + __disable_irq(); + + /* update counter*/ + s_osaState.interruptDisableCount++; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InstallIntHandler + * Description : This function is used to install interrupt handler. + * + *END**************************************************************************/ +void OSA_InstallIntHandler(uint32_t IRQNumber, void (*handler)(void)) +{ +#if defined(__IAR_SYSTEMS_ICC__) + _Pragma("diag_suppress = Pm138") +#endif +#if defined(ENABLE_RAM_VECTOR_TABLE) + (void) InstallIRQHandler((IRQn_Type)IRQNumber, (uint32_t) * (uint32_t *)&handler); +#endif /* ENABLE_RAM_VECTOR_TABLE. */ +#if defined(__IAR_SYSTEMS_ICC__) + _Pragma("diag_remark = PM138") +#endif +} + +/*!********************************************************************************* +************************************************************************************* +* Private functions +************************************************************************************* +********************************************************************************** */ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +#if (defined(FSL_OSA_MAIN_FUNC_ENABLE) && (FSL_OSA_MAIN_FUNC_ENABLE > 0U)) +static OSA_TASK_DEFINE(startup_task, gMainThreadPriority_c, 1, gMainThreadStackSize_c, 0); + +int main(void) +{ + extern void BOARD_InitHardware(void); + OSA_Init(); + /* Initialize MCU clock */ + BOARD_InitHardware(); + + (void)OSA_TaskCreate((osa_task_handle_t)s_osaState.mainTaskHandle, OSA_TASK(startup_task), NULL); + + OSA_Start(); + return 0; +} +#endif /*(defined(FSL_OSA_MAIN_FUNC_ENABLE) && (FSL_OSA_MAIN_FUNC_ENABLE > 0U))*/ +#endif /* FSL_OSA_TASK_ENABLE */ + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_Init + * Description : This function is used to setup the basic services, it should + * be called first in function main. + * + *END**************************************************************************/ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +void OSA_Init(void) +{ + LIST_Init((&s_osaState.taskList), 0); + s_osaState.basePriorityNesting = 0; + s_osaState.interruptDisableCount = 0; +} +#endif + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_Start + * Description : This function is used to start RTOS scheduler. + * + *END**************************************************************************/ +#if (defined(FSL_OSA_TASK_ENABLE) && (FSL_OSA_TASK_ENABLE > 0U)) +void OSA_Start(void) +{ + vTaskStartScheduler(); +} +#endif diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_free_rtos.h b/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_free_rtos.h new file mode 100644 index 0000000000000000000000000000000000000000..3648a5625dcd03259c0b92a3876c9aee787067fd --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_os_abstraction_free_rtos.h @@ -0,0 +1,132 @@ +/*! ********************************************************************************* + * Copyright (c) 2013-2014, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * ile + * + * SPDX-License-Identifier: BSD-3-Clause + ********************************************************************************** */ +#if !defined(__FSL_OS_ABSTRACTION_FREERTOS_H__) +#define __FSL_OS_ABSTRACTION_FREERTOS_H__ + +#if defined(__IAR_SYSTEMS_ICC__) +/** + * Workaround to disable MISRA C message suppress warnings for IAR compiler. + */ +/* http://supp.iar.com/Support/?note=24725 */ + +#define MISRAC_DISABLE \ + _Pragma( \ + "diag_suppress= \ + Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,Pm011,\ + Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\ + Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\ + Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\ + Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\ + Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\ + Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\ + Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\ + Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\ + Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\ + Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\ + Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\ + Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\ + Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\ + Pm155") + +#define MISRAC_ENABLE \ + _Pragma( \ + "diag_default= \ + Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,Pm011,\ + Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\ + Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\ + Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\ + Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\ + Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\ + Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\ + Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\ + Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\ + Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\ + Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\ + Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\ + Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\ + Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\ + Pm155") +#else +/* Empty MISRA C macros for other toolchains. */ +#define MISRAC_DISABLE +#define MISRAC_ENABLE +#endif + +MISRAC_DISABLE +#include "FreeRTOS.h" +#include "semphr.h" +#include "event_groups.h" +MISRAC_ENABLE + +/*! + * @addtogroup os_abstraction_free_rtos + * @{ + */ + +/******************************************************************************* + * Declarations + ******************************************************************************/ +/*! @brief Type for a task handler, returned by the OSA_TaskCreate function. */ +typedef TaskHandle_t task_handler_t; + +/*! @brief Type for a task stack.*/ +typedef portSTACK_TYPE task_stack_t; + +/*! @brief Type for task parameter */ +typedef void *task_param_t; + +/*! @brief Type for an event flags object.*/ +typedef EventBits_t event_flags_t; + +/*! @brief Constant to pass as timeout value in order to wait indefinitely. */ +#define OSA_WAIT_FOREVER 0xFFFFFFFFU + +/*! @brief OSA's time range in millisecond, OSA time wraps if exceeds this value. */ +#define FSL_OSA_TIME_RANGE 0xFFFFFFFFU + +/*! @brief The default interrupt handler installed in vector table. */ +#define OSA_DEFAULT_INT_HANDLER ((osa_int_handler_t)(&DefaultISR)) + +extern void DefaultISR(void); + +/*! + * @name Thread management + * @{ + */ + +/*! + * @brief To provide unified task piority for upper layer, OSA layer makes conversion. + */ +#define PRIORITY_OSA_TO_RTOS(osa_prio) ((UBaseType_t)configMAX_PRIORITIES - (osa_prio)-2U) +#define PRIORITY_RTOS_TO_OSA(rtos_prio) ((UBaseType_t)configMAX_PRIORITIES - (rtos_prio)-2U) + +/* @}*/ + +/*! + * @name Message queues + * @{ + */ + +/*! + * @brief This macro statically reserves the memory required for the queue. + * + * @param name Identifier for the memory region. + * @param number Number of elements in the queue. + * @param size Size of every elements in words. + */ +#define MSG_QUEUE_DECLARE(name, number, size) msg_queue_t *name = NULL + +/* @}*/ + +/*! @}*/ +/*! @}*/ +/*! @}*/ + +#endif /* __FSL_OS_ABSTRACTION_FREERTOS_H__ */ diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_common.c b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_common.c index 98642d9a8321a1a2f9b06963aa8e20a354964c4a..7ae64f4591f09ebff8d4f58fcb0f51eb340b2d60 100644 --- a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_common.c +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_common.c @@ -1,69 +1,55 @@ /* - * The Clear BSD License * Copyright (c) 2015, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted (subject to the limitations in the disclaimer below) provided - * that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * o Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_sdmmc_common.h" /******************************************************************************* * Variables ******************************************************************************/ -SDK_ALIGN(uint32_t g_sdmmc[SDK_SIZEALIGN(SDMMC_GLOBAL_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)], - MAX(SDMMC_DATA_BUFFER_ALIGN_CACHE, SDMMCHOST_DMA_BUFFER_ADDR_ALIGN)); +#if SDMMCHOST_SUPPORT_DDR50 || SDMMCHOST_SUPPORT_SDR104 || SDMMCHOST_SUPPORT_SDR50 || SDMMCHOST_SUPPORT_HS200 || \ + SDMMCHOST_SUPPORT_HS400 +/* sdmmc tuning block */ +const uint32_t SDMMC_TuningBlockPattern4Bit[16U] = { + 0xFF0FFF00U, 0xFFCCC3CCU, 0xC33CCCFFU, 0xFEFFFEEFU, 0xFFDFFFDDU, 0xFFFBFFFBU, 0xBFFF7FFFU, 0x77F7BDEFU, + 0xFFF0FFF0U, 0x0FFCCC3CU, 0xCC33CCCFU, 0xFFEFFFEEU, 0xFFFDFFFDU, 0xDFFFBFFFU, 0xBBFFF7FFU, 0xF77F7BDEU, +}; +const uint32_t SDMMC_TuningBlockPattern8Bit[32U] = { + 0xffff00ffU, 0xffff0000U, 0xffffccccU, 0xcc33ccccU, 0xcc3333ccU, 0xccccffffU, 0xffeeffffU, 0xffeeeeffU, + 0xffffddffU, 0xffffddddU, 0xffffffbbU, 0xffffffbbU, 0xbbffffffU, 0x77ffffffU, 0x7777ff77U, 0xbbddeeffU, + 0xffffff00U, 0xffffff00U, 0x00ffffccU, 0xcccc33ccU, 0xcccc3333U, 0xccccccffU, 0xffffeeffU, 0xffffeeeeU, + 0xffffffddU, 0xffffffddU, 0xddffffffU, 0xbbffffffU, 0xbbbbffffU, 0xff77ffffU, 0xff7777ffU, 0x77bbddeeU, +}; +#endif /******************************************************************************* * Code ******************************************************************************/ -status_t SDMMC_SelectCard(SDMMCHOST_TYPE *base, - SDMMCHOST_TRANSFER_FUNCTION transfer, - uint32_t relativeAddress, - bool isSelected) +status_t SDMMC_SelectCard(sdmmchost_t *host, uint32_t relativeAddress, bool isSelected) { - assert(transfer); + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + status_t error = kStatus_Success; - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; - - command.index = kSDMMC_SelectCard; - if (isSelected) { + command.index = (uint32_t)kSDMMC_SelectCard; + if (isSelected) + { command.argument = relativeAddress << 16U; command.responseType = kCARD_ResponseTypeR1; } - else { + else + { command.argument = 0U; command.responseType = kCARD_ResponseTypeNone; } content.command = &command; content.data = NULL; - if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & kSDMMC_R1ErrorAllFlag)) { + error = SDMMCHOST_TransferFunction(host, &content); + if ((kStatus_Success != error) || ((command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG) != 0U)) + { return kStatus_SDMMC_TransferFailed; } @@ -71,218 +57,110 @@ status_t SDMMC_SelectCard(SDMMCHOST_TYPE *base, return kStatus_Success; } -status_t SDMMC_SendApplicationCommand(SDMMCHOST_TYPE *base, - SDMMCHOST_TRANSFER_FUNCTION transfer, - uint32_t relativeAddress) +status_t SDMMC_SendApplicationCommand(sdmmchost_t *host, uint32_t relativeAddress) { - assert(transfer); - - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + status_t error = kStatus_Success; - command.index = kSDMMC_ApplicationCommand; + command.index = (uint32_t)kSDMMC_ApplicationCommand; command.argument = (relativeAddress << 16U); command.responseType = kCARD_ResponseTypeR1; content.command = &command; - content.data = 0U; - if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & kSDMMC_R1ErrorAllFlag)) { + content.data = NULL; + error = SDMMCHOST_TransferFunction(host, &content); + if ((kStatus_Success != error) || ((command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG) != 0U)) + { return kStatus_SDMMC_TransferFailed; } - if (!(command.response[0U] & kSDMMC_R1ApplicationCommandFlag)) { + if (0U == (command.response[0U] & SDMMC_MASK(kSDMMC_R1ApplicationCommandFlag))) + { return kStatus_SDMMC_CardNotSupport; } return kStatus_Success; } -status_t SDMMC_SetBlockCount(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer, uint32_t blockCount) +status_t SDMMC_SetBlockCount(sdmmchost_t *host, uint32_t blockCount) { - assert(transfer); + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + status_t error = kStatus_Success; - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; - - command.index = kSDMMC_SetBlockCount; + command.index = (uint32_t)kSDMMC_SetBlockCount; command.argument = blockCount; command.responseType = kCARD_ResponseTypeR1; content.command = &command; - content.data = 0U; - if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & kSDMMC_R1ErrorAllFlag)) { + content.data = NULL; + error = SDMMCHOST_TransferFunction(host, &content); + if ((kStatus_Success != error) || ((command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG) != 0U)) + { return kStatus_SDMMC_TransferFailed; } return kStatus_Success; } -status_t SDMMC_GoIdle(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer) +status_t SDMMC_GoIdle(sdmmchost_t *host) { - assert(transfer); + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + status_t error = kStatus_Success; - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; - - command.index = kSDMMC_GoIdleState; + command.index = (uint32_t)kSDMMC_GoIdleState; content.command = &command; - content.data = 0U; - if (kStatus_Success != transfer(base, &content)) { + content.data = NULL; + error = SDMMCHOST_TransferFunction(host, &content); + if (kStatus_Success != error) + { return kStatus_SDMMC_TransferFailed; } return kStatus_Success; } -status_t SDMMC_SetBlockSize(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer, uint32_t blockSize) +status_t SDMMC_SetBlockSize(sdmmchost_t *host, uint32_t blockSize) { - assert(transfer); + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + status_t error = kStatus_Success; - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; - - command.index = kSDMMC_SetBlockLength; + command.index = (uint32_t)kSDMMC_SetBlockLength; command.argument = blockSize; command.responseType = kCARD_ResponseTypeR1; content.command = &command; - content.data = 0U; - if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & kSDMMC_R1ErrorAllFlag)) { + content.data = NULL; + error = SDMMCHOST_TransferFunction(host, &content); + if ((kStatus_Success != error) || ((command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG) != 0U)) + { return kStatus_SDMMC_TransferFailed; } return kStatus_Success; } -status_t SDMMC_SetCardInactive(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer) +status_t SDMMC_SetCardInactive(sdmmchost_t *host) { - assert(transfer); - - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; + sdmmchost_transfer_t content = {0}; + sdmmchost_cmd_t command = {0}; + status_t error = kStatus_Success; - command.index = kSDMMC_GoInactiveState; + command.index = (uint32_t)kSDMMC_GoInactiveState; command.argument = 0U; command.responseType = kCARD_ResponseTypeNone; - content.command = &command; - content.data = 0U; - if ((kStatus_Success != transfer(base, &content))) { - return kStatus_SDMMC_TransferFailed; - } - - return kStatus_Success; -} - -status_t SDMMC_SwitchVoltage(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer) -{ - assert(transfer); - - SDMMCHOST_TRANSFER content = {0}; - SDMMCHOST_COMMAND command = {0}; - - command.index = kSD_VoltageSwitch; - command.argument = 0U; - command.responseType = kCARD_ResponseTypeR1; - content.command = &command; content.data = NULL; - if (kStatus_Success != transfer(base, &content)) { + error = SDMMCHOST_TransferFunction(host, &content); + if ((kStatus_Success != error)) + { return kStatus_SDMMC_TransferFailed; } - /* disable card clock */ - SDMMCHOST_ENABLE_CARD_CLOCK(base, false); - - /* check data line and cmd line status */ - if ((GET_SDMMCHOST_STATUS(base) & - (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY)) != 0U) { - return kStatus_SDMMC_SwitchVoltageFail; - } - - /* host switch to 1.8V */ - SDMMCHOST_SWITCH_VOLTAGE180V(base, true); - - SDMMCHOST_Delay(100U); - - /*enable sd clock*/ - SDMMCHOST_ENABLE_CARD_CLOCK(base, true); - /*enable force clock on*/ - SDMMCHOST_FORCE_SDCLOCK_ON(base, true); - /* dealy 1ms,not exactly correct when use while */ - SDMMCHOST_Delay(10U); - /*disable force clock on*/ - SDMMCHOST_FORCE_SDCLOCK_ON(base, false); - - /* check data line and cmd line status */ - if ((GET_SDMMCHOST_STATUS(base) & - (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY)) == 0U) { - return kStatus_SDMMC_SwitchVoltageFail; - } - - return kStatus_Success; -} - -status_t SDMMC_ExecuteTuning(SDMMCHOST_TYPE *base, - SDMMCHOST_TRANSFER_FUNCTION transfer, - uint32_t tuningCmd, - uint32_t blockSize) -{ - SDMMCHOST_TRANSFER content = {0U}; - SDMMCHOST_COMMAND command = {0U}; - SDMMCHOST_DATA data = {0U}; - uint32_t buffer[32U] = {0U}; - bool tuningError = true; - - command.index = tuningCmd; - command.argument = 0U; - command.responseType = kCARD_ResponseTypeR1; - - data.blockSize = blockSize; - data.blockCount = 1U; - data.rxData = buffer; - /* add this macro for adpter to different driver */ - SDMMCHOST_ENABLE_TUNING_FLAG(data); - - content.command = &command; - content.data = &data; - - /* enable the standard tuning */ - SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, true); - - while (true) { - /* send tuning block */ - if ((kStatus_Success != transfer(base, &content))) { - return kStatus_SDMMC_TransferFailed; - } - SDMMCHOST_Delay(1U); - - /*wait excute tuning bit clear*/ - if ((SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) != 0U)) { - continue; - } - - /* if tuning error , re-tuning again */ - if ((SDMMCHOST_CHECK_TUNING_ERROR(base) != 0U) && tuningError) { - tuningError = false; - /* enable the standard tuning */ - SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, true); - SDMMCHOST_ADJUST_TUNING_DELAY(base, SDMMCHOST_STANDARD_TUNING_START); - } - else { - break; - } - } - - /* delay to wait the host controller stable */ - SDMMCHOST_Delay(100U); - - /* check tuning result*/ - if (SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) == 0U) { - return kStatus_SDMMC_TuningFail; - } - - SDMMCHOST_AUTO_STANDARD_RETUNING_TIMER(base); return kStatus_Success; } diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_common.h b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_common.h index 31644c89be2cee448e47e8a2f6c5c0314f60afce..00799276425221afd98667078926e392cb056575 100644 --- a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_common.h +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_common.h @@ -1,35 +1,9 @@ /* - * The Clear BSD License * Copyright (c) 2015, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted (subject to the limitations in the disclaimer below) provided - * that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * o Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _FSL_SDMMC_COMMON_H_ @@ -40,11 +14,15 @@ #include "fsl_sdmmc_spec.h" #include "stdlib.h" +/*! + * @addtogroup sdmmc_common SDMMC Common + * @ingroup card + * @{ + */ + /******************************************************************************* * Definitions ******************************************************************************/ -/*! @brief Middleware version. */ -#define FSL_SDMMC_DRIVER_VERSION (MAKE_VERSION(2U, 2U, 4U)) /*2.2.4*/ /*! @brief Reverse byte sequence in uint32_t */ #define SWAP_WORD_BYTE_SEQUENCE(x) (__REV(x)) @@ -56,11 +34,8 @@ #define FSL_SDMMC_MAX_CMD_RETRIES (10U) /*! @brief Default block size */ #define FSL_SDMMC_DEFAULT_BLOCK_SIZE (512U) -/*! @brief SDMMC global data buffer size, word unit*/ -#define SDMMC_GLOBAL_BUFFER_SIZE (128U) -/* Common definition for cache line size align */ -#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL +/*! @brief make sure the internal buffer address is cache align */ #if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) #if defined(FSL_FEATURE_L2DCACHE_LINESIZE_BYTE) #define SDMMC_DATA_BUFFER_ALIGN_CACHE MAX(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE, FSL_FEATURE_L2DCACHE_LINESIZE_BYTE) @@ -68,14 +43,28 @@ #define SDMMC_DATA_BUFFER_ALIGN_CACHE FSL_FEATURE_L1DCACHE_LINESIZE_BYTE #endif #else -#define SDMMC_DATA_BUFFER_ALIGN_CACHE 1 +#define SDMMC_DATA_BUFFER_ALIGN_CACHE sizeof(uint32_t) #endif + +/*! @brief sdmmc card internal buffer size */ +#define FSL_SDMMC_CARD_INTERNAL_BUFFER_SIZE (FSL_SDMMC_DEFAULT_BLOCK_SIZE + SDMMC_DATA_BUFFER_ALIGN_CACHE) +#define FSL_SDMMC_CARD_INTERNAL_BUFFER_ALIGN_ADDR(buffer) \ + (uint32_t)((uint32_t)(buffer) + (uint32_t)SDMMC_DATA_BUFFER_ALIGN_CACHE - \ + ((uint32_t)(buffer) & ((uint32_t)SDMMC_DATA_BUFFER_ALIGN_CACHE - 1U))) +/*! @brief get maximum freq */ +#define FSL_SDMMC_CARD_MAX_BUS_FREQ(max, target) ((max) == 0U ? (target) : ((max) > (target) ? (target) : (max))) +/*! @brief SD/MMC error log. */ +#if defined SDMMC_ENABLE_LOG_PRINT +#include "fsl_debug_console.h" +#define SDMMC_LOG(...) PRINTF(__VA_ARGS__) #else -#define SDMMC_DATA_BUFFER_ALIGN_CACHE 1 +#define SDMMC_LOG(format, ...) #endif -/*! @brief SD/MMC card API's running status. */ -enum _sdmmc_status +/*! @brief SD/MMC card API's running status. + * @anchor _sdmmc_status + */ +enum { kStatus_SDMMC_NotSupportYet = MAKE_STATUS(kStatusGroup_SDMMC, 0U), /*!< Haven't supported */ kStatus_SDMMC_TransferFailed = MAKE_STATUS(kStatusGroup_SDMMC, 1U), /*!< Send command failed */ @@ -116,134 +105,264 @@ enum _sdmmc_status kStatus_SDMMC_SDIO_ReadCISFail = MAKE_STATUS(kStatusGroup_SDMMC, 31U), /*!< read CIS fail */ kStatus_SDMMC_SDIO_InvalidCard = MAKE_STATUS(kStatusGroup_SDMMC, 32U), /*!< invaild SDIO card */ kStatus_SDMMC_TuningFail = MAKE_STATUS(kStatusGroup_SDMMC, 33U), /*!< tuning fail */ - kStatus_SDMMC_SwitchVoltageFail = MAKE_STATUS(kStatusGroup_SDMMC, 34U), /*!< switch voltage fail*/ - kStatus_SDMMC_ReTuningRequest = MAKE_STATUS(kStatusGroup_SDMMC, 35U), /*!< retuning request */ - kStatus_SDMMC_SetDriverStrengthFail = MAKE_STATUS(kStatusGroup_SDMMC, 36U), /*!< set driver strength fail */ - kStatus_SDMMC_SetPowerClassFail = MAKE_STATUS(kStatusGroup_SDMMC, 37U), /*!< set power class fail */ - kStatus_SDMMC_HostNotReady = MAKE_STATUS(kStatusGroup_SDMMC, 38U), /*!< host controller not ready */ - kStatus_SDMMC_CardDetectFailed = MAKE_STATUS(kStatusGroup_SDMMC, 39U), /*!< card detect failed */ - kStatus_SDMMC_PartitioningFailed = MAKE_STATUS(kStatusGroup_SDMMC, 40U), /*!< Partitioning failed */ - kStatus_SDMMC_PartitioningNotSupported = MAKE_STATUS(kStatusGroup_SDMMC, 41U), /*!< Partitioning not supported */ + + kStatus_SDMMC_SwitchVoltageFail = MAKE_STATUS(kStatusGroup_SDMMC, 34U), /*!< switch voltage fail*/ + kStatus_SDMMC_SwitchVoltage18VFail33VSuccess = MAKE_STATUS(kStatusGroup_SDMMC, 35U), /*!< switch voltage fail*/ + + kStatus_SDMMC_ReTuningRequest = MAKE_STATUS(kStatusGroup_SDMMC, 36U), /*!< retuning request */ + kStatus_SDMMC_SetDriverStrengthFail = MAKE_STATUS(kStatusGroup_SDMMC, 37U), /*!< set driver strength fail */ + kStatus_SDMMC_SetPowerClassFail = MAKE_STATUS(kStatusGroup_SDMMC, 38U), /*!< set power class fail */ + kStatus_SDMMC_HostNotReady = MAKE_STATUS(kStatusGroup_SDMMC, 39U), /*!< host controller not ready */ + kStatus_SDMMC_CardDetectFailed = MAKE_STATUS(kStatusGroup_SDMMC, 40U), /*!< card detect failed */ + kStatus_SDMMC_AuSizeNotSetProperly = MAKE_STATUS(kStatusGroup_SDMMC, 41U), /*!< AU size not set properly */ + kStatus_SDMMC_PollingCardIdleFailed = MAKE_STATUS(kStatusGroup_SDMMC, 42U), /*!< polling card idle status failed */ + kStatus_SDMMC_DeselectCardFailed = MAKE_STATUS(kStatusGroup_SDMMC, 43U), /*!< deselect card failed */ + kStatus_SDMMC_CardStatusIdle = MAKE_STATUS(kStatusGroup_SDMMC, 44U), /*!< card idle */ + kStatus_SDMMC_CardStatusBusy = MAKE_STATUS(kStatusGroup_SDMMC, 45U), /*!< card busy */ + kStatus_SDMMC_CardInitFailed = MAKE_STATUS(kStatusGroup_SDMMC, 46U), /*!< card init failed */ +}; + +/*! @brief sdmmc signal line + * @anchor _sdmmc_signal_line + */ +enum +{ + kSDMMC_SignalLineCmd = 1U, /*!< cmd line */ + kSDMMC_SignalLineData0 = 2U, /*!< data line */ + kSDMMC_SignalLineData1 = 4U, /*!< data line */ + kSDMMC_SignalLineData2 = 8U, /*!< data line */ + kSDMMC_SignalLineData3 = 16U, /*!< data line */ + kSDMMC_SignalLineData4 = 32U, /*!< data line */ + kSDMMC_SignalLineData5 = 64U, /*!< data line */ + kSDMMC_SignalLineData6 = 128U, /*!< data line */ + kSDMMC_SignalLineData7 = 256U, /*!< data line */ }; /*! @brief card operation voltage */ typedef enum _sdmmc_operation_voltage { - kCARD_OperationVoltageNone = 0U, /*!< indicate current voltage setting is not setting bu suser*/ - kCARD_OperationVoltage330V = 1U, /*!< card operation voltage around 3.3v */ - kCARD_OperationVoltage300V = 2U, /*!< card operation voltage around 3.0v */ - kCARD_OperationVoltage180V = 3U, /*!< card operation voltage around 31.8v */ + kSDMMC_OperationVoltageNone = 0U, /*!< indicate current voltage setting is not setting by suser*/ + kSDMMC_OperationVoltage330V = 1U, /*!< card operation voltage around 3.3v */ + kSDMMC_OperationVoltage300V = 2U, /*!< card operation voltage around 3.0v */ + kSDMMC_OperationVoltage180V = 3U, /*!< card operation voltage around 1.8v */ } sdmmc_operation_voltage_t; +/*!@brief card bus width + * @anchor _sdmmc_bus_width + */ +enum +{ + kSDMMC_BusWdith1Bit = 0U, /*!< card bus 1 width */ + kSDMMC_BusWdith4Bit = 1U, /*!< card bus 4 width */ + kSDMMC_BusWdith8Bit = 2U, /*!< card bus 8 width */ +}; + +/*!@brief sdmmc capability flag + * @anchor _sdmmc_capability_flag + */ +enum +{ + kSDMMC_Support8BitWidth = 1U, /*!< 8 bit data width capability */ +}; + +/*!@ brief sdmmc data packet format + * @anchor _sdmmc_data_packet_format + */ +enum +{ + kSDMMC_DataPacketFormatLSBFirst, /*!< usual data packet format LSB first, MSB last */ + kSDMMC_DataPacketFormatMSBFirst, /*!< Wide width data packet format MSB first, LSB last */ +}; + +/*! @brief sd card detect type */ +typedef enum _sd_detect_card_type +{ + kSD_DetectCardByGpioCD, /*!< sd card detect by CD pin through GPIO */ + kSD_DetectCardByHostCD, /*!< sd card detect by CD pin through host */ + kSD_DetectCardByHostDATA3, /*!< sd card detect by DAT3 pin through host */ +} sd_detect_card_type_t; + +/*!@ brief SD card detect status + * @anchor _sd_card_cd_status + */ +enum +{ + kSD_Inserted = 1U, /*!< card is inserted*/ + kSD_Removed = 0U, /*!< card is removed */ +}; + +/*!@ brief SD card detect status + * @anchor _sd_card_dat3_pull_status + */ +enum +{ + kSD_DAT3PullDown = 0U, /*!< data3 pull down */ + kSD_DAT3PullUp = 1U, /*!< data3 pull up */ +}; + +/*! @brief card detect aoolication callback definition */ +typedef void (*sd_cd_t)(bool isInserted, void *userData); +/*! @brief card detect status */ +typedef bool (*sd_cd_status_t)(void); +typedef void (*sd_dat3_pull_t)(uint32_t pullStatus); + +/*! @brief sd card detect */ +typedef struct _sd_detect_card +{ + sd_detect_card_type_t type; /*!< card detect type */ + uint32_t cdDebounce_ms; /*!< card detect debounce delay ms */ + sd_cd_t callback; /*!< card inserted callback which is meaningful for interrupt case */ + sd_cd_status_t cardDetected; /*!< used to check sd cd status when card detect through GPIO */ + sd_dat3_pull_t dat3PullFunc; /*!< function pointer of DATA3 pull up/down */ + + void *userData; /*!< user data */ +} sd_detect_card_t; + +/*!@brief io voltage control type*/ +typedef enum _sd_io_voltage_ctrl_type +{ + kSD_IOVoltageCtrlNotSupport = 0U, /*!< io voltage control not support */ +#if SDMMCHOST_SUPPORT_VOLTAGE_CONTROL + kSD_IOVoltageCtrlByHost = 1U, /*!< io voltage control by host */ +#endif + kSD_IOVoltageCtrlByGpio = 2U, /*!< io voltage control by gpio */ +} sd_io_voltage_ctrl_type_t; + +/*! @brief card switch voltage function pointer */ +typedef void (*sd_io_voltage_func_t)(sdmmc_operation_voltage_t voltage); + +/*!@brief io voltage control configuration */ +typedef struct _sd_io_voltage +{ + sd_io_voltage_ctrl_type_t type; /*!< io voltage switch type */ + sd_io_voltage_func_t func; /*!< io voltage switch function */ +} sd_io_voltage_t; + +/*! @brief card power control function pointer */ +typedef void (*sd_pwr_t)(bool enable); +/*! @brief card io strength control */ +typedef void (*sd_io_strength_t)(uint32_t busFreq); +/*! @brief sdcard user parameter */ +typedef struct _sd_usr_param +{ + sd_pwr_t pwr; /*!< power control configuration pointer */ + uint32_t powerOnDelayMS; /*!< power on delay time */ + uint32_t powerOffDelayMS; /*!< power off delay time */ + + sd_io_strength_t ioStrength; /*!< swicth sd io strength */ + sd_io_voltage_t *ioVoltage; /*!< switch io voltage */ + sd_detect_card_t *cd; /*!< card detect */ + + uint32_t maxFreq; /*!< board support maximum frequency */ + uint32_t capability; /*!< board capability flag */ +} sd_usr_param_t; + +/*! @brief card interrupt function pointer */ +typedef void (*sdio_int_t)(void *userData); + +/*! @brief card interrupt application callback */ +typedef struct _sdio_card_int +{ + void *userData; /*!< user data */ + sdio_int_t cardInterrupt; /*!< card int call back */ +} sdio_card_int_t; + +/*! @brief sdio user parameter */ +typedef struct _sdio_usr_param +{ + sd_pwr_t pwr; /*!< power control configuration pointer */ + uint32_t powerOnDelayMS; /*!< power on delay time */ + uint32_t powerOffDelayMS; /*!< power off delay time */ + + sd_io_strength_t ioStrength; /*!< swicth sd io strength */ + sd_io_voltage_t *ioVoltage; /*!< switch io voltage */ + sd_detect_card_t *cd; /*!< card detect */ + sdio_card_int_t *sdioInt; /*!< card int */ + uint32_t maxFreq; /*!< board support maximum frequency */ + uint32_t capability; /*!< board capability flag */ +} sdio_usr_param_t; + +/*! @brief tuning pattern */ +#if SDMMCHOST_SUPPORT_DDR50 || SDMMCHOST_SUPPORT_SDR104 || SDMMCHOST_SUPPORT_SDR50 || SDMMCHOST_SUPPORT_HS200 || \ + SDMMCHOST_SUPPORT_HS400 +/* sdmmc tuning block */ +extern const uint32_t SDMMC_TuningBlockPattern4Bit[16U]; +extern const uint32_t SDMMC_TuningBlockPattern8Bit[32U]; +#endif + /************************************************************************************************* * API ************************************************************************************************/ #if defined(__cplusplus) -extern "C" -{ +extern "C" { #endif +/*! + * @name common function + * @{ + */ + +/*! + * @brief Selects the card to put it into transfer state. + * + * @param host host handler. + * @param relativeAddress Relative address. + * @param isSelected True to put card into transfer state. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SelectCard(sdmmchost_t *host, uint32_t relativeAddress, bool isSelected); - /*! - * @brief Selects the card to put it into transfer state. - * - * @param base SDMMCHOST peripheral base address. - * @param transfer SDMMCHOST transfer function. - * @param relativeAddress Relative address. - * @param isSelected True to put card into transfer state. - * @retval kStatus_SDMMC_TransferFailed Transfer failed. - * @retval kStatus_Success Operate successfully. - */ - status_t SDMMC_SelectCard(SDMMCHOST_TYPE *base, - SDMMCHOST_TRANSFER_FUNCTION transfer, - uint32_t relativeAddress, - bool isSelected); - - /*! - * @brief Sends an application command. - * - * @param base SDMMCHOST peripheral base address. - * @param transfer SDMMCHOST transfer function. - * @param relativeAddress Card relative address. - * @retval kStatus_SDMMC_TransferFailed Transfer failed. - * @retval kStatus_SDMMC_CardNotSupport Card doesn't support. - * @retval kStatus_Success Operate successfully. - */ - status_t SDMMC_SendApplicationCommand(SDMMCHOST_TYPE *base, - SDMMCHOST_TRANSFER_FUNCTION transfer, - uint32_t relativeAddress); - - /*! - * @brief Sets the block count. - * - * @param base SDMMCHOST peripheral base address. - * @param transfer SDMMCHOST transfer function. - * @param blockCount Block count. - * @retval kStatus_SDMMC_TransferFailed Transfer failed. - * @retval kStatus_Success Operate successfully. - */ - status_t SDMMC_SetBlockCount(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer, uint32_t blockCount); - - /*! - * @brief Sets the card to be idle state. - * - * @param base SDMMCHOST peripheral base address. - * @param transfer SDMMCHOST transfer function. - * @retval kStatus_SDMMC_TransferFailed Transfer failed. - * @retval kStatus_Success Operate successfully. - */ - status_t SDMMC_GoIdle(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer); - - /*! - * @brief Sets data block size. - * - * @param base SDMMCHOST peripheral base address. - * @param transfer SDMMCHOST transfer function. - * @param blockSize Block size. - * @retval kStatus_SDMMC_TransferFailed Transfer failed. - * @retval kStatus_Success Operate successfully. - */ - status_t SDMMC_SetBlockSize(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer, uint32_t blockSize); - - /*! - * @brief Sets card to inactive status - * - * @param base SDMMCHOST peripheral base address. - * @param transfer SDMMCHOST transfer function. - * @retval kStatus_SDMMC_TransferFailed Transfer failed. - * @retval kStatus_Success Operate successfully. - */ - status_t SDMMC_SetCardInactive(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer); - - /*! - * @brief provide a simple delay function for sdmmc - * - * @param num Delay num*10000. - */ - void SDMMC_Delay(uint32_t num); - - /*! - * @brief provide a voltage switch function for SD/SDIO card - * - * @param base SDMMCHOST peripheral base address. - * @param transfer SDMMCHOST transfer function. - */ - status_t SDMMC_SwitchVoltage(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer); - - /*! - * @brief excute tuning - * - * @param base SDMMCHOST peripheral base address. - * @param transfer Host transfer function - * @param tuningCmd Tuning cmd - * @param blockSize Tuning block size - */ - status_t SDMMC_ExecuteTuning(SDMMCHOST_TYPE *base, - SDMMCHOST_TRANSFER_FUNCTION transfer, - uint32_t tuningCmd, - uint32_t blockSize); +/*! + * @brief Sends an application command. + * + * @param host host handler. + * @param relativeAddress Card relative address. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_CardNotSupport Card doesn't support. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SendApplicationCommand(sdmmchost_t *host, uint32_t relativeAddress); + +/*! + * @brief Sets the block count. + * + * @param host host handler. + * @param blockCount Block count. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SetBlockCount(sdmmchost_t *host, uint32_t blockCount); + +/*! + * @brief Sets the card to be idle state. + * + * @param host host handler. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_GoIdle(sdmmchost_t *host); +/*! + * @brief Sets data block size. + * + * @param host host handler. + * @param blockSize Block size. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SetBlockSize(sdmmchost_t *host, uint32_t blockSize); +/*! + * @brief Sets card to inactive status + * + * @param host host handler. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SetCardInactive(sdmmchost_t *host); + +/* @} */ #if defined(__cplusplus) } #endif - +/* @} */ #endif /* _FSL_SDMMC_COMMON_H_ */ diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_host.c b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_host.c index 10d65fc8c08814a96df199e9f31c8cce113b655c..e42b65bbfa7aa71ac54bf55ded997adccb874287 100644 --- a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_host.c +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_host.c @@ -1,58 +1,43 @@ /* - * The Clear BSD License - * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2020 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted (subject to the limitations in the disclaimer below) provided - * that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * o Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_sdmmc_host.h" -#include "board.h" -#include "fsl_sdmmc_event.h" -#include "fsl_gpio.h" -#ifdef BOARD_USDHC_CD_PORT_BASE -#include "fsl_port.h" +#include "fsl_sdmmc_common.h" +#if ((defined __DCACHE_PRESENT) && __DCACHE_PRESENT) || (defined FSL_FEATURE_HAS_L1CACHE && FSL_FEATURE_HAS_L1CACHE) +#if !(defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) +#include "fsl_cache.h" +#endif #endif /******************************************************************************* * Definitions ******************************************************************************/ - +#define SDMMCHOST_TRANSFER_COMPLETE_TIMEOUT (~0U) +#define SDMMCHOST_TRANSFER_CMD_EVENT \ + SDMMC_OSA_EVENT_TRANSFER_CMD_SUCCESS | SDMMC_OSA_EVENT_TRANSFER_CMD_FAIL | SDMMC_OSA_EVENT_TRANSFER_DATA_SUCCESS | \ + SDMMC_OSA_EVENT_TRANSFER_DATA_FAIL +#define SDMMCHOST_TRANSFER_DATA_EVENT SDMMC_OSA_EVENT_TRANSFER_DATA_SUCCESS | SDMMC_OSA_EVENT_TRANSFER_DATA_FAIL /******************************************************************************* * Prototypes ******************************************************************************/ /*! - * @brief SDMMCHOST transfer function. + * @brief SDMMCHOST detect card insert status by host controller. * @param base host base address. - * @param content transfer configurations. + * @param userData user can register a application card insert callback through userData. */ -static status_t SDMMCHOST_TransferFunction(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER *content); +static void SDMMCHOST_DetectCardInsertByHost(USDHC_Type *base, void *userData); + +/*! + * @brief SDMMCHOST detect card remove status by host controller. + * @param base host base address. + * @param userData user can register a application card insert callback through userData. + */ +static void SDMMCHOST_DetectCardRemoveByHost(USDHC_Type *base, void *userData); /*! * @brief SDMMCHOST transfer complete callback. @@ -61,228 +46,990 @@ static status_t SDMMCHOST_TransferFunction(SDMMCHOST_TYPE *base, SDMMCHOST_TRANS * @param status interrupt status. * @param userData user data. */ -static void SDMMCHOST_TransferCompleteCallback(SDMMCHOST_TYPE *base, +static void SDMMCHOST_TransferCompleteCallback(USDHC_Type *base, usdhc_handle_t *handle, status_t status, void *userData); /*! - * @brief SDMMCHOST re-tuning callback + * @brief SDMMCHOST error recovery. * @param base host base address. - * @param userData user can register a application card insert callback through userData. */ -static void SDMMCHOST_ReTuningCallback(SDMMCHOST_TYPE *base, void *userData); +static void SDMMCHOST_ErrorRecovery(USDHC_Type *base); +#if SDMMCHOST_SUPPORT_SDR104 || SDMMCHOST_SUPPORT_SDR50 || SDMMCHOST_SUPPORT_HS200 || SDMMCHOST_SUPPORT_HS400 +/*! + * @brief SDMMCHOST execute manual tuning. + * @param host host handler. + * @param tuningCmd tuning command + * @param revBuf receive buffer pointer + * @param blockSize receive block size + */ +static status_t SDMMCHOST_ExecuteManualTuning(sdmmchost_t *host, + uint32_t tuningCmd, + uint32_t *revBuf, + uint32_t blockSize); +#endif /******************************************************************************* * Variables ******************************************************************************/ -/* DMA descriptor should allocate at non-cached memory */ -// TODO: check this !! I don't think this structure needs alignment and special cache treatment -AT_NONCACHEABLE_SECTION_ALIGN(uint32_t g_usdhcAdma2Table[USDHC_ADMA_TABLE_WORDS], USDHC_ADMA2_ADDR_ALIGN); - -usdhc_handle_t g_usdhcHandle; -volatile bool g_usdhcTransferSuccessFlag = true; -static volatile bool s_sdInsertedFlag = false; -volatile status_t g_reTuningFlag = false; - -/* This variables exists only for testing purposes. I will leave it until code matures. */ -static uint8_t transfer_in_progress = 0; /******************************************************************************* * Code ******************************************************************************/ -static void SDMMCHOST_TransferCompleteCallback(SDMMCHOST_TYPE *base, - usdhc_handle_t *handle, - status_t status, - void *userData) +static void SDMMCHOST_DetectCardInsertByHost(USDHC_Type *base, void *userData) { - /* wait the target status and then notify the transfer complete */ - if (status == kStatus_Success) { - g_usdhcTransferSuccessFlag = true; + sd_detect_card_t *cd = NULL; + + (void)SDMMC_OSAEventSet(&(((sdmmchost_t *)userData)->hostEvent), SDMMC_OSA_EVENT_CARD_INSERTED); + (void)SDMMC_OSAEventClear(&(((sdmmchost_t *)userData)->hostEvent), SDMMC_OSA_EVENT_CARD_REMOVED); + + if (userData != NULL) + { + cd = (sd_detect_card_t *)(((sdmmchost_t *)userData)->cd); + if (cd != NULL) + { + if (cd->callback != NULL) + { + cd->callback(true, cd->userData); + } + if (cd->type == kSD_DetectCardByHostDATA3) + { + USDHC_DisableInterruptSignal(base, kUSDHC_CardInsertionFlag); + if (cd->dat3PullFunc != NULL) + { + cd->dat3PullFunc(kSD_DAT3PullUp); + } + } + else + { + USDHC_EnableInterruptSignal(base, kUSDHC_CardRemovalFlag); + } + } + } +} + +static void SDMMCHOST_DetectCardRemoveByHost(USDHC_Type *base, void *userData) +{ + sd_detect_card_t *cd = NULL; + + (void)SDMMC_OSAEventSet(&(((sdmmchost_t *)userData)->hostEvent), SDMMC_OSA_EVENT_CARD_REMOVED); + (void)SDMMC_OSAEventClear(&(((sdmmchost_t *)userData)->hostEvent), SDMMC_OSA_EVENT_CARD_INSERTED); + + if (userData != NULL) + { + cd = (sd_detect_card_t *)(((sdmmchost_t *)userData)->cd); + if (cd != NULL) + { + if (cd->callback != NULL) + { + cd->callback(false, cd->userData); + } + + if (cd->type == kSD_DetectCardByHostDATA3) + { + USDHC_DisableInterruptSignal(base, kUSDHC_CardRemovalFlag); + if (cd->dat3PullFunc != NULL) + { + cd->dat3PullFunc(kSD_DAT3PullUp); + } + } + else + { + USDHC_EnableInterruptSignal(base, kUSDHC_CardInsertionFlag); + } + } } - else { - g_usdhcTransferSuccessFlag = false; +} + +static void SDMMCHOST_CardInterrupt(USDHC_Type *base, void *userData) +{ + sdio_card_int_t *cardInt = NULL; + + /* application callback */ + if (userData != NULL) + { + cardInt = ((sdmmchost_t *)userData)->cardInt; + if ((cardInt != NULL) && (cardInt->cardInterrupt != NULL)) + { + cardInt->cardInterrupt(cardInt->userData); + } } +} + +status_t SDMMCHOST_CardIntInit(sdmmchost_t *host, void *sdioInt) +{ + host->cardInt = sdioInt; + host->handle.callback.SdioInterrupt = SDMMCHOST_CardInterrupt; + SDMMCHOST_EnableCardInt(host, true); - transfer_in_progress = 0; - portEND_SWITCHING_ISR(SDMMCEVENT_Notify(status)); + return kStatus_Success; } -// TODO: this need to be checked when using HS200 -static void SDMMCHOST_ReTuningCallback(SDMMCHOST_TYPE *base, void *userData) +status_t SDMMCHOST_CardDetectInit(sdmmchost_t *host, void *cd) { - g_reTuningFlag = true; - // SDMMCEVENT_Notify(kSDMMCEVENT_TransferComplete); + USDHC_Type *base = host->hostController.base; + sd_detect_card_t *sdCD = (sd_detect_card_t *)cd; + if ((cd == NULL) || ((sdCD->type != kSD_DetectCardByHostDATA3) && (sdCD->type != kSD_DetectCardByHostCD))) + { + return kStatus_Fail; + } + + host->cd = cd; + host->handle.callback.CardInserted = SDMMCHOST_DetectCardInsertByHost; + host->handle.callback.CardRemoved = SDMMCHOST_DetectCardRemoveByHost; + + /* enable card detect interrupt */ + USDHC_ClearInterruptStatusFlags(base, (uint32_t)kUSDHC_CardInsertionFlag | (uint32_t)kUSDHC_CardRemovalFlag); + USDHC_EnableInterruptStatus(base, (uint32_t)kUSDHC_CardInsertionFlag | (uint32_t)kUSDHC_CardRemovalFlag); + + if (SDMMCHOST_CardDetectStatus(host) == (uint32_t)kSD_Inserted) + { + (void)SDMMC_OSAEventSet(&(host->hostEvent), SDMMC_OSA_EVENT_CARD_INSERTED); + /* notify application about the card insertion status */ + if (sdCD->callback != NULL) + { + sdCD->callback(true, sdCD->userData); + } + } + else + { + (void)SDMMC_OSAEventSet(&(host->hostEvent), SDMMC_OSA_EVENT_CARD_REMOVED); + USDHC_EnableInterruptSignal(base, kUSDHC_CardInsertionFlag); + } + + return kStatus_Success; } -extern uint32_t cntnotify; -extern uint32_t cntwait; +uint32_t SDMMCHOST_CardDetectStatus(sdmmchost_t *host) +{ + sd_detect_card_t *sdCD = (sd_detect_card_t *)(host->cd); + uint32_t insertStatus = kSD_Removed; + + if (sdCD->type == kSD_DetectCardByHostDATA3) + { + if (sdCD->dat3PullFunc != NULL) + { + sdCD->dat3PullFunc(kSD_DAT3PullDown); + SDMMC_OSADelay(SDMMCHOST_DATA3_DETECT_CARD_DELAY); + } + USDHC_CardDetectByData3(host->hostController.base, true); + /* Added 1ms delay after host enabled the DAT3 function to avoid CPU missing synchronization with host */ + SDMMC_OSADelay(SDMMCHOST_DATA3_DETECT_CARD_DELAY); + } + else + { + USDHC_CardDetectByData3(host->hostController.base, false); + } -static status_t SDMMCHOST_TransferFunction(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER *content) + if ((USDHC_GetPresentStatusFlags(host->hostController.base) & (uint32_t)kUSDHC_CardInsertedFlag) != 0U) + { + insertStatus = kSD_Inserted; + + if (sdCD->type == kSD_DetectCardByHostDATA3) + { + if (sdCD->dat3PullFunc != NULL) + { + sdCD->dat3PullFunc(kSD_DAT3PullUp); + } + /* disable the DAT3 card detec function */ + USDHC_CardDetectByData3(host->hostController.base, false); + } + } + + return insertStatus; +} + +status_t SDMMCHOST_PollingCardDetectStatus(sdmmchost_t *host, uint32_t waitCardStatus, uint32_t timeout) { - status_t error = kStatus_Success; + assert(host != NULL); + assert(host->cd != NULL); - usdhc_adma_config_t dmaConfig; + sd_detect_card_t *cd = host->cd; + uint32_t event = 0U; + + if (((waitCardStatus == (uint32_t)kSD_Inserted) && (SDMMCHOST_CardDetectStatus(host) == (uint32_t)kSD_Inserted)) || + (((waitCardStatus == (uint32_t)kSD_Removed) && SDMMCHOST_CardDetectStatus(host) == (uint32_t)kSD_Removed))) + { + return kStatus_Success; + } - if (SDMMCEVENT_Lock(500) == false) { - return kStatus_Timeout; + (void)SDMMC_OSAEventClear(&(host->hostEvent), SDMMC_OSA_EVENT_CARD_INSERTED | SDMMC_OSA_EVENT_CARD_REMOVED); + + if (cd->type == kSD_DetectCardByHostDATA3) + { + if (cd->dat3PullFunc != NULL) + { + cd->dat3PullFunc(kSD_DAT3PullDown); + } + USDHC_ClearInterruptStatusFlags(host->hostController.base, + (uint32_t)kUSDHC_CardInsertionFlag | (uint32_t)kUSDHC_CardRemovalFlag); + USDHC_EnableInterruptSignal(host->hostController.base, waitCardStatus == (uint32_t)kSD_Inserted ? + (uint32_t)kUSDHC_CardInsertionFlag : + (uint32_t)kUSDHC_CardRemovalFlag); } - if (transfer_in_progress) { - assert(0); + /* Wait card inserted. */ + do + { + if (SDMMC_OSAEventWait(&(host->hostEvent), SDMMC_OSA_EVENT_CARD_INSERTED | SDMMC_OSA_EVENT_CARD_REMOVED, + timeout, &event) != kStatus_Success) + { + return kStatus_Fail; + } + else + { + if ((waitCardStatus == (uint32_t)kSD_Inserted) && + ((event & SDMMC_OSA_EVENT_CARD_INSERTED) == SDMMC_OSA_EVENT_CARD_INSERTED)) + { + SDMMC_OSADelay(cd->cdDebounce_ms); + if (SDMMCHOST_CardDetectStatus(host) == (uint32_t)kSD_Inserted) + { + break; + } + } + + if (((event & SDMMC_OSA_EVENT_CARD_REMOVED) == SDMMC_OSA_EVENT_CARD_REMOVED) && + (waitCardStatus == (uint32_t)kSD_Removed)) + { + break; + } + } + } while (true); + + return kStatus_Success; +} + +void SDMMCHOST_ConvertDataToLittleEndian(sdmmchost_t *host, uint32_t *data, uint32_t wordSize, uint32_t format) +{ + uint32_t temp = 0U; + + if (((uint32_t)host->hostController.config.endianMode == (uint32_t)kSDMMCHOST_EndianModeLittle) && + (format == (uint32_t)kSDMMC_DataPacketFormatMSBFirst)) + { + for (uint32_t i = 0U; i < wordSize; i++) + { + temp = data[i]; + data[i] = SWAP_WORD_BYTE_SEQUENCE(temp); + } + } + else if ((uint32_t)host->hostController.config.endianMode == (uint32_t)kSDMMCHOST_EndianModeHalfWordBig) + { + for (uint32_t i = 0U; i < wordSize; i++) + { + temp = data[i]; + data[i] = SWAP_HALF_WROD_BYTE_SEQUENCE(temp); + } + } + else if (((uint32_t)host->hostController.config.endianMode == (uint32_t)kSDMMCHOST_EndianModeBig) && + (format == (uint32_t)kSDMMC_DataPacketFormatLSBFirst)) + { + for (uint32_t i = 0U; i < wordSize; i++) + { + temp = data[i]; + data[i] = SWAP_WORD_BYTE_SEQUENCE(temp); + } + } + else + { + /* nothing to do */ + } +} + +static void SDMMCHOST_TransferCompleteCallback(USDHC_Type *base, + usdhc_handle_t *handle, + status_t status, + void *userData) +{ + uint32_t eventStatus = 0U; + + if (status == kStatus_USDHC_TransferDataFailed) + { + eventStatus = SDMMC_OSA_EVENT_TRANSFER_DATA_FAIL; + } + else if (status == kStatus_USDHC_TransferDataComplete) + { + eventStatus = SDMMC_OSA_EVENT_TRANSFER_DATA_SUCCESS; + } + else if (status == kStatus_USDHC_SendCommandFailed) + { + eventStatus = SDMMC_OSA_EVENT_TRANSFER_CMD_FAIL; + } + else if (status == kStatus_USDHC_TransferDMAComplete) + { + eventStatus = SDMMC_OSA_EVENT_TRANSFER_DMA_COMPLETE; + } + else + { + eventStatus = SDMMC_OSA_EVENT_TRANSFER_CMD_SUCCESS; } - transfer_in_progress = 1; - assert(cntnotify == cntwait); + (void)SDMMC_OSAEventSet(&(((sdmmchost_t *)userData)->hostEvent), eventStatus); +} + +#if defined SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER && SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER +void SDMMCHOST_InstallCacheAlignBuffer(sdmmchost_t *host, void *cacheAlignBuffer, uint32_t cacheAlignBufferSize) +{ + assert(((uint32_t)cacheAlignBuffer & (SDMMC_DATA_BUFFER_ALIGN_CACHE - 1)) == 0U); + assert(cacheAlignBufferSize >= SDMMC_DATA_BUFFER_ALIGN_CACHE * 2U); + + host->cacheAlignBuffer = cacheAlignBuffer; + host->cacheAlignBufferSize = cacheAlignBufferSize; +} +#endif + +status_t SDMMCHOST_TransferFunction(sdmmchost_t *host, sdmmchost_transfer_t *content) +{ + status_t error = kStatus_Success; + uint32_t event = 0U; + usdhc_adma_config_t dmaConfig; + +#if defined SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER && SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER + usdhc_scatter_gather_data_list_t sgDataList0; + usdhc_scatter_gather_data_list_t sgDataList1; + usdhc_scatter_gather_data_t scatterGatherData; + uint32_t unAlignSize = 0U; + usdhc_scatter_gather_transfer_t transfer = {.data = NULL, .command = content->command}; +#endif + + (void)SDMMC_OSAMutexLock(&host->lock, osaWaitForever_c); - if (content->data != NULL) { - memset(&dmaConfig, 0, sizeof(usdhc_adma_config_t)); + if (content->data != NULL) + { + (void)memset(&dmaConfig, 0, sizeof(usdhc_adma_config_t)); /* config adma */ - dmaConfig.dmaMode = USDHC_DMA_MODE; - dmaConfig.burstLen = kUSDHC_EnBurstLenForINCR; - dmaConfig.admaTable = g_usdhcAdma2Table; - dmaConfig.admaTableWords = USDHC_ADMA_TABLE_WORDS; + dmaConfig.dmaMode = SDMMCHOST_DMA_MODE; +#if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) + dmaConfig.burstLen = kUSDHC_EnBurstLenForINCR; +#endif + dmaConfig.admaTable = host->dmaDesBuffer; + dmaConfig.admaTableWords = host->dmaDesBufferWordsNum; + +#if defined SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER && SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER + + if ((host->cacheAlignBuffer == NULL) || ((host->cacheAlignBufferSize == 0U))) + { + /* application should register cache line size align buffer for host driver maintain the unalign data + * transfer */ + assert(false); + return kStatus_InvalidArgument; + } + + scatterGatherData.enableAutoCommand12 = content->data->enableAutoCommand12; + scatterGatherData.enableAutoCommand23 = content->data->enableAutoCommand23; + scatterGatherData.enableIgnoreError = content->data->enableIgnoreError; + scatterGatherData.dataType = content->data->dataType; + scatterGatherData.blockSize = content->data->blockSize; + + transfer.data = &scatterGatherData; + + if (content->data->rxData != NULL) + { + scatterGatherData.sgData.dataAddr = content->data->rxData; + scatterGatherData.dataDirection = kUSDHC_TransferDirectionReceive; + } + else + { + scatterGatherData.sgData.dataAddr = (uint32_t *)content->data->txData; + scatterGatherData.dataDirection = kUSDHC_TransferDirectionSend; + } + scatterGatherData.sgData.dataSize = content->data->blockSize * content->data->blockCount; + scatterGatherData.sgData.dataList = NULL; + + /* + * If the receive transfer buffer address is not cache line size align, such as + *--------------------------------------------------------------------- + *| unalign head region| align region | unaling tail region| + *--------------------------------------------------------------------- + * + * Then host driver will splict it into three scatter gather transfers, + * 1. host->cacheAlignBuffer will be used as first scatter gather data address, the data size is the unalign + *head region size. + * 2. align region start address will be used as second scatter gather data address, the data size is the align + *region size. + * 3. (uint32_t *)((uint32_t)host->cacheAlignBuffer + SDMMC_DATA_BUFFER_ALIGN_CACHE) + * will be used as third scatter gather data address, the data size is the unaling tail region size. + * + * Once scatter gather transfer done, + * 1. host driver will invalidate the cache for the data buffer in the scatter gather transfer list + * 2. host driver will copy data from host->cacheAlignBuffer to unalign head region + * 3. host driver will copy data from (uint32_t *)((uint32_t)host->cacheAlignBuffer + + *SDMMC_DATA_BUFFER_ALIGN_CACHE) to unalign tail region + * + * At last, cache line unalign transfer done + */ + if ((content->data->rxData != NULL) && + (((uint32_t)content->data->rxData % SDMMC_DATA_BUFFER_ALIGN_CACHE) != 0U)) + { + unAlignSize = ((uint32_t)content->data->rxData - + (((uint32_t)content->data->rxData) & (~(SDMMC_DATA_BUFFER_ALIGN_CACHE - 1)))); + sgDataList1.dataSize = unAlignSize; + unAlignSize = SDMMC_DATA_BUFFER_ALIGN_CACHE - unAlignSize; + + scatterGatherData.sgData.dataAddr = host->cacheAlignBuffer; + scatterGatherData.sgData.dataSize = unAlignSize; + scatterGatherData.sgData.dataList = &sgDataList0; + + sgDataList0.dataAddr = + (void *)((((uint32_t)content->data->rxData) & (~(SDMMC_DATA_BUFFER_ALIGN_CACHE - 1))) + + SDMMC_DATA_BUFFER_ALIGN_CACHE); + sgDataList0.dataSize = content->data->blockCount * content->data->blockSize - SDMMC_DATA_BUFFER_ALIGN_CACHE; + sgDataList0.dataList = &sgDataList1; + sgDataList1.dataAddr = (uint32_t *)((uint32_t)host->cacheAlignBuffer + SDMMC_DATA_BUFFER_ALIGN_CACHE); + sgDataList1.dataList = NULL; + } +#endif + +#if ((defined __DCACHE_PRESENT) && __DCACHE_PRESENT) || (defined FSL_FEATURE_HAS_L1CACHE && FSL_FEATURE_HAS_L1CACHE) +#if !(defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) + if (host->enableCacheControl == kSDMMCHOST_CacheControlRWBuffer) + { + /* no matter read or write transfer, clean the cache line anyway to avoid data miss */ + DCACHE_CleanByRange( + (uint32_t)(content->data->txData == NULL ? content->data->rxData : content->data->txData), + (content->data->blockSize) * (content->data->blockCount)); + } +#endif +#endif } - do { - error = USDHC_TransferNonBlocking(base, &g_usdhcHandle, &dmaConfig, content); - } while (error == kStatus_USDHC_BusyTransferring); + /* clear redundant transfer event flag */ + (void)SDMMC_OSAEventClear(&(host->hostEvent), SDMMCHOST_TRANSFER_CMD_EVENT); + +#if defined SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER && SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER + error = USDHC_TransferScatterGatherADMANonBlocking(host->hostController.base, &host->handle, &dmaConfig, &transfer); +#else + error = USDHC_TransferNonBlocking(host->hostController.base, &host->handle, &dmaConfig, content); +#endif + + if (error == kStatus_Success) + { + /* wait command event */ + if ((kStatus_Fail == SDMMC_OSAEventWait(&(host->hostEvent), SDMMCHOST_TRANSFER_CMD_EVENT, + SDMMCHOST_TRANSFER_COMPLETE_TIMEOUT, &event)) || + ((event & SDMMC_OSA_EVENT_TRANSFER_CMD_FAIL) != 0U)) + { + error = kStatus_Fail; + } + else + { + if (content->data != NULL) + { + if ((event & SDMMC_OSA_EVENT_TRANSFER_DATA_SUCCESS) == 0U) + { + if (((event & SDMMC_OSA_EVENT_TRANSFER_DATA_FAIL) != 0U) || + (kStatus_Fail == SDMMC_OSAEventWait(&(host->hostEvent), SDMMCHOST_TRANSFER_DATA_EVENT, + SDMMCHOST_TRANSFER_COMPLETE_TIMEOUT, &event) || + ((event & SDMMC_OSA_EVENT_TRANSFER_DATA_FAIL) != 0U))) + { + error = kStatus_Fail; + } + } + } + } + } - if (error != kStatus_Success) { - SDMMCEVENT_Delete(); + if (error != kStatus_Success) + { /* host error recovery */ - SDMMCHOST_ErrorRecovery(base); - SDMMCEVENT_Unlock(); - return error; + SDMMCHOST_ErrorRecovery(host->hostController.base); } + else + { + if ((content->data != NULL) && (content->data->rxData != NULL)) + { +#if defined SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER && SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER + if (((uint32_t)content->data->rxData % SDMMC_DATA_BUFFER_ALIGN_CACHE) != 0U) + { +#if ((defined __DCACHE_PRESENT) && __DCACHE_PRESENT) || (defined FSL_FEATURE_HAS_L1CACHE && FSL_FEATURE_HAS_L1CACHE) +#if !(defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) + if (host->enableCacheControl == kSDMMCHOST_CacheControlRWBuffer) + { + DCACHE_InvalidateByRange((uint32_t)scatterGatherData.sgData.dataAddr, + scatterGatherData.sgData.dataSize); - bool ret = SDMMCEVENT_Wait(SDMMCHOST_TRANSFER_COMPLETE_TIMEOUT); + DCACHE_InvalidateByRange((uint32_t)sgDataList0.dataAddr, sgDataList0.dataSize); - if ((!ret) || (g_usdhcTransferSuccessFlag == false)) { - SDMMCEVENT_Delete(); - /* host error recovery */ - SDMMCHOST_ErrorRecovery(base); - SDMMCEVENT_Unlock(); - return kStatus_Fail; + DCACHE_InvalidateByRange((uint32_t)sgDataList1.dataAddr, sgDataList1.dataSize); + } +#endif +#endif + memcpy(content->data->rxData, scatterGatherData.sgData.dataAddr, scatterGatherData.sgData.dataSize); + memcpy((void *)((uint32_t)content->data->rxData + content->data->blockCount * content->data->blockSize - + sgDataList1.dataSize), + sgDataList1.dataAddr, sgDataList1.dataSize); + } + else +#endif + { +#if ((defined __DCACHE_PRESENT) && __DCACHE_PRESENT) || (defined FSL_FEATURE_HAS_L1CACHE && FSL_FEATURE_HAS_L1CACHE) +#if !(defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) + /* invalidate the cache for read */ + if (host->enableCacheControl == kSDMMCHOST_CacheControlRWBuffer) + { + DCACHE_InvalidateByRange((uint32_t)content->data->rxData, + (content->data->blockSize) * (content->data->blockCount)); + } +#endif +#endif + } + } } - SDMMCEVENT_Unlock(); + (void)SDMMC_OSAMutexUnlock(&host->lock); return error; } -void SDMMCHOST_ErrorRecovery(SDMMCHOST_TYPE *base) +static void SDMMCHOST_ErrorRecovery(USDHC_Type *base) { uint32_t status = 0U; /* get host present status */ status = USDHC_GetPresentStatusFlags(base); /* check command inhibit status flag */ - if ((status & kUSDHC_CommandInhibitFlag) != 0U) { + if ((status & (uint32_t)kUSDHC_CommandInhibitFlag) != 0U) + { /* reset command line */ - USDHC_Reset(base, kUSDHC_ResetCommand, 100U); + (void)USDHC_Reset(base, kUSDHC_ResetCommand, 100U); } /* check data inhibit status flag */ - if ((status & kUSDHC_DataInhibitFlag) != 0U) { + if (((status & (uint32_t)kUSDHC_DataInhibitFlag) != 0U) || (USDHC_GetAdmaErrorStatusFlags(base) != 0U)) + { /* reset data line */ - USDHC_Reset(base, kUSDHC_ResetData, 100U); + (void)USDHC_Reset(base, kUSDHC_ResetData, 100U); } } -void SDMMCHOST_Delay(uint32_t milliseconds) +void SDMMCHOST_SetCardPower(sdmmchost_t *host, bool enable) { - SDMMCEVENT_Delay(milliseconds); + /* host not support */ } -void SDMMCHOST_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +void SDMMCHOST_SetCardBusWidth(sdmmchost_t *host, uint32_t dataBusWidth) { - if (pwr != NULL) { - pwr->powerOff(); - SDMMCHOST_Delay(pwr->powerOffDelay_ms); - } - else { - /* only SD card need card detect*/ - SDMMCHOST_ENABLE_SD_POWER(false); - /* Delay several milliseconds to make card stable. */ - SDMMCHOST_Delay(100U); - } + USDHC_SetDataBusWidth(host->hostController.base, dataBusWidth == (uint32_t)kSDMMC_BusWdith1Bit ? + kUSDHC_DataBusWidth1Bit : + dataBusWidth == (uint32_t)kSDMMC_BusWdith4Bit ? + kUSDHC_DataBusWidth4Bit : + kUSDHC_DataBusWidth8Bit); } -void SDMMCHOST_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +status_t SDMMCHOST_Init(sdmmchost_t *host) { - /* use user define the power on function */ - if (pwr != NULL) { - pwr->powerOn(); - SDMMCHOST_Delay(pwr->powerOnDelay_ms); + assert(host != NULL); + + usdhc_transfer_callback_t usdhcCallback = {0}; + usdhc_host_t *usdhcHost = &(host->hostController); +#if defined FSL_FEATURE_USDHC_INSTANCE_SUPPORT_8_BIT_WIDTHn + uint32_t bus8bitCapability = (uint32_t)FSL_FEATURE_USDHC_INSTANCE_SUPPORT_8_BIT_WIDTHn(host->hostController.base); +#else + uint32_t bus8bitCapability = 0U; +#endif + +#if (defined(FSL_FEATURE_USDHC_HAS_HS400_MODE) && (FSL_FEATURE_USDHC_HAS_HS400_MODE)) +#if defined FSL_FEATURE_USDHC_INSTANCE_SUPPORT_HS400_MODEn + uint32_t hs400Capability = (uint32_t)FSL_FEATURE_USDHC_INSTANCE_SUPPORT_HS400_MODEn(host->hostController.base); +#else + uint32_t hs400Capability = 0U; +#endif +#endif + +#if defined FSL_FEATURE_USDHC_INSTANCE_SUPPORT_1V8_SIGNALn + uint32_t voltage1v8Capability = (uint32_t)FSL_FEATURE_USDHC_INSTANCE_SUPPORT_1V8_SIGNALn(host->hostController.base); +#else + uint32_t voltage1v8Capability = 0U; +#endif + status_t error = kStatus_Success; + /* sdmmc osa init */ + + host->capability = (uint32_t)kSDMMCHOST_SupportHighSpeed | (uint32_t)kSDMMCHOST_SupportSuspendResume | + (uint32_t)kSDMMCHOST_SupportVoltage3v3 | (uint32_t)kSDMMCHOST_SupportVoltage1v8 | + (uint32_t)kSDMMCHOST_SupportVoltage1v2 | (uint32_t)kSDMMCHOST_Support4BitDataWidth | + (uint32_t)kSDMMCHOST_SupportDDRMode | (uint32_t)kSDMMCHOST_SupportDetectCardByData3 | + (uint32_t)kSDMMCHOST_SupportDetectCardByCD | (uint32_t)kSDMMCHOST_SupportAutoCmd12; + + if (bus8bitCapability != 0U) + { + host->capability |= (uint32_t)kSDMMCHOST_Support8BitDataWidth; + } + + if (voltage1v8Capability != 0U) + { +#if (defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && (FSL_FEATURE_USDHC_HAS_SDR104_MODE)) + host->capability |= (uint32_t)kSDMMCHOST_SupportSDR104; +#endif + +#if (defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)) + host->capability |= (uint32_t)kSDMMCHOST_SupportSDR50 | (uint32_t)kSDMMCHOST_SupportHS200; +#endif } - else { - /* card power on */ - SDMMCHOST_ENABLE_SD_POWER(true); - /* Delay several milliseconds to make card stable. */ - SDMMCHOST_Delay(300U); + +#if (defined(FSL_FEATURE_USDHC_HAS_HS400_MODE) && (FSL_FEATURE_USDHC_HAS_HS400_MODE)) + if (hs400Capability != 0U) + { + host->capability |= (uint32_t)kSDMMCHOST_SupportHS400; } -} +#endif + host->maxBlockCount = SDMMCHOST_SUPPORT_MAX_BLOCK_COUNT; + host->maxBlockSize = SDMMCHOST_SUPPORT_MAX_BLOCK_LENGTH; -status_t SDMMCHOST_Init(SDMMCHOST_CONFIG *host, void *userData) -{ - usdhc_host_t *usdhcHost = (usdhc_host_t *)host; - usdhc_transfer_callback_t callback = { - .TransferComplete = SDMMCHOST_TransferCompleteCallback, - .ReTuning = SDMMCHOST_ReTuningCallback, - .CardInserted = NULL, /* Not used for eMMC */ - .CardRemoved = NULL, /* Not used for eMMC */ - .SdioInterrupt = NULL, - .BlockGap = NULL, - }; - /* init card power control */ - SDMMCHOST_INIT_SD_POWER(); - - SDMMCHOST_PowerOffCard(host->base, NULL); - SDMMCHOST_PowerOnCard(host->base, NULL); + (void)SDMMC_OSAMutexCreate(&host->lock); + (void)SDMMC_OSAMutexLock(&host->lock, osaWaitForever_c); /* Initializes USDHC. */ - usdhcHost->config.dataTimeout = USDHC_DATA_TIMEOUT; - usdhcHost->config.endianMode = USDHC_ENDIAN_MODE; - usdhcHost->config.readWatermarkLevel = USDHC_READ_WATERMARK_LEVEL; - usdhcHost->config.writeWatermarkLevel = USDHC_WRITE_WATERMARK_LEVEL; - usdhcHost->config.readBurstLen = USDHC_READ_BURST_LEN; - usdhcHost->config.writeBurstLen = USDHC_WRITE_BURST_LEN; - + usdhcHost->config.endianMode = kUSDHC_EndianModeLittle; + usdhcHost->config.dataTimeout = 0xFU; + usdhcHost->config.readWatermarkLevel = 0x80U; + usdhcHost->config.writeWatermarkLevel = 0x80U; USDHC_Init(usdhcHost->base, &(usdhcHost->config)); - /* disable the card insert/remove interrupt, due to use GPIO interrupt detect card */ - USDHC_DisableInterruptSignal(usdhcHost->base, kUSDHC_CardRemovalFlag | kUSDHC_CardInsertionFlag); - // TODO: change USDHC1_IRQn to sth different - SDMMCHOST_SET_IRQ_PRIORITY(USDHC2_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY); - /* create interrupt handler */ - USDHC_TransferCreateHandle(usdhcHost->base, &g_usdhcHandle, &callback, userData); - /* Create transfer complete event. */ - if (false == SDMMCEVENT_Create()) { - return kStatus_Fail; + /* Create handle for SDHC driver */ + usdhcCallback.TransferComplete = SDMMCHOST_TransferCompleteCallback; + USDHC_TransferCreateHandle(usdhcHost->base, &host->handle, &usdhcCallback, host); + + /* Create transfer event. */ + if (kStatus_Success != SDMMC_OSAEventCreate(&(host->hostEvent))) + { + error = kStatus_Fail; } - /* Define transfer function. */ - usdhcHost->transfer = SDMMCHOST_TransferFunction; + (void)SDMMC_OSAMutexUnlock(&host->lock); - return kStatus_Success; + return error; } -void SDMMCHOST_Reset(SDMMCHOST_TYPE *base) +void SDMMCHOST_Reset(sdmmchost_t *host) { + USDHC_Type *base = host->hostController.base; + + (void)SDMMC_OSAMutexLock(&host->lock, osaWaitForever_c); + +#if SDMMCHOST_SUPPORT_VOLTAGE_CONTROL /* voltage switch to normal but not 1.8V */ - SDMMCHOST_SWITCH_VOLTAGE180V(base, false); + UDSHC_SelectVoltage(base, false); +#endif /* Disable DDR mode */ - SDMMCHOST_ENABLE_DDR_MODE(base, false, 0U); + USDHC_EnableDDRMode(base, false, 0U); /* disable tuning */ - SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, false); +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) + USDHC_EnableStandardTuning(base, 0, 0, false); + USDHC_EnableAutoTuning(host->hostController.base, false); +#endif + +#if FSL_FEATURE_USDHC_HAS_HS400_MODE /* Disable HS400 mode */ - SDMMCHOST_ENABLE_HS400_MODE(base, false); + USDHC_EnableHS400Mode(base, false); /* Disable DLL */ - SDMMCHOST_ENABLE_STROBE_DLL(base, false); + USDHC_EnableStrobeDLL(base, false); +#endif + /* reset data/command/tuning circuit */ + (void)USDHC_Reset(base, kUSDHC_ResetAll, 100U); + + USDHC_DisableInterruptSignal(base, kUSDHC_AllInterruptFlags); + + (void)SDMMC_OSAMutexUnlock(&host->lock); +} + +void SDMMCHOST_Deinit(sdmmchost_t *host) +{ + (void)SDMMC_OSAMutexLock(&host->lock, osaWaitForever_c); + usdhc_host_t *sdhcHost = &host->hostController; + SDMMCHOST_Reset(host); + USDHC_Deinit(sdhcHost->base); + (void)SDMMC_OSAEventDestroy(&(host->hostEvent)); + (void)SDMMC_OSAMutexDestroy(&host->lock); +} + +void SDMMCHOST_SwitchToVoltage(sdmmchost_t *host, uint32_t voltage) +{ +#if !(defined(FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT) && (FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT)) + if (voltage == (uint32_t)kSDMMC_OperationVoltage180V) + { + UDSHC_SelectVoltage(host->hostController.base, true); + } + else + { + UDSHC_SelectVoltage(host->hostController.base, false); + } +#endif +} + +#if SDMMCHOST_SUPPORT_SDR104 || SDMMCHOST_SUPPORT_SDR50 || SDMMCHOST_SUPPORT_HS200 || SDMMCHOST_SUPPORT_HS400 +static status_t SDMMCHOST_ExecuteStdTuning(sdmmchost_t *host, uint32_t tuningCmd, uint32_t *revBuf, uint32_t blockSize) +{ + sdmmchost_transfer_t content = {0U}; + sdmmchost_cmd_t command = {0U}; + sdmmchost_data_t data = {0U}; + bool tuningError = true; + status_t error = kStatus_Success; + + command.index = tuningCmd; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR1; + + data.blockSize = blockSize; + data.blockCount = 1U; + data.rxData = revBuf; + data.dataType = kUSDHC_TransferDataTuning; + + content.command = &command; + content.data = &data; + + (void)USDHC_Reset(host->hostController.base, kUSDHC_ResetTuning, 100U); + USDHC_ForceClockOn(host->hostController.base, true); + /* disable standard tuning */ + USDHC_EnableStandardTuning(host->hostController.base, SDMMCHOST_STANDARD_TUNING_START, SDMMCHOST_TUINIG_STEP, + false); + /* + * Tuning fail found on some SOCS caused by the difference of delay cell, so we need to i + * ncrease the tuning counter to cover the adjustable tuninig window + */ + USDHC_SetStandardTuningCounter(host->hostController.base, SDMMCHOST_STANDARD_TUNING_COUNTER); + /* enable the standard tuning */ + USDHC_EnableStandardTuning(host->hostController.base, SDMMCHOST_STANDARD_TUNING_START, SDMMCHOST_TUINIG_STEP, true); + + while (true) + { + error = SDMMCHOST_TransferFunction(host, &content); + /* send tuning block */ + if (kStatus_Success != error) + { + return kStatus_SDMMC_TransferFailed; + } + SDMMC_OSADelay(1U); + + /*wait excute tuning bit clear*/ + if ((USDHC_GetExecuteStdTuningStatus(host->hostController.base) != 0U)) + { + continue; + } + + /* if tuning error , re-tuning again */ + if ((USDHC_CheckTuningError(host->hostController.base) != 0U) && tuningError) + { + tuningError = false; + /* enable the standard tuning */ + USDHC_EnableStandardTuning(host->hostController.base, SDMMCHOST_STANDARD_TUNING_START, + SDMMCHOST_TUINIG_STEP, true); + (void)USDHC_SetTuningDelay(host->hostController.base, SDMMCHOST_STANDARD_TUNING_START, 0U, 0U); + } + else + { + break; + } + } + + /* check tuning result*/ + if (USDHC_CheckStdTuningResult(host->hostController.base) == 0U) + { + return kStatus_SDMMC_TuningFail; + } + USDHC_ForceClockOn(host->hostController.base, false); + USDHC_EnableAutoTuning(host->hostController.base, true); + + return kStatus_Success; } -void SDMMCHOST_Deinit(void *host) +static status_t SDMMC_CheckTuningResult(uint32_t *tuningWindow, uint32_t *validWindowStart, uint32_t *validWindowEnd) { - usdhc_host_t *usdhcHost = (usdhc_host_t *)host; - SDMMCHOST_Reset(usdhcHost->base); - USDHC_Deinit(usdhcHost->base); + uint32_t tempValidWindowLen = 0U, tempValidWindowStart = 0U, tempValidWindowEnd = 0U; + uint32_t validWindowLenMax = 0U, ValidWindowStartMax = 0U, validWindowEndMax = 0U; + + for (uint32_t i = 0U; i < SDMMCHOST_MAX_TUNING_DELAY_CELL; i++) + { + if ((tuningWindow[i / 32U] & (1UL << (i % 32U))) != 0U) + { + if (tempValidWindowLen == 0U) + { + tempValidWindowStart = i; + } + tempValidWindowLen++; + } + else + { + if (tempValidWindowLen != 0U) + { + tempValidWindowEnd = i - 1U; + +#if defined SDMMC_ENABLE_LOG_PRINT + SDMMC_LOG("valid tuning window start: %d, end: %d\r\n", tempValidWindowStart, tempValidWindowEnd); +#endif + if (tempValidWindowLen > validWindowLenMax) + { + validWindowLenMax = tempValidWindowLen; + ValidWindowStartMax = tempValidWindowStart; + validWindowEndMax = tempValidWindowEnd; + } + tempValidWindowLen = 0U; + } + } + } + + if (validWindowLenMax == 0U) + { + return kStatus_Fail; + } + + *validWindowStart = ValidWindowStartMax; + *validWindowEnd = validWindowEndMax; + + return kStatus_Success; +} + +static status_t SDMMCHOST_ExecuteManualTuning(sdmmchost_t *host, + uint32_t tuningCmd, + uint32_t *revBuf, + uint32_t blockSize) +{ + uint32_t *buffer = revBuf; + status_t ret = kStatus_Success; + uint32_t tuningDelayCell = 0U; + uint32_t tuningWindow[4] = {0U}, tuningWindowStart = 0U, tuningWindowEnd = 0U; + + sdmmchost_transfer_t content = {0U}; + sdmmchost_cmd_t command = {0U}; + sdmmchost_data_t data = {0U}; + + command.index = tuningCmd; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR1; + + data.blockSize = blockSize; + data.blockCount = 1U; + data.rxData = revBuf; + + content.command = &command; + content.data = &data; + + (void)USDHC_Reset(host->hostController.base, kUSDHC_ResetAll, 100U); + USDHC_EnableManualTuning(host->hostController.base, true); + USDHC_ForceClockOn(host->hostController.base, true); + + while (true) + { + (void)USDHC_SetTuningDelay(host->hostController.base, tuningDelayCell, 0U, 0U); + + if ((SDMMCHOST_TransferFunction(host, &content) == kStatus_Success) && + (((uint32_t)kUSDHC_TuningPassFlag & USDHC_GetInterruptStatusFlags(host->hostController.base)) != 0U)) + { + USDHC_ClearInterruptStatusFlags(host->hostController.base, kUSDHC_TuningPassFlag); + tuningWindow[tuningDelayCell / 32U] |= 1UL << (tuningDelayCell % 32U); + +#if defined SDMMC_ENABLE_LOG_PRINT + SDMMC_LOG("tuning pass point: %d\r\n", tuningDelayCell); +#endif + } + else + { +#if defined SDMMC_ENABLE_LOG_PRINT + SDMMC_LOG("tuning fail point: %d\r\n", tuningDelayCell); +#endif + } + + if (++tuningDelayCell >= SDMMCHOST_MAX_TUNING_DELAY_CELL) + { + break; + } + + (void)memset(buffer, 0, blockSize); + + SDMMC_OSADelay(2U); + } + + /* After the whole 0-128 delay cell validated, tuning result information stored in tuningWindow, this function will + check the valid winddow and will select a longest window as the final tuning delay setting */ + if (SDMMC_CheckTuningResult(tuningWindow, &tuningWindowStart, &tuningWindowEnd) == kStatus_Fail) + { + return kStatus_Fail; + } + + /* abort tuning */ + USDHC_EnableManualTuning(host->hostController.base, false); + USDHC_ForceClockOn(host->hostController.base, false); + (void)USDHC_Reset(host->hostController.base, kUSDHC_ResetAll, 100U); + + /* select middle position of the window */ + (void)USDHC_SetTuningDelay(host->hostController.base, (tuningWindowStart + tuningWindowEnd) / 2U - 3U, 3U, 3U); + tuningDelayCell = ((tuningWindowStart + tuningWindowEnd) / 2U - 3U) << 8U | 0x33U; + /* wait the tuning delay value write successfully */ + while ((USDHC_GetTuningDelayStatus(host->hostController.base) & tuningDelayCell) != tuningDelayCell) + { + } + /* enable auto tuning */ + USDHC_EnableAutoTuning(host->hostController.base, true); + + return ret; +} +#endif + +status_t SDMMCHOST_ExecuteTuning(sdmmchost_t *host, uint32_t tuningCmd, uint32_t *revBuf, uint32_t blockSize) +{ +#if SDMMCHOST_SUPPORT_SDR104 || SDMMCHOST_SUPPORT_SDR50 || SDMMCHOST_SUPPORT_HS200 || SDMMCHOST_SUPPORT_HS400 + if (host->tuningType == (uint32_t)kSDMMCHOST_StandardTuning) + { + return SDMMCHOST_ExecuteStdTuning(host, tuningCmd, revBuf, blockSize); + } + + return SDMMCHOST_ExecuteManualTuning(host, tuningCmd, revBuf, blockSize); +#else + return kStatus_SDMMC_NotSupportYet; +#endif +} + +status_t SDMMCHOST_StartBoot(sdmmchost_t *host, + sdmmchost_boot_config_t *hostConfig, + sdmmchost_cmd_t *cmd, + uint8_t *buffer) +{ + sdmmchost_transfer_t content = {0}; + sdmmchost_data_t data = {0}; + status_t error = kStatus_Success; + + USDHC_SetMmcBootConfig(host->hostController.base, hostConfig); + + data.blockSize = hostConfig->blockSize; + data.blockCount = hostConfig->blockCount; + data.rxData = (uint32_t *)(uint32_t)buffer; + data.dataType = kUSDHC_TransferDataBoot; + + content.data = &data; + content.command = cmd; + + error = SDMMCHOST_TransferFunction(host, &content); + /* should check tuning error during every transfer*/ + if (kStatus_Success != error) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDMMCHOST_ReadBootData(sdmmchost_t *host, sdmmchost_boot_config_t *hostConfig, uint8_t *buffer) +{ + sdmmchost_cmd_t command = {0}; + sdmmchost_transfer_t content = {0}; + sdmmchost_data_t data = {0}; + status_t error = kStatus_Success; + + USDHC_SetMmcBootConfig(host->hostController.base, hostConfig); + USDHC_EnableMmcBoot(host->hostController.base, true); + + data.blockSize = hostConfig->blockSize; + data.blockCount = hostConfig->blockCount; + data.rxData = (uint32_t *)(uint32_t)buffer; + data.dataType = kUSDHC_TransferDataBootcontinous; + /* no command should be send out */ + command.type = kCARD_CommandTypeEmpty; + + content.data = &data; + content.command = &command; + + error = SDMMCHOST_TransferFunction(host, &content); + if (kStatus_Success != error) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; } diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_host.h b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_host.h index 9194a075863db53946d505260259874959bc3ca7..f159992bc630e3f16490182f6caab9d87c3691c6 100644 --- a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_host.h +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_host.h @@ -1,761 +1,512 @@ /* - * The Clear BSD License - * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2020 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted (subject to the limitations in the disclaimer below) provided - * that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * o Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _FSL_SDMMC_HOST_H #define _FSL_SDMMC_HOST_H #include "fsl_common.h" -#include "board.h" -#if defined(FSL_FEATURE_SOC_SDHC_COUNT) && FSL_FEATURE_SOC_SDHC_COUNT > 0U -#include "fsl_sdhc.h" -#elif defined(FSL_FEATURE_SOC_SDIF_COUNT) && FSL_FEATURE_SOC_SDIF_COUNT > 0U -#include "fsl_sdif.h" -#elif defined(FSL_FEATURE_SOC_USDHC_COUNT) && FSL_FEATURE_SOC_USDHC_COUNT > 0U +#include "fsl_sdmmc_osa.h" #include "fsl_usdhc.h" -#if (FSL_FEATURE_SOC_IOMUXC_COUNT != 0U) -#include "fsl_iomuxc.h" -#else -#include "fsl_port.h" -#endif -#endif /*! - * @addtogroup CARD + * @addtogroup sdmmchost_usdhc + * @ingroup sdmmchost * @{ */ /******************************************************************************* * Definitions ******************************************************************************/ +/*! @brief Middleware adapter version. */ +#define FSL_SDMMC_HOST_ADAPTER_VERSION (MAKE_VERSION(2U, 6U, 3U)) /*2.6.3*/ + +#if ((defined __DCACHE_PRESENT) && __DCACHE_PRESENT) || (defined FSL_FEATURE_HAS_L1CACHE && FSL_FEATURE_HAS_L1CACHE) +#define SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER 0 +#if SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER +#if !(defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) +#error "missing definition of macro FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER" +#endif +#endif +#endif -/* Common definition for support and not support macro */ -#define SDMMCHOST_NOT_SUPPORT 0U /*!< use this define to indicate the host not support feature*/ -#define SDMMCHOST_SUPPORT 1U /*!< use this define to indicate the host support feature*/ +/*! @brief sdmmc host capability */ +enum +{ + kSDMMCHOST_SupportHighSpeed = 1U << 0U, /*!< high speed capability */ + kSDMMCHOST_SupportSuspendResume = 1U << 1U, /*!< suspend resume capability */ + kSDMMCHOST_SupportVoltage3v3 = 1U << 2U, /*!< 3V3 capability */ + kSDMMCHOST_SupportVoltage3v0 = 1U << 3U, /*!< 3V0 capability */ + kSDMMCHOST_SupportVoltage1v8 = 1U << 4U, /*!< 1V8 capability */ + kSDMMCHOST_SupportVoltage1v2 = 1U << 5U, /*!< 1V2 capability */ + kSDMMCHOST_Support4BitDataWidth = 1U << 6U, /*!< 4 bit data width capability */ + kSDMMCHOST_Support8BitDataWidth = 1U << 7U, /*!< 8 bit data width capability */ + kSDMMCHOST_SupportDDRMode = 1U << 8U, /*!< DDR mode capability */ + kSDMMCHOST_SupportDetectCardByData3 = 1U << 9U, /*!< data3 detect card capability */ + kSDMMCHOST_SupportDetectCardByCD = 1U << 10U, /*!< CD detect card capability */ + kSDMMCHOST_SupportAutoCmd12 = 1U << 11U, /*!< auto command 12 capability */ + kSDMMCHOST_SupportSDR104 = 1U << 12U, /*!< SDR104 capability */ + kSDMMCHOST_SupportSDR50 = 1U << 13U, /*!< SDR50 capability */ + kSDMMCHOST_SupportHS200 = 1U << 14U, /*!< HS200 capability */ + kSDMMCHOST_SupportHS400 = 1U << 15U, /*!< HS400 capability */ +}; -/* Common definition for board support SDR104/HS200/HS400 frequency */ -/* SDR104 mode freq */ -#if defined BOARD_SD_HOST_SUPPORT_SDR104_FREQ -#define SDMMCHOST_SUPPORT_SDR104_FREQ BOARD_SD_HOST_SUPPORT_SDR104_FREQ +/*!@brief sdmmc host misc capability */ +#define SDMMCHOST_SUPPORT_HIGH_SPEED (1U) +#define SDMMCHOST_SUPPORT_SUSPEND_RESUME (1U) +#define SDMMCHOST_SUPPORT_VOLTAGE_3V3 (1U) +#define SDMMCHOST_SUPPORT_VOLTAGE_3V0 (0U) +#define SDMMCHOST_SUPPORT_VOLTAGE_1V8 (1U) +#define SDMMCHOST_SUPPORT_VOLTAGE_1V2 (1U) +#define SDMMCHOST_SUPPORT_4_BIT_WIDTH (1U) +#define SDMMCHOST_SUPPORT_8_BIT_WIDTH (1U) +#define SDMMCHOST_SUPPORT_DDR_MODE (1U) +#define SDMMCHOST_SUPPORT_DETECT_CARD_BY_DATA3 (1U) +#define SDMMCHOST_SUPPORT_DETECT_CARD_BY_CD (1U) +#define SDMMCHOST_SUPPORT_AUTO_CMD12 (1U) +#define SDMMCHOST_SUPPORT_MAX_BLOCK_LENGTH (4096U) +#define SDMMCHOST_SUPPORT_MAX_BLOCK_COUNT (USDHC_MAX_BLOCK_COUNT) +#if !(defined(FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT) && (FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT)) +#define SDMMCHOST_SUPPORT_VOLTAGE_CONTROL (1) #else -#define SDMMCHOST_SUPPORT_SDR104_FREQ SD_CLOCK_208MHZ +#define SDMMCHOST_SUPPORT_VOLTAGE_CONTROL (0) #endif -/* HS200 mode freq */ -#if defined BOARD_SD_HOST_SUPPORT_HS200_FREQ -#define SDMMCHOST_SUPPORT_HS200_FREQ BOARD_SD_HOST_SUPPORT_HS200_FREQ +/*! @brief sdmmc host sdcard DDR50 mode capability*/ +#define SDMMCHOST_SUPPORT_DDR50 (SDMMCHOST_SUPPORT_DDR_MODE) +/*! @brief sdmmc host sdcard SDR50 mode capability*/ +#if (defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && (FSL_FEATURE_USDHC_HAS_SDR104_MODE)) +#define SDMMCHOST_SUPPORT_SDR104 (1U) #else -#define SDMMCHOST_SUPPORT_HS200_FREQ MMC_CLOCK_HS200 +#define SDMMCHOST_SUPPORT_SDR104 (0U) #endif -/* HS400 mode freq */ -#if defined BOARD_SD_HOST_SUPPORT_HS400_FREQ -#define SDMMCHOST_SUPPORT_HS400_FREQ BOARD_SD_HOST_SUPPORT_HS400_FREQ +/*! @brief sdmmc host sdcard SDR104/mmccard HS200 mode capability*/ +#if (defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)) +#define SDMMCHOST_SUPPORT_SDR50 (1U) +#define SDMMCHOST_SUPPORT_HS200 (1U) #else -#define SDMMCHOST_SUPPORT_HS400_FREQ MMC_CLOCK_HS400 +#define SDMMCHOST_SUPPORT_HS200 (0U) +#define SDMMCHOST_SUPPORT_SDR50 (0U) #endif - -/* Common definition for SDMMCHOST transfer complete timeout */ -#define SDMMCHOST_TRANSFER_COMPLETE_TIMEOUT (1000U) -/* Common definition for card detect timeout */ -#define SDMMCHOST_CARD_DETECT_TIMEOUT (~0U) - -/* Common definition for IRQ */ -#if defined(__CORTEX_M) -#define SDMMCHOST_SET_IRQ_PRIORITY(id, priority) (NVIC_SetPriority(id, priority)) +/*! @brief sdmmc host mmccard HS400 mode capability*/ +#if (defined(FSL_FEATURE_USDHC_HAS_HS400_MODE) && (FSL_FEATURE_USDHC_HAS_HS400_MODE)) +#define SDMMCHOST_SUPPORT_HS400 (1U) #else -#define SDMMCHOST_SET_IRQ_PRIORITY(id, priority) (GIC_SetPriority(id, priority)) +#define SDMMCHOST_SUPPORT_HS400 (0U) #endif - -#define SDMMCHOST_ENABLE_IRQ(id) (EnableIRQ(id)) - -/*********************************************************SDHC**********************************************************/ -#if (defined(FSL_FEATURE_SOC_SDHC_COUNT) && (FSL_FEATURE_SOC_SDHC_COUNT > 0U)) - -/*define host baseaddr ,clk freq, IRQ number*/ -#define MMC_HOST_BASEADDR BOARD_SDHC_BASEADDR -#define MMC_HOST_CLK_FREQ BOARD_SDHC_CLK_FREQ -#define MMC_HOST_IRQ BOARD_SDHC_IRQ -#define SD_HOST_BASEADDR BOARD_SDHC_BASEADDR -#define SD_HOST_CLK_FREQ BOARD_SDHC_CLK_FREQ -#define SD_HOST_IRQ BOARD_SDHC_IRQ - -/* define for card bus speed/strength cnofig */ -#define CARD_BUS_FREQ_50MHZ (0U) -#define CARD_BUS_FREQ_100MHZ0 (0U) -#define CARD_BUS_FREQ_100MHZ1 (0U) -#define CARD_BUS_FREQ_200MHZ (0U) - -#define CARD_BUS_STRENGTH_0 (0U) -#define CARD_BUS_STRENGTH_1 (0U) -#define CARD_BUS_STRENGTH_2 (0U) -#define CARD_BUS_STRENGTH_3 (0U) -#define CARD_BUS_STRENGTH_4 (0U) -#define CARD_BUS_STRENGTH_5 (0U) -#define CARD_BUS_STRENGTH_6 (0U) -#define CARD_BUS_STRENGTH_7 (0U) - -#define SDMMCHOST_TYPE SDHC_Type -#define SDMMCHOST_CONFIG sdhc_host_t -#define SDMMCHOST_TRANSFER sdhc_transfer_t -#define SDMMCHOST_COMMAND sdhc_command_t -#define SDMMCHOST_DATA sdhc_data_t -#define SDMMCHOST_BUS_WIDTH_TYPE sdhc_data_bus_width_t -#define SDMMCHOST_CAPABILITY sdhc_capability_t -#define SDMMCHOST_BOOT_CONFIG sdhc_boot_config_t - -#define CARD_DATA0_STATUS_MASK kSDHC_Data0LineLevelFlag -#define CARD_DATA0_NOT_BUSY kSDHC_Data0LineLevelFlag -#define CARD_DATA1_STATUS_MASK kSDHC_Data1LineLevelFlag -#define CARD_DATA2_STATUS_MASK kSDHC_Data2LineLevelFlag -#define CARD_DATA3_STATUS_MASK kSDHC_Data3LineLevelFlag - -#define kSDMMCHOST_DATABUSWIDTH1BIT kSDHC_DataBusWidth1Bit /*!< 1-bit mode */ -#define kSDMMCHOST_DATABUSWIDTH4BIT kSDHC_DataBusWidth4Bit /*!< 4-bit mode */ -#define kSDMMCHOST_DATABUSWIDTH8BIT kSDHC_DataBusWidth8Bit /*!< 8-bit mode */ - -#define SDMMCHOST_STANDARD_TUNING_START (0U) /*!< standard tuning start point */ -#define SDMMCHOST_TUINIG_STEP (1U) /*!< standard tuning step */ -#define SDMMCHOST_RETUNING_TIMER_COUNT (4U) /*!< Re-tuning timer */ -#define SDMMCHOST_TUNING_DELAY_MAX (0x7FU) -#define SDMMCHOST_RETUNING_REQUEST (1U) -#define SDMMCHOST_TUNING_ERROR (2U) - -/* function pointer define */ -#define SDMMCHOST_TRANSFER_FUNCTION sdhc_transfer_function_t -#define GET_SDMMCHOST_CAPABILITY(base, capability) (SDHC_GetCapability(base, capability)) -#define GET_SDMMCHOST_STATUS(base) (SDHC_GetPresentStatusFlags(base)) -#define SDMMCHOST_SET_CARD_CLOCK(base, sourceClock_HZ, busClock_HZ) (SDHC_SetSdClock(base, sourceClock_HZ, busClock_HZ)) -#define SDMMCHOST_SET_CARD_BUS_WIDTH(base, busWidth) (SDHC_SetDataBusWidth(base, busWidth)) -#define SDMMCHOST_SEND_CARD_ACTIVE(base, timeout) (SDHC_SetCardActive(base, timeout)) -#define SDMMCHOST_SWITCH_VOLTAGE180V(base, enable18v) -#define SDMMCHOST_SWITCH_VOLTAGE120V(base, enable12v) -#define SDMMCHOST_CONFIG_IO_STRENGTH(speed, strength) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, flag) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) (0U) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) (1U) -#define SDMMCHOST_CONFIG_SD_IO(speed, strength) -#define SDMMCHOST_CONFIG_MMC_IO(speed, strength) -#define SDMMCHOST_ENABLE_DDR_MODE(base, flag, nibblePos) -#define SDMMCHOST_FORCE_SDCLOCK_ON(base, enable) -#define SDMMCHOST_EXECUTE_MANUAL_TUNING_ENABLE(base, flag) -#define SDMMCHOST_ADJUST_MANUAL_TUNING_DELAY(base, delay) -#define SDMMCHOST_AUTO_MANUAL_TUNING_ENABLE(base, flag) -#define SDMMCHOST_ENABLE_CARD_CLOCK(base, enable) (SDHC_EnableSdClock(base, enable)) -#define SDMMCHOST_RESET_TUNING(base, timeout) -#define SDMMCHOST_CHECK_TUNING_ERROR(base) (0U) -#define SDMMCHOST_ADJUST_TUNING_DELAY(base, delay) -#define SDMMCHOST_AUTO_STANDARD_RETUNING_TIMER(base) - -#define SDMMCHOST_ENABLE_HS400_MODE(base, flag) -#define SDMMCHOST_RESET_STROBE_DLL(base) -#define SDMMCHOST_ENABLE_STROBE_DLL(base, flag) -#define SDMMCHOST_CONFIG_STROBE_DLL(base, delay, updateInterval) -#define SDMMCHOST_GET_STROBE_DLL_STATUS(base) -/* sd card power */ -#define SDMMCHOST_INIT_SD_POWER() -#define SDMMCHOST_ENABLE_SD_POWER(enable) -#define SDMMCHOST_SWITCH_VCC_TO_180V() -#define SDMMCHOST_SWITCH_VCC_TO_330V() -/* mmc card power */ -#define SDMMCHOST_INIT_MMC_POWER() -#define SDMMCHOST_ENABLE_MMC_POWER(enable) -#define SDMMCHOST_ENABLE_TUNING_FLAG(data) -#define SDMMCHOST_ENABLE_BOOT_FLAG(data) -#define SDMMCHOST_ENABLE_BOOT_CONTINOUS_FLAG(data) -#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(config) (0U) -#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(config) (0U) -#define SDMMCHOST_GET_HOST_CONFIG_BOOT_MODE(config) (0U) -#define SDMMCHOST_EMPTY_CMD_FLAG(command) -#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_HANDLER BOARD_SDHC_CD_PORT_IRQ_HANDLER -#define SDMMCHOST_CARD_DETECT_IRQ BOARD_SDHC_CD_PORT_IRQ -/* sd card detect through host CD */ -#define SDMMCHOST_CARD_DETECT_INSERT_ENABLE(base) (SDHC_EnableInterruptStatus(base, kSDHC_CardInsertionFlag)) -#define SDMMCHOST_CARD_DETECT_REMOVE_ENABLE(base) (SDHC_EnableInterruptStatus(base, kSDHC_CardRemovalFlag)) -#define SDMMCHOST_CARD_DETECT_INSERT_STATUS(base) (SDHC_GetInterruptStatusFlags(base) & kSDHC_CardInsertionFlag) -#define SDMMCHOST_CARD_DETECT_REMOVE_STATUS(base) (SDHC_GetInterruptStatusFlags(base, kSDHC_CardRemovalFlag)) -#define SDMMCHOST_CARD_DETECT_INSERT_INTERRUPT_ENABLE(base) (SDHC_EnableInterruptSignal(base, kSDHC_CardInsertionFlag)) -#define SDMMCHOST_CARD_DETECT_INSERT_INTERRUPT_DISABLE(base) \ - (SDHC_DisableInterruptSignal(base, kSDHC_CardInsertionFlag)) -#define SDMMCHOST_CARD_DETECT_REMOVE_INTERRUPT_ENABLE(base) (SDHC_EnableInterruptSignal(base, kSDHC_CardRemovalFlag)) -#define SDMMCHOST_CARD_DETECT_DATA3_ENABLE(base, flag) (SDHC_CardDetectByData3(base, flag)) -#define SDMMCHOST_ENABLE_MMC_BOOT(base, flag) -#define SDMMCHOST_SETMMCBOOTCONFIG(base, config) (SDHC_SetMmcBootConfig(base, config)) -/* define card detect pin voltage level when card inserted */ -#if defined BOARD_SDHC_CARD_INSERT_CD_LEVEL -#define SDMMCHOST_CARD_INSERT_CD_LEVEL BOARD_SDHC_CARD_INSERT_CD_LEVEL +/*! @brief sdmmc host instance capability */ +#if defined FSL_FEATURE_USDHC_INSTANCE_SUPPORT_8_BIT_WIDTHn +#define SDMMCHOST_INSTANCE_SUPPORT_8_BIT_WIDTH(host) \ + FSL_FEATURE_USDHC_INSTANCE_SUPPORT_8_BIT_WIDTHn(host->hostController.base) +#else +#define SDMMCHOST_INSTANCE_SUPPORT_8_BIT_WIDTH(host) 0 +#endif +#if defined FSL_FEATURE_USDHC_INSTANCE_SUPPORT_HS400_MODEn +#define SDMMCHOST_INSTANCE_SUPPORT_HS400(host) FSL_FEATURE_USDHC_INSTANCE_SUPPORT_HS400_MODEn(host->hostController.base) #else -#define SDMMCHOST_CARD_INSERT_CD_LEVEL (0U) +#define SDMMCHOST_INSTANCE_SUPPORT_HS400(host) 0 +#endif +#if defined FSL_FEATURE_USDHC_INSTANCE_SUPPORT_1V8_SIGNALn +#define SDMMCHOST_INSTANCE_SUPPORT_1V8_SIGNAL(host) \ + FSL_FEATURE_USDHC_INSTANCE_SUPPORT_1V8_SIGNALn(host->hostController.base) +#define SDMMCHOST_INSTANCE_SUPPORT_HS200(host) SDMMCHOST_INSTANCE_SUPPORT_1V8_SIGNAL(host) +#define SDMMCHOST_INSTANCE_SUPPORT_SDR104(host) SDMMCHOST_INSTANCE_SUPPORT_1V8_SIGNAL(host) +#define SDMMCHOST_INSTANCE_SUPPORT_SDR50(host) SDMMCHOST_INSTANCE_SUPPORT_1V8_SIGNAL(host) +#define SDMMCHOST_INSTANCE_SUPPORT_DDR50(host) SDMMCHOST_INSTANCE_SUPPORT_1V8_SIGNAL(host) +#else +#define SDMMCHOST_INSTANCE_SUPPORT_1V8_SIGNAL(host) 0 +#define SDMMCHOST_INSTANCE_SUPPORT_HS200(host) 0 +#define SDMMCHOST_INSTANCE_SUPPORT_SDR104(host) 0 +#define SDMMCHOST_INSTANCE_SUPPORT_SDR50(host) 0 +#define SDMMCHOST_INSTANCE_SUPPORT_DDR50(host) 0 +#endif + +#ifndef SDMMCHOST_DMA_MODE +#define SDMMCHOST_DMA_MODE kUSDHC_DmaModeAdma2 +#endif +/*! @brief sdmmchost delay for DAT3 detect card */ +#ifndef SDMMCHOST_DATA3_DETECT_CARD_DELAY +#define SDMMCHOST_DATA3_DETECT_CARD_DELAY (10U) #endif -/*! @brief SDHC host capability*/ -enum _host_capability +/*!@brief SDMMC host dma descriptor buffer address align size */ +#define SDMMCHOST_DMA_DESCRIPTOR_BUFFER_ALIGN_SIZE (4U) +/*!@brief tuning configuration */ +#define SDMMCHOST_STANDARD_TUNING_START (10U) /*!< standard tuning start point */ +#define SDMMCHOST_TUINIG_STEP (2U) /*!< standard tuning stBep */ +#define SDMMCHOST_STANDARD_TUNING_COUNTER (60) +#define SDMMCHOST_STROBE_DLL_DELAY_TARGET (7U) +#define SDMMCHOST_STROBE_DLL_DELAY_UPDATE_INTERVAL (4U) +#define SDMMCHOST_MAX_TUNING_DELAY_CELL (128U) +/*!@brief sdmmc host transfer function */ +typedef usdhc_transfer_t sdmmchost_transfer_t; +typedef usdhc_command_t sdmmchost_cmd_t; +typedef usdhc_data_t sdmmchost_data_t; +typedef struct _sdmmchost_ SDMMCHOST_CONFIG; +typedef USDHC_Type SDMMCHOST_TYPE; +typedef void sdmmchost_detect_card_t; +typedef usdhc_boot_config_t sdmmchost_boot_config_t; +/*! @brief host Endian mode + * corresponding to driver define + * @anchor _sdmmchost_endian_mode + */ +enum { - kSDMMCHOST_SupportAdma = kSDHC_SupportAdmaFlag, - kSDMMCHOST_SupportHighSpeed = kSDHC_SupportHighSpeedFlag, - kSDMMCHOST_SupportDma = kSDHC_SupportDmaFlag, - kSDMMCHOST_SupportSuspendResume = kSDHC_SupportSuspendResumeFlag, - kSDMMCHOST_SupportV330 = kSDHC_SupportV330Flag, - kSDMMCHOST_SupportV300 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportV180 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportV120 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_Support4BitBusWidth = kSDHC_Support4BitFlag, - kSDMMCHOST_Support8BitBusWidth = kSDHC_Support8BitFlag, - kSDMMCHOST_SupportDDR50 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportSDR104 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportSDR50 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportHS200 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportHS400 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_EndianModeBig = 0U, /*!< Big endian mode */ + kSDMMCHOST_EndianModeHalfWordBig = 1U, /*!< Half word big endian mode */ + kSDMMCHOST_EndianModeLittle = 2U, /*!< Little endian mode */ }; -/* Endian mode. */ -#define SDHC_ENDIAN_MODE kSDHC_EndianModeLittle - -/* DMA mode */ -#define SDHC_DMA_MODE kSDHC_DmaModeAdma2 -/* address align */ -#define SDMMCHOST_DMA_BUFFER_ADDR_ALIGN (SDHC_ADMA2_ADDRESS_ALIGN) +/*! @brief sdmmc host tuning type + * @anchor _sdmmchost_tuning_type + */ +enum +{ + kSDMMCHOST_StandardTuning = 0U, /*!< standard tuning type */ + kSDMMCHOST_ManualTuning = 1U, /*!< manual tuning type */ +}; -/* Read/write watermark level. The bigger value indicates DMA has higher read/write performance. */ -#define SDHC_READ_WATERMARK_LEVEL (0x80U) -#define SDHC_WRITE_WATERMARK_LEVEL (0x80U) +/*! @brief sdmmc host maintain cache flag + * @anchor _sdmmc_host_cache_control + */ +enum +{ + kSDMMCHOST_NoCacheControl = 0U, /*!< sdmmc host cache control disabled */ + kSDMMCHOST_CacheControlRWBuffer = 1U, /*!< sdmmc host cache control read/write buffer */ +}; -/* ADMA table length united as word. - * - * SD card driver can't support ADMA1 transfer mode currently. - * One ADMA2 table item occupy two words which can transfer maximum 0xFFFFU bytes one time. - * The more data to be transferred in one time, the bigger value of SDHC_ADMA_TABLE_WORDS need to be set. - */ -#define SDHC_ADMA_TABLE_WORDS (8U) - -/*********************************************************SDIF**********************************************************/ -#elif (defined(FSL_FEATURE_SOC_SDIF_COUNT) && (FSL_FEATURE_SOC_SDIF_COUNT > 0U)) - -/*define host baseaddr ,clk freq, IRQ number*/ -#define MMC_HOST_BASEADDR BOARD_SDIF_BASEADDR -#define MMC_HOST_CLK_FREQ BOARD_SDIF_CLK_FREQ -#define MMC_HOST_IRQ BOARD_SDIF_IRQ -#define SD_HOST_BASEADDR BOARD_SDIF_BASEADDR -#define SD_HOST_CLK_FREQ BOARD_SDIF_CLK_FREQ -#define SD_HOST_IRQ BOARD_SDIF_IRQ - -/* define for card bus speed/strength cnofig */ -#define CARD_BUS_FREQ_50MHZ (0U) -#define CARD_BUS_FREQ_100MHZ0 (0U) -#define CARD_BUS_FREQ_100MHZ1 (0U) -#define CARD_BUS_FREQ_200MHZ (0U) - -#define CARD_BUS_STRENGTH_0 (0U) -#define CARD_BUS_STRENGTH_1 (0U) -#define CARD_BUS_STRENGTH_2 (0U) -#define CARD_BUS_STRENGTH_3 (0U) -#define CARD_BUS_STRENGTH_4 (0U) -#define CARD_BUS_STRENGTH_5 (0U) -#define CARD_BUS_STRENGTH_6 (0U) -#define CARD_BUS_STRENGTH_7 (0U) - -#define SDMMCHOST_TYPE SDIF_Type -#define SDMMCHOST_CONFIG sdif_host_t -#define SDMMCHOST_TRANSFER sdif_transfer_t -#define SDMMCHOST_COMMAND sdif_command_t -#define SDMMCHOST_DATA sdif_data_t -#define SDMMCHOST_BUS_WIDTH_TYPE sdif_bus_width_t -#define SDMMCHOST_CAPABILITY sdif_capability_t -#define SDMMCHOST_BOOT_CONFIG void - -#define CARD_DATA0_STATUS_MASK SDIF_STATUS_DATA_BUSY_MASK -#define CARD_DATA0_NOT_BUSY 0U - -#define CARD_DATA1_STATUS_MASK (0U) -#define CARD_DATA2_STATUS_MASK (0U) -#define CARD_DATA3_STATUS_MASK (0U) - -#define kSDMMCHOST_DATABUSWIDTH1BIT kSDIF_Bus1BitWidth /*!< 1-bit mode */ -#define kSDMMCHOST_DATABUSWIDTH4BIT kSDIF_Bus4BitWidth /*!< 4-bit mode */ -#define kSDMMCHOST_DATABUSWIDTH8BIT kSDIF_Bus8BitWidth /*!< 8-bit mode */ - -#define SDMMCHOST_STANDARD_TUNING_START (0U) /*!< standard tuning start point */ -#define SDMMCHOST_TUINIG_STEP (1U) /*!< standard tuning step */ -#define SDMMCHOST_RETUNING_TIMER_COUNT (4U) /*!< Re-tuning timer */ -#define SDMMCHOST_TUNING_DELAY_MAX (0x7FU) -#define SDMMCHOST_RETUNING_REQUEST (1U) -#define SDMMCHOST_TUNING_ERROR (2U) -/* function pointer define */ -#define SDMMCHOST_TRANSFER_FUNCTION sdif_transfer_function_t -#define GET_SDMMCHOST_CAPABILITY(base, capability) (SDIF_GetCapability(base, capability)) -#define GET_SDMMCHOST_STATUS(base) (SDIF_GetControllerStatus(base)) -#define SDMMCHOST_SET_CARD_CLOCK(base, sourceClock_HZ, busClock_HZ) \ - (SDIF_SetCardClock(base, sourceClock_HZ, busClock_HZ)) -#define SDMMCHOST_SET_CARD_BUS_WIDTH(base, busWidth) (SDIF_SetCardBusWidth(base, busWidth)) -#define SDMMCHOST_SEND_CARD_ACTIVE(base, timeout) (SDIF_SendCardActive(base, timeout)) -#define SDMMCHOST_SWITCH_VOLTAGE180V(base, enable18v) -#define SDMMCHOST_SWITCH_VOLTAGE120V(base, enable12v) -#define SDMMCHOST_CONFIG_IO_STRENGTH(speed, strength) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, flag) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) (0U) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) (1U) -#define SDMMCHOST_CONFIG_SD_IO(speed, strength) -#define SDMMCHOST_CONFIG_MMC_IO(speed, strength) -#define SDMMCHOST_ENABLE_DDR_MODE(base, flag, nibblePos) -#define SDMMCHOST_FORCE_SDCLOCK_ON(base, enable) -#define SDMMCHOST_EXECUTE_MANUAL_TUNING_ENABLE(base, flag) -#define SDMMCHOST_ADJUST_MANUAL_TUNING_DELAY(base, delay) -#define SDMMCHOST_AUTO_MANUAL_TUNING_ENABLE(base, flag) -#define SDMMCHOST_ENABLE_CARD_CLOCK(base, enable) (SDIF_EnableCardClock(base, enable)) -#define SDMMCHOST_RESET_TUNING(base, timeout) -#define SDMMCHOST_CHECK_TUNING_ERROR(base) (0U) -#define SDMMCHOST_ADJUST_TUNING_DELAY(base, delay) -#define SDMMCHOST_AUTO_STANDARD_RETUNING_TIMER(base) - -#define SDMMCHOST_ENABLE_HS400_MODE(base, flag) -#define SDMMCHOST_RESET_STROBE_DLL(base) -#define SDMMCHOST_ENABLE_STROBE_DLL(base, flag) -#define SDMMCHOST_CONFIG_STROBE_DLL(base, delay, updateInterval) -#define SDMMCHOST_GET_STROBE_DLL_STATUS(base) -/* sd card power */ -#define SDMMCHOST_INIT_SD_POWER() -#define SDMMCHOST_ENABLE_SD_POWER(enable) -#define SDMMCHOST_SWITCH_VCC_TO_180V() -#define SDMMCHOST_SWITCH_VCC_TO_330V() -/* mmc card power */ -#define SDMMCHOST_INIT_MMC_POWER() -#define SDMMCHOST_ENABLE_MMC_POWER(enable) -#define SDMMCHOST_ENABLE_TUNING_FLAG(data) -#define SDMMCHOST_ENABLE_MMC_BOOT(base, flag) -#define SDMMCHOST_SETMMCBOOTCONFIG(base, config) -#define SDMMCHOST_ENABLE_BOOT_FLAG(data) -#define SDMMCHOST_ENABLE_BOOT_CONTINOUS_FLAG(data) -#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(config) (0U) -#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(config) (0U) -#define SDMMCHOST_GET_HOST_CONFIG_BOOT_MODE(config) (0U) -#define SDMMCHOST_EMPTY_CMD_FLAG(command) -#define SDMMCHOST_CARD_DETECT_STATUS() BOARD_SDIF_CD_STATUS() -#define SDMMCHOST_CARD_DETECT_INIT() BOARD_SDIF_CD_GPIO_INIT() -#define SDMMCHOST_CARD_DETECT_INTERRUPT_STATUS() BOARD_SDIF_CD_INTERRUPT_STATUS() -#define SDMMCHOST_CARD_DETECT_INTERRUPT_CLEAR(flag) BOARD_SDIF_CD_CLEAR_INTERRUPT(flag) -#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_HANDLER BOARD_SDIF_CD_PORT_IRQ_HANDLER -#define SDMMCHOST_CARD_DETECT_IRQ BOARD_SDIF_CD_PORT_IRQ -/* define card detect pin voltage level when card inserted */ -#if defined BOARD_SDIF_CARD_INSERT_CD_LEVEL -#define SDMMCHOST_CARD_INSERT_CD_LEVEL BOARD_SDIF_CARD_INSERT_CD_LEVEL -#else -#define SDMMCHOST_CARD_INSERT_CD_LEVEL (0U) +/*!@brief sdmmc host handler */ +typedef struct _sdmmchost_ +{ + usdhc_host_t hostController; /*!< host configuration */ + void *dmaDesBuffer; /*!< DMA descriptor buffer address */ + uint32_t dmaDesBufferWordsNum; /*!< DMA descriptor buffer size in byte */ + usdhc_handle_t handle; /*!< host controller handler */ + uint32_t capability; /*!< host controller capability */ + uint32_t maxBlockCount; /*!< host controller maximum block count */ + uint32_t maxBlockSize; /*!< host controller maximum block size */ + + uint8_t tuningType; /*!< host tuning type */ + + sdmmc_osa_event_t hostEvent; /*!< host event handler */ + void *cd; /*!< card detect */ + void *cardInt; /*!< call back function for card interrupt */ + +#if ((defined __DCACHE_PRESENT) && __DCACHE_PRESENT) || (defined FSL_FEATURE_HAS_L1CACHE && FSL_FEATURE_HAS_L1CACHE) + uint8_t enableCacheControl; /*!< Cache maintain flag in host driver. Host driver only maintain cache when + FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL is not defined and enableCacheControl = + kSDMMCHOST_CacheControlRWBuffer. While FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL is + defined, host driver will not maintain cache and peripheral driver will do it.*/ +#if defined SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER && SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER + void *cacheAlignBuffer; /*!< cache line size align buffer */ + uint32_t cacheAlignBufferSize; /*!< cache line size align buffer size, the size must be not smaller than 2 * cache + line size */ +#endif #endif -/* sd card detect through host CD */ -#define SDMMCHOST_CARD_DETECT_INSERT_ENABLE(base) (SDIF_EnableInterrupt(base, kSDIF_CardDetect)) -#define SDMMCHOST_CARD_DETECT_INSERT_STATUS(base, data3) (SDIF_DetectCardInsert(base, data3)) + sdmmc_osa_mutex_t lock; /*!< host access lock */ +} sdmmchost_t; -/*! @brief SDIF host capability*/ -enum _host_capability -{ - kSDMMCHOST_SupportHighSpeed = kSDIF_SupportHighSpeedFlag, - kSDMMCHOST_SupportDma = kSDIF_SupportDmaFlag, - kSDMMCHOST_SupportSuspendResume = kSDIF_SupportSuspendResumeFlag, - kSDMMCHOST_SupportV330 = kSDIF_SupportV330Flag, - kSDMMCHOST_SupportV300 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportV180 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportV120 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_Support4BitBusWidth = kSDIF_Support4BitFlag, - kSDMMCHOST_Support8BitBusWidth = - SDMMCHOST_NOT_SUPPORT, /* mask the 8 bit here,user can change depend on your board */ - kSDMMCHOST_SupportDDR50 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportSDR104 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportSDR50 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportHS200 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_SupportHS400 = SDMMCHOST_NOT_SUPPORT, +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif -}; +/*! + * @name USDHC host controller function + * @{ + */ -/*! @brief DMA table length united as word - * One dma table item occupy four words which can transfer maximum 2*8188 bytes in dual DMA mode - * and 8188 bytes in chain mode - * The more data to be transferred in one time, the bigger value of SDHC_ADMA_TABLE_WORDS need to be set. - * user need check the DMA descriptor table lenght if bigger enough. - */ -#define SDIF_DMA_TABLE_WORDS (0x40U) -/* address align */ -#define SDMMCHOST_DMA_BUFFER_ADDR_ALIGN (4U) - -/*********************************************************USDHC**********************************************************/ -#elif (defined(FSL_FEATURE_SOC_USDHC_COUNT) && (FSL_FEATURE_SOC_USDHC_COUNT > 0U)) - -/*define host baseaddr ,clk freq, IRQ number*/ -#define MMC_HOST_BASEADDR BOARD_MMC_HOST_BASEADDR -#define MMC_HOST_CLK_FREQ BOARD_MMC_HOST_CLK_FREQ -#define MMC_HOST_IRQ BOARD_MMC_HOST_IRQ -#define SD_HOST_BASEADDR BOARD_SD_HOST_BASEADDR -#define SD_HOST_CLK_FREQ BOARD_SD_HOST_CLK_FREQ -#define SD_HOST_IRQ BOARD_SD_HOST_IRQ - -#define SDMMCHOST_TYPE USDHC_Type -#define SDMMCHOST_CONFIG usdhc_host_t -#define SDMMCHOST_TRANSFER usdhc_transfer_t -#define SDMMCHOST_COMMAND usdhc_command_t -#define SDMMCHOST_DATA usdhc_data_t -#define SDMMCHOST_BOOT_CONFIG usdhc_boot_config_t -#define CARD_DATA0_STATUS_MASK kUSDHC_Data0LineLevelFlag -#define CARD_DATA1_STATUS_MASK kUSDHC_Data1LineLevelFlag -#define CARD_DATA2_STATUS_MASK kUSDHC_Data2LineLevelFlag -#define CARD_DATA3_STATUS_MASK kUSDHC_Data3LineLevelFlag -#define CARD_DATA0_NOT_BUSY kUSDHC_Data0LineLevelFlag - -#define SDMMCHOST_BUS_WIDTH_TYPE usdhc_data_bus_width_t -#define SDMMCHOST_CAPABILITY usdhc_capability_t - -#define kSDMMCHOST_DATABUSWIDTH1BIT kUSDHC_DataBusWidth1Bit /*!< 1-bit mode */ -#define kSDMMCHOST_DATABUSWIDTH4BIT kUSDHC_DataBusWidth4Bit /*!< 4-bit mode */ -#define kSDMMCHOST_DATABUSWIDTH8BIT kUSDHC_DataBusWidth8Bit /*!< 8-bit mode */ - -#define SDMMCHOST_STANDARD_TUNING_START (10U) /*!< standard tuning start point */ -#define SDMMCHOST_TUINIG_STEP (2U) /*!< standard tuning step */ -#define SDMMCHOST_RETUNING_TIMER_COUNT (0U) /*!< Re-tuning timer */ -#define SDMMCHOST_TUNING_DELAY_MAX (0x7FU) -#define SDMMCHOST_RETUNING_REQUEST kStatus_USDHC_ReTuningRequest -#define SDMMCHOST_TUNING_ERROR kStatus_USDHC_TuningError -/* define for card bus speed/strength cnofig */ -#define CARD_BUS_FREQ_50MHZ (0U) -#define CARD_BUS_FREQ_100MHZ0 (1U) -#define CARD_BUS_FREQ_100MHZ1 (2U) -#define CARD_BUS_FREQ_200MHZ (3U) - -#define CARD_BUS_STRENGTH_0 (0U) -#define CARD_BUS_STRENGTH_1 (1U) -#define CARD_BUS_STRENGTH_2 (2U) -#define CARD_BUS_STRENGTH_3 (3U) -#define CARD_BUS_STRENGTH_4 (4U) -#define CARD_BUS_STRENGTH_5 (5U) -#define CARD_BUS_STRENGTH_6 (6U) -#define CARD_BUS_STRENGTH_7 (7U) +/*! + * @brief set data bus width. + * @param host host handler + * @param dataBusWidth data bus width + */ +void SDMMCHOST_SetCardBusWidth(sdmmchost_t *host, uint32_t dataBusWidth); -#define SDMMCHOST_STROBE_DLL_DELAY_TARGET (7U) -#define SDMMCHOST_STROBE_DLL_DELAY_UPDATE_INTERVAL (4U) +/*! + * @brief Send initilization active 80 clocks to card. + * @param host host handler + */ +static inline void SDMMCHOST_SendCardActive(sdmmchost_t *host) +{ + (void)USDHC_SetCardActive(host->hostController.base, 100U); +} -/* function pointer define */ -#define SDMMCHOST_TRANSFER_FUNCTION usdhc_transfer_function_t -#define GET_SDMMCHOST_CAPABILITY(base, capability) (USDHC_GetCapability(base, capability)) -#define GET_SDMMCHOST_STATUS(base) (USDHC_GetPresentStatusFlags(base)) -#define SDMMCHOST_SET_CARD_CLOCK(base, sourceClock_HZ, busClock_HZ) \ - (USDHC_SetSdClock(base, sourceClock_HZ, busClock_HZ)) -#define SDMMCHOST_ENABLE_CARD_CLOCK(base, enable) -#define SDMMCHOST_FORCE_SDCLOCK_ON(base, enable) (USDHC_ForceClockOn(base, enable)) -#define SDMMCHOST_SET_CARD_BUS_WIDTH(base, busWidth) (USDHC_SetDataBusWidth(base, busWidth)) -#define SDMMCHOST_SEND_CARD_ACTIVE(base, timeout) (USDHC_SetCardActive(base, timeout)) -#define SDMMCHOST_SWITCH_VOLTAGE180V(base, enable18v) (UDSHC_SelectVoltage(base, enable18v)) -#define SDMMCHOST_SWITCH_VOLTAGE120V(base, enable12v) -#define SDMMCHOST_CONFIG_SD_IO(speed, strength) BOARD_SD_PIN_CONFIG(speed, strength) -#define SDMMCHOST_CONFIG_MMC_IO(speed, strength) BOARD_MMC_PIN_CONFIG(speed, strength) -#define SDMMCHOST_SWITCH_VCC_TO_180V() -#define SDMMCHOST_SWITCH_VCC_TO_330V() - -#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) (0U) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) (1U) -#define SDMMCHOST_AUTO_STANDARD_RETUNING_TIMER(base) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, flag) -#define SDMMCHOST_CHECK_TUNING_ERROR(base) (0U) -#define SDMMCHOST_ADJUST_TUNING_DELAY(base, delay) -#else -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, flag) \ - (USDHC_EnableStandardTuning(base, SDMMCHOST_STANDARD_TUNING_START, SDMMCHOST_TUINIG_STEP, flag)) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) (USDHC_GetExecuteStdTuningStatus(base)) -#define SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) (USDHC_CheckStdTuningResult(base)) -#define SDMMCHOST_AUTO_STANDARD_RETUNING_TIMER(base) (USDHC_SetRetuningTimer(base, SDMMCHOST_RETUNING_TIMER_COUNT)) -#define SDMMCHOST_EXECUTE_MANUAL_TUNING_ENABLE(base, flag) (USDHC_EnableManualTuning(base, flag)) -#define SDMMCHOST_ADJUST_TUNING_DELAY(base, delay) (USDHC_AdjustDelayForManualTuning(base, delay)) -#define SDMMCHOST_AUTO_TUNING_ENABLE(base, flag) (USDHC_EnableAutoTuning(base, flag)) -#define SDMMCHOST_CHECK_TUNING_ERROR(base) (USDHC_CheckTuningError(base)) -#endif +/*! + * @brief Set card bus clock. + * @param host host handler + * @param targetClock target clock frequency + * @retval actual clock frequency can be reach. + */ +static inline uint32_t SDMMCHOST_SetCardClock(sdmmchost_t *host, uint32_t targetClock) +{ + return USDHC_SetSdClock(host->hostController.base, host->hostController.sourceClock_Hz, targetClock); +} -#define SDMMCHOST_AUTO_TUNING_CONFIG(base) (USDHC_EnableAutoTuningForCmdAndData(base)) -#define SDMMCHOST_RESET_TUNING(base, timeout) \ - { \ - (USDHC_Reset(base, kUSDHC_ResetTuning | kUSDHC_ResetData | kUSDHC_ResetCommand, timeout)); \ +/*! + * @brief check card status by DATA0. + * @param host host handler + * @retval true is busy, false is idle. + */ +static inline bool SDMMCHOST_IsCardBusy(sdmmchost_t *host) +{ + return (USDHC_GetPresentStatusFlags(host->hostController.base) & (uint32_t)kUSDHC_Data0LineLevelFlag) == + (uint32_t)kUSDHC_Data0LineLevelFlag ? + false : + true; +} + +/*! + * @brief Get signal line status. + * @param host host handler + * @param signalLine signal line type, reference _sdmmc_signal_line + */ +static inline uint32_t SDMMCHOST_GetSignalLineStatus(sdmmchost_t *host, uint32_t signalLine) +{ + return (USDHC_GetPresentStatusFlags(host->hostController.base) >> USDHC_PRES_STATE_CLSL_SHIFT) & signalLine; +} +/*! + * @brief enable card interrupt. + * @param host host handler + * @param enable true is enable, false is disable. + */ +static inline void SDMMCHOST_EnableCardInt(sdmmchost_t *host, bool enable) +{ + if (enable) + { + USDHC_EnableInterruptStatus(host->hostController.base, kUSDHC_CardInterruptFlag); + USDHC_EnableInterruptSignal(host->hostController.base, kUSDHC_CardInterruptFlag); + } + else + { + USDHC_DisableInterruptStatus(host->hostController.base, kUSDHC_CardInterruptFlag); + USDHC_DisableInterruptSignal(host->hostController.base, kUSDHC_CardInterruptFlag); } +} -#define SDMMCHOST_ENABLE_DDR_MODE(base, flag, nibblePos) (USDHC_EnableDDRMode(base, flag, nibblePos)) +/*! + * @brief enable DDR mode. + * @param host host handler + * @param enable true is enable, false is disable. + * @param nibblePos nibble position indictation. 0- the sequence is 'odd high nibble -> even high nibble -> + * odd low nibble -> even low nibble'; 1- the sequence is 'odd high nibble -> odd low nibble -> even high + * nibble -> even low nibble'. + */ +static inline void SDMMCHOST_EnableDDRMode(sdmmchost_t *host, bool enable, uint32_t nibblePos) +{ + USDHC_EnableDDRMode(host->hostController.base, enable, nibblePos); +} +/*! + * @brief enable HS400 mode. + * @param host host handler + * @param enable true is enable, false is disable. + */ +static inline void SDMMCHOST_EnableHS400Mode(sdmmchost_t *host, bool enable) +{ #if FSL_FEATURE_USDHC_HAS_HS400_MODE -#define SDMMCHOST_ENABLE_HS400_MODE(base, flag) (USDHC_EnableHS400Mode(base, flag)) -#define SDMMCHOST_RESET_STROBE_DLL(base) (USDHC_ResetStrobeDLL(base)) -#define SDMMCHOST_ENABLE_STROBE_DLL(base, flag) (USDHC_EnableStrobeDLL(base, flag)) -#define SDMMCHOST_CONFIG_STROBE_DLL(base, delay, updateInterval) (USDHC_ConfigStrobeDLL(base, delay, updateInterval)) -#define SDMMCHOST_GET_STROBE_DLL_STATUS (base)(USDHC_GetStrobeDLLStatus(base)) -#else -#define SDMMCHOST_ENABLE_HS400_MODE(base, flag) -#define SDMMCHOST_RESET_STROBE_DLL(base) -#define SDMMCHOST_ENABLE_STROBE_DLL(base, flag) -#define SDMMCHOST_CONFIG_STROBE_DLL(base, delay, updateInterval) -#define SDMMCHOST_GET_STROBE_DLL_STATUS(base) -#endif + assert(SDMMCHOST_INSTANCE_SUPPORT_HS400(host) != 0); -#define SDMMCHOST_ENABLE_MMC_BOOT(base, flag) (USDHC_EnableMmcBoot(base, flag)) -#define SDMMCHOST_SETMMCBOOTCONFIG(base, config) (USDHC_SetMmcBootConfig(base, config)) -/* sd card power */ -#define SDMMCHOST_INIT_SD_POWER() BOARD_USDHC_SDCARD_POWER_CONTROL_INIT() -#define SDMMCHOST_ENABLE_SD_POWER(enable) BOARD_USDHC_SDCARD_POWER_CONTROL(enable) -/* mmc card power */ -#define SDMMCHOST_INIT_MMC_POWER() BOARD_USDHC_MMCCARD_POWER_CONTROL_INIT() -#define SDMMCHOST_ENABLE_MMC_POWER(enable) BOARD_USDHC_MMCCARD_POWER_CONTROL(enable) -/* sd card detect through gpio */ -#define SDMMCHOST_CARD_DETECT_GPIO_STATUS() BOARD_USDHC_CD_STATUS() -#define SDMMCHOST_CARD_DETECT_GPIO_INIT() BOARD_USDHC_CD_GPIO_INIT() -#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_STATUS() BOARD_USDHC_CD_INTERRUPT_STATUS() -#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_STATUS_CLEAR(flag) BOARD_USDHC_CD_CLEAR_INTERRUPT(flag) -#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_HANDLER BOARD_USDHC_CD_PORT_IRQ_HANDLER -#define SDMMCHOST_CARD_DETECT_GPIO_IRQ BOARD_USDHC_CD_PORT_IRQ -/* sd card detect through host CD */ -#define SDMMCHOST_CARD_DETECT_INSERT_ENABLE(base) (USDHC_EnableInterruptStatus(base, kUSDHC_CardInsertionFlag)) -#define SDMMCHOST_CARD_DETECT_REMOVE_ENABLE(base) (USDHC_EnableInterruptStatus(base, kUSDHC_CardRemovalFlag)) -#define SDMMCHOST_CARD_DETECT_INSERT_STATUS(base) (USDHC_DetectCardInsert(base)) -#define SDMMCHOST_CARD_DETECT_REMOVE_STATUS(base) (USDHC_GetInterruptStatusFlags(base, kUSDHC_CardRemovalFlag)) -#define SDMMCHOST_CARD_DETECT_INSERT_INTERRUPT_ENABLE(base) \ - (USDHC_EnableInterruptSignal(base, kUSDHC_CardInsertionFlag)) -#define SDMMCHOST_CARD_DETECT_REMOVE_INTERRUPT_ENABLE(base) (USDHC_EnableInterruptSignal(base, kUSDHC_CardRemovalFlag)) -#define SDMMCHOST_CARD_DETECT_DATA3_ENABLE(base, flag) (USDHC_CardDetectByData3(base, flag)) - -/* define card detect pin voltage level when card inserted */ -#if defined BOARD_USDHC_CARD_INSERT_CD_LEVEL -#define SDMMCHOST_CARD_INSERT_CD_LEVEL BOARD_USDHC_CARD_INSERT_CD_LEVEL -#else -#define SDMMCHOST_CARD_INSERT_CD_LEVEL (0U) + USDHC_EnableHS400Mode(host->hostController.base, enable); #endif -#define SDMMCHOST_ENABLE_TUNING_FLAG(data) (data.dataType = kUSDHC_TransferDataTuning) -#define SDMMCHOST_ENABLE_BOOT_FLAG(data) (data.dataType = kUSDHC_TransferDataBoot) -#define SDMMCHOST_ENABLE_BOOT_CONTINOUS_FLAG(data) (data.dataType = kUSDHC_TransferDataBootcontinous) -#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(config) (config->blockSize) -#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(config) (config->blockCount) -#define SDMMCHOST_GET_HOST_CONFIG_BOOT_MODE(config) (config->bootMode) -#define SDMMCHOST_EMPTY_CMD_FLAG(command) (command.type = kCARD_CommandTypeEmpty) -/*! @brief USDHC host capability*/ -enum _host_capability +} + +/*! + * @brief enable STROBE DLL. + * @param host host handler + * @param enable true is enable, false is disable. + */ +static inline void SDMMCHOST_EnableStrobeDll(sdmmchost_t *host, bool enable) { - kSDMMCHOST_SupportAdma = kUSDHC_SupportAdmaFlag, - kSDMMCHOST_SupportHighSpeed = kUSDHC_SupportHighSpeedFlag, - kSDMMCHOST_SupportDma = kUSDHC_SupportDmaFlag, - kSDMMCHOST_SupportSuspendResume = kUSDHC_SupportSuspendResumeFlag, - kSDMMCHOST_SupportV330 = kUSDHC_SupportV330Flag, /* this define should depend on your board config */ - kSDMMCHOST_SupportV300 = kUSDHC_SupportV300Flag, /* this define should depend on your board config */ -#if defined(BOARD_SD_SUPPORT_180V) && !BOARD_SD_SUPPORT_180V - kSDMMCHOST_SupportV180 = SDMMCHOST_NOT_SUPPORT, /* this define should depend on you board config */ -#else - kSDMMCHOST_SupportV180 = kUSDHC_SupportV180Flag, /* this define should depend on you board config */ -#endif - kSDMMCHOST_SupportV120 = SDMMCHOST_NOT_SUPPORT, - kSDMMCHOST_Support4BitBusWidth = kUSDHC_Support4BitFlag, -#if defined(BOARD_MMC_SUPPORT_8BIT_BUS) -#if BOARD_MMC_SUPPORT_8BIT_BUS - kSDMMCHOST_Support8BitBusWidth = kUSDHC_Support8BitFlag, -#else - kSDMMCHOST_Support8BitBusWidth = SDMMCHOST_NOT_SUPPORT, -#endif -#else - kSDMMCHOST_Support8BitBusWidth = kUSDHC_Support8BitFlag, -#endif - kSDMMCHOST_SupportDDR50 = kUSDHC_SupportDDR50Flag, - kSDMMCHOST_SupportSDR104 = kUSDHC_SupportSDR104Flag, - kSDMMCHOST_SupportSDR50 = kUSDHC_SupportSDR50Flag, - kSDMMCHOST_SupportHS200 = kUSDHC_SupportSDR104Flag, #if FSL_FEATURE_USDHC_HAS_HS400_MODE - kSDMMCHOST_SupportHS400 = SDMMCHOST_SUPPORT -#else - kSDMMCHOST_SupportHS400 = SDMMCHOST_NOT_SUPPORT, + if (enable) + { + USDHC_ConfigStrobeDLL(host->hostController.base, SDMMCHOST_STROBE_DLL_DELAY_TARGET, + SDMMCHOST_STROBE_DLL_DELAY_UPDATE_INTERVAL); + USDHC_EnableStrobeDLL(host->hostController.base, enable); + } + else + { + USDHC_EnableStrobeDLL(host->hostController.base, enable); + } #endif -}; - -/* Endian mode. */ -#define USDHC_ENDIAN_MODE kUSDHC_EndianModeLittle - -/* DMA mode */ -#define USDHC_DMA_MODE kUSDHC_DmaModeAdma2 -/* address align */ -#define SDMMCHOST_DMA_BUFFER_ADDR_ALIGN (USDHC_ADMA2_ADDRESS_ALIGN) +} -/* Read/write watermark level. The bigger value indicates DMA has higher read/write performance. */ -#define USDHC_READ_WATERMARK_LEVEL (0x80U) -#define USDHC_WRITE_WATERMARK_LEVEL (0x80U) +/*! + * @brief start read boot data. + * @param host host handler + * @param hostConfig boot configuration + * @param cmd boot command + * @param buffer buffer address + */ +status_t SDMMCHOST_StartBoot(sdmmchost_t *host, + sdmmchost_boot_config_t *hostConfig, + sdmmchost_cmd_t *cmd, + uint8_t *buffer); -/* ADMA table length united as word. - * - * One ADMA2 table item occupy two words which can transfer maximum 0xFFFFU bytes one time. - * The more data to be transferred in one time, the bigger value of SDHC_ADMA_TABLE_WORDS need to be set. +/*! + * @brief read boot data. + * @param host host handler + * @param hostConfig boot configuration + * @param buffer buffer address */ -#define USDHC_ADMA_TABLE_WORDS (8U) /* define the ADMA descriptor table length */ -#define USDHC_ADMA2_ADDR_ALIGN (4U) /* define the ADMA2 descriptor table addr align size */ -#define USDHC_READ_BURST_LEN (8U) /*!< number of words USDHC read in a single burst */ -#define USDHC_WRITE_BURST_LEN (8U) /*!< number of words USDHC write in a single burst */ -#define USDHC_DATA_TIMEOUT (0xFU) /*!< data timeout counter value */ +status_t SDMMCHOST_ReadBootData(sdmmchost_t *host, sdmmchost_boot_config_t *hostConfig, uint8_t *buffer); -#endif /* (defined(FSL_FEATURE_SOC_SDHC_COUNT) && (FSL_FEATURE_SOC_SDHC_COUNT > 0U)) */ +/*! + * @brief enable boot mode. + * @param host host handler + * @param enable true is enable, false is disable + */ +static inline void SDMMCHOST_EnableBoot(sdmmchost_t *host, bool enable) +{ + USDHC_EnableMmcBoot(host->hostController.base, enable); +} -/*! @brief card detect callback definition */ -typedef void (*sdmmchost_cd_callback_t)(bool isInserted, void *userData); +/*! + * @brief card interrupt function. + * @param host host handler + * @param sdioInt card interrupt configuration + */ +status_t SDMMCHOST_CardIntInit(sdmmchost_t *host, void *sdioInt); -/*! @brief host Endian mode - * corresponding to driver define +/*! + * @brief force card clock on. + * @param host host handler + * @param enable true is enable, false is disable. */ -enum _sdmmchost_endian_mode +static inline void SDMMCHOST_ForceClockOn(sdmmchost_t *host, bool enable) { - kSDMMCHOST_EndianModeBig = 0U, /*!< Big endian mode */ - kSDMMCHOST_EndianModeHalfWordBig = 1U, /*!< Half word big endian mode */ - kSDMMCHOST_EndianModeLittle = 2U, /*!< Little endian mode */ -}; + USDHC_ForceClockOn(host->hostController.base, enable); +} -/*! @brief sd card detect type */ -typedef enum _sdmmchost_detect_card_type -{ - kSDMMCHOST_DetectCardByGpioCD, /*!< sd card detect by CD pin through GPIO */ - kSDMMCHOST_DetectCardByHostCD, /*!< sd card detect by CD pin through host */ - kSDMMCHOST_DetectCardByHostDATA3, /*!< sd card detect by DAT3 pin through host */ -} sdmmchost_detect_card_type_t; +/*! + * @brief switch to voltage. + * @param host host handler + * @param voltage switch to voltage level. + */ +void SDMMCHOST_SwitchToVoltage(sdmmchost_t *host, uint32_t voltage); -/*! @brief sd card detect */ -typedef struct _sdmmchost_detect_card -{ - sdmmchost_detect_card_type_t cdType; /*!< card detect type */ - uint32_t cdTimeOut_ms; /*!< card detect timeout which allow 0 - 0xFFFFFFF, value 0 will return immediately, value - 0xFFFFFFFF will block until card is insert */ +/*! + * @brief card detect init function. + * @param host host handler + * @param cd card detect configuration + */ +status_t SDMMCHOST_CardDetectInit(sdmmchost_t *host, void *cd); - sdmmchost_cd_callback_t cardInserted; /*!< card inserted callback which is meaningful for interrupt case */ - sdmmchost_cd_callback_t cardRemoved; /*!< card removed callback which is meaningful for interrupt case */ +/*! + * @brief Detect card insert, only need for SD cases. + * @param host host handler + * @param waitCardStatus status which user want to wait + * @param timeout wait time out. + * @retval kStatus_Success detect card insert + * @retval kStatus_Fail card insert event fail + */ +status_t SDMMCHOST_PollingCardDetectStatus(sdmmchost_t *host, uint32_t waitCardStatus, uint32_t timeout); - void *userData; /*!< user data */ -} sdmmchost_detect_card_t; +/*! + * @brief card detect status. + * @param host host handler + * @retval kSD_Inserted, kSD_Removed + */ +uint32_t SDMMCHOST_CardDetectStatus(sdmmchost_t *host); -/*! @brief card power control function pointer */ -typedef void (*sdmmchost_pwr_t)(void); +/*! + * @brief Init host controller. + * + * Thread safe function, please note that the function will create the mutex lock dynamically by default, + * so to avoid the mutex create redundantly, application must follow bellow sequence for card re-initialization + * @code + * SDMMCHOST_Deinit(host); + * SDMMCHOST_Init(host); + * @endcode + * + * @param host host handler + * @retval kStatus_Success host init success + * @retval kStatus_Fail event fail + */ +status_t SDMMCHOST_Init(sdmmchost_t *host); -/*! @brief card power control */ -typedef struct _sdmmchost_pwr_card -{ - sdmmchost_pwr_t powerOn; /*!< power on function pointer */ - uint32_t powerOnDelay_ms; /*!< power on delay */ +/*! + * @brief Deinit host controller. + * Please note it is a thread safe function. + * + * @param host host handler + */ +void SDMMCHOST_Deinit(sdmmchost_t *host); - sdmmchost_pwr_t powerOff; /*!< power off function pointer */ - uint32_t powerOffDelay_ms; /*!< power off delay */ -} sdmmchost_pwr_card_t; +/*! + * @brief host power off card function. + * @param host host handler + * @param enable true is power on, false is power down. + */ +void SDMMCHOST_SetCardPower(sdmmchost_t *host, bool enable); -/******************************************************************************* - * API - ******************************************************************************/ -#if defined(__cplusplus) -extern "C" -{ +#if defined SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER && SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER +/*! + * @brief Install cache line size align buffer for the transfer require cache line size align. + * @param host host handler + * @param cacheAlignBuffer cache line size align buffer pointer. + * @param cacheAlignBufferSize cache line size align buffer size. + */ +void SDMMCHOST_InstallCacheAlignBuffer(sdmmchost_t *host, void *cacheAlignBuffer, uint32_t cacheAlignBufferSize); #endif - /*! - * @name adaptor function - * @{ - */ - - /*! - * @brief host not support function, this function is used for host not support feature - * @param void parameter ,used to avoid build warning - * @retval kStatus_Fail ,host do not suppport - */ - static inline status_t SDMMCHOST_NotSupport(void *parameter) - { - parameter = parameter; - return kStatus_Success; - } +/*! + * @brief host transfer function. + * + * Please note it is a thread safe function. + * + * @note the host transfer function support below functionality, + * 1. Non-cache line size alignment check on the data buffer, it is means that no matter the data buffer used for data + * transfer is align with cache line size or not, sdmmc host driver will use the address directly. + * 2. Cache line size alignment check on the data buffer, sdmmc host driver will check the data buffer address, if the + * buffer is not align with cache line size, sdmmc host driver will convert it to cache line size align buffer, the + * functionality is enabled by \#define SDMMCHOST_ENABLE_CACHE_LINE_ALIGN_TRANSFER 1 \#define + * FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER 1U If application would like to enable the cache line size align + * functionality, please make sure the + * SDMMCHOST_InstallCacheAlignBuffer is called before submit data transfer request and make sure the installing buffer + * size is not smaller than 2 * cache line size. + * + * @param host host handler + * @param content transfer content. + */ +status_t SDMMCHOST_TransferFunction(sdmmchost_t *host, sdmmchost_transfer_t *content); - /*! - * @brief Detect card insert, only need for SD cases. - * @param base the pointer to host base address - * @param cd card detect configuration - * @param waitCardStatus status which user want to wait - * @retval kStatus_Success detect card insert - * @retval kStatus_Fail card insert event fail - */ - status_t SDMMCHOST_WaitCardDetectStatus(SDMMCHOST_TYPE *hostBase, - const sdmmchost_detect_card_t *cd, - bool waitCardStatus); - - /*! - * @brief check card is present or not. - * @retval true card is present - * @retval false card is not present - */ - bool SDMMCHOST_IsCardPresent(void); - - /*! - * @brief Init host controller. - * @param host the pointer to host structure in card structure. - * @param userData specific user data - * @retval kStatus_Success host init success - * @retval kStatus_Fail event fail - */ - status_t SDMMCHOST_Init(SDMMCHOST_CONFIG *host, void *userData); - - /*! - * @brief reset host controller. - * @param host base address. - */ - void SDMMCHOST_Reset(SDMMCHOST_TYPE *base); - - /*! - * @brief host controller error recovery. - * @param host base address. - */ - void SDMMCHOST_ErrorRecovery(SDMMCHOST_TYPE *base); - - /*! - * @brief Deinit host controller. - * @param host the pointer to host structure in card structure. - */ - void SDMMCHOST_Deinit(void *host); - - /*! - * @brief host power off card function. - * @param base host base address. - * @param pwr depend on user define power configuration. - */ - void SDMMCHOST_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr); - - /*! - * @brief host power on card function. - * @param base host base address. - * @param pwr depend on user define power configuration. - */ - void SDMMCHOST_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr); - - /*! - * @brief SDMMC host delay function. - * @param milliseconds delay counter. - */ - void SDMMCHOST_Delay(uint32_t milliseconds); - - /* @} */ +/*! + * @brief sdmmc host excute tuning. + * + * @param host host handler + * @param tuningCmd tuning command. + * @param revBuf receive buffer pointer + * @param blockSize tuning data block size. + */ +status_t SDMMCHOST_ExecuteTuning(sdmmchost_t *host, uint32_t tuningCmd, uint32_t *revBuf, uint32_t blockSize); + +/*! + * @brief host reset function. + * + * @param host host handler + */ +void SDMMCHOST_Reset(sdmmchost_t *host); + +/*! + * @brief sdmmc host convert data sequence to little endian sequence + * + * @param host host handler. + * @param data data buffer address. + * @param wordSize data buffer size in word. + * @param format data packet format. + */ +void SDMMCHOST_ConvertDataToLittleEndian(sdmmchost_t *host, uint32_t *data, uint32_t wordSize, uint32_t format); +/* @} */ #if defined(__cplusplus) } #endif - +/* @} */ #endif /* _FSL_SDMMC_HOST_H */ diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_osa.c b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_osa.c new file mode 100644 index 0000000000000000000000000000000000000000..4730bb02e8c6dfadb3faefb54a88f817737c89a0 --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_osa.c @@ -0,0 +1,275 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_sdmmc_osa.h" + +/******************************************************************************* + * Definitons + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +/*! + * brief Initialize OSA. + */ +void SDMMC_OSAInit(void) +{ + /* Intentional empty */ +} + +/*! + * brief OSA Create event. + * param event handle. + * retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventCreate(void *eventHandle) +{ + assert(eventHandle != NULL); + +#if defined(SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE) && SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE + (void)OSA_SemaphoreCreate(&(((sdmmc_osa_event_t *)eventHandle)->handle), 0U); +#else + (void)OSA_EventCreate(&(((sdmmc_osa_event_t *)eventHandle)->handle), true); +#endif + + return kStatus_Success; +} + +/*! + * brief Wait event. + * + * param eventHandle The event type + * param eventType Timeout time in milliseconds. + * param timeoutMilliseconds timeout value in ms. + * param event event flags. + * retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventWait(void *eventHandle, uint32_t eventType, uint32_t timeoutMilliseconds, uint32_t *event) +{ + assert(eventHandle != NULL); + + osa_status_t status = KOSA_StatusError; + +#if defined(SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE) && SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE + while (true) + { + status = OSA_SemaphoreWait(&(((sdmmc_osa_event_t *)eventHandle)->handle), timeoutMilliseconds); + if (KOSA_StatusTimeout == status) + { + break; + } + + if (KOSA_StatusSuccess == status) + { + (void)SDMMC_OSAEventGet(eventHandle, eventType, event); + if ((*event & eventType) != 0U) + { + return kStatus_Success; + } + } + } + +#else + while (true) + { + status = OSA_EventWait(&(((sdmmc_osa_event_t *)eventHandle)->handle), eventType, 0, timeoutMilliseconds, event); + if ((KOSA_StatusSuccess == status) || (KOSA_StatusTimeout == status)) + { + break; + } + } + + if (KOSA_StatusSuccess == status) + { + return kStatus_Success; + } +#endif + + return kStatus_Fail; +} + +/*! + * brief set event. + * param event event handle. + * param eventType The event type + * retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventSet(void *eventHandle, uint32_t eventType) +{ + assert(eventHandle != NULL); + +#if defined(SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE) && SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE + OSA_SR_ALLOC(); + OSA_ENTER_CRITICAL(); + ((sdmmc_osa_event_t *)eventHandle)->eventFlag |= eventType; + OSA_EXIT_CRITICAL(); + + (void)OSA_SemaphorePost(&(((sdmmc_osa_event_t *)eventHandle)->handle)); +#else + (void)OSA_EventSet(&(((sdmmc_osa_event_t *)eventHandle)->handle), eventType); +#endif + + return kStatus_Success; +} + +/*! + * brief Get event flag. + * param eventHandle event handle. + * param eventType The event type + * param flag pointer to store event value. + * retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventGet(void *eventHandle, uint32_t eventType, uint32_t *flag) +{ + assert(eventHandle != NULL); + assert(flag != NULL); + +#if defined(SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE) && SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE + *flag = ((sdmmc_osa_event_t *)eventHandle)->eventFlag; +#else + (void)OSA_EventGet(&(((sdmmc_osa_event_t *)eventHandle)->handle), eventType, flag); +#endif + + return kStatus_Success; +} + +/*! + * brief clear event flag. + * param eventHandle event handle. + * param eventType The event type + * retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventClear(void *eventHandle, uint32_t eventType) +{ + assert(eventHandle != NULL); + +#if defined(SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE) && SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE + OSA_SR_ALLOC(); + OSA_ENTER_CRITICAL(); + ((sdmmc_osa_event_t *)eventHandle)->eventFlag &= ~eventType; + OSA_EXIT_CRITICAL(); +#else + (void)OSA_EventClear(&(((sdmmc_osa_event_t *)eventHandle)->handle), eventType); +#endif + + return kStatus_Success; +} + +/*! + * brief Delete event. + * param event The event handle. + */ +status_t SDMMC_OSAEventDestroy(void *eventHandle) +{ + assert(eventHandle != NULL); + +#if defined(SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE) && SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE + (void)OSA_SemaphoreDestroy(&(((sdmmc_osa_event_t *)eventHandle)->handle)); +#else + (void)OSA_EventDestroy(&(((sdmmc_osa_event_t *)eventHandle)->handle)); +#endif + + return kStatus_Success; +} + +/*! + * brief Create a mutex. + * param mutexHandle mutex handle. + * retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAMutexCreate(void *mutexHandle) +{ + assert(mutexHandle != NULL); + + (void)OSA_MutexCreate(&((sdmmc_osa_mutex_t *)mutexHandle)->handle); + + return kStatus_Success; +} + +/*! + * brief set event. + * param mutexHandle mutex handle. + * param millisec The maximum number of milliseconds to wait for the mutex. + * If the mutex is locked, Pass the value osaWaitForever_c will + * wait indefinitely, pass 0 will return KOSA_StatusTimeout + * immediately. + * retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAMutexLock(void *mutexHandle, uint32_t millisec) +{ + assert(mutexHandle != NULL); + + (void)OSA_MutexLock(&((sdmmc_osa_mutex_t *)mutexHandle)->handle, millisec); + + return kStatus_Success; +} + +/*! + * brief Get event flag. + * param mutexHandle mutex handle. + * retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAMutexUnlock(void *mutexHandle) +{ + assert(mutexHandle != NULL); + + (void)OSA_MutexUnlock(&((sdmmc_osa_mutex_t *)mutexHandle)->handle); + + return kStatus_Success; +} + +/*! + * brief Delete mutex. + * param mutexHandle The mutex handle. + */ +status_t SDMMC_OSAMutexDestroy(void *mutexHandle) +{ + assert(mutexHandle != NULL); + + (void)OSA_MutexDestroy(&((sdmmc_osa_mutex_t *)mutexHandle)->handle); + + return kStatus_Success; +} + +/*! + * brief sdmmc delay. + * param milliseconds time to delay + */ +void SDMMC_OSADelay(uint32_t milliseconds) +{ +#if (defined FSL_OSA_BM_TIMER_CONFIG) && (FSL_OSA_BM_TIMER_CONFIG == FSL_OSA_BM_TIMER_NONE) + SDK_DelayAtLeastUs(milliseconds * 1000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); +#else + OSA_TimeDelay(milliseconds); +#endif +} + +/*! + * brief sdmmc delay us. + * param microseconds time to delay + * return actual delayed microseconds + */ +uint32_t SDMMC_OSADelayUs(uint32_t microseconds) +{ +#if (defined FSL_OSA_BM_TIMER_CONFIG) && (FSL_OSA_BM_TIMER_CONFIG == FSL_OSA_BM_TIMER_NONE) + SDK_DelayAtLeastUs(microseconds, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); + return microseconds; +#else + uint32_t milliseconds = microseconds / 1000U + ((microseconds % 1000U) == 0U ? 0U : 1U); + OSA_TimeDelay(milliseconds); + return milliseconds * 1000U; +#endif +} diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_osa.h b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_osa.h new file mode 100644 index 0000000000000000000000000000000000000000..2d9101ad8dfe86f674954bb5c84beccd25379f16 --- /dev/null +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_osa.h @@ -0,0 +1,170 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_SDMMC_OSA_H_ +#define _FSL_SDMMC_OSA_H_ + +#include "fsl_common.h" +#include "fsl_os_abstraction.h" + +/*! + * @addtogroup sdmmc_osa SDMMC OSA + * @ingroup card + * @{ + */ +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*!@brief transfer event */ +#define SDMMC_OSA_EVENT_TRANSFER_CMD_SUCCESS (1UL << 0U) +#define SDMMC_OSA_EVENT_TRANSFER_CMD_FAIL (1UL << 1U) +#define SDMMC_OSA_EVENT_TRANSFER_DATA_SUCCESS (1UL << 2U) +#define SDMMC_OSA_EVENT_TRANSFER_DATA_FAIL (1UL << 3U) +#define SDMMC_OSA_EVENT_TRANSFER_DMA_COMPLETE (1UL << 4U) + +/*!@brief card detect event, start from index 8 */ +#define SDMMC_OSA_EVENT_CARD_INSERTED (1UL << 8U) +#define SDMMC_OSA_EVENT_CARD_REMOVED (1UL << 9U) + +/*!@brief enable semphore by default */ +#ifndef SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE +#define SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE 1 +#endif + +/*!@brief sdmmc osa event */ +typedef struct _sdmmc_osa_event +{ +#if defined(SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE) && SDMMC_OSA_POLLING_EVENT_BY_SEMPHORE + volatile uint32_t eventFlag; + OSA_SEMAPHORE_HANDLE_DEFINE(handle); +#else + OSA_EVENT_HANDLE_DEFINE(handle); +#endif +} sdmmc_osa_event_t; + +/*!@brief sdmmc osa mutex */ +typedef struct _sdmmc_osa_mutex +{ + OSA_MUTEX_HANDLE_DEFINE(handle); +} sdmmc_osa_mutex_t; +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name sdmmc osa Function + * @{ + */ + +/*! + * @brief Initialize OSA. + */ +void SDMMC_OSAInit(void); + +/*! + * @brief OSA Create event. + * @param eventHandle event handle. + * @retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventCreate(void *eventHandle); + +/*! + * @brief Wait event. + * + * @param eventHandle The event type + * @param eventType Timeout time in milliseconds. + * @param timeoutMilliseconds timeout value in ms. + * @param event event flags. + * @retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventWait(void *eventHandle, uint32_t eventType, uint32_t timeoutMilliseconds, uint32_t *event); + +/*! + * @brief set event. + * @param eventHandle event handle. + * @param eventType The event type + * @retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventSet(void *eventHandle, uint32_t eventType); + +/*! + * @brief Get event flag. + * @param eventHandle event handle. + * @param eventType event type. + * @param flag pointer to store event value. + * @retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventGet(void *eventHandle, uint32_t eventType, uint32_t *flag); + +/*! + * @brief clear event flag. + * @param eventHandle event handle. + * @param eventType The event type + * @retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAEventClear(void *eventHandle, uint32_t eventType); + +/*! + * @brief Delete event. + * @param eventHandle The event handle. + */ +status_t SDMMC_OSAEventDestroy(void *eventHandle); + +/*! + * @brief Create a mutex. + * @param mutexHandle mutex handle. + * @retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAMutexCreate(void *mutexHandle); + +/*! + * @brief set event. + * @param mutexHandle mutex handle. + * @param millisec The maximum number of milliseconds to wait for the mutex. + * If the mutex is locked, Pass the value osaWaitForever_c will + * wait indefinitely, pass 0 will return KOSA_StatusTimeout + * immediately. + * @retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAMutexLock(void *mutexHandle, uint32_t millisec); + +/*! + * @brief Get event flag. + * @param mutexHandle mutex handle. + * @retval kStatus_Fail or kStatus_Success. + */ +status_t SDMMC_OSAMutexUnlock(void *mutexHandle); + +/*! + * @brief Delete mutex. + * @param mutexHandle The mutex handle. + */ +status_t SDMMC_OSAMutexDestroy(void *mutexHandle); + +/*! + * @brief sdmmc delay. + * @param milliseconds time to delay + */ +void SDMMC_OSADelay(uint32_t milliseconds); + +/*! + * @brief sdmmc delay us. + * @param microseconds time to delay + * @return actual delayed microseconds + */ +uint32_t SDMMC_OSADelayUs(uint32_t microseconds); + +/* @} */ + +#if defined(__cplusplus) +} +#endif +/* @} */ +#endif /* _FSL_SDMMC_OSA_H_*/ diff --git a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_spec.h b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_spec.h index f7919137deaafe0b5cad41cc16fe0ad975a2302c..f2e602c30cc1091020d40a8459b5f8c7320ef067 100644 --- a/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_spec.h +++ b/module-bsp/board/rt1051/bsp/eMMC/fsl_sdmmc_spec.h @@ -1,35 +1,9 @@ /* - * The Clear BSD License * Copyright (c) 2015, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted (subject to the limitations in the disclaimer below) provided - * that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * o Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _FSL_SDMMC_SPEC_H_ @@ -37,6 +11,12 @@ #include +/*! + * @addtogroup sdmmc_common SDMMC Common + * @ingroup card + * @{ + */ + /******************************************************************************* * Definitions ******************************************************************************/ @@ -61,40 +41,48 @@ /*! @brief MMC card bus frequency in high-speed HS400 mode */ #define MMC_CLOCK_HS400 (400000000U) -/*! @brief Card status bit in R1 */ -enum _sdmmc_r1_card_status_flag -{ - kSDMMC_R1OutOfRangeFlag = (1U << 31U), /*!< Out of range status bit */ - kSDMMC_R1AddressErrorFlag = (1U << 30U), /*!< Address error status bit */ - kSDMMC_R1BlockLengthErrorFlag = (1U << 29U), /*!< Block length error status bit */ - kSDMMC_R1EraseSequenceErrorFlag = (1U << 28U), /*!< Erase sequence error status bit */ - kSDMMC_R1EraseParameterErrorFlag = (1U << 27U), /*!< Erase parameter error status bit */ - kSDMMC_R1WriteProtectViolationFlag = (1U << 26U), /*!< Write protection violation status bit */ - kSDMMC_R1CardIsLockedFlag = (1U << 25U), /*!< Card locked status bit */ - kSDMMC_R1LockUnlockFailedFlag = (1U << 24U), /*!< lock/unlock error status bit */ - kSDMMC_R1CommandCrcErrorFlag = (1U << 23U), /*!< CRC error status bit */ - kSDMMC_R1IllegalCommandFlag = (1U << 22U), /*!< Illegal command status bit */ - kSDMMC_R1CardEccFailedFlag = (1U << 21U), /*!< Card ecc error status bit */ - kSDMMC_R1CardControllerErrorFlag = (1U << 20U), /*!< Internal card controller error status bit */ - kSDMMC_R1ErrorFlag = (1U << 19U), /*!< A general or an unknown error status bit */ - kSDMMC_R1CidCsdOverwriteFlag = (1U << 16U), /*!< Cid/csd overwrite status bit */ - kSDMMC_R1WriteProtectEraseSkipFlag = (1U << 15U), /*!< Write protection erase skip status bit */ - kSDMMC_R1CardEccDisabledFlag = (1U << 14U), /*!< Card ecc disabled status bit */ - kSDMMC_R1EraseResetFlag = (1U << 13U), /*!< Erase reset status bit */ - kSDMMC_R1ReadyForDataFlag = (1U << 8U), /*!< Ready for data status bit */ - kSDMMC_R1SwitchErrorFlag = (1U << 7U), /*!< Switch error status bit */ - kSDMMC_R1ApplicationCommandFlag = (1U << 5U), /*!< Application command enabled status bit */ - kSDMMC_R1AuthenticationSequenceErrorFlag = (1U << 3U), /*!< error in the sequence of authentication process */ - - kSDMMC_R1ErrorAllFlag = - (kSDMMC_R1OutOfRangeFlag | kSDMMC_R1AddressErrorFlag | kSDMMC_R1BlockLengthErrorFlag | - kSDMMC_R1EraseSequenceErrorFlag | kSDMMC_R1EraseParameterErrorFlag | kSDMMC_R1WriteProtectViolationFlag | - kSDMMC_R1CardIsLockedFlag | kSDMMC_R1LockUnlockFailedFlag | kSDMMC_R1CommandCrcErrorFlag | - kSDMMC_R1IllegalCommandFlag | kSDMMC_R1CardEccFailedFlag | kSDMMC_R1CardControllerErrorFlag | - kSDMMC_R1ErrorFlag | kSDMMC_R1CidCsdOverwriteFlag | - kSDMMC_R1AuthenticationSequenceErrorFlag), /*!< Card error status */ +/*!@brief mask convert */ +#define SDMMC_MASK(bit) (1UL << (bit)) + +/*! @brief Card status bit in R1 + * @anchor _sdmmc_r1_card_status_flag + */ +enum +{ + kSDMMC_R1OutOfRangeFlag = 31, /*!< Out of range status bit */ + kSDMMC_R1AddressErrorFlag = 30, /*!< Address error status bit */ + kSDMMC_R1BlockLengthErrorFlag = 29, /*!< Block length error status bit */ + kSDMMC_R1EraseSequenceErrorFlag = 28, /*!< Erase sequence error status bit */ + kSDMMC_R1EraseParameterErrorFlag = 27, /*!< Erase parameter error status bit */ + kSDMMC_R1WriteProtectViolationFlag = 26, /*!< Write protection violation status bit */ + kSDMMC_R1CardIsLockedFlag = 25, /*!< Card locked status bit */ + kSDMMC_R1LockUnlockFailedFlag = 24, /*!< lock/unlock error status bit */ + kSDMMC_R1CommandCrcErrorFlag = 23, /*!< CRC error status bit */ + kSDMMC_R1IllegalCommandFlag = 22, /*!< Illegal command status bit */ + kSDMMC_R1CardEccFailedFlag = 21, /*!< Card ecc error status bit */ + kSDMMC_R1CardControllerErrorFlag = 20, /*!< Internal card controller error status bit */ + kSDMMC_R1ErrorFlag = 19, /*!< A general or an unknown error status bit */ + kSDMMC_R1CidCsdOverwriteFlag = 16, /*!< Cid/csd overwrite status bit */ + kSDMMC_R1WriteProtectEraseSkipFlag = 15, /*!< Write protection erase skip status bit */ + kSDMMC_R1CardEccDisabledFlag = 14, /*!< Card ecc disabled status bit */ + kSDMMC_R1EraseResetFlag = 13, /*!< Erase reset status bit */ + kSDMMC_R1ReadyForDataFlag = 8, /*!< Ready for data status bit */ + kSDMMC_R1SwitchErrorFlag = 7, /*!< Switch error status bit */ + kSDMMC_R1ApplicationCommandFlag = 5, /*!< Application command enabled status bit */ + kSDMMC_R1AuthenticationSequenceErrorFlag = 3, /*!< error in the sequence of authentication process */ }; +/*! @brief R1 all the error flag */ +#define SDMMC_R1_ALL_ERROR_FLAG \ + (SDMMC_MASK(kSDMMC_R1OutOfRangeFlag) | SDMMC_MASK(kSDMMC_R1AddressErrorFlag) | \ + SDMMC_MASK(kSDMMC_R1BlockLengthErrorFlag) | SDMMC_MASK(kSDMMC_R1EraseSequenceErrorFlag) | \ + SDMMC_MASK(kSDMMC_R1EraseParameterErrorFlag) | SDMMC_MASK(kSDMMC_R1WriteProtectViolationFlag) | \ + SDMMC_MASK(kSDMMC_R1CardIsLockedFlag) | SDMMC_MASK(kSDMMC_R1LockUnlockFailedFlag) | \ + SDMMC_MASK(kSDMMC_R1CommandCrcErrorFlag) | SDMMC_MASK(kSDMMC_R1IllegalCommandFlag) | \ + SDMMC_MASK(kSDMMC_R1CardEccFailedFlag) | SDMMC_MASK(kSDMMC_R1CardControllerErrorFlag) | \ + SDMMC_MASK(kSDMMC_R1ErrorFlag) | SDMMC_MASK(kSDMMC_R1CidCsdOverwriteFlag) | \ + SDMMC_MASK(kSDMMC_R1AuthenticationSequenceErrorFlag)) + /*! @brief R1: current state */ #define SDMMC_R1_CURRENT_STATE(x) (((x)&0x00001E00U) >> 9U) @@ -112,8 +100,10 @@ typedef enum _sdmmc_r1_current_state kSDMMC_R1StateDisconnect = 8U, /*!< R1: current state: disconnect */ } sdmmc_r1_current_state_t; -/*! @brief Error bit in SPI mode R1 */ -enum _sdspi_r1_error_status_flag +/*! @brief Error bit in SPI mode R1 + * @anchor _sdspi_r1_error_status_flag + */ +enum { kSDSPI_R1InIdleStateFlag = (1U << 0U), /*!< In idle state */ kSDSPI_R1EraseResetFlag = (1U << 1U), /*!< Erase reset */ @@ -124,8 +114,10 @@ enum _sdspi_r1_error_status_flag kSDSPI_R1ParameterErrorFlag = (1U << 6U), /*!< Parameter error */ }; -/*! @brief Error bit in SPI mode R2 */ -enum _sdspi_r2_error_status_flag +/*! @brief Error bit in SPI mode R2 + * @anchor _sdspi_r2_error_status_flag + */ +enum { kSDSPI_R2CardLockedFlag = (1U << 0U), /*!< Card is locked */ kSDSPI_R2WriteProtectEraseSkip = (1U << 1U), /*!< Write protect erase skip */ @@ -156,8 +148,10 @@ enum _sdspi_r2_error_status_flag /*! @brief Data error token mask */ #define SDSPI_DATA_ERROR_TOKEN_MASK (0xFU) -/*! @brief Data Error Token mask bit */ -enum _sdspi_data_error_token +/*! @brief Data Error Token mask bit + * @anchor _sdspi_data_error_token + */ +enum { kSDSPI_DataErrorTokenError = (1U << 0U), /*!< Data error */ kSDSPI_DataErrorTokenCardControllerError = (1U << 1U), /*!< Card controller error */ @@ -215,8 +209,10 @@ typedef enum _sd_application_command kSD_ApplicationSendScr = 51U, /*!< Send Scr */ } sd_application_command_t; -/*! @brief SD card command class */ -enum _sdmmc_command_class +/*! @brief SD card command class + * @anchor _sdmmc_command_class + */ +enum { kSDMMC_CommandClassBasic = (1U << 0U), /*!< Card command class 0 */ kSDMMC_CommandClassBlockRead = (1U << 2U), /*!< Card command class 2 */ @@ -229,27 +225,31 @@ enum _sdmmc_command_class kSDMMC_CommandClassSwitch = (1U << 10U), /*!< Card command class 10 */ }; -/*! @brief OCR register in SD card */ -enum _sd_ocr_flag +/*! @brief OCR register in SD card + * @anchor _sd_ocr_flag + */ +enum { - kSD_OcrPowerUpBusyFlag = (1U << 31U), /*!< Power up busy status */ - kSD_OcrHostCapacitySupportFlag = (1U << 30U), /*!< Card capacity status */ + kSD_OcrPowerUpBusyFlag = 31, /*!< Power up busy status */ + kSD_OcrHostCapacitySupportFlag = 30, /*!< Card capacity status */ kSD_OcrCardCapacitySupportFlag = kSD_OcrHostCapacitySupportFlag, /*!< Card capacity status */ - kSD_OcrSwitch18RequestFlag = (1U << 24U), /*!< Switch to 1.8V request */ + kSD_OcrSwitch18RequestFlag = 24, /*!< Switch to 1.8V request */ kSD_OcrSwitch18AcceptFlag = kSD_OcrSwitch18RequestFlag, /*!< Switch to 1.8V accepted */ - kSD_OcrVdd27_28Flag = (1U << 15U), /*!< VDD 2.7-2.8 */ - kSD_OcrVdd28_29Flag = (1U << 16U), /*!< VDD 2.8-2.9 */ - kSD_OcrVdd29_30Flag = (1U << 17U), /*!< VDD 2.9-3.0 */ - kSD_OcrVdd30_31Flag = (1U << 18U), /*!< VDD 2.9-3.0 */ - kSD_OcrVdd31_32Flag = (1U << 19U), /*!< VDD 3.0-3.1 */ - kSD_OcrVdd32_33Flag = (1U << 20U), /*!< VDD 3.1-3.2 */ - kSD_OcrVdd33_34Flag = (1U << 21U), /*!< VDD 3.2-3.3 */ - kSD_OcrVdd34_35Flag = (1U << 22U), /*!< VDD 3.3-3.4 */ - kSD_OcrVdd35_36Flag = (1U << 23U), /*!< VDD 3.4-3.5 */ + kSD_OcrVdd27_28Flag = 15, /*!< VDD 2.7-2.8 */ + kSD_OcrVdd28_29Flag = 16, /*!< VDD 2.8-2.9 */ + kSD_OcrVdd29_30Flag = 17, /*!< VDD 2.9-3.0 */ + kSD_OcrVdd30_31Flag = 18, /*!< VDD 2.9-3.0 */ + kSD_OcrVdd31_32Flag = 19, /*!< VDD 3.0-3.1 */ + kSD_OcrVdd32_33Flag = 20, /*!< VDD 3.1-3.2 */ + kSD_OcrVdd33_34Flag = 21, /*!< VDD 3.2-3.3 */ + kSD_OcrVdd34_35Flag = 22, /*!< VDD 3.3-3.4 */ + kSD_OcrVdd35_36Flag = 23, /*!< VDD 3.4-3.5 */ }; -/*! @brief SD card specification version number */ -enum _sd_specification_version +/*! @brief SD card specification version number + * @anchor _sd_specification_version + */ +enum { kSD_SpecificationVersion1_0 = (1U << 0U), /*!< SD card version 1.0-1.01 */ kSD_SpecificationVersion1_1 = (1U << 1U), /*!< SD card version 1.10 */ @@ -257,13 +257,6 @@ enum _sd_specification_version kSD_SpecificationVersion3_0 = (1U << 3U), /*!< SD card version 3.0 */ }; -/*! @brief SD card bus width */ -typedef enum _sd_data_bus_width -{ - kSD_DataBusWidth1Bit = 0U, /*!< SD data bus width 1-bit mode */ - kSD_DataBusWidth4Bit = 1U, /*!< SD data bus width 4-bit mode */ -} sd_data_bus_width_t; - /*! @brief SD card switch mode */ typedef enum _sd_switch_mode { @@ -271,8 +264,10 @@ typedef enum _sd_switch_mode kSD_SwitchSet = 1U, /*!< SD switch mode 1: set function */ } sd_switch_mode_t; -/*! @brief SD card CSD register flags */ -enum _sd_csd_flag +/*! @brief SD card CSD register flags + * @anchor _sd_csd_flag + */ +enum { kSD_CsdReadBlockPartialFlag = (1U << 0U), /*!< Partial blocks for read allowed [79:79] */ kSD_CsdWriteBlockMisalignFlag = (1U << 1U), /*!< Write block misalignment [78:78] */ @@ -287,15 +282,19 @@ enum _sd_csd_flag kSD_CsdTemporaryWriteProtectFlag = (1U << 10U), /*!< Temporary write protection [12:12] */ }; -/*! @brief SD card SCR register flags */ -enum _sd_scr_flag +/*! @brief SD card SCR register flags + * @anchor _sd_scr_flag + */ +enum { kSD_ScrDataStatusAfterErase = (1U << 0U), /*!< Data status after erases [55:55] */ kSD_ScrSdSpecification3 = (1U << 1U), /*!< Specification version 3.00 or higher [47:47]*/ }; -/*! @brief SD timing function number */ -enum _sd_timing_function +/*! @brief SD timing function number + * @anchor _sd_timing_function + */ +enum { kSD_FunctionSDR12Deafult = 0U, /*!< SDR12 mode & default*/ kSD_FunctionSDR25HighSpeed = 1U, /*!< SDR25 & high speed*/ @@ -304,8 +303,10 @@ enum _sd_timing_function kSD_FunctionDDR50 = 4U, /*!< DDR50 mode*/ }; -/*! @brief SD group number */ -enum _sd_group_num +/*! @brief SD group number + * @anchor _sd_group_num + */ +enum { kSD_GroupTimingMode = 0U, /*!< acess mode group*/ kSD_GroupCommandSystem = 1U, /*!< command system group*/ @@ -370,27 +371,38 @@ typedef enum _sdmmc_command kSDMMC_ReadOcr = 58U, /*!< Read OCR */ } sdmmc_command_t; -/*! @brief sdio card cccr register addr */ -enum _sdio_cccr_reg -{ - kSDIO_RegCCCRSdioVer = 0x00U, /*!< CCCR & SDIO version*/ - kSDIO_RegSDVersion = 0x01U, /*!< SD version */ - kSDIO_RegIOEnable = 0x02U, /*!< io enable register */ - kSDIO_RegIOReady = 0x03U, /*!< io ready register */ - kSDIO_RegIOIntEnable = 0x04U, /*!< io interrupt enable register */ - kSDIO_RegIOIntPending = 0x05U, /*!< io interrupt pending register */ - kSDIO_RegIOAbort = 0x06U, /*!< io abort register */ - kSDIO_RegBusInterface = 0x07U, /*!< bus interface register */ - kSDIO_RegCardCapability = 0x08U, /*!< card capability register */ - kSDIO_RegCommonCISPointer = 0x09U, /*!< common CIS pointer register */ - kSDIO_RegBusSuspend = 0x0C, /*!< bus suspend register */ - kSDIO_RegFunctionSelect = 0x0DU, /*!< function select register */ - kSDIO_RegExecutionFlag = 0x0EU, /*!< execution flag register */ - kSDIO_RegReadyFlag = 0x0FU, /*!< ready flag register */ - kSDIO_RegFN0BlockSizeLow = 0x10U, /*!< FN0 block size register */ - kSDIO_RegFN0BlockSizeHigh = 0x11U, /*!< FN0 block size register */ - kSDIO_RegPowerControl = 0x12U, /*!< power control register */ - kSDIO_RegHighSpeed = 0x13U, /*!< high speed register */ +/*! @brief sdio card cccr register number */ +#define SDIO_CCCR_REG_NUMBER (0x16U) +/*! @brief sdio IO ready timeout steps */ +#ifndef SDIO_IO_READY_TIMEOUT_UNIT +#define SDIO_IO_READY_TIMEOUT_UNIT (10U) +#endif +/*! @brief sdio card cccr register addr + * @anchor _sdio_cccr_reg + */ +enum +{ + kSDIO_RegCCCRSdioVer = 0x00U, /*!< CCCR & SDIO version*/ + kSDIO_RegSDVersion = 0x01U, /*!< SD version */ + kSDIO_RegIOEnable = 0x02U, /*!< io enable register */ + kSDIO_RegIOReady = 0x03U, /*!< io ready register */ + kSDIO_RegIOIntEnable = 0x04U, /*!< io interrupt enable register */ + kSDIO_RegIOIntPending = 0x05U, /*!< io interrupt pending register */ + kSDIO_RegIOAbort = 0x06U, /*!< io abort register */ + kSDIO_RegBusInterface = 0x07U, /*!< bus interface register */ + kSDIO_RegCardCapability = 0x08U, /*!< card capability register */ + kSDIO_RegCommonCISPointer = 0x09U, /*!< common CIS pointer register */ + kSDIO_RegBusSuspend = 0x0C, /*!< bus suspend register */ + kSDIO_RegFunctionSelect = 0x0DU, /*!< function select register */ + kSDIO_RegExecutionFlag = 0x0EU, /*!< execution flag register */ + kSDIO_RegReadyFlag = 0x0FU, /*!< ready flag register */ + kSDIO_RegFN0BlockSizeLow = 0x10U, /*!< FN0 block size register */ + kSDIO_RegFN0BlockSizeHigh = 0x11U, /*!< FN0 block size register */ + kSDIO_RegPowerControl = 0x12U, /*!< power control register */ + kSDIO_RegBusSpeed = 0x13U, /*!< bus speed register */ + kSDIO_RegUHSITimingSupport = 0x14U, /*!< UHS-I timing support register */ + kSDIO_RegDriverStrength = 0x15U, /*!< Driver strength register */ + kSDIO_RegInterruptExtension = 0x16U, /*!< Interrupt extension register */ }; /*! @brief sdio card individual commands */ @@ -430,13 +442,15 @@ typedef enum _sdio_func_num #define SDIO_EXTEND_CMD_OP_CODE_MASK (0x04000000U) /*!< op code mask */ #define SDIO_EXTEND_CMD_COUNT_MASK (0x1FFU) /*!< byte/block count mask */ #define SDIO_MAX_BLOCK_SIZE (2048U) /*!< max block size */ -#define SDIO_FBR_BASE(x) (x * 0x100U) /*!< function basic register */ +#define SDIO_FBR_BASE(x) ((x)*0x100U) /*!< function basic register */ #define SDIO_TPL_CODE_END (0xFFU) /*!< tuple end */ #define SDIO_TPL_CODE_MANIFID (0x20U) /*!< manufacturer ID */ #define SDIO_TPL_CODE_FUNCID (0x21U) /*!< function ID */ #define SDIO_TPL_CODE_FUNCE (0x22U) /*!< function extension tuple*/ -/*! @brief sdio command response flag */ -enum _sdio_status_flag +/*! @brief sdio command response flag + * @anchor _sdio_status_flag + */ +enum { kSDIO_StatusCmdCRCError = 0x8000U, /*!< the CRC check of the previous cmd fail*/ kSDIO_StatusIllegalCmd = 0x4000U, /*!< cmd illegal for the card state */ @@ -446,49 +460,88 @@ enum _sdio_status_flag kSDIO_StatusOutofRange = 0x0100U, /*!< cmd argument was out of the allowed range*/ }; -/*! @brief sdio operation condition flag */ -enum _sdio_ocr_flag -{ - kSDIO_OcrPowerUpBusyFlag = (1U << 31U), /*!< Power up busy status */ - kSDIO_OcrIONumber = (7U << 28U), /*!< number of IO function */ - kSDIO_OcrMemPresent = (1U << 27U), /*!< memory present flag */ - - kSDIO_OcrVdd20_21Flag = (1U << 8U), /*!< VDD 2.0-2.1 */ - kSDIO_OcrVdd21_22Flag = (1U << 9U), /*!< VDD 2.1-2.2 */ - kSDIO_OcrVdd22_23Flag = (1U << 10U), /*!< VDD 2.2-2.3 */ - kSDIO_OcrVdd23_24Flag = (1U << 11U), /*!< VDD 2.3-2.4 */ - kSDIO_OcrVdd24_25Flag = (1U << 12U), /*!< VDD 2.4-2.5 */ - kSDIO_OcrVdd25_26Flag = (1U << 13U), /*!< VDD 2.5-2.6 */ - kSDIO_OcrVdd26_27Flag = (1U << 14U), /*!< VDD 2.6-2.7 */ - kSDIO_OcrVdd27_28Flag = (1U << 15U), /*!< VDD 2.7-2.8 */ - kSDIO_OcrVdd28_29Flag = (1U << 16U), /*!< VDD 2.8-2.9 */ - kSDIO_OcrVdd29_30Flag = (1U << 17U), /*!< VDD 2.9-3.0 */ - kSDIO_OcrVdd30_31Flag = (1U << 18U), /*!< VDD 2.9-3.0 */ - kSDIO_OcrVdd31_32Flag = (1U << 19U), /*!< VDD 3.0-3.1 */ - kSDIO_OcrVdd32_33Flag = (1U << 20U), /*!< VDD 3.1-3.2 */ - kSDIO_OcrVdd33_34Flag = (1U << 21U), /*!< VDD 3.2-3.3 */ - kSDIO_OcrVdd34_35Flag = (1U << 22U), /*!< VDD 3.3-3.4 */ - kSDIO_OcrVdd35_36Flag = (1U << 23U), /*!< VDD 3.4-3.5 */ - +/*! @brief sdio operation condition flag + * @anchor _sdio_ocr_flag + */ +enum +{ + kSDIO_OcrPowerUpBusyFlag = 31, /*!< Power up busy status */ + kSDIO_OcrIONumber = 28, /*!< number of IO function */ + kSDIO_OcrMemPresent = 27, /*!< memory present flag */ + + kSDIO_OcrVdd20_21Flag = 8, /*!< VDD 2.0-2.1 */ + kSDIO_OcrVdd21_22Flag = 9, /*!< VDD 2.1-2.2 */ + kSDIO_OcrVdd22_23Flag = 10, /*!< VDD 2.2-2.3 */ + kSDIO_OcrVdd23_24Flag = 11, /*!< VDD 2.3-2.4 */ + kSDIO_OcrVdd24_25Flag = 12, /*!< VDD 2.4-2.5 */ + kSDIO_OcrVdd25_26Flag = 13, /*!< VDD 2.5-2.6 */ + kSDIO_OcrVdd26_27Flag = 14, /*!< VDD 2.6-2.7 */ + kSDIO_OcrVdd27_28Flag = 15, /*!< VDD 2.7-2.8 */ + kSDIO_OcrVdd28_29Flag = 16, /*!< VDD 2.8-2.9 */ + kSDIO_OcrVdd29_30Flag = 17, /*!< VDD 2.9-3.0 */ + kSDIO_OcrVdd30_31Flag = 18, /*!< VDD 2.9-3.0 */ + kSDIO_OcrVdd31_32Flag = 19, /*!< VDD 3.0-3.1 */ + kSDIO_OcrVdd32_33Flag = 20, /*!< VDD 3.1-3.2 */ + kSDIO_OcrVdd33_34Flag = 21, /*!< VDD 3.2-3.3 */ + kSDIO_OcrVdd34_35Flag = 22, /*!< VDD 3.3-3.4 */ + kSDIO_OcrVdd35_36Flag = 23, /*!< VDD 3.4-3.5 */ }; +/*! @brief sdio ocr voltage window mask */ +#define SDIO_OCR_VOLTAGE_WINDOW_MASK (0xFFFFU << 8U) -/*! @brief sdio capability flag */ -enum _sdio_capability_flag -{ - kSDIO_CCCRSupportDirectCmdDuringDataTrans = (1U << 0U), /*!< support direct cmd during data transfer */ - kSDIO_CCCRSupportMultiBlock = (1U << 1U), /*!< support multi block mode */ - kSDIO_CCCRSupportReadWait = (1U << 2U), /*!< support read wait */ - kSDIO_CCCRSupportSuspendResume = (1U << 3U), /*!< support suspend resume */ - kSDIO_CCCRSupportIntDuring4BitDataTrans = (1U << 4U), /*!< support interrupt during 4-bit data transfer */ - kSDIO_CCCRSupportLowSpeed1Bit = (1U << 6U), /*!< support low speed 1bit mode */ - kSDIO_CCCRSupportLowSpeed4Bit = (1U << 7U), /*!< support low speed 4bit mode */ - kSDIO_CCCRSupportMasterPowerControl = (1U << 8U), /*!< support master power control */ - kSDIO_CCCRSupportHighSpeed = (1U << 9U), /*!< support high speed */ - kSDIO_CCCRSupportContinuousSPIInt = (1U << 10U), /*!< support continuous SPI interrupt */ -}; +/*! @brief sdio ocr reigster IO NUMBER mask */ +#define SDIO_OCR_IO_NUM_MASK (7U << kSDIO_OcrIONumber) -/*! @brief sdio fbr flag */ -enum _sdio_fbr_flag +/*! @brief sdio capability flag + * @anchor _sdio_capability_flag + */ +enum +{ + kSDIO_CCCRSupportDirectCmdDuringDataTrans = (1UL << 0U), /*!< support direct cmd during data transfer */ + kSDIO_CCCRSupportMultiBlock = (1UL << 1U), /*!< support multi block mode */ + kSDIO_CCCRSupportReadWait = (1UL << 2U), /*!< support read wait */ + kSDIO_CCCRSupportSuspendResume = (1UL << 3U), /*!< support suspend resume */ + kSDIO_CCCRSupportIntDuring4BitDataTrans = (1UL << 4U), /*!< support interrupt during 4-bit data transfer */ + kSDIO_CCCRSupportLowSpeed1Bit = (1UL << 6U), /*!< support low speed 1bit mode */ + kSDIO_CCCRSupportLowSpeed4Bit = (1UL << 7U), /*!< support low speed 4bit mode */ + kSDIO_CCCRSupportMasterPowerControl = (1UL << 8U), /*!< support master power control */ + kSDIO_CCCRSupportHighSpeed = (1UL << 9U), /*!< support high speed */ + kSDIO_CCCRSupportContinuousSPIInt = (1UL << 10U), /*!< support continuous SPI interrupt */ +}; +/*! @brief UHS timing mode flag */ +#define SDIO_CCCR_SUPPORT_HIGHSPEED (1UL << 9U) +#define SDIO_CCCR_SUPPORT_SDR50 (1UL << 11U) +#define SDIO_CCCR_SUPPORT_SDR104 (1UL << 12U) +#define SDIO_CCCR_SUPPORT_DDR50 (1UL << 13U) +#define SDIO_CCCR_SUPPORT_DRIVER_TYPE_A (1UL << 14U) +#define SDIO_CCCR_SUPPORT_DRIVER_TYPE_C (1UL << 15U) +#define SDIO_CCCR_SUPPORT_DRIVER_TYPE_D (1UL << 16U) +#define SDIO_CCCR_SUPPORT_ASYNC_INT (1UL << 17U) + +#define SDIO_CCCR_BUS_SPEED_MASK (7U << 1U) +#define SDIO_CCCR_ENABLE_HIGHSPEED_MODE (1U << 1U) +#define SDIO_CCCR_ENABLE_SDR50_MODE (2U << 1U) +#define SDIO_CCCR_ENABLE_SDR104_MODE (3U << 1U) +#define SDIO_CCCR_ENABLE_DDR50_MODE (4U << 1U) + +/*! @brief Driver type flag */ +#define SDIO_CCCR_DRIVER_TYPE_MASK (3U << 4U) +#define SDIO_CCCR_ENABLE_DRIVER_TYPE_B (0U << 4U) +#define SDIO_CCCR_ENABLE_DRIVER_TYPE_A (1U << 4U) +#define SDIO_CCCR_ENABLE_DRIVER_TYPE_C (2U << 4U) +#define SDIO_CCCR_ENABLE_DRIVER_TYPE_D (3U << 4U) + +/*! @brief aync interrupt flag*/ +#define SDIO_CCCR_ASYNC_INT_MASK (1U) +#define SDIO_CCCR_ENABLE_AYNC_INT (1U << 1U) + +/*! @brief 8 bit data bus flag*/ +#define SDIO_CCCR_SUPPORT_8BIT_BUS (1UL << 18U) +#define SDIO_CCCR_SUPPORT_LOW_SPEED_4BIT_BUS (1U << 7U) +/*! @brief sdio fbr flag + * @anchor _sdio_fbr_flag + */ +enum { kSDIO_FBRSupportCSA = (1U << 0U), /*!< function support CSA */ kSDIO_FBRSupportPowerSelection = (1U << 1U), /*!< function support power selection */ @@ -497,8 +550,9 @@ enum _sdio_fbr_flag /*! @brief sdio bus width */ typedef enum _sdio_bus_width { - kSDIO_DataBus1Bit = 0x00U, /*!< 1bit bus mode */ + kSDIO_DataBus1Bit = 0x00U, /*!< 1 bit bus mode */ kSDIO_DataBus4Bit = 0X02U, /*!< 4 bit bus mode*/ + kSDIO_DataBus8Bit = 0X03U, /*!< 8 bit bus mode*/ } sdio_bus_width_t; /*! @brief MMC card individual commands */ @@ -601,14 +655,16 @@ typedef enum _mmc_specification_version #define MMC_TRANSFER_SPEED_MULTIPLIER_MASK (0x78U) /*! @brief Read the value of FREQUENCY UNIT in TRANSFER SPEED. */ -#define READ_MMC_TRANSFER_SPEED_FREQUENCY_UNIT(CSD) \ - (((CSD.transferSpeed) & MMC_TRANSFER_SPEED_FREQUENCY_UNIT_MASK) >> MMC_TRANSFER_SPEED_FREQUENCY_UNIT_SHIFT) +#define READ_MMC_TRANSFER_SPEED_FREQUENCY_UNIT(CSD) \ + ((((CSD).transferSpeed) & MMC_TRANSFER_SPEED_FREQUENCY_UNIT_MASK) >> MMC_TRANSFER_SPEED_FREQUENCY_UNIT_SHIFT) /*! @brief Read the value of MULTIPLER filed in TRANSFER SPEED. */ -#define READ_MMC_TRANSFER_SPEED_MULTIPLIER(CSD) \ - (((CSD.transferSpeed) & MMC_TRANSFER_SPEED_MULTIPLIER_MASK) >> MMC_TRANSFER_SPEED_MULTIPLIER_SHIFT) +#define READ_MMC_TRANSFER_SPEED_MULTIPLIER(CSD) \ + ((((CSD).transferSpeed) & MMC_TRANSFER_SPEED_MULTIPLIER_MASK) >> MMC_TRANSFER_SPEED_MULTIPLIER_SHIFT) -/*! @brief MMC card Extended CSD fix version(EXT_CSD_REV in Extended CSD) */ -enum _mmc_extended_csd_revision +/*! @brief MMC card Extended CSD fix version(EXT_CSD_REV in Extended CSD) + * @anchor _mmc_extended_csd_revision + */ +enum { kMMC_ExtendedCsdRevision10 = 0U, /*!< Revision 1.0 */ kMMC_ExtendedCsdRevision11 = 1U, /*!< Revision 1.1 */ @@ -630,8 +686,10 @@ typedef enum _mmc_command_set kMMC_CommandSet4 = 4U, /*!< Command set 4 */ } mmc_command_set_t; -/*! @brief boot support(BOOT_INFO in Extended CSD) */ -enum _mmc_support_boot_mode +/*! @brief boot support(BOOT_INFO in Extended CSD) + * @anchor _mmc_support_boot_mode + */ +enum { kMMC_SupportAlternateBoot = 1U, /*!< support alternative boot mode*/ kMMC_SupportDDRBoot = 2U, /*!< support DDR boot mode*/ @@ -641,14 +699,19 @@ enum _mmc_support_boot_mode #define MMC_POWER_CLASS_4BIT_MASK (0x0FU) /*! @brief The power class current value bit mask when bus in 8 bit mode */ #define MMC_POWER_CLASS_8BIT_MASK (0xF0U) +/*! @brief mmc cache control enable*/ +#define MMC_CACHE_CONTROL_ENABLE (1U) +/*! @brief mmc cache flush */ +#define MMC_CACHE_TRIGGER_FLUSH (1U) /*! @brief MMC card high-speed timing(HS_TIMING in Extended CSD) */ typedef enum _mmc_high_speed_timing { - kMMC_HighSpeedTimingNone = 0U, /*!< MMC card using none high-speed timing */ - kMMC_HighSpeedTiming = 1U, /*!< MMC card using high-speed timing */ - kMMC_HighSpeed200Timing = 2U, /*!< MMC card high speed 200 timing*/ - kMMC_HighSpeed400Timing = 3U, /*!< MMC card high speed 400 timing*/ + kMMC_HighSpeedTimingNone = 0U, /*!< MMC card using none high-speed timing */ + kMMC_HighSpeedTiming = 1U, /*!< MMC card using high-speed timing */ + kMMC_HighSpeed200Timing = 2U, /*!< MMC card high speed 200 timing*/ + kMMC_HighSpeed400Timing = 3U, /*!< MMC card high speed 400 timing*/ + kMMC_EnhanceHighSpeed400Timing = 4U, /*!< MMC card high speed 400 timing*/ } mmc_high_speed_timing_t; /*! @brief The number of data bus width type */ @@ -656,11 +719,12 @@ typedef enum _mmc_high_speed_timing /*! @brief MMC card data bus width(BUS_WIDTH in Extended CSD) */ typedef enum _mmc_data_bus_width { - kMMC_DataBusWidth1bit = 0U, /*!< MMC data bus width is 1 bit */ - kMMC_DataBusWidth4bit = 1U, /*!< MMC data bus width is 4 bits */ - kMMC_DataBusWidth8bit = 2U, /*!< MMC data bus width is 8 bits */ - kMMC_DataBusWidth4bitDDR = 5U, /*!< MMC data bus width is 4 bits ddr */ - kMMC_DataBusWidth8bitDDR = 6U, /*!< MMC data bus width is 8 bits ddr */ + kMMC_DataBusWidth1bit = 0U, /*!< MMC data bus width is 1 bit */ + kMMC_DataBusWidth4bit = 1U, /*!< MMC data bus width is 4 bits */ + kMMC_DataBusWidth8bit = 2U, /*!< MMC data bus width is 8 bits */ + kMMC_DataBusWidth4bitDDR = 5U, /*!< MMC data bus width is 4 bits ddr */ + kMMC_DataBusWidth8bitDDR = 6U, /*!< MMC data bus width is 8 bits ddr */ + kMMC_DataBusWidth8bitDDRSTROBE = 0x86U, /*!< MMC data bus width is 8 bits ddr strobe mode */ } mmc_data_bus_width_t; /*! @brief MMC card boot partition enabled(BOOT_PARTITION_ENABLE in Extended CSD) */ @@ -669,7 +733,7 @@ typedef enum _mmc_boot_partition_enable kMMC_BootPartitionEnableNot = 0U, /*!< Device not boot enabled (default) */ kMMC_BootPartitionEnablePartition1 = 1U, /*!< Boot partition 1 enabled for boot */ kMMC_BootPartitionEnablePartition2 = 2U, /*!< Boot partition 2 enabled for boot */ - kMMC_BootPartitionEnableUserArea = 7U, /*!< User area enabled for boot */ + kMMC_BootPartitionEnableUserAera = 7U, /*!< User area enabled for boot */ } mmc_boot_partition_enable_t; /*! @brief boot mode configuration @@ -677,9 +741,9 @@ typedef enum _mmc_boot_partition_enable */ typedef enum _mmc_boot_timing_mode { - kMMC_BootModeSDRWithDefaultTiming = 0U << 3U, /*!< boot mode single data rate with backward compatiable timings */ - kMMC_BootModeSDRWithHighSpeedTiming = 1U << 3U, /*!< boot mode single data rate with high speed timing */ - kMMC_BootModeDDRTiming = 2U << 3U, /*!< boot mode dual date rate */ + kMMC_BootModeSDRWithDefaultTiming = 0U, /*!< boot mode single data rate with backward compatiable timings */ + kMMC_BootModeSDRWithHighSpeedTiming = 1U, /*!< boot mode single data rate with high speed timing */ + kMMC_BootModeDDRTiming = 2U, /*!< boot mode dual date rate */ } mmc_boot_timing_mode_t; /*! @brief MMC card boot partition write protect configurations @@ -710,8 +774,10 @@ typedef enum _mmc_boot_partition_wp 1U, /*!< permanent write protection apply to partition2, power on period write protection apply to partition1 */ } mmc_boot_partition_wp_t; -/*! @brief MMC card boot partition write protect status */ -enum _mmc_boot_partition_wp_status +/*! @brief MMC card boot partition write protect status + * @anchor _mmc_boot_partition_wp_status + */ +enum { kMMC_BootPartitionNotProtected = 0U, /*!< boot partition not protected */ kMMC_BootPartitionPwrProtected = 1U, /*!< boot partition is power on period write protected */ @@ -721,7 +787,7 @@ enum _mmc_boot_partition_wp_status /*! @brief MMC card partition to be accessed(BOOT_PARTITION_ACCESS in Extended CSD) */ typedef enum _mmc_access_partition { - kMMC_AccessPartitionUserArea = 0U, /*!< No access to boot partition (default), normal partition */ + kMMC_AccessPartitionUserAera = 0U, /*!< No access to boot partition (default), normal partition */ kMMC_AccessPartitionBoot1 = 1U, /*!< Read/Write boot partition 1 */ kMMC_AccessPartitionBoot2 = 2U, /*!< Read/Write boot partition 2*/ kMMC_AccessRPMB = 3U, /*!< Replay protected mem block */ @@ -751,11 +817,15 @@ typedef enum _mmc_access_partition #define MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_SHIFT (2U) /*! @brief The bit mask for BOOT BUS WIDTH RESET field in BOOT CONFIG */ #define MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_MASK (4U) -/*! @brief The bit mask for BOOT BUS WIDTH RESET field in BOOT CONFIG */ +/*! @brief The bit shift for BOOT MODE field in BOOT CONFIG */ +#define MMC_BOOT_BUS_CONDITION_BOOT_MODE_SHIFT (3U) +/*! @brief The bit mask for BOOT MODE field in BOOT CONFIG */ #define MMC_BOOT_BUS_CONDITION_BOOT_MODE_MASK (0x18U) -/*! @brief MMC card CSD register flags */ -enum _mmc_csd_flag +/*! @brief MMC card CSD register flags + * @anchor _mmc_csd_flag + */ +enum { kMMC_CsdReadBlockPartialFlag = (1U << 0U), /*!< Partial blocks for read allowed */ kMMC_CsdWriteBlockMisalignFlag = (1U << 1U), /*!< Write block misalignment */ @@ -782,24 +852,23 @@ typedef enum _mmc_extended_csd_access_mode /*! @brief EXT CSD byte index */ typedef enum _mmc_extended_csd_index { - kMMC_ExtendedCsdIndexBootPartitionWP = 173U, /*!< Boot partition write protect */ - kMMC_ExtendedCsdIndexEraseGroupDefinition = 175U, /*!< Erase Group Def */ - kMMC_ExtendedCsdIndexBootBusConditions = 177U, /*!< Boot Bus conditions */ - kMMC_ExtendedCsdIndexBootConfigWP = 178U, /*!< Boot config write protect */ - kMMC_ExtendedCsdIndexPartitionConfig = 179U, /*!< Partition Config, before BOOT_CONFIG */ - kMMC_ExtendedCsdIndexBusWidth = 183U, /*!< Bus Width */ - kMMC_ExtendedCsdIndexHighSpeedTiming = 185U, /*!< High-speed Timing */ - kMMC_ExtendedCsdIndexPowerClass = 187U, /*!< Power Class */ - kMMC_ExtendedCsdIndexCommandSet = 191U, /*!< Command Set */ - kMMC_ExtendedCsdIndexGenPartition1Base = 143U, /*!< General Purpose Partition n multiplier base */ - kMMC_ExtendedCsdIndexGenPartition2Base = 146U, /*!< General Purpose Partition n multiplier base */ - kMMC_ExtendedCsdIndexGenPartition3Base = 149U, /*!< General Purpose Partition n multiplier base */ - kMMC_ExtendedCsdIndexGenPartition4Base = 152U, /*!< General Purpose Partition n multiplier base */ - kMMC_ExtendedCsdIndexPartitioningCompleted = 155U /*!< Partitioning process complete */ + kMMC_ExtendedCsdIndexFlushCache = 32U, /*!< flush cache */ + kMMC_ExtendedCsdIndexCacheControl = 33U, /*!< cache control */ + kMMC_ExtendedCsdIndexBootPartitionWP = 173U, /*!< Boot partition write protect */ + kMMC_ExtendedCsdIndexEraseGroupDefinition = 175U, /*!< Erase Group Def */ + kMMC_ExtendedCsdIndexBootBusConditions = 177U, /*!< Boot Bus conditions */ + kMMC_ExtendedCsdIndexBootConfigWP = 178U, /*!< Boot config write protect */ + kMMC_ExtendedCsdIndexPartitionConfig = 179U, /*!< Partition Config, before BOOT_CONFIG */ + kMMC_ExtendedCsdIndexBusWidth = 183U, /*!< Bus Width */ + kMMC_ExtendedCsdIndexHighSpeedTiming = 185U, /*!< High-speed Timing */ + kMMC_ExtendedCsdIndexPowerClass = 187U, /*!< Power Class */ + kMMC_ExtendedCsdIndexCommandSet = 191U, /*!< Command Set */ } mmc_extended_csd_index_t; -/*! @brief mmc driver strength */ -enum _mmc_driver_strength +/*! @brief mmc driver strength + * @anchor _mmc_driver_strength + */ +enum { kMMC_DriverStrength0 = 0U, /*!< Driver type0 ,nominal impedance 50ohm */ kMMC_DriverStrength1 = 1U, /*!< Driver type1 ,nominal impedance 33ohm */ @@ -821,17 +890,17 @@ typedef enum _mmc_extended_csd_flags } mmc_extended_csd_flags_t; /*! @brief MMC card boot mode */ -enum _mmc_boot_mode +typedef enum _mmc_boot_mode { kMMC_BootModeNormal = 0U, /*!< Normal boot */ kMMC_BootModeAlternative = 1U, /*!< Alternative boot */ -}; +} mmc_boot_mode_t; /*! @brief The length of Extended CSD register, unit as bytes. */ #define MMC_EXTENDED_CSD_BYTES (512U) /*! @brief MMC card default relative address */ -#define MMC_DEFAULT_RELATIVE_ADDRESS (2U) +#define MMC_DEFAULT_RELATIVE_ADDRESS (2UL) /*! @brief SD card product name length united as bytes. */ #define SD_PRODUCT_NAME_BYTES (5U) @@ -897,6 +966,28 @@ typedef struct _sdio_func_cis when IO operating in lower current mode */ } sdio_func_cis_t; +/*! @brief SD AU start value */ +#define SD_AU_START_VALUE (1U) +/*! @brief SD UHS AU start value */ +#define SD_UHS_AU_START_VALUE (7U) + +/*! @brief SD card status */ +typedef struct _sd_status +{ + uint8_t busWidth; /*!< current buswidth */ + uint8_t secureMode; /*!< secured mode */ + uint16_t cardType; /*!< sdcard type */ + uint32_t protectedSize; /*!< size of protected area */ + uint8_t speedClass; /*!< speed class of card */ + uint8_t performanceMove; /*!< Performance of move indicated by 1[MB/S]step */ + uint8_t auSize; /*!< size of AU */ + uint16_t eraseSize; /*!< number of AUs to be erased at a time */ + uint8_t eraseTimeout; /*!< timeout value for erasing areas specified by UNIT OF ERASE AU */ + uint8_t eraseOffset; /*!< fixed offset value added to erase time */ + uint8_t uhsSpeedGrade; /*!< speed grade for UHS mode */ + uint8_t uhsAuSize; /*!< size of AU for UHS mode */ +} sd_status_t; + /*! @brief SD card CID register */ typedef struct _sd_cid { @@ -942,10 +1033,10 @@ typedef struct _sd_csd /*! @brief The bit mask for TIME VALUE field in TRANSFER SPEED */ #define SD_TRANSFER_SPEED_TIME_VALUE_MASK (0x78U) /*! @brief Read the value of FREQUENCY UNIT in TRANSFER SPEED field */ -#define SD_RD_TRANSFER_SPEED_RATE_UNIT(x) \ +#define SD_RD_TRANSFER_SPEED_RATE_UNIT(x) \ (((x.transferSpeed) & SD_TRANSFER_SPEED_RATE_UNIT_MASK) >> SD_TRANSFER_SPEED_RATE_UNIT_SHIFT) /*! @brief Read the value of TIME VALUE in TRANSFER SPEED field */ -#define SD_RD_TRANSFER_SPEED_TIME_VALUE(x) \ +#define SD_RD_TRANSFER_SPEED_TIME_VALUE(x) \ (((x.transferSpeed) & SD_TRANSFER_SPEED_TIME_VALUE_MASK) >> SD_TRANSFER_SPEED_TIME_VALUE_SHIFT) /*! @brief SD card SCR register */ @@ -1004,54 +1095,40 @@ typedef struct _mmc_csd /*! @brief MMC card Extended CSD register (unit: byte). */ typedef struct _mmc_extended_csd { - uint8_t SecureRemoveType; /*!< secure removal type[16]*/ - uint8_t enProductStateAware; /*!< product state awareness enablement[17]*/ - uint32_t maxPreLoadDataSize; /*!< max preload data size[21-18]*/ - uint32_t preLoadDataSize; /*!< pre-load data size[25-22]*/ - uint8_t ffuStatus; /*!< FFU status [26]*/ - uint8_t modeOperationCode; /*!< mode operation code[29]*/ - uint8_t modeConfig; /*!< mode config [30]*/ + /*uint8_t SecureRemoveType;*/ /*!< secure removal type[16]*/ + /*uint8_t enProductStateAware;*/ /*!< product state awareness enablement[17]*/ + /*uint32_t maxPreLoadDataSize;*/ /*!< max preload data size[21-18]*/ + /*uint32_t preLoadDataSize;*/ /*!< pre-load data size[25-22]*/ + /*uint8_t ffuStatus;*/ /*!< FFU status [26]*/ + /*uint8_t modeOperationCode;*/ /*!< mode operation code[29]*/ + /*uint8_t modeConfig;*/ /*!< mode config [30]*/ uint8_t cacheCtrl; /*!< control to turn on/off cache[33]*/ - uint8_t pwroffNotify; /*!< power off notification[34]*/ - uint8_t packedCmdFailIndex; /*!< packed cmd fail index [35]*/ - uint8_t packedCmdStatus; /*!< packed cmd status[36]*/ - uint32_t contextConfig[4U]; /*!< context configuration[51-37]*/ - uint16_t extPartitionAttr; /*!< extended partitions attribut[53-52]*/ - uint16_t exceptEventStatus; /*!< exception events status[55-54]*/ - uint16_t exceptEventControl; /*!< exception events control[57-56]*/ - uint8_t toReleaseAddressedGroup; /*!< number of group to be released[58]*/ - uint8_t class6CmdCtrl; /*!< class 6 command control[59]*/ - uint8_t intTimeoutEmu; /*!< 1st initiallization after disabling sector size emu[60]*/ - uint8_t sectorSize; /*!< sector size[61] */ - uint8_t sectorSizeEmu; /*!< sector size emulation[62]*/ - uint8_t nativeSectorSize; /*!< native sector size[63]*/ - uint8_t periodWakeup; /*!< period wakeup [131]*/ - uint8_t tCASESupport; /*!< package case temperature is controlled[132]*/ - uint8_t productionStateAware; /*!< production state awareness[133]*/ - uint32_t enhanceUsrDataStartAddr; /*!< enhanced user data start addr [139-136]*/ - uint32_t enhanceUsrDataSize; /*!< enhanced user data area size[142-140]*/ - uint8_t generalPartition1Multi0; /*!< General partition 1 multiplier 0 [143]*/ - uint8_t generalPartition1Multi1; /*!< General partition 1 multiplier 1 [144]*/ - uint8_t generalPartition1Multi2; /*!< General partition 1 multiplier 2 [145]*/ - uint8_t generalPartition2Multi0; /*!< General partition 2 multiplier 0 [146]*/ - uint8_t generalPartition2Multi1; /*!< General partition 2 multiplier 1 [147]*/ - uint8_t generalPartition2Multi2; /*!< General partition 2 multiplier 2 [148]*/ - uint8_t generalPartition3Multi0; /*!< General partition 3 multiplier 0 [149]*/ - uint8_t generalPartition3Multi1; /*!< General partition 3 multiplier 1 [150]*/ - uint8_t generalPartition3Multi2; /*!< General partition 3 multiplier 2 [151]*/ - uint8_t generalPartition4Multi0; /*!< General partition 4 multiplier 2 [152]*/ - uint8_t generalPartition4Multi1; /*!< General partition 4 multiplier 2 [153]*/ - uint8_t generalPartition4Multi2; /*!< General partition 4 multiplier 2 [154]*/ - uint32_t generalPartitionSize[3]; /*!< general purpose partition size[154-143]*/ - uint8_t partitioningSettingCompleted; /*!< Partitioning setting completed byte [155]*/ + /*uint8_t pwroffNotify;*/ /*!< power off notification[34]*/ + /*uint8_t packedCmdFailIndex;*/ /*!< packed cmd fail index [35]*/ + /*uint8_t packedCmdStatus;*/ /*!< packed cmd status[36]*/ + /*uint32_t contextConfig[4U];*/ /*!< context configuration[51-37]*/ + /*uint16_t extPartitionAttr;*/ /*!< extended partitions attribut[53-52]*/ + /*uint16_t exceptEventStatus;*/ /*!< exception events status[55-54]*/ + /*uint16_t exceptEventControl;*/ /*!< exception events control[57-56]*/ + /*uint8_t toReleaseAddressedGroup;*/ /*!< number of group to be released[58]*/ + /*uint8_t class6CmdCtrl;*/ /*!< class 6 command control[59]*/ + /*uint8_t intTimeoutEmu;*/ /*!< 1st initiallization after disabling sector size emu[60]*/ + /*uint8_t sectorSize;*/ /*!< sector size[61] */ + /*uint8_t sectorSizeEmu;*/ /*!< sector size emulation[62]*/ + /*uint8_t nativeSectorSize;*/ /*!< native sector size[63]*/ + /*uint8_t periodWakeup;*/ /*!< period wakeup [131]*/ + /*uint8_t tCASESupport;*/ /*!< package case temperature is controlled[132]*/ + /*uint8_t productionStateAware;*/ /*!< production state awareness[133]*/ + /*uint32_t enhanceUsrDataStartAddr;*/ /*!< enhanced user data start addr [139-136]*/ + /*uint32_t enhanceUsrDataSize;*/ /*!< enhanced user data area size[142-140]*/ + /*uint32_t generalPartitionSize[3];*/ /*!< general purpose partition size[154-143]*/ uint8_t partitionAttribute; /*!< partition attribute [156]*/ - uint32_t maxEnhanceAreaSize; /*!< max enhance area size [159-157]*/ - uint8_t partitioningSupport; /*!< Partitioning support [160U]*/ - uint8_t hpiManagementEn; /*!< HPI management [161]*/ - uint8_t writeReliabilityParameter; /*!< write reliability parameter register[166] */ - uint8_t writeReliabilitySet; /*!< write reliability setting register[167] */ - uint8_t rpmbSizeMult; /*!< RPMB size multi [168]*/ - uint8_t fwConfig; /*!< FW configuration[169]*/ + /*uint32_t maxEnhanceAreaSize;*/ /*!< max enhance area size [159-157]*/ + /*uint8_t hpiManagementEn;*/ /*!< HPI management [161]*/ + /*uint8_t writeReliabilityParameter;*/ /*!< write reliability parameter register[166] */ + /*uint8_t writeReliabilitySet;*/ /*!< write reliability setting register[167] */ + /*uint8_t rpmbSizeMult;*/ /*!< RPMB size multi [168]*/ + /*uint8_t fwConfig;*/ /*!< FW configuration[169]*/ uint8_t userWP; /*!< user write protect register[171] */ uint8_t bootPartitionWP; /*!< boot write protect register[173]*/ uint8_t bootWPStatus; /*!< boot write protect status register[174]*/ @@ -1069,8 +1146,8 @@ typedef struct _mmc_extended_csd uint8_t csdStructureVersion; /*!< CSD structure version [194] */ uint8_t cardType; /*!< Card Type [196] */ uint8_t ioDriverStrength; /*!< IO driver strength [197] */ - uint8_t OutofInterruptBusyTiming; /*!< out of interrupt busy timing [198] */ - uint8_t partitionSwitchTiming; /*!< partition switch timing [199] */ + /*uint8_t OutofInterruptBusyTiming;*/ /*!< out of interrupt busy timing [198] */ + uint8_t partitionSwitchTimeout; /*!< partition switch timing [199] */ uint8_t powerClass52MHz195V; /*!< Power Class for 52MHz @ 1.95V [200] */ uint8_t powerClass26MHz195V; /*!< Power Class for 26MHz @ 1.95V [201] */ uint8_t powerClass52MHz360V; /*!< Power Class for 52MHz @ 3.6V [202] */ @@ -1084,9 +1161,9 @@ typedef struct _mmc_extended_csd uint8_t minimumReadPerformance8Bit52MHz; /*!< Minimum Read Performance for 8bit at 52MHz [209] */ uint8_t minimumWritePerformance8Bit52MHz; /*!< Minimum Write Performance for 8bit at 52MHz [210] */ uint32_t sectorCount; /*!< Sector Count [215:212] */ - uint8_t sleepNotificationTimeout; /*!< sleep notification timeout [216]*/ + /*uint8_t sleepNotificationTimeout;*/ /*!< sleep notification timeout [216]*/ uint8_t sleepAwakeTimeout; /*!< Sleep/awake timeout [217] */ - uint8_t productionStateAwareTimeout; /*!< Production state awareness timeout [218]*/ + /*uint8_t productionStateAwareTimeout;*/ /*!< Production state awareness timeout [218]*/ uint8_t sleepCurrentVCCQ; /*!< Sleep current (VCCQ) [219] */ uint8_t sleepCurrentVCC; /*!< Sleep current (VCC) [220] */ uint8_t highCapacityWriteProtectGroupSize; /*!< High-capacity write protect group size [221] */ @@ -1094,45 +1171,45 @@ typedef struct _mmc_extended_csd uint8_t highCapacityEraseTimeout; /*!< High-capacity erase timeout [223] */ uint8_t highCapacityEraseUnitSize; /*!< High-capacity erase unit size [224] */ uint8_t accessSize; /*!< Access size [225] */ - uint8_t secureTrimMultiplier; /*!< secure trim multiplier[229]*/ - uint8_t secureEraseMultiplier; /*!< secure erase multiplier[230]*/ - uint8_t secureFeatureSupport; /*!< secure feature support[231]*/ - uint32_t trimMultiplier; /*!< trim multiplier[232]*/ + /*uint8_t secureTrimMultiplier;*/ /*!< secure trim multiplier[229]*/ + /*uint8_t secureEraseMultiplier;*/ /*!< secure erase multiplier[230]*/ + /*uint8_t secureFeatureSupport;*/ /*!< secure feature support[231]*/ + /*uint32_t trimMultiplier;*/ /*!< trim multiplier[232]*/ uint8_t minReadPerformance8bitAt52MHZDDR; /*!< Minimum read performance for 8bit at DDR 52MHZ[234]*/ uint8_t minWritePerformance8bitAt52MHZDDR; /*!< Minimum write performance for 8bit at DDR 52MHZ[235]*/ uint8_t powerClass200MHZVCCQ130VVCC360V; /*!< power class for 200MHZ, at VCCQ= 1.3V,VCC=3.6V[236]*/ uint8_t powerClass200MHZVCCQ195VVCC360V; /*!< power class for 200MHZ, at VCCQ= 1.95V,VCC=3.6V[237]*/ uint8_t powerClass52MHZDDR195V; /*!< power class for 52MHZ,DDR at Vcc 1.95V[238]*/ uint8_t powerClass52MHZDDR360V; /*!< power class for 52MHZ,DDR at Vcc 3.6V[239]*/ - uint8_t iniTimeoutAP; /*!< 1st initialization time after partitioning[241]*/ - uint32_t correctPrgSectorNum; /*!< correct prg sectors number[245-242]*/ - uint8_t bkOpsStatus; /*!< background operations status[246]*/ - uint8_t powerOffNotifyTimeout; /*!< power off notification timeout[247]*/ - uint8_t genericCMD6Timeout; /*!< generic CMD6 timeout[248]*/ + /*uint8_t iniTimeoutAP;*/ /*!< 1st initialization time after partitioning[241]*/ + /*uint32_t correctPrgSectorNum;*/ /*!< correct prg sectors number[245-242]*/ + /*uint8_t bkOpsStatus;*/ /*!< background operations status[246]*/ + /*uint8_t powerOffNotifyTimeout;*/ /*!< power off notification timeout[247]*/ + uint32_t genericCMD6Timeout; /*!< generic CMD6 timeout[248]*/ uint32_t cacheSize; /*!< cache size[252-249]*/ uint8_t powerClass200MHZDDR360V; /*!< power class for 200MHZ, DDR at VCC=2.6V[253]*/ - uint32_t fwVer[2U]; /*!< fw VERSION [261-254]*/ - uint16_t deviceVer; /*!< device version[263-262]*/ - uint8_t optimalTrimSize; /*!< optimal trim size[264]*/ - uint8_t optimalWriteSize; /*!< optimal write size[265]*/ - uint8_t optimalReadSize; /*!< optimal read size[266]*/ - uint8_t preEolInfo; /*!< pre EOL information[267]*/ - uint8_t deviceLifeTimeEstimationA; /*!< device life time estimation typeA[268]*/ - uint8_t deviceLifeTimeEstimationB; /*!< device life time estimation typeB[269]*/ - uint32_t correctPrgFWSectorNum; /*!< number of FW sectors correctly programmed[305-302]*/ - uint32_t ffuArg; /*!< FFU argument[490-487]*/ - uint8_t operationCodeTimeout; /*!< operation code timeout[491]*/ - uint8_t supportMode; /*!< support mode [493]*/ + /*uint32_t fwVer[2U];*/ /*!< fw VERSION [261-254]*/ + /*uint16_t deviceVer;*/ /*!< device version[263-262]*/ + /*uint8_t optimalTrimSize;*/ /*!< optimal trim size[264]*/ + /*uint8_t optimalWriteSize;*/ /*!< optimal write size[265]*/ + /*uint8_t optimalReadSize;*/ /*!< optimal read size[266]*/ + /*uint8_t preEolInfo;*/ /*!< pre EOL information[267]*/ + /*uint8_t deviceLifeTimeEstimationA;*/ /*!< device life time estimation typeA[268]*/ + /*uint8_t deviceLifeTimeEstimationB;*/ /*!< device life time estimation typeB[269]*/ + /*uint32_t correctPrgFWSectorNum;*/ /*!< number of FW sectors correctly programmed[305-302]*/ + /*uint32_t ffuArg;*/ /*!< FFU argument[490-487]*/ + /*uint8_t operationCodeTimeout;*/ /*!< operation code timeout[491]*/ + /*uint8_t supportMode;*/ /*!< support mode [493]*/ uint8_t extPartitionSupport; /*!< extended partition attribute support[494]*/ - uint8_t largeUnitSize; /*!< large unit size[495]*/ - uint8_t contextManageCap; /*!< context management capability[496]*/ - uint8_t tagResourceSize; /*!< tag resource size[497]*/ - uint8_t tagUnitSize; /*!< tag unit size[498]*/ - uint8_t maxPackedWriteCmd; /*!< max packed write cmd[500]*/ - uint8_t maxPackedReadCmd; /*!< max packed read cmd[501]*/ - uint8_t hpiFeature; /*!< HPI feature[503]*/ + /*uint8_t largeUnitSize;*/ /*!< large unit size[495]*/ + /*uint8_t contextManageCap;*/ /*!< context management capability[496]*/ + /*uint8_t tagResourceSize;*/ /*!< tag resource size[497]*/ + /*uint8_t tagUnitSize;*/ /*!< tag unit size[498]*/ + /*uint8_t maxPackedWriteCmd;*/ /*!< max packed write cmd[500]*/ + /*uint8_t maxPackedReadCmd;*/ /*!< max packed read cmd[501]*/ + /*uint8_t hpiFeature;*/ /*!< HPI feature[503]*/ uint8_t supportedCommandSet; /*!< Supported Command Sets [504] */ - uint8_t extSecurityCmdError; /*!< extended security commands error[505]*/ + /*uint8_t extSecurityCmdError;*/ /*!< extended security commands error[505]*/ } mmc_extended_csd_t; /*! @brief The bit shift for COMMAND SET field in SWITCH command. */ @@ -1164,6 +1241,7 @@ typedef struct _mmc_extended_csd_config /*! @brief MMC card boot configuration definition. */ typedef struct _mmc_boot_config { + mmc_boot_mode_t bootMode; /*!< mmc boot mode */ bool enableBootAck; /*!< Enable boot ACK */ mmc_boot_partition_enable_t bootPartition; /*!< Boot partition */ @@ -1179,4 +1257,6 @@ typedef struct _mmc_boot_config } mmc_boot_config_t; +/* @} */ + #endif /* _FSL_SDMMC_SPEC_H_ */ diff --git a/module-bsp/board/rt1051/common/fsl_drivers/fsl_common.h b/module-bsp/board/rt1051/common/fsl_drivers/fsl_common.h index 5184be00862eff87840dbe9676cc700908c1faa4..d94e85d6c2ff60787efee9b910b18181206f332e 100644 --- a/module-bsp/board/rt1051/common/fsl_drivers/fsl_common.h +++ b/module-bsp/board/rt1051/common/fsl_drivers/fsl_common.h @@ -349,6 +349,21 @@ _Pragma("diag_suppress=Pm120") #endif /* @} */ +/*! @name ISR exit barrier + * @{ + * + * ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + * exception return operation might vector to incorrect interrupt. + * For Cortex-M7, if core speed much faster than peripheral register write speed, + * the peripheral interrupt flags may be still set after exiting ISR, this results to + * the same error similar with errata 83869. + */ +#if (defined __CORTEX_M) && ((__CORTEX_M == 4U) || (__CORTEX_M == 7U)) +#define SDK_ISR_EXIT_BARRIER __DSB() +#else +#define SDK_ISR_EXIT_BARRIER +#endif + /*! @name Time sensitive region */ /* @{ */ #if defined(FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE) && FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE diff --git a/module-bsp/board/rt1051/common/fsl_drivers/fsl_usdhc.c b/module-bsp/board/rt1051/common/fsl_drivers/fsl_usdhc.c index 4fc14d4c4a3a1f6da55acef9db39aebc294c026d..f2c82d8cdeae60efdae012be06527bb541997849 100644 --- a/module-bsp/board/rt1051/common/fsl_drivers/fsl_usdhc.c +++ b/module-bsp/board/rt1051/common/fsl_drivers/fsl_usdhc.c @@ -1,42 +1,18 @@ /* - * The Clear BSD License * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2021 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted (subject to the limitations in the disclaimer below) provided - * that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * o Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_usdhc.h" #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL #include "fsl_cache.h" #endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ - +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET +#include "fsl_memory.h" +#endif /******************************************************************************* * Definitions ******************************************************************************/ @@ -52,11 +28,31 @@ #define USDHC_MAX_CLKFS ((USDHC_SYS_CTRL_SDCLKFS_MASK >> USDHC_SYS_CTRL_SDCLKFS_SHIFT) + 1U) #define USDHC_PREV_DVS(x) ((x) -= 1U) #define USDHC_PREV_CLKFS(x, y) ((x) >>= (y)) +/*! @brief USDHC ADMA table address align size */ +#define USDHC_ADMA_TABLE_ADDRESS_ALIGN (4U) /* Typedef for interrupt handler. */ typedef void (*usdhc_isr_t)(USDHC_Type *base, usdhc_handle_t *handle); -/*! @brief Dummy data buffer for mmc boot mode */ -AT_NONCACHEABLE_SECTION_ALIGN(uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALIGN); +/*! @brief check flag avalibility */ +#define IS_USDHC_FLAG_SET(reg, flag) (((reg) & ((uint32_t)flag)) != 0UL) + +/*! @brief usdhc transfer flags */ +enum _usdhc_transfer_flags +{ + kUSDHC_CommandOnly = 1U, /*!< transfer command only */ + kUSDHC_CommandAndTxData = 2U, /*!< transfer command and transmit data */ + kUSDHC_CommandAndRxData = 4U, /*!< transfer command and receive data */ + kUSDHC_DataWithAutoCmd12 = 8U, /*!< transfer data with auto cmd12 enabled */ + kUSDHC_DataWithAutoCmd23 = 16U, /*!< transfer data with auto cmd23 enabled */ + kUSDHC_BootData = 32U, /*!< transfer boot data */ + kUSDHC_BootDataContinuous = 64U, /*!< transfer boot data continuous */ +}; + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET +#define USDHC_ADDR_CPU_2_DMA(addr) (MEMORY_ConvertMemoryMapAddress((addr), kMEMORY_Local2DMA)) +#else +#define USDHC_ADDR_CPU_2_DMA(addr) (addr) +#endif /******************************************************************************* * Prototypes ******************************************************************************/ @@ -68,22 +64,18 @@ AT_NONCACHEABLE_SECTION_ALIGN(uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALI */ static uint32_t USDHC_GetInstance(USDHC_Type *base); -/*! - * @brief Set transfer interrupt. - * - * @param base USDHC peripheral base address. - * @param usingInterruptSignal True to use IRQ signal. - */ -static void USDHC_SetTransferInterrupt(USDHC_Type *base, bool usingInterruptSignal); - /*! * @brief Start transfer according to current transfer state * * @param base USDHC peripheral base address. - * @param data Data to be transferred. - * @param flag data present flag + * @param transferFlags transfer flags, @ref _usdhc_transfer_flags. + * @param blockSize block size. + * @param blockCount block count. */ -static status_t USDHC_SetDataTransferConfig(USDHC_Type *base, usdhc_data_t *data, uint32_t *dataPresentFlag); +static status_t USDHC_SetTransferConfig(USDHC_Type *base, + uint32_t transferFlags, + size_t blockSize, + uint32_t blockCount); /*! * @brief Receive command response @@ -145,6 +137,15 @@ static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *da */ static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA); +/*! + * @brief wait command done + * + * @param base USDHC peripheral base address. + * @param command configuration + * @param pollingCmdDone polling command done flag + */ +static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone); + /*! * @brief Handle card detect interrupt. * @@ -188,6 +189,7 @@ static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t * */ static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle); +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) /*! * @brief Handle retuning * @@ -196,16 +198,7 @@ static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handl * @param interrupt flags */ static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags); - -/*! - * @brief wait command done - * - * @param base USDHC peripheral base address. - * @param command configuration - * @param pollingCmdDone polling command done flag - */ -static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone); - +#endif /******************************************************************************* * Variables ******************************************************************************/ @@ -213,7 +206,7 @@ static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command static USDHC_Type *const s_usdhcBase[] = USDHC_BASE_PTRS; /*! @brief USDHC internal handle pointer array */ -static usdhc_handle_t *s_usdhcHandle[ARRAY_SIZE(s_usdhcBase)] = {NULL}; +static usdhc_handle_t *s_usdhcHandle[ARRAY_SIZE(s_usdhcBase)] = {0}; /*! @brief USDHC IRQ name array */ static const IRQn_Type s_usdhcIRQ[] = USDHC_IRQS; @@ -223,8 +216,19 @@ static const IRQn_Type s_usdhcIRQ[] = USDHC_IRQS; static const clock_ip_name_t s_usdhcClock[] = USDHC_CLOCKS; #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +#if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET) +/*! @brief Pointers to USDHC resets for each instance. */ +static const reset_ip_name_t s_usdhcResets[] = USDHC_RSTS; +#endif + /* USDHC ISR for transactional APIs. */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) +static usdhc_isr_t s_usdhcIsr = (usdhc_isr_t)DefaultISR; +#else static usdhc_isr_t s_usdhcIsr; +#endif +/*! @brief Dummy data buffer for mmc boot mode */ +AT_NONCACHEABLE_SECTION_ALIGN(static uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALIGN); /******************************************************************************* * Code @@ -233,7 +237,8 @@ static uint32_t USDHC_GetInstance(USDHC_Type *base) { uint8_t instance = 0; - while ((instance < ARRAY_SIZE(s_usdhcBase)) && (s_usdhcBase[instance] != base)) { + while ((instance < ARRAY_SIZE(s_usdhcBase)) && (s_usdhcBase[instance] != base)) + { instance++; } @@ -242,32 +247,26 @@ static uint32_t USDHC_GetInstance(USDHC_Type *base) return instance; } -static void USDHC_SetTransferInterrupt(USDHC_Type *base, bool usingInterruptSignal) +static status_t USDHC_SetTransferConfig(USDHC_Type *base, uint32_t transferFlags, size_t blockSize, uint32_t blockCount) { - uint32_t interruptEnabled; /* The Interrupt status flags to be enabled */ - - /* Disable all interrupts */ - USDHC_DisableInterruptStatus(base, (uint32_t)kUSDHC_AllInterruptFlags); - USDHC_DisableInterruptSignal(base, (uint32_t)kUSDHC_AllInterruptFlags); - DisableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]); - - interruptEnabled = (kUSDHC_CommandFlag | kUSDHC_CardInsertionFlag | kUSDHC_DataFlag | kUSDHC_CardRemovalFlag | - kUSDHC_SDR104TuningFlag | kUSDHC_BlockGapEventFlag); + uint32_t mixCtrl = base->MIX_CTRL; - USDHC_EnableInterruptStatus(base, interruptEnabled); + if (((uint32_t)kUSDHC_CommandOnly & transferFlags) != 0U) + { + /* clear data flags */ + mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK | + USDHC_MIX_CTRL_AC12EN_MASK | USDHC_MIX_CTRL_AC23EN_MASK); - if (usingInterruptSignal) { - USDHC_EnableInterruptSignal(base, interruptEnabled); + if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag)) + { + return kStatus_USDHC_BusyTransferring; + } } -} - -static status_t USDHC_SetDataTransferConfig(USDHC_Type *base, usdhc_data_t *data, uint32_t *dataPresentFlag) -{ - uint32_t mixCtrl = base->MIX_CTRL; - - if (data != NULL) { + else + { /* if transfer boot continous, only need set the CREQ bit, leave others as it is */ - if (data->dataType == kUSDHC_TransferDataBootcontinous) { + if ((transferFlags & (uint32_t)kUSDHC_BootDataContinuous) != 0U) + { /* clear stop at block gap request */ base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK; /* continous transfer data */ @@ -276,11 +275,13 @@ static status_t USDHC_SetDataTransferConfig(USDHC_Type *base, usdhc_data_t *data } /* check data inhibit flag */ - if (base->PRES_STATE & kUSDHC_DataInhibitFlag) { + if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_DataInhibitFlag)) + { return kStatus_USDHC_BusyTransferring; } /* check transfer block count */ - if ((data->blockCount > USDHC_MAX_BLOCK_COUNT) || ((data->txData == NULL) && (data->rxData == NULL))) { + if ((blockCount > USDHC_MAX_BLOCK_COUNT)) + { return kStatus_InvalidArgument; } @@ -288,86 +289,104 @@ static status_t USDHC_SetDataTransferConfig(USDHC_Type *base, usdhc_data_t *data mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK | USDHC_MIX_CTRL_AC12EN_MASK); - if (data->rxData) { + if ((transferFlags & (uint32_t)kUSDHC_CommandAndRxData) != 0U) + { mixCtrl |= USDHC_MIX_CTRL_DTDSEL_MASK; } - if (data->blockCount > 1U) { + + if (blockCount > 1U) + { mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK; /* auto command 12 */ - if (data->enableAutoCommand12) { + if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd12) != 0U) + { mixCtrl |= USDHC_MIX_CTRL_AC12EN_MASK; } } /* auto command 23, auto send set block count cmd before multiple read/write */ - if ((data->enableAutoCommand23)) { + if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd23) != 0U) + { mixCtrl |= USDHC_MIX_CTRL_AC23EN_MASK; base->VEND_SPEC2 |= USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK; /* config the block count to DS_ADDR */ - base->DS_ADDR = data->blockCount; + base->DS_ADDR = blockCount; } - else { + else + { mixCtrl &= ~USDHC_MIX_CTRL_AC23EN_MASK; base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK; } /* if transfer boot data, leave the block count to USDHC_SetMmcBootConfig function */ - if (data->dataType != kUSDHC_TransferDataBoot) { + if ((transferFlags & (uint32_t)kUSDHC_BootData) == 0U) + { /* config data block size/block count */ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) | - (USDHC_BLK_ATT_BLKSIZE(data->blockSize) | USDHC_BLK_ATT_BLKCNT(data->blockCount))); + (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount))); } - else { + else + { mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK; base->PROT_CTRL |= USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK; } - - /* data present flag */ - *dataPresentFlag |= kUSDHC_DataPresentFlag; - } - else { - /* clear data flags */ - mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK | - USDHC_MIX_CTRL_AC12EN_MASK); - - if (base->PRES_STATE & kUSDHC_CommandInhibitFlag) { - return kStatus_USDHC_BusyTransferring; - } } - /* config the mix parameter */ base->MIX_CTRL = mixCtrl; return kStatus_Success; } +void USDHC_SetDataConfig(USDHC_Type *base, + usdhc_transfer_direction_t dataDirection, + uint32_t blockCount, + uint32_t blockSize) +{ + assert(blockCount <= USDHC_MAX_BLOCK_COUNT); + + uint32_t mixCtrl = base->MIX_CTRL; + + /* block attribute configuration */ + base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) | + (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount))); + + /* config mix parameter */ + mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK); + + mixCtrl |= USDHC_MIX_CTRL_DTDSEL(dataDirection) | (blockCount > 1U ? USDHC_MIX_CTRL_MSBSEL_MASK : 0U); + + base->MIX_CTRL = mixCtrl; +} + static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command) { - uint32_t i; + assert(command != NULL); - if (command->responseType != kCARD_ResponseTypeNone) { - command->response[0U] = base->CMD_RSP0; - if (command->responseType == kCARD_ResponseTypeR2) { - command->response[1U] = base->CMD_RSP1; - command->response[2U] = base->CMD_RSP2; - command->response[3U] = base->CMD_RSP3; + uint32_t response0 = base->CMD_RSP0; + uint32_t response1 = base->CMD_RSP1; + uint32_t response2 = base->CMD_RSP2; - i = 4U; + if (command->responseType != kCARD_ResponseTypeNone) + { + command->response[0U] = response0; + if (command->responseType == kCARD_ResponseTypeR2) + { /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document after removed internal CRC7 and end bit. */ - do { - command->response[i - 1U] <<= 8U; - if (i > 1U) { - command->response[i - 1U] |= ((command->response[i - 2U] & 0xFF000000U) >> 24U); - } - } while (i--); + command->response[0U] <<= 8U; + command->response[1U] = (response1 << 8U) | ((response0 & 0xFF000000U) >> 24U); + command->response[2U] = (response2 << 8U) | ((response1 & 0xFF000000U) >> 24U); + command->response[3U] = (base->CMD_RSP3 << 8U) | ((response2 & 0xFF000000U) >> 24U); } } + /* check response error flag */ if ((command->responseErrorFlags != 0U) && ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) || - (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5))) { - if (((command->responseErrorFlags) & (command->response[0U])) != 0U) { + (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5))) + { + if (((command->responseErrorFlags) & (command->response[0U])) != 0U) + { return kStatus_USDHC_SendCommandFailed; } } @@ -383,13 +402,15 @@ static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_ uint32_t readWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_RD_WML_MASK) >> USDHC_WTMK_LVL_RD_WML_SHIFT); /* If DMA is enable, do not need to polling data port */ - if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U) { + if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U) + { /* * 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) { + if (data->blockSize % sizeof(uint32_t) != 0U) + { data->blockSize += sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ } @@ -397,23 +418,27 @@ static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t)); /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */ - if (readWatermark >= totalWords) { + if (readWatermark >= totalWords) + { wordsCanBeRead = totalWords; } /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark, transfers watermark level words. */ - else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark)) { + else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark)) + { wordsCanBeRead = readWatermark; } /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers left words. */ - else { + else + { wordsCanBeRead = (totalWords - transferredWords); } i = 0U; - while (i < wordsCanBeRead) { + while (i < wordsCanBeRead) + { data->rxData[transferredWords++] = USDHC_ReadData(base); i++; } @@ -433,40 +458,55 @@ static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *dat * 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) { + 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)) { - while (!(interruptStatus & (kUSDHC_BufferReadReadyFlag | kUSDHC_DataErrorFlag | kUSDHC_TuningErrorFlag))) { + while ((error == kStatus_Success) && (transferredWords < totalWords)) + { + while ( + !(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_BufferReadReadyFlag | + (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_TuningErrorFlag)))) + { interruptStatus = USDHC_GetInterruptStatusFlags(base); } /* during std tuning process, software do not need to read data, but wait BRR is enough */ - if ((data->dataType == kUSDHC_TransferDataTuning) && (interruptStatus & kUSDHC_BufferReadReadyFlag)) { - USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag | kUSDHC_TuningPassFlag); + if ((data->dataType == (uint32_t)kUSDHC_TransferDataTuning) && + (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_BufferReadReadyFlag))) + { + USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag); return kStatus_Success; } - else if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U) { +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) + else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag)) + { USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag); /* if tuning error occur ,return directly */ error = kStatus_USDHC_TuningError; } - else if ((interruptStatus & kUSDHC_DataErrorFlag) != 0U) { - if (!(data->enableIgnoreError)) { +#endif + else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag)) + { + if (!(data->enableIgnoreError)) + { error = kStatus_Fail; } /* clear data error flag */ USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag); } - else { + else + { + /* Intentional empty */ } - if (error == kStatus_Success) { + if (error == kStatus_Success) + { transferredWords = USDHC_ReadDataPort(base, data, transferredWords); /* clear buffer read ready */ USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag); @@ -488,13 +528,15 @@ static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32 uint32_t writeWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_WR_WML_MASK) >> USDHC_WTMK_LVL_WR_WML_SHIFT); /* If DMA is enable, do not need to polling data port */ - if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U) { + if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U) + { /* * 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) { + if (data->blockSize % sizeof(uint32_t) != 0U) + { data->blockSize += sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ } @@ -502,22 +544,26 @@ static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32 totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t)); /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/ - if (writeWatermark >= totalWords) { + if (writeWatermark >= totalWords) + { wordsCanBeWrote = totalWords; } /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark, transfers watermark level words. */ - else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark)) { + else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark)) + { wordsCanBeWrote = writeWatermark; } /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left words. */ - else { + else + { wordsCanBeWrote = (totalWords - transferredWords); } i = 0U; - while (i < wordsCanBeWrote) { + while (i < wordsCanBeWrote) + { USDHC_WriteData(base, data->txData[transferredWords++]); i++; } @@ -538,34 +584,47 @@ static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *da * 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) { + 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)) { - while (!(interruptStatus & (kUSDHC_BufferWriteReadyFlag | kUSDHC_DataErrorFlag | kUSDHC_TuningErrorFlag))) { + while ((error == kStatus_Success) && (transferredWords < totalWords)) + { + while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_BufferWriteReadyFlag | + (uint32_t)kUSDHC_DataErrorFlag | + (uint32_t)kUSDHC_TuningErrorFlag))) + { interruptStatus = USDHC_GetInterruptStatusFlags(base); } - - if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U) { +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) + if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag)) + { USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag); /* if tuning error occur ,return directly */ return kStatus_USDHC_TuningError; } - else if ((interruptStatus & kUSDHC_DataErrorFlag) != 0U) { - if (!(data->enableIgnoreError)) { + else +#endif + if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag)) + { + if (!(data->enableIgnoreError)) + { error = kStatus_Fail; } /* clear data error flag */ USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag); } - else { + else + { + /* Intentional empty */ } - if (error == kStatus_Success) { + if (error == kStatus_Success) + { transferredWords = USDHC_WriteDataPort(base, data, transferredWords); /* clear buffer write ready */ USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferWriteReadyFlag); @@ -574,58 +633,64 @@ static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *da } /* Wait write data complete or data transfer error after the last writing operation. */ - while (!(interruptStatus & (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag))) { + while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag))) + { interruptStatus = USDHC_GetInterruptStatusFlags(base); } - if ((interruptStatus & kUSDHC_DataErrorFlag) != 0U) { - if (!(data->enableIgnoreError)) { + if ((interruptStatus & (uint32_t)kUSDHC_DataErrorFlag) != 0UL) + { + if (!(data->enableIgnoreError)) + { error = kStatus_Fail; } } - USDHC_ClearInterruptStatusFlags(base, (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag)); + USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag)); return error; } +/*! + * brief send command function + * + * param base USDHC peripheral base address. + * param command configuration + */ void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command) { assert(NULL != command); uint32_t xferType = base->CMD_XFR_TYP, flags = command->flags; - if (((base->PRES_STATE & kUSDHC_CommandInhibitFlag) == 0U) && (command->type != kCARD_CommandTypeEmpty)) { - /* Define the flag corresponding to each response type. */ - switch (command->responseType) { - case kCARD_ResponseTypeNone: - break; - case kCARD_ResponseTypeR1: /* Response 1 */ - case kCARD_ResponseTypeR5: /* Response 5 */ - case kCARD_ResponseTypeR6: /* Response 6 */ - case kCARD_ResponseTypeR7: /* Response 7 */ - flags |= (kUSDHC_ResponseLength48Flag | kUSDHC_EnableCrcCheckFlag | kUSDHC_EnableIndexCheckFlag); - break; - - case kCARD_ResponseTypeR1b: /* Response 1 with busy */ - case kCARD_ResponseTypeR5b: /* Response 5 with busy */ - flags |= (kUSDHC_ResponseLength48BusyFlag | kUSDHC_EnableCrcCheckFlag | kUSDHC_EnableIndexCheckFlag); - break; - - case kCARD_ResponseTypeR2: /* Response 2 */ - flags |= (kUSDHC_ResponseLength136Flag | kUSDHC_EnableCrcCheckFlag); - break; - - case kCARD_ResponseTypeR3: /* Response 3 */ - case kCARD_ResponseTypeR4: /* Response 4 */ - flags |= (kUSDHC_ResponseLength48Flag); - break; - - default: - break; + if (((base->PRES_STATE & (uint32_t)kUSDHC_CommandInhibitFlag) == 0U) && (command->type != kCARD_CommandTypeEmpty)) + { + if ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR5) || + (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR7)) + { + flags |= ((uint32_t)kUSDHC_ResponseLength48Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag | + (uint32_t)kUSDHC_EnableIndexCheckFlag); + } + else if ((command->responseType == kCARD_ResponseTypeR1b) || (command->responseType == kCARD_ResponseTypeR5b)) + { + flags |= ((uint32_t)kUSDHC_ResponseLength48BusyFlag | (uint32_t)kUSDHC_EnableCrcCheckFlag | + (uint32_t)kUSDHC_EnableIndexCheckFlag); + } + else if (command->responseType == kCARD_ResponseTypeR2) + { + flags |= ((uint32_t)kUSDHC_ResponseLength136Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag); + } + else if ((command->responseType == kCARD_ResponseTypeR3) || (command->responseType == kCARD_ResponseTypeR4)) + { + flags |= ((uint32_t)kUSDHC_ResponseLength48Flag); + } + else + { + /* Intentional empty */ } - if (command->type == kCARD_CommandTypeAbort) { - flags |= kUSDHC_CommandTypeAbortFlag; + if (command->type == kCARD_CommandTypeAbort) + { + flags |= (uint32_t)kUSDHC_CommandTypeAbortFlag; } /* config cmd index */ @@ -642,7 +707,8 @@ void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command) base->CMD_XFR_TYP = xferType; } - if (command->type == kCARD_CommandTypeEmpty) { + if (command->type == kCARD_CommandTypeEmpty) + { /* disable CMD done interrupt for empty command */ base->INT_SIGNAL_EN &= ~USDHC_INT_SIGNAL_EN_CCIEN_MASK; } @@ -655,27 +721,26 @@ static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command status_t error = kStatus_Success; uint32_t interruptStatus = 0U; /* check if need polling command done or not */ - if (pollingCmdDone) { + if (pollingCmdDone) + { /* Wait command complete or USDHC encounters error. */ - while (!(interruptStatus & (kUSDHC_CommandCompleteFlag | kUSDHC_CommandErrorFlag))) { + while (!(IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_CommandFlag))) + { interruptStatus = USDHC_GetInterruptStatusFlags(base); } - if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U) { - error = kStatus_USDHC_TuningError; - } - else if ((interruptStatus & kUSDHC_CommandErrorFlag) != 0U) { + if ((interruptStatus & (uint32_t)kUSDHC_CommandErrorFlag) != 0UL) + { error = kStatus_Fail; } - else { - } + /* Receive response when command completes successfully. */ - if (error == kStatus_Success) { + if (error == kStatus_Success) + { error = USDHC_ReceiveCommandResponse(base, command); } - USDHC_ClearInterruptStatusFlags( - base, (kUSDHC_CommandCompleteFlag | kUSDHC_CommandErrorFlag | kUSDHC_TuningErrorFlag)); + USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag); } return error; @@ -686,58 +751,105 @@ static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, status_t error = kStatus_Success; uint32_t interruptStatus = 0U; - if (enDMA) { + if (enDMA) + { /* Wait data complete or USDHC encounters error. */ - while (!((interruptStatus & - (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag | kUSDHC_TuningErrorFlag)))) { + while (!(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag)))) + { interruptStatus = USDHC_GetInterruptStatusFlags(base); } - if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U) { +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) + if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag)) + { error = kStatus_USDHC_TuningError; } - else if (((interruptStatus & (kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag)) != 0U)) { - if ((!(data->enableIgnoreError)) || (interruptStatus & kUSDHC_DataTimeoutFlag)) { - error = kStatus_Fail; + else +#endif + if (IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag))) + { + if ((!(data->enableIgnoreError)) || (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataTimeoutFlag))) + { + error = kStatus_USDHC_TransferDataFailed; } } - else { + else + { + /* Intentional empty */ } /* load dummy data */ - if ((data->dataType == kUSDHC_TransferDataBootcontinous) && (error == kStatus_Success)) { + if ((data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous) && (error == kStatus_Success)) + { *(data->rxData) = s_usdhcBootDummy; } - USDHC_ClearInterruptStatusFlags(base, - (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag | - kUSDHC_TuningPassFlag | kUSDHC_TuningErrorFlag)); + USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag)); } - else { - if (data->rxData) { + else + { + if (data->rxData != NULL) + { error = USDHC_ReadByDataPortBlocking(base, data); + if (error != kStatus_Success) + { + return error; + } } - else { + else + { error = USDHC_WriteByDataPortBlocking(base, data); + if (error != kStatus_Success) + { + return error; + } } } return error; } +/*! + * brief USDHC module initialization function. + * + * Configures the USDHC according to the user configuration. + * + * Example: + code + usdhc_config_t config; + config.cardDetectDat3 = false; + config.endianMode = kUSDHC_EndianModeLittle; + config.dmaMode = kUSDHC_DmaModeAdma2; + config.readWatermarkLevel = 128U; + config.writeWatermarkLevel = 128U; + USDHC_Init(USDHC, &config); + endcode + * + * param base USDHC peripheral base address. + * param config USDHC configuration information. + * retval kStatus_Success Operate successfully. + */ void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config) { - assert(config); + assert(config != NULL); assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U)); assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U)); +#if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) assert(config->writeBurstLen <= 16U); - +#endif uint32_t proctl, sysctl, wml; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Enable USDHC clock. */ CLOCK_EnableClock(s_usdhcClock[USDHC_GetInstance(base)]); +#endif + +#if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET) + /* Reset the USDHC module */ + RESET_PeripheralReset(s_usdhcResets[USDHC_GetInstance(base)]); +#endif - /* Reset USDHC. */ - USDHC_Reset(base, kUSDHC_ResetAll, 100U); + /* Reset ALL USDHC. */ + base->SYS_CTRL |= USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK; proctl = base->PROT_CTRL; wml = base->WTMK_LVL; @@ -747,11 +859,17 @@ void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config) /* Endian mode*/ proctl |= USDHC_PROT_CTRL_EMODE(config->endianMode); +#if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) + /* Watermark level */ + wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK); + wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel)); +#else /* Watermark level */ wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK | USDHC_WTMK_LVL_RD_BRST_LEN_MASK | USDHC_WTMK_LVL_WR_BRST_LEN_MASK); wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel) | USDHC_WTMK_LVL_RD_BRST_LEN(config->readBurstLen) | USDHC_WTMK_LVL_WR_BRST_LEN(config->writeBurstLen)); +#endif /* config the data timeout value */ sysctl &= ~USDHC_SYS_CTRL_DTOCV_MASK; @@ -767,33 +885,63 @@ void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config) #endif /* disable internal DMA and DDR mode */ base->MIX_CTRL &= ~(USDHC_MIX_CTRL_DMAEN_MASK | USDHC_MIX_CTRL_DDR_EN_MASK); - /* Enable interrupt status but doesn't enable interrupt signal. */ - USDHC_SetTransferInterrupt(base, false); + /* disable interrupt, enable all the interrupt status, clear status. */ + base->INT_STATUS_EN = kUSDHC_AllInterruptFlags; + base->INT_SIGNAL_EN = 0UL; + base->INT_STATUS = kUSDHC_AllInterruptFlags; } +/*! + * brief Deinitializes the USDHC. + * + * param base USDHC peripheral base address. + */ void USDHC_Deinit(USDHC_Type *base) { +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable clock. */ CLOCK_DisableClock(s_usdhcClock[USDHC_GetInstance(base)]); +#endif } +/*! + * brief Resets the USDHC. + * + * param base USDHC peripheral base address. + * param mask The reset type mask(_usdhc_reset). + * param timeout Timeout for reset. + * retval true Reset successfully. + * retval false Reset failed. + */ bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout) { - base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK)); + base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) + | USDHC_SYS_CTRL_RSTT_MASK +#endif + )); /* Delay some time to wait reset success. */ - while ((base->SYS_CTRL & mask) != 0U) { - if (timeout == 0U) { + while (IS_USDHC_FLAG_SET(base->SYS_CTRL, mask)) + { + if (timeout == 0UL) + { break; } timeout--; } - return ((!timeout) ? false : true); + return ((0UL == timeout) ? false : true); } +/*! + * brief Gets the capability information. + * + * param base USDHC peripheral base address. + * param capability Structure to save capability information. + */ void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability) { - assert(capability); + assert(capability != NULL); uint32_t htCapability; uint32_t maxBlockLength; @@ -802,87 +950,129 @@ void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability) /* Get the capability of USDHC. */ maxBlockLength = ((htCapability & USDHC_HOST_CTRL_CAP_MBL_MASK) >> USDHC_HOST_CTRL_CAP_MBL_SHIFT); - capability->maxBlockLength = (512U << maxBlockLength); + capability->maxBlockLength = (512UL << maxBlockLength); /* Other attributes not in HTCAPBLT register. */ capability->maxBlockCount = USDHC_MAX_BLOCK_COUNT; - capability->flags = (htCapability & (kUSDHC_SupportAdmaFlag | kUSDHC_SupportHighSpeedFlag | kUSDHC_SupportDmaFlag | - kUSDHC_SupportSuspendResumeFlag | kUSDHC_SupportV330Flag)); - capability->flags |= (htCapability & kUSDHC_SupportV300Flag); - capability->flags |= (htCapability & kUSDHC_SupportV180Flag); - capability->flags |= - (htCapability & (kUSDHC_SupportDDR50Flag | kUSDHC_SupportSDR104Flag | kUSDHC_SupportSDR50Flag)); + capability->flags = + (htCapability & (USDHC_HOST_CTRL_CAP_ADMAS_MASK | USDHC_HOST_CTRL_CAP_HSS_MASK | USDHC_HOST_CTRL_CAP_DMAS_MASK | + USDHC_HOST_CTRL_CAP_SRS_MASK | USDHC_HOST_CTRL_CAP_VS33_MASK)); + capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS30_MASK; + capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS18_MASK; + capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK; +#if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR104_MODE + capability->flags |= USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK; +#endif + +#if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR50_MODE + capability->flags |= USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK; +#endif /* USDHC support 4/8 bit data bus width. */ - capability->flags |= (kUSDHC_Support4BitFlag | kUSDHC_Support8BitFlag); + capability->flags |= (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0UL) | (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1UL); } +/*! + * brief Sets the SD bus clock frequency. + * + * param base USDHC peripheral base address. + * param srcClock_Hz USDHC source clock frequency united in Hz. + * param busClock_Hz SD bus clock frequency united in Hz. + * + * return The nearest frequency of busClock_Hz configured to SD bus. + */ uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz) { assert(srcClock_Hz != 0U); - assert((busClock_Hz != 0U) && (busClock_Hz <= srcClock_Hz)); + assert(busClock_Hz != 0U); + + uint32_t totalDiv = 0UL; + uint32_t divisor = 0UL; + uint32_t prescaler = 0UL; + uint32_t sysctl = 0UL; + uint32_t nearestFrequency = 0UL; + + if (busClock_Hz > srcClock_Hz) + { + busClock_Hz = srcClock_Hz; + } - uint32_t totalDiv = 0U; - uint32_t divisor = 0U; - uint32_t prescaler = 0U; - uint32_t sysctl = 0U; - uint32_t nearestFrequency = 0U; + totalDiv = srcClock_Hz / busClock_Hz; /* calucate total divisor first */ - if ((totalDiv = srcClock_Hz / busClock_Hz) > (USDHC_MAX_CLKFS * USDHC_MAX_DVS)) { - return 0U; + if (totalDiv > (USDHC_MAX_CLKFS * USDHC_MAX_DVS)) + { + return 0UL; } - if (totalDiv != 0U) { + if (totalDiv != 0UL) + { /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */ - if ((srcClock_Hz / totalDiv) > busClock_Hz) { + if ((srcClock_Hz / totalDiv) > busClock_Hz) + { totalDiv++; } /* divide the total divisor to div and prescaler */ - if (totalDiv > USDHC_MAX_DVS) { + if (totalDiv > USDHC_MAX_DVS) + { prescaler = totalDiv / USDHC_MAX_DVS; /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */ - while (((USDHC_MAX_CLKFS % prescaler) != 0U) || (prescaler == 1U)) { + while (((USDHC_MAX_CLKFS % prescaler) != 0UL) || (prescaler == 1UL)) + { prescaler++; } /* calucate the divisor */ divisor = totalDiv / prescaler; /* fine tuning the divisor until divisor * prescaler >= totalDiv */ - while ((divisor * prescaler) < totalDiv) { + while ((divisor * prescaler) < totalDiv) + { divisor++; + if (divisor > USDHC_MAX_DVS) + { + prescaler <<= 1UL; + if (prescaler > USDHC_MAX_CLKFS) + { + return 0UL; + } + divisor = totalDiv / prescaler; + } } - - nearestFrequency = srcClock_Hz / (divisor == 0U ? 1U : divisor) / prescaler; } - else { + else + { /* in this situation , divsior and SDCLKFS can generate same clock use SDCLKFS*/ - if ((USDHC_MAX_DVS % totalDiv) == 0U) { - divisor = 0U; - prescaler = totalDiv; + if (((totalDiv % 2UL) != 0UL) && (totalDiv != 1UL)) + { + divisor = totalDiv; + prescaler = 1UL; } - else { - divisor = (totalDiv / 2U) + 1U; /* make sure the output frequency not bigger than target value */ - prescaler = 2U; + else + { + divisor = 1UL; + prescaler = totalDiv; } - nearestFrequency = srcClock_Hz / totalDiv; } + nearestFrequency = srcClock_Hz / (divisor == 0UL ? 1UL : divisor) / prescaler; } /* in this condition , srcClock_Hz = busClock_Hz, */ - else { + else + { /* in DDR mode , set SDCLKFS to 0, divisor = 0, actually the totoal divider = 2U */ - divisor = 0U; - prescaler = 0U; + divisor = 0UL; + prescaler = 0UL; nearestFrequency = srcClock_Hz; } /* calucate the value write to register */ - if (divisor != 0U) { + if (divisor != 0UL) + { USDHC_PREV_DVS(divisor); } /* calucate the value write to register */ - if (prescaler != 0U) { - USDHC_PREV_CLKFS(prescaler, 1U); + if (prescaler != 0UL) + { + USDHC_PREV_CLKFS(prescaler, 1UL); } /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */ @@ -892,51 +1082,95 @@ uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busCl base->SYS_CTRL = sysctl; /* Wait until the SD clock is stable. */ - while (!(base->PRES_STATE & USDHC_PRES_STATE_SDSTB_MASK)) {} + while (!IS_USDHC_FLAG_SET(base->PRES_STATE, USDHC_PRES_STATE_SDSTB_MASK)) + { + } return nearestFrequency; } +/*! + * brief Sends 80 clocks to the card to set it to the active state. + * + * This function must be called each time the card is inserted to ensure that the card can receive the command + * correctly. + * + * param base USDHC peripheral base address. + * param timeout Timeout to initialize card. + * retval true Set card active successfully. + * retval false Set card active failed. + */ bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout) { base->SYS_CTRL |= USDHC_SYS_CTRL_INITA_MASK; /* Delay some time to wait card become active state. */ - while ((base->SYS_CTRL & USDHC_SYS_CTRL_INITA_MASK) == USDHC_SYS_CTRL_INITA_MASK) { - if (!timeout) { + while (IS_USDHC_FLAG_SET(base->SYS_CTRL, USDHC_SYS_CTRL_INITA_MASK)) + { + if (0UL == timeout) + { break; } timeout--; } - return ((!timeout) ? false : true); + return ((0UL == timeout) ? false : true); } +/*! + * brief the enable/disable DDR mode + * + * param base USDHC peripheral base address. + * param enable/disable flag + * param nibble position + */ void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos) { uint32_t prescaler = (base->SYS_CTRL & USDHC_SYS_CTRL_SDCLKFS_MASK) >> USDHC_SYS_CTRL_SDCLKFS_SHIFT; - if (enable) { + if (enable) + { base->MIX_CTRL &= ~USDHC_MIX_CTRL_NIBBLE_POS_MASK; base->MIX_CTRL |= (USDHC_MIX_CTRL_DDR_EN_MASK | USDHC_MIX_CTRL_NIBBLE_POS(nibblePos)); - prescaler >>= 1U; + prescaler >>= 1UL; } - else { + else + { base->MIX_CTRL &= ~USDHC_MIX_CTRL_DDR_EN_MASK; - if (prescaler == 0U) { - prescaler += 1U; + if (prescaler == 0UL) + { + prescaler += 1UL; } - else { - prescaler <<= 1U; + else + { + prescaler <<= 1UL; } } base->SYS_CTRL = (base->SYS_CTRL & (~USDHC_SYS_CTRL_SDCLKFS_MASK)) | USDHC_SYS_CTRL_SDCLKFS(prescaler); } +/*! + * brief Configures the MMC boot feature. + * + * Example: + code + usdhc_boot_config_t config; + config.ackTimeoutCount = 4; + config.bootMode = kUSDHC_BootModeNormal; + config.blockCount = 5; + config.enableBootAck = true; + config.enableBoot = true; + config.enableAutoStopAtBlockGap = true; + USDHC_SetMmcBootConfig(USDHC, &config); + endcode + * + * param base USDHC peripheral base address. + * param config The MMC boot configuration information. + */ void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config) { - assert(config); + assert(config != NULL); assert(config->ackTimeoutCount <= (USDHC_MMC_BOOT_DTOCV_ACK_MASK >> USDHC_MMC_BOOT_DTOCV_ACK_SHIFT)); assert(config->blockCount <= (USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK >> USDHC_MMC_BOOT_BOOT_BLK_CNT_SHIFT)); @@ -945,17 +1179,20 @@ void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config) mmcboot &= ~(USDHC_MMC_BOOT_DTOCV_ACK_MASK | USDHC_MMC_BOOT_BOOT_MODE_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK); mmcboot |= USDHC_MMC_BOOT_DTOCV_ACK(config->ackTimeoutCount) | USDHC_MMC_BOOT_BOOT_MODE(config->bootMode); - if (config->enableBootAck) { + if (config->enableBootAck) + { mmcboot |= USDHC_MMC_BOOT_BOOT_ACK_MASK; } - if (config->enableAutoStopAtBlockGap) { + if (config->enableAutoStopAtBlockGap) + { mmcboot |= USDHC_MMC_BOOT_AUTO_SABG_EN_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT(USDHC_MAX_BLOCK_COUNT - config->blockCount); /* always set the block count to USDHC_MAX_BLOCK_COUNT to use auto stop at block gap feature */ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) | (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(USDHC_MAX_BLOCK_COUNT))); } - else { + else + { base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) | (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(config->blockCount))); } @@ -963,23 +1200,37 @@ void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config) base->MMC_BOOT = mmcboot; } +/*! + * brief Sets the ADMA1 descriptor table configuration. + * + * param admaTable Adma table address. + * param admaTableWords Adma table length. + * param dataBufferAddr Data buffer address. + * param dataBytes Data length. + * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * reference _usdhc_adma_flag. + * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * retval kStatus_Success Operate successfully. + */ status_t USDHC_SetADMA1Descriptor( uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags) { assert(NULL != admaTable); assert(NULL != dataBufferAddr); - uint32_t miniEntries, startEntries = 0U, + uint32_t miniEntries, startEntries = 0UL, maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma1_descriptor_t); - usdhc_adma1_descriptor_t *adma1EntryAddress = (usdhc_adma1_descriptor_t *)(admaTable); - uint32_t i, dmaBufferLen = 0U; + usdhc_adma1_descriptor_t *adma1EntryAddress = (usdhc_adma1_descriptor_t *)(uint32_t)(admaTable); + uint32_t i, dmaBufferLen = 0UL; const uint32_t *data = dataBufferAddr; - if (((uint32_t)data % USDHC_ADMA1_ADDRESS_ALIGN) != 0U) { + if (((uint32_t)data % USDHC_ADMA1_ADDRESS_ALIGN) != 0UL) + { return kStatus_USDHC_DMADataAddrNotAlign; } - if (flags == kUSDHC_AdmaDescriptorMultipleFlag) { + if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag) + { return kStatus_USDHC_NotSupport; } /* @@ -987,60 +1238,81 @@ status_t USDHC_SetADMA1Descriptor( * 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) { + if (dataBytes % sizeof(uint32_t) != 0UL) + { /* make the data length as word-aligned */ dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); } /* Check if ADMA descriptor's number is enough. */ - if ((dataBytes % USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0U) { + if ((dataBytes % USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL) + { miniEntries = dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; } - else { - miniEntries = ((dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U); + else + { + miniEntries = ((dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL); } /* ADMA1 needs two descriptors to finish a transfer */ - miniEntries <<= 1U; + miniEntries <<= 1UL; - if (miniEntries + startEntries > maxEntries) { + if (miniEntries + startEntries > maxEntries) + { return kStatus_OutOfRange; } - for (i = startEntries; i < (miniEntries + startEntries); i += 2U) { - if (dataBytes > USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) { + for (i = startEntries; i < (miniEntries + startEntries); i += 2UL) + { + if (dataBytes > USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + { dmaBufferLen = USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; } - else { + else + { dmaBufferLen = dataBytes; } adma1EntryAddress[i] = (dmaBufferLen << USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT); - adma1EntryAddress[i] |= kUSDHC_Adma1DescriptorTypeSetLength; - adma1EntryAddress[i + 1U] = (uint32_t)(data); - adma1EntryAddress[i + 1U] |= kUSDHC_Adma1DescriptorTypeTransfer; - data += dmaBufferLen / sizeof(uint32_t); + adma1EntryAddress[i] |= (uint32_t)kUSDHC_Adma1DescriptorTypeSetLength; + adma1EntryAddress[i + 1UL] = (uint32_t)(data); + adma1EntryAddress[i + 1UL] |= + (uint32_t)kUSDHC_Adma1DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma1DescriptorInterrupFlag; + data = (uint32_t *)((uint32_t)data + dmaBufferLen); dataBytes -= dmaBufferLen; } /* the end of the descriptor */ - adma1EntryAddress[i - 1U] |= kUSDHC_Adma1DescriptorEndFlag; + adma1EntryAddress[i - 1UL] |= (uint32_t)kUSDHC_Adma1DescriptorEndFlag; return kStatus_Success; } +/*! + * brief Sets the ADMA2 descriptor table configuration. + * + * param admaTable Adma table address. + * param admaTableWords Adma table length. + * param dataBufferAddr Data buffer address. + * param dataBytes Data Data length. + * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * reference _usdhc_adma_flag. + * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * retval kStatus_Success Operate successfully. + */ status_t USDHC_SetADMA2Descriptor( uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags) { assert(NULL != admaTable); assert(NULL != dataBufferAddr); - uint32_t miniEntries, startEntries = 0U, + uint32_t miniEntries, startEntries = 0UL, maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma2_descriptor_t); - usdhc_adma2_descriptor_t *adma2EntryAddress = (usdhc_adma2_descriptor_t *)(admaTable); - uint32_t i, dmaBufferLen = 0U; + usdhc_adma2_descriptor_t *adma2EntryAddress = (usdhc_adma2_descriptor_t *)(uint32_t)(admaTable); + uint32_t i, dmaBufferLen = 0UL; const uint32_t *data = dataBufferAddr; - if (((uint32_t)data % USDHC_ADMA2_ADDRESS_ALIGN) != 0U) { + if (((uint32_t)data % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL) + { return kStatus_USDHC_DMADataAddrNotAlign; } /* @@ -1048,52 +1320,65 @@ status_t USDHC_SetADMA2Descriptor( * 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) { + if (dataBytes % sizeof(uint32_t) != 0UL) + { /* make the data length as word-aligned */ dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); } /* Check if ADMA descriptor's number is enough. */ - if ((dataBytes % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0U) { + if ((dataBytes % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL) + { miniEntries = dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; } - else { - miniEntries = ((dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U); + else + { + miniEntries = ((dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL); } /* calucate the start entry for multiple descriptor mode, ADMA engine is not stop, so update the descriptor data adress and data size is enough */ - if (flags == kUSDHC_AdmaDescriptorMultipleFlag) { - for (i = 0U; i < maxEntries; i++) { - if ((adma2EntryAddress[i].attribute & kUSDHC_Adma2DescriptorValidFlag) == 0U) { + if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag) + { + for (i = 0UL; i < maxEntries; i++) + { + if ((adma2EntryAddress[i].attribute & (uint32_t)kUSDHC_Adma2DescriptorValidFlag) == 0UL) + { break; } } startEntries = i; /* add one entry for dummy entry */ - miniEntries += 1U; + miniEntries += 1UL; } - if ((miniEntries + startEntries) > maxEntries) { + if ((miniEntries + startEntries) > maxEntries) + { return kStatus_OutOfRange; } - for (i = startEntries; i < (miniEntries + startEntries); i++) { - if (dataBytes > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) { + for (i = startEntries; i < (miniEntries + startEntries); i++) + { + if (dataBytes > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + { dmaBufferLen = USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; } - else { - dmaBufferLen = (dataBytes == 0U ? sizeof(uint32_t) - : dataBytes); /* adma don't support 0 data length transfer descriptor */ + else + { + dmaBufferLen = (dataBytes == 0UL ? sizeof(uint32_t) : + dataBytes); /* adma don't support 0 data length transfer descriptor */ } /* Each descriptor for ADMA2 is 64-bit in length */ - adma2EntryAddress[i].address = (dataBytes == 0U) ? &s_usdhcBootDummy : data; + adma2EntryAddress[i].address = (dataBytes == 0UL) ? &s_usdhcBootDummy : data; adma2EntryAddress[i].attribute = (dmaBufferLen << USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT); adma2EntryAddress[i].attribute |= - (dataBytes == 0U) ? 0U : (kUSDHC_Adma2DescriptorTypeTransfer | kUSDHC_Adma2DescriptorInterruptFlag); - data += (dmaBufferLen / sizeof(uint32_t)); + (dataBytes == 0UL) ? + 0UL : + ((uint32_t)kUSDHC_Adma2DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma2DescriptorInterruptFlag); + data = (uint32_t *)((uint32_t)data + dmaBufferLen); - if (dataBytes != 0U) { + if (dataBytes != 0UL) + { dataBytes -= dmaBufferLen; } } @@ -1101,145 +1386,227 @@ status_t USDHC_SetADMA2Descriptor( /* add a dummy valid ADMA descriptor for multiple descriptor mode, this is useful when transfer boot data, the ADMA engine will not stop at block gap */ - if (flags == kUSDHC_AdmaDescriptorMultipleFlag) { - adma2EntryAddress[startEntries + 1U].attribute |= kUSDHC_Adma2DescriptorTypeTransfer; + if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag) + { + adma2EntryAddress[startEntries + 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorTypeTransfer; } - else { + else + { /* set the end bit */ - adma2EntryAddress[i - 1U].attribute |= kUSDHC_Adma2DescriptorEndFlag; + adma2EntryAddress[i - 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorEndFlag; } return kStatus_Success; } +/*! + * brief Internal DMA configuration. + * This function is used to config the USDHC DMA related registers. + * param base USDHC peripheral base address. + * param adma configuration + * param dataAddr transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL. + * param enAutoCmd23 flag to indicate Auto CMD23 is enable or not, a simple DMA parameter,if ADMA is used, leave it to + * false. + * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * retval kStatus_Success Operate successfully. + */ status_t USDHC_SetInternalDmaConfig(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, const uint32_t *dataAddr, bool enAutoCmd23) { - assert(dmaConfig); - assert(dataAddr); + assert(dmaConfig != NULL); + assert(dataAddr != NULL); + assert((NULL != dmaConfig->admaTable) && + (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL)); #if FSL_FEATURE_USDHC_HAS_EXT_DMA /* disable the external DMA if support */ base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK; #endif - if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple) { + if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple) + { /* check DMA data buffer address align or not */ - if (((uint32_t)dataAddr % USDHC_ADMA2_ADDRESS_ALIGN) != 0U) { + if (((uint32_t)dataAddr % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL) + { return kStatus_USDHC_DMADataAddrNotAlign; } /* in simple DMA mode if use auto CMD23, address should load to ADMA addr, and block count should load to DS_ADDR*/ - if (enAutoCmd23) { - base->ADMA_SYS_ADDR = (uint32_t)dataAddr; + if (enAutoCmd23) + { + base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr); } - else { - base->DS_ADDR = (uint32_t)dataAddr; + else + { + base->DS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr); } } - else { + else + { /* When use ADMA, disable simple DMA */ - base->DS_ADDR = 0U; - base->ADMA_SYS_ADDR = (uint32_t)(dmaConfig->admaTable); + base->DS_ADDR = 0UL; + base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)(dmaConfig->admaTable)); } +#if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) + /* select DMA mode and config the burst length */ + base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK); + base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode); +#else /* select DMA mode and config the burst length */ base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK | USDHC_PROT_CTRL_BURST_LEN_EN_MASK); base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode) | USDHC_PROT_CTRL_BURST_LEN_EN(dmaConfig->burstLen); +#endif /* enable DMA */ base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK; return kStatus_Success; } +/*! + * brief Sets the DMA descriptor table configuration. + * A high level DMA descriptor configuration function. + * param base USDHC peripheral base address. + * param adma configuration + * param data Data descriptor + * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * reference _usdhc_adma_flag + * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * retval kStatus_Success Operate successfully. + */ status_t USDHC_SetAdmaTableConfig(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_data_t *dataConfig, uint32_t flags) { assert(NULL != dmaConfig); - assert(NULL != dmaConfig->admaTable); + assert((NULL != dmaConfig->admaTable) && + (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL)); assert(NULL != dataConfig); - status_t error = kStatus_Fail; - uint32_t bootDummyOffset = dataConfig->dataType == kUSDHC_TransferDataBootcontinous ? sizeof(uint32_t) : 0U; - const uint32_t *data = - (const uint32_t *)((uint32_t)((dataConfig->rxData == NULL) ? dataConfig->txData : dataConfig->rxData) + - bootDummyOffset); - uint32_t blockSize = dataConfig->blockSize * dataConfig->blockCount - bootDummyOffset; + status_t error = kStatus_Fail; + uint32_t bootDummyOffset = + dataConfig->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous ? sizeof(uint32_t) : 0UL; + const uint32_t *data = (const uint32_t *)USDHC_ADDR_CPU_2_DMA((uint32_t)( + (uint32_t)((dataConfig->rxData == NULL) ? dataConfig->txData : dataConfig->rxData) + bootDummyOffset)); + uint32_t blockSize = dataConfig->blockSize * dataConfig->blockCount - bootDummyOffset; - switch (dmaConfig->dmaMode) { #if FSL_FEATURE_USDHC_HAS_EXT_DMA - case kUSDHC_ExternalDMA: + if (dmaConfig->dmaMode == kUSDHC_ExternalDMA) + { /* enable the external DMA */ base->VEND_SPEC |= USDHC_VEND_SPEC_EXT_DMA_EN_MASK; - break; + } + else #endif - case kUSDHC_DmaModeSimple: + if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple) + { error = kStatus_Success; - break; - - case kUSDHC_DmaModeAdma1: + } + else if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1) + { error = USDHC_SetADMA1Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags); - break; - - case kUSDHC_DmaModeAdma2: + } + /* ADMA2 */ + else + { error = USDHC_SetADMA2Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags); - break; - default: - return kStatus_USDHC_PrepareAdmaDescriptorFailed; } /* for internal dma, internal DMA configurations should not update the configurations when continous transfer the * boot data, only the DMA descriptor need update */ if ((dmaConfig->dmaMode != kUSDHC_ExternalDMA) && (error == kStatus_Success) && - (dataConfig->dataType != kUSDHC_TransferDataBootcontinous)) { + (dataConfig->dataType != (uint32_t)kUSDHC_TransferDataBootcontinous)) + { error = USDHC_SetInternalDmaConfig(base, dmaConfig, data, dataConfig->enableAutoCommand23); } return error; } +/*! + * brief Transfers the command/data using a blocking method. + * + * This function waits until the command response/data is received or the USDHC encounters an error by polling the + * status + * flag. + * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support + * the re-entry mechanism. + * + * note There is no need to call the API 'USDHC_TransferCreateHandle' when calling this API. + * + * param base USDHC peripheral base address. + * param adma configuration + * param transfer Transfer content. + * retval kStatus_InvalidArgument Argument is invalid. + * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * retval kStatus_USDHC_SendCommandFailed Send command failed. + * retval kStatus_USDHC_TransferDataFailed Transfer data failed. + * retval kStatus_Success Operate successfully. + */ status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer) { - assert(transfer); + assert(transfer != NULL); status_t error = kStatus_Fail; usdhc_command_t *command = transfer->command; usdhc_data_t *data = transfer->data; bool enDMA = true; - bool executeTuning = ((data == NULL) ? false : data->dataType == kUSDHC_TransferDataTuning); + bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning); + uint32_t transferFlags = (uint32_t)kUSDHC_CommandOnly; + size_t blockSize = 0U; + size_t blockCount = 0U; +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) /*check re-tuning request*/ - if ((USDHC_GetInterruptStatusFlags(base) & kUSDHC_ReTuningEventFlag) != 0U) { + if ((USDHC_GetInterruptStatusFlags(base) & (uint32_t)kUSDHC_ReTuningEventFlag) != 0UL) + { USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag); return kStatus_USDHC_ReTuningRequest; } +#endif - /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/ - if ((data != NULL) && (dmaConfig != NULL) && (!executeTuning)) { - error = USDHC_SetAdmaTableConfig(base, - dmaConfig, - data, - (data->dataType & kUSDHC_TransferDataBoot) ? kUSDHC_AdmaDescriptorMultipleFlag - : kUSDHC_AdmaDescriptorSingleFlag); + if (data != NULL) + { + /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/ + if ((dmaConfig != NULL) && (!executeTuning)) + { + error = USDHC_SetAdmaTableConfig(base, dmaConfig, data, + (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, kUSDHC_TransferDataBoot) ? + kUSDHC_AdmaDescriptorMultipleFlag : + kUSDHC_AdmaDescriptorSingleFlag)); + } + blockSize = data->blockSize; + blockCount = data->blockCount; + transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U; + transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U; + transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData; + transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U; + transferFlags |= + data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U; + + command->flags |= (uint32_t)kUSDHC_DataPresentFlag; } /* if the DMA desciptor configure fail or not needed , disable it */ - if (error != kStatus_Success) { + if (error != kStatus_Success) + { enDMA = false; /* disable DMA, using polling mode in this situation */ USDHC_EnableInternalDMA(base, false); } #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL - else { - if (data->txData != NULL) { + else + { + if (data->txData != NULL) + { /* clear the DCACHE */ DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount)); } - else if (data->rxData != NULL) { + else + { /* clear the DCACHE */ DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount)); } @@ -1247,107 +1614,397 @@ status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig #endif /* config the data transfer parameter */ - error = USDHC_SetDataTransferConfig(base, data, &(command->flags)); - if (kStatus_Success != error) { + error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount); + if (error != kStatus_Success) + { return error; } /* send command first */ USDHC_SendCommand(base, command); /* wait command done */ - error = USDHC_WaitCommandDone(base, command, (data == NULL) || (data->dataType == kUSDHC_TransferDataNormal)); + error = + USDHC_WaitCommandDone(base, command, (data == NULL) || (data->dataType == (uint32_t)kUSDHC_TransferDataNormal)); + if (kStatus_Success != error) + { + return kStatus_USDHC_SendCommandFailed; + } /* wait transfer data finsih */ - if ((data != NULL) && (error == kStatus_Success)) { - return USDHC_TransferDataBlocking(base, data, enDMA); + if (data != NULL) + { + error = USDHC_TransferDataBlocking(base, data, enDMA); + if (kStatus_Success != error) + { + return error; + } } + return kStatus_Success; +} + +#if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER +static status_t USDHC_SetScatterGatherAdmaTableConfig(USDHC_Type *base, + usdhc_adma_config_t *dmaConfig, + usdhc_scatter_gather_data_t *dataConfig, + uint32_t *totalTransferSize) +{ + assert(NULL != dmaConfig); + assert((NULL != dmaConfig->admaTable) && + (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL)); + assert(NULL != dataConfig); + + status_t error = kStatus_Fail; + uint32_t *admaDesBuffer = dmaConfig->admaTable; + uint32_t admaDesLen = dmaConfig->admaTableWords; + usdhc_scatter_gather_data_list_t *sgDataList = &dataConfig->sgData; + uint32_t oneDescriptorMaxTransferSize = dmaConfig->dmaMode == kUSDHC_DmaModeAdma1 ? + USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY : + USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; + uint32_t miniEntries = 0U; + + while (sgDataList != NULL) + { + if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1) + { + error = USDHC_SetADMA1Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U); + } + /* ADMA2 */ + else + { + error = USDHC_SetADMA2Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U); + } + + if (error != kStatus_Success) + { + return kStatus_USDHC_PrepareAdmaDescriptorFailed; + } + +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (dataConfig->dataDirection == kUSDHC_TransferDirectionSend) + { + /* clear the DCACHE */ + DCACHE_CleanByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize); + } + else + { + /* clear the DCACHE */ + DCACHE_CleanInvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize); + } +#endif + + *totalTransferSize += sgDataList->dataSize; + if (sgDataList->dataList != NULL) + { + if ((sgDataList->dataSize % oneDescriptorMaxTransferSize) == 0UL) + { + miniEntries = sgDataList->dataSize / oneDescriptorMaxTransferSize; + } + else + { + miniEntries = ((sgDataList->dataSize / oneDescriptorMaxTransferSize) + 1UL); + } + if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1) + { + admaDesBuffer[miniEntries * 2U - 1U] &= ~kUSDHC_Adma1DescriptorEndFlag; + } + else + { + admaDesBuffer[miniEntries * 2U - 2U] &= ~kUSDHC_Adma2DescriptorEndFlag; + } + admaDesBuffer += miniEntries * 2U; + admaDesLen -= miniEntries * 2U; + } + + sgDataList = sgDataList->dataList; + } + + base->DS_ADDR = 0UL; + base->ADMA_SYS_ADDR = (uint32_t)(dmaConfig->admaTable); + + /* select DMA mode and config the burst length */ + base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK); + base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode); + + /* enable DMA */ + base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK; + return error; } +/*! + * brief Transfers the command/scatter gather data using an interrupt and an asynchronous method. + * + * This function sends a command and data and returns immediately. It doesn't wait for the transfer to complete or + * to encounter an error. The application must not call this API in multiple threads at the same time. Because of that + * this API doesn't support the re-entry mechanism. + * This function is target for the application would like to have scatter gather buffer to be transferred within one + * read/write request, non scatter gather buffer is support by this function also. + * + * note Call API @ref USDHC_TransferCreateHandle when calling this API. + * + * param base USDHC peripheral base address. + * param handle USDHC handle. + * param dmaConfig adma configurations, must be not NULL, since the function is target for ADMA only. + * param transfer scatter gather transfer content. + * + * retval #kStatus_InvalidArgument Argument is invalid. + * retval #kStatus_USDHC_BusyTransferring Busy transferring. + * retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * retval #kStatus_Success Operate successfully. + */ +status_t USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type *base, + usdhc_handle_t *handle, + usdhc_adma_config_t *dmaConfig, + usdhc_scatter_gather_transfer_t *transfer) +{ + assert(handle != NULL); + assert(transfer != NULL); + assert(dmaConfig != NULL); + + status_t error = kStatus_Fail; + usdhc_command_t *command = transfer->command; + uint32_t totalTransferSize = 0U; + uint32_t transferFlags = kUSDHC_CommandOnly; + size_t blockSize = 0U; + size_t blockCount = 0U; + usdhc_scatter_gather_data_t *scatterGatherData = transfer->data; + bool enDMA = false; + + /* check data inhibit flag */ + if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag)) + { + return kStatus_USDHC_BusyTransferring; + } + + handle->command = command; + handle->data = scatterGatherData; + /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */ + handle->transferredWords = 0UL; + + /* Update ADMA descriptor table according to different DMA mode(ADMA1, ADMA2).*/ + if (scatterGatherData != NULL) + { + if (scatterGatherData->sgData.dataAddr == NULL) + { + return kStatus_InvalidArgument; + } + + if (scatterGatherData->dataType != (uint32_t)kUSDHC_TransferDataTuning) + { + if (USDHC_SetScatterGatherAdmaTableConfig(base, dmaConfig, transfer->data, &totalTransferSize) != + kStatus_Success) + { + return kStatus_USDHC_PrepareAdmaDescriptorFailed; + } + + enDMA = true; + } + blockSize = scatterGatherData->blockSize; + blockCount = totalTransferSize / scatterGatherData->blockSize; + transferFlags = scatterGatherData->enableAutoCommand12 ? kUSDHC_DataWithAutoCmd12 : 0U; + transferFlags |= scatterGatherData->enableAutoCommand23 ? kUSDHC_DataWithAutoCmd23 : 0U; + transferFlags |= scatterGatherData->dataDirection == kUSDHC_TransferDirectionSend ? kUSDHC_CommandAndTxData : + kUSDHC_CommandAndRxData; + command->flags |= kUSDHC_DataPresentFlag; + } + + error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount); + if (error != kStatus_Success) + { + return error; + } + + /* enable interrupt per transfer request */ + if (scatterGatherData != NULL) + { + USDHC_ClearInterruptStatusFlags( + base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) | + (uint32_t)kUSDHC_CommandFlag); + USDHC_EnableInterruptSignal( + base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) | + (uint32_t)kUSDHC_CommandFlag); + } + else + { + USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag); + USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag); + } + + /* send command first */ + USDHC_SendCommand(base, command); + + return kStatus_Success; +} +#else +/*! + * brief Transfers the command/data using an interrupt and an asynchronous method. + * + * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or encounter an + * error. + * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support + * the re-entry mechanism. + * + * note Call the API 'USDHC_TransferCreateHandle' when calling this API. + * + * param base USDHC peripheral base address. + * param handle USDHC handle. + * param adma configuration. + * param transfer Transfer content. + * retval kStatus_InvalidArgument Argument is invalid. + * retval kStatus_USDHC_BusyTransferring Busy transferring. + * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * retval kStatus_Success Operate successfully. + */ status_t USDHC_TransferNonBlocking(USDHC_Type *base, usdhc_handle_t *handle, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer) { - assert(handle); - assert(transfer); + assert(handle != NULL); + assert(transfer != NULL); status_t error = kStatus_Fail; usdhc_command_t *command = transfer->command; usdhc_data_t *data = transfer->data; - bool executeTuning = ((data == NULL) ? false : data->dataType == kUSDHC_TransferDataTuning); + bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning); + bool enDMA = true; + uint32_t transferFlags = (uint32_t)kUSDHC_CommandOnly; + size_t blockSize = 0U; + size_t blockCount = 0U; +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) /*check re-tuning request*/ - if ((USDHC_GetInterruptStatusFlags(base) & (kUSDHC_ReTuningEventFlag)) != 0U) { + if ((USDHC_GetInterruptStatusFlags(base) & ((uint32_t)kUSDHC_ReTuningEventFlag)) != 0UL) + { USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag); return kStatus_USDHC_ReTuningRequest; } - +#endif /* Save command and data into handle before transferring. */ - handle->command = command; - handle->data = data; - handle->interruptFlags = 0U; + + handle->command = command; + handle->data = data; /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */ - handle->transferredWords = 0U; + handle->transferredWords = 0UL; + + if (data != NULL) + { + /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/ + if ((dmaConfig != NULL) && (!executeTuning)) + { + error = USDHC_SetAdmaTableConfig( + base, dmaConfig, data, + (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, (uint32_t)kUSDHC_TransferDataBoot) ? + kUSDHC_AdmaDescriptorMultipleFlag : + kUSDHC_AdmaDescriptorSingleFlag)); + } + + blockSize = data->blockSize; + blockCount = data->blockCount; + transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U; + transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U; + transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData; + transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U; + transferFlags |= + data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U; - /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/ - if ((data != NULL) && (dmaConfig != NULL) && (!executeTuning)) { - error = USDHC_SetAdmaTableConfig(base, - dmaConfig, - data, - (data->dataType & kUSDHC_TransferDataBoot) ? kUSDHC_AdmaDescriptorMultipleFlag - : kUSDHC_AdmaDescriptorSingleFlag); + command->flags |= (uint32_t)kUSDHC_DataPresentFlag; } /* if the DMA desciptor configure fail or not needed , disable it */ - if (error != kStatus_Success) { + if (error != kStatus_Success) + { /* disable DMA, using polling mode in this situation */ USDHC_EnableInternalDMA(base, false); + enDMA = false; } #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL - else { - if (data->txData != NULL) { + else + { + if (data->txData != NULL) + { /* clear the DCACHE */ DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount)); } - else if (data->rxData != NULL) { + else + { /* clear the DCACHE */ DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount)); } } #endif - error = USDHC_SetDataTransferConfig(base, data, &(command->flags)); - if (kStatus_Success != error) { + /* config the data transfer parameter */ + error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount); + if (error != kStatus_Success) + { return error; } + /* enable interrupt per transfer request */ + if (handle->data != NULL) + { + USDHC_ClearInterruptStatusFlags( + base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) | (uint32_t)kUSDHC_CommandFlag | + (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? + (uint32_t)kUSDHC_DmaCompleteFlag : + 0U)); + USDHC_EnableInterruptSignal(base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) | + (uint32_t)kUSDHC_CommandFlag | + (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? + (uint32_t)kUSDHC_DmaCompleteFlag : + 0U)); + } + else + { + USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag); + USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag); + } + /* send command first */ USDHC_SendCommand(base, command); return kStatus_Success; } +#endif #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) +/*! + * brief manual tuning trigger or abort + * User should handle the tuning cmd and find the boundary of the delay + * then calucate a average value which will be config to the CLK_TUNE_CTRL_STATUS + * This function should called before USDHC_AdjustDelayforSDR104 function + * param base USDHC peripheral base address. + * param tuning enable flag + */ void USDHC_EnableManualTuning(USDHC_Type *base, bool enable) { - if (enable) { + if (enable) + { /* make sure std_tun_en bit is clear */ base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK; /* disable auto tuning here */ base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK; /* execute tuning for SDR104 mode */ - base->MIX_CTRL |= - USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK | USDHC_MIX_CTRL_FBCLK_SEL_MASK; + base->MIX_CTRL |= USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK; } - else { /* abort the tuning */ - base->MIX_CTRL &= ~(USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK); + else + { /* abort the tuning */ + base->MIX_CTRL &= ~USDHC_MIX_CTRL_EXE_TUNE_MASK; } } +/*! + * brief the SDR104 mode delay setting adjust + * This function should called after USDHC_ManualTuningForSDR104 + * param base USDHC peripheral base address. + * param delay setting configuration + * retval kStatus_Fail config the delay setting fail + * retval kStatus_Success config the delay setting success + */ status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay) { - uint32_t clkTuneCtrl = 0U; + uint32_t clkTuneCtrl = 0UL; clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS; @@ -1358,19 +2015,74 @@ status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay) /* load the delay setting */ base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl; /* check delat setting error */ - if (base->CLK_TUNE_CTRL_STATUS & - (USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK)) { + if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS, + USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK)) + { + return kStatus_Fail; + } + + return kStatus_Success; +} + +/*! + * brief The tuning delay cell setting. + * + * param base USDHC peripheral base address. + * param preDelay Set the number of delay cells on the feedback clock between the feedback clock and CLK_PRE. + * param outDelay Set the number of delay cells on the feedback clock between CLK_PRE and CLK_OUT. + * param postDelay Set the number of delay cells on the feedback clock between CLK_OUT and CLK_POST. + * retval kStatus_Fail config the delay setting fail + * retval kStatus_Success config the delay setting success + */ +status_t USDHC_SetTuningDelay(USDHC_Type *base, uint32_t preDelay, uint32_t outDelay, uint32_t postDelay) +{ + assert(preDelay <= + (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_SHIFT)); + assert(outDelay <= + (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_SHIFT)); + assert(postDelay <= + (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_SHIFT)); + + uint32_t clkTuneCtrl = 0UL; + + clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS; + + clkTuneCtrl &= + ~(USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK | USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK | + USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK); + + clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(preDelay) | + USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT(outDelay) | + USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST(postDelay); + + /* load the delay setting */ + base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl; + /* check delat setting error */ + if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS, + USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK)) + { return kStatus_Fail; } return kStatus_Success; } +/*! + * brief the enable standard tuning function + * The standard tuning window and tuning counter use the default config + * tuning cmd is send by the software, user need to check the tuning result + * can be used for SDR50,SDR104,HS200 mode tuning + * param base USDHC peripheral base address. + * param tuning start tap + * param tuning step + * param enable/disable flag + */ void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable) { - uint32_t tuningCtrl = 0U; + uint32_t tuningCtrl = 0UL; - if (enable) { + if (enable) + { /* feedback clock */ base->MIX_CTRL |= USDHC_MIX_CTRL_FBCLK_SEL_MASK; /* config tuning start and step */ @@ -1384,7 +2096,8 @@ void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint3 base->AUTOCMD12_ERR_STATUS |= (USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK); } - else { + else + { /* disable the standard tuning */ base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK; /* clear excute tuning */ @@ -1393,38 +2106,82 @@ void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint3 } } +#if FSL_FEATURE_USDHC_HAS_HS400_MODE +/*! + * brief config the strobe DLL delay target and update interval + * + * param base USDHC peripheral base address. + * param delayTarget delay target + * param updateInterval update interval + */ +void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval) +{ + assert(delayTarget <= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_MASK >> + USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT)); + + /* reset strobe dll firstly */ + base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK; + /* clear reset and other register fields */ + base->STROBE_DLL_CTRL = 0; + /* configure the DELAY target and update interval */ + base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK | + USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT(updateInterval) | + USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET(delayTarget); + + while ( + (USDHC_GetStrobeDLLStatus(base) & (USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK | + USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)) != + ((USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK | USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK))) + { + } +} +#endif + +/*! + * brief the auto tuning enbale for CMD/DATA line + * + * param base USDHC peripheral base address. + */ void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base) { - uint32_t busWidth = 0U; + uint32_t busWidth = (base->PROT_CTRL & USDHC_PROT_CTRL_DTW_MASK) >> USDHC_PROT_CTRL_DTW_SHIFT; base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_CMD_EN_MASK; - busWidth = (base->PROT_CTRL & USDHC_PROT_CTRL_DTW_MASK) >> USDHC_PROT_CTRL_DTW_SHIFT; - if (busWidth == kUSDHC_DataBusWidth1Bit) { + + /* 1bit data width */ + if (busWidth == 0UL) + { base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK; base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK; } - else if (busWidth == kUSDHC_DataBusWidth4Bit) { + /* 4bit data width */ + else if (busWidth == 1UL) + { base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK; base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK; } - else if (busWidth == kUSDHC_DataBusWidth8Bit) { + /* 8bit data width */ + else + { base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK; base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK; } - else { - } } #endif /* FSL_FEATURE_USDHC_HAS_SDR50_MODE */ static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags) { - if (interruptFlags & kUSDHC_CardInsertionFlag) { - if (handle->callback.CardInserted) { + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInsertionFlag)) + { + if (handle->callback.CardInserted != NULL) + { handle->callback.CardInserted(base, handle->userData); } } - else { - if (handle->callback.CardRemoved) { + else + { + if (handle->callback.CardRemoved != NULL) + { handle->callback.CardRemoved(base, handle->userData); } } @@ -1432,100 +2189,204 @@ static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *han static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags) { - assert(handle->command); + assert(handle->command != NULL); - if ((interruptFlags & kUSDHC_CommandErrorFlag) && (!(handle->data))) { - if (handle->callback.TransferComplete) { + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandErrorFlag)) + { + if (handle->callback.TransferComplete != NULL) + { handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData); } } - else { + else + { /* Receive response */ - if (kStatus_Success != USDHC_ReceiveCommandResponse(base, handle->command)) { - if (handle->callback.TransferComplete) { + if (kStatus_Success != USDHC_ReceiveCommandResponse(base, handle->command)) + { + if (handle->callback.TransferComplete != NULL) + { handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData); } } - else if ((!(handle->data)) && (handle->callback.TransferComplete)) { - if (handle->callback.TransferComplete) { - handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData); + else + { + if (handle->callback.TransferComplete != NULL) + { + handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandSuccess, handle->userData); } } - else { - } } + /* disable interrupt signal and reset command pointer */ + USDHC_DisableInterruptSignal(base, kUSDHC_CommandFlag); + handle->command = NULL; } +#if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags) { - assert(handle->data); + assert(handle->data != NULL); - if ((!(handle->data->enableIgnoreError)) && ((interruptFlags & (kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag)))) { - if (handle->callback.TransferComplete) { - handle->callback.TransferComplete(base, handle, kStatus_USDHC_TransferDataFailed, handle->userData); - } + status_t transferStatus = kStatus_USDHC_BusyTransferring; + + if ((!(handle->data->enableIgnoreError)) && + (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag))) + { + transferStatus = kStatus_USDHC_TransferDataFailed; } - else { - if (interruptFlags & kUSDHC_BufferReadReadyFlag) { + else + { + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag)) + { /* std tuning process only need to wait BRR */ - if (handle->data->dataType == kUSDHC_TransferDataTuning) { - if (handle->callback.TransferComplete) { - handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData); + if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning) + { + transferStatus = kStatus_USDHC_TransferDataComplete; + } + } + else + { + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag)) + { + transferStatus = kStatus_USDHC_TransferDMAComplete; + } + + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag)) + { + transferStatus = kStatus_USDHC_TransferDataComplete; + +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->data->dataDirection == kUSDHC_TransferDirectionReceive) + { + usdhc_scatter_gather_data_list_t *sgDataList = &handle->data->sgData; + while (sgDataList != NULL) + { + DCACHE_InvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize); + sgDataList = sgDataList->dataList; + } } +#endif + } + } + } + + if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring)) + { + handle->callback.TransferComplete(base, handle, transferStatus, handle->userData); + USDHC_DisableInterruptSignal( + base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_DmaCompleteFlag); + handle->data = NULL; + } +} + +#else +static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags) +{ + assert(handle->data != NULL); + + status_t transferStatus = kStatus_USDHC_BusyTransferring; + uint32_t transferredWords = handle->transferredWords; + + if ((!(handle->data->enableIgnoreError)) && + (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag))) + { + transferStatus = kStatus_USDHC_TransferDataFailed; + } + else + { + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag)) + { + /* std tuning process only need to wait BRR */ + if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning) + { + transferStatus = kStatus_USDHC_TransferDataComplete; } - else { - handle->transferredWords = USDHC_ReadDataPort(base, handle->data, handle->transferredWords); + else + { + handle->transferredWords = USDHC_ReadDataPort(base, handle->data, transferredWords); } } - else if (interruptFlags & kUSDHC_BufferWriteReadyFlag) { - handle->transferredWords = USDHC_WriteDataPort(base, handle->data, handle->transferredWords); + else if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferWriteReadyFlag)) + { + handle->transferredWords = USDHC_WriteDataPort(base, handle->data, transferredWords); } - else { - if ((interruptFlags & kUSDHC_DmaCompleteFlag) && - (handle->data->dataType == kUSDHC_TransferDataBootcontinous)) { + else + { + if ((IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag)) && + (handle->data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous)) + { *(handle->data->rxData) = s_usdhcBootDummy; } - if ((handle->callback.TransferComplete) && (interruptFlags & kUSDHC_DataCompleteFlag)) { - handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData); + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag)) + { + transferStatus = kStatus_USDHC_TransferDataComplete; + +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->data->rxData != NULL) + { + DCACHE_InvalidateByRange((uint32_t)(handle->data->rxData), + (handle->data->blockSize) * (handle->data->blockCount)); + } +#endif } } } + + if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring)) + { + handle->callback.TransferComplete(base, handle, transferStatus, handle->userData); + USDHC_DisableInterruptSignal(base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag); + handle->data = NULL; + } } +#endif static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle) { - if (handle->callback.SdioInterrupt) { + if (handle->callback.SdioInterrupt != NULL) + { handle->callback.SdioInterrupt(base, handle->userData); } } +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags) { - assert(handle->callback.ReTuning); + assert(handle->callback.ReTuning != NULL); /* retuning request */ - if ((interruptFlags & kUSDHC_TuningErrorFlag) == kUSDHC_TuningErrorFlag) { + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_TuningErrorFlag)) + { handle->callback.ReTuning(base, handle->userData); /* retuning fail */ } } +#endif static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle) { - if (handle->callback.BlockGap) { + if (handle->callback.BlockGap != NULL) + { handle->callback.BlockGap(base, handle->userData); } } +/*! + * brief Creates the USDHC handle. + * + * param base USDHC peripheral base address. + * param handle USDHC handle pointer. + * param callback Structure pointer to contain all callback functions. + * param userData Callback function parameter. + */ void USDHC_TransferCreateHandle(USDHC_Type *base, usdhc_handle_t *handle, const usdhc_transfer_callback_t *callback, void *userData) { - assert(handle); - assert(callback); + assert(handle != NULL); + assert(callback != NULL); /* Zero the handle. */ - memset(handle, 0, sizeof(*handle)); + (void)memset(handle, 0, sizeof(*handle)); /* Set the callback. */ handle->callback.CardInserted = callback->CardInserted; @@ -1539,79 +2400,81 @@ void USDHC_TransferCreateHandle(USDHC_Type *base, /* Save the handle in global variables to support the double weak mechanism. */ s_usdhcHandle[USDHC_GetInstance(base)] = handle; - /* Enable interrupt in NVIC. */ - USDHC_SetTransferInterrupt(base, true); - /* disable the tuning pass interrupt */ - USDHC_DisableInterruptSignal(base, kUSDHC_TuningPassFlag | kUSDHC_ReTuningEventFlag); /* save IRQ handler */ s_usdhcIsr = USDHC_TransferHandleIRQ; - EnableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]); + (void)EnableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]); } +/*! + * brief IRQ handler for the USDHC. + * + * This function deals with the IRQs on the given host controller. + * + * param base USDHC peripheral base address. + * param handle USDHC handle. + */ void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle) { - assert(handle); + assert(handle != NULL); uint32_t interruptFlags; - interruptFlags = USDHC_GetInterruptStatusFlags(base); - handle->interruptFlags = interruptFlags; + interruptFlags = USDHC_GetEnabledInterruptStatusFlags(base); - if (interruptFlags & kUSDHC_CardDetectFlag) { - USDHC_TransferHandleCardDetect(base, handle, (interruptFlags & kUSDHC_CardDetectFlag)); + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardDetectFlag)) + { + USDHC_TransferHandleCardDetect(base, handle, interruptFlags); } - if (interruptFlags & kUSDHC_CommandFlag) { - USDHC_TransferHandleCommand(base, handle, (interruptFlags & kUSDHC_CommandFlag)); + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandFlag)) + { + USDHC_TransferHandleCommand(base, handle, interruptFlags); } - if (interruptFlags & kUSDHC_DataFlag) { - USDHC_TransferHandleData(base, handle, (interruptFlags & kUSDHC_DataFlag)); + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataFlag)) + { + USDHC_TransferHandleData(base, handle, interruptFlags); } - if (interruptFlags & kUSDHC_CardInterruptFlag) { + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInterruptFlag)) + { USDHC_TransferHandleSdioInterrupt(base, handle); } - if (interruptFlags & kUSDHC_BlockGapEventFlag) { + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BlockGapEventFlag)) + { USDHC_TransferHandleBlockGap(base, handle); } - if (interruptFlags & kUSDHC_SDR104TuningFlag) { - USDHC_TransferHandleReTuning(base, handle, (interruptFlags & kUSDHC_SDR104TuningFlag)); +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) + if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_SDR104TuningFlag)) + { + USDHC_TransferHandleReTuning(base, handle, interruptFlags); } +#endif USDHC_ClearInterruptStatusFlags(base, interruptFlags); } #ifdef USDHC0 +void USDHC0_DriverIRQHandler(void); void USDHC0_DriverIRQHandler(void) { s_usdhcIsr(s_usdhcBase[0U], s_usdhcHandle[0U]); -/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping - exception return operation might vector to incorrect interrupt */ -#if defined __CORTEX_M && (__CORTEX_M == 4U) - __DSB(); -#endif + SDK_ISR_EXIT_BARRIER; } #endif #ifdef USDHC1 +void USDHC1_DriverIRQHandler(void); void USDHC1_DriverIRQHandler(void) { s_usdhcIsr(s_usdhcBase[1U], s_usdhcHandle[1U]); -/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping - exception return operation might vector to incorrect interrupt */ -#if defined __CORTEX_M && (__CORTEX_M == 4U) - __DSB(); -#endif + SDK_ISR_EXIT_BARRIER; } #endif #ifdef USDHC2 +void USDHC2_DriverIRQHandler(void); void USDHC2_DriverIRQHandler(void) { s_usdhcIsr(s_usdhcBase[2U], s_usdhcHandle[2U]); -/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping - exception return operation might vector to incorrect interrupt */ -#if defined __CORTEX_M && (__CORTEX_M == 4U) - __DSB(); -#endif + SDK_ISR_EXIT_BARRIER; } #endif diff --git a/module-bsp/board/rt1051/common/fsl_drivers/fsl_usdhc.h b/module-bsp/board/rt1051/common/fsl_drivers/fsl_usdhc.h index 3069a317d515047cafcbf2a115e62d33c69acc87..9cf1fc07c312e3fa5dffeb46503a1eb4fd225d91 100644 --- a/module-bsp/board/rt1051/common/fsl_drivers/fsl_usdhc.h +++ b/module-bsp/board/rt1051/common/fsl_drivers/fsl_usdhc.h @@ -1,35 +1,9 @@ /* - * The Clear BSD License * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2021 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted (subject to the limitations in the disclaimer below) provided - * that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * o Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _FSL_USDHC_H_ #define _FSL_USDHC_H_ @@ -47,274 +21,314 @@ /*! @name Driver version */ /*@{*/ -/*! @brief Driver version 2.2.3. */ -#define FSL_USDHC_DRIVER_VERSION (MAKE_VERSION(2U, 2U, 3U)) +/*! @brief Driver version 2.8.2. */ +#define FSL_USDHC_DRIVER_VERSION (MAKE_VERSION(2U, 8U, 2U)) /*@}*/ /*! @brief Maximum block count can be set one time */ #define USDHC_MAX_BLOCK_COUNT (USDHC_BLK_ATT_BLKCNT_MASK >> USDHC_BLK_ATT_BLKCNT_SHIFT) -/*! @brief USDHC status */ -enum _usdhc_status -{ - kStatus_USDHC_BusyTransferring = MAKE_STATUS(kStatusGroup_USDHC, 0U), /*!< Transfer is on-going */ - kStatus_USDHC_PrepareAdmaDescriptorFailed = MAKE_STATUS(kStatusGroup_USDHC, 1U), /*!< Set DMA descriptor failed */ - kStatus_USDHC_SendCommandFailed = MAKE_STATUS(kStatusGroup_USDHC, 2U), /*!< Send command failed */ - kStatus_USDHC_TransferDataFailed = MAKE_STATUS(kStatusGroup_USDHC, 3U), /*!< Transfer data failed */ - kStatus_USDHC_DMADataAddrNotAlign = MAKE_STATUS(kStatusGroup_USDHC, 4U), /*!< data address not align */ - kStatus_USDHC_ReTuningRequest = MAKE_STATUS(kStatusGroup_USDHC, 5U), /*!< re-tuning request */ - kStatus_USDHC_TuningError = MAKE_STATUS(kStatusGroup_USDHC, 6U), /*!< tuning error */ - kStatus_USDHC_NotSupport = MAKE_STATUS(kStatusGroup_USDHC, 7U), /*!< not support */ +/*! @brief USDHC scatter gather feature control macro */ +#ifndef FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER +#define FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER 0U +#endif + +/*! @brief Enum _usdhc_status. USDHC status. */ +enum +{ + kStatus_USDHC_BusyTransferring = MAKE_STATUS(kStatusGroup_USDHC, 0U), /*!< Transfer is on-going. */ + kStatus_USDHC_PrepareAdmaDescriptorFailed = MAKE_STATUS(kStatusGroup_USDHC, 1U), /*!< Set DMA descriptor failed. */ + kStatus_USDHC_SendCommandFailed = MAKE_STATUS(kStatusGroup_USDHC, 2U), /*!< Send command failed. */ + kStatus_USDHC_TransferDataFailed = MAKE_STATUS(kStatusGroup_USDHC, 3U), /*!< Transfer data failed. */ + kStatus_USDHC_DMADataAddrNotAlign = MAKE_STATUS(kStatusGroup_USDHC, 4U), /*!< Data address not aligned. */ + kStatus_USDHC_ReTuningRequest = MAKE_STATUS(kStatusGroup_USDHC, 5U), /*!< Re-tuning request. */ + kStatus_USDHC_TuningError = MAKE_STATUS(kStatusGroup_USDHC, 6U), /*!< Tuning error. */ + kStatus_USDHC_NotSupport = MAKE_STATUS(kStatusGroup_USDHC, 7U), /*!< Not support. */ + kStatus_USDHC_TransferDataComplete = MAKE_STATUS(kStatusGroup_USDHC, 8U), /*!< Transfer data complete. */ + kStatus_USDHC_SendCommandSuccess = MAKE_STATUS(kStatusGroup_USDHC, 9U), /*!< Transfer command complete. */ + kStatus_USDHC_TransferDMAComplete = MAKE_STATUS(kStatusGroup_USDHC, 10U), /*!< Transfer DMA complete. */ }; -/*! @brief Host controller capabilities flag mask */ -enum _usdhc_capability_flag -{ - kUSDHC_SupportAdmaFlag = USDHC_HOST_CTRL_CAP_ADMAS_MASK, /*!< Support ADMA */ - kUSDHC_SupportHighSpeedFlag = USDHC_HOST_CTRL_CAP_HSS_MASK, /*!< Support high-speed */ - kUSDHC_SupportDmaFlag = USDHC_HOST_CTRL_CAP_DMAS_MASK, /*!< Support DMA */ - kUSDHC_SupportSuspendResumeFlag = USDHC_HOST_CTRL_CAP_SRS_MASK, /*!< Support suspend/resume */ - kUSDHC_SupportV330Flag = USDHC_HOST_CTRL_CAP_VS33_MASK, /*!< Support voltage 3.3V */ - kUSDHC_SupportV300Flag = USDHC_HOST_CTRL_CAP_VS30_MASK, /*!< Support voltage 3.0V */ - kUSDHC_SupportV180Flag = USDHC_HOST_CTRL_CAP_VS18_MASK, /*!< Support voltage 1.8V */ - /* Put additional two flags in HTCAPBLT_MBL's position. */ - kUSDHC_Support4BitFlag = (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0U), /*!< Support 4 bit mode */ - kUSDHC_Support8BitFlag = (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1U), /*!< Support 8 bit mode */ - /* sd version 3.0 new feature */ - kUSDHC_SupportDDR50Flag = USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK, /*!< support DDR50 mode */ +/*! @brief Enum _usdhc_capability_flag. Host controller capabilities flag mask. + * @anchor _usdhc_capability_flag + */ +enum +{ + kUSDHC_SupportAdmaFlag = USDHC_HOST_CTRL_CAP_ADMAS_MASK, /*!< Support ADMA. */ + kUSDHC_SupportHighSpeedFlag = USDHC_HOST_CTRL_CAP_HSS_MASK, /*!< Support high-speed. */ + kUSDHC_SupportDmaFlag = USDHC_HOST_CTRL_CAP_DMAS_MASK, /*!< Support DMA. */ + kUSDHC_SupportSuspendResumeFlag = USDHC_HOST_CTRL_CAP_SRS_MASK, /*!< Support suspend/resume. */ + kUSDHC_SupportV330Flag = USDHC_HOST_CTRL_CAP_VS33_MASK, /*!< Support voltage 3.3V. */ + kUSDHC_SupportV300Flag = USDHC_HOST_CTRL_CAP_VS30_MASK, /*!< Support voltage 3.0V. */ + kUSDHC_SupportV180Flag = USDHC_HOST_CTRL_CAP_VS18_MASK, /*!< Support voltage 1.8V. */ + kUSDHC_Support4BitFlag = (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0U), + /*!< Flag in HTCAPBLT_MBL's position, supporting 4-bit mode. */ + kUSDHC_Support8BitFlag = (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1U), + /*!< Flag in HTCAPBLT_MBL's position, supporting 8-bit mode. */ + kUSDHC_SupportDDR50Flag = USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK, +/*!< SD version 3.0 new feature, supporting DDR50 mode. */ #if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR104_MODE) kUSDHC_SupportSDR104Flag = 0, /*!< not support SDR104 mode */ #else - kUSDHC_SupportSDR104Flag = USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK, /*!< support SDR104 mode */ + kUSDHC_SupportSDR104Flag = USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK, /*!< Support SDR104 mode. */ #endif #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) kUSDHC_SupportSDR50Flag = 0U, /*!< not support SDR50 mode */ #else - kUSDHC_SupportSDR50Flag = USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK, /*!< support SDR50 mode */ + kUSDHC_SupportSDR50Flag = USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK, /*!< Support SDR50 mode. */ #endif }; -/*! @brief Wakeup event mask */ -enum _usdhc_wakeup_event +/*! @brief Enum _usdhc_wakeup_event. Wakeup event mask. + * @anchor _usdhc_wakeup_event + */ +enum { - kUSDHC_WakeupEventOnCardInt = USDHC_PROT_CTRL_WECINT_MASK, /*!< Wakeup on card interrupt */ - kUSDHC_WakeupEventOnCardInsert = USDHC_PROT_CTRL_WECINS_MASK, /*!< Wakeup on card insertion */ - kUSDHC_WakeupEventOnCardRemove = USDHC_PROT_CTRL_WECRM_MASK, /*!< Wakeup on card removal */ - - kUSDHC_WakeupEventsAll = (kUSDHC_WakeupEventOnCardInt | kUSDHC_WakeupEventOnCardInsert | - kUSDHC_WakeupEventOnCardRemove), /*!< All wakeup events */ + kUSDHC_WakeupEventOnCardInt = USDHC_PROT_CTRL_WECINT_MASK, /*!< Wakeup on card interrupt. */ + kUSDHC_WakeupEventOnCardInsert = USDHC_PROT_CTRL_WECINS_MASK, /*!< Wakeup on card insertion. */ + kUSDHC_WakeupEventOnCardRemove = USDHC_PROT_CTRL_WECRM_MASK, /*!< Wakeup on card removal. */ + kUSDHC_WakeupEventsAll = + (kUSDHC_WakeupEventOnCardInt | kUSDHC_WakeupEventOnCardInsert | kUSDHC_WakeupEventOnCardRemove), + /*!< All wakeup events */ }; -/*! @brief Reset type mask */ -enum _usdhc_reset +/*! @brief Enum _usdhc_reset. Reset type mask. + * @anchor _usdhc_reset + */ +enum { - kUSDHC_ResetAll = USDHC_SYS_CTRL_RSTA_MASK, /*!< Reset all except card detection */ - kUSDHC_ResetCommand = USDHC_SYS_CTRL_RSTC_MASK, /*!< Reset command line */ - kUSDHC_ResetData = USDHC_SYS_CTRL_RSTD_MASK, /*!< Reset data line */ + kUSDHC_ResetAll = USDHC_SYS_CTRL_RSTA_MASK, /*!< Reset all except card detection. */ + kUSDHC_ResetCommand = USDHC_SYS_CTRL_RSTC_MASK, /*!< Reset command line. */ + kUSDHC_ResetData = USDHC_SYS_CTRL_RSTD_MASK, /*!< Reset data line. */ #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) kUSDHC_ResetTuning = 0U, /*!< no reset tuning circuit bit */ #else - kUSDHC_ResetTuning = USDHC_SYS_CTRL_RSTT_MASK, /*!< reset tuning circuit */ + kUSDHC_ResetTuning = USDHC_SYS_CTRL_RSTT_MASK, /*!< Reset tuning circuit. */ #endif - kUSDHC_ResetsAll = - (kUSDHC_ResetAll | kUSDHC_ResetCommand | kUSDHC_ResetData | kUSDHC_ResetTuning), /*!< All reset types */ + kUSDHC_ResetsAll = (kUSDHC_ResetAll | kUSDHC_ResetCommand | kUSDHC_ResetData | kUSDHC_ResetTuning), + /*!< All reset types */ }; -/*! @brief Transfer flag mask */ -enum _usdhc_transfer_flag +/*! @brief Enum _usdhc_transfer_flag. Transfer flag mask. */ +enum { - kUSDHC_EnableDmaFlag = USDHC_MIX_CTRL_DMAEN_MASK, /*!< Enable DMA */ + kUSDHC_EnableDmaFlag = USDHC_MIX_CTRL_DMAEN_MASK, /*!< Enable DMA. */ - kUSDHC_CommandTypeSuspendFlag = (USDHC_CMD_XFR_TYP_CMDTYP(1U)), /*!< Suspend command */ - kUSDHC_CommandTypeResumeFlag = (USDHC_CMD_XFR_TYP_CMDTYP(2U)), /*!< Resume command */ - kUSDHC_CommandTypeAbortFlag = (USDHC_CMD_XFR_TYP_CMDTYP(3U)), /*!< Abort command */ + kUSDHC_CommandTypeSuspendFlag = USDHC_CMD_XFR_TYP_CMDTYP(1U), /*!< Suspend command. */ + kUSDHC_CommandTypeResumeFlag = USDHC_CMD_XFR_TYP_CMDTYP(2U), /*!< Resume command. */ + kUSDHC_CommandTypeAbortFlag = USDHC_CMD_XFR_TYP_CMDTYP(3U), /*!< Abort command. */ - kUSDHC_EnableBlockCountFlag = USDHC_MIX_CTRL_BCEN_MASK, /*!< Enable block count */ - kUSDHC_EnableAutoCommand12Flag = USDHC_MIX_CTRL_AC12EN_MASK, /*!< Enable auto CMD12 */ - kUSDHC_DataReadFlag = USDHC_MIX_CTRL_DTDSEL_MASK, /*!< Enable data read */ - kUSDHC_MultipleBlockFlag = USDHC_MIX_CTRL_MSBSEL_MASK, /*!< Multiple block data read/write */ - kUSDHC_EnableAutoCommand23Flag = USDHC_MIX_CTRL_AC23EN_MASK, /*!< Enable auto CMD23 */ + kUSDHC_EnableBlockCountFlag = USDHC_MIX_CTRL_BCEN_MASK, /*!< Enable block count. */ + kUSDHC_EnableAutoCommand12Flag = USDHC_MIX_CTRL_AC12EN_MASK, /*!< Enable auto CMD12. */ + kUSDHC_DataReadFlag = USDHC_MIX_CTRL_DTDSEL_MASK, /*!< Enable data read. */ + kUSDHC_MultipleBlockFlag = USDHC_MIX_CTRL_MSBSEL_MASK, /*!< Multiple block data read/write. */ + kUSDHC_EnableAutoCommand23Flag = USDHC_MIX_CTRL_AC23EN_MASK, /*!< Enable auto CMD23. */ - kUSDHC_ResponseLength136Flag = USDHC_CMD_XFR_TYP_RSPTYP(1U), /*!< 136 bit response length */ - kUSDHC_ResponseLength48Flag = USDHC_CMD_XFR_TYP_RSPTYP(2U), /*!< 48 bit response length */ - kUSDHC_ResponseLength48BusyFlag = USDHC_CMD_XFR_TYP_RSPTYP(3U), /*!< 48 bit response length with busy status */ + kUSDHC_ResponseLength136Flag = USDHC_CMD_XFR_TYP_RSPTYP(1U), /*!< 136-bit response length. */ + kUSDHC_ResponseLength48Flag = USDHC_CMD_XFR_TYP_RSPTYP(2U), /*!< 48-bit response length. */ + kUSDHC_ResponseLength48BusyFlag = USDHC_CMD_XFR_TYP_RSPTYP(3U), /*!< 48-bit response length with busy status. */ - kUSDHC_EnableCrcCheckFlag = USDHC_CMD_XFR_TYP_CCCEN_MASK, /*!< Enable CRC check */ - kUSDHC_EnableIndexCheckFlag = USDHC_CMD_XFR_TYP_CICEN_MASK, /*!< Enable index check */ - kUSDHC_DataPresentFlag = USDHC_CMD_XFR_TYP_DPSEL_MASK, /*!< Data present flag */ + kUSDHC_EnableCrcCheckFlag = USDHC_CMD_XFR_TYP_CCCEN_MASK, /*!< Enable CRC check. */ + kUSDHC_EnableIndexCheckFlag = USDHC_CMD_XFR_TYP_CICEN_MASK, /*!< Enable index check. */ + kUSDHC_DataPresentFlag = USDHC_CMD_XFR_TYP_DPSEL_MASK, /*!< Data present flag. */ }; -/*! @brief Present status flag mask */ -enum _usdhc_present_status_flag +/*! @brief Enum _usdhc_present_status_flag. Present status flag mask. + * @anchor _usdhc_present_status_flag + */ +enum { - kUSDHC_CommandInhibitFlag = USDHC_PRES_STATE_CIHB_MASK, /*!< Command inhibit */ - kUSDHC_DataInhibitFlag = USDHC_PRES_STATE_CDIHB_MASK, /*!< Data inhibit */ - kUSDHC_DataLineActiveFlag = USDHC_PRES_STATE_DLA_MASK, /*!< Data line active */ - kUSDHC_SdClockStableFlag = USDHC_PRES_STATE_SDSTB_MASK, /*!< SD bus clock stable */ - kUSDHC_WriteTransferActiveFlag = USDHC_PRES_STATE_WTA_MASK, /*!< Write transfer active */ - kUSDHC_ReadTransferActiveFlag = USDHC_PRES_STATE_RTA_MASK, /*!< Read transfer active */ - kUSDHC_BufferWriteEnableFlag = USDHC_PRES_STATE_BWEN_MASK, /*!< Buffer write enable */ - kUSDHC_BufferReadEnableFlag = USDHC_PRES_STATE_BREN_MASK, /*!< Buffer read enable */ + kUSDHC_CommandInhibitFlag = USDHC_PRES_STATE_CIHB_MASK, /*!< Command inhibit. */ + kUSDHC_DataInhibitFlag = USDHC_PRES_STATE_CDIHB_MASK, /*!< Data inhibit. */ + kUSDHC_DataLineActiveFlag = USDHC_PRES_STATE_DLA_MASK, /*!< Data line active. */ + kUSDHC_SdClockStableFlag = USDHC_PRES_STATE_SDSTB_MASK, /*!< SD bus clock stable. */ + kUSDHC_WriteTransferActiveFlag = USDHC_PRES_STATE_WTA_MASK, /*!< Write transfer active. */ + kUSDHC_ReadTransferActiveFlag = USDHC_PRES_STATE_RTA_MASK, /*!< Read transfer active. */ + kUSDHC_BufferWriteEnableFlag = USDHC_PRES_STATE_BWEN_MASK, /*!< Buffer write enable. */ + kUSDHC_BufferReadEnableFlag = USDHC_PRES_STATE_BREN_MASK, /*!< Buffer read enable. */ #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) kUSDHC_DelaySettingFinishedFlag = 0U, /*!< not support */ kUSDHC_ReTuningRequestFlag = 0U, /*!< not support */ #else - kUSDHC_ReTuningRequestFlag = USDHC_PRES_STATE_RTR_MASK, /*!< re-tuning request flag ,only used for SDR104 mode */ - kUSDHC_DelaySettingFinishedFlag = USDHC_PRES_STATE_TSCD_MASK, /*!< delay setting finished flag */ + kUSDHC_ReTuningRequestFlag = USDHC_PRES_STATE_RTR_MASK, /*!< Re-tuning request flag, only used for SDR104 mode. */ + kUSDHC_DelaySettingFinishedFlag = USDHC_PRES_STATE_TSCD_MASK, /*!< Delay setting finished flag. */ #endif - kUSDHC_CardInsertedFlag = USDHC_PRES_STATE_CINST_MASK, /*!< Card inserted */ - kUSDHC_CommandLineLevelFlag = USDHC_PRES_STATE_CLSL_MASK, /*!< Command line signal level */ - - kUSDHC_Data0LineLevelFlag = (1U << USDHC_PRES_STATE_DLSL_SHIFT), /*!< Data0 line signal level */ - kUSDHC_Data1LineLevelFlag = (1U << (USDHC_PRES_STATE_DLSL_SHIFT + 1U)), /*!< Data1 line signal level */ - kUSDHC_Data2LineLevelFlag = (1U << (USDHC_PRES_STATE_DLSL_SHIFT + 2U)), /*!< Data2 line signal level */ - kUSDHC_Data3LineLevelFlag = (1U << (USDHC_PRES_STATE_DLSL_SHIFT + 3U)), /*!< Data3 line signal level */ - kUSDHC_Data4LineLevelFlag = (1U << (USDHC_PRES_STATE_DLSL_SHIFT + 4U)), /*!< Data4 line signal level */ - kUSDHC_Data5LineLevelFlag = (1U << (USDHC_PRES_STATE_DLSL_SHIFT + 5U)), /*!< Data5 line signal level */ - kUSDHC_Data6LineLevelFlag = (1U << (USDHC_PRES_STATE_DLSL_SHIFT + 6U)), /*!< Data6 line signal level */ - kUSDHC_Data7LineLevelFlag = (1U << (USDHC_PRES_STATE_DLSL_SHIFT + 7U)), /*!< Data7 line signal level */ + kUSDHC_CardInsertedFlag = USDHC_PRES_STATE_CINST_MASK, /*!< Card inserted. */ + kUSDHC_CommandLineLevelFlag = USDHC_PRES_STATE_CLSL_MASK, /*!< Command line signal level. */ + + kUSDHC_Data0LineLevelFlag = 1U << USDHC_PRES_STATE_DLSL_SHIFT, /*!< Data0 line signal level. */ + kUSDHC_Data1LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 1U), /*!< Data1 line signal level. */ + kUSDHC_Data2LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 2U), /*!< Data2 line signal level. */ + kUSDHC_Data3LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 3U), /*!< Data3 line signal level. */ + kUSDHC_Data4LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 4U), /*!< Data4 line signal level. */ + kUSDHC_Data5LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 5U), /*!< Data5 line signal level. */ + kUSDHC_Data6LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 6U), /*!< Data6 line signal level. */ + kUSDHC_Data7LineLevelFlag = (int)(1U << (USDHC_PRES_STATE_DLSL_SHIFT + 7U)), /*!< Data7 line signal level. */ }; -/*! @brief Interrupt status flag mask */ -enum _usdhc_interrupt_status_flag +/*! @brief Enum _usdhc_interrupt_status_flag. Interrupt status flag mask. + * @anchor _usdhc_interrupt_status_flag + */ +enum { - kUSDHC_CommandCompleteFlag = USDHC_INT_STATUS_CC_MASK, /*!< Command complete */ - kUSDHC_DataCompleteFlag = USDHC_INT_STATUS_TC_MASK, /*!< Data complete */ - kUSDHC_BlockGapEventFlag = USDHC_INT_STATUS_BGE_MASK, /*!< Block gap event */ - kUSDHC_DmaCompleteFlag = USDHC_INT_STATUS_DINT_MASK, /*!< DMA interrupt */ - kUSDHC_BufferWriteReadyFlag = USDHC_INT_STATUS_BWR_MASK, /*!< Buffer write ready */ - kUSDHC_BufferReadReadyFlag = USDHC_INT_STATUS_BRR_MASK, /*!< Buffer read ready */ - kUSDHC_CardInsertionFlag = USDHC_INT_STATUS_CINS_MASK, /*!< Card inserted */ - kUSDHC_CardRemovalFlag = USDHC_INT_STATUS_CRM_MASK, /*!< Card removed */ - kUSDHC_CardInterruptFlag = USDHC_INT_STATUS_CINT_MASK, /*!< Card interrupt */ + kUSDHC_CommandCompleteFlag = USDHC_INT_STATUS_CC_MASK, /*!< Command complete. */ + kUSDHC_DataCompleteFlag = USDHC_INT_STATUS_TC_MASK, /*!< Data complete. */ + kUSDHC_BlockGapEventFlag = USDHC_INT_STATUS_BGE_MASK, /*!< Block gap event. */ + kUSDHC_DmaCompleteFlag = USDHC_INT_STATUS_DINT_MASK, /*!< DMA interrupt. */ + kUSDHC_BufferWriteReadyFlag = USDHC_INT_STATUS_BWR_MASK, /*!< Buffer write ready. */ + kUSDHC_BufferReadReadyFlag = USDHC_INT_STATUS_BRR_MASK, /*!< Buffer read ready. */ + kUSDHC_CardInsertionFlag = USDHC_INT_STATUS_CINS_MASK, /*!< Card inserted. */ + kUSDHC_CardRemovalFlag = USDHC_INT_STATUS_CRM_MASK, /*!< Card removed. */ + kUSDHC_CardInterruptFlag = USDHC_INT_STATUS_CINT_MASK, /*!< Card interrupt. */ #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) - kUSDHC_ReTuningEventFlag = 0U, /*!< Re-Tuning event,only for SD3.0 SDR104 mode */ - kUSDHC_TuningPassFlag = 0U, /*!< SDR104 mode tuning pass flag */ - kUSDHC_TuningErrorFlag = 0U, /*!< SDR104 tuning error flag */ + kUSDHC_ReTuningEventFlag = 0U, /*!< Re-Tuning event, only for SD3.0 SDR104 mode. */ + kUSDHC_TuningPassFlag = 0U, /*!< SDR104 mode tuning pass flag. */ + kUSDHC_TuningErrorFlag = 0U, /*!< SDR104 tuning error flag. */ #else - kUSDHC_ReTuningEventFlag = USDHC_INT_STATUS_RTE_MASK, /*!< Re-Tuning event,only for SD3.0 SDR104 mode */ - kUSDHC_TuningPassFlag = USDHC_INT_STATUS_TP_MASK, /*!< SDR104 mode tuning pass flag */ - kUSDHC_TuningErrorFlag = USDHC_INT_STATUS_TNE_MASK, /*!< SDR104 tuning error flag */ + kUSDHC_ReTuningEventFlag = USDHC_INT_STATUS_RTE_MASK, /*!< Re-Tuning event, only for SD3.0 SDR104 mode. */ + kUSDHC_TuningPassFlag = USDHC_INT_STATUS_TP_MASK, /*!< SDR104 mode tuning pass flag. */ + kUSDHC_TuningErrorFlag = USDHC_INT_STATUS_TNE_MASK, /*!< SDR104 tuning error flag. */ #endif - kUSDHC_CommandTimeoutFlag = USDHC_INT_STATUS_CTOE_MASK, /*!< Command timeout error */ - kUSDHC_CommandCrcErrorFlag = USDHC_INT_STATUS_CCE_MASK, /*!< Command CRC error */ - kUSDHC_CommandEndBitErrorFlag = USDHC_INT_STATUS_CEBE_MASK, /*!< Command end bit error */ - kUSDHC_CommandIndexErrorFlag = USDHC_INT_STATUS_CIE_MASK, /*!< Command index error */ - kUSDHC_DataTimeoutFlag = USDHC_INT_STATUS_DTOE_MASK, /*!< Data timeout error */ - kUSDHC_DataCrcErrorFlag = USDHC_INT_STATUS_DCE_MASK, /*!< Data CRC error */ - kUSDHC_DataEndBitErrorFlag = USDHC_INT_STATUS_DEBE_MASK, /*!< Data end bit error */ - kUSDHC_AutoCommand12ErrorFlag = USDHC_INT_STATUS_AC12E_MASK, /*!< Auto CMD12 error */ - kUSDHC_DmaErrorFlag = USDHC_INT_STATUS_DMAE_MASK, /*!< DMA error */ + kUSDHC_CommandTimeoutFlag = USDHC_INT_STATUS_CTOE_MASK, /*!< Command timeout error. */ + kUSDHC_CommandCrcErrorFlag = USDHC_INT_STATUS_CCE_MASK, /*!< Command CRC error. */ + kUSDHC_CommandEndBitErrorFlag = USDHC_INT_STATUS_CEBE_MASK, /*!< Command end bit error. */ + kUSDHC_CommandIndexErrorFlag = USDHC_INT_STATUS_CIE_MASK, /*!< Command index error. */ + kUSDHC_DataTimeoutFlag = USDHC_INT_STATUS_DTOE_MASK, /*!< Data timeout error. */ + kUSDHC_DataCrcErrorFlag = USDHC_INT_STATUS_DCE_MASK, /*!< Data CRC error. */ + kUSDHC_DataEndBitErrorFlag = USDHC_INT_STATUS_DEBE_MASK, /*!< Data end bit error. */ + kUSDHC_AutoCommand12ErrorFlag = USDHC_INT_STATUS_AC12E_MASK, /*!< Auto CMD12 error. */ + kUSDHC_DmaErrorFlag = USDHC_INT_STATUS_DMAE_MASK, /*!< DMA error. */ kUSDHC_CommandErrorFlag = (kUSDHC_CommandTimeoutFlag | kUSDHC_CommandCrcErrorFlag | kUSDHC_CommandEndBitErrorFlag | kUSDHC_CommandIndexErrorFlag), /*!< Command error */ kUSDHC_DataErrorFlag = (kUSDHC_DataTimeoutFlag | kUSDHC_DataCrcErrorFlag | kUSDHC_DataEndBitErrorFlag | kUSDHC_AutoCommand12ErrorFlag), /*!< Data error */ kUSDHC_ErrorFlag = (kUSDHC_CommandErrorFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag), /*!< All error */ - kUSDHC_DataFlag = (kUSDHC_DataCompleteFlag | kUSDHC_DmaCompleteFlag | kUSDHC_BufferWriteReadyFlag | - kUSDHC_BufferReadReadyFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag), /*!< Data interrupts */ + + kUSDHC_DataFlag = (kUSDHC_DataCompleteFlag | kUSDHC_BufferWriteReadyFlag | kUSDHC_BufferReadReadyFlag | + kUSDHC_DataErrorFlag), /*!< Data interrupts */ + + kUSDHC_DataDMAFlag = (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag), /*!< Data interrupts */ + kUSDHC_CommandFlag = (kUSDHC_CommandErrorFlag | kUSDHC_CommandCompleteFlag), /*!< Command interrupts */ kUSDHC_CardDetectFlag = (kUSDHC_CardInsertionFlag | kUSDHC_CardRemovalFlag), /*!< Card detection interrupts */ kUSDHC_SDR104TuningFlag = (kUSDHC_TuningErrorFlag | kUSDHC_TuningPassFlag | kUSDHC_ReTuningEventFlag), - - kUSDHC_AllInterruptFlags = (kUSDHC_BlockGapEventFlag | kUSDHC_CardInterruptFlag | kUSDHC_CommandFlag | - kUSDHC_DataFlag | kUSDHC_ErrorFlag | kUSDHC_SDR104TuningFlag), /*!< All flags mask */ + /*!< SDR104 tuning flag. */ + kUSDHC_AllInterruptFlags = + (kUSDHC_BlockGapEventFlag | kUSDHC_CardInterruptFlag | kUSDHC_CommandFlag | kUSDHC_DataFlag | kUSDHC_ErrorFlag | + kUSDHC_SDR104TuningFlag | kUSDHC_DmaCompleteFlag), /*!< All flags mask */ }; -/*! @brief Auto CMD12 error status flag mask */ -enum _usdhc_auto_command12_error_status_flag +/*! @brief Enum _usdhc_auto_command12_error_status_flag. Auto CMD12 error status flag mask. + * @anchor _usdhc_auto_command12_error_status_flag + */ +enum { - kUSDHC_AutoCommand12NotExecutedFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12NE_MASK, /*!< Not executed error */ - kUSDHC_AutoCommand12TimeoutFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12TOE_MASK, /*!< Timeout error */ - kUSDHC_AutoCommand12EndBitErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12EBE_MASK, /*!< End bit error */ - kUSDHC_AutoCommand12CrcErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12CE_MASK, /*!< CRC error */ - kUSDHC_AutoCommand12IndexErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12IE_MASK, /*!< Index error */ - kUSDHC_AutoCommand12NotIssuedFlag = USDHC_AUTOCMD12_ERR_STATUS_CNIBAC12E_MASK, /*!< Not issued error */ + kUSDHC_AutoCommand12NotExecutedFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12NE_MASK, /*!< Not executed error. */ + kUSDHC_AutoCommand12TimeoutFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12TOE_MASK, /*!< Timeout error. */ + kUSDHC_AutoCommand12EndBitErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12EBE_MASK, /*!< End bit error. */ + kUSDHC_AutoCommand12CrcErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12CE_MASK, /*!< CRC error. */ + kUSDHC_AutoCommand12IndexErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12IE_MASK, /*!< Index error. */ + kUSDHC_AutoCommand12NotIssuedFlag = USDHC_AUTOCMD12_ERR_STATUS_CNIBAC12E_MASK, /*!< Not issued error. */ }; -/*! @brief standard tuning flag */ -enum _usdhc_standard_tuning +/*! @brief Enum _usdhc_standard_tuning. Standard tuning flag. */ +enum { #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) kUSDHC_ExecuteTuning = 0U, /*!< not support */ kUSDHC_TuningSampleClockSel = 0U, /*!< not support */ #else - kUSDHC_ExecuteTuning = USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK, /*!< used to start tuning procedure */ - kUSDHC_TuningSampleClockSel = USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK, /*!< when std_tuning_en bit is set, this - bit is used select sampleing clock */ + kUSDHC_ExecuteTuning = USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK, /*!< Used to start tuning procedure. */ + kUSDHC_TuningSampleClockSel = + USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK, /*!< When std_tuning_en bit is set, this + bit is used to select sampleing clock. */ #endif }; -/*! @brief ADMA error status flag mask */ -enum _usdhc_adma_error_status_flag +/*! @brief Enum _usdhc_adma_error_status_flag. ADMA error status flag mask. + * @anchor _usdhc_adma_error_status_flag + */ +enum { - kUSDHC_AdmaLenghMismatchFlag = USDHC_ADMA_ERR_STATUS_ADMALME_MASK, /*!< Length mismatch error */ - kUSDHC_AdmaDescriptorErrorFlag = USDHC_ADMA_ERR_STATUS_ADMADCE_MASK, /*!< Descriptor error */ + kUSDHC_AdmaLenghMismatchFlag = USDHC_ADMA_ERR_STATUS_ADMALME_MASK, /*!< Length mismatch error. */ + kUSDHC_AdmaDescriptorErrorFlag = USDHC_ADMA_ERR_STATUS_ADMADCE_MASK, /*!< Descriptor error. */ }; /*! - * @brief ADMA error state + * @brief Enum _usdhc_adma_error_state. ADMA error state. * * This state is the detail state when ADMA error has occurred. */ -enum _usdhc_adma_error_state +enum { - kUSDHC_AdmaErrorStateStopDma = - 0x00U, /*!< Stop DMA, previous location set in the ADMA system address is error address */ - kUSDHC_AdmaErrorStateFetchDescriptor = - 0x01U, /*!< Fetch descriptor, current location set in the ADMA system address is error address */ - kUSDHC_AdmaErrorStateChangeAddress = 0x02U, /*!< Change address, no DMA error is occured */ - kUSDHC_AdmaErrorStateTransferData = - 0x03U, /*!< Transfer data, previous location set in the ADMA system address is error address */ - kUSDHC_AdmaErrorStateInvalidLength = 0x04U, /*!< Invalid length in ADMA descriptor */ - kUSDHC_AdmaErrorStateInvalidDescriptor = 0x08U, /*!< Invalid descriptor fetched by ADMA */ + kUSDHC_AdmaErrorStateStopDma = 0x00U, + /*!< Stop DMA, previous location set in the ADMA system address is errored address. */ + kUSDHC_AdmaErrorStateFetchDescriptor = 0x01U, + /*!< Fetch descriptor, current location set in the ADMA system address is errored address. */ + kUSDHC_AdmaErrorStateChangeAddress = 0x02U, /*!< Change address, no DMA error has occurred. */ + kUSDHC_AdmaErrorStateTransferData = 0x03U, + /*!< Transfer data, previous location set in the ADMA system address is errored address. */ + kUSDHC_AdmaErrorStateInvalidLength = 0x04U, /*!< Invalid length in ADMA descriptor. */ + kUSDHC_AdmaErrorStateInvalidDescriptor = 0x08U, /*!< Invalid descriptor fetched by ADMA. */ kUSDHC_AdmaErrorState = kUSDHC_AdmaErrorStateInvalidLength | kUSDHC_AdmaErrorStateInvalidDescriptor | kUSDHC_AdmaErrorStateFetchDescriptor, /*!< ADMA error state */ }; -/*! @brief Force event mask */ -enum _usdhc_force_event -{ - kUSDHC_ForceEventAutoCommand12NotExecuted = USDHC_FORCE_EVENT_FEVTAC12NE_MASK, /*!< Auto CMD12 not executed error */ - kUSDHC_ForceEventAutoCommand12Timeout = USDHC_FORCE_EVENT_FEVTAC12TOE_MASK, /*!< Auto CMD12 timeout error */ - kUSDHC_ForceEventAutoCommand12CrcError = USDHC_FORCE_EVENT_FEVTAC12CE_MASK, /*!< Auto CMD12 CRC error */ - kUSDHC_ForceEventEndBitError = USDHC_FORCE_EVENT_FEVTAC12EBE_MASK, /*!< Auto CMD12 end bit error */ - kUSDHC_ForceEventAutoCommand12IndexError = USDHC_FORCE_EVENT_FEVTAC12IE_MASK, /*!< Auto CMD12 index error */ - kUSDHC_ForceEventAutoCommand12NotIssued = USDHC_FORCE_EVENT_FEVTCNIBAC12E_MASK, /*!< Auto CMD12 not issued error */ - kUSDHC_ForceEventCommandTimeout = USDHC_FORCE_EVENT_FEVTCTOE_MASK, /*!< Command timeout error */ - kUSDHC_ForceEventCommandCrcError = USDHC_FORCE_EVENT_FEVTCCE_MASK, /*!< Command CRC error */ - kUSDHC_ForceEventCommandEndBitError = USDHC_FORCE_EVENT_FEVTCEBE_MASK, /*!< Command end bit error */ - kUSDHC_ForceEventCommandIndexError = USDHC_FORCE_EVENT_FEVTCIE_MASK, /*!< Command index error */ - kUSDHC_ForceEventDataTimeout = USDHC_FORCE_EVENT_FEVTDTOE_MASK, /*!< Data timeout error */ - kUSDHC_ForceEventDataCrcError = USDHC_FORCE_EVENT_FEVTDCE_MASK, /*!< Data CRC error */ - kUSDHC_ForceEventDataEndBitError = USDHC_FORCE_EVENT_FEVTDEBE_MASK, /*!< Data end bit error */ - kUSDHC_ForceEventAutoCommand12Error = USDHC_FORCE_EVENT_FEVTAC12E_MASK, /*!< Auto CMD12 error */ - kUSDHC_ForceEventCardInt = USDHC_FORCE_EVENT_FEVTCINT_MASK, /*!< Card interrupt */ - kUSDHC_ForceEventDmaError = USDHC_FORCE_EVENT_FEVTDMAE_MASK, /*!< Dma error */ +/*! @brief Enum _usdhc_force_event. Force event bit position. + * @anchor _usdhc_force_event + */ +enum +{ + kUSDHC_ForceEventAutoCommand12NotExecuted = + USDHC_FORCE_EVENT_FEVTAC12NE_MASK, /*!< Auto CMD12 not executed error. */ + kUSDHC_ForceEventAutoCommand12Timeout = USDHC_FORCE_EVENT_FEVTAC12TOE_MASK, /*!< Auto CMD12 timeout error. */ + kUSDHC_ForceEventAutoCommand12CrcError = USDHC_FORCE_EVENT_FEVTAC12CE_MASK, /*!< Auto CMD12 CRC error. */ + kUSDHC_ForceEventEndBitError = USDHC_FORCE_EVENT_FEVTAC12EBE_MASK, /*!< Auto CMD12 end bit error. */ + kUSDHC_ForceEventAutoCommand12IndexError = USDHC_FORCE_EVENT_FEVTAC12IE_MASK, /*!< Auto CMD12 index error. */ + kUSDHC_ForceEventAutoCommand12NotIssued = USDHC_FORCE_EVENT_FEVTCNIBAC12E_MASK, /*!< Auto CMD12 not issued error. */ + kUSDHC_ForceEventCommandTimeout = USDHC_FORCE_EVENT_FEVTCTOE_MASK, /*!< Command timeout error. */ + kUSDHC_ForceEventCommandCrcError = USDHC_FORCE_EVENT_FEVTCCE_MASK, /*!< Command CRC error. */ + kUSDHC_ForceEventCommandEndBitError = USDHC_FORCE_EVENT_FEVTCEBE_MASK, /*!< Command end bit error. */ + kUSDHC_ForceEventCommandIndexError = USDHC_FORCE_EVENT_FEVTCIE_MASK, /*!< Command index error. */ + kUSDHC_ForceEventDataTimeout = USDHC_FORCE_EVENT_FEVTDTOE_MASK, /*!< Data timeout error. */ + kUSDHC_ForceEventDataCrcError = USDHC_FORCE_EVENT_FEVTDCE_MASK, /*!< Data CRC error. */ + kUSDHC_ForceEventDataEndBitError = USDHC_FORCE_EVENT_FEVTDEBE_MASK, /*!< Data end bit error. */ + kUSDHC_ForceEventAutoCommand12Error = USDHC_FORCE_EVENT_FEVTAC12E_MASK, /*!< Auto CMD12 error. */ + kUSDHC_ForceEventCardInt = (int)USDHC_FORCE_EVENT_FEVTCINT_MASK, /*!< Card interrupt. */ + kUSDHC_ForceEventDmaError = USDHC_FORCE_EVENT_FEVTDMAE_MASK, /*!< Dma error. */ #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) kUSDHC_ForceEventTuningError = 0U, /*!< not support */ #else - kUSDHC_ForceEventTuningError = USDHC_FORCE_EVENT_FEVTTNE_MASK, /*!< Tuning error */ + kUSDHC_ForceEventTuningError = USDHC_FORCE_EVENT_FEVTTNE_MASK, /*!< Tuning error. */ #endif + kUSDHC_ForceEventsAll = - (kUSDHC_ForceEventAutoCommand12NotExecuted | kUSDHC_ForceEventAutoCommand12Timeout | - kUSDHC_ForceEventAutoCommand12CrcError | kUSDHC_ForceEventEndBitError | - kUSDHC_ForceEventAutoCommand12IndexError | kUSDHC_ForceEventAutoCommand12NotIssued | - kUSDHC_ForceEventCommandTimeout | kUSDHC_ForceEventCommandCrcError | kUSDHC_ForceEventCommandEndBitError | - kUSDHC_ForceEventCommandIndexError | kUSDHC_ForceEventDataTimeout | kUSDHC_ForceEventDataCrcError | - kUSDHC_ForceEventDataEndBitError | kUSDHC_ForceEventAutoCommand12Error | kUSDHC_ForceEventCardInt | - kUSDHC_ForceEventDmaError | kUSDHC_ForceEventTuningError), /*!< All force event flags mask */ + (int)(USDHC_FORCE_EVENT_FEVTAC12NE_MASK | USDHC_FORCE_EVENT_FEVTAC12TOE_MASK | + USDHC_FORCE_EVENT_FEVTAC12CE_MASK | USDHC_FORCE_EVENT_FEVTAC12EBE_MASK | + USDHC_FORCE_EVENT_FEVTAC12IE_MASK | USDHC_FORCE_EVENT_FEVTCNIBAC12E_MASK | + USDHC_FORCE_EVENT_FEVTCTOE_MASK | USDHC_FORCE_EVENT_FEVTCCE_MASK | USDHC_FORCE_EVENT_FEVTCEBE_MASK | + USDHC_FORCE_EVENT_FEVTCIE_MASK | USDHC_FORCE_EVENT_FEVTDTOE_MASK | USDHC_FORCE_EVENT_FEVTDCE_MASK | + USDHC_FORCE_EVENT_FEVTDEBE_MASK | USDHC_FORCE_EVENT_FEVTAC12E_MASK | USDHC_FORCE_EVENT_FEVTCINT_MASK | + USDHC_FORCE_EVENT_FEVTDMAE_MASK | kUSDHC_ForceEventTuningError), /*!< All force event flags mask. */ }; -/*! @brief Data transfer width */ +/*! @brief Data transfer direction. */ +typedef enum _usdhc_transfer_direction +{ + kUSDHC_TransferDirectionReceive = 1U, /*!< USDHC transfer direction receive. */ + kUSDHC_TransferDirectionSend = 0U, /*!< USDHC transfer direction send. */ +} usdhc_transfer_direction_t; + +/*! @brief Data transfer width. */ typedef enum _usdhc_data_bus_width { kUSDHC_DataBusWidth1Bit = 0U, /*!< 1-bit mode */ @@ -325,28 +339,30 @@ typedef enum _usdhc_data_bus_width /*! @brief Endian mode */ typedef enum _usdhc_endian_mode { - kUSDHC_EndianModeBig = 0U, /*!< Big endian mode */ - kUSDHC_EndianModeHalfWordBig = 1U, /*!< Half word big endian mode */ - kUSDHC_EndianModeLittle = 2U, /*!< Little endian mode */ + kUSDHC_EndianModeBig = 0U, /*!< Big endian mode. */ + kUSDHC_EndianModeHalfWordBig = 1U, /*!< Half word big endian mode. */ + kUSDHC_EndianModeLittle = 2U, /*!< Little endian mode. */ } usdhc_endian_mode_t; /*! @brief DMA mode */ typedef enum _usdhc_dma_mode { - kUSDHC_DmaModeSimple = 0U, /*!< external DMA */ - kUSDHC_DmaModeAdma1 = 1U, /*!< ADMA1 is selected */ - kUSDHC_DmaModeAdma2 = 2U, /*!< ADMA2 is selected */ - kUSDHC_ExternalDMA = 3U, /*!< external dma mode select */ + kUSDHC_DmaModeSimple = 0U, /*!< External DMA. */ + kUSDHC_DmaModeAdma1 = 1U, /*!< ADMA1 is selected. */ + kUSDHC_DmaModeAdma2 = 2U, /*!< ADMA2 is selected. */ + kUSDHC_ExternalDMA = 3U, /*!< External DMA mode selected. */ } usdhc_dma_mode_t; -/*! @brief SDIO control flag mask */ -enum _usdhc_sdio_control_flag +/*! @brief Enum _usdhc_sdio_control_flag. SDIO control flag mask. + * @anchor _usdhc_sdio_control_flag + */ +enum { - kUSDHC_StopAtBlockGapFlag = USDHC_PROT_CTRL_SABGREQ_MASK, /*!< Stop at block gap */ - kUSDHC_ReadWaitControlFlag = USDHC_PROT_CTRL_RWCTL_MASK, /*!< Read wait control */ - kUSDHC_InterruptAtBlockGapFlag = USDHC_PROT_CTRL_IABG_MASK, /*!< Interrupt at block gap */ - kUSDHC_ReadDoneNo8CLK = USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK, /*!< read done without 8 clk for block gap */ - kUSDHC_ExactBlockNumberReadFlag = USDHC_PROT_CTRL_NON_EXACT_BLK_RD_MASK, /*!< Exact block number read */ + kUSDHC_StopAtBlockGapFlag = USDHC_PROT_CTRL_SABGREQ_MASK, /*!< Stop at block gap. */ + kUSDHC_ReadWaitControlFlag = USDHC_PROT_CTRL_RWCTL_MASK, /*!< Read wait control. */ + kUSDHC_InterruptAtBlockGapFlag = USDHC_PROT_CTRL_IABG_MASK, /*!< Interrupt at block gap. */ + kUSDHC_ReadDoneNo8CLK = USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK, /*!< Read done without 8 clk for block gap. */ + kUSDHC_ExactBlockNumberReadFlag = USDHC_PROT_CTRL_NON_EXACT_BLK_RD_MASK, /*!< Exact block number read. */ }; /*! @brief MMC card boot mode */ @@ -369,7 +385,7 @@ typedef enum _usdhc_card_command_type /*! * @brief The command response type. * - * Define the command response type from card to host controller. + * Defines the command response type from card to host controller. */ typedef enum _usdhc_card_response_type { @@ -385,16 +401,16 @@ typedef enum _usdhc_card_response_type kCARD_ResponseTypeR7 = 9U, /*!< Response type: R7 */ } usdhc_card_response_type_t; -/*! @brief The alignment size for ADDRESS filed in ADMA1's descriptor */ +/*! @brief The alignment size for ADDRESS filed in ADMA1's descriptor. */ #define USDHC_ADMA1_ADDRESS_ALIGN (4096U) -/*! @brief The alignment size for LENGTH field in ADMA1's descriptor */ +/*! @brief The alignment size for LENGTH field in ADMA1's descriptor. */ #define USDHC_ADMA1_LENGTH_ALIGN (4096U) -/*! @brief The alignment size for ADDRESS field in ADMA2's descriptor */ +/*! @brief The alignment size for ADDRESS field in ADMA2's descriptor. */ #define USDHC_ADMA2_ADDRESS_ALIGN (4U) -/*! @brief The alignment size for LENGTH filed in ADMA2's descriptor */ +/*! @brief The alignment size for LENGTH filed in ADMA2's descriptor. */ #define USDHC_ADMA2_LENGTH_ALIGN (4U) -/* ADMA1 descriptor table +/* ADMA1 descriptor table: * |------------------------|---------|--------------------------| * | Address/page field |Reserved | Attribute | * |------------------------|---------|--------------------------| @@ -403,7 +419,7 @@ typedef enum _usdhc_card_response_type * | address or data length | 000000 |Act2|Act1| 0|Int|End|Valid| * |------------------------|---------|----|----|--|---|---|-----| * - * + * ADMA2 action table: * |------|------|-----------------|-------|-------------| * | Act2 | Act1 | Comment | 31-28 | 27 - 12 | * |------|------|-----------------|---------------------| @@ -416,35 +432,57 @@ typedef enum _usdhc_card_response_type * | 1 | 1 | Link descriptor | Descriptor address | * |------|------|-----------------|---------------------| */ -/*! @brief The bit shift for ADDRESS filed in ADMA1's descriptor */ +/****************************tables below are created only for Doxygen*********************************/ +/*! @brief The bit shift for ADDRESS filed in ADMA1's descriptor. + * + * + *
ADMA1 descriptor table
Address/page field Reserved Attribute + *
31 12 11 6 05 04 03 02 01 00 + *
address or data length 000000 Act2 Act1 0 Int End Valid + *
+ * + * + * + *
ADMA2 action
Act2 Act1 Comment 31-28 27-12 + *
0 0 No op Don't care + *
0 1 Set data length 0000 Data Length + *
1 0 Transfer data Data address + *
1 1 Link descriptor Descriptor address + *
+ */ #define USDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT (12U) -/*! @brief The bit mask for ADDRESS field in ADMA1's descriptor */ +/*! @brief The bit mask for ADDRESS field in ADMA1's descriptor. */ #define USDHC_ADMA1_DESCRIPTOR_ADDRESS_MASK (0xFFFFFU) -/*! @brief The bit shift for LENGTH filed in ADMA1's descriptor */ +/*! @brief The bit shift for LENGTH filed in ADMA1's descriptor. */ #define USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT (12U) -/*! @brief The mask for LENGTH field in ADMA1's descriptor */ +/*! @brief The mask for LENGTH field in ADMA1's descriptor. */ #define USDHC_ADMA1_DESCRIPTOR_LENGTH_MASK (0xFFFFU) -/*! @brief The maximum value of LENGTH filed in ADMA1's descriptor */ -#define USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY (USDHC_ADMA1_DESCRIPTOR_LENGTH_MASK - 3U) - -/*! @brief The mask for the control/status field in ADMA1 descriptor */ -enum _usdhc_adma1_descriptor_flag -{ - kUSDHC_Adma1DescriptorValidFlag = (1U << 0U), /*!< Valid flag */ - kUSDHC_Adma1DescriptorEndFlag = (1U << 1U), /*!< End flag */ - kUSDHC_Adma1DescriptorInterrupFlag = (1U << 2U), /*!< Interrupt flag */ - kUSDHC_Adma1DescriptorActivity1Flag = (1U << 4U), /*!< Activity 1 flag */ - kUSDHC_Adma1DescriptorActivity2Flag = (1U << 5U), /*!< Activity 2 flag */ - kUSDHC_Adma1DescriptorTypeNop = (kUSDHC_Adma1DescriptorValidFlag), /*!< No operation */ - kUSDHC_Adma1DescriptorTypeTransfer = - (kUSDHC_Adma1DescriptorActivity2Flag | kUSDHC_Adma1DescriptorValidFlag), /*!< Transfer data */ - kUSDHC_Adma1DescriptorTypeLink = (kUSDHC_Adma1DescriptorActivity1Flag | kUSDHC_Adma1DescriptorActivity2Flag | - kUSDHC_Adma1DescriptorValidFlag), /*!< Link descriptor */ - kUSDHC_Adma1DescriptorTypeSetLength = - (kUSDHC_Adma1DescriptorActivity1Flag | kUSDHC_Adma1DescriptorValidFlag), /*!< Set data length */ +/*! @brief The maximum value of LENGTH filed in ADMA1's descriptor. + * Since the max transfer size ADMA1 support is 65535 which is indivisible by + * 4096, so to make sure a large data load transfer (>64KB) continuously (require the data + * address be always align with 4096), software will set the maximum data length + * for ADMA1 to (64 - 4)KB. + */ +#define USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY (USDHC_ADMA1_DESCRIPTOR_LENGTH_MASK + 1U - 4096U) + +/*! @brief Enum _usdhc_adma1_descriptor_flag. The mask for the control/status field in ADMA1 descriptor. */ +enum +{ + kUSDHC_Adma1DescriptorValidFlag = (1U << 0U), /*!< Valid flag. */ + kUSDHC_Adma1DescriptorEndFlag = (1U << 1U), /*!< End flag. */ + kUSDHC_Adma1DescriptorInterrupFlag = (1U << 2U), /*!< Interrupt flag. */ + kUSDHC_Adma1DescriptorActivity1Flag = (1U << 4U), /*!< Activity 1 flag. */ + kUSDHC_Adma1DescriptorActivity2Flag = (1U << 5U), /*!< Activity 2 flag. */ + kUSDHC_Adma1DescriptorTypeNop = (kUSDHC_Adma1DescriptorValidFlag), /*!< No operation. */ + kUSDHC_Adma1DescriptorTypeTransfer = (kUSDHC_Adma1DescriptorActivity2Flag | kUSDHC_Adma1DescriptorValidFlag), + /*!< Transfer data. */ + kUSDHC_Adma1DescriptorTypeLink = (kUSDHC_Adma1DescriptorActivity1Flag | kUSDHC_Adma1DescriptorActivity2Flag | + kUSDHC_Adma1DescriptorValidFlag), /*!< Link descriptor. */ + kUSDHC_Adma1DescriptorTypeSetLength = (kUSDHC_Adma1DescriptorActivity1Flag | kUSDHC_Adma1DescriptorValidFlag), + /*!< Set data length. */ }; -/* ADMA2 descriptor table +/* ADMA2 descriptor table: * |----------------|---------------|-------------|--------------------------| * | Address field | Length | Reserved | Attribute | * |----------------|---------------|-------------|--------------------------| @@ -453,7 +491,7 @@ enum _usdhc_adma1_descriptor_flag * | 32-bit address | 16-bit length | 0000000000 |Act2|Act1| 0|Int|End|Valid| * |----------------|---------------|-------------|----|----|--|---|---|-----| * - * + * ADMA2 action table: * | Act2 | Act1 | Comment | Operation | * |------|------|-----------------|-------------------------------------------------------------------| * | 0 | 0 | No op | Don't care | @@ -465,68 +503,89 @@ enum _usdhc_adma1_descriptor_flag * | 1 | 1 | Link descriptor | Link to another descriptor | * |------|------|-----------------|-------------------------------------------------------------------| */ -/*! @brief The bit shift for LENGTH field in ADMA2's descriptor */ +/**********************************tables below are created only for Doxygen***********************************/ +/*! @brief The bit shift for LENGTH field in ADMA2's descriptor. + * + * + * + *
ADMA2 descriptor table
Address field Length Reserved Attribute + *
63 32 31 16 15 06 05 04 03 02 01 00 + *
32-bit address 16-bit length 0000000000 Act2 Act1 0 Int End Valid + *
+ * + * + * + *
ADMA2 action
Act2 Act1 Comment Operation + *
0 0 No op Don't care + *
0 1 Reserved Read this line and go to next one + *
1 0 Transfer data Transfer data with address and length set in this descriptor line + *
1 1 Link descriptor Link to another descriptor + *
+ */ #define USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT (16U) -/*! @brief The bit mask for LENGTH field in ADMA2's descriptor */ +/*! @brief The bit mask for LENGTH field in ADMA2's descriptor. */ #define USDHC_ADMA2_DESCRIPTOR_LENGTH_MASK (0xFFFFU) -/*! @brief The maximum value of LENGTH field in ADMA2's descriptor */ +/*! @brief The maximum value of LENGTH field in ADMA2's descriptor. */ #define USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY (USDHC_ADMA2_DESCRIPTOR_LENGTH_MASK - 3U) -/*! @brief ADMA1 descriptor control and status mask */ -enum _usdhc_adma2_descriptor_flag +/*! @brief Enum _usdhc_adma2_descriptor_flag. ADMA1 descriptor control and status mask. */ +enum { - kUSDHC_Adma2DescriptorValidFlag = (1U << 0U), /*!< Valid flag */ - kUSDHC_Adma2DescriptorEndFlag = (1U << 1U), /*!< End flag */ - kUSDHC_Adma2DescriptorInterruptFlag = (1U << 2U), /*!< Interrupt flag */ - kUSDHC_Adma2DescriptorActivity1Flag = (1U << 4U), /*!< Activity 1 mask */ - kUSDHC_Adma2DescriptorActivity2Flag = (1U << 5U), /*!< Activity 2 mask */ - - kUSDHC_Adma2DescriptorTypeNop = (kUSDHC_Adma2DescriptorValidFlag), /*!< No operation */ - kUSDHC_Adma2DescriptorTypeReserved = - (kUSDHC_Adma2DescriptorActivity1Flag | kUSDHC_Adma2DescriptorValidFlag), /*!< Reserved */ - kUSDHC_Adma2DescriptorTypeTransfer = - (kUSDHC_Adma2DescriptorActivity2Flag | kUSDHC_Adma2DescriptorValidFlag), /*!< Transfer type */ + kUSDHC_Adma2DescriptorValidFlag = (1U << 0U), /*!< Valid flag. */ + kUSDHC_Adma2DescriptorEndFlag = (1U << 1U), /*!< End flag. */ + kUSDHC_Adma2DescriptorInterruptFlag = (1U << 2U), /*!< Interrupt flag. */ + kUSDHC_Adma2DescriptorActivity1Flag = (1U << 4U), /*!< Activity 1 mask. */ + kUSDHC_Adma2DescriptorActivity2Flag = (1U << 5U), /*!< Activity 2 mask. */ + + kUSDHC_Adma2DescriptorTypeNop = (kUSDHC_Adma2DescriptorValidFlag), /*!< No operation. */ + kUSDHC_Adma2DescriptorTypeReserved = (kUSDHC_Adma2DescriptorActivity1Flag | kUSDHC_Adma2DescriptorValidFlag), + /*!< Reserved. */ + kUSDHC_Adma2DescriptorTypeTransfer = (kUSDHC_Adma2DescriptorActivity2Flag | kUSDHC_Adma2DescriptorValidFlag), + /*!< Transfer type. */ kUSDHC_Adma2DescriptorTypeLink = (kUSDHC_Adma2DescriptorActivity1Flag | kUSDHC_Adma2DescriptorActivity2Flag | - kUSDHC_Adma2DescriptorValidFlag), /*!< Link type */ + kUSDHC_Adma2DescriptorValidFlag), /*!< Link type. */ }; -/*! @brief ADMA descriptor configuration flag */ -enum _usdhc_adma_flag +/*! @brief Enum _usdhc_adma_flag. ADMA descriptor configuration flag. + * @anchor _usdhc_adma_flag + */ +enum { - kUSDHC_AdmaDescriptorSingleFlag = - 0U, /*!< try to finish the transfer in a single ADMA descriptor, if transfer size is bigger than one - ADMA descriptor's ability, new another descriptor for data transfer */ - kUSDHC_AdmaDescriptorMultipleFlag = 1U, /*!< create multiple ADMA descriptor within the ADMA table, this is used for - mmc boot mode specifically, which need - to modify the ADMA descriptor on the fly, so the flag should be used - combine with stop at block gap feature */ + kUSDHC_AdmaDescriptorSingleFlag = 0U, + /*!< Try to finish the transfer in a single ADMA descriptor. If transfer size is bigger than one + ADMA descriptor's ability, new another descriptor for data transfer. */ + kUSDHC_AdmaDescriptorMultipleFlag = + 1U, /*!< Create multiple ADMA descriptors within the ADMA table, this is used for + mmc boot mode specifically, which need + to modify the ADMA descriptor on the fly, so the flag should be used + combining with stop at block gap feature. */ }; -/*! @brief dma transfer burst len config. */ +/*! @brief DMA transfer burst len config. */ typedef enum _usdhc_burst_len { - kUSDHC_EnBurstLenForINCR = 0x01U, /*!< enable burst len for INCR */ - kUSDHC_EnBurstLenForINCR4816 = 0x02U, /*!< enable burst len for INCR4/INCR8/INCR16 */ - kUSDHC_EnBurstLenForINCR4816WRAP = 0x04U, /*!< enable burst len for INCR4/8/16 WRAP */ + kUSDHC_EnBurstLenForINCR = 0x01U, /*!< Enable burst len for INCR. */ + kUSDHC_EnBurstLenForINCR4816 = 0x02U, /*!< Enable burst len for INCR4/INCR8/INCR16. */ + kUSDHC_EnBurstLenForINCR4816WRAP = 0x04U, /*!< Enable burst len for INCR4/8/16 WRAP. */ } usdhc_burst_len_t; -/*! @brief transfer data type definition. */ -enum _usdhc_transfer_data_type +/*! @brief Enum _usdhc_transfer_data_type. Tansfer data type definition. */ +enum { - kUSDHC_TransferDataNormal = 0U, /*!< transfer normal read/write data */ - kUSDHC_TransferDataTuning = 1U, /*!< transfer tuning data */ - kUSDHC_TransferDataBoot = 2U, /*!< transfer boot data */ - kUSDHC_TransferDataBootcontinous = 3U, /*!< transfer boot data continous */ + kUSDHC_TransferDataNormal = 0U, /*!< Transfer normal read/write data. */ + kUSDHC_TransferDataTuning = 1U, /*!< Transfer tuning data. */ + kUSDHC_TransferDataBoot = 2U, /*!< Transfer boot data. */ + kUSDHC_TransferDataBootcontinous = 3U, /*!< Transfer boot data continuously. */ }; -/*! @brief Defines the adma1 descriptor structure. */ +/*! @brief Defines the ADMA1 descriptor structure. */ typedef uint32_t usdhc_adma1_descriptor_t; /*! @brief Defines the ADMA2 descriptor structure. */ typedef struct _usdhc_adma2_descriptor { - uint32_t attribute; /*!< The control and status field */ - const uint32_t *address; /*!< The address field */ + uint32_t attribute; /*!< The control and status field. */ + const uint32_t *address; /*!< The address field. */ } usdhc_adma2_descriptor_t; /*! @@ -536,91 +595,131 @@ typedef struct _usdhc_adma2_descriptor */ typedef struct _usdhc_capability { - uint32_t sdVersion; /*!< support SD card/sdio version */ - uint32_t mmcVersion; /*!< support emmc card version */ - uint32_t maxBlockLength; /*!< Maximum block length united as byte */ - uint32_t maxBlockCount; /*!< Maximum block count can be set one time */ - uint32_t flags; /*!< Capability flags to indicate the support information(_usdhc_capability_flag) */ + uint32_t sdVersion; /*!< Support SD card/sdio version. */ + uint32_t mmcVersion; /*!< Support EMMC card version. */ + uint32_t maxBlockLength; /*!< Maximum block length united as byte. */ + uint32_t maxBlockCount; /*!< Maximum block count can be set one time. */ + uint32_t flags; /*!< Capability flags to indicate the support information(@ref _usdhc_capability_flag). */ } usdhc_capability_t; -/*! @brief Data structure to configure the MMC boot feature */ +/*! @brief Data structure to configure the MMC boot feature. */ typedef struct _usdhc_boot_config { uint32_t ackTimeoutCount; /*!< Timeout value for the boot ACK. The available range is 0 ~ 15. */ usdhc_boot_mode_t bootMode; /*!< Boot mode selection. */ uint32_t blockCount; /*!< Stop at block gap value of automatic mode. Available range is 0 ~ 65535. */ - size_t blockSize; /*!< Block size */ - bool enableBootAck; /*!< Enable or disable boot ACK */ - bool enableAutoStopAtBlockGap; /*!< Enable or disable auto stop at block gap function in boot period */ + size_t blockSize; /*!< Block size. */ + bool enableBootAck; /*!< Enable or disable boot ACK. */ + bool enableAutoStopAtBlockGap; /*!< Enable or disable auto stop at block gap function in boot period. */ } usdhc_boot_config_t; -/*! @brief Data structure to initialize the USDHC */ +/*! @brief Data structure to initialize the USDHC. */ typedef struct _usdhc_config { - uint32_t dataTimeout; /*!< Data timeout value */ - usdhc_endian_mode_t endianMode; /*!< Endian mode */ + uint32_t dataTimeout; /*!< Data timeout value. */ + usdhc_endian_mode_t endianMode; /*!< Endian mode. */ uint8_t readWatermarkLevel; /*!< Watermark level for DMA read operation. Available range is 1 ~ 128. */ uint8_t writeWatermarkLevel; /*!< Watermark level for DMA write operation. Available range is 1 ~ 128. */ - uint8_t readBurstLen; /*!< Read burst len */ - uint8_t writeBurstLen; /*!< Write burst len */ +#if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) + uint8_t readBurstLen; /*!< Read burst len. */ + uint8_t writeBurstLen; /*!< Write burst len. */ +#endif } usdhc_config_t; /*! - * @brief Card data descriptor + * @brief Card command descriptor. * - * Defines a structure to contain data-related attribute. 'enableIgnoreError' is used for the case that upper card - * driver - * want to ignore the error event to read/write all the data not to stop read/write immediately when error event - * happen for example bus testing procedure for MMC card. + * Defines card command-related attribute. */ -typedef struct _usdhc_data +typedef struct _usdhc_command { - bool enableAutoCommand12; /*!< Enable auto CMD12 */ - bool enableAutoCommand23; /*!< Enable auto CMD23 */ - bool enableIgnoreError; /*!< Enable to ignore error event to read/write all the data */ - uint8_t dataType; /*!< this is used to distinguish the normal/tuning/boot data */ - size_t blockSize; /*!< Block size */ - uint32_t blockCount; /*!< Block count */ - uint32_t *rxData; /*!< Buffer to save data read */ - const uint32_t *txData; /*!< Data buffer to write */ -} usdhc_data_t; + uint32_t index; /*!< Command index. */ + uint32_t argument; /*!< Command argument. */ + usdhc_card_command_type_t type; /*!< Command type. */ + usdhc_card_response_type_t responseType; /*!< Command response type. */ + uint32_t response[4U]; /*!< Response for this command. */ + uint32_t responseErrorFlags; /*!< Response error flag, which need to check + the command reponse. */ + uint32_t flags; /*!< Cmd flags. */ +} usdhc_command_t; + +/*! @brief ADMA configuration. */ +typedef struct _usdhc_adma_config +{ + usdhc_dma_mode_t dmaMode; /*!< DMA mode. */ +#if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) + usdhc_burst_len_t burstLen; /*!< Burst len config. */ +#endif + uint32_t *admaTable; /*!< ADMA table address, can't be null if transfer way is ADMA1/ADMA2. */ + uint32_t admaTableWords; /*!< ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2. */ +} usdhc_adma_config_t; /*! - * @brief Card command descriptor + * @brief Card scatter gather data list. * - * Define card command-related attribute. + * Allow application register uncontinuous data buffer for data transfer. */ -typedef struct _usdhc_command +typedef struct _usdhc_scatter_gather_data_list { - uint32_t index; /*!< Command index */ - uint32_t argument; /*!< Command argument */ - usdhc_card_command_type_t type; /*!< Command type */ - usdhc_card_response_type_t responseType; /*!< Command response type */ - uint32_t response[4U]; /*!< Response for this command */ - uint32_t responseErrorFlags; /*!< response error flag, the flag which need to check - the command reponse*/ - uint32_t flags; /*!< Cmd flags */ -} usdhc_command_t; + uint32_t *dataAddr; + uint32_t dataSize; + struct _usdhc_scatter_gather_data_list *dataList; +} usdhc_scatter_gather_data_list_t; -/*! @brief ADMA configuration */ -typedef struct _usdhc_adma_config +/*! + * @brief Card scatter gather data descriptor. + * + * Defines a structure to contain data-related attribute. The 'enableIgnoreError' is used when upper card + * driver wants to ignore the error event to read/write all the data and not to stop read/write immediately when an + * error event happens. For example, bus testing procedure for MMC card. + */ +typedef struct _usdhc_scatter_gather_data { - usdhc_dma_mode_t dmaMode; /*!< DMA mode */ + bool enableAutoCommand12; /*!< Enable auto CMD12. */ + bool enableAutoCommand23; /*!< Enable auto CMD23. */ + bool enableIgnoreError; /*!< Enable to ignore error event to read/write all the data. */ - usdhc_burst_len_t burstLen; /*!< burst len config */ + usdhc_transfer_direction_t dataDirection; /*!< data direction */ + uint8_t dataType; /*!< this is used to distinguish the normal/tuning/boot data. */ + size_t blockSize; /*!< Block size. */ - uint32_t *admaTable; /*!< ADMA table address, can't be null if transfer way is ADMA1/ADMA2 */ - uint32_t admaTableWords; /*!< ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2 */ -} usdhc_adma_config_t; + usdhc_scatter_gather_data_list_t sgData; /*!< scatter gather data */ +} usdhc_scatter_gather_data_t; + +/*! @brief usdhc scatter gather transfer. */ +typedef struct _usdhc_scatter_gather_transfer +{ + usdhc_scatter_gather_data_t *data; /*!< Data to transfer. */ + usdhc_command_t *command; /*!< Command to send. */ +} usdhc_scatter_gather_transfer_t; -/*! @brief Transfer state */ +/*! + * @brief Card data descriptor. + * + * Defines a structure to contain data-related attribute. The 'enableIgnoreError' is used when upper card + * driver wants to ignore the error event to read/write all the data and not to stop read/write immediately when an + * error event happens. For example, bus testing procedure for MMC card. + */ +typedef struct _usdhc_data +{ + bool enableAutoCommand12; /*!< Enable auto CMD12. */ + bool enableAutoCommand23; /*!< Enable auto CMD23. */ + bool enableIgnoreError; /*!< Enable to ignore error event to read/write all the data. */ + uint8_t dataType; /*!< this is used to distinguish the normal/tuning/boot data. */ + size_t blockSize; /*!< Block size. */ + uint32_t blockCount; /*!< Block count. */ + uint32_t *rxData; /*!< Buffer to save data read. */ + const uint32_t *txData; /*!< Data buffer to write. */ +} usdhc_data_t; + +/*! @brief Transfer state. */ typedef struct _usdhc_transfer { - usdhc_data_t *data; /*!< Data to transfer */ - usdhc_command_t *command; /*!< Command to send */ + usdhc_data_t *data; /*!< Data to transfer. */ + usdhc_command_t *command; /*!< Command to send. */ } usdhc_transfer_t; -/*! @brief USDHC handle typedef */ +/*! @brief USDHC handle typedef. */ typedef struct _usdhc_handle usdhc_handle_t; /*! @brief USDHC callback functions. */ @@ -634,849 +733,967 @@ typedef struct _usdhc_transfer_callback void (*TransferComplete)(USDHC_Type *base, usdhc_handle_t *handle, status_t status, - void *userData); /*!< Transfer complete callback */ - void (*ReTuning)(USDHC_Type *base, void *userData); /*!< handle the re-tuning */ + void *userData); /*!< Transfer complete callback. */ + void (*ReTuning)(USDHC_Type *base, void *userData); /*!< Handle the re-tuning. */ } usdhc_transfer_callback_t; /*! - * @brief USDHC handle + * @brief USDHC handle. * - * Defines the structure to save the USDHC state information and callback function. The detailed interrupt status when - * sending a command or transfering data can be obtained from the interruptFlags field by using the mask defined in - * usdhc_interrupt_flag_t. + * Defines the structure to save the USDHC state information and callback function. * * @note All the fields except interruptFlags and transferredWords must be allocated by the user. */ struct _usdhc_handle { - /* Transfer parameter */ - usdhc_data_t *volatile data; /*!< Data to transfer */ - usdhc_command_t *volatile command; /*!< Command to send */ +#if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER + usdhc_scatter_gather_data_t *volatile data; /*!< scatter gather data pointer */ +#else + usdhc_data_t *volatile data; /*!< Transfer parameter. Data to transfer. */ +#endif + usdhc_command_t *volatile command; /*!< Transfer parameter. Command to send. */ - /* Transfer status */ - volatile uint32_t interruptFlags; /*!< Interrupt flags of last transaction */ - volatile uint32_t transferredWords; /*!< Words transferred by DATAPORT way */ + volatile uint32_t transferredWords; /*!< Transfer status. Words transferred by DATAPORT way. */ - /* Callback functions */ - usdhc_transfer_callback_t callback; /*!< Callback function */ - void *userData; /*!< Parameter for transfer complete callback */ + usdhc_transfer_callback_t callback; /*!< Callback function. */ + void *userData; /*!< Parameter for transfer complete callback. */ }; /*! @brief USDHC transfer function. */ typedef status_t (*usdhc_transfer_function_t)(USDHC_Type *base, usdhc_transfer_t *content); -/*! @brief USDHC host descriptor */ +/*! @brief USDHC host descriptor. */ typedef struct _usdhc_host { - USDHC_Type *base; /*!< USDHC peripheral base address */ - uint32_t sourceClock_Hz; /*!< USDHC source clock frequency united in Hz */ - usdhc_config_t config; /*!< USDHC configuration */ - usdhc_capability_t capability; /*!< USDHC capability information */ - usdhc_transfer_function_t transfer; /*!< USDHC transfer function */ + USDHC_Type *base; /*!< USDHC peripheral base address. */ + uint32_t sourceClock_Hz; /*!< USDHC source clock frequency united in Hz. */ + usdhc_config_t config; /*!< USDHC configuration. */ + usdhc_capability_t capability; /*!< USDHC capability information. */ + usdhc_transfer_function_t transfer; /*!< USDHC transfer function. */ } usdhc_host_t; /************************************************************************************************* * API ************************************************************************************************/ #if defined(__cplusplus) -extern "C" -{ +extern "C" { #endif - /*! - * @name Initialization and deinitialization - * @{ - */ - - /*! - * @brief USDHC module initialization function. - * - * Configures the USDHC according to the user configuration. - * - * Example: - @code - usdhc_config_t config; - config.cardDetectDat3 = false; - config.endianMode = kUSDHC_EndianModeLittle; - config.dmaMode = kUSDHC_DmaModeAdma2; - config.readWatermarkLevel = 128U; - config.writeWatermarkLevel = 128U; - USDHC_Init(USDHC, &config); - @endcode - * - * @param base USDHC peripheral base address. - * @param config USDHC configuration information. - * @retval kStatus_Success Operate successfully. - */ - void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config); - - /*! - * @brief Deinitializes the USDHC. - * - * @param base USDHC peripheral base address. - */ - void USDHC_Deinit(USDHC_Type *base); - - /*! - * @brief Resets the USDHC. - * - * @param base USDHC peripheral base address. - * @param mask The reset type mask(_usdhc_reset). - * @param timeout Timeout for reset. - * @retval true Reset successfully. - * @retval false Reset failed. - */ - bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout); - - /* @} */ - - /*! - * @name DMA Control - * @{ - */ - - /*! - * @brief Sets the DMA descriptor table configuration. - * A high level DMA descriptor configuration function. - * @param base USDHC peripheral base address. - * @param adma configuration - * @param data Data descriptor - * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please - * reference _usdhc_adma_flag - * @retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. - * @retval kStatus_Success Operate successfully. - */ - status_t USDHC_SetAdmaTableConfig(USDHC_Type *base, - usdhc_adma_config_t *dmaConfig, - usdhc_data_t *dataConfig, - uint32_t flags); - - /*! - * @brief Internal DMA configuration. - * This function is used to config the USDHC DMA related registers. - * @param base USDHC peripheral base address. - * @param adma configuration - * @param dataAddr tranfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL. - * @param enAutoCmd23 flag to indicate Auto CMD23 is enable or not, a simple DMA parameter,if ADMA is used, leave it - * to false. - * @retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. - * @retval kStatus_Success Operate successfully. - */ - status_t USDHC_SetInternalDmaConfig(USDHC_Type *base, - usdhc_adma_config_t *dmaConfig, - const uint32_t *dataAddr, - bool enAutoCmd23); - - /*! - * @brief Sets the ADMA2 descriptor table configuration. - * - * @param admaTable Adma table address. - * @param admaTableWords Adma table length. - * @param dataBufferAddr Data buffer address. - * @param dataBytes Data Data length. - * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please - * reference _usdhc_adma_flag. - * @retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. - * @retval kStatus_Success Operate successfully. - */ - status_t USDHC_SetADMA2Descriptor(uint32_t *admaTable, - uint32_t admaTableWords, - const uint32_t *dataBufferAddr, - uint32_t dataBytes, - uint32_t flags); - - /*! - * @brief Sets the ADMA1 descriptor table configuration. - * - * @param admaTable Adma table address. - * @param admaTableWords Adma table length. - * @param dataBufferAddr Data buffer address. - * @param dataBytes Data length. - * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please - * reference _usdhc_adma_flag. - * @retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. - * @retval kStatus_Success Operate successfully. - */ - status_t USDHC_SetADMA1Descriptor(uint32_t *admaTable, - uint32_t admaTableWords, - const uint32_t *dataBufferAddr, - uint32_t dataBytes, - uint32_t flags); - - /*! - * @brief enable internal DMA. - * - * @param base USDHC peripheral base address. - * @param enable enable or disable flag - */ - static inline void USDHC_EnableInternalDMA(USDHC_Type *base, bool enable) - { - if (enable) { - base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK; - } - else { - base->MIX_CTRL &= ~USDHC_MIX_CTRL_DMAEN_MASK; - base->PROT_CTRL &= ~USDHC_PROT_CTRL_DMASEL_MASK; - } - } +/*! + * @name Initialization and deinitialization + * @{ + */ - /* @} */ +/*! + * @brief USDHC module initialization function. + * + * Configures the USDHC according to the user configuration. + * + * Example: + @code + usdhc_config_t config; + config.cardDetectDat3 = false; + config.endianMode = kUSDHC_EndianModeLittle; + config.dmaMode = kUSDHC_DmaModeAdma2; + config.readWatermarkLevel = 128U; + config.writeWatermarkLevel = 128U; + USDHC_Init(USDHC, &config); + @endcode + * + * @param base USDHC peripheral base address. + * @param config USDHC configuration information. + * @retval #kStatus_Success Operate successfully. + */ +void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config); - /*! - * @name Interrupts - * @{ - */ +/*! + * @brief Deinitializes the USDHC. + * + * @param base USDHC peripheral base address. + */ +void USDHC_Deinit(USDHC_Type *base); - /*! - * @brief Enables the interrupt status. - * - * @param base USDHC peripheral base address. - * @param mask Interrupt status flags mask(_usdhc_interrupt_status_flag). - */ - static inline void USDHC_EnableInterruptStatus(USDHC_Type *base, uint32_t mask) - { - base->INT_STATUS_EN |= mask; - } +/*! + * @brief Resets the USDHC. + * + * @param base USDHC peripheral base address. + * @param mask The reset type mask(@ref _usdhc_reset). + * @param timeout Timeout for reset. + * @retval true Reset successfully. + * @retval false Reset failed. + */ +bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout); - /*! - * @brief Disables the interrupt status. - * - * @param base USDHC peripheral base address. - * @param mask The interrupt status flags mask(_usdhc_interrupt_status_flag). - */ - static inline void USDHC_DisableInterruptStatus(USDHC_Type *base, uint32_t mask) - { - base->INT_STATUS_EN &= ~mask; - } +/* @} */ - /*! - * @brief Enables the interrupt signal corresponding to the interrupt status flag. - * - * @param base USDHC peripheral base address. - * @param mask The interrupt status flags mask(_usdhc_interrupt_status_flag). - */ - static inline void USDHC_EnableInterruptSignal(USDHC_Type *base, uint32_t mask) - { - base->INT_SIGNAL_EN |= mask; - } +/*! + * @name DMA Control + * @{ + */ - /*! - * @brief Disables the interrupt signal corresponding to the interrupt status flag. - * - * @param base USDHC peripheral base address. - * @param mask The interrupt status flags mask(_usdhc_interrupt_status_flag). - */ - static inline void USDHC_DisableInterruptSignal(USDHC_Type *base, uint32_t mask) - { - base->INT_SIGNAL_EN &= ~mask; - } +/*! + * @brief Sets the DMA descriptor table configuration. + * A high level DMA descriptor configuration function. + * @param base USDHC peripheral base address. + * @param dmaConfig ADMA configuration + * @param dataConfig Data descriptor + * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * refer to enum @ref _usdhc_adma_flag. + * @retval #kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * @retval #kStatus_Success Operate successfully. + */ +status_t USDHC_SetAdmaTableConfig(USDHC_Type *base, + usdhc_adma_config_t *dmaConfig, + usdhc_data_t *dataConfig, + uint32_t flags); - /* @} */ +/*! + * @brief Internal DMA configuration. + * This function is used to config the USDHC DMA related registers. + * @param base USDHC peripheral base address. + * @param dmaConfig ADMA configuration. + * @param dataAddr Transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL. + * @param enAutoCmd23 Flag to indicate Auto CMD23 is enable or not, a simple DMA parameter, if ADMA is used, leave it + * to false. + * @retval #kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * @retval #kStatus_Success Operate successfully. + */ +status_t USDHC_SetInternalDmaConfig(USDHC_Type *base, + usdhc_adma_config_t *dmaConfig, + const uint32_t *dataAddr, + bool enAutoCmd23); - /*! - * @name Status - * @{ - */ +/*! + * @brief Sets the ADMA2 descriptor table configuration. + * + * @param admaTable ADMA table address. + * @param admaTableWords ADMA table length. + * @param dataBufferAddr Data buffer address. + * @param dataBytes Data Data length. + * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * refer to enum @ref _usdhc_adma_flag. + * @retval #kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * @retval #kStatus_Success Operate successfully. + */ +status_t USDHC_SetADMA2Descriptor( + uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags); - /*! - * @brief Gets the current interrupt status. - * - * @param base USDHC peripheral base address. - * @return Current interrupt status flags mask(_usdhc_interrupt_status_flag). - */ - static inline uint32_t USDHC_GetInterruptStatusFlags(USDHC_Type *base) - { - return base->INT_STATUS; - } +/*! + * @brief Sets the ADMA1 descriptor table configuration. + * + * @param admaTable ADMA table address. + * @param admaTableWords ADMA table length. + * @param dataBufferAddr Data buffer address. + * @param dataBytes Data length. + * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * refer to enum @ref _usdhc_adma_flag. + * @retval #kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * @retval #kStatus_Success Operate successfully. + */ +status_t USDHC_SetADMA1Descriptor( + uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags); - /*! - * @brief Clears a specified interrupt status. - * write 1 clears - * @param base USDHC peripheral base address. - * @param mask The interrupt status flags mask(_usdhc_interrupt_status_flag). - */ - static inline void USDHC_ClearInterruptStatusFlags(USDHC_Type *base, uint32_t mask) +/*! + * @brief Enables internal DMA. + * + * @param base USDHC peripheral base address. + * @param enable enable or disable flag + */ +static inline void USDHC_EnableInternalDMA(USDHC_Type *base, bool enable) +{ + if (enable) { - base->INT_STATUS = mask; + base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK; } - - /*! - * @brief Gets the status of auto command 12 error. - * - * @param base USDHC peripheral base address. - * @return Auto command 12 error status flags mask(_usdhc_auto_command12_error_status_flag). - */ - static inline uint32_t USDHC_GetAutoCommand12ErrorStatusFlags(USDHC_Type *base) + else { - return base->AUTOCMD12_ERR_STATUS; + base->MIX_CTRL &= ~USDHC_MIX_CTRL_DMAEN_MASK; + base->PROT_CTRL &= ~USDHC_PROT_CTRL_DMASEL_MASK; } +} + +/* @} */ + +/*! + * @name Interrupts + * @{ + */ + +/*! + * @brief Enables the interrupt status. + * + * @param base USDHC peripheral base address. + * @param mask Interrupt status flags mask(@ref _usdhc_interrupt_status_flag). + */ +static inline void USDHC_EnableInterruptStatus(USDHC_Type *base, uint32_t mask) +{ + base->INT_STATUS_EN |= mask; +} - /*! - * @brief Gets the status of the ADMA error. - * - * @param base USDHC peripheral base address. - * @return ADMA error status flags mask(_usdhc_adma_error_status_flag). - */ - static inline uint32_t USDHC_GetAdmaErrorStatusFlags(USDHC_Type *base) +/*! + * @brief Disables the interrupt status. + * + * @param base USDHC peripheral base address. + * @param mask The interrupt status flags mask(@ref _usdhc_interrupt_status_flag). + */ +static inline void USDHC_DisableInterruptStatus(USDHC_Type *base, uint32_t mask) +{ + base->INT_STATUS_EN &= ~mask; +} + +/*! + * @brief Enables the interrupt signal corresponding to the interrupt status flag. + * + * @param base USDHC peripheral base address. + * @param mask The interrupt status flags mask(@ref _usdhc_interrupt_status_flag). + */ +static inline void USDHC_EnableInterruptSignal(USDHC_Type *base, uint32_t mask) +{ + base->INT_SIGNAL_EN |= mask; +} + +/*! + * @brief Disables the interrupt signal corresponding to the interrupt status flag. + * + * @param base USDHC peripheral base address. + * @param mask The interrupt status flags mask(@ref _usdhc_interrupt_status_flag). + */ +static inline void USDHC_DisableInterruptSignal(USDHC_Type *base, uint32_t mask) +{ + base->INT_SIGNAL_EN &= ~mask; +} + +/* @} */ + +/*! + * @name Status + * @{ + */ + +/*! + * @brief Gets the enabled interrupt status. + * + * @param base USDHC peripheral base address. + * @return Current interrupt status flags mask(@ref _usdhc_interrupt_status_flag). + */ +static inline uint32_t USDHC_GetEnabledInterruptStatusFlags(USDHC_Type *base) +{ + uint32_t intStatus = base->INT_STATUS; + + return intStatus & base->INT_SIGNAL_EN; +} + +/*! + * @brief Gets the current interrupt status. + * + * @param base USDHC peripheral base address. + * @return Current interrupt status flags mask(@ref _usdhc_interrupt_status_flag). + */ +static inline uint32_t USDHC_GetInterruptStatusFlags(USDHC_Type *base) +{ + return base->INT_STATUS; +} + +/*! + * @brief Clears a specified interrupt status. + * write 1 clears + * @param base USDHC peripheral base address. + * @param mask The interrupt status flags mask(@ref _usdhc_interrupt_status_flag). + */ +static inline void USDHC_ClearInterruptStatusFlags(USDHC_Type *base, uint32_t mask) +{ + base->INT_STATUS = mask; +} + +/*! + * @brief Gets the status of auto command 12 error. + * + * @param base USDHC peripheral base address. + * @return Auto command 12 error status flags mask(@ref _usdhc_auto_command12_error_status_flag). + */ +static inline uint32_t USDHC_GetAutoCommand12ErrorStatusFlags(USDHC_Type *base) +{ + return base->AUTOCMD12_ERR_STATUS; +} + +/*! + * @brief Gets the status of the ADMA error. + * + * @param base USDHC peripheral base address. + * @return ADMA error status flags mask(@ref _usdhc_adma_error_status_flag). + */ +static inline uint32_t USDHC_GetAdmaErrorStatusFlags(USDHC_Type *base) +{ + return base->ADMA_ERR_STATUS & 0xFUL; +} + +/*! + * @brief Gets a present status. + * + * This function gets the present USDHC's status except for an interrupt status and an error status. + * + * @param base USDHC peripheral base address. + * @return Present USDHC's status flags mask(@ref _usdhc_present_status_flag). + */ +static inline uint32_t USDHC_GetPresentStatusFlags(USDHC_Type *base) +{ + return base->PRES_STATE; +} + +/* @} */ + +/*! + * @name Bus Operations + * @{ + */ + +/*! + * @brief Gets the capability information. + * + * @param base USDHC peripheral base address. + * @param capability Structure to save capability information. + */ +void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability); + +/*! + * @brief Forces the card clock on. + * + * @param base USDHC peripheral base address. + * @param enable enable/disable flag + */ +static inline void USDHC_ForceClockOn(USDHC_Type *base, bool enable) +{ + if (enable) { - return base->ADMA_ERR_STATUS & 0xFU; + base->VEND_SPEC |= USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK; } - - /*! - * @brief Gets a present status. - * - * This function gets the present USDHC's status except for an interrupt status and an error status. - * - * @param base USDHC peripheral base address. - * @return Present USDHC's status flags mask(_usdhc_present_status_flag). - */ - static inline uint32_t USDHC_GetPresentStatusFlags(USDHC_Type *base) + else { - return base->PRES_STATE; + base->VEND_SPEC &= ~USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK; } +} + +/*! + * @brief Sets the SD bus clock frequency. + * + * @param base USDHC peripheral base address. + * @param srcClock_Hz USDHC source clock frequency united in Hz. + * @param busClock_Hz SD bus clock frequency united in Hz. + * + * @return The nearest frequency of busClock_Hz configured for SD bus. + */ +uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz); - /* @} */ - - /*! - * @name Bus Operations - * @{ - */ - - /*! - * @brief Gets the capability information. - * - * @param base USDHC peripheral base address. - * @param capability Structure to save capability information. - */ - void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability); - - /*! - * @brief force the card clock on. - * - * @param base USDHC peripheral base address. - * @param enable/disable flag. - */ - static inline void USDHC_ForceClockOn(USDHC_Type *base, bool enable) +/*! + * @brief Sends 80 clocks to the card to set it to the active state. + * + * This function must be called each time the card is inserted to ensure that the card can receive the command + * correctly. + * + * @param base USDHC peripheral base address. + * @param timeout Timeout to initialize card. + * @retval true Set card active successfully. + * @retval false Set card active failed. + */ +bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout); + +/*! + * @brief Triggers a hardware reset. + * + * @param base USDHC peripheral base address. + * @param high 1 or 0 level + */ +static inline void USDHC_AssertHardwareReset(USDHC_Type *base, bool high) +{ + if (high) { - if (enable) { - base->VEND_SPEC |= USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK; - } - else { - base->VEND_SPEC &= ~USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK; - } + base->SYS_CTRL |= USDHC_SYS_CTRL_IPP_RST_N_MASK; } - - /*! - * @brief Sets the SD bus clock frequency. - * - * @param base USDHC peripheral base address. - * @param srcClock_Hz USDHC source clock frequency united in Hz. - * @param busClock_Hz SD bus clock frequency united in Hz. - * - * @return The nearest frequency of busClock_Hz configured to SD bus. - */ - uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz); - - /*! - * @brief Sends 80 clocks to the card to set it to the active state. - * - * This function must be called each time the card is inserted to ensure that the card can receive the command - * correctly. - * - * @param base USDHC peripheral base address. - * @param timeout Timeout to initialize card. - * @retval true Set card active successfully. - * @retval false Set card active failed. - */ - bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout); - - /*! - * @brief trigger a hardware reset. - * - * @param base USDHC peripheral base address. - * @param 1 or 0 level - */ - static inline void USDHC_AssertHardwareReset(USDHC_Type *base, bool high) + else { - if (high) { - base->SYS_CTRL |= USDHC_SYS_CTRL_IPP_RST_N_MASK; - } - else { - base->SYS_CTRL &= ~USDHC_SYS_CTRL_IPP_RST_N_MASK; - } + base->SYS_CTRL &= ~USDHC_SYS_CTRL_IPP_RST_N_MASK; } +} - /*! - * @brief Sets the data transfer width. - * - * @param base USDHC peripheral base address. - * @param width Data transfer width. - */ - static inline void USDHC_SetDataBusWidth(USDHC_Type *base, usdhc_data_bus_width_t width) +/*! + * @brief Sets the data transfer width. + * + * @param base USDHC peripheral base address. + * @param width Data transfer width. + */ +static inline void USDHC_SetDataBusWidth(USDHC_Type *base, usdhc_data_bus_width_t width) +{ + base->PROT_CTRL = ((base->PROT_CTRL & ~USDHC_PROT_CTRL_DTW_MASK) | USDHC_PROT_CTRL_DTW(width)); +} + +/*! + * @brief Fills the data port. + * + * This function is used to implement the data transfer by Data Port instead of DMA. + * + * @param base USDHC peripheral base address. + * @param data The data about to be sent. + */ +static inline void USDHC_WriteData(USDHC_Type *base, uint32_t data) +{ + base->DATA_BUFF_ACC_PORT = data; +} + +/*! + * @brief Retrieves the data from the data port. + * + * This function is used to implement the data transfer by Data Port instead of DMA. + * + * @param base USDHC peripheral base address. + * @return The data has been read. + */ +static inline uint32_t USDHC_ReadData(USDHC_Type *base) +{ + return base->DATA_BUFF_ACC_PORT; +} + +/*! + * @brief Sends command function. + * + * @param base USDHC peripheral base address. + * @param command configuration + */ +void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command); + +/*! + * @brief Enables or disables a wakeup event in low-power mode. + * + * @param base USDHC peripheral base address. + * @param mask Wakeup events mask(@ref _usdhc_wakeup_event). + * @param enable True to enable, false to disable. + */ +static inline void USDHC_EnableWakeupEvent(USDHC_Type *base, uint32_t mask, bool enable) +{ + if (enable) { - base->PROT_CTRL = ((base->PROT_CTRL & ~USDHC_PROT_CTRL_DTW_MASK) | USDHC_PROT_CTRL_DTW(width)); + base->PROT_CTRL |= mask; } - - /*! - * @brief Fills the data port. - * - * This function is used to implement the data transfer by Data Port instead of DMA. - * - * @param base USDHC peripheral base address. - * @param data The data about to be sent. - */ - static inline void USDHC_WriteData(USDHC_Type *base, uint32_t data) + else { - base->DATA_BUFF_ACC_PORT = data; + base->PROT_CTRL &= ~mask; } +} - /*! - * @brief Retrieves the data from the data port. - * - * This function is used to implement the data transfer by Data Port instead of DMA. - * - * @param base USDHC peripheral base address. - * @return The data has been read. - */ - static inline uint32_t USDHC_ReadData(USDHC_Type *base) +/*! + * @brief Detects card insert status. + * + * @param base USDHC peripheral base address. + * @param enable enable/disable flag + */ +static inline void USDHC_CardDetectByData3(USDHC_Type *base, bool enable) +{ + if (enable) { - return base->DATA_BUFF_ACC_PORT; + base->PROT_CTRL |= USDHC_PROT_CTRL_D3CD_MASK; } - - /*! - * @brief send command function - * - * @param base USDHC peripheral base address. - * @param command configuration - */ - void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command); - - /*! - * @brief Enables or disables a wakeup event in low-power mode. - * - * @param base USDHC peripheral base address. - * @param mask Wakeup events mask(_usdhc_wakeup_event). - * @param enable True to enable, false to disable. - */ - static inline void USDHC_EnableWakeupEvent(USDHC_Type *base, uint32_t mask, bool enable) + else { - if (enable) { - base->PROT_CTRL |= mask; - } - else { - base->PROT_CTRL &= ~mask; - } + base->PROT_CTRL &= ~USDHC_PROT_CTRL_D3CD_MASK; } +} + +/*! + * @brief Detects card insert status. + * + * @param base USDHC peripheral base address. + */ +static inline bool USDHC_DetectCardInsert(USDHC_Type *base) +{ + return ((base->PRES_STATE & (uint32_t)kUSDHC_CardInsertedFlag) != 0UL) ? true : false; +} - /*! - * @brief detect card insert status. - * - * @param base USDHC peripheral base address. - * @param enable/disable flag - */ - static inline void USDHC_CardDetectByData3(USDHC_Type *base, bool enable) +/*! + * @brief Enables or disables the SDIO card control. + * + * @param base USDHC peripheral base address. + * @param mask SDIO card control flags mask(@ref _usdhc_sdio_control_flag). + * @param enable True to enable, false to disable. + */ +static inline void USDHC_EnableSdioControl(USDHC_Type *base, uint32_t mask, bool enable) +{ + if (enable) { - if (enable) { - base->PROT_CTRL |= USDHC_PROT_CTRL_D3CD_MASK; - } - else { - base->PROT_CTRL &= ~USDHC_PROT_CTRL_D3CD_MASK; - } + base->PROT_CTRL |= mask; } - - /*! - * @brief detect card insert status. - * - * @param base USDHC peripheral base address. - */ - static inline bool USDHC_DetectCardInsert(USDHC_Type *base) + else { - return (base->PRES_STATE & kUSDHC_CardInsertedFlag) ? true : false; + base->PROT_CTRL &= ~mask; } +} + +/*! + * @brief Restarts a transaction which has stopped at the block GAP for the SDIO card. + * + * @param base USDHC peripheral base address. + */ +static inline void USDHC_SetContinueRequest(USDHC_Type *base) +{ + base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK; +} - /*! - * @brief Enables or disables the SDIO card control. - * - * @param base USDHC peripheral base address. - * @param mask SDIO card control flags mask(_usdhc_sdio_control_flag). - * @param enable True to enable, false to disable. - */ - static inline void USDHC_EnableSdioControl(USDHC_Type *base, uint32_t mask, bool enable) +/*! + * @brief Request stop at block gap function. + * + * @param base USDHC peripheral base address. + * @param enable True to stop at block gap, false to normal transfer. + */ +static inline void USDHC_RequestStopAtBlockGap(USDHC_Type *base, bool enable) +{ + if (enable) { - if (enable) { - base->PROT_CTRL |= mask; - } - else { - base->PROT_CTRL &= ~mask; - } + base->PROT_CTRL |= USDHC_PROT_CTRL_SABGREQ_MASK; } - - /*! - * @brief Restarts a transaction which has stopped at the block GAP for the SDIO card. - * - * @param base USDHC peripheral base address. - */ - static inline void USDHC_SetContinueRequest(USDHC_Type *base) + else { - base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK; + base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK; } +} + +/*! + * @brief Configures the MMC boot feature. + * + * Example: + @code + usdhc_boot_config_t config; + config.ackTimeoutCount = 4; + config.bootMode = kUSDHC_BootModeNormal; + config.blockCount = 5; + config.enableBootAck = true; + config.enableBoot = true; + config.enableAutoStopAtBlockGap = true; + USDHC_SetMmcBootConfig(USDHC, &config); + @endcode + * + * @param base USDHC peripheral base address. + * @param config The MMC boot configuration information. + */ +void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config); - /*! - * @brief Request stop at block gap function. - * - * @param base USDHC peripheral base address. - * @param enable true to stop at block gap, false to normal transfer - */ - static inline void USDHC_RequestStopAtBlockGap(USDHC_Type *base, bool enable) +/*! + * @brief Enables or disables the mmc boot mode. + * + * @param base USDHC peripheral base address. + * @param enable True to enable, false to disable. + */ +static inline void USDHC_EnableMmcBoot(USDHC_Type *base, bool enable) +{ + if (enable) { - if (enable) { - base->PROT_CTRL |= USDHC_PROT_CTRL_SABGREQ_MASK; - } - else { - base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK; - } + base->MMC_BOOT |= USDHC_MMC_BOOT_BOOT_EN_MASK; } - - /*! - * @brief Configures the MMC boot feature. - * - * Example: - @code - usdhc_boot_config_t config; - config.ackTimeoutCount = 4; - config.bootMode = kUSDHC_BootModeNormal; - config.blockCount = 5; - config.enableBootAck = true; - config.enableBoot = true; - config.enableAutoStopAtBlockGap = true; - USDHC_SetMmcBootConfig(USDHC, &config); - @endcode - * - * @param base USDHC peripheral base address. - * @param config The MMC boot configuration information. - */ - void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config); - - /*! - * @brief Enables or disables the mmc boot mode. - * - * @param base USDHC peripheral base address. - * @param enable True to enable, false to disable. - */ - static inline void USDHC_EnableMmcBoot(USDHC_Type *base, bool enable) + else { - if (enable) { - base->MMC_BOOT |= USDHC_MMC_BOOT_BOOT_EN_MASK; - } - else { - base->MMC_BOOT &= ~USDHC_MMC_BOOT_BOOT_EN_MASK; - } + base->MMC_BOOT &= ~USDHC_MMC_BOOT_BOOT_EN_MASK; } +} + +/*! + * @brief Forces generating events according to the given mask. + * + * @param base USDHC peripheral base address. + * @param mask The force events bit posistion (_usdhc_force_event). + */ +static inline void USDHC_SetForceEvent(USDHC_Type *base, uint32_t mask) +{ + base->FORCE_EVENT = mask; +} - /*! - * @brief Forces generating events according to the given mask. - * - * @param base USDHC peripheral base address. - * @param mask The force events mask(_usdhc_force_event). - */ - static inline void USDHC_SetForceEvent(USDHC_Type *base, uint32_t mask) +#if !(defined(FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT) && (FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT)) +/*! + * @brief Selects the USDHC output voltage. + * + * @param base USDHC peripheral base address. + * @param en18v True means 1.8V, false means 3.0V. + */ +static inline void UDSHC_SelectVoltage(USDHC_Type *base, bool en18v) +{ + if (en18v) { - base->FORCE_EVENT = mask; + base->VEND_SPEC |= USDHC_VEND_SPEC_VSELECT_MASK; } - - /*! - * @brief select the usdhc output voltage - * - * @param base USDHC peripheral base address. - * @param true 1.8V, false 3.0V - */ - static inline void UDSHC_SelectVoltage(USDHC_Type *base, bool en18v) + else { - if (en18v) { - base->VEND_SPEC |= USDHC_VEND_SPEC_VSELECT_MASK; - } - else { - base->VEND_SPEC &= ~USDHC_VEND_SPEC_VSELECT_MASK; - } + base->VEND_SPEC &= ~USDHC_VEND_SPEC_VSELECT_MASK; } +} +#endif #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) - /*! - * @brief check the SDR50 mode request tuning bit - * When this bit set, user should call USDHC_StandardTuning function - * @param base USDHC peripheral base address. - */ - static inline bool USDHC_RequestTuningForSDR50(USDHC_Type *base) - { - return base->HOST_CTRL_CAP & USDHC_HOST_CTRL_CAP_USE_TUNING_SDR50_MASK ? true : false; - } +/*! + * @brief Checks the SDR50 mode request tuning bit. + * When this bit set, application shall perform tuning for SDR50 mode. + * @param base USDHC peripheral base address. + */ +static inline bool USDHC_RequestTuningForSDR50(USDHC_Type *base) +{ + return ((base->HOST_CTRL_CAP & USDHC_HOST_CTRL_CAP_USE_TUNING_SDR50_MASK) != 0UL) ? true : false; +} - /*! - * @brief check the request re-tuning bit - * When this bit is set, user should do manual tuning or standard tuning function - * @param base USDHC peripheral base address. - */ - static inline bool USDHC_RequestReTuning(USDHC_Type *base) - { - return base->PRES_STATE & USDHC_PRES_STATE_RTR_MASK ? true : false; - } +/*! + * @brief Checks the request re-tuning bit. + * When this bit is set, user should do manual tuning or standard tuning function. + * @param base USDHC peripheral base address. + */ +static inline bool USDHC_RequestReTuning(USDHC_Type *base) +{ + return ((base->PRES_STATE & USDHC_PRES_STATE_RTR_MASK) != 0UL) ? true : false; +} - /*! - * @brief the SDR104 mode auto tuning enable and disable - * This function should call after tuning function execute pass, auto tuning will handle - * by hardware - * @param base USDHC peripheral base address. - * @param enable/disable flag - */ - static inline void USDHC_EnableAutoTuning(USDHC_Type *base, bool enable) +/*! + * @brief The SDR104 mode auto tuning enable and disable. + * This function should be called after tuning function execute pass, auto tuning will handle + * by hardware. + * @param base USDHC peripheral base address. + * @param enable enable/disable flag + */ +static inline void USDHC_EnableAutoTuning(USDHC_Type *base, bool enable) +{ + if (enable) { - if (enable) { - base->MIX_CTRL |= USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK; - } - else { - base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK; - } + base->MIX_CTRL |= USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK; } - - /*! - * @brief the config the re-tuning timer for mode 1 and mode 3 - * This timer is used for standard tuning auto re-tuning, - * @param base USDHC peripheral base address. - * @param timer counter value - */ - static inline void USDHC_SetRetuningTimer(USDHC_Type *base, uint32_t counter) + else { - base->HOST_CTRL_CAP &= ~USDHC_HOST_CTRL_CAP_TIME_COUNT_RETUNING_MASK; - base->HOST_CTRL_CAP |= USDHC_HOST_CTRL_CAP_TIME_COUNT_RETUNING(counter); + base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK; } +} - /*! - * @brief the auto tuning enbale for CMD/DATA line - * - * @param base USDHC peripheral base address. - */ - void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base); - - /*! - * @brief manual tuning trigger or abort - * User should handle the tuning cmd and find the boundary of the delay - * then calucate a average value which will be config to the CLK_TUNE_CTRL_STATUS - * This function should called before USDHC_AdjustDelayforSDR104 function - * @param base USDHC peripheral base address. - * @param tuning enable flag - */ - void USDHC_EnableManualTuning(USDHC_Type *base, bool enable); - - /*! - * @brief the SDR104 mode delay setting adjust - * This function should called after USDHC_ManualTuningForSDR104 - * @param base USDHC peripheral base address. - * @param delay setting configuration - * @retval kStatus_Fail config the delay setting fail - * @retval kStatus_Success config the delay setting success - */ - status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay); - - /*! - * @brief the enable standard tuning function - * The standard tuning window and tuning counter use the default config - * tuning cmd is send by the software, user need to check the tuning result - * can be used for SDR50,SDR104,HS200 mode tuning - * @param base USDHC peripheral base address. - * @param tuning start tap - * @param tuning step - * @param enable/disable flag - */ - void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable); - - /*! - * @brief Get execute std tuning status - * - * @param base USDHC peripheral base address. - */ - static inline uint32_t USDHC_GetExecuteStdTuningStatus(USDHC_Type *base) - { - return (base->AUTOCMD12_ERR_STATUS & USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK); - } +#if !(defined(FSL_FEATURE_USDHC_REGISTER_HOST_CTRL_CAP_HAS_NO_RETUNING_TIME_COUNTER) && \ + FSL_FEATURE_USDHC_REGISTER_HOST_CTRL_CAP_HAS_NO_RETUNING_TIME_COUNTER) +/*! + * @brief Configs the re-tuning timer for mode 1 and mode 3. + * This timer is used for standard tuning auto re-tuning, + * @param base USDHC peripheral base address. + * @param counter timer counter value + */ +static inline void USDHC_SetRetuningTimer(USDHC_Type *base, uint32_t counter) +{ + base->HOST_CTRL_CAP &= ~USDHC_HOST_CTRL_CAP_TIME_COUNT_RETUNING_MASK; + base->HOST_CTRL_CAP |= USDHC_HOST_CTRL_CAP_TIME_COUNT_RETUNING(counter); +} +#endif /* FSL_FEATURE_USDHC_REGISTER_HOST_CTRL_CAP_HAS_RETUNING_TIME_COUNTER */ - /*! - * @brief check std tuning result - * - * @param base USDHC peripheral base address. - */ - static inline uint32_t USDHC_CheckStdTuningResult(USDHC_Type *base) - { - return (base->AUTOCMD12_ERR_STATUS & USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK); - } +/*! + * @brief The auto tuning enbale for CMD/DATA line. + * + * @param base USDHC peripheral base address. + */ +void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base); - /*! - * @brief check tuning error - * - * @param base USDHC peripheral base address. - */ - static inline uint32_t USDHC_CheckTuningError(USDHC_Type *base) - { - return (base->CLK_TUNE_CTRL_STATUS & - (USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK)); - } +/*! + * @brief Manual tuning trigger or abort. + * User should handle the tuning cmd and find the boundary of the delay + * then calucate a average value which will be configured to the CLK_TUNE_CTRL_STATUS + * This function should be called before function @ref USDHC_AdjustDelayForManualTuning. + * @param base USDHC peripheral base address. + * @param enable tuning enable flag + */ +void USDHC_EnableManualTuning(USDHC_Type *base, bool enable); -#endif - /*! - * @brief the enable/disable DDR mode - * - * @param base USDHC peripheral base address. - * @param enable/disable flag - * @param nibble position - */ - void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos); +/*! + * @brief Get the tuning delay cell setting. + * + * @param base USDHC peripheral base address. + * @retval CLK Tuning Control and Status register value. + */ +static inline uint32_t USDHC_GetTuningDelayStatus(USDHC_Type *base) +{ + return base->CLK_TUNE_CTRL_STATUS >> 16U; +} /*! - * @brief the enable/disable HS400 mode + * @brief The tuning delay cell setting. * * @param base USDHC peripheral base address. - * @param enable/disable flag + * @param preDelay Set the number of delay cells on the feedback clock between the feedback clock and CLK_PRE. + * @param outDelay Set the number of delay cells on the feedback clock between CLK_PRE and CLK_OUT. + * @param postDelay Set the number of delay cells on the feedback clock between CLK_OUT and CLK_POST. + * @retval kStatus_Fail config the delay setting fail + * @retval kStatus_Success config the delay setting success + */ +status_t USDHC_SetTuningDelay(USDHC_Type *base, uint32_t preDelay, uint32_t outDelay, uint32_t postDelay); + +/*! + * @brief Adjusts delay for mannual tuning. + * @deprecated Do not use this function. It has been superceded by USDHC_SetTuingDelay + * @param base USDHC peripheral base address. + * @param delay setting configuration + * @retval #kStatus_Fail config the delay setting fail + * @retval #kStatus_Success config the delay setting success */ +status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay); + +/*! + * @brief set tuning counter tuning. + * @param base USDHC peripheral base address. + * @param counter tuning counter + * @retval #kStatus_Fail config the delay setting fail + * @retval #kStatus_Success config the delay setting success + */ +static inline void USDHC_SetStandardTuningCounter(USDHC_Type *base, uint8_t counter) +{ + base->TUNING_CTRL = + (base->TUNING_CTRL & (~USDHC_TUNING_CTRL_TUNING_COUNTER_MASK)) | USDHC_TUNING_CTRL_TUNING_COUNTER(counter); +} + +/*! + * @brief The enable standard tuning function. + * The standard tuning window and tuning counter using the default config + * tuning cmd is sent by the software, user need to check whether the tuning result + * can be used for SDR50, SDR104, and HS200 mode tuning. + * @param base USDHC peripheral base address. + * @param tuningStartTap start tap + * @param step tuning step + * @param enable enable/disable flag + */ +void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable); + +/*! + * @brief Gets execute STD tuning status. + * + * @param base USDHC peripheral base address. + */ +static inline uint32_t USDHC_GetExecuteStdTuningStatus(USDHC_Type *base) +{ + return (base->AUTOCMD12_ERR_STATUS & USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK); +} + +/*! + * @brief Checks STD tuning result. + * + * @param base USDHC peripheral base address. + */ +static inline uint32_t USDHC_CheckStdTuningResult(USDHC_Type *base) +{ + return (base->AUTOCMD12_ERR_STATUS & USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK); +} + +/*! + * @brief Checks tuning error. + * + * @param base USDHC peripheral base address. + */ +static inline uint32_t USDHC_CheckTuningError(USDHC_Type *base) +{ + return (base->CLK_TUNE_CTRL_STATUS & + (USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK)); +} + +#endif +/*! + * @brief The enable/disable DDR mode. + * + * @param base USDHC peripheral base address. + * @param enable enable/disable flag + * @param nibblePos nibble position + */ +void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos); + #if FSL_FEATURE_USDHC_HAS_HS400_MODE - static inline void USDHC_EnableHS400Mode(USDHC_Type *base, bool enable) +/*! + * @brief The enable/disable HS400 mode. + * + * @param base USDHC peripheral base address. + * @param enable enable/disable flag + */ +static inline void USDHC_EnableHS400Mode(USDHC_Type *base, bool enable) +{ + if (enable) { - if (enable) { - base->MIX_CTRL |= USDHC_MIX_CTRL_HS400_MODE_MASK; - } - else { - base->MIX_CTRL &= ~USDHC_MIX_CTRL_HS400_MODE_MASK; - } + base->MIX_CTRL |= USDHC_MIX_CTRL_HS400_MODE_MASK; } - - /*! - * @brief reset the strobe DLL - * - * @param base USDHC peripheral base address. - */ - static inline void USDHC_ResetStrobeDLL(USDHC_Type *base) + else { - base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK; + base->MIX_CTRL &= ~USDHC_MIX_CTRL_HS400_MODE_MASK; } +} - /*! - * @brief enable/disable the strobe DLL - * - * @param base USDHC peripheral base address. - * @param enable/disable flag - */ - static inline void USDHC_EnableStrobeDLL(USDHC_Type *base, bool enable) - { - if (enable) { - base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK; - } - else { - base->STROBE_DLL_CTRL &= ~USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK; - } - } +/*! + * @brief Resets the strobe DLL. + * + * @param base USDHC peripheral base address. + */ +static inline void USDHC_ResetStrobeDLL(USDHC_Type *base) +{ + base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK; +} - /*! - * @brief config the strobe DLL delay target and update interval - * - * @param base USDHC peripheral base address. - * @param delay target - * @param update interval - */ - static inline void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval) +/*! + * @brief Enables/disables the strobe DLL. + * + * @param base USDHC peripheral base address. + * @param enable enable/disable flag + */ +static inline void USDHC_EnableStrobeDLL(USDHC_Type *base, bool enable) +{ + if (enable) { - base->STROBE_DLL_CTRL &= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT_MASK | - USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_MASK); - - base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT(updateInterval) | - USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET(delayTarget); + base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK; } - - /*! - * @brief get the strobe DLL status - * - * @param base USDHC peripheral base address. - */ - static inline uint32_t USDHC_GetStrobeDLLStatus(USDHC_Type *base) + else { - return base->STROBE_DLL_STATUS; + base->STROBE_DLL_CTRL &= ~USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK; } +} +/*! + * @brief Configs the strobe DLL delay target and update interval. + * + * @param base USDHC peripheral base address. + * @param delayTarget delay target + * @param updateInterval update interval + */ +void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval); + +/*! + * @brief Enables manual override for slave delay chain using STROBE_SLV_OVERRIDE_VAL. + * + * @param base USDHC peripheral base address. + * @param delayTaps Valid delay taps range from 1 - 128 taps. A value of 0 selects tap 1, and a value of 0x7F selects + * tap 128. + */ +static inline void USDHC_SetStrobeDllOverride(USDHC_Type *base, uint32_t delayTaps) +{ + base->STROBE_DLL_CTRL &= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK | + USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_OVERRIDE_VAL_MASK); + + base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_OVERRIDE_MASK | + USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_OVERRIDE_VAL(delayTaps); +} + +/*! + * @brief Gets the strobe DLL status. + * + * @param base USDHC peripheral base address. + */ +static inline uint32_t USDHC_GetStrobeDLLStatus(USDHC_Type *base) +{ + return base->STROBE_DLL_STATUS; +} + +#endif + +/*! + * @brief USDHC data configuration. + * + * @param base USDHC peripheral base address. + * @param dataDirection Data direction, tx or rx. + * @param blockCount Data block count. + * @param blockSize Data block size. + * + */ +void USDHC_SetDataConfig(USDHC_Type *base, + usdhc_transfer_direction_t dataDirection, + uint32_t blockCount, + uint32_t blockSize); +/* @} */ + +/*! + * @name Transactional functions + * @{ + */ + +/*! + * @brief Creates the USDHC handle. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle pointer. + * @param callback Structure pointer to contain all callback functions. + * @param userData Callback function parameter. + */ +void USDHC_TransferCreateHandle(USDHC_Type *base, + usdhc_handle_t *handle, + const usdhc_transfer_callback_t *callback, + void *userData); + +#if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER +/*! + * @brief Transfers the command/scatter gather data using an interrupt and an asynchronous method. + * + * This function sends a command and data and returns immediately. It doesn't wait for the transfer to complete or + * to encounter an error. The application must not call this API in multiple threads at the same time. Because of that + * this API doesn't support the re-entry mechanism. + * This function is target for the application would like to have scatter gather buffer to be transferred within one + * read/write request, non scatter gather buffer is support by this function also. + * + * @note Call API @ref USDHC_TransferCreateHandle when calling this API. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + * @param dmaConfig adma configurations, must be not NULL, since the function is target for ADMA only. + * @param transfer scatter gather transfer content. + * + * @retval #kStatus_InvalidArgument Argument is invalid. + * @retval #kStatus_USDHC_BusyTransferring Busy transferring. + * @retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * @retval #kStatus_Success Operate successfully. + */ +status_t USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type *base, + usdhc_handle_t *handle, + usdhc_adma_config_t *dmaConfig, + usdhc_scatter_gather_transfer_t *transfer); +#else +/*! + * @brief Transfers the command/data using an interrupt and an asynchronous method. + * + * This function sends a command and data and returns immediately. It doesn't wait for the transfer to complete or + * to encounter an error. The application must not call this API in multiple threads at the same time. Because of that + * this API doesn't support the re-entry mechanism. + * + * @note Call API @ref USDHC_TransferCreateHandle when calling this API. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + * @param dmaConfig ADMA configuration. + * @param transfer Transfer content. + * @retval #kStatus_InvalidArgument Argument is invalid. + * @retval #kStatus_USDHC_BusyTransferring Busy transferring. + * @retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * @retval #kStatus_Success Operate successfully. + */ +status_t USDHC_TransferNonBlocking(USDHC_Type *base, + usdhc_handle_t *handle, + usdhc_adma_config_t *dmaConfig, + usdhc_transfer_t *transfer); #endif - /* @} */ - - /*! - * @name Transactional - * @{ - */ - - /*! - * @brief Transfers the command/data using a blocking method. - * - * This function waits until the command response/data is received or the USDHC encounters an error by polling the - * status - * flag. - * The application must not call this API in multiple threads at the same time. Because of that this API doesn't - * support the re-entry mechanism. - * - * @note There is no need to call the API 'USDHC_TransferCreateHandle' when calling this API. - * - * @param base USDHC peripheral base address. - * @param adma configuration - * @param transfer Transfer content. - * @retval kStatus_InvalidArgument Argument is invalid. - * @retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. - * @retval kStatus_USDHC_SendCommandFailed Send command failed. - * @retval kStatus_USDHC_TransferDataFailed Transfer data failed. - * @retval kStatus_Success Operate successfully. - */ - status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer); - - /*! - * @brief Creates the USDHC handle. - * - * @param base USDHC peripheral base address. - * @param handle USDHC handle pointer. - * @param callback Structure pointer to contain all callback functions. - * @param userData Callback function parameter. - */ - void USDHC_TransferCreateHandle(USDHC_Type *base, - usdhc_handle_t *handle, - const usdhc_transfer_callback_t *callback, - void *userData); - - /*! - * @brief Transfers the command/data using an interrupt and an asynchronous method. - * - * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or - * encounter an error. The application must not call this API in multiple threads at the same time. Because of that - * this API doesn't support the re-entry mechanism. - * - * @note Call the API 'USDHC_TransferCreateHandle' when calling this API. - * - * @param base USDHC peripheral base address. - * @param handle USDHC handle. - * @param adma configuration. - * @param transfer Transfer content. - * @retval kStatus_InvalidArgument Argument is invalid. - * @retval kStatus_USDHC_BusyTransferring Busy transferring. - * @retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. - * @retval kStatus_Success Operate successfully. - */ - status_t USDHC_TransferNonBlocking(USDHC_Type *base, - usdhc_handle_t *handle, - usdhc_adma_config_t *dmaConfig, - usdhc_transfer_t *transfer); - - /*! - * @brief IRQ handler for the USDHC. - * - * This function deals with the IRQs on the given host controller. - * - * @param base USDHC peripheral base address. - * @param handle USDHC handle. - */ - void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle); - - /* @} */ +/*! + * @brief Transfers the command/data using a blocking method. + * + * This function waits until the command response/data is received or the USDHC encounters an error by polling the + * status flag. \n + * The application must not call this API in multiple threads at the same time. Because this API doesn't + * support the re-entry mechanism. + * + * @note There is no need to call API @ref USDHC_TransferCreateHandle when calling this API. + * + * @param base USDHC peripheral base address. + * @param dmaConfig adma configuration + * @param transfer Transfer content. + * @retval #kStatus_InvalidArgument Argument is invalid. + * @retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * @retval #kStatus_USDHC_SendCommandFailed Send command failed. + * @retval #kStatus_USDHC_TransferDataFailed Transfer data failed. + * @retval #kStatus_Success Operate successfully. + */ +status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer); + +/*! + * @brief IRQ handler for the USDHC. + * + * This function deals with the IRQs on the given host controller. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + */ +void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle); + +/* @} */ #if defined(__cplusplus) } diff --git a/module-bsp/board/rt1051/puretx/board/pin_mux.h b/module-bsp/board/rt1051/puretx/board/pin_mux.h index 70c3c1857bc97d58c74bef29003412f358865c3f..5a0e897d91d55be82032bce85246df6235ef8d73 100644 --- a/module-bsp/board/rt1051/puretx/board/pin_mux.h +++ b/module-bsp/board/rt1051/puretx/board/pin_mux.h @@ -1,3 +1,6 @@ +// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + /* * The Clear BSD License * Copyright 2017-2018 NXP @@ -94,7 +97,7 @@ extern "C" #define PINMUX_EMMC_CMD IOMUXC_GPIO_SD_B1_05_USDHC2_CMD #define PINMUX_EMMC_RESET IOMUXC_GPIO_SD_B1_06_USDHC2_RESET_B - void PINMUX_InitEMMC(void); + void emmc_pin_config(uint32_t freq); #define PINMUX_AUDIOCODEC_SAIx_MCLK IOMUXC_GPIO_AD_B0_10_SAI2_MCLK #define PINMUX_AUDIOCODEC_SAIx_TX_DATA00 IOMUXC_GPIO_AD_B0_09_SAI2_TX_DATA diff --git a/module-bsp/board/rt1051/puretx/clock_config.cpp b/module-bsp/board/rt1051/puretx/clock_config.cpp index e6fc065e0d4a92821d2bf9578986d1a0bd31f962..bc61f102733667402d2251dfdfc38ea21219e1c0 100644 --- a/module-bsp/board/rt1051/puretx/clock_config.cpp +++ b/module-bsp/board/rt1051/puretx/clock_config.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md /* @@ -168,7 +168,7 @@ void BOARD_BootClockRUN(void) CLOCK_SetMux(kCLOCK_Usdhc1Mux, 0); // CSCMR1 (16) 0 - PLL2_PFD2, 1 - PLL2_PFD0 /* Set USDHC2_PODF. */ - CLOCK_SetDiv(kCLOCK_Usdhc2Div, 2); // CSCDR1 + CLOCK_SetDiv(kCLOCK_Usdhc2Div, 3); // CSCDR1 Div by 4 (3 + 1) to get ~82MHz clock /* Set Usdhc2 clock source. */ /* PLL2_PFD2/3 = 396MHz/3 = 132MHz */ CLOCK_SetMux(kCLOCK_Usdhc2Mux, 0); // CSCMR1 (17) 0 - PLL2_PFD2, 1 - PLL2_PFD0 diff --git a/module-bsp/board/rt1051/puretx/pin_mux.c b/module-bsp/board/rt1051/puretx/pin_mux.c index 87af9f6ba5cb22e04e6f06bb7a682e6547c75a72..678a71a0a43c41cdfcef2dccb4b0fc87d40d90ea 100644 --- a/module-bsp/board/rt1051/puretx/pin_mux.c +++ b/module-bsp/board/rt1051/puretx/pin_mux.c @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md /* @@ -297,7 +297,6 @@ void PINMUX_InitBootPins(void) { PINMUX_InitDEBUG_UART(); PINMUX_InitPowerButton(); - PINMUX_InitEMMC(); PINMUX_InitKeyboard(); PINMUX_InitAudioCodec(); PINMUX_InitEINK(); @@ -893,122 +892,72 @@ PINMUX_InitUSDHC: * Description : Configures pin routing and optionally pin electrical features. * * END ****************************************************************************************************************/ -void PINMUX_InitEMMC(void) +void emmc_pin_config(uint32_t freq) { - CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ - - IOMUXC_SetPinMux(PINMUX_EMMC_CMD, /* GPIO_SD_B0_00 is configured as USDHC1_CMD */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux(PINMUX_EMMC_CLK, /* GPIO_SD_B0_01 is configured as USDHC1_CLK */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux(PINMUX_EMMC_DATA0, /* GPIO_SD_B0_02 is configured as USDHC1_DATA0 */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux(PINMUX_EMMC_DATA1, /* GPIO_SD_B0_03 is configured as USDHC1_DATA1 */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux(PINMUX_EMMC_DATA2, /* GPIO_SD_B0_04 is configured as USDHC1_DATA2 */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux(PINMUX_EMMC_DATA3, /* GPIO_SD_B0_05 is configured as USDHC1_DATA3 */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux(PINMUX_EMMC_DATA4, /* GPIO_SD_B0_02 is configured as USDHC1_DATA0 */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux(PINMUX_EMMC_DATA5, /* GPIO_SD_B0_03 is configured as USDHC1_DATA1 */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux(PINMUX_EMMC_DATA6, /* GPIO_SD_B0_04 is configured as USDHC1_DATA2 */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux(PINMUX_EMMC_DATA7, /* GPIO_SD_B0_05 is configured as USDHC1_DATA3 */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - - IOMUXC_SetPinConfig(PINMUX_EMMC_CMD, /* GPIO_SD_B0_00 PAD functional properties : */ - 0x017089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Pull - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ - IOMUXC_SetPinConfig(PINMUX_EMMC_CLK, /* GPIO_SD_B0_01 PAD functional properties : */ - 0x014089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Disabled - Pull / Keep Select Field: Keeper - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ - IOMUXC_SetPinConfig(PINMUX_EMMC_DATA0, /* GPIO_SD_B0_02 PAD functional properties : */ - 0x017089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Pull - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ - IOMUXC_SetPinConfig(PINMUX_EMMC_DATA1, /* GPIO_SD_B0_03 PAD functional properties : */ - 0x017089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Pull - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ - IOMUXC_SetPinConfig(PINMUX_EMMC_DATA2, /* GPIO_SD_B0_04 PAD functional properties : */ - 0x017089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Pull - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ - IOMUXC_SetPinConfig(PINMUX_EMMC_DATA3, /* GPIO_SD_B0_05 PAD functional properties : */ - 0x017089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Pull - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ - - IOMUXC_SetPinConfig(PINMUX_EMMC_DATA4, /* GPIO_SD_B0_02 PAD functional properties : */ - 0x017089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Pull - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ - IOMUXC_SetPinConfig(PINMUX_EMMC_DATA5, /* GPIO_SD_B0_03 PAD functional properties : */ - 0x017089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Pull - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ - IOMUXC_SetPinConfig(PINMUX_EMMC_DATA6, /* GPIO_SD_B0_04 PAD functional properties : */ - 0x017089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Pull - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ - IOMUXC_SetPinConfig(PINMUX_EMMC_DATA7, /* GPIO_SD_B0_05 PAD functional properties : */ - 0x017089u); /* Slew Rate Field: Fast Slew Rate - Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Pull - Pull Up / Down Config. Field: 47K Ohm Pull Up - Hyst. Enable Field: Hysteresis Enabled */ + uint32_t speed = 0U, strength = 0U; + + if (freq <= 50000000) { + speed = 0U; + strength = 7U; + } + else if (freq <= 100000000) { + speed = 2U; + strength = 7U; + } + else { + speed = 3U; + strength = 7U; + } + + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_05_USDHC2_CMD, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_04_USDHC2_CLK, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(0) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_USDHC2_DATA0, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_02_USDHC2_DATA1, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_01_USDHC2_DATA2, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_00_USDHC2_DATA3, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_08_USDHC2_DATA4, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_09_USDHC2_DATA5, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_10_USDHC2_DATA6, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); + IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_11_USDHC2_DATA7, + IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength)); } void PINMUX_InitPowerButton(void) diff --git a/module-platform/rt1051/src/disk_emmc.cpp b/module-platform/rt1051/src/disk_emmc.cpp index 3347d79a59f1c03ce4ea7d87067ed7d90e8ced93..54bdca2905e38adb8e7e60c351d737b9b4477be1 100644 --- a/module-platform/rt1051/src/disk_emmc.cpp +++ b/module-platform/rt1051/src/disk_emmc.cpp @@ -1,27 +1,59 @@ -// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "disk_emmc.hpp" #include "board/rt1051/bsp/eMMC/fsl_mmc.h" #include "board/BoardDefinitions.hpp" +#include "board/pin_mux.h" #include #include #include #include +namespace +{ + constexpr uint32_t BOARD_SDMMC_MMC_HOST_SUPPORT_HS200_FREQ = 180000000U; + constexpr uint32_t DMA_BUFFER_WORD_SIZE = 1024U; + constexpr uint32_t USDHC_IRQ_PRIORITY = 6U; +} // namespace + namespace purefs::blkdev { - disk_emmc::disk_emmc() : initStatus(kStatus_Success), mmcCard(std::make_unique<_mmc_card>()) + AT_NONCACHEABLE_SECTION_ALIGN(uint32_t s_sdmmcHostDmaBuffer[DMA_BUFFER_WORD_SIZE], + SDMMCHOST_DMA_DESCRIPTOR_BUFFER_ALIGN_SIZE); + + disk_emmc::disk_emmc() + : initStatus(kStatus_Success), mmcCard(std::make_unique<_mmc_card>()), mmcHost(std::make_unique()) { assert(mmcCard.get()); + assert(mmcHost.get()); std::memset(mmcCard.get(), 0, sizeof(_mmc_card)); + std::memset(mmcHost.get(), 0, sizeof(sdmmchost_t)); + mmcCard->host = mmcHost.get(); + + mmcHost->dmaDesBuffer = s_sdmmcHostDmaBuffer; + mmcHost->dmaDesBufferWordsNum = DMA_BUFFER_WORD_SIZE; + mmcHost->enableCacheControl = kSDMMCHOST_CacheControlRWBuffer; +#if defined SDmmc_host_ENABLE_CACHE_LINE_ALIGN_TRANSFER && SDmmc_host_ENABLE_CACHE_LINE_ALIGN_TRANSFER + mmcHost->cacheAlignBuffer = s_sdmmcCacheLineAlignBuffer; + mmcHost->cacheAlignBufferSize = BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE * 2U; +#endif mmcCard->busWidth = kMMC_DataBusWidth8bit; - mmcCard->busTiming = kMMC_HighSpeedTiming; + mmcCard->busTiming = kMMC_HighSpeed200Timing; mmcCard->enablePreDefinedBlockCount = true; - mmcCard->host.base = USDHC2; - mmcCard->host.sourceClock_Hz = GetPerphSourceClock(PerphClock_USDHC2); + mmcCard->host->hostController.base = USDHC2; + mmcCard->host->hostController.sourceClock_Hz = + CLOCK_GetFreq(kCLOCK_SysPllPfd2Clk) / (CLOCK_GetDiv(kCLOCK_Usdhc2Div) + 1U); + mmcCard->usrParam.ioStrength = emmc_pin_config; + mmcCard->usrParam.maxFreq = BOARD_SDMMC_MMC_HOST_SUPPORT_HS200_FREQ; + mmcCard->hostVoltageWindowVCCQ = kMMC_VoltageWindow120; + mmcCard->hostVoltageWindowVCC = kMMC_VoltageWindow170to195; + /* card detect type */ +#if defined DEMO_SDCARD_POWER_CTRL_FUNCTION_EXIST + g_sd.usrParam.pwr = &s_sdCardPwrCtrl; +#endif driverUSDHC = drivers::DriverUSDHC::Create( "EMMC", static_cast(BoardDefinitions::EMMC_USDHC_INSTANCE)); @@ -38,7 +70,7 @@ namespace purefs::blkdev initStatus = err; return initStatus; } - + NVIC_SetPriority(USDHC2_IRQn, USDHC_IRQ_PRIORITY); LOG_INFO("\neMMC card info:\n%s", get_emmc_info_str().c_str()); return statusBlkDevSuccess; @@ -105,18 +137,21 @@ namespace purefs::blkdev if (!mmcCard->isHostReady) { return statusBlkDevFail; } - // Wait for the card's buffer to become empty - while ((GET_SDMMCHOST_STATUS(mmcCard->host.base) & CARD_DATA0_STATUS_MASK) != CARD_DATA0_NOT_BUSY) { - taskYIELD(); + status_t error = MMC_PollingCardStatusBusy(mmcCard.get(), true, 10000U); + if (kStatus_SDMMC_CardStatusIdle != error) { + SDMMC_LOG("Error : read failed with wrong card status\r\n"); + return kStatus_SDMMC_PollingCardIdleFailed; } + if (pmState == pm_state::suspend) { driverUSDHC->Enable(); } - auto err = MMC_WaitWriteComplete(mmcCard.get()); + + error = MMC_PollingCardStatusBusy(mmcCard.get(), true, 10000U); if (pmState == pm_state::suspend) { driverUSDHC->Disable(); } - if (err != kStatus_Success) { + if (error != kStatus_Success) { return kStatus_SDMMC_WaitWriteCompleteFailed; } return statusBlkDevSuccess; @@ -145,13 +180,13 @@ namespace purefs::blkdev return mmcCard->blockSize; case info_type::sector_count: switch (hwpart) { - case kMMC_AccessPartitionUserArea: + case kMMC_AccessPartitionUserAera: return mmcCard->userPartitionBlocks; case kMMC_AccessPartitionBoot1: case kMMC_AccessPartitionBoot2: return mmcCard->bootPartitionBlocks; default: - return mmcCard->systemPartitionBlocks; + return mmcCard->bootPartitionBlocks; } case info_type::erase_block: // not supported diff --git a/module-platform/rt1051/src/disk_emmc.hpp b/module-platform/rt1051/src/disk_emmc.hpp index ca4e91f6181ab0356472ae1d2541e6f6bcf607b2..a73a3b85f49ebdee89e8e85d53bdaabdce48dd7a 100644 --- a/module-platform/rt1051/src/disk_emmc.hpp +++ b/module-platform/rt1051/src/disk_emmc.hpp @@ -4,6 +4,7 @@ #pragma once #include "drivers/usdhc/DriverUSDHC.hpp" +#include "board/rt1051/bsp/eMMC/fsl_sdmmc_host.h" #include #include #include @@ -63,6 +64,7 @@ namespace purefs::blkdev std::atomic currHwPart{0}; std::unique_ptr<_mmc_card> mmcCard; + std::unique_ptr mmcHost; std::shared_ptr driverUSDHC; /* Read from datasheets */ diff --git a/products/PurePhone/BinaryAssetsVersions.cmake b/products/PurePhone/BinaryAssetsVersions.cmake index 6d1cd3c9c019eeb56f58b2d606b8a496a14d54bd..252da7c351cf1c6ae7576f8ef3dfc6ca3d9b17b0 100644 --- a/products/PurePhone/BinaryAssetsVersions.cmake +++ b/products/PurePhone/BinaryAssetsVersions.cmake @@ -1,9 +1,9 @@ # This file sets versions of downloaded binaries for release packaging purposes if (NOT DEFINED ECOBOOT_BIN_VERSION) - set(ECOBOOT_BIN_VERSION 2.0.2 CACHE STRING "bootloader binary version to download from bootloader release page") + set(ECOBOOT_BIN_VERSION 2.0.3 CACHE STRING "bootloader binary version to download from bootloader release page") endif() if (NOT DEFINED RECOVERY_BIN_VERSION) - set(RECOVERY_BIN_VERSION 1.0.0 CACHE STRING "recovery binary version to download from recovery release page") + set(RECOVERY_BIN_VERSION 1.0.1 CACHE STRING "recovery binary version to download from recovery release page") endif()